|
319 | 319 | this.recognition = null; |
320 | 320 | this.isListening = false; |
321 | 321 | this.currentFormSchema = null; |
| 322 | + // Track all extracted values across the session |
| 323 | + this.allExtractedValues = {}; |
| 324 | + this.isFormComplete = false; |
| 325 | + this.fillFormBtn = null; |
322 | 326 | } |
323 | 327 |
|
324 | 328 | create() { |
|
652 | 656 | .fill-btn-inline:hover { opacity: 0.9; transform: scale(1.02); } |
653 | 657 | .fill-btn-inline svg { width: 14px; height: 14px; } |
654 | 658 |
|
| 659 | + /* Sticky Fill Form Button */ |
| 660 | + .fill-form-container { |
| 661 | + padding: 12px 16px; |
| 662 | + background: linear-gradient(180deg, transparent 0%, rgba(13, 13, 13, 0.95) 20%); |
| 663 | + opacity: 0; |
| 664 | + transform: translateY(20px); |
| 665 | + transition: all 0.4s cubic-bezier(0.16, 1, 0.3, 1); |
| 666 | + } |
| 667 | + .fill-form-container.visible { |
| 668 | + opacity: 1; |
| 669 | + transform: translateY(0); |
| 670 | + } |
| 671 | + |
| 672 | + .fill-form-btn { |
| 673 | + width: 100%; |
| 674 | + padding: 14px 24px; |
| 675 | + border-radius: 12px; |
| 676 | + background: linear-gradient(135deg, var(--primary) 0%, #059669 100%); |
| 677 | + color: white; |
| 678 | + border: none; |
| 679 | + cursor: pointer; |
| 680 | + font-weight: 600; |
| 681 | + font-size: 15px; |
| 682 | + display: flex; |
| 683 | + align-items: center; |
| 684 | + justify-content: center; |
| 685 | + gap: 10px; |
| 686 | + transition: all 0.3s cubic-bezier(0.16, 1, 0.3, 1); |
| 687 | + box-shadow: 0 4px 20px rgba(16, 185, 129, 0.3); |
| 688 | + } |
| 689 | + .fill-form-btn:hover:not(:disabled) { |
| 690 | + transform: translateY(-2px); |
| 691 | + box-shadow: 0 8px 30px rgba(16, 185, 129, 0.4); |
| 692 | + } |
| 693 | + .fill-form-btn:active:not(:disabled) { |
| 694 | + transform: translateY(0); |
| 695 | + } |
| 696 | + .fill-form-btn:disabled { |
| 697 | + opacity: 0.7; |
| 698 | + cursor: not-allowed; |
| 699 | + } |
| 700 | + .fill-form-btn svg { width: 20px; height: 20px; } |
| 701 | +
|
| 702 | + /* Toast Notification */ |
| 703 | + .notification { |
| 704 | + background: linear-gradient(135deg, #10b981 0%, #059669 100%); |
| 705 | + color: white; |
| 706 | + padding: 10px 16px; |
| 707 | + font-size: 13px; |
| 708 | + font-weight: 500; |
| 709 | + text-align: center; |
| 710 | + opacity: 0; |
| 711 | + transform: translateY(-100%); |
| 712 | + transition: all 0.3s cubic-bezier(0.16, 1, 0.3, 1); |
| 713 | + border-bottom: 1px solid rgba(255, 255, 255, 0.1); |
| 714 | + } |
| 715 | + .notification.visible { |
| 716 | + opacity: 1; |
| 717 | + transform: translateY(0); |
| 718 | + } |
| 719 | +
|
655 | 720 | @keyframes fadeIn { from { opacity: 0; transform: translateY(5px); } to { opacity: 1; transform: translateY(0); } } |
656 | 721 |
|
| 722 | +
|
657 | 723 | /* Prompt Input Box (Redesigned) */ |
658 | 724 | .prompt-box { |
659 | 725 | background: var(--bg-dark); |
|
1216 | 1282 | if (response.success) { |
1217 | 1283 | this.addMessage(response.response, 'ai'); |
1218 | 1284 |
|
1219 | | - if (Object.keys(response.extractedValues || {}).length > 0) { |
1220 | | - // Create a fill form button inside a chat bubble |
1221 | | - const actionBubble = document.createElement('div'); |
1222 | | - actionBubble.className = 'chat-bubble ai'; |
1223 | | - actionBubble.innerHTML = ` |
1224 | | - < div class="avatar ai" > AI</div > |
1225 | | - <div class="msg-content"> |
1226 | | - <span>Form data ready!</span> |
1227 | | - <button class="fill-btn-inline"> |
1228 | | - ${ICONS.SEND} |
1229 | | - Fill Form |
1230 | | - </button> |
1231 | | - </div> |
1232 | | - `; |
1233 | | - this.chatHistory.appendChild(actionBubble); |
1234 | | - actionBubble.querySelector('button').onclick = () => { |
1235 | | - this.autoFill(response.extractedValues); |
1236 | | - actionBubble.remove(); |
1237 | | - }; |
1238 | | - this.scrollToBottom(); |
| 1285 | + // Accumulate extracted values across the session |
| 1286 | + if (response.extractedValues && Object.keys(response.extractedValues).length > 0) { |
| 1287 | + Object.assign(this.allExtractedValues, response.extractedValues); |
| 1288 | + console.log('FormFlow: Accumulated values:', this.allExtractedValues); |
| 1289 | + |
| 1290 | + // Show extraction notification |
| 1291 | + const extractedCount = Object.keys(this.allExtractedValues).length; |
| 1292 | + this.showNotification(`✓ ${extractedCount} field${extractedCount > 1 ? 's' : ''} collected`); |
| 1293 | + } |
| 1294 | + |
| 1295 | + // Check if form is complete - show sticky Fill Form button |
| 1296 | + if (response.isComplete) { |
| 1297 | + this.isFormComplete = true; |
| 1298 | + this.showFillFormButton(); |
| 1299 | + this.showNotification('🎉 All fields collected! Ready to fill form.'); |
1239 | 1300 | } |
1240 | 1301 |
|
| 1302 | + |
1241 | 1303 | } else { |
1242 | 1304 | this.addMessage("Error: " + response.error, 'ai'); |
1243 | 1305 | } |
|
1248 | 1310 | } |
1249 | 1311 | } |
1250 | 1312 |
|
| 1313 | + showFillFormButton() { |
| 1314 | + // Only create if not already present |
| 1315 | + if (this.fillFormBtn) return; |
| 1316 | + |
| 1317 | + // Get the shadow root |
| 1318 | + const shadow = this.container.shadowRoot; |
| 1319 | + if (!shadow) return; |
| 1320 | + |
| 1321 | + // Create sticky button container |
| 1322 | + const btnContainer = document.createElement('div'); |
| 1323 | + btnContainer.className = 'fill-form-container'; |
| 1324 | + btnContainer.innerHTML = ` |
| 1325 | + <button class="fill-form-btn"> |
| 1326 | + <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> |
| 1327 | + <path d="M12 5v14"/><path d="m19 12-7 7-7-7"/> |
| 1328 | + </svg> |
| 1329 | + <span>Fill Form (${Object.keys(this.allExtractedValues).length} fields)</span> |
| 1330 | + </button> |
| 1331 | + `; |
| 1332 | + |
| 1333 | + // Insert before the prompt box |
| 1334 | + const promptBox = shadow.querySelector('.prompt-box'); |
| 1335 | + if (promptBox) { |
| 1336 | + promptBox.parentNode.insertBefore(btnContainer, promptBox); |
| 1337 | + } |
| 1338 | + |
| 1339 | + this.fillFormBtn = btnContainer; |
| 1340 | + |
| 1341 | + // Add click handler |
| 1342 | + btnContainer.querySelector('button').onclick = async () => { |
| 1343 | + btnContainer.querySelector('button').disabled = true; |
| 1344 | + btnContainer.querySelector('span').textContent = 'Filling...'; |
| 1345 | + await this.autoFill(this.allExtractedValues); |
| 1346 | + btnContainer.querySelector('span').textContent = '✓ Done!'; |
| 1347 | + setTimeout(() => { |
| 1348 | + btnContainer.remove(); |
| 1349 | + this.fillFormBtn = null; |
| 1350 | + }, 1500); |
| 1351 | + }; |
| 1352 | + |
| 1353 | + // Add animation |
| 1354 | + setTimeout(() => btnContainer.classList.add('visible'), 50); |
| 1355 | + } |
| 1356 | + |
| 1357 | + showNotification(message) { |
| 1358 | + const shadow = this.container?.shadowRoot; |
| 1359 | + if (!shadow) return; |
| 1360 | + |
| 1361 | + // Create notification element |
| 1362 | + const notification = document.createElement('div'); |
| 1363 | + notification.className = 'notification'; |
| 1364 | + notification.textContent = message; |
| 1365 | + |
| 1366 | + // Insert at top of panel |
| 1367 | + const panel = shadow.querySelector('.panel'); |
| 1368 | + if (panel) { |
| 1369 | + panel.insertBefore(notification, panel.firstChild); |
| 1370 | + |
| 1371 | + // Animate in |
| 1372 | + setTimeout(() => notification.classList.add('visible'), 10); |
| 1373 | + |
| 1374 | + // Remove after delay |
| 1375 | + setTimeout(() => { |
| 1376 | + notification.classList.remove('visible'); |
| 1377 | + setTimeout(() => notification.remove(), 300); |
| 1378 | + }, 2500); |
| 1379 | + } |
| 1380 | + } |
| 1381 | + |
1251 | 1382 | async autoFill(data) { |
1252 | 1383 | const formFiller = new FormFiller(); |
1253 | | - await formFiller.fillFields(data, this.currentFormSchema); |
1254 | | - this.addMessage("✅ Form updated.", 'ai'); |
| 1384 | + const filledCount = await formFiller.fillFields(data, this.currentFormSchema); |
| 1385 | + this.addMessage(`✅ Form filled! (${filledCount} fields updated)`, 'ai'); |
1255 | 1386 | } |
1256 | 1387 |
|
1257 | 1388 | hide() { |
|
0 commit comments