diff --git a/src/api/order.ts b/src/api/order.ts index ab4dddc..a18da40 100644 --- a/src/api/order.ts +++ b/src/api/order.ts @@ -1,15 +1,44 @@ import { client } from './client'; -/** - * 인자가 필요하다면 인자를 받고 api를 return 하세요 - * index.ts 에서 모든 API를 return 하고있으니 - * 여기서는 API 하나만 return 하면 됩니다. - * - * { productsApi, bannersApi, categoryApi, promotionApi, userApi, cartApi, orderApi } - * 본인 API 위치에서 productsApi.예시(인자) 이런식으로 사용하세요 - * @param id - * @returns - */ -export const 예시 = async (id: number) => { - return client.get(`/API 주소 적으세요/${id}`); +// export const getOrderSearch = async (params?: any) => { +// return client +// .get(`order/search`, { params: params }) +// .then((response) => response) +// .catch((error) => { +// console.log(error); +// }); +// }; +export const getOrderSearch = async (params?: any) => { + return client + .get(`order/search`, { params: params }) + .then((response) => response) + .catch((error) => { + console.log(error); + }); +}; +export const getOrderStatistics = async () => { + return client + .get(`order/statistics`) + .then((response) => response) + .catch((error) => { + console.log(error); + }); +}; +export const postOrderPurchase = async ( + order_id: number, + purchase_number: number, + purchase_date: string, + status: string +) => { + const params: any = {}; + if (order_id !== undefined) params.order_id = order_id; + if (purchase_number !== undefined) params.purchase_number = purchase_number; + if (purchase_date !== undefined) params.purchase_date = purchase_date; + if (status !== undefined) params.status = status; + return client + .post(`order/purchase`) + .then((response) => response, params) + .catch((error) => { + console.log(error); + }); }; diff --git a/src/pages/admin/components/Category.tsx b/src/pages/admin/components/Category.tsx index 6c2cfac..3e2f1c3 100644 --- a/src/pages/admin/components/Category.tsx +++ b/src/pages/admin/components/Category.tsx @@ -147,6 +147,7 @@ export const Category = ({ onClose }: { onClose: () => void }) => { const onSubmit = (data: any) => { postCategoryMutation.mutate({ parent_id, name: data.addCategoryName }); }; + //같은카테고리 요청할때 셍긱하기, 키를 동적으로 받기| 대분류 중분류 소분류 api 같은걸로 할 수 있기 return (
diff --git a/src/pages/admin/components/Pagination.tsx b/src/pages/admin/components/Pagination.tsx index c51c266..6547896 100644 --- a/src/pages/admin/components/Pagination.tsx +++ b/src/pages/admin/components/Pagination.tsx @@ -1,17 +1,20 @@ import { useEffect } from 'react'; import { PaginationProps } from './type'; +import { useSearchParams } from 'react-router-dom'; const Pagination = ({ total = 200, page, setPage }: PaginationProps) => { - const limit = Number(localStorage.getItem('pageListLimit') || '100'); //page_size - + const [searchParams, setSearchParams] = useSearchParams(); + const limit = Number(localStorage.getItem('pageListLimit') || '10'); const numPages = Math.ceil(total / limit); - const showedLecture = new Array(numPages).fill(0); - //린트가 알려주는 방법도 있음 - useEffect(() => {}, [total]); + useEffect(() => { + const currentParams = new URLSearchParams(searchParams); + currentParams.set('page', String(page)); + setSearchParams(currentParams); + }, [page]); return (
- {showedLecture.map((_, index) => ( @@ -19,12 +22,12 @@ const Pagination = ({ total = 200, page, setPage }: PaginationProps) => { type='button' key={index + 1} onClick={() => setPage(index + 1)} - className={index + 1 === page ? 'font-semibold text-black' : 'font-thin text-neutral-500'} + className={`p-1 ${index + 1 === page ? 'font-semibold text-black' : 'font-thin text-neutral-500'}`} > {index + 1} ))} -
diff --git a/src/pages/admin/components/SectionBox.tsx b/src/pages/admin/components/SectionBox.tsx index a003f3c..60f4291 100644 --- a/src/pages/admin/components/SectionBox.tsx +++ b/src/pages/admin/components/SectionBox.tsx @@ -25,11 +25,9 @@ export const SectionBox = ({ className='mr-4 w-20 rounded-md border border-neutral-200 px-1 py-1 text-sm' onChange={(e) => { const value = e.target.value; - if (setPageLimit) { setPageLimit(Number(value)); localStorage.setItem('pageListLimit', value); - const currentParams = new URLSearchParams(searchParams); currentParams.set('page_size', value); setSearchParams(currentParams); diff --git a/src/pages/admin/product/ProductSearch.tsx b/src/pages/admin/product/ProductSearch.tsx index 3ee6f7f..69b049c 100644 --- a/src/pages/admin/product/ProductSearch.tsx +++ b/src/pages/admin/product/ProductSearch.tsx @@ -37,13 +37,14 @@ const ProductSearch = () => { error, refetch, } = useQuery({ - queryKey: ['productFilter', searchParams.toString(), pageLimit], + queryKey: ['productFilter', searchParams.toString(), pageLimit, page], queryFn: async () => { const response = await adminApi.getAdminProducts(searchParams); if (!response) return null; return response.data; }, }); + useEffect(() => { refetch(); }, [pageLimit, refetch]); diff --git a/src/pages/admin/product/components/ProductList.tsx b/src/pages/admin/product/components/ProductList.tsx index 0cd5b79..24b11a1 100644 --- a/src/pages/admin/product/components/ProductList.tsx +++ b/src/pages/admin/product/components/ProductList.tsx @@ -33,6 +33,7 @@ const ProductList = ({ setQuantitPopupData, setSearchParams, }: ProductListProps) => { + const productList = productListArray?.products; const navigate = useNavigate(); const queryClient = useQueryClient(); const [checkedList, setCheckedList] = useState([]); @@ -74,7 +75,7 @@ const ProductList = ({ return (
- {!productListArray &&
상품이 없습니다.
} + {!productList &&
상품이 없습니다.
} {isPending &&
Loading...
} {error &&
An error has occurred: {error.message}
} - {productListArray && - productListArray.map((item, index) => ( + {productList && + productList.map((item, index) => (
- +
); diff --git a/src/pages/admin/product/type.ts b/src/pages/admin/product/type.ts index 95af75d..e29f0c0 100644 --- a/src/pages/admin/product/type.ts +++ b/src/pages/admin/product/type.ts @@ -32,7 +32,7 @@ export interface ProductListType { } export interface ProductListProps { - productListArray: ProductListType[]; + productListArray: { products: ProductListType[]; total_count: number }; isPending: boolean; error: any; pageLimit: number; @@ -47,6 +47,7 @@ export interface ProductFilterProps { pageLimit: number; setSearchParams: (params: any) => void; onSubmit: () => void; + searchParams?: URLSearchParams; } export interface ProductFilterFormData { diff --git a/src/pages/admin/sale/ordering/SaleOrdering.tsx b/src/pages/admin/sale/ordering/SaleOrdering.tsx index c500080..cf1be00 100644 --- a/src/pages/admin/sale/ordering/SaleOrdering.tsx +++ b/src/pages/admin/sale/ordering/SaleOrdering.tsx @@ -3,14 +3,12 @@ import ProductStatusDashboard from '../../components/ProductStatusDashboard'; import OrderingList from './components/OrderList'; import OrderStatePopup from './components/OrderStatePopup'; import { OrderingListType } from './type'; - -const productStatusArray = [ - { title: '발주 전', count: 0 }, - { title: '발주 후', count: 0 }, -]; +import { useQuery } from '@tanstack/react-query'; +import { orderApi } from '@/api'; const SaleOrdering = () => { const [checkedList, setCheckedList] = useState([]); + const [isOpen, setIsOpen] = useState(false); useEffect(() => { if (isOpen) { @@ -22,6 +20,19 @@ const SaleOrdering = () => { document.body.style.overflow = 'auto'; }; }, [isOpen]); + const { data: orderStatisticsData } = useQuery({ + queryKey: ['orderStatisiecs'], + queryFn: async () => { + const response = await orderApi.getOrderStatistics(); + if (!response) return null; + return response.data; + }, + staleTime: 1000 * 60, + }); + const productStatusArray = [ + { title: '신규주문(발주확인 처리 전)', count: orderStatisticsData?.pending_orders }, + { title: '신규주문(발주확인 처리 후)', count: orderStatisticsData?.shipping_orders }, + ]; return ( <> diff --git a/src/pages/admin/sale/ordering/components/OrderList.tsx b/src/pages/admin/sale/ordering/components/OrderList.tsx index 6405ced..0f7505a 100644 --- a/src/pages/admin/sale/ordering/components/OrderList.tsx +++ b/src/pages/admin/sale/ordering/components/OrderList.tsx @@ -1,6 +1,11 @@ import { SectionBox } from '@/pages/admin/components/SectionBox'; import ListHeader from '@/pages/admin/components/ListHeader'; import { OrderingListType } from '../type'; +import { useQuery } from '@tanstack/react-query'; +import { useEffect, useState } from 'react'; +import { orderApi } from '@/api'; +import Pagination from '@/pages/admin/components/Pagination'; +import { useSearchParams } from 'react-router-dom'; const ListHeaderArray = [ { className: 'w-1/12', title: '체크박스' }, @@ -10,32 +15,6 @@ const ListHeaderArray = [ { className: 'basis-full', title: '택배사' }, { className: 'basis-full', title: '송장번호' }, ]; -const productListArray: OrderingListType[] = [ - { - id: 1, - orderNumber: '주문번호1', - productOrderNumber: '상품주문번호1', - orderDate: '발주상태1', - orderStatus: '택배사1', - depositDueDate: '송장번호1', - }, - { - id: 2, - orderNumber: '주문번호2', - productOrderNumber: '상품주문번호2', - orderDate: '발주상태2', - orderStatus: '택배사2', - depositDueDate: '송장번호2', - }, - { - id: 3, - orderNumber: '주문번호1', - productOrderNumber: '상품주문번호3', - orderDate: '발주상태1', - orderStatus: '택배사1', - depositDueDate: '송장번호1', - }, -]; const OrderingList = ({ handleShowPopup, checkedList, @@ -45,64 +24,108 @@ const OrderingList = ({ checkedList: OrderingListType[]; setCheckedList: React.Dispatch>; }) => { + const [page, setPage] = useState(1); + const [pageLimit, setPageLimit] = useState(10); + const [searchParams] = useSearchParams(); + + const { data: orderSearchData, refetch } = useQuery({ + queryKey: ['orderSearch', pageLimit, searchParams.toString()], + queryFn: async () => { + const response = await orderApi.getOrderSearch(searchParams); + if (!response) return null; + return response.data; + }, + }); + useEffect(() => { + refetch(); + }, [pageLimit, refetch]); + const formatDate = (isoString: string) => { + const date = new Date(isoString); + const year = date.getFullYear(); + const month = String(date.getMonth() + 1).padStart(2, '0'); + const day = String(date.getDate()).padStart(2, '0'); + const hours = String(date.getHours()).padStart(2, '0'); + const minutes = String(date.getMinutes()).padStart(2, '0'); + const seconds = String(date.getSeconds()).padStart(2, '0'); + + return `${year}:${month}:${day} ${hours}:${minutes}:${seconds}`; + }; + const orderSearchOrders = orderSearchData?.orders ? orderSearchData?.orders : undefined; + useEffect(() => console.log(checkedList)); return ( - +
- {productListArray.map((item, index) => ( -
-
- checkedItem.id === item.id)} - onChange={() => { - if (checkedList.some((checkedItem) => checkedItem.id === item.id)) { - setCheckedList(checkedList.filter((checkedItem) => checkedItem.id !== item.id)); - } else { - setCheckedList([...checkedList, item]); - } - }} - disabled={false} - /> -
+ {orderSearchOrders && + orderSearchOrders.map((order: any) => { + if (orderSearchOrders.length === 0 || orderSearchOrders == undefined) return

주문이 없습니다.

; + if (order.products.length === 0) return console.log('주문상태에 상품이 포함되어있지 않음'); + order.products.map((order: any) => { + return ( +
+
+ checkedItem.id === order.id)} + onChange={() => { + if (checkedList.some((checkedItem) => checkedItem.id === order.id)) { + setCheckedList(checkedList.filter((checkedItem) => checkedItem.id !== order.id)); + } else { + setCheckedList([...checkedList, order]); + } + }} + disabled={false} + /> +
-
{item.orderNumber}
-
{item.productOrderNumber}
-
{item.orderDate}
-
{item.orderStatus}
-
{item.depositDueDate}
-
- ))} +
{order.order_number}
+
{order.products.id}
+
{formatDate(order.created_at)}
+
{order.shipping.courier}
+
{order.shipping.tracking_number}
+
+ ); + }); + })}
+
); diff --git a/src/pages/admin/sale/ordering/components/OrderStatePopup.tsx b/src/pages/admin/sale/ordering/components/OrderStatePopup.tsx index 84467ef..d526cc4 100644 --- a/src/pages/admin/sale/ordering/components/OrderStatePopup.tsx +++ b/src/pages/admin/sale/ordering/components/OrderStatePopup.tsx @@ -3,16 +3,15 @@ import { OrderingListType } from '../type'; import { useForm, FormProvider } from 'react-hook-form'; const OrderStatePopup = ({ onClose, checkedList }: { onClose: () => void; checkedList: OrderingListType[] }) => { - const orderNumber = [...new Set(checkedList.map((item) => item.orderNumber))]; + const orderNumber = [...new Set(checkedList.map((item) => item.order_number))]; const methods = useForm(); const { handleSubmit } = methods; const handlerSubmit = (data: any) => console.log(data); return ( - -
-
-
+
+ +

주문번호 : {orderNumber.join(', ')}

{orderNumber.length > 1 ?

주문번호가 2건 이상입니다. 확인해주세요.

: ''}
@@ -32,7 +31,7 @@ const OrderStatePopup = ({ onClose, checkedList }: { onClose: () => void; checke {checkedList.map((item) => ( - {item.orderNumber} + {item.order_number} {item.productOrderNumber} {item.orderDate} @@ -56,9 +55,10 @@ const OrderStatePopup = ({ onClose, checkedList }: { onClose: () => void; checke 등록
-
- - + +
+ +
); }; diff --git a/src/pages/admin/sale/ordering/type.ts b/src/pages/admin/sale/ordering/type.ts index 0ce8bf8..3eefd7e 100644 --- a/src/pages/admin/sale/ordering/type.ts +++ b/src/pages/admin/sale/ordering/type.ts @@ -1,6 +1,6 @@ export type OrderingListType = { id: number; - orderNumber: string; + order_number: string; productOrderNumber: string; orderDate: string; orderStatus: string; diff --git a/src/pages/admin/sale/search/SaleSearch.tsx b/src/pages/admin/sale/search/SaleSearch.tsx index 86d68a3..1f03ad7 100644 --- a/src/pages/admin/sale/search/SaleSearch.tsx +++ b/src/pages/admin/sale/search/SaleSearch.tsx @@ -1,10 +1,46 @@ +import { useQuery } from '@tanstack/react-query'; import SaleFilter from './components/SaleFilter'; import SaleList from './components/SaleList'; +import { orderApi } from '@/api'; +import { useEffect, useState } from 'react'; +import { useSearchParams } from 'react-router-dom'; export const SaleSearch = () => { + const [page, setPage] = useState(1); + const [pageLimit, setPageLimit] = useState(10); + const [searchParams, setSearchParams] = useSearchParams(); + + const { + data: orderSearchData, + isPending, + error, + refetch, + } = useQuery({ + queryKey: ['orderSearch', searchParams.toString(), pageLimit], + queryFn: async () => { + const response = await orderApi.getOrderSearch(searchParams); + if (!response) return null; + return response.data; + }, + }); + console.log('orderSearchData', orderSearchData); + + useEffect(() => { + refetch(); + }, [pageLimit, refetch]); return ( <> - - + refetch()} pageLimit={pageLimit} /> + ); }; diff --git a/src/pages/admin/sale/search/components/SaleFilter.tsx b/src/pages/admin/sale/search/components/SaleFilter.tsx index 03dc588..925dd68 100644 --- a/src/pages/admin/sale/search/components/SaleFilter.tsx +++ b/src/pages/admin/sale/search/components/SaleFilter.tsx @@ -3,12 +3,29 @@ import { useForm, FormProvider } from 'react-hook-form'; import arrowDropDown from '@/assets/icons/arrowDropDown.svg'; import arrowDropUp from '@/assets/icons/arrowDropUp.svg'; import DatePickInputs from '@/pages/admin/components/DatePickInputs'; +import { ProductFilterProps } from '@/pages/admin/product/type'; -const SaleFilter = () => { +const SaleFilter = ({ setSearchParams, onSubmit, pageLimit }: ProductFilterProps) => { + const searchParamsData = new URLSearchParams(); const methods = useForm(); const { handleSubmit, register, reset } = methods; + const handlerSubmit = (data: any) => { + console.log(searchParamsData); + switch (data.searchType) { + case 'orderNumber': + searchParamsData.append('order_number', data.searchKeyword); + break; + } + if (data.startDate) searchParamsData.append('start_date', data.startDate); + if (data.endDate) searchParamsData.append('end_date', data.endDate); - const handlerSubmit = (data: any) => console.log(data); + searchParamsData.append('page', '1'); + searchParamsData.append('page_size', String(pageLimit)); + searchParamsData.append('sort', 'created_at'); + setSearchParams(searchParamsData); + onSubmit(); + console.log(data); + }; const [isOpen, setIsOpen] = useState(false); return ( @@ -30,14 +47,9 @@ const SaleFilter = () => { defaultValue='all' > - - - - - { + +const SaleList = ({ orderSearchData, page, setPage, pageLimit, setPageLimit, setSearchParams }: any) => { + const formatDate = (isoString: string) => { + const date = new Date(isoString); + const year = date.getFullYear(); + const month = String(date.getMonth() + 1).padStart(2, '0'); + const day = String(date.getDate()).padStart(2, '0'); + const hours = String(date.getHours()).padStart(2, '0'); + const minutes = String(date.getMinutes()).padStart(2, '0'); + const seconds = String(date.getSeconds()).padStart(2, '0'); + + return `${year}:${month}:${day} ${hours}:${minutes}:${seconds}`; + }; + const orderSearchOrders = orderSearchData?.orders ? orderSearchData?.orders : undefined; + console.log(orderSearchOrders); return ( - +
- {saleListArray.map((item, index) => ( -
-
{item.orderNumber}
-
{item.productOrderNumber}
-
{item.orderDate}
-
{item.orderStatus}
-
{item.deliveryAttributes}
-
{item.claimStatus}
-
{item.productNumber}
-
{item.productName}
-
{item.optionInfo}
-
- ))} + {orderSearchOrders && + orderSearchOrders.map((order: any) => { + if (orderSearchOrders.length === 0 || orderSearchOrders == undefined) return

주문이 없습니다.

; + if (order.products.length === 0) return console.log('주문상태에 상품이 포함되어있지 않음'); + order.products.map((item: any) => { + return ( +
+
{order.order_number}
+
{item.id}
+
{formatDate(order.created_at)}
+
{order.order_status}
+
{item.shipping_status}
+
{order.claimStatus ? order.claimStatus : '-'}
+
{order.productNumber}
+
{item.product_name}
+
+ {item.option.size}, {item.option.color} +
+
+ ); + }); + })}
+
);