@usechatting/react-native 0.1.0 → 0.1.1

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 CHANGED
@@ -1,14 +1,6 @@
1
1
  # @usechatting/react-native
2
2
 
3
- Expo-friendly React Native chat package for Chatting.
4
-
5
- ## What it includes
6
-
7
- - JavaScript client for Chatting public chat APIs
8
- - pluggable async session storage
9
- - React hook for conversation state
10
- - simple React Native chat screen
11
- - live conversation sync with automatic polling fallback
3
+ Add Chatting customer support to an Expo or React Native app.
12
4
 
13
5
  ## Install
14
6
 
@@ -16,107 +8,46 @@ Expo-friendly React Native chat package for Chatting.
16
8
  npm install @usechatting/react-native
17
9
  ```
18
10
 
19
- If you want session persistence across app restarts, also install an async storage adapter in your app, for example React Native Async Storage.
20
-
21
- For Expo push notifications in your host app, also install:
22
-
23
- ```bash
24
- npx expo install expo-notifications
25
- ```
26
-
27
- ## Required config
11
+ ## Get your site ID
28
12
 
29
- - `baseURL`: use `https://usechatting.com`
30
- - `siteId`: your site/workspace ID inside Chatting
13
+ Open [Widget Installation](https://usechatting.com/dashboard/widget?tab=installation) in Chatting and copy the `data-site-id` value.
31
14
 
32
- ## Exact Expo integration snippet
15
+ ## Add the support screen
33
16
 
34
17
  ```tsx
35
- import { useEffect, useMemo, useState } from "react";
36
- import AsyncStorage from "@react-native-async-storage/async-storage";
37
- import * as Notifications from "expo-notifications";
38
- import { AppState, Platform } from "react-native";
39
18
  import {
40
19
  ChattingClient,
41
- ChattingConversationScreen,
42
- createKeyValueSessionStore
20
+ ChattingConversationScreen
43
21
  } from "@usechatting/react-native";
44
22
 
45
- Notifications.setNotificationHandler({
46
- handleNotification: async () => ({
47
- shouldShowAlert: false,
48
- shouldPlaySound: false,
49
- shouldSetBadge: false
50
- })
51
- });
52
-
53
23
  const client = new ChattingClient({
54
- baseURL: "https://usechatting.com",
55
- siteId: "your-site-id",
56
- sessionStore: createKeyValueSessionStore(AsyncStorage, "your-site-id")
24
+ siteId: "your-site-id"
57
25
  });
58
26
 
59
27
  export function SupportScreen() {
60
- const [refreshKey, setRefreshKey] = useState(0);
61
- const context = useMemo(() => ({ pageUrl: "myapp://support" }), []);
62
-
63
- useEffect(() => {
64
- let mounted = true;
65
- const refreshChat = async () => {
66
- await client.syncPushToken();
67
- if (mounted) {
68
- setRefreshKey((current) => current + 1);
69
- }
70
- };
71
-
72
- const registerPush = async () => {
73
- const permission = await Notifications.requestPermissionsAsync();
74
- if (!mounted || permission.status !== "granted") {
75
- return;
76
- }
77
-
78
- const token = await Notifications.getExpoPushTokenAsync({
79
- projectId: "your-expo-project-id"
80
- });
81
-
82
- await client.registerPushToken({
83
- pushToken: token.data,
84
- platform: Platform.OS
85
- });
86
- };
87
-
88
- void registerPush();
89
-
90
- const appStateSubscription = AppState.addEventListener("change", (nextState) => {
91
- if (nextState === "active") {
92
- void refreshChat();
93
- }
94
- });
95
-
96
- const responseSubscription = Notifications.addNotificationResponseReceivedListener(() => {
97
- void refreshChat();
98
- });
99
-
100
- return () => {
101
- mounted = false;
102
- appStateSubscription.remove();
103
- responseSubscription.remove();
104
- };
105
- }, []);
106
-
107
- return (
108
- <ChattingConversationScreen
109
- key={refreshKey}
110
- client={client}
111
- context={context}
112
- draftVisitorEmail="customer@example.com"
113
- />
114
- );
28
+ return <ChattingConversationScreen client={client} />;
115
29
  }
116
30
  ```
117
31
 
118
- ## Realtime behavior
32
+ Messages sent here appear in your Chatting inbox. Team replies appear in the app while the screen is open.
33
+
34
+ ## Keep conversations after the app closes
35
+
36
+ Add `persistSession: true` so customers can reopen the same conversation later:
37
+
38
+ ```tsx
39
+ import { ChattingClient } from "@usechatting/react-native";
40
+
41
+ const client = new ChattingClient({
42
+ siteId: "your-site-id",
43
+ persistSession: true
44
+ });
45
+ ```
46
+
47
+ ## Optional features
119
48
 
120
- This package uses a dedicated React Native live transport for Chatting's SSE conversation stream, so new team messages and team typing updates show up immediately while the app is open. If that live connection drops, the hook falls back to foreground polling so the conversation stays usable while reconnecting.
49
+ - Pass a signed-in customer to the screen with `profile={signedInCustomer}`.
50
+ - Register an Expo push token if customers should receive phone notifications when your team replies and the app is not open.
51
+ - Use `useChattingConversation` instead of the ready-made screen if you want to build your own interface.
121
52
 
122
- Expo push delivery is now supported for background and suspended apps once the host app registers an Expo push token through `client.registerPushToken(...)`. When the app becomes active again or a notification is tapped, call `client.syncPushToken()` and remount or refresh your chat screen so the conversation refetches cleanly.
53
+ See the [complete setup guide](https://usechatting.com/guides/chatting-react-native-expo-guide).
@@ -1,4 +1,4 @@
1
- import type { ChattingClientOptions, ChattingConversationState, ChattingLiveEvent, ChattingPushRegistrationInput, ChattingSendMessageResult, ChattingSessionState, ChattingSiteConfig, ChattingSiteStatus, ChattingVisitorContext, ChattingVisitorProfile } from "./chatting-types";
1
+ import type { ChattingClientOptions, ChattingConversationState, ChattingLiveEvent, ChattingPushRegistrationInput, ChattingSendMessageResult, ChattingSessionState, ChattingSiteStatus, ChattingVisitorContext, ChattingVisitorProfile } from "./chatting-types";
2
2
  export declare class ChattingClient {
3
3
  readonly siteId: string;
4
4
  private readonly sessionStore;
@@ -7,7 +7,7 @@ export declare class ChattingClient {
7
7
  currentSessionState(): Promise<ChattingSessionState>;
8
8
  clearConversation(): Promise<void>;
9
9
  saveEmail(email: string): Promise<void>;
10
- fetchSiteConfig(context?: ChattingVisitorContext): Promise<ChattingSiteConfig>;
10
+ fetchSiteConfig(context?: ChattingVisitorContext): Promise<import("./chatting-types").ChattingSiteConfig>;
11
11
  fetchSiteStatus(context?: ChattingVisitorContext): Promise<ChattingSiteStatus>;
12
12
  fetchConversationIfAvailable(): Promise<ChattingConversationState | null>;
13
13
  fetchConversation(): Promise<ChattingConversationState>;
@@ -1,4 +1,5 @@
1
- import { createMemorySessionStore } from "./chatting-session-store";
1
+ import { resolveChattingSessionStore } from "./chatting-session-store";
2
+ import { fetchChattingSiteConfig } from "./chatting-sdk-presence";
2
3
  import { buildChattingSiteQuery, DEFAULT_CHATTING_BASE_URL, requireChattingText } from "./chatting-client-shared";
3
4
  import { clearConversationPushState, registerChattingPushToken, syncChattingPushToken, unregisterChattingPushToken } from "./chatting-push-registration";
4
5
  import { ChattingTransport } from "./chatting-transport";
@@ -9,7 +10,7 @@ export class ChattingClient {
9
10
  transport;
10
11
  constructor(options) {
11
12
  this.siteId = options.siteId;
12
- this.sessionStore = options.sessionStore ?? createMemorySessionStore();
13
+ this.sessionStore = resolveChattingSessionStore(options);
13
14
  this.transport = new ChattingTransport(options.baseURL ?? DEFAULT_CHATTING_BASE_URL, options.fetchImpl ?? fetch);
14
15
  }
15
16
  async currentSessionState() {
@@ -42,11 +43,12 @@ export class ChattingClient {
42
43
  }
43
44
  async fetchSiteConfig(context = {}) {
44
45
  const state = await this.currentSessionState();
45
- const response = await this.transport.get("/api/public/site-config", {
46
- ...buildChattingSiteQuery(this.siteId, state, resolveContext(context)),
47
- conversationId: state.conversationId ?? null
46
+ return fetchChattingSiteConfig({
47
+ transport: this.transport,
48
+ siteId: this.siteId,
49
+ state,
50
+ context: resolveContext(context)
48
51
  });
49
- return response.site;
50
52
  }
51
53
  async fetchSiteStatus(context = {}) {
52
54
  const state = await this.currentSessionState();
@@ -0,0 +1,9 @@
1
+ import { ChattingTransport } from "./chatting-transport";
2
+ import type { ChattingSessionState, ChattingSiteConfig } from "./chatting-types";
3
+ import type { resolveContext } from "./chatting-utils";
4
+ export declare function fetchChattingSiteConfig(input: {
5
+ transport: ChattingTransport;
6
+ siteId: string;
7
+ state: ChattingSessionState;
8
+ context: ReturnType<typeof resolveContext>;
9
+ }): Promise<ChattingSiteConfig>;
@@ -0,0 +1,10 @@
1
+ import { buildChattingSiteQuery } from "./chatting-client-shared";
2
+ export async function fetchChattingSiteConfig(input) {
3
+ const request = buildChattingSiteQuery(input.siteId, input.state, input.context);
4
+ await input.transport.post("/api/public/sdk-presence", request).catch(() => undefined);
5
+ const response = await input.transport.get("/api/public/site-config", {
6
+ ...request,
7
+ conversationId: input.state.conversationId ?? null
8
+ });
9
+ return response.site;
10
+ }
@@ -1,3 +1,4 @@
1
- import type { ChattingKeyValueStorage, ChattingSessionStore } from "./chatting-types";
1
+ import type { ChattingClientOptions, ChattingKeyValueStorage, ChattingSessionStore } from "./chatting-types";
2
+ export declare function resolveChattingSessionStore(options: ChattingClientOptions): ChattingSessionStore;
2
3
  export declare function createMemorySessionStore(): ChattingSessionStore;
3
4
  export declare function createKeyValueSessionStore(storage: ChattingKeyValueStorage, namespace: string): ChattingSessionStore;
@@ -1,3 +1,12 @@
1
+ import AsyncStorage from "@react-native-async-storage/async-storage";
2
+ export function resolveChattingSessionStore(options) {
3
+ if (options.sessionStore) {
4
+ return options.sessionStore;
5
+ }
6
+ return options.persistSession
7
+ ? createKeyValueSessionStore(AsyncStorage, options.siteId)
8
+ : createMemorySessionStore();
9
+ }
1
10
  export function createMemorySessionStore() {
2
11
  let state = null;
3
12
  return {
@@ -98,6 +98,7 @@ export interface ChattingSiteStatus {
98
98
  export interface ChattingClientOptions {
99
99
  siteId: string;
100
100
  baseURL?: string;
101
+ persistSession?: boolean;
101
102
  sessionStore?: ChattingSessionStore;
102
103
  fetchImpl?: typeof fetch;
103
104
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@usechatting/react-native",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "React Native and Expo visitor chat SDK for Chatting.",
5
5
  "license": "Proprietary",
6
6
  "main": "dist/index.js",
@@ -14,6 +14,9 @@
14
14
  "scripts": {
15
15
  "build": "tsc -p tsconfig.json"
16
16
  },
17
+ "dependencies": {
18
+ "@react-native-async-storage/async-storage": "2.2.0"
19
+ },
17
20
  "peerDependencies": {
18
21
  "react": ">=18",
19
22
  "react-native": ">=0.74"