tf-checkout-react 1.7.19 → 1.7.23
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/components/addonsContainer/AddonComponent.d.ts +4 -1
- package/dist/components/addonsContainer/SimpleAddonsContainer.d.ts +3 -1
- package/dist/components/addonsContainer/index.d.ts +1 -0
- package/dist/tf-checkout-react.cjs.development.js +87 -12
- package/dist/tf-checkout-react.cjs.development.js.map +1 -1
- package/dist/tf-checkout-react.cjs.production.min.js +1 -1
- package/dist/tf-checkout-react.cjs.production.min.js.map +1 -1
- package/dist/tf-checkout-react.esm.js +87 -12
- package/dist/tf-checkout-react.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/components/addonsContainer/AddonComponent.tsx +24 -2
- package/src/components/addonsContainer/SimpleAddonsContainer.tsx +40 -5
- package/src/components/addonsContainer/index.tsx +2 -0
package/package.json
CHANGED
|
@@ -23,6 +23,9 @@ interface IAddonComponentProps {
|
|
|
23
23
|
values: any;
|
|
24
24
|
errors: any;
|
|
25
25
|
useStepperQty?: boolean;
|
|
26
|
+
siblingIds?: string[];
|
|
27
|
+
allAddonIds?: string[];
|
|
28
|
+
maxTotalQuantity?: number;
|
|
26
29
|
onCustomFieldChange?: (
|
|
27
30
|
addon: any,
|
|
28
31
|
groupId: string | number,
|
|
@@ -31,16 +34,29 @@ interface IAddonComponentProps {
|
|
|
31
34
|
) => void;
|
|
32
35
|
}
|
|
33
36
|
|
|
34
|
-
const AddonStepper = ({ id, selectOptions, handleAddonChange, classNamePrefix }: any) => {
|
|
37
|
+
const AddonStepper = ({ id, selectOptions, handleAddonChange, classNamePrefix, siblingIds = [], allAddonIds = [], maxTotalQuantity }: any) => {
|
|
35
38
|
const { values, setFieldValue } = useFormikContext<any>()
|
|
36
39
|
const qty = Number(values[id] ?? 0)
|
|
37
40
|
const max = selectOptions?.length > 0 ? selectOptions[selectOptions.length - 1].value : 0
|
|
38
41
|
|
|
42
|
+
const totalSelected = allAddonIds.length > 0
|
|
43
|
+
? allAddonIds.reduce((sum: number, aid: string) => sum + Number(values[aid] ?? 0), 0)
|
|
44
|
+
: 0
|
|
45
|
+
|
|
39
46
|
const change = (next: number) => {
|
|
47
|
+
if (next > qty) {
|
|
48
|
+
if (maxTotalQuantity != null) {
|
|
49
|
+
allAddonIds.forEach((aid: string) => { if (aid !== id) setFieldValue(aid, 0) })
|
|
50
|
+
} else {
|
|
51
|
+
siblingIds.forEach((siblingId: string) => setFieldValue(siblingId, 0))
|
|
52
|
+
}
|
|
53
|
+
}
|
|
40
54
|
setFieldValue(id, next)
|
|
41
55
|
handleAddonChange(id, next)
|
|
42
56
|
}
|
|
43
57
|
|
|
58
|
+
const incrementDisabled = qty >= max || (maxTotalQuantity != null && totalSelected >= maxTotalQuantity && qty === 0)
|
|
59
|
+
|
|
44
60
|
return (
|
|
45
61
|
<div className={`${classNamePrefix}_stepper`}>
|
|
46
62
|
<button
|
|
@@ -57,7 +73,7 @@ const AddonStepper = ({ id, selectOptions, handleAddonChange, classNamePrefix }:
|
|
|
57
73
|
type="button"
|
|
58
74
|
className={`${classNamePrefix}_stepper__btn`}
|
|
59
75
|
onClick={() => change(qty + 1)}
|
|
60
|
-
disabled={
|
|
76
|
+
disabled={incrementDisabled}
|
|
61
77
|
aria-label="Increase quantity"
|
|
62
78
|
>
|
|
63
79
|
+
|
|
@@ -76,6 +92,9 @@ const AddonComponent = ({
|
|
|
76
92
|
values,
|
|
77
93
|
errors,
|
|
78
94
|
useStepperQty = false,
|
|
95
|
+
siblingIds = [],
|
|
96
|
+
allAddonIds = [],
|
|
97
|
+
maxTotalQuantity,
|
|
79
98
|
onCustomFieldChange = _identity,
|
|
80
99
|
}: IAddonComponentProps) => {
|
|
81
100
|
const { id, name, active, stock } = data
|
|
@@ -101,6 +120,9 @@ const AddonComponent = ({
|
|
|
101
120
|
selectOptions={selectOptions}
|
|
102
121
|
handleAddonChange={handleAddonChange}
|
|
103
122
|
classNamePrefix={classNamePrefix}
|
|
123
|
+
siblingIds={siblingIds}
|
|
124
|
+
allAddonIds={allAddonIds}
|
|
125
|
+
maxTotalQuantity={maxTotalQuantity}
|
|
104
126
|
/>
|
|
105
127
|
</div>
|
|
106
128
|
) : (
|
|
@@ -31,6 +31,8 @@ export interface ISimpleAddonContainerProps {
|
|
|
31
31
|
configs: any;
|
|
32
32
|
eventId: string;
|
|
33
33
|
useStepperQty?: boolean;
|
|
34
|
+
maxTotalQuantity?: number;
|
|
35
|
+
addonMaxQuantityGroups?: number;
|
|
34
36
|
onAddOnSelect?: (id: string, value: string, addon: any, fieldUpdates: any) => void;
|
|
35
37
|
handleConfirm?: (values: any) => void;
|
|
36
38
|
}
|
|
@@ -48,6 +50,7 @@ export const SimpleAddonsContainer = ({
|
|
|
48
50
|
configs,
|
|
49
51
|
eventId,
|
|
50
52
|
useStepperQty = false,
|
|
53
|
+
addonMaxQuantityGroups,
|
|
51
54
|
onAddOnSelect = _identity,
|
|
52
55
|
handleConfirm = _identity,
|
|
53
56
|
}: ISimpleAddonContainerProps) => {
|
|
@@ -56,6 +59,7 @@ export const SimpleAddonsContainer = ({
|
|
|
56
59
|
const [groupsWithSelectedVariants, setGroupsWithSelectedVariants] = useState<any>({})
|
|
57
60
|
const [groupsWithInitialVariantsValues, setGroupsWithInitialVariantsValues] =
|
|
58
61
|
useState<any>({})
|
|
62
|
+
const [crossGroupSelections, setCrossGroupSelections] = useState<ObjectLiteral>({})
|
|
59
63
|
const [loading, setLoading] = useState(true)
|
|
60
64
|
|
|
61
65
|
const [visibleDescription, setVisibleDescription] = useState<string | null>(null)
|
|
@@ -206,6 +210,34 @@ export const SimpleAddonsContainer = ({
|
|
|
206
210
|
}
|
|
207
211
|
}
|
|
208
212
|
|
|
213
|
+
// Cross-group cap: when addonMaxQuantityGroups is set, limits total selections
|
|
214
|
+
// across ALL addon groups to that number by capping each stepper's max.
|
|
215
|
+
const effectiveAddonsOptions = useMemo(() => {
|
|
216
|
+
if (!addonMaxQuantityGroups) return addonsOptions
|
|
217
|
+
|
|
218
|
+
const totalSelected = Object.values(crossGroupSelections).reduce(
|
|
219
|
+
(sum: number, v: any) => sum + Number(v), 0
|
|
220
|
+
)
|
|
221
|
+
const globalRemaining = addonMaxQuantityGroups - totalSelected
|
|
222
|
+
const result: ObjectLiteral = {}
|
|
223
|
+
|
|
224
|
+
for (const id in addonsOptions) {
|
|
225
|
+
const opts = addonsOptions[id] || []
|
|
226
|
+
const sdkMax = opts.length ? opts[opts.length - 1].value : 0
|
|
227
|
+
const currSelected = Number(crossGroupSelections[id] || 0)
|
|
228
|
+
const allowedMax = Math.max(0, Math.min(sdkMax, globalRemaining + currSelected))
|
|
229
|
+
result[id] = opts.filter((opt: any) => opt.value <= allowedMax)
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
return result
|
|
233
|
+
}, [addonsOptions, crossGroupSelections, addonMaxQuantityGroups])
|
|
234
|
+
|
|
235
|
+
const handleCrossGroupChange = (id: any, value: any) => {
|
|
236
|
+
if (addonMaxQuantityGroups) {
|
|
237
|
+
setCrossGroupSelections((prev: ObjectLiteral) => ({ ...prev, [id]: Number(value) }))
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
209
241
|
const initialValues = useMemo(() => {
|
|
210
242
|
const addOnsData: any = {}
|
|
211
243
|
if (addons?.length > 0 && addOnDataWithCustomFields?.fields?.length > 0) {
|
|
@@ -252,7 +284,8 @@ export const SimpleAddonsContainer = ({
|
|
|
252
284
|
// Real-time validation can be handled here if needed
|
|
253
285
|
}}
|
|
254
286
|
>
|
|
255
|
-
{({ values, errors, setFieldTouched }) =>
|
|
287
|
+
{({ values, errors, setFieldTouched }) => {
|
|
288
|
+
return (
|
|
256
289
|
<Form autoComplete="off" className="form_holder">
|
|
257
290
|
<>
|
|
258
291
|
{addons.map((addon: any) => {
|
|
@@ -359,10 +392,11 @@ export const SimpleAddonsContainer = ({
|
|
|
359
392
|
<AddonComponent
|
|
360
393
|
key={variant.id}
|
|
361
394
|
data={variant}
|
|
362
|
-
selectOptions={
|
|
395
|
+
selectOptions={effectiveAddonsOptions[variant.id]}
|
|
363
396
|
classNamePrefix={classNamePrefix}
|
|
397
|
+
siblingIds={addon.variants.filter((v: any) => v.id !== variant.id).map((v: any) => v.id)}
|
|
364
398
|
handleAddonChange={(id, value) => {
|
|
365
|
-
|
|
399
|
+
handleCrossGroupChange(id, value)
|
|
366
400
|
onFieldChange(id, value, addon)
|
|
367
401
|
const fieldUpdates = collectAddonFieldUpdates(
|
|
368
402
|
addon,
|
|
@@ -383,9 +417,10 @@ export const SimpleAddonsContainer = ({
|
|
|
383
417
|
<AddonComponent
|
|
384
418
|
key={addon.id}
|
|
385
419
|
data={addon}
|
|
386
|
-
selectOptions={
|
|
420
|
+
selectOptions={effectiveAddonsOptions[addon.id]}
|
|
387
421
|
classNamePrefix={classNamePrefix}
|
|
388
422
|
handleAddonChange={(id, value) => {
|
|
423
|
+
handleCrossGroupChange(id, value)
|
|
389
424
|
onFieldChange(id, value, addon)
|
|
390
425
|
const fieldUpdates = collectAddonFieldUpdates(addon, values)
|
|
391
426
|
onAddOnSelect(id, value, addon, fieldUpdates)
|
|
@@ -414,7 +449,7 @@ export const SimpleAddonsContainer = ({
|
|
|
414
449
|
})}
|
|
415
450
|
</>
|
|
416
451
|
</Form>
|
|
417
|
-
)}
|
|
452
|
+
)}}
|
|
418
453
|
</Formik>
|
|
419
454
|
</div>
|
|
420
455
|
</div>
|
|
@@ -38,6 +38,7 @@ export interface IAddonContainterProps {
|
|
|
38
38
|
|
|
39
39
|
onAddOnSelect?: (id: string, value: string, addon: any) => void;
|
|
40
40
|
useStepperQty?: boolean;
|
|
41
|
+
addonMaxQuantityGroups?: number;
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
|
|
@@ -279,6 +280,7 @@ export const AddonsContainter = ({
|
|
|
279
280
|
data={variant}
|
|
280
281
|
selectOptions={addonsOptions[variant.id]}
|
|
281
282
|
classNamePrefix={classNamePrefix}
|
|
283
|
+
siblingIds={addon.variants.map((v: any) => v.id).filter((vid: string) => vid !== variant.id)}
|
|
282
284
|
handleAddonChange={(id, value) => {
|
|
283
285
|
onAddOnSelect(id, value, addon)
|
|
284
286
|
onFieldChange(id, value, addon)
|