@chatlychat/react-native 0.0.0-stage → 0.1.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/README.md +208 -2
- package/dist/ChatlyProvider.d.ts +69 -0
- package/dist/ChatlyProvider.d.ts.map +1 -0
- package/dist/ChatlyProvider.js +146 -0
- package/dist/ChatlyProvider.js.map +1 -0
- package/dist/ChatlyWidget.d.ts +15 -0
- package/dist/ChatlyWidget.d.ts.map +1 -0
- package/dist/ChatlyWidget.js +122 -0
- package/dist/ChatlyWidget.js.map +1 -0
- package/dist/blocks/money.d.ts +56 -0
- package/dist/blocks/money.d.ts.map +1 -0
- package/dist/blocks/money.js +82 -0
- package/dist/blocks/money.js.map +1 -0
- package/dist/blocks/money.parity.spec.d.ts +2 -0
- package/dist/blocks/money.parity.spec.d.ts.map +1 -0
- package/dist/blocks/money.parity.spec.js +87 -0
- package/dist/blocks/money.parity.spec.js.map +1 -0
- package/dist/blocks/read-envelope.d.ts +15 -0
- package/dist/blocks/read-envelope.d.ts.map +1 -0
- package/dist/blocks/read-envelope.js +196 -0
- package/dist/blocks/read-envelope.js.map +1 -0
- package/dist/blocks/read-envelope.parity.spec.d.ts +2 -0
- package/dist/blocks/read-envelope.parity.spec.d.ts.map +1 -0
- package/dist/blocks/read-envelope.parity.spec.js +146 -0
- package/dist/blocks/read-envelope.parity.spec.js.map +1 -0
- package/dist/blocks/types.d.ts +171 -0
- package/dist/blocks/types.d.ts.map +1 -0
- package/dist/blocks/types.js +3 -0
- package/dist/blocks/types.js.map +1 -0
- package/dist/client/RealtimeClient.d.ts +29 -0
- package/dist/client/RealtimeClient.d.ts.map +1 -0
- package/dist/client/RealtimeClient.js +113 -0
- package/dist/client/RealtimeClient.js.map +1 -0
- package/dist/client/RealtimeClient.spec.d.ts +2 -0
- package/dist/client/RealtimeClient.spec.d.ts.map +1 -0
- package/dist/client/RealtimeClient.spec.js +123 -0
- package/dist/client/RealtimeClient.spec.js.map +1 -0
- package/dist/client/RestClient.d.ts +160 -0
- package/dist/client/RestClient.d.ts.map +1 -0
- package/dist/client/RestClient.js +395 -0
- package/dist/client/RestClient.js.map +1 -0
- package/dist/client/RestClient.spec.d.ts +2 -0
- package/dist/client/RestClient.spec.d.ts.map +1 -0
- package/dist/client/RestClient.spec.js +267 -0
- package/dist/client/RestClient.spec.js.map +1 -0
- package/dist/client/types.d.ts +148 -0
- package/dist/client/types.d.ts.map +1 -0
- package/dist/client/types.js +14 -0
- package/dist/client/types.js.map +1 -0
- package/dist/components/Composer.d.ts +35 -0
- package/dist/components/Composer.d.ts.map +1 -0
- package/dist/components/Composer.js +180 -0
- package/dist/components/Composer.js.map +1 -0
- package/dist/components/HelpCenter.d.ts +13 -0
- package/dist/components/HelpCenter.d.ts.map +1 -0
- package/dist/components/HelpCenter.js +96 -0
- package/dist/components/HelpCenter.js.map +1 -0
- package/dist/components/MessageBlocks.d.ts +41 -0
- package/dist/components/MessageBlocks.d.ts.map +1 -0
- package/dist/components/MessageBlocks.js +167 -0
- package/dist/components/MessageBlocks.js.map +1 -0
- package/dist/components/MessageBubble.d.ts +14 -0
- package/dist/components/MessageBubble.d.ts.map +1 -0
- package/dist/components/MessageBubble.js +87 -0
- package/dist/components/MessageBubble.js.map +1 -0
- package/dist/components/MessageBubble.spec.d.ts +2 -0
- package/dist/components/MessageBubble.spec.d.ts.map +1 -0
- package/dist/components/MessageBubble.spec.js +207 -0
- package/dist/components/MessageBubble.spec.js.map +1 -0
- package/dist/components/MessageCanvas.d.ts +39 -0
- package/dist/components/MessageCanvas.d.ts.map +1 -0
- package/dist/components/MessageCanvas.js +144 -0
- package/dist/components/MessageCanvas.js.map +1 -0
- package/dist/components/MessageCanvas.spec.d.ts +2 -0
- package/dist/components/MessageCanvas.spec.d.ts.map +1 -0
- package/dist/components/MessageCanvas.spec.js +142 -0
- package/dist/components/MessageCanvas.spec.js.map +1 -0
- package/dist/components/MessagesList.d.ts +8 -0
- package/dist/components/MessagesList.d.ts.map +1 -0
- package/dist/components/MessagesList.js +58 -0
- package/dist/components/MessagesList.js.map +1 -0
- package/dist/index.d.ts +48 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +35 -0
- package/dist/index.js.map +1 -0
- package/dist/push/registerPushToken.d.ts +12 -0
- package/dist/push/registerPushToken.d.ts.map +1 -0
- package/dist/push/registerPushToken.js +32 -0
- package/dist/push/registerPushToken.js.map +1 -0
- package/dist/storage/TokenStore.d.ts +53 -0
- package/dist/storage/TokenStore.d.ts.map +1 -0
- package/dist/storage/TokenStore.js +89 -0
- package/dist/storage/TokenStore.js.map +1 -0
- package/dist/test/react-native-dom.d.ts +97 -0
- package/dist/test/react-native-dom.d.ts.map +1 -0
- package/dist/test/react-native-dom.js +155 -0
- package/dist/test/react-native-dom.js.map +1 -0
- package/dist/test/react-native-dom.spec.d.ts +2 -0
- package/dist/test/react-native-dom.spec.d.ts.map +1 -0
- package/dist/test/react-native-dom.spec.js +83 -0
- package/dist/test/react-native-dom.spec.js.map +1 -0
- package/dist/theme/ChatlyTheme.d.ts +37 -0
- package/dist/theme/ChatlyTheme.d.ts.map +1 -0
- package/dist/theme/ChatlyTheme.js +2 -0
- package/dist/theme/ChatlyTheme.js.map +1 -0
- package/dist/theme/defaultTheme.d.ts +7 -0
- package/dist/theme/defaultTheme.d.ts.map +1 -0
- package/dist/theme/defaultTheme.js +37 -0
- package/dist/theme/defaultTheme.js.map +1 -0
- package/dist/useChatly.d.ts +3 -0
- package/dist/useChatly.d.ts.map +1 -0
- package/dist/useChatly.js +10 -0
- package/dist/useChatly.js.map +1 -0
- package/package.json +50 -4
package/README.md
CHANGED
|
@@ -1,3 +1,209 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @chatlychat/react-native
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
React Native SDK for the Chatly live chat platform. Drop-in chat inbox, help
|
|
4
|
+
center, and push-notification wiring for iOS and Android. Talks to the same
|
|
5
|
+
`/v1/widget/*` REST surface and Socket.IO realtime channel as the web widget.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
npm install @chatlychat/react-native @react-native-async-storage/async-storage
|
|
11
|
+
# or
|
|
12
|
+
yarn add @chatlychat/react-native @react-native-async-storage/async-storage
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
`react`, `react-native`, and `@react-native-async-storage/async-storage` are
|
|
16
|
+
peer dependencies. `socket.io-client` is bundled.
|
|
17
|
+
|
|
18
|
+
For bare React Native apps, run `pod install` in `ios/` after installing
|
|
19
|
+
AsyncStorage.
|
|
20
|
+
|
|
21
|
+
## Quick start
|
|
22
|
+
|
|
23
|
+
Wrap your app in `<ChatlyProvider>` and drop in `<ChatlyWidget />`.
|
|
24
|
+
|
|
25
|
+
```tsx
|
|
26
|
+
import { ChatlyProvider, ChatlyWidget, useChatly } from '@chatlychat/react-native';
|
|
27
|
+
|
|
28
|
+
export default function App() {
|
|
29
|
+
return (
|
|
30
|
+
<ChatlyProvider config={{ publicId: 'pub_abc123', apiHost: 'api.chatly.com' }}>
|
|
31
|
+
<Support />
|
|
32
|
+
</ChatlyProvider>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function Support() {
|
|
37
|
+
const { unreadCount, identify, setPushToken } = useChatly();
|
|
38
|
+
return <ChatlyWidget />;
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Identifying users
|
|
43
|
+
|
|
44
|
+
Call `identify()` once you know who the user is. The SDK persists a visitor
|
|
45
|
+
token under `chatly:vt:<publicId>` in AsyncStorage, so subsequent app launches
|
|
46
|
+
re-attach to the same contact automatically.
|
|
47
|
+
|
|
48
|
+
```tsx
|
|
49
|
+
const { identify } = useChatly();
|
|
50
|
+
|
|
51
|
+
await identify({
|
|
52
|
+
externalId: 'user-123',
|
|
53
|
+
email: 'alex@example.com',
|
|
54
|
+
name: 'Alex',
|
|
55
|
+
// HMAC-SHA256(externalId, workspace identity secret). Compute server-side.
|
|
56
|
+
userHash: 'a1b2c3…',
|
|
57
|
+
});
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
`userHash` is optional but strongly recommended in production — without it,
|
|
61
|
+
any client could impersonate any `externalId`.
|
|
62
|
+
|
|
63
|
+
## Push notifications
|
|
64
|
+
|
|
65
|
+
The SDK does not bundle a push provider — pick the one that suits your app:
|
|
66
|
+
|
|
67
|
+
- Expo: `expo-notifications` → `getDevicePushTokenAsync()`
|
|
68
|
+
- Bare RN: `@react-native-firebase/messaging` → `messaging().getToken()`
|
|
69
|
+
- iOS APNs directly: `@react-native-community/push-notification-ios`
|
|
70
|
+
|
|
71
|
+
Then forward the token to Chatly:
|
|
72
|
+
|
|
73
|
+
```tsx
|
|
74
|
+
import messaging from '@react-native-firebase/messaging';
|
|
75
|
+
|
|
76
|
+
const { setPushToken } = useChatly();
|
|
77
|
+
|
|
78
|
+
useEffect(() => {
|
|
79
|
+
(async () => {
|
|
80
|
+
const auth = await messaging().requestPermission();
|
|
81
|
+
if (auth) {
|
|
82
|
+
const token = await messaging().getToken();
|
|
83
|
+
await setPushToken({ platform: 'ios', token, bundleId: 'com.your.app' });
|
|
84
|
+
}
|
|
85
|
+
})();
|
|
86
|
+
}, [setPushToken]);
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
On the native side you still need the standard setup for your provider:
|
|
90
|
+
|
|
91
|
+
- iOS: enable Push Notifications + Background Modes (Remote notifications) in
|
|
92
|
+
Xcode, and configure an APNs key in the Chatly dashboard.
|
|
93
|
+
- Android: add `google-services.json` and the FCM Sender ID in the dashboard.
|
|
94
|
+
|
|
95
|
+
## Customization
|
|
96
|
+
|
|
97
|
+
Pass a `theme` prop to override the defaults. Anything you omit falls back to
|
|
98
|
+
the default palette (primary `#2563eb`, background `#ffffff`, foreground
|
|
99
|
+
`#0f172a`).
|
|
100
|
+
|
|
101
|
+
```tsx
|
|
102
|
+
<ChatlyProvider
|
|
103
|
+
config={{ publicId: 'pub_abc123' }}
|
|
104
|
+
theme={{ colors: { primary: '#10b981', onPrimary: '#ffffff' } }}
|
|
105
|
+
>
|
|
106
|
+
<App />
|
|
107
|
+
</ChatlyProvider>
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Need full control over rendering? Use the lower-level pieces directly:
|
|
111
|
+
|
|
112
|
+
```tsx
|
|
113
|
+
import { MessagesList, Composer, HelpCenter } from '@chatlychat/react-native';
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Rich blocks and card actions
|
|
117
|
+
|
|
118
|
+
Bot replies can carry cards, a carousel, a price, quick replies and a status
|
|
119
|
+
line. `MessageBubble` renders them, so you get them for free — and the buttons
|
|
120
|
+
on them are real buttons, unlike the read-only rendering in the agent app.
|
|
121
|
+
|
|
122
|
+
Four of the five action kinds are handled for you: a `url` opens a link, a
|
|
123
|
+
`postback` sends a reply (invisibly, if the card asked), a `step` requests a
|
|
124
|
+
canvas. The fifth is yours.
|
|
125
|
+
|
|
126
|
+
### `host_event` — the one your app has to run
|
|
127
|
+
|
|
128
|
+
A card saying **Pay $48.20** cannot run Stripe from inside a chat library. It
|
|
129
|
+
has to happen in your app, with the buyer's real session and a native payment
|
|
130
|
+
sheet. So the SDK does nothing for a `host_event` and calls you:
|
|
131
|
+
|
|
132
|
+
```tsx
|
|
133
|
+
<ChatlyProvider
|
|
134
|
+
config={{ publicId: 'pub_abc123' }}
|
|
135
|
+
onAction={async ({ event, data, conversationId, messageId, actionId }) => {
|
|
136
|
+
if (event !== 'pay' || conversationId === null) return;
|
|
137
|
+
try {
|
|
138
|
+
await presentNativePaymentSheet(data);
|
|
139
|
+
await rest.reportAction(conversationId, {
|
|
140
|
+
messageId,
|
|
141
|
+
actionId,
|
|
142
|
+
status: 'done',
|
|
143
|
+
text: 'Paid — thank you!',
|
|
144
|
+
});
|
|
145
|
+
} catch (err) {
|
|
146
|
+
await rest.reportAction(conversationId, { messageId, actionId, status: 'failed' });
|
|
147
|
+
}
|
|
148
|
+
}}
|
|
149
|
+
>
|
|
150
|
+
<App />
|
|
151
|
+
</ChatlyProvider>
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
**Report the outcome.** `reportAction` is what appends the visible line under
|
|
155
|
+
the card and tells the bot what happened. Without it the shopper is looking at
|
|
156
|
+
a card with nothing under it and the bot asks again.
|
|
157
|
+
|
|
158
|
+
### Canvas steps
|
|
159
|
+
|
|
160
|
+
A Tier 2 canvas is a form inside the bubble — a confirm step for a purchase,
|
|
161
|
+
a return request. `MessageCanvas` renders it and submits it, and the step's
|
|
162
|
+
answer replaces what is on screen: a changed total comes back as a **fresh
|
|
163
|
+
step** rather than a charge.
|
|
164
|
+
|
|
165
|
+
A step's answer may itself carry a host event (this is how 3-D Secure works on
|
|
166
|
+
a phone), and that reaches the same `onAction`.
|
|
167
|
+
|
|
168
|
+
A Tier 3 canvas — your own page in a sandboxed frame — is deliberately **not**
|
|
169
|
+
rendered. There is no React Native equivalent of a sandbox attribute, and a
|
|
170
|
+
WebView is the thing a native SDK exists to avoid. The SDK shows the step's
|
|
171
|
+
title and leaves it to you.
|
|
172
|
+
|
|
173
|
+
### Rendering blocks yourself
|
|
174
|
+
|
|
175
|
+
Want your own card design, a real markdown renderer, a video player, a native
|
|
176
|
+
clipboard? Read the envelope and render it:
|
|
177
|
+
|
|
178
|
+
```tsx
|
|
179
|
+
import { readBlocksEnvelope, formatMoney } from '@chatlychat/react-native';
|
|
180
|
+
|
|
181
|
+
const envelope = readBlocksEnvelope(message.blocks);
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
`readBlocksEnvelope` applies the same refusals the rest of the product does —
|
|
185
|
+
`https:` media only, an unreadable price dropped rather than rendered as
|
|
186
|
+
`NaN`, an unknown block type dropped instead of throwing. Prices are **minor
|
|
187
|
+
units**: `4820` is `$48.20` and also `¥4,820`. Use `formatMoney`; the divisor
|
|
188
|
+
is not 100.
|
|
189
|
+
|
|
190
|
+
## API surface
|
|
191
|
+
|
|
192
|
+
| Export | Purpose |
|
|
193
|
+
| --------------------------------------------------------- | -------------------------------------------------- |
|
|
194
|
+
| `ChatlyProvider` | Bootstraps clients, restores session |
|
|
195
|
+
| `ChatlyWidget` | Drop-in inbox + help center UI |
|
|
196
|
+
| `useChatly()` | Access session, identify, push token, refresh |
|
|
197
|
+
| `MessagesList`, `Composer`, `MessageBubble`, `HelpCenter` | Composable UI |
|
|
198
|
+
| `MessageBlocks`, `MessageCanvas` | Cards and canvas steps, rendered |
|
|
199
|
+
| `onAction` on `ChatlyProvider` | `host_event` card actions, for your app to run |
|
|
200
|
+
| `RestClient`, `RealtimeClient` | Headless access |
|
|
201
|
+
| `rest.reportAction` | Tell the thread and the bot what your app did |
|
|
202
|
+
| `readBlocksEnvelope`, `readCanvas` | Render blocks yourself, with the same refusals |
|
|
203
|
+
| `formatMoney`, `readMoney` | Minor-unit prices, formatted for the device locale |
|
|
204
|
+
| `registerPushToken` | Helper used by `setPushToken` |
|
|
205
|
+
| `defaultTheme`, `ChatlyTheme` | Theming |
|
|
206
|
+
|
|
207
|
+
## License
|
|
208
|
+
|
|
209
|
+
MIT
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* <ChatlyProvider /> bootstraps the REST + realtime clients, restores the
|
|
3
|
+
* persisted visitor token, fires `/v1/widget/init`, and exposes session state
|
|
4
|
+
* to descendants via the `useChatly` hook.
|
|
5
|
+
*
|
|
6
|
+
* The provider is intentionally state-light: the heavy lifting (message lists,
|
|
7
|
+
* composer state) lives in the components that use it. This keeps the public
|
|
8
|
+
* context surface stable as we add features.
|
|
9
|
+
*/
|
|
10
|
+
import React from 'react';
|
|
11
|
+
import { RealtimeClient } from './client/RealtimeClient';
|
|
12
|
+
import { RestClient } from './client/RestClient';
|
|
13
|
+
import type { ChatlyConfig, ChatlyIdentity, ConversationSummary, InitResponse, PushTokenRegistration, SessionState } from './client/types';
|
|
14
|
+
import type { ChatlyTheme } from './theme/ChatlyTheme';
|
|
15
|
+
export interface ChatlyContextValue {
|
|
16
|
+
config: ChatlyConfig;
|
|
17
|
+
theme: ChatlyTheme;
|
|
18
|
+
rest: RestClient;
|
|
19
|
+
realtime: RealtimeClient;
|
|
20
|
+
session: SessionState | null;
|
|
21
|
+
init: InitResponse | null;
|
|
22
|
+
isReady: boolean;
|
|
23
|
+
error: Error | null;
|
|
24
|
+
unreadCount: number;
|
|
25
|
+
conversations: ConversationSummary[];
|
|
26
|
+
identify: (identity: ChatlyIdentity) => Promise<void>;
|
|
27
|
+
logout: () => Promise<void>;
|
|
28
|
+
setPushToken: (registration: PushTokenRegistration) => Promise<void>;
|
|
29
|
+
refresh: () => Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* What the APP does about a `host_event` card action.
|
|
32
|
+
*
|
|
33
|
+
* The one feature a native SDK exists for. A card saying "Pay $48.20" has
|
|
34
|
+
* to run with the buyer's real session — a native payment sheet, the app's
|
|
35
|
+
* own cart, a screen push — and none of that can happen inside a chat
|
|
36
|
+
* library. So the renderer does nothing for a `host_event` and calls this.
|
|
37
|
+
*
|
|
38
|
+
* Report the outcome back with `rest.reportAction`, which appends the
|
|
39
|
+
* visible line under the card and tells the owning bot. Not reporting is a
|
|
40
|
+
* shopper looking at a card with nothing under it and a bot that asks
|
|
41
|
+
* again.
|
|
42
|
+
*
|
|
43
|
+
* `undefined` when the consumer did not supply one, and the renderer then
|
|
44
|
+
* draws the button and the tap does nothing — which is the right failure:
|
|
45
|
+
* a card that renders without its buttons would hide that the integrator
|
|
46
|
+
* has work to do.
|
|
47
|
+
*/
|
|
48
|
+
onAction?: ((event: ChatlyActionEvent) => void) | undefined;
|
|
49
|
+
}
|
|
50
|
+
/** One `host_event` tap, with everything needed to report the outcome. */
|
|
51
|
+
export interface ChatlyActionEvent {
|
|
52
|
+
/** The author's own event name, e.g. `add_to_cart`. */
|
|
53
|
+
readonly event: string;
|
|
54
|
+
readonly data: Record<string, unknown>;
|
|
55
|
+
readonly conversationId: string | null;
|
|
56
|
+
readonly messageId: string;
|
|
57
|
+
/** Pass this back to `reportAction` so the result lands under the card. */
|
|
58
|
+
readonly actionId: string;
|
|
59
|
+
}
|
|
60
|
+
export declare const ChatlyContext: React.Context<ChatlyContextValue | null>;
|
|
61
|
+
export interface ChatlyProviderProps {
|
|
62
|
+
config: ChatlyConfig;
|
|
63
|
+
theme?: Partial<ChatlyTheme>;
|
|
64
|
+
children: React.ReactNode;
|
|
65
|
+
/** See `ChatlyContextValue.onAction`. */
|
|
66
|
+
onAction?: (event: ChatlyActionEvent) => void;
|
|
67
|
+
}
|
|
68
|
+
export declare function ChatlyProvider({ config, theme, children, onAction, }: ChatlyProviderProps): React.JSX.Element;
|
|
69
|
+
//# sourceMappingURL=ChatlyProvider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChatlyProvider.d.ts","sourceRoot":"","sources":["../src/ChatlyProvider.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAA2E,MAAM,OAAO,CAAC;AAEhG,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAIjD,OAAO,KAAK,EACV,YAAY,EACZ,cAAc,EACd,mBAAmB,EACnB,YAAY,EACZ,qBAAqB,EACrB,YAAY,EACb,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,YAAY,CAAC;IACrB,KAAK,EAAE,WAAW,CAAC;IACnB,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,cAAc,CAAC;IACzB,OAAO,EAAE,YAAY,GAAG,IAAI,CAAC;IAC7B,IAAI,EAAE,YAAY,GAAG,IAAI,CAAC;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,mBAAmB,EAAE,CAAC;IACrC,QAAQ,EAAE,CAAC,QAAQ,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACtD,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,YAAY,EAAE,CAAC,YAAY,EAAE,qBAAqB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACrE,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B;;;;;;;;;;;;;;;;;OAiBG;IACH,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;CAC7D;AAED,0EAA0E;AAC1E,MAAM,WAAW,iBAAiB;IAChC,uDAAuD;IACvD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACvC,QAAQ,CAAC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IACvC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,2EAA2E;IAC3E,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,eAAO,MAAM,aAAa,0CAAiD,CAAC;AAE5E,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,YAAY,CAAC;IACrB,KAAK,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;IAC7B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,yCAAyC;IACzC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC;CAC/C;AAED,wBAAgB,cAAc,CAAC,EAC7B,MAAM,EACN,KAAK,EACL,QAAQ,EACR,QAAQ,GACT,EAAE,mBAAmB,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CA6IzC"}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* <ChatlyProvider /> bootstraps the REST + realtime clients, restores the
|
|
4
|
+
* persisted visitor token, fires `/v1/widget/init`, and exposes session state
|
|
5
|
+
* to descendants via the `useChatly` hook.
|
|
6
|
+
*
|
|
7
|
+
* The provider is intentionally state-light: the heavy lifting (message lists,
|
|
8
|
+
* composer state) lives in the components that use it. This keeps the public
|
|
9
|
+
* context surface stable as we add features.
|
|
10
|
+
*/
|
|
11
|
+
import { createContext, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
12
|
+
import { RealtimeClient } from './client/RealtimeClient';
|
|
13
|
+
import { RestClient } from './client/RestClient';
|
|
14
|
+
import { registerPushToken } from './push/registerPushToken';
|
|
15
|
+
import { defaultTheme } from './theme/defaultTheme';
|
|
16
|
+
export const ChatlyContext = createContext(null);
|
|
17
|
+
export function ChatlyProvider({ config, theme, children, onAction, }) {
|
|
18
|
+
const rest = useMemo(() => new RestClient(config), [config]);
|
|
19
|
+
const realtime = useMemo(() => new RealtimeClient(config), [config]);
|
|
20
|
+
const mergedTheme = useMemo(() => mergeTheme(defaultTheme, theme), [theme]);
|
|
21
|
+
const [session, setSession] = useState(null);
|
|
22
|
+
const [init, setInit] = useState(null);
|
|
23
|
+
const [error, setError] = useState(null);
|
|
24
|
+
const [conversations, setConversations] = useState([]);
|
|
25
|
+
const mounted = useRef(true);
|
|
26
|
+
const bootstrap = useCallback(async (identity) => {
|
|
27
|
+
try {
|
|
28
|
+
const result = await rest.init(identity);
|
|
29
|
+
if (!mounted.current) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
setInit(result);
|
|
33
|
+
setSession(result.session);
|
|
34
|
+
realtime.connect(result.session, result.session.token);
|
|
35
|
+
realtime.subscribe([`contact:${result.session.contactId}`]);
|
|
36
|
+
try {
|
|
37
|
+
const list = await rest.listConversations();
|
|
38
|
+
if (mounted.current) {
|
|
39
|
+
setConversations(list.conversations);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
// Non-fatal: surface as zero conversations rather than blocking init.
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
if (mounted.current) {
|
|
48
|
+
setError(err);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}, [rest, realtime]);
|
|
52
|
+
useEffect(() => {
|
|
53
|
+
mounted.current = true;
|
|
54
|
+
void bootstrap();
|
|
55
|
+
return () => {
|
|
56
|
+
mounted.current = false;
|
|
57
|
+
realtime.disconnect();
|
|
58
|
+
};
|
|
59
|
+
}, [bootstrap, realtime]);
|
|
60
|
+
// Refresh conversation summaries on inbound message events.
|
|
61
|
+
useEffect(() => {
|
|
62
|
+
const off = realtime.on('message.created', () => {
|
|
63
|
+
void rest
|
|
64
|
+
.listConversations()
|
|
65
|
+
.then((res) => {
|
|
66
|
+
if (mounted.current) {
|
|
67
|
+
setConversations(res.conversations);
|
|
68
|
+
}
|
|
69
|
+
})
|
|
70
|
+
.catch(() => undefined);
|
|
71
|
+
});
|
|
72
|
+
return off;
|
|
73
|
+
}, [realtime, rest]);
|
|
74
|
+
const unreadCount = useMemo(() => conversations.reduce((acc, c) => acc + (c.unreadContactCount ?? 0), 0), [conversations]);
|
|
75
|
+
const identify = useCallback(async (identity) => {
|
|
76
|
+
await bootstrap(identity);
|
|
77
|
+
}, [bootstrap]);
|
|
78
|
+
const logout = useCallback(async () => {
|
|
79
|
+
realtime.disconnect();
|
|
80
|
+
await rest.clearToken();
|
|
81
|
+
setSession(null);
|
|
82
|
+
setInit(null);
|
|
83
|
+
setConversations([]);
|
|
84
|
+
}, [realtime, rest]);
|
|
85
|
+
const setPushToken = useCallback(async (registration) => {
|
|
86
|
+
await registerPushToken(rest, registration);
|
|
87
|
+
}, [rest]);
|
|
88
|
+
const refresh = useCallback(async () => {
|
|
89
|
+
try {
|
|
90
|
+
const res = await rest.listConversations();
|
|
91
|
+
if (mounted.current) {
|
|
92
|
+
setConversations(res.conversations);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
catch (err) {
|
|
96
|
+
if (mounted.current) {
|
|
97
|
+
setError(err);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}, [rest]);
|
|
101
|
+
const value = useMemo(() => ({
|
|
102
|
+
config,
|
|
103
|
+
theme: mergedTheme,
|
|
104
|
+
rest,
|
|
105
|
+
realtime,
|
|
106
|
+
session,
|
|
107
|
+
init,
|
|
108
|
+
isReady: session !== null,
|
|
109
|
+
error,
|
|
110
|
+
unreadCount,
|
|
111
|
+
conversations,
|
|
112
|
+
identify,
|
|
113
|
+
logout,
|
|
114
|
+
setPushToken,
|
|
115
|
+
refresh,
|
|
116
|
+
onAction,
|
|
117
|
+
}), [
|
|
118
|
+
config,
|
|
119
|
+
mergedTheme,
|
|
120
|
+
rest,
|
|
121
|
+
realtime,
|
|
122
|
+
session,
|
|
123
|
+
init,
|
|
124
|
+
error,
|
|
125
|
+
unreadCount,
|
|
126
|
+
conversations,
|
|
127
|
+
identify,
|
|
128
|
+
logout,
|
|
129
|
+
setPushToken,
|
|
130
|
+
refresh,
|
|
131
|
+
onAction,
|
|
132
|
+
]);
|
|
133
|
+
return _jsx(ChatlyContext.Provider, { value: value, children: children });
|
|
134
|
+
}
|
|
135
|
+
function mergeTheme(base, override) {
|
|
136
|
+
if (override === undefined) {
|
|
137
|
+
return base;
|
|
138
|
+
}
|
|
139
|
+
return {
|
|
140
|
+
colors: { ...base.colors, ...(override.colors ?? {}) },
|
|
141
|
+
radius: { ...base.radius, ...(override.radius ?? {}) },
|
|
142
|
+
spacing: { ...base.spacing, ...(override.spacing ?? {}) },
|
|
143
|
+
typography: { ...base.typography, ...(override.typography ?? {}) },
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=ChatlyProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChatlyProvider.js","sourceRoot":"","sources":["../src/ChatlyProvider.tsx"],"names":[],"mappings":";AAAA;;;;;;;;GAQG;AAEH,OAAc,EAAE,aAAa,EAAE,WAAW,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAEhG,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AA2DpD,MAAM,CAAC,MAAM,aAAa,GAAG,aAAa,CAA4B,IAAI,CAAC,CAAC;AAU5E,MAAM,UAAU,cAAc,CAAC,EAC7B,MAAM,EACN,KAAK,EACL,QAAQ,EACR,QAAQ,GACY;IACpB,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,IAAI,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;IAC7D,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,IAAI,cAAc,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;IAErE,MAAM,WAAW,GAAG,OAAO,CAAc,GAAG,EAAE,CAAC,UAAU,CAAC,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;IAEzF,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAsB,IAAI,CAAC,CAAC;IAClE,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAsB,IAAI,CAAC,CAAC;IAC5D,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAe,IAAI,CAAC,CAAC;IACvD,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,QAAQ,CAAwB,EAAE,CAAC,CAAC;IAC9E,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;IAE7B,MAAM,SAAS,GAAG,WAAW,CAC3B,KAAK,EAAE,QAAyB,EAAiB,EAAE;QACjD,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACzC,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;gBACrB,OAAO;YACT,CAAC;YACD,OAAO,CAAC,MAAM,CAAC,CAAC;YAChB,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YAC3B,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;YACvD,QAAQ,CAAC,SAAS,CAAC,CAAC,WAAW,MAAM,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;YAC5D,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,iBAAiB,EAAE,CAAC;gBAC5C,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;oBACpB,gBAAgB,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;gBACvC,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,sEAAsE;YACxE,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;gBACpB,QAAQ,CAAC,GAAY,CAAC,CAAC;YACzB,CAAC;QACH,CAAC;IACH,CAAC,EACD,CAAC,IAAI,EAAE,QAAQ,CAAC,CACjB,CAAC;IAEF,SAAS,CAAC,GAAG,EAAE;QACb,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;QACvB,KAAK,SAAS,EAAE,CAAC;QACjB,OAAO,GAAS,EAAE;YAChB,OAAO,CAAC,OAAO,GAAG,KAAK,CAAC;YACxB,QAAQ,CAAC,UAAU,EAAE,CAAC;QACxB,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC;IAE1B,4DAA4D;IAC5D,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,GAAG,GAAG,QAAQ,CAAC,EAAE,CAAC,iBAAiB,EAAE,GAAG,EAAE;YAC9C,KAAK,IAAI;iBACN,iBAAiB,EAAE;iBACnB,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE;gBACZ,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;oBACpB,gBAAgB,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;gBACtC,CAAC;YACH,CAAC,CAAC;iBACD,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QAC5B,CAAC,CAAC,CAAC;QACH,OAAO,GAAG,CAAC;IACb,CAAC,EAAE,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC;IAErB,MAAM,WAAW,GAAG,OAAO,CACzB,GAAG,EAAE,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,kBAAkB,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,EAC5E,CAAC,aAAa,CAAC,CAChB,CAAC;IAEF,MAAM,QAAQ,GAAG,WAAW,CAC1B,KAAK,EAAE,QAAwB,EAAiB,EAAE;QAChD,MAAM,SAAS,CAAC,QAAQ,CAAC,CAAC;IAC5B,CAAC,EACD,CAAC,SAAS,CAAC,CACZ,CAAC;IAEF,MAAM,MAAM,GAAG,WAAW,CAAC,KAAK,IAAmB,EAAE;QACnD,QAAQ,CAAC,UAAU,EAAE,CAAC;QACtB,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC;QACxB,UAAU,CAAC,IAAI,CAAC,CAAC;QACjB,OAAO,CAAC,IAAI,CAAC,CAAC;QACd,gBAAgB,CAAC,EAAE,CAAC,CAAC;IACvB,CAAC,EAAE,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC;IAErB,MAAM,YAAY,GAAG,WAAW,CAC9B,KAAK,EAAE,YAAmC,EAAiB,EAAE;QAC3D,MAAM,iBAAiB,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;IAC9C,CAAC,EACD,CAAC,IAAI,CAAC,CACP,CAAC;IAEF,MAAM,OAAO,GAAG,WAAW,CAAC,KAAK,IAAmB,EAAE;QACpD,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,iBAAiB,EAAE,CAAC;YAC3C,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;gBACpB,gBAAgB,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;YACtC,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;gBACpB,QAAQ,CAAC,GAAY,CAAC,CAAC;YACzB,CAAC;QACH,CAAC;IACH,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;IAEX,MAAM,KAAK,GAAG,OAAO,CACnB,GAAG,EAAE,CAAC,CAAC;QACL,MAAM;QACN,KAAK,EAAE,WAAW;QAClB,IAAI;QACJ,QAAQ;QACR,OAAO;QACP,IAAI;QACJ,OAAO,EAAE,OAAO,KAAK,IAAI;QACzB,KAAK;QACL,WAAW;QACX,aAAa;QACb,QAAQ;QACR,MAAM;QACN,YAAY;QACZ,OAAO;QACP,QAAQ;KACT,CAAC,EACF;QACE,MAAM;QACN,WAAW;QACX,IAAI;QACJ,QAAQ;QACR,OAAO;QACP,IAAI;QACJ,KAAK;QACL,WAAW;QACX,aAAa;QACb,QAAQ;QACR,MAAM;QACN,YAAY;QACZ,OAAO;QACP,QAAQ;KACT,CACF,CAAC;IAEF,OAAO,KAAC,aAAa,CAAC,QAAQ,IAAC,KAAK,EAAE,KAAK,YAAG,QAAQ,GAA0B,CAAC;AACnF,CAAC;AAED,SAAS,UAAU,CAAC,IAAiB,EAAE,QAA+B;IACpE,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO;QACL,MAAM,EAAE,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,QAAQ,CAAC,MAAM,IAAI,EAAE,CAAC,EAAE;QACtD,MAAM,EAAE,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,QAAQ,CAAC,MAAM,IAAI,EAAE,CAAC,EAAE;QACtD,OAAO,EAAE,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,QAAQ,CAAC,OAAO,IAAI,EAAE,CAAC,EAAE;QACzD,UAAU,EAAE,EAAE,GAAG,IAAI,CAAC,UAAU,EAAE,GAAG,CAAC,QAAQ,CAAC,UAAU,IAAI,EAAE,CAAC,EAAE;KACnE,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* <ChatlyWidget /> — drop-in inbox surface. Renders the conversation list when
|
|
3
|
+
* none is selected, the message view + composer when one is, and (optionally)
|
|
4
|
+
* the help center via a tab toggle. Mirrors the "open the bubble, see your
|
|
5
|
+
* conversations" UX of Tawk.to / Intercom mobile SDKs.
|
|
6
|
+
*/
|
|
7
|
+
import React from 'react';
|
|
8
|
+
export interface ChatlyWidgetProps {
|
|
9
|
+
/** Show the help-center tab. Defaults to true. */
|
|
10
|
+
enableHelpCenter?: boolean;
|
|
11
|
+
/** Pre-open a specific conversation. */
|
|
12
|
+
initialConversationId?: string;
|
|
13
|
+
}
|
|
14
|
+
export declare function ChatlyWidget({ enableHelpCenter, initialConversationId, }: ChatlyWidgetProps): React.JSX.Element;
|
|
15
|
+
//# sourceMappingURL=ChatlyWidget.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChatlyWidget.d.ts","sourceRoot":"","sources":["../src/ChatlyWidget.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAA2C,MAAM,OAAO,CAAC;AAqBhE,MAAM,WAAW,iBAAiB;IAChC,kDAAkD;IAClD,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,wCAAwC;IACxC,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAChC;AAED,wBAAgB,YAAY,CAAC,EAC3B,gBAAuB,EACvB,qBAAqB,GACtB,EAAE,iBAAiB,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAmIvC"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* <ChatlyWidget /> — drop-in inbox surface. Renders the conversation list when
|
|
4
|
+
* none is selected, the message view + composer when one is, and (optionally)
|
|
5
|
+
* the help center via a tab toggle. Mirrors the "open the bubble, see your
|
|
6
|
+
* conversations" UX of Tawk.to / Intercom mobile SDKs.
|
|
7
|
+
*/
|
|
8
|
+
import { useCallback, useEffect, useState } from 'react';
|
|
9
|
+
import { ActivityIndicator, FlatList, Pressable, SafeAreaView, StyleSheet, Text, View, } from 'react-native';
|
|
10
|
+
import { Composer } from './components/Composer';
|
|
11
|
+
import { HelpCenter } from './components/HelpCenter';
|
|
12
|
+
import { MessagesList } from './components/MessagesList';
|
|
13
|
+
import { useChatly } from './useChatly';
|
|
14
|
+
export function ChatlyWidget({ enableHelpCenter = true, initialConversationId, }) {
|
|
15
|
+
const { isReady, error, conversations, theme, refresh, init } = useChatly();
|
|
16
|
+
const [tab, setTab] = useState('messages');
|
|
17
|
+
const [selected, setSelected] = useState(initialConversationId ?? null);
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
if (initialConversationId !== undefined) {
|
|
20
|
+
setSelected(initialConversationId);
|
|
21
|
+
}
|
|
22
|
+
}, [initialConversationId]);
|
|
23
|
+
const onSent = useCallback((conversationId) => {
|
|
24
|
+
setSelected(conversationId);
|
|
25
|
+
void refresh();
|
|
26
|
+
}, [refresh]);
|
|
27
|
+
if (error !== null) {
|
|
28
|
+
return (_jsx(SafeAreaView, { style: [styles.fill, { backgroundColor: theme.colors.background }], children: _jsx(View, { style: styles.center, children: _jsx(Text, { style: { color: theme.colors.danger, padding: theme.spacing.lg }, children: `Couldn't load chat: ${error.message}` }) }) }));
|
|
29
|
+
}
|
|
30
|
+
if (!isReady) {
|
|
31
|
+
return (_jsx(SafeAreaView, { style: [styles.fill, { backgroundColor: theme.colors.background }], children: _jsx(View, { style: styles.center, children: _jsx(ActivityIndicator, { color: theme.colors.primary }) }) }));
|
|
32
|
+
}
|
|
33
|
+
const header = (_jsxs(View, { style: [
|
|
34
|
+
styles.header,
|
|
35
|
+
{
|
|
36
|
+
borderBottomColor: theme.colors.border,
|
|
37
|
+
padding: theme.spacing.md,
|
|
38
|
+
backgroundColor: theme.colors.background,
|
|
39
|
+
},
|
|
40
|
+
], children: [_jsx(Text, { style: {
|
|
41
|
+
color: theme.colors.foreground,
|
|
42
|
+
fontSize: theme.typography.sizeTitle,
|
|
43
|
+
fontWeight: theme.typography.weightBold,
|
|
44
|
+
}, children: init?.workspace.name ?? 'Support' }), enableHelpCenter && (_jsxs(View, { style: styles.tabs, children: [_jsx(TabButton, { label: "Messages", active: tab === 'messages', onPress: () => setTab('messages') }), _jsx(TabButton, { label: "Help", active: tab === 'help', onPress: () => setTab('help') })] }))] }));
|
|
45
|
+
if (tab === 'help') {
|
|
46
|
+
return (_jsxs(SafeAreaView, { style: [styles.fill, { backgroundColor: theme.colors.background }], children: [header, _jsx(HelpCenter, {})] }));
|
|
47
|
+
}
|
|
48
|
+
if (selected !== null) {
|
|
49
|
+
return (_jsxs(SafeAreaView, { style: [styles.fill, { backgroundColor: theme.colors.background }], children: [_jsxs(View, { style: [
|
|
50
|
+
styles.header,
|
|
51
|
+
{
|
|
52
|
+
borderBottomColor: theme.colors.border,
|
|
53
|
+
padding: theme.spacing.md,
|
|
54
|
+
backgroundColor: theme.colors.background,
|
|
55
|
+
flexDirection: 'row',
|
|
56
|
+
alignItems: 'center',
|
|
57
|
+
},
|
|
58
|
+
], children: [_jsx(Pressable, { onPress: () => setSelected(null), accessibilityRole: "button", accessibilityLabel: "Back to conversation list", style: { paddingRight: theme.spacing.md }, children: _jsx(Text, { style: { color: theme.colors.primary, fontSize: theme.typography.sizeBody }, children: "\u2190" }) }), _jsx(Text, { style: {
|
|
59
|
+
color: theme.colors.foreground,
|
|
60
|
+
fontSize: theme.typography.sizeTitle,
|
|
61
|
+
fontWeight: theme.typography.weightBold,
|
|
62
|
+
}, children: "Conversation" })] }), _jsx(MessagesList, { conversationId: selected }), _jsx(Composer, { conversationId: selected, onSent: onSent })] }));
|
|
63
|
+
}
|
|
64
|
+
return (_jsxs(SafeAreaView, { style: [styles.fill, { backgroundColor: theme.colors.background }], children: [header, _jsx(ConversationList, { conversations: conversations, onOpen: setSelected }), _jsx(Composer, { conversationId: null, onSent: onSent, placeholder: "Start a new conversation\u2026" })] }));
|
|
65
|
+
}
|
|
66
|
+
function ConversationList({ conversations, onOpen, }) {
|
|
67
|
+
const { theme } = useChatly();
|
|
68
|
+
const renderItem = ({ item }) => (_jsxs(Pressable, { onPress: () => onOpen(item.id), accessibilityRole: "button", accessibilityLabel: `Open conversation ${item.subject ?? item.id}`, style: ({ pressed }) => [
|
|
69
|
+
{
|
|
70
|
+
padding: theme.spacing.md,
|
|
71
|
+
backgroundColor: pressed ? theme.colors.surface : theme.colors.background,
|
|
72
|
+
borderBottomColor: theme.colors.border,
|
|
73
|
+
borderBottomWidth: StyleSheet.hairlineWidth,
|
|
74
|
+
flexDirection: 'row',
|
|
75
|
+
alignItems: 'center',
|
|
76
|
+
},
|
|
77
|
+
], children: [_jsxs(View, { style: { flex: 1 }, children: [_jsx(Text, { style: {
|
|
78
|
+
color: theme.colors.foreground,
|
|
79
|
+
fontWeight: theme.typography.weightMedium,
|
|
80
|
+
fontSize: theme.typography.sizeBody,
|
|
81
|
+
}, children: item.subject ?? 'Conversation' }), _jsx(Text, { style: {
|
|
82
|
+
color: theme.colors.mutedForeground,
|
|
83
|
+
fontSize: theme.typography.sizeSmall,
|
|
84
|
+
marginTop: 2,
|
|
85
|
+
}, numberOfLines: 1, children: item.lastMessagePreview ?? 'No messages yet.' })] }), item.unreadContactCount > 0 && (_jsx(View, { style: {
|
|
86
|
+
backgroundColor: theme.colors.primary,
|
|
87
|
+
borderRadius: 999,
|
|
88
|
+
minWidth: 22,
|
|
89
|
+
paddingHorizontal: 6,
|
|
90
|
+
paddingVertical: 2,
|
|
91
|
+
alignItems: 'center',
|
|
92
|
+
}, children: _jsx(Text, { style: {
|
|
93
|
+
color: theme.colors.onPrimary,
|
|
94
|
+
fontSize: theme.typography.sizeSmall,
|
|
95
|
+
fontWeight: theme.typography.weightBold,
|
|
96
|
+
}, children: item.unreadContactCount }) }))] }));
|
|
97
|
+
return (_jsx(FlatList, { data: conversations, keyExtractor: (c) => c.id, renderItem: renderItem, ListEmptyComponent: _jsx(Text, { style: {
|
|
98
|
+
color: theme.colors.mutedForeground,
|
|
99
|
+
textAlign: 'center',
|
|
100
|
+
padding: theme.spacing.lg,
|
|
101
|
+
}, children: "No conversations yet. Send a message to get started." }) }));
|
|
102
|
+
}
|
|
103
|
+
function TabButton({ label, active, onPress, }) {
|
|
104
|
+
const { theme } = useChatly();
|
|
105
|
+
return (_jsx(Pressable, { onPress: onPress, accessibilityRole: "tab", accessibilityState: { selected: active }, style: {
|
|
106
|
+
paddingHorizontal: theme.spacing.md,
|
|
107
|
+
paddingVertical: theme.spacing.xs,
|
|
108
|
+
borderBottomColor: active ? theme.colors.primary : 'transparent',
|
|
109
|
+
borderBottomWidth: 2,
|
|
110
|
+
}, children: _jsx(Text, { style: {
|
|
111
|
+
color: active ? theme.colors.primary : theme.colors.mutedForeground,
|
|
112
|
+
fontWeight: active ? theme.typography.weightBold : theme.typography.weightRegular,
|
|
113
|
+
fontSize: theme.typography.sizeBody,
|
|
114
|
+
}, children: label }) }));
|
|
115
|
+
}
|
|
116
|
+
const styles = StyleSheet.create({
|
|
117
|
+
fill: { flex: 1 },
|
|
118
|
+
center: { flex: 1, alignItems: 'center', justifyContent: 'center' },
|
|
119
|
+
header: { borderBottomWidth: StyleSheet.hairlineWidth },
|
|
120
|
+
tabs: { flexDirection: 'row', marginTop: 6 },
|
|
121
|
+
});
|
|
122
|
+
//# sourceMappingURL=ChatlyWidget.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChatlyWidget.js","sourceRoot":"","sources":["../src/ChatlyWidget.tsx"],"names":[],"mappings":";AAAA;;;;;GAKG;AAEH,OAAc,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAChE,OAAO,EACL,iBAAiB,EACjB,QAAQ,EAER,SAAS,EACT,YAAY,EACZ,UAAU,EACV,IAAI,EACJ,IAAI,GACL,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAaxC,MAAM,UAAU,YAAY,CAAC,EAC3B,gBAAgB,GAAG,IAAI,EACvB,qBAAqB,GACH;IAClB,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,SAAS,EAAE,CAAC;IAC5E,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,QAAQ,CAAM,UAAU,CAAC,CAAC;IAChD,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAgB,qBAAqB,IAAI,IAAI,CAAC,CAAC;IAEvF,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,qBAAqB,KAAK,SAAS,EAAE,CAAC;YACxC,WAAW,CAAC,qBAAqB,CAAC,CAAC;QACrC,CAAC;IACH,CAAC,EAAE,CAAC,qBAAqB,CAAC,CAAC,CAAC;IAE5B,MAAM,MAAM,GAAG,WAAW,CACxB,CAAC,cAAsB,EAAE,EAAE;QACzB,WAAW,CAAC,cAAc,CAAC,CAAC;QAC5B,KAAK,OAAO,EAAE,CAAC;IACjB,CAAC,EACD,CAAC,OAAO,CAAC,CACV,CAAC;IAEF,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QACnB,OAAO,CACL,KAAC,YAAY,IAAC,KAAK,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,eAAe,EAAE,KAAK,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,YAC9E,KAAC,IAAI,IAAC,KAAK,EAAE,MAAM,CAAC,MAAM,YACxB,KAAC,IAAI,IAAC,KAAK,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,EAAE,EAAE,YACnE,uBAAuB,KAAK,CAAC,OAAO,EAAE,GAClC,GACF,GACM,CAChB,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,CACL,KAAC,YAAY,IAAC,KAAK,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,eAAe,EAAE,KAAK,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,YAC9E,KAAC,IAAI,IAAC,KAAK,EAAE,MAAM,CAAC,MAAM,YACxB,KAAC,iBAAiB,IAAC,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,OAAO,GAAI,GAC7C,GACM,CAChB,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,CACb,MAAC,IAAI,IACH,KAAK,EAAE;YACL,MAAM,CAAC,MAAM;YACb;gBACE,iBAAiB,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM;gBACtC,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,EAAE;gBACzB,eAAe,EAAE,KAAK,CAAC,MAAM,CAAC,UAAU;aACzC;SACF,aAED,KAAC,IAAI,IACH,KAAK,EAAE;oBACL,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,UAAU;oBAC9B,QAAQ,EAAE,KAAK,CAAC,UAAU,CAAC,SAAS;oBACpC,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,UAAU;iBACxC,YAEA,IAAI,EAAE,SAAS,CAAC,IAAI,IAAI,SAAS,GAC7B,EACN,gBAAgB,IAAI,CACnB,MAAC,IAAI,IAAC,KAAK,EAAE,MAAM,CAAC,IAAI,aACtB,KAAC,SAAS,IACR,KAAK,EAAC,UAAU,EAChB,MAAM,EAAE,GAAG,KAAK,UAAU,EAC1B,OAAO,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,GACjC,EACF,KAAC,SAAS,IAAC,KAAK,EAAC,MAAM,EAAC,MAAM,EAAE,GAAG,KAAK,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,GAAI,IAC5E,CACR,IACI,CACR,CAAC;IAEF,IAAI,GAAG,KAAK,MAAM,EAAE,CAAC;QACnB,OAAO,CACL,MAAC,YAAY,IAAC,KAAK,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,eAAe,EAAE,KAAK,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,aAC7E,MAAM,EACP,KAAC,UAAU,KAAG,IACD,CAChB,CAAC;IACJ,CAAC;IAED,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;QACtB,OAAO,CACL,MAAC,YAAY,IAAC,KAAK,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,eAAe,EAAE,KAAK,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,aAC9E,MAAC,IAAI,IACH,KAAK,EAAE;wBACL,MAAM,CAAC,MAAM;wBACb;4BACE,iBAAiB,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM;4BACtC,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,EAAE;4BACzB,eAAe,EAAE,KAAK,CAAC,MAAM,CAAC,UAAU;4BACxC,aAAa,EAAE,KAAK;4BACpB,UAAU,EAAE,QAAQ;yBACrB;qBACF,aAED,KAAC,SAAS,IACR,OAAO,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,EAChC,iBAAiB,EAAC,QAAQ,EAC1B,kBAAkB,EAAC,2BAA2B,EAC9C,KAAK,EAAE,EAAE,YAAY,EAAE,KAAK,CAAC,OAAO,CAAC,EAAE,EAAE,YAEzC,KAAC,IAAI,IAAC,KAAK,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE,QAAQ,EAAE,KAAK,CAAC,UAAU,CAAC,QAAQ,EAAE,uBAE1E,GACG,EACZ,KAAC,IAAI,IACH,KAAK,EAAE;gCACL,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,UAAU;gCAC9B,QAAQ,EAAE,KAAK,CAAC,UAAU,CAAC,SAAS;gCACpC,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,UAAU;6BACxC,6BAGI,IACF,EACP,KAAC,YAAY,IAAC,cAAc,EAAE,QAAQ,GAAI,EAC1C,KAAC,QAAQ,IAAC,cAAc,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAI,IACzC,CAChB,CAAC;IACJ,CAAC;IAED,OAAO,CACL,MAAC,YAAY,IAAC,KAAK,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,eAAe,EAAE,KAAK,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,aAC7E,MAAM,EACP,KAAC,gBAAgB,IAAC,aAAa,EAAE,aAAa,EAAE,MAAM,EAAE,WAAW,GAAI,EACvE,KAAC,QAAQ,IAAC,cAAc,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAC,gCAA2B,GAAG,IAC7E,CAChB,CAAC;AACJ,CAAC;AAED,SAAS,gBAAgB,CAAC,EACxB,aAAa,EACb,MAAM,GAIP;IACC,MAAM,EAAE,KAAK,EAAE,GAAG,SAAS,EAAE,CAAC;IAC9B,MAAM,UAAU,GAAG,CAAC,EAAE,IAAI,EAA2C,EAAqB,EAAE,CAAC,CAC3F,MAAC,SAAS,IACR,OAAO,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,EAC9B,iBAAiB,EAAC,QAAQ,EAC1B,kBAAkB,EAAE,qBAAqB,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,EAAE,EAAE,EAClE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;YACtB;gBACE,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,EAAE;gBACzB,eAAe,EAAE,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU;gBACzE,iBAAiB,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM;gBACtC,iBAAiB,EAAE,UAAU,CAAC,aAAa;gBAC3C,aAAa,EAAE,KAAK;gBACpB,UAAU,EAAE,QAAQ;aACrB;SACF,aAED,MAAC,IAAI,IAAC,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,aACtB,KAAC,IAAI,IACH,KAAK,EAAE;4BACL,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,UAAU;4BAC9B,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,YAAY;4BACzC,QAAQ,EAAE,KAAK,CAAC,UAAU,CAAC,QAAQ;yBACpC,YAEA,IAAI,CAAC,OAAO,IAAI,cAAc,GAC1B,EACP,KAAC,IAAI,IACH,KAAK,EAAE;4BACL,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,eAAe;4BACnC,QAAQ,EAAE,KAAK,CAAC,UAAU,CAAC,SAAS;4BACpC,SAAS,EAAE,CAAC;yBACb,EACD,aAAa,EAAE,CAAC,YAEf,IAAI,CAAC,kBAAkB,IAAI,kBAAkB,GACzC,IACF,EACN,IAAI,CAAC,kBAAkB,GAAG,CAAC,IAAI,CAC9B,KAAC,IAAI,IACH,KAAK,EAAE;oBACL,eAAe,EAAE,KAAK,CAAC,MAAM,CAAC,OAAO;oBACrC,YAAY,EAAE,GAAG;oBACjB,QAAQ,EAAE,EAAE;oBACZ,iBAAiB,EAAE,CAAC;oBACpB,eAAe,EAAE,CAAC;oBAClB,UAAU,EAAE,QAAQ;iBACrB,YAED,KAAC,IAAI,IACH,KAAK,EAAE;wBACL,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,SAAS;wBAC7B,QAAQ,EAAE,KAAK,CAAC,UAAU,CAAC,SAAS;wBACpC,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,UAAU;qBACxC,YAEA,IAAI,CAAC,kBAAkB,GACnB,GACF,CACR,IACS,CACb,CAAC;IACF,OAAO,CACL,KAAC,QAAQ,IACP,IAAI,EAAE,aAAa,EACnB,YAAY,EAAE,CAAC,CAAC,EAAU,EAAE,CAAC,CAAC,CAAC,EAAE,EACjC,UAAU,EAAE,UAAU,EACtB,kBAAkB,EAChB,KAAC,IAAI,IACH,KAAK,EAAE;gBACL,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,eAAe;gBACnC,SAAS,EAAE,QAAQ;gBACnB,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,EAAE;aAC1B,qEAGI,GAET,CACH,CAAC;AACJ,CAAC;AAED,SAAS,SAAS,CAAC,EACjB,KAAK,EACL,MAAM,EACN,OAAO,GAKR;IACC,MAAM,EAAE,KAAK,EAAE,GAAG,SAAS,EAAE,CAAC;IAC9B,OAAO,CACL,KAAC,SAAS,IACR,OAAO,EAAE,OAAO,EAChB,iBAAiB,EAAC,KAAK,EACvB,kBAAkB,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,EACxC,KAAK,EAAE;YACL,iBAAiB,EAAE,KAAK,CAAC,OAAO,CAAC,EAAE;YACnC,eAAe,EAAE,KAAK,CAAC,OAAO,CAAC,EAAE;YACjC,iBAAiB,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa;YAChE,iBAAiB,EAAE,CAAC;SACrB,YAED,KAAC,IAAI,IACH,KAAK,EAAE;gBACL,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,eAAe;gBACnE,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,aAAa;gBACjF,QAAQ,EAAE,KAAK,CAAC,UAAU,CAAC,QAAQ;aACpC,YAEA,KAAK,GACD,GACG,CACb,CAAC;AACJ,CAAC;AAED,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC;IAC/B,IAAI,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE;IACjB,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,UAAU,EAAE,QAAQ,EAAE,cAAc,EAAE,QAAQ,EAAE;IACnE,MAAM,EAAE,EAAE,iBAAiB,EAAE,UAAU,CAAC,aAAa,EAAE;IACvD,IAAI,EAAE,EAAE,aAAa,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,EAAE;CAC7C,CAAC,CAAC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Money on a card, restated for the published package.
|
|
3
|
+
*
|
|
4
|
+
* ── Why this is a copy and not an import ───────────────────────────────
|
|
5
|
+
*
|
|
6
|
+
* The canonical implementation is `packages/shared/src/widget-blocks/money.ts`
|
|
7
|
+
* and this file is deliberately identical in behaviour. `@livechat/shared` is
|
|
8
|
+
* `private: true` — it is the monorepo's internal package with a hundred
|
|
9
|
+
* export paths — so a published npm package cannot depend on it. The same
|
|
10
|
+
* reason `client/types.ts` restates the realtime types rather than importing
|
|
11
|
+
* them.
|
|
12
|
+
*
|
|
13
|
+
* A copy is a drift risk, so it is pinned rather than trusted:
|
|
14
|
+
* `money.parity.spec.ts` imports BOTH this and the shared original and
|
|
15
|
+
* asserts they agree over a currency table that includes the cases a
|
|
16
|
+
* hand-rolled version gets wrong. `check-block-field-parity.mjs` knows about
|
|
17
|
+
* the second `Intl.NumberFormat` by name, with that spec as the reason.
|
|
18
|
+
*
|
|
19
|
+
* ── Minor units, never a float ─────────────────────────────────────────
|
|
20
|
+
*
|
|
21
|
+
* `amount` is an integer count of the currency's smallest unit: 4820 is
|
|
22
|
+
* $48.20, 4820 is also ¥4,820, and 4820 is 4.820 KWD.
|
|
23
|
+
*
|
|
24
|
+
* The DIVISOR IS NOT 100. Three currencies have no minor unit (JPY, KRW, VND)
|
|
25
|
+
* and four have three digits (KWD, BHD, JOD, OMR), so `(amount / 100)`
|
|
26
|
+
* renders ¥4,820 as "¥48" and 4.820 KWD as "48.200 KWD" — wrong by two orders
|
|
27
|
+
* of magnitude in opposite directions, and perfect in USD, which is why it
|
|
28
|
+
* would ship. The digit count is read off the formatter, so a currency added
|
|
29
|
+
* to CLDR after this was written is right with no table here.
|
|
30
|
+
*
|
|
31
|
+
* React Native ships a full ICU on iOS and, since 0.73 with Hermes
|
|
32
|
+
* `intl` enabled, on Android too. The `catch` below is what covers an engine
|
|
33
|
+
* without it: a card with an unrecognised currency still shows a price rather
|
|
34
|
+
* than taking the thread's render down.
|
|
35
|
+
*/
|
|
36
|
+
/** A price on a card. `amount` and `compareAt` are both MINOR units. */
|
|
37
|
+
export interface Money {
|
|
38
|
+
readonly amount: number;
|
|
39
|
+
/** ISO 4217, upper case. */
|
|
40
|
+
readonly currency: string;
|
|
41
|
+
/** The was-price. Rendered only when above `amount`. */
|
|
42
|
+
readonly compareAt?: number;
|
|
43
|
+
}
|
|
44
|
+
/** Read a price off a stored card, or null. Refuses what cannot be drawn. */
|
|
45
|
+
export declare function readMoney(raw: unknown): Money | null;
|
|
46
|
+
/** The locale-free rendition, used as the fallback and for accessibility text. */
|
|
47
|
+
export declare function moneyToPlainText(money: Money): string;
|
|
48
|
+
/**
|
|
49
|
+
* Format one amount in the DEVICE's locale.
|
|
50
|
+
*
|
|
51
|
+
* `locale` undefined means "whatever this device is set to", which is the
|
|
52
|
+
* right default: the app runs on the shopper's phone and a German shopper
|
|
53
|
+
* reads `48,20 $`.
|
|
54
|
+
*/
|
|
55
|
+
export declare function formatMoney(money: Money, locale?: string): string;
|
|
56
|
+
//# sourceMappingURL=money.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"money.d.ts","sourceRoot":"","sources":["../../src/blocks/money.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,wEAAwE;AACxE,MAAM,WAAW,KAAK;IACpB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,4BAA4B;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,wDAAwD;IACxD,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAOD,6EAA6E;AAC7E,wBAAgB,SAAS,CAAC,GAAG,EAAE,OAAO,GAAG,KAAK,GAAG,IAAI,CAepD;AAOD,kFAAkF;AAClF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,CAErD;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAUjE"}
|