@droppii-org/chat-mobile 0.2.109 → 0.2.110
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/module/screens/chat-detail/ChatDetail.js +42 -7
- package/lib/module/screens/chat-detail/ChatDetail.js.map +1 -1
- package/lib/module/screens/chat-detail/ChatListLegend.js +249 -49
- package/lib/module/screens/chat-detail/ChatListLegend.js.map +1 -1
- package/lib/module/screens/chat-detail/hooks/createUnreadMarkReadGate.js +32 -0
- package/lib/module/screens/chat-detail/hooks/createUnreadMarkReadGate.js.map +1 -0
- package/lib/module/screens/chat-detail/hooks/useMarkConversationRead.js +180 -0
- package/lib/module/screens/chat-detail/hooks/useMarkConversationRead.js.map +1 -0
- package/lib/module/screens/chat-detail/hooks/useUnreadAnchorSeen.js +88 -0
- package/lib/module/screens/chat-detail/hooks/useUnreadAnchorSeen.js.map +1 -0
- package/lib/module/screens/chat-detail/hooks/useUnreadDeeplinkCheck.js +59 -0
- package/lib/module/screens/chat-detail/hooks/useUnreadDeeplinkCheck.js.map +1 -0
- package/lib/module/screens/chat-detail/hooks/useUnreadIndicator.js +105 -0
- package/lib/module/screens/chat-detail/hooks/useUnreadIndicator.js.map +1 -0
- package/lib/module/screens/chat-detail/hooks/useUnreadIndicatorInList.js +157 -0
- package/lib/module/screens/chat-detail/hooks/useUnreadIndicatorInList.js.map +1 -0
- package/lib/module/screens/chat-detail/legend/LegendChatUnreadButton.js +140 -0
- package/lib/module/screens/chat-detail/legend/LegendChatUnreadButton.js.map +1 -0
- package/lib/module/screens/chat-detail/legend/LegendChatUnreadDivider.js +51 -0
- package/lib/module/screens/chat-detail/legend/LegendChatUnreadDivider.js.map +1 -0
- package/lib/module/services/message.js +30 -0
- package/lib/module/services/message.js.map +1 -1
- package/lib/module/store/message.js +25 -4
- package/lib/module/store/message.js.map +1 -1
- package/lib/module/store/unreadIndicator.js +26 -0
- package/lib/module/store/unreadIndicator.js.map +1 -0
- package/lib/module/translation/resources/i18n.js +2 -0
- package/lib/module/translation/resources/i18n.js.map +1 -1
- package/lib/module/types/chat.js.map +1 -1
- package/lib/module/types/unreadIndicator.js +2 -0
- package/lib/module/types/unreadIndicator.js.map +1 -0
- package/lib/module/utils/markReadPolicy.js +25 -0
- package/lib/module/utils/markReadPolicy.js.map +1 -0
- package/lib/module/utils/promise.js +16 -0
- package/lib/module/utils/promise.js.map +1 -1
- package/lib/module/utils/unreadAnchor.js +57 -0
- package/lib/module/utils/unreadAnchor.js.map +1 -0
- package/lib/module/utils/unreadIndicatorState.js +96 -0
- package/lib/module/utils/unreadIndicatorState.js.map +1 -0
- package/lib/typescript/src/screens/chat-detail/ChatDetail.d.ts.map +1 -1
- package/lib/typescript/src/screens/chat-detail/ChatListLegend.d.ts +4 -1
- package/lib/typescript/src/screens/chat-detail/ChatListLegend.d.ts.map +1 -1
- package/lib/typescript/src/screens/chat-detail/hooks/createUnreadMarkReadGate.d.ts +9 -0
- package/lib/typescript/src/screens/chat-detail/hooks/createUnreadMarkReadGate.d.ts.map +1 -0
- package/lib/typescript/src/screens/chat-detail/hooks/useMarkConversationRead.d.ts +39 -0
- package/lib/typescript/src/screens/chat-detail/hooks/useMarkConversationRead.d.ts.map +1 -0
- package/lib/typescript/src/screens/chat-detail/hooks/useUnreadAnchorSeen.d.ts +26 -0
- package/lib/typescript/src/screens/chat-detail/hooks/useUnreadAnchorSeen.d.ts.map +1 -0
- package/lib/typescript/src/screens/chat-detail/hooks/useUnreadDeeplinkCheck.d.ts +17 -0
- package/lib/typescript/src/screens/chat-detail/hooks/useUnreadDeeplinkCheck.d.ts.map +1 -0
- package/lib/typescript/src/screens/chat-detail/hooks/useUnreadIndicator.d.ts +21 -0
- package/lib/typescript/src/screens/chat-detail/hooks/useUnreadIndicator.d.ts.map +1 -0
- package/lib/typescript/src/screens/chat-detail/hooks/useUnreadIndicatorInList.d.ts +35 -0
- package/lib/typescript/src/screens/chat-detail/hooks/useUnreadIndicatorInList.d.ts.map +1 -0
- package/lib/typescript/src/screens/chat-detail/legend/LegendChatUnreadButton.d.ts +8 -0
- package/lib/typescript/src/screens/chat-detail/legend/LegendChatUnreadButton.d.ts.map +1 -0
- package/lib/typescript/src/screens/chat-detail/legend/LegendChatUnreadDivider.d.ts +7 -0
- package/lib/typescript/src/screens/chat-detail/legend/LegendChatUnreadDivider.d.ts.map +1 -0
- package/lib/typescript/src/services/message.d.ts +8 -0
- package/lib/typescript/src/services/message.d.ts.map +1 -1
- package/lib/typescript/src/store/message.d.ts.map +1 -1
- package/lib/typescript/src/store/unreadIndicator.d.ts +10 -0
- package/lib/typescript/src/store/unreadIndicator.d.ts.map +1 -0
- package/lib/typescript/src/translation/resources/i18n.d.ts.map +1 -1
- package/lib/typescript/src/types/chat.d.ts +3 -0
- package/lib/typescript/src/types/chat.d.ts.map +1 -1
- package/lib/typescript/src/types/events.d.ts +17 -1
- package/lib/typescript/src/types/events.d.ts.map +1 -1
- package/lib/typescript/src/types/unreadIndicator.d.ts +45 -0
- package/lib/typescript/src/types/unreadIndicator.d.ts.map +1 -0
- package/lib/typescript/src/utils/markReadPolicy.d.ts +27 -0
- package/lib/typescript/src/utils/markReadPolicy.d.ts.map +1 -0
- package/lib/typescript/src/utils/promise.d.ts +6 -0
- package/lib/typescript/src/utils/promise.d.ts.map +1 -1
- package/lib/typescript/src/utils/unreadAnchor.d.ts +33 -0
- package/lib/typescript/src/utils/unreadAnchor.d.ts.map +1 -0
- package/lib/typescript/src/utils/unreadIndicatorState.d.ts +26 -0
- package/lib/typescript/src/utils/unreadIndicatorState.d.ts.map +1 -0
- package/package.json +2 -2
- package/src/screens/chat-detail/ChatDetail.tsx +58 -5
- package/src/screens/chat-detail/ChatListLegend.tsx +314 -46
- package/src/screens/chat-detail/hooks/createUnreadMarkReadGate.ts +41 -0
- package/src/screens/chat-detail/hooks/useMarkConversationRead.ts +197 -0
- package/src/screens/chat-detail/hooks/useUnreadAnchorSeen.ts +105 -0
- package/src/screens/chat-detail/hooks/useUnreadDeeplinkCheck.ts +68 -0
- package/src/screens/chat-detail/hooks/useUnreadIndicator.ts +112 -0
- package/src/screens/chat-detail/hooks/useUnreadIndicatorInList.ts +181 -0
- package/src/screens/chat-detail/legend/LegendChatUnreadButton.tsx +165 -0
- package/src/screens/chat-detail/legend/LegendChatUnreadDivider.tsx +52 -0
- package/src/services/message.ts +42 -0
- package/src/store/message.ts +23 -5
- package/src/store/unreadIndicator.ts +38 -0
- package/src/translation/resources/i18n.ts +2 -0
- package/src/types/chat.ts +3 -0
- package/src/types/events.ts +18 -1
- package/src/types/unreadIndicator.ts +49 -0
- package/src/utils/markReadPolicy.ts +55 -0
- package/src/utils/promise.ts +20 -0
- package/src/utils/unreadAnchor.ts +87 -0
- package/src/utils/unreadIndicatorState.ts +131 -0
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
BeginUnreadSessionOptions,
|
|
3
|
+
UnreadAnchor,
|
|
4
|
+
UnreadIndicatorState,
|
|
5
|
+
} from '../types/unreadIndicator';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Pure transitions behind `useUnreadIndicatorStore` — kept free of React and
|
|
9
|
+
* zustand so they can be unit-tested. Every transition after `begin` is
|
|
10
|
+
* token-scoped: a token that isn't the current session's leaves the state
|
|
11
|
+
* untouched (same reference).
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
// Slack past the lookup timeout before the gate treats itself as open even if
|
|
15
|
+
// `resolve` never ran.
|
|
16
|
+
export const UNREAD_GATE_WATCHDOG_SLACK_MS = 500;
|
|
17
|
+
|
|
18
|
+
export const INITIAL_UNREAD_INDICATOR_STATE: UnreadIndicatorState = {
|
|
19
|
+
token: 0,
|
|
20
|
+
routeKey: undefined,
|
|
21
|
+
conversationId: undefined,
|
|
22
|
+
pending: false,
|
|
23
|
+
pendingSince: 0,
|
|
24
|
+
anchor: null,
|
|
25
|
+
pillDismissed: false,
|
|
26
|
+
awaitingDeeplinkCheck: false,
|
|
27
|
+
settledBy: null,
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const isMine = (s: UnreadIndicatorState, token: number) => token === s.token;
|
|
31
|
+
|
|
32
|
+
export const beginUnreadSession = (
|
|
33
|
+
s: UnreadIndicatorState,
|
|
34
|
+
{
|
|
35
|
+
routeKey,
|
|
36
|
+
conversationId,
|
|
37
|
+
skip,
|
|
38
|
+
awaitDeeplinkCheck,
|
|
39
|
+
}: BeginUnreadSessionOptions,
|
|
40
|
+
now: number
|
|
41
|
+
): UnreadIndicatorState => ({
|
|
42
|
+
...INITIAL_UNREAD_INDICATOR_STATE,
|
|
43
|
+
token: s.token + 1,
|
|
44
|
+
routeKey,
|
|
45
|
+
conversationId,
|
|
46
|
+
pending: !skip,
|
|
47
|
+
pendingSince: skip ? 0 : now,
|
|
48
|
+
awaitingDeeplinkCheck: !skip && awaitDeeplinkCheck,
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
export const resolveUnreadSession = (
|
|
52
|
+
s: UnreadIndicatorState,
|
|
53
|
+
token: number,
|
|
54
|
+
anchor: UnreadAnchor | null
|
|
55
|
+
): UnreadIndicatorState =>
|
|
56
|
+
!isMine(s, token) || !s.pending
|
|
57
|
+
? s
|
|
58
|
+
: { ...s, pending: false, anchor, settledBy: 'resolve' };
|
|
59
|
+
|
|
60
|
+
// Doesn't bump the token: a late `resolve` is already ignored because
|
|
61
|
+
// `pending` is false. Only a new `begin` (a new visit) bumps it.
|
|
62
|
+
export const clearUnreadSession = (
|
|
63
|
+
s: UnreadIndicatorState,
|
|
64
|
+
token: number
|
|
65
|
+
): UnreadIndicatorState =>
|
|
66
|
+
!isMine(s, token)
|
|
67
|
+
? s
|
|
68
|
+
: {
|
|
69
|
+
...s,
|
|
70
|
+
pending: false,
|
|
71
|
+
anchor: null,
|
|
72
|
+
pillDismissed: true,
|
|
73
|
+
awaitingDeeplinkCheck: false,
|
|
74
|
+
settledBy: 'clear',
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
export const dismissUnreadPill = (
|
|
78
|
+
s: UnreadIndicatorState,
|
|
79
|
+
token: number
|
|
80
|
+
): UnreadIndicatorState =>
|
|
81
|
+
!isMine(s, token) || s.pillDismissed ? s : { ...s, pillDismissed: true };
|
|
82
|
+
|
|
83
|
+
export const confirmUnreadDeeplinkCheck = (
|
|
84
|
+
s: UnreadIndicatorState,
|
|
85
|
+
token: number,
|
|
86
|
+
hide: boolean
|
|
87
|
+
): UnreadIndicatorState => {
|
|
88
|
+
if (!isMine(s, token)) return s;
|
|
89
|
+
// Not a clear: the user is still on the screen, so it must not trigger
|
|
90
|
+
// the leave flush that a blur's clear does.
|
|
91
|
+
if (hide) return { ...clearUnreadSession(s, token), settledBy: 'hide' };
|
|
92
|
+
return s.awaitingDeeplinkCheck ? { ...s, awaitingDeeplinkCheck: false } : s;
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
export const rearmUnreadDeeplinkCheck = (
|
|
96
|
+
s: UnreadIndicatorState,
|
|
97
|
+
token: number
|
|
98
|
+
): UnreadIndicatorState =>
|
|
99
|
+
!isMine(s, token) || !s.anchor || s.awaitingDeeplinkCheck
|
|
100
|
+
? s
|
|
101
|
+
: { ...s, awaitingDeeplinkCheck: true };
|
|
102
|
+
|
|
103
|
+
export const resetUnreadSession = (
|
|
104
|
+
s: UnreadIndicatorState
|
|
105
|
+
): UnreadIndicatorState => ({
|
|
106
|
+
...INITIAL_UNREAD_INDICATOR_STATE,
|
|
107
|
+
token: s.token + 1,
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
/** When the watchdog opens a still-pending gate on its own. */
|
|
111
|
+
export const getUnreadGateDeadline = (
|
|
112
|
+
s: UnreadIndicatorState,
|
|
113
|
+
timeoutMs: number
|
|
114
|
+
): number => s.pendingSince + timeoutMs + UNREAD_GATE_WATCHDOG_SLACK_MS;
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Whether mark-read must wait. Closed only for MY session while its lookup is
|
|
118
|
+
* still pending and within the watchdog deadline. No session yet (not focused,
|
|
119
|
+
* or access not confirmed) is fail-closed; a session superseded by another
|
|
120
|
+
* visit is not this screen's gate.
|
|
121
|
+
*/
|
|
122
|
+
export const isUnreadGateClosed = (
|
|
123
|
+
s: UnreadIndicatorState,
|
|
124
|
+
myToken: number | null,
|
|
125
|
+
now: number,
|
|
126
|
+
timeoutMs: number
|
|
127
|
+
): boolean => {
|
|
128
|
+
if (myToken == null) return true;
|
|
129
|
+
if (!isMine(s, myToken)) return false;
|
|
130
|
+
return s.pending && now <= getUnreadGateDeadline(s, timeoutMs);
|
|
131
|
+
};
|