@planningcenter/chat-react-native 3.21.0-rc.0 → 3.21.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/build/hooks/use_conversation_jolt_events.d.ts.map +1 -1
- package/build/hooks/use_conversation_jolt_events.js +29 -6
- package/build/hooks/use_conversation_jolt_events.js.map +1 -1
- package/build/hooks/use_conversations_actions.js +1 -1
- package/build/hooks/use_conversations_actions.js.map +1 -1
- package/build/hooks/use_mark_latest_message_read.d.ts.map +1 -1
- package/build/hooks/use_mark_latest_message_read.js +10 -21
- package/build/hooks/use_mark_latest_message_read.js.map +1 -1
- package/build/types/resources/conversation.d.ts +1 -0
- package/build/types/resources/conversation.d.ts.map +1 -1
- package/build/types/resources/conversation.js.map +1 -1
- package/package.json +2 -2
- package/src/hooks/use_conversation_jolt_events.ts +36 -8
- package/src/hooks/use_conversations_actions.ts +1 -1
- package/src/hooks/use_mark_latest_message_read.ts +15 -30
- package/src/types/resources/conversation.ts +1 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use_conversation_jolt_events.d.ts","sourceRoot":"","sources":["../../src/hooks/use_conversation_jolt_events.ts"],"names":[],"mappings":"AAWA,UAAU,KAAK;IACb,cAAc,EAAE,MAAM,CAAA;CACvB;AAED,wBAAgB,yBAAyB,CAAC,EAAE,cAAc,EAAE,EAAE,KAAK,
|
|
1
|
+
{"version":3,"file":"use_conversation_jolt_events.d.ts","sourceRoot":"","sources":["../../src/hooks/use_conversation_jolt_events.ts"],"names":[],"mappings":"AAWA,UAAU,KAAK;IACb,cAAc,EAAE,MAAM,CAAA;CACvB;AAED,wBAAgB,yBAAyB,CAAC,EAAE,cAAc,EAAE,EAAE,KAAK,QA8FlE"}
|
|
@@ -1,27 +1,28 @@
|
|
|
1
|
-
import { useJoltChannel, useJoltEvent } from './use_jolt';
|
|
2
|
-
import { getConversationRequestArgs } from './use_conversation';
|
|
3
1
|
import { useQueryClient } from '@tanstack/react-query';
|
|
4
|
-
import { getRequestQueryKey } from './use_suspense_api';
|
|
5
2
|
import { useCallback, useMemo } from 'react';
|
|
6
3
|
import { completeMessageCreationConversationTracking } from '../utils/performance_tracking';
|
|
7
|
-
import { useCurrentPerson } from './use_current_person';
|
|
8
4
|
import { useApiClient } from './use_api_client';
|
|
5
|
+
import { getConversationRequestArgs } from './use_conversation';
|
|
6
|
+
import { useCurrentPerson } from './use_current_person';
|
|
7
|
+
import { useJoltChannel, useJoltEvent } from './use_jolt';
|
|
8
|
+
import { getRequestQueryKey } from './use_suspense_api';
|
|
9
9
|
export function useConversationJoltEvents({ conversationId }) {
|
|
10
10
|
const joltChannel = useJoltChannel(`chat.conversations.${conversationId}`);
|
|
11
11
|
const queryClient = useQueryClient();
|
|
12
12
|
const currentPerson = useCurrentPerson();
|
|
13
|
+
const currentPersonId = currentPerson?.id;
|
|
13
14
|
const apiClient = useApiClient();
|
|
14
15
|
const queryKey = useMemo(() => getRequestQueryKey(getConversationRequestArgs({ conversation_id: conversationId })), [conversationId]);
|
|
15
16
|
const handleUpdatedConversation = useCallback((e) => {
|
|
16
17
|
const { last_message_idempotent_key, last_message_author_id } = e.data.data;
|
|
17
|
-
if (last_message_idempotent_key && last_message_author_id ===
|
|
18
|
+
if (last_message_idempotent_key && last_message_author_id === currentPersonId) {
|
|
18
19
|
completeMessageCreationConversationTracking({
|
|
19
20
|
apiClient,
|
|
20
21
|
idempotentKey: last_message_idempotent_key,
|
|
21
22
|
});
|
|
22
23
|
}
|
|
23
24
|
queryClient.invalidateQueries({ queryKey });
|
|
24
|
-
}, [queryClient, queryKey,
|
|
25
|
+
}, [queryClient, queryKey, currentPersonId, apiClient]);
|
|
25
26
|
const handleConversationRead = useCallback((e) => {
|
|
26
27
|
const { latest_read_message_sort_key } = e.data.data;
|
|
27
28
|
queryClient.setQueryData(queryKey, prev => {
|
|
@@ -36,6 +37,7 @@ export function useConversationJoltEvents({ conversationId }) {
|
|
|
36
37
|
data: {
|
|
37
38
|
...prev.data,
|
|
38
39
|
latestReadMessageSortKey: latest_read_message_sort_key,
|
|
40
|
+
unreadReactionCount: 0,
|
|
39
41
|
},
|
|
40
42
|
};
|
|
41
43
|
});
|
|
@@ -53,8 +55,29 @@ export function useConversationJoltEvents({ conversationId }) {
|
|
|
53
55
|
};
|
|
54
56
|
});
|
|
55
57
|
}, [queryClient, queryKey]);
|
|
58
|
+
const handleReactionJoltEvent = useCallback((event) => {
|
|
59
|
+
queryClient.setQueryData(queryKey, prev => {
|
|
60
|
+
if (!prev?.data)
|
|
61
|
+
return prev;
|
|
62
|
+
if (event.data.data.author_id === currentPersonId) {
|
|
63
|
+
return prev;
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
...prev,
|
|
67
|
+
data: {
|
|
68
|
+
...prev.data,
|
|
69
|
+
// Not a real count, just a derived value from Jolt events so we can
|
|
70
|
+
// determine if we should mark the conversation as read
|
|
71
|
+
unreadReactionCount: prev.data.unreadReactionCount
|
|
72
|
+
? prev.data.unreadReactionCount + 1
|
|
73
|
+
: 1,
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
});
|
|
77
|
+
}, [queryClient, queryKey, currentPersonId]);
|
|
56
78
|
useJoltEvent(joltChannel, 'conversation.updated', handleUpdatedConversation);
|
|
57
79
|
useJoltEvent(joltChannel, 'conversation.read', handleConversationRead);
|
|
58
80
|
useJoltEvent(joltChannel, 'conversation.destroyed', handleConversationDestroyed);
|
|
81
|
+
useJoltEvent(joltChannel, 'reaction.*', handleReactionJoltEvent);
|
|
59
82
|
}
|
|
60
83
|
//# sourceMappingURL=use_conversation_jolt_events.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use_conversation_jolt_events.js","sourceRoot":"","sources":["../../src/hooks/use_conversation_jolt_events.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"use_conversation_jolt_events.js","sourceRoot":"","sources":["../../src/hooks/use_conversation_jolt_events.ts"],"names":[],"mappings":"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","sourcesContent":["import { useQueryClient } from '@tanstack/react-query'\nimport { useCallback, useMemo } from 'react'\nimport { ApiResource, ConversationResource } from '../types'\nimport { JoltConversationEvent, JoltReactionEvent } from '../types/jolt_events'\nimport { completeMessageCreationConversationTracking } from '../utils/performance_tracking'\nimport { useApiClient } from './use_api_client'\nimport { getConversationRequestArgs } from './use_conversation'\nimport { useCurrentPerson } from './use_current_person'\nimport { useJoltChannel, useJoltEvent } from './use_jolt'\nimport { getRequestQueryKey } from './use_suspense_api'\n\ninterface Props {\n conversationId: number\n}\n\nexport function useConversationJoltEvents({ conversationId }: Props) {\n const joltChannel = useJoltChannel(`chat.conversations.${conversationId}`)\n const queryClient = useQueryClient()\n const currentPerson = useCurrentPerson()\n const currentPersonId = currentPerson?.id\n const apiClient = useApiClient()\n const queryKey = useMemo(\n () => getRequestQueryKey(getConversationRequestArgs({ conversation_id: conversationId })),\n [conversationId]\n )\n\n const handleUpdatedConversation = useCallback(\n (e: JoltConversationEvent) => {\n const { last_message_idempotent_key, last_message_author_id } = e.data.data\n\n if (last_message_idempotent_key && last_message_author_id === currentPersonId) {\n completeMessageCreationConversationTracking({\n apiClient,\n idempotentKey: last_message_idempotent_key,\n })\n }\n queryClient.invalidateQueries({ queryKey })\n },\n [queryClient, queryKey, currentPersonId, apiClient]\n )\n\n const handleConversationRead = useCallback(\n (e: JoltConversationEvent) => {\n const { latest_read_message_sort_key } = e.data.data\n queryClient.setQueryData<ApiResource<ConversationResource>>(queryKey, prev => {\n if (!prev?.data || !latest_read_message_sort_key) return prev\n if (\n prev.data.latestReadMessageSortKey &&\n prev.data.latestReadMessageSortKey >= latest_read_message_sort_key\n ) {\n return prev\n }\n\n return {\n ...prev,\n data: {\n ...prev.data,\n latestReadMessageSortKey: latest_read_message_sort_key,\n unreadReactionCount: 0,\n },\n }\n })\n },\n [queryClient, queryKey]\n )\n\n const handleConversationDestroyed = useCallback(() => {\n queryClient.setQueryData<ApiResource<ConversationResource>>(queryKey, prev => {\n if (!prev?.data) return prev\n\n return {\n ...prev,\n data: {\n ...prev.data,\n deleted: true,\n },\n }\n })\n }, [queryClient, queryKey])\n\n const handleReactionJoltEvent = useCallback(\n (event: JoltReactionEvent) => {\n queryClient.setQueryData<ApiResource<ConversationResource>>(queryKey, prev => {\n if (!prev?.data) return prev\n\n if (event.data.data.author_id === currentPersonId) {\n return prev\n }\n\n return {\n ...prev,\n data: {\n ...prev.data,\n // Not a real count, just a derived value from Jolt events so we can\n // determine if we should mark the conversation as read\n unreadReactionCount: prev.data.unreadReactionCount\n ? prev.data.unreadReactionCount + 1\n : 1,\n },\n }\n })\n },\n [queryClient, queryKey, currentPersonId]\n )\n\n useJoltEvent(joltChannel, 'conversation.updated', handleUpdatedConversation)\n useJoltEvent(joltChannel, 'conversation.read', handleConversationRead)\n useJoltEvent(joltChannel, 'conversation.destroyed', handleConversationDestroyed)\n useJoltEvent(joltChannel, 'reaction.*', handleReactionJoltEvent)\n}\n"]}
|
|
@@ -13,7 +13,7 @@ export const useConversationsMarkRead = ({ conversation, }) => {
|
|
|
13
13
|
currentPersonCache.update({}, person => {
|
|
14
14
|
const currentUnread = person.unreadCount;
|
|
15
15
|
const updatedUnread = read ? Math.max(currentUnread - 1, 0) : currentUnread + 1;
|
|
16
|
-
return { ...person, unreadCount: updatedUnread };
|
|
16
|
+
return { ...person, unreadCount: updatedUnread, unreadReactionCount: 0 };
|
|
17
17
|
});
|
|
18
18
|
}
|
|
19
19
|
const { mutate: handleMarkRead, ...mutation } = useMutation({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use_conversations_actions.js","sourceRoot":"","sources":["../../src/hooks/use_conversations_actions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AACnD,OAAO,EAAE,KAAK,EAAE,MAAM,cAAc,CAAA;AACpC,OAAO,EAAE,uBAAuB,EAAE,MAAM,mCAAmC,CAAA;AAE3E,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAC/C,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAA;AACjE,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAA;AAE5D,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,EACvC,YAAY,GAGb,EAAE,EAAE;IACH,MAAM,SAAS,GAAG,YAAY,EAAE,CAAA;IAChC,MAAM,EAAE,IAAI,EAAE,GAAG,uBAAuB,EAAE,CAAA;IAC1C,MAAM,kBAAkB,GAAG,qBAAqB,EAAE,CAAA;IAClD,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAA;IAEvE,SAAS,uBAAuB,CAAC,IAAa;QAC5C,kBAAkB,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,EAAE;YACrC,MAAM,aAAa,GAAG,MAAM,CAAC,WAAW,CAAA;YACxC,MAAM,aAAa,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,aAAa,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,GAAG,CAAC,CAAA;YAC/E,OAAO,EAAE,GAAG,MAAM,EAAE,WAAW,EAAE,aAAa,EAAE,CAAA;
|
|
1
|
+
{"version":3,"file":"use_conversations_actions.js","sourceRoot":"","sources":["../../src/hooks/use_conversations_actions.ts"],"names":[],"mappings":"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","sourcesContent":["import { useMutation } from '@tanstack/react-query'\nimport { Alert } from 'react-native'\nimport { useConversationsContext } from '../contexts/conversations_context'\nimport { ApiResource, ConversationResource } from '../types'\nimport { useApiClient } from './use_api_client'\nimport { useConversationsCache } from './use_conversations_cache'\nimport { useCurrentPersonCache } from './use_current_person'\n\nexport const useConversationsMarkRead = ({\n conversation,\n}: {\n conversation: ConversationResource\n}) => {\n const apiClient = useApiClient()\n const { args } = useConversationsContext()\n const currentPersonCache = useCurrentPersonCache()\n const { update, invalidate, fetchUpdate } = useConversationsCache(args)\n\n function handlePersonUnreadCount(read: boolean) {\n currentPersonCache.update({}, person => {\n const currentUnread = person.unreadCount\n const updatedUnread = read ? Math.max(currentUnread - 1, 0) : currentUnread + 1\n return { ...person, unreadCount: updatedUnread, unreadReactionCount: 0 }\n })\n }\n\n const { mutate: handleMarkRead, ...mutation } = useMutation({\n onMutate: async (read: boolean) => {\n update({\n ...conversation,\n unreadCount: read ? 0 : 1,\n })\n handlePersonUnreadCount(read)\n },\n mutationKey: ['markRead', conversation.id],\n mutationFn: async (read: boolean) => {\n const action = read ? 'mark_read' : 'mark_unread'\n\n return apiClient.chat.post({\n url: `/me/conversations/${conversation.id}/${action}`,\n data: { data: { type: '', attributes: {} }, fields: { Conversation: 'unread_count,id' } },\n })\n },\n onSuccess: () => {\n fetchUpdate(conversation)\n },\n onError: () => {\n Alert.alert('Oops', 'Something went wrong updating this conversation, please try again')\n invalidate()\n },\n })\n\n return {\n read: conversation.unreadCount < 1, // prefer cache\n markRead: handleMarkRead,\n ...mutation,\n }\n}\n\nexport const useConversationsMute = ({ conversation }: { conversation: ConversationResource }) => {\n const apiClient = useApiClient()\n const { args } = useConversationsContext()\n const { update, invalidate } = useConversationsCache(args)\n\n const { mutate: setMuted, ...mutation } = useMutation({\n onMutate: async (muted: boolean) => {\n update({\n ...conversation,\n muted,\n })\n },\n mutationKey: ['muteConversation'],\n mutationFn: async (muted: boolean) => {\n const action = muted ? 'mute' : 'unmute'\n\n return apiClient.chat.post<ApiResource<ConversationResource>>({\n url: `/me/conversations/${conversation.id}/${action}`,\n data: { data: { type: '', attributes: {} }, fields: { Conversation: 'muted' } },\n })\n },\n onSuccess: (response: ApiResource<ConversationResource>) => {\n update(response.data)\n },\n onError: () => {\n Alert.alert('Oops', 'Something went wrong muting this conversation, please try again')\n invalidate()\n },\n })\n\n return {\n muted: conversation.muted, // prefer cache\n setMuted,\n ...mutation,\n }\n}\n\nexport const useMarkAllRead = () => {\n const apiClient = useApiClient()\n const { args } = useConversationsContext()\n const { invalidate, updateAll } = useConversationsCache(args)\n const { mutate: markAllRead, ...query } = useMutation({\n onMutate: () => {\n updateAll({\n unreadCount: 0,\n })\n },\n mutationKey: ['markAllRead', args],\n mutationFn: () =>\n apiClient.chat.post({\n url: '/me/mark_all_read',\n }),\n onSettled: invalidate,\n })\n\n return {\n markAllRead,\n ...query,\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use_mark_latest_message_read.d.ts","sourceRoot":"","sources":["../../src/hooks/use_mark_latest_message_read.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"use_mark_latest_message_read.d.ts","sourceRoot":"","sources":["../../src/hooks/use_mark_latest_message_read.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAIhE,UAAU,KAAK;IACb,YAAY,EAAE,oBAAoB,CAAA;IAClC,QAAQ,EAAE,eAAe,EAAE,CAAA;CAC5B;AAED,wBAAgB,wBAAwB,CAAC,EAAE,YAAY,EAAE,EAAE,KAAK,QAsB/D"}
|
|
@@ -1,33 +1,22 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { debounce } from 'lodash';
|
|
2
|
+
import { useEffect, useMemo, useRef } from 'react';
|
|
2
3
|
import { useAppState } from './use_app_state';
|
|
3
4
|
import { useConversationsMarkRead } from './use_conversations_actions';
|
|
4
5
|
export function useMarkLatestMessageRead({ conversation }) {
|
|
6
|
+
const firedOnce = useRef(false);
|
|
5
7
|
const { markRead } = useConversationsMarkRead({ conversation });
|
|
6
|
-
const debouncedMarkRead =
|
|
8
|
+
const debouncedMarkRead = useMemo(() => debounce(markRead, 1000, { leading: true, trailing: true }), [markRead]);
|
|
7
9
|
const unreadCount = conversation.unreadCount;
|
|
10
|
+
const unreadReactionCount = conversation.unreadReactionCount || 0;
|
|
11
|
+
const shouldMarkRead = Boolean(unreadCount >= 1 || unreadReactionCount > 0);
|
|
8
12
|
const appState = useAppState();
|
|
9
13
|
const isActive = appState === 'active';
|
|
10
|
-
/**
|
|
11
|
-
* Handle marking the conversation as read.
|
|
12
|
-
* * The app needs to be active
|
|
13
|
-
* * The latest message from someone else is newer than the last read message
|
|
14
|
-
*/
|
|
15
14
|
useEffect(() => {
|
|
16
|
-
if (!isActive ||
|
|
15
|
+
if (!isActive || !shouldMarkRead)
|
|
17
16
|
return;
|
|
17
|
+
firedOnce.current = true;
|
|
18
18
|
debouncedMarkRead(true);
|
|
19
|
-
|
|
19
|
+
// keeping unreadReactionCount in the dependency array to watch for changes
|
|
20
|
+
}, [debouncedMarkRead, isActive, shouldMarkRead, unreadReactionCount]);
|
|
20
21
|
}
|
|
21
|
-
const useDebounce = (fn, delay) => {
|
|
22
|
-
const lastBroadcastTime = useRef(0);
|
|
23
|
-
const action = useCallback((...args) => {
|
|
24
|
-
const now = Date.now();
|
|
25
|
-
if (now - lastBroadcastTime.current < delay) {
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
lastBroadcastTime.current = now;
|
|
29
|
-
fn(...args);
|
|
30
|
-
}, [delay, fn]);
|
|
31
|
-
return action;
|
|
32
|
-
};
|
|
33
22
|
//# sourceMappingURL=use_mark_latest_message_read.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use_mark_latest_message_read.js","sourceRoot":"","sources":["../../src/hooks/use_mark_latest_message_read.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"use_mark_latest_message_read.js","sourceRoot":"","sources":["../../src/hooks/use_mark_latest_message_read.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAA;AACjC,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,OAAO,CAAA;AAElD,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAC7C,OAAO,EAAE,wBAAwB,EAAE,MAAM,6BAA6B,CAAA;AAOtE,MAAM,UAAU,wBAAwB,CAAC,EAAE,YAAY,EAAS;IAC9D,MAAM,SAAS,GAAG,MAAM,CAAU,KAAK,CAAC,CAAA;IACxC,MAAM,EAAE,QAAQ,EAAE,GAAG,wBAAwB,CAAC,EAAE,YAAY,EAAE,CAAC,CAAA;IAC/D,MAAM,iBAAiB,GAAG,OAAO,CAC/B,GAAG,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,EACjE,CAAC,QAAQ,CAAC,CACX,CAAA;IACD,MAAM,WAAW,GAAG,YAAY,CAAC,WAAW,CAAA;IAC5C,MAAM,mBAAmB,GAAG,YAAY,CAAC,mBAAmB,IAAI,CAAC,CAAA;IAEjE,MAAM,cAAc,GAAG,OAAO,CAAC,WAAW,IAAI,CAAC,IAAI,mBAAmB,GAAG,CAAC,CAAC,CAAA;IAC3E,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAA;IAC9B,MAAM,QAAQ,GAAG,QAAQ,KAAK,QAAQ,CAAA;IAEtC,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,QAAQ,IAAI,CAAC,cAAc;YAAE,OAAM;QAExC,SAAS,CAAC,OAAO,GAAG,IAAI,CAAA;QAExB,iBAAiB,CAAC,IAAI,CAAC,CAAA;QACvB,2EAA2E;IAC7E,CAAC,EAAE,CAAC,iBAAiB,EAAE,QAAQ,EAAE,cAAc,EAAE,mBAAmB,CAAC,CAAC,CAAA;AACxE,CAAC","sourcesContent":["import { debounce } from 'lodash'\nimport { useEffect, useMemo, useRef } from 'react'\nimport { ConversationResource, MessageResource } from '../types'\nimport { useAppState } from './use_app_state'\nimport { useConversationsMarkRead } from './use_conversations_actions'\n\ninterface Props {\n conversation: ConversationResource\n messages: MessageResource[]\n}\n\nexport function useMarkLatestMessageRead({ conversation }: Props) {\n const firedOnce = useRef<boolean>(false)\n const { markRead } = useConversationsMarkRead({ conversation })\n const debouncedMarkRead = useMemo(\n () => debounce(markRead, 1000, { leading: true, trailing: true }),\n [markRead]\n )\n const unreadCount = conversation.unreadCount\n const unreadReactionCount = conversation.unreadReactionCount || 0\n\n const shouldMarkRead = Boolean(unreadCount >= 1 || unreadReactionCount > 0)\n const appState = useAppState()\n const isActive = appState === 'active'\n\n useEffect(() => {\n if (!isActive || !shouldMarkRead) return\n\n firedOnce.current = true\n\n debouncedMarkRead(true)\n // keeping unreadReactionCount in the dependency array to watch for changes\n }, [debouncedMarkRead, isActive, shouldMarkRead, unreadReactionCount])\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conversation.d.ts","sourceRoot":"","sources":["../../../src/types/resources/conversation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,sBAAsB,CAAA;AACrE,OAAO,EAAE,yBAAyB,EAAE,MAAM,sBAAsB,CAAA;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAChD,OAAO,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAA;AAExD,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,cAAc,CAAA;IACpB,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,CAAC,EAAE,yBAAyB,EAAE,CAAA;IACpC,iBAAiB,CAAC,EAAE,yBAAyB,CAAA;IAC7C,sBAAsB,CAAC,EAAE;QACvB,sBAAsB,EAAE,MAAM,CAAA;KAC/B,CAAA;IACD,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,MAAM,CAAC,EAAE,aAAa,EAAE,CAAA;IACxB,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAA;IAC5B,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,oBAAoB,CAAC,EAAE,MAAM,CAAA;IAC7B,sBAAsB,CAAC,EAAE,MAAM,CAAA;IAC/B,wBAAwB,CAAC,EAAE,MAAM,CAAA;IACjC,aAAa,CAAC,EAAE,qBAAqB,CAAA;IACrC,KAAK,EAAE,OAAO,CAAA;IACd,eAAe,EAAE,OAAO,CAAA;IACxB,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,MAAM,CAAA;IACnB,SAAS,EAAE,MAAM,CAAA;CAClB"}
|
|
1
|
+
{"version":3,"file":"conversation.d.ts","sourceRoot":"","sources":["../../../src/types/resources/conversation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,sBAAsB,CAAA;AACrE,OAAO,EAAE,yBAAyB,EAAE,MAAM,sBAAsB,CAAA;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAChD,OAAO,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAA;AAExD,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,cAAc,CAAA;IACpB,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,CAAC,EAAE,yBAAyB,EAAE,CAAA;IACpC,iBAAiB,CAAC,EAAE,yBAAyB,CAAA;IAC7C,sBAAsB,CAAC,EAAE;QACvB,sBAAsB,EAAE,MAAM,CAAA;KAC/B,CAAA;IACD,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,MAAM,CAAC,EAAE,aAAa,EAAE,CAAA;IACxB,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAA;IAC5B,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,oBAAoB,CAAC,EAAE,MAAM,CAAA;IAC7B,sBAAsB,CAAC,EAAE,MAAM,CAAA;IAC/B,wBAAwB,CAAC,EAAE,MAAM,CAAA;IACjC,aAAa,CAAC,EAAE,qBAAqB,CAAA;IACrC,KAAK,EAAE,OAAO,CAAA;IACd,eAAe,EAAE,OAAO,CAAA;IACxB,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,MAAM,CAAA;IACnB,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,SAAS,EAAE,MAAM,CAAA;CAClB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conversation.js","sourceRoot":"","sources":["../../../src/types/resources/conversation.ts"],"names":[],"mappings":"","sourcesContent":["import type { AnalyticsMetadataResource } from './analytics_metadata'\nimport { ConversationBadgeResource } from './conversation_badge'\nimport { GroupResource } from './group_resource'\nimport { MemberAbilityResource } from './member_ability'\n\nexport interface ConversationResource {\n type: 'Conversation'\n id: number\n badges?: ConversationBadgeResource[]\n analyticsMetadata?: AnalyticsMetadataResource\n conversationMembership?: {\n lastReadMessageSortKey: string\n }\n createdAt: string\n deleted?: boolean\n groups?: GroupResource[]\n previewAvatarUrls?: string[]\n lastMessageAuthorId?: string\n lastMessageAuthorName?: string\n lastMessageCreatedAt?: string\n lastMessageTextPreview?: string\n latestReadMessageSortKey?: string\n memberAbility?: MemberAbilityResource\n muted: boolean\n repliesDisabled: boolean\n title: string\n unreadCount: number\n updatedAt: string\n}\n"]}
|
|
1
|
+
{"version":3,"file":"conversation.js","sourceRoot":"","sources":["../../../src/types/resources/conversation.ts"],"names":[],"mappings":"","sourcesContent":["import type { AnalyticsMetadataResource } from './analytics_metadata'\nimport { ConversationBadgeResource } from './conversation_badge'\nimport { GroupResource } from './group_resource'\nimport { MemberAbilityResource } from './member_ability'\n\nexport interface ConversationResource {\n type: 'Conversation'\n id: number\n badges?: ConversationBadgeResource[]\n analyticsMetadata?: AnalyticsMetadataResource\n conversationMembership?: {\n lastReadMessageSortKey: string\n }\n createdAt: string\n deleted?: boolean\n groups?: GroupResource[]\n previewAvatarUrls?: string[]\n lastMessageAuthorId?: string\n lastMessageAuthorName?: string\n lastMessageCreatedAt?: string\n lastMessageTextPreview?: string\n latestReadMessageSortKey?: string\n memberAbility?: MemberAbilityResource\n muted: boolean\n repliesDisabled: boolean\n title: string\n unreadCount: number\n unreadReactionCount?: number // Derived from Jolt events\n updatedAt: string\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@planningcenter/chat-react-native",
|
|
3
|
-
"version": "3.21.0
|
|
3
|
+
"version": "3.21.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"types": "build/index.d.ts",
|
|
@@ -58,5 +58,5 @@
|
|
|
58
58
|
"react-native-url-polyfill": "^2.0.0",
|
|
59
59
|
"typescript": "<5.6.0"
|
|
60
60
|
},
|
|
61
|
-
"gitHead": "
|
|
61
|
+
"gitHead": "87d647a43fc939216c10395feba49e5e517b66e8"
|
|
62
62
|
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { JoltConversationEvent } from '../types/jolt_events'
|
|
2
|
-
import { useJoltChannel, useJoltEvent } from './use_jolt'
|
|
3
|
-
import { getConversationRequestArgs } from './use_conversation'
|
|
4
1
|
import { useQueryClient } from '@tanstack/react-query'
|
|
5
|
-
import { ApiResource, ConversationResource } from '../types'
|
|
6
|
-
import { getRequestQueryKey } from './use_suspense_api'
|
|
7
2
|
import { useCallback, useMemo } from 'react'
|
|
3
|
+
import { ApiResource, ConversationResource } from '../types'
|
|
4
|
+
import { JoltConversationEvent, JoltReactionEvent } from '../types/jolt_events'
|
|
8
5
|
import { completeMessageCreationConversationTracking } from '../utils/performance_tracking'
|
|
9
|
-
import { useCurrentPerson } from './use_current_person'
|
|
10
6
|
import { useApiClient } from './use_api_client'
|
|
7
|
+
import { getConversationRequestArgs } from './use_conversation'
|
|
8
|
+
import { useCurrentPerson } from './use_current_person'
|
|
9
|
+
import { useJoltChannel, useJoltEvent } from './use_jolt'
|
|
10
|
+
import { getRequestQueryKey } from './use_suspense_api'
|
|
11
11
|
|
|
12
12
|
interface Props {
|
|
13
13
|
conversationId: number
|
|
@@ -17,6 +17,7 @@ export function useConversationJoltEvents({ conversationId }: Props) {
|
|
|
17
17
|
const joltChannel = useJoltChannel(`chat.conversations.${conversationId}`)
|
|
18
18
|
const queryClient = useQueryClient()
|
|
19
19
|
const currentPerson = useCurrentPerson()
|
|
20
|
+
const currentPersonId = currentPerson?.id
|
|
20
21
|
const apiClient = useApiClient()
|
|
21
22
|
const queryKey = useMemo(
|
|
22
23
|
() => getRequestQueryKey(getConversationRequestArgs({ conversation_id: conversationId })),
|
|
@@ -27,7 +28,7 @@ export function useConversationJoltEvents({ conversationId }: Props) {
|
|
|
27
28
|
(e: JoltConversationEvent) => {
|
|
28
29
|
const { last_message_idempotent_key, last_message_author_id } = e.data.data
|
|
29
30
|
|
|
30
|
-
if (last_message_idempotent_key && last_message_author_id ===
|
|
31
|
+
if (last_message_idempotent_key && last_message_author_id === currentPersonId) {
|
|
31
32
|
completeMessageCreationConversationTracking({
|
|
32
33
|
apiClient,
|
|
33
34
|
idempotentKey: last_message_idempotent_key,
|
|
@@ -35,7 +36,7 @@ export function useConversationJoltEvents({ conversationId }: Props) {
|
|
|
35
36
|
}
|
|
36
37
|
queryClient.invalidateQueries({ queryKey })
|
|
37
38
|
},
|
|
38
|
-
[queryClient, queryKey,
|
|
39
|
+
[queryClient, queryKey, currentPersonId, apiClient]
|
|
39
40
|
)
|
|
40
41
|
|
|
41
42
|
const handleConversationRead = useCallback(
|
|
@@ -55,6 +56,7 @@ export function useConversationJoltEvents({ conversationId }: Props) {
|
|
|
55
56
|
data: {
|
|
56
57
|
...prev.data,
|
|
57
58
|
latestReadMessageSortKey: latest_read_message_sort_key,
|
|
59
|
+
unreadReactionCount: 0,
|
|
58
60
|
},
|
|
59
61
|
}
|
|
60
62
|
})
|
|
@@ -76,7 +78,33 @@ export function useConversationJoltEvents({ conversationId }: Props) {
|
|
|
76
78
|
})
|
|
77
79
|
}, [queryClient, queryKey])
|
|
78
80
|
|
|
81
|
+
const handleReactionJoltEvent = useCallback(
|
|
82
|
+
(event: JoltReactionEvent) => {
|
|
83
|
+
queryClient.setQueryData<ApiResource<ConversationResource>>(queryKey, prev => {
|
|
84
|
+
if (!prev?.data) return prev
|
|
85
|
+
|
|
86
|
+
if (event.data.data.author_id === currentPersonId) {
|
|
87
|
+
return prev
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return {
|
|
91
|
+
...prev,
|
|
92
|
+
data: {
|
|
93
|
+
...prev.data,
|
|
94
|
+
// Not a real count, just a derived value from Jolt events so we can
|
|
95
|
+
// determine if we should mark the conversation as read
|
|
96
|
+
unreadReactionCount: prev.data.unreadReactionCount
|
|
97
|
+
? prev.data.unreadReactionCount + 1
|
|
98
|
+
: 1,
|
|
99
|
+
},
|
|
100
|
+
}
|
|
101
|
+
})
|
|
102
|
+
},
|
|
103
|
+
[queryClient, queryKey, currentPersonId]
|
|
104
|
+
)
|
|
105
|
+
|
|
79
106
|
useJoltEvent(joltChannel, 'conversation.updated', handleUpdatedConversation)
|
|
80
107
|
useJoltEvent(joltChannel, 'conversation.read', handleConversationRead)
|
|
81
108
|
useJoltEvent(joltChannel, 'conversation.destroyed', handleConversationDestroyed)
|
|
109
|
+
useJoltEvent(joltChannel, 'reaction.*', handleReactionJoltEvent)
|
|
82
110
|
}
|
|
@@ -20,7 +20,7 @@ export const useConversationsMarkRead = ({
|
|
|
20
20
|
currentPersonCache.update({}, person => {
|
|
21
21
|
const currentUnread = person.unreadCount
|
|
22
22
|
const updatedUnread = read ? Math.max(currentUnread - 1, 0) : currentUnread + 1
|
|
23
|
-
return { ...person, unreadCount: updatedUnread }
|
|
23
|
+
return { ...person, unreadCount: updatedUnread, unreadReactionCount: 0 }
|
|
24
24
|
})
|
|
25
25
|
}
|
|
26
26
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { debounce } from 'lodash'
|
|
2
|
+
import { useEffect, useMemo, useRef } from 'react'
|
|
2
3
|
import { ConversationResource, MessageResource } from '../types'
|
|
3
4
|
import { useAppState } from './use_app_state'
|
|
4
5
|
import { useConversationsMarkRead } from './use_conversations_actions'
|
|
@@ -9,41 +10,25 @@ interface Props {
|
|
|
9
10
|
}
|
|
10
11
|
|
|
11
12
|
export function useMarkLatestMessageRead({ conversation }: Props) {
|
|
13
|
+
const firedOnce = useRef<boolean>(false)
|
|
12
14
|
const { markRead } = useConversationsMarkRead({ conversation })
|
|
13
|
-
const debouncedMarkRead =
|
|
15
|
+
const debouncedMarkRead = useMemo(
|
|
16
|
+
() => debounce(markRead, 1000, { leading: true, trailing: true }),
|
|
17
|
+
[markRead]
|
|
18
|
+
)
|
|
14
19
|
const unreadCount = conversation.unreadCount
|
|
20
|
+
const unreadReactionCount = conversation.unreadReactionCount || 0
|
|
21
|
+
|
|
22
|
+
const shouldMarkRead = Boolean(unreadCount >= 1 || unreadReactionCount > 0)
|
|
15
23
|
const appState = useAppState()
|
|
16
24
|
const isActive = appState === 'active'
|
|
17
25
|
|
|
18
|
-
/**
|
|
19
|
-
* Handle marking the conversation as read.
|
|
20
|
-
* * The app needs to be active
|
|
21
|
-
* * The latest message from someone else is newer than the last read message
|
|
22
|
-
*/
|
|
23
26
|
useEffect(() => {
|
|
24
|
-
if (!isActive ||
|
|
25
|
-
|
|
26
|
-
debouncedMarkRead(true)
|
|
27
|
-
}, [debouncedMarkRead, isActive, unreadCount])
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const useDebounce = (fn: (...args: any[]) => void, delay: number) => {
|
|
31
|
-
const lastBroadcastTime = useRef<number>(0)
|
|
27
|
+
if (!isActive || !shouldMarkRead) return
|
|
32
28
|
|
|
33
|
-
|
|
34
|
-
(...args: any[]) => {
|
|
35
|
-
const now = Date.now()
|
|
29
|
+
firedOnce.current = true
|
|
36
30
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
lastBroadcastTime.current = now
|
|
42
|
-
|
|
43
|
-
fn(...args)
|
|
44
|
-
},
|
|
45
|
-
[delay, fn]
|
|
46
|
-
)
|
|
47
|
-
|
|
48
|
-
return action
|
|
31
|
+
debouncedMarkRead(true)
|
|
32
|
+
// keeping unreadReactionCount in the dependency array to watch for changes
|
|
33
|
+
}, [debouncedMarkRead, isActive, shouldMarkRead, unreadReactionCount])
|
|
49
34
|
}
|