snapshot of https://github.com/RocketChat/Rocket.Chat.git (develop, 2026-09-16; blobs > 131072B omitted)
Some checks failed
Create issues from TODOs / todos (push) Failing after 3s
Close inactive issues / close-issues (push) Has been cancelled
Deploy GitHub Pages / deploy-preview (push) Has been cancelled
CI / ⚙️ Variables Setup (push) Has been cancelled
CI / ⚙️ Test Guard (push) Has been cancelled
CI / 🚀 Notify external services - draft (push) Has been cancelled
CI / 📦 Build Packages (push) Has been cancelled
CI / 📦 Meteor Build (coverage) (push) Has been cancelled
CI / 📦 Meteor Build (production) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], fips) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Publish Docker Images (ghcr.io) (push) Has been cancelled
CI / 📦 Track Image Sizes (push) Has been cancelled
CI / 🔎 Code Check - Action Lint (push) Has been cancelled
CI / 🔎 Code Check (push) Has been cancelled
CI / 🔨 Test Storybook (push) Has been cancelled
CI / 🔨 Test Unit (push) Has been cancelled
CI / 🔨 Test API (CE) (push) Has been cancelled
CI / 🔨 Test API Livechat (CE) (push) Has been cancelled
CI / 🔨 Test UI (CE) (push) Has been cancelled
CI / 🔨 Test API (EE) (push) Has been cancelled
CI / 🔨 Test API Livechat (EE) (push) Has been cancelled
CI / 🔨 Test API Apps (deno-runtime - EE) (push) Has been cancelled
CI / 🔨 Test UI (EE) (push) Has been cancelled
CI / 🔨 Test API (FIPS) (push) Has been cancelled
CI / 🔨 Test API Livechat (FIPS) (push) Has been cancelled
CI / 🔨 Test UI (FIPS) (push) Has been cancelled
CI / 🔨 Test Federation Matrix (push) Has been cancelled
CI / 📊 Report Coverage (push) Has been cancelled
CI / ✅ Tests Done (push) Has been cancelled
CI / 🚀 Publish build assets (push) Has been cancelled
CI / 🚀 Publish Docker Images (DockerHub) (push) Has been cancelled
CI / 🚀 Notify external services (push) Has been cancelled
CI / Update Version Durability (push) Has been cancelled
Release / Release (push) Has been cancelled
Auto-close duplicate issues / auto-close-duplicates (push) Failing after 1s
Code scanning - action / CodeQL-Build (push) Failing after 1s
Some checks failed
Create issues from TODOs / todos (push) Failing after 3s
Close inactive issues / close-issues (push) Has been cancelled
Deploy GitHub Pages / deploy-preview (push) Has been cancelled
CI / ⚙️ Variables Setup (push) Has been cancelled
CI / ⚙️ Test Guard (push) Has been cancelled
CI / 🚀 Notify external services - draft (push) Has been cancelled
CI / 📦 Build Packages (push) Has been cancelled
CI / 📦 Meteor Build (coverage) (push) Has been cancelled
CI / 📦 Meteor Build (production) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], fips) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Publish Docker Images (ghcr.io) (push) Has been cancelled
CI / 📦 Track Image Sizes (push) Has been cancelled
CI / 🔎 Code Check - Action Lint (push) Has been cancelled
CI / 🔎 Code Check (push) Has been cancelled
CI / 🔨 Test Storybook (push) Has been cancelled
CI / 🔨 Test Unit (push) Has been cancelled
CI / 🔨 Test API (CE) (push) Has been cancelled
CI / 🔨 Test API Livechat (CE) (push) Has been cancelled
CI / 🔨 Test UI (CE) (push) Has been cancelled
CI / 🔨 Test API (EE) (push) Has been cancelled
CI / 🔨 Test API Livechat (EE) (push) Has been cancelled
CI / 🔨 Test API Apps (deno-runtime - EE) (push) Has been cancelled
CI / 🔨 Test UI (EE) (push) Has been cancelled
CI / 🔨 Test API (FIPS) (push) Has been cancelled
CI / 🔨 Test API Livechat (FIPS) (push) Has been cancelled
CI / 🔨 Test UI (FIPS) (push) Has been cancelled
CI / 🔨 Test Federation Matrix (push) Has been cancelled
CI / 📊 Report Coverage (push) Has been cancelled
CI / ✅ Tests Done (push) Has been cancelled
CI / 🚀 Publish build assets (push) Has been cancelled
CI / 🚀 Publish Docker Images (DockerHub) (push) Has been cancelled
CI / 🚀 Notify external services (push) Has been cancelled
CI / Update Version Durability (push) Has been cancelled
Release / Release (push) Has been cancelled
Auto-close duplicate issues / auto-close-duplicates (push) Failing after 1s
Code scanning - action / CodeQL-Build (push) Failing after 1s
This commit is contained in:
18
apps/meteor/client/components/UserInfo/UserInfo.spec.tsx
Normal file
18
apps/meteor/client/components/UserInfo/UserInfo.spec.tsx
Normal file
@@ -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(<Story />);
|
||||
expect(baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test.each(testCases)('%s should have no a11y violations', async (_storyname, Story) => {
|
||||
const { container } = render(<Story />);
|
||||
|
||||
const results = await axe(container);
|
||||
expect(results).toHaveNoViolations();
|
||||
});
|
||||
72
apps/meteor/client/components/UserInfo/UserInfo.stories.tsx
Normal file
72
apps/meteor/client/components/UserInfo/UserInfo.stories.tsx
Normal file
@@ -0,0 +1,72 @@
|
||||
import { ContextualbarDialog } from '@rocket.chat/ui-client';
|
||||
import type { Meta, StoryFn } from '@storybook/react';
|
||||
|
||||
import UserInfo from './UserInfo';
|
||||
import { UserCardRole } from '../UserCard';
|
||||
import * as Status from '../UserStatus';
|
||||
import { UserStatusText } from '../UserStatusText';
|
||||
|
||||
export default {
|
||||
component: UserInfo,
|
||||
parameters: {
|
||||
layout: 'fullscreen',
|
||||
actions: { argTypesRegex: '^on.*' },
|
||||
},
|
||||
decorators: [
|
||||
(fn) => (
|
||||
<ContextualbarDialog aria-label='User Info' height='100vh'>
|
||||
{fn()}
|
||||
</ContextualbarDialog>
|
||||
),
|
||||
],
|
||||
} satisfies Meta<typeof UserInfo>;
|
||||
|
||||
const defaultArgs = {
|
||||
name: 'Guilherme Gazzo',
|
||||
username: 'guilherme.gazzo',
|
||||
nickname: 'gazzo',
|
||||
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: <Status.Offline />,
|
||||
customStatus: <UserStatusText statusText='🛴 currently working on User Card' />,
|
||||
roles: [<UserCardRole key='admin'>admin</UserCardRole>, <UserCardRole key='user'>user</UserCardRole>],
|
||||
};
|
||||
|
||||
const Template: StoryFn<typeof UserInfo> = (args) => <UserInfo {...defaultArgs} {...args} />;
|
||||
|
||||
export const Default = {
|
||||
render: Template,
|
||||
};
|
||||
|
||||
export const WithVoiceCallExtension = {
|
||||
render: Template,
|
||||
|
||||
args: {
|
||||
freeSwitchExtension: '1234567890',
|
||||
},
|
||||
};
|
||||
|
||||
export const WithABACAttributes = {
|
||||
render: Template,
|
||||
|
||||
args: {
|
||||
abacAttributes: [
|
||||
{
|
||||
key: 'Classified',
|
||||
values: ['Top Secret', 'Confidential'],
|
||||
},
|
||||
{
|
||||
key: 'Security_Clearance',
|
||||
values: ['Top Secret', 'Confidential'],
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export const InvitedUser = {
|
||||
render: Template,
|
||||
|
||||
args: {
|
||||
invitationDate: '2025-01-01T12:00:00Z',
|
||||
},
|
||||
};
|
||||
233
apps/meteor/client/components/UserInfo/UserInfo.tsx
Normal file
233
apps/meteor/client/components/UserInfo/UserInfo.tsx
Normal file
@@ -0,0 +1,233 @@
|
||||
import type { IUser, Serialized } from '@rocket.chat/core-typings';
|
||||
import { Box, Margins, Tag } from '@rocket.chat/fuselage';
|
||||
import {
|
||||
useUserDisplayName,
|
||||
ContextualbarScrollableContent,
|
||||
InfoPanel,
|
||||
InfoPanelActionGroup,
|
||||
InfoPanelAvatar,
|
||||
InfoPanelField,
|
||||
InfoPanelLabel,
|
||||
InfoPanelSection,
|
||||
InfoPanelText,
|
||||
InfoPanelTitle,
|
||||
} from '@rocket.chat/ui-client';
|
||||
import type { TranslationKey } from '@rocket.chat/ui-contexts';
|
||||
import type { ReactNode } from 'react';
|
||||
import { memo, useId } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { useTimeAgo } from '../../hooks/useTimeAgo';
|
||||
import { useUserCustomFields } from '../../hooks/useUserCustomFields';
|
||||
import MarkdownText from '../MarkdownText';
|
||||
import UTCClock from '../UTCClock';
|
||||
import { UserCardRoles } from '../UserCard';
|
||||
import UserInfoABACAttributes from './UserInfoABACAttributes';
|
||||
import UserInfoAvatar from './UserInfoAvatar';
|
||||
|
||||
type UserInfoDataProps = Serialized<
|
||||
Pick<
|
||||
IUser,
|
||||
| 'name'
|
||||
| 'username'
|
||||
| 'nickname'
|
||||
| 'bio'
|
||||
| 'lastLogin'
|
||||
| 'avatarETag'
|
||||
| 'utcOffset'
|
||||
| 'phone'
|
||||
| 'createdAt'
|
||||
| 'canViewAllInfo'
|
||||
| 'customFields'
|
||||
| 'freeSwitchExtension'
|
||||
| 'abacAttributes'
|
||||
>
|
||||
>;
|
||||
|
||||
export type UserInfoProps = UserInfoDataProps & {
|
||||
status: ReactNode;
|
||||
customStatus?: ReactNode;
|
||||
email?: string;
|
||||
verified?: boolean;
|
||||
actions: ReactNode;
|
||||
roles: ReactNode[];
|
||||
reason?: string;
|
||||
invitationDate?: string;
|
||||
};
|
||||
|
||||
const UserInfo = ({
|
||||
username,
|
||||
name,
|
||||
lastLogin,
|
||||
nickname,
|
||||
bio,
|
||||
avatarETag,
|
||||
roles,
|
||||
utcOffset,
|
||||
phone,
|
||||
email,
|
||||
verified,
|
||||
createdAt,
|
||||
status,
|
||||
customStatus,
|
||||
customFields,
|
||||
canViewAllInfo,
|
||||
actions,
|
||||
reason,
|
||||
freeSwitchExtension,
|
||||
abacAttributes,
|
||||
invitationDate,
|
||||
...props
|
||||
}: UserInfoProps) => {
|
||||
const { t } = useTranslation();
|
||||
const timeAgo = useTimeAgo();
|
||||
const userDisplayName = useUserDisplayName({ name, username });
|
||||
const userCustomFields = useUserCustomFields(customFields);
|
||||
|
||||
const usernameId = useId();
|
||||
|
||||
return (
|
||||
<ContextualbarScrollableContent padding={24} {...props}>
|
||||
<InfoPanel>
|
||||
{username && (
|
||||
<InfoPanelAvatar>
|
||||
<UserInfoAvatar username={username} etag={avatarETag} />
|
||||
</InfoPanelAvatar>
|
||||
)}
|
||||
|
||||
{actions && <InfoPanelActionGroup>{actions}</InfoPanelActionGroup>}
|
||||
|
||||
<InfoPanelSection>
|
||||
{userDisplayName && <InfoPanelTitle icon={status} title={userDisplayName} />}
|
||||
|
||||
{customStatus && <InfoPanelText>{customStatus}</InfoPanelText>}
|
||||
</InfoPanelSection>
|
||||
|
||||
<InfoPanelSection>
|
||||
{reason && (
|
||||
<InfoPanelField>
|
||||
<InfoPanelLabel>{t('Reason_for_joining')}</InfoPanelLabel>
|
||||
<InfoPanelText>{reason}</InfoPanelText>
|
||||
</InfoPanelField>
|
||||
)}
|
||||
|
||||
{nickname && (
|
||||
<InfoPanelField>
|
||||
<InfoPanelLabel>{t('Nickname')}</InfoPanelLabel>
|
||||
<InfoPanelText>{nickname}</InfoPanelText>
|
||||
</InfoPanelField>
|
||||
)}
|
||||
|
||||
{roles?.length !== 0 && (
|
||||
<InfoPanelField>
|
||||
<InfoPanelLabel>{t('Roles')}</InfoPanelLabel>
|
||||
<UserCardRoles>{roles}</UserCardRoles>
|
||||
</InfoPanelField>
|
||||
)}
|
||||
|
||||
{username && username !== name && (
|
||||
<InfoPanelField is='dl'>
|
||||
<InfoPanelLabel is='dt' id={usernameId}>
|
||||
{t('Username')}
|
||||
</InfoPanelLabel>
|
||||
<InfoPanelText is='dd' aria-labelledby={usernameId}>
|
||||
{username}
|
||||
</InfoPanelText>
|
||||
</InfoPanelField>
|
||||
)}
|
||||
|
||||
{utcOffset && Number.isInteger(utcOffset) && (
|
||||
<InfoPanelField>
|
||||
<InfoPanelLabel>{t('Local_Time')}</InfoPanelLabel>
|
||||
<InfoPanelText>
|
||||
<UTCClock utcOffset={utcOffset} />
|
||||
</InfoPanelText>
|
||||
</InfoPanelField>
|
||||
)}
|
||||
|
||||
{bio && (
|
||||
<InfoPanelField>
|
||||
<InfoPanelLabel>{t('Bio')}</InfoPanelLabel>
|
||||
<InfoPanelText withTruncatedText={false}>
|
||||
<MarkdownText variant='inline' content={bio} />
|
||||
</InfoPanelText>
|
||||
</InfoPanelField>
|
||||
)}
|
||||
|
||||
{Number.isInteger(utcOffset) && canViewAllInfo && (
|
||||
<InfoPanelField>
|
||||
<InfoPanelLabel>{t('Last_login')}</InfoPanelLabel>
|
||||
<InfoPanelText>{lastLogin ? timeAgo(lastLogin) : t('Never')}</InfoPanelText>
|
||||
</InfoPanelField>
|
||||
)}
|
||||
|
||||
{phone && (
|
||||
<InfoPanelField>
|
||||
<InfoPanelLabel>{t('Phone')}</InfoPanelLabel>
|
||||
<InfoPanelText display='flex' flexDirection='row' alignItems='center'>
|
||||
<Box is='a' withTruncatedText href={`tel:${phone}`}>
|
||||
{phone}
|
||||
</Box>
|
||||
</InfoPanelText>
|
||||
</InfoPanelField>
|
||||
)}
|
||||
|
||||
{email && (
|
||||
<InfoPanelField>
|
||||
<InfoPanelLabel>{t('Email')}</InfoPanelLabel>
|
||||
<InfoPanelText display='flex' flexDirection='row' alignItems='center'>
|
||||
<Box is='a' withTruncatedText href={`mailto:${email}`}>
|
||||
{email}
|
||||
</Box>
|
||||
<Margins inline={4}>
|
||||
<Tag>{verified ? t('Verified') : t('Not_verified')}</Tag>
|
||||
</Margins>
|
||||
</InfoPanelText>
|
||||
</InfoPanelField>
|
||||
)}
|
||||
|
||||
{freeSwitchExtension && (
|
||||
<InfoPanelField>
|
||||
<InfoPanelLabel>{t('Voice_call_extension')}</InfoPanelLabel>
|
||||
<InfoPanelText>{freeSwitchExtension}</InfoPanelText>
|
||||
</InfoPanelField>
|
||||
)}
|
||||
|
||||
{abacAttributes && abacAttributes.length > 0 && (
|
||||
<InfoPanelField>
|
||||
<InfoPanelLabel title={t('ABAC_Attributes_description')}>{t('ABAC_Attributes')}</InfoPanelLabel>
|
||||
<UserInfoABACAttributes abacAttributes={abacAttributes} />
|
||||
</InfoPanelField>
|
||||
)}
|
||||
{userCustomFields?.map(
|
||||
(customField) =>
|
||||
customField?.value && (
|
||||
<InfoPanelField key={customField.value}>
|
||||
<InfoPanelLabel>{t(customField.label as TranslationKey)}</InfoPanelLabel>
|
||||
<InfoPanelText>
|
||||
<MarkdownText content={customField.value} variant='inline' />
|
||||
</InfoPanelText>
|
||||
</InfoPanelField>
|
||||
),
|
||||
)}
|
||||
|
||||
{invitationDate && (
|
||||
<InfoPanelField>
|
||||
<InfoPanelLabel>{t('Invitation_date')}</InfoPanelLabel>
|
||||
<InfoPanelText>{timeAgo(invitationDate)}</InfoPanelText>
|
||||
</InfoPanelField>
|
||||
)}
|
||||
|
||||
{createdAt && (
|
||||
<InfoPanelField>
|
||||
<InfoPanelLabel>{t('Created_at')}</InfoPanelLabel>
|
||||
<InfoPanelText>{timeAgo(createdAt)}</InfoPanelText>
|
||||
</InfoPanelField>
|
||||
)}
|
||||
</InfoPanelSection>
|
||||
</InfoPanel>
|
||||
</ContextualbarScrollableContent>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(UserInfo);
|
||||
@@ -0,0 +1,11 @@
|
||||
import { Tag } from '@rocket.chat/fuselage';
|
||||
|
||||
export type UserInfoABACAttributeProps = {
|
||||
attribute: string;
|
||||
};
|
||||
|
||||
const UserInfoABACAttribute = ({ attribute }: UserInfoABACAttributeProps) => {
|
||||
return <Tag variant='secondary-warning'>{attribute}</Tag>;
|
||||
};
|
||||
|
||||
export default UserInfoABACAttribute;
|
||||
@@ -0,0 +1,26 @@
|
||||
import type { IAbacAttributeDefinition } from '@rocket.chat/core-typings';
|
||||
import { Box, Margins } from '@rocket.chat/fuselage';
|
||||
|
||||
import UserInfoABACAttribute from './UserInfoABACAttribute';
|
||||
|
||||
export type UserInfoABACAttributesProps = {
|
||||
abacAttributes: IAbacAttributeDefinition[];
|
||||
};
|
||||
|
||||
const UserInfoABACAttributes = ({ abacAttributes }: UserInfoABACAttributesProps) => {
|
||||
return (
|
||||
<Box margin='neg-x2'>
|
||||
<Box flexWrap='wrap' display='flex' flexShrink={0} marginBlock={8}>
|
||||
{abacAttributes.map((attribute, index) =>
|
||||
attribute.values.map((value) => (
|
||||
<Margins inline={2} blockEnd={4} key={`${attribute.key}-${value}-${index}`}>
|
||||
<UserInfoABACAttribute attribute={value} />
|
||||
</Margins>
|
||||
)),
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default UserInfoABACAttributes;
|
||||
21
apps/meteor/client/components/UserInfo/UserInfoAction.tsx
Normal file
21
apps/meteor/client/components/UserInfo/UserInfoAction.tsx
Normal file
@@ -0,0 +1,21 @@
|
||||
import { Button, IconButton } from '@rocket.chat/fuselage';
|
||||
import type { Keys as IconName } from '@rocket.chat/icons';
|
||||
import type { ComponentProps } from 'react';
|
||||
|
||||
export type UserInfoActionProps = {
|
||||
icon: IconName;
|
||||
} & ComponentProps<typeof Button>;
|
||||
|
||||
const UserInfoAction = ({ icon, label, title, ...props }: UserInfoActionProps) => {
|
||||
if (!label && icon && title) {
|
||||
return <IconButton small secondary icon={icon} title={title} aria-label={title} {...props} marginInline={4} size={40} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<Button icon={icon} {...props} marginInline={4}>
|
||||
{label}
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
export default UserInfoAction;
|
||||
@@ -0,0 +1,6 @@
|
||||
import { UserAvatar } from '@rocket.chat/ui-avatar';
|
||||
import type { ComponentProps } from 'react';
|
||||
|
||||
const UserInfoAvatar = (props: ComponentProps<typeof UserAvatar>) => <UserAvatar size='x332' {...props} />;
|
||||
|
||||
export default UserInfoAvatar;
|
||||
16
apps/meteor/client/components/UserInfo/UserInfoUsername.tsx
Normal file
16
apps/meteor/client/components/UserInfo/UserInfoUsername.tsx
Normal file
@@ -0,0 +1,16 @@
|
||||
import type { IUser } from '@rocket.chat/core-typings';
|
||||
import type { Box } from '@rocket.chat/fuselage';
|
||||
import type { ComponentProps, ReactNode } from 'react';
|
||||
|
||||
import { UserCardUsername } from '../UserCard';
|
||||
|
||||
export type UserInfoUsernameProps = {
|
||||
username: IUser['username'];
|
||||
status: ReactNode;
|
||||
} & ComponentProps<typeof Box>;
|
||||
|
||||
const UserInfoUsername = ({ username, status, ...props }: UserInfoUsernameProps) => (
|
||||
<UserCardUsername name={username} status={status} {...props} />
|
||||
);
|
||||
|
||||
export default UserInfoUsername;
|
||||
File diff suppressed because it is too large
Load Diff
4
apps/meteor/client/components/UserInfo/index.ts
Normal file
4
apps/meteor/client/components/UserInfo/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export { default as UserInfo } from './UserInfo';
|
||||
export { default as UserInfoAction } from './UserInfoAction';
|
||||
export { default as UserInfoAvatar } from './UserInfoAvatar';
|
||||
export { default as UserInfoUsername } from './UserInfoUsername';
|
||||
Reference in New Issue
Block a user