shopify-chatbot-widget 0.0.4 → 0.2.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.
- package/dist/jaweb-chatbot.css +1 -0
- package/dist/jaweb-chatbot.iife.js +685 -0
- package/dist/vite.svg +1 -0
- package/package.json +1 -1
- package/src/App.css +0 -42
- package/src/App.tsx +0 -13
- package/src/Chatbot/Chatbot.css +0 -154
- package/src/Chatbot/Chatbot.tsx +0 -207
- package/src/Chatbot/components/ChatInput.css +0 -127
- package/src/Chatbot/components/ChatInput.tsx +0 -262
- package/src/Chatbot/components/Messages/Addcart.tsx +0 -70
- package/src/Chatbot/components/Messages/AgentStatus.tsx +0 -37
- package/src/Chatbot/components/Messages/AssistantMesage.tsx +0 -316
- package/src/Chatbot/components/Messages/AudioMessage.tsx +0 -123
- package/src/Chatbot/components/Messages/CartWidget.tsx +0 -116
- package/src/Chatbot/components/Messages/ChatImage.tsx +0 -46
- package/src/Chatbot/components/Messages/ChatImageText.tsx +0 -74
- package/src/Chatbot/components/Messages/ChatImageTextAssis.tsx +0 -72
- package/src/Chatbot/components/Messages/ChatMessages.css +0 -5
- package/src/Chatbot/components/Messages/ChatMessages.tsx +0 -284
- package/src/Chatbot/components/Messages/Support.tsx +0 -177
- package/src/Chatbot/components/Messages/Typing.css +0 -27
- package/src/Chatbot/components/Messages/Typing.tsx +0 -14
- package/src/Chatbot/components/Messages/ZidAssistantMesage.tsx +0 -142
- package/src/Chatbot/components/Messenger/Messenger.tsx +0 -521
- package/src/Chatbot/components/Notification.tsx +0 -27
- package/src/Chatbot/components/Powered.css +0 -16
- package/src/Chatbot/components/Powered.tsx +0 -13
- package/src/Chatbot/components/Sessions/CreateSession.tsx +0 -139
- package/src/Chatbot/components/Sessions/RenderList.tsx +0 -202
- package/src/Chatbot/components/Suggestions.css +0 -34
- package/src/Chatbot/components/Suggestions.tsx +0 -28
- package/src/assets/react.svg +0 -1
- package/src/chatbot-widget/index.tsx +0 -14
- package/src/hooks/config.tsx +0 -13
- package/src/hooks/useCart.tsx +0 -99
- package/src/hooks/useChatbotAPI.tsx +0 -160
- package/src/hooks/useChatbotData.tsx +0 -129
- package/src/hooks/useSessionMessages.tsx +0 -51
- package/src/hooks/useWebsocke.tsx +0 -45
- package/src/i18n.tsx +0 -30
- package/src/index.css +0 -1
- package/src/main.tsx +0 -10
- package/src/types/chatbot.ts +0 -38
- package/src/utils/cookies.tsx +0 -14
- package/src/vite-env.d.ts +0 -1
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
import React, { useEffect, useRef, useState } from "react";
|
|
2
|
-
import WaveSurfer from "wavesurfer.js";
|
|
3
|
-
import {
|
|
4
|
-
PlayCircleOutlined,
|
|
5
|
-
PauseCircleOutlined
|
|
6
|
-
} from "@ant-design/icons";
|
|
7
|
-
|
|
8
|
-
interface AudioVisualizerProps {
|
|
9
|
-
link: string;
|
|
10
|
-
colorCode: string;
|
|
11
|
-
transcription?: string;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const AudioVisualizer: React.FC<AudioVisualizerProps> = ({
|
|
15
|
-
link,
|
|
16
|
-
colorCode,
|
|
17
|
-
transcription,
|
|
18
|
-
}) => {
|
|
19
|
-
const audioRef = useRef<HTMLDivElement | null>(null);
|
|
20
|
-
const wavesurferRef = useRef<WaveSurfer | null>(null);
|
|
21
|
-
const [isPlaying, setIsPlaying] = useState(false);
|
|
22
|
-
const [showTranscription, setShowTranscription] = useState(false);
|
|
23
|
-
|
|
24
|
-
useEffect(() => {
|
|
25
|
-
if (!audioRef.current) return;
|
|
26
|
-
|
|
27
|
-
wavesurferRef.current?.destroy();
|
|
28
|
-
|
|
29
|
-
wavesurferRef.current = WaveSurfer.create({
|
|
30
|
-
container: audioRef.current,
|
|
31
|
-
waveColor: "white",
|
|
32
|
-
progressColor: "white",
|
|
33
|
-
cursorWidth: 0,
|
|
34
|
-
barWidth: 3,
|
|
35
|
-
barHeight: 1.5,
|
|
36
|
-
barGap: 2,
|
|
37
|
-
height: 40,
|
|
38
|
-
interact: true,
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
wavesurferRef.current.load(link);
|
|
42
|
-
wavesurferRef.current.on("finish", () => setIsPlaying(false));
|
|
43
|
-
|
|
44
|
-
return () => {
|
|
45
|
-
wavesurferRef.current?.destroy();
|
|
46
|
-
};
|
|
47
|
-
}, [link, colorCode]);
|
|
48
|
-
|
|
49
|
-
const togglePlay = () => {
|
|
50
|
-
if (wavesurferRef.current) {
|
|
51
|
-
wavesurferRef.current.playPause();
|
|
52
|
-
setIsPlaying((prev) => !prev);
|
|
53
|
-
}
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
return (
|
|
57
|
-
<div
|
|
58
|
-
style={{
|
|
59
|
-
backgroundColor:colorCode,
|
|
60
|
-
padding: "12px",
|
|
61
|
-
borderRadius: "20px",
|
|
62
|
-
color: "white",
|
|
63
|
-
maxWidth: "350px",
|
|
64
|
-
marginBottom: "16px",
|
|
65
|
-
}}
|
|
66
|
-
>
|
|
67
|
-
<div style={{ display: "flex", alignItems: "center" }}>
|
|
68
|
-
<button
|
|
69
|
-
onClick={togglePlay}
|
|
70
|
-
style={{
|
|
71
|
-
background: "transparent",
|
|
72
|
-
border: "none",
|
|
73
|
-
color: "white",
|
|
74
|
-
marginRight: "12px",
|
|
75
|
-
cursor: "pointer",
|
|
76
|
-
}}
|
|
77
|
-
>
|
|
78
|
-
{isPlaying ? (
|
|
79
|
-
<PauseCircleOutlined style={{ fontSize: "24px" }} />
|
|
80
|
-
) : (
|
|
81
|
-
<PlayCircleOutlined style={{ fontSize: "24px" }} />
|
|
82
|
-
)}
|
|
83
|
-
</button>
|
|
84
|
-
|
|
85
|
-
<div
|
|
86
|
-
ref={audioRef}
|
|
87
|
-
style={{
|
|
88
|
-
width: "130px",
|
|
89
|
-
height: "40px",
|
|
90
|
-
overflow: "hidden",
|
|
91
|
-
color:'white'
|
|
92
|
-
}}
|
|
93
|
-
/>
|
|
94
|
-
|
|
95
|
-
</div>
|
|
96
|
-
|
|
97
|
-
{transcription && (
|
|
98
|
-
<div style={{ marginTop: "12px", fontSize: "14px", color: "rgba(255,255,255,0.85)" }}>
|
|
99
|
-
<button
|
|
100
|
-
onClick={() => setShowTranscription(!showTranscription)}
|
|
101
|
-
style={{
|
|
102
|
-
background: "none",
|
|
103
|
-
border: "none",
|
|
104
|
-
color: "white",
|
|
105
|
-
textDecoration: "underline",
|
|
106
|
-
fontSize: "13px",
|
|
107
|
-
cursor: "pointer",
|
|
108
|
-
padding: 0,
|
|
109
|
-
}}
|
|
110
|
-
>
|
|
111
|
-
{showTranscription ? "Hide transcript" : "Show transcript"}
|
|
112
|
-
</button>
|
|
113
|
-
|
|
114
|
-
{showTranscription && (
|
|
115
|
-
<p style={{ marginTop: "6px", lineHeight: "1.4" }}>{transcription}</p>
|
|
116
|
-
)}
|
|
117
|
-
</div>
|
|
118
|
-
)}
|
|
119
|
-
</div>
|
|
120
|
-
);
|
|
121
|
-
};
|
|
122
|
-
|
|
123
|
-
export default AudioVisualizer;
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
// src/components/Messages/CartWidget.tsx
|
|
2
|
-
import { useState, useRef, useEffect } from 'react';
|
|
3
|
-
import type { CartItem } from '../../../hooks/useCart';
|
|
4
|
-
import { ShoppingCartOutlined, CloseOutlined } from '@ant-design/icons';
|
|
5
|
-
import { Button } from 'antd';
|
|
6
|
-
|
|
7
|
-
interface Props {
|
|
8
|
-
items: CartItem[];
|
|
9
|
-
colorCode:string;
|
|
10
|
-
loading: boolean;
|
|
11
|
-
onRefresh: () => void;
|
|
12
|
-
onRemove: (variantId: string, qty: number) => void;
|
|
13
|
-
sendMessage: (message: string) => Promise<void>;
|
|
14
|
-
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export default function CartWidget({
|
|
18
|
-
items,
|
|
19
|
-
loading,
|
|
20
|
-
colorCode,
|
|
21
|
-
onRefresh,
|
|
22
|
-
onRemove,
|
|
23
|
-
sendMessage
|
|
24
|
-
}: Props) {
|
|
25
|
-
const [open, setOpen] = useState(false);
|
|
26
|
-
const containerRef = useRef<HTMLDivElement>(null);
|
|
27
|
-
|
|
28
|
-
useEffect(() => {
|
|
29
|
-
const handleClickOutside = (e: MouseEvent) => {
|
|
30
|
-
if (
|
|
31
|
-
containerRef.current &&
|
|
32
|
-
!containerRef.current.contains(e.target as Node)
|
|
33
|
-
) {
|
|
34
|
-
setOpen(false);
|
|
35
|
-
}
|
|
36
|
-
};
|
|
37
|
-
document.addEventListener('mousedown', handleClickOutside);
|
|
38
|
-
return () => document.removeEventListener('mousedown', handleClickOutside);
|
|
39
|
-
}, []);
|
|
40
|
-
|
|
41
|
-
const totalCount = items.reduce((sum, i) => sum + i.quantity, 0);
|
|
42
|
-
|
|
43
|
-
return (
|
|
44
|
-
<div className="relative inline-block" ref={containerRef}>
|
|
45
|
-
<button
|
|
46
|
-
onClick={() => setOpen(o => !o)}
|
|
47
|
-
className="flex items-center space-x-1 px-3 py-1 hover:bg-gray-100 rounded-md"
|
|
48
|
-
>
|
|
49
|
-
<ShoppingCartOutlined className="text-xl" />
|
|
50
|
-
<span className="font-semibold">Cart ({totalCount})</span>
|
|
51
|
-
</button>
|
|
52
|
-
|
|
53
|
-
{open && (
|
|
54
|
-
<div className="absolute right-0 mt-4 w-80 bg-white border border-gray-200 rounded-lg shadow-lg z-50">
|
|
55
|
-
{/* Header */}
|
|
56
|
-
<div className="flex items-center justify-between px-4 py-2 border-b border-gray-100">
|
|
57
|
-
<span className="text-lg font-medium">Your Cart</span>
|
|
58
|
-
<button
|
|
59
|
-
onClick={onRefresh}
|
|
60
|
-
disabled={loading}
|
|
61
|
-
className="text-sm text-blue-600 hover:underline disabled:opacity-50"
|
|
62
|
-
>
|
|
63
|
-
{loading ? 'Refreshing…' : 'Refresh'}
|
|
64
|
-
</button>
|
|
65
|
-
</div>
|
|
66
|
-
|
|
67
|
-
{/* Concatenated-name summary */}
|
|
68
|
-
|
|
69
|
-
{/* Items list */}
|
|
70
|
-
{items.length === 0 ? (
|
|
71
|
-
<div className="p-4 text-center text-gray-500">
|
|
72
|
-
Your cart is empty.
|
|
73
|
-
</div>
|
|
74
|
-
) : (
|
|
75
|
-
<ul className="max-h-60 overflow-auto">
|
|
76
|
-
{items.map(i => (
|
|
77
|
-
<li
|
|
78
|
-
key={i.variantId}
|
|
79
|
-
className="flex items-center justify-between px-4 py-2 hover:bg-gray-50"
|
|
80
|
-
>
|
|
81
|
-
{/* Fixed-width, truncated name */}
|
|
82
|
-
<span className="inline-block w-40 text-sm font-medium truncate">
|
|
83
|
-
{i.name}
|
|
84
|
-
</span>
|
|
85
|
-
|
|
86
|
-
<div className="flex items-center space-x-2">
|
|
87
|
-
<span className="text-sm text-gray-700">×{i.quantity}</span>
|
|
88
|
-
<CloseOutlined
|
|
89
|
-
onClick={() => onRemove(i.variantId, i.quantity)}
|
|
90
|
-
className="text-red-500 hover:text-red-700 cursor-pointer"
|
|
91
|
-
/>
|
|
92
|
-
</div>
|
|
93
|
-
</li>
|
|
94
|
-
))}
|
|
95
|
-
</ul>
|
|
96
|
-
)}
|
|
97
|
-
|
|
98
|
-
{/* Footer */}
|
|
99
|
-
{items.length > 0 && (
|
|
100
|
-
<div className="px-4 py-3 border-t border-gray-100">
|
|
101
|
-
<Button
|
|
102
|
-
type="primary"
|
|
103
|
-
style={{backgroundColor:colorCode}}
|
|
104
|
-
block
|
|
105
|
-
disabled={totalCount === 0}
|
|
106
|
-
onClick={() => sendMessage('I want to Checkout')}
|
|
107
|
-
>
|
|
108
|
-
Checkout ({totalCount})
|
|
109
|
-
</Button>
|
|
110
|
-
</div>
|
|
111
|
-
)}
|
|
112
|
-
</div>
|
|
113
|
-
)}
|
|
114
|
-
</div>
|
|
115
|
-
);
|
|
116
|
-
}
|
|
@@ -1,46 +0,0 @@
|
|
|
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;
|
|
@@ -1,74 +0,0 @@
|
|
|
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;
|
|
@@ -1,72 +0,0 @@
|
|
|
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;
|