@blocklet/discuss-kit 1.0.0
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/LICENSE +13 -0
- package/README.md +15 -0
- package/lib/cjs/api.js +45 -0
- package/lib/cjs/comment-list.js +117 -0
- package/lib/cjs/components/comment.js +335 -0
- package/lib/cjs/components/error-fallback.js +26 -0
- package/lib/cjs/components/menu.js +84 -0
- package/lib/cjs/components/rating/binary-thumb.js +199 -0
- package/lib/cjs/components/rating/emoji-based.js +39 -0
- package/lib/cjs/components/rating/index.js +9 -0
- package/lib/cjs/components/rating/rating.js +93 -0
- package/lib/cjs/context.js +77 -0
- package/lib/cjs/did-comment-with-session.js +25 -0
- package/lib/cjs/did-comment.js +389 -0
- package/lib/cjs/hooks.js +202 -0
- package/lib/cjs/index.js +21 -0
- package/lib/cjs/lib/utils.js +17 -0
- package/lib/cjs/locales/en.js +27 -0
- package/lib/cjs/locales/index.js +10 -0
- package/lib/cjs/locales/zh.js +27 -0
- package/lib/cjs/session.js +14 -0
- package/lib/cjs/theme-provider.js +48 -0
- package/lib/cjs/ws.js +39 -0
- package/lib/es/api.js +43 -0
- package/lib/es/comment-list.js +112 -0
- package/lib/es/components/comment.js +309 -0
- package/lib/es/components/error-fallback.js +23 -0
- package/lib/es/components/menu.js +77 -0
- package/lib/es/components/rating/binary-thumb.js +176 -0
- package/lib/es/components/rating/emoji-based.js +37 -0
- package/lib/es/components/rating/index.js +4 -0
- package/lib/es/components/rating/rating.js +91 -0
- package/lib/es/context.js +74 -0
- package/lib/es/did-comment-with-session.js +24 -0
- package/lib/es/did-comment.js +377 -0
- package/lib/es/hooks.js +197 -0
- package/lib/es/index.js +8 -0
- package/lib/es/lib/utils.js +17 -0
- package/lib/es/locales/en.js +26 -0
- package/lib/es/locales/index.js +7 -0
- package/lib/es/locales/zh.js +26 -0
- package/lib/es/session.js +14 -0
- package/lib/es/theme-provider.js +46 -0
- package/lib/es/ws.js +37 -0
- package/package.json +79 -0
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
import { useMemo, useEffect, useContext } from "react";
|
|
2
|
+
import styled from "@emotion/styled";
|
|
3
|
+
import joinUrl from "url-join";
|
|
4
|
+
import PropTypes from "prop-types";
|
|
5
|
+
import useAsyncRetry from "react-use/lib/useAsyncRetry";
|
|
6
|
+
import SessionManager from "@arcblock/did-connect/lib/SessionManager";
|
|
7
|
+
import { SessionContext } from "@arcblock/did-connect/lib/Session";
|
|
8
|
+
import Button from "@arcblock/ux/lib/Button";
|
|
9
|
+
import Box from "@mui/material/Box";
|
|
10
|
+
import CircularProgress from "@mui/material/CircularProgress";
|
|
11
|
+
import ButtonGroup from "@mui/material/ButtonGroup";
|
|
12
|
+
import { useLocaleContext, LocaleProvider } from "@arcblock/ux/lib/Locale/context";
|
|
13
|
+
import { ErrorBoundary } from "react-error-boundary";
|
|
14
|
+
import { InternalThemeProvider, CommentsProvider, useCommentsContext, BinaryThumb, CommentInput, CommentList } from "@blocklet/discuss-kit-ux";
|
|
15
|
+
import ErrorFallback from "./components/error-fallback";
|
|
16
|
+
import { translations } from "./locales";
|
|
17
|
+
import getWsClient, { useSubscription } from "./ws";
|
|
18
|
+
import api, { fetchRatingStats } from "./api";
|
|
19
|
+
import { jsx, jsxs, Fragment } from "react/jsx-runtime";
|
|
20
|
+
const getPrefix = () => {
|
|
21
|
+
var _a, _b;
|
|
22
|
+
const service = (_b = (_a = window.blocklet) == null ? void 0 : _a.componentMountPoints) == null ? void 0 : _b.find((x) => x.name === "did-comments");
|
|
23
|
+
return service ? joinUrl(service.mountPoint, "/") : "";
|
|
24
|
+
};
|
|
25
|
+
const formatComment = (comment) => {
|
|
26
|
+
var _a;
|
|
27
|
+
return {
|
|
28
|
+
...comment,
|
|
29
|
+
rootId: comment.commentId,
|
|
30
|
+
author: comment.commenter,
|
|
31
|
+
createdAt: comment.createdAt ? new Date(comment.createdAt) : null,
|
|
32
|
+
updatedAt: comment.updatedAt ? new Date(comment.updatedAt) : null,
|
|
33
|
+
deletedAt: comment.deletedAt ? new Date(comment.deletedAt) : null,
|
|
34
|
+
replies: (_a = comment.replies) == null ? void 0 : _a.map(formatComment)
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
const commentAPI = {
|
|
38
|
+
fetchComments: async (params) => {
|
|
39
|
+
const copy = {
|
|
40
|
+
...params,
|
|
41
|
+
embed: params.rootId ? "rating" : "replies,rating",
|
|
42
|
+
size: params.limit
|
|
43
|
+
};
|
|
44
|
+
const {
|
|
45
|
+
data: {
|
|
46
|
+
data,
|
|
47
|
+
nextCursor,
|
|
48
|
+
total
|
|
49
|
+
}
|
|
50
|
+
} = await api.get("/comments", {
|
|
51
|
+
params: copy
|
|
52
|
+
});
|
|
53
|
+
return {
|
|
54
|
+
data: data == null ? void 0 : data.map(formatComment),
|
|
55
|
+
nextCursor,
|
|
56
|
+
total
|
|
57
|
+
};
|
|
58
|
+
},
|
|
59
|
+
fetchCommentPosition: async ({
|
|
60
|
+
id,
|
|
61
|
+
...params
|
|
62
|
+
}) => {
|
|
63
|
+
const {
|
|
64
|
+
data
|
|
65
|
+
} = await api.get(`/comments/${id}/position`, {
|
|
66
|
+
params
|
|
67
|
+
});
|
|
68
|
+
return data;
|
|
69
|
+
},
|
|
70
|
+
deleteComment: async ({
|
|
71
|
+
id
|
|
72
|
+
}) => {
|
|
73
|
+
const {
|
|
74
|
+
data
|
|
75
|
+
} = await api.delete(`/comments/${id}`);
|
|
76
|
+
return data;
|
|
77
|
+
},
|
|
78
|
+
updateComment: async ({
|
|
79
|
+
id
|
|
80
|
+
}, content) => {
|
|
81
|
+
await api.put(`/comments/${id}`, {
|
|
82
|
+
content
|
|
83
|
+
});
|
|
84
|
+
},
|
|
85
|
+
reply: async ({
|
|
86
|
+
id,
|
|
87
|
+
rootId
|
|
88
|
+
}, content) => {
|
|
89
|
+
const {
|
|
90
|
+
data
|
|
91
|
+
} = await api.post(`/comments/${rootId || id}/replies`, {
|
|
92
|
+
content,
|
|
93
|
+
parentId: id
|
|
94
|
+
});
|
|
95
|
+
return formatComment(data);
|
|
96
|
+
},
|
|
97
|
+
rate: async (comment, value, ratingType) => {
|
|
98
|
+
await api.post(`/objects/${comment.objectId}/comments/${comment.id}/ratings`, {
|
|
99
|
+
ratingType,
|
|
100
|
+
value
|
|
101
|
+
});
|
|
102
|
+
},
|
|
103
|
+
unrate: async (comment) => {
|
|
104
|
+
await api.delete(`/objects/${comment.objectId}/comments/${comment.id}/ratings`);
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
function DIDComment({
|
|
108
|
+
showConnectBtn,
|
|
109
|
+
object,
|
|
110
|
+
onChange
|
|
111
|
+
}) {
|
|
112
|
+
const {
|
|
113
|
+
session
|
|
114
|
+
} = useContext(SessionContext) || {};
|
|
115
|
+
const {
|
|
116
|
+
state,
|
|
117
|
+
sort,
|
|
118
|
+
add,
|
|
119
|
+
updateCommentState
|
|
120
|
+
} = useCommentsContext();
|
|
121
|
+
const {
|
|
122
|
+
total,
|
|
123
|
+
order,
|
|
124
|
+
initialized
|
|
125
|
+
} = state;
|
|
126
|
+
const {
|
|
127
|
+
t
|
|
128
|
+
} = useLocaleContext();
|
|
129
|
+
const objectRatingState = useAsyncRetry(() => fetchRatingStats(object.id));
|
|
130
|
+
const handlers = {
|
|
131
|
+
ADD_COMMENT: (data) => add(formatComment(data)),
|
|
132
|
+
RATING: () => objectRatingState.retry(),
|
|
133
|
+
RATING_COMMENT: async ({
|
|
134
|
+
commentId
|
|
135
|
+
}) => {
|
|
136
|
+
const rating = await fetchRatingStats(commentId);
|
|
137
|
+
updateCommentState(commentId, (current) => ({
|
|
138
|
+
...current,
|
|
139
|
+
rating
|
|
140
|
+
}));
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
useSubscription(object.id, ({
|
|
144
|
+
event,
|
|
145
|
+
data
|
|
146
|
+
}) => {
|
|
147
|
+
var _a;
|
|
148
|
+
(_a = handlers[event]) == null ? void 0 : _a.call(handlers, data);
|
|
149
|
+
}, [object.id, state]);
|
|
150
|
+
if (!initialized) {
|
|
151
|
+
return /* @__PURE__ */ jsx(CircularProgress, {});
|
|
152
|
+
}
|
|
153
|
+
const sendComment = async (content) => {
|
|
154
|
+
const {
|
|
155
|
+
data
|
|
156
|
+
} = await api.post("/comments", {
|
|
157
|
+
content,
|
|
158
|
+
object
|
|
159
|
+
});
|
|
160
|
+
add(formatComment(data));
|
|
161
|
+
onChange();
|
|
162
|
+
};
|
|
163
|
+
const handleOnRate = async ({
|
|
164
|
+
ratingType,
|
|
165
|
+
value
|
|
166
|
+
}) => {
|
|
167
|
+
if (!session.user) {
|
|
168
|
+
session.login();
|
|
169
|
+
throw new Error("Unauthenticated.");
|
|
170
|
+
}
|
|
171
|
+
await api.post(`/objects/${object.id}/ratings`, {
|
|
172
|
+
ratingType,
|
|
173
|
+
value
|
|
174
|
+
});
|
|
175
|
+
};
|
|
176
|
+
const handleOnUnrate = async () => {
|
|
177
|
+
if (!session.user) {
|
|
178
|
+
session.login();
|
|
179
|
+
throw new Error("Unauthenticated.");
|
|
180
|
+
}
|
|
181
|
+
await api.delete(`/objects/${object.id}/ratings`);
|
|
182
|
+
};
|
|
183
|
+
return /* @__PURE__ */ jsxs(Container, {
|
|
184
|
+
children: [/* @__PURE__ */ jsxs(Fragment, {
|
|
185
|
+
children: [/* @__PURE__ */ jsxs(Box, {
|
|
186
|
+
display: "flex",
|
|
187
|
+
justifyContent: "space-between",
|
|
188
|
+
alignItems: "center",
|
|
189
|
+
children: [/* @__PURE__ */ jsx(Box, {
|
|
190
|
+
mb: 1,
|
|
191
|
+
children: objectRatingState.value && /* @__PURE__ */ jsx(BinaryThumb, {
|
|
192
|
+
selectedValue: objectRatingState.value.myRating,
|
|
193
|
+
countPerValue: objectRatingState.value.counts,
|
|
194
|
+
onRate: handleOnRate,
|
|
195
|
+
onUnrate: handleOnUnrate,
|
|
196
|
+
variant: "inverse",
|
|
197
|
+
size: "lg"
|
|
198
|
+
})
|
|
199
|
+
}), showConnectBtn && (session.user ? /* @__PURE__ */ jsx(SessionManager, {
|
|
200
|
+
style: {
|
|
201
|
+
padding: 0
|
|
202
|
+
},
|
|
203
|
+
showText: true,
|
|
204
|
+
showRole: true,
|
|
205
|
+
session
|
|
206
|
+
}) : /* @__PURE__ */ jsx(Button, {
|
|
207
|
+
size: "medium",
|
|
208
|
+
variant: "contained",
|
|
209
|
+
color: "primary",
|
|
210
|
+
onClick: () => session.login(),
|
|
211
|
+
children: t("connect")
|
|
212
|
+
})), !showConnectBtn && !session.user && /* @__PURE__ */ jsx(Button, {
|
|
213
|
+
size: "medium",
|
|
214
|
+
variant: "contained",
|
|
215
|
+
color: "primary",
|
|
216
|
+
onClick: () => session.login(),
|
|
217
|
+
children: t("connect")
|
|
218
|
+
})]
|
|
219
|
+
}), !session.user && /* @__PURE__ */ jsx("div", {
|
|
220
|
+
className: "input-no-connect",
|
|
221
|
+
children: /* @__PURE__ */ jsxs("span", {
|
|
222
|
+
className: "connect-tip",
|
|
223
|
+
children: [t("connectDIDWallet"), " ", /* @__PURE__ */ jsx("a", {
|
|
224
|
+
className: "down-load-wallet",
|
|
225
|
+
href: "https://www.didwallet.io/",
|
|
226
|
+
target: "_blank",
|
|
227
|
+
rel: "noreferrer",
|
|
228
|
+
children: t("installDIDWallet")
|
|
229
|
+
})]
|
|
230
|
+
})
|
|
231
|
+
}), session.user && /* @__PURE__ */ jsx(Box, {
|
|
232
|
+
mt: 2.5,
|
|
233
|
+
children: /* @__PURE__ */ jsx(CommentInput, {
|
|
234
|
+
send: sendComment
|
|
235
|
+
})
|
|
236
|
+
})]
|
|
237
|
+
}), !!total && /* @__PURE__ */ jsxs(Box, {
|
|
238
|
+
display: "flex",
|
|
239
|
+
justifyContent: "space-between",
|
|
240
|
+
mt: 4,
|
|
241
|
+
children: [/* @__PURE__ */ jsxs("span", {
|
|
242
|
+
children: [total > 0 ? `${total} ${t("comments")}` : t("comment"), " "]
|
|
243
|
+
}), /* @__PURE__ */ jsxs(ButtonGroup, {
|
|
244
|
+
children: [/* @__PURE__ */ jsx(Button, {
|
|
245
|
+
variant: "contained",
|
|
246
|
+
color: order !== "desc" ? "primary" : "inherit",
|
|
247
|
+
size: "small",
|
|
248
|
+
onClick: () => sort("asc"),
|
|
249
|
+
children: t("oldest")
|
|
250
|
+
}), /* @__PURE__ */ jsx(Button, {
|
|
251
|
+
variant: "contained",
|
|
252
|
+
color: order === "desc" ? "primary" : "inherit",
|
|
253
|
+
size: "small",
|
|
254
|
+
onClick: () => sort("desc"),
|
|
255
|
+
children: t("newest")
|
|
256
|
+
})]
|
|
257
|
+
})]
|
|
258
|
+
}), /* @__PURE__ */ jsx(CommentList, {})]
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
DIDComment.propTypes = {
|
|
262
|
+
showConnectBtn: PropTypes.bool,
|
|
263
|
+
object: PropTypes.object.isRequired,
|
|
264
|
+
onChange: PropTypes.func
|
|
265
|
+
};
|
|
266
|
+
DIDComment.defaultProps = {
|
|
267
|
+
showConnectBtn: false,
|
|
268
|
+
onChange: () => {
|
|
269
|
+
}
|
|
270
|
+
};
|
|
271
|
+
function Wrapper({
|
|
272
|
+
target,
|
|
273
|
+
prefix,
|
|
274
|
+
flatView,
|
|
275
|
+
...rest
|
|
276
|
+
}) {
|
|
277
|
+
if (!(target == null ? void 0 : target.id)) {
|
|
278
|
+
throw new Error("target is required.");
|
|
279
|
+
}
|
|
280
|
+
const {
|
|
281
|
+
locale
|
|
282
|
+
} = useLocaleContext();
|
|
283
|
+
const object = useMemo(
|
|
284
|
+
() => ({
|
|
285
|
+
...target,
|
|
286
|
+
link: window.location.href
|
|
287
|
+
}),
|
|
288
|
+
[target]
|
|
289
|
+
);
|
|
290
|
+
const _prefix = prefix || getPrefix();
|
|
291
|
+
if (!_prefix) {
|
|
292
|
+
throw new Error("prefix is required.");
|
|
293
|
+
}
|
|
294
|
+
const wsClient = getWsClient(_prefix);
|
|
295
|
+
useEffect(() => {
|
|
296
|
+
wsClient.connect();
|
|
297
|
+
return () => {
|
|
298
|
+
if (wsClient.isConnected()) {
|
|
299
|
+
wsClient.disconnect();
|
|
300
|
+
}
|
|
301
|
+
};
|
|
302
|
+
}, []);
|
|
303
|
+
api.defaults.baseURL = joinUrl(_prefix, "/api/");
|
|
304
|
+
return /* @__PURE__ */ jsx(ErrorBoundary, {
|
|
305
|
+
FallbackComponent: ErrorFallback,
|
|
306
|
+
children: /* @__PURE__ */ jsx(LocaleProvider, {
|
|
307
|
+
translations,
|
|
308
|
+
locale,
|
|
309
|
+
children: /* @__PURE__ */ jsx(InternalThemeProvider, {
|
|
310
|
+
children: /* @__PURE__ */ jsx(CommentsProvider, {
|
|
311
|
+
target: object,
|
|
312
|
+
api: commentAPI,
|
|
313
|
+
flatView,
|
|
314
|
+
children: /* @__PURE__ */ jsx(DIDComment, {
|
|
315
|
+
...rest,
|
|
316
|
+
object
|
|
317
|
+
})
|
|
318
|
+
})
|
|
319
|
+
})
|
|
320
|
+
})
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
Wrapper.propTypes = {
|
|
324
|
+
target: PropTypes.shape({
|
|
325
|
+
id: PropTypes.string.isRequired,
|
|
326
|
+
title: PropTypes.string,
|
|
327
|
+
desc: PropTypes.string,
|
|
328
|
+
owner: PropTypes.string
|
|
329
|
+
}).isRequired,
|
|
330
|
+
showConnectBtn: PropTypes.bool,
|
|
331
|
+
onChange: PropTypes.func,
|
|
332
|
+
prefix: PropTypes.string,
|
|
333
|
+
flatView: PropTypes.bool
|
|
334
|
+
};
|
|
335
|
+
Wrapper.defaultProps = {
|
|
336
|
+
showConnectBtn: false,
|
|
337
|
+
onChange: () => {
|
|
338
|
+
},
|
|
339
|
+
prefix: "",
|
|
340
|
+
flatView: false
|
|
341
|
+
};
|
|
342
|
+
const Container = styled.div`
|
|
343
|
+
background-color: #fff;
|
|
344
|
+
width: 100%;
|
|
345
|
+
margin: 0 auto;
|
|
346
|
+
box-sizing: border-box;
|
|
347
|
+
padding: ${(props) => props.padding ? "20px" : "0"};
|
|
348
|
+
color: #25292f;
|
|
349
|
+
border: ${(props) => props.border ? "1px solid rgb(208, 215, 222)" : "none"};
|
|
350
|
+
border-radius: 6px;
|
|
351
|
+
.input-no-connect {
|
|
352
|
+
margin: 24px 0 0 0;
|
|
353
|
+
display: flex;
|
|
354
|
+
font-size: 16px;
|
|
355
|
+
width: 100%;
|
|
356
|
+
text-align: start;
|
|
357
|
+
word-break: break-all;
|
|
358
|
+
flex-direction: column;
|
|
359
|
+
.connect-tip {
|
|
360
|
+
background: #f2f3f5;
|
|
361
|
+
padding: 10px;
|
|
362
|
+
border-radius: 4px;
|
|
363
|
+
box-sizing: border-box;
|
|
364
|
+
color: #c4c5ca;
|
|
365
|
+
margin-bottom: 10px;
|
|
366
|
+
}
|
|
367
|
+
.down-load-wallet {
|
|
368
|
+
color: #6bbdfe;
|
|
369
|
+
}
|
|
370
|
+
@media (max-width: 768px) {
|
|
371
|
+
font-size: 14px;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
`;
|
|
375
|
+
export {
|
|
376
|
+
Wrapper as default
|
|
377
|
+
};
|
package/lib/es/hooks.js
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { useMemo, useRef, useEffect } from "react";
|
|
2
|
+
import useSetState from "react-use/lib/useSetState";
|
|
3
|
+
import uniqBy from "lodash/uniqBy";
|
|
4
|
+
import orderBy from "lodash/orderBy";
|
|
5
|
+
import Toast from "@arcblock/ux/lib/Toast";
|
|
6
|
+
import { fetchRatingStats, fetchMoreReplies, fetchComments } from "./api";
|
|
7
|
+
import { useSubscription } from "./ws";
|
|
8
|
+
const lastItem = (arr) => (arr == null ? void 0 : arr.length) ? arr[arr.length - 1] : null;
|
|
9
|
+
const getInitialState = () => ({
|
|
10
|
+
comments: [],
|
|
11
|
+
cursor: null,
|
|
12
|
+
total: 0,
|
|
13
|
+
initialized: false,
|
|
14
|
+
loading: true,
|
|
15
|
+
error: null,
|
|
16
|
+
rating: {},
|
|
17
|
+
sortType: localStorage.getItem("sortType") || "asc"
|
|
18
|
+
});
|
|
19
|
+
const useComments = ({ objectId, flatMode }, deps = []) => {
|
|
20
|
+
const [state, setState] = useSetState(getInitialState());
|
|
21
|
+
const commentsKeyById = useMemo(() => {
|
|
22
|
+
return state.comments.reduce((acc, cur) => {
|
|
23
|
+
var _a;
|
|
24
|
+
acc[cur.id] = cur;
|
|
25
|
+
if ((_a = cur.replies) == null ? void 0 : _a.length) {
|
|
26
|
+
cur.replies.forEach((item) => {
|
|
27
|
+
acc[item.id] = item;
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
return acc;
|
|
31
|
+
}, {});
|
|
32
|
+
}, [state]);
|
|
33
|
+
const hasMore = useMemo(() => !!state.cursor, [state]);
|
|
34
|
+
const fetchParamsRef = useRef({
|
|
35
|
+
objectId,
|
|
36
|
+
size: 12,
|
|
37
|
+
embed: "replies,rating",
|
|
38
|
+
...flatMode && { includeReplies: 1 }
|
|
39
|
+
});
|
|
40
|
+
const updateCommentList = () => {
|
|
41
|
+
setState({ comments: [...state.comments] });
|
|
42
|
+
};
|
|
43
|
+
const updateComment = (commentId, mapper) => {
|
|
44
|
+
const commentOrReply = commentsKeyById[commentId];
|
|
45
|
+
if (commentOrReply) {
|
|
46
|
+
const rootComment = commentsKeyById[commentOrReply.commentId];
|
|
47
|
+
if (!rootComment || flatMode) {
|
|
48
|
+
const index = state.comments.findIndex((item) => item.id === commentId);
|
|
49
|
+
if (index !== -1) {
|
|
50
|
+
state.comments[index] = mapper(state.comments[index]);
|
|
51
|
+
updateCommentList();
|
|
52
|
+
}
|
|
53
|
+
} else {
|
|
54
|
+
const index = rootComment.replies.findIndex((item) => item.id === commentId);
|
|
55
|
+
if (index !== -1) {
|
|
56
|
+
rootComment.replies[index] = mapper(rootComment.replies[index]);
|
|
57
|
+
updateComment(rootComment.id, (current) => ({
|
|
58
|
+
...current,
|
|
59
|
+
replies: [...rootComment.replies]
|
|
60
|
+
}));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
const addComment = (commentOrReply) => {
|
|
66
|
+
if (commentsKeyById[commentOrReply.id]) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
const rootComment = commentsKeyById[commentOrReply.commentId];
|
|
70
|
+
if (!rootComment || flatMode) {
|
|
71
|
+
const comments = uniqBy([...state.comments, commentOrReply], "id");
|
|
72
|
+
setState({ comments: orderBy(comments, ["createdAt"], [state.sortType]), total: state.total + 1 });
|
|
73
|
+
} else {
|
|
74
|
+
updateComment(rootComment.id, (current) => {
|
|
75
|
+
var _a;
|
|
76
|
+
const replies = uniqBy([...rootComment.replies || [], commentOrReply], "id");
|
|
77
|
+
const newComment = {
|
|
78
|
+
...current,
|
|
79
|
+
replies: orderBy(replies, ["createdAt"], ["asc"]),
|
|
80
|
+
totalReplies: (current.totalReplies || 0) + 1
|
|
81
|
+
};
|
|
82
|
+
if (!current.repliesCursor) {
|
|
83
|
+
newComment.repliesCursor = (_a = lastItem(current.replies)) == null ? void 0 : _a.createdAt;
|
|
84
|
+
}
|
|
85
|
+
return newComment;
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
const removeComment = (comment) => {
|
|
90
|
+
const isReply = comment.commentId;
|
|
91
|
+
if (isReply && !flatMode) {
|
|
92
|
+
updateComment(comment.commentId, (current) => {
|
|
93
|
+
return {
|
|
94
|
+
...current,
|
|
95
|
+
replies: (current.replies || []).map((item) => {
|
|
96
|
+
if (item.id === comment.id) {
|
|
97
|
+
return { ...item, deletedAt: new Date() };
|
|
98
|
+
}
|
|
99
|
+
return item;
|
|
100
|
+
})
|
|
101
|
+
};
|
|
102
|
+
});
|
|
103
|
+
} else {
|
|
104
|
+
updateComment(comment.id, (current) => {
|
|
105
|
+
return { ...current, deletedAt: new Date() };
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
const handlers = {
|
|
110
|
+
ADD_COMMENT: (data) => addComment(data),
|
|
111
|
+
RATING: async () => {
|
|
112
|
+
const rating = await fetchRatingStats(objectId);
|
|
113
|
+
setState({ rating });
|
|
114
|
+
},
|
|
115
|
+
RATING_COMMENT: async ({ commentId }) => {
|
|
116
|
+
const rating = await fetchRatingStats(commentId);
|
|
117
|
+
updateComment(commentId, (current) => ({
|
|
118
|
+
...current,
|
|
119
|
+
rating
|
|
120
|
+
}));
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
useSubscription(
|
|
124
|
+
objectId,
|
|
125
|
+
({ event, data }) => {
|
|
126
|
+
var _a;
|
|
127
|
+
(_a = handlers[event]) == null ? void 0 : _a.call(handlers, data);
|
|
128
|
+
},
|
|
129
|
+
[objectId, state]
|
|
130
|
+
);
|
|
131
|
+
const fetch = async () => {
|
|
132
|
+
try {
|
|
133
|
+
setState({ loading: true });
|
|
134
|
+
return fetchComments({ ...fetchParamsRef.current, order: state.sortType, cursor: state.cursor });
|
|
135
|
+
} catch (e) {
|
|
136
|
+
Toast.warning("Failed to load comments data.");
|
|
137
|
+
setState({ error: e });
|
|
138
|
+
return { comments: [], total: 0, cursor: null };
|
|
139
|
+
} finally {
|
|
140
|
+
setState({ loading: false });
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
const loadMore = async () => {
|
|
144
|
+
if (hasMore) {
|
|
145
|
+
const { data: comments, total, nextCursor } = await fetch();
|
|
146
|
+
const sorted = orderBy([...state.comments, ...comments], ["createdAt"], [state.sortType]);
|
|
147
|
+
setState({ comments: sorted, total, cursor: nextCursor });
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
const loadMoreReplies = async (commentId) => {
|
|
151
|
+
var _a;
|
|
152
|
+
const rootComment = commentsKeyById[commentId];
|
|
153
|
+
const cursor = rootComment.repliesCursor || ((_a = lastItem(rootComment.replies)) == null ? void 0 : _a.createdAt);
|
|
154
|
+
const data = await fetchMoreReplies({
|
|
155
|
+
commentId,
|
|
156
|
+
cursor,
|
|
157
|
+
embed: "rating"
|
|
158
|
+
});
|
|
159
|
+
const loadedReplies = data.data;
|
|
160
|
+
let replies = uniqBy([...rootComment.replies || [], ...loadedReplies || []], "id");
|
|
161
|
+
replies = orderBy(replies, ["createdAt"], ["asc"]);
|
|
162
|
+
updateComment(commentId, (current) => {
|
|
163
|
+
var _a2;
|
|
164
|
+
return {
|
|
165
|
+
...current,
|
|
166
|
+
replies,
|
|
167
|
+
totalReplies: data.total,
|
|
168
|
+
repliesCursor: (_a2 = lastItem(loadedReplies)) == null ? void 0 : _a2.createdAt
|
|
169
|
+
};
|
|
170
|
+
});
|
|
171
|
+
};
|
|
172
|
+
const sort = (sortType) => {
|
|
173
|
+
setState({ sortType, cursor: null });
|
|
174
|
+
localStorage.setItem("sortType", sortType);
|
|
175
|
+
};
|
|
176
|
+
useEffect(() => {
|
|
177
|
+
const init = async () => {
|
|
178
|
+
setState({ ...getInitialState(), initialized: false });
|
|
179
|
+
const [{ data: comments, total, nextCursor }, rating] = await Promise.all([fetch(), fetchRatingStats(objectId)]);
|
|
180
|
+
setState({ comments, total, cursor: nextCursor, rating, initialized: true });
|
|
181
|
+
};
|
|
182
|
+
init();
|
|
183
|
+
}, [objectId, state.sortType, ...deps || []]);
|
|
184
|
+
return {
|
|
185
|
+
...state,
|
|
186
|
+
hasMore,
|
|
187
|
+
loadMore,
|
|
188
|
+
sort,
|
|
189
|
+
addComment,
|
|
190
|
+
updateComment,
|
|
191
|
+
loadMoreReplies,
|
|
192
|
+
removeComment
|
|
193
|
+
};
|
|
194
|
+
};
|
|
195
|
+
export {
|
|
196
|
+
useComments
|
|
197
|
+
};
|
package/lib/es/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { default as default2 } from "./did-comment";
|
|
2
|
+
import { default as default3 } from "./did-comment-with-session";
|
|
3
|
+
import { default as default4 } from "./theme-provider";
|
|
4
|
+
export {
|
|
5
|
+
default2 as DIDComment,
|
|
6
|
+
default3 as DIDCommentWithSession,
|
|
7
|
+
default4 as ThemeProvider
|
|
8
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
const protectLogin = (session, action) => {
|
|
2
|
+
if (session.user) {
|
|
3
|
+
return action();
|
|
4
|
+
}
|
|
5
|
+
return new Promise((resolve) => {
|
|
6
|
+
session.login(() => resolve(action()));
|
|
7
|
+
});
|
|
8
|
+
};
|
|
9
|
+
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
10
|
+
const minDelay = (promise, ms) => {
|
|
11
|
+
return Promise.all([promise, sleep(ms)]).then(([result]) => result);
|
|
12
|
+
};
|
|
13
|
+
export {
|
|
14
|
+
minDelay,
|
|
15
|
+
protectLogin,
|
|
16
|
+
sleep
|
|
17
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import flat from "flat";
|
|
2
|
+
const en = flat({
|
|
3
|
+
comments: "Comments",
|
|
4
|
+
comment: "Comment",
|
|
5
|
+
poweredBy: "- powered by DID Comments",
|
|
6
|
+
connect: "Connect",
|
|
7
|
+
inputPlaceHolder: "Write a comment",
|
|
8
|
+
oldest: "Oldest",
|
|
9
|
+
newest: "Newest",
|
|
10
|
+
loadMore: "Click To Load More",
|
|
11
|
+
connectDIDWallet: "Please connect DID Wallet.",
|
|
12
|
+
installDIDWallet: "Click to get your own DID Wallet\u2192",
|
|
13
|
+
empty: "Be the first to leave a comment.",
|
|
14
|
+
delete: "Delete",
|
|
15
|
+
edit: "Edit",
|
|
16
|
+
confirm: "Confirm",
|
|
17
|
+
cancel: "Cancel",
|
|
18
|
+
tip: "Tip",
|
|
19
|
+
deleteCommentDesc: "Confirm delete this comment?",
|
|
20
|
+
readMore: "Read more",
|
|
21
|
+
showMoreReplies: "Show more replies",
|
|
22
|
+
deleted: "This comment has been deleted"
|
|
23
|
+
});
|
|
24
|
+
export {
|
|
25
|
+
en as default
|
|
26
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import flat from "flat";
|
|
2
|
+
const zh = flat({
|
|
3
|
+
comments: "\u6761\u8BC4\u8BBA",
|
|
4
|
+
comment: "\u8BC4\u8BBA",
|
|
5
|
+
poweredBy: "- \u7531 DID Comments \u63D0\u4F9B\u652F\u6301",
|
|
6
|
+
connect: "\u8FDE\u63A5",
|
|
7
|
+
inputPlaceHolder: "\u5199\u8BC4\u8BBA",
|
|
8
|
+
oldest: "\u6700\u65E7",
|
|
9
|
+
newest: "\u6700\u65B0",
|
|
10
|
+
loadMore: "\u70B9\u51FB\u52A0\u8F7D\u66F4\u591A",
|
|
11
|
+
connectDIDWallet: "\u8BF7\u5148\u8FDE\u63A5 DID Wallet.",
|
|
12
|
+
installDIDWallet: "\u70B9\u51FB\u62E5\u6709\u4F60\u7684 DID Wallet\u2192",
|
|
13
|
+
empty: "\u6210\u4E3A\u7B2C\u4E00\u4E2A\u7559\u4E0B\u8BC4\u8BBA\u7684\u4EBA.",
|
|
14
|
+
delete: "\u5220\u9664",
|
|
15
|
+
edit: "\u7F16\u8F91",
|
|
16
|
+
confirm: "\u786E\u8BA4",
|
|
17
|
+
cancel: "\u53D6\u6D88",
|
|
18
|
+
tip: "\u63D0\u793A",
|
|
19
|
+
deleteCommentDesc: "\u786E\u8BA4\u5220\u9664\u8FD9\u6761\u8BC4\u8BBA?",
|
|
20
|
+
readMore: "\u66F4\u591A\u5185\u5BB9",
|
|
21
|
+
showMoreReplies: "\u663E\u793A\u66F4\u591A\u56DE\u590D",
|
|
22
|
+
deleted: "\u8BE5\u8BC4\u8BBA\u5DF2\u88AB\u5220\u9664"
|
|
23
|
+
});
|
|
24
|
+
export {
|
|
25
|
+
zh as default
|
|
26
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { useContext } from "react";
|
|
2
|
+
import { createAuthServiceSessionContext } from "@arcblock/did-connect/lib/Session";
|
|
3
|
+
const { SessionProvider, SessionContext, SessionConsumer, withSession } = createAuthServiceSessionContext();
|
|
4
|
+
function useSessionContext() {
|
|
5
|
+
const data = useContext(SessionContext);
|
|
6
|
+
return data;
|
|
7
|
+
}
|
|
8
|
+
export {
|
|
9
|
+
SessionConsumer,
|
|
10
|
+
SessionContext,
|
|
11
|
+
SessionProvider,
|
|
12
|
+
useSessionContext,
|
|
13
|
+
withSession
|
|
14
|
+
};
|