diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..0d15d33 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,9 @@ +{ + "useTabs": false, + "printWidth": 80, + "tabWidth": 2, + "singleQuote": true, + "trailingComma": "all", + "endOfLine": "lf", + "arrowParens": "always" +} diff --git a/package-lock.json b/package-lock.json index 037ab52..4f36314 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,9 @@ "@pic-pik/react": "^0.1.3", "@tanstack/react-query": "^5.51.24", "@tanstack/react-query-devtools": "^5.51.24", + "@tanstack/react-table": "^8.20.5", "axios": "^1.7.4", + "date-fns": "^4.0.0", "jotai": "^2.9.3", "lodash": "^4.17.21", "msw": "^2.3.5", @@ -5210,6 +5212,39 @@ "react": "^18 || ^19" } }, + "node_modules/@tanstack/react-table": { + "version": "8.20.5", + "resolved": "https://registry.npmjs.org/@tanstack/react-table/-/react-table-8.20.5.tgz", + "integrity": "sha512-WEHopKw3znbUZ61s9i0+i9g8drmDo6asTWbrQh8Us63DAk/M0FkmIqERew6P71HI75ksZ2Pxyuf4vvKh9rAkiA==", + "license": "MIT", + "dependencies": { + "@tanstack/table-core": "8.20.5" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, + "node_modules/@tanstack/table-core": { + "version": "8.20.5", + "resolved": "https://registry.npmjs.org/@tanstack/table-core/-/table-core-8.20.5.tgz", + "integrity": "sha512-P9dF7XbibHph2PFRz8gfBKEXEY/HJPOhym8CHmjF8y3q5mWpKx9xtZapXQUWCgkqvsK0R46Azuz+VaxD4Xl+Tg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, "node_modules/@testing-library/dom": { "version": "10.4.0", "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz", @@ -7486,6 +7521,16 @@ "node": ">=18" } }, + "node_modules/date-fns": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.0.0.tgz", + "integrity": "sha512-6K33+I8fQ5otvHgLIvKK1xmMbLAh0pduyrx7dwMXKiGYeoWhmk6M3Zoak9n7bXHMJQlHq1yqmdGy1QxKddJjUA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, "node_modules/debug": { "version": "4.3.6", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", diff --git a/package.json b/package.json index 7355ef2..7bdaf32 100644 --- a/package.json +++ b/package.json @@ -17,11 +17,13 @@ "dependencies": { "@emotion/react": "^11.13.3", "@emotion/styled": "^11.13.0", - "@pic-pik/react": "^0.1.3", "@hookform/resolvers": "^3.9.0", + "@pic-pik/react": "^0.1.3", "@tanstack/react-query": "^5.51.24", "@tanstack/react-query-devtools": "^5.51.24", + "@tanstack/react-table": "^8.20.5", "axios": "^1.7.4", + "date-fns": "^4.0.0", "jotai": "^2.9.3", "lodash": "^4.17.21", "msw": "^2.3.5", diff --git a/src/App.tsx b/src/App.tsx index fd30142..3f606bf 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,11 +1,19 @@ -import AppRoutes from "routes/AppRoutes"; -import Layout from "common/components/layout"; +import AppRoutes from 'routes/AppRoutes'; +import Layout from 'common/components/layout'; +import ErrorBoundary from 'common/components/errorBoundary'; +import ErrorOrLoaderMsg from 'common/components/loader'; +import { Suspense } from 'react'; //아래 Route외 html Layout 컴포넌트로 변경 예정 function App() { + // 레이아웃 내부에 에러바운더리, 로더 추가 return ( - + }> + }> + + + ); } diff --git a/src/api/modules/stores/index.ts b/src/api/modules/stores/index.ts index 4058ec6..7b62efe 100644 --- a/src/api/modules/stores/index.ts +++ b/src/api/modules/stores/index.ts @@ -1,6 +1,21 @@ import axiosInstance from 'api/core'; -import { type CreateStoreRequest, CreateStoreResponse, GetStoreResponse, StoresParams, GetStoresMenuResponse, GetStoresMenuParams, GetMenuDetailResponse, CreateMenuRequest, CreateMenuResponse, GetOrderResponse, GetOrderDetailResponse, UpdateOrderRequest, GetReviewsResponse, GetReviewsParams } from 'api/modules/stores/types'; +import { + type CreateStoreRequest, + CreateStoreResponse, + GetStoreResponse, + StoresParams, + GetStoresMenuResponse, + GetStoresMenuParams, + GetMenuDetailResponse, + CreateMenuRequest, + CreateMenuResponse, + GetOrderResponse, + GetOrderDetailResponse, + UpdateOrderRequest, + GetReviewsResponse, + GetReviewsParams, +} from 'api/modules/stores/types'; import { type CommonResponseReturnType } from 'api/modules/commonType'; const URL_ROOT = 'stores'; @@ -8,13 +23,18 @@ const URL_ROOT = 'stores'; export const storeAPI = { store: { // 음식점 정보 등록 API - createStore: async (payload: CreateStoreRequest): Promise> => { + createStore: async ( + payload: CreateStoreRequest, + ): Promise> => { const res = await axiosInstance.post(`${URL_ROOT}`, payload); return res.data; }, // 음식점 정보 조회 API - getStore: async (storeId: number, queryParams?: GetStoresMenuParams): Promise => { + getStore: async ( + storeId: number, + queryParams?: GetStoresMenuParams, + ): Promise => { const res = await axiosInstance.get(`${URL_ROOT}/${storeId}`, { params: queryParams, }); @@ -30,7 +50,10 @@ export const storeAPI = { menu: { // 메뉴 정보 조회 API - getStoresMenu: async (storeId: number, queryParams?: StoresParams): Promise => { + getStoresMenu: async ( + storeId: number, + queryParams?: StoresParams, + ): Promise => { const res = await axiosInstance.get(`${URL_ROOT}/${storeId}/menus`, { params: queryParams, }); @@ -38,20 +61,36 @@ export const storeAPI = { }, // 메뉴 정보 상세 조회 API - getStoresMenuDetail: async (storeId: number, menuId: number): Promise => { - const res = await axiosInstance.get(`${URL_ROOT}/${storeId}/menus/${menuId}`); + getStoresMenuDetail: async ( + storeId: number, + menuId: number, + ): Promise => { + const res = await axiosInstance.get( + `${URL_ROOT}/${storeId}/menus/${menuId}`, + ); return res.data; }, // 메뉴 정보 추가 - createStoresMenu: async (storeId: number, payload: CreateMenuRequest): Promise => { - const res = await axiosInstance.post(`${URL_ROOT}/${storeId}/menus`, payload); + createStoresMenu: async ( + storeId: number, + payload: CreateMenuRequest, + ): Promise => { + const res = await axiosInstance.post( + `${URL_ROOT}/${storeId}/menus`, + payload, + ); return res.data; }, // 메뉴 정보 삭제 - deleteStoresMenu: async (storeId: number, menuId: number): Promise => { - const res = await axiosInstance.delete(`${URL_ROOT}/${storeId}/menus/${menuId}`); + deleteStoresMenu: async ( + storeId: number, + menuId: number, + ): Promise => { + const res = await axiosInstance.delete( + `${URL_ROOT}/${storeId}/menus/${menuId}`, + ); return res.data; }, }, @@ -64,21 +103,36 @@ export const storeAPI = { }, // 주문 정보 상세 조회 - getStoresOrderDetail: async (storeId: number, orderId: number): Promise => { - const res = await axiosInstance.get(`${URL_ROOT}/${storeId}/orders/${orderId}`); + getStoresOrderDetail: async ( + storeId: number, + orderId: number, + ): Promise => { + const res = await axiosInstance.get( + `${URL_ROOT}/${storeId}/orders/${orderId}`, + ); return res.data; }, // 주문 정보 수정(취소) API - updateStoresOrder: async (storeId: number, orderId: number, payload: UpdateOrderRequest): Promise => { - const res = await axiosInstance.patch(`${URL_ROOT}/${storeId}/orders/${orderId}`, payload); + updateStoresOrder: async ( + storeId: number, + orderId: number, + payload: UpdateOrderRequest, + ): Promise => { + const res = await axiosInstance.patch( + `${URL_ROOT}/${storeId}/orders/${orderId}`, + payload, + ); return res.data; }, }, review: { // 리뷰 정보 조회 - getStoresReviews: async (storeId: number, queryParams?: GetReviewsParams): Promise => { + getStoresReviews: async ( + storeId: number, + queryParams?: GetReviewsParams, + ): Promise => { const res = await axiosInstance.get(`${URL_ROOT}/${storeId}/reviews`, { params: queryParams, }); @@ -86,7 +140,10 @@ export const storeAPI = { }, // 리뷰 정보 삭제 - 관리자만 가능 - deleteStoresReview: async (storeId: number, reviewId: number): Promise => { + deleteStoresReview: async ( + storeId: number, + reviewId: number, + ): Promise => { await axiosInstance.delete(`${URL_ROOT}/${storeId}/reviews/${reviewId}`); }, }, diff --git a/src/api/modules/stores/types.ts b/src/api/modules/stores/types.ts index 5eb400c..87e8acf 100644 --- a/src/api/modules/stores/types.ts +++ b/src/api/modules/stores/types.ts @@ -10,7 +10,7 @@ export type CreateStoreRequest = { closeTime: string; categories: string[]; minimumOrderAmount: number; -} +}; export type CreateStoreResponse = { id: number; @@ -26,7 +26,7 @@ export type CreateStoreResponse = { categories: string[]; minimumOrderAmount: number; createdAt: string; -} +}; export type GetStoreResponse = CreateStoreResponse & { deliveryArea: string; @@ -36,7 +36,7 @@ export type GetStoreResponse = CreateStoreResponse & { export type StoresParams = { page?: number; size?: number; -} +}; export type Menu = { id: number; @@ -45,16 +45,16 @@ export type Menu = { desc: string; price: number; images: Image[]; -} +}; export type Image = { seq: number; imageUrl: string; -} +}; export type GetStoresMenuParams = StoresParams & { - status?: "SOLDOUT" | "DISABLED" | "ENABLED" -} + status?: 'SOLDOUT' | 'DISABLED' | 'ENABLED'; +}; export type GetStoresMenuResponse = { response: { @@ -62,10 +62,10 @@ export type GetStoresMenuResponse = { page: number; totalLength: number; size: number; - } + }; statusCode: number; msg: string; -} +}; export type OptionGroup = { optionGroupId: number; @@ -102,7 +102,7 @@ export type CreateMenuRequest = { price: number; images: Image[]; options: OptionGroup[]; -} +}; export type CreateMenuResponse = { response: { @@ -113,16 +113,16 @@ export type CreateMenuResponse = { price: number; images: Image[]; options: OptionGroup[]; - } -} + }; +}; export type GetOrderRequest = { startDate: string; endDate: string; - status: "ORDER" | "CANCEL" + status: 'ORDER' | 'CANCEL'; page: number; size: number; -} +}; export type Store = { storeId: number; @@ -143,17 +143,15 @@ export type OrderMenu = { }; export type Order = { + orderId: number; status: string; - store: Store; - orderer: Orderer; - menu: OrderMenu; + storeName: string; + ordererName: string; + menutotalPrice: number; }; export type GetOrderResponse = { - response: { - status: string; - orders: Order[]; - }; + orders: Order[]; }; export type GetOrderDetailResponse = { @@ -191,7 +189,7 @@ export type GetOrderDetailResponse = { export type UpdateOrderRequest = { orderId: number; reason: string; -} +}; export type Review = { id: number; @@ -206,7 +204,7 @@ export type Review = { }; menus: { name: string; - } + }; }; export type ReviewImage = { @@ -215,7 +213,7 @@ export type ReviewImage = { }; export type GetReviewsParams = StoresParams & { - sort?: "GRADE" | "ID"; + sort?: 'GRADE' | 'ID'; }; export type GetReviewsResponse = { diff --git a/src/atoms/authAtom.ts b/src/atoms/authAtom.ts index 3281d3d..779096e 100644 --- a/src/atoms/authAtom.ts +++ b/src/atoms/authAtom.ts @@ -2,4 +2,4 @@ import { atom } from "jotai"; export type UserRole = "admin" | "owner" | "guest"; //추후 API맞춰서 변경 예정 -export const roleAtom = atom("owner"); // 기본 역할은 'guest'지만 로그인페이지 개발전 Owner를 기본적으로 +export const roleAtom = atom("admin"); // 기본 역할은 'guest'지만 로그인페이지 개발전 Owner를 기본적으로 diff --git a/src/common/components/errorBoundary/index.tsx b/src/common/components/errorBoundary/index.tsx new file mode 100644 index 0000000..63e1241 --- /dev/null +++ b/src/common/components/errorBoundary/index.tsx @@ -0,0 +1,39 @@ +import React from 'react'; + +interface ErrorBoundaryProps { + children: React.ReactNode; + fallbackUI?: React.ReactNode; +} + +interface ErrorBoundaryState { + hasError: boolean; +} + +class ErrorBoundary extends React.Component< + ErrorBoundaryProps, + ErrorBoundaryState +> { + constructor(props: ErrorBoundaryProps) { + super(props); + this.state = { hasError: false }; + } + + static getDerivedStateFromError() { + return { hasError: true }; + } + + componentDidCatch(error: Error, errorInfo: React.ErrorInfo) { + console.log('error', error); + console.log('errorInfo', errorInfo); + } + + render() { + if (this.state.hasError) { + return this.props.fallbackUI ??

에러가 발생했습니다.

; + } + + return this.props.children; + } +} + +export default ErrorBoundary; diff --git a/src/common/components/icons/assets/arrow.svg b/src/common/components/icons/assets/arrow.svg new file mode 100644 index 0000000..64ca1c9 --- /dev/null +++ b/src/common/components/icons/assets/arrow.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/common/components/icons/assets/calendar.svg b/src/common/components/icons/assets/calendar.svg new file mode 100644 index 0000000..58c2058 --- /dev/null +++ b/src/common/components/icons/assets/calendar.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/common/components/icons/assets/check-circle.svg b/src/common/components/icons/assets/check-circle.svg new file mode 100644 index 0000000..9058965 --- /dev/null +++ b/src/common/components/icons/assets/check-circle.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/common/components/icons/assets/coffee.svg b/src/common/components/icons/assets/coffee.svg new file mode 100644 index 0000000..4d691da --- /dev/null +++ b/src/common/components/icons/assets/coffee.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/common/components/icons/assets/dallars.svg b/src/common/components/icons/assets/dallars.svg new file mode 100644 index 0000000..97fd605 --- /dev/null +++ b/src/common/components/icons/assets/dallars.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/common/components/icons/assets/downArrow.svg b/src/common/components/icons/assets/downArrow.svg new file mode 100644 index 0000000..19e78f8 --- /dev/null +++ b/src/common/components/icons/assets/downArrow.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/common/components/icons/assets/logo.svg b/src/common/components/icons/assets/logo.svg new file mode 100644 index 0000000..38cbe6f --- /dev/null +++ b/src/common/components/icons/assets/logo.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/src/common/components/icons/assets/orders.svg b/src/common/components/icons/assets/orders.svg new file mode 100644 index 0000000..28bbd16 --- /dev/null +++ b/src/common/components/icons/assets/orders.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/common/components/icons/assets/store.svg b/src/common/components/icons/assets/store.svg new file mode 100644 index 0000000..b56a899 --- /dev/null +++ b/src/common/components/icons/assets/store.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/common/components/icons/assets/upArrow.svg b/src/common/components/icons/assets/upArrow.svg new file mode 100644 index 0000000..86141cb --- /dev/null +++ b/src/common/components/icons/assets/upArrow.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/common/components/icons/assets/updown.svg b/src/common/components/icons/assets/updown.svg new file mode 100644 index 0000000..47e96bc --- /dev/null +++ b/src/common/components/icons/assets/updown.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/common/components/icons/assets/x-circle.svg b/src/common/components/icons/assets/x-circle.svg new file mode 100644 index 0000000..996e043 --- /dev/null +++ b/src/common/components/icons/assets/x-circle.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/common/components/icons/index.ts b/src/common/components/icons/index.ts index 6e8b141..3871171 100644 --- a/src/common/components/icons/index.ts +++ b/src/common/components/icons/index.ts @@ -1,8 +1,28 @@ -export { default as Search } from "./assets/search.svg"; -export { default as Dashboard } from "./assets/dashboard.svg"; -export { default as Order } from "./assets/order.svg"; -export { default as Menu } from "./assets/menus.svg"; -export { default as Review } from "./assets/review.svg"; +export { default as Search } from './assets/search.svg'; +export { default as Dashboard } from './assets/dashboard.svg'; +export { default as Order } from './assets/order.svg'; +export { default as Menu } from './assets/menus.svg'; +export { default as Review } from './assets/review.svg'; -export { default as Edit } from "./assets/edit.svg"; -export { default as Delete } from "./assets/trash.svg"; +export { default as Edit } from './assets/edit.svg'; +export { default as Delete } from './assets/trash.svg'; +export { default as Store } from './assets/store.svg'; + +export { default as P1 } from './assets/person/p1.svg'; +export { default as P2 } from './assets/person/p2.svg'; +export { default as P3 } from './assets/person/p3.svg'; +export { default as P4 } from './assets/person/p4.svg'; +export { default as Star } from './assets/star.svg'; +export { default as StarEmpty } from './assets/star_empty.svg'; + +export { default as Arrow } from './assets/arrow.svg'; +export { default as Calendar } from './assets/calendar.svg'; +export { default as Coffee } from './assets/coffee.svg'; +export { default as Dallars } from './assets/dallars.svg'; +export { default as Orders } from './assets/orders.svg'; +export { default as XCircle } from './assets/x-circle.svg'; +export { default as CheckCircle } from './assets/check-circle.svg'; +export { default as UpArrow } from './assets/upArrow.svg'; +export { default as DownArrow } from './assets/downArrow.svg'; +export { default as UpdownArrow } from './assets/updown.svg'; +export { default as Logo } from './assets/logo.svg'; diff --git a/src/common/components/layout/index.tsx b/src/common/components/layout/index.tsx index ba8232d..415ed5c 100644 --- a/src/common/components/layout/index.tsx +++ b/src/common/components/layout/index.tsx @@ -1,10 +1,10 @@ /** @jsxImportSource @emotion/react */ -import { css } from "@emotion/react"; -import { HTMLAttributes, ReactNode } from "react"; -import { Link } from "react-router-dom"; -import colors from "styles/color"; -import Menus from "common/components/menus"; -import { Search } from "common/components/icons"; +import { css } from '@emotion/react'; +import { HTMLAttributes, ReactNode } from 'react'; +import { Link } from 'react-router-dom'; +import colors from 'styles/color'; +import Menus from 'common/components/menus'; +import { Logo, Search } from 'common/components/icons'; interface Props extends HTMLAttributes { children: ReactNode; @@ -16,7 +16,7 @@ const Layout = ({ children }: Props) => {