From ec4fe282895b7666b93d0cf8404c6eb7e7688768 Mon Sep 17 00:00:00 2001 From: hamid zarghami Date: Sat, 11 Oct 2025 14:40:24 +0330 Subject: [PATCH] wholesale request --- .env | 4 +- src/config/Pages.ts | 1 + src/pages/seller/WholeSaleRequest.tsx | 94 +++++++++++++++ .../components/WholesaleRequestTableRow.tsx | 111 ++++++++++++++++++ src/pages/seller/hooks/useSellerData.ts | 13 ++ src/pages/seller/service/SellerService.ts | 19 ++- src/pages/seller/types/Types.ts | 37 ++++++ src/router/Main.tsx | 3 +- 8 files changed, 278 insertions(+), 4 deletions(-) create mode 100644 src/pages/seller/WholeSaleRequest.tsx create mode 100644 src/pages/seller/components/WholesaleRequestTableRow.tsx diff --git a/.env b/.env index 9111a01..eaf93d1 100644 --- a/.env +++ b/.env @@ -1,4 +1,4 @@ -VITE_BASE_URL = 'https://shop-api.dev.danakcorp.com' -# VITE_BASE_URL = 'http://192.168.1.122:4000' +# VITE_BASE_URL = 'https://shop-api.dev.danakcorp.com' +VITE_BASE_URL = 'https://api.shinan.ir' VITE_TOKEN_NAME = 'sh_admin_token' VITE_REFRESH_TOKEN_NAME = 'sh_admin_refresh_token' \ No newline at end of file diff --git a/src/config/Pages.ts b/src/config/Pages.ts index 675b7da..4140c82 100644 --- a/src/config/Pages.ts +++ b/src/config/Pages.ts @@ -196,5 +196,6 @@ export const Pages = { }, sellers: { list: "/sellers/list", + wholesaleRequests: "/sellers/wholesale-requests", }, }; diff --git a/src/pages/seller/WholeSaleRequest.tsx b/src/pages/seller/WholeSaleRequest.tsx new file mode 100644 index 0000000..7195879 --- /dev/null +++ b/src/pages/seller/WholeSaleRequest.tsx @@ -0,0 +1,94 @@ +import { type FC, useState } from 'react' +import { useApproveWholesaleRequest, useGetWholesaleRequests } from './hooks/useSellerData' +import { type WholesaleRequest } from './types/Types' +import { type PagerType } from '../products/types/Types' +import PageLoading from '../../components/PageLoading' +import Error from '../../components/Error' +import PaginationUi from '../../components/PaginationUi' +import Td from '../../components/Td' +import WholesaleRequestTableRow from './components/WholesaleRequestTableRow' +import { toast } from 'react-toastify' +import { extractErrorMessage } from '@/helpers/utils' + +const WholeSaleRequest: FC = () => { + const [currentPage, setCurrentPage] = useState(1); + const { data: wholesaleData, isLoading, error, refetch } = useGetWholesaleRequests(currentPage); + const approveWholesaleRequestMutation = useApproveWholesaleRequest(); + + if (isLoading) { + return ( +
+ +
+ ); + } + + if (error) { + return ( +
+ +
+ ); + } + + const handleApprove = async (id: string) => { + await approveWholesaleRequestMutation.mutateAsync(id, { + onSuccess: () => { + refetch(); + toast.success('درخواست با موفقیت تایید شد'); + }, + onError: (error) => { + toast.error(extractErrorMessage(error)); + } + }); + }; + + const requests = wholesaleData?.results?.requests || []; + const pager = wholesaleData?.results?.pager; + + return ( +
+
+ + + + + + + {requests.length === 0 ? ( + + + + ) : ( + requests.map((request: WholesaleRequest) => ( + + )) + )} + +
+ + + + + + +
+ هیچ درخواست عمده‌فروشی یافت نشد +
+
+ + { + setCurrentPage(page); + }} + /> +
+ ) +} + +export default WholeSaleRequest \ No newline at end of file diff --git a/src/pages/seller/components/WholesaleRequestTableRow.tsx b/src/pages/seller/components/WholesaleRequestTableRow.tsx new file mode 100644 index 0000000..4952fa5 --- /dev/null +++ b/src/pages/seller/components/WholesaleRequestTableRow.tsx @@ -0,0 +1,111 @@ +import { type FC, useState } from 'react' +import { type WholesaleRequest } from '../types/Types' +import StatusWithText from '../../../components/StatusWithText' +import Td from '../../../components/Td' +import Button from '../../../components/Button' +import ModalConfrim from '../../../components/ModalConfrim' +import { Calendar, Call, Card, User as UserIcon, Shop, TickCircle } from 'iconsax-react' + +interface Props { + request: WholesaleRequest + onApprove: (id: string) => void +} + +const WholesaleRequestTableRow: FC = ({ request, onApprove }) => { + const [isConfirmOpen, setIsConfirmOpen] = useState(false); + const getStatusVariant = (status: string) => { + switch (status) { + case 'Approved': return 'success'; + case 'Pending': return 'warning'; + default: return 'warning'; + } + }; + + const getStatusText = (status: string) => { + switch (status) { + case 'Approved': return 'تایید شده'; + case 'Pending': return 'در انتظار'; + default: return status; + } + }; + + const formatDate = (dateString: string) => { + if (!dateString) return '-'; + return new Date(dateString).toLocaleDateString('fa-IR'); + }; + + const handleApprove = () => { + setIsConfirmOpen(true); + }; + + const confirmApprove = () => { + onApprove(request._id); + setIsConfirmOpen(false); + }; + + return ( + <> + + +
+ + {request.seller?.fullName || '-'} +
+ + +
+ + {request.shop?.shopName || '-'} +
+ + +
+ + {request.seller?.email || '-'} +
+ + +
+ + {request.seller?.phoneNumber} +
+ + + + + +
+ + {formatDate(request.createdAt)} +
+ + + {request.status === 'Pending' && ( + + )} + + + setIsConfirmOpen(false)} + onConfrim={confirmApprove} + label="آیا از تایید این درخواست عمده‌فروشی اطمینان دارید؟" + /> + + ) +} + +export default WholesaleRequestTableRow diff --git a/src/pages/seller/hooks/useSellerData.ts b/src/pages/seller/hooks/useSellerData.ts index fbe6ae6..7592103 100644 --- a/src/pages/seller/hooks/useSellerData.ts +++ b/src/pages/seller/hooks/useSellerData.ts @@ -19,3 +19,16 @@ export const useApproveContract = () => { mutationFn: api.approveContract, }); }; + +export const useGetWholesaleRequests = (page: number = 1) => { + return useQuery({ + queryKey: ["wholesale-requests", page], + queryFn: () => api.getWholesaleRequests(page), + }); +}; + +export const useApproveWholesaleRequest = () => { + return useMutation({ + mutationFn: api.approveWholesaleRequest, + }); +}; diff --git a/src/pages/seller/service/SellerService.ts b/src/pages/seller/service/SellerService.ts index 0ce4f5d..f432f4e 100644 --- a/src/pages/seller/service/SellerService.ts +++ b/src/pages/seller/service/SellerService.ts @@ -1,5 +1,8 @@ import axios from "@/config/axios"; -import type { SellersResponse } from "../types/Types"; +import type { + SellersResponse, + WholesaleRequestsResponse, +} from "../types/Types"; export const getSellers = async ( page: number = 1 @@ -21,3 +24,17 @@ export const approveContract = async (sellerId: string) => { ); return data; }; + +export const getWholesaleRequests = async ( + page: number = 1 +): Promise => { + const { data } = await axios.get( + `/admin/sellers/wholesale-requests?page=${page}` + ); + return data; +}; + +export const approveWholesaleRequest = async (id: string) => { + const { data } = await axios.patch(`/admin/sellers/wholesale-requests/${id}`); + return data; +}; diff --git a/src/pages/seller/types/Types.ts b/src/pages/seller/types/Types.ts index eccf35e..67cc299 100644 --- a/src/pages/seller/types/Types.ts +++ b/src/pages/seller/types/Types.ts @@ -85,3 +85,40 @@ export interface SellersResponse { pager: Pager; }; } + +export interface WholesaleRequest { + _id: string; + seller: { + _id: string; + fullName: string; + dateOfBirth: string; + phoneNumber: string; + accountStatus: "Pending" | "Approved"; + isRegisterCompleted: boolean; + businessType: string; + isWholesaler: boolean; + createdAt: string; + updatedAt: string; + email: string; + }; + shop: Shop; + status: "Pending" | "Approved"; + createdAt: string; + updatedAt: string; +} + +export interface WholesaleRequestsResponse { + status: number; + success: boolean; + results: { + requests: WholesaleRequest[]; + pager: { + page: number; + limit: number; + totalItems: number; + totalPages: number; + prevPage: boolean; + nextPage: boolean; + }; + }; +} diff --git a/src/router/Main.tsx b/src/router/Main.tsx index 4d5f3b3..b2eea0d 100644 --- a/src/router/Main.tsx +++ b/src/router/Main.tsx @@ -63,7 +63,7 @@ import Resumes from '@/pages/jobs/Resume' import ContactUsList from '@/pages/contactUs/List' import Dashboard from '@/pages/dashboard/Dashboard' import SellerList from '@/pages/seller/List' - +import WholeSaleRequest from '@/pages/seller/WholeSaleRequest' const MainRouter: FC = () => { const { hasSubMenu } = useSharedStore() @@ -160,6 +160,7 @@ const MainRouter: FC = () => { } /> } /> + } />