ajaxter-chat 1.0.3 → 2.0.1
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 +96 -204
- package/dist/components/ChatScreen/index.d.ts +12 -0
- package/dist/components/ChatScreen/index.js +83 -0
- package/dist/components/ChatWidget.d.ts +0 -24
- package/dist/components/ChatWidget.js +129 -38
- package/dist/components/HomeScreen/index.d.ts +9 -0
- package/dist/components/HomeScreen/index.js +71 -0
- package/dist/components/MaintenanceView/index.d.ts +1 -1
- package/dist/components/MaintenanceView/index.js +15 -52
- package/dist/components/RecentChatsScreen/index.d.ts +16 -0
- package/dist/components/RecentChatsScreen/index.js +38 -0
- package/dist/components/Tabs/BottomTabs.d.ts +10 -0
- package/dist/components/Tabs/BottomTabs.js +29 -0
- package/dist/components/TicketScreen/index.d.ts +9 -0
- package/dist/components/TicketScreen/index.js +71 -0
- package/dist/components/UserListScreen/index.d.ts +13 -0
- package/dist/components/UserListScreen/index.js +64 -0
- package/dist/config/index.d.ts +0 -13
- package/dist/config/index.js +20 -95
- package/dist/hooks/useChat.d.ts +3 -7
- package/dist/hooks/useChat.js +8 -30
- package/dist/hooks/useUsers.d.ts +3 -10
- package/dist/hooks/useUsers.js +5 -11
- package/dist/index.d.ts +8 -7
- package/dist/index.js +7 -12
- package/dist/services/userService.d.ts +0 -5
- package/dist/services/userService.js +6 -15
- package/dist/src/components/ChatScreen/index.d.ts +12 -0
- package/dist/src/components/ChatScreen/index.js +83 -0
- package/dist/src/components/ChatWidget.d.ts +4 -0
- package/dist/src/components/ChatWidget.js +141 -0
- package/dist/src/components/HomeScreen/index.d.ts +9 -0
- package/dist/src/components/HomeScreen/index.js +71 -0
- package/dist/src/components/MaintenanceView/index.d.ts +7 -0
- package/dist/src/components/MaintenanceView/index.js +16 -0
- package/dist/src/components/RecentChatsScreen/index.d.ts +16 -0
- package/dist/src/components/RecentChatsScreen/index.js +38 -0
- package/dist/src/components/Tabs/BottomTabs.d.ts +10 -0
- package/dist/src/components/Tabs/BottomTabs.js +29 -0
- package/dist/src/components/TicketScreen/index.d.ts +9 -0
- package/dist/src/components/TicketScreen/index.js +71 -0
- package/dist/src/components/UserListScreen/index.d.ts +13 -0
- package/dist/src/components/UserListScreen/index.js +64 -0
- package/dist/src/config/index.d.ts +3 -0
- package/dist/src/config/index.js +38 -0
- package/dist/src/hooks/useChat.d.ts +8 -0
- package/dist/src/hooks/useChat.js +26 -0
- package/dist/src/hooks/useUsers.d.ts +7 -0
- package/dist/src/hooks/useUsers.js +26 -0
- package/dist/src/index.d.ts +14 -0
- package/dist/src/index.js +13 -0
- package/dist/src/services/userService.d.ts +2 -0
- package/dist/src/services/userService.js +9 -0
- package/dist/src/types/index.d.ts +59 -0
- package/dist/src/types/index.js +1 -0
- package/dist/src/utils/theme.d.ts +3 -0
- package/dist/src/utils/theme.js +13 -0
- package/dist/types/index.d.ts +23 -36
- package/dist/utils/theme.d.ts +0 -1
- package/dist/utils/theme.js +3 -18
- package/package.json +10 -20
- package/src/components/ChatScreen/index.tsx +205 -0
- package/src/components/ChatWidget.tsx +327 -0
- package/src/components/HomeScreen/index.tsx +130 -0
- package/src/components/MaintenanceView/index.tsx +41 -0
- package/src/components/RecentChatsScreen/index.tsx +108 -0
- package/src/components/Tabs/BottomTabs.tsx +82 -0
- package/src/components/TicketScreen/index.tsx +170 -0
- package/src/components/UserListScreen/index.tsx +181 -0
- package/src/config/index.ts +46 -0
- package/src/hooks/useChat.ts +31 -0
- package/src/hooks/useUsers.ts +27 -0
- package/src/index.ts +18 -0
- package/src/services/userService.ts +9 -0
- package/src/types/index.ts +82 -0
- package/src/utils/theme.ts +16 -0
- package/dist/components/BottomNav/index.d.ts +0 -10
- package/dist/components/BottomNav/index.js +0 -32
- package/dist/components/ChatBox/index.d.ts +0 -15
- package/dist/components/ChatBox/index.js +0 -228
- package/dist/components/ChatButton/index.d.ts +0 -9
- package/dist/components/ChatButton/index.js +0 -17
- package/dist/components/ChatWindow/index.d.ts +0 -10
- package/dist/components/ChatWindow/index.js +0 -286
- package/dist/components/HomeView/index.d.ts +0 -12
- package/dist/components/HomeView/index.js +0 -51
- package/dist/components/UserList/index.d.ts +0 -13
- package/dist/components/UserList/index.js +0 -136
|
@@ -1,50 +1,141 @@
|
|
|
1
|
-
'use client';
|
|
1
|
+
'use client';
|
|
2
2
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { useState, useEffect } from 'react';
|
|
4
|
-
import { loadChatConfig } from '../config';
|
|
5
|
-
import { ChatButton } from './ChatButton';
|
|
6
|
-
import { ChatWindow } from './ChatWindow';
|
|
3
|
+
import { useState, useEffect, useCallback } from 'react';
|
|
4
|
+
import { loadChatConfig, buildUserListUrl } from '../config';
|
|
7
5
|
import { mergeTheme } from '../utils/theme';
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
*
|
|
19
|
-
* @example
|
|
20
|
-
* // With custom theme
|
|
21
|
-
* <ChatWidget
|
|
22
|
-
* theme={{
|
|
23
|
-
* primaryColor: '#FF6B6B',
|
|
24
|
-
* buttonColor: '#FF6B6B',
|
|
25
|
-
* buttonLabel: 'Need Help?',
|
|
26
|
-
* buttonPosition: 'bottom-left',
|
|
27
|
-
* fontFamily: "'Inter', sans-serif",
|
|
28
|
-
* borderRadius: '12px',
|
|
29
|
-
* }}
|
|
30
|
-
* />
|
|
31
|
-
*/
|
|
6
|
+
import { useUsers } from '../hooks/useUsers';
|
|
7
|
+
import { useChat } from '../hooks/useChat';
|
|
8
|
+
// Screens
|
|
9
|
+
import { HomeScreen } from './HomeScreen';
|
|
10
|
+
import { UserListScreen } from './UserListScreen';
|
|
11
|
+
import { ChatScreen } from './ChatScreen';
|
|
12
|
+
import { RecentChatsScreen } from './RecentChatsScreen';
|
|
13
|
+
import { TicketScreen } from './TicketScreen';
|
|
14
|
+
import { MaintenanceView } from './MaintenanceView';
|
|
15
|
+
import { BottomTabs } from './Tabs/BottomTabs';
|
|
32
16
|
export const ChatWidget = ({ theme }) => {
|
|
33
|
-
const [isOpen, setIsOpen] = useState(false);
|
|
34
17
|
const [isMounted, setIsMounted] = useState(false);
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
18
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
19
|
+
const [isMaximized, setIsMaximized] = useState(false);
|
|
20
|
+
const [activeTab, setActiveTab] = useState('home');
|
|
21
|
+
const [screen, setScreen] = useState('home');
|
|
22
|
+
const [userListCtx, setUserListCtx] = useState('support');
|
|
23
|
+
const [tickets, setTickets] = useState([]);
|
|
24
|
+
// SSR guard
|
|
25
|
+
useEffect(() => { setIsMounted(true); }, []);
|
|
40
26
|
const config = loadChatConfig();
|
|
41
27
|
const t = mergeTheme(theme);
|
|
42
|
-
|
|
28
|
+
const apiUrl = buildUserListUrl(config);
|
|
29
|
+
// Determine filter based on context
|
|
30
|
+
const filterType = userListCtx === 'support' ? 'developer' : 'user';
|
|
31
|
+
const { users, loading, error } = useUsers(apiUrl, filterType, config.status === 'ACTIVE' && screen === 'user-list');
|
|
32
|
+
const { messages, activeUser, selectUser, sendMessage, clearChat } = useChat();
|
|
33
|
+
// ── Navigation helpers ─────────────────────────────────────────────────────
|
|
34
|
+
const goHome = useCallback(() => { setScreen('home'); setActiveTab('home'); }, []);
|
|
35
|
+
const handleTabChange = useCallback((tab) => {
|
|
36
|
+
setActiveTab(tab);
|
|
37
|
+
if (tab === 'home') {
|
|
38
|
+
setScreen('home');
|
|
39
|
+
}
|
|
40
|
+
if (tab === 'chats') {
|
|
41
|
+
setScreen('recent-chats');
|
|
42
|
+
}
|
|
43
|
+
if (tab === 'tickets') {
|
|
44
|
+
setScreen('tickets');
|
|
45
|
+
}
|
|
46
|
+
}, []);
|
|
47
|
+
const handleCardClick = useCallback((ctx) => {
|
|
48
|
+
if (ctx === 'ticket') {
|
|
49
|
+
setActiveTab('tickets');
|
|
50
|
+
setScreen('tickets');
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
setUserListCtx(ctx);
|
|
54
|
+
setScreen('user-list');
|
|
55
|
+
}
|
|
56
|
+
}, []);
|
|
57
|
+
const handleSelectUser = useCallback((user) => {
|
|
58
|
+
selectUser(user);
|
|
59
|
+
setScreen('chat');
|
|
60
|
+
}, [selectUser]);
|
|
61
|
+
const handleBackFromUserList = useCallback(() => {
|
|
62
|
+
setScreen('home');
|
|
63
|
+
}, []);
|
|
64
|
+
const handleBackFromChat = useCallback(() => {
|
|
65
|
+
clearChat();
|
|
66
|
+
setScreen('user-list');
|
|
67
|
+
}, [clearChat]);
|
|
68
|
+
const handleRaiseTicket = useCallback((title, description) => {
|
|
69
|
+
const t = {
|
|
70
|
+
id: `ticket_${Date.now()}`,
|
|
71
|
+
title,
|
|
72
|
+
description,
|
|
73
|
+
status: 'open',
|
|
74
|
+
priority: 'medium',
|
|
75
|
+
createdAt: new Date(),
|
|
76
|
+
updatedAt: new Date(),
|
|
77
|
+
};
|
|
78
|
+
setTickets(prev => [t, ...prev]);
|
|
79
|
+
}, []);
|
|
80
|
+
// ── Sizing ─────────────────────────────────────────────────────────────────
|
|
81
|
+
const normalW = 380;
|
|
82
|
+
const normalH = 560;
|
|
83
|
+
const maxW = 480;
|
|
84
|
+
const maxH = 720;
|
|
85
|
+
const width = isMaximized ? maxW : normalW;
|
|
86
|
+
const height = isMaximized ? maxH : normalH;
|
|
87
|
+
const posStyle = t.buttonPosition === 'bottom-left'
|
|
88
|
+
? { left: 24, right: 'auto' }
|
|
89
|
+
: { right: 24, left: 'auto' };
|
|
43
90
|
if (!isMounted)
|
|
44
91
|
return null;
|
|
45
|
-
// DISABLE: render nothing at all
|
|
46
92
|
if (config.status === 'DISABLE')
|
|
47
93
|
return null;
|
|
48
|
-
return (_jsxs(_Fragment, { children: [
|
|
94
|
+
return (_jsxs(_Fragment, { children: [_jsx("style", { children: `
|
|
95
|
+
@import url('https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700;800&display=swap');
|
|
96
|
+
@keyframes cw-fadeUp {
|
|
97
|
+
from { opacity:0; transform:translateY(10px); }
|
|
98
|
+
to { opacity:1; transform:translateY(0); }
|
|
99
|
+
}
|
|
100
|
+
@keyframes cw-slideInRight {
|
|
101
|
+
from { opacity:0; transform:translateX(18px); }
|
|
102
|
+
to { opacity:1; transform:translateX(0); }
|
|
103
|
+
}
|
|
104
|
+
@keyframes cw-popIn {
|
|
105
|
+
from { opacity:0; transform:scale(0.88) translateY(16px); }
|
|
106
|
+
to { opacity:1; transform:scale(1) translateY(0); }
|
|
107
|
+
}
|
|
108
|
+
.cw-scrollbar::-webkit-scrollbar { width:4px; }
|
|
109
|
+
.cw-scrollbar::-webkit-scrollbar-track { background:transparent; }
|
|
110
|
+
.cw-scrollbar::-webkit-scrollbar-thumb { background:#e0e0e0; border-radius:4px; }
|
|
111
|
+
` }), _jsx("button", { onClick: () => setIsOpen(o => !o), "aria-label": isOpen ? 'Close chat' : t.buttonLabel, style: Object.assign(Object.assign({ position: 'fixed', bottom: 24 }, posStyle), { zIndex: 9999, display: 'flex', alignItems: 'center', gap: 10, padding: isOpen ? '14px' : '13px 22px', backgroundColor: t.buttonColor, color: t.buttonTextColor, border: 'none', borderRadius: 50, cursor: 'pointer', fontFamily: t.fontFamily, fontSize: '15px', fontWeight: 700, boxShadow: `0 8px 28px ${t.buttonColor}55`, transition: 'all 0.3s cubic-bezier(0.34,1.56,0.64,1)', transform: isOpen ? 'scale(0.94)' : 'scale(1)', minWidth: isOpen ? 50 : 'auto', justifyContent: 'center' }), onMouseEnter: e => {
|
|
112
|
+
if (!isOpen) {
|
|
113
|
+
e.currentTarget.style.transform = 'scale(1.06) translateY(-2px)';
|
|
114
|
+
e.currentTarget.style.boxShadow = `0 12px 36px ${t.buttonColor}77`;
|
|
115
|
+
}
|
|
116
|
+
}, onMouseLeave: e => {
|
|
117
|
+
e.currentTarget.style.transform = isOpen ? 'scale(0.94)' : 'scale(1)';
|
|
118
|
+
e.currentTarget.style.boxShadow = `0 8px 28px ${t.buttonColor}55`;
|
|
119
|
+
}, children: isOpen
|
|
120
|
+
? _jsx(CloseIcon, { color: t.buttonTextColor })
|
|
121
|
+
: _jsxs(_Fragment, { children: [_jsx(ChatBubbleIcon, { color: t.buttonTextColor }), _jsx("span", { children: t.buttonLabel })] }) }), isOpen && (_jsxs("div", { style: Object.assign(Object.assign({ position: 'fixed', bottom: 86 }, posStyle), { zIndex: 9998, width,
|
|
122
|
+
height, maxWidth: 'calc(100vw - 32px)', maxHeight: 'calc(100vh - 110px)', backgroundColor: '#fff', borderRadius: t.borderRadius, boxShadow: '0 20px 70px rgba(0,0,0,0.2), 0 6px 20px rgba(0,0,0,0.08)', display: 'flex', flexDirection: 'column', overflow: 'hidden', fontFamily: t.fontFamily, animation: 'cw-popIn 0.3s cubic-bezier(0.34,1.56,0.64,1)', transition: 'width 0.3s ease, height 0.3s ease' }), children: [screen !== 'chat' && (_jsx("button", { onClick: () => setIsMaximized(m => !m), title: isMaximized ? 'Minimize' : 'Maximize', style: {
|
|
123
|
+
position: 'absolute', top: 12, right: 48, zIndex: 10,
|
|
124
|
+
background: 'rgba(255,255,255,0.22)', border: 'none', borderRadius: '50%',
|
|
125
|
+
width: 28, height: 28, display: 'flex', alignItems: 'center', justifyContent: 'center',
|
|
126
|
+
cursor: 'pointer', transition: 'background 0.15s',
|
|
127
|
+
}, onMouseEnter: e => e.currentTarget.style.background = 'rgba(255,255,255,0.38)', onMouseLeave: e => e.currentTarget.style.background = 'rgba(255,255,255,0.22)', children: isMaximized
|
|
128
|
+
? _jsx(MinimizeIcon, {})
|
|
129
|
+
: _jsx(MaximizeIcon, {}) })), screen !== 'chat' && (_jsx("button", { onClick: () => setIsOpen(false), title: "Close", style: {
|
|
130
|
+
position: 'absolute', top: 12, right: 12, zIndex: 10,
|
|
131
|
+
background: 'rgba(255,255,255,0.22)', border: 'none', borderRadius: '50%',
|
|
132
|
+
width: 28, height: 28, display: 'flex', alignItems: 'center', justifyContent: 'center',
|
|
133
|
+
cursor: 'pointer',
|
|
134
|
+
}, children: _jsx("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", children: _jsx("path", { d: "M18 6L6 18M6 6l12 12", stroke: "#fff", strokeWidth: "2.5", strokeLinecap: "round" }) }) })), _jsxs("div", { className: "cw-scrollbar", style: { flex: 1, overflow: 'hidden', display: 'flex', flexDirection: 'column' }, children: [config.status === 'MAINTENANCE' && (_jsx(MaintenanceView, { primaryColor: t.primaryColor, fontFamily: t.fontFamily })), config.status === 'ACTIVE' && (_jsxs(_Fragment, { children: [screen === 'home' && (_jsx(HomeScreen, { config: config, theme: theme, onNavigate: handleCardClick })), screen === 'user-list' && (_jsx(UserListScreen, { context: userListCtx, users: users, loading: loading, error: error, theme: theme, onBack: handleBackFromUserList, onSelectUser: handleSelectUser })), screen === 'chat' && activeUser && (_jsx(ChatScreen, { activeUser: activeUser, messages: messages, onSend: sendMessage, onBack: handleBackFromChat, onClose: () => setIsOpen(false), theme: theme })), screen === 'recent-chats' && (_jsx(RecentChatsScreen, { chats: [], theme: theme, onSelectChat: handleSelectUser })), screen === 'tickets' && (_jsx(TicketScreen, { tickets: tickets, theme: theme, onRaiseTicket: handleRaiseTicket }))] }))] }), screen !== 'chat' && screen !== 'user-list' && config.status !== 'MAINTENANCE' && (_jsx(BottomTabs, { active: activeTab, onChange: handleTabChange, primaryColor: t.primaryColor, fontFamily: t.fontFamily }))] }))] }));
|
|
49
135
|
};
|
|
50
136
|
export default ChatWidget;
|
|
137
|
+
// ── Tiny SVG icons ─────────────────────────────────────────────────────────────
|
|
138
|
+
const ChatBubbleIcon = ({ color }) => (_jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", children: _jsx("path", { d: "M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2z", stroke: color, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }));
|
|
139
|
+
const CloseIcon = ({ color }) => (_jsx("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", children: _jsx("path", { d: "M18 6L6 18M6 6l12 12", stroke: color, strokeWidth: "2.5", strokeLinecap: "round" }) }));
|
|
140
|
+
const MaximizeIcon = () => (_jsx("svg", { width: "13", height: "13", viewBox: "0 0 24 24", fill: "none", children: _jsx("path", { d: "M8 3H5a2 2 0 00-2 2v3M21 8V5a2 2 0 00-2-2h-3M3 16v3a2 2 0 002 2h3M16 21h3a2 2 0 002-2v-3", stroke: "#fff", strokeWidth: "2.2", strokeLinecap: "round" }) }));
|
|
141
|
+
const MinimizeIcon = () => (_jsx("svg", { width: "13", height: "13", viewBox: "0 0 24 24", fill: "none", children: _jsx("path", { d: "M8 3v5H3M21 8h-5V3M3 16h5v5M16 21v-5h5", stroke: "#fff", strokeWidth: "2.2", strokeLinecap: "round" }) }));
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { ChatConfig, ChatWidgetTheme, UserListContext } from '../../types';
|
|
3
|
+
interface HomeScreenProps {
|
|
4
|
+
config: ChatConfig;
|
|
5
|
+
theme?: ChatWidgetTheme;
|
|
6
|
+
onNavigate: (ctx: UserListContext | 'ticket') => void;
|
|
7
|
+
}
|
|
8
|
+
export declare const HomeScreen: React.FC<HomeScreenProps>;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { mergeTheme } from '../../utils/theme';
|
|
3
|
+
export const HomeScreen = ({ config, theme, onNavigate }) => {
|
|
4
|
+
const t = mergeTheme(theme);
|
|
5
|
+
const showSupport = config.chatType === 'SUPPORT' || config.chatType === 'BOTH';
|
|
6
|
+
const showConversation = config.chatType === 'CHAT' || config.chatType === 'BOTH';
|
|
7
|
+
const cards = [
|
|
8
|
+
showSupport && {
|
|
9
|
+
key: 'support',
|
|
10
|
+
title: 'Need Support',
|
|
11
|
+
subtitle: 'We typically reply in a few minutes',
|
|
12
|
+
onClick: () => onNavigate('support'),
|
|
13
|
+
},
|
|
14
|
+
showConversation && {
|
|
15
|
+
key: 'conversation',
|
|
16
|
+
title: 'New Conversation',
|
|
17
|
+
subtitle: 'With your colleague',
|
|
18
|
+
onClick: () => onNavigate('conversation'),
|
|
19
|
+
},
|
|
20
|
+
// Raise Ticket is always shown
|
|
21
|
+
{
|
|
22
|
+
key: 'ticket',
|
|
23
|
+
title: 'Raise Ticket',
|
|
24
|
+
subtitle: 'For major changes',
|
|
25
|
+
onClick: () => onNavigate('ticket'),
|
|
26
|
+
},
|
|
27
|
+
].filter(Boolean);
|
|
28
|
+
return (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', height: '100%' }, children: [_jsxs("div", { style: {
|
|
29
|
+
backgroundColor: t.primaryColor,
|
|
30
|
+
padding: '32px 24px 40px',
|
|
31
|
+
flexShrink: 0,
|
|
32
|
+
}, children: [_jsx("h1", { style: {
|
|
33
|
+
margin: '0 0 8px',
|
|
34
|
+
fontSize: '28px',
|
|
35
|
+
fontWeight: 800,
|
|
36
|
+
color: '#fff',
|
|
37
|
+
letterSpacing: '-0.03em',
|
|
38
|
+
fontFamily: t.fontFamily,
|
|
39
|
+
}, children: "Hi there \uD83D\uDC4B" }), _jsx("p", { style: { margin: 0, fontSize: '15px', color: 'rgba(255,255,255,0.85)', fontFamily: t.fontFamily }, children: "Need help? start a conversation:" })] }), _jsx("div", { style: {
|
|
40
|
+
flex: 1,
|
|
41
|
+
overflowY: 'auto',
|
|
42
|
+
padding: '0 16px 16px',
|
|
43
|
+
marginTop: '-24px',
|
|
44
|
+
display: 'flex',
|
|
45
|
+
flexDirection: 'column',
|
|
46
|
+
gap: '10px',
|
|
47
|
+
}, children: cards.map((card, i) => (_jsxs("button", { onClick: card.onClick, style: {
|
|
48
|
+
width: '100%',
|
|
49
|
+
background: '#fff',
|
|
50
|
+
border: 'none',
|
|
51
|
+
borderRadius: '14px',
|
|
52
|
+
padding: '18px 20px',
|
|
53
|
+
display: 'flex',
|
|
54
|
+
alignItems: 'center',
|
|
55
|
+
justifyContent: 'space-between',
|
|
56
|
+
cursor: 'pointer',
|
|
57
|
+
textAlign: 'left',
|
|
58
|
+
boxShadow: '0 2px 12px rgba(0,0,0,0.09)',
|
|
59
|
+
transition: 'transform 0.15s ease, box-shadow 0.15s ease',
|
|
60
|
+
animation: `cw-fadeUp 0.35s ease both`,
|
|
61
|
+
animationDelay: `${i * 0.08}s`,
|
|
62
|
+
fontFamily: t.fontFamily,
|
|
63
|
+
}, onMouseEnter: e => {
|
|
64
|
+
e.currentTarget.style.transform = 'translateY(-2px)';
|
|
65
|
+
e.currentTarget.style.boxShadow = '0 6px 20px rgba(0,0,0,0.13)';
|
|
66
|
+
}, onMouseLeave: e => {
|
|
67
|
+
e.currentTarget.style.transform = 'translateY(0)';
|
|
68
|
+
e.currentTarget.style.boxShadow = '0 2px 12px rgba(0,0,0,0.09)';
|
|
69
|
+
}, children: [_jsxs("div", { children: [_jsx("div", { style: { fontWeight: 700, fontSize: '15px', color: '#1a2332', marginBottom: '3px' }, children: card.title }), _jsx("div", { style: { fontSize: '13px', color: '#7b8fa1' }, children: card.subtitle })] }), _jsx(SendArrow, { color: t.primaryColor })] }, card.key))) })] }));
|
|
70
|
+
};
|
|
71
|
+
const SendArrow = ({ color }) => (_jsx("svg", { width: "22", height: "22", viewBox: "0 0 24 24", fill: "none", style: { flexShrink: 0 }, children: _jsx("path", { d: "M22 2L11 13M22 2L15 22L11 13L2 9L22 2Z", stroke: color, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }));
|
|
@@ -1,53 +1,16 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
export const MaintenanceView = ({
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
backgroundColor: `${primaryColor}15`,
|
|
18
|
-
display: 'flex',
|
|
19
|
-
alignItems: 'center',
|
|
20
|
-
justifyContent: 'center',
|
|
21
|
-
marginBottom: '8px',
|
|
22
|
-
}, children: _jsx("svg", { width: "32", height: "32", viewBox: "0 0 24 24", fill: "none", children: _jsx("path", { d: "M12 9v4M12 17h.01M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z", stroke: primaryColor, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }) }), _jsx("h3", { style: {
|
|
23
|
-
margin: 0,
|
|
24
|
-
fontSize: '17px',
|
|
25
|
-
fontWeight: 700,
|
|
26
|
-
color: '#1a1a2e',
|
|
27
|
-
letterSpacing: '-0.02em',
|
|
28
|
-
}, children: "Under Maintenance" }), _jsx("p", { style: {
|
|
29
|
-
margin: 0,
|
|
30
|
-
fontSize: '14px',
|
|
31
|
-
color: '#888',
|
|
32
|
-
lineHeight: 1.6,
|
|
33
|
-
maxWidth: '220px',
|
|
34
|
-
}, children: "Chat is under maintenance. We'll be back shortly. Thank you for your patience!" }), _jsxs("span", { style: {
|
|
35
|
-
display: 'inline-flex',
|
|
36
|
-
alignItems: 'center',
|
|
37
|
-
gap: '6px',
|
|
38
|
-
padding: '6px 14px',
|
|
39
|
-
borderRadius: '20px',
|
|
40
|
-
backgroundColor: '#fff3cd',
|
|
41
|
-
color: '#856404',
|
|
42
|
-
fontSize: '12px',
|
|
43
|
-
fontWeight: 600,
|
|
44
|
-
marginTop: '8px',
|
|
45
|
-
border: '1px solid #ffc10730',
|
|
46
|
-
}, children: [_jsx("span", { style: {
|
|
47
|
-
width: '6px',
|
|
48
|
-
height: '6px',
|
|
49
|
-
borderRadius: '50%',
|
|
50
|
-
backgroundColor: '#ffc107',
|
|
51
|
-
display: 'inline-block',
|
|
52
|
-
} }), "Temporarily Unavailable"] })] }));
|
|
53
|
-
};
|
|
2
|
+
export const MaintenanceView = ({ primaryColor, fontFamily }) => (_jsxs("div", { style: {
|
|
3
|
+
display: 'flex', flexDirection: 'column', alignItems: 'center',
|
|
4
|
+
justifyContent: 'center', height: '100%', padding: '32px',
|
|
5
|
+
fontFamily, textAlign: 'center', gap: 16,
|
|
6
|
+
}, children: [_jsx("div", { style: {
|
|
7
|
+
width: 72, height: 72, borderRadius: '50%',
|
|
8
|
+
backgroundColor: `${primaryColor}15`,
|
|
9
|
+
display: 'flex', alignItems: 'center', justifyContent: 'center',
|
|
10
|
+
}, children: _jsx("svg", { width: "32", height: "32", viewBox: "0 0 24 24", fill: "none", children: _jsx("path", { d: "M12 9v4M12 17h.01M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z", stroke: primaryColor, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }) }), _jsx("h3", { style: { margin: 0, fontSize: '17px', fontWeight: 800, color: '#1a2332', letterSpacing: '-0.02em' }, children: "Under Maintenance" }), _jsx("p", { style: { margin: 0, fontSize: '14px', color: '#7b8fa1', lineHeight: 1.6, maxWidth: 220 }, children: "Chat is under maintenance. We'll be back shortly!" }), _jsxs("span", { style: {
|
|
11
|
+
display: 'inline-flex', alignItems: 'center', gap: 6,
|
|
12
|
+
padding: '6px 14px', borderRadius: 20,
|
|
13
|
+
backgroundColor: '#fff3cd', color: '#856404',
|
|
14
|
+
fontSize: '12px', fontWeight: 700,
|
|
15
|
+
border: '1px solid #ffc10730',
|
|
16
|
+
}, children: [_jsx("span", { style: { width: 6, height: 6, borderRadius: '50%', backgroundColor: '#ffc107', display: 'inline-block' } }), "Temporarily Unavailable"] })] }));
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { ChatUser, ChatWidgetTheme } from '../../types';
|
|
3
|
+
interface RecentChat {
|
|
4
|
+
id: string;
|
|
5
|
+
user: ChatUser;
|
|
6
|
+
lastMessage: string;
|
|
7
|
+
lastTime: Date;
|
|
8
|
+
unread: number;
|
|
9
|
+
}
|
|
10
|
+
interface RecentChatsScreenProps {
|
|
11
|
+
chats: RecentChat[];
|
|
12
|
+
theme?: ChatWidgetTheme;
|
|
13
|
+
onSelectChat: (user: ChatUser) => void;
|
|
14
|
+
}
|
|
15
|
+
export declare const RecentChatsScreen: React.FC<RecentChatsScreenProps>;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { mergeTheme } from '../../utils/theme';
|
|
3
|
+
export const RecentChatsScreen = ({ chats, theme, onSelectChat }) => {
|
|
4
|
+
const t = mergeTheme(theme);
|
|
5
|
+
return (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', height: '100%' }, children: [_jsxs("div", { style: {
|
|
6
|
+
backgroundColor: t.primaryColor,
|
|
7
|
+
padding: '20px 20px 24px',
|
|
8
|
+
flexShrink: 0,
|
|
9
|
+
}, children: [_jsx("h2", { style: { margin: 0, fontSize: '20px', fontWeight: 800, color: '#fff', fontFamily: t.fontFamily, letterSpacing: '-0.02em' }, children: "Recent Chats" }), _jsx("p", { style: { margin: '4px 0 0', fontSize: '13px', color: 'rgba(255,255,255,0.8)', fontFamily: t.fontFamily }, children: "Your conversation history" })] }), _jsx("div", { style: { flex: 1, overflowY: 'auto' }, children: chats.length === 0 ? (_jsxs("div", { style: { padding: '50px 24px', textAlign: 'center', fontFamily: t.fontFamily }, children: [_jsx("div", { style: { fontSize: '36px', marginBottom: 12 }, children: "\uD83D\uDCAC" }), _jsx("div", { style: { fontWeight: 700, color: '#1a2332', marginBottom: 6 }, children: "No chats yet" }), _jsx("div", { style: { fontSize: '13px', color: '#7b8fa1' }, children: "Start a conversation from the home tab" })] })) : (chats.map((chat, i) => {
|
|
10
|
+
const initials = chat.user.name.split(' ').map(n => n[0]).join('').toUpperCase().slice(0, 2);
|
|
11
|
+
const avatarColors = ['#1aaa96', '#2563EB', '#7C3AED', '#D97706', '#DC2626'];
|
|
12
|
+
const bg = avatarColors[chat.user.name.charCodeAt(0) % avatarColors.length];
|
|
13
|
+
const timeStr = new Date(chat.lastTime).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
|
|
14
|
+
return (_jsxs("button", { onClick: () => onSelectChat(chat.user), style: {
|
|
15
|
+
width: '100%', padding: '14px 20px',
|
|
16
|
+
display: 'flex', alignItems: 'center', gap: '14px',
|
|
17
|
+
background: 'transparent', border: 'none',
|
|
18
|
+
borderBottom: '1px solid #f3f4f6',
|
|
19
|
+
cursor: 'pointer', textAlign: 'left',
|
|
20
|
+
fontFamily: t.fontFamily,
|
|
21
|
+
animation: `cw-fadeUp 0.3s ease both`,
|
|
22
|
+
animationDelay: `${i * 0.05}s`,
|
|
23
|
+
transition: 'background 0.15s',
|
|
24
|
+
}, onMouseEnter: e => e.currentTarget.style.background = '#f8fdfc', onMouseLeave: e => e.currentTarget.style.background = 'transparent', children: [_jsxs("div", { style: {
|
|
25
|
+
width: 46, height: 46, borderRadius: '50%', backgroundColor: bg,
|
|
26
|
+
display: 'flex', alignItems: 'center', justifyContent: 'center',
|
|
27
|
+
color: '#fff', fontWeight: 700, fontSize: '15px', flexShrink: 0,
|
|
28
|
+
position: 'relative',
|
|
29
|
+
}, children: [initials, chat.unread > 0 && (_jsx("span", { style: {
|
|
30
|
+
position: 'absolute', top: -2, right: -2,
|
|
31
|
+
width: 18, height: 18, borderRadius: '50%',
|
|
32
|
+
backgroundColor: '#ff4757', color: '#fff',
|
|
33
|
+
fontSize: '10px', fontWeight: 700,
|
|
34
|
+
display: 'flex', alignItems: 'center', justifyContent: 'center',
|
|
35
|
+
border: '2px solid #fff',
|
|
36
|
+
}, children: chat.unread }))] }), _jsxs("div", { style: { flex: 1, minWidth: 0 }, children: [_jsxs("div", { style: { display: 'flex', justifyContent: 'space-between', marginBottom: 3 }, children: [_jsx("span", { style: { fontWeight: 700, fontSize: '14px', color: '#1a2332' }, children: chat.user.name }), _jsx("span", { style: { fontSize: '11px', color: '#b0bec5' }, children: timeStr })] }), _jsx("div", { style: { fontSize: '13px', color: '#7b8fa1', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }, children: chat.lastMessage })] })] }, chat.id));
|
|
37
|
+
})) })] }));
|
|
38
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { BottomTab } from '../../types';
|
|
3
|
+
interface BottomTabsProps {
|
|
4
|
+
active: BottomTab;
|
|
5
|
+
onChange: (tab: BottomTab) => void;
|
|
6
|
+
primaryColor: string;
|
|
7
|
+
fontFamily: string;
|
|
8
|
+
}
|
|
9
|
+
export declare const BottomTabs: React.FC<BottomTabsProps>;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
export const BottomTabs = ({ active, onChange, primaryColor, fontFamily }) => {
|
|
3
|
+
const tabs = [
|
|
4
|
+
{ key: 'home', label: 'Home', Icon: HomeIcon },
|
|
5
|
+
{ key: 'chats', label: 'Chats', Icon: ChatsIcon },
|
|
6
|
+
{ key: 'tickets', label: 'Tickets', Icon: TicketsIcon },
|
|
7
|
+
];
|
|
8
|
+
return (_jsx("div", { style: {
|
|
9
|
+
display: 'flex',
|
|
10
|
+
borderTop: '1px solid #eef0f5',
|
|
11
|
+
backgroundColor: '#fff',
|
|
12
|
+
flexShrink: 0,
|
|
13
|
+
}, children: tabs.map(tab => {
|
|
14
|
+
const isActive = active === tab.key;
|
|
15
|
+
return (_jsxs("button", { onClick: () => onChange(tab.key), style: {
|
|
16
|
+
flex: 1, padding: '10px 0 8px',
|
|
17
|
+
display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 3,
|
|
18
|
+
background: 'transparent', border: 'none', cursor: 'pointer',
|
|
19
|
+
fontFamily, fontSize: '10px', fontWeight: isActive ? 700 : 500,
|
|
20
|
+
color: isActive ? primaryColor : '#9aa3af',
|
|
21
|
+
transition: 'color 0.15s',
|
|
22
|
+
borderTop: isActive ? `2px solid ${primaryColor}` : '2px solid transparent',
|
|
23
|
+
}, children: [_jsx(tab.Icon, { active: isActive, color: isActive ? primaryColor : '#b0bec5' }), tab.label] }, tab.key));
|
|
24
|
+
}) }));
|
|
25
|
+
};
|
|
26
|
+
// ── Icons ─────────────────────────────────────────────────────────────────────
|
|
27
|
+
const HomeIcon = ({ active, color }) => (_jsxs("svg", { width: "22", height: "22", viewBox: "0 0 24 24", fill: "none", children: [_jsx("path", { d: "M3 9.5L12 3l9 6.5V20a1 1 0 01-1 1H4a1 1 0 01-1-1V9.5z", stroke: color, strokeWidth: active ? 2.2 : 1.8, strokeLinecap: "round", strokeLinejoin: "round", fill: active ? `${color}20` : 'none' }), _jsx("path", { d: "M9 21V12h6v9", stroke: color, strokeWidth: active ? 2.2 : 1.8, strokeLinecap: "round", strokeLinejoin: "round" })] }));
|
|
28
|
+
const ChatsIcon = ({ active, color }) => (_jsx("svg", { width: "22", height: "22", viewBox: "0 0 24 24", fill: "none", children: _jsx("path", { d: "M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2z", stroke: color, strokeWidth: active ? 2.2 : 1.8, strokeLinecap: "round", strokeLinejoin: "round", fill: active ? `${color}20` : 'none' }) }));
|
|
29
|
+
const TicketsIcon = ({ active, color }) => (_jsxs("svg", { width: "22", height: "22", viewBox: "0 0 24 24", fill: "none", children: [_jsx("path", { d: "M15 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V9l-4-4z", stroke: color, strokeWidth: active ? 2.2 : 1.8, strokeLinecap: "round", strokeLinejoin: "round", fill: active ? `${color}20` : 'none' }), _jsx("path", { d: "M15 5v4h4M9 13h6M9 17h4", stroke: color, strokeWidth: active ? 2.2 : 1.8, strokeLinecap: "round" })] }));
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { ChatWidgetTheme, Ticket } from '../../types';
|
|
3
|
+
interface TicketScreenProps {
|
|
4
|
+
tickets: Ticket[];
|
|
5
|
+
theme?: ChatWidgetTheme;
|
|
6
|
+
onRaiseTicket: (title: string, description: string) => void;
|
|
7
|
+
}
|
|
8
|
+
export declare const TicketScreen: React.FC<TicketScreenProps>;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { mergeTheme } from '../../utils/theme';
|
|
4
|
+
export const TicketScreen = ({ tickets, theme, onRaiseTicket }) => {
|
|
5
|
+
const t = mergeTheme(theme);
|
|
6
|
+
const [showForm, setShowForm] = useState(false);
|
|
7
|
+
const [title, setTitle] = useState('');
|
|
8
|
+
const [desc, setDesc] = useState('');
|
|
9
|
+
const handleSubmit = () => {
|
|
10
|
+
if (!title.trim())
|
|
11
|
+
return;
|
|
12
|
+
onRaiseTicket(title.trim(), desc.trim());
|
|
13
|
+
setTitle('');
|
|
14
|
+
setDesc('');
|
|
15
|
+
setShowForm(false);
|
|
16
|
+
};
|
|
17
|
+
const statusMeta = {
|
|
18
|
+
'open': { label: 'Open', bg: '#e6faf8', color: t.primaryColor },
|
|
19
|
+
'in-progress': { label: 'In Progress', bg: '#fffbeb', color: '#d97706' },
|
|
20
|
+
'resolved': { label: 'Resolved', bg: '#f0fdf4', color: '#16a34a' },
|
|
21
|
+
'closed': { label: 'Closed', bg: '#f3f4f6', color: '#6b7280' },
|
|
22
|
+
};
|
|
23
|
+
const priorityMeta = {
|
|
24
|
+
low: { label: '↓ Low', color: '#6b7280' },
|
|
25
|
+
medium: { label: '→ Medium', color: '#d97706' },
|
|
26
|
+
high: { label: '↑ High', color: '#dc2626' },
|
|
27
|
+
};
|
|
28
|
+
return (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', height: '100%' }, children: [_jsx("div", { style: { backgroundColor: t.primaryColor, padding: '20px 20px 24px', flexShrink: 0 }, children: _jsxs("div", { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between' }, children: [_jsxs("div", { children: [_jsx("h2", { style: { margin: 0, fontSize: '20px', fontWeight: 800, color: '#fff', fontFamily: t.fontFamily, letterSpacing: '-0.02em' }, children: "Tickets" }), _jsxs("p", { style: { margin: '4px 0 0', fontSize: '13px', color: 'rgba(255,255,255,0.8)', fontFamily: t.fontFamily }, children: [tickets.length, " ticket", tickets.length !== 1 ? 's' : '', " raised"] })] }), _jsx("button", { onClick: () => setShowForm(v => !v), style: {
|
|
29
|
+
background: 'rgba(255,255,255,0.25)', border: 'none', borderRadius: '20px',
|
|
30
|
+
padding: '8px 16px', color: '#fff', fontWeight: 700, fontSize: '13px',
|
|
31
|
+
cursor: 'pointer', fontFamily: t.fontFamily, display: 'flex', alignItems: 'center', gap: 5,
|
|
32
|
+
}, children: showForm ? '✕ Cancel' : '+ New Ticket' })] }) }), showForm && (_jsxs("div", { style: {
|
|
33
|
+
padding: '16px 20px',
|
|
34
|
+
borderBottom: '1px solid #eef0f5',
|
|
35
|
+
backgroundColor: '#fafcff',
|
|
36
|
+
animation: 'cw-fadeUp 0.2s ease',
|
|
37
|
+
flexShrink: 0,
|
|
38
|
+
}, children: [_jsx("input", { placeholder: "Ticket title *", value: title, onChange: e => setTitle(e.target.value), style: {
|
|
39
|
+
width: '100%', padding: '10px 14px', borderRadius: 10,
|
|
40
|
+
border: '1.5px solid #e2e8f0', outline: 'none',
|
|
41
|
+
fontFamily: t.fontFamily, fontSize: '14px', color: '#1a2332',
|
|
42
|
+
marginBottom: 10, boxSizing: 'border-box',
|
|
43
|
+
}, onFocus: e => (e.target.style.borderColor = t.primaryColor), onBlur: e => (e.target.style.borderColor = '#e2e8f0') }), _jsx("textarea", { placeholder: "Describe the issue (optional)", value: desc, onChange: e => setDesc(e.target.value), rows: 3, style: {
|
|
44
|
+
width: '100%', padding: '10px 14px', borderRadius: 10,
|
|
45
|
+
border: '1.5px solid #e2e8f0', outline: 'none', resize: 'none',
|
|
46
|
+
fontFamily: t.fontFamily, fontSize: '14px', color: '#1a2332',
|
|
47
|
+
marginBottom: 10, boxSizing: 'border-box',
|
|
48
|
+
}, onFocus: e => (e.target.style.borderColor = t.primaryColor), onBlur: e => (e.target.style.borderColor = '#e2e8f0') }), _jsx("button", { onClick: handleSubmit, disabled: !title.trim(), style: {
|
|
49
|
+
width: '100%', padding: '11px', borderRadius: 10,
|
|
50
|
+
backgroundColor: title.trim() ? t.primaryColor : '#e2e8f0',
|
|
51
|
+
color: title.trim() ? '#fff' : '#9aa3af',
|
|
52
|
+
border: 'none', cursor: title.trim() ? 'pointer' : 'not-allowed',
|
|
53
|
+
fontWeight: 700, fontSize: '14px', fontFamily: t.fontFamily,
|
|
54
|
+
transition: 'background 0.2s',
|
|
55
|
+
}, children: "Submit Ticket" })] })), _jsx("div", { style: { flex: 1, overflowY: 'auto' }, children: tickets.length === 0 ? (_jsxs("div", { style: { padding: '50px 24px', textAlign: 'center', fontFamily: t.fontFamily }, children: [_jsx("div", { style: { fontSize: '36px', marginBottom: 12 }, children: "\uD83C\uDFAB" }), _jsx("div", { style: { fontWeight: 700, color: '#1a2332', marginBottom: 6 }, children: "No tickets yet" }), _jsx("div", { style: { fontSize: '13px', color: '#7b8fa1' }, children: "Raise a ticket for major issues or changes" })] })) : (tickets.map((ticket, i) => {
|
|
56
|
+
const sm = statusMeta[ticket.status];
|
|
57
|
+
const pm = priorityMeta[ticket.priority];
|
|
58
|
+
const date = new Date(ticket.createdAt).toLocaleDateString([], { month: 'short', day: 'numeric' });
|
|
59
|
+
return (_jsxs("div", { style: {
|
|
60
|
+
padding: '14px 20px',
|
|
61
|
+
borderBottom: '1px solid #f3f4f6',
|
|
62
|
+
fontFamily: t.fontFamily,
|
|
63
|
+
animation: `cw-fadeUp 0.3s ease both`,
|
|
64
|
+
animationDelay: `${i * 0.05}s`,
|
|
65
|
+
}, children: [_jsxs("div", { style: { display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', marginBottom: 6 }, children: [_jsx("span", { style: { fontWeight: 700, fontSize: '14px', color: '#1a2332', flex: 1, paddingRight: 12 }, children: ticket.title }), _jsx("span", { style: {
|
|
66
|
+
fontSize: '10px', fontWeight: 700, padding: '3px 9px', borderRadius: 20,
|
|
67
|
+
backgroundColor: sm.bg, color: sm.color, whiteSpace: 'nowrap',
|
|
68
|
+
textTransform: 'uppercase', letterSpacing: '0.04em',
|
|
69
|
+
}, children: sm.label })] }), ticket.description && (_jsx("div", { style: { fontSize: '13px', color: '#7b8fa1', marginBottom: 8, lineHeight: 1.5 }, children: ticket.description })), _jsxs("div", { style: { display: 'flex', gap: 12, fontSize: '11px', color: '#b0bec5' }, children: [_jsx("span", { style: { color: pm.color, fontWeight: 600 }, children: pm.label }), _jsxs("span", { children: ["#", ticket.id.slice(-6).toUpperCase()] }), _jsx("span", { children: date })] })] }, ticket.id));
|
|
70
|
+
})) })] }));
|
|
71
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { ChatUser, ChatWidgetTheme, UserListContext } from '../../types';
|
|
3
|
+
interface UserListScreenProps {
|
|
4
|
+
context: UserListContext;
|
|
5
|
+
users: ChatUser[];
|
|
6
|
+
loading: boolean;
|
|
7
|
+
error: string | null;
|
|
8
|
+
theme?: ChatWidgetTheme;
|
|
9
|
+
onBack: () => void;
|
|
10
|
+
onSelectUser: (user: ChatUser) => void;
|
|
11
|
+
}
|
|
12
|
+
export declare const UserListScreen: React.FC<UserListScreenProps>;
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { mergeTheme } from '../../utils/theme';
|
|
3
|
+
export const UserListScreen = ({ context, users, loading, error, theme, onBack, onSelectUser, }) => {
|
|
4
|
+
const t = mergeTheme(theme);
|
|
5
|
+
const title = context === 'support' ? 'Need Support' : 'New Conversation';
|
|
6
|
+
const subtitle = context === 'support'
|
|
7
|
+
? 'Choose a support agent'
|
|
8
|
+
: 'Choose a colleague to chat with';
|
|
9
|
+
return (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', height: '100%', animation: 'cw-slideInRight 0.25s ease' }, children: [_jsxs("div", { style: {
|
|
10
|
+
backgroundColor: t.primaryColor,
|
|
11
|
+
padding: '16px 20px',
|
|
12
|
+
display: 'flex',
|
|
13
|
+
alignItems: 'center',
|
|
14
|
+
gap: '12px',
|
|
15
|
+
flexShrink: 0,
|
|
16
|
+
}, children: [_jsx("button", { onClick: onBack, style: {
|
|
17
|
+
background: 'rgba(255,255,255,0.2)',
|
|
18
|
+
border: 'none',
|
|
19
|
+
borderRadius: '50%',
|
|
20
|
+
width: '34px',
|
|
21
|
+
height: '34px',
|
|
22
|
+
display: 'flex',
|
|
23
|
+
alignItems: 'center',
|
|
24
|
+
justifyContent: 'center',
|
|
25
|
+
cursor: 'pointer',
|
|
26
|
+
flexShrink: 0,
|
|
27
|
+
}, children: _jsx("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", children: _jsx("path", { d: "M19 12H5M5 12L12 19M5 12L12 5", stroke: "#fff", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" }) }) }), _jsxs("div", { children: [_jsx("div", { style: { fontWeight: 700, fontSize: '16px', color: '#fff', fontFamily: t.fontFamily }, children: title }), _jsx("div", { style: { fontSize: '12px', color: 'rgba(255,255,255,0.8)', fontFamily: t.fontFamily }, children: subtitle })] })] }), _jsxs("div", { style: { flex: 1, overflowY: 'auto', padding: '8px 0' }, children: [loading && _jsx(UserListSkeleton, {}), error && _jsx(ErrorState, { message: error, color: t.primaryColor, font: t.fontFamily }), !loading && !error && users.length === 0 && (_jsx(EmptyState, { color: t.primaryColor, font: t.fontFamily })), !loading && !error && users.map((user, i) => (_jsx(UserRow, { user: user, index: i, primaryColor: t.primaryColor, fontFamily: t.fontFamily, onClick: () => onSelectUser(user) }, user.uid)))] })] }));
|
|
28
|
+
};
|
|
29
|
+
// ── Sub-components ─────────────────────────────────────────────────────────────
|
|
30
|
+
const UserRow = ({ user, index, primaryColor, fontFamily, onClick }) => {
|
|
31
|
+
const initials = user.name.split(' ').map(n => n[0]).join('').toUpperCase().slice(0, 2);
|
|
32
|
+
const avatarColors = ['#1aaa96', '#2563EB', '#7C3AED', '#D97706', '#DC2626', '#059669'];
|
|
33
|
+
const bg = avatarColors[user.name.charCodeAt(0) % avatarColors.length];
|
|
34
|
+
return (_jsxs("button", { onClick: onClick, style: {
|
|
35
|
+
width: '100%',
|
|
36
|
+
padding: '14px 20px',
|
|
37
|
+
display: 'flex',
|
|
38
|
+
alignItems: 'center',
|
|
39
|
+
gap: '14px',
|
|
40
|
+
background: 'transparent',
|
|
41
|
+
border: 'none',
|
|
42
|
+
borderBottom: '1px solid #f3f4f6',
|
|
43
|
+
cursor: 'pointer',
|
|
44
|
+
textAlign: 'left',
|
|
45
|
+
fontFamily,
|
|
46
|
+
animation: 'cw-fadeUp 0.3s ease both',
|
|
47
|
+
animationDelay: `${index * 0.05}s`,
|
|
48
|
+
transition: 'background 0.15s',
|
|
49
|
+
}, onMouseEnter: e => e.currentTarget.style.background = '#f8fdfc', onMouseLeave: e => e.currentTarget.style.background = 'transparent', children: [_jsx("div", { style: {
|
|
50
|
+
width: '46px', height: '46px', borderRadius: '50%',
|
|
51
|
+
backgroundColor: bg, flexShrink: 0,
|
|
52
|
+
display: 'flex', alignItems: 'center', justifyContent: 'center',
|
|
53
|
+
color: '#fff', fontWeight: 700, fontSize: '15px',
|
|
54
|
+
}, children: initials }), _jsxs("div", { style: { flex: 1, minWidth: 0 }, children: [_jsx("div", { style: { fontWeight: 700, fontSize: '14px', color: '#1a2332', marginBottom: '2px' }, children: user.name }), _jsx("div", { style: { fontSize: '12px', color: '#7b8fa1', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }, children: user.project || user.email })] }), _jsx("span", { style: {
|
|
55
|
+
fontSize: '10px', fontWeight: 700, padding: '3px 9px',
|
|
56
|
+
borderRadius: '20px', textTransform: 'uppercase', letterSpacing: '0.05em',
|
|
57
|
+
backgroundColor: user.type === 'developer' ? '#e6faf8' : '#eff6ff',
|
|
58
|
+
color: user.type === 'developer' ? primaryColor : '#2563EB',
|
|
59
|
+
border: `1px solid ${user.type === 'developer' ? primaryColor + '30' : '#2563eb30'}`,
|
|
60
|
+
}, children: user.type === 'developer' ? 'Dev' : 'User' })] }));
|
|
61
|
+
};
|
|
62
|
+
const UserListSkeleton = () => (_jsx(_Fragment, { children: [1, 2, 3, 4].map(i => (_jsxs("div", { style: { padding: '14px 20px', display: 'flex', gap: '14px', alignItems: 'center' }, children: [_jsx("div", { style: { width: 46, height: 46, borderRadius: '50%', background: '#f0f0f0', flexShrink: 0 } }), _jsxs("div", { style: { flex: 1 }, children: [_jsx("div", { style: { height: 13, width: '55%', background: '#f0f0f0', borderRadius: 6, marginBottom: 7 } }), _jsx("div", { style: { height: 11, width: '38%', background: '#f0f0f0', borderRadius: 6 } })] })] }, i))) }));
|
|
63
|
+
const ErrorState = ({ message, color, font }) => (_jsxs("div", { style: { padding: '40px 24px', textAlign: 'center', fontFamily: font }, children: [_jsx("div", { style: { fontSize: '32px', marginBottom: '10px' }, children: "\u26A0\uFE0F" }), _jsx("div", { style: { fontWeight: 700, color: '#1a2332', marginBottom: '6px' }, children: "Could not load users" }), _jsx("div", { style: { fontSize: '13px', color: '#7b8fa1' }, children: message })] }));
|
|
64
|
+
const EmptyState = ({ color, font }) => (_jsxs("div", { style: { padding: '40px 24px', textAlign: 'center', fontFamily: font }, children: [_jsx("div", { style: { fontSize: '32px', marginBottom: '10px' }, children: "\uD83D\uDC65" }), _jsx("div", { style: { fontWeight: 700, color: '#1a2332', marginBottom: '6px' }, children: "No users available" }), _jsx("div", { style: { fontSize: '13px', color: '#7b8fa1' }, children: "Check back later" })] }));
|