shopify-chatbot-widget 0.7.9 β†’ 0.8.2

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 +3 -3
  3. package/package.json +1 -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 +111 -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,259 @@
1
+ import React, { useState,useEffect } from 'react';
2
+ import { Button } from 'antd';
3
+
4
+ import { useChatbotData } from '../hooks/useChatbotData';
5
+ import ChatSessions from './components/Sessions/RenderList';
6
+ import CreateSession from './components/Sessions/CreateSession';
7
+ import Messenger from './components/Messenger/Messenger';
8
+ import './Chatbot.css'
9
+ import config from '../hooks/config';
10
+ import FingerprintJS from '@fingerprintjs/fingerprintjs';
11
+
12
+ const Chatbot: React.FC = () => {
13
+ const [open, setOpen] = useState(false);
14
+ const [viewMode, setViewMode] = useState<'sessions' | 'create' | 'messenger'>('sessions');
15
+ const [activeSessionId, setActiveSessionId] = useState<string | null>(null);
16
+ const [HasInfo,setHasInfo]=useState(false)
17
+ const [activeAgentName,setActiveAgentName]=useState('')
18
+ const [activeAgentImage,setActiveAgentImage]=useState('')
19
+ const [newSession,setNewSession]=useState(false)
20
+
21
+
22
+ const windowWidth = window.innerWidth;
23
+
24
+ const {
25
+ chatbotLogo,
26
+ colorCode,
27
+ subscription,
28
+ messagesSuggestions,
29
+ isFetchingDetails,
30
+ disableForm,
31
+ merchantPhone,
32
+ userType,
33
+ calendly,
34
+ disbleCheckout
35
+ } = useChatbotData();
36
+
37
+ const [visitorData, setVisitorData] = useState<{ visitorId: string; country: string } | null>(null);
38
+
39
+
40
+ const handleNewSessionClick = () => {
41
+ // If the form is *not* disabled, always go to create
42
+ if (!disableForm && !HasInfo) {
43
+ setViewMode('create');
44
+ return;
45
+ }
46
+
47
+ else {
48
+ const newSessionId = crypto.randomUUID();
49
+ setActiveSessionId(newSessionId);
50
+ setActiveAgentImage(chatbotLogo);
51
+ setActiveAgentName('Ai Agent');
52
+ setNewSession(true);
53
+ setViewMode('messenger');
54
+ }
55
+
56
+ // Otherwise (disableForm true && !HasInfo) we simply bail.
57
+ };
58
+
59
+ useEffect(() => {
60
+ const fetchVisitorInfo = async () => {
61
+ try {
62
+ let visitorId = localStorage.getItem('visitor_id');
63
+ let ip = localStorage.getItem('ip_address');
64
+ let country = localStorage.getItem('country');
65
+
66
+ // βœ… If all cached, safely set and exit
67
+ // if (visitorId && ip && country) {
68
+ // setVisitorData({ visitorId, country });
69
+
70
+ // return;
71
+ // }
72
+
73
+ // πŸ” Generate fingerprint if needed
74
+ if (!visitorId) {
75
+ const fp = await FingerprintJS.load();
76
+ const result = await fp.get();
77
+ visitorId = result.visitorId;
78
+ localStorage.setItem('visitor_id', visitorId);
79
+ }
80
+
81
+ // 🌍 Fetch IP info if missing
82
+ if (!ip || !country) {
83
+ const res = await fetch('https://ipapi.co/json');
84
+ const data = await res.json();
85
+ ip = data.ip;
86
+ country = data.country_name;
87
+
88
+ if (ip) localStorage.setItem('ip_address', ip);
89
+ if (country) localStorage.setItem('country', country);
90
+ }
91
+
92
+ // βœ… Ensure values are non-null before use
93
+ if (visitorId && ip && country) {
94
+ setVisitorData({ visitorId, country });
95
+
96
+ // πŸ“‘ Send to backend
97
+ const backendRes = await fetch(`${config.apiUrl}register-ip/`, {
98
+ method: 'POST',
99
+ headers: {
100
+ 'Content-Type': 'application/json',
101
+ },
102
+ body: JSON.stringify({
103
+ ip_address: ip,
104
+ country,
105
+ visitor_id: visitorId,
106
+ }),
107
+ });
108
+
109
+ const result = await backendRes.json();
110
+ setHasInfo(result.has_user_info || false);
111
+ } else {
112
+ console.warn('Missing IP or country info after fetch');
113
+ }
114
+ } catch (err) {
115
+ console.error('Failed to fetch or send visitor info', err);
116
+ }
117
+ };
118
+
119
+ fetchVisitorInfo();
120
+ }, []);
121
+
122
+
123
+
124
+
125
+
126
+ const handleSessionSelect = (sessionId: string,agentName:string,agentImage:string) => {
127
+ setActiveSessionId(sessionId);
128
+ setActiveAgentName(agentName)
129
+ setActiveAgentImage(agentImage)
130
+ setNewSession(false)
131
+ setViewMode('messenger');
132
+ };
133
+
134
+
135
+ useEffect(() => {
136
+ const onMessage = (e: MessageEvent) => {
137
+ const msg = (e.data || {}) as any;
138
+ if (msg.type !== 'JAWEB_CHAT') return;
139
+
140
+ if (msg.action === 'open-ready') {
141
+ // Parent has expanded iframe β†’ now we can render full UI
142
+ setOpen(true);
143
+ } else if (msg.action === 'closed') {
144
+ // Parent collapsed iframe β†’ hide full UI
145
+ setOpen(false);
146
+ }
147
+ };
148
+ window.addEventListener('message', onMessage);
149
+ return () => window.removeEventListener('message', onMessage);
150
+ }, []);
151
+
152
+ const requestOpen = () => {
153
+ // Ask parent to expand iframe
154
+ window.parent?.postMessage({ type: 'JAWEB_CHAT', action: 'open' }, '*');
155
+ };
156
+ const requestClose = () => {
157
+ // Ask parent to collapse iframe
158
+ window.parent?.postMessage({ type: 'JAWEB_CHAT', action: 'close' }, '*');
159
+ };
160
+
161
+
162
+
163
+
164
+ return (
165
+ <div>
166
+ {!isFetchingDetails && subscription ? (
167
+ <div
168
+ style={{
169
+ bottom: windowWidth < 768 ? '20%' : 0,
170
+ top: windowWidth < 768 ? '0' : '5%',
171
+ height: windowWidth < 768 ? '100%' : '85%',
172
+ borderRadius: 10,
173
+ width: '100%',
174
+ zIndex: 9999,
175
+ }}
176
+ >
177
+ {open && (
178
+ <div className="chatbot-box">
179
+ {viewMode === 'sessions' && (
180
+ <ChatSessions
181
+ chatbotLogo={chatbotLogo}
182
+ Phone={merchantPhone || ''}
183
+ colorCode={colorCode}
184
+ visitorId={visitorData?.visitorId || ''}
185
+ Opened={open}
186
+ // when a child wants to close, talk to parent
187
+ setOpen={(v: boolean) => (v ? requestOpen() : requestClose())}
188
+ onNewSession={handleNewSessionClick}
189
+ onSessionSelect={handleSessionSelect}
190
+ />
191
+ )}
192
+
193
+ {viewMode === 'create' && (
194
+ <CreateSession
195
+ colorCode={colorCode}
196
+ visitorId={visitorData?.visitorId || ''}
197
+ country={visitorData?.country || ''}
198
+ onBack={() => setViewMode('sessions')}
199
+ onCreate={(userData) => {
200
+ setActiveSessionId(userData.session_id);
201
+ setHasInfo(userData.hasInfo);
202
+ setViewMode('messenger');
203
+ }}
204
+ />
205
+ )}
206
+
207
+ {viewMode === 'messenger' && activeSessionId && (
208
+ <Messenger
209
+ sessionId={activeSessionId}
210
+ chatbotLogo={activeAgentImage || chatbotLogo}
211
+ agentName={activeAgentName || 'Ai Assistant'}
212
+ colorCode={colorCode}
213
+ messagesSuggestions={messagesSuggestions}
214
+ newSession={newSession}
215
+ disableForm={disableForm}
216
+ calendly={calendly ?? ''}
217
+ // children call this to close/open β†’ routed to parent
218
+ setOpen={(v: boolean) => (v ? requestOpen() : requestClose())}
219
+ setNewSession={setNewSession}
220
+ Opened={open}
221
+ setView={() => setViewMode('sessions')}
222
+ userType={userType}
223
+ disbleCheckout={disbleCheckout}
224
+ />
225
+ )}
226
+ </div>
227
+ )}
228
+ </div>
229
+ ) : null}
230
+
231
+ <div className="jaweb-chatbot-container">
232
+ {!isFetchingDetails && subscription ? (
233
+ <Button
234
+ type="primary"
235
+ shape="circle"
236
+ icon={
237
+ <img
238
+ src="https://jaweb.me/wp-content/uploads/2025/03/download__2_-removebg-preview.png"
239
+ alt="Chat Icon"
240
+ style={{ width: 30, height: 30 }}
241
+ />
242
+ }
243
+ size="large"
244
+ style={{ backgroundColor: colorCode, width: 60, height: 60 }}
245
+ className={`chat-launcher ${open ? 'chatbot-open' : ''}`}
246
+ // πŸ”‘ Don’t setOpen directly; request parent resize
247
+ onClick={() => (open ? requestClose() : requestOpen())}
248
+ />
249
+ ) : null}
250
+ </div>
251
+ </div>
252
+ );
253
+ };
254
+
255
+ export default Chatbot;
256
+
257
+
258
+
259
+
@@ -0,0 +1,127 @@
1
+ .jawebcss-chat-input-container {
2
+ display: flex;
3
+ align-items: center;
4
+ background-color: white;
5
+ border: 1px solid #d1d5db;
6
+ border-radius: 9999px;
7
+ padding: 0.5rem 0.75rem;
8
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
9
+ width: 95%;
10
+ height: 56px;
11
+ }
12
+
13
+ .jawebcss-chat-icon-button {
14
+ color: #6b7280;
15
+ background: none;
16
+ border: none;
17
+ margin: 0 0.5rem;
18
+ cursor: pointer;
19
+ }
20
+
21
+ .jawebcss-chat-icon-button:hover {
22
+ color: #374151;
23
+ }
24
+
25
+ .jawebcss-chat-icon-button.recording {
26
+ color: #ef4444;
27
+ }
28
+
29
+ .jawebcss-hidden-input {
30
+ display: none;
31
+ }
32
+
33
+ .jawebcss-image-preview-wrapper {
34
+ position: relative;
35
+ }
36
+
37
+ .jawebcss-image-preview {
38
+ width: 2rem;
39
+ height: 2rem;
40
+ border-radius: 9999px;
41
+ object-fit: cover;
42
+ }
43
+
44
+ .jawebcss-remove-image-icon {
45
+ position: absolute;
46
+ top: -0.5rem;
47
+ right: -0.5rem;
48
+ font-size: 14px;
49
+ color: #ef4444;
50
+ background: white;
51
+ border-radius: 9999px;
52
+ cursor: pointer;
53
+ }
54
+
55
+ .jawebcss-chat-input-wrapper {
56
+ flex: 1;
57
+ margin: 0 0.5rem;
58
+ min-width: 0;
59
+ max-width: 100%;
60
+ display: flex;
61
+ align-items: center;
62
+ }
63
+
64
+ .jawebcss-text-input {
65
+ width: 100%;
66
+ border: none;
67
+ font-size: 16px;
68
+ line-height: 1.5;
69
+ color: #374151;
70
+ }
71
+
72
+ .jawebcss-text-input:focus {
73
+ outline: none;
74
+ box-shadow: none;
75
+ }
76
+
77
+
78
+
79
+
80
+ .jawebcss-audio-preview {
81
+ display: flex;
82
+ align-items: center;
83
+ width: 100%;
84
+ background-color: #f3f4f6;
85
+ padding: 0.5rem 1rem;
86
+ border-radius: 0.5rem;
87
+ }
88
+
89
+ .jawebcss-audio-play-button {
90
+ background: none;
91
+ border: none;
92
+ margin-right: 0.75rem;
93
+ color: #7f28f8;
94
+ cursor: pointer;
95
+ }
96
+
97
+ .jawebcss-remove-audio-icon {
98
+ font-size: 18px;
99
+ color: #ef4444;
100
+ margin-left: 0.75rem;
101
+ cursor: pointer;
102
+ }
103
+
104
+ .jawebcss-waveform {
105
+ width: 100%;
106
+ height: 2rem;
107
+ }
108
+
109
+ .jawebcss-recording-indicator {
110
+ display: flex;
111
+ align-items: center;
112
+ justify-content: center;
113
+ background-color: #f3f4f6;
114
+ padding: 0.5rem 1rem;
115
+ border-radius: 0.5rem;
116
+ animation: pulse 2s infinite;
117
+ }
118
+
119
+ @keyframes pulse {
120
+ 0%, 100% {
121
+ opacity: 1;
122
+ }
123
+ 50% {
124
+ opacity: 0.5;
125
+ }
126
+ }
127
+