@appsupportkit/support-sdk 0.1.2 → 0.3.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/lib/commonjs/api.js +17 -2
- package/lib/commonjs/api.js.map +1 -1
- package/lib/commonjs/components/BottomSheet.js +67 -47
- package/lib/commonjs/components/BottomSheet.js.map +1 -1
- package/lib/commonjs/components/LauncherButton.js +177 -0
- package/lib/commonjs/components/LauncherButton.js.map +1 -0
- package/lib/commonjs/components/SupportButton.js +168 -190
- package/lib/commonjs/components/SupportButton.js.map +1 -1
- package/lib/commonjs/components/icons.js +110 -23
- package/lib/commonjs/components/icons.js.map +1 -1
- package/lib/commonjs/components/primitives.js +191 -44
- package/lib/commonjs/components/primitives.js.map +1 -1
- package/lib/commonjs/components/screens/ComposeScreen.js +108 -60
- package/lib/commonjs/components/screens/ComposeScreen.js.map +1 -1
- package/lib/commonjs/components/screens/HomeScreen.js +221 -118
- package/lib/commonjs/components/screens/HomeScreen.js.map +1 -1
- package/lib/commonjs/components/screens/LanguageScreen.js +150 -0
- package/lib/commonjs/components/screens/LanguageScreen.js.map +1 -0
- package/lib/commonjs/components/screens/ThreadScreen.js +237 -111
- package/lib/commonjs/components/screens/ThreadScreen.js.map +1 -1
- package/lib/commonjs/i18n/index.js +101 -0
- package/lib/commonjs/i18n/index.js.map +1 -0
- package/lib/commonjs/i18n/languages.js +95 -0
- package/lib/commonjs/i18n/languages.js.map +1 -0
- package/lib/commonjs/i18n/strings/de.js +72 -0
- package/lib/commonjs/i18n/strings/de.js.map +1 -0
- package/lib/commonjs/i18n/strings/en.js +88 -0
- package/lib/commonjs/i18n/strings/en.js.map +1 -0
- package/lib/commonjs/i18n/strings/es.js +72 -0
- package/lib/commonjs/i18n/strings/es.js.map +1 -0
- package/lib/commonjs/i18n/strings/fr.js +72 -0
- package/lib/commonjs/i18n/strings/fr.js.map +1 -0
- package/lib/commonjs/i18n/strings/hi.js +72 -0
- package/lib/commonjs/i18n/strings/hi.js.map +1 -0
- package/lib/commonjs/i18n/strings/it.js +72 -0
- package/lib/commonjs/i18n/strings/it.js.map +1 -0
- package/lib/commonjs/i18n/strings/ja.js +72 -0
- package/lib/commonjs/i18n/strings/ja.js.map +1 -0
- package/lib/commonjs/i18n/strings/ko.js +72 -0
- package/lib/commonjs/i18n/strings/ko.js.map +1 -0
- package/lib/commonjs/i18n/strings/nl.js +72 -0
- package/lib/commonjs/i18n/strings/nl.js.map +1 -0
- package/lib/commonjs/i18n/strings/pl.js +72 -0
- package/lib/commonjs/i18n/strings/pl.js.map +1 -0
- package/lib/commonjs/i18n/strings/pt.js +72 -0
- package/lib/commonjs/i18n/strings/pt.js.map +1 -0
- package/lib/commonjs/i18n/strings/ru.js +72 -0
- package/lib/commonjs/i18n/strings/ru.js.map +1 -0
- package/lib/commonjs/i18n/strings/tr.js +72 -0
- package/lib/commonjs/i18n/strings/tr.js.map +1 -0
- package/lib/commonjs/i18n/strings/zh.js +72 -0
- package/lib/commonjs/i18n/strings/zh.js.map +1 -0
- package/lib/commonjs/index.js +31 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/theme.js +136 -17
- package/lib/commonjs/theme.js.map +1 -1
- package/lib/commonjs/types.js +18 -0
- package/lib/commonjs/types.js.map +1 -1
- package/lib/commonjs/unread.js +92 -0
- package/lib/commonjs/unread.js.map +1 -0
- package/lib/commonjs/useSupportThreads.js +296 -0
- package/lib/commonjs/useSupportThreads.js.map +1 -0
- package/lib/commonjs/utils.js +58 -10
- package/lib/commonjs/utils.js.map +1 -1
- package/lib/module/api.js +16 -2
- package/lib/module/api.js.map +1 -1
- package/lib/module/components/BottomSheet.js +68 -48
- package/lib/module/components/BottomSheet.js.map +1 -1
- package/lib/module/components/LauncherButton.js +172 -0
- package/lib/module/components/LauncherButton.js.map +1 -0
- package/lib/module/components/SupportButton.js +172 -194
- package/lib/module/components/SupportButton.js.map +1 -1
- package/lib/module/components/icons.js +107 -22
- package/lib/module/components/icons.js.map +1 -1
- package/lib/module/components/primitives.js +187 -45
- package/lib/module/components/primitives.js.map +1 -1
- package/lib/module/components/screens/ComposeScreen.js +114 -64
- package/lib/module/components/screens/ComposeScreen.js.map +1 -1
- package/lib/module/components/screens/HomeScreen.js +224 -121
- package/lib/module/components/screens/HomeScreen.js.map +1 -1
- package/lib/module/components/screens/LanguageScreen.js +147 -0
- package/lib/module/components/screens/LanguageScreen.js.map +1 -0
- package/lib/module/components/screens/ThreadScreen.js +243 -115
- package/lib/module/components/screens/ThreadScreen.js.map +1 -1
- package/lib/module/i18n/index.js +56 -0
- package/lib/module/i18n/index.js.map +1 -0
- package/lib/module/i18n/languages.js +88 -0
- package/lib/module/i18n/languages.js.map +1 -0
- package/lib/module/i18n/strings/de.js +68 -0
- package/lib/module/i18n/strings/de.js.map +1 -0
- package/lib/module/i18n/strings/en.js +84 -0
- package/lib/module/i18n/strings/en.js.map +1 -0
- package/lib/module/i18n/strings/es.js +68 -0
- package/lib/module/i18n/strings/es.js.map +1 -0
- package/lib/module/i18n/strings/fr.js +68 -0
- package/lib/module/i18n/strings/fr.js.map +1 -0
- package/lib/module/i18n/strings/hi.js +68 -0
- package/lib/module/i18n/strings/hi.js.map +1 -0
- package/lib/module/i18n/strings/it.js +68 -0
- package/lib/module/i18n/strings/it.js.map +1 -0
- package/lib/module/i18n/strings/ja.js +68 -0
- package/lib/module/i18n/strings/ja.js.map +1 -0
- package/lib/module/i18n/strings/ko.js +68 -0
- package/lib/module/i18n/strings/ko.js.map +1 -0
- package/lib/module/i18n/strings/nl.js +68 -0
- package/lib/module/i18n/strings/nl.js.map +1 -0
- package/lib/module/i18n/strings/pl.js +68 -0
- package/lib/module/i18n/strings/pl.js.map +1 -0
- package/lib/module/i18n/strings/pt.js +68 -0
- package/lib/module/i18n/strings/pt.js.map +1 -0
- package/lib/module/i18n/strings/ru.js +68 -0
- package/lib/module/i18n/strings/ru.js.map +1 -0
- package/lib/module/i18n/strings/tr.js +68 -0
- package/lib/module/i18n/strings/tr.js.map +1 -0
- package/lib/module/i18n/strings/zh.js +68 -0
- package/lib/module/i18n/strings/zh.js.map +1 -0
- package/lib/module/index.js +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/theme.js +135 -16
- package/lib/module/theme.js.map +1 -1
- package/lib/module/types.js +18 -0
- package/lib/module/types.js.map +1 -1
- package/lib/module/unread.js +83 -0
- package/lib/module/unread.js.map +1 -0
- package/lib/module/useSupportThreads.js +291 -0
- package/lib/module/useSupportThreads.js.map +1 -0
- package/lib/module/utils.js +55 -10
- package/lib/module/utils.js.map +1 -1
- package/lib/typescript/api.d.ts +9 -0
- package/lib/typescript/api.d.ts.map +1 -1
- package/lib/typescript/components/BottomSheet.d.ts.map +1 -1
- package/lib/typescript/components/LauncherButton.d.ts +14 -0
- package/lib/typescript/components/LauncherButton.d.ts.map +1 -0
- package/lib/typescript/components/SupportButton.d.ts +3 -3
- package/lib/typescript/components/SupportButton.d.ts.map +1 -1
- package/lib/typescript/components/icons.d.ts +18 -2
- package/lib/typescript/components/icons.d.ts.map +1 -1
- package/lib/typescript/components/primitives.d.ts +42 -7
- package/lib/typescript/components/primitives.d.ts.map +1 -1
- package/lib/typescript/components/screens/ComposeScreen.d.ts +3 -1
- package/lib/typescript/components/screens/ComposeScreen.d.ts.map +1 -1
- package/lib/typescript/components/screens/HomeScreen.d.ts +8 -2
- package/lib/typescript/components/screens/HomeScreen.d.ts.map +1 -1
- package/lib/typescript/components/screens/LanguageScreen.d.ts +30 -0
- package/lib/typescript/components/screens/LanguageScreen.d.ts.map +1 -0
- package/lib/typescript/components/screens/ThreadScreen.d.ts +3 -1
- package/lib/typescript/components/screens/ThreadScreen.d.ts.map +1 -1
- package/lib/typescript/i18n/index.d.ts +15 -0
- package/lib/typescript/i18n/index.d.ts.map +1 -0
- package/lib/typescript/i18n/languages.d.ts +36 -0
- package/lib/typescript/i18n/languages.d.ts.map +1 -0
- package/lib/typescript/i18n/strings/de.d.ts +3 -0
- package/lib/typescript/i18n/strings/de.d.ts.map +1 -0
- package/lib/typescript/i18n/strings/en.d.ts +83 -0
- package/lib/typescript/i18n/strings/en.d.ts.map +1 -0
- package/lib/typescript/i18n/strings/es.d.ts +3 -0
- package/lib/typescript/i18n/strings/es.d.ts.map +1 -0
- package/lib/typescript/i18n/strings/fr.d.ts +3 -0
- package/lib/typescript/i18n/strings/fr.d.ts.map +1 -0
- package/lib/typescript/i18n/strings/hi.d.ts +3 -0
- package/lib/typescript/i18n/strings/hi.d.ts.map +1 -0
- package/lib/typescript/i18n/strings/it.d.ts +3 -0
- package/lib/typescript/i18n/strings/it.d.ts.map +1 -0
- package/lib/typescript/i18n/strings/ja.d.ts +3 -0
- package/lib/typescript/i18n/strings/ja.d.ts.map +1 -0
- package/lib/typescript/i18n/strings/ko.d.ts +3 -0
- package/lib/typescript/i18n/strings/ko.d.ts.map +1 -0
- package/lib/typescript/i18n/strings/nl.d.ts +3 -0
- package/lib/typescript/i18n/strings/nl.d.ts.map +1 -0
- package/lib/typescript/i18n/strings/pl.d.ts +3 -0
- package/lib/typescript/i18n/strings/pl.d.ts.map +1 -0
- package/lib/typescript/i18n/strings/pt.d.ts +3 -0
- package/lib/typescript/i18n/strings/pt.d.ts.map +1 -0
- package/lib/typescript/i18n/strings/ru.d.ts +3 -0
- package/lib/typescript/i18n/strings/ru.d.ts.map +1 -0
- package/lib/typescript/i18n/strings/tr.d.ts +3 -0
- package/lib/typescript/i18n/strings/tr.d.ts.map +1 -0
- package/lib/typescript/i18n/strings/zh.d.ts +3 -0
- package/lib/typescript/i18n/strings/zh.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +2 -1
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/theme.d.ts +44 -3
- package/lib/typescript/theme.d.ts.map +1 -1
- package/lib/typescript/types.d.ts +54 -2
- package/lib/typescript/types.d.ts.map +1 -1
- package/lib/typescript/unread.d.ts +22 -0
- package/lib/typescript/unread.d.ts.map +1 -0
- package/lib/typescript/useSupportThreads.d.ts +38 -0
- package/lib/typescript/useSupportThreads.d.ts.map +1 -0
- package/lib/typescript/utils.d.ts +8 -2
- package/lib/typescript/utils.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/api.ts +24 -1
- package/src/components/BottomSheet.tsx +61 -43
- package/src/components/LauncherButton.tsx +217 -0
- package/src/components/SupportButton.tsx +195 -210
- package/src/components/icons.tsx +113 -19
- package/src/components/primitives.tsx +230 -39
- package/src/components/screens/ComposeScreen.tsx +129 -63
- package/src/components/screens/HomeScreen.tsx +230 -120
- package/src/components/screens/LanguageScreen.tsx +172 -0
- package/src/components/screens/ThreadScreen.tsx +319 -122
- package/src/i18n/index.ts +81 -0
- package/src/i18n/languages.ts +106 -0
- package/src/i18n/strings/de.ts +78 -0
- package/src/i18n/strings/en.ts +94 -0
- package/src/i18n/strings/es.ts +77 -0
- package/src/i18n/strings/fr.ts +78 -0
- package/src/i18n/strings/hi.ts +77 -0
- package/src/i18n/strings/it.ts +77 -0
- package/src/i18n/strings/ja.ts +77 -0
- package/src/i18n/strings/ko.ts +76 -0
- package/src/i18n/strings/nl.ts +77 -0
- package/src/i18n/strings/pl.ts +77 -0
- package/src/i18n/strings/pt.ts +77 -0
- package/src/i18n/strings/ru.ts +77 -0
- package/src/i18n/strings/tr.ts +77 -0
- package/src/i18n/strings/zh.ts +75 -0
- package/src/index.tsx +9 -0
- package/src/theme.ts +165 -18
- package/src/types.ts +56 -2
- package/src/unread.ts +91 -0
- package/src/useSupportThreads.ts +392 -0
- package/src/utils.ts +48 -10
|
@@ -1,8 +1,17 @@
|
|
|
1
|
+
import type { StyleProp, ViewStyle } from 'react-native';
|
|
2
|
+
import type { Language } from './i18n/languages';
|
|
1
3
|
export type QueryType = 'feedback' | 'feature_request' | 'bug_report';
|
|
2
4
|
export type QueryStatus = 'open' | 'resolved';
|
|
3
5
|
export type MessageSender = 'user' | 'admin';
|
|
4
6
|
export type ThemeName = 'dark' | 'light';
|
|
5
7
|
export type PushPermissionStatus = 'undetermined' | 'granted' | 'denied';
|
|
8
|
+
/**
|
|
9
|
+
* How the launcher renders:
|
|
10
|
+
* solid — accent fill, elevated. The floating action button.
|
|
11
|
+
* soft — app surface + hairline border. Sits in a header or toolbar.
|
|
12
|
+
* minimal — bare mark, no fill or border. Sits in a nav bar.
|
|
13
|
+
*/
|
|
14
|
+
export type LauncherVariant = 'solid' | 'soft' | 'minimal';
|
|
6
15
|
export interface SupportUser {
|
|
7
16
|
/** Display name shown to the support team. */
|
|
8
17
|
name: string;
|
|
@@ -28,6 +37,20 @@ export interface SupportButtonProps {
|
|
|
28
37
|
supabaseUrl: string;
|
|
29
38
|
/** Visual theme. Matches the admin dashboard tokens. Default "dark". */
|
|
30
39
|
theme?: ThemeName;
|
|
40
|
+
/**
|
|
41
|
+
* Brand color (hex, e.g. "#FF5A1F") replacing the default accent across
|
|
42
|
+
* the launcher, buttons, and the user's own message bubbles. The pressed
|
|
43
|
+
* shade, the 12% wash, and a legible foreground are derived from it.
|
|
44
|
+
*/
|
|
45
|
+
accentColor?: string;
|
|
46
|
+
/** Launcher style. Default "solid" — the floating action button. */
|
|
47
|
+
variant?: LauncherVariant;
|
|
48
|
+
/** Launcher diameter in px (height when `label` is set). Default 52. */
|
|
49
|
+
size?: number;
|
|
50
|
+
/** Renders the launcher as a pill with this text beside the mark. */
|
|
51
|
+
label?: string;
|
|
52
|
+
/** Style applied to the launcher — position it, add margins, etc. */
|
|
53
|
+
style?: StyleProp<ViewStyle>;
|
|
31
54
|
/**
|
|
32
55
|
* Idle poll interval (ms) — how often the unread badge is refreshed while
|
|
33
56
|
* the sheet is CLOSED, using a lightweight count-only endpoint. Default
|
|
@@ -45,21 +68,43 @@ export interface SupportButtonProps {
|
|
|
45
68
|
* installed — it is an optional peer dependency.
|
|
46
69
|
*/
|
|
47
70
|
expoProjectId?: string;
|
|
71
|
+
/**
|
|
72
|
+
* Pre-selects a language in the picker the first time a user opens support.
|
|
73
|
+
* Pass it when the host app already knows what the user reads — an in-app
|
|
74
|
+
* language setting beats the device locale, which is what the SDK falls
|
|
75
|
+
* back to. It is a default, not an override: the user still chooses, and a
|
|
76
|
+
* choice they have already made always wins.
|
|
77
|
+
*/
|
|
78
|
+
defaultLanguage?: Language;
|
|
48
79
|
}
|
|
49
80
|
export interface ThreadMessage {
|
|
50
81
|
id: string;
|
|
51
82
|
sender: MessageSender;
|
|
83
|
+
/**
|
|
84
|
+
* Already in the user's language: their own messages as they wrote them,
|
|
85
|
+
* support replies translated. The server does the choosing — see the
|
|
86
|
+
* get-threads function.
|
|
87
|
+
*/
|
|
52
88
|
body: string;
|
|
53
89
|
created_at: string;
|
|
54
|
-
|
|
90
|
+
/**
|
|
91
|
+
* A support reply whose translation hasn't landed yet. `body` currently
|
|
92
|
+
* holds the English original; it will change under the reader shortly, so
|
|
93
|
+
* the UI says so rather than letting it flicker.
|
|
94
|
+
*/
|
|
95
|
+
translation_pending: boolean;
|
|
55
96
|
}
|
|
97
|
+
/**
|
|
98
|
+
* Note the absence of any admin identity: end users see one support team,
|
|
99
|
+
* not the people staffing it, so the names never leave the server. The
|
|
100
|
+
* dashboard still shows who wrote and who resolved what.
|
|
101
|
+
*/
|
|
56
102
|
export interface Thread {
|
|
57
103
|
id: string;
|
|
58
104
|
type: QueryType;
|
|
59
105
|
status: QueryStatus;
|
|
60
106
|
created_at: string;
|
|
61
107
|
resolved_at: string | null;
|
|
62
|
-
resolved_by_name: string | null;
|
|
63
108
|
app_version: string;
|
|
64
109
|
unread_count: number;
|
|
65
110
|
last_message: {
|
|
@@ -72,7 +117,14 @@ export interface Thread {
|
|
|
72
117
|
export interface ThreadsResponse {
|
|
73
118
|
threads: Thread[];
|
|
74
119
|
total_unread: number;
|
|
120
|
+
/** Null when this user has never picked one — the SDK then asks. */
|
|
121
|
+
language: string | null;
|
|
75
122
|
}
|
|
123
|
+
/**
|
|
124
|
+
* English labels, kept for host apps that render their own entry points.
|
|
125
|
+
* Inside the sheet the labels come from the string table instead, so they
|
|
126
|
+
* follow the user's language.
|
|
127
|
+
*/
|
|
76
128
|
export declare const QUERY_TYPE_LABEL: Record<QueryType, string>;
|
|
77
129
|
export declare const USER_MESSAGE_MIN = 10;
|
|
78
130
|
export declare const USER_MESSAGE_MAX = 300;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,SAAS,GAAG,UAAU,GAAG,iBAAiB,GAAG,YAAY,CAAC;AACtE,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,UAAU,CAAC;AAC9C,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,OAAO,CAAC;AAC7C,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC;AACzC,MAAM,MAAM,oBAAoB,GAAG,cAAc,GAAG,SAAS,GAAG,QAAQ,CAAC;AAEzE,MAAM,WAAW,WAAW;IAC1B,8CAA8C;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,0CAA0C;IAC1C,MAAM,EAAE,OAAO,CAAC;IAChB,8DAA8D;IAC9D,YAAY,EAAE,MAAM,CAAC;IACrB,sCAAsC;IACtC,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,kBAAkB;IACjC,+DAA+D;IAC/D,OAAO,EAAE,MAAM,CAAC;IAChB,0EAA0E;IAC1E,MAAM,EAAE,MAAM,CAAC;IACf,sCAAsC;IACtC,IAAI,EAAE,WAAW,CAAC;IAClB;;;;OAIG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB,wEAAwE;IACxE,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB;;;;;;;;OAQG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Thread } from './types';
|
|
2
|
+
/** Watermark map: thread id → `created_at` (ms) of the newest seen reply. */
|
|
3
|
+
export type ReadWatermarks = Map<string, number>;
|
|
4
|
+
/** `created_at` (ms) of the newest admin message, or 0 if there are none. */
|
|
5
|
+
export declare function latestAdminMessageAt(thread: Thread): number;
|
|
6
|
+
/** Admin messages in `thread` newer than `watermark`. */
|
|
7
|
+
export declare function unreadSince(thread: Thread, watermark: number): number;
|
|
8
|
+
/**
|
|
9
|
+
* Returns `thread` with `unread_count` narrowed by what this device knows
|
|
10
|
+
* the user has read. Identity is preserved when nothing changes so lists
|
|
11
|
+
* stay referentially stable between polls.
|
|
12
|
+
*/
|
|
13
|
+
export declare function reconcileThread(thread: Thread, watermarks: ReadWatermarks): Thread;
|
|
14
|
+
export declare function reconcileThreads(threads: Thread[], watermarks: ReadWatermarks): Thread[];
|
|
15
|
+
export declare function sumUnread(threads: Thread[]): number;
|
|
16
|
+
/**
|
|
17
|
+
* Drops watermarks the server has caught up on (its own count is already 0)
|
|
18
|
+
* and ones for threads that no longer exist, so the map can't grow without
|
|
19
|
+
* bound over a long session.
|
|
20
|
+
*/
|
|
21
|
+
export declare function pruneWatermarks(watermarks: ReadWatermarks, serverThreads: Thread[]): ReadWatermarks;
|
|
22
|
+
//# sourceMappingURL=unread.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unread.d.ts","sourceRoot":"","sources":["../../src/unread.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEtC,6EAA6E;AAC7E,MAAM,MAAM,cAAc,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAEjD,6EAA6E;AAC7E,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAQ3D;AAED,yDAAyD;AACzD,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAQrE;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,cAAc,GACzB,MAAM,CAKR;AAED,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,MAAM,EAAE,EACjB,UAAU,EAAE,cAAc,GACzB,MAAM,EAAE,CAEV;AAED,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,CAEnD;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,UAAU,EAAE,cAAc,EAC1B,aAAa,EAAE,MAAM,EAAE,GACtB,cAAc,CAShB"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { type ApiConfig } from './api';
|
|
2
|
+
import type { StringKey } from './i18n';
|
|
3
|
+
import type { Thread } from './types';
|
|
4
|
+
export declare const IDLE_POLL_MS = 60000;
|
|
5
|
+
export interface SupportThreadsState {
|
|
6
|
+
/** Server threads with unread counts narrowed by local reads. */
|
|
7
|
+
threads: Thread[] | null;
|
|
8
|
+
totalUnread: number;
|
|
9
|
+
/** First load only — there is nothing cached to show yet. */
|
|
10
|
+
loading: boolean;
|
|
11
|
+
/** User-pulled refresh with content already on screen. */
|
|
12
|
+
refreshing: boolean;
|
|
13
|
+
/** Set only when there is nothing cached; background failures stay quiet. */
|
|
14
|
+
errorKey: StringKey | null;
|
|
15
|
+
/** The language this user picked, or null if they never have. */
|
|
16
|
+
serverLanguage: string | null;
|
|
17
|
+
/**
|
|
18
|
+
* False until the first successful load. `serverLanguage === null` only
|
|
19
|
+
* means "never picked" once this is true — before that it means "don't
|
|
20
|
+
* know yet", and showing the picker on a guess would nag a user who
|
|
21
|
+
* answered on another device.
|
|
22
|
+
*/
|
|
23
|
+
languageLoaded: boolean;
|
|
24
|
+
/** User-initiated refresh (pull-to-refresh, retry button). */
|
|
25
|
+
refresh: () => void;
|
|
26
|
+
/** Awaited by send/submit handlers so the list reflects the write. */
|
|
27
|
+
reload: () => Promise<void>;
|
|
28
|
+
}
|
|
29
|
+
export declare function useSupportThreads({ config, revenuecatId, enabled, sheetOpen, activeThreadId, idlePollMs, }: {
|
|
30
|
+
config: ApiConfig;
|
|
31
|
+
revenuecatId: string;
|
|
32
|
+
/** False when props failed validation — no requests are made. */
|
|
33
|
+
enabled: boolean;
|
|
34
|
+
sheetOpen: boolean;
|
|
35
|
+
activeThreadId: string | null;
|
|
36
|
+
idlePollMs: number;
|
|
37
|
+
}): SupportThreadsState;
|
|
38
|
+
//# sourceMappingURL=useSupportThreads.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useSupportThreads.d.ts","sourceRoot":"","sources":["../../src/useSupportThreads.ts"],"names":[],"mappings":"AAgBA,OAAO,EAKL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAetC,eAAO,MAAM,YAAY,QAAS,CAAC;AA8CnC,MAAM,WAAW,mBAAmB;IAClC,iEAAiE;IACjE,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,6DAA6D;IAC7D,OAAO,EAAE,OAAO,CAAC;IACjB,0DAA0D;IAC1D,UAAU,EAAE,OAAO,CAAC;IACpB,6EAA6E;IAC7E,QAAQ,EAAE,SAAS,GAAG,IAAI,CAAC;IAC3B,iEAAiE;IACjE,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B;;;;;OAKG;IACH,cAAc,EAAE,OAAO,CAAC;IACxB,8DAA8D;IAC9D,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,sEAAsE;IACtE,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7B;AAED,wBAAgB,iBAAiB,CAAC,EAChC,MAAM,EACN,YAAY,EACZ,OAAO,EACP,SAAS,EACT,cAAc,EACd,UAAU,GACX,EAAE;IACD,MAAM,EAAE,SAAS,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,iEAAiE;IACjE,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;IACnB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,UAAU,EAAE,MAAM,CAAC;CACpB,GAAG,mBAAmB,CA0QtB"}
|
|
@@ -1,6 +1,12 @@
|
|
|
1
|
+
import type { Translator } from './i18n';
|
|
1
2
|
/** "2h ago" relative time — mirrors the web dashboard's formatting. */
|
|
2
|
-
export declare function relativeTime(iso: string): string;
|
|
3
|
-
export declare function formatDate(iso: string): string;
|
|
3
|
+
export declare function relativeTime(iso: string, strings: Translator): string;
|
|
4
|
+
export declare function formatDate(iso: string, strings: Translator): string;
|
|
5
|
+
/** "14:32" in the user's locale — shown under a group of messages. */
|
|
6
|
+
export declare function formatTime(iso: string, strings: Translator): string;
|
|
7
|
+
export declare function isSameDay(a: string, b: string): boolean;
|
|
8
|
+
/** Date separator label: Today / Yesterday / "Mon, 5 Jan". */
|
|
9
|
+
export declare function dayLabel(iso: string, strings: Translator): string;
|
|
4
10
|
/** Dev-mode prop validation with actionable messages. */
|
|
5
11
|
export declare function validateProps(props: {
|
|
6
12
|
appName?: unknown;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAKzC,uEAAuE;AACvE,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,GAAG,MAAM,CAerE;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,GAAG,MAAM,CAMnE;AAED,sEAAsE;AACtE,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,GAAG,MAAM,CAKnE;AAED,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAQvD;AAED,8DAA8D;AAC9D,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,GAAG,MAAM,CAYjE;AAED,yDAAyD;AACzD,wBAAgB,aAAa,CAAC,KAAK,EAAE;IACnC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,GAAG,MAAM,GAAG,IAAI,CA8BhB"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@appsupportkit/support-sdk",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "In-app customer support for React Native: feedback, feature requests, and bug reports with two-way threads.",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "In-app customer support for React Native: feedback, feature requests, and bug reports with two-way threads, in the user's own language.",
|
|
5
5
|
"main": "./lib/commonjs/index.js",
|
|
6
6
|
"module": "./lib/module/index.js",
|
|
7
7
|
"types": "./lib/typescript/index.d.ts",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
],
|
|
20
20
|
"license": "MIT",
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@appsupportkit/design-tokens": "^0.
|
|
22
|
+
"@appsupportkit/design-tokens": "^0.2.0"
|
|
23
23
|
},
|
|
24
24
|
"peerDependencies": {
|
|
25
25
|
"expo-notifications": ">=0.27.0",
|
package/src/api.ts
CHANGED
|
@@ -112,6 +112,20 @@ export function registerPush(
|
|
|
112
112
|
});
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
+
/** Records the language the user reads and writes support messages in. */
|
|
116
|
+
export function setLanguage(
|
|
117
|
+
config: ApiConfig,
|
|
118
|
+
input: { revenuecatId: string; language: string },
|
|
119
|
+
): Promise<{ language: string }> {
|
|
120
|
+
return request(config, 'set-language', {
|
|
121
|
+
method: 'POST',
|
|
122
|
+
body: JSON.stringify({
|
|
123
|
+
revenuecat_id: input.revenuecatId,
|
|
124
|
+
language: input.language,
|
|
125
|
+
}),
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
115
129
|
export function submitQuery(
|
|
116
130
|
config: ApiConfig,
|
|
117
131
|
input: {
|
|
@@ -121,6 +135,7 @@ export function submitQuery(
|
|
|
121
135
|
isPaid: boolean;
|
|
122
136
|
revenuecatId: string;
|
|
123
137
|
appVersion: string;
|
|
138
|
+
language: string;
|
|
124
139
|
},
|
|
125
140
|
): Promise<{ query_id: string }> {
|
|
126
141
|
return request(config, 'submit-query', {
|
|
@@ -133,13 +148,20 @@ export function submitQuery(
|
|
|
133
148
|
is_paid: input.isPaid,
|
|
134
149
|
revenuecat_id: input.revenuecatId,
|
|
135
150
|
app_version: input.appVersion,
|
|
151
|
+
// Sent on every write so a lost set-language call self-heals.
|
|
152
|
+
language: input.language,
|
|
136
153
|
}),
|
|
137
154
|
});
|
|
138
155
|
}
|
|
139
156
|
|
|
140
157
|
export function postMessage(
|
|
141
158
|
config: ApiConfig,
|
|
142
|
-
input: {
|
|
159
|
+
input: {
|
|
160
|
+
queryId: string;
|
|
161
|
+
revenuecatId: string;
|
|
162
|
+
message: string;
|
|
163
|
+
language: string;
|
|
164
|
+
},
|
|
143
165
|
): Promise<{ message_id: string }> {
|
|
144
166
|
return request(config, 'post-message', {
|
|
145
167
|
method: 'POST',
|
|
@@ -147,6 +169,7 @@ export function postMessage(
|
|
|
147
169
|
query_id: input.queryId,
|
|
148
170
|
revenuecat_id: input.revenuecatId,
|
|
149
171
|
message: input.message,
|
|
172
|
+
language: input.language,
|
|
150
173
|
}),
|
|
151
174
|
});
|
|
152
175
|
}
|
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
// Bottom sheet built on the built-in Modal + Animated APIs.
|
|
2
2
|
//
|
|
3
3
|
// Why no sheet library: the SDK needs exactly one detent, a drag handle, a
|
|
4
|
-
// backdrop fade, and a
|
|
4
|
+
// backdrop fade, and a short ease-out slide — all achievable with core APIs.
|
|
5
5
|
// Skipping reanimated/gesture-handler keeps the package free of native
|
|
6
6
|
// dependencies and install friction for consumers.
|
|
7
|
-
|
|
7
|
+
//
|
|
8
|
+
// `visible` drives a single animation path: the sheet stays mounted until
|
|
9
|
+
// its exit finishes, so closing from the header button, the backdrop, the
|
|
10
|
+
// hardware back button, or a drag all animate identically — and a reopen
|
|
11
|
+
// always starts from off-screen instead of appearing already in place.
|
|
12
|
+
import { useCallback, useEffect, useRef, useState, type ReactNode } from 'react';
|
|
8
13
|
import {
|
|
9
14
|
Animated,
|
|
10
15
|
Easing,
|
|
@@ -17,7 +22,8 @@ import {
|
|
|
17
22
|
import { SafeAreaProvider, SafeAreaView } from 'react-native-safe-area-context';
|
|
18
23
|
import type { SupportTheme } from '../theme';
|
|
19
24
|
|
|
20
|
-
const SLIDE_MS =
|
|
25
|
+
const SLIDE_MS = 260;
|
|
26
|
+
const FADE_MS = 200;
|
|
21
27
|
|
|
22
28
|
export function BottomSheet({
|
|
23
29
|
visible,
|
|
@@ -31,57 +37,67 @@ export function BottomSheet({
|
|
|
31
37
|
children: ReactNode;
|
|
32
38
|
}) {
|
|
33
39
|
const { height: windowHeight } = useWindowDimensions();
|
|
34
|
-
const sheetHeight = Math.min(windowHeight * 0.
|
|
40
|
+
const sheetHeight = Math.min(windowHeight * 0.88, 720);
|
|
35
41
|
|
|
42
|
+
const [rendered, setRendered] = useState(false);
|
|
36
43
|
const translateY = useRef(new Animated.Value(sheetHeight)).current;
|
|
37
44
|
const backdrop = useRef(new Animated.Value(0)).current;
|
|
45
|
+
/** Whether the entrance has already played for the current open. */
|
|
46
|
+
const shown = useRef(false);
|
|
38
47
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
toValue: 0,
|
|
43
|
-
duration: SLIDE_MS,
|
|
44
|
-
easing: Easing.out(Easing.cubic),
|
|
45
|
-
useNativeDriver: true,
|
|
46
|
-
}),
|
|
47
|
-
Animated.timing(backdrop, {
|
|
48
|
-
toValue: 1,
|
|
49
|
-
duration: SLIDE_MS,
|
|
50
|
-
easing: Easing.out(Easing.cubic),
|
|
51
|
-
useNativeDriver: true,
|
|
52
|
-
}),
|
|
53
|
-
]).start();
|
|
54
|
-
}, [translateY, backdrop]);
|
|
48
|
+
useEffect(() => {
|
|
49
|
+
if (visible) setRendered(true);
|
|
50
|
+
}, [visible]);
|
|
55
51
|
|
|
56
|
-
|
|
57
|
-
|
|
52
|
+
useEffect(() => {
|
|
53
|
+
if (!rendered) return;
|
|
54
|
+
|
|
55
|
+
if (visible && !shown.current) {
|
|
56
|
+
shown.current = true;
|
|
57
|
+
translateY.setValue(sheetHeight);
|
|
58
58
|
Animated.parallel([
|
|
59
59
|
Animated.timing(translateY, {
|
|
60
|
-
toValue:
|
|
60
|
+
toValue: 0,
|
|
61
61
|
duration: SLIDE_MS,
|
|
62
|
+
easing: Easing.bezier(0.16, 1, 0.3, 1),
|
|
63
|
+
useNativeDriver: true,
|
|
64
|
+
}),
|
|
65
|
+
Animated.timing(backdrop, {
|
|
66
|
+
toValue: 1,
|
|
67
|
+
duration: FADE_MS,
|
|
62
68
|
easing: Easing.out(Easing.cubic),
|
|
63
69
|
useNativeDriver: true,
|
|
64
70
|
}),
|
|
71
|
+
]).start();
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (!visible && shown.current) {
|
|
76
|
+
shown.current = false;
|
|
77
|
+
// Starts from wherever the sheet is now, so a drag that crosses the
|
|
78
|
+
// dismiss threshold continues rather than jumping.
|
|
79
|
+
Animated.parallel([
|
|
80
|
+
Animated.timing(translateY, {
|
|
81
|
+
toValue: sheetHeight,
|
|
82
|
+
duration: theme.motion.slow,
|
|
83
|
+
easing: Easing.in(Easing.cubic),
|
|
84
|
+
useNativeDriver: true,
|
|
85
|
+
}),
|
|
65
86
|
Animated.timing(backdrop, {
|
|
66
87
|
toValue: 0,
|
|
67
|
-
duration:
|
|
68
|
-
easing: Easing.
|
|
88
|
+
duration: theme.motion.slow,
|
|
89
|
+
easing: Easing.in(Easing.cubic),
|
|
69
90
|
useNativeDriver: true,
|
|
70
91
|
}),
|
|
71
92
|
]).start(({ finished }) => {
|
|
72
|
-
if (finished)
|
|
93
|
+
if (finished) setRendered(false);
|
|
73
94
|
});
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
);
|
|
77
|
-
|
|
78
|
-
useEffect(() => {
|
|
79
|
-
if (visible) animateIn();
|
|
80
|
-
}, [visible, animateIn]);
|
|
95
|
+
}
|
|
96
|
+
}, [rendered, visible, sheetHeight, translateY, backdrop, theme.motion.slow]);
|
|
81
97
|
|
|
82
98
|
const requestClose = useCallback(() => {
|
|
83
|
-
|
|
84
|
-
}, [
|
|
99
|
+
onClose();
|
|
100
|
+
}, [onClose]);
|
|
85
101
|
|
|
86
102
|
// Drag handle: follow the finger downward; past 25% (or a flick), dismiss.
|
|
87
103
|
const panResponder = useRef(
|
|
@@ -97,7 +113,7 @@ export function BottomSheet({
|
|
|
97
113
|
} else {
|
|
98
114
|
Animated.timing(translateY, {
|
|
99
115
|
toValue: 0,
|
|
100
|
-
duration:
|
|
116
|
+
duration: theme.motion.slow,
|
|
101
117
|
easing: Easing.out(Easing.cubic),
|
|
102
118
|
useNativeDriver: true,
|
|
103
119
|
}).start();
|
|
@@ -106,7 +122,7 @@ export function BottomSheet({
|
|
|
106
122
|
}),
|
|
107
123
|
).current;
|
|
108
124
|
|
|
109
|
-
if (!
|
|
125
|
+
if (!rendered) return null;
|
|
110
126
|
|
|
111
127
|
return (
|
|
112
128
|
<Modal
|
|
@@ -125,7 +141,7 @@ export function BottomSheet({
|
|
|
125
141
|
right: 0,
|
|
126
142
|
bottom: 0,
|
|
127
143
|
left: 0,
|
|
128
|
-
backgroundColor: 'rgba(0,0,0,0.
|
|
144
|
+
backgroundColor: 'rgba(0,0,0,0.55)',
|
|
129
145
|
opacity: backdrop,
|
|
130
146
|
}}
|
|
131
147
|
>
|
|
@@ -139,25 +155,27 @@ export function BottomSheet({
|
|
|
139
155
|
<Animated.View
|
|
140
156
|
style={{
|
|
141
157
|
height: sheetHeight,
|
|
142
|
-
backgroundColor: theme.colors.
|
|
158
|
+
backgroundColor: theme.colors.bg,
|
|
143
159
|
borderTopLeftRadius: theme.radii.sheet,
|
|
144
160
|
borderTopRightRadius: theme.radii.sheet,
|
|
145
161
|
borderWidth: 1,
|
|
146
162
|
borderBottomWidth: 0,
|
|
147
163
|
borderColor: theme.colors.border,
|
|
164
|
+
overflow: 'hidden',
|
|
148
165
|
transform: [{ translateY }],
|
|
166
|
+
...theme.shadows.sheet,
|
|
149
167
|
}}
|
|
150
168
|
>
|
|
151
169
|
{/* Drag handle */}
|
|
152
170
|
<View
|
|
153
171
|
{...panResponder.panHandlers}
|
|
154
|
-
style={{ alignItems: 'center',
|
|
172
|
+
style={{ alignItems: 'center', paddingTop: 10, paddingBottom: 6 }}
|
|
155
173
|
>
|
|
156
174
|
<View
|
|
157
175
|
style={{
|
|
158
|
-
width:
|
|
159
|
-
height:
|
|
160
|
-
borderRadius:
|
|
176
|
+
width: 40,
|
|
177
|
+
height: 5,
|
|
178
|
+
borderRadius: 3,
|
|
161
179
|
backgroundColor: theme.colors.borderStrong,
|
|
162
180
|
}}
|
|
163
181
|
/>
|