@ethora/chat-component 26.6.1 → 26.6.3
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/{VideoCallOverlay-6PVJgibC.js → VideoCallOverlay-DwlOo5Jp.js} +2 -2
- package/dist/{VideoCallOverlay-6PVJgibC.js.map → VideoCallOverlay-DwlOo5Jp.js.map} +1 -1
- package/dist/components/MainComponents/ChatHeader.d.ts +2 -1
- package/dist/components/MainComponents/LanguageSelectorModal.d.ts +0 -10
- package/dist/components/MainComponents/Switch.d.ts +8 -0
- package/dist/components/MessageBubble/MessageTranslate.d.ts +8 -4
- package/dist/components/MessageBubble/TranslatedMessageBody.d.ts +8 -1
- package/dist/firebase-messaging-sw.js +16 -4
- package/dist/helpers/callLogMessage.d.ts +14 -0
- package/dist/helpers/createUserNameFromSetUser.d.ts +36 -1
- package/dist/helpers/toBaseLanguage.d.ts +8 -0
- package/dist/hooks/useChatSettingState.d.ts +2 -0
- package/dist/hooks/useChatWrapperInit.d.ts +1 -0
- package/dist/hooks/useMessageTranslation.d.ts +13 -10
- package/dist/hooks/useSendMessage.d.ts +1 -0
- package/dist/i18n/useT.d.ts +20 -0
- package/dist/main-aegXJZvS.js +74357 -0
- package/dist/main-aegXJZvS.js.map +1 -0
- package/dist/main.js +1 -1
- package/dist/roomStore/chatSettingsSlice.d.ts +25 -1
- package/dist/roomStore/index.d.ts +3 -0
- package/dist/types/models/config.model.d.ts +45 -25
- package/dist/types/models/language.model.d.ts +1 -1
- package/dist/types/models/message.model.d.ts +1 -0
- package/dist/utils/translateModePolicy.d.ts +19 -0
- package/package.json +1 -1
- package/public/firebase-messaging-sw.js +16 -4
- package/dist/main-L70Zd5ai.js +0 -54215
- package/dist/main-L70Zd5ai.js.map +0 -1
- package/dist/networking/api-requests/translate.api.d.ts +0 -9
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
|
-
import { IRoom } from '../../types/types';
|
|
2
|
+
import { IConfig, IRoom } from '../../types/types';
|
|
3
3
|
interface ChatHeaderProps {
|
|
4
4
|
currentRoom: IRoom;
|
|
5
5
|
handleBackClick?: (value: boolean) => void;
|
|
6
6
|
}
|
|
7
|
+
export declare const shouldShowLanguageSelector: (translatesConfig: IConfig["translates"] | undefined) => boolean;
|
|
7
8
|
declare const ChatHeader: React.FC<ChatHeaderProps>;
|
|
8
9
|
export default ChatHeader;
|
|
@@ -1,13 +1,3 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
|
-
/**
|
|
3
|
-
* Globe-icon button for the chat header that opens a language picker modal.
|
|
4
|
-
* Picking a language dispatches `setLangSource`, which drives both:
|
|
5
|
-
* - the reader's translation target (Message.tsx falls back to it when
|
|
6
|
-
* `config.translates.readerLocale` / `config.i18n.locale` aren't set),
|
|
7
|
-
* - the source language declared on the reader's own outgoing messages.
|
|
8
|
-
*
|
|
9
|
-
* `langSource` lives in `chatSettingStore`, which redux-persist already
|
|
10
|
-
* persists (see roomStore/index.ts) - no separate storage needed here.
|
|
11
|
-
*/
|
|
12
2
|
export declare const LanguageSelectorButton: React.FC;
|
|
13
3
|
export default LanguageSelectorButton;
|
|
@@ -4,6 +4,14 @@ interface SwitchProps {
|
|
|
4
4
|
bgColor?: string;
|
|
5
5
|
onSwitchOn?: () => void;
|
|
6
6
|
onSwitchOff?: () => void;
|
|
7
|
+
/**
|
|
8
|
+
* Reflects an existing value (e.g. redux state) instead of always
|
|
9
|
+
* starting from "off". Optional and defaults to undefined so every
|
|
10
|
+
* existing fire-and-forget caller keeps its original always-starts-off
|
|
11
|
+
* behaviour unchanged - only pass this when the switch represents a
|
|
12
|
+
* real, already-known boolean.
|
|
13
|
+
*/
|
|
14
|
+
checked?: boolean;
|
|
7
15
|
}
|
|
8
16
|
declare const Switch: React.FC<SwitchProps>;
|
|
9
17
|
export default Switch;
|
|
@@ -6,10 +6,14 @@ interface MessageTranslateProps {
|
|
|
6
6
|
config?: IConfig;
|
|
7
7
|
}
|
|
8
8
|
/**
|
|
9
|
-
*
|
|
10
|
-
* under an incoming message; on click it calls
|
|
11
|
-
* (host
|
|
12
|
-
*
|
|
9
|
+
* Manual-mode message translation (LinkedIn-style). Renders a "Translate"
|
|
10
|
+
* link under an incoming message; on click it calls
|
|
11
|
+
* `config.translates.onTranslate` (host-provided) - or, when the host
|
|
12
|
+
* doesn't supply one, reads whatever translation already arrived attached
|
|
13
|
+
* to the stanza (`message.translations`) - and shows the result inline
|
|
14
|
+
* with a "Show original" toggle. No default translation service is called
|
|
15
|
+
* here; a message with nothing attached and no host `onTranslate` simply
|
|
16
|
+
* has nothing to reveal (see `translation.failed`).
|
|
13
17
|
*
|
|
14
18
|
* Visibility: `config.translates.showTranslateForMessage(message)` if the host
|
|
15
19
|
* supplies it (they keep the locale logic and just tell us yes/no); otherwise
|
|
@@ -5,10 +5,17 @@ interface TranslatedMessageBodyProps {
|
|
|
5
5
|
accentColor?: string;
|
|
6
6
|
/** Renders the translated text (markdown pipeline, mentions, etc). */
|
|
7
7
|
children: ReactNode;
|
|
8
|
+
/**
|
|
9
|
+
* Whether this message was sent by the current user. The sender already
|
|
10
|
+
* knows what they wrote, so their own messages skip the quote-plus-
|
|
11
|
+
* translation treatment and just show the original text.
|
|
12
|
+
*/
|
|
13
|
+
isUser: boolean;
|
|
8
14
|
}
|
|
9
15
|
/**
|
|
10
16
|
* A message body that is showing a translation: the translated text reads
|
|
11
|
-
* as the primary content, with the original quoted above it for reference
|
|
17
|
+
* as the primary content, with the original quoted above it for reference
|
|
18
|
+
* - skipped for the current user's own messages (see `isUser`).
|
|
12
19
|
*/
|
|
13
20
|
export declare const TranslatedMessageBody: React.FC<TranslatedMessageBodyProps>;
|
|
14
21
|
export default TranslatedMessageBody;
|
|
@@ -384,9 +384,10 @@ async function handlePush(raw = {}, source = 'push') {
|
|
|
384
384
|
});
|
|
385
385
|
|
|
386
386
|
const visible = isVisibleClients(windowClients);
|
|
387
|
+
const hasAnyClient = windowClients.length > 0;
|
|
387
388
|
|
|
388
389
|
if (DEBUG) log('clients:', dumpClients(windowClients));
|
|
389
|
-
log('visibleClientExists:', visible);
|
|
390
|
+
log('visibleClientExists:', visible, 'anyClientExists:', hasAnyClient);
|
|
390
391
|
|
|
391
392
|
await broadcastDebugMessage({
|
|
392
393
|
source,
|
|
@@ -445,9 +446,20 @@ async function handlePush(raw = {}, source = 'push') {
|
|
|
445
446
|
},
|
|
446
447
|
};
|
|
447
448
|
|
|
448
|
-
|
|
449
|
+
// Calls: a client that's merely backgrounded (open, just not the
|
|
450
|
+
// visible/focused tab) is NOT the "nobody will hear this ring" case -
|
|
451
|
+
// VideoCallOverlay already rings its own OS notification for exactly
|
|
452
|
+
// that state (see its comment: this SW push is meant to be the
|
|
453
|
+
// fully-offline fallback). `visible` collapses "backgrounded but open"
|
|
454
|
+
// and "fully closed" into the same false, which duplicated that
|
|
455
|
+
// client-side ring every time the tab was merely hidden. Suppress on
|
|
456
|
+
// ANY open client for calls; regular messages keep the visible-only
|
|
457
|
+
// check they already had.
|
|
458
|
+
const suppress = isCall ? hasAnyClient : visible;
|
|
459
|
+
|
|
460
|
+
if (!suppress) {
|
|
449
461
|
log('SHOW NOTIFICATION', {
|
|
450
|
-
reason: 'NO_VISIBLE_CLIENT',
|
|
462
|
+
reason: isCall ? 'NO_CLIENT_AT_ALL' : 'NO_VISIBLE_CLIENT',
|
|
451
463
|
tag: options.tag,
|
|
452
464
|
isCall,
|
|
453
465
|
});
|
|
@@ -456,7 +468,7 @@ async function handlePush(raw = {}, source = 'push') {
|
|
|
456
468
|
}
|
|
457
469
|
|
|
458
470
|
log('SKIP NOTIFICATION', {
|
|
459
|
-
reason: 'VISIBLE_CLIENT',
|
|
471
|
+
reason: isCall ? 'CLIENT_OPEN_WILL_RING_ITSELF' : 'VISIBLE_CLIENT',
|
|
460
472
|
});
|
|
461
473
|
}
|
|
462
474
|
|
|
@@ -17,3 +17,17 @@ export declare const buildLocalCallLogMessage: (params: {
|
|
|
17
17
|
kind: "audio" | "video";
|
|
18
18
|
selfXmppUsername: string;
|
|
19
19
|
}) => IMessage;
|
|
20
|
+
/**
|
|
21
|
+
* The label for a call-log entry, built at RENDER time from the callLog
|
|
22
|
+
* meta rather than read off `message.body`.
|
|
23
|
+
*
|
|
24
|
+
* transformCallLogMessage bakes an English sentence into `body` the moment
|
|
25
|
+
* the stanza arrives, which freezes the language: switch to Chinese and
|
|
26
|
+
* every call log you already received stays English forever, because the
|
|
27
|
+
* text is data by then, not a rendering. The meta (direction/duration/
|
|
28
|
+
* missed) is the actual fact - the sentence is a view of it, so it belongs
|
|
29
|
+
* where the view is. `body` stays as the fallback for entries received
|
|
30
|
+
* before this existed, and for the notification/sidebar preview paths that
|
|
31
|
+
* only have the raw message.
|
|
32
|
+
*/
|
|
33
|
+
export declare const formatCallLogLabel: (callLog: CallLogMeta | undefined, t: (key: string, vars?: Record<string, string | number>) => string, fallbackBody?: string) => string;
|
|
@@ -1,2 +1,37 @@
|
|
|
1
|
-
import { RoomMember } from '../types/types';
|
|
1
|
+
import { IMessage, RoomMember } from '../types/types';
|
|
2
|
+
/**
|
|
3
|
+
* Cache-only lookup. Returns the literal "Deleted User" as a MISS sentinel
|
|
4
|
+
* when `usersSet` has no entry for `userId` yet - callers that want a
|
|
5
|
+
* better fallback (e.g. resolveSenderDisplayName below) check for that
|
|
6
|
+
* exact string rather than treating it as a real name.
|
|
7
|
+
*/
|
|
2
8
|
export declare const createUserNameFromSetUser: (usersSet: Record<string, RoomMember>, userId: string) => string;
|
|
9
|
+
/**
|
|
10
|
+
* The sender's display name, resolved WITHOUT depending on `usersSet`
|
|
11
|
+
* having already been hydrated.
|
|
12
|
+
*
|
|
13
|
+
* `usersSet` is populated by a separate fetch (member list / presence) that
|
|
14
|
+
* can still be in flight when a message arrives - most reliably right after
|
|
15
|
+
* reconnect, when a burst of catch-up messages can land before that fetch
|
|
16
|
+
* resolves. A cache-only lookup shows the literal "Deleted User" for every
|
|
17
|
+
* one of those messages, even though the sender is very much not deleted.
|
|
18
|
+
*
|
|
19
|
+
* The message itself already carries the sender's name on the wire: every
|
|
20
|
+
* client that sends through this SDK stamps `senderFirstName` /
|
|
21
|
+
* `senderLastName` / `fullName` onto the outgoing stanza's `<data>` element
|
|
22
|
+
* (see sendTextMessage.xmpp.ts / sendTextMessageWithTranslateTag.xmpp.ts),
|
|
23
|
+
* and createMessageFromXml spreads those onto the top-level message object.
|
|
24
|
+
* Preferring that over the cache removes the timing dependency entirely for
|
|
25
|
+
* the common case, and "Deleted User" becomes what it should have always
|
|
26
|
+
* been: a rare last resort, not "usersSet hasn't loaded yet".
|
|
27
|
+
*
|
|
28
|
+
* Mirrors roomsSlice.ts's enrichMessageAuthor, which does the same
|
|
29
|
+
* self-healing for the message list - this is that same resolution used
|
|
30
|
+
* where a live decision is needed once (e.g. a notification), rather than
|
|
31
|
+
* baked into a message object that re-resolves on every store update.
|
|
32
|
+
*/
|
|
33
|
+
export declare const resolveSenderDisplayName: (message: Pick<IMessage, "user"> & {
|
|
34
|
+
fullName?: string;
|
|
35
|
+
senderFirstName?: string;
|
|
36
|
+
senderLastName?: string;
|
|
37
|
+
}, usersSet: Record<string, RoomMember>) => string;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Iso639_1Codes } from '../types/models/language.model';
|
|
2
|
+
/**
|
|
3
|
+
* "fr-CA" -> "fr", "EN" -> "en". Region only matters for the translation
|
|
4
|
+
* service's dialect handling - everywhere else (matching a source language
|
|
5
|
+
* against a reader's, caching, `langSource`) only the base language is
|
|
6
|
+
* meaningful.
|
|
7
|
+
*/
|
|
8
|
+
export declare const toBaseLanguage: (locale?: string | null) => Iso639_1Codes;
|
|
@@ -16,5 +16,6 @@ interface useChatWrapperInitResult {
|
|
|
16
16
|
isConnectionLost: boolean;
|
|
17
17
|
}
|
|
18
18
|
export declare const resolveLegacyTranslatesLangSource: (translatesConfig?: IConfig["translates"]) => Iso639_1Codes | undefined;
|
|
19
|
+
export declare const resolveExternalReaderLocaleLangSource: (readerLocale?: string) => Iso639_1Codes | undefined;
|
|
19
20
|
declare const useChatWrapperInit: ({ roomJID, wasAutoSelected, config, }: useChatWrapperInitProps) => useChatWrapperInitResult;
|
|
20
21
|
export default useChatWrapperInit;
|
|
@@ -1,25 +1,28 @@
|
|
|
1
1
|
import { IMessage } from '../types/types';
|
|
2
2
|
export interface MessageTranslationState {
|
|
3
3
|
/** False when the message is already in the reader's language, or no
|
|
4
|
-
* translation is available
|
|
4
|
+
* translation is available - render the plain body, no quote. */
|
|
5
5
|
hasTranslation: boolean;
|
|
6
6
|
originalText: string;
|
|
7
7
|
/** Translation when hasTranslation, else the original - always safe to
|
|
8
8
|
* render directly. */
|
|
9
9
|
displayText: string;
|
|
10
10
|
}
|
|
11
|
-
/** Test-only: the cache is module state and would leak between cases. */
|
|
12
|
-
export declare const resetMessageTranslationCacheForTests: () => void;
|
|
13
11
|
/**
|
|
14
12
|
* Translation for ONE message, into the reader's language only.
|
|
15
13
|
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
14
|
+
* Pure and synchronous - no HTTP call. Every translation this client ever
|
|
15
|
+
* shows arrives over XMPP already: the sender tags outgoing messages with
|
|
16
|
+
* `<translate source="xx"/>` (see sendTextMessageWithTranslateTag) and
|
|
17
|
+
* whatever process attaches actual translations does so server-side,
|
|
18
|
+
* landing on `message.translations` when the stanza is parsed (see
|
|
19
|
+
* getDataFromXml). This function only ever reads that - it never calls a
|
|
20
|
+
* translation service itself, so there's nothing to fail when one isn't
|
|
21
|
+
* reachable, and nothing to await.
|
|
21
22
|
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
23
|
+
* A message sent before the sender had translate-sending turned on simply
|
|
24
|
+
* never got tagged, so it has no translation to show - not an error, just
|
|
25
|
+
* absence of the underlying data (see the enable/disable-translates
|
|
26
|
+
* disclaimer in LanguageSelectorModal).
|
|
24
27
|
*/
|
|
25
28
|
export declare const useMessageTranslation: (message: Pick<IMessage, "body" | "langSource" | "translations">, readerLocale?: string, enabled?: boolean) => MessageTranslationState;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export declare const shouldTagOutgoingTranslateSource: (translatesEnabled: boolean | undefined, translateSendEnabled: boolean | undefined) => boolean;
|
|
1
2
|
export declare const useSendMessage: () => {
|
|
2
3
|
sendMessage: (message: string, activeRoomJID: string, isReply?: boolean, isChecked?: boolean, mainMessage?: string) => Promise<void>;
|
|
3
4
|
sendMedia: (data: File, type: string, activeRoomJID: string, isReply?: boolean, isChecked?: boolean, mainMessage?: string) => Promise<void>;
|
package/dist/i18n/useT.d.ts
CHANGED
|
@@ -9,5 +9,25 @@
|
|
|
9
9
|
* Locale resolves to the base language for captions (region is only used for
|
|
10
10
|
* message translation). Missing keys fall back to English, then to the raw
|
|
11
11
|
* key, so nothing ever renders blank.
|
|
12
|
+
*
|
|
13
|
+
* When the host doesn't set `config.i18n.locale` explicitly, this falls
|
|
14
|
+
* back to `langSource` - the same reader-language state the in-chat globe
|
|
15
|
+
* picker (LanguageSelectorButton) and `config.translates.readerLocale`
|
|
16
|
+
* drive (see useChatWrapperInit's resolveExternalReaderLocaleLangSource).
|
|
17
|
+
* So picking a language in the chat changes both message translations AND
|
|
18
|
+
* static captions together, as one language switch, unless the host is
|
|
19
|
+
* explicitly managing UI locale separately via `config.i18n.locale`.
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* The locale the UI is currently in, resolved by the same rule useT uses
|
|
23
|
+
* (explicit `config.i18n.locale`, else the reader's `langSource`).
|
|
24
|
+
*
|
|
25
|
+
* For anything Intl already localises - dates, numbers, relative times -
|
|
26
|
+
* where you need the locale itself rather than a string from the table.
|
|
27
|
+
* Without it components reach for a hardcoded 'en-US' and quietly render
|
|
28
|
+
* American dates under a Chinese UI (DateLabel did exactly that).
|
|
29
|
+
* Undefined means "no explicit choice", which Intl reads as the browser's
|
|
30
|
+
* own locale - the right default.
|
|
12
31
|
*/
|
|
32
|
+
export declare const useUiLocale: () => string | undefined;
|
|
13
33
|
export declare const useT: () => (key: string, vars?: Record<string, string | number>) => string;
|