Commit cf3dc786 authored by Ezekiel Kigbo's avatar Ezekiel Kigbo

Merge branch '337935-add-timezone-to-snapshot-view-of-gitlab-user-profile' into 'master'

Add local time to user popover

See merge request gitlab-org/gitlab!70806
parents fdf3bd55 1b3e7dba
...@@ -41,6 +41,7 @@ const populateUserInfo = (user) => { ...@@ -41,6 +41,7 @@ const populateUserInfo = (user) => {
workInformation: userData.work_information, workInformation: userData.work_information,
websiteUrl: userData.website_url, websiteUrl: userData.website_url,
pronouns: userData.pronouns, pronouns: userData.pronouns,
localTime: userData.local_time,
loaded: true, loaded: true,
}); });
} }
......
...@@ -93,19 +93,27 @@ export default { ...@@ -93,19 +93,27 @@ export default {
</div> </div>
<div class="gl-text-gray-500"> <div class="gl-text-gray-500">
<div v-if="user.bio" class="gl-display-flex gl-mb-2"> <div v-if="user.bio" class="gl-display-flex gl-mb-2">
<gl-icon name="profile" class="gl-text-gray-400 gl-flex-shrink-0" /> <gl-icon name="profile" class="gl-flex-shrink-0" />
<span ref="bio" class="gl-ml-2 gl-overflow-hidden">{{ user.bio }}</span> <span ref="bio" class="gl-ml-2 gl-overflow-hidden">{{ user.bio }}</span>
</div> </div>
<div v-if="user.workInformation" class="gl-display-flex gl-mb-2"> <div v-if="user.workInformation" class="gl-display-flex gl-mb-2">
<gl-icon name="work" class="gl-text-gray-400 gl-flex-shrink-0" /> <gl-icon name="work" class="gl-flex-shrink-0" />
<span ref="workInformation" class="gl-ml-2">{{ user.workInformation }}</span> <span ref="workInformation" class="gl-ml-2">{{ user.workInformation }}</span>
</div> </div>
<div v-if="user.location" class="gl-display-flex gl-mb-2">
<gl-icon name="location" class="gl-flex-shrink-0" />
<span class="gl-ml-2">{{ user.location }}</span>
</div>
<div
v-if="user.localTime && !user.bot"
class="gl-display-flex gl-mb-2"
data-testid="user-popover-local-time"
>
<gl-icon name="clock" class="gl-flex-shrink-0" />
<span class="gl-ml-2">{{ user.localTime }}</span>
</div>
</div> </div>
<div v-if="user.location" class="js-location gl-text-gray-500 gl-display-flex"> <div v-if="statusHtml" class="gl-mb-2" data-testid="user-popover-status">
<gl-icon name="location" class="gl-text-gray-400 flex-shrink-0" />
<span class="gl-ml-2">{{ user.location }}</span>
</div>
<div v-if="statusHtml" class="js-user-status gl-mt-3">
<span v-safe-html:[$options.safeHtmlConfig]="statusHtml"></span> <span v-safe-html:[$options.safeHtmlConfig]="statusHtml"></span>
</div> </div>
<div v-if="user.bot" class="gl-text-blue-500"> <div v-if="user.bot" class="gl-text-blue-500">
......
...@@ -4,6 +4,7 @@ module API ...@@ -4,6 +4,7 @@ module API
module Entities module Entities
class User < UserBasic class User < UserBasic
include UsersHelper include UsersHelper
include TimeZoneHelper
include ActionView::Helpers::SanitizeHelper include ActionView::Helpers::SanitizeHelper
expose :created_at, if: ->(user, opts) { Ability.allowed?(opts[:current_user], :read_user_profile, user) } expose :created_at, if: ->(user, opts) { Ability.allowed?(opts[:current_user], :read_user_profile, user) }
...@@ -24,6 +25,10 @@ module API ...@@ -24,6 +25,10 @@ module API
expose :bio_html do |user| expose :bio_html do |user|
strip_tags(user.bio) strip_tags(user.bio)
end end
expose :local_time do |user|
local_time(user.timezone)
end
end end
end end
end end
...@@ -9,6 +9,7 @@ const DEFAULT_PROPS = { ...@@ -9,6 +9,7 @@ const DEFAULT_PROPS = {
username: 'root', username: 'root',
name: 'Administrator', name: 'Administrator',
location: 'Vienna', location: 'Vienna',
localTime: '2:30 PM',
bot: false, bot: false,
bio: null, bio: null,
workInformation: null, workInformation: null,
...@@ -31,10 +32,11 @@ describe('User Popover Component', () => { ...@@ -31,10 +32,11 @@ describe('User Popover Component', () => {
wrapper.destroy(); wrapper.destroy();
}); });
const findUserStatus = () => wrapper.find('.js-user-status'); const findUserStatus = () => wrapper.findByTestId('user-popover-status');
const findTarget = () => document.querySelector('.js-user-link'); const findTarget = () => document.querySelector('.js-user-link');
const findUserName = () => wrapper.find(UserNameWithStatus); const findUserName = () => wrapper.find(UserNameWithStatus);
const findSecurityBotDocsLink = () => wrapper.findByTestId('user-popover-bot-docs-link'); const findSecurityBotDocsLink = () => wrapper.findByTestId('user-popover-bot-docs-link');
const findUserLocalTime = () => wrapper.findByTestId('user-popover-local-time');
const createWrapper = (props = {}, options = {}) => { const createWrapper = (props = {}, options = {}) => {
wrapper = mountExtended(UserPopover, { wrapper = mountExtended(UserPopover, {
...@@ -71,7 +73,6 @@ describe('User Popover Component', () => { ...@@ -71,7 +73,6 @@ describe('User Popover Component', () => {
expect(wrapper.text()).toContain(DEFAULT_PROPS.user.name); expect(wrapper.text()).toContain(DEFAULT_PROPS.user.name);
expect(wrapper.text()).toContain(DEFAULT_PROPS.user.username); expect(wrapper.text()).toContain(DEFAULT_PROPS.user.username);
expect(wrapper.text()).toContain(DEFAULT_PROPS.user.location);
}); });
it('shows icon for location', () => { it('shows icon for location', () => {
...@@ -164,6 +165,25 @@ describe('User Popover Component', () => { ...@@ -164,6 +165,25 @@ describe('User Popover Component', () => {
}); });
}); });
describe('local time', () => {
it('should show local time when it is available', () => {
createWrapper();
expect(findUserLocalTime().exists()).toBe(true);
});
it('should not show local time when it is not available', () => {
const user = {
...DEFAULT_PROPS.user,
localTime: null,
};
createWrapper({ user });
expect(findUserLocalTime().exists()).toBe(false);
});
});
describe('status data', () => { describe('status data', () => {
it('should show only message', () => { it('should show only message', () => {
const user = { ...DEFAULT_PROPS.user, status: { message_html: 'Hello World' } }; const user = { ...DEFAULT_PROPS.user, status: { message_html: 'Hello World' } };
...@@ -256,5 +276,11 @@ describe('User Popover Component', () => { ...@@ -256,5 +276,11 @@ describe('User Popover Component', () => {
const securityBotDocsLink = findSecurityBotDocsLink(); const securityBotDocsLink = findSecurityBotDocsLink();
expect(securityBotDocsLink.text()).toBe('Learn more about %<>\';"'); expect(securityBotDocsLink.text()).toBe('Learn more about %<>\';"');
}); });
it('does not display local time', () => {
createWrapper({ user: SECURITY_BOT_USER });
expect(findUserLocalTime().exists()).toBe(false);
});
}); });
}); });
...@@ -3,10 +3,13 @@ ...@@ -3,10 +3,13 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe API::Entities::User do RSpec.describe API::Entities::User do
let(:user) { create(:user) } let_it_be(:timezone) { 'America/Los_Angeles' }
let(:user) { create(:user, timezone: timezone) }
let(:current_user) { create(:user) } let(:current_user) { create(:user) }
let(:entity) { described_class.new(user, current_user: current_user) }
subject { described_class.new(user, current_user: current_user).as_json } subject { entity.as_json }
it 'exposes correct attributes' do it 'exposes correct attributes' do
expect(subject).to include(:bio, :location, :public_email, :skype, :linkedin, :twitter, :website_url, :organization, :job_title, :work_information, :pronouns) expect(subject).to include(:bio, :location, :public_email, :skype, :linkedin, :twitter, :website_url, :organization, :job_title, :work_information, :pronouns)
...@@ -35,4 +38,10 @@ RSpec.describe API::Entities::User do ...@@ -35,4 +38,10 @@ RSpec.describe API::Entities::User do
expect(subject[:bot]).to eq(true) expect(subject[:bot]).to eq(true)
end end
end end
it 'exposes local_time' do
local_time = '2:30 PM'
expect(entity).to receive(:local_time).with(timezone).and_return(local_time)
expect(subject[:local_time]).to eq(local_time)
end
end end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment