@usechatting/react-native 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.
@@ -0,0 +1,161 @@
1
+ import { useEffect, useRef, useState } from "react";
2
+ import { applyConversation, startConversationSync, syncTyping } from "./chatting-hook-helpers";
3
+ import { normalizeText, toErrorMessage } from "./chatting-utils";
4
+ export function useChattingConversation(input) {
5
+ const [siteConfig, setSiteConfig] = useState(null);
6
+ const [siteStatus, setSiteStatus] = useState(null);
7
+ const [messages, setMessages] = useState([]);
8
+ const [faqSuggestions, setFaqSuggestions] = useState(null);
9
+ const [draftMessage, setDraftMessageState] = useState("");
10
+ const [emailAddress, setEmailAddress] = useState(input.draftVisitorEmail ?? "");
11
+ const [teamTyping, setTeamTyping] = useState(false);
12
+ const [errorMessage, setErrorMessage] = useState(null);
13
+ const [isLoading, setIsLoading] = useState(false);
14
+ const [isSending, setIsSending] = useState(false);
15
+ const [isSavingEmail, setIsSavingEmail] = useState(false);
16
+ const stopSyncRef = useRef(null);
17
+ const activeConversationIdRef = useRef(null);
18
+ const typingTimeoutRef = useRef(null);
19
+ const refreshConversation = () => input.client.fetchConversation();
20
+ const refreshConversationState = async () => {
21
+ const conversation = await refreshConversation();
22
+ setTeamTyping(false);
23
+ applyConversation(conversation, setMessages, setFaqSuggestions);
24
+ await startConversationSync({
25
+ client: input.client,
26
+ pollIntervalMs: input.pollIntervalMs,
27
+ stopSyncRef,
28
+ activeConversationIdRef,
29
+ setMessages,
30
+ setFaqSuggestions,
31
+ setTeamTyping,
32
+ setErrorMessage,
33
+ refreshConversation
34
+ });
35
+ };
36
+ useEffect(() => {
37
+ if (typeof input.draftVisitorEmail === "string") {
38
+ setEmailAddress(input.draftVisitorEmail);
39
+ }
40
+ }, [input.draftVisitorEmail]);
41
+ useEffect(() => {
42
+ let cancelled = false;
43
+ stopSyncRef.current?.();
44
+ stopSyncRef.current = null;
45
+ activeConversationIdRef.current = null;
46
+ setMessages([]);
47
+ setFaqSuggestions(null);
48
+ setTeamTyping(false);
49
+ const bootstrap = async () => {
50
+ setIsLoading(true);
51
+ setErrorMessage(null);
52
+ try {
53
+ if (input.draftVisitorEmail) {
54
+ await input.client.saveEmail(input.draftVisitorEmail);
55
+ }
56
+ if (input.profile) {
57
+ await input.client.identify(input.profile, input.context);
58
+ }
59
+ const [nextConfig, nextStatus, nextConversation] = await Promise.all([
60
+ input.client.fetchSiteConfig(input.context),
61
+ input.client.fetchSiteStatus(input.context),
62
+ input.client.fetchConversationIfAvailable()
63
+ ]);
64
+ if (cancelled) {
65
+ return;
66
+ }
67
+ setSiteConfig(nextConfig);
68
+ setSiteStatus(nextStatus);
69
+ if (!nextConversation) {
70
+ return;
71
+ }
72
+ await input.client.syncPushToken();
73
+ applyConversation(nextConversation, setMessages, setFaqSuggestions);
74
+ await startConversationSync({
75
+ client: input.client,
76
+ pollIntervalMs: input.pollIntervalMs,
77
+ stopSyncRef,
78
+ activeConversationIdRef,
79
+ setMessages,
80
+ setFaqSuggestions,
81
+ setTeamTyping,
82
+ setErrorMessage,
83
+ refreshConversation
84
+ });
85
+ }
86
+ catch (error) {
87
+ if (!cancelled) {
88
+ setErrorMessage(toErrorMessage(error));
89
+ }
90
+ }
91
+ finally {
92
+ if (!cancelled) {
93
+ setIsLoading(false);
94
+ }
95
+ }
96
+ };
97
+ void bootstrap();
98
+ return () => {
99
+ cancelled = true;
100
+ stopSyncRef.current?.();
101
+ if (typingTimeoutRef.current) {
102
+ clearTimeout(typingTimeoutRef.current);
103
+ }
104
+ };
105
+ }, [input.client, input.context, input.draftVisitorEmail, input.pollIntervalMs, input.profile]);
106
+ const setDraftMessage = (value) => {
107
+ setDraftMessageState(value);
108
+ void syncTyping({ client: input.client, value, typingTimeoutRef });
109
+ };
110
+ const sendMessage = async () => {
111
+ const nextMessage = normalizeText(draftMessage);
112
+ if (!nextMessage) {
113
+ return;
114
+ }
115
+ setIsSending(true);
116
+ setErrorMessage(null);
117
+ try {
118
+ await input.client.sendMessage(nextMessage, { context: input.context, email: emailAddress });
119
+ setDraftMessageState("");
120
+ setTeamTyping(false);
121
+ await refreshConversationState();
122
+ }
123
+ catch (error) {
124
+ setErrorMessage(toErrorMessage(error));
125
+ }
126
+ finally {
127
+ setIsSending(false);
128
+ }
129
+ };
130
+ const saveEmail = async () => {
131
+ setIsSavingEmail(true);
132
+ setErrorMessage(null);
133
+ try {
134
+ await input.client.saveEmail(emailAddress);
135
+ }
136
+ catch (error) {
137
+ setErrorMessage(toErrorMessage(error));
138
+ }
139
+ finally {
140
+ setIsSavingEmail(false);
141
+ }
142
+ };
143
+ return {
144
+ siteConfig,
145
+ siteStatus,
146
+ messages,
147
+ faqSuggestions,
148
+ draftMessage,
149
+ emailAddress,
150
+ teamTyping,
151
+ errorMessage,
152
+ isLoading,
153
+ isSending,
154
+ isSavingEmail,
155
+ setDraftMessage,
156
+ setEmailAddress,
157
+ refreshConversation: refreshConversationState,
158
+ sendMessage,
159
+ saveEmail
160
+ };
161
+ }
package/package.json ADDED
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "@usechatting/react-native",
3
+ "version": "0.1.0",
4
+ "description": "React Native and Expo visitor chat SDK for Chatting.",
5
+ "license": "Proprietary",
6
+ "main": "dist/index.js",
7
+ "react-native": "dist/index.js",
8
+ "types": "dist/index.d.ts",
9
+ "files": [
10
+ "dist",
11
+ "README.md"
12
+ ],
13
+ "sideEffects": false,
14
+ "scripts": {
15
+ "build": "tsc -p tsconfig.json"
16
+ },
17
+ "peerDependencies": {
18
+ "react": ">=18",
19
+ "react-native": ">=0.74"
20
+ }
21
+ }