🐛 fix(subscribe): Refactor discount calculations and default selection logic in subscription forms
This commit is contained in:
parent
fa2fb2864f
commit
423b24077f
@ -232,16 +232,6 @@ export default function SubscribeAppForm<
|
|||||||
name: 'is_default',
|
name: 'is_default',
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
placeholder: t('defaultVersion'),
|
placeholder: t('defaultVersion'),
|
||||||
calculateValue: (value) => {
|
|
||||||
const newField = field.value?.map((item) => {
|
|
||||||
if (item.is_default) {
|
|
||||||
item.is_default = false;
|
|
||||||
}
|
|
||||||
return item;
|
|
||||||
});
|
|
||||||
form.setValue(field.name, newField);
|
|
||||||
return value;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'url',
|
name: 'url',
|
||||||
@ -250,12 +240,26 @@ export default function SubscribeAppForm<
|
|||||||
className: 'col-span-3',
|
className: 'col-span-3',
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
value={field.value}
|
|
||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
form.setValue(
|
const filteredValue = value.filter((item) => item.url);
|
||||||
field.name,
|
|
||||||
value.filter((item) => item.url),
|
const defaultIndex = filteredValue.findIndex(
|
||||||
|
(item) => item.is_default,
|
||||||
);
|
);
|
||||||
|
let finalValue = filteredValue;
|
||||||
|
if (defaultIndex >= 0) {
|
||||||
|
finalValue = filteredValue.map((item, index) => ({
|
||||||
|
...item,
|
||||||
|
is_default: index === defaultIndex,
|
||||||
|
}));
|
||||||
|
} else if (filteredValue.length > 0) {
|
||||||
|
finalValue = filteredValue.map((item, index) => ({
|
||||||
|
...item,
|
||||||
|
is_default: index === 0,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
form.setValue(field.name, finalValue as any);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
|
|||||||
@ -157,6 +157,32 @@ export default function SubscribeForm<T extends Record<string, any>>({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const unit_time = form.watch('unit_time');
|
const unit_time = form.watch('unit_time');
|
||||||
|
const unit_price = form.watch('unit_price');
|
||||||
|
const discounts = form.watch('discount');
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!discounts?.length || !unit_price) return;
|
||||||
|
|
||||||
|
const calculatedValues = discounts.map((item: any) => {
|
||||||
|
const result = { ...item };
|
||||||
|
|
||||||
|
if (item.quantity && item.discount) {
|
||||||
|
result.price = evaluateWithPrecision(
|
||||||
|
`${unit_price || 0} * ${item.quantity} * ${item.discount} / 100`,
|
||||||
|
);
|
||||||
|
} else if (item.quantity && item.price && !item.discount) {
|
||||||
|
result.discount = evaluateWithPrecision(
|
||||||
|
`${item.price} / ${item.quantity} / ${unit_price} * 100`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (JSON.stringify(calculatedValues) !== JSON.stringify(discounts)) {
|
||||||
|
form.setValue('discount', calculatedValues);
|
||||||
|
}
|
||||||
|
}, [unit_price, discounts, form]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Sheet open={open} onOpenChange={setOpen}>
|
<Sheet open={open} onOpenChange={setOpen}>
|
||||||
@ -543,7 +569,7 @@ export default function SubscribeForm<T extends Record<string, any>>({
|
|||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>{t('form.discount')}</FormLabel>
|
<FormLabel>{t('form.discount')}</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<ArrayInput<API.SubscribeDiscount>
|
<ArrayInput<API.SubscribeDiscount & { price?: number }>
|
||||||
fields={[
|
fields={[
|
||||||
{
|
{
|
||||||
name: 'quantity',
|
name: 'quantity',
|
||||||
@ -559,15 +585,6 @@ export default function SubscribeForm<T extends Record<string, any>>({
|
|||||||
max: 100,
|
max: 100,
|
||||||
placeholder: t('form.discountPercent'),
|
placeholder: t('form.discountPercent'),
|
||||||
suffix: '%',
|
suffix: '%',
|
||||||
calculateValue: function (data) {
|
|
||||||
const { unit_price } = form.getValues();
|
|
||||||
return {
|
|
||||||
...data,
|
|
||||||
price: evaluateWithPrecision(
|
|
||||||
`${unit_price || 0} * ${data.quantity || 0} * ${data.discount || 0} / 100`,
|
|
||||||
),
|
|
||||||
};
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'price',
|
name: 'price',
|
||||||
@ -575,21 +592,49 @@ export default function SubscribeForm<T extends Record<string, any>>({
|
|||||||
type: 'number',
|
type: 'number',
|
||||||
formatInput: (value) => unitConversion('centsToDollars', value),
|
formatInput: (value) => unitConversion('centsToDollars', value),
|
||||||
formatOutput: (value) => unitConversion('dollarsToCents', value),
|
formatOutput: (value) => unitConversion('dollarsToCents', value),
|
||||||
internal: true,
|
|
||||||
calculateValue: (data) => {
|
|
||||||
const { unit_price } = form.getValues();
|
|
||||||
return {
|
|
||||||
...data,
|
|
||||||
discount: evaluateWithPrecision(
|
|
||||||
`${data.price || 0} / ${data.quantity || 0} / ${unit_price || 0} * 100`,
|
|
||||||
),
|
|
||||||
};
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
value={field.value}
|
value={field.value}
|
||||||
onChange={(value) => {
|
onChange={(newValues) => {
|
||||||
form.setValue(field.name, value);
|
const oldValues = field.value || [];
|
||||||
|
const { unit_price } = form.getValues();
|
||||||
|
|
||||||
|
const calculatedValues = newValues.map((newItem, index) => {
|
||||||
|
const oldItem = oldValues[index] || {};
|
||||||
|
|
||||||
|
const result = { ...newItem };
|
||||||
|
|
||||||
|
const quantityChanged = newItem.quantity !== oldItem.quantity;
|
||||||
|
const discountChanged = newItem.discount !== oldItem.discount;
|
||||||
|
const priceChanged = newItem.price !== oldItem.price;
|
||||||
|
|
||||||
|
if (
|
||||||
|
(quantityChanged || discountChanged) &&
|
||||||
|
!priceChanged &&
|
||||||
|
newItem.quantity &&
|
||||||
|
newItem.discount
|
||||||
|
) {
|
||||||
|
result.price = evaluateWithPrecision(
|
||||||
|
`${unit_price || 0} * ${newItem.quantity} * ${newItem.discount} / 100`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
priceChanged &&
|
||||||
|
!discountChanged &&
|
||||||
|
newItem.price &&
|
||||||
|
newItem.quantity &&
|
||||||
|
unit_price
|
||||||
|
) {
|
||||||
|
result.discount = evaluateWithPrecision(
|
||||||
|
`${newItem.price} / ${newItem.quantity} / ${unit_price} * 100`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
|
||||||
|
form.setValue(field.name, calculatedValues);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
|
|||||||
@ -11,9 +11,6 @@ interface FieldConfig extends Omit<EnhancedInputProps, 'type'> {
|
|||||||
name: string;
|
name: string;
|
||||||
type: 'text' | 'number' | 'select' | 'time' | 'boolean';
|
type: 'text' | 'number' | 'select' | 'time' | 'boolean';
|
||||||
options?: { label: string; value: string }[];
|
options?: { label: string; value: string }[];
|
||||||
internal?: boolean;
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
calculateValue?: (value: Record<string, any>) => any;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ObjectInputProps<T> {
|
interface ObjectInputProps<T> {
|
||||||
@ -33,36 +30,13 @@ export function ObjectInput<T extends Record<string, any>>({
|
|||||||
const [internalState, setInternalState] = useState<T>(value);
|
const [internalState, setInternalState] = useState<T>(value);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let updatedState = { ...internalState, ...value };
|
setInternalState(value);
|
||||||
|
}, [value]);
|
||||||
fields.forEach((field) => {
|
|
||||||
if (field?.calculateValue) {
|
|
||||||
updatedState = field.calculateValue(updatedState);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
setInternalState(updatedState);
|
|
||||||
}, [value, fields]);
|
|
||||||
|
|
||||||
const updateField = (key: keyof T, fieldValue: string | number | boolean) => {
|
const updateField = (key: keyof T, fieldValue: string | number | boolean) => {
|
||||||
let updatedInternalState = { ...internalState, [key]: fieldValue };
|
const updatedInternalState = { ...internalState, [key]: fieldValue };
|
||||||
fields.forEach((field) => {
|
|
||||||
if (field.calculateValue && field.name === key) {
|
|
||||||
const newValue = field.calculateValue(updatedInternalState);
|
|
||||||
updatedInternalState = newValue;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
setInternalState(updatedInternalState);
|
setInternalState(updatedInternalState);
|
||||||
|
onChange(updatedInternalState);
|
||||||
const filteredValue = Object.keys(updatedInternalState).reduce((acc, fieldKey) => {
|
|
||||||
const field = fields.find((f) => f.name === fieldKey);
|
|
||||||
if (field && !field.internal) {
|
|
||||||
acc[fieldKey as keyof T] = updatedInternalState[fieldKey as keyof T];
|
|
||||||
}
|
|
||||||
return acc;
|
|
||||||
}, {} as T);
|
|
||||||
|
|
||||||
onChange(filteredValue);
|
|
||||||
};
|
};
|
||||||
const renderField = (field: FieldConfig) => {
|
const renderField = (field: FieldConfig) => {
|
||||||
switch (field.type) {
|
switch (field.type) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user