diff --git a/apps/meteor/client/components/UserInfo/UserInfo.spec.tsx b/apps/meteor/client/components/UserInfo/UserInfo.spec.tsx new file mode 100644 index 0000000000000..6e2c772e368a3 --- /dev/null +++ b/apps/meteor/client/components/UserInfo/UserInfo.spec.tsx @@ -0,0 +1,18 @@ +import { composeStories } from '@storybook/react'; +import { render } from '@testing-library/react'; +import { axe } from 'jest-axe'; + +import * as stories from './UserInfo.stories'; + +const testCases = Object.values(composeStories(stories)).map((Story) => [Story.storyName || 'Story', Story]); +test.each(testCases)(`renders %s without crashing`, async (_storyname, Story) => { + const { baseElement } = render(); + expect(baseElement).toMatchSnapshot(); +}); + +test.each(testCases)('%s should have no a11y violations', async (_storyname, Story) => { + const { container } = render(); + + const results = await axe(container); + expect(results).toHaveNoViolations(); +}); diff --git a/apps/meteor/client/components/UserInfo/UserInfo.stories.tsx b/apps/meteor/client/components/UserInfo/UserInfo.stories.tsx index d6bd2cf662e1d..9e76aa0064590 100644 --- a/apps/meteor/client/components/UserInfo/UserInfo.stories.tsx +++ b/apps/meteor/client/components/UserInfo/UserInfo.stories.tsx @@ -1,8 +1,9 @@ import type { Meta, StoryFn } from '@storybook/react'; -import { Contextualbar } from '../Contextualbar'; +import { ContextualbarDialog } from '../Contextualbar'; import * as Status from '../UserStatus'; import UserInfo from './UserInfo'; +import { UserCardRole } from '../UserCard'; export default { component: UserInfo, @@ -10,32 +11,32 @@ export default { layout: 'fullscreen', actions: { argTypesRegex: '^on.*' }, }, - decorators: [(fn) => {fn()}], + decorators: [ + (fn) => ( + + {fn()} + + ), + ], } satisfies Meta; -const Template: StoryFn = (args) => ; - -export const Default = Template.bind({}); -Default.args = { +const defaultArgs = { name: 'Guilherme Gazzo', username: 'guilherme.gazzo', + nickname: 'gazzo', statusText: '🛴 currently working on User Card', - bio: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla tempus, eros convallis vulputate cursus, nisi neque eleifend libero, eget lacinia justo purus nec est. In at sodales ipsum. Sed lacinia quis purus eget pulvinar. Aenean eu pretium nunc, at aliquam magna. Praesent dignissim, tortor sed volutpat mattis, mauris diam pulvinar leo, porta commodo risus est non purus. Mauris in justo vel lorem ullamcorper hendrerit. Nam est metus, viverra a pellentesque vitae, ornare eget odio. Morbi tempor feugiat mattis. Morbi non felis tempor, aliquam justo sed, sagittis nibh. Mauris consequat ex metus. Praesent sodales sit amet nibh a vulputate. Integer commodo, mi vel bibendum sollicitudin, urna lectus accumsan ante, eget faucibus augue ex id neque. Aenean consectetur, orci a pellentesque mattis, tortor tellus fringilla elit, non ullamcorper risus nunc feugiat risus. Fusce sit amet nisi dapibus turpis commodo placerat. In tortor ante, vehicula sit amet augue et, imperdiet porta sem.', - // actions: [, ], - utcOffset: -3, + bio: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla tempus, eros convallis vulputate cursus, nisi neque eleifend libero, eget lacinia justo purus nec est. In at sodales ipsum. Sed lacinia quis purus eget pulvinar. Aenean eu pretium nunc, at aliquam magna. Praesent dignissim, tortor sed volutpat mattis, mauris diam pulvinar leo, porta commodo risus est non purus.', email: 'rocketchat@rocket.chat', status: , + roles: [admin, user], }; -export const WithNickname = Template.bind({}); -WithNickname.args = { - name: 'Guilherme Gazzo', - username: 'guilherme.gazzo', - statusText: '🛴 currently working on User Card', - bio: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla tempus, eros convallis vulputate cursus, nisi neque eleifend libero, eget lacinia justo purus nec est. In at sodales ipsum. Sed lacinia quis purus eget pulvinar. Aenean eu pretium nunc, at aliquam magna. Praesent dignissim, tortor sed volutpat mattis, mauris diam pulvinar leo, porta commodo risus est non purus. Mauris in justo vel lorem ullamcorper hendrerit. Nam est metus, viverra a pellentesque vitae, ornare eget odio. Morbi tempor feugiat mattis. Morbi non felis tempor, aliquam justo sed, sagittis nibh. Mauris consequat ex metus. Praesent sodales sit amet nibh a vulputate. Integer commodo, mi vel bibendum sollicitudin, urna lectus accumsan ante, eget faucibus augue ex id neque. Aenean consectetur, orci a pellentesque mattis, tortor tellus fringilla elit, non ullamcorper risus nunc feugiat risus. Fusce sit amet nisi dapibus turpis commodo placerat. In tortor ante, vehicula sit amet augue et, imperdiet porta sem.', - // actions: [, ], - utcOffset: -3, - email: 'rocketchat@rocket.chat', - status: , - nickname: 'Nickname', +const Template: StoryFn = (args) => ; + +export const Default = Template.bind({}); + +export const WithABACAttributes = Template.bind({}); +WithABACAttributes.args = { + // @ts-expect-error - abacAttributes is not yet implemented in Users properties + abacAttributes: ['Classified', 'Top Secret', 'Confidential'], }; diff --git a/apps/meteor/client/components/UserInfo/UserInfo.tsx b/apps/meteor/client/components/UserInfo/UserInfo.tsx index 4a0413d912870..58bbbc1a52ee5 100644 --- a/apps/meteor/client/components/UserInfo/UserInfo.tsx +++ b/apps/meteor/client/components/UserInfo/UserInfo.tsx @@ -22,6 +22,7 @@ import { import MarkdownText from '../MarkdownText'; import UTCClock from '../UTCClock'; import { UserCardRoles } from '../UserCard'; +import UserInfoABACAttributes from './UserInfoABACAttributes'; import UserInfoAvatar from './UserInfoAvatar'; type UserInfoDataProps = Serialized< @@ -70,6 +71,8 @@ const UserInfo = ({ canViewAllInfo, actions, reason, + // @ts-expect-error - abacAttributes is not yet implemented in Users properties + abacAttributes = null, ...props }: UserInfoProps): ReactElement => { const { t } = useTranslation(); @@ -113,7 +116,7 @@ const UserInfo = ({ )} - {roles.length !== 0 && ( + {roles?.length !== 0 && ( {t('Roles')} {roles} @@ -127,10 +130,12 @@ const UserInfo = ({ )} - {Number.isInteger(utcOffset) && ( + {utcOffset && Number.isInteger(utcOffset) && ( {t('Local_Time')} - {utcOffset && } + + + )} @@ -175,6 +180,12 @@ const UserInfo = ({ )} + {abacAttributes?.length > 0 && ( + + {t('ABAC_Attributes')} + + + )} {userCustomFields?.map( (customField) => customField?.value && ( diff --git a/apps/meteor/client/components/UserInfo/UserInfoABACAttribute.tsx b/apps/meteor/client/components/UserInfo/UserInfoABACAttribute.tsx new file mode 100644 index 0000000000000..5605bd91d7cd7 --- /dev/null +++ b/apps/meteor/client/components/UserInfo/UserInfoABACAttribute.tsx @@ -0,0 +1,11 @@ +import { Tag } from '@rocket.chat/fuselage'; + +type UserInfoABACAttributeProps = { + attribute: string; +}; + +const UserInfoABACAttribute = ({ attribute }: UserInfoABACAttributeProps) => { + return ; +}; + +export default UserInfoABACAttribute; diff --git a/apps/meteor/client/components/UserInfo/UserInfoABACAttributes.tsx b/apps/meteor/client/components/UserInfo/UserInfoABACAttributes.tsx new file mode 100644 index 0000000000000..b9cf2870d3d64 --- /dev/null +++ b/apps/meteor/client/components/UserInfo/UserInfoABACAttributes.tsx @@ -0,0 +1,23 @@ +import { Box, Margins } from '@rocket.chat/fuselage'; + +import UserInfoABACAttribute from './UserInfoABACAttribute'; + +type UserInfoABACAttributesProps = { + abacAttributes: string[]; +}; + +const UserInfoABACAttributes = ({ abacAttributes }: UserInfoABACAttributesProps) => { + return ( + + + {abacAttributes.map((attribute, index) => ( + + + + ))} + + + ); +}; + +export default UserInfoABACAttributes; diff --git a/apps/meteor/client/components/UserInfo/__snapshots__/UserInfo.spec.tsx.snap b/apps/meteor/client/components/UserInfo/__snapshots__/UserInfo.spec.tsx.snap new file mode 100644 index 0000000000000..33c5d0d0d537b --- /dev/null +++ b/apps/meteor/client/components/UserInfo/__snapshots__/UserInfo.spec.tsx.snap @@ -0,0 +1,574 @@ +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing + +exports[`renders Default without crashing 1`] = ` + +
+