lisichatbot 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/package.json +1 -1
- package/src/index.js +213 -18
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) {
|
|
@@ -1012,7 +1094,52 @@ function handleCustomSelectClick(element, field, customConfig) {
|
|
|
1012
1094
|
|
|
1013
1095
|
console.log(`Custom-select clicked:`, { field, name: optionName, isCustom });
|
|
1014
1096
|
|
|
1097
|
+
// ✅ FIX: Check if this option is already selected - allow deselection
|
|
1098
|
+
const isAlreadySelected = element.classList.contains('cf-checked');
|
|
1099
|
+
|
|
1015
1100
|
const allOptions = document.querySelectorAll(`[data-field="${field}"][data-chat-element="single-select-input"]`);
|
|
1101
|
+
|
|
1102
|
+
if (isAlreadySelected) {
|
|
1103
|
+
// ✅ Deselect the currently selected option
|
|
1104
|
+
console.log(` 🔄 Deselecting "${optionName}"`);
|
|
1105
|
+
|
|
1106
|
+
element.classList.remove('cf-checked');
|
|
1107
|
+
element.style.setProperty('background-color', 'transparent', 'important');
|
|
1108
|
+
const tickIcon = element.querySelector('[data-chat-input-element="tick-icon"]');
|
|
1109
|
+
if (tickIcon) tickIcon.style.setProperty('display', 'none', 'important');
|
|
1110
|
+
|
|
1111
|
+
// Hide range wrapper if custom was deselected
|
|
1112
|
+
if (isCustom) {
|
|
1113
|
+
const rangeWrapper = document.querySelector(`[data-chat-element="range-wrapper"][data-field="${field}"]`);
|
|
1114
|
+
if (rangeWrapper) {
|
|
1115
|
+
rangeWrapper.style.display = 'none';
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
// Clear data
|
|
1120
|
+
delete chatState.data[field];
|
|
1121
|
+
chatState.currentSelection = null;
|
|
1122
|
+
|
|
1123
|
+
console.log(` ❌ Deselected "${optionName}" - No selection`);
|
|
1124
|
+
|
|
1125
|
+
// ✅ Check if input is required - disable button if nothing selected
|
|
1126
|
+
const currentStep = flowData.flow[chatState.step];
|
|
1127
|
+
const inputRequired = currentStep.inputRequired === true;
|
|
1128
|
+
|
|
1129
|
+
if (inputRequired) {
|
|
1130
|
+
disableNextButton();
|
|
1131
|
+
console.log(' 🔒 Input required - Next button disabled');
|
|
1132
|
+
} else {
|
|
1133
|
+
enableNextButton();
|
|
1134
|
+
console.log(' 🔓 Input not required - Next button still enabled');
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
return; // Exit early
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1140
|
+
// ✅ Select this option (deselect others first)
|
|
1141
|
+
console.log(` ✅ Selecting "${optionName}"`);
|
|
1142
|
+
|
|
1016
1143
|
allOptions.forEach(opt => {
|
|
1017
1144
|
opt.classList.remove('cf-checked');
|
|
1018
1145
|
opt.style.setProperty('background-color', 'transparent', 'important');
|
|
@@ -1460,27 +1587,63 @@ function handleOptionClick(element, field, isSingleSelect) {
|
|
|
1460
1587
|
}
|
|
1461
1588
|
|
|
1462
1589
|
if (isSingleSelect) {
|
|
1590
|
+
// ✅ FIX: Check if this option is already selected - allow deselection
|
|
1591
|
+
const isAlreadySelected = element.classList.contains('cf-checked');
|
|
1592
|
+
|
|
1463
1593
|
const selector = `[data-field="${field}"][data-chat-element="${inputType}"]`;
|
|
1464
1594
|
const allOptions = document.querySelectorAll(selector);
|
|
1465
1595
|
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1596
|
+
if (isAlreadySelected) {
|
|
1597
|
+
// ✅ Deselect the currently selected option
|
|
1598
|
+
console.log(` 🔄 Deselecting "${optionName}"`);
|
|
1469
1599
|
|
|
1470
|
-
|
|
1471
|
-
|
|
1600
|
+
element.classList.remove('cf-checked');
|
|
1601
|
+
element.style.setProperty('background-color', 'transparent', 'important');
|
|
1602
|
+
if (tickIcon) tickIcon.style.setProperty('display', 'none', 'important');
|
|
1603
|
+
if (input) input.checked = false;
|
|
1472
1604
|
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1605
|
+
// Clear data
|
|
1606
|
+
delete chatState.data[field];
|
|
1607
|
+
chatState.currentSelection = null;
|
|
1608
|
+
|
|
1609
|
+
console.log(` ❌ Deselected "${optionName}" - No selection`);
|
|
1610
|
+
|
|
1611
|
+
// ✅ Check if input is required - disable button if nothing selected
|
|
1612
|
+
const currentStep = flowData.flow[chatState.step];
|
|
1613
|
+
const inputRequired = currentStep.inputRequired === true;
|
|
1614
|
+
|
|
1615
|
+
if (inputRequired) {
|
|
1616
|
+
disableNextButton();
|
|
1617
|
+
console.log(' 🔒 Input required - Next button disabled');
|
|
1618
|
+
} else {
|
|
1619
|
+
enableNextButton();
|
|
1620
|
+
console.log(' 🔓 Input not required - Next button still enabled');
|
|
1621
|
+
}
|
|
1622
|
+
} else {
|
|
1623
|
+
// ✅ Select this option (deselect others first)
|
|
1624
|
+
console.log(` ✅ Selecting "${optionName}"`);
|
|
1625
|
+
|
|
1626
|
+
allOptions.forEach(opt => {
|
|
1627
|
+
opt.classList.remove('cf-checked');
|
|
1628
|
+
opt.style.setProperty('background-color', 'transparent', 'important');
|
|
1629
|
+
|
|
1630
|
+
const otherTick = opt.querySelector('[data-chat-input-element="tick-icon"]');
|
|
1631
|
+
const otherInput = opt.querySelector('[data-chat-input-element="input"]');
|
|
1632
|
+
|
|
1633
|
+
if (otherTick) otherTick.style.setProperty('display', 'none', 'important');
|
|
1634
|
+
if (otherInput) otherInput.checked = false;
|
|
1635
|
+
});
|
|
1476
1636
|
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1637
|
+
element.classList.add('cf-checked');
|
|
1638
|
+
element.style.setProperty('background-color', config.selectedBackground, 'important');
|
|
1639
|
+
if (tickIcon) tickIcon.style.setProperty('display', 'block', 'important');
|
|
1640
|
+
if (input) input.checked = true;
|
|
1481
1641
|
|
|
1482
|
-
|
|
1483
|
-
|
|
1642
|
+
chatState.data[field] = value;
|
|
1643
|
+
chatState.currentSelection = { field, value, name: optionName };
|
|
1644
|
+
|
|
1645
|
+
enableNextButton();
|
|
1646
|
+
}
|
|
1484
1647
|
|
|
1485
1648
|
} else {
|
|
1486
1649
|
const isChecked = !element.classList.contains('cf-checked');
|
|
@@ -1764,9 +1927,19 @@ async function showNextStep() {
|
|
|
1764
1927
|
} else if (inputType === 'multi-select-color') {
|
|
1765
1928
|
renderColorOptions(nextStep.input.options, nextStep.input.field);
|
|
1766
1929
|
|
|
1767
|
-
if
|
|
1930
|
+
// ✅ Check if pre-filled - renderColorOptions handles enabling if pre-filled
|
|
1931
|
+
// Only disable if NOT pre-filled and required
|
|
1932
|
+
const existingData = chatState.data[nextStep.input.field];
|
|
1933
|
+
const hasPreFill = Array.isArray(existingData) && existingData.length > 0;
|
|
1934
|
+
|
|
1935
|
+
if (inputRequired && !hasPreFill) {
|
|
1936
|
+
disableNextButton();
|
|
1937
|
+
console.log(' 🔒 Multi-select-color required with no pre-fill - Next button disabled');
|
|
1938
|
+
} else if (!inputRequired && !hasPreFill) {
|
|
1768
1939
|
enableNextButton();
|
|
1940
|
+
console.log(' 🔓 Multi-select-color not required - Next button enabled');
|
|
1769
1941
|
}
|
|
1942
|
+
// If hasPreFill, renderColorOptions already handled it
|
|
1770
1943
|
} else if (inputType === 'single-select-custom') {
|
|
1771
1944
|
renderCustomSelectOptions(
|
|
1772
1945
|
nextStep.input.options,
|
|
@@ -1774,11 +1947,18 @@ async function showNextStep() {
|
|
|
1774
1947
|
nextStep.input.custom
|
|
1775
1948
|
);
|
|
1776
1949
|
|
|
1777
|
-
if
|
|
1950
|
+
// ✅ Check if pre-filled - renderCustomSelectOptions handles enabling if pre-filled
|
|
1951
|
+
const existingData = chatState.data[nextStep.input.field];
|
|
1952
|
+
const hasPreFill = existingData !== undefined && existingData !== null;
|
|
1953
|
+
|
|
1954
|
+
if (inputRequired && !hasPreFill) {
|
|
1778
1955
|
disableNextButton();
|
|
1779
|
-
|
|
1956
|
+
console.log(' 🔒 Single-select-custom required with no pre-fill - Next button disabled');
|
|
1957
|
+
} else if (!inputRequired && !hasPreFill) {
|
|
1780
1958
|
enableNextButton();
|
|
1959
|
+
console.log(' 🔓 Single-select-custom not required - Next button enabled');
|
|
1781
1960
|
}
|
|
1961
|
+
// If hasPreFill, renderCustomSelectOptions already handled it
|
|
1782
1962
|
} else if (inputType === 'multi-select-dropdown') {
|
|
1783
1963
|
// ✅ Render multi-select dropdown
|
|
1784
1964
|
renderMultiSelectDropdown(nextStep.input.options, nextStep.input.field);
|
|
@@ -1795,9 +1975,24 @@ async function showNextStep() {
|
|
|
1795
1975
|
const isSingleSelect = inputType === 'single-select';
|
|
1796
1976
|
renderOptions(nextStep.input.options, nextStep.input.field, isSingleSelect);
|
|
1797
1977
|
|
|
1798
|
-
if
|
|
1978
|
+
// ✅ Check if pre-filled - renderOptions handles enabling if pre-filled
|
|
1979
|
+
const existingData = chatState.data[nextStep.input.field];
|
|
1980
|
+
let hasPreFill = false;
|
|
1981
|
+
|
|
1982
|
+
if (isSingleSelect) {
|
|
1983
|
+
hasPreFill = existingData !== undefined && existingData !== null;
|
|
1984
|
+
} else {
|
|
1985
|
+
hasPreFill = Array.isArray(existingData) && existingData.length > 0;
|
|
1986
|
+
}
|
|
1987
|
+
|
|
1988
|
+
if (inputRequired && !hasPreFill) {
|
|
1989
|
+
disableNextButton();
|
|
1990
|
+
console.log(` 🔒 ${inputType} required with no pre-fill - Next button disabled`);
|
|
1991
|
+
} else if (!inputRequired && !hasPreFill) {
|
|
1799
1992
|
enableNextButton();
|
|
1993
|
+
console.log(` 🔓 ${inputType} not required - Next button enabled`);
|
|
1800
1994
|
}
|
|
1995
|
+
// If hasPreFill, renderOptions already handled it
|
|
1801
1996
|
}
|
|
1802
1997
|
} else {
|
|
1803
1998
|
const delay = nextStep.autoAdvanceDelay !== undefined ? nextStep.autoAdvanceDelay : config.autoAdvanceDelay;
|