@ethora/chat-component 26.10.7 → 26.10.8
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/README.md +88 -3
- package/dist/ChatProfileModal-83t5BRkI.js +2298 -0
- package/dist/{FilePreviewModal-DlOjnYzv.js → FilePreviewModal-DxUGjSHe.js} +130 -130
- package/dist/{ManageDataModal-BZLGJZze.js → ManageDataModal-DFE_Wegj.js} +14 -14
- package/dist/{MarkdownBody-CtArwCDa.js → MarkdownBody-uFITrPjT.js} +1 -1
- package/dist/{MessageSearchModal-CcUnfZlU.js → MessageSearchModal-CsbTWgNm.js} +32 -32
- package/dist/{PublicChatsModal-BWn0NXVo.js → PublicChatsModal-bDOp3IL9.js} +19 -19
- package/dist/{SideDrawer-CqZl9sxK.js → SideDrawer-A_1ECqD2.js} +28 -28
- package/dist/{UserProfileModal-D0JZ3-uy.js → UserProfileModal-Ca5wHYvr.js} +124 -120
- package/dist/{UserSettingsModal-OvykYDsT.js → UserSettingsModal-CAyyQGV6.js} +2 -2
- package/dist/{VideoCallOverlay-DrvO2v_g.js → VideoCallOverlay-BMiQh8kI.js} +5908 -4168
- package/dist/{VisibilityModal-pOF9-UXR.js → VisibilityModal-BXyIy7_J.js} +7 -7
- package/dist/assets/icons.d.ts +4 -0
- package/dist/calls/callDisplay.d.ts +22 -0
- package/dist/calls/callMode.d.ts +105 -0
- package/dist/calls/openScheduledCall.d.ts +20 -0
- package/dist/calls/p2p/P2PCallController.d.ts +160 -0
- package/dist/calls/p2p/icePolicy.d.ts +36 -0
- package/dist/calls/p2p/negotiator.d.ts +56 -0
- package/dist/calls/p2p/p2pRuntime.d.ts +35 -0
- package/dist/calls/p2p/signalInbox.d.ts +34 -0
- package/dist/calls/p2p/signalStanza.d.ts +51 -0
- package/dist/calls/placeCall.d.ts +20 -0
- package/dist/calls/scheduledCall.d.ts +101 -0
- package/dist/calls/scheduledCallActions.d.ts +12 -0
- package/dist/calls/scheduledCallFormat.d.ts +13 -0
- package/dist/calls/scheduledCallsConfig.d.ts +27 -0
- package/dist/calls/senderTrust.d.ts +7 -0
- package/dist/calls/startCall.d.ts +16 -0
- package/dist/components/MainComponents/ChatWrapper.d.ts +1 -0
- package/dist/components/MainComponents/LoginWrapper.d.ts +1 -0
- package/dist/components/MainComponents/ProfileImagePlaceholder.d.ts +1 -0
- package/dist/components/MainComponents/ReduxWrapper.d.ts +6 -0
- package/dist/components/MenuRoom/MenuRoom.d.ts +1 -0
- package/dist/components/Modals/NewChatModal/styledNewChatComponents.d.ts +27 -0
- package/dist/components/Modals/styledModalComponents.d.ts +21 -0
- package/dist/components/ScheduledCalls/ScheduleCallModal.d.ts +3 -0
- package/dist/components/ScheduledCalls/ScheduledCallCancelConfirm.d.ts +8 -0
- package/dist/components/ScheduledCalls/ScheduledCallCard.d.ts +7 -0
- package/dist/components/ScheduledCalls/ScheduledCallLayer.d.ts +15 -0
- package/dist/components/ScheduledCalls/ScheduledCallPreJoin.d.ts +3 -0
- package/dist/components/VideoCalls/P2PCallRunner.d.ts +1 -0
- package/dist/components/VideoCalls/P2PCallSession.d.ts +14 -0
- package/dist/components/VideoCalls/VideoCallSession.d.ts +37 -0
- package/dist/{handleCopyClick-BUbVvd2G.js → handleCopyClick-BX1fcFGN.js} +1 -1
- package/dist/helpers/callPush.d.ts +2 -0
- package/dist/helpers/canLeaveRoom.d.ts +3 -0
- package/dist/helpers/chatComponentConfigEvents.d.ts +16 -0
- package/dist/helpers/liveConfig.d.ts +46 -0
- package/dist/helpers/reportRoom.d.ts +18 -0
- package/dist/helpers/scheduledCallMessage.d.ts +23 -0
- package/dist/helpers/storeConsole.d.ts +1 -0
- package/dist/hooks/useNow.d.ts +6 -0
- package/dist/hooks/useRemoteAppearance.d.ts +21 -0
- package/dist/hooks/useTypography.d.ts +4 -0
- package/dist/{main-CpHMnydn.js → main-B25iFKAC.js} +15794 -13324
- package/dist/main.d.ts +3 -1
- package/dist/main.js +28 -26
- package/dist/networking/api-requests/callState.api.d.ts +24 -0
- package/dist/networking/api-requests/remoteAppearance.api.d.ts +20 -0
- package/dist/networking/api-requests/rooms.api.d.ts +2 -1
- package/dist/networking/api-requests/scheduledCalls.api.d.ts +19 -0
- package/dist/networking/ethoraEvents.d.ts +14 -1
- package/dist/networking/xmpp/notifyXmppEvent.d.ts +6 -0
- package/dist/roomStore/callSlice.d.ts +23 -1
- package/dist/roomStore/chatSettingsSlice.d.ts +9 -1
- package/dist/roomStore/index.d.ts +4 -0
- package/dist/roomStore/scheduledCallSlice.d.ts +47 -0
- package/dist/types/models/config.model.d.ts +71 -1
- package/dist/types/models/message.model.d.ts +2 -0
- package/dist/types/models/room.model.d.ts +2 -0
- package/dist/types/models/scheduledCall.model.d.ts +116 -0
- package/package.json +1 -1
- package/dist/ChatProfileModal-BDZvd0rm.js +0 -2168
package/README.md
CHANGED
|
@@ -20,6 +20,7 @@ Use it as a standalone chat page, as an embedded widget in your existing app, or
|
|
|
20
20
|
- [Chat Props Reference](#chat-props-reference)
|
|
21
21
|
- [Full Config Reference (`IConfig`)](#full-config-reference-iconfig)
|
|
22
22
|
- [Custom Widgets and Overrides](#custom-widgets-and-overrides)
|
|
23
|
+
- [Scheduled Calls](#scheduled-calls)
|
|
23
24
|
- [Push Notifications](#push-notifications)
|
|
24
25
|
- [Auth Strategies](#auth-strategies)
|
|
25
26
|
- [Hooks and API Exports](#hooks-and-api-exports)
|
|
@@ -325,6 +326,7 @@ These are the top-level props accepted by `Chat` (exported from `ReduxWrapper`).
|
|
|
325
326
|
| --- | --- | --- | --- |
|
|
326
327
|
| `config` | `IConfig` | No | Main behavior/configuration object. |
|
|
327
328
|
| `roomJID` | `string` | No | Force specific room JID on load. |
|
|
329
|
+
| `scheduledCallSlug` | `string` | No | Open a scheduled call: once signed in, selects its room and shows the pre-join panel. The slug is the last part of a `/call/<slug>` join link. See [Scheduled Calls](#scheduled-calls). |
|
|
328
330
|
| `user` | `{ email: string; password: string }` | No | Credentials for email/password login helper path. |
|
|
329
331
|
| `loginData` | `{ email: string; password: string }` | No | Optional login payload. |
|
|
330
332
|
| `MainComponentStyles` | `React.CSSProperties` | No | Outer container style override. |
|
|
@@ -351,7 +353,8 @@ Below is a grouped reference for all `config` options.
|
|
|
351
353
|
| `newArch` | `boolean` | Defaults to `true`; set `false` to explicitly force legacy/old architecture paths. |
|
|
352
354
|
| `useStoreConsoleEnabled` | `boolean` | Enable verbose internal logging in console. |
|
|
353
355
|
| `userLookupRoute` | `'auto' \| 'v1' \| 'v2'` | Route used to look up one sender that is not in the room member list. Default `'auto'`: `GET /v1/apps/users/<xmppUsername>` first; if the backend refuses the user token there (400/401, missing route) the chat uses `GET /v2/chats/users?xmppUsername=` for 10 minutes, then tries v1 again. A 403 from v1 is treated as a per-user "not allowed" and shows the name carried on the message, or "Unknown user". `'v1'` / `'v2'` pin one route. |
|
|
354
|
-
| `trustedEventSenders` | `string[]` | Who may push server `ethora-event` headlines (see Server events). Default (unset): any bare JID without a resource on the account's own XMPP domain, which is how the server sends them. Set it to pin the exact sender(s) as full bare JIDs (`admin@xmpp.example.com`) or local parts (`admin`). |
|
|
356
|
+
| `trustedEventSenders` | `string[]` | Who may push server `ethora-event` headlines (see Server events). Default (unset): any bare JID without a resource on the account's own XMPP domain, which is how the server sends them. Set it to pin the exact sender(s) as full bare JIDs (`admin@xmpp.example.com`) or local parts (`admin`). The `chat-component-config-updated` event comes from the bare server domain (see [Server events](#server-events-urnethoraevents1)), so a pinned list must name the domain (`xmpp.example.com`) for it to be heard. |
|
|
357
|
+
| `remoteAppearance` | `{ appId: string; baseUrl?: string; initialWaitMs?: number }` | Read the App's look from the server and keep it current: the colours, fonts, layout switches and AI display options saved in the admin's Chat component tab. Opt in by naming the App. Read at start (the first paint waits for it, at most `initialWaitMs`, default 2500) and again on every `chat-component-config-updated` server event, applied to the open chat without reconnecting. Only the keys in [Applying config live](#applying-config-live-and-remoteappearance) are accepted from the server. Off by default. |
|
|
355
358
|
| `historyPreload` | `{ mode?: 'staged' \| 'all' \| 'off'; topRooms?: number; concurrency?: number }` | Background message-history preload after connect, for accounts with many rooms. Default `{ mode: 'staged', topRooms: 8, concurrency: 3 }`. `staged`: the `topRooms` most recently active rooms get a full page loaded, `concurrency` at a time, and rooms the backend gave no `lastMessage` for get a one-message preview (up to 4x `topRooms` of them); every other room loads the moment it is opened. A room the user opens jumps the queue, and a reconnect only re-queues rooms that are not already preloaded. `all`: preload every room (the old behaviour; fine for a handful of rooms). `off`: no background preload at all. The room list's last message, time and unread badge come from `GET /v1/chats/my` (`lastMessage`, `unreadCount`) when the backend sends them, so they render without waiting for any history; a backend without those fields falls back to the history preload. The older `historyQoS.preloadTopKRooms` / `stagedPreloadConcurrency` are still honoured when the matching field here is not set; pinning `historyQoS.stagedPreloadEnabled: false` keeps the legacy startup catch-up path. |
|
|
356
359
|
| `historyQoS.joinHistoryStanzas` | `number` | Messages the MUC service replays on every room join (sent as `<history maxstanzas="N"/>`). Default `0`: history comes from the message archive only, so connecting an account with many rooms no longer pulls the server default (up to 20 messages) per room. Raise it only if a room of yours has no archiving and relies on the join replay. |
|
|
357
360
|
| `historyQoS.joinConcurrency` | `number` | Rooms joined in parallel by the background join sweep. The room list is shown as soon as `/chats/my` returns; every room is then joined in the background (the open room first, then most recent activity; a room you open while it is queued jumps the queue). Default `5`. |
|
|
@@ -420,7 +423,7 @@ Below is a grouped reference for all `config` options.
|
|
|
420
423
|
| `disableSentLogic` | `boolean` | Disable default sent-state logic when needed. |
|
|
421
424
|
| `secondarySendButton` | `{ enabled: boolean; messageEdit: string; label?: React.ReactNode; buttonStyles?: React.CSSProperties; hideInputSendButton?: boolean; overwriteEnterClick?: true }` | Extra send action/button config. |
|
|
422
425
|
| `messageTextFilter` | `{ enabled: boolean; filterFunction: (text: string) => string }` | Transform/filter outgoing message text. |
|
|
423
|
-
| `eventHandlers` | `{ onMessageSent?; onMessageFailed?; onMessageEdited?; onError? }` | Lifecycle callbacks for message operations
|
|
426
|
+
| `eventHandlers` | `{ onXmppEvent?; onMessageSent?; onMessageFailed?; onMessageEdited?; onError?; onChatComponentConfigUpdated? }` | Lifecycle callbacks for incoming XMPP messages and message operations. `onXmppEvent` receives every incoming `<message/>` stanza as raw XML plus its `from`, `to`, `id`, and `type`, including archive and protocol messages. On end-to-end encrypted messages the XML may still be encrypted. `onError` reports uncaught render errors caught by the SDK's error boundary, see [Error handling](#error-handling-and-crash-containment); `onChatComponentConfigUpdated({ appId, version })` runs when the server says the App's chat component config changed, see [Applying config live](#applying-config-live-and-remoteappearance). |
|
|
424
427
|
| `translates` | `{ enabled: boolean; translations?: Iso639_1Codes; mode?: 'auto' \| 'manual'; forceType?: boolean; readerLocale?: string; showLanguageSelector?: boolean; showLanguageList?: boolean; onTranslate?: (text, ctx) => Promise<string>; showTranslateForMessage?: (message) => boolean; endpoint?: string }` | Message translation-related options. In manual mode, an on-demand translate click shows exactly what `mode: 'auto'` would have shown automatically - the same `message.translations` lookup, no network call - unless `onTranslate` is provided, in which case it wins and may do its own HTTP. The built-in translate-service fetch is strictly opt-in: it only runs when the host sets `endpoint` explicitly (there is no default derived from `config.baseUrl`), and the result is cached onto the message so a second click, or switching to 'auto', sees it for free. The call is made directly from the browser, so `endpoint` must respond with `Access-Control-Allow-Origin` for that origin (a self-hosted translate service needs its `CORS_ORIGIN` env var set) or the fetch is blocked with no error shown beyond the retry link; if you can't set that on the endpoint, use `onTranslate` and proxy the call through your own backend instead. When there is genuinely nothing to reveal (no attached translation, no `onTranslate`, no `endpoint`), no "Translate" link is shown at all. |
|
|
425
428
|
| `whitelistSystemMessage` | `string[]` | Restrict/render only selected system message types. |
|
|
426
429
|
| `customSystemMessage` | `React.ComponentType<MessageProps>` | Replace system message component renderer. |
|
|
@@ -489,6 +492,7 @@ with React's component stack, regardless of `useStoreConsoleEnabled`.
|
|
|
489
492
|
|
|
490
493
|
| Option | Type | Description |
|
|
491
494
|
| --- | --- | --- |
|
|
495
|
+
| `eventHandlers.onXmppEvent` | `(event: XmppMessageEvent) => void \| Promise<void>` | Called for every incoming XMPP `<message/>` before chat/protocol/MAM routing. The event contains the raw XML `stanza` and optional `from`, `to`, `id`, and `type`. Encrypted message XML may still be encrypted. Callback errors are caught and logged. |
|
|
492
496
|
| `fallbackScreens.error` | `React.ReactNode \| ((ctx) => React.ReactNode)` | Replaces the built-in crash screen. A plain string renders as centered text, a React node renders as-is, a function receives `{ error, componentStack, scope, reset }`. |
|
|
493
497
|
| `eventHandlers.onError` | `(event: ChatErrorInfo) => void` | Called with `{ error, componentStack, scope }` when the boundary catches a crash. Wire it to your crash reporter. A throw inside your handler is caught and logged, never rethrown. |
|
|
494
498
|
|
|
@@ -535,8 +539,37 @@ The server tells a user that something they display changed by sending a `type="
|
|
|
535
539
|
| --- | --- | --- |
|
|
536
540
|
| `user-profile-updated` | `xmppUsername` (`<appId>_<userId>`), `uuid`, `appId`, `ts` | Re-fetches that user, bypassing the cache and any "not found" memory, through the same lookup route as unknown senders (`userLookupRoute`). Existing bubbles are re-named and re-pictured. If it is the signed-in user, their own profile data is updated too. Bursts within 500 ms collapse into one request. |
|
|
537
541
|
| `chat-meta-updated` | `chatName` (`<appId>_<roomId>`), `appId`, `ts` | Re-fetches `GET /v1/chats/my/<chatName>` and applies only title, description, picture, type and user count to the room. Members, messages, last message and unread counters are never replaced, and the user count is never lowered. Events for rooms the chat does not hold are ignored. Debounced per room (500 ms), one request in flight, backoff after errors. |
|
|
542
|
+
| `chat-component-config-updated` | `appId`, `version`, `ts` | The admin saved a change in the Chat component tab. Calls `config.eventHandlers.onChatComponentConfigUpdated({ appId, version })` and, when `config.remoteAppearance` is set, reads the config again and applies it live. Ignored unless `appId` is this session's own App (`config.appId` or `remoteAppearance.appId`). Once per `version`, a few hundred ms after the last of a burst. No values travel in the event. |
|
|
538
543
|
|
|
539
|
-
Unknown event types and malformed attributes are ignored. Trust rule: the stanza must come from a bare JID (no resource) on the session's own XMPP domain, so room occupants, other users, the `conference.` domain and other servers are ignored; `trustedEventSenders` narrows this to named senders. `xmppUsername` and `chatName` are validated (charset, length, `<appId>_` prefix) before use. The older `<user-update>` / `<chat-update>` headlines (namespace `your:custom:ns`) are still handled as before.
|
|
544
|
+
Unknown event types and malformed attributes are ignored. Trust rule: the stanza must come from a bare JID (no resource) on the session's own XMPP domain, so room occupants, other users, the `conference.` domain and other servers are ignored; `trustedEventSenders` narrows this to named senders. `chat-component-config-updated` is the one event that is also accepted from the bare server domain itself (`xmpp.example.com`, no user part): the server delivers it to every online session of the host in a single announcement (ejabberd `announce/online`), so it also arrives for other Apps on the host and is dropped unless it names this session's App. A client cannot send as the server domain. `xmppUsername` and `chatName` are validated (charset, length, `<appId>_` prefix) before use. The older `<user-update>` / `<chat-update>` headlines (namespace `your:custom:ns`) are still handled as before.
|
|
545
|
+
|
|
546
|
+
### Applying config live, and `remoteAppearance`
|
|
547
|
+
|
|
548
|
+
Changing the `config` prop of a mounted `<Chat>` restyles it in place. Nothing reconnects, no room or message is reloaded, no draft is lost, and the signed-in session is left alone: the new config replaces the one in the store, the components that read it re-render, and the CSS variables, fonts and icon tint are re-published (a font or colour you remove goes back to the default). The connection and login are keyed on identity fields, not on the config object, so a host that rebuilds `config` on every render is already safe.
|
|
549
|
+
|
|
550
|
+
| Applied live (change them any time) | Read when the chat starts (a new value is used by the next mount) |
|
|
551
|
+
| --- | --- |
|
|
552
|
+
| `colorScheme`; `colors.*` (`primary`, `secondary`, `icons`, `iconsBg`, `ownMessageBackground`, `otherMessageBackground`, `inputBackground`); `typography.*`; `backgroundChat.*` | `appId`, `baseUrl`, `customAppToken`, `xmppSettings.*` (these also pick the cache scope, a different one clears the local cache) |
|
|
553
|
+
| `disableHeader`, `disableMedia`, `disableRooms`, `disableRoomMenu`, `disableNewChatButton`, `disableUserCount`, `disableTypingIndicator`, `disableProfilesInteractions`, `chatHeaderBurgerMenu`, `chatHeaderSettings.hideSearch` | `userLogin`, `jwtLogin`, `customLogin`, `refreshTokens`, `initBeforeLoad`, `initBeforeLoadAuth` |
|
|
554
|
+
| `blockMessageSendingWhenProcessing`, `customTypingIndicator.enabled` / `.text` / `.position`, `translates.enabled`, `secondarySendButton.enabled` | `newArch`, `historyQoS`, `historyPreload`, `disableLastRead`, `receipts`, `e2ee`, `videoCalls`, `pushNotifications` |
|
|
555
|
+
|
|
556
|
+
Anything not in the left column is not applied from the server by `remoteAppearance` either.
|
|
557
|
+
|
|
558
|
+
**`remoteAppearance`.** The Ethora admin saves these options per App (`PUT /v2/apps/<appId>/chat-component/config`), and the server tells every online chat of that App with the `chat-component-config-updated` event. Opt in and the chat does the rest:
|
|
559
|
+
|
|
560
|
+
```tsx
|
|
561
|
+
<Chat config={{ appId, baseUrl, remoteAppearance: { appId } /* baseUrl defaults to config.baseUrl */ }} />
|
|
562
|
+
```
|
|
563
|
+
|
|
564
|
+
It reads `GET /v2/chat-component/config?appId=` (public, no token) at start and holds the first paint for it, at most `initialWaitMs` (2500), so the chat starts once with its final look; the saved values win over the same keys in your `config`. On every event it reads again with `&v=<version>` (which gets past the endpoint's 30 s cache) and applies the answer live. A failed read keeps the look you have. Only the left-column keys are taken from the answer, each checked (colours, font names and sizes, a few enums and booleans), so a wrong answer cannot do more than restyle. The record is kept in the store next to `config`, so a second writer of `config` (for example `<XmppProvider config>`) does not undo it.
|
|
565
|
+
|
|
566
|
+
Prefer to fetch yourself? Leave `remoteAppearance` out, read the endpoint in the callback and pass the merged result as `config`:
|
|
567
|
+
|
|
568
|
+
```tsx
|
|
569
|
+
<Chat config={{ ...base, ...saved, eventHandlers: { onChatComponentConfigUpdated: ({ appId, version }) => reload(appId, version) } }} />
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
Delivery is best effort, like any push: a client that was offline misses the event and picks the change up at its next start.
|
|
540
573
|
|
|
541
574
|
## Custom Widgets and Overrides
|
|
542
575
|
|
|
@@ -584,6 +617,56 @@ Reference example components in repository:
|
|
|
584
617
|
- `src/examples/customComponents/CustomDaySeparator.tsx`
|
|
585
618
|
- `src/examples/customComponents/CustomNewMessageLabel.tsx`
|
|
586
619
|
|
|
620
|
+
## Scheduled Calls
|
|
621
|
+
|
|
622
|
+
Scheduled calls let a member book a call in a chat. Everyone in the room gets an invite card with "Google Calendar", "Outlook" and "Download .ics" links, and a Join button that opens 15 minutes before the start. Booking only decides when: the call itself runs on the existing call path (1:1 rooms over P2P WebRTC, group rooms over LiveKit), and no camera or microphone is touched until the user taps Join on the pre-join panel. Calendar delivery is `.ics` and template links only; there is no calendar OAuth.
|
|
623
|
+
|
|
624
|
+
It needs a backend that serves the scheduled-call endpoints (`/v1/chats/calls/scheduled`) and is on by default whenever `config.videoCalls.enabled` is on:
|
|
625
|
+
|
|
626
|
+
```tsx
|
|
627
|
+
<Chat
|
|
628
|
+
config={{
|
|
629
|
+
videoCalls: { enabled: true, livekitUrl: 'wss://livekit.example.com', enableAudioCalls: true },
|
|
630
|
+
// scheduledCalls is optional; these are the defaults.
|
|
631
|
+
scheduledCalls: { enabled: true },
|
|
632
|
+
}}
|
|
633
|
+
/>
|
|
634
|
+
```
|
|
635
|
+
|
|
636
|
+
What the user sees:
|
|
637
|
+
|
|
638
|
+
- A "Schedule call" button next to the call buttons in the chat header (same room types and gating as the call buttons). The form takes a title, date and time in the local time zone, a duration (15 minutes to 2 hours, or the call's own when editing) and video or audio (audio only when `videoCalls.enableAudioCalls` is on).
|
|
639
|
+
- An invite card in the room for each scheduled call. An edit or a cancel from the backend replaces the card (one card per call, the newest status wins): upcoming, open to join, ended (greyed) or cancelled (struck through). The person who scheduled the call (the message names them in `scheduledCallCreatedBy`, so no request is needed) and the room owner also get Edit and Cancel.
|
|
640
|
+
- Join opens the pre-join panel (title, time, duration, room, calendar links) and a "Join call" button, enabled from 15 minutes before the start until the call ends.
|
|
641
|
+
|
|
642
|
+
Clients that do not know the message type show its plain-text body, so older apps stay readable.
|
|
643
|
+
|
|
644
|
+
### Opening a call from a link
|
|
645
|
+
|
|
646
|
+
A join link looks like `https://<web app host>/call/<slug>`. Pass the slug to `<Chat>` and, once the user is signed in and the room list has loaded, the chat selects that room and shows the pre-join panel. Nothing starts until the user taps Join.
|
|
647
|
+
|
|
648
|
+
```tsx
|
|
649
|
+
import { Chat, parseScheduledCallLink, openScheduledCall } from '@ethora/chat-component';
|
|
650
|
+
|
|
651
|
+
// Declarative: the route /call/:slug renders the chat with the slug.
|
|
652
|
+
<Chat config={config} scheduledCallSlug={slug} />
|
|
653
|
+
|
|
654
|
+
// Imperative: from a deep-link handler, any time after import.
|
|
655
|
+
const slug = parseScheduledCallLink(url); // null when `url` is not a join link
|
|
656
|
+
if (slug) openScheduledCall(slug);
|
|
657
|
+
```
|
|
658
|
+
|
|
659
|
+
`parseScheduledCallLink(url, options?)` accepts `https://<host>/call/<slug>` and `<scheme>://call/<slug>` (never plain `http`), on `app.chat.ethora.com`, the page's own host and `options.hosts` (or, when omitted, `config.scheduledCalls.hosts`); schemes follow `options.schemes` or the configured ones. A request made before sign-in or before `<Chat>` is mounted is held and opened once both are true. A slug that cannot be opened (unknown, not a member, cancelled, offline) shows a toast and calls `config.scheduledCalls.onOpenError({ slug, reason })` with `reason` one of `'not-found' | 'not-a-member' | 'cancelled' | 'network'`. A host that wants its own error screens can call `GET /v1/chats/calls/scheduled/:slug` itself first (as `ethora-app-reactjs` does) and only mount the chat for a call that can be opened.
|
|
660
|
+
|
|
661
|
+
| Option | Type | Description |
|
|
662
|
+
| --- | --- | --- |
|
|
663
|
+
| `scheduledCalls.enabled` | `boolean` | Default `true` when `videoCalls.enabled` is on. `false` hides the "Schedule call" button and the Join button on cards; cards still render with their calendar links. |
|
|
664
|
+
| `scheduledCalls.hosts` | `string[]` | Extra hosts whose `https://<host>/call/<slug>` links `parseScheduledCallLink` accepts, on top of `app.chat.ethora.com` and the page's own host. Same option and defaults as the React Native SDK. |
|
|
665
|
+
| `scheduledCalls.schemes` | `string[]` | App URL schemes (without `://`) accepted for `<scheme>://call/<slug>`. Unset accepts any scheme. |
|
|
666
|
+
| `scheduledCalls.onOpenError` | `(e: { slug: string; reason: ScheduledCallOpenError }) => void` | Called when `scheduledCallSlug` / `openScheduledCall` could not open a call. |
|
|
667
|
+
|
|
668
|
+
Notes: the invite message is sent by the backend in the clear, also in `e2ee` rooms, like other system messages. Calendar links on a card are accepted only when they are plausible (https calendar provider hosts, and an `.ics` link on the API's own origin), because any member could forge the message attributes.
|
|
669
|
+
|
|
587
670
|
## Push Notifications
|
|
588
671
|
|
|
589
672
|
### Prerequisites
|
|
@@ -745,6 +828,8 @@ With `videoCalls.enabled: true` and push enabled, a data-only call push (`type:
|
|
|
745
828
|
| `useInAppNotifications` | hook | Enables and handles in-app notifications. |
|
|
746
829
|
| `usePushNotifications` | hook | Push subscription + foreground handling workflow. |
|
|
747
830
|
| `resendMessage` | function | Retry sending failed/pending messages. |
|
|
831
|
+
| `parseScheduledCallLink` | function | `parseScheduledCallLink(url)` returns the slug of a scheduled-call join link (`https://<host>/call/<slug>` or `<scheme>://call/<slug>`), or `null`. |
|
|
832
|
+
| `openScheduledCall` | function | `openScheduledCall(slug)` asks the mounted `<Chat>` to select that call's room and show its pre-join panel; held until the user is signed in. Returns `false` for an implausible slug. |
|
|
748
833
|
| `useRoomMute` | hook | `useRoomMute(roomJid)` returns `{ muted, isSupported, isPending, toggleMute, setMuted }` for a room's mute preference - optimistic with rollback on failure. `isSupported` is only `true` once the backend has reported a `muted` boolean for that room (it hasn't shipped to prod yet), so hosts building their own UI should hide a mute control until then. |
|
|
749
834
|
|
|
750
835
|
Basic hook usage:
|