shopify-chatbot-widget 0.7.8 → 0.8.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.
Files changed (58) hide show
  1. package/dist/jaweb-chatbot.css +1 -1
  2. package/dist/jaweb-chatbot.iife.js +117 -117
  3. package/package.json +3 -1
  4. package/src/App.css +42 -0
  5. package/src/App.tsx +13 -0
  6. package/src/Chatbot/Chatbot.css +270 -0
  7. package/src/Chatbot/Chatbot.tsx +214 -0
  8. package/src/Chatbot/ChatbotTransition.css +19 -0
  9. package/src/Chatbot/OLDCHAT.tsx +259 -0
  10. package/src/Chatbot/components/ChatInput.css +127 -0
  11. package/src/Chatbot/components/ChatInput.tsx +354 -0
  12. package/src/Chatbot/components/Messages/Addcart.tsx +70 -0
  13. package/src/Chatbot/components/Messages/AgentStatus.tsx +37 -0
  14. package/src/Chatbot/components/Messages/AssistantMesage.tsx +206 -0
  15. package/src/Chatbot/components/Messages/AudioMessage.tsx +123 -0
  16. package/src/Chatbot/components/Messages/CalendlyEmbeds.tsx +66 -0
  17. package/src/Chatbot/components/Messages/CardSwiper.tsx +194 -0
  18. package/src/Chatbot/components/Messages/Carousel/CardSwiper.tsx +264 -0
  19. package/src/Chatbot/components/Messages/Carousel/CardSwiperSalla.tsx +208 -0
  20. package/src/Chatbot/components/Messages/Carousel/CardSwiperZid.tsx +208 -0
  21. package/src/Chatbot/components/Messages/Carousel/SallaSwiper.css +245 -0
  22. package/src/Chatbot/components/Messages/Carousel/TryOn.tsx +108 -0
  23. package/src/Chatbot/components/Messages/CartWidget.tsx +151 -0
  24. package/src/Chatbot/components/Messages/ChatImage.tsx +46 -0
  25. package/src/Chatbot/components/Messages/ChatImageText.tsx +74 -0
  26. package/src/Chatbot/components/Messages/ChatImageTextAssis.tsx +72 -0
  27. package/src/Chatbot/components/Messages/ChatMessages.css +31 -0
  28. package/src/Chatbot/components/Messages/ChatMessages.tsx +334 -0
  29. package/src/Chatbot/components/Messages/ProductCard.css +149 -0
  30. package/src/Chatbot/components/Messages/SallaAssistantMessage.tsx +196 -0
  31. package/src/Chatbot/components/Messages/Support.tsx +177 -0
  32. package/src/Chatbot/components/Messages/Typing.css +31 -0
  33. package/src/Chatbot/components/Messages/Typing.tsx +19 -0
  34. package/src/Chatbot/components/Messages/ZidAssistantMesage.tsx +196 -0
  35. package/src/Chatbot/components/Messages/cartwidget.css +123 -0
  36. package/src/Chatbot/components/Messenger/Messenger.tsx +531 -0
  37. package/src/Chatbot/components/Notification.tsx +28 -0
  38. package/src/Chatbot/components/Powered.css +29 -0
  39. package/src/Chatbot/components/Powered.tsx +12 -0
  40. package/src/Chatbot/components/Sessions/CreateSession.tsx +201 -0
  41. package/src/Chatbot/components/Sessions/RenderList.tsx +212 -0
  42. package/src/Chatbot/components/Suggestions.css +35 -0
  43. package/src/Chatbot/components/Suggestions.tsx +57 -0
  44. package/src/Chatbot/notification.css +17 -0
  45. package/src/assets/react.svg +1 -0
  46. package/src/chatbot-widget/index.tsx +14 -0
  47. package/src/hooks/config.tsx +13 -0
  48. package/src/hooks/useCart.tsx +107 -0
  49. package/src/hooks/useChatbotAPI.tsx +167 -0
  50. package/src/hooks/useChatbotData.tsx +132 -0
  51. package/src/hooks/useSessionMessages.tsx +50 -0
  52. package/src/hooks/useWebsocke.tsx +45 -0
  53. package/src/i18n.tsx +30 -0
  54. package/src/index.css +2 -0
  55. package/src/main.tsx +10 -0
  56. package/src/types/chatbot.ts +40 -0
  57. package/src/utils/cookies.tsx +14 -0
  58. package/src/vite-env.d.ts +1 -0
@@ -0,0 +1,108 @@
1
+ import React, { useState } from 'react';
2
+ import { Button, Spin } from 'antd';
3
+ import { LoadingOutlined, CloudUploadOutlined } from '@ant-design/icons';
4
+ import config from '../../../../hooks/config';
5
+
6
+ interface TryOnProps {
7
+ productImage: string; // product variant image URL
8
+ }
9
+
10
+ const TryOnBox: React.FC<TryOnProps> = ({ productImage }) => {
11
+ const [userImage, setUserImage] = useState<string | null>(null);
12
+ const [resultImage, setResultImage] = useState<string | null>(null);
13
+ const [loading, setLoading] = useState(false);
14
+
15
+ // Call your Django Ark API
16
+ const sendToArk = async (file: File) => {
17
+ setLoading(true);
18
+ setResultImage(null);
19
+
20
+ const reader = new FileReader();
21
+ reader.onload = async () => {
22
+ const base64UserImage = reader.result as string;
23
+
24
+ try {
25
+ const response = await fetch(`${config.apiUrl}ark-tryon/`, {
26
+ method: 'POST',
27
+ headers: { 'Content-Type': 'application/json' },
28
+ body: JSON.stringify({
29
+ userImageUrl: base64UserImage, // can also be a hosted URL
30
+ productImageUrl: productImage, // product image URL
31
+ }),
32
+ });
33
+
34
+ const data = await response.json();
35
+
36
+ if (data.resultImage) {
37
+ setResultImage(data.resultImage); // base64 string or URL from backend
38
+ } else {
39
+ console.error('Ark API error:', data);
40
+ }
41
+ } catch (err) {
42
+ console.error('Error calling Ark API:', err);
43
+ } finally {
44
+ setLoading(false);
45
+ }
46
+ };
47
+ reader.readAsDataURL(file);
48
+ };
49
+
50
+ const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
51
+ if (e.target.files && e.target.files[0]) {
52
+ setUserImage(URL.createObjectURL(e.target.files[0]));
53
+ sendToArk(e.target.files[0]);
54
+ }
55
+ };
56
+
57
+ return (
58
+ <div className="mt-4 border rounded-lg p-4 bg-gray-50">
59
+ {/* Upload prompt */}
60
+ {!userImage && !resultImage && !loading && (
61
+ <label className="flex flex-col items-center justify-center border-2 border-dashed border-gray-400 rounded-lg w-full h-40 cursor-pointer hover:bg-gray-100 transition">
62
+ <CloudUploadOutlined style={{ fontSize: 28, marginBottom: 8 }} />
63
+ <span className="text-gray-500">Click or Drop your photo here</span>
64
+ <input
65
+ type="file"
66
+ accept="image/*"
67
+ className="hidden"
68
+ onChange={handleFileChange}
69
+ />
70
+ </label>
71
+ )}
72
+
73
+ {/* Loader */}
74
+ {loading && (
75
+ <div className="flex flex-col items-center justify-center h-40">
76
+ <Spin indicator={<LoadingOutlined style={{ fontSize: 32 }} spin />} />
77
+ <p className="mt-2 text-gray-600">Generating your try-on...</p>
78
+ </div>
79
+ )}
80
+
81
+ {/* Result Preview */}
82
+ {!loading && resultImage && (
83
+ <div className="flex flex-col items-center">
84
+ <p className="mb-2 text-sm font-medium">✨ Try-On Result</p>
85
+ <img
86
+ src={resultImage}
87
+ alt="Result"
88
+ className="max-h-64 object-contain rounded-md border"
89
+ />
90
+
91
+ <Button
92
+ style={{margin:'4px'}}
93
+ type="default"
94
+ className="mt-3"
95
+ onClick={() => {
96
+ setUserImage(null);
97
+ setResultImage(null);
98
+ }}
99
+ >
100
+ Try Another
101
+ </Button>
102
+ </div>
103
+ )}
104
+ </div>
105
+ );
106
+ };
107
+
108
+ export default TryOnBox;
@@ -0,0 +1,151 @@
1
+ import { useState, useRef, useEffect } from 'react';
2
+ import type { CartItem } from '../../../hooks/useCart';
3
+ import { ShoppingCartOutlined, CloseOutlined } from '@ant-design/icons';
4
+ import { Button } from 'antd';
5
+ import './CartWidget.css'; // import the encapsulated styles
6
+ import config from '../../../hooks/config';
7
+
8
+ interface Props {
9
+ items: CartItem[];
10
+ colorCode: string;
11
+ loading: boolean;
12
+ onRefresh: () => void;
13
+ onRemove: (variantId: string, qty: number) => void;
14
+ sendMessage: (message: string) => Promise<void>;
15
+ sessionId: string;
16
+ }
17
+
18
+ export default function CartWidget({
19
+ items,
20
+ loading,
21
+ colorCode,
22
+ sessionId,
23
+ onRefresh,
24
+ onRemove,
25
+ }: Props) {
26
+ const [open, setOpen] = useState(false);
27
+ const containerRef = useRef<HTMLDivElement>(null);
28
+
29
+ const [isLoading,setIsLoading]=useState(false)
30
+
31
+ const checkOut = async () => {
32
+
33
+ setIsLoading(true);
34
+ try {
35
+ const response = await fetch(`${config.apiUrl}checkout/shopify`, {
36
+ method: 'POST',
37
+ headers: {
38
+ 'Content-Type': 'application/json',
39
+ },
40
+ body: JSON.stringify({
41
+ sessionId,
42
+ company_username: localStorage.getItem('company_username'),
43
+ }),
44
+ });
45
+
46
+ if (!response.ok) throw new Error('Failed to initiate checkout.');
47
+
48
+ const data = await response.json();
49
+
50
+ if (data?.checkoutUrl) {
51
+
52
+ window.parent?.postMessage(
53
+ { type: 'JAWEB_CHAT', action: 'navigate', target: '_blank', url: data.checkoutUrl },
54
+ '*'
55
+ );
56
+
57
+
58
+
59
+ } else {
60
+ alert('No checkout URL returned.');
61
+ }
62
+ } catch (err) {
63
+
64
+ console.error('Checkout error:', err);
65
+ } finally {
66
+ setIsLoading(false);
67
+ }
68
+ };
69
+
70
+
71
+ useEffect(() => {
72
+ const handleClickOutside = (e: MouseEvent) => {
73
+ if (
74
+ containerRef.current &&
75
+ !containerRef.current.contains(e.target as Node)
76
+ ) {
77
+ setOpen(false);
78
+ }
79
+ };
80
+ document.addEventListener('mousedown', handleClickOutside);
81
+ return () => document.removeEventListener('mousedown', handleClickOutside);
82
+ }, []);
83
+
84
+ const totalCount = items.reduce((sum, i) => sum + i.quantity, 0);
85
+
86
+ return (
87
+ <div className="jawebchatbotcss-cart-widget" ref={containerRef}>
88
+ <button
89
+ onClick={() => setOpen(o => !o)}
90
+ className="jawebchatbotcss-cart-button"
91
+ >
92
+ <ShoppingCartOutlined className="jawebchatbotcss-cart-icon" />
93
+ <span className="jawebchatbotcss-cart-label">Cart ({totalCount})</span>
94
+ </button>
95
+
96
+ {open && (
97
+ <div className="jawebchatbotcss-cart-dropdown">
98
+ <div className="jawebchatbotcss-cart-header">
99
+ <span className="jawebchatbotcss-cart-title">Your Cart</span>
100
+ <button
101
+ onClick={onRefresh}
102
+ disabled={loading}
103
+ className="jawebchatbotcss-refresh-button"
104
+ >
105
+ {loading ? 'Refreshing…' : 'Refresh'}
106
+ </button>
107
+ </div>
108
+
109
+ {items.length === 0 ? (
110
+ <div className="jawebchatbotcss-cart-empty">
111
+ Your cart is empty.
112
+ </div>
113
+ ) : (
114
+ <ul className="jawebchatbotcss-cart-list">
115
+ {items.map(i => (
116
+ <li key={i.variantId} className="jawebchatbotcss-cart-item">
117
+ <span className="jawebchatbotcss-item-name">{i.name}</span>
118
+ <div className="jawebchatbotcss-item-controls">
119
+ <span className="jawebchatbotcss-item-qty">×{i.quantity}</span>
120
+ <CloseOutlined
121
+ onClick={() => onRemove(i.variantId, i.quantity)}
122
+ className="jawebchatbotcss-remove-icon"
123
+ />
124
+ </div>
125
+ </li>
126
+ ))}
127
+ </ul>
128
+ )}
129
+
130
+ {items.length > 0 && (
131
+ <div className="jawebchatbotcss-cart-footer">
132
+ <Button
133
+ type="primary"
134
+ style={{ backgroundColor: colorCode }}
135
+ block
136
+ disabled={totalCount === 0}
137
+ loading={isLoading}
138
+ onClick={() => {
139
+ checkOut()
140
+ // Define `checkOut()` or pass it via props
141
+ }}
142
+ >
143
+ Checkout ({totalCount})
144
+ </Button>
145
+ </div>
146
+ )}
147
+ </div>
148
+ )}
149
+ </div>
150
+ );
151
+ }
@@ -0,0 +1,46 @@
1
+ import React from 'react';
2
+
3
+ type MessagePart = {
4
+ type: string;
5
+ text?: string;
6
+ image_url?: {
7
+ url?: string;
8
+ };
9
+ };
10
+
11
+ type ChatImageProps = {
12
+ message: MessagePart[] & { isBusiness?: boolean };
13
+
14
+ };
15
+
16
+ const ChatImage: React.FC<ChatImageProps> = ({ message }) => {
17
+ const imgPart = message.find(part => part.type === 'image_url')?.image_url?.url;
18
+ const isBusiness = (message as any)?.isBusiness;
19
+
20
+
21
+ return (
22
+ <div>
23
+ <div>
24
+ {imgPart && (
25
+ <div className="mb-2 bg-transparent text-white ">
26
+ <img
27
+ src={imgPart}
28
+ alt="Chat image"
29
+ style={{ width: 200 }}
30
+ className={`rounded-md bg-transparent mt-2 max-w-xs ${
31
+ isBusiness ? 'border border-gray-300 shadow-sm' : ''
32
+ }`}
33
+ />
34
+ </div>
35
+ )}
36
+
37
+
38
+ </div>
39
+
40
+ </div>
41
+
42
+
43
+ );
44
+ };
45
+
46
+ export default ChatImage;
@@ -0,0 +1,74 @@
1
+ import React from 'react';
2
+
3
+ type MessagePart = {
4
+ type: string;
5
+ text?: string;
6
+ image_url?: {
7
+ url?: string;
8
+ };
9
+ };
10
+
11
+ type ChatImageProps = {
12
+ message: MessagePart[] & { isBusiness?: boolean };
13
+ colorCode:string;
14
+ };
15
+
16
+ const ChatImageText: React.FC<ChatImageProps> = ({ message ,colorCode}) => {
17
+ const textPart = message.find(part => part.type === 'text')?.text;
18
+
19
+
20
+ const formatTextWithLinks = (text: string): React.ReactNode[] => {
21
+ const urlRegex = /(https?:\/\/[^\s]+)/g;
22
+ return text.split(urlRegex).map((part, i) =>
23
+ urlRegex.test(part) ? (
24
+ <a
25
+ key={i}
26
+ href={part.trim()}
27
+ style={{ color: colorCode }}
28
+ target="_blank"
29
+ rel="noopener noreferrer"
30
+ className="underline break-words"
31
+ >
32
+ {part}
33
+ </a>
34
+ ) : (
35
+ <span key={i}>{part}</span>
36
+ )
37
+ );
38
+ };
39
+
40
+ return (
41
+ <>
42
+ {textPart && (
43
+ <div
44
+ style={{
45
+ color:'white',
46
+ border:1,
47
+ backgroundColor:colorCode,
48
+ paddingTop:10,
49
+ paddingBottom:10,
50
+ paddingInline:14,
51
+ maxWidth:'85%',
52
+ lineHeight:1.4,
53
+ borderRadius:'16px'
54
+ ,wordBreak:'break-word'
55
+
56
+ }}
57
+ >
58
+
59
+ <p >
60
+ {formatTextWithLinks(textPart)}
61
+ </p>
62
+
63
+ </div>
64
+ )}
65
+ </>
66
+
67
+
68
+
69
+
70
+
71
+ );
72
+ };
73
+
74
+ export default ChatImageText;
@@ -0,0 +1,72 @@
1
+ import React from 'react';
2
+
3
+ type MessagePart = {
4
+ type: string;
5
+ text?: string;
6
+ image_url?: {
7
+ url?: string;
8
+ };
9
+ };
10
+
11
+ type ChatImageProps = {
12
+ message: MessagePart[] & { isBusiness?: boolean };
13
+ };
14
+
15
+ const ChatImageTextAssist: React.FC<ChatImageProps> = ({ message }) => {
16
+ const textPart = message.find(part => part.type === 'text')?.text;
17
+
18
+
19
+ const formatTextWithLinks = (text: string): React.ReactNode[] => {
20
+ const urlRegex = /(https?:\/\/[^\s]+)/g;
21
+ return text.split(urlRegex).map((part, i) =>
22
+ urlRegex.test(part) ? (
23
+ <a
24
+ key={i}
25
+ href={part.trim()}
26
+ style={{ color: 'black' }}
27
+ target="_blank"
28
+ rel="noopener noreferrer"
29
+ className="underline break-words"
30
+ >
31
+ {part}
32
+ </a>
33
+ ) : (
34
+ <span key={i}>{part}</span>
35
+ )
36
+ );
37
+ };
38
+
39
+ return (
40
+ <>
41
+ {textPart && (
42
+ <div
43
+ style={{
44
+ color:'black',
45
+ border:1,
46
+ paddingTop:10,
47
+ paddingBottom:10,
48
+ paddingInline:14,
49
+ maxWidth:'85%',
50
+ lineHeight:1.4,
51
+ borderRadius:'16px'
52
+ ,wordBreak:'break-word',
53
+ backgroundColor:'#f0f0f0'
54
+ }}
55
+ >
56
+
57
+ <p >
58
+ {formatTextWithLinks(textPart)}
59
+ </p>
60
+
61
+ </div>
62
+ )}
63
+ </>
64
+
65
+
66
+
67
+
68
+
69
+ );
70
+ };
71
+
72
+ export default ChatImageTextAssist;
@@ -0,0 +1,31 @@
1
+ .chat-image-wrapper {
2
+ padding: 4px 12px;
3
+
4
+ }
5
+
6
+ .box-loader {
7
+ width: 6px;
8
+ height: 10px;
9
+ border-radius: 3px;
10
+ animation: pulseBox 0.8s infinite alternate;
11
+ }
12
+
13
+ .box-loader:nth-child(2) {
14
+ animation-delay: 0.2s;
15
+ }
16
+
17
+ .box-loader:nth-child(3) {
18
+ animation-delay: 0.4s;
19
+ }
20
+
21
+ @keyframes pulseBox {
22
+ from {
23
+ transform: scale(1);
24
+ opacity: 0.6;
25
+ }
26
+ to {
27
+ transform: scale(1.3);
28
+ opacity: 1;
29
+ }
30
+ }
31
+