mirror of
https://github.com/chillpadclub/bedolaga-cabinet.git
synced 2026-07-30 02:23:47 +00:00
fix(promocode): correct activation UX, error mapping and validity dates
Map promocode errors by stable backend code (detail.code) instead of brittle English
substring matching, so previously-unmapped codes (active_discount_exists, daily_limit,
no_subscription_for_days, trial_*, etc.) show the right message instead of 'server error';
added the missing keys to all 4 locales.
valid_until now anchors to end-of-day in the admin's LOCAL timezone on both create AND
edit read-back, so codes no longer expire at the start of the day and editing no longer
drifts the date forward for negative-offset admins.
Allow 0-hour discount ('until first purchase'). Route user-facing discount deactivation
to the endpoint that rolls back promocode usage when the discount came from a promocode,
and parse the structured {code,message} error.
This commit is contained in:
@@ -118,9 +118,21 @@ export default function PromoOffersSection({ className = '' }: PromoOffersSectio
|
||||
},
|
||||
});
|
||||
|
||||
// Deactivate discount mutation
|
||||
// Deactivate discount mutation.
|
||||
// A discount granted by a PROMOCODE must be turned off via the dedicated route
|
||||
// (POST /cabinet/promocode/deactivate-discount), which also rolls back the promocode
|
||||
// usage (deletes the PromoCodeUse, decrements current_uses, strips the promo group) so
|
||||
// the user can re-activate it later. The plain clearActiveDiscount route only zeroes
|
||||
// the discount fields and is correct for admin/offer-sourced discounts.
|
||||
const deactivateMutation = useMutation({
|
||||
mutationFn: promoApi.clearActiveDiscount,
|
||||
mutationFn: async () => {
|
||||
const source = activeDiscount?.source ?? '';
|
||||
if (source.startsWith('promocode:')) {
|
||||
await promoApi.deactivateDiscount();
|
||||
} else {
|
||||
await promoApi.clearActiveDiscount();
|
||||
}
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['active-discount'] });
|
||||
queryClient.invalidateQueries({ queryKey: ['promo-offers'] });
|
||||
@@ -131,8 +143,14 @@ export default function PromoOffersSection({ className = '' }: PromoOffersSectio
|
||||
setTimeout(() => setSuccessMessage(null), 5000);
|
||||
},
|
||||
onError: (error: unknown) => {
|
||||
const axiosErr = error as { response?: { data?: { detail?: string } } };
|
||||
setErrorMessage(axiosErr.response?.data?.detail || t('promo.deactivate.error'));
|
||||
// detail may be a plain string (clearActiveDiscount route) or a structured
|
||||
// { code, message } object (deactivate-discount route). Handle both.
|
||||
const axiosErr = error as {
|
||||
response?: { data?: { detail?: string | { message?: string } } };
|
||||
};
|
||||
const detail = axiosErr.response?.data?.detail;
|
||||
const message = typeof detail === 'string' ? detail : detail?.message;
|
||||
setErrorMessage(message || t('promo.deactivate.error'));
|
||||
|
||||
setTimeout(() => setErrorMessage(null), 5000);
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user