@poolse/react 2.0.12 → 2.1.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/dist/index.cjs +87 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +40 -3
- package/dist/index.d.ts +40 -3
- package/dist/index.js +84 -8
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -316,6 +316,7 @@ function useMessages(conversationId) {
|
|
|
316
316
|
const [error, setError] = react.useState(null);
|
|
317
317
|
const [hasMore, setHasMore] = react.useState(true);
|
|
318
318
|
const oldestSequenceRef = react.useRef(null);
|
|
319
|
+
const refetchRef = react.useRef(null);
|
|
319
320
|
const meIdRef = react.useRef(me?.id ?? null);
|
|
320
321
|
meIdRef.current = me?.id ?? null;
|
|
321
322
|
const meExternalIdRef = react.useRef(me?.external_id ?? null);
|
|
@@ -340,6 +341,13 @@ function useMessages(conversationId) {
|
|
|
340
341
|
setError(err instanceof Error ? err : new Error(String(err)));
|
|
341
342
|
setLoading(false);
|
|
342
343
|
});
|
|
344
|
+
refetchRef.current = async () => {
|
|
345
|
+
const page = await handle.list({ limit: PAGE_SIZE });
|
|
346
|
+
const ordered = [...page.data].reverse();
|
|
347
|
+
setMessages(ordered);
|
|
348
|
+
setHasMore(page.data.length === PAGE_SIZE);
|
|
349
|
+
oldestSequenceRef.current = ordered[0]?.sequence ?? null;
|
|
350
|
+
};
|
|
343
351
|
const conv = chat.realtime.conversation(conversationId);
|
|
344
352
|
const offNew = conv.onMessage((msg) => {
|
|
345
353
|
if (msg.thread_root_id) {
|
|
@@ -489,6 +497,11 @@ function useMessages(conversationId) {
|
|
|
489
497
|
},
|
|
490
498
|
[chat, conversationId]
|
|
491
499
|
);
|
|
500
|
+
const refetch = react.useCallback(async () => {
|
|
501
|
+
const fn = refetchRef.current;
|
|
502
|
+
if (!fn) return;
|
|
503
|
+
await fn();
|
|
504
|
+
}, []);
|
|
492
505
|
return {
|
|
493
506
|
messages,
|
|
494
507
|
loading,
|
|
@@ -498,7 +511,8 @@ function useMessages(conversationId) {
|
|
|
498
511
|
send,
|
|
499
512
|
edit,
|
|
500
513
|
delete: deleteMessage,
|
|
501
|
-
markReadUpTo
|
|
514
|
+
markReadUpTo,
|
|
515
|
+
refetch
|
|
502
516
|
};
|
|
503
517
|
}
|
|
504
518
|
function upsertById(prev, msg) {
|
|
@@ -735,6 +749,7 @@ function upsertById2(prev, msg) {
|
|
|
735
749
|
next[idx] = msg;
|
|
736
750
|
return next;
|
|
737
751
|
}
|
|
752
|
+
var TYPING_TIMEOUT_MS = 4e3;
|
|
738
753
|
function useTyping(conversationId) {
|
|
739
754
|
const chat = usePoolse();
|
|
740
755
|
const { me } = useMe();
|
|
@@ -744,11 +759,31 @@ function useTyping(conversationId) {
|
|
|
744
759
|
meExtRef.current = me?.external_id ?? null;
|
|
745
760
|
react.useEffect(() => {
|
|
746
761
|
setTyping(/* @__PURE__ */ new Set());
|
|
762
|
+
const timers = /* @__PURE__ */ new Map();
|
|
763
|
+
const evict = (ext) => {
|
|
764
|
+
const t = timers.get(ext);
|
|
765
|
+
if (t) {
|
|
766
|
+
clearTimeout(t);
|
|
767
|
+
timers.delete(ext);
|
|
768
|
+
}
|
|
769
|
+
setTyping((prev) => {
|
|
770
|
+
if (!prev.has(ext)) return prev;
|
|
771
|
+
const next = new Set(prev);
|
|
772
|
+
next.delete(ext);
|
|
773
|
+
return next;
|
|
774
|
+
});
|
|
775
|
+
};
|
|
747
776
|
const conv = chat.realtime.conversation(conversationId);
|
|
748
777
|
const offStart = conv.onTypingStart((evt) => {
|
|
749
778
|
const ext = evt.external_id;
|
|
750
779
|
if (!ext) return;
|
|
751
780
|
if (meExtRef.current && ext === meExtRef.current) return;
|
|
781
|
+
const existing = timers.get(ext);
|
|
782
|
+
if (existing) clearTimeout(existing);
|
|
783
|
+
timers.set(
|
|
784
|
+
ext,
|
|
785
|
+
setTimeout(() => evict(ext), TYPING_TIMEOUT_MS)
|
|
786
|
+
);
|
|
752
787
|
setTyping((prev) => {
|
|
753
788
|
if (prev.has(ext)) return prev;
|
|
754
789
|
const next = new Set(prev);
|
|
@@ -760,16 +795,20 @@ function useTyping(conversationId) {
|
|
|
760
795
|
const ext = evt.external_id;
|
|
761
796
|
if (!ext) return;
|
|
762
797
|
if (meExtRef.current && ext === meExtRef.current) return;
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
798
|
+
evict(ext);
|
|
799
|
+
});
|
|
800
|
+
const offMessage = conv.onMessage((msg) => {
|
|
801
|
+
const ext = msg.sender_external_id;
|
|
802
|
+
if (!ext) return;
|
|
803
|
+
if (meExtRef.current && ext === meExtRef.current) return;
|
|
804
|
+
evict(ext);
|
|
769
805
|
});
|
|
770
806
|
return () => {
|
|
771
807
|
offStart();
|
|
772
808
|
offStop();
|
|
809
|
+
offMessage();
|
|
810
|
+
for (const t of timers.values()) clearTimeout(t);
|
|
811
|
+
timers.clear();
|
|
773
812
|
};
|
|
774
813
|
}, [chat, conversationId]);
|
|
775
814
|
const signalTyping = react.useCallback(() => {
|
|
@@ -986,6 +1025,43 @@ function useUser(externalId) {
|
|
|
986
1025
|
return state;
|
|
987
1026
|
}
|
|
988
1027
|
|
|
1028
|
+
// src/grouping.ts
|
|
1029
|
+
function computeGroupPosition(msg, prev, next, windowMs) {
|
|
1030
|
+
const continuesPrev = sameGroup(msg, prev, windowMs);
|
|
1031
|
+
const continuesNext = sameGroup(next, msg, windowMs);
|
|
1032
|
+
if (continuesPrev && continuesNext) return "middle";
|
|
1033
|
+
if (continuesPrev) return "last";
|
|
1034
|
+
if (continuesNext) return "first";
|
|
1035
|
+
return "standalone";
|
|
1036
|
+
}
|
|
1037
|
+
function sameGroup(a, b, windowMs) {
|
|
1038
|
+
if (!a || !b) return false;
|
|
1039
|
+
if (a.sender_id !== b.sender_id) return false;
|
|
1040
|
+
if (!sameDay(a.inserted_at, b.inserted_at)) return false;
|
|
1041
|
+
const ta = new Date(a.inserted_at).getTime();
|
|
1042
|
+
const tb = new Date(b.inserted_at).getTime();
|
|
1043
|
+
return Math.abs(ta - tb) <= windowMs;
|
|
1044
|
+
}
|
|
1045
|
+
function sameDay(a, b) {
|
|
1046
|
+
const da = new Date(a);
|
|
1047
|
+
const db = new Date(b);
|
|
1048
|
+
return da.getFullYear() === db.getFullYear() && da.getMonth() === db.getMonth() && da.getDate() === db.getDate();
|
|
1049
|
+
}
|
|
1050
|
+
function formatDayLabel(iso, now = /* @__PURE__ */ new Date()) {
|
|
1051
|
+
const d = new Date(iso);
|
|
1052
|
+
const startOfDay = (x) => new Date(x.getFullYear(), x.getMonth(), x.getDate()).getTime();
|
|
1053
|
+
const diffDays = Math.floor((startOfDay(now) - startOfDay(d)) / 864e5);
|
|
1054
|
+
if (diffDays === 0) return "Today";
|
|
1055
|
+
if (diffDays === 1) return "Yesterday";
|
|
1056
|
+
if (diffDays < 7) {
|
|
1057
|
+
return d.toLocaleDateString(void 0, { weekday: "long" });
|
|
1058
|
+
}
|
|
1059
|
+
if (d.getFullYear() === now.getFullYear()) {
|
|
1060
|
+
return d.toLocaleDateString(void 0, { weekday: "short", day: "numeric", month: "short" });
|
|
1061
|
+
}
|
|
1062
|
+
return d.toLocaleDateString(void 0, { day: "numeric", month: "short", year: "numeric" });
|
|
1063
|
+
}
|
|
1064
|
+
|
|
989
1065
|
Object.defineProperty(exports, "ApiError", {
|
|
990
1066
|
enumerable: true,
|
|
991
1067
|
get: function () { return sdk.ApiError; }
|
|
@@ -1007,6 +1083,10 @@ Object.defineProperty(exports, "RateLimitedError", {
|
|
|
1007
1083
|
get: function () { return sdk.RateLimitedError; }
|
|
1008
1084
|
});
|
|
1009
1085
|
exports.PoolseProvider = PoolseProvider;
|
|
1086
|
+
exports.computeGroupPosition = computeGroupPosition;
|
|
1087
|
+
exports.formatDayLabel = formatDayLabel;
|
|
1088
|
+
exports.sameDay = sameDay;
|
|
1089
|
+
exports.sameGroup = sameGroup;
|
|
1010
1090
|
exports.useAttachmentUpload = useAttachmentUpload;
|
|
1011
1091
|
exports.useAttachmentUrl = useAttachmentUrl;
|
|
1012
1092
|
exports.useConversation = useConversation;
|