@codingfactory/socialkit-vue 0.7.0 → 0.7.3
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/dist/services/circles.d.ts.map +1 -1
- package/dist/services/circles.js +12 -1
- package/dist/services/circles.js.map +1 -1
- package/dist/stores/discussion.d.ts.map +1 -1
- package/dist/stores/discussion.js +121 -65
- package/dist/stores/discussion.js.map +1 -1
- package/package.json +4 -2
- package/src/services/circles.ts +13 -1
- package/src/stores/discussion.ts +151 -68
package/src/stores/discussion.ts
CHANGED
|
@@ -241,6 +241,7 @@ export function createDiscussionStoreDefinition(config: DiscussionStoreConfig) {
|
|
|
241
241
|
const threads = ref<Thread[]>([])
|
|
242
242
|
const currentThread = ref<Thread | null>(null)
|
|
243
243
|
const replies = ref<Reply[]>([])
|
|
244
|
+
const currentReplySort = ref<'best' | 'top' | 'new' | 'controversial'>('best')
|
|
244
245
|
|
|
245
246
|
const spacesLoadingState = createLoadingState()
|
|
246
247
|
const threadsLoadingState = createLoadingState()
|
|
@@ -322,6 +323,78 @@ export function createDiscussionStoreDefinition(config: DiscussionStoreConfig) {
|
|
|
322
323
|
}
|
|
323
324
|
}
|
|
324
325
|
|
|
326
|
+
function hasQuotedReplyBody(quotedReply: Reply['quoted_reply']): boolean {
|
|
327
|
+
return typeof quotedReply?.body === 'string' && quotedReply.body.trim().length > 0
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
function hasQuotedReplyAuthorName(quotedReply: Reply['quoted_reply']): boolean {
|
|
331
|
+
return typeof quotedReply?.author?.name === 'string' && quotedReply.author.name.trim().length > 0
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
function buildQuotedReplyFromReply(sourceReply: Reply | null | undefined): Reply['quoted_reply'] {
|
|
335
|
+
if (!sourceReply?.id || !sourceReply.author_id || typeof sourceReply.body !== 'string' || sourceReply.body.trim().length === 0) {
|
|
336
|
+
return null
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
return {
|
|
340
|
+
id: sourceReply.id,
|
|
341
|
+
author_id: sourceReply.author_id,
|
|
342
|
+
author: sourceReply.author
|
|
343
|
+
? {
|
|
344
|
+
id: sourceReply.author.id,
|
|
345
|
+
name: sourceReply.author.name,
|
|
346
|
+
...(sourceReply.author.handle ? { handle: sourceReply.author.handle } : {}),
|
|
347
|
+
}
|
|
348
|
+
: null,
|
|
349
|
+
body: sourceReply.body,
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
function resolveQuotedReply(reply: Reply, existingReply?: Reply | null): Reply['quoted_reply'] {
|
|
354
|
+
const quotedReplyId = typeof reply.quoted_reply_id === 'string'
|
|
355
|
+
? reply.quoted_reply_id.trim()
|
|
356
|
+
: ''
|
|
357
|
+
|
|
358
|
+
if (quotedReplyId.length === 0) {
|
|
359
|
+
return null
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
const incomingQuotedReply = reply.quoted_reply ?? null
|
|
363
|
+
if (hasQuotedReplyBody(incomingQuotedReply) && hasQuotedReplyAuthorName(incomingQuotedReply)) {
|
|
364
|
+
return incomingQuotedReply
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
const referencedReply = replies.value.find((candidate) => candidate.id === quotedReplyId)
|
|
368
|
+
const hydratedQuotedReply = buildQuotedReplyFromReply(referencedReply)
|
|
369
|
+
if (hydratedQuotedReply) {
|
|
370
|
+
return hydratedQuotedReply
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
const existingQuotedReply = existingReply?.quoted_reply ?? null
|
|
374
|
+
if (hasQuotedReplyBody(existingQuotedReply) && hasQuotedReplyAuthorName(existingQuotedReply)) {
|
|
375
|
+
return existingQuotedReply
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
return hasQuotedReplyBody(incomingQuotedReply) ? incomingQuotedReply : null
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
function normalizeReplyPayload(reply: Reply, existingReply?: Reply | null): Reply {
|
|
382
|
+
const normalized: Reply = { ...reply }
|
|
383
|
+
const hasQuotedReplyId = typeof normalized.quoted_reply_id === 'string'
|
|
384
|
+
&& normalized.quoted_reply_id.trim().length > 0
|
|
385
|
+
|
|
386
|
+
if (!hasQuotedReplyId) {
|
|
387
|
+
normalized.quoted_reply_id = null
|
|
388
|
+
normalized.quoted_reply = null
|
|
389
|
+
normalized.quote_data = null
|
|
390
|
+
return normalized
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
normalized.quoted_reply = resolveQuotedReply(normalized, existingReply)
|
|
394
|
+
|
|
395
|
+
return normalized
|
|
396
|
+
}
|
|
397
|
+
|
|
325
398
|
function mergeUniqueById<TItem extends { id: string }>(
|
|
326
399
|
existingItems: TItem[],
|
|
327
400
|
incomingItems: TItem[]
|
|
@@ -950,6 +1023,7 @@ export function createDiscussionStoreDefinition(config: DiscussionStoreConfig) {
|
|
|
950
1023
|
}
|
|
951
1024
|
|
|
952
1025
|
const filteredReplyBatch = filterOpeningReplies(loadedReplyBatch)
|
|
1026
|
+
currentReplySort.value = sortBy
|
|
953
1027
|
|
|
954
1028
|
if (cursor) {
|
|
955
1029
|
replies.value = mergeUniqueById(replies.value, filteredReplyBatch)
|
|
@@ -998,6 +1072,70 @@ export function createDiscussionStoreDefinition(config: DiscussionStoreConfig) {
|
|
|
998
1072
|
}
|
|
999
1073
|
}
|
|
1000
1074
|
|
|
1075
|
+
function insertTopLevelReply(reply: Reply): void {
|
|
1076
|
+
if (currentReplySort.value === 'new') {
|
|
1077
|
+
replies.value.unshift(reply)
|
|
1078
|
+
return
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
replies.value.push(reply)
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
function insertReplyIntoActiveThread(reply: Reply, parentReplyId?: string | null): boolean {
|
|
1085
|
+
const existingReplyIndex = replies.value.findIndex((candidate) => candidate.id === reply.id)
|
|
1086
|
+
|
|
1087
|
+
if (existingReplyIndex !== -1) {
|
|
1088
|
+
const existingReply = replies.value[existingReplyIndex]
|
|
1089
|
+
if (existingReply) {
|
|
1090
|
+
replies.value[existingReplyIndex] = {
|
|
1091
|
+
...existingReply,
|
|
1092
|
+
...reply,
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
return false
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
if (parentReplyId) {
|
|
1100
|
+
const parentIndex = replies.value.findIndex((candidate) => candidate.id === parentReplyId)
|
|
1101
|
+
if (parentIndex !== -1) {
|
|
1102
|
+
const parent = replies.value[parentIndex]
|
|
1103
|
+
const parentDepth = parent?.depth ?? parent?.display_depth ?? 0
|
|
1104
|
+
|
|
1105
|
+
reply.depth = parentDepth + 1
|
|
1106
|
+
reply.display_depth = parentDepth + 1
|
|
1107
|
+
reply.parent_reply_id = parentReplyId
|
|
1108
|
+
|
|
1109
|
+
let insertIndex = parentIndex + 1
|
|
1110
|
+
while (insertIndex < replies.value.length) {
|
|
1111
|
+
const nextReply = replies.value[insertIndex]
|
|
1112
|
+
const nextDepth = nextReply?.depth ?? nextReply?.display_depth ?? 0
|
|
1113
|
+
if (nextDepth <= parentDepth) {
|
|
1114
|
+
break
|
|
1115
|
+
}
|
|
1116
|
+
insertIndex += 1
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
replies.value.splice(insertIndex, 0, reply)
|
|
1120
|
+
|
|
1121
|
+
if (parent) {
|
|
1122
|
+
parent.reply_count = (parent.reply_count ?? 0) + 1
|
|
1123
|
+
parent.children_count = (parent.children_count ?? 0) + 1
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
return true
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1129
|
+
replies.value.push(reply)
|
|
1130
|
+
return true
|
|
1131
|
+
}
|
|
1132
|
+
|
|
1133
|
+
reply.depth = 0
|
|
1134
|
+
reply.display_depth = 0
|
|
1135
|
+
insertTopLevelReply(reply)
|
|
1136
|
+
return true
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1001
1139
|
async function createThread(
|
|
1002
1140
|
spaceSlug: string,
|
|
1003
1141
|
input: CreateThreadInput
|
|
@@ -1144,7 +1282,8 @@ export function createDiscussionStoreDefinition(config: DiscussionStoreConfig) {
|
|
|
1144
1282
|
})
|
|
1145
1283
|
|
|
1146
1284
|
const responseData = toRecord(response.data)
|
|
1147
|
-
const
|
|
1285
|
+
const createdReply = (responseData?.data ?? null) as Reply | null
|
|
1286
|
+
const newReply = createdReply ? normalizeReplyPayload(createdReply) : null
|
|
1148
1287
|
|
|
1149
1288
|
if (newReply?.id) {
|
|
1150
1289
|
locallyCreatedReplyIds.add(newReply.id)
|
|
@@ -1153,52 +1292,7 @@ export function createDiscussionStoreDefinition(config: DiscussionStoreConfig) {
|
|
|
1153
1292
|
let didInsertReply = false
|
|
1154
1293
|
|
|
1155
1294
|
if (newReply) {
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
if (existingReplyIndex !== -1) {
|
|
1159
|
-
const existingReply = replies.value[existingReplyIndex]
|
|
1160
|
-
if (existingReply) {
|
|
1161
|
-
replies.value[existingReplyIndex] = {
|
|
1162
|
-
...existingReply,
|
|
1163
|
-
...newReply,
|
|
1164
|
-
}
|
|
1165
|
-
}
|
|
1166
|
-
} else if (input.parent_id) {
|
|
1167
|
-
const parentIndex = replies.value.findIndex((reply) => reply.id === input.parent_id)
|
|
1168
|
-
if (parentIndex !== -1) {
|
|
1169
|
-
const parent = replies.value[parentIndex]
|
|
1170
|
-
const parentDepth = parent?.depth ?? parent?.display_depth ?? 0
|
|
1171
|
-
newReply.depth = parentDepth + 1
|
|
1172
|
-
newReply.display_depth = parentDepth + 1
|
|
1173
|
-
newReply.parent_reply_id = input.parent_id
|
|
1174
|
-
|
|
1175
|
-
let insertIndex = parentIndex + 1
|
|
1176
|
-
while (insertIndex < replies.value.length) {
|
|
1177
|
-
const reply = replies.value[insertIndex]
|
|
1178
|
-
const replyDepth = reply?.depth ?? reply?.display_depth ?? 0
|
|
1179
|
-
if (replyDepth <= parentDepth) {
|
|
1180
|
-
break
|
|
1181
|
-
}
|
|
1182
|
-
insertIndex += 1
|
|
1183
|
-
}
|
|
1184
|
-
|
|
1185
|
-
replies.value.splice(insertIndex, 0, newReply)
|
|
1186
|
-
didInsertReply = true
|
|
1187
|
-
|
|
1188
|
-
if (parent) {
|
|
1189
|
-
parent.reply_count = (parent.reply_count ?? 0) + 1
|
|
1190
|
-
parent.children_count = (parent.children_count ?? 0) + 1
|
|
1191
|
-
}
|
|
1192
|
-
} else {
|
|
1193
|
-
replies.value.push(newReply)
|
|
1194
|
-
didInsertReply = true
|
|
1195
|
-
}
|
|
1196
|
-
} else {
|
|
1197
|
-
newReply.depth = 0
|
|
1198
|
-
newReply.display_depth = 0
|
|
1199
|
-
replies.value.push(newReply)
|
|
1200
|
-
didInsertReply = true
|
|
1201
|
-
}
|
|
1295
|
+
didInsertReply = insertReplyIntoActiveThread(newReply, input.parent_id)
|
|
1202
1296
|
}
|
|
1203
1297
|
|
|
1204
1298
|
if (didInsertReply && currentThread.value?.id === threadId) {
|
|
@@ -1380,29 +1474,18 @@ export function createDiscussionStoreDefinition(config: DiscussionStoreConfig) {
|
|
|
1380
1474
|
return
|
|
1381
1475
|
}
|
|
1382
1476
|
|
|
1383
|
-
const
|
|
1384
|
-
|
|
1477
|
+
const existingReply = replies.value.find((candidate) => candidate.id === payload.id) ?? null
|
|
1478
|
+
const normalizedPayload = normalizeReplyPayload(payload, existingReply)
|
|
1385
1479
|
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
normalized.quoted_reply = null
|
|
1391
|
-
normalized.quote_data = null
|
|
1392
|
-
}
|
|
1393
|
-
|
|
1394
|
-
return normalized
|
|
1395
|
-
})()
|
|
1480
|
+
const didInsertReply = insertReplyIntoActiveThread(
|
|
1481
|
+
normalizedPayload,
|
|
1482
|
+
normalizedPayload.parent_reply_id ?? null
|
|
1483
|
+
)
|
|
1396
1484
|
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
if (currentThread.value && payload.id && !realtimeCountedReplyIds.has(payload.id)) {
|
|
1402
|
-
realtimeCountedReplyIds.add(payload.id)
|
|
1403
|
-
currentThread.value.reply_count = (currentThread.value.reply_count || 0) + 1
|
|
1404
|
-
currentThread.value.last_activity_at = payload.created_at ?? new Date().toISOString()
|
|
1405
|
-
}
|
|
1485
|
+
if (didInsertReply && currentThread.value && payload.id && !realtimeCountedReplyIds.has(payload.id)) {
|
|
1486
|
+
realtimeCountedReplyIds.add(payload.id)
|
|
1487
|
+
currentThread.value.reply_count = (currentThread.value.reply_count || 0) + 1
|
|
1488
|
+
currentThread.value.last_activity_at = payload.created_at ?? new Date().toISOString()
|
|
1406
1489
|
}
|
|
1407
1490
|
}
|
|
1408
1491
|
|