@blumessage/react-chat 1.4.1 → 1.4.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/BlumessageChat.js +555 -535
- package/dist/index.browser.js +6 -4
- package/dist/index.commonjs.js +13 -6
- package/package.json +1 -1
package/dist/BlumessageChat.js
CHANGED
|
@@ -1,153 +1,198 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
9
26
|
};
|
|
10
|
-
return
|
|
11
|
-
|
|
12
|
-
var
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
20
37
|
};
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
34
|
-
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
35
|
-
default:
|
|
36
|
-
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
37
|
-
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
38
|
-
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
39
|
-
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
40
|
-
if (t[2]) _.ops.pop();
|
|
41
|
-
_.trys.pop(); continue;
|
|
42
|
-
}
|
|
43
|
-
op = body.call(thisArg, _);
|
|
44
|
-
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
45
|
-
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.BlumessageChat = void 0;
|
|
40
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
41
|
+
const react_1 = __importStar(require("react"));
|
|
42
|
+
const react_markdown_1 = __importDefault(require("react-markdown"));
|
|
43
|
+
const remark_gfm_1 = __importDefault(require("remark-gfm"));
|
|
44
|
+
const lucide_react_1 = require("lucide-react");
|
|
45
|
+
// Custom CSS animations that don't depend on Tailwind
|
|
46
|
+
const customStyles = `
|
|
47
|
+
@keyframes bounce {
|
|
48
|
+
0%, 100% {
|
|
49
|
+
transform: translateY(0);
|
|
46
50
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
50
|
-
if (ar || !(i in from)) {
|
|
51
|
-
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
52
|
-
ar[i] = from[i];
|
|
53
|
-
}
|
|
51
|
+
50% {
|
|
52
|
+
transform: translateY(-25%);
|
|
54
53
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
@keyframes spin {
|
|
57
|
+
0% {
|
|
58
|
+
transform: rotate(0deg);
|
|
59
|
+
}
|
|
60
|
+
100% {
|
|
61
|
+
transform: rotate(360deg);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.blumessage-animate-bounce {
|
|
66
|
+
animation: bounce 1s infinite;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.blumessage-animate-spin {
|
|
70
|
+
animation: spin 1s linear infinite;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/* Mobile-specific styles */
|
|
74
|
+
@media (max-width: 768px) {
|
|
75
|
+
.blumessage-mobile-fullscreen {
|
|
76
|
+
position: fixed !important;
|
|
77
|
+
top: 0 !important;
|
|
78
|
+
left: 0 !important;
|
|
79
|
+
right: 0 !important;
|
|
80
|
+
bottom: 0 !important;
|
|
81
|
+
width: 100% !important;
|
|
82
|
+
height: 100% !important;
|
|
83
|
+
max-width: 100% !important;
|
|
84
|
+
max-height: 100% !important;
|
|
85
|
+
border-radius: 0 !important;
|
|
86
|
+
z-index: 9999 !important;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.blumessage-mobile-chat {
|
|
90
|
+
border-radius: 16px !important;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.blumessage-mobile-button {
|
|
94
|
+
position: fixed !important;
|
|
95
|
+
bottom: 20px !important;
|
|
96
|
+
right: 20px !important;
|
|
97
|
+
left: auto !important;
|
|
98
|
+
top: auto !important;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
@media (max-width: 480px) {
|
|
103
|
+
.blumessage-mobile-fullscreen {
|
|
104
|
+
border-radius: 0 !important;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.blumessage-mobile-chat {
|
|
108
|
+
border-radius: 12px !important;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.blumessage-mobile-button {
|
|
112
|
+
bottom: 16px !important;
|
|
113
|
+
right: 16px !important;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
`;
|
|
64
117
|
// Inject custom styles
|
|
65
118
|
if (typeof document !== 'undefined' && !document.getElementById('blumessage-styles')) {
|
|
66
|
-
|
|
119
|
+
const style = document.createElement('style');
|
|
67
120
|
style.id = 'blumessage-styles';
|
|
68
121
|
style.textContent = customStyles;
|
|
69
122
|
document.head.appendChild(style);
|
|
70
123
|
}
|
|
71
124
|
// Session storage key for conversation token
|
|
72
|
-
|
|
125
|
+
const CONVERSATION_TOKEN_KEY = 'blumessage_conversation_token';
|
|
73
126
|
// Utility functions for storage
|
|
74
|
-
|
|
75
|
-
if (persistent === void 0) { persistent = false; }
|
|
127
|
+
const saveConversationToken = (token, persistent = false) => {
|
|
76
128
|
try {
|
|
77
|
-
|
|
129
|
+
const storage = persistent ? localStorage : sessionStorage;
|
|
78
130
|
storage.setItem(CONVERSATION_TOKEN_KEY, token);
|
|
79
131
|
}
|
|
80
132
|
catch (error) {
|
|
81
|
-
console.warn(
|
|
133
|
+
console.warn(`Failed to save conversation token to ${persistent ? 'local' : 'session'} storage:`, error);
|
|
82
134
|
}
|
|
83
135
|
};
|
|
84
|
-
|
|
85
|
-
if (persistent === void 0) { persistent = false; }
|
|
136
|
+
const getStoredConversationToken = (persistent = false) => {
|
|
86
137
|
try {
|
|
87
|
-
|
|
138
|
+
const storage = persistent ? localStorage : sessionStorage;
|
|
88
139
|
return storage.getItem(CONVERSATION_TOKEN_KEY);
|
|
89
140
|
}
|
|
90
141
|
catch (error) {
|
|
91
|
-
console.warn(
|
|
142
|
+
console.warn(`Failed to get conversation token from ${persistent ? 'local' : 'session'} storage:`, error);
|
|
92
143
|
return null;
|
|
93
144
|
}
|
|
94
145
|
};
|
|
95
|
-
|
|
96
|
-
if (persistent === void 0) { persistent = false; }
|
|
146
|
+
const clearStoredConversationToken = (persistent = false) => {
|
|
97
147
|
try {
|
|
98
|
-
|
|
148
|
+
const storage = persistent ? localStorage : sessionStorage;
|
|
99
149
|
storage.removeItem(CONVERSATION_TOKEN_KEY);
|
|
100
150
|
}
|
|
101
151
|
catch (error) {
|
|
102
|
-
console.warn(
|
|
152
|
+
console.warn(`Failed to clear conversation token from ${persistent ? 'local' : 'session'} storage:`, error);
|
|
103
153
|
}
|
|
104
154
|
};
|
|
105
155
|
// Custom hook for mobile detection
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
156
|
+
const useIsMobile = () => {
|
|
157
|
+
const [isMobile, setIsMobile] = (0, react_1.useState)(false);
|
|
158
|
+
(0, react_1.useEffect)(() => {
|
|
159
|
+
const checkIsMobile = () => {
|
|
160
|
+
const userAgent = navigator.userAgent || navigator.vendor || window.opera;
|
|
161
|
+
const mobileRegex = /android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/i;
|
|
162
|
+
const isMobileDevice = mobileRegex.test(userAgent.toLowerCase());
|
|
163
|
+
const isSmallScreen = window.innerWidth <= 768;
|
|
114
164
|
setIsMobile(isMobileDevice || isSmallScreen);
|
|
115
165
|
};
|
|
116
166
|
checkIsMobile();
|
|
117
167
|
window.addEventListener('resize', checkIsMobile);
|
|
118
|
-
return
|
|
168
|
+
return () => window.removeEventListener('resize', checkIsMobile);
|
|
119
169
|
}, []);
|
|
120
170
|
return isMobile;
|
|
121
171
|
};
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
var _3 = useState(false), isAnimating = _3[0], setIsAnimating = _3[1];
|
|
139
|
-
var _4 = useState(false), isLoading = _4[0], setIsLoading = _4[1];
|
|
140
|
-
var _5 = useState(false), isMaximized = _5[0], setIsMaximized = _5[1];
|
|
141
|
-
var messagesEndRef = useRef(null);
|
|
142
|
-
var isInitialLoad = useRef(true);
|
|
172
|
+
exports.BlumessageChat = (0, react_1.forwardRef)(({ apiKey, placeholder = "Type your message...", theme = 'light', width, height, size = 'medium', name = "Blumessage AI", subtitle = "Online • Instant responses", initialMessages = [], onUserMessage, onAssistantMessage, token: initialToken, onTokenChange, onChatWidgetOpen, onChatWidgetClosed, onError, persistent = false, showTimestamps = false, typingText = "Agent is typing...", emptyStateText = "Start a conversation!", markdown = true, disableAutoScroll = false,
|
|
173
|
+
// Floating button props
|
|
174
|
+
floating = true, buttonText = "Chat with us", buttonPosition = 'bottom-right', buttonStyle, defaultOpen = false, maximizeToggleButton = true, fullScreen = false, icon = 'message-circle',
|
|
175
|
+
// Styling props
|
|
176
|
+
primaryColor = "linear-gradient(to right, #3b82f6,rgb(8, 98, 242))" }, ref) => {
|
|
177
|
+
const [isInitialized, setIsInitialized] = (0, react_1.useState)(false);
|
|
178
|
+
const [error, setError] = (0, react_1.useState)(null);
|
|
179
|
+
const [messages, setMessages] = (0, react_1.useState)(initialMessages);
|
|
180
|
+
const [inputValue, setInputValue] = (0, react_1.useState)('');
|
|
181
|
+
const [token, setToken] = (0, react_1.useState)(initialToken || getStoredConversationToken(persistent));
|
|
182
|
+
const [isOpen, setIsOpen] = (0, react_1.useState)(defaultOpen);
|
|
183
|
+
const [isAnimating, setIsAnimating] = (0, react_1.useState)(false);
|
|
184
|
+
const [isLoading, setIsLoading] = (0, react_1.useState)(false);
|
|
185
|
+
const [isMaximized, setIsMaximized] = (0, react_1.useState)(false);
|
|
186
|
+
const messagesEndRef = (0, react_1.useRef)(null);
|
|
187
|
+
const isInitialLoad = (0, react_1.useRef)(true);
|
|
143
188
|
// Mobile detection
|
|
144
|
-
|
|
189
|
+
const isMobile = useIsMobile();
|
|
145
190
|
// Helper function to format timestamp
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
191
|
+
const formatTimestamp = (timestamp) => {
|
|
192
|
+
const date = new Date(timestamp);
|
|
193
|
+
const now = new Date();
|
|
149
194
|
// Check if the message is from today
|
|
150
|
-
|
|
195
|
+
const isToday = date.toDateString() === now.toDateString();
|
|
151
196
|
if (isToday) {
|
|
152
197
|
// If today: show time only in user's locale format (14:00 or 2:00 PM)
|
|
153
198
|
return date.toLocaleTimeString(undefined, {
|
|
@@ -158,23 +203,23 @@ export var BlumessageChat = forwardRef(function (_a, ref) {
|
|
|
158
203
|
}
|
|
159
204
|
else {
|
|
160
205
|
// If more than a day: show "17 July, 13:00" format in user's locale
|
|
161
|
-
|
|
206
|
+
const dateStr = date.toLocaleDateString(undefined, {
|
|
162
207
|
day: 'numeric',
|
|
163
208
|
month: 'long'
|
|
164
209
|
});
|
|
165
|
-
|
|
210
|
+
const timeStr = date.toLocaleTimeString(undefined, {
|
|
166
211
|
hour: '2-digit',
|
|
167
212
|
minute: '2-digit',
|
|
168
213
|
hour12: undefined // Let browser decide based on user's locale
|
|
169
214
|
});
|
|
170
|
-
return
|
|
215
|
+
return `${dateStr}, ${timeStr}`;
|
|
171
216
|
}
|
|
172
217
|
};
|
|
173
218
|
// Helper function to get dimensions based on size
|
|
174
|
-
|
|
219
|
+
const getDimensions = () => {
|
|
175
220
|
// If custom width/height are provided, use them
|
|
176
221
|
if (width && height) {
|
|
177
|
-
return { width
|
|
222
|
+
return { width, height };
|
|
178
223
|
}
|
|
179
224
|
// Mobile-first responsive dimensions
|
|
180
225
|
if (isMobile) {
|
|
@@ -193,7 +238,7 @@ export var BlumessageChat = forwardRef(function (_a, ref) {
|
|
|
193
238
|
}
|
|
194
239
|
}
|
|
195
240
|
// Desktop dimensions based on size
|
|
196
|
-
|
|
241
|
+
let dimensions;
|
|
197
242
|
switch (size) {
|
|
198
243
|
case 'small':
|
|
199
244
|
dimensions = { width: '320px', height: '400px' };
|
|
@@ -207,14 +252,14 @@ export var BlumessageChat = forwardRef(function (_a, ref) {
|
|
|
207
252
|
}
|
|
208
253
|
return dimensions;
|
|
209
254
|
};
|
|
210
|
-
|
|
255
|
+
const { width: actualWidth, height: actualHeight } = getDimensions();
|
|
211
256
|
// Function to clear conversation and start fresh
|
|
212
|
-
|
|
257
|
+
const clearConversation = () => {
|
|
213
258
|
updateConversationToken(null);
|
|
214
259
|
setMessages([]);
|
|
215
260
|
};
|
|
216
261
|
// Function to update conversation token and notify parent
|
|
217
|
-
|
|
262
|
+
const updateConversationToken = (newToken) => {
|
|
218
263
|
setToken(newToken);
|
|
219
264
|
if (newToken) {
|
|
220
265
|
saveConversationToken(newToken, persistent);
|
|
@@ -227,53 +272,44 @@ export var BlumessageChat = forwardRef(function (_a, ref) {
|
|
|
227
272
|
}
|
|
228
273
|
};
|
|
229
274
|
// Function to fetch conversation history
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
case 1:
|
|
244
|
-
response = _a.sent();
|
|
245
|
-
if (!response.ok) return [3 /*break*/, 3];
|
|
246
|
-
return [4 /*yield*/, response.json()];
|
|
247
|
-
case 2:
|
|
248
|
-
sessionData = _a.sent();
|
|
249
|
-
console.log("Conversation history loaded successfully");
|
|
250
|
-
return [2 /*return*/, sessionData.messages || []];
|
|
251
|
-
case 3:
|
|
252
|
-
console.error("Failed to fetch conversation history:", response.status, response.statusText);
|
|
253
|
-
// Clear invalid conversation ID from storage
|
|
254
|
-
updateConversationToken(null);
|
|
255
|
-
if (onError) {
|
|
256
|
-
onError("Failed to fetch conversation history: ".concat(response.status, " ").concat(response.statusText), "conversation_history");
|
|
257
|
-
}
|
|
258
|
-
return [2 /*return*/, []];
|
|
259
|
-
case 4: return [3 /*break*/, 6];
|
|
260
|
-
case 5:
|
|
261
|
-
error_1 = _a.sent();
|
|
262
|
-
console.error("Error fetching conversation history:", error_1);
|
|
263
|
-
// Clear invalid conversation ID from storage
|
|
264
|
-
updateConversationToken(null);
|
|
265
|
-
if (onError) {
|
|
266
|
-
onError("Error fetching conversation history: ".concat(error_1), "conversation_history");
|
|
267
|
-
}
|
|
268
|
-
return [2 /*return*/, []];
|
|
269
|
-
case 6: return [2 /*return*/];
|
|
275
|
+
const fetchConversationHistory = async (convToken) => {
|
|
276
|
+
try {
|
|
277
|
+
console.log("Fetching conversation history for:", convToken);
|
|
278
|
+
const response = await fetch(`https://api.blumessage.com/api/v1/conversations/session/${convToken}`, {
|
|
279
|
+
method: 'GET',
|
|
280
|
+
headers: {
|
|
281
|
+
'Authorization': `Bearer ${apiKey}`,
|
|
282
|
+
},
|
|
283
|
+
});
|
|
284
|
+
if (response.ok) {
|
|
285
|
+
const sessionData = await response.json();
|
|
286
|
+
console.log("Conversation history loaded successfully");
|
|
287
|
+
return sessionData.messages || [];
|
|
270
288
|
}
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
289
|
+
else {
|
|
290
|
+
console.error("Failed to fetch conversation history:", response.status, response.statusText);
|
|
291
|
+
// Clear invalid conversation ID from storage
|
|
292
|
+
updateConversationToken(null);
|
|
293
|
+
if (onError) {
|
|
294
|
+
onError(`Failed to fetch conversation history: ${response.status} ${response.statusText}`, "conversation_history");
|
|
295
|
+
}
|
|
296
|
+
return [];
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
catch (error) {
|
|
300
|
+
console.error("Error fetching conversation history:", error);
|
|
301
|
+
// Clear invalid conversation ID from storage
|
|
302
|
+
updateConversationToken(null);
|
|
303
|
+
if (onError) {
|
|
304
|
+
onError(`Error fetching conversation history: ${error}`, "conversation_history");
|
|
305
|
+
}
|
|
306
|
+
return [];
|
|
307
|
+
}
|
|
308
|
+
};
|
|
309
|
+
(0, react_1.useEffect)(() => {
|
|
274
310
|
if (!apiKey) {
|
|
275
311
|
console.error("Blumessage Chat: API key is required");
|
|
276
|
-
|
|
312
|
+
const errorMessage = "API key is required";
|
|
277
313
|
setError(errorMessage);
|
|
278
314
|
if (onError) {
|
|
279
315
|
onError(errorMessage, "missing_api_key");
|
|
@@ -281,225 +317,196 @@ export var BlumessageChat = forwardRef(function (_a, ref) {
|
|
|
281
317
|
return;
|
|
282
318
|
}
|
|
283
319
|
// Validate API key with Blumessage API
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
case 1:
|
|
301
|
-
response = _a.sent();
|
|
302
|
-
if (response.ok) {
|
|
303
|
-
console.log("Blumessage chat initialized successfully");
|
|
304
|
-
setIsInitialized(true);
|
|
305
|
-
setError(null);
|
|
306
|
-
}
|
|
307
|
-
else {
|
|
308
|
-
console.error("Blumessage chat initialization failed:", response.status, response.statusText);
|
|
309
|
-
errorMessage = "Unable to connect - invalid API key";
|
|
310
|
-
setError(errorMessage);
|
|
311
|
-
setIsInitialized(false);
|
|
312
|
-
if (onError) {
|
|
313
|
-
onError(errorMessage, "api_key_validation");
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
return [3 /*break*/, 3];
|
|
317
|
-
case 2:
|
|
318
|
-
err_1 = _a.sent();
|
|
319
|
-
console.error("Blumessage chat initialization error:", err_1);
|
|
320
|
-
errorMessage = "Unable to connect - network error";
|
|
321
|
-
setError(errorMessage);
|
|
322
|
-
setIsInitialized(false);
|
|
323
|
-
if (onError) {
|
|
324
|
-
onError(errorMessage, "network_error");
|
|
325
|
-
}
|
|
326
|
-
return [3 /*break*/, 3];
|
|
327
|
-
case 3: return [2 /*return*/];
|
|
320
|
+
const validateApiKey = async () => {
|
|
321
|
+
try {
|
|
322
|
+
setIsInitialized(false);
|
|
323
|
+
setError(null);
|
|
324
|
+
console.log("Initializing Blumessage chat...");
|
|
325
|
+
const response = await fetch('https://api.blumessage.com/api/v1/api-keys/validate', {
|
|
326
|
+
method: 'POST',
|
|
327
|
+
headers: {
|
|
328
|
+
'Content-Type': 'application/json',
|
|
329
|
+
},
|
|
330
|
+
body: JSON.stringify({ apiKey }),
|
|
331
|
+
});
|
|
332
|
+
if (response.ok) {
|
|
333
|
+
console.log("Blumessage chat initialized successfully");
|
|
334
|
+
setIsInitialized(true);
|
|
335
|
+
setError(null);
|
|
328
336
|
}
|
|
329
|
-
|
|
330
|
-
|
|
337
|
+
else {
|
|
338
|
+
console.error("Blumessage chat initialization failed:", response.status, response.statusText);
|
|
339
|
+
const errorMessage = "Unable to connect - invalid API key";
|
|
340
|
+
setError(errorMessage);
|
|
341
|
+
setIsInitialized(false);
|
|
342
|
+
if (onError) {
|
|
343
|
+
onError(errorMessage, "api_key_validation");
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
catch (err) {
|
|
348
|
+
console.error("Blumessage chat initialization error:", err);
|
|
349
|
+
const errorMessage = "Unable to connect - network error";
|
|
350
|
+
setError(errorMessage);
|
|
351
|
+
setIsInitialized(false);
|
|
352
|
+
if (onError) {
|
|
353
|
+
onError(errorMessage, "network_error");
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
};
|
|
331
357
|
validateApiKey();
|
|
332
358
|
}, [apiKey]);
|
|
333
359
|
// Handle initial message loading (only runs once on mount)
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
// Warn if both are provided - initialMessages takes precedence
|
|
344
|
-
console.warn('Both initialMessages and token provided. Using initialMessages and ignoring stored token.');
|
|
345
|
-
setMessages(initialMessages);
|
|
346
|
-
return [3 /*break*/, 5];
|
|
347
|
-
case 1:
|
|
348
|
-
if (!(initialMessages.length > 0)) return [3 /*break*/, 2];
|
|
349
|
-
// Use provided initial messages
|
|
350
|
-
setMessages(initialMessages);
|
|
351
|
-
return [3 /*break*/, 5];
|
|
352
|
-
case 2:
|
|
353
|
-
if (!token) return [3 /*break*/, 4];
|
|
354
|
-
return [4 /*yield*/, fetchConversationHistory(token)];
|
|
355
|
-
case 3:
|
|
356
|
-
historyMessages = _a.sent();
|
|
357
|
-
setMessages(historyMessages); // Will be empty array if fetch failed
|
|
358
|
-
return [3 /*break*/, 5];
|
|
359
|
-
case 4:
|
|
360
|
-
// No conversation ID and no initial messages - start with empty array
|
|
361
|
-
setMessages([]);
|
|
362
|
-
_a.label = 5;
|
|
363
|
-
case 5: return [2 /*return*/];
|
|
360
|
+
(0, react_1.useEffect)(() => {
|
|
361
|
+
const loadInitialMessages = async () => {
|
|
362
|
+
if (isInitialLoad.current) {
|
|
363
|
+
isInitialLoad.current = false;
|
|
364
|
+
// Handle message initialization based on conversation state
|
|
365
|
+
if (initialMessages.length > 0 && token) {
|
|
366
|
+
// Warn if both are provided - initialMessages takes precedence
|
|
367
|
+
console.warn('Both initialMessages and token provided. Using initialMessages and ignoring stored token.');
|
|
368
|
+
setMessages(initialMessages);
|
|
364
369
|
}
|
|
365
|
-
|
|
366
|
-
|
|
370
|
+
else if (initialMessages.length > 0) {
|
|
371
|
+
// Use provided initial messages
|
|
372
|
+
setMessages(initialMessages);
|
|
373
|
+
}
|
|
374
|
+
else if (token) {
|
|
375
|
+
// Fetch conversation history if we have a stored conversation ID
|
|
376
|
+
const historyMessages = await fetchConversationHistory(token);
|
|
377
|
+
setMessages(historyMessages); // Will be empty array if fetch failed
|
|
378
|
+
}
|
|
379
|
+
else {
|
|
380
|
+
// No conversation ID and no initial messages - start with empty array
|
|
381
|
+
setMessages([]);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
};
|
|
367
385
|
// Only load initial messages after API key is validated
|
|
368
386
|
if (isInitialized) {
|
|
369
387
|
loadInitialMessages();
|
|
370
388
|
}
|
|
371
389
|
}, [isInitialized]);
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
apiResponse = _a.sent();
|
|
418
|
-
// Update token from response (for both first message and continuing conversations)
|
|
419
|
-
updateConversationToken(apiResponse.token);
|
|
420
|
-
assistantMessages = apiResponse.messages.filter(function (msg) { return msg.role === 'assistant'; });
|
|
421
|
-
latestAssistantMessage = assistantMessages[assistantMessages.length - 1];
|
|
422
|
-
if (latestAssistantMessage) {
|
|
423
|
-
assistantResponse_1 = {
|
|
424
|
-
id: (Date.now() + 1).toString(),
|
|
425
|
-
content: latestAssistantMessage.content,
|
|
426
|
-
role: 'assistant',
|
|
427
|
-
timestamp: latestAssistantMessage.timestamp,
|
|
428
|
-
};
|
|
429
|
-
setMessages(function (prev) { return __spreadArray(__spreadArray([], prev, true), [assistantResponse_1], false); });
|
|
430
|
-
if (onAssistantMessage) {
|
|
431
|
-
onAssistantMessage(assistantResponse_1);
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
return [3 /*break*/, 5];
|
|
435
|
-
case 4:
|
|
436
|
-
console.error('Failed to send message to Blumessage API:', response.status, response.statusText);
|
|
437
|
-
// If token is invalid, clear it
|
|
438
|
-
if (response.status === 401 || response.status === 403) {
|
|
439
|
-
updateConversationToken(null);
|
|
440
|
-
}
|
|
441
|
-
errorMessage_1 = {
|
|
442
|
-
id: (Date.now() + 1).toString(),
|
|
443
|
-
content: "Sorry, I'm having trouble connecting right now. Please try again.",
|
|
444
|
-
role: 'assistant',
|
|
445
|
-
timestamp: Date.now(),
|
|
446
|
-
};
|
|
447
|
-
setMessages(function (prev) { return __spreadArray(__spreadArray([], prev, true), [errorMessage_1], false); });
|
|
448
|
-
if (onError) {
|
|
449
|
-
onError("Failed to send message: ".concat(response.status, " ").concat(response.statusText), "message_send");
|
|
450
|
-
}
|
|
451
|
-
_a.label = 5;
|
|
452
|
-
case 5: return [3 /*break*/, 8];
|
|
453
|
-
case 6:
|
|
454
|
-
error_2 = _a.sent();
|
|
455
|
-
console.error('Error sending message to Blumessage API:', error_2);
|
|
456
|
-
errorMessage_2 = {
|
|
390
|
+
const handleSendMessage = async () => {
|
|
391
|
+
if (!inputValue.trim() || isLoading)
|
|
392
|
+
return;
|
|
393
|
+
const userMessage = {
|
|
394
|
+
id: Date.now().toString(),
|
|
395
|
+
content: inputValue.trim(),
|
|
396
|
+
role: 'user',
|
|
397
|
+
timestamp: Date.now()
|
|
398
|
+
};
|
|
399
|
+
// Add user message to UI immediately
|
|
400
|
+
setMessages(prev => [...prev, userMessage]);
|
|
401
|
+
const currentInput = inputValue.trim();
|
|
402
|
+
setInputValue('');
|
|
403
|
+
setIsLoading(true);
|
|
404
|
+
// Call the callback if provided
|
|
405
|
+
if (onUserMessage) {
|
|
406
|
+
onUserMessage(userMessage);
|
|
407
|
+
}
|
|
408
|
+
try {
|
|
409
|
+
// Call Blumessage API
|
|
410
|
+
const requestBody = {
|
|
411
|
+
message: currentInput,
|
|
412
|
+
};
|
|
413
|
+
// Include token if we have one
|
|
414
|
+
if (token) {
|
|
415
|
+
requestBody.token = token;
|
|
416
|
+
}
|
|
417
|
+
const response = await fetch('https://api.blumessage.com/api/v1/conversations', {
|
|
418
|
+
method: 'POST',
|
|
419
|
+
headers: {
|
|
420
|
+
'Content-Type': 'application/json',
|
|
421
|
+
'Authorization': `Bearer ${apiKey}`,
|
|
422
|
+
},
|
|
423
|
+
body: JSON.stringify(requestBody),
|
|
424
|
+
});
|
|
425
|
+
if (response.ok) {
|
|
426
|
+
const apiResponse = await response.json();
|
|
427
|
+
// Update token from response (for both first message and continuing conversations)
|
|
428
|
+
updateConversationToken(apiResponse.token);
|
|
429
|
+
// Find the assistant's response (the last message that's not from user)
|
|
430
|
+
const assistantMessages = apiResponse.messages.filter(msg => msg.role === 'assistant');
|
|
431
|
+
const latestAssistantMessage = assistantMessages[assistantMessages.length - 1];
|
|
432
|
+
if (latestAssistantMessage) {
|
|
433
|
+
// Add assistant's response to messages
|
|
434
|
+
const assistantResponse = {
|
|
457
435
|
id: (Date.now() + 1).toString(),
|
|
458
|
-
content:
|
|
436
|
+
content: latestAssistantMessage.content,
|
|
459
437
|
role: 'assistant',
|
|
460
|
-
timestamp:
|
|
438
|
+
timestamp: latestAssistantMessage.timestamp,
|
|
461
439
|
};
|
|
462
|
-
setMessages(
|
|
463
|
-
if (
|
|
464
|
-
|
|
440
|
+
setMessages(prev => [...prev, assistantResponse]);
|
|
441
|
+
if (onAssistantMessage) {
|
|
442
|
+
onAssistantMessage(assistantResponse);
|
|
465
443
|
}
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
else {
|
|
447
|
+
console.error('Failed to send message to Blumessage API:', response.status, response.statusText);
|
|
448
|
+
// If token is invalid, clear it
|
|
449
|
+
if (response.status === 401 || response.status === 403) {
|
|
450
|
+
updateConversationToken(null);
|
|
451
|
+
}
|
|
452
|
+
// Add error message
|
|
453
|
+
const errorMessage = {
|
|
454
|
+
id: (Date.now() + 1).toString(),
|
|
455
|
+
content: "Sorry, I'm having trouble connecting right now. Please try again.",
|
|
456
|
+
role: 'assistant',
|
|
457
|
+
timestamp: Date.now(),
|
|
458
|
+
};
|
|
459
|
+
setMessages(prev => [...prev, errorMessage]);
|
|
460
|
+
if (onError) {
|
|
461
|
+
onError(`Failed to send message: ${response.status} ${response.statusText}`, "message_send");
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
catch (error) {
|
|
466
|
+
console.error('Error sending message to Blumessage API:', error);
|
|
467
|
+
// Add error message
|
|
468
|
+
const errorMessage = {
|
|
469
|
+
id: (Date.now() + 1).toString(),
|
|
470
|
+
content: "Sorry, I'm having trouble connecting right now. Please try again.",
|
|
471
|
+
role: 'assistant',
|
|
472
|
+
timestamp: Date.now(),
|
|
473
|
+
};
|
|
474
|
+
setMessages(prev => [...prev, errorMessage]);
|
|
475
|
+
if (onError) {
|
|
476
|
+
onError(`Error sending message: ${error}`, "message_send");
|
|
471
477
|
}
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
|
|
478
|
+
}
|
|
479
|
+
finally {
|
|
480
|
+
setIsLoading(false);
|
|
481
|
+
}
|
|
482
|
+
};
|
|
483
|
+
const handleKeyPress = (e) => {
|
|
475
484
|
if (e.key === 'Enter' && !e.shiftKey && !isLoading) {
|
|
476
485
|
e.preventDefault();
|
|
477
486
|
handleSendMessage();
|
|
478
487
|
}
|
|
479
488
|
};
|
|
480
489
|
// Auto-scroll to bottom when messages change
|
|
481
|
-
|
|
482
|
-
var _a;
|
|
490
|
+
(0, react_1.useEffect)(() => {
|
|
483
491
|
if (!disableAutoScroll) {
|
|
484
|
-
|
|
492
|
+
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
|
|
485
493
|
}
|
|
486
494
|
}, [messages]);
|
|
487
495
|
// Auto-scroll to bottom when chat widget opens
|
|
488
|
-
|
|
496
|
+
(0, react_1.useEffect)(() => {
|
|
489
497
|
if (isOpen && floating && !disableAutoScroll) {
|
|
490
498
|
// Add a small delay to ensure the DOM is updated after the animation starts
|
|
491
|
-
setTimeout(
|
|
492
|
-
|
|
493
|
-
(_a = messagesEndRef.current) === null || _a === void 0 ? void 0 : _a.scrollIntoView({ behavior: 'smooth' });
|
|
499
|
+
setTimeout(() => {
|
|
500
|
+
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
|
|
494
501
|
}, 50);
|
|
495
502
|
}
|
|
496
503
|
}, [isOpen, floating, disableAutoScroll]);
|
|
497
504
|
// Handle opening the chat with animation
|
|
498
|
-
|
|
505
|
+
const handleOpenChat = () => {
|
|
499
506
|
if (!isOpen && !isAnimating) {
|
|
500
507
|
setIsAnimating(true);
|
|
501
508
|
// Small delay to ensure smooth animation start
|
|
502
|
-
setTimeout(
|
|
509
|
+
setTimeout(() => {
|
|
503
510
|
setIsOpen(true);
|
|
504
511
|
// Call the callback after the chat is open
|
|
505
512
|
if (onChatWidgetOpen) {
|
|
@@ -507,13 +514,13 @@ export var BlumessageChat = forwardRef(function (_a, ref) {
|
|
|
507
514
|
}
|
|
508
515
|
}, 10);
|
|
509
516
|
// Animation duration
|
|
510
|
-
setTimeout(
|
|
517
|
+
setTimeout(() => {
|
|
511
518
|
setIsAnimating(false);
|
|
512
519
|
}, 300);
|
|
513
520
|
}
|
|
514
521
|
};
|
|
515
522
|
// Handle closing the chat with animation
|
|
516
|
-
|
|
523
|
+
const handleCloseChat = () => {
|
|
517
524
|
if (isOpen && !isAnimating) {
|
|
518
525
|
setIsAnimating(true);
|
|
519
526
|
setIsOpen(false);
|
|
@@ -524,155 +531,146 @@ export var BlumessageChat = forwardRef(function (_a, ref) {
|
|
|
524
531
|
onChatWidgetClosed();
|
|
525
532
|
}
|
|
526
533
|
// Wait for animation to complete
|
|
527
|
-
setTimeout(
|
|
534
|
+
setTimeout(() => {
|
|
528
535
|
setIsAnimating(false);
|
|
529
536
|
}, 300);
|
|
530
537
|
}
|
|
531
538
|
};
|
|
532
539
|
// Handle maximize/minimize toggle
|
|
533
|
-
|
|
540
|
+
const handleToggleMaximize = () => {
|
|
534
541
|
setIsMaximized(!isMaximized);
|
|
535
542
|
};
|
|
536
543
|
// Get the icon component based on the icon prop
|
|
537
|
-
|
|
544
|
+
const getIconComponent = () => {
|
|
538
545
|
// More permissive icon matching - handle various naming patterns
|
|
539
|
-
|
|
546
|
+
const iconName = icon.toLowerCase().replace(/[-_\s]/g, '');
|
|
540
547
|
// Try to match common icon patterns
|
|
541
548
|
if (iconName.includes('message') || iconName.includes('chat')) {
|
|
542
549
|
if (iconName.includes('square'))
|
|
543
|
-
return MessageSquare;
|
|
544
|
-
return MessageCircle;
|
|
550
|
+
return lucide_react_1.MessageSquare;
|
|
551
|
+
return lucide_react_1.MessageCircle;
|
|
545
552
|
}
|
|
546
553
|
if (iconName.includes('bot') || iconName.includes('robot'))
|
|
547
|
-
return Bot;
|
|
554
|
+
return lucide_react_1.Bot;
|
|
548
555
|
if (iconName.includes('phone') || iconName.includes('call'))
|
|
549
|
-
return Phone;
|
|
556
|
+
return lucide_react_1.Phone;
|
|
550
557
|
if (iconName.includes('mail') || iconName.includes('email'))
|
|
551
|
-
return Mail;
|
|
558
|
+
return lucide_react_1.Mail;
|
|
552
559
|
if (iconName.includes('headphone') || iconName.includes('support'))
|
|
553
|
-
return Headphones;
|
|
560
|
+
return lucide_react_1.Headphones;
|
|
554
561
|
if (iconName.includes('user')) {
|
|
555
562
|
if (iconName.includes('users') || iconName.includes('group'))
|
|
556
|
-
return Users;
|
|
557
|
-
return User;
|
|
563
|
+
return lucide_react_1.Users;
|
|
564
|
+
return lucide_react_1.User;
|
|
558
565
|
}
|
|
559
566
|
if (iconName.includes('heart') || iconName.includes('like') || iconName.includes('love'))
|
|
560
|
-
return Heart;
|
|
567
|
+
return lucide_react_1.Heart;
|
|
561
568
|
if (iconName.includes('star') || iconName.includes('favorite'))
|
|
562
|
-
return Star;
|
|
569
|
+
return lucide_react_1.Star;
|
|
563
570
|
if (iconName.includes('zap') || iconName.includes('lightning') || iconName.includes('bolt'))
|
|
564
|
-
return Zap;
|
|
571
|
+
return lucide_react_1.Zap;
|
|
565
572
|
// Default fallback
|
|
566
|
-
return MessageCircle;
|
|
573
|
+
return lucide_react_1.MessageCircle;
|
|
567
574
|
};
|
|
568
575
|
// Expose methods to parent component via ref
|
|
569
|
-
useImperativeHandle(ref,
|
|
570
|
-
sendMessage:
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
}
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
apiResponse = _a.sent();
|
|
615
|
-
// Update token from response (for both first message and continuing conversations)
|
|
616
|
-
updateConversationToken(apiResponse.token);
|
|
617
|
-
assistantMessages = apiResponse.messages.filter(function (msg) { return msg.role === 'assistant'; });
|
|
618
|
-
latestAssistantMessage = assistantMessages[assistantMessages.length - 1];
|
|
619
|
-
if (latestAssistantMessage) {
|
|
620
|
-
assistantResponse_2 = {
|
|
621
|
-
id: (Date.now() + 1).toString(),
|
|
622
|
-
content: latestAssistantMessage.content,
|
|
623
|
-
role: 'assistant',
|
|
624
|
-
timestamp: latestAssistantMessage.timestamp,
|
|
625
|
-
};
|
|
626
|
-
setMessages(function (prev) { return __spreadArray(__spreadArray([], prev, true), [assistantResponse_2], false); });
|
|
627
|
-
if (onAssistantMessage) {
|
|
628
|
-
onAssistantMessage(assistantResponse_2);
|
|
629
|
-
}
|
|
630
|
-
}
|
|
631
|
-
return [3 /*break*/, 5];
|
|
632
|
-
case 4:
|
|
633
|
-
console.error('Failed to send message to Blumessage API:', response.status, response.statusText);
|
|
634
|
-
// If token is invalid, clear it
|
|
635
|
-
if (response.status === 401 || response.status === 403) {
|
|
636
|
-
updateConversationToken(null);
|
|
637
|
-
}
|
|
638
|
-
errorMessage_3 = {
|
|
639
|
-
id: (Date.now() + 1).toString(),
|
|
640
|
-
content: "Sorry, I'm having trouble connecting right now. Please try again.",
|
|
641
|
-
role: 'assistant',
|
|
642
|
-
timestamp: Date.now(),
|
|
643
|
-
};
|
|
644
|
-
setMessages(function (prev) { return __spreadArray(__spreadArray([], prev, true), [errorMessage_3], false); });
|
|
645
|
-
if (onError) {
|
|
646
|
-
onError("Failed to send message: ".concat(response.status, " ").concat(response.statusText), "message_send");
|
|
647
|
-
}
|
|
648
|
-
_a.label = 5;
|
|
649
|
-
case 5: return [3 /*break*/, 8];
|
|
650
|
-
case 6:
|
|
651
|
-
error_3 = _a.sent();
|
|
652
|
-
console.error('Error sending message to Blumessage API:', error_3);
|
|
653
|
-
errorMessage_4 = {
|
|
576
|
+
(0, react_1.useImperativeHandle)(ref, () => ({
|
|
577
|
+
sendMessage: async (message) => {
|
|
578
|
+
if (!message.trim() || isLoading)
|
|
579
|
+
return;
|
|
580
|
+
const userMessage = {
|
|
581
|
+
id: Date.now().toString(),
|
|
582
|
+
content: message.trim(),
|
|
583
|
+
role: 'user',
|
|
584
|
+
timestamp: Date.now()
|
|
585
|
+
};
|
|
586
|
+
// Add user message to UI immediately
|
|
587
|
+
setMessages(prev => [...prev, userMessage]);
|
|
588
|
+
const currentInput = message.trim();
|
|
589
|
+
setIsLoading(true);
|
|
590
|
+
// Call the callback if provided
|
|
591
|
+
if (onUserMessage) {
|
|
592
|
+
onUserMessage(userMessage);
|
|
593
|
+
}
|
|
594
|
+
try {
|
|
595
|
+
// Call Blumessage API
|
|
596
|
+
const requestBody = {
|
|
597
|
+
message: currentInput,
|
|
598
|
+
};
|
|
599
|
+
// Include token if we have one
|
|
600
|
+
if (token) {
|
|
601
|
+
requestBody.token = token;
|
|
602
|
+
}
|
|
603
|
+
const response = await fetch('https://api.blumessage.com/api/v1/conversations', {
|
|
604
|
+
method: 'POST',
|
|
605
|
+
headers: {
|
|
606
|
+
'Content-Type': 'application/json',
|
|
607
|
+
'Authorization': `Bearer ${apiKey}`,
|
|
608
|
+
},
|
|
609
|
+
body: JSON.stringify(requestBody),
|
|
610
|
+
});
|
|
611
|
+
if (response.ok) {
|
|
612
|
+
const apiResponse = await response.json();
|
|
613
|
+
// Update token from response (for both first message and continuing conversations)
|
|
614
|
+
updateConversationToken(apiResponse.token);
|
|
615
|
+
// Find the assistant's response (the last message that's not from user)
|
|
616
|
+
const assistantMessages = apiResponse.messages.filter(msg => msg.role === 'assistant');
|
|
617
|
+
const latestAssistantMessage = assistantMessages[assistantMessages.length - 1];
|
|
618
|
+
if (latestAssistantMessage) {
|
|
619
|
+
// Add assistant's response to messages
|
|
620
|
+
const assistantResponse = {
|
|
654
621
|
id: (Date.now() + 1).toString(),
|
|
655
|
-
content:
|
|
622
|
+
content: latestAssistantMessage.content,
|
|
656
623
|
role: 'assistant',
|
|
657
|
-
timestamp:
|
|
624
|
+
timestamp: latestAssistantMessage.timestamp,
|
|
658
625
|
};
|
|
659
|
-
setMessages(
|
|
660
|
-
if (
|
|
661
|
-
|
|
626
|
+
setMessages(prev => [...prev, assistantResponse]);
|
|
627
|
+
if (onAssistantMessage) {
|
|
628
|
+
onAssistantMessage(assistantResponse);
|
|
662
629
|
}
|
|
663
|
-
|
|
664
|
-
case 7:
|
|
665
|
-
setIsLoading(false);
|
|
666
|
-
return [7 /*endfinally*/];
|
|
667
|
-
case 8: return [2 /*return*/];
|
|
630
|
+
}
|
|
668
631
|
}
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
632
|
+
else {
|
|
633
|
+
console.error('Failed to send message to Blumessage API:', response.status, response.statusText);
|
|
634
|
+
// If token is invalid, clear it
|
|
635
|
+
if (response.status === 401 || response.status === 403) {
|
|
636
|
+
updateConversationToken(null);
|
|
637
|
+
}
|
|
638
|
+
// Add error message
|
|
639
|
+
const errorMessage = {
|
|
640
|
+
id: (Date.now() + 1).toString(),
|
|
641
|
+
content: "Sorry, I'm having trouble connecting right now. Please try again.",
|
|
642
|
+
role: 'assistant',
|
|
643
|
+
timestamp: Date.now(),
|
|
644
|
+
};
|
|
645
|
+
setMessages(prev => [...prev, errorMessage]);
|
|
646
|
+
if (onError) {
|
|
647
|
+
onError(`Failed to send message: ${response.status} ${response.statusText}`, "message_send");
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
catch (error) {
|
|
652
|
+
console.error('Error sending message to Blumessage API:', error);
|
|
653
|
+
// Add error message
|
|
654
|
+
const errorMessage = {
|
|
655
|
+
id: (Date.now() + 1).toString(),
|
|
656
|
+
content: "Sorry, I'm having trouble connecting right now. Please try again.",
|
|
657
|
+
role: 'assistant',
|
|
658
|
+
timestamp: Date.now(),
|
|
659
|
+
};
|
|
660
|
+
setMessages(prev => [...prev, errorMessage]);
|
|
661
|
+
if (onError) {
|
|
662
|
+
onError(`Error sending message: ${error}`, "message_send");
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
finally {
|
|
666
|
+
setIsLoading(false);
|
|
667
|
+
}
|
|
668
|
+
},
|
|
669
|
+
openChat: () => {
|
|
672
670
|
if (!isOpen && !isAnimating) {
|
|
673
671
|
setIsAnimating(true);
|
|
674
672
|
// Small delay to ensure smooth animation start
|
|
675
|
-
setTimeout(
|
|
673
|
+
setTimeout(() => {
|
|
676
674
|
setIsOpen(true);
|
|
677
675
|
// Call the callback after the chat is open
|
|
678
676
|
if (onChatWidgetOpen) {
|
|
@@ -680,12 +678,12 @@ export var BlumessageChat = forwardRef(function (_a, ref) {
|
|
|
680
678
|
}
|
|
681
679
|
}, 10);
|
|
682
680
|
// Animation duration
|
|
683
|
-
setTimeout(
|
|
681
|
+
setTimeout(() => {
|
|
684
682
|
setIsAnimating(false);
|
|
685
683
|
}, 300);
|
|
686
684
|
}
|
|
687
685
|
},
|
|
688
|
-
closeChat:
|
|
686
|
+
closeChat: () => {
|
|
689
687
|
if (isOpen && !isAnimating) {
|
|
690
688
|
setIsAnimating(true);
|
|
691
689
|
setIsOpen(false);
|
|
@@ -696,21 +694,21 @@ export var BlumessageChat = forwardRef(function (_a, ref) {
|
|
|
696
694
|
onChatWidgetClosed();
|
|
697
695
|
}
|
|
698
696
|
// Wait for animation to complete
|
|
699
|
-
setTimeout(
|
|
697
|
+
setTimeout(() => {
|
|
700
698
|
setIsAnimating(false);
|
|
701
699
|
}, 300);
|
|
702
700
|
}
|
|
703
701
|
},
|
|
704
|
-
clearConversation:
|
|
702
|
+
clearConversation: () => {
|
|
705
703
|
setMessages([]);
|
|
706
704
|
updateConversationToken(null);
|
|
707
705
|
},
|
|
708
|
-
getMessages:
|
|
709
|
-
getToken:
|
|
710
|
-
})
|
|
706
|
+
getMessages: () => messages,
|
|
707
|
+
getToken: () => token,
|
|
708
|
+
}));
|
|
711
709
|
// Helper function to get position styles for floating button
|
|
712
|
-
|
|
713
|
-
|
|
710
|
+
const getButtonPositionStyles = () => {
|
|
711
|
+
const baseStyles = {
|
|
714
712
|
position: 'fixed',
|
|
715
713
|
zIndex: 1000,
|
|
716
714
|
opacity: isOpen ? 0 : 1,
|
|
@@ -719,32 +717,38 @@ export var BlumessageChat = forwardRef(function (_a, ref) {
|
|
|
719
717
|
};
|
|
720
718
|
// Mobile-specific positioning
|
|
721
719
|
if (isMobile) {
|
|
722
|
-
return
|
|
720
|
+
return {
|
|
721
|
+
...baseStyles,
|
|
722
|
+
bottom: '20px',
|
|
723
|
+
right: '20px',
|
|
724
|
+
left: 'auto',
|
|
725
|
+
top: 'auto'
|
|
726
|
+
};
|
|
723
727
|
}
|
|
724
728
|
// Desktop positioning
|
|
725
729
|
switch (buttonPosition) {
|
|
726
730
|
case 'bottom-right':
|
|
727
|
-
return
|
|
731
|
+
return { ...baseStyles, bottom: '24px', right: '24px' };
|
|
728
732
|
case 'bottom-left':
|
|
729
|
-
return
|
|
733
|
+
return { ...baseStyles, bottom: '24px', left: '24px' };
|
|
730
734
|
case 'top-right':
|
|
731
|
-
return
|
|
735
|
+
return { ...baseStyles, top: '24px', right: '24px' };
|
|
732
736
|
case 'top-left':
|
|
733
|
-
return
|
|
737
|
+
return { ...baseStyles, top: '24px', left: '24px' };
|
|
734
738
|
default:
|
|
735
|
-
return
|
|
739
|
+
return { ...baseStyles, bottom: '24px', right: '24px' };
|
|
736
740
|
}
|
|
737
741
|
};
|
|
738
742
|
// Helper function to get position styles for floating chat window
|
|
739
|
-
|
|
740
|
-
|
|
743
|
+
const getChatPositionStyles = () => {
|
|
744
|
+
const getTransform = () => {
|
|
741
745
|
if (!isOpen) {
|
|
742
746
|
// Slide down for bottom positions, slide up for top positions
|
|
743
|
-
return
|
|
747
|
+
return buttonPosition?.includes('bottom') ? 'translateY(100%)' : 'translateY(-100%)';
|
|
744
748
|
}
|
|
745
749
|
return 'translateY(0)';
|
|
746
750
|
};
|
|
747
|
-
|
|
751
|
+
const baseStyles = {
|
|
748
752
|
position: 'fixed',
|
|
749
753
|
zIndex: 999,
|
|
750
754
|
transform: getTransform(),
|
|
@@ -754,13 +758,21 @@ export var BlumessageChat = forwardRef(function (_a, ref) {
|
|
|
754
758
|
};
|
|
755
759
|
// Mobile-specific positioning (always fullscreen on mobile)
|
|
756
760
|
if (isMobile) {
|
|
757
|
-
return
|
|
761
|
+
return {
|
|
762
|
+
...baseStyles,
|
|
763
|
+
top: '0',
|
|
764
|
+
left: '0',
|
|
765
|
+
right: '0',
|
|
766
|
+
bottom: '0',
|
|
767
|
+
transform: isOpen ? 'translateY(0)' : 'translateY(100%)',
|
|
768
|
+
transformOrigin: 'bottom center',
|
|
769
|
+
};
|
|
758
770
|
}
|
|
759
771
|
// If fullScreen or maximized, override positioning to be centered and full screen
|
|
760
772
|
if (fullScreen || isMaximized) {
|
|
761
773
|
// Set transform origin and direction based on button position for proper animation
|
|
762
|
-
|
|
763
|
-
|
|
774
|
+
let transformOrigin = 'center';
|
|
775
|
+
let closedTransform = 'translateY(100%)';
|
|
764
776
|
switch (buttonPosition) {
|
|
765
777
|
case 'bottom-right':
|
|
766
778
|
transformOrigin = 'bottom right';
|
|
@@ -782,86 +794,94 @@ export var BlumessageChat = forwardRef(function (_a, ref) {
|
|
|
782
794
|
transformOrigin = 'bottom right';
|
|
783
795
|
closedTransform = 'translateY(100%)';
|
|
784
796
|
}
|
|
785
|
-
return
|
|
797
|
+
return {
|
|
798
|
+
...baseStyles,
|
|
799
|
+
top: '20px',
|
|
800
|
+
left: '20px',
|
|
801
|
+
right: '20px',
|
|
802
|
+
bottom: '20px',
|
|
803
|
+
transform: isOpen ? 'translateY(0)' : closedTransform,
|
|
804
|
+
transformOrigin,
|
|
805
|
+
};
|
|
786
806
|
}
|
|
787
807
|
// Desktop positioning
|
|
788
808
|
switch (buttonPosition) {
|
|
789
809
|
case 'bottom-right':
|
|
790
|
-
return
|
|
810
|
+
return { ...baseStyles, bottom: '24px', right: '24px', transformOrigin: 'bottom right' };
|
|
791
811
|
case 'bottom-left':
|
|
792
|
-
return
|
|
812
|
+
return { ...baseStyles, bottom: '24px', left: '24px', transformOrigin: 'bottom left' };
|
|
793
813
|
case 'top-right':
|
|
794
|
-
return
|
|
814
|
+
return { ...baseStyles, top: '24px', right: '24px', transformOrigin: 'top right' };
|
|
795
815
|
case 'top-left':
|
|
796
|
-
return
|
|
816
|
+
return { ...baseStyles, top: '24px', left: '24px', transformOrigin: 'top left' };
|
|
797
817
|
default:
|
|
798
|
-
return
|
|
818
|
+
return { ...baseStyles, bottom: '24px', right: '24px', transformOrigin: 'bottom right' };
|
|
799
819
|
}
|
|
800
820
|
};
|
|
801
|
-
|
|
802
|
-
return (
|
|
821
|
+
const renderMessage = (message) => {
|
|
822
|
+
return ((0, jsx_runtime_1.jsx)("div", { className: `blumessage-flex blumessage-gap-3 blumessage-mb-4 ${message.role === 'user' ? 'blumessage-flex-row-reverse' : ''}`, children: (0, jsx_runtime_1.jsxs)("div", { className: "blumessage-flex blumessage-flex-col blumessage-gap-1 blumessage-max-w-[80%]", children: [(0, jsx_runtime_1.jsx)("div", { className: `blumessage-rounded-lg blumessage-px-4 blumessage-py-2 ${message.role === 'user'
|
|
803
823
|
? 'blumessage-bg-gradient-to-r blumessage-from-blue-500 blumessage-to-purple-600 blumessage-text-white'
|
|
804
824
|
: theme === 'light'
|
|
805
825
|
? 'blumessage-bg-gray-100'
|
|
806
|
-
: 'blumessage-bg-gray-700'
|
|
826
|
+
: 'blumessage-bg-gray-700'}`, children: message.role === 'assistant' ? ((0, jsx_runtime_1.jsx)("div", { className: `blumessage-prose ${theme === 'dark' ? 'blumessage-text-white' : 'blumessage-text-gray-900'}`, children: markdown ? ((0, jsx_runtime_1.jsx)(react_markdown_1.default, { remarkPlugins: [remark_gfm_1.default], children: message.content }, `assistant-${message.id}`)) : ((0, jsx_runtime_1.jsx)("p", { className: "blumessage-text-sm blumessage-whitespace-pre-wrap", children: message.content })) })) : ((0, jsx_runtime_1.jsx)("div", { className: "blumessage-text-sm blumessage-whitespace-pre-wrap blumessage-text-white", children: markdown ? ((0, jsx_runtime_1.jsx)(react_markdown_1.default, { remarkPlugins: [remark_gfm_1.default], children: message.content }, `user-${message.id}`)) : ((0, jsx_runtime_1.jsx)("p", { className: "blumessage-text-sm blumessage-whitespace-pre-wrap", children: message.content })) })) }), showTimestamps && ((0, jsx_runtime_1.jsx)("span", { className: "blumessage-text-xs blumessage-text-gray-500", children: formatTimestamp(message.timestamp) }))] }) }, message.id));
|
|
807
827
|
};
|
|
808
828
|
// Render chat window component
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
829
|
+
const renderChatWindow = () => {
|
|
830
|
+
const isFullscreenMode = fullScreen || isMaximized || isMobile;
|
|
831
|
+
const chatContent = ((0, jsx_runtime_1.jsxs)("div", { className: `shadow-2xl flex flex-col overflow-hidden border ${isMobile ? 'blumessage-mobile-fullscreen' : ''} ${theme === 'dark'
|
|
812
832
|
? 'bg-gray-900 border-gray-700'
|
|
813
|
-
: 'bg-white border-black/10'
|
|
833
|
+
: 'bg-white border-black/10'}`, style: {
|
|
814
834
|
width: isFullscreenMode ? '100%' : actualWidth,
|
|
815
835
|
height: isFullscreenMode ? '100%' : actualHeight,
|
|
816
836
|
fontFamily: 'system-ui, -apple-system, sans-serif',
|
|
817
837
|
borderRadius: isMobile ? '0' : (isFullscreenMode ? '12px' : '24px')
|
|
818
|
-
}, children: [
|
|
838
|
+
}, children: [(0, jsx_runtime_1.jsxs)("div", { className: `border-b ${theme === 'dark'
|
|
819
839
|
? 'bg-gray-900 border-gray-700'
|
|
820
|
-
: 'bg-white border-gray-100'
|
|
840
|
+
: 'bg-white border-gray-100'}`, style: {
|
|
821
841
|
display: 'flex',
|
|
822
842
|
alignItems: 'center',
|
|
823
843
|
padding: isMobile ? '12px 16px' : '16px 24px'
|
|
824
|
-
}, children: [
|
|
844
|
+
}, children: [(0, jsx_runtime_1.jsx)("div", { className: "rounded-full flex items-center justify-center", style: {
|
|
825
845
|
backgroundImage: primaryColor,
|
|
826
846
|
width: isMobile ? '40px' : '48px',
|
|
827
847
|
height: isMobile ? '40px' : '48px',
|
|
828
848
|
marginRight: isMobile ? '16px' : '24px'
|
|
829
|
-
}, children:
|
|
849
|
+
}, children: react_1.default.createElement(getIconComponent(), {
|
|
830
850
|
className: isMobile ? "w-5 h-5 text-white" : "w-6 h-6 text-white"
|
|
831
|
-
}) }),
|
|
851
|
+
}) }), (0, jsx_runtime_1.jsxs)("div", { style: { flex: 1 }, children: [(0, jsx_runtime_1.jsx)("div", { className: `${isMobile ? 'text-base' : 'text-lg'} font-semibold m-0 leading-6 ${theme === 'dark' ? 'text-gray-100' : 'text-gray-900'}`, children: name }), (0, jsx_runtime_1.jsx)("div", { className: `text-sm m-0 leading-5 ${theme === 'dark' ? 'text-gray-400' : 'text-gray-500'}`, children: subtitle })] }), floating && ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-1", children: [maximizeToggleButton && !isMobile && ((0, jsx_runtime_1.jsx)("button", { onClick: handleToggleMaximize, className: `w-8 h-8 rounded-full flex items-center justify-center cursor-pointer transition-colors ${theme === 'dark'
|
|
832
852
|
? 'hover:bg-gray-800 text-gray-400 hover:text-gray-200'
|
|
833
|
-
: 'hover:bg-gray-100 text-gray-500 hover:text-gray-700'
|
|
853
|
+
: 'hover:bg-gray-100 text-gray-500 hover:text-gray-700'}`, children: isMaximized ? (0, jsx_runtime_1.jsx)(lucide_react_1.Minimize2, { className: "w-4 h-4" }) : (0, jsx_runtime_1.jsx)(lucide_react_1.Maximize, { className: "w-4 h-4" }) })), (0, jsx_runtime_1.jsx)("button", { onClick: handleCloseChat, className: `w-8 h-8 rounded-full flex items-center justify-center cursor-pointer transition-colors ${theme === 'dark'
|
|
834
854
|
? 'hover:bg-gray-800 text-gray-400 hover:text-gray-200'
|
|
835
|
-
: 'hover:bg-gray-100 text-gray-500 hover:text-gray-700'
|
|
855
|
+
: 'hover:bg-gray-100 text-gray-500 hover:text-gray-700'}`, children: (0, jsx_runtime_1.jsx)(lucide_react_1.X, { className: "w-4 h-4" }) })] }))] }), (0, jsx_runtime_1.jsxs)("div", { className: `flex-1 overflow-y-auto ${theme === 'dark' ? 'bg-gray-800' : 'bg-gray-50'}`, style: { padding: isMobile ? '12px 16px' : '16px 24px' }, children: [messages.map((message) => ((0, jsx_runtime_1.jsx)("div", { className: `flex ${message.role === 'user' ? 'justify-end' : 'justify-start'} mb-4`, children: (0, jsx_runtime_1.jsx)("div", { className: `${isMobile ? 'max-w-[85%]' : 'max-w-[80%]'} inline-block ${message.role === 'user' ? '' : 'text-left'}`, children: (0, jsx_runtime_1.jsxs)("div", { className: `inline-block px-4 py-3 rounded-2xl text-sm leading-6 text-left ${message.role === 'user'
|
|
836
856
|
? 'text-white'
|
|
837
857
|
: theme === 'dark'
|
|
838
858
|
? 'bg-gray-700 text-gray-100 border border-gray-600 shadow-sm'
|
|
839
|
-
: 'bg-white text-gray-800 border border-gray-200 shadow-sm'
|
|
859
|
+
: 'bg-white text-gray-800 border border-gray-200 shadow-sm'}`, style: message.role === 'user' ? { backgroundImage: primaryColor } : {}, children: [message.role === 'assistant' ? (markdown ? ((0, jsx_runtime_1.jsx)(react_markdown_1.default, { remarkPlugins: [remark_gfm_1.default], children: message.content }, `assistant-${message.id}`)) : ((0, jsx_runtime_1.jsx)("div", { className: "whitespace-pre-wrap", children: message.content }))) : ((0, jsx_runtime_1.jsx)("div", { className: "inline-block", children: markdown ? ((0, jsx_runtime_1.jsx)(react_markdown_1.default, { remarkPlugins: [remark_gfm_1.default], children: message.content }, `user-${message.id}`)) : ((0, jsx_runtime_1.jsx)("div", { className: "whitespace-pre-wrap", children: message.content })) })), showTimestamps && ((0, jsx_runtime_1.jsx)("div", { className: `text-[10px] mt-1 opacity-75 ${message.role === 'user'
|
|
840
860
|
? 'text-white/75'
|
|
841
861
|
: theme === 'dark'
|
|
842
862
|
? 'text-gray-400'
|
|
843
|
-
: 'text-gray-500'
|
|
863
|
+
: 'text-gray-500'}`, style: {
|
|
844
864
|
textAlign: message.role === 'user' ? 'right' : 'left'
|
|
845
|
-
}, children: formatTimestamp(message.timestamp) }))] }) }) }, message.id))
|
|
865
|
+
}, children: formatTimestamp(message.timestamp) }))] }) }) }, message.id))), isLoading && ((0, jsx_runtime_1.jsx)("div", { className: "flex justify-start mb-4", children: (0, jsx_runtime_1.jsx)("div", { className: `px-4 py-3 rounded-2xl ${isMobile ? 'max-w-[85%]' : 'max-w-[80%]'} text-sm leading-6 shadow-sm ${theme === 'dark'
|
|
846
866
|
? 'bg-gray-700 text-gray-100 border border-gray-600'
|
|
847
|
-
: 'bg-white text-gray-800 border border-gray-200'
|
|
867
|
+
: 'bg-white text-gray-800 border border-gray-200'}`, children: (0, jsx_runtime_1.jsx)("div", { className: `${theme === 'dark' ? 'text-gray-300' : 'text-gray-600'}`, style: { fontStyle: 'italic' }, children: typingText }) }) })), messages.length === 0 && !isLoading && ((0, jsx_runtime_1.jsx)("div", { className: `text-center text-sm py-8 ${theme === 'dark' ? 'text-gray-400' : 'text-gray-500'}`, children: emptyStateText })), (0, jsx_runtime_1.jsx)("div", { ref: messagesEndRef })] }), (0, jsx_runtime_1.jsx)("div", { className: `border-t ${theme === 'dark'
|
|
848
868
|
? 'bg-gray-900 border-gray-700'
|
|
849
|
-
: 'bg-white border-gray-100'
|
|
869
|
+
: 'bg-white border-gray-100'}`, style: { padding: isMobile ? '12px 16px' : '16px 24px' }, children: (0, jsx_runtime_1.jsxs)("div", { className: `flex items-center rounded-2xl px-4 py-3 border ${theme === 'dark'
|
|
850
870
|
? 'bg-gray-800 border-gray-600'
|
|
851
|
-
: 'bg-gray-50 border-gray-200'
|
|
871
|
+
: 'bg-gray-50 border-gray-200'}`, children: [(0, jsx_runtime_1.jsx)("textarea", { className: `flex-1 border-none bg-transparent outline-none text-sm font-inherit resize-none ${theme === 'dark' ? 'text-gray-100' : 'text-gray-700'}`, placeholder: placeholder, value: inputValue, onChange: (e) => setInputValue(e.target.value), onKeyDown: handleKeyPress, rows: 1, style: {
|
|
852
872
|
minHeight: '20px',
|
|
853
873
|
maxHeight: isMobile ? '100px' : '120px',
|
|
854
874
|
overflowY: inputValue.split('\n').length > 4 ? 'auto' : 'hidden',
|
|
855
875
|
lineHeight: '1.5',
|
|
856
876
|
paddingTop: '2px',
|
|
857
877
|
paddingBottom: '2px'
|
|
858
|
-
}, onInput:
|
|
859
|
-
|
|
878
|
+
}, onInput: (e) => {
|
|
879
|
+
const target = e.target;
|
|
860
880
|
target.style.height = 'auto';
|
|
861
881
|
target.style.height = Math.min(target.scrollHeight, isMobile ? 100 : 120) + 'px';
|
|
862
|
-
} }),
|
|
882
|
+
} }), (0, jsx_runtime_1.jsx)("button", { className: "w-8 h-8 rounded-full border-none flex items-center justify-center cursor-pointer ml-2 text-white transition-all disabled:opacity-50 disabled:cursor-not-allowed", style: { backgroundImage: primaryColor }, onClick: handleSendMessage, disabled: !inputValue.trim() || isLoading, children: isLoading ? ((0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { className: "w-4 h-4 blumessage-animate-spin" })) : ((0, jsx_runtime_1.jsx)(lucide_react_1.Send, { className: "w-4 h-4" })) })] }) })] }));
|
|
863
883
|
if (floating) {
|
|
864
|
-
return (
|
|
884
|
+
return ((0, jsx_runtime_1.jsx)("div", { style: getChatPositionStyles(), children: chatContent }));
|
|
865
885
|
}
|
|
866
886
|
return chatContent;
|
|
867
887
|
};
|
|
@@ -870,62 +890,62 @@ export var BlumessageChat = forwardRef(function (_a, ref) {
|
|
|
870
890
|
return null;
|
|
871
891
|
}
|
|
872
892
|
if (error) {
|
|
873
|
-
|
|
874
|
-
|
|
893
|
+
const isFullscreenMode = fullScreen || isMaximized || isMobile;
|
|
894
|
+
const errorContent = ((0, jsx_runtime_1.jsxs)("div", { className: `shadow-2xl flex flex-col overflow-hidden border ${isMobile ? 'blumessage-mobile-fullscreen' : ''} ${theme === 'dark'
|
|
875
895
|
? 'bg-gray-900 border-gray-700'
|
|
876
|
-
: 'bg-white border-black/10'
|
|
896
|
+
: 'bg-white border-black/10'}`, style: {
|
|
877
897
|
width: isFullscreenMode ? '100%' : actualWidth,
|
|
878
898
|
height: isFullscreenMode ? '100%' : actualHeight,
|
|
879
899
|
fontFamily: 'system-ui, -apple-system, sans-serif',
|
|
880
900
|
borderRadius: isMobile ? '0' : (isFullscreenMode ? '12px' : '24px')
|
|
881
|
-
}, children: [
|
|
901
|
+
}, children: [(0, jsx_runtime_1.jsxs)("div", { className: `flex items-center border-b ${theme === 'dark'
|
|
882
902
|
? 'bg-gray-900 border-gray-700'
|
|
883
|
-
: 'bg-white border-gray-100'
|
|
903
|
+
: 'bg-white border-gray-100'}`, style: { padding: isMobile ? '12px 16px' : '16px 24px' }, children: [(0, jsx_runtime_1.jsx)("div", { className: "rounded-full flex items-center justify-center", style: {
|
|
884
904
|
backgroundColor: '#ef4444',
|
|
885
905
|
width: isMobile ? '40px' : '48px',
|
|
886
906
|
height: isMobile ? '40px' : '48px',
|
|
887
907
|
marginRight: isMobile ? '16px' : '24px'
|
|
888
|
-
}, children:
|
|
908
|
+
}, children: (0, jsx_runtime_1.jsx)(lucide_react_1.AlertTriangle, { className: isMobile ? "w-5 h-5 text-white" : "w-6 h-6 text-white" }) }), (0, jsx_runtime_1.jsxs)("div", { className: "flex-1", children: [(0, jsx_runtime_1.jsx)("div", { className: `${isMobile ? 'text-base' : 'text-lg'} font-semibold m-0 leading-6 ${theme === 'dark' ? 'text-gray-100' : 'text-gray-900'}`, children: "Connection Error" }), (0, jsx_runtime_1.jsx)("div", { className: `text-sm m-0 leading-5 ${theme === 'dark' ? 'text-gray-400' : 'text-gray-500'}`, children: "Unable to connect" })] }), floating && ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-1", children: [maximizeToggleButton && !isMobile && ((0, jsx_runtime_1.jsx)("button", { onClick: handleToggleMaximize, className: `w-8 h-8 rounded-full flex items-center justify-center cursor-pointer transition-colors ${theme === 'dark'
|
|
889
909
|
? 'hover:bg-gray-800 text-gray-400 hover:text-gray-200'
|
|
890
|
-
: 'hover:bg-gray-100 text-gray-500 hover:text-gray-700'
|
|
910
|
+
: 'hover:bg-gray-100 text-gray-500 hover:text-gray-700'}`, children: isMaximized ? (0, jsx_runtime_1.jsx)(lucide_react_1.Minimize2, { className: "w-4 h-4" }) : (0, jsx_runtime_1.jsx)(lucide_react_1.Maximize, { className: "w-4 h-4" }) })), (0, jsx_runtime_1.jsx)("button", { onClick: handleCloseChat, className: `w-8 h-8 rounded-full flex items-center justify-center cursor-pointer transition-colors ${theme === 'dark'
|
|
891
911
|
? 'hover:bg-gray-800 text-gray-400 hover:text-gray-200'
|
|
892
|
-
: 'hover:bg-gray-100 text-gray-500 hover:text-gray-700'
|
|
912
|
+
: 'hover:bg-gray-100 text-gray-500 hover:text-gray-700'}`, children: (0, jsx_runtime_1.jsx)(lucide_react_1.X, { className: "w-4 h-4" }) })] }))] }), (0, jsx_runtime_1.jsx)("div", { className: `flex-1 overflow-y-auto ${theme === 'dark' ? 'bg-gray-800' : 'bg-gray-50'}`, style: { padding: isMobile ? '12px 16px' : '16px 24px' }, children: (0, jsx_runtime_1.jsx)("div", { className: "flex justify-start", children: (0, jsx_runtime_1.jsx)("div", { className: `px-4 py-3 rounded-2xl ${isMobile ? 'max-w-[85%]' : 'max-w-[80%]'} text-sm leading-6 shadow-sm ${theme === 'dark'
|
|
893
913
|
? 'bg-gray-700 text-gray-100 border border-gray-600'
|
|
894
|
-
: 'bg-white text-gray-800 border border-gray-200'
|
|
914
|
+
: 'bg-white text-gray-800 border border-gray-200'}`, children: error }) }) })] }));
|
|
895
915
|
if (floating) {
|
|
896
|
-
return (
|
|
916
|
+
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("button", { onClick: handleOpenChat, className: `text-white rounded-full shadow-lg transition-all duration-200 flex items-center justify-center gap-2 ${isMobile ? 'blumessage-mobile-button' : ''} ${buttonText ? 'px-4 py-3 h-12' : 'w-14 h-14'}`, style: { ...getButtonPositionStyles(), ...buttonStyle, backgroundImage: primaryColor }, children: [react_1.default.createElement(getIconComponent(), { className: "w-6 h-6" }), buttonText && !isMobile && (0, jsx_runtime_1.jsx)("span", { className: "text-sm font-medium whitespace-nowrap", children: buttonText })] }), (0, jsx_runtime_1.jsx)("div", { style: getChatPositionStyles(), children: errorContent })] }));
|
|
897
917
|
}
|
|
898
918
|
return errorContent;
|
|
899
919
|
}
|
|
900
920
|
if (!isInitialized) {
|
|
901
|
-
|
|
902
|
-
|
|
921
|
+
const isFullscreenMode = fullScreen || isMaximized || isMobile;
|
|
922
|
+
const loadingContent = ((0, jsx_runtime_1.jsxs)("div", { className: `shadow-2xl flex flex-col overflow-hidden border ${isMobile ? 'blumessage-mobile-fullscreen' : ''} ${theme === 'dark'
|
|
903
923
|
? 'bg-gray-900 border-gray-700'
|
|
904
|
-
: 'bg-white border-black/10'
|
|
924
|
+
: 'bg-white border-black/10'}`, style: {
|
|
905
925
|
width: isFullscreenMode ? '100%' : actualWidth,
|
|
906
926
|
height: isFullscreenMode ? '100%' : actualHeight,
|
|
907
927
|
fontFamily: 'system-ui, -apple-system, sans-serif',
|
|
908
928
|
borderRadius: isMobile ? '0' : (isFullscreenMode ? '12px' : '24px')
|
|
909
|
-
}, children: [
|
|
929
|
+
}, children: [(0, jsx_runtime_1.jsxs)("div", { className: `flex items-center border-b ${theme === 'dark'
|
|
910
930
|
? 'bg-gray-900 border-gray-700'
|
|
911
|
-
: 'bg-white border-gray-100'
|
|
931
|
+
: 'bg-white border-gray-100'}`, style: { padding: isMobile ? '12px 16px' : '16px 24px' }, children: [(0, jsx_runtime_1.jsx)("div", { className: "rounded-full flex items-center justify-center", style: {
|
|
912
932
|
backgroundImage: primaryColor,
|
|
913
933
|
width: isMobile ? '40px' : '48px',
|
|
914
934
|
height: isMobile ? '40px' : '48px',
|
|
915
935
|
marginRight: isMobile ? '16px' : '24px'
|
|
916
|
-
}, children:
|
|
936
|
+
}, children: (0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { className: isMobile ? "w-5 h-5 text-white animate-spin" : "w-6 h-6 text-white animate-spin" }) }), (0, jsx_runtime_1.jsxs)("div", { className: "flex-1", children: [(0, jsx_runtime_1.jsx)("div", { className: `${isMobile ? 'text-base' : 'text-lg'} font-semibold m-0 leading-6 ${theme === 'dark' ? 'text-gray-100' : 'text-gray-900'}`, children: name }), (0, jsx_runtime_1.jsx)("div", { className: `text-sm m-0 leading-5 ${theme === 'dark' ? 'text-gray-400' : 'text-gray-500'}`, children: subtitle })] }), floating && ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-1", children: [maximizeToggleButton && !isMobile && ((0, jsx_runtime_1.jsx)("button", { onClick: handleToggleMaximize, className: `w-8 h-8 rounded-full flex items-center justify-center cursor-pointer transition-colors ${theme === 'dark'
|
|
917
937
|
? 'hover:bg-gray-800 text-gray-400 hover:text-gray-200'
|
|
918
|
-
: 'hover:bg-gray-100 text-gray-500 hover:text-gray-700'
|
|
938
|
+
: 'hover:bg-gray-100 text-gray-500 hover:text-gray-700'}`, children: isMaximized ? (0, jsx_runtime_1.jsx)(lucide_react_1.Minimize2, { className: "w-4 h-4" }) : (0, jsx_runtime_1.jsx)(lucide_react_1.Maximize, { className: "w-4 h-4" }) })), (0, jsx_runtime_1.jsx)("button", { onClick: handleCloseChat, className: `w-8 h-8 rounded-full flex items-center justify-center cursor-pointer transition-colors ${theme === 'dark'
|
|
919
939
|
? 'hover:bg-gray-800 text-gray-400 hover:text-gray-200'
|
|
920
|
-
: 'hover:bg-gray-100 text-gray-500 hover:text-gray-700'
|
|
940
|
+
: 'hover:bg-gray-100 text-gray-500 hover:text-gray-700'}`, children: (0, jsx_runtime_1.jsx)(lucide_react_1.X, { className: "w-4 h-4" }) })] }))] }), (0, jsx_runtime_1.jsx)("div", { className: `flex-1 overflow-y-auto ${theme === 'dark' ? 'bg-gray-800' : 'bg-gray-50'}`, style: { padding: isMobile ? '12px 16px' : '16px 24px' }, children: (0, jsx_runtime_1.jsx)("div", { className: `text-center text-sm py-8 ${theme === 'dark' ? 'text-gray-400' : 'text-gray-500'}`, children: "Ready to chat..." }) })] }));
|
|
921
941
|
if (floating) {
|
|
922
|
-
return (
|
|
942
|
+
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("button", { onClick: handleOpenChat, className: `text-white rounded-full shadow-lg transition-all duration-200 flex items-center justify-center gap-2 ${isMobile ? 'blumessage-mobile-button' : ''} ${buttonText ? 'px-4 py-3 h-12' : 'w-14 h-14'}`, style: { ...getButtonPositionStyles(), ...buttonStyle, backgroundImage: primaryColor }, children: [react_1.default.createElement(getIconComponent(), { className: "w-6 h-6" }), buttonText && !isMobile && (0, jsx_runtime_1.jsx)("span", { className: "text-sm font-medium whitespace-nowrap", children: buttonText })] }), (0, jsx_runtime_1.jsx)("div", { style: getChatPositionStyles(), children: loadingContent })] }));
|
|
923
943
|
}
|
|
924
944
|
return loadingContent;
|
|
925
945
|
}
|
|
926
946
|
// Main render for initialized state
|
|
927
947
|
if (floating) {
|
|
928
|
-
return (
|
|
948
|
+
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("button", { onClick: handleOpenChat, className: `text-white rounded-full shadow-lg transition-all duration-200 flex items-center justify-center gap-2 ${isMobile ? 'blumessage-mobile-button' : ''} ${buttonText ? 'px-4 py-3 h-12' : 'w-14 h-14'}`, style: { ...getButtonPositionStyles(), ...buttonStyle, backgroundImage: primaryColor }, children: [react_1.default.createElement(getIconComponent(), { className: "w-6 h-6" }), buttonText && !isMobile && (0, jsx_runtime_1.jsx)("span", { className: "text-sm font-medium whitespace-nowrap", children: buttonText })] }), renderChatWindow()] }));
|
|
929
949
|
}
|
|
930
950
|
return renderChatWindow();
|
|
931
951
|
});
|