shopify-chatbot-widget 0.8.7 → 0.8.9

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "shopify-chatbot-widget",
3
3
  "private": false,
4
- "version": "0.8.7",
4
+ "version": "0.8.9",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "dev": "vite",
@@ -9,10 +9,11 @@ import FingerprintJS from '@fingerprintjs/fingerprintjs';
9
9
  import { LoadingOutlined } from '@ant-design/icons';
10
10
  import { Spin } from 'antd';
11
11
  import { motion, AnimatePresence } from 'framer-motion';
12
+ import CartLayout from './components/Cart/Index';
12
13
 
13
14
  const Chatbot: React.FC = () => {
14
15
  const [open, setOpen] = useState(false);
15
- const [viewMode, setViewMode] = useState<'sessions' | 'create' | 'messenger'>('sessions');
16
+ const [viewMode, setViewMode] = useState<'sessions' | 'create' | 'messenger' | 'cartView' >('sessions');
16
17
  const [activeSessionId, setActiveSessionId] = useState<string | null>(null);
17
18
  const [HasInfo, setHasInfo] = useState(false);
18
19
  const [activeAgentName, setActiveAgentName] = useState('');
@@ -31,6 +32,7 @@ const Chatbot: React.FC = () => {
31
32
  calendly,
32
33
  disbleCheckout,
33
34
  chatbotName,
35
+ setMessagesSuggestions
34
36
  } = useChatbotData();
35
37
 
36
38
  const [visitorData, setVisitorData] = useState<{ visitorId: string; country: string } | null>(null);
@@ -177,6 +179,34 @@ const Chatbot: React.FC = () => {
177
179
  </motion.div>
178
180
  )}
179
181
 
182
+ {viewMode === 'cartView' && (
183
+ <motion.div
184
+ key="create"
185
+ initial={{ opacity: 0, y: 30 }}
186
+ animate={{ opacity: 1, y: 0 }}
187
+ exit={{ opacity: 0, y: -30 }}
188
+ transition={{ duration: 0.3 }}
189
+ style={{height:'100%'}}
190
+
191
+
192
+ >
193
+ <CartLayout
194
+ setOpen={(v: boolean) => (v ? requestOpen() : requestClose())}
195
+ sessionId={activeSessionId}
196
+ Opened={open}
197
+ chatbotLogo={chatbotLogo}
198
+ colorCode={colorCode}
199
+ onBack={() => {
200
+ setNewSession(false);
201
+ setViewMode("messenger");
202
+ }}
203
+ />
204
+
205
+
206
+ </motion.div>
207
+ )}
208
+
209
+
180
210
  {viewMode === 'messenger' && activeSessionId && (
181
211
  <motion.div
182
212
  key="messenger"
@@ -198,12 +228,15 @@ const Chatbot: React.FC = () => {
198
228
  setOpen={(v: boolean) => (v ? requestOpen() : requestClose())}
199
229
  setNewSession={setNewSession}
200
230
  Opened={open}
201
- setView={() => setViewMode('sessions')}
231
+ setView={setViewMode}
202
232
  userType={userType}
203
233
  disbleCheckout={disbleCheckout}
234
+ setMessagesSuggestions={setMessagesSuggestions}
204
235
  />
205
236
  </motion.div>
206
237
  )}
238
+
239
+
207
240
  </AnimatePresence>
208
241
  )}
209
242
  </div>
@@ -0,0 +1,287 @@
1
+ import React, { useState } from "react";
2
+ import {
3
+ CloseOutlined,
4
+ ArrowLeftOutlined,
5
+ DeleteOutlined,
6
+ ShoppingOutlined,
7
+ LoadingOutlined
8
+ } from "@ant-design/icons";
9
+ import { Button, Spin, message } from "antd";
10
+ import { useCart } from "../../../hooks/useCart";
11
+ import { useCartAPI } from "../../../hooks/useCheckout";
12
+
13
+ type CartSessionProps = {
14
+ setOpen: (v: boolean) => void;
15
+ sessionId: string | null;
16
+ Opened: boolean;
17
+ chatbotLogo: string;
18
+ colorCode?: string;
19
+ onBack: () => void;
20
+ };
21
+
22
+ const CartLayout: React.FC<CartSessionProps> = ({
23
+ colorCode,
24
+ setOpen,
25
+ Opened,
26
+ onBack,
27
+ sessionId,
28
+ }) => {
29
+ const { items, loading, removeFromCart, refresh } = useCart(sessionId || "");
30
+ const { checkOut } = useCartAPI();
31
+ const [isLoading, setIsLoading] = useState(false);
32
+
33
+
34
+ const handleCheckout = async () => {
35
+ if (!sessionId) {
36
+ message.warning("No session found — please start a chat first.");
37
+ return;
38
+ }
39
+
40
+ setIsLoading(true);
41
+ try {
42
+ await checkOut(sessionId);
43
+ } catch (err: any) {
44
+ message.error("Checkout failed. Please try again.");
45
+ console.error("Checkout error:", err);
46
+ } finally {
47
+ setIsLoading(false);
48
+ }
49
+ };
50
+
51
+ const loadingIcon = <LoadingOutlined style={{ fontSize: 24, color: colorCode||'#7F28F8' }} spin />;
52
+
53
+
54
+ const handleRemove = async (variantId: string) => {
55
+ await removeFromCart(variantId, 1);
56
+ message.info("Item removed from cart");
57
+ await refresh();
58
+ };
59
+
60
+ return (
61
+ <div
62
+ style={{
63
+ maxWidth: "100%",
64
+ height: "100%",
65
+ border: "1px solid #f0f0f0",
66
+ borderRadius: 8,
67
+ display: "flex",
68
+ flexDirection: "column",
69
+ backgroundColor: "#fff",
70
+ overflow: "hidden",
71
+ }}
72
+ >
73
+ {/* Header */}
74
+ <div
75
+ style={{
76
+ padding: "16px",
77
+ display: "flex",
78
+ alignItems: "center",
79
+ borderBottom: "1px solid #f5f5f5",
80
+ boxShadow: "0 2px 6px rgba(0,0,0,0.03)",
81
+ zIndex: 5,
82
+ height:'8%'
83
+ }}
84
+ >
85
+ <Button
86
+ type="text"
87
+ icon={<ArrowLeftOutlined />}
88
+ onClick={onBack}
89
+ style={{ color: "#333", fontWeight: 500 }}
90
+ >
91
+ Back
92
+ </Button>
93
+
94
+ <div style={{ marginLeft: "auto" }}>
95
+ <CloseOutlined
96
+ onClick={() => setOpen(!Opened)}
97
+ style={{
98
+ fontSize: 18,
99
+ cursor: "pointer",
100
+ color: "#555",
101
+ transition: "color 0.2s ease",
102
+ }}
103
+ onMouseEnter={(e) =>
104
+ ((e.currentTarget as HTMLElement).style.color =
105
+ colorCode || "#7F28F8")
106
+ }
107
+ onMouseLeave={(e) =>
108
+ ((e.currentTarget as HTMLElement).style.color = "#555")
109
+ }
110
+ />
111
+ </div>
112
+ </div>
113
+
114
+ {/* Scrollable Content */}
115
+ <div
116
+ style={{
117
+ flex: 1,
118
+ overflowY: "auto",
119
+ padding: "16px",
120
+ height:'66%'
121
+
122
+ }}
123
+
124
+ >
125
+ <h3 style={{ fontWeight: 600, marginBottom: 16 }}>
126
+ <ShoppingOutlined style={{ marginRight: 8 }} />
127
+ Your Cart ({items.length})
128
+ </h3>
129
+
130
+ {loading ? (
131
+ <div style={{ textAlign: "center", marginTop: 40 }}>
132
+ <Spin indicator={loadingIcon} />
133
+ </div>
134
+ ) : items.length === 0 ? (
135
+ <div style={{ textAlign: "center", color: "#888", marginTop: 60 }}>
136
+ Your cart is empty 🛒
137
+ </div>
138
+ ) : (
139
+ <div
140
+ style={{
141
+ flex: 1, // fill remaining space
142
+ overflowY: "auto", // scroll only this part
143
+ display: "flex",
144
+ flexDirection: "column",
145
+ height:'80%',
146
+ gap: "12px",
147
+ paddingRight: "4px",
148
+ }}
149
+ >
150
+ {items.map((item) => (
151
+
152
+ <div
153
+ key={item.variantId}
154
+ style={{
155
+ display: "flex",
156
+ justifyContent: "space-between",
157
+ alignItems: "center",
158
+ background: "#fafafa",
159
+ borderRadius: 10,
160
+ padding: "12px 10px",
161
+ transition: "all 0.2s ease",
162
+ }}
163
+ className="hover:shadow-sm"
164
+ >
165
+ {/* ✅ Left side */}
166
+ <div style={{ display: "flex", alignItems: "center", gap: 12 }}>
167
+ <img
168
+ src={item.variantImage}
169
+ alt={item.name}
170
+ style={{
171
+ width: 64,
172
+ height: 64,
173
+ borderRadius: 8,
174
+ objectFit: "cover",
175
+ backgroundColor: "#f3f3f3",
176
+ }}
177
+ />
178
+ <div>
179
+ <p style={{ fontWeight: 600, color: "#222", marginBottom: 4 }}>
180
+ {item.name}
181
+ </p>
182
+ <p style={{ fontSize: 13, color: "#777", margin: 0 }}>
183
+ Qty: {item.quantity}
184
+ </p>
185
+ </div>
186
+ </div>
187
+
188
+ {/* ✅ Right side */}
189
+ <div style={{ display: "flex", alignItems: "center", gap: 12 }}>
190
+ <span style={{ fontWeight: 600 }}>£29.99</span>
191
+ <DeleteOutlined
192
+ onClick={() => handleRemove(item.variantId)}
193
+ style={{
194
+ cursor: "pointer",
195
+ color: "#999",
196
+ fontSize: 16,
197
+ transition: "color 0.2s ease",
198
+ }}
199
+ onMouseEnter={(e) =>
200
+ ((e.currentTarget as HTMLElement).style.color = "#e74c3c")
201
+ }
202
+ onMouseLeave={(e) =>
203
+ ((e.currentTarget as HTMLElement).style.color = "#999")
204
+ }
205
+ />
206
+ </div>
207
+ </div>
208
+
209
+ ))}
210
+ </div>
211
+ )}
212
+
213
+ {/* <Divider style={{ margin: "20px 0" }} /> */}
214
+
215
+ {/* Discount Section */}
216
+ {/* <div style={{ display: "flex", gap: "8px", marginBottom: "16px" }}>
217
+ <Input placeholder="Enter discount code" size="large" />
218
+ <Button
219
+ type="primary"
220
+ size="large"
221
+ style={{
222
+ backgroundColor: colorCode || "black",
223
+ borderColor: colorCode || "black",
224
+ borderRadius: 6,
225
+ }}
226
+ >
227
+ APPLY
228
+ </Button>
229
+ </div> */}
230
+
231
+ {/* Summary */}
232
+
233
+ </div>
234
+
235
+ {/* Sticky Footer */}
236
+ <div
237
+ style={{
238
+ position: "sticky",
239
+ bottom: 0,
240
+ left: 0,
241
+ right: 0,
242
+ background: "#fff",
243
+ borderTop: "1px solid #f0f0f0",
244
+ padding: "16px 20px",
245
+ boxShadow: "0 -3px 10px rgba(0,0,0,0.05)",
246
+ zIndex: 10,
247
+ }}
248
+ >
249
+ <Button
250
+ type="primary"
251
+ block
252
+ size="large"
253
+ onClick={handleCheckout}
254
+ loading={isLoading}
255
+ disabled={items.length === 0}
256
+ style={{
257
+ backgroundColor: colorCode || "black",
258
+ borderColor: colorCode || "black",
259
+ borderRadius: 10,
260
+ fontWeight: 600,
261
+ }}
262
+ >
263
+ <span style={{color:'white'}}>
264
+ CHECKOUT
265
+
266
+ </span>
267
+ </Button>
268
+ </div>
269
+
270
+ {/* Scrollbar */}
271
+ <style>{`
272
+ .custom-scrollbar::-webkit-scrollbar {
273
+ width: 6px;
274
+ }
275
+ .custom-scrollbar::-webkit-scrollbar-thumb {
276
+ background-color: rgba(0,0,0,0.2);
277
+ border-radius: 3px;
278
+ }
279
+ .custom-scrollbar::-webkit-scrollbar-thumb:hover {
280
+ background-color: rgba(0,0,0,0.4);
281
+ }
282
+ `}</style>
283
+ </div>
284
+ );
285
+ };
286
+
287
+ export default CartLayout;
@@ -300,18 +300,23 @@ const ChatInput: React.FC<ChatInputProps> = ({
300
300
  padding: "0"
301
301
  }}
302
302
  onKeyDown={(e) => {
303
- if (e.key === "Enter") {
303
+ if (e.key === "Enter" && !isSending) {
304
304
  e.preventDefault();
305
- if (selectedImage) {
305
+
306
+ const hasImage = !!selectedImage;
307
+ const hasText = !!userMessage.trim();
308
+
309
+ if (hasImage) {
306
310
  handleSendImage(selectedImage, userMessage);
307
311
  removeSelectedImage();
308
312
  setUserMessage("");
309
- } else if (userMessage.trim()) {
313
+ } else if (hasText) {
310
314
  handleSendMessage();
311
315
  setUserMessage("");
312
316
  }
313
317
  }
314
318
  }}
319
+
315
320
  />
316
321
  )}
317
322
  </div>
@@ -22,7 +22,7 @@ interface AssistantMessageProps {
22
22
  colorCode: string;
23
23
  isBusiness?: boolean;
24
24
  disableCheckout?:boolean;
25
- handleAddToCart: (variantId: string, name: string, qty?: number) => Promise<void>;
25
+ handleAddToCart: (variantId: string, name: string,variantImage:string, qty?: number) => Promise<void>;
26
26
  handleRemoveFromCart: (variantId: string, qty?: number) => Promise<void>;
27
27
  }
28
28
 
@@ -20,7 +20,7 @@ interface Props {
20
20
  setSelectedVariants: React.Dispatch<React.SetStateAction<Record<string, string>>>;
21
21
  counts: Record<string, number>;
22
22
  setCounts: React.Dispatch<React.SetStateAction<Record<string, number>>>;
23
- handleAddToCart: (variantId: string, name: string, qty: number) => Promise<void>;
23
+ handleAddToCart: (variantId: string, name: string,variantImage:string, qty?: number) => Promise<void>;
24
24
  handleRemoveFromCart: (variantId: string, qty: number) => Promise<void>;
25
25
  colorCode?: string;
26
26
  shortenName: (name: string) => string;
@@ -88,7 +88,7 @@ const ProductCarousel: FC<Props> = ({
88
88
  ...prev,
89
89
  [currentVariant.variant_id]: (prev[currentVariant.variant_id] || 0) + 1,
90
90
  }));
91
- await handleAddToCart(currentVariant.variant_id, currentVariant.name, 1);
91
+ await handleAddToCart(currentVariant.variant_id,currentVariant.name,currentVariant.image, 1);
92
92
  };
93
93
 
94
94
  const decrement = async () => {
@@ -23,7 +23,7 @@ interface Props {
23
23
  setSelectedVariants: React.Dispatch<React.SetStateAction<Record<string, string>>>;
24
24
  counts: Record<string, number>;
25
25
  setCounts: React.Dispatch<React.SetStateAction<Record<string, number>>>;
26
- handleAddToCart: (variantId: string, name: string, qty?: number) => Promise<void>;
26
+ handleAddToCart: (variantId: string, name: string, variantImage:string, qty?: number) => Promise<void>;
27
27
  handleRemoveFromCart: (variantId: string, qty?: number) => Promise<void>;
28
28
  colorCode?: string;
29
29
  shortenName: (name: string) => string;
@@ -101,11 +101,8 @@ const ProductCarousel: FC<Props> = ({
101
101
  [currentVariant.variant_id]: (prev[currentVariant.variant_id] || 0) + 1,
102
102
  }));
103
103
  try {
104
- // wait for backend to confirm success
105
- await handleAddToCart(currentVariant.variant_id, currentVariant.name, 1);
104
+ await handleAddToCart(currentVariant.variant_id, currentVariant.name,currentVariant.image, 1);
106
105
 
107
- // only update counts if the request succeeded
108
-
109
106
  } catch (err: any) {
110
107
  console.warn("Add to cart failed:", err.message);
111
108
  setCounts(prev => ({
@@ -21,7 +21,7 @@ interface Props {
21
21
  setSelectedVariants: React.Dispatch<React.SetStateAction<Record<string, string>>>;
22
22
  counts: Record<string, number>;
23
23
  setCounts: React.Dispatch<React.SetStateAction<Record<string, number>>>;
24
- handleAddToCart: (variantId: string, name: string, qty: number) => Promise<void>;
24
+ handleAddToCart: (variantId: string, name: string,variantImage:string, qty: number) => Promise<void>;
25
25
  handleRemoveFromCart: (variantId: string, qty: number) => Promise<void>;
26
26
  colorCode?: string; // accent
27
27
  shortenName: (name: string) => string;
@@ -21,7 +21,7 @@ interface Props {
21
21
  setSelectedVariants: React.Dispatch<React.SetStateAction<Record<string, string>>>;
22
22
  counts: Record<string, number>;
23
23
  setCounts: React.Dispatch<React.SetStateAction<Record<string, number>>>;
24
- handleAddToCart: (variantId: string, name: string, qty: number) => Promise<void>;
24
+ handleAddToCart: (variantId: string, name: string, variantImage:string,qty: number) => Promise<void>;
25
25
  handleRemoveFromCart: (variantId: string, qty: number) => Promise<void>;
26
26
  colorCode?: string; // accent
27
27
  shortenName: (name: string) => string;
@@ -33,11 +33,15 @@ interface ChatMessagesProps {
33
33
  messages: Message[];
34
34
  colorCode: string;
35
35
  isLoading: boolean;
36
+
36
37
  handleAddToCart: (
37
38
  variantId: string,
38
39
  name: string,
39
- qty?: number
40
+ variantImage:string,
41
+ qty?: number,
42
+
40
43
  ) => Promise<void>;
44
+
41
45
  handleRemoveFromCart: (variantId: string, qty?: number) => Promise<void>;
42
46
  sessionId:string;
43
47
  isBusiness?: boolean;
@@ -20,7 +20,7 @@ interface AssistantMessageProps {
20
20
  message: string;
21
21
  colorCode: string;
22
22
  isBusiness?: boolean;
23
- handleAddToCart: (variantId: string, name: string, qty?: number) => Promise<void>;
23
+ handleAddToCart: (variantId: string, name: string,variantImage:string, qty?: number) => Promise<void>;
24
24
  handleRemoveFromCart: (variantId: string, qty?: number) => Promise<void>;
25
25
  }
26
26
 
@@ -105,7 +105,7 @@ const SupportConnect: React.FC<SupportConnectProps> = ({
105
105
  >
106
106
  <div className="flex items-center space-x-4">
107
107
  <img
108
- src={data.userImage}
108
+ src={data.userImage || 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSaC0jamaBcOGTbS86459UezKUs2Wo0lPU_mw&s'}
109
109
  alt="User"
110
110
  className="w-12 h-12 rounded-full border-2"
111
111
  style={{ borderColor: colorCode }}
@@ -117,7 +117,7 @@ const SupportConnect: React.FC<SupportConnectProps> = ({
117
117
  </span>
118
118
  </p>
119
119
  <img
120
- src={data.companyImage}
120
+ src={data.companyImage || 'https://cdn-icons-png.flaticon.com/512/4812/4812244.png'}
121
121
  alt="Company"
122
122
  className="w-12 h-12 rounded-full border"
123
123
  />
@@ -20,7 +20,7 @@ interface AssistantMessageProps {
20
20
  message: string;
21
21
  colorCode: string;
22
22
  isBusiness?: boolean;
23
- handleAddToCart: (variantId: string, name: string, qty?: number) => Promise<void>;
23
+ handleAddToCart: (variantId: string, name: string,variantImage:string, qty?: number) => Promise<void>;
24
24
  handleRemoveFromCart: (variantId: string, qty?: number) => Promise<void>;
25
25
  }
26
26
 
@@ -1,6 +1,6 @@
1
1
  import React, { useState,useCallback } from 'react';
2
2
  import { Button, Avatar } from 'antd';
3
- import { CloseOutlined,ArrowLeftOutlined } from '@ant-design/icons';
3
+ import { CloseOutlined,ArrowLeftOutlined,ShoppingCartOutlined} from '@ant-design/icons';
4
4
  import '../../Chatbot.css';
5
5
  import { useChatbotMessage } from '../../../hooks/useSessionMessages';
6
6
  import axios from 'axios';
@@ -14,7 +14,7 @@ import type { ChatMessage } from '../../../types/chatbot';
14
14
  import { getCookie } from '../../../utils/cookies';
15
15
  import useChatSocket from '../../../hooks/useWebsocke';
16
16
  import Notification from '../Notification';
17
- import CartWidget from '../Messages/CartWidget';
17
+ // import CartWidget from '../Messages/CartWidget';
18
18
  import { useCart } from '../../../hooks/useCart';
19
19
 
20
20
  type MessengerProps = {
@@ -24,10 +24,11 @@ type MessengerProps = {
24
24
  colorCode: string;
25
25
  newSession: boolean;
26
26
  messagesSuggestions: string[];
27
+ setMessagesSuggestions: React.Dispatch<React.SetStateAction<string[]>>;
27
28
  disableForm: boolean;
28
29
  sessionId:string;
29
30
  setOpen: (v: boolean) => void;
30
- setView: (v: string) => void;
31
+ setView: React.Dispatch<React.SetStateAction<'sessions' | 'create' | 'messenger' | 'cartView'>>;
31
32
  setNewSession: (v: boolean) => void;
32
33
  Opened: boolean;
33
34
  calendly:string;
@@ -52,6 +53,7 @@ const Messenger: React.FC<MessengerProps> = ({
52
53
  userType,
53
54
  setNewSession,
54
55
  messagesSuggestions,
56
+ setMessagesSuggestions,
55
57
  disableForm,
56
58
  sessionId,
57
59
  setOpen,
@@ -168,7 +170,10 @@ const socket = useChatSocket(sessionId, handleSocketData);
168
170
  const sendMessageSuggestion = async (message: string): Promise<void> => {
169
171
  if (!message.trim()) return;
170
172
 
171
- setIsSending(true); // 🔒 Disable input
173
+ setIsSending(true);
174
+
175
+ // Remove only the clicked suggestion
176
+ setMessagesSuggestions(prev => prev.filter(suggestion => suggestion !== message));
172
177
 
173
178
  const userMsg: ChatMessage = { role: 'user', content: message };
174
179
  setMessages(prev => [...prev, userMsg]);
@@ -187,10 +192,12 @@ const socket = useChatSocket(sessionId, handleSocketData);
187
192
  } catch (error) {
188
193
  console.error("Error sending suggestion:", error);
189
194
  } finally {
190
- setIsSending(false); // 🔓 Re-enable input
195
+ setIsSending(false);
191
196
  }
192
197
  };
193
198
 
199
+
200
+
194
201
 
195
202
 
196
203
  async function handleSendImage (image: File, userMessage:string) {
@@ -398,7 +405,7 @@ const socket = useChatSocket(sessionId, handleSocketData);
398
405
  }
399
406
  };
400
407
 
401
- const { items, loading, addToCart, removeFromCart, refresh } = useCart(sessionId);
408
+ const { items, addToCart, removeFromCart } = useCart(sessionId);
402
409
 
403
410
 
404
411
  // replace your old handleToCart:
@@ -407,9 +414,9 @@ const socket = useChatSocket(sessionId, handleSocketData);
407
414
  }
408
415
 
409
416
  const handleToCart = useCallback(
410
- async (variantId: string, name: string, qty = 1) => {
417
+ async (variantId: string, name: string, variantImage: string, qty = 1) => {
411
418
  try {
412
- await addToCart(variantId, name, qty);
419
+ await addToCart(variantId, name, qty, variantImage);
413
420
 
414
421
  const shortName = shorten(name, 20);
415
422
  setNotification(`✅ ${qty}× ${shortName} added to cart`);
@@ -420,6 +427,7 @@ const socket = useChatSocket(sessionId, handleSocketData);
420
427
  [addToCart]
421
428
  );
422
429
 
430
+
423
431
  const handleRemoveFromCart = useCallback(
424
432
  async (variantId: string, qty = 1) => {
425
433
  await removeFromCart(variantId, qty);
@@ -452,18 +460,59 @@ const socket = useChatSocket(sessionId, handleSocketData);
452
460
  <span className="chatbot-title">{agentName || 'Ai Assistant'}</span>
453
461
 
454
462
  {items.length > 0 && (
455
- <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
456
- <CartWidget
457
- items={items}
458
- loading={loading}
459
- sessionId={sessionId}
460
- onRefresh={refresh}
461
- onRemove={removeFromCart}
462
- colorCode={colorCode}
463
- sendMessage={sendMessageSuggestion}
464
- />
465
- </div>
466
- )}
463
+ <div
464
+ style={{
465
+ position: "relative",
466
+ display: "flex",
467
+ alignItems: "center",
468
+ justifyContent: "center",
469
+ marginLeft: "auto",
470
+ marginRight: 12,
471
+ }}
472
+ >
473
+ <ShoppingCartOutlined
474
+ onClick={() => setView("cartView")}
475
+ style={{
476
+ fontSize: 26,
477
+ cursor: "pointer",
478
+ color: "#333",
479
+ padding: 6,
480
+ borderRadius: "50%",
481
+ transition: "0.2s",
482
+ }}
483
+ onMouseEnter={(e) => {
484
+ (e.currentTarget as HTMLElement).style.background = "rgba(0,0,0,0.05)";
485
+ }}
486
+ onMouseLeave={(e) => {
487
+ (e.currentTarget as HTMLElement).style.background = "transparent";
488
+ }}
489
+ />
490
+
491
+ {/* Counter Badge */}
492
+ <span
493
+ style={{
494
+ position: "absolute",
495
+ top: 2,
496
+ right: 2,
497
+ backgroundColor: colorCode || "#7F28F8",
498
+ color: "white",
499
+ fontSize: 10,
500
+ fontWeight: 600,
501
+ width: 18,
502
+ height: 18,
503
+ borderRadius: "50%",
504
+ display: "flex",
505
+ alignItems: "center",
506
+ justifyContent: "center",
507
+ boxShadow: "0 1px 3px rgba(0,0,0,0.3)",
508
+ }}
509
+ >
510
+ {items.length}
511
+ </span>
512
+ </div>
513
+ )}
514
+
515
+
467
516
 
468
517
 
469
518
  {/* Close Button */}