[IMPROVE] Rewrite read receipts to react. #23455
parent
d343604820
commit
363ea0137c
@ -1 +0,0 @@ |
||||
import './views/readReceipts'; |
||||
@ -1,16 +0,0 @@ |
||||
<template name="readReceipts"> |
||||
{{#if isLoading}} |
||||
{{> loading class="loading-animation--primary"}} |
||||
{{else}} |
||||
<p>{{_ "Read_by"}}:</p> |
||||
<ul class="read-receipts"> |
||||
{{#each receipts}} |
||||
<li class="read-receipts__user background-transparent-dark-hover"> |
||||
{{> avatar username=user.username}} |
||||
<div class="read-receipts__name color-primary-font-color">{{displayName}}</div> |
||||
<span class="read-receipts__time color-info-font-color" title="{{dateTime}}">{{time}}</span> |
||||
</li> |
||||
{{/each}} |
||||
</ul> |
||||
{{/if}} |
||||
</template> |
||||
@ -1,39 +0,0 @@ |
||||
import { Meteor } from 'meteor/meteor'; |
||||
import { ReactiveVar } from 'meteor/reactive-var'; |
||||
import { Template } from 'meteor/templating'; |
||||
import moment from 'moment'; |
||||
|
||||
import { settings } from '../../../settings'; |
||||
|
||||
import './readReceipts.html'; |
||||
|
||||
Template.readReceipts.helpers({ |
||||
receipts() { |
||||
return Template.instance().readReceipts.get(); |
||||
}, |
||||
displayName() { |
||||
return (settings.get('UI_Use_Real_Name') && this.user.name) || this.user.username; |
||||
}, |
||||
time() { |
||||
return moment(this.ts).format('L LTS'); |
||||
}, |
||||
isLoading() { |
||||
return Template.instance().loading.get(); |
||||
}, |
||||
}); |
||||
|
||||
Template.readReceipts.onCreated(function readReceiptsOnCreated() { |
||||
this.loading = new ReactiveVar(false); |
||||
this.readReceipts = new ReactiveVar([]); |
||||
}); |
||||
|
||||
Template.readReceipts.onRendered(function readReceiptsOnRendered() { |
||||
this.loading.set(true); |
||||
Meteor.call('getReadReceipts', { messageId: this.data.messageId }, (error, result) => { |
||||
if (!error) { |
||||
this.readReceipts.set(result); |
||||
} |
||||
|
||||
this.loading.set(false); |
||||
}); |
||||
}); |
||||
@ -1 +0,0 @@ |
||||
export { default } from './ReactionList'; |
||||
@ -0,0 +1,4 @@ |
||||
import type { IMessage } from '../../../../definition/IMessage'; |
||||
import type { ReadReceipt } from '../../../../definition/ReadReceipt'; |
||||
|
||||
export type GetReadReceiptsMethod = (options: { mid: IMessage['_id'] }) => Array<ReadReceipt>; |
||||
@ -0,0 +1,12 @@ |
||||
import { IUser } from '../../definition/IUser'; |
||||
import { useSetting } from '../contexts/SettingsContext'; |
||||
import { getUserDisplayName } from '../lib/getUserDisplayName'; |
||||
|
||||
export const useUserDisplayName = ({ |
||||
name, |
||||
username, |
||||
}: Pick<IUser, 'name' | 'username'>): string | undefined => { |
||||
const useRealName = useSetting('UI_Use_Real_Name'); |
||||
|
||||
return getUserDisplayName(name, username, !!useRealName); |
||||
}; |
||||
@ -0,0 +1,7 @@ |
||||
import { IUser } from '../../definition/IUser'; |
||||
|
||||
export const getUserDisplayName = ( |
||||
name: IUser['name'], |
||||
username: IUser['username'], |
||||
useRealName: boolean, |
||||
): string | undefined => (useRealName ? name || username : username); |
||||
@ -1,6 +1,6 @@ |
||||
import React, { ReactElement } from 'react'; |
||||
|
||||
import { isIE11 } from '../../../lib/utils/isIE11'; |
||||
import { isIE11 } from '../../../../lib/utils/isIE11'; |
||||
import GenericPreview from './GenericPreview'; |
||||
import MediaPreview from './MediaPreview'; |
||||
|
||||
@ -1,7 +1,7 @@ |
||||
import { Box, Icon } from '@rocket.chat/fuselage'; |
||||
import React, { ReactElement } from 'react'; |
||||
|
||||
import { formatBytes } from '../../../lib/utils/formatBytes'; |
||||
import { formatBytes } from '../../../../lib/utils/formatBytes'; |
||||
|
||||
const GenericPreview = ({ file }: { file: File }): ReactElement => ( |
||||
<Box display='flex' alignItems='center' w='full' fontScale='s2'> |
||||
@ -1,7 +1,7 @@ |
||||
import { Box, Icon } from '@rocket.chat/fuselage'; |
||||
import React, { ReactElement, useEffect, useState, memo } from 'react'; |
||||
|
||||
import { useTranslation } from '../../../contexts/TranslationContext'; |
||||
import { useTranslation } from '../../../../contexts/TranslationContext'; |
||||
import { FilePreviewType } from './FilePreview'; |
||||
import ImagePreview from './ImagePreview'; |
||||
import PreviewSkeleton from './PreviewSkeleton'; |
||||
@ -1,10 +1,10 @@ |
||||
import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; |
||||
import React, { ReactElement } from 'react'; |
||||
|
||||
import { openUserCard } from '../../../../app/ui/client/lib/UserCard'; |
||||
import { IUser } from '../../../../definition/IUser'; |
||||
import { useTranslation } from '../../../contexts/TranslationContext'; |
||||
import GenericModal from '../../GenericModal'; |
||||
import { openUserCard } from '../../../../../app/ui/client/lib/UserCard'; |
||||
import { IUser } from '../../../../../definition/IUser'; |
||||
import GenericModal from '../../../../components/GenericModal'; |
||||
import { useTranslation } from '../../../../contexts/TranslationContext'; |
||||
import Reactions from './Reactions'; |
||||
|
||||
type ReactionListProps = { |
||||
@ -1,7 +1,7 @@ |
||||
import { Box, Tag } from '@rocket.chat/fuselage'; |
||||
import React, { ReactElement } from 'react'; |
||||
|
||||
import { IUser } from '../../../../definition/IUser'; |
||||
import { IUser } from '../../../../../definition/IUser'; |
||||
|
||||
type ReactionUserTag = { |
||||
username: IUser['username']; |
||||
@ -1,9 +1,9 @@ |
||||
import { Box } from '@rocket.chat/fuselage'; |
||||
import React, { ReactElement } from 'react'; |
||||
|
||||
import { IUser } from '../../../../definition/IUser'; |
||||
import { useSetting } from '../../../contexts/SettingsContext'; |
||||
import Emoji from '../../Emoji'; |
||||
import { IUser } from '../../../../../definition/IUser'; |
||||
import Emoji from '../../../../components/Emoji'; |
||||
import { useSetting } from '../../../../contexts/SettingsContext'; |
||||
import ReactionUserTag from './ReactionUserTag'; |
||||
|
||||
type ReactionsProps = { |
||||
@ -0,0 +1 @@ |
||||
export { default } from './ReactionListModal'; |
||||
@ -0,0 +1,45 @@ |
||||
import { css } from '@rocket.chat/css-in-js'; |
||||
import { Box } from '@rocket.chat/fuselage'; |
||||
import colors from '@rocket.chat/fuselage-tokens/colors'; |
||||
import React, { ReactElement } from 'react'; |
||||
|
||||
import type { ReadReceipt } from '../../../../../definition/ReadReceipt'; |
||||
import UserAvatar from '../../../../components/avatar/UserAvatar'; |
||||
import { useFormatDateAndTime } from '../../../../hooks/useFormatDateAndTime'; |
||||
import { useUserDisplayName } from '../../../../hooks/useUserDisplayName'; |
||||
|
||||
const hoverStyle = css` |
||||
&:hover { |
||||
background-color: ${colors.n400}; |
||||
} |
||||
`;
|
||||
|
||||
const ReadReceiptRow = ({ user, ts }: ReadReceipt): ReactElement => { |
||||
const displayName = useUserDisplayName(user); |
||||
const formatDateAndTime = useFormatDateAndTime(); |
||||
|
||||
return ( |
||||
<Box |
||||
display='flex' |
||||
flexDirection='row' |
||||
justifyContent='space-between' |
||||
alignItems='center' |
||||
p='x4' |
||||
pi='x32' |
||||
mi='neg-x32' |
||||
className={hoverStyle} |
||||
> |
||||
<Box> |
||||
<UserAvatar username={user.username || ''} size='x24' /> |
||||
<Box is='span' mis='x8'> |
||||
{displayName} |
||||
</Box> |
||||
</Box> |
||||
<Box is='span' fontScale='c1' color='info'> |
||||
{formatDateAndTime(ts)} |
||||
</Box> |
||||
</Box> |
||||
); |
||||
}; |
||||
|
||||
export default ReadReceiptRow; |
||||
@ -0,0 +1,52 @@ |
||||
import { Skeleton } from '@rocket.chat/fuselage'; |
||||
import React, { ReactElement, useMemo, useEffect } from 'react'; |
||||
|
||||
import type { IMessage } from '../../../../../definition/IMessage/IMessage'; |
||||
import type { ReadReceipt } from '../../../../../definition/ReadReceipt'; |
||||
import GenericModal from '../../../../components/GenericModal'; |
||||
import { useToastMessageDispatch } from '../../../../contexts/ToastMessagesContext'; |
||||
import { useTranslation } from '../../../../contexts/TranslationContext'; |
||||
import { useMethodData } from '../../../../hooks/useMethodData'; |
||||
import { AsyncStatePhase } from '../../../../lib/asyncState'; |
||||
import ReadReceiptRow from './ReadReceiptRow'; |
||||
|
||||
type ReadReceiptsModalProps = { |
||||
messageId: IMessage['_id']; |
||||
onClose: () => void; |
||||
}; |
||||
|
||||
const ReadReceiptsModal = ({ messageId, onClose }: ReadReceiptsModalProps): ReactElement => { |
||||
const t = useTranslation(); |
||||
const dispatchToastMessage = useToastMessageDispatch(); |
||||
|
||||
const { phase, value, error } = useMethodData<Array<ReadReceipt>>( |
||||
'getReadReceipts', |
||||
useMemo(() => [{ messageId }], [messageId]), |
||||
); |
||||
|
||||
useEffect(() => { |
||||
if (error) { |
||||
dispatchToastMessage({ type: 'error', message: error }); |
||||
onClose(); |
||||
} |
||||
}, [error, dispatchToastMessage, t, onClose]); |
||||
|
||||
if (phase === AsyncStatePhase.LOADING || !value || error) { |
||||
return ( |
||||
<GenericModal title={t('Read_by')} onConfirm={onClose} onClose={onClose}> |
||||
<Skeleton type='rect' w='full' h='x120' /> |
||||
</GenericModal> |
||||
); |
||||
} |
||||
|
||||
return ( |
||||
<GenericModal title={t('Read_by')} onConfirm={onClose} onClose={onClose}> |
||||
{value.length < 1 && t('No_results_found')} |
||||
{value.map((receipt) => ( |
||||
<ReadReceiptRow {...receipt} key={receipt._id} /> |
||||
))} |
||||
</GenericModal> |
||||
); |
||||
}; |
||||
|
||||
export default ReadReceiptsModal; |
||||
@ -0,0 +1 @@ |
||||
export { default } from './ReadReceiptsModal'; |
||||
@ -0,0 +1,12 @@ |
||||
import type { IMessage } from './IMessage/IMessage'; |
||||
import type { IRoom } from './IRoom'; |
||||
import type { IUser } from './IUser'; |
||||
|
||||
export type ReadReceipt = { |
||||
messageId: IMessage['_id']; |
||||
roomId: IRoom['_id']; |
||||
ts: Date; |
||||
user: Pick<IUser, '_id' | 'name' | 'username'>; |
||||
userId: IUser['_id']; |
||||
_id: string; |
||||
} |
||||
Loading…
Reference in new issue