🐛 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',
|
||||
type: 'boolean',
|
||||
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',
|
||||
@ -250,12 +240,26 @@ export default function SubscribeAppForm<
|
||||
className: 'col-span-3',
|
||||
},
|
||||
]}
|
||||
value={field.value}
|
||||
onChange={(value) => {
|
||||
form.setValue(
|
||||
field.name,
|
||||
value.filter((item) => item.url),
|
||||
const filteredValue = 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>
|
||||
|
||||
@ -157,6 +157,32 @@ export default function SubscribeForm<T extends Record<string, any>>({
|
||||
});
|
||||
|
||||
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 (
|
||||
<Sheet open={open} onOpenChange={setOpen}>
|
||||
@ -543,7 +569,7 @@ export default function SubscribeForm<T extends Record<string, any>>({
|
||||
<FormItem>
|
||||
<FormLabel>{t('form.discount')}</FormLabel>
|
||||
<FormControl>
|
||||
<ArrayInput<API.SubscribeDiscount>
|
||||
<ArrayInput<API.SubscribeDiscount & { price?: number }>
|
||||
fields={[
|
||||
{
|
||||
name: 'quantity',
|
||||
@ -559,15 +585,6 @@ export default function SubscribeForm<T extends Record<string, any>>({
|
||||
max: 100,
|
||||
placeholder: t('form.discountPercent'),
|
||||
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',
|
||||
@ -575,21 +592,49 @@ export default function SubscribeForm<T extends Record<string, any>>({
|
||||
type: 'number',
|
||||
formatInput: (value) => unitConversion('centsToDollars', 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}
|
||||
onChange={(value) => {
|
||||
form.setValue(field.name, value);
|
||||
onChange={(newValues) => {
|
||||
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>
|
||||
|
||||
@ -11,9 +11,6 @@ interface FieldConfig extends Omit<EnhancedInputProps, 'type'> {
|
||||
name: string;
|
||||
type: 'text' | 'number' | 'select' | 'time' | 'boolean';
|
||||
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> {
|
||||
@ -33,36 +30,13 @@ export function ObjectInput<T extends Record<string, any>>({
|
||||
const [internalState, setInternalState] = useState<T>(value);
|
||||
|
||||
useEffect(() => {
|
||||
let updatedState = { ...internalState, ...value };
|
||||
|
||||
fields.forEach((field) => {
|
||||
if (field?.calculateValue) {
|
||||
updatedState = field.calculateValue(updatedState);
|
||||
}
|
||||
});
|
||||
|
||||
setInternalState(updatedState);
|
||||
}, [value, fields]);
|
||||
setInternalState(value);
|
||||
}, [value]);
|
||||
|
||||
const updateField = (key: keyof T, fieldValue: string | number | boolean) => {
|
||||
let updatedInternalState = { ...internalState, [key]: fieldValue };
|
||||
fields.forEach((field) => {
|
||||
if (field.calculateValue && field.name === key) {
|
||||
const newValue = field.calculateValue(updatedInternalState);
|
||||
updatedInternalState = newValue;
|
||||
}
|
||||
});
|
||||
const updatedInternalState = { ...internalState, [key]: fieldValue };
|
||||
setInternalState(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);
|
||||
onChange(updatedInternalState);
|
||||
};
|
||||
const renderField = (field: FieldConfig) => {
|
||||
switch (field.type) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user