🐛 fix(subscribe): Refactor discount calculations and default selection logic in subscription forms

This commit is contained in:
web@ppanel 2025-03-30 00:53:47 +07:00
parent fa2fb2864f
commit 423b24077f
3 changed files with 89 additions and 66 deletions

View File

@ -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>

View File

@ -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>

View File

@ -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) {