ttp-agent-sdk 2.39.0 → 2.43.0
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/agent-widget.dev.js +5002 -2914
- package/dist/agent-widget.dev.js.map +1 -1
- package/dist/agent-widget.esm.js +1 -1
- package/dist/agent-widget.esm.js.map +1 -1
- package/dist/agent-widget.js +1 -1
- package/dist/agent-widget.js.map +1 -1
- package/dist/audio-processor.js +4 -0
- package/dist/demos/index.html +45 -0
- package/dist/demos/test-ecommerce.html +34 -16
- package/dist/demos/test-tour.html +375 -0
- package/dist/demos/widget-customization-dev.html +8 -14
- package/dist/demos/widget-customization.html +1721 -608
- package/dist/examples/test-ecommerce.html +34 -16
- package/dist/examples/test-index.html +45 -0
- package/dist/examples/test-restaurant.html +373 -0
- package/dist/examples/test-text-chat.html +18 -9
- package/dist/examples/test-tour.html +375 -0
- package/dist/examples/widget-customization-dev.html +8 -14
- package/dist/examples/widget-customization.html +1721 -608
- package/examples/test-ecommerce.html +34 -16
- package/examples/test-index.html +45 -0
- package/examples/test-restaurant.html +373 -0
- package/examples/test-text-chat.html +18 -9
- package/examples/test-tour.html +375 -0
- package/examples/widget-customization-dev.html +8 -14
- package/examples/widget-customization.html +1721 -608
- package/package.json +1 -1
|
@@ -138,7 +138,11 @@
|
|
|
138
138
|
<div class="settings-grid">
|
|
139
139
|
<label>Agent
|
|
140
140
|
<select id="agentSelect" onchange="handleAgentChange()">
|
|
141
|
-
<option value="
|
|
141
|
+
<option value="agent_ed18369b3|app_wNGQKiMUfUT5JdVIaxzXOJfdcgBegxGY5hZo|ecommerce|mock-store">Ecommerce Demo (agent_ed18369b3)</option>
|
|
142
|
+
<option value="agent_d0774f1af|app_wNGQKiMUfUT5JdVIaxzXOJfdcgBegxGY5hZo|hotels|mock-hotel" selected>Hotels Demo (agent_d0774f1af)</option>
|
|
143
|
+
<option value="agent_PHARMA_ID|app_wNGQKiMUfUT5JdVIaxzXOJfdcgBegxGY5hZo|pharma|mock-pharm">Pharma Demo (update agent ID)</option>
|
|
144
|
+
<option value="agent_RESTAURANT_ID|app_wNGQKiMUfUT5JdVIaxzXOJfdcgBegxGY5hZo|restaurants|mock-restaurant">Restaurant Demo (update agent ID)</option>
|
|
145
|
+
<option value="agent_TOUR_ID|app_wNGQKiMUfUT5JdVIaxzXOJfdcgBegxGY5hZo|tours|mock-tour">Tour Demo (update agent ID)</option>
|
|
142
146
|
<option value="custom">Custom...</option>
|
|
143
147
|
</select>
|
|
144
148
|
</label>
|
|
@@ -160,17 +164,19 @@
|
|
|
160
164
|
<option value="rtl">RTL</option>
|
|
161
165
|
</select>
|
|
162
166
|
</label>
|
|
163
|
-
<label>
|
|
164
|
-
<select id="
|
|
165
|
-
<option value="
|
|
166
|
-
<option value="
|
|
167
|
-
<option value="
|
|
167
|
+
<label>STT Provider
|
|
168
|
+
<select id="sttSelect">
|
|
169
|
+
<option value="">Default (server)</option>
|
|
170
|
+
<option value="azure-stt" selected>Azure STT</option>
|
|
171
|
+
<option value="cartesia-stt">Cartesia (Ink-Whisper)</option>
|
|
172
|
+
<option value="openai-realtime">OpenAI Realtime</option>
|
|
173
|
+
<option value="soniox">Soniox</option>
|
|
168
174
|
</select>
|
|
169
175
|
</label>
|
|
170
176
|
<label>Start Open
|
|
171
177
|
<select id="startOpenSelect">
|
|
172
|
-
<option value="true"
|
|
173
|
-
<option value="false">No</option>
|
|
178
|
+
<option value="true">Yes</option>
|
|
179
|
+
<option value="false" selected>No</option>
|
|
174
180
|
</select>
|
|
175
181
|
</label>
|
|
176
182
|
</div>
|
|
@@ -267,11 +273,13 @@ window.testWidget._flavor.messageHandlers['show_media']({
|
|
|
267
273
|
if (sel.value === 'custom') {
|
|
268
274
|
return {
|
|
269
275
|
agentId: document.getElementById('customAgentId').value,
|
|
270
|
-
appId: document.getElementById('customAppId').value
|
|
276
|
+
appId: document.getElementById('customAppId').value,
|
|
277
|
+
flavorType: 'ecommerce',
|
|
278
|
+
partnerId: 'mock-store'
|
|
271
279
|
};
|
|
272
280
|
}
|
|
273
|
-
const [agentId, appId] = sel.value.split('|');
|
|
274
|
-
return { agentId, appId };
|
|
281
|
+
const [agentId, appId, flavorType, partnerId] = sel.value.split('|');
|
|
282
|
+
return { agentId, appId, flavorType, partnerId };
|
|
275
283
|
}
|
|
276
284
|
|
|
277
285
|
function createWidget() {
|
|
@@ -293,24 +301,34 @@ window.testWidget._flavor.messageHandlers['show_media']({
|
|
|
293
301
|
appId: agent.appId,
|
|
294
302
|
language: document.getElementById('languageSelect').value,
|
|
295
303
|
direction: document.getElementById('dirSelect').value,
|
|
304
|
+
agentSettingsOverride: (() => {
|
|
305
|
+
const override = {};
|
|
306
|
+
const stt = document.getElementById('sttSelect').value;
|
|
307
|
+
if (stt) override.sttProvider = stt;
|
|
308
|
+
return override;
|
|
309
|
+
})(),
|
|
296
310
|
behavior: {
|
|
297
|
-
mode: document.getElementById('modeSelect').value,
|
|
298
311
|
startOpen: document.getElementById('startOpenSelect').value === 'true'
|
|
299
312
|
},
|
|
300
313
|
flavor: {
|
|
301
|
-
type:
|
|
302
|
-
partnerId:
|
|
314
|
+
type: agent.flavorType,
|
|
315
|
+
partnerId: agent.partnerId
|
|
303
316
|
},
|
|
304
317
|
icon: {
|
|
305
318
|
type: 'custom',
|
|
306
|
-
customImage
|
|
319
|
+
/* Omit customImage — SDK shows animated waveform (same as mobile), not the old default logo */
|
|
307
320
|
size: 'medium',
|
|
308
321
|
backgroundColor: '#FFFFFF'
|
|
322
|
+
},
|
|
323
|
+
whatsapp: {
|
|
324
|
+
number: '+972508665824',
|
|
325
|
+
text: 'היי, אשמח אם תוכלי לעזור לי '
|
|
309
326
|
}
|
|
310
327
|
});
|
|
311
328
|
|
|
312
329
|
window.testWidget = chatWidget;
|
|
313
|
-
|
|
330
|
+
const sttLabel = document.getElementById('sttSelect').selectedOptions[0].text;
|
|
331
|
+
updateStatus('TTPChatWidget created — ' + agent.flavorType + ' flavor (' + agent.partnerId + '), STT: ' + sttLabel, 'success');
|
|
314
332
|
}
|
|
315
333
|
|
|
316
334
|
// Button handlers
|
package/examples/test-index.html
CHANGED
|
@@ -316,6 +316,51 @@
|
|
|
316
316
|
<span class="badge badge--new">E-Commerce</span>
|
|
317
317
|
</div>
|
|
318
318
|
</a>
|
|
319
|
+
|
|
320
|
+
<a href="../examples/test-pharma.html" class="test-card">
|
|
321
|
+
<span class="test-card__icon">💊</span>
|
|
322
|
+
<h3 class="test-card__title">Pharma Widget Test</h3>
|
|
323
|
+
<p class="test-card__description">
|
|
324
|
+
Test the pharmacy flavor — medication search, prescription management,
|
|
325
|
+
and medication cards with Rx/OTC badges. Simulate show_items and
|
|
326
|
+
prescription_updated messages without a live voice call.
|
|
327
|
+
</p>
|
|
328
|
+
<div class="test-card__badges">
|
|
329
|
+
<span class="badge badge--widget">Widget</span>
|
|
330
|
+
<span class="badge badge--voice">Voice</span>
|
|
331
|
+
<span class="badge badge--new">Pharma</span>
|
|
332
|
+
</div>
|
|
333
|
+
</a>
|
|
334
|
+
|
|
335
|
+
<a href="../examples/test-restaurant.html" class="test-card">
|
|
336
|
+
<span class="test-card__icon">🍽️</span>
|
|
337
|
+
<h3 class="test-card__title">Restaurant Widget Test</h3>
|
|
338
|
+
<p class="test-card__description">
|
|
339
|
+
Test the restaurant flavor — menu search, order management, menu item cards
|
|
340
|
+
with allergen/dietary tags, and photo gallery. Simulate show_items,
|
|
341
|
+
order_updated, and show_media messages without a live voice call.
|
|
342
|
+
</p>
|
|
343
|
+
<div class="test-card__badges">
|
|
344
|
+
<span class="badge badge--widget">Widget</span>
|
|
345
|
+
<span class="badge badge--voice">Voice</span>
|
|
346
|
+
<span class="badge badge--new">Restaurant</span>
|
|
347
|
+
</div>
|
|
348
|
+
</a>
|
|
349
|
+
|
|
350
|
+
<a href="../examples/test-tour.html" class="test-card">
|
|
351
|
+
<span class="test-card__icon">🗺️</span>
|
|
352
|
+
<h3 class="test-card__title">Tour Widget Test</h3>
|
|
353
|
+
<p class="test-card__description">
|
|
354
|
+
Test the tours flavor — tour search, booking management, tour cards
|
|
355
|
+
with activity tags, and photo gallery. Simulate show_items,
|
|
356
|
+
cart_updated, and show_media messages without a live voice call.
|
|
357
|
+
</p>
|
|
358
|
+
<div class="test-card__badges">
|
|
359
|
+
<span class="badge badge--widget">Widget</span>
|
|
360
|
+
<span class="badge badge--voice">Voice</span>
|
|
361
|
+
<span class="badge badge--new">Tours</span>
|
|
362
|
+
</div>
|
|
363
|
+
</a>
|
|
319
364
|
</div>
|
|
320
365
|
</div>
|
|
321
366
|
|
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
|
6
|
+
<title>TTP Restaurant Flavor - Test</title>
|
|
7
|
+
<style>
|
|
8
|
+
body {
|
|
9
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
10
|
+
max-width: 1200px;
|
|
11
|
+
margin: 40px auto;
|
|
12
|
+
padding: 20px;
|
|
13
|
+
background: #F9FAFB;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.container {
|
|
17
|
+
background: white;
|
|
18
|
+
padding: 30px;
|
|
19
|
+
border-radius: 12px;
|
|
20
|
+
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
h1 { color: #111827; margin-top: 0; }
|
|
24
|
+
h2 { color: #374151; border-bottom: 2px solid #E5E7EB; padding-bottom: 8px; margin-top: 30px; }
|
|
25
|
+
|
|
26
|
+
.info {
|
|
27
|
+
background: #EFF6FF;
|
|
28
|
+
border-left: 4px solid #3B82F6;
|
|
29
|
+
padding: 16px;
|
|
30
|
+
margin: 20px 0;
|
|
31
|
+
border-radius: 4px;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.status {
|
|
35
|
+
margin: 20px 0;
|
|
36
|
+
padding: 12px;
|
|
37
|
+
background: #F3F4F6;
|
|
38
|
+
border-radius: 6px;
|
|
39
|
+
font-family: monospace;
|
|
40
|
+
font-size: 14px;
|
|
41
|
+
}
|
|
42
|
+
.status.success { background: #D1FAE5; color: #065F46; }
|
|
43
|
+
.status.error { background: #FEE2E2; color: #991B1B; }
|
|
44
|
+
|
|
45
|
+
button {
|
|
46
|
+
background: #2563EB;
|
|
47
|
+
color: white;
|
|
48
|
+
border: none;
|
|
49
|
+
padding: 12px 24px;
|
|
50
|
+
border-radius: 6px;
|
|
51
|
+
cursor: pointer;
|
|
52
|
+
font-size: 16px;
|
|
53
|
+
margin: 10px 10px 10px 0;
|
|
54
|
+
}
|
|
55
|
+
button:hover { background: #1D4ED8; }
|
|
56
|
+
button.secondary { background: #6B7280; }
|
|
57
|
+
button.secondary:hover { background: #4B5563; }
|
|
58
|
+
button.success { background: #059669; }
|
|
59
|
+
button.success:hover { background: #047857; }
|
|
60
|
+
|
|
61
|
+
label {
|
|
62
|
+
display: flex;
|
|
63
|
+
flex-direction: column;
|
|
64
|
+
gap: 4px;
|
|
65
|
+
font-size: 14px;
|
|
66
|
+
color: #374151;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
select, input[type="text"] {
|
|
70
|
+
padding: 8px 12px;
|
|
71
|
+
border: 1px solid #D1D5DB;
|
|
72
|
+
border-radius: 6px;
|
|
73
|
+
font-size: 14px;
|
|
74
|
+
font-family: inherit;
|
|
75
|
+
background: white;
|
|
76
|
+
color: #111827;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.settings-grid {
|
|
80
|
+
display: grid;
|
|
81
|
+
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
|
82
|
+
gap: 16px;
|
|
83
|
+
margin: 16px 0;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.test-section {
|
|
87
|
+
border: 1px solid #E5E7EB;
|
|
88
|
+
border-radius: 8px;
|
|
89
|
+
padding: 20px;
|
|
90
|
+
margin: 16px 0;
|
|
91
|
+
background: #F9FAFB;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.test-section h3 {
|
|
95
|
+
margin: 0 0 12px 0;
|
|
96
|
+
color: #111827;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.code-block {
|
|
100
|
+
background: #1F2937;
|
|
101
|
+
color: #F9FAFB;
|
|
102
|
+
padding: 16px;
|
|
103
|
+
border-radius: 6px;
|
|
104
|
+
font-family: monospace;
|
|
105
|
+
font-size: 12px;
|
|
106
|
+
overflow-x: auto;
|
|
107
|
+
margin: 20px 0;
|
|
108
|
+
white-space: pre-wrap;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
@media (max-width: 768px) {
|
|
112
|
+
body { margin: 0; padding: 10px; }
|
|
113
|
+
.container { padding: 16px; border-radius: 8px; }
|
|
114
|
+
h1 { font-size: 24px; }
|
|
115
|
+
button { width: 100%; margin: 8px 0; }
|
|
116
|
+
.settings-grid { grid-template-columns: 1fr; }
|
|
117
|
+
}
|
|
118
|
+
</style>
|
|
119
|
+
</head>
|
|
120
|
+
<body>
|
|
121
|
+
<div class="container">
|
|
122
|
+
<h1>TTP Restaurant Flavor Test</h1>
|
|
123
|
+
|
|
124
|
+
<div class="info">
|
|
125
|
+
<strong>How it works:</strong>
|
|
126
|
+
<ul>
|
|
127
|
+
<li>Uses <code>TTPChatWidget</code> with <code>flavor: { type: 'restaurants', partnerId: 'mock-restaurant' }</code></li>
|
|
128
|
+
<li>The backend injects restaurant tools (<code>search_menu</code>, <code>add_to_order</code>, <code>get_order</code>, <code>show_media</code>)</li>
|
|
129
|
+
<li>Menu item cards display when the agent sends <code>show_items</code> messages</li>
|
|
130
|
+
<li>Order summary updates on <code>cart_updated</code> messages (same universal shape as ecommerce: <code>product</code>, <code>cartTotal</code>, <code>cartItemCount</code>)</li>
|
|
131
|
+
<li>Gallery (<code>show_media</code>) opens fullscreen for dish photos, ambiance, etc.</li>
|
|
132
|
+
</ul>
|
|
133
|
+
</div>
|
|
134
|
+
|
|
135
|
+
<div id="status" class="status">Loading SDK...</div>
|
|
136
|
+
|
|
137
|
+
<h2>Widget Configuration</h2>
|
|
138
|
+
<div class="settings-grid">
|
|
139
|
+
<label>Agent ID
|
|
140
|
+
<input id="agentId" type="text" value="agent_e165840eb" placeholder="agent_..." />
|
|
141
|
+
</label>
|
|
142
|
+
<label>App ID
|
|
143
|
+
<input id="appId" type="text" value="app_wNGQKiMUfUT5JdVIaxzXOJfdcgBegxGY5hZo" placeholder="app_..." />
|
|
144
|
+
</label>
|
|
145
|
+
<label>Language
|
|
146
|
+
<select id="languageSelect">
|
|
147
|
+
<option value="en" selected>English</option>
|
|
148
|
+
</select>
|
|
149
|
+
</label>
|
|
150
|
+
<label>STT Provider
|
|
151
|
+
<select id="sttSelect">
|
|
152
|
+
<option value="">Default (server)</option>
|
|
153
|
+
<option value="azure-stt" selected>Azure STT</option>
|
|
154
|
+
</select>
|
|
155
|
+
</label>
|
|
156
|
+
</div>
|
|
157
|
+
|
|
158
|
+
<div style="margin-top: 16px;">
|
|
159
|
+
<button id="createBtn">Create Widget</button>
|
|
160
|
+
<button id="destroyBtn" class="secondary">Destroy Widget</button>
|
|
161
|
+
</div>
|
|
162
|
+
|
|
163
|
+
<h2>Test Actions (Simulated Messages)</h2>
|
|
164
|
+
|
|
165
|
+
<div class="test-section">
|
|
166
|
+
<h3>Show Menu Items</h3>
|
|
167
|
+
<p style="color: #6B7280; font-size: 14px; margin-bottom: 12px;">
|
|
168
|
+
Injects a <code>show_items</code> message with mock menu items.
|
|
169
|
+
</p>
|
|
170
|
+
<button id="showMenuBtn" class="success">Show Menu Items</button>
|
|
171
|
+
</div>
|
|
172
|
+
|
|
173
|
+
<div class="test-section">
|
|
174
|
+
<h3>Show Gallery</h3>
|
|
175
|
+
<p style="color: #6B7280; font-size: 14px; margin-bottom: 12px;">
|
|
176
|
+
Injects a <code>show_media</code> message to test fullscreen gallery.
|
|
177
|
+
</p>
|
|
178
|
+
<button id="showGalleryBtn" class="success">Show Gallery</button>
|
|
179
|
+
</div>
|
|
180
|
+
|
|
181
|
+
<div class="test-section">
|
|
182
|
+
<h3>Order Updated</h3>
|
|
183
|
+
<p style="color: #6B7280; font-size: 14px; margin-bottom: 12px;">
|
|
184
|
+
Injects an <code>order_updated</code> message to test the order summary bar.
|
|
185
|
+
</p>
|
|
186
|
+
<button id="orderBtn" class="success">Simulate Order</button>
|
|
187
|
+
<button id="clearOrderBtn" class="secondary">Clear Order</button>
|
|
188
|
+
</div>
|
|
189
|
+
|
|
190
|
+
<h2>Console Commands</h2>
|
|
191
|
+
<div class="code-block">// Access the widget instance
|
|
192
|
+
window.testWidget
|
|
193
|
+
|
|
194
|
+
// Inject messages manually
|
|
195
|
+
window.testWidget._flavor.messageHandlers['show_items']({
|
|
196
|
+
t: 'show_items',
|
|
197
|
+
items: [
|
|
198
|
+
{ id: 'MAIN-001', name: 'Grilled Salmon', category: 'Mains', price: 24.99, currency: 'USD', imageUrl: '...', available: true, tags: ['seafood', 'healthy'], allergens: ['fish'] }
|
|
199
|
+
],
|
|
200
|
+
title: 'Test Menu'
|
|
201
|
+
});</div>
|
|
202
|
+
</div>
|
|
203
|
+
|
|
204
|
+
<script>
|
|
205
|
+
(function() {
|
|
206
|
+
var isNgrok = window.location.hostname.includes('ngrok');
|
|
207
|
+
if (isNgrok) {
|
|
208
|
+
var s = document.createElement('script');
|
|
209
|
+
s.type = 'text/javascript';
|
|
210
|
+
document.head.appendChild(s);
|
|
211
|
+
fetch('/agent-widget.js', { headers: { 'ngrok-skip-browser-warning': '1' } })
|
|
212
|
+
.then(function(r) { return r.text(); })
|
|
213
|
+
.then(function(code) { s.textContent = code; })
|
|
214
|
+
.catch(function(e) { console.error('SDK fetch failed:', e); });
|
|
215
|
+
} else {
|
|
216
|
+
var s = document.createElement('script');
|
|
217
|
+
s.src = '/agent-widget.js';
|
|
218
|
+
document.head.appendChild(s);
|
|
219
|
+
}
|
|
220
|
+
})();
|
|
221
|
+
</script>
|
|
222
|
+
|
|
223
|
+
<script>
|
|
224
|
+
let chatWidget = null;
|
|
225
|
+
|
|
226
|
+
function updateStatus(msg, type = '') {
|
|
227
|
+
const el = document.getElementById('status');
|
|
228
|
+
el.textContent = msg;
|
|
229
|
+
el.className = 'status ' + type;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function createWidget() {
|
|
233
|
+
if (chatWidget) {
|
|
234
|
+
chatWidget.destroy();
|
|
235
|
+
chatWidget = null;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const TTPAgentSDK = window.TTPAgentSDK;
|
|
239
|
+
if (!TTPAgentSDK || !TTPAgentSDK.TTPChatWidget) {
|
|
240
|
+
updateStatus('TTPChatWidget not available in SDK', 'error');
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
const agentId = document.getElementById('agentId').value;
|
|
245
|
+
const appId = document.getElementById('appId').value;
|
|
246
|
+
|
|
247
|
+
chatWidget = new TTPAgentSDK.TTPChatWidget({
|
|
248
|
+
agentId,
|
|
249
|
+
appId,
|
|
250
|
+
language: document.getElementById('languageSelect').value,
|
|
251
|
+
agentSettingsOverride: (() => {
|
|
252
|
+
const override = {};
|
|
253
|
+
const stt = document.getElementById('sttSelect').value;
|
|
254
|
+
if (stt) override.sttProvider = stt;
|
|
255
|
+
return override;
|
|
256
|
+
})(),
|
|
257
|
+
behavior: {
|
|
258
|
+
mode: 'unified',
|
|
259
|
+
startOpen: true
|
|
260
|
+
},
|
|
261
|
+
flavor: {
|
|
262
|
+
type: 'restaurants',
|
|
263
|
+
partnerId: 'mock-restaurant'
|
|
264
|
+
},
|
|
265
|
+
icon: {
|
|
266
|
+
type: 'custom',
|
|
267
|
+
size: 'medium',
|
|
268
|
+
backgroundColor: '#FFFFFF'
|
|
269
|
+
}
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
window.testWidget = chatWidget;
|
|
273
|
+
updateStatus('TTPChatWidget created — restaurants flavor (mock-restaurant)', 'success');
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
document.getElementById('createBtn').onclick = createWidget;
|
|
277
|
+
|
|
278
|
+
document.getElementById('destroyBtn').onclick = () => {
|
|
279
|
+
if (chatWidget) {
|
|
280
|
+
chatWidget.destroy();
|
|
281
|
+
chatWidget = null;
|
|
282
|
+
updateStatus('Widget destroyed', '');
|
|
283
|
+
}
|
|
284
|
+
};
|
|
285
|
+
|
|
286
|
+
document.getElementById('showMenuBtn').onclick = () => {
|
|
287
|
+
if (!chatWidget || !chatWidget._flavor) {
|
|
288
|
+
updateStatus('Create widget first', 'error');
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
chatWidget._flavor.messageHandlers['show_items']({
|
|
292
|
+
t: 'show_items',
|
|
293
|
+
items: [
|
|
294
|
+
{ id: 'APP-001', name: 'Bruschetta', category: 'Appetizers', price: 9.99, currency: 'USD', imageUrl: 'https://images.unsplash.com/photo-1572695157366-5e585ab2b69f?w=300&h=300&fit=crop', available: true, tags: ['appetizer', 'italian', 'vegetarian'], allergens: ['gluten', 'dairy'], description: 'Toasted bread with fresh tomatoes and basil' },
|
|
295
|
+
{ id: 'MAIN-001', name: 'Grilled Salmon', category: 'Mains', price: 24.99, currency: 'USD', imageUrl: 'https://images.unsplash.com/photo-1467003909585-2f8a72700288?w=300&h=300&fit=crop', available: true, tags: ['seafood', 'healthy', 'grilled'], allergens: ['fish'], description: 'Atlantic salmon with seasonal vegetables' },
|
|
296
|
+
{ id: 'MAIN-002', name: 'Ribeye Steak', category: 'Mains', price: 32.99, currency: 'USD', imageUrl: 'https://images.unsplash.com/photo-1600891964092-4316c288032e?w=300&h=300&fit=crop', available: true, tags: ['steak', 'beef', 'grilled'], allergens: [], description: '12oz USDA choice ribeye, char-grilled' },
|
|
297
|
+
{ id: 'DES-001', name: 'Tiramisu', category: 'Desserts', price: 10.99, currency: 'USD', imageUrl: 'https://images.unsplash.com/photo-1571877227200-a0d98ea607e9?w=300&h=300&fit=crop', available: true, tags: ['dessert', 'italian', 'coffee'], allergens: ['gluten', 'dairy', 'eggs'], description: 'Classic Italian dessert with mascarpone' }
|
|
298
|
+
],
|
|
299
|
+
title: '4 menu items found'
|
|
300
|
+
});
|
|
301
|
+
updateStatus('show_items injected with 4 menu items', 'success');
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
document.getElementById('showGalleryBtn').onclick = () => {
|
|
305
|
+
if (!chatWidget || !chatWidget._flavor) {
|
|
306
|
+
updateStatus('Create widget first', 'error');
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
chatWidget._flavor.messageHandlers['show_media']({
|
|
310
|
+
t: 'show_media',
|
|
311
|
+
images: [
|
|
312
|
+
{ url: 'https://images.unsplash.com/photo-1517248135467-4c7edcad34c4?w=800', caption: 'Main dining room' },
|
|
313
|
+
{ url: 'https://images.unsplash.com/photo-1414235077428-338989a2e8c0?w=800', caption: 'Candlelit evening ambiance' },
|
|
314
|
+
{ url: 'https://images.unsplash.com/photo-1504674900247-0877df9cc836?w=800', caption: "Chef's signature plating" },
|
|
315
|
+
{ url: 'https://images.unsplash.com/photo-1514933651103-005eec06c04b?w=800', caption: 'Our craft cocktail bar' }
|
|
316
|
+
],
|
|
317
|
+
title: 'Restaurant Gallery'
|
|
318
|
+
});
|
|
319
|
+
updateStatus('show_media injected with 4 images (fullscreen gallery)', 'success');
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
document.getElementById('orderBtn').onclick = () => {
|
|
323
|
+
if (!chatWidget || !chatWidget._flavor) {
|
|
324
|
+
updateStatus('Create widget first', 'error');
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
chatWidget._flavor.messageHandlers['cart_updated']({
|
|
328
|
+
t: 'cart_updated',
|
|
329
|
+
cartItemCount: 3,
|
|
330
|
+
cartTotal: 67.97,
|
|
331
|
+
currency: 'USD',
|
|
332
|
+
action: 'added',
|
|
333
|
+
product: { id: 'MAIN-001', name: 'Grilled Salmon', price: 24.99 }
|
|
334
|
+
});
|
|
335
|
+
updateStatus('cart_updated injected (3 items, $67.97)', 'success');
|
|
336
|
+
};
|
|
337
|
+
|
|
338
|
+
document.getElementById('clearOrderBtn').onclick = () => {
|
|
339
|
+
if (!chatWidget || !chatWidget._flavor) {
|
|
340
|
+
updateStatus('Create widget first', 'error');
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
chatWidget._flavor.messageHandlers['cart_updated']({
|
|
344
|
+
t: 'cart_updated',
|
|
345
|
+
cartItemCount: 0,
|
|
346
|
+
cartTotal: 0,
|
|
347
|
+
currency: 'USD',
|
|
348
|
+
action: 'refreshed'
|
|
349
|
+
});
|
|
350
|
+
updateStatus('Order cleared', '');
|
|
351
|
+
};
|
|
352
|
+
|
|
353
|
+
function waitForSDK() {
|
|
354
|
+
return new Promise((resolve, reject) => {
|
|
355
|
+
if (window.TTPAgentSDK?.TTPChatWidget) { resolve(); return; }
|
|
356
|
+
let attempts = 0;
|
|
357
|
+
const iv = setInterval(() => {
|
|
358
|
+
attempts++;
|
|
359
|
+
if (window.TTPAgentSDK?.TTPChatWidget) { clearInterval(iv); resolve(); }
|
|
360
|
+
else if (attempts >= 150) { clearInterval(iv); reject(new Error('SDK failed to load')); }
|
|
361
|
+
}, 100);
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
waitForSDK().then(() => {
|
|
366
|
+
updateStatus('SDK loaded — creating widget...', '');
|
|
367
|
+
createWidget();
|
|
368
|
+
}).catch(e => {
|
|
369
|
+
updateStatus('SDK load failed: ' + e.message, 'error');
|
|
370
|
+
});
|
|
371
|
+
</script>
|
|
372
|
+
</body>
|
|
373
|
+
</html>
|
|
@@ -94,11 +94,15 @@
|
|
|
94
94
|
font-size: 13px;
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
-
select, input[type="text"], input[type="number"], input[type="color"] {
|
|
97
|
+
select, input[type="text"], input[type="number"], input[type="color"], textarea {
|
|
98
98
|
font-size: 16px; /* Prevents iOS zoom on focus */
|
|
99
99
|
padding: 10px 12px;
|
|
100
100
|
min-height: 44px;
|
|
101
101
|
}
|
|
102
|
+
|
|
103
|
+
textarea {
|
|
104
|
+
min-height: 100px;
|
|
105
|
+
}
|
|
102
106
|
|
|
103
107
|
input[type="color"] {
|
|
104
108
|
min-width: 50px;
|
|
@@ -188,7 +192,8 @@
|
|
|
188
192
|
background: #4B5563;
|
|
189
193
|
}
|
|
190
194
|
|
|
191
|
-
label {
|
|
195
|
+
/* Scope form labels — global `label { flex-direction: column }` can break in-widget flex rows when useShadowDOM is false */
|
|
196
|
+
.customization-container label {
|
|
192
197
|
display: flex;
|
|
193
198
|
flex-direction: column;
|
|
194
199
|
gap: 4px;
|
|
@@ -196,7 +201,7 @@
|
|
|
196
201
|
color: #374151;
|
|
197
202
|
}
|
|
198
203
|
|
|
199
|
-
select, input[type="text"], input[type="number"], input[type="color"] {
|
|
204
|
+
select, input[type="text"], input[type="number"], input[type="color"], textarea {
|
|
200
205
|
padding: 8px 12px;
|
|
201
206
|
border: 1px solid #D1D5DB;
|
|
202
207
|
border-radius: 6px;
|
|
@@ -206,7 +211,12 @@
|
|
|
206
211
|
color: #111827;
|
|
207
212
|
}
|
|
208
213
|
|
|
209
|
-
|
|
214
|
+
textarea {
|
|
215
|
+
resize: vertical;
|
|
216
|
+
min-height: 80px;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
select:focus, input:focus, textarea:focus {
|
|
210
220
|
outline: none;
|
|
211
221
|
border-color: #667eea;
|
|
212
222
|
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
|
|
@@ -844,7 +854,7 @@
|
|
|
844
854
|
} else {
|
|
845
855
|
initializeUI();
|
|
846
856
|
}
|
|
847
|
-
|
|
857
|
+
|
|
848
858
|
// Clear hover color (set to empty to test no hover color behavior)
|
|
849
859
|
function clearHoverColor() {
|
|
850
860
|
const hoverColorInput = document.getElementById('buttonHoverColor');
|
|
@@ -931,7 +941,6 @@
|
|
|
931
941
|
|
|
932
942
|
icon: {
|
|
933
943
|
type: 'custom',
|
|
934
|
-
customImage: 'https://talktopc.com/logo192.png',
|
|
935
944
|
size: document.getElementById('buttonSize').value,
|
|
936
945
|
backgroundColor: document.getElementById('buttonBgColor').value || '#FFFFFF' // Widget default: white
|
|
937
946
|
},
|
|
@@ -1050,7 +1059,7 @@
|
|
|
1050
1059
|
textCardIcon: document.getElementById('landingTextIcon').value
|
|
1051
1060
|
}
|
|
1052
1061
|
};
|
|
1053
|
-
|
|
1062
|
+
|
|
1054
1063
|
// Only include hoverColor if user has set a custom value (not default #7C3AED)
|
|
1055
1064
|
// If hoverColor is not included, widget will keep original color on hover
|
|
1056
1065
|
const hoverColorInput = document.getElementById('buttonHoverColor');
|
|
@@ -1098,8 +1107,8 @@
|
|
|
1098
1107
|
// Skip if already has listener
|
|
1099
1108
|
if (elementsWithListeners.has(element)) return;
|
|
1100
1109
|
|
|
1101
|
-
// For text inputs - apply on every keystroke (input event) with debounce
|
|
1102
|
-
if (element.type === 'text' || element.tagName === 'TEXTAREA') {
|
|
1110
|
+
// For text inputs and textareas - apply on every keystroke (input event) with debounce
|
|
1111
|
+
if (element.type === 'text' || element.type === 'textarea' || element.tagName === 'TEXTAREA') {
|
|
1103
1112
|
let timeout;
|
|
1104
1113
|
element.addEventListener('input', function() {
|
|
1105
1114
|
// Debounce for text inputs to avoid too many updates
|