@selfcommunity/react-core 0.6.4-alpha.8 → 0.6.4-courses.101
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/lib/cjs/components/provider/SCRoutingProvider/index.js +1 -0
- package/lib/cjs/components/provider/SCUserProvider/index.js +6 -0
- package/lib/cjs/constants/Cache.d.ts +25 -2
- package/lib/cjs/constants/Cache.js +34 -4
- package/lib/cjs/constants/Notification.d.ts +1 -0
- package/lib/cjs/constants/Notification.js +2 -1
- package/lib/cjs/constants/Preferences.d.ts +8 -0
- package/lib/cjs/constants/Preferences.js +18 -2
- package/lib/cjs/constants/Routes.d.ts +8 -0
- package/lib/cjs/constants/Routes.js +17 -1
- package/lib/cjs/hooks/useSCFetchCourse.d.ts +23 -0
- package/lib/cjs/hooks/useSCFetchCourse.js +81 -0
- package/lib/cjs/hooks/useSCFetchCourses.d.ts +22 -0
- package/lib/cjs/hooks/useSCFetchCourses.js +83 -0
- package/lib/cjs/hooks/useSCFetchLesson.d.ts +22 -0
- package/lib/cjs/hooks/useSCFetchLesson.js +72 -0
- package/lib/cjs/hooks/useSCFetchLessonCommentObject.d.ts +23 -0
- package/lib/cjs/hooks/useSCFetchLessonCommentObject.js +72 -0
- package/lib/cjs/hooks/useSCFetchLessonCommentObjects.d.ts +48 -0
- package/lib/cjs/hooks/useSCFetchLessonCommentObjects.js +302 -0
- package/lib/cjs/hooks/useSCFetchLiveStream.d.ts +20 -0
- package/lib/cjs/hooks/useSCFetchLiveStream.js +76 -0
- package/lib/cjs/hooks/useSCJoinedCoursesManager.d.ts +38 -0
- package/lib/cjs/hooks/useSCJoinedCoursesManager.js +277 -0
- package/lib/cjs/index.d.ts +8 -2
- package/lib/cjs/index.js +14 -2
- package/lib/cjs/types/context.d.ts +36 -1
- package/lib/cjs/types/index.d.ts +2 -2
- package/lib/esm/components/provider/SCRoutingProvider/index.js +2 -1
- package/lib/esm/components/provider/SCUserProvider/index.js +6 -0
- package/lib/esm/constants/Cache.d.ts +25 -2
- package/lib/esm/constants/Cache.js +25 -2
- package/lib/esm/constants/Notification.d.ts +1 -0
- package/lib/esm/constants/Notification.js +2 -1
- package/lib/esm/constants/Preferences.d.ts +8 -0
- package/lib/esm/constants/Preferences.js +16 -0
- package/lib/esm/constants/Routes.d.ts +8 -0
- package/lib/esm/constants/Routes.js +16 -0
- package/lib/esm/hooks/useSCFetchCourse.d.ts +23 -0
- package/lib/esm/hooks/useSCFetchCourse.js +78 -0
- package/lib/esm/hooks/useSCFetchCourses.d.ts +22 -0
- package/lib/esm/hooks/useSCFetchCourses.js +81 -0
- package/lib/esm/hooks/useSCFetchLesson.d.ts +22 -0
- package/lib/esm/hooks/useSCFetchLesson.js +69 -0
- package/lib/esm/hooks/useSCFetchLessonCommentObject.d.ts +23 -0
- package/lib/esm/hooks/useSCFetchLessonCommentObject.js +69 -0
- package/lib/esm/hooks/useSCFetchLessonCommentObjects.d.ts +48 -0
- package/lib/esm/hooks/useSCFetchLessonCommentObjects.js +297 -0
- package/lib/esm/hooks/useSCFetchLiveStream.d.ts +20 -0
- package/lib/esm/hooks/useSCFetchLiveStream.js +73 -0
- package/lib/esm/hooks/useSCJoinedCoursesManager.d.ts +38 -0
- package/lib/esm/hooks/useSCJoinedCoursesManager.js +273 -0
- package/lib/esm/index.d.ts +8 -2
- package/lib/esm/index.js +7 -1
- package/lib/esm/types/context.d.ts +36 -1
- package/lib/esm/types/index.d.ts +2 -2
- package/lib/umd/react-core.js +1 -1
- package/lib/umd/react-core.js.LICENSE.txt +2 -0
- package/package.json +132 -127
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
import { useEffect, useReducer } from 'react';
|
|
2
|
+
import { SCOPE_SC_CORE } from '../constants/Errors';
|
|
3
|
+
import { SCCommentsOrderBy } from '@selfcommunity/types';
|
|
4
|
+
import { Endpoints, http } from '@selfcommunity/api-services';
|
|
5
|
+
import { CacheStrategies, Logger, LRUCache } from '@selfcommunity/utils';
|
|
6
|
+
import { getLessonCommentCacheKey, getLessonCommentsCacheKey } from '../constants/Cache';
|
|
7
|
+
import { useIsComponentMountedRef } from '../utils/hooks';
|
|
8
|
+
import { getCurrentPage } from '../utils/pagination';
|
|
9
|
+
import useSCFetchLesson from '../hooks/useSCFetchLesson';
|
|
10
|
+
/**
|
|
11
|
+
* @hidden
|
|
12
|
+
* We have complex state logic that involves multiple sub-values,
|
|
13
|
+
* so useReducer is preferable to useState.
|
|
14
|
+
* Define all possible auth action types label
|
|
15
|
+
* Use this to export actions and dispatch an action
|
|
16
|
+
*/
|
|
17
|
+
export const commentsObjectActionTypes = {
|
|
18
|
+
LOADING_NEXT: '_loading_next',
|
|
19
|
+
LOADING_PREVIOUS: '_loading_previous',
|
|
20
|
+
DATA_NEXT_LOADED: '_data_next_loaded',
|
|
21
|
+
DATA_PREVIOUS_LOADED: '_data_previous_loaded',
|
|
22
|
+
DATA_RELOAD: '_data_reload',
|
|
23
|
+
DATA_RELOADED: '_data_reloaded',
|
|
24
|
+
DATA_REVALIDATE: '_data_revalidate',
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* commentsReducer:
|
|
28
|
+
* - manage the state of comments object
|
|
29
|
+
* - update the state base on action type
|
|
30
|
+
* @param state
|
|
31
|
+
* @param action
|
|
32
|
+
*/
|
|
33
|
+
function commentsReducer(state, action) {
|
|
34
|
+
switch (action.type) {
|
|
35
|
+
case commentsObjectActionTypes.LOADING_NEXT:
|
|
36
|
+
return Object.assign(Object.assign({}, state), { isLoadingNext: true, isLoadingPrevious: false });
|
|
37
|
+
case commentsObjectActionTypes.LOADING_PREVIOUS:
|
|
38
|
+
return Object.assign(Object.assign({}, state), { isLoadingNext: false, isLoadingPrevious: true });
|
|
39
|
+
case commentsObjectActionTypes.DATA_NEXT_LOADED:
|
|
40
|
+
return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, state), { comments: action.payload.comments, isLoadingNext: false, componentLoaded: true, revalidate: false, revalidateNext: null, revalidatePrevious: null, next: action.payload.next }), (action.payload.page ? { page: action.payload.page } : {})), (action.payload.nextPage ? { nextPage: action.payload.nextPage } : {})), (action.payload.previous ? { previous: action.payload.previous } : {})), (action.payload.previousPage ? { previousPage: action.payload.previousPage } : {})), (action.payload.total ? { total: action.payload.total } : {}));
|
|
41
|
+
case commentsObjectActionTypes.DATA_PREVIOUS_LOADED:
|
|
42
|
+
return Object.assign(Object.assign(Object.assign(Object.assign({}, state), { comments: action.payload.comments, isLoadingPrevious: false, revalidate: false, revalidateNext: null, revalidatePrevious: null, previous: action.payload.previous }), (action.payload.page ? { page: action.payload.page } : {})), (action.payload.previousPage ? { previousPage: action.payload.previousPage } : {}));
|
|
43
|
+
case commentsObjectActionTypes.DATA_RELOAD:
|
|
44
|
+
return Object.assign(Object.assign({}, state), { next: action.payload.next, previousPage: null, nextPage: null, comments: [], total: 0, previous: null, isLoadingNext: true, reload: true });
|
|
45
|
+
case commentsObjectActionTypes.DATA_RELOADED:
|
|
46
|
+
return Object.assign(Object.assign({}, state), { componentLoaded: true, reload: false });
|
|
47
|
+
case commentsObjectActionTypes.DATA_REVALIDATE:
|
|
48
|
+
return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, state), { componentLoaded: true, revalidate: true }), (action.payload.revalidateNext ? { revalidateNext: action.payload.revalidateNext } : {})), (action.payload.revalidatePrevious ? { revalidatePrevious: action.payload.revalidatePrevious } : {})), { reload: false });
|
|
49
|
+
default:
|
|
50
|
+
throw new Error(`Unhandled type: ${action.type}`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Define initial state
|
|
55
|
+
* @param data
|
|
56
|
+
*/
|
|
57
|
+
function stateInitializer(data) {
|
|
58
|
+
const __commentsObjectCacheKey = data.scLesson ? getLessonCommentsCacheKey(data.scLesson.id, data.next) : null;
|
|
59
|
+
let _initState = {
|
|
60
|
+
componentLoaded: false,
|
|
61
|
+
comments: [],
|
|
62
|
+
total: 0,
|
|
63
|
+
next: data.next,
|
|
64
|
+
previous: null,
|
|
65
|
+
isLoadingNext: false,
|
|
66
|
+
isLoadingPrevious: false,
|
|
67
|
+
page: Math.ceil(data.offset / data.pageSize + 1),
|
|
68
|
+
reload: false,
|
|
69
|
+
revalidate: false,
|
|
70
|
+
revalidateNext: null,
|
|
71
|
+
revalidatePrevious: null,
|
|
72
|
+
};
|
|
73
|
+
_initState['nextPage'] = _initState.next ? _initState.page + 1 : null;
|
|
74
|
+
_initState['previousPage'] = _initState.previous ? _initState.page - 1 : null;
|
|
75
|
+
if (__commentsObjectCacheKey && LRUCache.hasKey(__commentsObjectCacheKey) && data.cacheStrategy !== CacheStrategies.NETWORK_ONLY) {
|
|
76
|
+
const _cachedData = LRUCache.get(__commentsObjectCacheKey);
|
|
77
|
+
let page = Math.max(getCurrentPage(_cachedData.next, data.pageSize), 1);
|
|
78
|
+
const nextPage = _cachedData.next ? getCurrentPage(_cachedData.next, data.pageSize) : null;
|
|
79
|
+
const previousPage = _cachedData.previous ? Math.max(getCurrentPage(_cachedData.previous, data.pageSize) - 1, 1) : null;
|
|
80
|
+
return Object.assign(Object.assign({}, _initState), {
|
|
81
|
+
total: _cachedData.count,
|
|
82
|
+
next: _cachedData.next,
|
|
83
|
+
previous: _cachedData.previous,
|
|
84
|
+
comments: _cachedData.results,
|
|
85
|
+
page,
|
|
86
|
+
nextPage,
|
|
87
|
+
previousPage,
|
|
88
|
+
componentLoaded: true,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
return _initState;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
:::info
|
|
95
|
+
This custom hooks is used to fetch paginated comments for a specific course lesson.
|
|
96
|
+
:::
|
|
97
|
+
* @param props
|
|
98
|
+
*/
|
|
99
|
+
export default function useSCFetchLessonCommentObjects(props) {
|
|
100
|
+
// PROPS
|
|
101
|
+
const { id, lessonObject, offset = 0, pageSize = 5, orderBy = SCCommentsOrderBy.ADDED_AT_DESC, parent, onChangePage, cacheStrategy = CacheStrategies.NETWORK_ONLY, } = props;
|
|
102
|
+
// FeedObject
|
|
103
|
+
const { scLesson, setSCLesson } = useSCFetchLesson({
|
|
104
|
+
id: id,
|
|
105
|
+
lesson: lessonObject,
|
|
106
|
+
courseId: lessonObject.course_id,
|
|
107
|
+
sectionId: lessonObject.section_id,
|
|
108
|
+
cacheStrategy,
|
|
109
|
+
});
|
|
110
|
+
/**
|
|
111
|
+
* Get next url
|
|
112
|
+
*/
|
|
113
|
+
const getNextUrl = () => {
|
|
114
|
+
const _offset = offset ? `&offset=${offset}` : '';
|
|
115
|
+
const _parent = parent ? `&parent=${parent}` : '';
|
|
116
|
+
const _lessonId = scLesson ? scLesson.id : id;
|
|
117
|
+
const _courseId = scLesson ? scLesson.course_id : lessonObject.course_id;
|
|
118
|
+
const _sectionId = scLesson ? scLesson.section_id : lessonObject.section_id;
|
|
119
|
+
return `${Endpoints.GetCourseLessonComments.url({
|
|
120
|
+
id: _courseId,
|
|
121
|
+
section_id: _sectionId,
|
|
122
|
+
lesson_id: _lessonId,
|
|
123
|
+
})}?limit=${pageSize}&ordering=${orderBy}${_offset}${_parent}`;
|
|
124
|
+
};
|
|
125
|
+
// STATE
|
|
126
|
+
const [state, dispatch] = useReducer(commentsReducer, { scLesson, offset, pageSize, next: getNextUrl(), cacheStrategy }, stateInitializer);
|
|
127
|
+
// REFS
|
|
128
|
+
const isMountedRef = useIsComponentMountedRef();
|
|
129
|
+
/**
|
|
130
|
+
* Get Comments (with cache)
|
|
131
|
+
*/
|
|
132
|
+
const revalidate = (url, forward) => {
|
|
133
|
+
return performFetchComments(url, false).then((res) => {
|
|
134
|
+
let _comments;
|
|
135
|
+
let page = getCurrentPage(forward ? res.next : res.previous, pageSize);
|
|
136
|
+
if (forward) {
|
|
137
|
+
let start = state.comments.slice(0, state.comments.length - res.results.length);
|
|
138
|
+
_comments = start.concat(res.results);
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
let start = state.comments.slice(res.results.length, state.comments.length);
|
|
142
|
+
_comments = res.results.concat(start);
|
|
143
|
+
}
|
|
144
|
+
if (isMountedRef.current) {
|
|
145
|
+
dispatch({
|
|
146
|
+
type: forward ? commentsObjectActionTypes.DATA_NEXT_LOADED : commentsObjectActionTypes.DATA_PREVIOUS_LOADED,
|
|
147
|
+
payload: Object.assign(Object.assign({ page, comments: _comments }, (forward ? { next: res.next } : { previous: res.previous })), { total: res.count }),
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
};
|
|
152
|
+
/**
|
|
153
|
+
* Get Comments
|
|
154
|
+
*/
|
|
155
|
+
const performFetchComments = (url, seekCache = true) => {
|
|
156
|
+
const __commentObjectsCacheKey = getLessonCommentsCacheKey(scLesson.id, url);
|
|
157
|
+
if (seekCache && LRUCache.hasKey(__commentObjectsCacheKey) && cacheStrategy !== CacheStrategies.NETWORK_ONLY) {
|
|
158
|
+
return Promise.resolve(LRUCache.get(__commentObjectsCacheKey));
|
|
159
|
+
}
|
|
160
|
+
return http
|
|
161
|
+
.request({
|
|
162
|
+
url,
|
|
163
|
+
method: Endpoints.GetCourseLessonComments.method,
|
|
164
|
+
})
|
|
165
|
+
.then((res) => {
|
|
166
|
+
if (res.status >= 300) {
|
|
167
|
+
return Promise.reject(res);
|
|
168
|
+
}
|
|
169
|
+
LRUCache.set(__commentObjectsCacheKey, res.data);
|
|
170
|
+
res.data.results.forEach((e) => LRUCache.set(getLessonCommentCacheKey(e.id), e));
|
|
171
|
+
return Promise.resolve(res.data);
|
|
172
|
+
});
|
|
173
|
+
};
|
|
174
|
+
/**
|
|
175
|
+
* Fetch previous comments
|
|
176
|
+
*/
|
|
177
|
+
function getPreviousPage() {
|
|
178
|
+
if (scLesson && state.previous && !state.isLoadingPrevious) {
|
|
179
|
+
const _previous = state.previous;
|
|
180
|
+
dispatch({ type: commentsObjectActionTypes.LOADING_PREVIOUS });
|
|
181
|
+
performFetchComments(_previous)
|
|
182
|
+
.then((res) => {
|
|
183
|
+
if (isMountedRef.current) {
|
|
184
|
+
let currentPage = getCurrentPage(_previous, pageSize);
|
|
185
|
+
let previousPage = res.previous ? currentPage - 1 : null;
|
|
186
|
+
dispatch({
|
|
187
|
+
type: commentsObjectActionTypes.DATA_PREVIOUS_LOADED,
|
|
188
|
+
payload: {
|
|
189
|
+
page: currentPage,
|
|
190
|
+
previousPage,
|
|
191
|
+
comments: [...res.results, ...state.comments],
|
|
192
|
+
previous: res.previous,
|
|
193
|
+
},
|
|
194
|
+
});
|
|
195
|
+
onChangePage && onChangePage(currentPage);
|
|
196
|
+
}
|
|
197
|
+
})
|
|
198
|
+
.catch((error) => {
|
|
199
|
+
Logger.error(SCOPE_SC_CORE, error);
|
|
200
|
+
})
|
|
201
|
+
.then(() => {
|
|
202
|
+
if (isMountedRef.current && cacheStrategy === CacheStrategies.STALE_WHILE_REVALIDATE) {
|
|
203
|
+
dispatch({ type: commentsObjectActionTypes.DATA_REVALIDATE, payload: { revalidatePrevious: _previous } });
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Fetch next comments
|
|
210
|
+
*/
|
|
211
|
+
function getNextPage() {
|
|
212
|
+
if (scLesson && state.next && !state.isLoadingNext) {
|
|
213
|
+
const _next = state.next;
|
|
214
|
+
dispatch({ type: commentsObjectActionTypes.LOADING_NEXT });
|
|
215
|
+
performFetchComments(_next)
|
|
216
|
+
.then((res) => {
|
|
217
|
+
if (isMountedRef.current) {
|
|
218
|
+
let currentPage = getCurrentPage(_next, pageSize);
|
|
219
|
+
let nextPage = res.next ? currentPage + 1 : null;
|
|
220
|
+
dispatch({
|
|
221
|
+
type: commentsObjectActionTypes.DATA_NEXT_LOADED,
|
|
222
|
+
payload: Object.assign({ page: currentPage, nextPage, comments: [...state.comments, ...res.results], next: res.next, total: res.count, componentLoaded: true }, (offset && state.comments.length === 0 ? { previous: res.previous, previousPage: res.previous ? currentPage - 1 : null } : {})),
|
|
223
|
+
});
|
|
224
|
+
onChangePage && onChangePage(currentPage);
|
|
225
|
+
}
|
|
226
|
+
})
|
|
227
|
+
.catch((error) => {
|
|
228
|
+
Logger.error(SCOPE_SC_CORE, error);
|
|
229
|
+
})
|
|
230
|
+
.then(() => {
|
|
231
|
+
if (isMountedRef.current && cacheStrategy === CacheStrategies.STALE_WHILE_REVALIDATE) {
|
|
232
|
+
dispatch({ type: commentsObjectActionTypes.DATA_REVALIDATE, payload: { revalidateNext: _next } });
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Reset component status on change orderBy, pageSize, offset
|
|
239
|
+
*/
|
|
240
|
+
const reload = () => {
|
|
241
|
+
if (isMountedRef.current && state.componentLoaded && Boolean(scLesson) && !state.isLoadingNext && !state.reload) {
|
|
242
|
+
dispatch({
|
|
243
|
+
type: commentsObjectActionTypes.DATA_RELOAD,
|
|
244
|
+
payload: {
|
|
245
|
+
next: getNextUrl(),
|
|
246
|
+
},
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
};
|
|
250
|
+
/**
|
|
251
|
+
* Reload fetch comments
|
|
252
|
+
*/
|
|
253
|
+
useEffect(() => {
|
|
254
|
+
if (isMountedRef.current && state.componentLoaded && state.reload && !state.isLoadingNext && !state.isLoadingPrevious) {
|
|
255
|
+
dispatch({
|
|
256
|
+
type: commentsObjectActionTypes.DATA_RELOADED,
|
|
257
|
+
});
|
|
258
|
+
getNextPage();
|
|
259
|
+
}
|
|
260
|
+
}, [state.reload, isMountedRef]);
|
|
261
|
+
/**
|
|
262
|
+
* Revalidate last fetched comments
|
|
263
|
+
*/
|
|
264
|
+
useEffect(() => {
|
|
265
|
+
if (isMountedRef.current && state.componentLoaded && Boolean(scLesson) && !state.reload && state.revalidate) {
|
|
266
|
+
revalidate(state.revalidateNext, Boolean(state.revalidateNext));
|
|
267
|
+
}
|
|
268
|
+
}, [state.revalidate, isMountedRef]);
|
|
269
|
+
/**
|
|
270
|
+
* Update lesson comments list
|
|
271
|
+
* @param updatedData
|
|
272
|
+
*/
|
|
273
|
+
const updateLessonComments = (updatedData) => {
|
|
274
|
+
if (updatedData) {
|
|
275
|
+
dispatch({
|
|
276
|
+
type: commentsObjectActionTypes.DATA_NEXT_LOADED,
|
|
277
|
+
payload: {
|
|
278
|
+
comments: updatedData,
|
|
279
|
+
next: state.next,
|
|
280
|
+
total: updatedData.length,
|
|
281
|
+
},
|
|
282
|
+
});
|
|
283
|
+
const __commentsCacheKey = getLessonCommentsCacheKey(scLesson.id, state.next);
|
|
284
|
+
LRUCache.set(__commentsCacheKey, updatedData.map((comment) => {
|
|
285
|
+
const __commentCacheKey = getLessonCommentCacheKey(comment.id);
|
|
286
|
+
LRUCache.set(__commentCacheKey, comment);
|
|
287
|
+
return comment.id;
|
|
288
|
+
}));
|
|
289
|
+
}
|
|
290
|
+
};
|
|
291
|
+
return Object.assign(Object.assign({ lessonObject: scLesson, setLessonObject: setSCLesson }, state), { pageSize,
|
|
292
|
+
getNextPage,
|
|
293
|
+
getPreviousPage,
|
|
294
|
+
orderBy,
|
|
295
|
+
reload,
|
|
296
|
+
updateLessonComments });
|
|
297
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { SCLiveStreamType } from '@selfcommunity/types';
|
|
2
|
+
import { CacheStrategies } from '@selfcommunity/utils';
|
|
3
|
+
/**
|
|
4
|
+
:::info
|
|
5
|
+
This custom hook is used to fetch an liveStream object.
|
|
6
|
+
:::
|
|
7
|
+
* @param object
|
|
8
|
+
* @param object.id
|
|
9
|
+
* @param object.liveStream
|
|
10
|
+
* @param object.cacheStrategy
|
|
11
|
+
*/
|
|
12
|
+
export default function useSCFetchLiveStream({ id, liveStream, cacheStrategy, }: {
|
|
13
|
+
id?: number | string;
|
|
14
|
+
liveStream?: SCLiveStreamType;
|
|
15
|
+
cacheStrategy?: CacheStrategies;
|
|
16
|
+
}): {
|
|
17
|
+
scLiveStream: SCLiveStreamType;
|
|
18
|
+
setSCLiveStream: (e: SCLiveStreamType) => void;
|
|
19
|
+
error: string;
|
|
20
|
+
};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { Endpoints, http } from '@selfcommunity/api-services';
|
|
2
|
+
import { CacheStrategies, Logger, LRUCache, objectWithoutProperties } from '@selfcommunity/utils';
|
|
3
|
+
import { useEffect, useMemo, useState } from 'react';
|
|
4
|
+
import { useDeepCompareEffectNoCheck } from 'use-deep-compare-effect';
|
|
5
|
+
import { useSCUser } from '../components/provider/SCUserProvider';
|
|
6
|
+
import { getLiveStreamObjectCacheKey } from '../constants/Cache';
|
|
7
|
+
import { SCOPE_SC_CORE } from '../constants/Errors';
|
|
8
|
+
/**
|
|
9
|
+
:::info
|
|
10
|
+
This custom hook is used to fetch an liveStream object.
|
|
11
|
+
:::
|
|
12
|
+
* @param object
|
|
13
|
+
* @param object.id
|
|
14
|
+
* @param object.liveStream
|
|
15
|
+
* @param object.cacheStrategy
|
|
16
|
+
*/
|
|
17
|
+
export default function useSCFetchLiveStream({ id = null, liveStream = null, cacheStrategy = CacheStrategies.CACHE_FIRST, }) {
|
|
18
|
+
const __eventId = liveStream ? liveStream.id : id;
|
|
19
|
+
// CONTEXT
|
|
20
|
+
const scUserContext = useSCUser();
|
|
21
|
+
const authUserId = scUserContext.user ? scUserContext.user.id : null;
|
|
22
|
+
// CACHE
|
|
23
|
+
const __liveStreamCacheKey = getLiveStreamObjectCacheKey(__eventId);
|
|
24
|
+
const __liveStream = authUserId ? liveStream : objectWithoutProperties(liveStream, ['subscription_status']);
|
|
25
|
+
const [scLiveStream, setScLiveStream] = useState(cacheStrategy !== CacheStrategies.NETWORK_ONLY ? LRUCache.get(__liveStreamCacheKey, __liveStream) : null);
|
|
26
|
+
const [error, setError] = useState(null);
|
|
27
|
+
/**
|
|
28
|
+
* Memoized setSCLiveStream (auto-subscription if need it)
|
|
29
|
+
*/
|
|
30
|
+
const setSCLiveStream = useMemo(() => (e) => {
|
|
31
|
+
setScLiveStream(e);
|
|
32
|
+
LRUCache.set(__liveStreamCacheKey, e);
|
|
33
|
+
}, [authUserId, setScLiveStream]);
|
|
34
|
+
/**
|
|
35
|
+
* Memoized fetchTag
|
|
36
|
+
*/
|
|
37
|
+
const fetchLiveStream = useMemo(() => (id) => {
|
|
38
|
+
return http
|
|
39
|
+
.request({
|
|
40
|
+
url: Endpoints.GetLiveStreamInfo.url({ id }),
|
|
41
|
+
method: Endpoints.GetLiveStreamInfo.method,
|
|
42
|
+
})
|
|
43
|
+
.then((res) => {
|
|
44
|
+
if (res.status >= 300) {
|
|
45
|
+
return Promise.reject(res);
|
|
46
|
+
}
|
|
47
|
+
return Promise.resolve(res.data);
|
|
48
|
+
});
|
|
49
|
+
}, []);
|
|
50
|
+
/**
|
|
51
|
+
* If id attempt to get the liveStream by id
|
|
52
|
+
*/
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
if (id !== null && id !== undefined && !liveStream) {
|
|
55
|
+
fetchLiveStream(id)
|
|
56
|
+
.then((e) => {
|
|
57
|
+
setSCLiveStream(e);
|
|
58
|
+
})
|
|
59
|
+
.catch((err) => {
|
|
60
|
+
LRUCache.delete(__liveStreamCacheKey);
|
|
61
|
+
setError(`LiveStream with id ${id} not found`);
|
|
62
|
+
Logger.error(SCOPE_SC_CORE, `LiveStream with id ${id} not found`);
|
|
63
|
+
Logger.error(SCOPE_SC_CORE, err.message);
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}, [id, liveStream, authUserId]);
|
|
67
|
+
useDeepCompareEffectNoCheck(() => {
|
|
68
|
+
if (liveStream) {
|
|
69
|
+
setSCLiveStream(liveStream);
|
|
70
|
+
}
|
|
71
|
+
}, [liveStream, authUserId]);
|
|
72
|
+
return { scLiveStream, setSCLiveStream, error };
|
|
73
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { SCCourseType, SCUserType } from '@selfcommunity/types';
|
|
2
|
+
/**
|
|
3
|
+
:::info
|
|
4
|
+
This custom hook is used to manage the courses followed.
|
|
5
|
+
:::
|
|
6
|
+
|
|
7
|
+
:::tip How to use it:
|
|
8
|
+
Follow these steps:
|
|
9
|
+
```jsx
|
|
10
|
+
1. const scUserContext: SCUserContextType = useSCUser();
|
|
11
|
+
2. const scJoinedCoursesManager: SCJoinedCoursesManagerType = scUserContext.manager.courses;
|
|
12
|
+
3. scJoinedCoursesManager.isJoined(course)
|
|
13
|
+
```
|
|
14
|
+
:::
|
|
15
|
+
*/
|
|
16
|
+
export default function useSCJoinedCoursesManager(user?: SCUserType): {
|
|
17
|
+
courses: any[];
|
|
18
|
+
loading: any[];
|
|
19
|
+
isLoading: (v: number | {
|
|
20
|
+
id: number;
|
|
21
|
+
}) => boolean;
|
|
22
|
+
join?: undefined;
|
|
23
|
+
leave?: undefined;
|
|
24
|
+
joinStatus?: undefined;
|
|
25
|
+
refresh?: undefined;
|
|
26
|
+
emptyCache?: undefined;
|
|
27
|
+
} | {
|
|
28
|
+
courses: any[];
|
|
29
|
+
loading: any[];
|
|
30
|
+
isLoading: (v: number | {
|
|
31
|
+
id: number;
|
|
32
|
+
}) => boolean;
|
|
33
|
+
join: (course: SCCourseType, userId?: number) => Promise<any>;
|
|
34
|
+
leave: (course: SCCourseType) => Promise<any>;
|
|
35
|
+
joinStatus: (course: SCCourseType) => string;
|
|
36
|
+
refresh: () => void;
|
|
37
|
+
emptyCache: () => void;
|
|
38
|
+
};
|