lisichatbot 1.3.9 → 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/index.js +195 -21
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -540,6 +540,8 @@ function renderOptions(options, field, isSingleSelect = true) {
|
|
|
540
540
|
optionsWrapper.style.alignItems = 'flex-start';
|
|
541
541
|
optionsWrapper.style.gap = '8px';
|
|
542
542
|
|
|
543
|
+
let hasPreselectedOptions = false; // ✅ Track if any options are pre-selected
|
|
544
|
+
|
|
543
545
|
options.forEach((option, index) => {
|
|
544
546
|
const optionName = option.name || option;
|
|
545
547
|
const optionValue = option.value !== undefined ? option.value : option;
|
|
@@ -562,6 +564,7 @@ function renderOptions(options, field, isSingleSelect = true) {
|
|
|
562
564
|
clone.classList.add('cf-checked');
|
|
563
565
|
clone.style.backgroundColor = config.selectedBackground;
|
|
564
566
|
console.log(` ✅ Pre-selected: ${optionName}`);
|
|
567
|
+
hasPreselectedOptions = true; // ✅ Mark that we have pre-selections
|
|
565
568
|
} else {
|
|
566
569
|
clone.classList.remove('cf-checked');
|
|
567
570
|
clone.style.backgroundColor = 'transparent';
|
|
@@ -610,6 +613,31 @@ function renderOptions(options, field, isSingleSelect = true) {
|
|
|
610
613
|
handleOptionClick(el, field, isSingleSelect);
|
|
611
614
|
};
|
|
612
615
|
});
|
|
616
|
+
|
|
617
|
+
// ✅ FIX: Enable Next button if options are pre-selected
|
|
618
|
+
if (hasPreselectedOptions) {
|
|
619
|
+
// Set currentSelection for pre-selected options
|
|
620
|
+
if (isSingleSelect) {
|
|
621
|
+
chatState.currentSelection = {
|
|
622
|
+
field,
|
|
623
|
+
value: existingData,
|
|
624
|
+
name: options.find(o => JSON.stringify(o.value !== undefined ? o.value : o) === JSON.stringify(existingData))?.name || existingData
|
|
625
|
+
};
|
|
626
|
+
} else {
|
|
627
|
+
const selectedNames = existingData.map(val => {
|
|
628
|
+
const opt = options.find(o => JSON.stringify(o.value !== undefined ? o.value : o) === JSON.stringify(val));
|
|
629
|
+
return opt ? (opt.name || opt) : val;
|
|
630
|
+
}).join(', ');
|
|
631
|
+
chatState.currentSelection = {
|
|
632
|
+
field,
|
|
633
|
+
value: existingData,
|
|
634
|
+
name: selectedNames
|
|
635
|
+
};
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
enableNextButton();
|
|
639
|
+
console.log(` ✅ Pre-selected options found - Next button enabled`);
|
|
640
|
+
}
|
|
613
641
|
}
|
|
614
642
|
|
|
615
643
|
// =============================================================================
|
|
@@ -637,6 +665,8 @@ function renderColorOptions(options, field) {
|
|
|
637
665
|
optionsWrapper.style.alignItems = 'flex-start';
|
|
638
666
|
optionsWrapper.style.gap = '8px';
|
|
639
667
|
|
|
668
|
+
let hasPreselectedOptions = false; // ✅ Track if any options are pre-selected
|
|
669
|
+
|
|
640
670
|
options.forEach((option, index) => {
|
|
641
671
|
const optionName = option.name || option;
|
|
642
672
|
const optionValue = option.value !== undefined ? option.value : option;
|
|
@@ -654,6 +684,7 @@ function renderColorOptions(options, field) {
|
|
|
654
684
|
clone.classList.add('cf-checked');
|
|
655
685
|
clone.style.backgroundColor = config.selectedBackground;
|
|
656
686
|
console.log(` ✅ Pre-selected color: ${optionName}`);
|
|
687
|
+
hasPreselectedOptions = true; // ✅ Mark that we have pre-selections
|
|
657
688
|
} else {
|
|
658
689
|
clone.classList.remove('cf-checked');
|
|
659
690
|
clone.style.backgroundColor = 'transparent';
|
|
@@ -711,6 +742,24 @@ function renderColorOptions(options, field) {
|
|
|
711
742
|
handleOptionClick(el, field, false);
|
|
712
743
|
};
|
|
713
744
|
});
|
|
745
|
+
|
|
746
|
+
// ✅ FIX: Enable Next button if options are pre-selected
|
|
747
|
+
if (hasPreselectedOptions) {
|
|
748
|
+
// Set currentSelection for pre-selected options
|
|
749
|
+
const selectedNames = existingData.map(val => {
|
|
750
|
+
const opt = options.find(o => JSON.stringify(o.value !== undefined ? o.value : o) === JSON.stringify(val));
|
|
751
|
+
return opt ? (opt.name || opt) : val;
|
|
752
|
+
}).join(', ');
|
|
753
|
+
|
|
754
|
+
chatState.currentSelection = {
|
|
755
|
+
field,
|
|
756
|
+
value: existingData,
|
|
757
|
+
name: selectedNames
|
|
758
|
+
};
|
|
759
|
+
|
|
760
|
+
enableNextButton();
|
|
761
|
+
console.log(` ✅ Pre-selected color options found - Next button enabled`);
|
|
762
|
+
}
|
|
714
763
|
}
|
|
715
764
|
|
|
716
765
|
// =============================================================================
|
|
@@ -738,6 +787,8 @@ function renderCustomSelectOptions(options, field, customConfig) {
|
|
|
738
787
|
optionsWrapper.style.alignItems = 'flex-start';
|
|
739
788
|
optionsWrapper.style.gap = '8px';
|
|
740
789
|
|
|
790
|
+
let hasPreselectedOption = false; // ✅ Track if any option is pre-selected
|
|
791
|
+
|
|
741
792
|
options.forEach((option, index) => {
|
|
742
793
|
const optionName = option.name || option;
|
|
743
794
|
const optionValue = option.value !== undefined ? option.value : option;
|
|
@@ -755,6 +806,7 @@ function renderCustomSelectOptions(options, field, customConfig) {
|
|
|
755
806
|
clone.classList.add('cf-checked');
|
|
756
807
|
clone.style.backgroundColor = config.selectedBackground;
|
|
757
808
|
console.log(` ✅ Pre-selected: ${optionName}`);
|
|
809
|
+
hasPreselectedOption = true; // ✅ Mark that we have a pre-selection
|
|
758
810
|
} else {
|
|
759
811
|
clone.classList.remove('cf-checked');
|
|
760
812
|
clone.style.backgroundColor = 'transparent';
|
|
@@ -799,6 +851,7 @@ function renderCustomSelectOptions(options, field, customConfig) {
|
|
|
799
851
|
customClone.classList.add('cf-checked');
|
|
800
852
|
customClone.style.backgroundColor = config.selectedBackground;
|
|
801
853
|
console.log(` ✅ Pre-selected: Custom Range [${existingData[0]}, ${existingData[1]}]`);
|
|
854
|
+
hasPreselectedOption = true; // ✅ Mark that custom is pre-selected
|
|
802
855
|
} else {
|
|
803
856
|
customClone.classList.remove('cf-checked');
|
|
804
857
|
customClone.style.backgroundColor = 'transparent';
|
|
@@ -842,6 +895,35 @@ function renderCustomSelectOptions(options, field, customConfig) {
|
|
|
842
895
|
handleCustomSelectClick(el, field, customConfig);
|
|
843
896
|
};
|
|
844
897
|
});
|
|
898
|
+
|
|
899
|
+
// ✅ FIX: Enable Next button if option is pre-selected
|
|
900
|
+
if (hasPreselectedOption) {
|
|
901
|
+
// Set currentSelection
|
|
902
|
+
const isCustomSelected = Array.isArray(existingData) && existingData.length === 2;
|
|
903
|
+
|
|
904
|
+
if (isCustomSelected) {
|
|
905
|
+
// Custom range selected - currentSelection will be set by validateMinMax
|
|
906
|
+
const validation = validateMinMax(field, customConfig);
|
|
907
|
+
if (validation.valid) {
|
|
908
|
+
enableNextButton();
|
|
909
|
+
console.log(` ✅ Pre-selected custom range is valid - Next button enabled`);
|
|
910
|
+
}
|
|
911
|
+
} else {
|
|
912
|
+
// Regular option selected
|
|
913
|
+
const selectedOption = options.find(o =>
|
|
914
|
+
JSON.stringify(o.value !== undefined ? o.value : o) === JSON.stringify(existingData)
|
|
915
|
+
);
|
|
916
|
+
|
|
917
|
+
chatState.currentSelection = {
|
|
918
|
+
field,
|
|
919
|
+
value: existingData,
|
|
920
|
+
name: selectedOption ? (selectedOption.name || selectedOption) : existingData
|
|
921
|
+
};
|
|
922
|
+
|
|
923
|
+
enableNextButton();
|
|
924
|
+
console.log(` ✅ Pre-selected option found - Next button enabled`);
|
|
925
|
+
}
|
|
926
|
+
}
|
|
845
927
|
}
|
|
846
928
|
|
|
847
929
|
function renderMinMaxInputs(field, customConfig, existingData) {
|
|
@@ -1331,10 +1413,21 @@ function renderTextInput(field, inputType = 'text', inputConfig = {}) {
|
|
|
1331
1413
|
inputElement.type = inputType === 'number' ? 'number' : 'text';
|
|
1332
1414
|
|
|
1333
1415
|
inputElement.oninput = (e) => {
|
|
1334
|
-
const
|
|
1416
|
+
const rawValue = e.target.value;
|
|
1417
|
+
const value = inputType === 'number' ? parseFloat(rawValue) : rawValue;
|
|
1335
1418
|
|
|
1336
|
-
|
|
1337
|
-
|
|
1419
|
+
// ✅ FIX: Only set data and currentSelection if value is valid
|
|
1420
|
+
const isEmpty = rawValue === '' || (inputType === 'number' && isNaN(value));
|
|
1421
|
+
const isEmptyText = inputType === 'text' && (!rawValue || rawValue.trim() === '');
|
|
1422
|
+
|
|
1423
|
+
if (!isEmpty && !isEmptyText) {
|
|
1424
|
+
chatState.data[field] = value;
|
|
1425
|
+
chatState.currentSelection = { field, value, name: value.toString() };
|
|
1426
|
+
} else {
|
|
1427
|
+
// Clear data and selection for empty values
|
|
1428
|
+
delete chatState.data[field];
|
|
1429
|
+
chatState.currentSelection = null;
|
|
1430
|
+
}
|
|
1338
1431
|
|
|
1339
1432
|
if (hasValidation) {
|
|
1340
1433
|
const min = inputConfig.min;
|
|
@@ -1343,7 +1436,7 @@ function renderTextInput(field, inputType = 'text', inputConfig = {}) {
|
|
|
1343
1436
|
let isValid = true;
|
|
1344
1437
|
let errorMessage = '';
|
|
1345
1438
|
|
|
1346
|
-
if (
|
|
1439
|
+
if (rawValue === '' || (inputType === 'number' && isNaN(value))) {
|
|
1347
1440
|
isValid = false;
|
|
1348
1441
|
errorMessage = 'Please enter a valid number';
|
|
1349
1442
|
} else if (min !== undefined && value < min) {
|
|
@@ -1362,21 +1455,43 @@ function renderTextInput(field, inputType = 'text', inputConfig = {}) {
|
|
|
1362
1455
|
console.log(` ❌ Number input invalid: ${errorMessage} - Next button disabled`);
|
|
1363
1456
|
}
|
|
1364
1457
|
} else {
|
|
1365
|
-
// ✅ FIX:
|
|
1366
|
-
if (
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1458
|
+
// ✅ FIX: Handle number inputs without validation
|
|
1459
|
+
if (inputType === 'number') {
|
|
1460
|
+
// For number inputs, check if value is valid
|
|
1461
|
+
if (rawValue === '' || isNaN(value)) {
|
|
1462
|
+
// Empty or NaN
|
|
1463
|
+
const currentStep = flowData.flow[chatState.step];
|
|
1464
|
+
const inputRequired = currentStep.inputRequired === true;
|
|
1465
|
+
|
|
1466
|
+
if (inputRequired) {
|
|
1467
|
+
disableNextButton();
|
|
1468
|
+
console.log(` 🔒 Number input empty/NaN and required - Next button disabled`);
|
|
1469
|
+
} else {
|
|
1470
|
+
enableNextButton();
|
|
1471
|
+
console.log(` 🔓 Number input empty/NaN but not required - Next button enabled`);
|
|
1472
|
+
}
|
|
1377
1473
|
} else {
|
|
1474
|
+
// Has valid number value
|
|
1378
1475
|
enableNextButton();
|
|
1379
|
-
console.log(`
|
|
1476
|
+
console.log(` ✅ Number input has value: ${value} - Next button enabled`);
|
|
1477
|
+
}
|
|
1478
|
+
} else {
|
|
1479
|
+
// Text input logic
|
|
1480
|
+
if (rawValue && rawValue.trim() !== '') {
|
|
1481
|
+
enableNextButton();
|
|
1482
|
+
console.log(` ✅ Text input has value - Next button enabled`);
|
|
1483
|
+
} else {
|
|
1484
|
+
// ✅ Check if input is required
|
|
1485
|
+
const currentStep = flowData.flow[chatState.step];
|
|
1486
|
+
const inputRequired = currentStep.inputRequired === true;
|
|
1487
|
+
|
|
1488
|
+
if (inputRequired) {
|
|
1489
|
+
disableNextButton();
|
|
1490
|
+
console.log(` 🔒 Text input empty and required - Next button disabled`);
|
|
1491
|
+
} else {
|
|
1492
|
+
enableNextButton();
|
|
1493
|
+
console.log(` 🔓 Text input empty but not required - Next button enabled`);
|
|
1494
|
+
}
|
|
1380
1495
|
}
|
|
1381
1496
|
}
|
|
1382
1497
|
}
|
|
@@ -1516,6 +1631,33 @@ async function handleNext() {
|
|
|
1516
1631
|
console.log('Selection required but none made');
|
|
1517
1632
|
return;
|
|
1518
1633
|
}
|
|
1634
|
+
|
|
1635
|
+
// ✅ FIX: Validate text/number inputs when required
|
|
1636
|
+
if (currentStep.input && inputRequired) {
|
|
1637
|
+
const inputType = currentStep.inputType || 'single-select';
|
|
1638
|
+
|
|
1639
|
+
if (inputType === 'text' || inputType === 'number') {
|
|
1640
|
+
const field = currentStep.input.field;
|
|
1641
|
+
const value = chatState.data[field];
|
|
1642
|
+
|
|
1643
|
+
// Check for empty or invalid values
|
|
1644
|
+
if (inputType === 'text') {
|
|
1645
|
+
if (value === undefined || value === null || value === '' || (typeof value === 'string' && value.trim() === '')) {
|
|
1646
|
+
console.log('❌ Text input required but empty - cannot proceed');
|
|
1647
|
+
disableNextButton();
|
|
1648
|
+
return;
|
|
1649
|
+
}
|
|
1650
|
+
} else if (inputType === 'number') {
|
|
1651
|
+
if (value === undefined || value === null || value === '' || isNaN(value)) {
|
|
1652
|
+
console.log('❌ Number input required but empty/NaN - cannot proceed');
|
|
1653
|
+
disableNextButton();
|
|
1654
|
+
return;
|
|
1655
|
+
}
|
|
1656
|
+
}
|
|
1657
|
+
|
|
1658
|
+
console.log(`✅ ${inputType} input validation passed:`, value);
|
|
1659
|
+
}
|
|
1660
|
+
}
|
|
1519
1661
|
|
|
1520
1662
|
if (currentStep.inputType === 'single-select-custom' && currentStep.input) {
|
|
1521
1663
|
const field = currentStep.input.field;
|
|
@@ -1704,9 +1846,19 @@ async function showNextStep() {
|
|
|
1704
1846
|
} else if (inputType === 'multi-select-color') {
|
|
1705
1847
|
renderColorOptions(nextStep.input.options, nextStep.input.field);
|
|
1706
1848
|
|
|
1707
|
-
if
|
|
1849
|
+
// ✅ Check if pre-filled - renderColorOptions handles enabling if pre-filled
|
|
1850
|
+
// Only disable if NOT pre-filled and required
|
|
1851
|
+
const existingData = chatState.data[nextStep.input.field];
|
|
1852
|
+
const hasPreFill = Array.isArray(existingData) && existingData.length > 0;
|
|
1853
|
+
|
|
1854
|
+
if (inputRequired && !hasPreFill) {
|
|
1855
|
+
disableNextButton();
|
|
1856
|
+
console.log(' 🔒 Multi-select-color required with no pre-fill - Next button disabled');
|
|
1857
|
+
} else if (!inputRequired && !hasPreFill) {
|
|
1708
1858
|
enableNextButton();
|
|
1859
|
+
console.log(' 🔓 Multi-select-color not required - Next button enabled');
|
|
1709
1860
|
}
|
|
1861
|
+
// If hasPreFill, renderColorOptions already handled it
|
|
1710
1862
|
} else if (inputType === 'single-select-custom') {
|
|
1711
1863
|
renderCustomSelectOptions(
|
|
1712
1864
|
nextStep.input.options,
|
|
@@ -1714,11 +1866,18 @@ async function showNextStep() {
|
|
|
1714
1866
|
nextStep.input.custom
|
|
1715
1867
|
);
|
|
1716
1868
|
|
|
1717
|
-
if
|
|
1869
|
+
// ✅ Check if pre-filled - renderCustomSelectOptions handles enabling if pre-filled
|
|
1870
|
+
const existingData = chatState.data[nextStep.input.field];
|
|
1871
|
+
const hasPreFill = existingData !== undefined && existingData !== null;
|
|
1872
|
+
|
|
1873
|
+
if (inputRequired && !hasPreFill) {
|
|
1718
1874
|
disableNextButton();
|
|
1719
|
-
|
|
1875
|
+
console.log(' 🔒 Single-select-custom required with no pre-fill - Next button disabled');
|
|
1876
|
+
} else if (!inputRequired && !hasPreFill) {
|
|
1720
1877
|
enableNextButton();
|
|
1878
|
+
console.log(' 🔓 Single-select-custom not required - Next button enabled');
|
|
1721
1879
|
}
|
|
1880
|
+
// If hasPreFill, renderCustomSelectOptions already handled it
|
|
1722
1881
|
} else if (inputType === 'multi-select-dropdown') {
|
|
1723
1882
|
// ✅ Render multi-select dropdown
|
|
1724
1883
|
renderMultiSelectDropdown(nextStep.input.options, nextStep.input.field);
|
|
@@ -1735,9 +1894,24 @@ async function showNextStep() {
|
|
|
1735
1894
|
const isSingleSelect = inputType === 'single-select';
|
|
1736
1895
|
renderOptions(nextStep.input.options, nextStep.input.field, isSingleSelect);
|
|
1737
1896
|
|
|
1738
|
-
if
|
|
1897
|
+
// ✅ Check if pre-filled - renderOptions handles enabling if pre-filled
|
|
1898
|
+
const existingData = chatState.data[nextStep.input.field];
|
|
1899
|
+
let hasPreFill = false;
|
|
1900
|
+
|
|
1901
|
+
if (isSingleSelect) {
|
|
1902
|
+
hasPreFill = existingData !== undefined && existingData !== null;
|
|
1903
|
+
} else {
|
|
1904
|
+
hasPreFill = Array.isArray(existingData) && existingData.length > 0;
|
|
1905
|
+
}
|
|
1906
|
+
|
|
1907
|
+
if (inputRequired && !hasPreFill) {
|
|
1908
|
+
disableNextButton();
|
|
1909
|
+
console.log(` 🔒 ${inputType} required with no pre-fill - Next button disabled`);
|
|
1910
|
+
} else if (!inputRequired && !hasPreFill) {
|
|
1739
1911
|
enableNextButton();
|
|
1912
|
+
console.log(` 🔓 ${inputType} not required - Next button enabled`);
|
|
1740
1913
|
}
|
|
1914
|
+
// If hasPreFill, renderOptions already handled it
|
|
1741
1915
|
}
|
|
1742
1916
|
} else {
|
|
1743
1917
|
const delay = nextStep.autoAdvanceDelay !== undefined ? nextStep.autoAdvanceDelay : config.autoAdvanceDelay;
|