|
1 | | -import React from 'react'; |
| 1 | +import React, { useCallback, useMemo } from 'react'; |
| 2 | +import { HotKeys } from 'react-hotkeys'; |
2 | 3 | import { useHistory } from 'react-router-dom'; |
3 | 4 |
|
4 | 5 | import { markConversationRead } from 'soapbox/actions/conversations'; |
5 | | -import StatusContainer from 'soapbox/containers/status_container'; |
| 6 | +import Account from 'soapbox/components/account'; |
| 7 | +import { Icon } from 'soapbox/components/ui'; |
6 | 8 | import { useAppDispatch, useAppSelector } from 'soapbox/hooks'; |
| 9 | +import { Account as AccountEntity, Status } from 'soapbox/types/entities'; |
7 | 10 |
|
8 | 11 | interface IConversation { |
| 12 | + className?: string, |
9 | 13 | conversationId: string, |
10 | 14 | onMoveUp: (id: string) => void, |
11 | 15 | onMoveDown: (id: string) => void, |
12 | 16 | } |
13 | 17 |
|
14 | | -const Conversation: React.FC<IConversation> = ({ conversationId, onMoveUp, onMoveDown }) => { |
| 18 | +const Conversation: React.FC<IConversation> = ({ conversationId, onMoveUp, onMoveDown, className }) => { |
15 | 19 | const dispatch = useAppDispatch(); |
16 | 20 | const history = useHistory(); |
17 | 21 |
|
18 | | - const { accounts, unread, lastStatusId } = useAppSelector((state) => { |
| 22 | + const { accounts, unread, lastStatusId, lastStatus } = useAppSelector((state) => { |
19 | 23 | const conversation = state.conversations.items.find(x => x.id === conversationId)!; |
20 | 24 |
|
21 | 25 | return { |
22 | | - accounts: conversation.accounts.map((accountId: string) => state.accounts.get(accountId, null)!), |
| 26 | + accounts: conversation.accounts.map((accountId: string) => state.accounts.get<AccountEntity>(accountId, null)!), |
23 | 27 | unread: conversation.unread, |
| 28 | + lastStatus: state.statuses.get<Status>(conversation.last_status, null)!, |
24 | 29 | lastStatusId: conversation.last_status || null, |
25 | 30 | }; |
26 | 31 | }); |
27 | 32 |
|
28 | | - const handleClick = () => { |
| 33 | + const handleClick = useCallback(() => { |
29 | 34 | if (unread) { |
30 | 35 | dispatch(markConversationRead(conversationId)); |
31 | 36 | } |
32 | | - |
33 | 37 | history.push(`/statuses/${lastStatusId}`); |
34 | | - }; |
| 38 | + }, [conversationId, dispatch, history, lastStatusId, unread]); |
35 | 39 |
|
36 | | - const handleHotkeyMoveUp = () => { |
| 40 | + const handleHotkeyMoveUp = useCallback(() => { |
37 | 41 | onMoveUp(conversationId); |
38 | | - }; |
| 42 | + }, [conversationId, onMoveUp]); |
39 | 43 |
|
40 | | - const handleHotkeyMoveDown = () => { |
| 44 | + const handleHotkeyMoveDown = useCallback(() => { |
41 | 45 | onMoveDown(conversationId); |
42 | | - }; |
| 46 | + }, [conversationId, onMoveDown]); |
| 47 | + |
| 48 | + const handlers = useMemo(() => { |
| 49 | + return { |
| 50 | + open: handleClick, |
| 51 | + moveUp: handleHotkeyMoveUp, |
| 52 | + moveDown: handleHotkeyMoveDown, |
| 53 | + }; |
| 54 | + }, [handleClick, handleHotkeyMoveDown, handleHotkeyMoveUp]); |
43 | 55 |
|
44 | 56 | if (lastStatusId === null) { |
45 | 57 | return null; |
46 | 58 | } |
47 | 59 |
|
48 | 60 | return ( |
49 | | - // @ts-ignore |
50 | | - <StatusContainer |
51 | | - id={lastStatusId} |
52 | | - unread={unread} |
53 | | - otherAccounts={accounts} |
54 | | - onMoveUp={handleHotkeyMoveUp} |
55 | | - onMoveDown={handleHotkeyMoveDown} |
56 | | - onClick={handleClick} |
57 | | - /> |
| 61 | + <HotKeys handlers={handlers} data-testid='status'> |
| 62 | + <div onClick={handleClick} role='button' tabIndex={0} className={`bg-white dark:bg-slate-800 px-4 py-6 sm:shadow-sm dark:shadow-inset sm:p-5 sm:rounded-xl ${className}`}> |
| 63 | + <div className='flex justify-between gap-3'> |
| 64 | + <div className='flex gap-2 grow'> |
| 65 | + {accounts.map((a) => <Account withLinkToProfile={false} account={a} />)} |
| 66 | + </div> |
| 67 | + <Icon |
| 68 | + src={require('@tabler/icons/messages.svg')} |
| 69 | + count={unread ? 1 : 0} |
| 70 | + className='h-6 w-6 dark:group-hover:text-primary-500' |
| 71 | + /> |
| 72 | + </div> |
| 73 | + <div className='flex justify-between mt-3 items-end gap-2'> |
| 74 | + <div style={{ 'whiteSpace': 'nowrap' }} className='overflow-x-hidden text-ellipsis text-gray-700 dark:text-gray-300' dangerouslySetInnerHTML={{ __html: lastStatus.contentHtml.replace(/<br.*>/, '') }} /> |
| 75 | + <div className='text-gray-300 dark:text-gray-300 text-xs'> |
| 76 | + {new Date(lastStatus.get('created_at')).toLocaleDateString(undefined, { day: '2-digit', month: '2-digit', year: 'numeric' })} |
| 77 | + </div> |
| 78 | + </div> |
| 79 | + |
| 80 | + </div> |
| 81 | + </HotKeys> |
58 | 82 | ); |
59 | 83 | }; |
60 | 84 |
|
|
0 commit comments