@messenger-box/chakra-ui-inbox 0.0.1-alpha.168
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/LICENSE +21 -0
- package/jest.config.js +9 -0
- package/lib/components/InboxMessage/ConversationItem.d.ts +11 -0
- package/lib/components/InboxMessage/ConversationItem.d.ts.map +1 -0
- package/lib/components/InboxMessage/ConversationItem.js +50 -0
- package/lib/components/InboxMessage/ConversationItem.js.map +1 -0
- package/lib/components/InboxMessage/LeftSidebar.d.ts +17 -0
- package/lib/components/InboxMessage/LeftSidebar.d.ts.map +1 -0
- package/lib/components/InboxMessage/LeftSidebar.js +107 -0
- package/lib/components/InboxMessage/LeftSidebar.js.map +1 -0
- package/lib/components/InboxMessage/MessageInput.d.ts +8 -0
- package/lib/components/InboxMessage/MessageInput.d.ts.map +1 -0
- package/lib/components/InboxMessage/MessageInput.js +45 -0
- package/lib/components/InboxMessage/MessageInput.js.map +1 -0
- package/lib/components/InboxMessage/Messages.d.ts +10 -0
- package/lib/components/InboxMessage/Messages.d.ts.map +1 -0
- package/lib/components/InboxMessage/Messages.js +42 -0
- package/lib/components/InboxMessage/Messages.js.map +1 -0
- package/lib/components/InboxMessage/Popover.d.ts +3 -0
- package/lib/components/InboxMessage/Popover.d.ts.map +1 -0
- package/lib/components/InboxMessage/UserModalContent.d.ts +3 -0
- package/lib/components/InboxMessage/UserModalContent.d.ts.map +1 -0
- package/lib/components/InboxMessage/index.d.ts +4 -0
- package/lib/components/InboxMessage/index.d.ts.map +1 -0
- package/lib/components/inbox/FilesList.d.ts +12 -0
- package/lib/components/inbox/FilesList.d.ts.map +1 -0
- package/lib/components/inbox/FilesList.js +7 -0
- package/lib/components/inbox/FilesList.js.map +1 -0
- package/lib/components/inbox/MessageItem.d.ts +17 -0
- package/lib/components/inbox/MessageItem.d.ts.map +1 -0
- package/lib/compute.d.ts +8 -0
- package/lib/compute.d.ts.map +1 -0
- package/lib/compute.js +19 -0
- package/lib/compute.js.map +1 -0
- package/lib/constants/index.d.ts +2 -0
- package/lib/constants/index.d.ts.map +1 -0
- package/lib/constants/index.js +5 -0
- package/lib/constants/index.js.map +1 -0
- package/lib/container/Inbox.d.ts +4 -0
- package/lib/container/Inbox.d.ts.map +1 -0
- package/lib/container/Inbox.js +169 -0
- package/lib/container/Inbox.js.map +1 -0
- package/lib/container/index.d.ts +3 -0
- package/lib/container/index.d.ts.map +1 -0
- package/lib/hooks/upload-file.d.ts +27 -0
- package/lib/hooks/upload-file.d.ts.map +1 -0
- package/lib/hooks/upload-file.js +56 -0
- package/lib/hooks/upload-file.js.map +1 -0
- package/lib/hooks/upload-filex.d.ts +11 -0
- package/lib/hooks/upload-filex.d.ts.map +1 -0
- package/lib/hooks/upload-filex.js +5 -0
- package/lib/hooks/upload-filex.js.map +1 -0
- package/lib/hooks/upload-msg-files.d.ts +3 -0
- package/lib/hooks/upload-msg-files.d.ts.map +1 -0
- package/lib/hooks/upload-msg-files.js +10 -0
- package/lib/hooks/upload-msg-files.js.map +1 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +1 -0
- package/lib/index.js.map +1 -0
- package/lib/module.d.ts +4 -0
- package/lib/module.d.ts.map +1 -0
- package/lib/module.js +5 -0
- package/lib/module.js.map +1 -0
- package/package.json +79 -0
- package/rollup.config.js +32 -0
- package/src/components/InboxMessage/ConversationItem.tsx +98 -0
- package/src/components/InboxMessage/LeftSidebar.tsx +250 -0
- package/src/components/InboxMessage/MessageInput.tsx +148 -0
- package/src/components/InboxMessage/Messages.tsx +137 -0
- package/src/components/InboxMessage/Popover.tsx +56 -0
- package/src/components/InboxMessage/UserModalContent.tsx +52 -0
- package/src/components/InboxMessage/index.ts +3 -0
- package/src/components/inbox/FilesList.tsx +17 -0
- package/src/components/inbox/MessageItem.tsx +56 -0
- package/src/compute.tsx +33 -0
- package/src/constants/index.ts +4 -0
- package/src/container/Inbox.tsx +283 -0
- package/src/container/index.ts +3 -0
- package/src/hooks/upload-file.tsx +92 -0
- package/src/hooks/upload-filex.tsx +22 -0
- package/src/hooks/upload-msg-files.tsx +14 -0
- package/src/index.ts +1 -0
- package/src/module.tsx +9 -0
- package/tsconfig.json +26 -0
- package/webpack.config.js +97 -0
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
import { SearchIcon } from '@chakra-ui/icons';
|
|
2
|
+
import {
|
|
3
|
+
Button,
|
|
4
|
+
Avatar,
|
|
5
|
+
Box,
|
|
6
|
+
Heading,
|
|
7
|
+
Icon,
|
|
8
|
+
Input,
|
|
9
|
+
InputGroup,
|
|
10
|
+
InputRightElement,
|
|
11
|
+
Tab,
|
|
12
|
+
TabList,
|
|
13
|
+
TabPanel,
|
|
14
|
+
TabPanels,
|
|
15
|
+
Tabs,
|
|
16
|
+
useColorModeValue,
|
|
17
|
+
} from '@chakra-ui/react';
|
|
18
|
+
import { GoSettings } from '@react-icons/all-files/go/GoSettings';
|
|
19
|
+
import React, { useEffect, useState } from 'react';
|
|
20
|
+
import { ConversationItem } from './ConversationItem';
|
|
21
|
+
|
|
22
|
+
type LeftSidebarProps = {
|
|
23
|
+
allChannels: any;
|
|
24
|
+
allChannelsLoading: boolean;
|
|
25
|
+
userChannels: any;
|
|
26
|
+
userChannelsLoading: boolean;
|
|
27
|
+
currentUser: any;
|
|
28
|
+
users?: any[];
|
|
29
|
+
handleSelectChannel: (channel: any) => void;
|
|
30
|
+
clearMessages: () => void;
|
|
31
|
+
selectedChannelId?: any;
|
|
32
|
+
channelToTop: number;
|
|
33
|
+
getChannelsRefetch: any;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export const LeftSidebar = (props: LeftSidebarProps) => {
|
|
37
|
+
const {
|
|
38
|
+
currentUser,
|
|
39
|
+
handleSelectChannel,
|
|
40
|
+
clearMessages,
|
|
41
|
+
users,
|
|
42
|
+
allChannels,
|
|
43
|
+
allChannelsLoading,
|
|
44
|
+
channelToTop,
|
|
45
|
+
userChannels,
|
|
46
|
+
userChannelsLoading,
|
|
47
|
+
getChannelsRefetch,
|
|
48
|
+
selectedChannelId,
|
|
49
|
+
} = props;
|
|
50
|
+
const [hostChannels, setHostChannels] = useState([]);
|
|
51
|
+
const [guestChannels, setGuestChannels] = useState([]);
|
|
52
|
+
const [hostKeyword, setHostKeyword] = useState('');
|
|
53
|
+
const [guestKeyword, setGuestKeyword] = useState('');
|
|
54
|
+
const [tabIndex, setTabIndex] = useState(0);
|
|
55
|
+
|
|
56
|
+
useEffect(() => {
|
|
57
|
+
if (channelToTop) {
|
|
58
|
+
}
|
|
59
|
+
}, [channelToTop]);
|
|
60
|
+
|
|
61
|
+
useEffect(() => {
|
|
62
|
+
if (!userChannelsLoading && userChannels.length !== 0) {
|
|
63
|
+
let fChannels = [];
|
|
64
|
+
let diChal = [];
|
|
65
|
+
// if (currentUser?.id !== '' && !allChannelsLoading) {
|
|
66
|
+
// console.log(props);
|
|
67
|
+
let uc = [];
|
|
68
|
+
userChannels?.channelsByUser?.forEach((u) => uc.push(u.id)); // id of user's channel
|
|
69
|
+
let ac = [];
|
|
70
|
+
allChannels?.channels?.forEach((a) => ac.push(a.id)); // id of all channel
|
|
71
|
+
diChal = ac.filter((t) => !uc.includes(t)); // id of other's channel
|
|
72
|
+
allChannels?.channels?.filter((dc) => {
|
|
73
|
+
if (diChal.includes(dc.id)) {
|
|
74
|
+
dc.members.forEach((m) => {
|
|
75
|
+
if (m.user === currentUser?.id) {
|
|
76
|
+
fChannels.push(dc);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
// }
|
|
82
|
+
console.log(props);
|
|
83
|
+
let chls = [...(userChannels?.channelsByUser ?? []), ...fChannels];
|
|
84
|
+
const tempGuestChannels = [
|
|
85
|
+
...(chls && chls.length && currentUser
|
|
86
|
+
? chls?.filter(
|
|
87
|
+
(chl) =>
|
|
88
|
+
chl.type === 'DIRECT' &&
|
|
89
|
+
chl?.displayName !== 'admin (you)' &&
|
|
90
|
+
chl?.displayName !== 'surveybot' &&
|
|
91
|
+
chl.members[0].user == currentUser?.id,
|
|
92
|
+
)
|
|
93
|
+
: []),
|
|
94
|
+
];
|
|
95
|
+
setGuestChannels(tempGuestChannels);
|
|
96
|
+
const tempHostChannels = [
|
|
97
|
+
...(chls && chls.length && currentUser
|
|
98
|
+
? chls?.filter(
|
|
99
|
+
(chl) =>
|
|
100
|
+
chl.type === 'DIRECT' &&
|
|
101
|
+
chl?.displayName !== 'admin (you)' &&
|
|
102
|
+
chl?.displayName !== 'surveybot' &&
|
|
103
|
+
chl.members[0].user != currentUser?.id,
|
|
104
|
+
)
|
|
105
|
+
: []),
|
|
106
|
+
];
|
|
107
|
+
setHostChannels(tempHostChannels);
|
|
108
|
+
const isHost = tempHostChannels.findIndex((chl) => chl.id == selectedChannelId);
|
|
109
|
+
const isGuest = tempGuestChannels.findIndex((chl) => chl.id == selectedChannelId);
|
|
110
|
+
if (isHost == -1 && isGuest == -1) getChannelsRefetch();
|
|
111
|
+
// setHostChannels([...fChannels.filter((chl) => chl.type === 'DIRECT')]);
|
|
112
|
+
}
|
|
113
|
+
}, [allChannels, allChannelsLoading, userChannels, userChannelsLoading, currentUser, getChannelsRefetch]);
|
|
114
|
+
|
|
115
|
+
useEffect(() => {
|
|
116
|
+
if (selectedChannelId && hostChannels && hostChannels.length !== 0) {
|
|
117
|
+
const chlIndex = hostChannels.findIndex((chl) => chl.id == selectedChannelId);
|
|
118
|
+
if (chlIndex > -1) setTabIndex(0);
|
|
119
|
+
}
|
|
120
|
+
if (selectedChannelId && guestChannels && guestChannels.length !== 0) {
|
|
121
|
+
const chlIndex = guestChannels.findIndex((chl) => chl.id == selectedChannelId);
|
|
122
|
+
if (chlIndex > -1) setTabIndex(1);
|
|
123
|
+
}
|
|
124
|
+
}, [hostChannels, guestChannels, selectedChannelId]);
|
|
125
|
+
|
|
126
|
+
const handleTabChange = (index: number) => {
|
|
127
|
+
setTabIndex(index);
|
|
128
|
+
if ((index == 0 && hostChannels.length == 0) || (index == 1 && guestChannels.length == 0)) {
|
|
129
|
+
clearMessages();
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
handleSelectChannel(index == 0 ? hostChannels[0].id : guestChannels[0].id);
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
return (
|
|
136
|
+
<Box w="100%" p="4" borderRightWidth="1px" borderRightColor="gray.300">
|
|
137
|
+
<Tabs index={tabIndex} onChange={handleTabChange}>
|
|
138
|
+
<TabList w="100%">
|
|
139
|
+
<Tab w="50%" fontSize="24px" justifyContent={'flex-start'}>
|
|
140
|
+
Host
|
|
141
|
+
</Tab>
|
|
142
|
+
<Tab w="50%" fontSize="24px" justifyContent={'flex-start'}>
|
|
143
|
+
Guest
|
|
144
|
+
</Tab>
|
|
145
|
+
</TabList>
|
|
146
|
+
<TabPanels>
|
|
147
|
+
<TabPanel p="0" pt="1">
|
|
148
|
+
<SearchInput keyword={hostKeyword} setKeyword={setHostKeyword} />
|
|
149
|
+
{currentUser &&
|
|
150
|
+
hostChannels &&
|
|
151
|
+
hostChannels.length !== 0 &&
|
|
152
|
+
hostChannels.map((channel, index) => (
|
|
153
|
+
<ConversationItem
|
|
154
|
+
key={`conv_channel_${channel.id}`}
|
|
155
|
+
filter={hostKeyword}
|
|
156
|
+
channel={channel}
|
|
157
|
+
currentUser={currentUser}
|
|
158
|
+
handleSelectChannel={handleSelectChannel}
|
|
159
|
+
users={users}
|
|
160
|
+
selectedChannelId={selectedChannelId}
|
|
161
|
+
showBorder={index == hostChannels.length - 1 ? false : true}
|
|
162
|
+
/>
|
|
163
|
+
))}
|
|
164
|
+
</TabPanel>
|
|
165
|
+
<TabPanel p="0" pt="1">
|
|
166
|
+
<SearchInput keyword={guestKeyword} setKeyword={setGuestKeyword} />
|
|
167
|
+
{currentUser &&
|
|
168
|
+
guestChannels &&
|
|
169
|
+
guestChannels.length !== 0 &&
|
|
170
|
+
guestChannels.map((channel, index) => (
|
|
171
|
+
<ConversationItem
|
|
172
|
+
key={`conv_channel_${channel.id}`}
|
|
173
|
+
filter={guestKeyword}
|
|
174
|
+
channel={channel}
|
|
175
|
+
currentUser={currentUser}
|
|
176
|
+
handleSelectChannel={handleSelectChannel}
|
|
177
|
+
users={users}
|
|
178
|
+
selectedChannelId={selectedChannelId}
|
|
179
|
+
showBorder={index == guestChannels.length - 1 ? false : true}
|
|
180
|
+
/>
|
|
181
|
+
))}
|
|
182
|
+
</TabPanel>
|
|
183
|
+
</TabPanels>
|
|
184
|
+
</Tabs>
|
|
185
|
+
</Box>
|
|
186
|
+
);
|
|
187
|
+
};
|
|
188
|
+
const SearchInput = ({ keyword, setKeyword }: any) => {
|
|
189
|
+
return (
|
|
190
|
+
<Box w="100%" d="flex" alignItems={'center'} my="15px">
|
|
191
|
+
<InputGroup size="md">
|
|
192
|
+
<Input
|
|
193
|
+
pr="4.5rem"
|
|
194
|
+
pl="2rem"
|
|
195
|
+
type="text"
|
|
196
|
+
placeholder="Search Inbox"
|
|
197
|
+
display="flex"
|
|
198
|
+
alignItems="center"
|
|
199
|
+
color="gray.500"
|
|
200
|
+
backgroundColor="white"
|
|
201
|
+
borderRadius="30px"
|
|
202
|
+
borderWidth="1px"
|
|
203
|
+
borderColor="gray.200"
|
|
204
|
+
height="60px"
|
|
205
|
+
value={keyword}
|
|
206
|
+
onChange={(e) => setKeyword(e.target.value)}
|
|
207
|
+
fontWeight="medium"
|
|
208
|
+
/>
|
|
209
|
+
<InputRightElement width="60px" height="100%">
|
|
210
|
+
<Button
|
|
211
|
+
alignSelf="center"
|
|
212
|
+
size="lg"
|
|
213
|
+
minW="50px"
|
|
214
|
+
w="50px"
|
|
215
|
+
h="50px"
|
|
216
|
+
borderRadius="24px"
|
|
217
|
+
alignItems="center"
|
|
218
|
+
justifyContent="center"
|
|
219
|
+
borderWidth="1px"
|
|
220
|
+
borderColor="yellow.400"
|
|
221
|
+
backgroundColor="yellow.400"
|
|
222
|
+
color="white"
|
|
223
|
+
d="flex"
|
|
224
|
+
onClick={() => {}}
|
|
225
|
+
>
|
|
226
|
+
<SearchIcon w="1.4rem" h="1.4rem" />
|
|
227
|
+
</Button>
|
|
228
|
+
</InputRightElement>
|
|
229
|
+
</InputGroup>
|
|
230
|
+
<Button
|
|
231
|
+
alignSelf="center"
|
|
232
|
+
size="lg"
|
|
233
|
+
minW="50px"
|
|
234
|
+
w="50px"
|
|
235
|
+
h="50px"
|
|
236
|
+
marginLeft="5px"
|
|
237
|
+
borderRadius="30px"
|
|
238
|
+
alignItems="center"
|
|
239
|
+
justifyContent="center"
|
|
240
|
+
backgroundColor="white"
|
|
241
|
+
borderWidth="1px"
|
|
242
|
+
borderColor="gray.200"
|
|
243
|
+
color="#333"
|
|
244
|
+
d="flex"
|
|
245
|
+
>
|
|
246
|
+
<Icon as={GoSettings} w="1.4rem" h="1.4rem" />
|
|
247
|
+
</Button>
|
|
248
|
+
</Box>
|
|
249
|
+
);
|
|
250
|
+
};
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Box,
|
|
3
|
+
Button,
|
|
4
|
+
Image,
|
|
5
|
+
InputGroup,
|
|
6
|
+
InputLeftElement,
|
|
7
|
+
InputRightElement,
|
|
8
|
+
Textarea,
|
|
9
|
+
Tooltip,
|
|
10
|
+
} from '@chakra-ui/react';
|
|
11
|
+
import { BiImage } from '@react-icons/all-files/bi/BiImage';
|
|
12
|
+
import { fi } from 'date-fns/locale';
|
|
13
|
+
import React, { useMemo, useRef, useState } from 'react';
|
|
14
|
+
import { logoURL } from '../../constants/index';
|
|
15
|
+
import { FilesList } from '../inbox/FilesList';
|
|
16
|
+
|
|
17
|
+
type MessageInputProps = {
|
|
18
|
+
channelId: string;
|
|
19
|
+
handleSend: (message: string, files?: File[]) => void;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export const MessageInput = ({ channelId, handleSend: handleSendProp }: MessageInputProps) => {
|
|
23
|
+
const files$ = useRef<HTMLInputElement>();
|
|
24
|
+
const [files, setFiles] = useState([]);
|
|
25
|
+
const [message, setMessage] = useState('');
|
|
26
|
+
const [height, setHeight] = useState<any>('40px');
|
|
27
|
+
const handleSend = () => {
|
|
28
|
+
handleSendProp(message, files);
|
|
29
|
+
|
|
30
|
+
setMessage('');
|
|
31
|
+
setFiles([]);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const handleKeyDown = (e) => {
|
|
35
|
+
const keyCode = e.which || e.keyCode;
|
|
36
|
+
if (keyCode == 13 && !e.shiftKey) {
|
|
37
|
+
e.preventDefault();
|
|
38
|
+
handleSend();
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const inputHeight = useMemo(() => {
|
|
43
|
+
return 40 + (message.split('\n').length - 1) * 20 + 'px';
|
|
44
|
+
}, [message]);
|
|
45
|
+
|
|
46
|
+
const handleFileChange = ({ target: { files } }) => setFiles((existing) => existing.concat(...files));
|
|
47
|
+
|
|
48
|
+
const openFileUpload = () => files$.current?.click();
|
|
49
|
+
return (
|
|
50
|
+
<>
|
|
51
|
+
<input
|
|
52
|
+
style={{ display: 'none' }}
|
|
53
|
+
accept="image/png, image/gif, image/jpeg"
|
|
54
|
+
type="file" onChange={handleFileChange} ref={files$} multiple={true} />
|
|
55
|
+
<Box p="6" px={{ base: 0, md: '80px', lg: '150px'}}>
|
|
56
|
+
<Tooltip
|
|
57
|
+
label="Image"
|
|
58
|
+
placement="top"
|
|
59
|
+
// bg="white"
|
|
60
|
+
display="flex"
|
|
61
|
+
alignItems="center"
|
|
62
|
+
width="60px"
|
|
63
|
+
height="40px"
|
|
64
|
+
borderRadius="10px"
|
|
65
|
+
fontSize="15px"
|
|
66
|
+
justifyContent="center"
|
|
67
|
+
marginTop="5px"
|
|
68
|
+
// color="white"
|
|
69
|
+
boxShadow="0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23)"
|
|
70
|
+
hasArrow={true}
|
|
71
|
+
>
|
|
72
|
+
<Button
|
|
73
|
+
onClick={openFileUpload}
|
|
74
|
+
border="none"
|
|
75
|
+
borderRadius="50%"
|
|
76
|
+
bg="none"
|
|
77
|
+
width="42px"
|
|
78
|
+
height="42px"
|
|
79
|
+
p="4px"
|
|
80
|
+
_hover={{ backgroundColor: 'rgb(221, 221, 221)' }}
|
|
81
|
+
>
|
|
82
|
+
<BiImage color="#464646" width="full" height="full" />
|
|
83
|
+
</Button>
|
|
84
|
+
</Tooltip>
|
|
85
|
+
<InputGroup size="md" marginBottom={15}>
|
|
86
|
+
<InputLeftElement height="100%" pl="25px" width="60px">
|
|
87
|
+
<Image width={'28px'} height={'28px'} src={logoURL} />
|
|
88
|
+
</InputLeftElement>
|
|
89
|
+
<Textarea
|
|
90
|
+
fontSize="16px"
|
|
91
|
+
placeholder="Reminder - Leave a review"
|
|
92
|
+
value={message}
|
|
93
|
+
height={inputHeight}
|
|
94
|
+
minHeight="50px"
|
|
95
|
+
maxH="220px"
|
|
96
|
+
pl="75px"
|
|
97
|
+
pr="15px"
|
|
98
|
+
pt="12px"
|
|
99
|
+
pb="12px"
|
|
100
|
+
borderRadius={'25px'}
|
|
101
|
+
borderColor={'transparent'}
|
|
102
|
+
backgroundColor={'gray.300'}
|
|
103
|
+
color="gray.600"
|
|
104
|
+
resize="none"
|
|
105
|
+
overflow={'hidden'}
|
|
106
|
+
onKeyDown={handleKeyDown}
|
|
107
|
+
onChange={(e) => setMessage(e.target.value)}
|
|
108
|
+
onSubmit={(e) => alert(e)}
|
|
109
|
+
/>
|
|
110
|
+
<InputRightElement height="100%">
|
|
111
|
+
{message || files.length && (
|
|
112
|
+
<Box
|
|
113
|
+
position="relative"
|
|
114
|
+
right="20px"
|
|
115
|
+
as="button"
|
|
116
|
+
height="30px"
|
|
117
|
+
lineHeight="1.2"
|
|
118
|
+
transition="all 0.2s cubic-bezier(.08,.52,.52,1)"
|
|
119
|
+
border="1px"
|
|
120
|
+
px="15px"
|
|
121
|
+
borderRadius="5px"
|
|
122
|
+
fontSize="13px"
|
|
123
|
+
fontWeight="semibold"
|
|
124
|
+
bg="transparent"
|
|
125
|
+
borderColor="#ccd0d5"
|
|
126
|
+
color="#4b4f56"
|
|
127
|
+
_hover={{ bg: '#ebedf0' }}
|
|
128
|
+
_active={{
|
|
129
|
+
bg: '#dddfe2',
|
|
130
|
+
transform: 'scale(0.98)',
|
|
131
|
+
borderColor: '#bec3c9',
|
|
132
|
+
}}
|
|
133
|
+
_focus={{
|
|
134
|
+
boxShadow: '0 0 1px 2px rgba(88, 144, 255, .75), 0 1px 1px rgba(0, 0, 0, .15)',
|
|
135
|
+
}}
|
|
136
|
+
onClick={handleSend}
|
|
137
|
+
>
|
|
138
|
+
Send
|
|
139
|
+
</Box>
|
|
140
|
+
)}
|
|
141
|
+
{/* </Button> */}
|
|
142
|
+
</InputRightElement>
|
|
143
|
+
</InputGroup>
|
|
144
|
+
<FilesList files={files} />
|
|
145
|
+
</Box>
|
|
146
|
+
</>
|
|
147
|
+
);
|
|
148
|
+
};
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Icon,
|
|
3
|
+
Avatar,
|
|
4
|
+
Box,
|
|
5
|
+
Flex,
|
|
6
|
+
Modal,
|
|
7
|
+
ModalBody,
|
|
8
|
+
ModalCloseButton,
|
|
9
|
+
ModalContent,
|
|
10
|
+
ModalOverlay,
|
|
11
|
+
Text,
|
|
12
|
+
useDisclosure,
|
|
13
|
+
} from '@chakra-ui/react';
|
|
14
|
+
import { BsFlag } from '@react-icons/all-files/bs/BsFlag';
|
|
15
|
+
import React, { useMemo, useRef } from 'react';
|
|
16
|
+
import { UserModalContent } from './UserModalContent';
|
|
17
|
+
import { isToday, isYesterday, format } from 'date-fns';
|
|
18
|
+
import { FilesList } from '../inbox/FilesList';
|
|
19
|
+
|
|
20
|
+
type MessagesProps = {
|
|
21
|
+
channelId: number;
|
|
22
|
+
currentUser: any;
|
|
23
|
+
channelMessages: any[];
|
|
24
|
+
totalCount: number;
|
|
25
|
+
};
|
|
26
|
+
export const Messages = ({ channelId, currentUser, channelMessages, totalCount }: MessagesProps) => {
|
|
27
|
+
const { isOpen, onOpen, onClose } = useDisclosure();
|
|
28
|
+
|
|
29
|
+
const messagesEndRef = useRef(null);
|
|
30
|
+
const scrollToBottom = () => {
|
|
31
|
+
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const messageList = useMemo(() => {
|
|
35
|
+
let currentDate = '';
|
|
36
|
+
let res = [];
|
|
37
|
+
channelMessages.map((msg) => {
|
|
38
|
+
const date = new Date(msg.createdAt);
|
|
39
|
+
let msgDate;
|
|
40
|
+
if (isToday(date)) msgDate = 'Today';
|
|
41
|
+
else if (isYesterday(date)) msgDate = 'Yesterday';
|
|
42
|
+
else msgDate = format(new Date(msg.createdAt), 'eee, do MMMM');
|
|
43
|
+
|
|
44
|
+
if (msgDate !== currentDate) {
|
|
45
|
+
res.push(msgDate);
|
|
46
|
+
currentDate = msgDate;
|
|
47
|
+
}
|
|
48
|
+
res.push(msg);
|
|
49
|
+
});
|
|
50
|
+
return res;
|
|
51
|
+
}, [channelMessages]);
|
|
52
|
+
return (
|
|
53
|
+
<Box w="full">
|
|
54
|
+
{messageList.map((message, index) => {
|
|
55
|
+
return typeof message !== 'object' ? (
|
|
56
|
+
<Flex w="full" key={`msgList_${index}`} justifyContent={'center'} mb="7">
|
|
57
|
+
<Text fontSize="14px" color="gray.600" fontWeight={'bold'}>
|
|
58
|
+
{message}
|
|
59
|
+
</Text>
|
|
60
|
+
</Flex>
|
|
61
|
+
) : (
|
|
62
|
+
<Flex w="full" key={`msgList_${index}`} justifyContent={'flex-start'} mb="7">
|
|
63
|
+
<Flex flexGrow={1}>
|
|
64
|
+
<Avatar
|
|
65
|
+
width="60px"
|
|
66
|
+
height="60px"
|
|
67
|
+
backgroundColor="grey"
|
|
68
|
+
borderRadius="50%"
|
|
69
|
+
src={message?.imageUrl ? message?.imageUrl : ''}
|
|
70
|
+
marginRight="15px"
|
|
71
|
+
onClick={onOpen}
|
|
72
|
+
></Avatar>
|
|
73
|
+
<Box flexGrow={1}>
|
|
74
|
+
<Flex flexGrow={1} mt="5px">
|
|
75
|
+
<Text fontSize="14px" color="gray.600" fontWeight={'bold'}>
|
|
76
|
+
{message?.author?.familyName && message?.author?.givenName
|
|
77
|
+
? message?.author?.givenName + ' ' + message?.author?.familyName
|
|
78
|
+
: message?.author?.username}
|
|
79
|
+
</Text>
|
|
80
|
+
<Text fontSize="14px" color="gray.500" ml="10px">
|
|
81
|
+
{format(new Date(message?.createdAt), 'MMM dd, yyyy hh:mm aaa')}
|
|
82
|
+
</Text>
|
|
83
|
+
</Flex>
|
|
84
|
+
<Box>
|
|
85
|
+
<Text fontSize="14px" mt="5px" mb="5px" color="gray.600" whiteSpace={'pre-line'}>
|
|
86
|
+
{message?.message}
|
|
87
|
+
</Text>
|
|
88
|
+
{message.files?.totalCount ? <FilesList uploaded files={message.files?.data} /> : null}
|
|
89
|
+
</Box>
|
|
90
|
+
</Box>
|
|
91
|
+
</Flex>
|
|
92
|
+
{currentUser?.id !== message?.author?.id && (
|
|
93
|
+
<Box ml="8px">
|
|
94
|
+
<Icon as={BsFlag} color="gray.600" width={'24px'} height={'24px'} />
|
|
95
|
+
</Box>
|
|
96
|
+
)}
|
|
97
|
+
</Flex>
|
|
98
|
+
);
|
|
99
|
+
})}
|
|
100
|
+
</Box>
|
|
101
|
+
);
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
// TODO: remove unused code
|
|
105
|
+
const ChateeModal = ({ element, isOpen, onClose }) => {
|
|
106
|
+
return (
|
|
107
|
+
<Modal isOpen={isOpen} onClose={onClose} motionPreset="slideInBottom">
|
|
108
|
+
<ModalOverlay />
|
|
109
|
+
<ModalContent
|
|
110
|
+
backgroundColor="white"
|
|
111
|
+
width="1036px"
|
|
112
|
+
position="absolute"
|
|
113
|
+
left="530px"
|
|
114
|
+
top="100px"
|
|
115
|
+
height="700px"
|
|
116
|
+
borderRadius="10px"
|
|
117
|
+
boxShadow="0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23)"
|
|
118
|
+
>
|
|
119
|
+
<Box
|
|
120
|
+
display="flex"
|
|
121
|
+
justifyContent="space-between"
|
|
122
|
+
borderBottom="1px solid rgb(221, 221, 221)"
|
|
123
|
+
paddingBottom="15px"
|
|
124
|
+
paddingTop="15px"
|
|
125
|
+
>
|
|
126
|
+
<ModalCloseButton as="a" width="30px" marginLeft="10px" color="black" _hover={{ color: 'black' }} />
|
|
127
|
+
</Box>
|
|
128
|
+
<ModalBody>
|
|
129
|
+
<UserModalContent
|
|
130
|
+
username={element?.author?.username}
|
|
131
|
+
image={element.imageUrl ? element.imageUrl : ''}
|
|
132
|
+
/>
|
|
133
|
+
</ModalBody>
|
|
134
|
+
</ModalContent>
|
|
135
|
+
</Modal>
|
|
136
|
+
);
|
|
137
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { useFela } from 'react-fela';
|
|
3
|
+
import { Button, Box } from '@chakra-ui/react';
|
|
4
|
+
|
|
5
|
+
export const Popover = () => {
|
|
6
|
+
const content = [
|
|
7
|
+
{
|
|
8
|
+
name: 'All Conversations',
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
name: 'Archived Conversations',
|
|
12
|
+
total: '0',
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
name: 'Unread Conversations',
|
|
16
|
+
total: '0',
|
|
17
|
+
},
|
|
18
|
+
];
|
|
19
|
+
return (
|
|
20
|
+
<Box>
|
|
21
|
+
{content?.map((item, index) => {
|
|
22
|
+
if (!item.total) {
|
|
23
|
+
return (
|
|
24
|
+
<Box _hover={{ bg: '#edecec' }} className="popover-style" key={index}>
|
|
25
|
+
<Button
|
|
26
|
+
border="none"
|
|
27
|
+
fontSize="15px"
|
|
28
|
+
color="#282121"
|
|
29
|
+
variant="link"
|
|
30
|
+
bg='none'
|
|
31
|
+
height= '30px'
|
|
32
|
+
>
|
|
33
|
+
{item.name}
|
|
34
|
+
</Button>
|
|
35
|
+
</Box>
|
|
36
|
+
);
|
|
37
|
+
} else {
|
|
38
|
+
return (
|
|
39
|
+
<Box _hover={{ bg: '#edecec' }} className="popover-style" key={index}>
|
|
40
|
+
<Button
|
|
41
|
+
border="none"
|
|
42
|
+
fontSize="15px"
|
|
43
|
+
color="#282121"
|
|
44
|
+
variant="link"
|
|
45
|
+
bg='none'
|
|
46
|
+
height= '30px'
|
|
47
|
+
>
|
|
48
|
+
{item.name + `(${item.total})`}
|
|
49
|
+
</Button>
|
|
50
|
+
</Box>
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
})}
|
|
54
|
+
</Box>
|
|
55
|
+
);
|
|
56
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Avatar, Button, Box, Flex, Text, Link } from '@chakra-ui/react';
|
|
3
|
+
import { AiOutlineSecurityScan } from '@react-icons/all-files/ai/AiOutlineSecurityScan';
|
|
4
|
+
import { FiCheck } from '@react-icons/all-files/fi/FiCheck';
|
|
5
|
+
import { BsFillStarFill } from '@react-icons/all-files/bs/BsFillStarFill';
|
|
6
|
+
|
|
7
|
+
export const UserModalContent = ({ username, imageUrl }: any) => {
|
|
8
|
+
return (
|
|
9
|
+
<Box>
|
|
10
|
+
<Box>
|
|
11
|
+
<Avatar
|
|
12
|
+
size="large"
|
|
13
|
+
src={imageUrl !== '' ? imageUrl : ''}
|
|
14
|
+
backgroundColor="grey"
|
|
15
|
+
width="200px"
|
|
16
|
+
height="200px"
|
|
17
|
+
borderRadius="50%"
|
|
18
|
+
/>
|
|
19
|
+
<a href="#">Update photo</a>
|
|
20
|
+
<AiOutlineSecurityScan style={{ width: '24px', height: '24px', color: 'black' }} />
|
|
21
|
+
<Box>
|
|
22
|
+
<Text>Identity verification</Text>
|
|
23
|
+
<Text as="p" color="black">
|
|
24
|
+
Show others you’re really you with the identity verification badge.
|
|
25
|
+
</Text>
|
|
26
|
+
<Button className="get-badge-btn" color="black" bg="transparent">
|
|
27
|
+
Get the badge
|
|
28
|
+
</Button>
|
|
29
|
+
</Box>
|
|
30
|
+
<Box>
|
|
31
|
+
<Text>{username} confirmed </Text>
|
|
32
|
+
<Box>
|
|
33
|
+
<FiCheck color="black" />
|
|
34
|
+
<Text as="p" color="black">
|
|
35
|
+
Email address
|
|
36
|
+
</Text>
|
|
37
|
+
</Box>
|
|
38
|
+
</Box>
|
|
39
|
+
</Box>
|
|
40
|
+
<Box>
|
|
41
|
+
<Flex>
|
|
42
|
+
<Text>Hi, I'm {username}</Text>
|
|
43
|
+
<Text as="p">Joined in 2021</Text>
|
|
44
|
+
<Link>Edit profile</Link>
|
|
45
|
+
<BsFillStarFill color="black" fontSize="md" />
|
|
46
|
+
Reviews
|
|
47
|
+
</Flex>
|
|
48
|
+
<Link href="">Reviews by you</Link>
|
|
49
|
+
</Box>
|
|
50
|
+
</Box>
|
|
51
|
+
);
|
|
52
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import React, { useMemo } from 'react';
|
|
2
|
+
|
|
3
|
+
export function FilesList({ files, uploaded = false }: { files: any[], uploaded?: boolean }) {
|
|
4
|
+
return (
|
|
5
|
+
<div style={{ display: 'flex', flexDirection: 'row' }}>
|
|
6
|
+
{files.map(file => <FilesList.FileElement uploaded={uploaded} file={file} />)}
|
|
7
|
+
</div>
|
|
8
|
+
);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
FilesList.FileElement = function FileElement({ file, uploaded }: { file: any, uploaded: boolean }) {
|
|
12
|
+
const url = useMemo(() => uploaded ? file.url : URL.createObjectURL(file), [file, uploaded]);
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<div style={{ height: 50, width: 50, backgroundImage: `url(${url})`, backgroundSize: 'contain', marginRight: '10px' }} />
|
|
16
|
+
);
|
|
17
|
+
}
|