@blumessage/react-chat 1.4.0 → 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/README.md +13 -0
- package/dist/BlumessageChat.js +559 -537
- package/dist/blumessage-chat.browser.js +1 -1
- package/dist/index.browser.js +6 -4
- package/dist/index.commonjs.js +13 -6
- package/dist/index.js +1 -1
- package/dist/types/BlumessageChat.d.ts +1 -0
- 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 _2 = useState(false), isAnimating = _2[0], setIsAnimating = _2[1];
|
|
139
|
-
var _3 = useState(false), isLoading = _3[0], setIsLoading = _3[1];
|
|
140
|
-
var _4 = useState(false), isMaximized = _4[0], setIsMaximized = _4[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,223 +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
|
-
case 7:
|
|
468
|
-
setIsLoading(false);
|
|
469
|
-
return [7 /*endfinally*/];
|
|
470
|
-
case 8: return [2 /*return*/];
|
|
444
|
+
}
|
|
471
445
|
}
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
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");
|
|
477
|
+
}
|
|
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
|
-
|
|
483
|
-
|
|
490
|
+
(0, react_1.useEffect)(() => {
|
|
491
|
+
if (!disableAutoScroll) {
|
|
492
|
+
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
|
|
493
|
+
}
|
|
484
494
|
}, [messages]);
|
|
485
495
|
// Auto-scroll to bottom when chat widget opens
|
|
486
|
-
|
|
487
|
-
if (isOpen && floating) {
|
|
496
|
+
(0, react_1.useEffect)(() => {
|
|
497
|
+
if (isOpen && floating && !disableAutoScroll) {
|
|
488
498
|
// Add a small delay to ensure the DOM is updated after the animation starts
|
|
489
|
-
setTimeout(
|
|
490
|
-
|
|
491
|
-
(_a = messagesEndRef.current) === null || _a === void 0 ? void 0 : _a.scrollIntoView({ behavior: 'smooth' });
|
|
499
|
+
setTimeout(() => {
|
|
500
|
+
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
|
|
492
501
|
}, 50);
|
|
493
502
|
}
|
|
494
|
-
}, [isOpen, floating]);
|
|
503
|
+
}, [isOpen, floating, disableAutoScroll]);
|
|
495
504
|
// Handle opening the chat with animation
|
|
496
|
-
|
|
505
|
+
const handleOpenChat = () => {
|
|
497
506
|
if (!isOpen && !isAnimating) {
|
|
498
507
|
setIsAnimating(true);
|
|
499
508
|
// Small delay to ensure smooth animation start
|
|
500
|
-
setTimeout(
|
|
509
|
+
setTimeout(() => {
|
|
501
510
|
setIsOpen(true);
|
|
502
511
|
// Call the callback after the chat is open
|
|
503
512
|
if (onChatWidgetOpen) {
|
|
@@ -505,13 +514,13 @@ export var BlumessageChat = forwardRef(function (_a, ref) {
|
|
|
505
514
|
}
|
|
506
515
|
}, 10);
|
|
507
516
|
// Animation duration
|
|
508
|
-
setTimeout(
|
|
517
|
+
setTimeout(() => {
|
|
509
518
|
setIsAnimating(false);
|
|
510
519
|
}, 300);
|
|
511
520
|
}
|
|
512
521
|
};
|
|
513
522
|
// Handle closing the chat with animation
|
|
514
|
-
|
|
523
|
+
const handleCloseChat = () => {
|
|
515
524
|
if (isOpen && !isAnimating) {
|
|
516
525
|
setIsAnimating(true);
|
|
517
526
|
setIsOpen(false);
|
|
@@ -522,155 +531,146 @@ export var BlumessageChat = forwardRef(function (_a, ref) {
|
|
|
522
531
|
onChatWidgetClosed();
|
|
523
532
|
}
|
|
524
533
|
// Wait for animation to complete
|
|
525
|
-
setTimeout(
|
|
534
|
+
setTimeout(() => {
|
|
526
535
|
setIsAnimating(false);
|
|
527
536
|
}, 300);
|
|
528
537
|
}
|
|
529
538
|
};
|
|
530
539
|
// Handle maximize/minimize toggle
|
|
531
|
-
|
|
540
|
+
const handleToggleMaximize = () => {
|
|
532
541
|
setIsMaximized(!isMaximized);
|
|
533
542
|
};
|
|
534
543
|
// Get the icon component based on the icon prop
|
|
535
|
-
|
|
544
|
+
const getIconComponent = () => {
|
|
536
545
|
// More permissive icon matching - handle various naming patterns
|
|
537
|
-
|
|
546
|
+
const iconName = icon.toLowerCase().replace(/[-_\s]/g, '');
|
|
538
547
|
// Try to match common icon patterns
|
|
539
548
|
if (iconName.includes('message') || iconName.includes('chat')) {
|
|
540
549
|
if (iconName.includes('square'))
|
|
541
|
-
return MessageSquare;
|
|
542
|
-
return MessageCircle;
|
|
550
|
+
return lucide_react_1.MessageSquare;
|
|
551
|
+
return lucide_react_1.MessageCircle;
|
|
543
552
|
}
|
|
544
553
|
if (iconName.includes('bot') || iconName.includes('robot'))
|
|
545
|
-
return Bot;
|
|
554
|
+
return lucide_react_1.Bot;
|
|
546
555
|
if (iconName.includes('phone') || iconName.includes('call'))
|
|
547
|
-
return Phone;
|
|
556
|
+
return lucide_react_1.Phone;
|
|
548
557
|
if (iconName.includes('mail') || iconName.includes('email'))
|
|
549
|
-
return Mail;
|
|
558
|
+
return lucide_react_1.Mail;
|
|
550
559
|
if (iconName.includes('headphone') || iconName.includes('support'))
|
|
551
|
-
return Headphones;
|
|
560
|
+
return lucide_react_1.Headphones;
|
|
552
561
|
if (iconName.includes('user')) {
|
|
553
562
|
if (iconName.includes('users') || iconName.includes('group'))
|
|
554
|
-
return Users;
|
|
555
|
-
return User;
|
|
563
|
+
return lucide_react_1.Users;
|
|
564
|
+
return lucide_react_1.User;
|
|
556
565
|
}
|
|
557
566
|
if (iconName.includes('heart') || iconName.includes('like') || iconName.includes('love'))
|
|
558
|
-
return Heart;
|
|
567
|
+
return lucide_react_1.Heart;
|
|
559
568
|
if (iconName.includes('star') || iconName.includes('favorite'))
|
|
560
|
-
return Star;
|
|
569
|
+
return lucide_react_1.Star;
|
|
561
570
|
if (iconName.includes('zap') || iconName.includes('lightning') || iconName.includes('bolt'))
|
|
562
|
-
return Zap;
|
|
571
|
+
return lucide_react_1.Zap;
|
|
563
572
|
// Default fallback
|
|
564
|
-
return MessageCircle;
|
|
573
|
+
return lucide_react_1.MessageCircle;
|
|
565
574
|
};
|
|
566
575
|
// Expose methods to parent component via ref
|
|
567
|
-
useImperativeHandle(ref,
|
|
568
|
-
sendMessage:
|
|
569
|
-
|
|
570
|
-
|
|
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
|
-
apiResponse = _a.sent();
|
|
613
|
-
// Update token from response (for both first message and continuing conversations)
|
|
614
|
-
updateConversationToken(apiResponse.token);
|
|
615
|
-
assistantMessages = apiResponse.messages.filter(function (msg) { return msg.role === 'assistant'; });
|
|
616
|
-
latestAssistantMessage = assistantMessages[assistantMessages.length - 1];
|
|
617
|
-
if (latestAssistantMessage) {
|
|
618
|
-
assistantResponse_2 = {
|
|
619
|
-
id: (Date.now() + 1).toString(),
|
|
620
|
-
content: latestAssistantMessage.content,
|
|
621
|
-
role: 'assistant',
|
|
622
|
-
timestamp: latestAssistantMessage.timestamp,
|
|
623
|
-
};
|
|
624
|
-
setMessages(function (prev) { return __spreadArray(__spreadArray([], prev, true), [assistantResponse_2], false); });
|
|
625
|
-
if (onAssistantMessage) {
|
|
626
|
-
onAssistantMessage(assistantResponse_2);
|
|
627
|
-
}
|
|
628
|
-
}
|
|
629
|
-
return [3 /*break*/, 5];
|
|
630
|
-
case 4:
|
|
631
|
-
console.error('Failed to send message to Blumessage API:', response.status, response.statusText);
|
|
632
|
-
// If token is invalid, clear it
|
|
633
|
-
if (response.status === 401 || response.status === 403) {
|
|
634
|
-
updateConversationToken(null);
|
|
635
|
-
}
|
|
636
|
-
errorMessage_3 = {
|
|
637
|
-
id: (Date.now() + 1).toString(),
|
|
638
|
-
content: "Sorry, I'm having trouble connecting right now. Please try again.",
|
|
639
|
-
role: 'assistant',
|
|
640
|
-
timestamp: Date.now(),
|
|
641
|
-
};
|
|
642
|
-
setMessages(function (prev) { return __spreadArray(__spreadArray([], prev, true), [errorMessage_3], false); });
|
|
643
|
-
if (onError) {
|
|
644
|
-
onError("Failed to send message: ".concat(response.status, " ").concat(response.statusText), "message_send");
|
|
645
|
-
}
|
|
646
|
-
_a.label = 5;
|
|
647
|
-
case 5: return [3 /*break*/, 8];
|
|
648
|
-
case 6:
|
|
649
|
-
error_3 = _a.sent();
|
|
650
|
-
console.error('Error sending message to Blumessage API:', error_3);
|
|
651
|
-
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 = {
|
|
652
621
|
id: (Date.now() + 1).toString(),
|
|
653
|
-
content:
|
|
622
|
+
content: latestAssistantMessage.content,
|
|
654
623
|
role: 'assistant',
|
|
655
|
-
timestamp:
|
|
624
|
+
timestamp: latestAssistantMessage.timestamp,
|
|
656
625
|
};
|
|
657
|
-
setMessages(
|
|
658
|
-
if (
|
|
659
|
-
|
|
626
|
+
setMessages(prev => [...prev, assistantResponse]);
|
|
627
|
+
if (onAssistantMessage) {
|
|
628
|
+
onAssistantMessage(assistantResponse);
|
|
660
629
|
}
|
|
661
|
-
|
|
662
|
-
case 7:
|
|
663
|
-
setIsLoading(false);
|
|
664
|
-
return [7 /*endfinally*/];
|
|
665
|
-
case 8: return [2 /*return*/];
|
|
630
|
+
}
|
|
666
631
|
}
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
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: () => {
|
|
670
670
|
if (!isOpen && !isAnimating) {
|
|
671
671
|
setIsAnimating(true);
|
|
672
672
|
// Small delay to ensure smooth animation start
|
|
673
|
-
setTimeout(
|
|
673
|
+
setTimeout(() => {
|
|
674
674
|
setIsOpen(true);
|
|
675
675
|
// Call the callback after the chat is open
|
|
676
676
|
if (onChatWidgetOpen) {
|
|
@@ -678,12 +678,12 @@ export var BlumessageChat = forwardRef(function (_a, ref) {
|
|
|
678
678
|
}
|
|
679
679
|
}, 10);
|
|
680
680
|
// Animation duration
|
|
681
|
-
setTimeout(
|
|
681
|
+
setTimeout(() => {
|
|
682
682
|
setIsAnimating(false);
|
|
683
683
|
}, 300);
|
|
684
684
|
}
|
|
685
685
|
},
|
|
686
|
-
closeChat:
|
|
686
|
+
closeChat: () => {
|
|
687
687
|
if (isOpen && !isAnimating) {
|
|
688
688
|
setIsAnimating(true);
|
|
689
689
|
setIsOpen(false);
|
|
@@ -694,21 +694,21 @@ export var BlumessageChat = forwardRef(function (_a, ref) {
|
|
|
694
694
|
onChatWidgetClosed();
|
|
695
695
|
}
|
|
696
696
|
// Wait for animation to complete
|
|
697
|
-
setTimeout(
|
|
697
|
+
setTimeout(() => {
|
|
698
698
|
setIsAnimating(false);
|
|
699
699
|
}, 300);
|
|
700
700
|
}
|
|
701
701
|
},
|
|
702
|
-
clearConversation:
|
|
702
|
+
clearConversation: () => {
|
|
703
703
|
setMessages([]);
|
|
704
704
|
updateConversationToken(null);
|
|
705
705
|
},
|
|
706
|
-
getMessages:
|
|
707
|
-
getToken:
|
|
708
|
-
})
|
|
706
|
+
getMessages: () => messages,
|
|
707
|
+
getToken: () => token,
|
|
708
|
+
}));
|
|
709
709
|
// Helper function to get position styles for floating button
|
|
710
|
-
|
|
711
|
-
|
|
710
|
+
const getButtonPositionStyles = () => {
|
|
711
|
+
const baseStyles = {
|
|
712
712
|
position: 'fixed',
|
|
713
713
|
zIndex: 1000,
|
|
714
714
|
opacity: isOpen ? 0 : 1,
|
|
@@ -717,32 +717,38 @@ export var BlumessageChat = forwardRef(function (_a, ref) {
|
|
|
717
717
|
};
|
|
718
718
|
// Mobile-specific positioning
|
|
719
719
|
if (isMobile) {
|
|
720
|
-
return
|
|
720
|
+
return {
|
|
721
|
+
...baseStyles,
|
|
722
|
+
bottom: '20px',
|
|
723
|
+
right: '20px',
|
|
724
|
+
left: 'auto',
|
|
725
|
+
top: 'auto'
|
|
726
|
+
};
|
|
721
727
|
}
|
|
722
728
|
// Desktop positioning
|
|
723
729
|
switch (buttonPosition) {
|
|
724
730
|
case 'bottom-right':
|
|
725
|
-
return
|
|
731
|
+
return { ...baseStyles, bottom: '24px', right: '24px' };
|
|
726
732
|
case 'bottom-left':
|
|
727
|
-
return
|
|
733
|
+
return { ...baseStyles, bottom: '24px', left: '24px' };
|
|
728
734
|
case 'top-right':
|
|
729
|
-
return
|
|
735
|
+
return { ...baseStyles, top: '24px', right: '24px' };
|
|
730
736
|
case 'top-left':
|
|
731
|
-
return
|
|
737
|
+
return { ...baseStyles, top: '24px', left: '24px' };
|
|
732
738
|
default:
|
|
733
|
-
return
|
|
739
|
+
return { ...baseStyles, bottom: '24px', right: '24px' };
|
|
734
740
|
}
|
|
735
741
|
};
|
|
736
742
|
// Helper function to get position styles for floating chat window
|
|
737
|
-
|
|
738
|
-
|
|
743
|
+
const getChatPositionStyles = () => {
|
|
744
|
+
const getTransform = () => {
|
|
739
745
|
if (!isOpen) {
|
|
740
746
|
// Slide down for bottom positions, slide up for top positions
|
|
741
|
-
return
|
|
747
|
+
return buttonPosition?.includes('bottom') ? 'translateY(100%)' : 'translateY(-100%)';
|
|
742
748
|
}
|
|
743
749
|
return 'translateY(0)';
|
|
744
750
|
};
|
|
745
|
-
|
|
751
|
+
const baseStyles = {
|
|
746
752
|
position: 'fixed',
|
|
747
753
|
zIndex: 999,
|
|
748
754
|
transform: getTransform(),
|
|
@@ -752,13 +758,21 @@ export var BlumessageChat = forwardRef(function (_a, ref) {
|
|
|
752
758
|
};
|
|
753
759
|
// Mobile-specific positioning (always fullscreen on mobile)
|
|
754
760
|
if (isMobile) {
|
|
755
|
-
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
|
+
};
|
|
756
770
|
}
|
|
757
771
|
// If fullScreen or maximized, override positioning to be centered and full screen
|
|
758
772
|
if (fullScreen || isMaximized) {
|
|
759
773
|
// Set transform origin and direction based on button position for proper animation
|
|
760
|
-
|
|
761
|
-
|
|
774
|
+
let transformOrigin = 'center';
|
|
775
|
+
let closedTransform = 'translateY(100%)';
|
|
762
776
|
switch (buttonPosition) {
|
|
763
777
|
case 'bottom-right':
|
|
764
778
|
transformOrigin = 'bottom right';
|
|
@@ -780,86 +794,94 @@ export var BlumessageChat = forwardRef(function (_a, ref) {
|
|
|
780
794
|
transformOrigin = 'bottom right';
|
|
781
795
|
closedTransform = 'translateY(100%)';
|
|
782
796
|
}
|
|
783
|
-
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
|
+
};
|
|
784
806
|
}
|
|
785
807
|
// Desktop positioning
|
|
786
808
|
switch (buttonPosition) {
|
|
787
809
|
case 'bottom-right':
|
|
788
|
-
return
|
|
810
|
+
return { ...baseStyles, bottom: '24px', right: '24px', transformOrigin: 'bottom right' };
|
|
789
811
|
case 'bottom-left':
|
|
790
|
-
return
|
|
812
|
+
return { ...baseStyles, bottom: '24px', left: '24px', transformOrigin: 'bottom left' };
|
|
791
813
|
case 'top-right':
|
|
792
|
-
return
|
|
814
|
+
return { ...baseStyles, top: '24px', right: '24px', transformOrigin: 'top right' };
|
|
793
815
|
case 'top-left':
|
|
794
|
-
return
|
|
816
|
+
return { ...baseStyles, top: '24px', left: '24px', transformOrigin: 'top left' };
|
|
795
817
|
default:
|
|
796
|
-
return
|
|
818
|
+
return { ...baseStyles, bottom: '24px', right: '24px', transformOrigin: 'bottom right' };
|
|
797
819
|
}
|
|
798
820
|
};
|
|
799
|
-
|
|
800
|
-
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'
|
|
801
823
|
? 'blumessage-bg-gradient-to-r blumessage-from-blue-500 blumessage-to-purple-600 blumessage-text-white'
|
|
802
824
|
: theme === 'light'
|
|
803
825
|
? 'blumessage-bg-gray-100'
|
|
804
|
-
: '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));
|
|
805
827
|
};
|
|
806
828
|
// Render chat window component
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
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'
|
|
810
832
|
? 'bg-gray-900 border-gray-700'
|
|
811
|
-
: 'bg-white border-black/10'
|
|
833
|
+
: 'bg-white border-black/10'}`, style: {
|
|
812
834
|
width: isFullscreenMode ? '100%' : actualWidth,
|
|
813
835
|
height: isFullscreenMode ? '100%' : actualHeight,
|
|
814
836
|
fontFamily: 'system-ui, -apple-system, sans-serif',
|
|
815
837
|
borderRadius: isMobile ? '0' : (isFullscreenMode ? '12px' : '24px')
|
|
816
|
-
}, children: [
|
|
838
|
+
}, children: [(0, jsx_runtime_1.jsxs)("div", { className: `border-b ${theme === 'dark'
|
|
817
839
|
? 'bg-gray-900 border-gray-700'
|
|
818
|
-
: 'bg-white border-gray-100'
|
|
840
|
+
: 'bg-white border-gray-100'}`, style: {
|
|
819
841
|
display: 'flex',
|
|
820
842
|
alignItems: 'center',
|
|
821
843
|
padding: isMobile ? '12px 16px' : '16px 24px'
|
|
822
|
-
}, children: [
|
|
844
|
+
}, children: [(0, jsx_runtime_1.jsx)("div", { className: "rounded-full flex items-center justify-center", style: {
|
|
823
845
|
backgroundImage: primaryColor,
|
|
824
846
|
width: isMobile ? '40px' : '48px',
|
|
825
847
|
height: isMobile ? '40px' : '48px',
|
|
826
848
|
marginRight: isMobile ? '16px' : '24px'
|
|
827
|
-
}, children:
|
|
849
|
+
}, children: react_1.default.createElement(getIconComponent(), {
|
|
828
850
|
className: isMobile ? "w-5 h-5 text-white" : "w-6 h-6 text-white"
|
|
829
|
-
}) }),
|
|
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'
|
|
830
852
|
? 'hover:bg-gray-800 text-gray-400 hover:text-gray-200'
|
|
831
|
-
: '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'
|
|
832
854
|
? 'hover:bg-gray-800 text-gray-400 hover:text-gray-200'
|
|
833
|
-
: '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'
|
|
834
856
|
? 'text-white'
|
|
835
857
|
: theme === 'dark'
|
|
836
858
|
? 'bg-gray-700 text-gray-100 border border-gray-600 shadow-sm'
|
|
837
|
-
: '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'
|
|
838
860
|
? 'text-white/75'
|
|
839
861
|
: theme === 'dark'
|
|
840
862
|
? 'text-gray-400'
|
|
841
|
-
: 'text-gray-500'
|
|
863
|
+
: 'text-gray-500'}`, style: {
|
|
842
864
|
textAlign: message.role === 'user' ? 'right' : 'left'
|
|
843
|
-
}, 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'
|
|
844
866
|
? 'bg-gray-700 text-gray-100 border border-gray-600'
|
|
845
|
-
: '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'
|
|
846
868
|
? 'bg-gray-900 border-gray-700'
|
|
847
|
-
: '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'
|
|
848
870
|
? 'bg-gray-800 border-gray-600'
|
|
849
|
-
: '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: {
|
|
850
872
|
minHeight: '20px',
|
|
851
873
|
maxHeight: isMobile ? '100px' : '120px',
|
|
852
874
|
overflowY: inputValue.split('\n').length > 4 ? 'auto' : 'hidden',
|
|
853
875
|
lineHeight: '1.5',
|
|
854
876
|
paddingTop: '2px',
|
|
855
877
|
paddingBottom: '2px'
|
|
856
|
-
}, onInput:
|
|
857
|
-
|
|
878
|
+
}, onInput: (e) => {
|
|
879
|
+
const target = e.target;
|
|
858
880
|
target.style.height = 'auto';
|
|
859
881
|
target.style.height = Math.min(target.scrollHeight, isMobile ? 100 : 120) + 'px';
|
|
860
|
-
} }),
|
|
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" })) })] }) })] }));
|
|
861
883
|
if (floating) {
|
|
862
|
-
return (
|
|
884
|
+
return ((0, jsx_runtime_1.jsx)("div", { style: getChatPositionStyles(), children: chatContent }));
|
|
863
885
|
}
|
|
864
886
|
return chatContent;
|
|
865
887
|
};
|
|
@@ -868,62 +890,62 @@ export var BlumessageChat = forwardRef(function (_a, ref) {
|
|
|
868
890
|
return null;
|
|
869
891
|
}
|
|
870
892
|
if (error) {
|
|
871
|
-
|
|
872
|
-
|
|
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'
|
|
873
895
|
? 'bg-gray-900 border-gray-700'
|
|
874
|
-
: 'bg-white border-black/10'
|
|
896
|
+
: 'bg-white border-black/10'}`, style: {
|
|
875
897
|
width: isFullscreenMode ? '100%' : actualWidth,
|
|
876
898
|
height: isFullscreenMode ? '100%' : actualHeight,
|
|
877
899
|
fontFamily: 'system-ui, -apple-system, sans-serif',
|
|
878
900
|
borderRadius: isMobile ? '0' : (isFullscreenMode ? '12px' : '24px')
|
|
879
|
-
}, children: [
|
|
901
|
+
}, children: [(0, jsx_runtime_1.jsxs)("div", { className: `flex items-center border-b ${theme === 'dark'
|
|
880
902
|
? 'bg-gray-900 border-gray-700'
|
|
881
|
-
: '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: {
|
|
882
904
|
backgroundColor: '#ef4444',
|
|
883
905
|
width: isMobile ? '40px' : '48px',
|
|
884
906
|
height: isMobile ? '40px' : '48px',
|
|
885
907
|
marginRight: isMobile ? '16px' : '24px'
|
|
886
|
-
}, 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'
|
|
887
909
|
? 'hover:bg-gray-800 text-gray-400 hover:text-gray-200'
|
|
888
|
-
: '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'
|
|
889
911
|
? 'hover:bg-gray-800 text-gray-400 hover:text-gray-200'
|
|
890
|
-
: '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'
|
|
891
913
|
? 'bg-gray-700 text-gray-100 border border-gray-600'
|
|
892
|
-
: 'bg-white text-gray-800 border border-gray-200'
|
|
914
|
+
: 'bg-white text-gray-800 border border-gray-200'}`, children: error }) }) })] }));
|
|
893
915
|
if (floating) {
|
|
894
|
-
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 })] }));
|
|
895
917
|
}
|
|
896
918
|
return errorContent;
|
|
897
919
|
}
|
|
898
920
|
if (!isInitialized) {
|
|
899
|
-
|
|
900
|
-
|
|
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'
|
|
901
923
|
? 'bg-gray-900 border-gray-700'
|
|
902
|
-
: 'bg-white border-black/10'
|
|
924
|
+
: 'bg-white border-black/10'}`, style: {
|
|
903
925
|
width: isFullscreenMode ? '100%' : actualWidth,
|
|
904
926
|
height: isFullscreenMode ? '100%' : actualHeight,
|
|
905
927
|
fontFamily: 'system-ui, -apple-system, sans-serif',
|
|
906
928
|
borderRadius: isMobile ? '0' : (isFullscreenMode ? '12px' : '24px')
|
|
907
|
-
}, children: [
|
|
929
|
+
}, children: [(0, jsx_runtime_1.jsxs)("div", { className: `flex items-center border-b ${theme === 'dark'
|
|
908
930
|
? 'bg-gray-900 border-gray-700'
|
|
909
|
-
: '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: {
|
|
910
932
|
backgroundImage: primaryColor,
|
|
911
933
|
width: isMobile ? '40px' : '48px',
|
|
912
934
|
height: isMobile ? '40px' : '48px',
|
|
913
935
|
marginRight: isMobile ? '16px' : '24px'
|
|
914
|
-
}, 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'
|
|
915
937
|
? 'hover:bg-gray-800 text-gray-400 hover:text-gray-200'
|
|
916
|
-
: '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'
|
|
917
939
|
? 'hover:bg-gray-800 text-gray-400 hover:text-gray-200'
|
|
918
|
-
: '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..." }) })] }));
|
|
919
941
|
if (floating) {
|
|
920
|
-
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 })] }));
|
|
921
943
|
}
|
|
922
944
|
return loadingContent;
|
|
923
945
|
}
|
|
924
946
|
// Main render for initialized state
|
|
925
947
|
if (floating) {
|
|
926
|
-
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()] }));
|
|
927
949
|
}
|
|
928
950
|
return renderChatWindow();
|
|
929
951
|
});
|