@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 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
- setTyping((prev) => {
764
- if (!prev.has(ext)) return prev;
765
- const next = new Set(prev);
766
- next.delete(ext);
767
- return next;
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;