Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions apps/meteor/client/components/UserInfo/UserInfo.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,8 @@ WithABACAttributes.args = {
// @ts-expect-error - abacAttributes is not yet implemented in Users properties
abacAttributes: ['Classified', 'Top Secret', 'Confidential'],
};

export const InvitedUser = Template.bind({});
InvitedUser.args = {
invitationDate: '2025-01-01T12:00:00Z',
};
9 changes: 9 additions & 0 deletions apps/meteor/client/components/UserInfo/UserInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ type UserInfoProps = UserInfoDataProps & {
actions: ReactElement;
roles: ReactElement[];
reason?: string;
invitationDate?: string;
};

const UserInfo = ({
Expand All @@ -75,6 +76,7 @@ const UserInfo = ({
freeSwitchExtension,
// @ts-expect-error - abacAttributes is not yet implemented in Users properties
abacAttributes = null,
invitationDate,
...props
}: UserInfoProps): ReactElement => {
const { t } = useTranslation();
Expand Down Expand Up @@ -207,6 +209,13 @@ const UserInfo = ({
),
)}

{invitationDate && (
<InfoPanelField>
<InfoPanelLabel>{t('Invitation_date')}</InfoPanelLabel>
<InfoPanelText>{timeAgo(invitationDate)}</InfoPanelText>
</InfoPanelField>
)}

{createdAt && (
<InfoPanelField>
<InfoPanelLabel>{t('Created_at')}</InfoPanelLabel>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,281 @@ exports[`renders Default without crashing 1`] = `
</body>
`;

exports[`renders InvitedUser without crashing 1`] = `
<body>
<div>
<span
data-focus-scope-start="true"
hidden=""
/>
<div
aria-label="User Info"
aria-labelledby="contextualbarTitle"
class="rcx-box rcx-box--full rcx-vertical-bar rcx-css-1ajmw95"
role="dialog"
tabindex="-1"
>
<div
class="rcx-box rcx-box--full rcx-css-1svuzur"
>
<div
class="rcx-box rcx-box--full rcx-css-pln26h rcx-css-1cb6i7s"
data-overlayscrollbars="host"
>
<div
class="os-size-observer"
>
<div
class="os-size-observer-listener"
/>
</div>
<div
class=""
data-overlayscrollbars-viewport="scrollbarHidden overflowXHidden overflowYHidden"
style="margin-right: 0px; margin-bottom: 0px; margin-left: 0px; top: 0px; left: 0px; width: calc(100% + 0px); padding: 0px 0px 0px 0px;"
tabindex="-1"
>
<div
class="rcx-box rcx-box--full rcx-css-iag4sp"
>
<div
class="rcx-box rcx-box--full rcx-css-15qq8ie"
>
<div
class="rcx-box rcx-box--full rcx-css-13kmycs"
>
<figure
class="rcx-box rcx-box--full rcx-avatar rcx-avatar--x332"
>
<img
alt=""
aria-hidden="true"
class="rcx-avatar__element rcx-avatar__element--x332"
data-username="guilherme.gazzo"
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQYV2Oora39DwAFaQJ3y3rKeAAAAABJRU5ErkJggg=="
title="guilherme.gazzo"
/>
</figure>
</div>
<div
class="rcx-box rcx-box--full rcx-css-6jv9ad"
>
<div
class="rcx-box rcx-box--full rcx-css-1rn5ews"
>
<svg
class="rcx-status-bullet rcx-status-bullet--offline undefined "
fill="none"
height="12"
viewBox="0 0 12 12"
width="12"
xmlns="http://www.w3.org/2000/svg"
>
<circle
class="rcx-status-bullet rcx-status-bullet--offline"
cx="6"
cy="6"
r="5"
stroke-width="2"
/>
</svg>
<div
class="rcx-box rcx-box--full rcx-css-dredvr"
title="guilherme.gazzo"
>
guilherme.gazzo
</div>
</div>
<div
class="rcx-box rcx-box--full rcx-css-6hwe8l rcx-css-11phrl6"
>
<div
class="rcx-box rcx-box--full rcx-box--with-block-elements rcx-box--with-inline-elements"
>
<img
alt="🛴"
class="emojione"
src="https://cdn.jsdelivr.net/emojione/assets/4.5/png/32/1f6f4.png"
title=":scooter:"
/>
currently working on User Card
</div>
</div>
</div>
<div
class="rcx-box rcx-box--full rcx-css-6jv9ad"
>
<div
class="rcx-box rcx-box--full rcx-css-1jagyun"
>
<div
class="rcx-box rcx-box--full rcx-css-f0ql1y"
>
Nickname
</div>
<div
class="rcx-box rcx-box--full rcx-css-6hwe8l rcx-css-11phrl6"
>
gazzo
</div>
</div>
<div
class="rcx-box rcx-box--full rcx-css-1jagyun"
>
<div
class="rcx-box rcx-box--full rcx-css-f0ql1y"
>
Roles
</div>
<div
class="rcx-box rcx-box--full rcx-css-9vcs0o"
>
<span
class="rcx-box rcx-box--full rcx-css-1vab7ss"
>
<div
class="rcx-box rcx-box--full rcx-css-1i2tyln"
>
<span
class="rcx-box rcx-box--full rcx-tag "
>
<span
class="rcx-tag__inner"
>
admin
</span>
</span>
</div>
<div
class="rcx-box rcx-box--full rcx-css-1i2tyln"
>
<span
class="rcx-box rcx-box--full rcx-tag "
>
<span
class="rcx-tag__inner"
>
user
</span>
</span>
</div>
</span>
</div>
</div>
<div
class="rcx-box rcx-box--full rcx-css-1jagyun"
>
<div
class="rcx-box rcx-box--full rcx-css-f0ql1y"
>
Username
</div>
<div
class="rcx-box rcx-box--full rcx-css-6hwe8l rcx-css-11phrl6"
data-qa="UserInfoUserName"
>
guilherme.gazzo
</div>
</div>
<div
class="rcx-box rcx-box--full rcx-css-1jagyun"
>
<div
class="rcx-box rcx-box--full rcx-css-f0ql1y"
>
Bio
</div>
<div
class="rcx-box rcx-box--full rcx-css-6hwe8l rcx-css-11phrl6"
>
<div
class="rcx-box rcx-box--full rcx-box--with-block-elements rcx-box--with-inline-elements"
>
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.
</div>
</div>
</div>
<div
class="rcx-box rcx-box--full rcx-css-1jagyun"
>
<div
class="rcx-box rcx-box--full rcx-css-f0ql1y"
>
Email
</div>
<div
class="rcx-box rcx-box--full rcx-css-6hwe8l rcx-css-tj8yjq"
>
<a
class="rcx-box rcx-box--full rcx-css-1te28na"
href="mailto:[email protected]"
>
[email protected]
</a>
<span
class="rcx-box rcx-box--full rcx-tag rcx-css-1dtwr38 rcx-css-1eogw2f"
>
<span
class="rcx-tag__inner"
>
Not_verified
</span>
</span>
</div>
</div>
<div
class="rcx-box rcx-box--full rcx-css-1jagyun"
>
<div
class="rcx-box rcx-box--full rcx-css-f0ql1y"
>
Invitation_date
</div>
<div
class="rcx-box rcx-box--full rcx-css-6hwe8l rcx-css-11phrl6"
>
January 1, 2025
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="os-scrollbar os-scrollbar-horizontal os-theme-dark os-scrollbar-auto-hide os-scrollbar-auto-hide-hidden os-scrollbar-handle-interactive os-scrollbar-cornerless os-scrollbar-unusable"
style="--os-scroll-percent: 0; --os-viewport-percent: 0; --os-scroll-direction: 0;"
>
<div
class="os-scrollbar-track"
>
<div
class="os-scrollbar-handle"
/>
</div>
</div>
<div
class="os-scrollbar os-scrollbar-vertical os-theme-dark os-scrollbar-auto-hide os-scrollbar-auto-hide-hidden os-scrollbar-handle-interactive os-scrollbar-cornerless os-scrollbar-unusable"
style="--os-scroll-percent: 0; --os-viewport-percent: 0; --os-scroll-direction: 0;"
>
<div
class="os-scrollbar-track"
>
<div
class="os-scrollbar-handle"
/>
</div>
</div>
</div>
</div>
</div>
<span
data-focus-scope-end="true"
hidden=""
/>
</div>
</body>
`;

exports[`renders WithABACAttributes without crashing 1`] = `
<body>
<div>
Expand Down
21 changes: 0 additions & 21 deletions apps/meteor/client/views/hooks/useMemberList.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -120,27 +120,6 @@ describe('useMembersList', () => {
expect(result.current.data?.pages[0].members).toHaveLength(fakeMembersPage1.members.length);
});

it('fetches from /v1/im.members if roomType is d', async () => {
const { result } = renderHook(
() =>
useMembersList({
rid: 'directRoomId',
type: 'all',
limit: 3,
debouncedText: '',
roomType: 'd',
}),
{ wrapper: wrapper.build() },
);

await waitFor(() => expect(result.current.isLoading).toBe(false));

expect(mockDMMembersEndpoint).toHaveBeenCalled();
expect(mockRoomMembersEndpoint).not.toHaveBeenCalled();

expect(result.current.data?.pages[0].members).toHaveLength(fakeMembersPage1.members.length);
});

it('applies pagination with fetchNextPage', async () => {
const { result } = renderHook(
() =>
Expand Down
25 changes: 15 additions & 10 deletions apps/meteor/client/views/hooks/useMembersList.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { IRole, IUser, AtLeast } from '@rocket.chat/core-typings';
import type { IRole, IUser, AtLeast, SubscriptionStatus } from '@rocket.chat/core-typings';
import { useEndpoint, useSetting, useStream } from '@rocket.chat/ui-contexts';
import type { InfiniteData, QueryClient } from '@tanstack/react-query';
import { useInfiniteQuery, useQueryClient } from '@tanstack/react-query';
Expand All @@ -14,15 +14,20 @@ type MembersListOptions = {
roomType: 'd' | 'p' | 'c';
};

const endpointsByRoomType = {
d: '/v1/im.members',
p: '/v1/rooms.membersOrderedByRole',
c: '/v1/rooms.membersOrderedByRole',
} as const;

export type RoomMember = Pick<IUser, 'username' | '_id' | 'name' | 'status' | 'freeSwitchExtension'> & { roles?: IRole['_id'][] };
export type RoomMember = Pick<IUser, 'username' | '_id' | 'name' | 'status' | 'federated' | 'freeSwitchExtension'> & {
roles?: IRole['_id'][];
subscription?: {
status: SubscriptionStatus;
createdAt: string;
};
};

type MembersListPage = { members: RoomMember[]; count: number; total: number; offset: number };
type MembersListPage = {
members: RoomMember[];
count: number;
total: number;
offset: number;
};

const getSortedMembers = (members: RoomMember[], useRealName = false) => {
const membersWithRolePriority: (RoomMember & { rolePriority: number })[] = members.map((member) => ({
Expand Down Expand Up @@ -106,7 +111,7 @@ const updateMemberInCache = (
};

export const useMembersList = (options: MembersListOptions) => {
const getMembers = useEndpoint('GET', endpointsByRoomType[options.roomType]);
const getMembers = useEndpoint('GET', '/v1/rooms.membersOrderedByRole');
const useRealName = useSetting<boolean>('UI_Use_Real_Name', false);
const queryClient = useQueryClient();

Expand Down
Loading
Loading