/
useUserList.ts
142 lines (128 loc) · 4.18 KB
/
useUserList.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
import { useMemo, useRef, useState } from 'react';
import type { Optional, SendbirdChatSDK, SendbirdUser, UserStruct } from '@sendbird/uikit-utils';
import { Logger, SBErrorCode, SBErrorMessage, useAsyncEffect, useFreshCallback } from '@sendbird/uikit-utils';
import type { CustomQueryInterface, UseUserListOptions, UseUserListReturn } from '../types';
const createUserQuery = <User extends UserStruct>(
sdk: SendbirdChatSDK,
queryCreator?: UseUserListOptions<User>['queryCreator'],
) => {
if (queryCreator) return queryCreator();
// In order to use the API, the option must be turned on in the dashboard.
return sdk.createApplicationUserListQuery() as unknown as CustomQueryInterface<User>;
};
/**
* Get user list from query.
* default query uses 'instance.createApplicationUserListQuery'
* The response type of hook is depends on return type of 'query.next()'
*
* You can call hook with your custom query using {@link CustomQuery}
* Or you can create your 'CustomQueryClass' implemented {@link CustomQueryInterface}'
*
* ```example
* const { users } = useUserList(sdk, {
* queryCreator: () => {
* const friendQuery = sdk.createFriendListQuery();
* return new CustomQuery({
* next: () => friendQuery.next(),
* isLoading: () => friendQuery.isLoading,
* hasNext: () => friendQuery.hasMore,
* });
* }
* })
* ```
* */
export const useUserList = <
Options extends UseUserListOptions<UserStruct>,
QueriedUser extends UserStruct = Options['queryCreator'] extends Optional<
() => CustomQueryInterface<infer User extends UserStruct>
>
? User
: SendbirdUser,
>(
sdk: SendbirdChatSDK,
options?: UseUserListOptions<QueriedUser>,
): UseUserListReturn<QueriedUser> => {
const query = useRef<CustomQueryInterface<QueriedUser>>();
const [error, setError] = useState<unknown>(null);
const [loading, setLoading] = useState(false);
const [refreshing, setRefreshing] = useState(false);
const [users, setUsers] = useState<QueriedUser[]>([]);
const sortedUsers = useMemo((): QueriedUser[] => {
if (options?.sortComparator) return users.sort(options.sortComparator);
return users;
}, [users, options?.sortComparator]);
const upsertUser = useFreshCallback((user: QueriedUser) => {
setUsers(([...draft]) => {
const userIdx = draft.findIndex((it) => it.userId === user.userId);
if (userIdx > -1) draft[userIdx] = user;
else draft.push(user);
return draft;
});
});
const deleteUser = useFreshCallback((userId: QueriedUser['userId']) => {
setUsers(([...draft]) => {
const userIdx = draft.findIndex((it) => it.userId === userId);
if (userIdx > -1) draft.splice(userIdx, 1);
return draft;
});
});
const updateUsers = (users: QueriedUser[], clearPrev: boolean) => {
if (clearPrev) setUsers(users);
else setUsers((prev) => prev.concat(users));
};
const init = useFreshCallback(async () => {
query.current = createUserQuery<QueriedUser>(sdk, options?.queryCreator);
if (query.current?.hasNext) {
const users = await query.current?.next().catch((e) => {
Logger.error(e);
if (e.code === SBErrorCode.UNAUTHORIZED_REQUEST) Logger.warn(SBErrorMessage.ACL);
throw e;
});
updateUsers(users, true);
}
});
useAsyncEffect(async () => {
setLoading(true);
setError(null);
try {
await init();
} catch (e) {
setError(e);
setUsers([]);
} finally {
setLoading(false);
}
}, []);
const refresh = useFreshCallback(async () => {
setRefreshing(true);
setError(null);
try {
await init();
} catch (e) {
setError(e);
setUsers([]);
} finally {
setRefreshing(false);
}
});
const next = useFreshCallback(async () => {
if (query.current && query.current?.hasNext) {
const nextUsers = await query.current.next().catch((e) => {
Logger.error(e);
if (e.code === SBErrorCode.UNAUTHORIZED_REQUEST) Logger.warn(SBErrorMessage.ACL);
throw e;
});
updateUsers(nextUsers, false);
}
});
return {
loading,
error,
users: sortedUsers,
upsertUser,
deleteUser,
next,
refreshing,
refresh,
};
};