diff --git a/src/features/cart/ui/OrderPage.tsx b/src/features/cart/ui/OrderPage.tsx index b8b8a9e..5d5df38 100644 --- a/src/features/cart/ui/OrderPage.tsx +++ b/src/features/cart/ui/OrderPage.tsx @@ -64,6 +64,15 @@ interface CoordsData { polygon: [number, number][][]; } +type DRFError = { + [key: string]: Array< + | string + | { + [key: string]: string[]; + } + >; +}; + // Yetkazib berish vaqt oraliqlar const deliveryTimeSlots = [ { id: 1, label: '10:00 - 12:00', start: '10:00', end: '12:00' }, @@ -119,14 +128,38 @@ const OrderPage = () => { }); } }, - onError: (error: AxiosError) => { - const errors = (error.response?.data as { data: { message: string } }) - .data.message; - const errorsDetail = ( - error.response?.data as { data: { detail: string } } - ).data.detail; + onError: (error: AxiosError) => { + const data = error.response?.data; - toast.error(errors || errorsDetail || t('Xatolik yuz berdi'), { + let message = t('Xatolik yuz berdi'); + + if (data) { + // 🔥 DRF validation error parsing + if (typeof data === 'object') { + const firstKey = Object.keys(data)[0]; // "order" + const firstValue = data[firstKey]; + + if (Array.isArray(firstValue)) { + const firstErrorObj = firstValue[0]; // { note: [...] } + + if (typeof firstErrorObj === 'object') { + const innerKey = Object.keys(firstErrorObj)[0]; // "note" + const innerValue = firstErrorObj[innerKey]; + + if (Array.isArray(innerValue)) { + message = innerValue[0]; // "This field may not be blank." + } + } + } + } + } + + // fallback + if (!error.response) { + message = error.message; + } + + toast.error(message, { richColors: true, position: 'top-center', }); diff --git a/src/features/profile/ui/RefreshOrder.tsx b/src/features/profile/ui/RefreshOrder.tsx index 218de41..7e76b92 100644 --- a/src/features/profile/ui/RefreshOrder.tsx +++ b/src/features/profile/ui/RefreshOrder.tsx @@ -36,6 +36,7 @@ import { ZoomControl, } from '@pbe/react-yandex-maps'; import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; +import { AxiosError } from 'axios'; import { Calendar as CalIcon, CheckCircle2, @@ -72,6 +73,15 @@ interface CoordsData { polygon: [number, number][][]; } +type DRFError = { + [key: string]: Array< + | string + | { + [key: string]: string[]; + } + >; +}; + const RefreshOrder = () => { const [deliveryDate, setDeliveryDate] = useState(); const [selectedTimeSlot, setSelectedTimeSlot] = useState(''); @@ -126,13 +136,57 @@ const RefreshOrder = () => { const { mutate, isPending } = useMutation({ mutationFn: (body: OrderCreateBody) => cart_api.createOrder(body), - onSuccess: () => { - setOrderSuccess(true); - queryClient.refetchQueries({ queryKey: ['cart_items'] }); - queryClient.refetchQueries({ queryKey: ['order_list'] }); + onSuccess: (res) => { + const message = JSON.parse(res.data.response); + + if (message.successes && message.successes.length > 0) { + setOrderSuccess(true); + queryClient.refetchQueries({ queryKey: ['cart_items'] }); + queryClient.refetchQueries({ queryKey: ['order_list'] }); + } else if (message.errors && message.errors.length > 0) { + toast.error(t('Xatolik yuz berdi') + message.errors[0].message, { + richColors: true, + position: 'top-center', + }); + } else { + toast.error(t('Xatolik yuz berdi'), { + richColors: true, + position: 'top-center', + }); + } }, - onError: () => { - toast.error(t('Xatolik yuz berdi'), { + onError: (error: AxiosError) => { + const data = error.response?.data; + + let message = t('Xatolik yuz berdi'); + + if (data) { + // 🔥 DRF validation error parsing + if (typeof data === 'object') { + const firstKey = Object.keys(data)[0]; // "order" + const firstValue = data[firstKey]; + + if (Array.isArray(firstValue)) { + const firstErrorObj = firstValue[0]; // { note: [...] } + + if (typeof firstErrorObj === 'object') { + const innerKey = Object.keys(firstErrorObj)[0]; // "note" + const innerValue = firstErrorObj[innerKey]; + + if (Array.isArray(innerValue)) { + message = innerValue[0]; // "This field may not be blank." + } + } + } + } + } + + // fallback + if (!error.response) { + message = error.message; + } + + toast.error(message, { richColors: true, position: 'top-center', }); diff --git a/src/shared/config/api/httpClient.ts b/src/shared/config/api/httpClient.ts index ce8acc2..04ac169 100644 --- a/src/shared/config/api/httpClient.ts +++ b/src/shared/config/api/httpClient.ts @@ -45,10 +45,6 @@ httpClient.interceptors.response.use( if ((error as AxiosError)?.status === 403) { try { const refToken = getRefToken(); - if (!refToken) { - removeToken(); - removeRefToken(); - } const { data } = await axios.post( `${BASE_URL}api/v1/accounts/refresh/token/`, { refresh: refToken }, @@ -62,10 +58,6 @@ httpClient.interceptors.response.use( } else if ((error as AxiosError)?.status === 401) { try { const refToken = getRefToken(); - if (!refToken) { - removeToken(); - removeRefToken(); - } const { data } = await axios.post( `${BASE_URL}api/v1/accounts/refresh/token/`, { refresh: refToken },