@tellescope/chat 1.3.21 → 1.3.23

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tellescope/chat",
3
- "version": "1.3.21",
3
+ "version": "1.3.23",
4
4
  "description": "",
5
5
  "main": "./lib/cjs/index.js",
6
6
  "module": "./lib/esm/index.js",
@@ -34,13 +34,13 @@
34
34
  "@fontsource/roboto": "^4.5.1",
35
35
  "@mui/icons-material": "^5.0.1",
36
36
  "@mui/material": "^5.0.2",
37
- "@tellescope/constants": "^1.3.20",
38
- "@tellescope/react-components": "^1.3.21",
39
- "@tellescope/sdk": "^1.3.21",
40
- "@tellescope/types-client": "^1.3.20",
41
- "@tellescope/types-models": "^1.3.20",
37
+ "@tellescope/constants": "^1.3.23",
38
+ "@tellescope/react-components": "^1.3.23",
39
+ "@tellescope/sdk": "^1.3.23",
40
+ "@tellescope/types-client": "^1.3.23",
41
+ "@tellescope/types-models": "^1.3.23",
42
42
  "@tellescope/types-utilities": "^1.3.20",
43
- "@tellescope/utilities": "^1.3.20",
43
+ "@tellescope/utilities": "^1.3.23",
44
44
  "@typescript-eslint/eslint-plugin": "^4.33.0",
45
45
  "@typescript-eslint/parser": "^4.33.0",
46
46
  "eslint": "^7.32.0",
@@ -51,7 +51,7 @@
51
51
  "react": "^16.8.0 || ^17.0.0 || ^18.0.0",
52
52
  "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
53
53
  },
54
- "gitHead": "845e7199208a281a8e6b80f84510cf9870a5413a",
54
+ "gitHead": "23050ae45de66ab1b293ee02d7f98e46b85ea0e6",
55
55
  "publishConfig": {
56
56
  "access": "public"
57
57
  }
@@ -1,17 +1,30 @@
1
- import React, { CSSProperties, useEffect, useState } from "react"
2
- import { ChatMessage, ChatRoom } from "@tellescope/types-client";
1
+ import React, { CSSProperties, useCallback, useEffect, useMemo, useState } from "react"
2
+ import { ChatMessage, ChatRoom, Enduser, User } from "@tellescope/types-client";
3
3
 
4
4
  import {
5
5
  APIError,
6
6
  AsyncIconButton,
7
+ Button,
8
+ EnduserOrUserSearch,
9
+ EnduserSearch,
7
10
  Flex,
11
+ HoverPaper,
12
+ List,
13
+ LoadingButton,
14
+ LoadingData,
15
+ Paper,
16
+ ScrollingList,
8
17
  SendIcon,
9
- TextField,
18
+ Typography,
10
19
  useChatRooms,
11
20
  useChats,
12
21
  useEndusers,
22
+ useFilters,
23
+ UserSearch,
13
24
  useUsers,
14
25
  } from "@tellescope/react-components"
26
+ import { user_display_name } from "@tellescope/utilities";
27
+ import { Checkbox, TextField, FormControlLabel, Grid } from "@mui/material";
15
28
 
16
29
  interface SendMessage_T {
17
30
  roomId: string,
@@ -68,7 +81,8 @@ export const SendMessage = ({
68
81
  return (
69
82
  <Flex row flex={1} alignContent="center" style={style}>
70
83
  <Flex column flex={1}>
71
- <TextField variant="outlined" value={message} onChange={setMessage} disabled={sending}
84
+ <TextField variant="outlined" value={message} disabled={sending}
85
+ onChange={e => setMessage(e.target.value)}
72
86
  aria-label="Enter a message"
73
87
  multiline={multiline} maxRows={maxRows}
74
88
  placeholder={placeholderText}
@@ -97,8 +111,13 @@ export interface CreateChatRoomProps {
97
111
  onGoBack?: () => void,
98
112
  onSuccess?: (c: ChatRoom) => void,
99
113
  onError?: (e: APIError) => void,
114
+ title?: string,
100
115
  roomTitle?: string,
101
116
  radio?: boolean,
117
+ minHeight?: React.CSSProperties['maxHeight']
118
+ maxHeight?: React.CSSProperties['maxHeight']
119
+ showTitleInput?: boolean,
120
+ searchBarPlacement?: "top" | "bottom",
102
121
  }
103
122
  export const CreateChatRoom: React.JSXElementConstructor<CreateChatRoomProps> = ({
104
123
  excludeEndusers,
@@ -106,78 +125,142 @@ export const CreateChatRoom: React.JSXElementConstructor<CreateChatRoomProps> =
106
125
  onGoBack,
107
126
  onSuccess,
108
127
  onError=console.error,
109
- roomTitle="Group Chat",
128
+ showTitleInput,
129
+ title="Select Members",
130
+ roomTitle: defaultRoomTitle = "Group Chat",
131
+ minHeight,
132
+ maxHeight='50vh',
133
+ searchBarPlacement="top"
110
134
  }) => {
111
- return null
112
- // const [, { createElement: createRoom }] = useChatRooms()
113
- // const [endusersLoading] = useEndusers()
114
- // const [usersLoading] = useUsers()
115
-
116
- // const [selected, setSelected] = useState<string[]>([])
117
-
118
- // return (
119
- // <LoadingData data={{ endusers: endusersLoading, users: usersLoading }} render={({ users, endusers }) => (
120
- // <Flex flex={1} column>
121
- // <Flex alignItems="center" justifyContent={"space-between"} style={{
122
- // marginBottom: 10,
123
- // }}>
124
- // {onGoBack &&
125
- // <Button onClick={onGoBack}>
126
- // Back
127
- // </Button>
128
- // }
129
- // <Typography style={{ fontSize: 20, textAlign: 'center' }}>
130
- // Select Members
131
- // </Typography>
132
-
133
- // <LoadingButton submitText='Create' submittingText='Create'
134
- // disabled={selected.length === 0}
135
- // style={{ display: 'flex', marginRight: 5 }}
136
- // onClick={() => {
137
- // const userIds = selected.filter(s => users.find(u => u.id === s))
138
- // const enduserIds = selected.filter(s => endusers.find(u => u.id === s))
139
-
140
- // createRoom({
141
- // enduserIds,
142
- // userIds,
143
- // title: roomTitle,
144
- // })
145
- // .then(r => {
146
- // setSelected([])
147
- // onSuccess?.(r)
148
- // })
149
- // .catch(onError)
150
- // }}
151
- // />
152
- // </Flex>
153
-
154
- // <List items={[...excludeUsers ? [] : users, ... excludeEndusers ? [] : endusers]} render={user => (
155
- // <Paper flex elevation={5} style={{
156
- // marginBottom: 2,
157
- // }}>
158
- // <Flex flex={1} alignItems="center" justifyContent="space-between"
159
- // onClick={() => setSelected(ss => (
160
- // ss.includes(user.id)
161
- // ? ss.filter(s => s !== user.id)
162
- // : [user.id, ...ss]
163
- // ))}
164
- // style={{
165
- // paddingLeft: 5, paddingRight: 5,
166
- // }}
167
- // >
168
- // <RadioButton value={user.id}
169
- // status={selected.includes(user.id) ? 'checked' : 'unchecked'}
170
- // />
171
-
172
- // <Typography style={{
173
- // fontWeight: selected.includes(user.id) ? 'bold' : undefined,
174
- // }}>
175
- // {user_display_name(user)}
176
- // </Typography>
177
- // </Flex>
178
- // </Paper>
179
- // )} />
180
- // </Flex>
181
- // )} />
182
- // )
135
+ const [, { createElement: createRoom }] = useChatRooms()
136
+ const [endusersLoading, { loadMore: loadMoreEndusers, doneLoading: doneLoadingEndusers }] = useEndusers()
137
+ const [usersLoading, { loadMore: loadMoreUsers, doneLoading: doneLoadingUsers }] = useUsers()
138
+ const [roomTitle, setRoomTitle] = useState(defaultRoomTitle)
139
+
140
+ const doneLoading = useCallback(() =>
141
+ (excludeUsers || doneLoadingUsers()) && (excludeEndusers || doneLoadingEndusers()),
142
+ [doneLoadingEndusers, excludeUsers, excludeEndusers, doneLoadingUsers]
143
+ )
144
+
145
+ const loadMore = useCallback(async () => {
146
+ if (!excludeEndusers && !doneLoadingEndusers()) { loadMoreEndusers().catch(console.error) };
147
+ if (!excludeUsers && !doneLoadingUsers()) { loadMoreUsers().catch(console.error) };
148
+ }, [doneLoadingEndusers, doneLoadingUsers, loadMoreEndusers, loadMoreUsers])
149
+
150
+ const [selected, setSelected] = useState<string[]>([])
151
+
152
+ const { applyFilters, ...filterProps } = useFilters<any>()
153
+
154
+ const searchbarFullWidth = searchBarPlacement === "bottom"
155
+
156
+ const searchbar = useMemo(() => (
157
+ excludeUsers
158
+ ? <EnduserSearch {...filterProps} fullWidth={searchbarFullWidth} />
159
+ : excludeEndusers
160
+ ? <UserSearch {...filterProps} fullWidth={searchbarFullWidth} />
161
+ : <EnduserOrUserSearch {...filterProps} fullWidth={searchbarFullWidth} />
162
+ ), [excludeUsers, excludeEndusers, filterProps, searchbarFullWidth])
163
+
164
+ const handleCreateRoom = useCallback((users: User[], endusers: Enduser[]) => {
165
+ const userIds = selected.filter(s => users.find(u => u.id === s))
166
+ const enduserIds = selected.filter(s => endusers.find(u => u.id === s))
167
+
168
+ createRoom({
169
+ enduserIds,
170
+ userIds,
171
+ title: roomTitle,
172
+ })
173
+ .then(r => {
174
+ setSelected([])
175
+ onSuccess?.(r)
176
+ })
177
+ .catch(onError)
178
+ }, [createRoom, roomTitle, onSuccess, onError])
179
+
180
+ return (
181
+ <LoadingData data={{ endusers: endusersLoading, users: usersLoading }} render={({ users, endusers }) => {
182
+ const itemsUnfiltered = [...excludeUsers ? [] : users, ... excludeEndusers ? [] : endusers]
183
+ const items = applyFilters(itemsUnfiltered)
184
+ return (
185
+ <Flex flex={1} column>
186
+ <Grid container alignItems="center" justifyContent={"space-between"} wrap="nowrap"
187
+ style={{
188
+ marginBottom: 10,
189
+ }}
190
+ >
191
+ {onGoBack &&
192
+ <Button onClick={onGoBack}>
193
+ Back
194
+ </Button>
195
+ }
196
+ <Typography style={{ fontSize: 16, textAlign: 'center' }}>
197
+ {title}
198
+ </Typography>
199
+
200
+ <LoadingButton submitText='Create' submittingText='Create'
201
+ disabled={selected.length === 0}
202
+ style={{ display: 'flex' }}
203
+ onClick={() => handleCreateRoom(users, endusers)}
204
+ />
205
+ </Grid>
206
+
207
+ <ScrollingList items={items}
208
+ emptyText={
209
+ itemsUnfiltered.length === 0
210
+ ? "No contacts found"
211
+ : "No one found for search"
212
+ }
213
+ minHeight={minHeight} maxHeight={maxHeight}
214
+ doneLoading={doneLoading}
215
+ loadMore={loadMore}
216
+ title={
217
+ showTitleInput &&
218
+ <TextField autoFocus value={roomTitle} onChange={e => setRoomTitle(e.target.value)}
219
+ fullWidth={searchBarPlacement !== 'top'}
220
+ label="Title" placeholder="Enter conversation title..."
221
+ size="small"
222
+ />
223
+ }
224
+ titleStyle={searchBarPlacement !== "top" ?
225
+ {
226
+ width: '100%',
227
+ }
228
+ : {}
229
+ }
230
+ titleActionsComponent={searchBarPlacement === 'top' ? searchbar : undefined}
231
+ Item={({ item: user }) => (
232
+ <HoverPaper style={{
233
+ marginBottom: 4,
234
+ }}>
235
+ <Flex flex={1} alignItems="center" justifyContent="space-between"
236
+ onClick={() => setSelected(ss => (
237
+ ss.includes(user.id)
238
+ ? ss.filter(s => s !== user.id)
239
+ : [user.id, ...ss]
240
+ ))}
241
+ style={{
242
+ paddingLeft: 5, paddingRight: 5,
243
+ }}
244
+ >
245
+ <FormControlLabel control={<Checkbox checked={selected.includes(user.id)} />} label="" />
246
+
247
+ <Typography style={{
248
+ fontWeight: selected.includes(user.id) ? 'bold' : undefined,
249
+ }}>
250
+ {user_display_name(user)}
251
+ </Typography>
252
+ </Flex>
253
+ </HoverPaper>
254
+ )}
255
+ />
256
+
257
+ {searchBarPlacement === 'bottom' &&
258
+ <Grid item alignSelf="flex-end" sx={{ mt: 1, width: '100%' }}>
259
+ {searchbar}
260
+ </Grid>
261
+ }
262
+ </Flex>
263
+ )}
264
+ } />
265
+ )
183
266
  }