@aslaluroba/help-center-react 3.2.5 → 3.2.7
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 +0 -3
- package/dist/components/shared/Button/button.d.ts +3 -3
- package/dist/components/ui/index.d.ts +0 -1
- package/dist/core/api.d.ts +4 -4
- package/dist/index.css +1 -1
- package/dist/index.esm.js +15543 -15136
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +15546 -15145
- package/dist/index.js.map +1 -1
- package/dist/lib/theme-utils.d.ts +0 -9
- package/dist/lib/types.d.ts +6 -3
- package/dist/services.esm.js +9474 -9222
- package/dist/services.esm.js.map +1 -1
- package/dist/services.js +9472 -9222
- package/dist/services.js.map +1 -1
- package/dist/ui/chatbot-popup/active-chat-actions.d.ts +7 -0
- package/dist/ui/chatbot-popup/chat-window-screen/action-button.d.ts +10 -0
- package/dist/ui/chatbot-popup/chat-window-screen/footer.d.ts +1 -0
- package/dist/ui/chatbot-popup/chat-window-screen/header.d.ts +2 -5
- package/dist/ui/chatbot-popup/chat-window-screen/in-chat-review.d.ts +9 -0
- package/dist/ui/chatbot-popup/chat-window-screen/index.d.ts +7 -3
- package/dist/ui/chatbot-popup/chat-window-screen/typing-indicator.d.ts +6 -0
- package/dist/ui/chatbot-popup/error-screen/index.d.ts +0 -1
- package/dist/ui/chatbot-popup/loading-screen/index.d.ts +0 -2
- package/dist/ui/chatbot-popup/options-list-screen/company-card.d.ts +9 -0
- package/dist/ui/chatbot-popup/options-list-screen/header.d.ts +1 -2
- package/dist/ui/chatbot-popup/options-list-screen/helpscreen-intro.d.ts +6 -0
- package/dist/ui/chatbot-popup/options-list-screen/helpscreen-list.d.ts +10 -0
- package/dist/ui/chatbot-popup/options-list-screen/helpscreen-option.d.ts +9 -0
- package/dist/ui/chatbot-popup/options-list-screen/index.d.ts +1 -4
- package/dist/ui/help-center.d.ts +2 -5
- package/dist/ui/help-popup.d.ts +16 -7
- package/dist/ui/review-dialog/index.d.ts +2 -1
- package/package.json +35 -29
- package/src/components/shared/Button/button.tsx +11 -18
- package/src/components/shared/Card/card.tsx +8 -8
- package/src/components/ui/agent-response/agent-response.tsx +4 -4
- package/src/components/ui/image-attachment.tsx +8 -8
- package/src/components/ui/image-preview-dialog.tsx +41 -41
- package/src/components/ui/index.ts +0 -1
- package/src/core/AblyService.ts +22 -17
- package/src/core/api.ts +9 -7
- package/src/globals.css +216 -50
- package/src/lib/theme-utils.ts +1 -33
- package/src/lib/types.ts +7 -4
- package/src/locales/ar.json +16 -6
- package/src/locales/en.json +16 -6
- package/src/types/icons.d.ts +6 -0
- package/src/ui/chatbot-popup/active-chat-actions.tsx +39 -0
- package/src/ui/chatbot-popup/chat-window-screen/action-button.tsx +37 -0
- package/src/ui/chatbot-popup/chat-window-screen/footer.tsx +42 -43
- package/src/ui/chatbot-popup/chat-window-screen/header.tsx +34 -67
- package/src/ui/chatbot-popup/chat-window-screen/in-chat-review.tsx +83 -0
- package/src/ui/chatbot-popup/chat-window-screen/index.tsx +49 -42
- package/src/ui/chatbot-popup/chat-window-screen/typing-indicator.tsx +27 -0
- package/src/ui/chatbot-popup/error-screen/index.tsx +7 -7
- package/src/ui/chatbot-popup/loading-screen/index.tsx +6 -17
- package/src/ui/chatbot-popup/options-list-screen/company-card.tsx +37 -0
- package/src/ui/chatbot-popup/options-list-screen/header.tsx +12 -31
- package/src/ui/chatbot-popup/options-list-screen/helpscreen-intro.tsx +32 -0
- package/src/ui/chatbot-popup/options-list-screen/helpscreen-list.tsx +48 -0
- package/src/ui/chatbot-popup/options-list-screen/helpscreen-option.tsx +38 -0
- package/src/ui/chatbot-popup/options-list-screen/index.tsx +44 -38
- package/src/ui/confirmation-modal/index.tsx +27 -12
- package/src/ui/floating-message.tsx +8 -7
- package/src/ui/help-button.tsx +5 -5
- package/src/ui/help-center.tsx +71 -59
- package/src/ui/help-popup.tsx +114 -91
- package/src/ui/powered-by.tsx +49 -7
- package/src/ui/review-dialog/index.tsx +48 -65
- package/src/ui/review-dialog/rating.tsx +7 -7
- package/dist/components/ui/header.d.ts +0 -6
- package/dist/ui/chatbot-popup/home-screen/card.d.ts +0 -6
- package/dist/ui/chatbot-popup/home-screen/chat-now-card.d.ts +0 -5
- package/dist/ui/chatbot-popup/home-screen/index.d.ts +0 -7
- package/dist/ui/chatbot-popup/options-list-screen/expanded-option.d.ts +0 -7
- package/dist/ui/chatbot-popup/options-list-screen/option-card.d.ts +0 -5
- package/src/assets/icons/arrowRight.svg +0 -3
- package/src/assets/icons/chat.svg +0 -4
- package/src/assets/icons/close.svg +0 -1
- package/src/assets/icons/closeCircle.svg +0 -3
- package/src/assets/icons/closeCirclePrimary.svg +0 -4
- package/src/assets/icons/envelope.svg +0 -3
- package/src/assets/icons/paperclip.svg +0 -3
- package/src/assets/icons/threeDots.svg +0 -3
- package/src/assets/icons/user.svg +0 -3
- package/src/assets/icons/x.svg +0 -4
- package/src/assets/logoColors.svg +0 -5
- package/src/assets/logo_ai.svg +0 -14
- package/src/assets/thinking-logo.svg +0 -3
- package/src/components/ui/header.tsx +0 -22
- package/src/ui/chatbot-popup/home-screen/card.tsx +0 -33
- package/src/ui/chatbot-popup/home-screen/chat-now-card.tsx +0 -36
- package/src/ui/chatbot-popup/home-screen/index.tsx +0 -44
- package/src/ui/chatbot-popup/options-list-screen/expanded-option.tsx +0 -37
- package/src/ui/chatbot-popup/options-list-screen/option-card.tsx +0 -31
- /package/src/assets/{icons/seperator.svg → seperator.svg} +0 -0
package/src/lib/theme-utils.ts
CHANGED
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
|
|
5
5
|
export interface ThemeColors {
|
|
6
6
|
primaryColor?: string;
|
|
7
|
-
secondaryColor?: string;
|
|
8
7
|
}
|
|
9
8
|
|
|
10
9
|
/**
|
|
@@ -12,7 +11,7 @@ export interface ThemeColors {
|
|
|
12
11
|
*/
|
|
13
12
|
export const getPrimaryColorStyles = (primaryColor?: string) => {
|
|
14
13
|
if (!primaryColor) return {};
|
|
15
|
-
|
|
14
|
+
|
|
16
15
|
return {
|
|
17
16
|
'--babylai-primary-color': primaryColor,
|
|
18
17
|
'--babylai-primary-color-100': lightenColor(primaryColor, 0.9),
|
|
@@ -28,37 +27,6 @@ export const getPrimaryColorStyles = (primaryColor?: string) => {
|
|
|
28
27
|
} as React.CSSProperties;
|
|
29
28
|
};
|
|
30
29
|
|
|
31
|
-
/**
|
|
32
|
-
* Generate dynamic styles for secondary color
|
|
33
|
-
*/
|
|
34
|
-
export const getSecondaryColorStyles = (secondaryColor?: string) => {
|
|
35
|
-
if (!secondaryColor) return {};
|
|
36
|
-
|
|
37
|
-
return {
|
|
38
|
-
'--babylai-secondary-color': secondaryColor,
|
|
39
|
-
'--babylai-secondary-color-100': lightenColor(secondaryColor, 0.9),
|
|
40
|
-
'--babylai-secondary-color-200': lightenColor(secondaryColor, 0.8),
|
|
41
|
-
'--babylai-secondary-color-300': lightenColor(secondaryColor, 0.7),
|
|
42
|
-
'--babylai-secondary-color-400': lightenColor(secondaryColor, 0.6),
|
|
43
|
-
'--babylai-secondary-color-500': secondaryColor,
|
|
44
|
-
'--babylai-secondary-color-600': darkenColor(secondaryColor, 0.1),
|
|
45
|
-
'--babylai-secondary-color-700': darkenColor(secondaryColor, 0.2),
|
|
46
|
-
'--babylai-secondary-color-800': darkenColor(secondaryColor, 0.3),
|
|
47
|
-
'--babylai-secondary-color-900': darkenColor(secondaryColor, 0.4),
|
|
48
|
-
'--babylai-secondary-color-950': darkenColor(secondaryColor, 0.5),
|
|
49
|
-
} as React.CSSProperties;
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Get combined theme styles
|
|
54
|
-
*/
|
|
55
|
-
export const getThemeStyles = (colors: ThemeColors): React.CSSProperties => {
|
|
56
|
-
return {
|
|
57
|
-
...getPrimaryColorStyles(colors.primaryColor),
|
|
58
|
-
...getSecondaryColorStyles(colors.secondaryColor),
|
|
59
|
-
};
|
|
60
|
-
};
|
|
61
|
-
|
|
62
30
|
/**
|
|
63
31
|
* Lighten a color by a percentage
|
|
64
32
|
*/
|
package/src/lib/types.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
export interface HelpCenterProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
2
2
|
helpScreenId: string;
|
|
3
3
|
primaryColor?: string;
|
|
4
|
-
|
|
5
|
-
logoUrl?: string;
|
|
4
|
+
language?: 'ar' | 'en';
|
|
6
5
|
}
|
|
7
6
|
|
|
8
7
|
export interface Theme {
|
|
@@ -88,7 +87,11 @@ export interface HelpScreenData {
|
|
|
88
87
|
tenant: {
|
|
89
88
|
id: string;
|
|
90
89
|
name: string;
|
|
91
|
-
key: string;
|
|
90
|
+
key: string;
|
|
91
|
+
logoUrl: string;
|
|
92
|
+
settings: {
|
|
93
|
+
description: string;
|
|
94
|
+
};
|
|
92
95
|
};
|
|
93
96
|
title: string;
|
|
94
97
|
description: string;
|
|
@@ -125,7 +128,7 @@ export interface Option {
|
|
|
125
128
|
}
|
|
126
129
|
|
|
127
130
|
export interface ReviewProps {
|
|
128
|
-
comment
|
|
131
|
+
comment?: string;
|
|
129
132
|
rating: number;
|
|
130
133
|
}
|
|
131
134
|
|
package/src/locales/ar.json
CHANGED
|
@@ -13,21 +13,31 @@
|
|
|
13
13
|
"poweredBy": "مدعوم بواسطة",
|
|
14
14
|
|
|
15
15
|
"ReviewDialog": {
|
|
16
|
-
"title": "
|
|
17
|
-
"
|
|
16
|
+
"title": "نحن نقدر ملاحظاتك!",
|
|
17
|
+
"simple_title": "نود معرفة رأيك!",
|
|
18
|
+
"simple_description": "رأيك يساعدنا على التحسين وتقديم دعم أفضل. يُرجى تقييم تجربتك مع خدمتنا وإخبارنا كيف كان أداؤنا.",
|
|
19
|
+
"description": "رأيك يساعدنا على التحسين وتقديم دعم أفضل. يُرجى تقييم تجربتك مع خدمتنا وإخبارنا كيف كان أداؤنا.",
|
|
18
20
|
"rating_label": "التقييم:",
|
|
19
21
|
"comment_label": "التعليق:",
|
|
20
22
|
"comment_placeholder": "اكتب تعليقك هنا...",
|
|
21
23
|
"submit_button": "إرسال التقييم",
|
|
24
|
+
"rate_button": "تقييم",
|
|
22
25
|
"comment_error": "يجب أن يكون التعليق بين 10 و500 حرف.",
|
|
23
26
|
"rating_error": "يجب أن يكون التقييم بين 1 و5.",
|
|
24
27
|
"skip_button": "تخطي"
|
|
25
28
|
},
|
|
29
|
+
"InChatReview": {
|
|
30
|
+
"title": "كيف كانت محادثتك معنا اليوم؟",
|
|
31
|
+
"description": "نحب أن نعرف كيف كان أداؤنا - ملاحظاتك تساعدنا على جعل كل محادثة أفضل.",
|
|
32
|
+
"follow_up": "رائع! نحن سعداء أنك استمتعت بالدردشة معنا. هل يمكنك تقييم تجربتك الإجمالية لمساعدتنا على الحفاظ على ذلك؟",
|
|
33
|
+
"note_placeholder": "اكتب ملاحظتك",
|
|
34
|
+
"submit_button": "تقديم"
|
|
35
|
+
},
|
|
26
36
|
"ConfirmationModal": {
|
|
27
|
-
"title": "
|
|
28
|
-
"message": "
|
|
29
|
-
"confirmation_button": "
|
|
30
|
-
"cancel_button": "
|
|
37
|
+
"title": "تريد المغادرة؟ 👋",
|
|
38
|
+
"message": "لا تقلق، يمكنك العودة في أي وقت. نحن دائما هنا إذا كنت تحتاج مساعدة أو لديك أسئلة.",
|
|
39
|
+
"confirmation_button": "إغلاق المحادثة",
|
|
40
|
+
"cancel_button": "استمرار",
|
|
31
41
|
"endAndStartNewChatTitle": "إنهاء وبدء محادثة جديدة",
|
|
32
42
|
"endAndStartNewChatMessage": "هل أنت متأكد أنك تريد إنهاء هذه المحادثة وبدء محادثة جديدة؟"
|
|
33
43
|
}
|
package/src/locales/en.json
CHANGED
|
@@ -13,21 +13,31 @@
|
|
|
13
13
|
"poweredBy": "Powered by",
|
|
14
14
|
|
|
15
15
|
"ReviewDialog": {
|
|
16
|
-
"title": "
|
|
17
|
-
"
|
|
16
|
+
"title": "We’d Love Your Feedback!",
|
|
17
|
+
"simple_title": "We'd Love Your Feedback!",
|
|
18
|
+
"simple_description": "Your opinion helps us improve and deliver better support. Please rate your experience with our service and let us know how we did.",
|
|
19
|
+
"description": "Your opinion helps us improve and deliver better support. Please rate your experience with our service and let us know how we did.",
|
|
18
20
|
"rating_label": "Rating:",
|
|
19
21
|
"comment_label": "Comment:",
|
|
20
22
|
"comment_placeholder": "Write your comment here...",
|
|
21
23
|
"submit_button": "Submit Review",
|
|
24
|
+
"rate_button": "Rate",
|
|
22
25
|
"comment_error": "Comment must be between 10 and 500 characters.",
|
|
23
26
|
"rating_error": "Rating must be between 1 and 5.",
|
|
24
27
|
"skip_button": "Skip"
|
|
25
28
|
},
|
|
29
|
+
"InChatReview": {
|
|
30
|
+
"title": "How was your conversation with us today?",
|
|
31
|
+
"description": "We'd love to know how we did - your feedback helps us make every chat even better.",
|
|
32
|
+
"follow_up": "Awesome! We're glad you enjoyed chatting with us. Could you rate your overall experience to help us keep it that way?",
|
|
33
|
+
"note_placeholder": "Write Your Note",
|
|
34
|
+
"submit_button": "Submit Review"
|
|
35
|
+
},
|
|
26
36
|
"ConfirmationModal": {
|
|
27
|
-
"title": "
|
|
28
|
-
"message": "
|
|
29
|
-
"confirmation_button": "
|
|
30
|
-
"cancel_button": "
|
|
37
|
+
"title": "Leaving so soon? 👋",
|
|
38
|
+
"message": "Don't worry, you can come back anytime. We're always here if you need help or have questions.",
|
|
39
|
+
"confirmation_button": "Close Chat",
|
|
40
|
+
"cancel_button": "Continue",
|
|
31
41
|
"endAndStartNewChatTitle": "End and Start New Chat",
|
|
32
42
|
"endAndStartNewChatMessage": "Are you sure you want to end the current conversation and start a new one?"
|
|
33
43
|
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Button } from '@/components';
|
|
2
|
+
import { useLocalTranslation } from '@/useLocalTranslation';
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import SolarPlain2BoldDuotone from '~icons/solar/plain-2-bold-duotone';
|
|
5
|
+
|
|
6
|
+
interface ActiveChatActionsProps {
|
|
7
|
+
onConfirm: () => void;
|
|
8
|
+
onCancel: () => void;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const ActiveChatActions: React.FC<ActiveChatActionsProps> = ({
|
|
12
|
+
onConfirm,
|
|
13
|
+
onCancel,
|
|
14
|
+
}) => {
|
|
15
|
+
const { t } = useLocalTranslation();
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<section className="babylai:flex babylai:justify-between babylai:gap-3 babylai:px-4 babylai:py-6 babylai:absolute babylai:left-0 babylai:right-0 babylai:bottom-11 babylai:z-20 babylai:bg-linear-to-t babylai:from-card babylai:to-transparent babylai:from-[28.32%] babylai:to-[112.59%]">
|
|
19
|
+
<Button
|
|
20
|
+
onClick={onConfirm}
|
|
21
|
+
variant='secondary'
|
|
22
|
+
>
|
|
23
|
+
{t('homeSdk.ConfirmationModal.confirmation_button')}
|
|
24
|
+
|
|
25
|
+
</Button>
|
|
26
|
+
<Button
|
|
27
|
+
onClick={onCancel}
|
|
28
|
+
variant='default'
|
|
29
|
+
>
|
|
30
|
+
{t('homeSdk.ConfirmationModal.cancel_button')}
|
|
31
|
+
<SolarPlain2BoldDuotone className="babylai:w-6 babylai:h-6" />
|
|
32
|
+
</Button>
|
|
33
|
+
</section>
|
|
34
|
+
);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
ActiveChatActions.displayName = 'ActiveChatActions';
|
|
38
|
+
|
|
39
|
+
export default ActiveChatActions;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { cn } from '@/lib/utils';
|
|
3
|
+
|
|
4
|
+
interface ActionButtonProps {
|
|
5
|
+
onClick: () => void;
|
|
6
|
+
icon?: React.ReactNode;
|
|
7
|
+
children?: React.ReactNode;
|
|
8
|
+
ariaLabel?: string;
|
|
9
|
+
className?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const ActionButton: React.FC<ActionButtonProps> = ({
|
|
13
|
+
onClick,
|
|
14
|
+
icon,
|
|
15
|
+
children,
|
|
16
|
+
ariaLabel,
|
|
17
|
+
className,
|
|
18
|
+
}) => {
|
|
19
|
+
return (
|
|
20
|
+
<button
|
|
21
|
+
onClick={onClick}
|
|
22
|
+
className={cn(
|
|
23
|
+
'babylai:bg-card babylai:text-card-foreground babylai:h-6 babylai:w-8 babylai:rounded-full babylai:flex babylai:items-center babylai:justify-center babylai:font-bold babylai:text-base babylai:ml-auto babylai:cursor-pointer',
|
|
24
|
+
className
|
|
25
|
+
)}
|
|
26
|
+
aria-label={ariaLabel}
|
|
27
|
+
type="button"
|
|
28
|
+
>
|
|
29
|
+
{icon}
|
|
30
|
+
{children}
|
|
31
|
+
</button>
|
|
32
|
+
);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
ActionButton.displayName = 'ActionButton';
|
|
36
|
+
|
|
37
|
+
export default ActionButton;
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import React, { useRef, useState, useCallback } from 'react';
|
|
2
2
|
import axios from 'axios';
|
|
3
|
-
import { Button } from '@/components';
|
|
4
3
|
import { ImagePreviewDialog } from '@/components/ui';
|
|
5
|
-
import
|
|
6
|
-
import PaperclipIcon from './../../../assets/icons/paperclip.svg';
|
|
7
|
-
import XIcon from './../../../assets/icons/x.svg';
|
|
4
|
+
import MaterialSymbolsCloseSmallOutlineRounded from '~icons/material-symbols/close-small-outline-rounded'
|
|
8
5
|
import { useLocalTranslation } from '../../../useLocalTranslation';
|
|
9
6
|
import { presignUpload } from '@/core/api';
|
|
7
|
+
import SolarPlain2BoldDuotone from '~icons/solar/plain-2-bold-duotone'
|
|
8
|
+
import SolarPaperclipBoldDuotone from '~icons/solar/paperclip-bold-duotone'
|
|
10
9
|
|
|
11
10
|
interface SelectedFileDto {
|
|
12
11
|
file: File;
|
|
@@ -21,12 +20,13 @@ interface ChatWindowFooterProps {
|
|
|
21
20
|
setInputMessage: (e: string) => void;
|
|
22
21
|
handleSendMessage: (attachmentIds: string[]) => void;
|
|
23
22
|
isLoading: boolean;
|
|
23
|
+
isChatClosed?: boolean;
|
|
24
24
|
onEnsureSession: () => Promise<string>;
|
|
25
25
|
sessionId?: string | null; // Pass existing sessionId to avoid creating new sessions
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
const ChatWindowFooter: React.FC<ChatWindowFooterProps> = (props) => {
|
|
29
|
-
const { t,
|
|
29
|
+
const { t, i18n } = useLocalTranslation();
|
|
30
30
|
const fileInputRef = useRef<HTMLInputElement>(null);
|
|
31
31
|
const [selectedFiles, setSelectedFiles] = useState<SelectedFileDto[]>([]);
|
|
32
32
|
const [previewImage, setPreviewImage] = useState<string | null>(null);
|
|
@@ -74,8 +74,8 @@ const ChatWindowFooter: React.FC<ChatWindowFooterProps> = (props) => {
|
|
|
74
74
|
}, []);
|
|
75
75
|
|
|
76
76
|
const handleSendMessageWithAttachments = useCallback(async () => {
|
|
77
|
-
// Prevent sending if already loading
|
|
78
|
-
if (props.isLoading || isSending) {
|
|
77
|
+
// Prevent sending if already loading or chat was closed from chat screen
|
|
78
|
+
if (props.isLoading || props.isChatClosed || isSending) {
|
|
79
79
|
return;
|
|
80
80
|
}
|
|
81
81
|
|
|
@@ -127,7 +127,7 @@ const ChatWindowFooter: React.FC<ChatWindowFooterProps> = (props) => {
|
|
|
127
127
|
);
|
|
128
128
|
|
|
129
129
|
// Get presigned URL
|
|
130
|
-
const presignResponse = await presignUpload(sessionId, fileDto.file, i18n.language);
|
|
130
|
+
const presignResponse = await presignUpload(sessionId, fileDto.file, i18n.language as 'ar' | 'en');
|
|
131
131
|
|
|
132
132
|
// Upload file to presigned URL using axios
|
|
133
133
|
const uploadResponse = await axios.put(presignResponse.uploadUrl, fileDto.file, {
|
|
@@ -190,7 +190,7 @@ const ChatWindowFooter: React.FC<ChatWindowFooterProps> = (props) => {
|
|
|
190
190
|
console.error('[ChatWindowFooter] Error sending message:', error);
|
|
191
191
|
setIsSending(false);
|
|
192
192
|
}
|
|
193
|
-
}, [selectedFiles, props, i18n.language, isSending]);
|
|
193
|
+
}, [selectedFiles, props, i18n.language as 'ar' | 'en', isSending]);
|
|
194
194
|
|
|
195
195
|
// Check if any files are currently uploading
|
|
196
196
|
const hasUploadingFiles = selectedFiles.some((f) => f.uploading);
|
|
@@ -200,7 +200,8 @@ const ChatWindowFooter: React.FC<ChatWindowFooterProps> = (props) => {
|
|
|
200
200
|
|
|
201
201
|
// Allow sending if there's text OR files selected (files will be uploaded on send)
|
|
202
202
|
const hasContentToSend = props.inputMessage.trim() !== '' || selectedFiles.length > 0;
|
|
203
|
-
const isSendDisabled =
|
|
203
|
+
const isSendDisabled =
|
|
204
|
+
props.isLoading || props.isChatClosed || isSending || !hasContentToSend || hasUploadingFiles || hasFileErrors;
|
|
204
205
|
const showLoading = props.isLoading || isSending || hasUploadingFiles;
|
|
205
206
|
|
|
206
207
|
const handleKeyDown = useCallback(
|
|
@@ -216,85 +217,83 @@ const ChatWindowFooter: React.FC<ChatWindowFooterProps> = (props) => {
|
|
|
216
217
|
);
|
|
217
218
|
|
|
218
219
|
return (
|
|
219
|
-
<footer className='babylai
|
|
220
|
+
<footer className='babylai:flex babylai:flex-col babylai:gap-2 babylai:mx-4 babylai:mb-2'>
|
|
220
221
|
{selectedFiles.length > 0 && (
|
|
221
|
-
<div className='babylai
|
|
222
|
+
<div className='babylai:flex babylai:gap-2 babylai:flex-wrap babylai:p-2 babylai:bg-card babylai:rounded-lg'>
|
|
222
223
|
{selectedFiles.map((file) => (
|
|
223
|
-
<div key={file.previewUrl} className='babylai
|
|
224
|
+
<div key={file.previewUrl} className='babylai:relative babylai:group'>
|
|
224
225
|
<img
|
|
225
226
|
src={file.previewUrl}
|
|
226
227
|
alt='Preview'
|
|
227
|
-
className='babylai
|
|
228
|
+
className='babylai:w-16 babylai:h-16 babylai:object-cover babylai:rounded-lg babylai:border babylai:border-black-white-200 babylai:cursor-pointer babylai:hover:opacity-80 babylai:transition-opacity'
|
|
228
229
|
onClick={() => setPreviewImage(file.previewUrl)}
|
|
229
230
|
role='button'
|
|
230
231
|
aria-label='Click to preview image'
|
|
231
232
|
/>
|
|
232
233
|
{file.uploading && (
|
|
233
|
-
<div className='babylai
|
|
234
|
-
<div className='babylai
|
|
234
|
+
<div className='babylai:absolute babylai:inset-0 babylai:flex babylai:items-center babylai:justify-center babylai:bg-black babylai:bg-opacity-50 babylai:rounded-lg'>
|
|
235
|
+
<div className='babylai:animate-spin babylai:rounded-full babylai:h-6 babylai:w-6 babylai:border-2 babylai:border-white babylai:border-t-transparent'></div>
|
|
235
236
|
</div>
|
|
236
237
|
)}
|
|
237
238
|
{file.error && (
|
|
238
|
-
<div className='babylai
|
|
239
|
-
<span className='babylai
|
|
239
|
+
<div className='babylai:absolute babylai:inset-0 babylai:flex babylai:items-center babylai:justify-center babylai:bg-red-500 babylai:bg-opacity-70 babylai:rounded-lg'>
|
|
240
|
+
<span className='babylai:text-white babylai:text-xs'>Error</span>
|
|
240
241
|
</div>
|
|
241
242
|
)}
|
|
242
243
|
<button
|
|
243
244
|
onClick={() => handleRemoveFile(file.previewUrl)}
|
|
244
|
-
className='babylai
|
|
245
|
+
className='babylai:absolute babylai:-top-2 babylai:-right-2 babylai:bg-destructive babylai:text-white babylai:rounded-full babylai:w-5 babylai:h-5 babylai:flex babylai:items-center babylai:justify-center babylai:cursor-pointer'
|
|
245
246
|
type='button'
|
|
246
247
|
aria-label='Remove image'
|
|
247
248
|
>
|
|
248
|
-
<
|
|
249
|
+
<MaterialSymbolsCloseSmallOutlineRounded className='babylai:w-3 babylai:h-3' />
|
|
249
250
|
</button>
|
|
250
251
|
</div>
|
|
251
252
|
))}
|
|
252
253
|
</div>
|
|
253
254
|
)}
|
|
254
255
|
|
|
255
|
-
<div className='babylai
|
|
256
|
+
<div className='babylai:flex babylai:items-center babylai:gap-2 babylai:relative babylai:rounded-full babylai:bg-card babylai:py-3 babylai:px-4'>
|
|
256
257
|
<input
|
|
257
258
|
type='file'
|
|
258
259
|
ref={fileInputRef}
|
|
259
260
|
onChange={handleFileSelect}
|
|
260
261
|
accept='image/*'
|
|
261
262
|
multiple
|
|
262
|
-
className='babylai
|
|
263
|
+
className='babylai:hidden'
|
|
263
264
|
/>
|
|
264
|
-
<
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
265
|
+
<div className='babylai:border-e babylai:border-border babylai:pe-2'>
|
|
266
|
+
<button
|
|
267
|
+
onClick={handleAttachClick}
|
|
268
|
+
disabled={props.isLoading || props.isChatClosed}
|
|
269
|
+
className='babylai:flex babylai:items-center babylai:justify-center babylai:rounded-full babylai:w-8 babylai:h-8 babylai:cursor-pointer babylai:bg-secondary babylai:text-muted-foreground babylai:hover:text-primary-500 babylai:transition-colors babylai:disabled:opacity-50 babylai:disabled:cursor-not-allowed'
|
|
270
|
+
type='button'
|
|
271
|
+
aria-label='Attach image'
|
|
272
|
+
>
|
|
273
|
+
<SolarPaperclipBoldDuotone className='babylai:w-4 babylai:h-4' />
|
|
274
|
+
</button>
|
|
275
|
+
</div>
|
|
274
276
|
<input
|
|
275
277
|
type='text'
|
|
276
278
|
value={props.inputMessage}
|
|
277
279
|
onChange={(e) => props.setInputMessage(e.target.value)}
|
|
278
280
|
onKeyDown={handleKeyDown}
|
|
279
281
|
placeholder={t('homeSdk.placeholder')}
|
|
280
|
-
|
|
282
|
+
disabled={props.isChatClosed}
|
|
283
|
+
className='babylai:flex-1 babylai:py-2 babylai:px-2 babylai:bg-transparent babylai:outline-none babylai:text-sm babylai:border-none babylai:text-card-foreground babylai:disabled:opacity-50 babylai:disabled:cursor-not-allowed'
|
|
281
284
|
/>
|
|
282
|
-
<
|
|
283
|
-
variant='default'
|
|
284
|
-
size='icon'
|
|
285
|
+
<button
|
|
285
286
|
onClick={handleSendMessageWithAttachments}
|
|
286
|
-
disabled={isSendDisabled}
|
|
287
|
-
className='babylai
|
|
287
|
+
disabled={isSendDisabled || props.isChatClosed}
|
|
288
|
+
className='babylai:rounded-full babylai:bg-primary-500 babylai:hover:bg-primary-600 babylai:w-8 babylai:h-8 babylai:p-0 babylai:flex babylai:items-center babylai:justify-center babylai:disabled:opacity-50 babylai:text-white babylai:cursor-pointer babylai:disabled:cursor-not-allowed'
|
|
288
289
|
type='button'
|
|
289
290
|
>
|
|
290
291
|
{showLoading ? (
|
|
291
|
-
<div className='babylai
|
|
292
|
+
<div className='babylai:inline-block babylai:animate-spin babylai:rounded-full babylai:h-4 babylai:w-4 babylai:aspect-square babylai:border-2 babylai:border-white babylai:border-t-transparent babylai:box-border'></div>
|
|
292
293
|
) : (
|
|
293
|
-
<
|
|
294
|
-
className={`babylai-w-4 babylai-h-4 babylai-flex-shrink-0 ${dir === 'rtl' ? 'babylai-rotate-270' : ''}`}
|
|
295
|
-
/>
|
|
294
|
+
<SolarPlain2BoldDuotone className="babylai:w-4 babylai:h-4" />
|
|
296
295
|
)}
|
|
297
|
-
</
|
|
296
|
+
</button>
|
|
298
297
|
</div>
|
|
299
298
|
|
|
300
299
|
{/* Image Preview Dialog */}
|
|
@@ -1,81 +1,48 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import { useLocalTranslation } from "../../../useLocalTranslation";
|
|
1
|
+
import React from "react";
|
|
2
|
+
import ActionButton from "./action-button";
|
|
3
|
+
import SolarAltArrowLeftLinear from '~icons/solar/alt-arrow-left-linear'
|
|
4
|
+
import IcRoundMinus from '~icons/ic/round-minus'
|
|
5
|
+
import MaterialSymbolsCloseSmallOutlineRounded from '~icons/material-symbols/close-small-outline-rounded'
|
|
7
6
|
|
|
8
7
|
interface ChatWindowHeaderProps {
|
|
9
|
-
isShowList: boolean;
|
|
10
|
-
setIsShowList?: (isShowList: boolean) => void;
|
|
11
|
-
showChat: boolean;
|
|
12
|
-
onClose: () => void;
|
|
13
8
|
handleBack: () => void;
|
|
14
9
|
handleEndChat: () => void;
|
|
15
|
-
|
|
10
|
+
handleMinimize: () => void;
|
|
11
|
+
optionTitle: string;
|
|
16
12
|
}
|
|
17
13
|
|
|
18
|
-
const ChatWindowHeader: React.FC<ChatWindowHeaderProps> = (
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
14
|
+
const ChatWindowHeader: React.FC<ChatWindowHeaderProps> = ({
|
|
15
|
+
handleBack,
|
|
16
|
+
handleEndChat,
|
|
17
|
+
handleMinimize,
|
|
18
|
+
optionTitle,
|
|
19
|
+
}) => {
|
|
22
20
|
|
|
23
21
|
return (
|
|
24
|
-
<header className="
|
|
25
|
-
<div className="babylai
|
|
26
|
-
<
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
>
|
|
32
|
-
<ArrowRight
|
|
33
|
-
className={`babylai-w-3 babylai-h-3 ${isRTL ? "" : "babylai-rotate-180"} babylai-text-primary-500 dark:babylai-text-white`}
|
|
34
|
-
/>
|
|
35
|
-
</Button>
|
|
36
|
-
<div className="babylai-relative">
|
|
37
|
-
<Button
|
|
38
|
-
variant="rounded-icon"
|
|
39
|
-
size="icon"
|
|
40
|
-
className="!babylai-bg-primary-100 dark:!babylai-bg-storm-dust-950"
|
|
41
|
-
onClick={() => setShowMenu(!showMenu)}
|
|
42
|
-
>
|
|
43
|
-
<ThreeDots className="babylai-w-3.5 babylai-h-1 babylai-text-primary-500 dark:babylai-text-white" />
|
|
44
|
-
</Button>
|
|
22
|
+
<header className="bg-header babylai:flex babylai:items-center babylai:justify-between babylai:p-6 babylai:border-b babylai:border-black-white-200">
|
|
23
|
+
<div className="babylai:flex babylai:items-center babylai:gap-2">
|
|
24
|
+
<ActionButton
|
|
25
|
+
onClick={handleBack}
|
|
26
|
+
icon={<SolarAltArrowLeftLinear />}
|
|
27
|
+
ariaLabel="Back"
|
|
28
|
+
/>
|
|
45
29
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
aria-orientation="vertical"
|
|
52
|
-
>
|
|
53
|
-
<Button
|
|
54
|
-
role="menuitem"
|
|
55
|
-
variant="link"
|
|
56
|
-
onClick={(e) => {
|
|
57
|
-
e.stopPropagation();
|
|
58
|
-
props.handleEndChat();
|
|
59
|
-
setShowMenu(false);
|
|
60
|
-
}}
|
|
61
|
-
>
|
|
62
|
-
{t("homeSdk.endChat")}
|
|
63
|
-
</Button>
|
|
64
|
-
</div>
|
|
65
|
-
</div>
|
|
66
|
-
)}
|
|
67
|
-
</div>
|
|
30
|
+
<ActionButton
|
|
31
|
+
onClick={handleEndChat}
|
|
32
|
+
icon={<MaterialSymbolsCloseSmallOutlineRounded />}
|
|
33
|
+
ariaLabel="End Chat"
|
|
34
|
+
/>
|
|
68
35
|
</div>
|
|
69
36
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
37
|
+
<h2 className="babylai:text-lg babylai:font-semibold babylai:ml-auto babylai:text-card-foreground">
|
|
38
|
+
{optionTitle}
|
|
39
|
+
</h2>
|
|
40
|
+
|
|
41
|
+
<ActionButton
|
|
42
|
+
onClick={handleMinimize}
|
|
43
|
+
icon={<IcRoundMinus />}
|
|
44
|
+
ariaLabel="Minimize"
|
|
45
|
+
/>
|
|
79
46
|
</header>
|
|
80
47
|
);
|
|
81
48
|
};
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import React, { useState, useCallback } from 'react';
|
|
2
|
+
import { ReviewProps } from '@/lib/types';
|
|
3
|
+
import { Rating } from '@/ui/review-dialog/rating';
|
|
4
|
+
import { useLocalTranslation } from '@/useLocalTranslation';
|
|
5
|
+
import LogoIcon from '@/assets/logo.svg';
|
|
6
|
+
|
|
7
|
+
interface InChatReviewProps {
|
|
8
|
+
onSubmit: (payload: ReviewProps) => void | Promise<void>;
|
|
9
|
+
onDone?: () => void;
|
|
10
|
+
isSubmitting?: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const InChatReview: React.FC<InChatReviewProps> = ({ onSubmit, isSubmitting = false }) => {
|
|
14
|
+
const { t } = useLocalTranslation();
|
|
15
|
+
const [rating, setRating] = useState<number>(0);
|
|
16
|
+
const [comment, setComment] = useState<string>('');
|
|
17
|
+
|
|
18
|
+
const hasRating = rating >= 1 && rating <= 5;
|
|
19
|
+
|
|
20
|
+
const handleRatingChange = useCallback((val: number) => {
|
|
21
|
+
setRating(val);
|
|
22
|
+
}, []);
|
|
23
|
+
|
|
24
|
+
const handleSubmit = useCallback(() => {
|
|
25
|
+
void onSubmit({ rating, comment: comment.trim() });
|
|
26
|
+
}, [rating, comment, onSubmit]);
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<section className="babylai:mb-4 babylai:flex babylai:justify-start">
|
|
30
|
+
<div className="babylai:shrink-0 babylai:me-3 babylai:w-8 babylai:h-8 babylai:rounded-full babylai:flex babylai:items-center babylai:justify-center babylai:bg-primary">
|
|
31
|
+
<LogoIcon className="babylai:w-4 babylai:h-4 babylai:text-primary" />
|
|
32
|
+
</div>
|
|
33
|
+
|
|
34
|
+
<div className="babylai:bg-card babylai:max-w-[80%] babylai:p-5 babylai:rounded-3xl babylai:text-sm babylai:flex babylai:flex-col babylai:gap-2.5 babylai:text-start">
|
|
35
|
+
<h2 className='babylai:text-card-foreground'>
|
|
36
|
+
{t('homeSdk.InChatReview.title')}
|
|
37
|
+
</h2>
|
|
38
|
+
<p className="babylai:font-normal babylai:text-muted-foreground">
|
|
39
|
+
{t('homeSdk.InChatReview.description')}
|
|
40
|
+
</p>
|
|
41
|
+
|
|
42
|
+
<section className='babylai:bg-muted babylai:rounded-3xl babylai:p-3'>
|
|
43
|
+
<Rating value={rating} onChange={handleRatingChange} size="md" />
|
|
44
|
+
</section>
|
|
45
|
+
|
|
46
|
+
{hasRating && (
|
|
47
|
+
<>
|
|
48
|
+
<p className="babylai:text-card-foreground">{t('homeSdk.InChatReview.follow_up')}</p>
|
|
49
|
+
|
|
50
|
+
<textarea
|
|
51
|
+
className="babylai:w-full babylai:bg-secondary babylai:border babylai:border-black-white-200 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"
|
|
52
|
+
rows={4}
|
|
53
|
+
placeholder={t('homeSdk.InChatReview.note_placeholder')}
|
|
54
|
+
value={comment}
|
|
55
|
+
onChange={(e) => setComment(e.target.value)}
|
|
56
|
+
aria-label={t('homeSdk.InChatReview.note_placeholder')}
|
|
57
|
+
/>
|
|
58
|
+
|
|
59
|
+
<button
|
|
60
|
+
onClick={handleSubmit}
|
|
61
|
+
disabled={isSubmitting}
|
|
62
|
+
className="babylai:bg-primary babylai:border babylai:border-primary babylai:cursor-pointer babylai:disabled:bg-black-white-300 babylai:disabled:border-black-white-300 babylai:disabled:cursor-not-allowed babylai:disabled:text-white babylai:duration-200 babylai:ease-out babylai:flex babylai:gap-1 babylai:items-center babylai:justify-center babylai:p-3 babylai:relative babylai:rounded-2xl babylai:text-white babylai:text-xl babylai:transition-all babylai:w-full"
|
|
63
|
+
>
|
|
64
|
+
{isSubmitting ? (
|
|
65
|
+
<>
|
|
66
|
+
<span
|
|
67
|
+
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"
|
|
68
|
+
aria-hidden
|
|
69
|
+
/>
|
|
70
|
+
{t('homeSdk.InChatReview.submit_button')}
|
|
71
|
+
</>
|
|
72
|
+
) : (
|
|
73
|
+
t('homeSdk.InChatReview.submit_button')
|
|
74
|
+
)}
|
|
75
|
+
</button>
|
|
76
|
+
</>
|
|
77
|
+
)}
|
|
78
|
+
</div>
|
|
79
|
+
</section>
|
|
80
|
+
);
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
InChatReview.displayName = 'InChatReview';
|