@aslaluroba/help-center-react 3.2.17 → 3.2.18

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.
Files changed (101) hide show
  1. package/dist/components/shared/Button/button.d.ts +1 -1
  2. package/dist/components/shared/Card/card.d.ts +1 -4
  3. package/dist/components/ui/agent-response/agent-response.d.ts +2 -1
  4. package/dist/index.css +1424 -1
  5. package/dist/index.d.ts +3 -3
  6. package/dist/index.esm.js +19194 -38923
  7. package/dist/index.esm.js.map +1 -1
  8. package/dist/index.js +19198 -38927
  9. package/dist/index.js.map +1 -1
  10. package/dist/lib/LanguageContext.d.ts +1 -1
  11. package/dist/lib/custom-hooks/useAblyConnection.d.ts +25 -0
  12. package/dist/lib/custom-hooks/useActionHandler.d.ts +1 -7
  13. package/dist/lib/custom-hooks/useChatSession.d.ts +37 -0
  14. package/dist/lib/custom-hooks/useMessageQueue.d.ts +16 -0
  15. package/dist/lib/custom-hooks/useReview.d.ts +14 -0
  16. package/dist/lib/index.d.ts +1 -2
  17. package/dist/services.d.ts +9 -6
  18. package/dist/services.esm.js +1 -14348
  19. package/dist/services.esm.js.map +1 -1
  20. package/dist/services.js +19 -14344
  21. package/dist/services.js.map +1 -1
  22. package/dist/ui/chatbot-popup/chat-window-screen/footer.d.ts +1 -1
  23. package/dist/ui/chatbot-popup/chat-window-screen/in-chat-review.d.ts +1 -1
  24. package/dist/ui/chatbot-popup/chat-window-screen/index.d.ts +2 -2
  25. package/dist/ui/chatbot-popup/options-list-screen/helpscreen-list.d.ts +1 -1
  26. package/dist/ui/chatbot-popup/options-list-screen/helpscreen-option.d.ts +1 -1
  27. package/dist/ui/chatbot-popup/options-list-screen/index.d.ts +1 -1
  28. package/dist/ui/help-center.d.ts +1 -1
  29. package/dist/ui/help-popup.d.ts +4 -27
  30. package/dist/ui/review-dialog/index.d.ts +1 -1
  31. package/package.json +12 -26
  32. package/postcss.config.js +5 -0
  33. package/rollup.config.mjs +34 -0
  34. package/dist/core/AblyService.d.ts +0 -16
  35. package/dist/core/ApiService.d.ts +0 -16
  36. package/dist/core/api.d.ts +0 -10
  37. package/dist/core/token-service.d.ts +0 -10
  38. package/dist/i18n.d.ts +0 -3
  39. package/dist/lib/config.d.ts +0 -18
  40. package/dist/lib/theme-utils.d.ts +0 -10
  41. package/dist/lib/types.d.ts +0 -145
  42. package/dist/lib/utils.d.ts +0 -2
  43. package/src/assets/animatedLogo.gif +0 -0
  44. package/src/assets/logo.svg +0 -5
  45. package/src/assets/seperator.svg +0 -5
  46. package/src/components/index.ts +0 -1
  47. package/src/components/shared/Button/button.tsx +0 -38
  48. package/src/components/shared/Button/index.ts +0 -1
  49. package/src/components/shared/Card/card.tsx +0 -44
  50. package/src/components/shared/Card/index.ts +0 -1
  51. package/src/components/shared/index.ts +0 -2
  52. package/src/components/ui/agent-response/agent-response.tsx +0 -57
  53. package/src/components/ui/agent-response/doc.md +0 -88
  54. package/src/components/ui/image-attachment.tsx +0 -119
  55. package/src/components/ui/image-preview-dialog.tsx +0 -400
  56. package/src/components/ui/index.ts +0 -3
  57. package/src/core/AblyService.ts +0 -243
  58. package/src/core/ApiService.ts +0 -116
  59. package/src/core/api.ts +0 -278
  60. package/src/core/token-service.ts +0 -35
  61. package/src/globals.css +0 -268
  62. package/src/i18n.ts +0 -21
  63. package/src/index.ts +0 -19
  64. package/src/lib/LanguageContext.tsx +0 -28
  65. package/src/lib/config.ts +0 -52
  66. package/src/lib/custom-hooks/useActionHandler.ts +0 -102
  67. package/src/lib/custom-hooks/useTypewriter.ts +0 -26
  68. package/src/lib/index.ts +0 -4
  69. package/src/lib/theme-utils.ts +0 -56
  70. package/src/lib/types.ts +0 -158
  71. package/src/lib/utils.ts +0 -6
  72. package/src/locales/ar.json +0 -45
  73. package/src/locales/en.json +0 -45
  74. package/src/services.ts +0 -14
  75. package/src/types/icons.d.ts +0 -6
  76. package/src/types/svg.d.ts +0 -5
  77. package/src/types.d.ts +0 -9
  78. package/src/ui/chatbot-popup/active-chat-actions.tsx +0 -39
  79. package/src/ui/chatbot-popup/chat-window-screen/action-button.tsx +0 -37
  80. package/src/ui/chatbot-popup/chat-window-screen/footer.tsx +0 -313
  81. package/src/ui/chatbot-popup/chat-window-screen/header.tsx +0 -53
  82. package/src/ui/chatbot-popup/chat-window-screen/in-chat-review.tsx +0 -116
  83. package/src/ui/chatbot-popup/chat-window-screen/index.tsx +0 -366
  84. package/src/ui/chatbot-popup/chat-window-screen/typing-indicator.tsx +0 -31
  85. package/src/ui/chatbot-popup/error-screen/index.tsx +0 -22
  86. package/src/ui/chatbot-popup/loading-screen/index.tsx +0 -21
  87. package/src/ui/chatbot-popup/options-list-screen/company-card.tsx +0 -39
  88. package/src/ui/chatbot-popup/options-list-screen/header.tsx +0 -23
  89. package/src/ui/chatbot-popup/options-list-screen/helpscreen-intro.tsx +0 -32
  90. package/src/ui/chatbot-popup/options-list-screen/helpscreen-list.tsx +0 -57
  91. package/src/ui/chatbot-popup/options-list-screen/helpscreen-option.tsx +0 -56
  92. package/src/ui/chatbot-popup/options-list-screen/index.tsx +0 -70
  93. package/src/ui/confirmation-modal/index.tsx +0 -62
  94. package/src/ui/floating-message.tsx +0 -29
  95. package/src/ui/help-button.tsx +0 -25
  96. package/src/ui/help-center.tsx +0 -448
  97. package/src/ui/help-popup.tsx +0 -367
  98. package/src/ui/powered-by.tsx +0 -62
  99. package/src/ui/review-dialog/index.tsx +0 -149
  100. package/src/ui/review-dialog/rating.tsx +0 -79
  101. package/src/useLocalTranslation.ts +0 -15
@@ -1,367 +0,0 @@
1
- import { ChatWindow } from '@/ui/chatbot-popup/chat-window-screen';
2
- import ChatWindowHeader from '@/ui/chatbot-popup/chat-window-screen/header';
3
- import ChatBotErrorScreen from '@/ui/chatbot-popup/error-screen';
4
- import ChatBotLoadingScreen from '@/ui/chatbot-popup/loading-screen';
5
- import OptionsListScreen from '@/ui/chatbot-popup/options-list-screen';
6
- import { ActiveChatActions } from '@/ui/chatbot-popup/active-chat-actions';
7
- import { useEffect, useRef, useState, useCallback, useMemo } from 'react';
8
- import { HelpScreenData, Message, Option, ReviewProps } from '@/lib/types';
9
- import { cn } from '@/lib/utils';
10
- import { useLocalTranslation } from '../useLocalTranslation';
11
- import ConfirmationModal from './confirmation-modal';
12
- import ReviewDialog from './review-dialog';
13
-
14
- const POPUP_ANIMATION_DURATION_MS = 250;
15
-
16
- type HelpPopupProps = {
17
- isOpen: boolean;
18
- isClosing?: boolean;
19
- onClose: () => void;
20
- onCloseAnimationEnd?: () => void;
21
- helpScreen: HelpScreenData | null;
22
- status: string;
23
- error: string | null;
24
- user: unknown;
25
- onStartChat: (option: Option) => void;
26
- onSendMessage: (message: string, attachmentIds: string[]) => void;
27
- onEnsureSession: () => Promise<string>;
28
- onEndChat: (options?: { fromChatScreen?: boolean; sessionClosedByServer?: boolean }) => void | Promise<void>;
29
- messages: Message[];
30
- needsAgent: boolean;
31
- assistantStatus: string;
32
- sessionId: string | null;
33
- isChatClosed: boolean;
34
- selectedOption: Option | null;
35
- setSelectedOption: (option: Option | null) => void;
36
- inChatReviewSessionId?: string | null;
37
- onInChatReviewSubmit?: (payload: ReviewProps) => void | Promise<void>;
38
- onInChatReviewDone?: () => void;
39
- navigateToOptionsListAfterReview?: boolean;
40
- onNavigatedToOptionsList?: () => void;
41
- isReviewDialogOpen?: boolean;
42
- reviewSessionId?: string | null;
43
- isSubmittingReview?: boolean;
44
- onReviewDialogSubmit?: (payload: ReviewProps) => void | Promise<void>;
45
- onReviewDialogClose?: () => void;
46
- };
47
-
48
- const HelpPopup = ({
49
- isOpen,
50
- isClosing = false,
51
- onClose,
52
- onCloseAnimationEnd,
53
- helpScreen,
54
- status,
55
- error,
56
- onStartChat,
57
- onSendMessage,
58
- onEnsureSession,
59
- onEndChat,
60
- messages,
61
- assistantStatus,
62
- needsAgent,
63
- sessionId,
64
- isChatClosed,
65
- selectedOption,
66
- setSelectedOption,
67
- inChatReviewSessionId = null,
68
- onInChatReviewSubmit,
69
- onInChatReviewDone,
70
- navigateToOptionsListAfterReview = false,
71
- onNavigatedToOptionsList,
72
- isReviewDialogOpen = false,
73
- reviewSessionId = null,
74
- isSubmittingReview = false,
75
- onReviewDialogSubmit,
76
- onReviewDialogClose,
77
- }: HelpPopupProps) => {
78
- // ALL HOOKS MUST BE CALLED FIRST - BEFORE ANY EARLY RETURNS
79
- const [showChat, setShowChat] = useState(false);
80
- const [endChatConfirmation, setEndChatConfirmation] = useState<boolean>(false);
81
- const [startNewChatConfirmation, setStartNewChatConfirmation] = useState<boolean>(false);
82
- const [tempSelectedOption, setTempSelectedOption] = useState<Option | null>(null);
83
- const [isEntering, setIsEntering] = useState(true);
84
-
85
- const chatBoxRef = useRef<HTMLDivElement>(null);
86
- const prevIsOpenRef = useRef(false);
87
- const { t } = useLocalTranslation();
88
- const messagesRef = useRef<Message[]>([]);
89
-
90
- // Enter animation: transition from initial state to visible
91
- useEffect(() => {
92
- const id = requestAnimationFrame(() => {
93
- requestAnimationFrame(() => setIsEntering(false));
94
- });
95
- return () => cancelAnimationFrame(id);
96
- }, []);
97
-
98
- // Exit animation: notify parent to unmount after transition
99
- useEffect(() => {
100
- if (!isClosing || !onCloseAnimationEnd) return;
101
- const tId = setTimeout(onCloseAnimationEnd, POPUP_ANIMATION_DURATION_MS);
102
- return () => clearTimeout(tId);
103
- }, [isClosing, onCloseAnimationEnd]);
104
-
105
- // Memoize the current messages to prevent unnecessary re-renders
106
- const memoizedMessages = useMemo(() => {
107
- return messages;
108
- }, [messages]);
109
-
110
- // Add this function to show the end chat confirmation modal
111
- const showEndChatConfirmation = useCallback(() => setEndChatConfirmation(true), []);
112
-
113
- // Optimize scroll to bottom with debouncing
114
- const scrollToBottom = useCallback(() => {
115
- if (chatBoxRef.current) {
116
- requestAnimationFrame(() => {
117
- if (chatBoxRef.current) {
118
- chatBoxRef.current.scrollTop = chatBoxRef.current.scrollHeight;
119
- }
120
- });
121
- }
122
- }, []);
123
-
124
- const handleBack = useCallback(() => {
125
- if (showChat) {
126
- setShowChat(false);
127
- // onEndChat()
128
- } else if (selectedOption) {
129
- setSelectedOption(null);
130
- }
131
- }, [showChat, selectedOption, setSelectedOption]);
132
-
133
- const handleStartChat = useCallback(
134
- (option: Option) => {
135
- if (option) {
136
- if (sessionId) {
137
- setStartNewChatConfirmation(true);
138
- setTempSelectedOption(option);
139
- } else {
140
- setShowChat(true);
141
- onStartChat(option);
142
- setSelectedOption(option);
143
- }
144
- }
145
- },
146
- [onStartChat, setSelectedOption, sessionId, setStartNewChatConfirmation, setTempSelectedOption]
147
- );
148
-
149
- const handleSendMessage = useCallback(
150
- (message: string, attachmentIds: string[]) => {
151
- // Allow sending if there's text OR attachments
152
- if (message.trim() || attachmentIds.length > 0) {
153
- onSendMessage(message.trim(), attachmentIds);
154
- }
155
- },
156
- [onSendMessage]
157
- );
158
-
159
- const hideEndChatConfirmation = useCallback(() => {
160
- setEndChatConfirmation(false);
161
- }, []);
162
-
163
- const handleEndAndStartNewChat = async () => {
164
- if (tempSelectedOption) {
165
- setStartNewChatConfirmation(false);
166
-
167
- await onEndChat();
168
- setShowChat(true);
169
- onStartChat(tempSelectedOption);
170
- setSelectedOption(tempSelectedOption);
171
- setTempSelectedOption(null);
172
- }
173
- };
174
-
175
- const handleEndChatFromChatScreen = useCallback(async () => {
176
- setEndChatConfirmation(false);
177
- if (!sessionId) {
178
- setShowChat(false);
179
- setSelectedOption(null);
180
- return;
181
- }
182
- await onEndChat({ fromChatScreen: true });
183
- }, [onEndChat, sessionId, setSelectedOption]);
184
-
185
- const handleMinimize = useCallback(() => {
186
- onClose();
187
- }, [onClose]);
188
-
189
- const handleShowActiveChat = useCallback(() => {
190
- setShowChat(true);
191
- }, []);
192
-
193
- const handleEndChatFromActiveActions = useCallback(async () => {
194
- await onEndChat();
195
- setShowChat(false);
196
- setSelectedOption(null);
197
- }, [onEndChat, setSelectedOption]);
198
-
199
- // Memoize render content function
200
- const renderContent = useCallback(() => {
201
- if (showChat && selectedOption) {
202
- return (
203
- <>
204
- <ChatWindowHeader
205
- handleBack={handleBack}
206
- handleEndChat={showEndChatConfirmation}
207
- handleMinimize={handleMinimize}
208
- optionTitle={selectedOption?.title}
209
- />
210
- <ChatWindow
211
- onSendMessage={handleSendMessage}
212
- onEnsureSession={onEnsureSession}
213
- messages={memoizedMessages}
214
- assistantStatus={assistantStatus}
215
- needsAgent={needsAgent}
216
- sessionId={sessionId}
217
- isChatClosed={isChatClosed}
218
- inChatReviewSessionId={inChatReviewSessionId ?? undefined}
219
- isSubmittingReview={isSubmittingReview}
220
- onInChatReviewSubmit={onInChatReviewSubmit}
221
- onInChatReviewDone={onInChatReviewDone}
222
- />
223
- </>
224
- );
225
- }
226
-
227
- return (
228
- <OptionsListScreen
229
- helpScreen={helpScreen}
230
- handleStartChat={handleStartChat}
231
- handleMinimize={handleMinimize}
232
- hasActiveSession={!!sessionId}
233
- />
234
- );
235
- }, [
236
- showChat,
237
- selectedOption,
238
- handleBack,
239
- showEndChatConfirmation,
240
- handleSendMessage,
241
- onEnsureSession,
242
- memoizedMessages,
243
- assistantStatus,
244
- needsAgent,
245
- helpScreen,
246
- handleStartChat,
247
- handleMinimize,
248
- sessionId,
249
- isChatClosed,
250
- inChatReviewSessionId,
251
- isSubmittingReview,
252
- onInChatReviewSubmit,
253
- onInChatReviewDone,
254
- ]);
255
-
256
- // Memoize confirmation modal (End Chat from chat screen → keep chat open, show in-chat review)
257
- const confirmationModal = useMemo(() => {
258
- if (!endChatConfirmation) return null;
259
-
260
- return (
261
- <ConfirmationModal
262
- title={t('homeSdk.ConfirmationModal.title')}
263
- message={t('homeSdk.ConfirmationModal.message')}
264
- onCancel={hideEndChatConfirmation}
265
- onConfirm={handleEndChatFromChatScreen}
266
- />
267
- );
268
- }, [endChatConfirmation, t, hideEndChatConfirmation, handleEndChatFromChatScreen]);
269
-
270
- // Memoize active chat button
271
- const activeChatButton = useMemo(() => {
272
- if (!sessionId || showChat) return null;
273
-
274
- return (
275
- <ActiveChatActions
276
- onConfirm={handleEndChatFromActiveActions}
277
- onCancel={handleShowActiveChat}
278
- />
279
- );
280
- }, [sessionId, showChat, handleShowActiveChat, handleEndChatFromActiveActions]);
281
-
282
- // Restore chat view only when popup reopens (not when user clicks back)
283
- useEffect(() => {
284
- const justOpened = isOpen && !prevIsOpenRef.current;
285
- prevIsOpenRef.current = isOpen;
286
- if (justOpened && sessionId && selectedOption && !showChat) {
287
- setShowChat(true);
288
- }
289
- }, [isOpen, sessionId, selectedOption, showChat]);
290
-
291
- // After submitting in-chat review, navigate to options list
292
- useEffect(() => {
293
- if (navigateToOptionsListAfterReview) {
294
- setShowChat(false);
295
- setSelectedOption(null);
296
- onNavigatedToOptionsList?.();
297
- }
298
- }, [navigateToOptionsListAfterReview, onNavigatedToOptionsList, setSelectedOption]);
299
-
300
- // Scroll to bottom when new messages arrive - optimize with ref comparison
301
- useEffect(() => {
302
- if (messagesRef.current !== messages) {
303
- messagesRef.current = messages;
304
- scrollToBottom();
305
- }
306
- }, [messages, scrollToBottom]);
307
-
308
- const popupBaseClasses =
309
- 'babylai:fixed babylai:inset-auto babylai:max-w-sm babylai:h-[calc(100vh-220px)] babylai:max-h-[800px] babylai:overflow-auto babylai:w-full babylai:bg-secondary babylai:mb-4 babylai:bottom-24 babylai:right-4 babylai:rounded-3xl babylai:shadow-lg babylai:z-50 babylai:flex babylai:flex-col';
310
- const popupAnimationClasses = cn(
311
- 'babylai:transition-all babylai:duration-[250ms] babylai:ease-out',
312
- (isEntering || isClosing) && 'babylai:opacity-0 babylai:scale-[0.96] babylai:translate-y-2',
313
- !isEntering && !isClosing && 'babylai:opacity-100 babylai:scale-100 babylai:translate-y-0'
314
- );
315
-
316
- // EARLY RETURNS MUST COME AFTER ALL HOOKS
317
- // Early returns for performance - moved after all hooks
318
- if (status === 'loading' && !helpScreen) {
319
- return (
320
- <div className={cn(popupBaseClasses, popupAnimationClasses)}>
321
- <ChatBotLoadingScreen onClose={onClose} />
322
- </div>
323
- );
324
- }
325
-
326
- if (error) {
327
- return (
328
- <div className={cn(popupBaseClasses, popupAnimationClasses)}>
329
- <ChatBotErrorScreen onClose={onClose} error={error || ''} />
330
- </div>
331
- );
332
- }
333
-
334
- return (
335
- <div className={cn(popupBaseClasses, popupAnimationClasses)}>
336
- <div className='babylai:h-full babylai:rounded-3xl babylai:flex babylai:flex-col babylai:relative'
337
- >
338
- {activeChatButton}
339
-
340
- {/* Content */}
341
- {renderContent()}
342
-
343
- {/* End Chat Confirmation Modal */}
344
- {confirmationModal}
345
-
346
- {startNewChatConfirmation && (
347
- <ConfirmationModal
348
- title={t('homeSdk.ConfirmationModal.endAndStartNewChatTitle')}
349
- message={t('homeSdk.ConfirmationModal.endAndStartNewChatMessage')}
350
- onCancel={() => setStartNewChatConfirmation(false)}
351
- onConfirm={handleEndAndStartNewChat}
352
- />
353
- )}
354
-
355
- {!!isReviewDialogOpen && !!reviewSessionId && onReviewDialogSubmit && onReviewDialogClose && (
356
- <ReviewDialog
357
- handleSubmit={onReviewDialogSubmit}
358
- onClose={onReviewDialogClose}
359
- isSubmitting={isSubmittingReview}
360
- />
361
- )}
362
- </div>
363
- </div>
364
- );
365
- };
366
-
367
- export default HelpPopup;
@@ -1,62 +0,0 @@
1
- import { useLocalTranslation } from '@/useLocalTranslation';
2
-
3
- const PoweredBy: React.FC = () => {
4
- const { t } = useLocalTranslation();
5
-
6
- return (
7
- <footer className="babylai:flex babylai:items-center babylai:justify-center babylai:p-3 babylai:border-t babylai:border-border">
8
- <a
9
- href="https://babylai.net"
10
- target="_blank"
11
- dir="auto"
12
- className="babylai:flex babylai:items-center babylai:justify-center babylai:gap-2 babylai:text-sm babylai:text-card-foreground babylai:no-underline babylai:transition-opacity babylai:duration-200 babylai:hover:opacity-80"
13
- >
14
- <span>
15
- {t('homeSdk.poweredBy')}
16
- </span>
17
- <span>|</span>
18
- <svg viewBox="0 0 54 19" fill="none" className="babylai:w-15">
19
- <path
20
- d="M0 4.97873C0 2.22905 2.22908 0 4.97879 0H13.2768C16.0265 0 18.2556 2.22905 18.2556 4.97873V13.2766C18.2556 16.0263 16.0265 18.2554 13.2768 18.2554H0V4.97873Z"
21
- fill="#606060"
22
- />
23
- <path
24
- d="M5.76107 6.10571C5.76153 6.10407 5.76177 6.10325 5.76187 6.10287C5.83413 5.8495 6.19321 5.8495 6.26546 6.10287C6.26557 6.10325 6.2658 6.10407 6.26627 6.10571C6.26749 6.11004 6.26809 6.1122 6.26867 6.11423C6.60441 7.29978 7.53101 8.22637 8.71657 8.5621C8.7186 8.56268 8.72076 8.56329 8.72509 8.56451C8.72673 8.56497 8.72755 8.5652 8.72793 8.56531C8.98131 8.63756 8.98131 8.99664 8.72793 9.06889C8.72755 9.069 8.72673 9.06923 8.72509 9.0697C8.72076 9.07092 8.7186 9.07153 8.71657 9.0721C7.53101 9.40783 6.60441 10.3344 6.26867 11.52C6.26809 11.522 6.26749 11.5242 6.26627 11.5285C6.2658 11.5301 6.26557 11.531 6.26546 11.5313C6.19321 11.7847 5.83413 11.7847 5.76187 11.5313C5.76177 11.531 5.76153 11.5301 5.76107 11.5285C5.75985 11.5242 5.75924 11.522 5.75867 11.52C5.42293 10.3344 4.49633 9.40783 3.31077 9.0721C3.30874 9.07153 3.30657 9.07092 3.30225 9.0697C3.3006 9.06923 3.29978 9.069 3.2994 9.06889C3.04603 8.99664 3.04603 8.63756 3.2994 8.56531C3.29978 8.5652 3.3006 8.56497 3.30225 8.56451C3.30657 8.56329 3.30874 8.56268 3.31077 8.5621C4.49633 8.22637 5.42293 7.29978 5.75867 6.11423C5.75924 6.1122 5.75985 6.11004 5.76107 6.10571Z"
25
- fill="white"
26
- />
27
- <path
28
- d="M14.7275 8.76473C14.7275 9.99635 13.7523 10.9948 12.5493 10.9948C11.3463 10.9948 10.3711 9.99635 10.3711 8.76473C10.3711 7.5331 11.3463 6.53467 12.5493 6.53467C13.7523 6.53467 14.7275 7.5331 14.7275 8.76473Z"
29
- fill="white"
30
- />
31
- <path
32
- d="M51.6133 13.0924V5.27515H53.1931V13.0924H51.6133Z"
33
- fill="#606060"
34
- />
35
- <path
36
- d="M44.5938 13.0924L46.5857 5.27515H49.3446L51.325 13.0924H49.7452L49.3102 11.513H46.5742L46.1621 13.0924H44.5938ZM46.8261 10.2425H49.0813L48.1998 6.55705H47.719L46.8261 10.2425Z"
37
- fill="#606060"
38
- />
39
- <path d="M42.5703 13.092V5H44.0929V13.092H42.5703Z" fill="#919191" />
40
- <path
41
- d="M38.6905 15.5069L39.4231 13.0919H38.1982L36.8359 7.34619H38.4272L39.446 11.7985H39.7437L40.7625 7.34619H42.2965L40.3161 15.5069H38.6905Z"
42
- fill="#919191"
43
- />
44
- <path
45
- d="M34.008 13.2179C33.8172 13.2179 33.5845 13.2103 33.3097 13.195C33.035 13.1797 32.7526 13.1569 32.4626 13.1263C32.1802 13.0958 31.9284 13.0691 31.707 13.0462V5H33.241V7.52946C33.3555 7.48368 33.4967 7.4379 33.6646 7.39212C33.8325 7.34633 34.008 7.30818 34.1912 7.27766C34.382 7.23951 34.5575 7.22043 34.7178 7.22043C35.252 7.22043 35.6756 7.33107 35.9885 7.55235C36.309 7.766 36.538 8.08648 36.6754 8.51378C36.8127 8.94108 36.8814 9.47902 36.8814 10.1276C36.8814 10.8906 36.7937 11.5011 36.6181 11.9589C36.4502 12.4091 36.1564 12.7334 35.7366 12.9318C35.3169 13.1225 34.7407 13.2179 34.008 13.2179ZM34.0195 11.936C34.3934 11.936 34.672 11.8711 34.8552 11.7414C35.0383 11.6041 35.1604 11.4019 35.2215 11.1348C35.2902 10.8677 35.3245 10.5396 35.3245 10.1505C35.3245 9.75371 35.294 9.43705 35.2329 9.20051C35.1719 8.95634 35.0689 8.78084 34.9238 8.67402C34.7865 8.55956 34.5919 8.50233 34.34 8.50233C34.2179 8.50233 34.0882 8.51759 33.9508 8.54812C33.8134 8.57101 33.6799 8.60153 33.5501 8.63968C33.428 8.6702 33.325 8.70072 33.241 8.73124V11.8902C33.3555 11.8978 33.4891 11.9093 33.6417 11.9245C33.7943 11.9322 33.9203 11.936 34.0195 11.936Z"
46
- fill="#919191"
47
- />
48
- <path
49
- d="M27.8012 13.2177C27.2059 13.2177 26.7556 13.0689 26.4504 12.7713C26.1527 12.4661 26.0039 12.0083 26.0039 11.3978C26.0039 10.9705 26.0802 10.6386 26.2329 10.4021C26.3855 10.1579 26.6106 9.9824 26.9083 9.87558C27.2136 9.76112 27.5837 9.69245 28.0187 9.66956L29.4153 9.54366V9.20029C29.4153 8.9256 29.3467 8.73484 29.2093 8.62802C29.0719 8.51356 28.8697 8.45633 28.6025 8.45633C28.3889 8.45633 28.1408 8.46396 27.8584 8.47922C27.5837 8.49448 27.309 8.51356 27.0342 8.53645C26.7671 8.55934 26.5343 8.58223 26.3359 8.60512L26.2901 7.52924C26.4885 7.48346 26.7251 7.43768 26.9999 7.3919C27.2822 7.33849 27.5761 7.29652 27.8813 7.266C28.1866 7.23548 28.469 7.22021 28.7285 7.22021C29.2169 7.22021 29.6252 7.28126 29.9534 7.40334C30.2816 7.52543 30.5296 7.72763 30.6975 8.00996C30.8654 8.28465 30.9493 8.65854 30.9493 9.13162V11.7526C30.9646 11.8595 31.0218 11.9434 31.1211 12.0044C31.2203 12.0579 31.3347 12.096 31.4645 12.1189L31.4301 13.1719C31.308 13.1719 31.1859 13.1719 31.0638 13.1719C30.9493 13.1795 30.8387 13.1795 30.7318 13.1719C30.625 13.1719 30.5296 13.1643 30.4456 13.149C30.2701 13.1261 30.1175 13.0803 29.9877 13.0117C29.8656 12.943 29.7664 12.8705 29.6901 12.7942C29.568 12.8476 29.4039 12.9086 29.1978 12.9773C28.9918 13.046 28.7666 13.1032 28.5224 13.149C28.2858 13.1948 28.0454 13.2177 27.8012 13.2177ZM28.1675 12.0846C28.3125 12.0846 28.4652 12.0693 28.6254 12.0388C28.7857 12.0083 28.9345 11.9739 29.0719 11.9358C29.2169 11.89 29.3314 11.848 29.4153 11.8099V10.4936L28.2477 10.5966C27.9958 10.6195 27.8127 10.6958 27.6982 10.8256C27.5913 10.9476 27.5379 11.1231 27.5379 11.3521C27.5379 11.581 27.5875 11.7603 27.6867 11.89C27.7936 12.0197 27.9538 12.0846 28.1675 12.0846Z"
50
- fill="#919191"
51
- />
52
- <path
53
- d="M19.9531 13.0924V5.27515H23.0669C23.5859 5.27515 24.0323 5.34 24.4063 5.46972C24.7803 5.59944 25.0703 5.80927 25.2763 6.09923C25.49 6.38155 25.5969 6.76307 25.5969 7.24378C25.5969 7.57188 25.5625 7.85039 25.4938 8.0793C25.4328 8.30058 25.3336 8.49134 25.1962 8.65158C25.0665 8.80419 24.8947 8.94535 24.681 9.07506C24.91 9.159 25.1084 9.27345 25.2763 9.41843C25.4519 9.55578 25.5854 9.74272 25.677 9.97926C25.7686 10.2082 25.8144 10.5134 25.8144 10.8949C25.8144 11.3146 25.7495 11.6656 25.6198 11.9479C25.49 12.2302 25.303 12.4553 25.0588 12.6232C24.8222 12.791 24.5437 12.9131 24.2231 12.9894C23.9026 13.0581 23.5515 13.0924 23.1699 13.0924H19.9531ZM21.5329 11.925H23.0555C23.3226 11.925 23.5439 11.8945 23.7194 11.8334C23.9026 11.7648 24.04 11.6465 24.1316 11.4786C24.2308 11.3108 24.2804 11.078 24.2804 10.7804C24.2804 10.5515 24.2422 10.3646 24.1659 10.2196C24.0896 10.0746 23.9904 9.96782 23.8683 9.89914C23.7461 9.82284 23.6088 9.76943 23.4561 9.7389C23.3111 9.70838 23.1661 9.69312 23.0211 9.69312H21.5329V11.925ZM21.5329 8.57146H23.0097C23.2692 8.57146 23.479 8.53331 23.6393 8.457C23.7996 8.37307 23.9179 8.25099 23.9942 8.09075C24.0705 7.92288 24.1087 7.71304 24.1087 7.46124C24.1087 7.10262 24.0133 6.84318 23.8225 6.68295C23.6393 6.52271 23.3493 6.44259 22.9524 6.44259H21.5329V8.57146Z"
54
- fill="#919191"
55
- />
56
- </svg>
57
- </a>
58
- </footer>
59
- );
60
- };
61
-
62
- export default PoweredBy;
@@ -1,149 +0,0 @@
1
- import { ReviewProps } from '@/lib/types'
2
- import { cn } from '@/lib/utils'
3
- import { Rating } from '@/ui/review-dialog/rating'
4
- import { useLocalTranslation } from '../../useLocalTranslation'
5
- import { useState } from 'react';
6
- import SolarCloseCircleLineDuotone from '~icons/solar/close-circle-line-duotone'
7
- import { Button } from '@/components';
8
- import PoweredBy from '../powered-by';
9
-
10
- const COMMENT_MAX_LENGTH = 500;
11
-
12
- interface ReviewDialogProps {
13
- handleSubmit: ({ rating }: ReviewProps) => void;
14
- onClose: () => void;
15
- isSubmitting?: boolean;
16
- }
17
-
18
- const ReviewDialog: React.FC<ReviewDialogProps> = (props) => {
19
- const { t } = useLocalTranslation()
20
- const [rating, setRating] = useState<number>(0)
21
- const [comment, setComment] = useState<string>('');
22
- const [error, setError] = useState<{ comment?: string; rating?: string }>({})
23
-
24
- const hasRating = rating >= 1 && rating <= 5;
25
- const isRatingValid = rating >= 1 && rating <= 5
26
-
27
- const validateAndSubmit = () => {
28
- const newError: typeof error = {}
29
- const trimmedComment = comment.trim()
30
-
31
- if (!isRatingValid) {
32
- newError.rating = t('homeSdk.ReviewDialog.rating_error') || 'Rating must be between 1 and 5.'
33
- }
34
-
35
- if (trimmedComment.length > COMMENT_MAX_LENGTH) {
36
- newError.comment = t('homeSdk.ReviewDialog.comment_error') || 'The field Comment must be a string with a maximum length of 500.'
37
- }
38
-
39
- if (Object.keys(newError).length > 0) {
40
- setError(newError)
41
- return
42
- }
43
-
44
- setError({})
45
- props.handleSubmit({ rating, comment: trimmedComment })
46
- }
47
-
48
- const handleRatingChange = (val: number) => {
49
- setRating(val)
50
- if (error.rating && val >= 1 && val <= 5) {
51
- setError((prev) => ({ ...prev, rating: undefined }))
52
- }
53
- }
54
-
55
- const handleCommentChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
56
- const value = e.target.value
57
- setComment(value)
58
- if (error.comment && value.length <= COMMENT_MAX_LENGTH) {
59
- setError((prev) => ({ ...prev, comment: undefined }))
60
- }
61
- }
62
-
63
- return (
64
- <section className="babylai:absolute babylai:inset-0 babylai:z-50 babylai:flex babylai:items-end babylai:rounded-3xl babylai:overflow-hidden">
65
- <div className='babylai:absolute babylai:inset-0 babylai:bg-black/60' onClick={props.onClose}></div>
66
- <div className='babylai:flex babylai:flex-col babylai:bg-card babylai:rounded-2xl babylai:w-full babylai:z-50 babylai:shadow-lg'>
67
- <div className='babylai:flex babylai:flex-col babylai:p-6 babylai:pb-5 babylai:w-full'>
68
- <button className="babylai:border-0 babylai:p-0 babylai:flex babylai:bg-transparent babylai:cursor-pointer babylai:mb-6 babylai:ms-auto babylai:text-card-foreground"
69
- type='button'
70
- onClick={props.onClose}
71
- >
72
- <SolarCloseCircleLineDuotone className="babylai:w-7 babylai:h-7" />
73
- </button>
74
-
75
- <section className='babylai:flex babylai:items-center babylai:justify-center babylai:border-b babylai:border-black-white-200 babylai:pb-6 babylai:mb-6'>
76
- <Rating value={rating} onChange={handleRatingChange} size='lg' />
77
- </section>
78
-
79
- <h2 className="babylai:text-2xl! babylai:text-center babylai:font-bold! babylai:mb-2! babylai:text-card-foreground">{t('homeSdk.ReviewDialog.title')}</h2>
80
-
81
- <p className="babylai:text-xs babylai:text-center babylai:text-muted-foreground babylai:mb-4 babylai:leading-snug">
82
- {t('homeSdk.ReviewDialog.description')}
83
- </p>
84
-
85
- {hasRating && (
86
- <div className='babylai:flex babylai:flex-col babylai:gap-6 babylai:mt-6'>
87
- <p className="babylai:text-sm babylai:text-card-foreground babylai:leading-snug">{t('homeSdk.InChatReview.follow_up')}</p>
88
-
89
- <div className='babylai:flex babylai:flex-col babylai:gap-2'>
90
- <textarea
91
- className={cn(
92
- "babylai:resize-none babylai:w-full babylai:bg-secondary babylai:border babylai:rounded-xl babylai:text-card-foreground babylai:text-sm babylai:p-3 babylai:resize-vertical babylai:min-h-20 babylai:disabled:opacity-50 babylai:disabled:cursor-not-allowed babylai:disabled:bg-secondary",
93
- error.comment ? "babylai:border-destructive" : "babylai:border-black-white-200"
94
- )}
95
- rows={4}
96
- maxLength={COMMENT_MAX_LENGTH}
97
- placeholder={t('homeSdk.InChatReview.note_placeholder')}
98
- value={comment}
99
- onChange={handleCommentChange}
100
- aria-label={t('homeSdk.InChatReview.note_placeholder')}
101
- aria-invalid={!!error.comment}
102
- aria-describedby={error.comment ? 'review-comment-error' : undefined}
103
- />
104
- {error.comment && (
105
- <p id="review-comment-error" className="babylai:text-sm babylai:text-destructive" role="alert">
106
- {error.comment}
107
- </p>
108
- )}
109
- <p className="babylai:text-xs babylai:text-muted-foreground">
110
- {comment.length}/{COMMENT_MAX_LENGTH}
111
- </p>
112
- </div>
113
- </div>
114
- )}
115
-
116
- <footer className="babylai:flex babylai:justify-between babylai:gap-3 babylai:mt-6">
117
- <Button
118
- onClick={props.onClose}
119
- variant='secondary'
120
- disabled={props.isSubmitting}
121
- >
122
- {t('homeSdk.ReviewDialog.skip_button')}
123
- </Button>
124
- <Button
125
- onClick={validateAndSubmit}
126
- variant='default'
127
- disabled={props.isSubmitting || !hasRating}
128
- >
129
- {props.isSubmitting ? (
130
- <span className="babylai:inline-flex babylai:items-center babylai:gap-2">
131
- <span
132
- className="babylai:inline-block babylai:animate-spin babylai:rounded-full babylai:h-4 babylai:w-4 babylai:border-2 babylai:border-white babylai:border-t-transparent babylai:box-border"
133
- aria-hidden
134
- />
135
- {t('homeSdk.ReviewDialog.submit_button')}
136
- </span>
137
- ) : (
138
- t('homeSdk.ReviewDialog.submit_button')
139
- )}
140
- </Button>
141
- </footer>
142
- </div>
143
- <PoweredBy />
144
- </div>
145
- </section>
146
- )
147
- }
148
-
149
- export default ReviewDialog
@@ -1,79 +0,0 @@
1
- import { cn } from '@/lib'
2
- import { IconHeart as Heart, IconThumbUp as ThumbsUp } from '@tabler/icons-react'
3
- import SolarStarBold from '~icons/solar/star-bold'
4
- import * as React from 'react'
5
-
6
- export interface RatingProps {
7
- value: number
8
- onChange?: (value: number) => void
9
- max?: number
10
- icon?: 'star' | 'heart' | 'thumbsUp'
11
- size?: 'sm' | 'md' | 'lg'
12
- readOnly?: boolean
13
- className?: string
14
- style?: React.CSSProperties
15
- }
16
-
17
- const iconMap = {
18
- star: SolarStarBold,
19
- heart: Heart,
20
- thumbsUp: ThumbsUp
21
- }
22
-
23
- const sizeMap = {
24
- sm: 'babylai:w-4 babylai:h-4',
25
- md: 'babylai:w-7 babylai:h-7',
26
- lg: 'babylai:w-13 babylai:h-13'
27
- }
28
-
29
- export const Rating = React.forwardRef<HTMLDivElement, RatingProps>(
30
- ({ value, onChange, max = 5, icon = 'star', size = 'md', readOnly = false, className, ...props }, ref) => {
31
- const [hoverValue, setHoverValue] = React.useState<number | null>(null)
32
- const Icon = iconMap[icon]
33
-
34
- const handleMouseEnter = (index: number) => {
35
- if (!readOnly) {
36
- setHoverValue(index)
37
- }
38
- }
39
-
40
- const handleMouseLeave = () => {
41
- setHoverValue(null)
42
- }
43
-
44
- const handleClick = (index: number) => {
45
- if (!readOnly && onChange) {
46
- onChange(index)
47
- }
48
- }
49
-
50
- return (
51
- <div ref={ref} className={cn('babylai:inline-flex babylai:gap-2', className)} {...props}>
52
- {[...Array(max)].map((_, index) => {
53
- const filled = (hoverValue !== null ? hoverValue : value) > index
54
-
55
- return (
56
- <Icon
57
- key={index}
58
- className={cn(
59
- sizeMap[size],
60
- 'babylai:cursor-pointer babylai:transition-colors',
61
- filled ? 'babylai:text-[#F49E00] babylai:fill-[#F49E00]' : 'babylai:text-gray-300',
62
- readOnly && 'babylai:cursor-default'
63
- )}
64
- onMouseEnter={() => handleMouseEnter(index + 1)}
65
- onMouseLeave={handleMouseLeave}
66
- onClick={() => handleClick(index + 1)}
67
- aria-hidden={readOnly}
68
- role={readOnly ? undefined : 'button'}
69
- tabIndex={readOnly ? -1 : 0}
70
- aria-label={`Rate ${index + 1} out of ${max}`}
71
- />
72
- )
73
- })}
74
- </div>
75
- )
76
- }
77
- )
78
-
79
- Rating.displayName = 'Rating'
@@ -1,15 +0,0 @@
1
- import { useMemo } from "react";
2
- import { createHelpCenterI18n, defaultLanguage } from "@/i18n";
3
- import { useLanguage } from "@/lib/LanguageContext";
4
-
5
- export const useLocalTranslation = () => {
6
- // Get language from context, fallback to default if not available
7
- const context = useLanguage();
8
- const language = context?.language || defaultLanguage;
9
-
10
- const i18n = useMemo(() => createHelpCenterI18n(language), [language]);
11
- const t = (key: string) => i18n.t(key);
12
- const dir = i18n.dir();
13
-
14
- return { t, dir, i18n };
15
- };