fix(auth,checkout): add Axios 401/403 auto-logout response interceptor and fix charity round-up 10k exact math
This commit is contained in:
parent
72badb1a7b
commit
bdf8856883
@ -262,14 +262,71 @@
|
|||||||
{ "index": 1, "name": "update_user_store_guest_reset", "description": "Reset profile to empty guest state in userStore on logout/unauthenticated", "status": "done" },
|
{ "index": 1, "name": "update_user_store_guest_reset", "description": "Reset profile to empty guest state in userStore on logout/unauthenticated", "status": "done" },
|
||||||
{ "index": 2, "name": "sync_client_layout_auth", "description": "Sync ClientLayout mount check with localStorage token state", "status": "done" }
|
{ "index": 2, "name": "sync_client_layout_auth", "description": "Sync ClientLayout mount check with localStorage token state", "status": "done" }
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "EPIC-08-TASK-01",
|
||||||
|
"title": "Axios 401/403 Global Automatic Token Expiry Interceptor",
|
||||||
|
"description": "Add response interceptor in api.ts to capture HTTP 401/403 status codes, clear localStorage tokens, and invoke userStore logout to wipe stale profile state globally.",
|
||||||
|
"architectural_layer": "network_communication",
|
||||||
|
"assigned_role": "06_dev_frontend",
|
||||||
|
"priority": "HIGH",
|
||||||
|
"status": "completed",
|
||||||
|
"max_files_allowed": 3,
|
||||||
|
"estimated_minutes": 20,
|
||||||
|
"dependency_task_ids": ["EPIC-07-TASK-02"],
|
||||||
|
"acceptance_criteria": [
|
||||||
|
"افزودن اینترسپتور پاسخ Axios برای تشخیص ۴۰۱ و ۴۰۳",
|
||||||
|
"پاکسازی انی و خودکار توکن و ریست پروفایل به حالت مهمان در صورت انقضای جلسه"
|
||||||
|
],
|
||||||
|
"sub_steps": [
|
||||||
|
{ "index": 1, "name": "add_axios_401_interceptor", "description": "Add 401/403 response interceptor to api.ts", "status": "done" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "EPIC-08-TASK-02",
|
||||||
|
"title": "Charity Round-Up Exact Math Calculation Fix",
|
||||||
|
"description": "Fix charity round-up formula in CheckoutPage.tsx and cartStore.ts so total invoice amount is ALWAYS rounded up to the exact next 10,000 Toman multiple.",
|
||||||
|
"architectural_layer": "presentation_ui",
|
||||||
|
"assigned_role": "06_dev_frontend",
|
||||||
|
"priority": "HIGH",
|
||||||
|
"status": "completed",
|
||||||
|
"max_files_allowed": 3,
|
||||||
|
"estimated_minutes": 20,
|
||||||
|
"dependency_task_ids": ["EPIC-08-TASK-01"],
|
||||||
|
"acceptance_criteria": [
|
||||||
|
"رند کردن دقیق و ریاضیات کامل مبلغ سفارش به اولین ۱۰,۰۰۰ تومان بعدی",
|
||||||
|
"تطابق ۱۰۰٪ مبلغ اهدایی محاسبهشده با کل فاکتور بدون ناهماهنگی ریاضی"
|
||||||
|
],
|
||||||
|
"sub_steps": [
|
||||||
|
{ "index": 1, "name": "fix_checkout_charity_formula", "description": "Fix round-up calculation in CheckoutPage.tsx and cartStore.ts", "status": "done" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "EPIC-08-TASK-03",
|
||||||
|
"title": "Backend OrdersService Hardening & Error Inspection",
|
||||||
|
"description": "Audit OrdersService for edge case exceptions, invalid items handling, and ensure zero unhandled exceptions during order creation.",
|
||||||
|
"architectural_layer": "business_logic",
|
||||||
|
"assigned_role": "05_dev_backend",
|
||||||
|
"priority": "HIGH",
|
||||||
|
"status": "completed",
|
||||||
|
"max_files_allowed": 3,
|
||||||
|
"estimated_minutes": 20,
|
||||||
|
"dependency_task_ids": ["EPIC-08-TASK-02"],
|
||||||
|
"acceptance_criteria": [
|
||||||
|
"بررسی کامل سرویس سفارشات بکاند و رفع خطاهای بالقوه در ثبت فاکتور و تخفیفها",
|
||||||
|
"اجرای موفق بیلد تولیدی بکاند"
|
||||||
|
],
|
||||||
|
"sub_steps": [
|
||||||
|
{ "index": 1, "name": "audit_orders_service", "description": "Audit and fix edge case handling in orders.service.ts", "status": "done" }
|
||||||
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"total": 13,
|
"total": 16,
|
||||||
"completed": 13,
|
"completed": 16,
|
||||||
"in_progress": 0,
|
"in_progress": 0,
|
||||||
"pending": 0,
|
"pending": 0,
|
||||||
"generated_at": "2026-07-26T20:25:00Z",
|
"generated_at": "2026-07-26T20:30:00Z",
|
||||||
"decomposition_pass": 5
|
"decomposition_pass": 6
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -61,12 +61,12 @@ export default function CheckoutPage() {
|
|||||||
}, [profile, isLoggedIn]);
|
}, [profile, isLoggedIn]);
|
||||||
|
|
||||||
const subtotal = getSubtotal();
|
const subtotal = getSubtotal();
|
||||||
const roundedAmount = Math.ceil(subtotal / 10000) * 10000;
|
const remainder = subtotal % 10000;
|
||||||
const roundUpDiff = roundedAmount - subtotal;
|
const roundUpDiff = remainder === 0 ? 10000 : 10000 - remainder;
|
||||||
|
|
||||||
const handleCharityToggle = () => {
|
const handleCharityToggle = () => {
|
||||||
if (!useRoundUp) {
|
if (!useRoundUp) {
|
||||||
setCharityDonation(Math.max(roundUpDiff, Math.round(subtotal * 0.01)));
|
setCharityDonation(roundUpDiff);
|
||||||
setUseRoundUp(true);
|
setUseRoundUp(true);
|
||||||
} else {
|
} else {
|
||||||
setCharityDonation(0);
|
setCharityDonation(0);
|
||||||
|
|||||||
@ -10,7 +10,7 @@ const api = axios.create({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// Interceptor to add auth token in the future
|
// Interceptor to add auth token in request headers
|
||||||
api.interceptors.request.use(
|
api.interceptors.request.use(
|
||||||
(config) => {
|
(config) => {
|
||||||
let token = null;
|
let token = null;
|
||||||
@ -25,4 +25,25 @@ api.interceptors.request.use(
|
|||||||
(error) => Promise.reject(error)
|
(error) => Promise.reject(error)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Interceptor to handle 401/403 token expiration globally
|
||||||
|
api.interceptors.response.use(
|
||||||
|
(response) => response,
|
||||||
|
(error) => {
|
||||||
|
if (error.response && (error.response.status === 401 || error.response.status === 403)) {
|
||||||
|
if (typeof window !== 'undefined') {
|
||||||
|
localStorage.removeItem('accessToken');
|
||||||
|
localStorage.removeItem('refreshToken');
|
||||||
|
try {
|
||||||
|
// Dynamic import to avoid circular dependency
|
||||||
|
const { useUserStore } = require('../store/userStore');
|
||||||
|
useUserStore.getState().logout();
|
||||||
|
} catch {
|
||||||
|
// Ignore if store not initialized
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Promise.reject(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
export default api;
|
export default api;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user