@giovchat/react-native 0.0.0-stage → 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/LICENSE +21 -0
- package/README.md +390 -2
- package/dist/GiovChat.d.ts +135 -0
- package/dist/GiovChat.d.ts.map +1 -0
- package/dist/GiovChat.js +294 -0
- package/dist/GiovChat.js.map +1 -0
- package/dist/attachments.d.ts +121 -0
- package/dist/attachments.d.ts.map +1 -0
- package/dist/attachments.js +185 -0
- package/dist/attachments.js.map +1 -0
- package/dist/brand-assets.d.ts +6 -0
- package/dist/brand-assets.d.ts.map +1 -0
- package/dist/brand-assets.js +9 -0
- package/dist/brand-assets.js.map +1 -0
- package/dist/brandingStyle.d.ts +38 -0
- package/dist/brandingStyle.d.ts.map +1 -0
- package/dist/brandingStyle.js +71 -0
- package/dist/brandingStyle.js.map +1 -0
- package/dist/client.d.ts +226 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +891 -0
- package/dist/client.js.map +1 -0
- package/dist/color.d.ts +25 -0
- package/dist/color.d.ts.map +1 -0
- package/dist/color.js +78 -0
- package/dist/color.js.map +1 -0
- package/dist/components/Attachments.d.ts +13 -0
- package/dist/components/Attachments.d.ts.map +1 -0
- package/dist/components/Attachments.js +42 -0
- package/dist/components/Attachments.js.map +1 -0
- package/dist/components/Branding.d.ts +29 -0
- package/dist/components/Branding.d.ts.map +1 -0
- package/dist/components/Branding.js +71 -0
- package/dist/components/Branding.js.map +1 -0
- package/dist/components/ChatMarkdown.d.ts +15 -0
- package/dist/components/ChatMarkdown.d.ts.map +1 -0
- package/dist/components/ChatMarkdown.js +72 -0
- package/dist/components/ChatMarkdown.js.map +1 -0
- package/dist/components/GiovBotMark.d.ts +6 -0
- package/dist/components/GiovBotMark.d.ts.map +1 -0
- package/dist/components/GiovBotMark.js +11 -0
- package/dist/components/GiovBotMark.js.map +1 -0
- package/dist/components/GreetingBubble.d.ts +7 -0
- package/dist/components/GreetingBubble.d.ts.map +1 -0
- package/dist/components/GreetingBubble.js +12 -0
- package/dist/components/GreetingBubble.js.map +1 -0
- package/dist/components/Header.d.ts +18 -0
- package/dist/components/Header.d.ts.map +1 -0
- package/dist/components/Header.js +67 -0
- package/dist/components/Header.js.map +1 -0
- package/dist/components/MessageBubble.d.ts +23 -0
- package/dist/components/MessageBubble.d.ts.map +1 -0
- package/dist/components/MessageBubble.js +51 -0
- package/dist/components/MessageBubble.js.map +1 -0
- package/dist/components/PreChatForm.d.ts +11 -0
- package/dist/components/PreChatForm.d.ts.map +1 -0
- package/dist/components/PreChatForm.js +72 -0
- package/dist/components/PreChatForm.js.map +1 -0
- package/dist/components/RatingCard.d.ts +23 -0
- package/dist/components/RatingCard.d.ts.map +1 -0
- package/dist/components/RatingCard.js +107 -0
- package/dist/components/RatingCard.js.map +1 -0
- package/dist/components/TypingIndicator.d.ts +9 -0
- package/dist/components/TypingIndicator.d.ts.map +1 -0
- package/dist/components/TypingIndicator.js +18 -0
- package/dist/components/TypingIndicator.js.map +1 -0
- package/dist/components/WidgetStyles.d.ts +3 -0
- package/dist/components/WidgetStyles.d.ts.map +1 -0
- package/dist/components/WidgetStyles.js +9 -0
- package/dist/components/WidgetStyles.js.map +1 -0
- package/dist/components/bubbleStyles.d.ts +47 -0
- package/dist/components/bubbleStyles.d.ts.map +1 -0
- package/dist/components/bubbleStyles.js +19 -0
- package/dist/components/bubbleStyles.js.map +1 -0
- package/dist/components/index.d.ts +11 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +14 -0
- package/dist/components/index.js.map +1 -0
- package/dist/errors.d.ts +20 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +26 -0
- package/dist/errors.js.map +1 -0
- package/dist/i18n.d.ts +96 -0
- package/dist/i18n.d.ts.map +1 -0
- package/dist/i18n.js +392 -0
- package/dist/i18n.js.map +1 -0
- package/dist/identity.d.ts +41 -0
- package/dist/identity.d.ts.map +1 -0
- package/dist/identity.js +41 -0
- package/dist/identity.js.map +1 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +64 -0
- package/dist/index.js.map +1 -0
- package/dist/markdown.d.ts +56 -0
- package/dist/markdown.d.ts.map +1 -0
- package/dist/markdown.js +219 -0
- package/dist/markdown.js.map +1 -0
- package/dist/outbox.d.ts +68 -0
- package/dist/outbox.d.ts.map +1 -0
- package/dist/outbox.js +168 -0
- package/dist/outbox.js.map +1 -0
- package/dist/protocol.d.ts +9 -0
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.js +39 -0
- package/dist/protocol.js.map +1 -0
- package/dist/rating.d.ts +41 -0
- package/dist/rating.d.ts.map +1 -0
- package/dist/rating.js +165 -0
- package/dist/rating.js.map +1 -0
- package/dist/ratingStore.d.ts +36 -0
- package/dist/ratingStore.d.ts.map +1 -0
- package/dist/ratingStore.js +55 -0
- package/dist/ratingStore.js.map +1 -0
- package/dist/styleOverrides.d.ts +45 -0
- package/dist/styleOverrides.d.ts.map +1 -0
- package/dist/styleOverrides.js +63 -0
- package/dist/styleOverrides.js.map +1 -0
- package/dist/types.d.ts +156 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/unread.d.ts +9 -0
- package/dist/unread.d.ts.map +1 -0
- package/dist/unread.js +49 -0
- package/dist/unread.js.map +1 -0
- package/dist/useChatSession.d.ts +95 -0
- package/dist/useChatSession.d.ts.map +1 -0
- package/dist/useChatSession.js +965 -0
- package/dist/useChatSession.js.map +1 -0
- package/package.json +60 -4
- package/src/GiovChat.tsx +640 -0
- package/src/attachments.ts +218 -0
- package/src/brand-assets.ts +5 -0
- package/src/brandingStyle.ts +87 -0
- package/src/client.ts +848 -0
- package/src/color.ts +74 -0
- package/src/components/Attachments.tsx +75 -0
- package/src/components/Branding.tsx +94 -0
- package/src/components/ChatMarkdown.tsx +111 -0
- package/src/components/GiovBotMark.tsx +19 -0
- package/src/components/GreetingBubble.tsx +20 -0
- package/src/components/Header.tsx +131 -0
- package/src/components/MessageBubble.tsx +137 -0
- package/src/components/PreChatForm.tsx +183 -0
- package/src/components/RatingCard.tsx +219 -0
- package/src/components/TypingIndicator.tsx +34 -0
- package/src/components/WidgetStyles.tsx +5 -0
- package/src/components/bubbleStyles.ts +16 -0
- package/src/components/index.ts +14 -0
- package/src/errors.ts +33 -0
- package/src/i18n.ts +474 -0
- package/src/identity.ts +54 -0
- package/src/index.ts +85 -0
- package/src/markdown.ts +227 -0
- package/src/outbox.ts +175 -0
- package/src/protocol.ts +36 -0
- package/src/rating.ts +169 -0
- package/src/ratingStore.ts +65 -0
- package/src/styleOverrides.ts +98 -0
- package/src/types.ts +170 -0
- package/src/unread.ts +39 -0
- package/src/useChatSession.ts +841 -0
package/src/i18n.ts
ADDED
|
@@ -0,0 +1,474 @@
|
|
|
1
|
+
import { createContext, useContext } from "react";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The SDK's own interface text in the five languages the Giov dashboard ships. Text the business
|
|
5
|
+
* writes (greeting, placeholder, bot name) comes from the widget configuration and is not translated.
|
|
6
|
+
* Hosts pick the language with the `locale` prop (default: the device language) and can replace any
|
|
7
|
+
* string with `strings`.
|
|
8
|
+
*/
|
|
9
|
+
export interface GiovChatStrings {
|
|
10
|
+
loading: string;
|
|
11
|
+
tryAgain: string;
|
|
12
|
+
retry: string;
|
|
13
|
+
closeChat: string;
|
|
14
|
+
/** The header menu button. */
|
|
15
|
+
menu: string;
|
|
16
|
+
/** The header menu's link to the workspace's privacy policy, as in the web widget. */
|
|
17
|
+
privacyPolicy: string;
|
|
18
|
+
/** Spoken when a reply arrives: who wrote it and what they wrote. */
|
|
19
|
+
newMessage: (sender: string, text: string) => string;
|
|
20
|
+
connecting: string;
|
|
21
|
+
reconnecting: string;
|
|
22
|
+
statusPerson: string;
|
|
23
|
+
statusBot: string;
|
|
24
|
+
statusTeam: string;
|
|
25
|
+
composerPlaceholder: string;
|
|
26
|
+
messageInput: string;
|
|
27
|
+
sendMessage: string;
|
|
28
|
+
attachFile: string;
|
|
29
|
+
removeAttachment: (name: string) => string;
|
|
30
|
+
you: string;
|
|
31
|
+
agent: string;
|
|
32
|
+
automated: string;
|
|
33
|
+
botTyping: (name: string) => string;
|
|
34
|
+
teamTyping: string;
|
|
35
|
+
sending: string;
|
|
36
|
+
notSent: string;
|
|
37
|
+
tapToRetry: string;
|
|
38
|
+
/** On a message that was not sent, to drop it. */
|
|
39
|
+
discard: string;
|
|
40
|
+
uploading: (percent: number) => string;
|
|
41
|
+
uploadFailed: string;
|
|
42
|
+
/** Errors, by kind; the SDK never shows raw server text. */
|
|
43
|
+
sessionExpired: string;
|
|
44
|
+
conversationEnded: string;
|
|
45
|
+
unavailable: string;
|
|
46
|
+
sendFailed: string;
|
|
47
|
+
busy: string;
|
|
48
|
+
attachmentsOff: string;
|
|
49
|
+
typeNotAllowed: (name: string) => string;
|
|
50
|
+
fileTooLarge: (name: string, maxMb: number) => string;
|
|
51
|
+
tooManyFiles: (max: number) => string;
|
|
52
|
+
openAttachment: (name: string) => string;
|
|
53
|
+
attachment: string;
|
|
54
|
+
image: string;
|
|
55
|
+
/** In place of an image that could not load (it loads again once its link is renewed). */
|
|
56
|
+
imageUnavailable: string;
|
|
57
|
+
preChatTitle: string;
|
|
58
|
+
firstName: string;
|
|
59
|
+
lastName: string;
|
|
60
|
+
email: string;
|
|
61
|
+
phone: string;
|
|
62
|
+
required: (label: string) => string;
|
|
63
|
+
startChat: string;
|
|
64
|
+
/** Conversation ratings (the card, the thumbs under GiovBot answers): visible text and screen-reader labels. */
|
|
65
|
+
rateTitle: string;
|
|
66
|
+
yourRating: string;
|
|
67
|
+
/** The five faces, from 1 (Very bad) to 5 (Great). */
|
|
68
|
+
ratingFace: (score: number) => string;
|
|
69
|
+
ratingComment: string;
|
|
70
|
+
ratingSend: string;
|
|
71
|
+
ratingThanks: string;
|
|
72
|
+
ratingChange: string;
|
|
73
|
+
ratingCancel: string;
|
|
74
|
+
ratingClosed: string;
|
|
75
|
+
ratingFailed: string;
|
|
76
|
+
ratingTooMany: string;
|
|
77
|
+
ratingWait: (seconds: number) => string;
|
|
78
|
+
answerGroup: string;
|
|
79
|
+
answerGood: string;
|
|
80
|
+
answerBad: string;
|
|
81
|
+
answerReason: string;
|
|
82
|
+
answerSkip: string;
|
|
83
|
+
answerFailed: string;
|
|
84
|
+
closeRating: string;
|
|
85
|
+
/** Replaces the composer once the team closed the conversation. */
|
|
86
|
+
startNewConversation: string;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export type GiovChatLocale = "en" | "fr" | "es" | "pt" | "de";
|
|
90
|
+
|
|
91
|
+
const en: GiovChatStrings = {
|
|
92
|
+
loading: "Loading…",
|
|
93
|
+
tryAgain: "Try again",
|
|
94
|
+
retry: "Retry",
|
|
95
|
+
closeChat: "Close chat",
|
|
96
|
+
menu: "Menu",
|
|
97
|
+
privacyPolicy: "GDPR and privacy",
|
|
98
|
+
newMessage: (sender, text) => `${sender}: ${text}`,
|
|
99
|
+
connecting: "Connecting…",
|
|
100
|
+
reconnecting: "Connection lost. Reconnecting…",
|
|
101
|
+
statusPerson: "Live agent",
|
|
102
|
+
statusBot: "AI assistant · Online",
|
|
103
|
+
statusTeam: "We'll be with you shortly",
|
|
104
|
+
composerPlaceholder: "Type a message…",
|
|
105
|
+
messageInput: "Message",
|
|
106
|
+
sendMessage: "Send message",
|
|
107
|
+
attachFile: "Attach file",
|
|
108
|
+
removeAttachment: (name) => `Remove ${name}`,
|
|
109
|
+
you: "You",
|
|
110
|
+
agent: "Agent",
|
|
111
|
+
automated: "Automated",
|
|
112
|
+
botTyping: (name) => `${name} is typing`,
|
|
113
|
+
teamTyping: "Support team is typing",
|
|
114
|
+
sending: "Sending…",
|
|
115
|
+
notSent: "Not sent",
|
|
116
|
+
tapToRetry: "Tap to retry",
|
|
117
|
+
discard: "Discard",
|
|
118
|
+
uploading: (percent) => `Uploading ${percent}%`,
|
|
119
|
+
uploadFailed: "File upload failed",
|
|
120
|
+
sessionExpired: "Chat session expired. Please start a new chat.",
|
|
121
|
+
conversationEnded: "This conversation has ended.",
|
|
122
|
+
unavailable: "Chat is unavailable. Please try again.",
|
|
123
|
+
sendFailed: "Message could not be sent.",
|
|
124
|
+
busy: "The team is busy right now. Please try again in a moment.",
|
|
125
|
+
attachmentsOff: "File attachments are turned off for this chat.",
|
|
126
|
+
typeNotAllowed: (name) => `${name}: this file type is not allowed.`,
|
|
127
|
+
fileTooLarge: (name, maxMb) => `${name}: files must be ${maxMb} MB or smaller.`,
|
|
128
|
+
tooManyFiles: (max) => `You can attach up to ${max} files at a time.`,
|
|
129
|
+
openAttachment: (name) => `Open ${name}`,
|
|
130
|
+
attachment: "Attachment",
|
|
131
|
+
image: "Image",
|
|
132
|
+
imageUnavailable: "Image unavailable",
|
|
133
|
+
preChatTitle: "Before we start…",
|
|
134
|
+
firstName: "First name",
|
|
135
|
+
lastName: "Last name",
|
|
136
|
+
email: "Email",
|
|
137
|
+
phone: "Phone",
|
|
138
|
+
required: (label) => `${label} *`,
|
|
139
|
+
startChat: "Start chat",
|
|
140
|
+
rateTitle: "Rate this conversation",
|
|
141
|
+
yourRating: "Your rating",
|
|
142
|
+
ratingFace: (score) => ["Very bad", "Bad", "Okay", "Good", "Great"][score - 1] ?? String(score),
|
|
143
|
+
ratingComment: "Add a comment (optional)",
|
|
144
|
+
ratingSend: "Send",
|
|
145
|
+
ratingThanks: "Thanks",
|
|
146
|
+
ratingChange: "Change",
|
|
147
|
+
ratingCancel: "Cancel",
|
|
148
|
+
ratingClosed: "This rating request has closed.",
|
|
149
|
+
ratingFailed: "Couldn't send. Please try again.",
|
|
150
|
+
ratingTooMany: "You have changed this rating too many times.",
|
|
151
|
+
ratingWait: (seconds) => `Too many requests. Please wait ${seconds} s and try again.`,
|
|
152
|
+
answerGroup: "Rate this answer",
|
|
153
|
+
answerGood: "Good answer",
|
|
154
|
+
answerBad: "Bad answer",
|
|
155
|
+
answerReason: "What went wrong? (optional)",
|
|
156
|
+
answerSkip: "Skip",
|
|
157
|
+
answerFailed: "Couldn't save",
|
|
158
|
+
closeRating: "Close",
|
|
159
|
+
startNewConversation: "Start a new conversation",
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
const fr: GiovChatStrings = {
|
|
163
|
+
loading: "Chargement…",
|
|
164
|
+
tryAgain: "Réessayer",
|
|
165
|
+
retry: "Réessayer",
|
|
166
|
+
closeChat: "Fermer le chat",
|
|
167
|
+
menu: "Menu",
|
|
168
|
+
privacyPolicy: "RGPD et confidentialité",
|
|
169
|
+
newMessage: (sender, text) => `${sender} : ${text}`,
|
|
170
|
+
connecting: "Connexion…",
|
|
171
|
+
reconnecting: "Connexion perdue. Reconnexion…",
|
|
172
|
+
statusPerson: "Conseiller en ligne",
|
|
173
|
+
statusBot: "Assistant IA · En ligne",
|
|
174
|
+
statusTeam: "Nous vous répondons très vite",
|
|
175
|
+
composerPlaceholder: "Écrivez un message…",
|
|
176
|
+
messageInput: "Message",
|
|
177
|
+
sendMessage: "Envoyer le message",
|
|
178
|
+
attachFile: "Joindre un fichier",
|
|
179
|
+
removeAttachment: (name) => `Retirer ${name}`,
|
|
180
|
+
you: "Vous",
|
|
181
|
+
agent: "Conseiller",
|
|
182
|
+
automated: "Automatique",
|
|
183
|
+
botTyping: (name) => `${name} écrit`,
|
|
184
|
+
teamTyping: "L'équipe écrit",
|
|
185
|
+
sending: "Envoi…",
|
|
186
|
+
notSent: "Non envoyé",
|
|
187
|
+
tapToRetry: "Touchez pour réessayer",
|
|
188
|
+
discard: "Supprimer",
|
|
189
|
+
uploading: (percent) => `Envoi ${percent} %`,
|
|
190
|
+
uploadFailed: "Échec de l'envoi du fichier",
|
|
191
|
+
sessionExpired: "La session de chat a expiré. Démarrez un nouveau chat.",
|
|
192
|
+
conversationEnded: "Cette conversation est terminée.",
|
|
193
|
+
unavailable: "Le chat est indisponible. Réessayez.",
|
|
194
|
+
sendFailed: "Le message n'a pas pu être envoyé.",
|
|
195
|
+
busy: "L'équipe est très occupée. Réessayez dans un instant.",
|
|
196
|
+
attachmentsOff: "Les pièces jointes sont désactivées pour ce chat.",
|
|
197
|
+
typeNotAllowed: (name) => `${name} : ce type de fichier n'est pas autorisé.`,
|
|
198
|
+
fileTooLarge: (name, maxMb) => `${name} : les fichiers doivent faire ${maxMb} Mo maximum.`,
|
|
199
|
+
tooManyFiles: (max) => `Vous pouvez joindre jusqu'à ${max} fichiers à la fois.`,
|
|
200
|
+
openAttachment: (name) => `Ouvrir ${name}`,
|
|
201
|
+
attachment: "Pièce jointe",
|
|
202
|
+
image: "Image",
|
|
203
|
+
imageUnavailable: "Image indisponible",
|
|
204
|
+
preChatTitle: "Avant de commencer…",
|
|
205
|
+
firstName: "Prénom",
|
|
206
|
+
lastName: "Nom",
|
|
207
|
+
email: "E-mail",
|
|
208
|
+
phone: "Téléphone",
|
|
209
|
+
required: (label) => `${label} *`,
|
|
210
|
+
startChat: "Démarrer le chat",
|
|
211
|
+
rateTitle: "Évaluer cette conversation",
|
|
212
|
+
yourRating: "Votre note",
|
|
213
|
+
ratingFace: (score) => ["Très mauvais", "Mauvais", "Moyen", "Bon", "Excellent"][score - 1] ?? String(score),
|
|
214
|
+
ratingComment: "Ajouter un commentaire (facultatif)",
|
|
215
|
+
ratingSend: "Envoyer",
|
|
216
|
+
ratingThanks: "Merci",
|
|
217
|
+
ratingChange: "Modifier",
|
|
218
|
+
ratingCancel: "Annuler",
|
|
219
|
+
ratingClosed: "Cette demande d'évaluation est terminée.",
|
|
220
|
+
ratingFailed: "Envoi impossible. Réessayez.",
|
|
221
|
+
ratingTooMany: "Vous avez trop souvent modifié cette note.",
|
|
222
|
+
ratingWait: (seconds) => `Trop de demandes. Patientez ${seconds} s puis réessayez.`,
|
|
223
|
+
answerGroup: "Évaluer cette réponse",
|
|
224
|
+
answerGood: "Bonne réponse",
|
|
225
|
+
answerBad: "Mauvaise réponse",
|
|
226
|
+
answerReason: "Qu'est-ce qui n'allait pas ? (facultatif)",
|
|
227
|
+
answerSkip: "Passer",
|
|
228
|
+
answerFailed: "Enregistrement impossible",
|
|
229
|
+
closeRating: "Fermer",
|
|
230
|
+
startNewConversation: "Démarrer une nouvelle conversation",
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
const es: GiovChatStrings = {
|
|
234
|
+
loading: "Cargando…",
|
|
235
|
+
tryAgain: "Reintentar",
|
|
236
|
+
retry: "Reintentar",
|
|
237
|
+
closeChat: "Cerrar chat",
|
|
238
|
+
menu: "Menú",
|
|
239
|
+
privacyPolicy: "RGPD y privacidad",
|
|
240
|
+
newMessage: (sender, text) => `${sender}: ${text}`,
|
|
241
|
+
connecting: "Conectando…",
|
|
242
|
+
reconnecting: "Conexión perdida. Reconectando…",
|
|
243
|
+
statusPerson: "Agente en vivo",
|
|
244
|
+
statusBot: "Asistente de IA · En línea",
|
|
245
|
+
statusTeam: "Te atenderemos en breve",
|
|
246
|
+
composerPlaceholder: "Escribe un mensaje…",
|
|
247
|
+
messageInput: "Mensaje",
|
|
248
|
+
sendMessage: "Enviar mensaje",
|
|
249
|
+
attachFile: "Adjuntar archivo",
|
|
250
|
+
removeAttachment: (name) => `Quitar ${name}`,
|
|
251
|
+
you: "Tú",
|
|
252
|
+
agent: "Agente",
|
|
253
|
+
automated: "Automático",
|
|
254
|
+
botTyping: (name) => `${name} está escribiendo`,
|
|
255
|
+
teamTyping: "El equipo está escribiendo",
|
|
256
|
+
sending: "Enviando…",
|
|
257
|
+
notSent: "No enviado",
|
|
258
|
+
tapToRetry: "Toca para reintentar",
|
|
259
|
+
discard: "Descartar",
|
|
260
|
+
uploading: (percent) => `Subiendo ${percent} %`,
|
|
261
|
+
uploadFailed: "No se pudo subir el archivo",
|
|
262
|
+
sessionExpired: "La sesión de chat caducó. Inicia un chat nuevo.",
|
|
263
|
+
conversationEnded: "Esta conversación ha terminado.",
|
|
264
|
+
unavailable: "El chat no está disponible. Inténtalo de nuevo.",
|
|
265
|
+
sendFailed: "No se pudo enviar el mensaje.",
|
|
266
|
+
busy: "El equipo está ocupado ahora. Inténtalo de nuevo en un momento.",
|
|
267
|
+
attachmentsOff: "Los archivos adjuntos están desactivados en este chat.",
|
|
268
|
+
typeNotAllowed: (name) => `${name}: este tipo de archivo no está permitido.`,
|
|
269
|
+
fileTooLarge: (name, maxMb) => `${name}: los archivos deben pesar ${maxMb} MB o menos.`,
|
|
270
|
+
tooManyFiles: (max) => `Puedes adjuntar hasta ${max} archivos a la vez.`,
|
|
271
|
+
openAttachment: (name) => `Abrir ${name}`,
|
|
272
|
+
attachment: "Archivo adjunto",
|
|
273
|
+
image: "Imagen",
|
|
274
|
+
imageUnavailable: "Imagen no disponible",
|
|
275
|
+
preChatTitle: "Antes de empezar…",
|
|
276
|
+
firstName: "Nombre",
|
|
277
|
+
lastName: "Apellido",
|
|
278
|
+
email: "Correo electrónico",
|
|
279
|
+
phone: "Teléfono",
|
|
280
|
+
required: (label) => `${label} *`,
|
|
281
|
+
startChat: "Iniciar chat",
|
|
282
|
+
rateTitle: "Valora esta conversación",
|
|
283
|
+
yourRating: "Tu valoración",
|
|
284
|
+
ratingFace: (score) => ["Muy mala", "Mala", "Regular", "Buena", "Excelente"][score - 1] ?? String(score),
|
|
285
|
+
ratingComment: "Añade un comentario (opcional)",
|
|
286
|
+
ratingSend: "Enviar",
|
|
287
|
+
ratingThanks: "Gracias",
|
|
288
|
+
ratingChange: "Cambiar",
|
|
289
|
+
ratingCancel: "Cancelar",
|
|
290
|
+
ratingClosed: "Esta solicitud de valoración ha terminado.",
|
|
291
|
+
ratingFailed: "No se pudo enviar. Inténtalo de nuevo.",
|
|
292
|
+
ratingTooMany: "Has cambiado esta valoración demasiadas veces.",
|
|
293
|
+
ratingWait: (seconds) => `Demasiadas solicitudes. Espera ${seconds} s e inténtalo de nuevo.`,
|
|
294
|
+
answerGroup: "Valora esta respuesta",
|
|
295
|
+
answerGood: "Buena respuesta",
|
|
296
|
+
answerBad: "Mala respuesta",
|
|
297
|
+
answerReason: "¿Qué salió mal? (opcional)",
|
|
298
|
+
answerSkip: "Omitir",
|
|
299
|
+
answerFailed: "No se pudo guardar",
|
|
300
|
+
closeRating: "Cerrar",
|
|
301
|
+
startNewConversation: "Iniciar una conversación nueva",
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
const pt: GiovChatStrings = {
|
|
305
|
+
loading: "Carregando…",
|
|
306
|
+
tryAgain: "Tentar novamente",
|
|
307
|
+
retry: "Tentar novamente",
|
|
308
|
+
closeChat: "Fechar chat",
|
|
309
|
+
menu: "Menu",
|
|
310
|
+
privacyPolicy: "RGPD e privacidade",
|
|
311
|
+
newMessage: (sender, text) => `${sender}: ${text}`,
|
|
312
|
+
connecting: "Conectando…",
|
|
313
|
+
reconnecting: "Conexão perdida. Reconectando…",
|
|
314
|
+
statusPerson: "Atendente ao vivo",
|
|
315
|
+
statusBot: "Assistente de IA · Online",
|
|
316
|
+
statusTeam: "Responderemos em breve",
|
|
317
|
+
composerPlaceholder: "Digite uma mensagem…",
|
|
318
|
+
messageInput: "Mensagem",
|
|
319
|
+
sendMessage: "Enviar mensagem",
|
|
320
|
+
attachFile: "Anexar arquivo",
|
|
321
|
+
removeAttachment: (name) => `Remover ${name}`,
|
|
322
|
+
you: "Você",
|
|
323
|
+
agent: "Atendente",
|
|
324
|
+
automated: "Automático",
|
|
325
|
+
botTyping: (name) => `${name} está digitando`,
|
|
326
|
+
teamTyping: "A equipe está digitando",
|
|
327
|
+
sending: "Enviando…",
|
|
328
|
+
notSent: "Não enviada",
|
|
329
|
+
tapToRetry: "Toque para tentar novamente",
|
|
330
|
+
discard: "Descartar",
|
|
331
|
+
uploading: (percent) => `Enviando ${percent}%`,
|
|
332
|
+
uploadFailed: "Falha ao enviar o arquivo",
|
|
333
|
+
sessionExpired: "A sessão do chat expirou. Inicie um novo chat.",
|
|
334
|
+
conversationEnded: "Esta conversa foi encerrada.",
|
|
335
|
+
unavailable: "O chat está indisponível. Tente novamente.",
|
|
336
|
+
sendFailed: "Não foi possível enviar a mensagem.",
|
|
337
|
+
busy: "A equipe está ocupada agora. Tente novamente em instantes.",
|
|
338
|
+
attachmentsOff: "Os anexos estão desativados neste chat.",
|
|
339
|
+
typeNotAllowed: (name) => `${name}: este tipo de arquivo não é permitido.`,
|
|
340
|
+
fileTooLarge: (name, maxMb) => `${name}: os arquivos devem ter até ${maxMb} MB.`,
|
|
341
|
+
tooManyFiles: (max) => `Você pode anexar até ${max} arquivos por vez.`,
|
|
342
|
+
openAttachment: (name) => `Abrir ${name}`,
|
|
343
|
+
attachment: "Anexo",
|
|
344
|
+
image: "Imagem",
|
|
345
|
+
imageUnavailable: "Imagem indisponível",
|
|
346
|
+
preChatTitle: "Antes de começar…",
|
|
347
|
+
firstName: "Nome",
|
|
348
|
+
lastName: "Sobrenome",
|
|
349
|
+
email: "E-mail",
|
|
350
|
+
phone: "Telefone",
|
|
351
|
+
required: (label) => `${label} *`,
|
|
352
|
+
startChat: "Iniciar chat",
|
|
353
|
+
rateTitle: "Avalie esta conversa",
|
|
354
|
+
yourRating: "Sua avaliação",
|
|
355
|
+
ratingFace: (score) => ["Muito ruim", "Ruim", "Regular", "Boa", "Ótima"][score - 1] ?? String(score),
|
|
356
|
+
ratingComment: "Adicione um comentário (opcional)",
|
|
357
|
+
ratingSend: "Enviar",
|
|
358
|
+
ratingThanks: "Obrigado",
|
|
359
|
+
ratingChange: "Alterar",
|
|
360
|
+
ratingCancel: "Cancelar",
|
|
361
|
+
ratingClosed: "Este pedido de avaliação foi encerrado.",
|
|
362
|
+
ratingFailed: "Não foi possível enviar. Tente novamente.",
|
|
363
|
+
ratingTooMany: "Você alterou esta avaliação vezes demais.",
|
|
364
|
+
ratingWait: (seconds) => `Muitas solicitações. Aguarde ${seconds} s e tente novamente.`,
|
|
365
|
+
answerGroup: "Avalie esta resposta",
|
|
366
|
+
answerGood: "Boa resposta",
|
|
367
|
+
answerBad: "Resposta ruim",
|
|
368
|
+
answerReason: "O que deu errado? (opcional)",
|
|
369
|
+
answerSkip: "Pular",
|
|
370
|
+
answerFailed: "Não foi possível salvar",
|
|
371
|
+
closeRating: "Fechar",
|
|
372
|
+
startNewConversation: "Iniciar uma nova conversa",
|
|
373
|
+
};
|
|
374
|
+
|
|
375
|
+
const de: GiovChatStrings = {
|
|
376
|
+
loading: "Wird geladen…",
|
|
377
|
+
tryAgain: "Erneut versuchen",
|
|
378
|
+
retry: "Erneut versuchen",
|
|
379
|
+
closeChat: "Chat schließen",
|
|
380
|
+
menu: "Menü",
|
|
381
|
+
privacyPolicy: "DSGVO und Datenschutz",
|
|
382
|
+
newMessage: (sender, text) => `${sender}: ${text}`,
|
|
383
|
+
connecting: "Verbindung wird hergestellt…",
|
|
384
|
+
reconnecting: "Verbindung unterbrochen. Neuer Versuch…",
|
|
385
|
+
statusPerson: "Live-Support",
|
|
386
|
+
statusBot: "KI-Assistent · Online",
|
|
387
|
+
statusTeam: "Wir sind gleich für dich da",
|
|
388
|
+
composerPlaceholder: "Nachricht schreiben…",
|
|
389
|
+
messageInput: "Nachricht",
|
|
390
|
+
sendMessage: "Nachricht senden",
|
|
391
|
+
attachFile: "Datei anhängen",
|
|
392
|
+
removeAttachment: (name) => `${name} entfernen`,
|
|
393
|
+
you: "Du",
|
|
394
|
+
agent: "Support",
|
|
395
|
+
automated: "Automatisch",
|
|
396
|
+
botTyping: (name) => `${name} schreibt`,
|
|
397
|
+
teamTyping: "Das Team schreibt",
|
|
398
|
+
sending: "Wird gesendet…",
|
|
399
|
+
notSent: "Nicht gesendet",
|
|
400
|
+
tapToRetry: "Tippen zum Wiederholen",
|
|
401
|
+
discard: "Verwerfen",
|
|
402
|
+
uploading: (percent) => `Wird hochgeladen: ${percent} %`,
|
|
403
|
+
uploadFailed: "Datei konnte nicht hochgeladen werden",
|
|
404
|
+
sessionExpired: "Die Chat-Sitzung ist abgelaufen. Starte einen neuen Chat.",
|
|
405
|
+
conversationEnded: "Diese Unterhaltung ist beendet.",
|
|
406
|
+
unavailable: "Der Chat ist nicht verfügbar. Bitte versuche es erneut.",
|
|
407
|
+
sendFailed: "Die Nachricht konnte nicht gesendet werden.",
|
|
408
|
+
busy: "Das Team ist gerade ausgelastet. Bitte versuche es gleich noch einmal.",
|
|
409
|
+
attachmentsOff: "Dateianhänge sind in diesem Chat deaktiviert.",
|
|
410
|
+
typeNotAllowed: (name) => `${name}: Dieser Dateityp ist nicht erlaubt.`,
|
|
411
|
+
fileTooLarge: (name, maxMb) => `${name}: Dateien dürfen höchstens ${maxMb} MB groß sein.`,
|
|
412
|
+
tooManyFiles: (max) => `Du kannst bis zu ${max} Dateien auf einmal anhängen.`,
|
|
413
|
+
openAttachment: (name) => `${name} öffnen`,
|
|
414
|
+
attachment: "Anhang",
|
|
415
|
+
image: "Bild",
|
|
416
|
+
imageUnavailable: "Bild nicht verfügbar",
|
|
417
|
+
preChatTitle: "Bevor es losgeht…",
|
|
418
|
+
firstName: "Vorname",
|
|
419
|
+
lastName: "Nachname",
|
|
420
|
+
email: "E-Mail",
|
|
421
|
+
phone: "Telefon",
|
|
422
|
+
required: (label) => `${label} *`,
|
|
423
|
+
startChat: "Chat starten",
|
|
424
|
+
rateTitle: "Bewerte diese Unterhaltung",
|
|
425
|
+
yourRating: "Deine Bewertung",
|
|
426
|
+
ratingFace: (score) => ["Sehr schlecht", "Schlecht", "Okay", "Gut", "Sehr gut"][score - 1] ?? String(score),
|
|
427
|
+
ratingComment: "Kommentar hinzufügen (optional)",
|
|
428
|
+
ratingSend: "Senden",
|
|
429
|
+
ratingThanks: "Danke",
|
|
430
|
+
ratingChange: "Ändern",
|
|
431
|
+
ratingCancel: "Abbrechen",
|
|
432
|
+
ratingClosed: "Diese Bewertungsanfrage ist beendet.",
|
|
433
|
+
ratingFailed: "Senden fehlgeschlagen. Bitte versuche es erneut.",
|
|
434
|
+
ratingTooMany: "Du hast diese Bewertung zu oft geändert.",
|
|
435
|
+
ratingWait: (seconds) => `Zu viele Anfragen. Warte ${seconds} s und versuche es erneut.`,
|
|
436
|
+
answerGroup: "Bewerte diese Antwort",
|
|
437
|
+
answerGood: "Gute Antwort",
|
|
438
|
+
answerBad: "Schlechte Antwort",
|
|
439
|
+
answerReason: "Was ist schiefgelaufen? (optional)",
|
|
440
|
+
answerSkip: "Überspringen",
|
|
441
|
+
answerFailed: "Speichern fehlgeschlagen",
|
|
442
|
+
closeRating: "Schließen",
|
|
443
|
+
startNewConversation: "Neue Unterhaltung starten",
|
|
444
|
+
};
|
|
445
|
+
|
|
446
|
+
export const GIOVCHAT_STRINGS: Readonly<Record<GiovChatLocale, GiovChatStrings>> = { en, fr, es, pt, de };
|
|
447
|
+
|
|
448
|
+
/** "fr-CA" → "fr", "pt_BR" → "pt"; anything not shipped falls back to English. */
|
|
449
|
+
export function resolveLocale(value: string | null | undefined): GiovChatLocale {
|
|
450
|
+
const language = String(value ?? "").trim().toLowerCase().split(/[-_]/)[0];
|
|
451
|
+
return (Object.keys(GIOVCHAT_STRINGS) as GiovChatLocale[]).includes(language as GiovChatLocale) ? language as GiovChatLocale : "en";
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
/** The device language from Intl (Hermes and JSC both ship it), with no native module. */
|
|
455
|
+
export function deviceLocale(): string {
|
|
456
|
+
try { return Intl.DateTimeFormat().resolvedOptions().locale || "en"; } catch { return "en"; }
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
/** The strings for a locale with the host's overrides on top; malformed overrides are ignored. */
|
|
460
|
+
export function resolveStrings(locale?: string | null, overrides?: Partial<GiovChatStrings> | null): GiovChatStrings {
|
|
461
|
+
const base = GIOVCHAT_STRINGS[resolveLocale(locale ?? deviceLocale())];
|
|
462
|
+
if (!overrides || typeof overrides !== "object") return base;
|
|
463
|
+
const result = { ...base } as Record<string, unknown>;
|
|
464
|
+
for (const [key, value] of Object.entries(overrides)) {
|
|
465
|
+
const current = (base as unknown as Record<string, unknown>)[key];
|
|
466
|
+
if (current === undefined || typeof value !== typeof current) continue;
|
|
467
|
+
if (typeof value === "string" && !value.trim()) continue;
|
|
468
|
+
result[key] = value;
|
|
469
|
+
}
|
|
470
|
+
return result as unknown as GiovChatStrings;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
export const GiovChatStringsContext = createContext<GiovChatStrings>(en);
|
|
474
|
+
export const useGiovChatStrings = () => useContext(GiovChatStringsContext);
|
package/src/identity.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { GiovWidgetConfig } from "./types";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Who the visitor is talking to, as the web widget shows it (apps/widget-web/src/components/
|
|
5
|
+
* header-identity.ts): a person once one has taken over (their name and photo), otherwise the AI
|
|
6
|
+
* assistant while it answers (its own name and avatar), and the team title when neither is set up.
|
|
7
|
+
*/
|
|
8
|
+
export type HeaderIdentityKind = "person" | "bot" | "team";
|
|
9
|
+
export interface HeaderIdentity {
|
|
10
|
+
kind: HeaderIdentityKind;
|
|
11
|
+
title: string;
|
|
12
|
+
avatar: string | null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function headerIdentity(
|
|
16
|
+
config: Pick<GiovWidgetConfig, "title" | "botEnabled" | "botName" | "botAvatarUrl" | "avatarUrl">,
|
|
17
|
+
currentAgentName?: string | null,
|
|
18
|
+
currentAgentAvatar?: string | null,
|
|
19
|
+
): HeaderIdentity {
|
|
20
|
+
if (currentAgentName) return { kind: "person", title: currentAgentName, avatar: safeImageUrl(currentAgentAvatar) };
|
|
21
|
+
if (config.botEnabled && config.botName) return { kind: "bot", title: config.botName, avatar: safeImageUrl(config.botAvatarUrl) };
|
|
22
|
+
return { kind: "team", title: config.title, avatar: safeImageUrl(config.avatarUrl) };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** Only http(s) images are loaded; anything else falls back to the initial. */
|
|
26
|
+
export function safeImageUrl(value: unknown): string | null {
|
|
27
|
+
return typeof value === "string" && /^https?:\/\//i.test(value.trim()) ? value.trim() : null;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
type IdentityInput = { role: string; isBot?: boolean; isAutomated?: boolean; senderName?: string | null };
|
|
31
|
+
|
|
32
|
+
/** The label above a bubble. AI delivery is also automated internally; the AI identity takes precedence. */
|
|
33
|
+
export function messageSenderLabel(
|
|
34
|
+
message: IdentityInput,
|
|
35
|
+
labels: { botName?: string; agentName?: string | null; you: string; automated: string; agent: string },
|
|
36
|
+
): string {
|
|
37
|
+
if (message.role !== "agent") return labels.you;
|
|
38
|
+
if (message.isBot === true) return labels.botName?.trim() || "GiovBot";
|
|
39
|
+
if (message.isAutomated === true) return labels.automated;
|
|
40
|
+
return message.senderName?.trim() || labels.agentName?.trim() || labels.agent;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export type AgentTypingState = { visible: boolean; isBot?: boolean };
|
|
44
|
+
|
|
45
|
+
/** Only explicit server AI metadata may brand a typing indicator as the AI (as in the widget). */
|
|
46
|
+
export function reduceAgentTyping(current: AgentTypingState, event: { type?: unknown; role?: unknown; isBot?: unknown }): AgentTypingState {
|
|
47
|
+
if (event.role !== "agent") return current;
|
|
48
|
+
if (event.type === "typing") return { visible: true, isBot: typeof event.isBot === "boolean" ? event.isBot : undefined };
|
|
49
|
+
if (event.type === "typing_end") {
|
|
50
|
+
if (typeof event.isBot === "boolean" && typeof current.isBot === "boolean" && event.isBot !== current.isBot) return current;
|
|
51
|
+
return { visible: false };
|
|
52
|
+
}
|
|
53
|
+
return current;
|
|
54
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// Public types
|
|
2
|
+
export type {
|
|
3
|
+
GiovChatContact,
|
|
4
|
+
GiovChatSession,
|
|
5
|
+
GiovChatSessionStorage,
|
|
6
|
+
GiovChatConnectionStatus,
|
|
7
|
+
GiovAnswerFeedback,
|
|
8
|
+
GiovFeedbackValue,
|
|
9
|
+
GiovMessage,
|
|
10
|
+
GiovRatingBlock,
|
|
11
|
+
GiovRatingRequest,
|
|
12
|
+
GiovRatingResult,
|
|
13
|
+
GiovRatingScore,
|
|
14
|
+
GiovWidgetConfig,
|
|
15
|
+
MessageHandler,
|
|
16
|
+
RequestUserInfo,
|
|
17
|
+
StatusHandler,
|
|
18
|
+
} from "./types";
|
|
19
|
+
|
|
20
|
+
// Advanced / headless usage
|
|
21
|
+
export {
|
|
22
|
+
ChatClient,
|
|
23
|
+
createConversation,
|
|
24
|
+
DEFAULT_BASE_URL,
|
|
25
|
+
fetchWidgetConfig,
|
|
26
|
+
fetchConversationHistory,
|
|
27
|
+
PUSH_TOKEN_PATH,
|
|
28
|
+
SDK_VERSION,
|
|
29
|
+
UPLOAD_TIMEOUT_MS,
|
|
30
|
+
unregisterPushToken,
|
|
31
|
+
} from "./client";
|
|
32
|
+
export type {
|
|
33
|
+
ChatClientOptions,
|
|
34
|
+
GiovConversationHistory,
|
|
35
|
+
GiovConversationState,
|
|
36
|
+
GiovPushOptions,
|
|
37
|
+
GiovPushPlatform,
|
|
38
|
+
GiovPushRegistration,
|
|
39
|
+
GiovStreamEvent,
|
|
40
|
+
GiovUploadResult,
|
|
41
|
+
} from "./client";
|
|
42
|
+
export { Outbox, ACK_TIMEOUT_MS, MAX_SEND_FAILURES, MAX_MESSAGE_CHARS, clampMessage } from "./outbox";
|
|
43
|
+
export type { OutboxEntry, OutboxState } from "./outbox";
|
|
44
|
+
export { parseChatMarkdown, parseInline, plainText } from "./markdown";
|
|
45
|
+
export type { Block as ChatMarkdownBlock, InlineNode as ChatMarkdownInline } from "./markdown";
|
|
46
|
+
export { headerIdentity, messageSenderLabel, reduceAgentTyping } from "./identity";
|
|
47
|
+
export type { HeaderIdentity, HeaderIdentityKind, AgentTypingState } from "./identity";
|
|
48
|
+
export {
|
|
49
|
+
DEFAULT_ATTACHMENT_POLICY,
|
|
50
|
+
MAX_ATTACHED_FILES,
|
|
51
|
+
SUPPORTED_ATTACHMENT_TYPES,
|
|
52
|
+
normalizeAttachmentPolicy,
|
|
53
|
+
validateAttachments,
|
|
54
|
+
} from "./attachments";
|
|
55
|
+
export type {
|
|
56
|
+
GiovAttachment,
|
|
57
|
+
GiovAttachmentPolicy,
|
|
58
|
+
GiovAttachmentPreview,
|
|
59
|
+
GiovChatAttachmentPicker,
|
|
60
|
+
GiovChatPickedFile,
|
|
61
|
+
} from "./attachments";
|
|
62
|
+
|
|
63
|
+
// Main component
|
|
64
|
+
export { GiovChat } from "./GiovChat";
|
|
65
|
+
export type { GiovChatProps, GiovChatHandle } from "./GiovChat";
|
|
66
|
+
export { useGiovChatUnreadCount } from "./unread";
|
|
67
|
+
export { GIOVCHAT_STRINGS, resolveLocale, resolveStrings } from "./i18n";
|
|
68
|
+
export type { GiovChatLocale, GiovChatStrings } from "./i18n";
|
|
69
|
+
export { useGiovRating } from "./ratingStore";
|
|
70
|
+
export type { GiovRatingController } from "./ratingStore";
|
|
71
|
+
export { MAX_FEEDBACK_REASON, MAX_RATING_COMMENT, nextFeedback, parseRatingFrame, patchRating, pendingRatingRequest, ratingPhase, supersedeRatings } from "./rating";
|
|
72
|
+
export type { GiovRatingFrame } from "./rating";
|
|
73
|
+
export { RatingCard, AnswerFeedback } from "./components/RatingCard";
|
|
74
|
+
export type { RatingCardProps, RateFn, VoteFn } from "./components/RatingCard";
|
|
75
|
+
export { GiovChatError } from "./errors";
|
|
76
|
+
export type { GiovChatErrorCode } from "./errors";
|
|
77
|
+
export { GiovBranding } from "./components/Branding";
|
|
78
|
+
export type { GiovBrandingProps } from "./components/Branding";
|
|
79
|
+
export { FOOTER_MIN_CONTRAST } from "./brandingStyle";
|
|
80
|
+
export type { GiovChatBrandingStyle } from "./brandingStyle";
|
|
81
|
+
export type {
|
|
82
|
+
GiovChatStyleOverrides,
|
|
83
|
+
GiovChatTextStyle,
|
|
84
|
+
GiovChatBackgroundStyle,
|
|
85
|
+
} from "./styleOverrides";
|