@droppii-org/chat-mobile 0.2.77 → 0.2.78
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/components/messages/groupNotificationMessage/index.js +5 -3
- package/lib/module/components/messages/groupNotificationMessage/index.js.map +1 -1
- package/lib/module/core/useChatListener.js +8 -5
- package/lib/module/core/useChatListener.js.map +1 -1
- package/lib/module/hooks/groups/useLeaveGroup.js +93 -0
- package/lib/module/hooks/groups/useLeaveGroup.js.map +1 -0
- package/lib/module/hooks/query-keys.js +2 -1
- package/lib/module/hooks/query-keys.js.map +1 -1
- package/lib/module/hooks/useConversationList.js +6 -9
- package/lib/module/hooks/useConversationList.js.map +1 -1
- package/lib/module/screens/ChatInfo/ChatInfo.js +17 -2
- package/lib/module/screens/ChatInfo/ChatInfo.js.map +1 -1
- package/lib/module/translation/resources/i18n.js +20 -1
- package/lib/module/translation/resources/i18n.js.map +1 -1
- package/lib/module/utils/legendListMessage.js +5 -1
- package/lib/module/utils/legendListMessage.js.map +1 -1
- package/lib/module/utils/messageUtils.js +117 -8
- package/lib/module/utils/messageUtils.js.map +1 -1
- package/lib/module/utils/toastFlashMessage.js +6 -0
- package/lib/module/utils/toastFlashMessage.js.map +1 -1
- package/lib/typescript/src/components/messages/groupNotificationMessage/index.d.ts.map +1 -1
- package/lib/typescript/src/core/useChatListener.d.ts.map +1 -1
- package/lib/typescript/src/hooks/groups/useLeaveGroup.d.ts +6 -0
- package/lib/typescript/src/hooks/groups/useLeaveGroup.d.ts.map +1 -0
- package/lib/typescript/src/hooks/query-keys.d.ts +1 -0
- package/lib/typescript/src/hooks/query-keys.d.ts.map +1 -1
- package/lib/typescript/src/hooks/useConversationList.d.ts.map +1 -1
- package/lib/typescript/src/screens/ChatInfo/ChatInfo.d.ts.map +1 -1
- package/lib/typescript/src/translation/resources/i18n.d.ts.map +1 -1
- package/lib/typescript/src/utils/legendListMessage.d.ts.map +1 -1
- package/lib/typescript/src/utils/messageUtils.d.ts +6 -0
- package/lib/typescript/src/utils/messageUtils.d.ts.map +1 -1
- package/lib/typescript/src/utils/toastFlashMessage.d.ts.map +1 -1
- package/package.json +5 -2
- package/src/components/messages/groupNotificationMessage/index.tsx +8 -4
- package/src/core/useChatListener.ts +15 -4
- package/src/hooks/groups/useLeaveGroup.ts +104 -0
- package/src/hooks/query-keys.ts +1 -0
- package/src/hooks/useConversationList.ts +8 -17
- package/src/screens/ChatInfo/ChatInfo.tsx +27 -2
- package/src/translation/resources/i18n.ts +27 -1
- package/src/utils/legendListMessage.ts +5 -1
- package/src/utils/messageUtils.ts +127 -7
- package/src/utils/toastFlashMessage.ts +8 -2
|
@@ -79,6 +79,120 @@ export const GROUP_NOTIFICATION_TEXT: Partial<
|
|
|
79
79
|
previewKey: 'msg_type_group_name_updated',
|
|
80
80
|
bySenderKey: 'chat:group_name_updated_by',
|
|
81
81
|
},
|
|
82
|
+
[MessageType.GroupMemberSetToAdmin]: {
|
|
83
|
+
previewKey: 'msg_type_group_member_set_admin',
|
|
84
|
+
bySenderKey: 'chat:group_member_set_admin_by_generic',
|
|
85
|
+
},
|
|
86
|
+
// One content type, two texts (pinned vs unpinned) — the base entry here is
|
|
87
|
+
// just the "unpinned" fallback; resolveNotificationText() below overrides
|
|
88
|
+
// it to the "pinned" keys when notificationElem.detail.isPinned is true.
|
|
89
|
+
[MessageType.PinMsg]: {
|
|
90
|
+
previewKey: 'msg_type_message_unpinned',
|
|
91
|
+
bySenderKey: 'chat:group_message_unpinned_by',
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const parseNotificationDetail = (message: MessageItem): any => {
|
|
96
|
+
if (!message.notificationElem?.detail) return undefined;
|
|
97
|
+
try {
|
|
98
|
+
return JSON.parse(message.notificationElem.detail);
|
|
99
|
+
} catch {
|
|
100
|
+
return undefined;
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
// PM-approved rule for "N members added/removed at once": 1-2 names are
|
|
105
|
+
// listed in full, 3+ collapse to the first two names plus a trailing count.
|
|
106
|
+
// Renders identically to the spec either way — e.g. 4 invites become
|
|
107
|
+
// "B, C và 2 người khác".
|
|
108
|
+
const formatMemberNames = (
|
|
109
|
+
members: Array<{ nickname?: string }> | undefined
|
|
110
|
+
): string | undefined => {
|
|
111
|
+
const names = (members ?? [])
|
|
112
|
+
.map((member) => member?.nickname)
|
|
113
|
+
.filter((nickname): nickname is string => !!nickname);
|
|
114
|
+
|
|
115
|
+
if (names.length === 0) return undefined;
|
|
116
|
+
if (names.length <= 2) return names.join(', ');
|
|
117
|
+
return `${names[0]}, ${names[1]} và ${names.length - 2} người khác`;
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
export interface ResolvedNotificationText {
|
|
121
|
+
previewKey: string;
|
|
122
|
+
bySenderKey: string;
|
|
123
|
+
params: Record<string, string>;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// GROUP_NOTIFICATION_TEXT above only covers the static "no extra data needed"
|
|
127
|
+
// shape. This resolver layers in the per-event params (affected member name,
|
|
128
|
+
// new group name, pinned/unpinned) confirmed against real captured payloads —
|
|
129
|
+
// upgrading to a `_named`/`_by` key when the data is present, and silently
|
|
130
|
+
// falling back to the generic base key when it's missing or malformed so the
|
|
131
|
+
// UI never shows a raw `{{placeholder}}` or throws on a bad payload.
|
|
132
|
+
export const resolveNotificationText = (
|
|
133
|
+
message: MessageItem
|
|
134
|
+
): ResolvedNotificationText | undefined => {
|
|
135
|
+
const base = GROUP_NOTIFICATION_TEXT[message.contentType];
|
|
136
|
+
if (!base) return undefined;
|
|
137
|
+
|
|
138
|
+
let previewKey = base.previewKey;
|
|
139
|
+
let bySenderKey = base.bySenderKey;
|
|
140
|
+
const params: Record<string, string> = {};
|
|
141
|
+
const detail = parseNotificationDetail(message);
|
|
142
|
+
|
|
143
|
+
switch (message.contentType) {
|
|
144
|
+
case MessageType.GroupNameUpdated: {
|
|
145
|
+
const newGroupName = detail?.group?.groupName;
|
|
146
|
+
if (newGroupName) {
|
|
147
|
+
params.newGroupName = newGroupName;
|
|
148
|
+
bySenderKey = 'chat:group_name_updated_by_named';
|
|
149
|
+
}
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
case MessageType.MemberInvited: {
|
|
153
|
+
const names = formatMemberNames(detail?.invitedUserList);
|
|
154
|
+
if (names) {
|
|
155
|
+
params.names = names;
|
|
156
|
+
bySenderKey = 'chat:member_invited_by_named';
|
|
157
|
+
}
|
|
158
|
+
break;
|
|
159
|
+
}
|
|
160
|
+
case MessageType.MemberKicked: {
|
|
161
|
+
const names = formatMemberNames(detail?.kickedUserList);
|
|
162
|
+
if (names) {
|
|
163
|
+
params.names = names;
|
|
164
|
+
bySenderKey = 'chat:member_kicked_by_named';
|
|
165
|
+
}
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
case MessageType.GroupOwnerTransferred: {
|
|
169
|
+
const memberName = detail?.newGroupOwner?.nickname;
|
|
170
|
+
if (memberName) {
|
|
171
|
+
params.memberName = memberName;
|
|
172
|
+
bySenderKey = 'chat:group_owner_transferred_by_named';
|
|
173
|
+
}
|
|
174
|
+
break;
|
|
175
|
+
}
|
|
176
|
+
case MessageType.GroupMemberSetToAdmin: {
|
|
177
|
+
const memberName = detail?.changedUser?.nickname;
|
|
178
|
+
if (memberName) {
|
|
179
|
+
params.memberName = memberName;
|
|
180
|
+
bySenderKey = 'chat:group_member_set_admin_by';
|
|
181
|
+
}
|
|
182
|
+
break;
|
|
183
|
+
}
|
|
184
|
+
case MessageType.PinMsg: {
|
|
185
|
+
if (detail?.isPinned === true) {
|
|
186
|
+
previewKey = 'msg_type_message_pinned';
|
|
187
|
+
bySenderKey = 'chat:group_message_pinned_by';
|
|
188
|
+
}
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
default:
|
|
192
|
+
break;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return { previewKey, bySenderKey, params };
|
|
82
196
|
};
|
|
83
197
|
|
|
84
198
|
export const extractTextContent = (message: MessageItem): string => {
|
|
@@ -177,9 +291,9 @@ export const getMessagePreview = (message?: MessageItem): string => {
|
|
|
177
291
|
return trans('msg_type_burn_message_change');
|
|
178
292
|
|
|
179
293
|
default: {
|
|
180
|
-
const
|
|
181
|
-
if (
|
|
182
|
-
return trans(
|
|
294
|
+
const resolved = resolveNotificationText(message);
|
|
295
|
+
if (resolved) {
|
|
296
|
+
return trans(resolved.previewKey, resolved.params);
|
|
183
297
|
}
|
|
184
298
|
return '[Tin nhắn không được hỗ trợ]';
|
|
185
299
|
}
|
|
@@ -305,8 +419,11 @@ export const getNotificationOpUserNickname = (
|
|
|
305
419
|
try {
|
|
306
420
|
const parsed = JSON.parse(message.notificationElem.detail) as {
|
|
307
421
|
opUser?: { nickname?: string };
|
|
422
|
+
quitUser?: { nickname?: string };
|
|
308
423
|
};
|
|
309
|
-
|
|
424
|
+
// MemberQuit puts the leaver in `quitUser`, not `opUser` — every other
|
|
425
|
+
// group-notification content type uses `opUser` for the actor.
|
|
426
|
+
return parsed?.opUser?.nickname ?? parsed?.quitUser?.nickname;
|
|
310
427
|
} catch {
|
|
311
428
|
return undefined;
|
|
312
429
|
}
|
|
@@ -353,9 +470,12 @@ export const getLastMessageText = ({
|
|
|
353
470
|
return trans('chat:revoked_by_sender', { sender });
|
|
354
471
|
}
|
|
355
472
|
|
|
356
|
-
const
|
|
357
|
-
if (
|
|
358
|
-
return trans(
|
|
473
|
+
const resolvedNotification = resolveNotificationText(message);
|
|
474
|
+
if (resolvedNotification) {
|
|
475
|
+
return trans(resolvedNotification.bySenderKey, {
|
|
476
|
+
sender,
|
|
477
|
+
...resolvedNotification.params,
|
|
478
|
+
});
|
|
359
479
|
}
|
|
360
480
|
|
|
361
481
|
const hideSenderPrefix =
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import Toast from 'react-native-toast-message';
|
|
1
|
+
import Toast, { type BaseToastProps } from 'react-native-toast-message';
|
|
2
2
|
|
|
3
3
|
interface ShowFlashMessageParams {
|
|
4
4
|
key: string;
|
|
@@ -16,6 +16,12 @@ const VISIBILITY_TIME_MS = 2000;
|
|
|
16
16
|
|
|
17
17
|
const displayToast = (params: ShowFlashMessageParams) => {
|
|
18
18
|
currentKey = params.key;
|
|
19
|
+
// `text2Props` isn't part of react-native-toast-message's own
|
|
20
|
+
// `ToastShowParams` type, but the `info` renderer registered in
|
|
21
|
+
// toastFlashMessageConfig.tsx spreads these show() params straight onto
|
|
22
|
+
// `<BaseToast>`, which does declare `text2Props` — so it works at runtime,
|
|
23
|
+
// it's just missing from the upstream type. Widen the type locally instead
|
|
24
|
+
// of casting the whole call to `any`.
|
|
19
25
|
Toast.show({
|
|
20
26
|
type: 'info',
|
|
21
27
|
text1: params.title,
|
|
@@ -32,7 +38,7 @@ const displayToast = (params: ShowFlashMessageParams) => {
|
|
|
32
38
|
avatarUrl: params?.avatarUrl,
|
|
33
39
|
fullName: params.title,
|
|
34
40
|
},
|
|
35
|
-
});
|
|
41
|
+
} as Parameters<typeof Toast.show>[0] & Pick<BaseToastProps, 'text2Props'>);
|
|
36
42
|
};
|
|
37
43
|
|
|
38
44
|
function advanceQueue() {
|