From 9b7f80a088f0305ba45a0cbfd8a19a4f1df5b223 Mon Sep 17 00:00:00 2001 From: saewookkang Date: Wed, 17 Apr 2024 22:29:06 +0900 Subject: [PATCH 01/39] =?UTF-8?q?feat:=20=EC=BF=A0=ED=82=A4=20=EC=A0=91?= =?UTF-8?q?=EA=B7=BC=20=EB=A0=88=ED=8D=BC=EC=A7=80=ED=86=A0=EB=A6=AC=20hoo?= =?UTF-8?q?k=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hooks/useCookieRepository/service.ts | 38 +++++++++++ src/common/hooks/useCookieRepository/type.ts | 21 ++++++ .../useCookieRepository.ts | 65 +++++++++++++++++++ 3 files changed, 124 insertions(+) create mode 100644 src/common/hooks/useCookieRepository/service.ts create mode 100644 src/common/hooks/useCookieRepository/type.ts create mode 100644 src/common/hooks/useCookieRepository/useCookieRepository.ts diff --git a/src/common/hooks/useCookieRepository/service.ts b/src/common/hooks/useCookieRepository/service.ts new file mode 100644 index 000000000..c635b544d --- /dev/null +++ b/src/common/hooks/useCookieRepository/service.ts @@ -0,0 +1,38 @@ +import { CookieOptions } from './type' + +/** + * @summary name에 해당하는 쿠키 값을 가져온다. + * @reference https://developer.mozilla.org/en-US/docs/Web/API/Document/cookie#example_2_get_a_sample_cookie_named_test2 + */ +export function getCookie(name: T) { + const cookie = document.cookie + .split('; ') + .find((row) => row.startsWith(`${name}=`)) + ?.split('=')[1] + + return decodeURIComponent(cookie || '') +} + +/** + * @summary 쿠키를 저장한다. + * @reference https://developer.mozilla.org/en-US/docs/Web/API/Document/cookie + */ +export function setCookie( + name: Key, + value: Value, + options: CookieOptions +) { + const cookieString = `${encodeURIComponent(name)}=${encodeURIComponent(value)}` + + // eslint-disable-next-line no-shadow + const cookieOptions = Object.entries(options).reduce((prev, [key, value]) => { + switch (key) { + case 'expires': + return (prev += `; expires=${(value as Date).toUTCString()}`) + default: + return (prev += `; ${key}=${value}`) + } + }, '') + + document.cookie = cookieString + cookieOptions +} diff --git a/src/common/hooks/useCookieRepository/type.ts b/src/common/hooks/useCookieRepository/type.ts new file mode 100644 index 000000000..07b51bbda --- /dev/null +++ b/src/common/hooks/useCookieRepository/type.ts @@ -0,0 +1,21 @@ +export interface CookieOptions { + /** + * @summary 쿠키의 + * @default 세션 쿠기(브라우저 종료시 자동 삭제) + * @description 지정시 영구 쿠기(지정 날짜까지 유지) + */ + expires?: Date + /** + * @default "/" + */ + path?: string + /** + * @default 현재 도메인 + * @description 미지정시 하위 도메인 접근 불가 + */ + domain?: string + /** + * 기타 키 정의 + */ + [key: string]: unknown +} diff --git a/src/common/hooks/useCookieRepository/useCookieRepository.ts b/src/common/hooks/useCookieRepository/useCookieRepository.ts new file mode 100644 index 000000000..6e6a011a5 --- /dev/null +++ b/src/common/hooks/useCookieRepository/useCookieRepository.ts @@ -0,0 +1,65 @@ +import { useEffect, useState } from 'react' + +import { getCookie, setCookie } from './service' +import { CookieOptions } from './type' + +interface CookieRepository { + get(): Value | undefined + set(value: Value): void + remove(key: Key): void + update(key: Key, value: Value): void + clear(): void +} + +/** + * @summary 쿠키 레파지토리 + */ +export const useCookie = ( + key: Key, + option?: CookieOptions +): CookieRepository => { + const [cookie, setStateCookie] = useState() + + useEffect(() => { + const initializeCookie = () => { + // eslint-disable-next-line no-shadow + const cookie = getCookie(key) + + if (cookie) { + setStateCookie(JSON.parse(cookie) as Value) + } + } + + initializeCookie() + }, [key]) + + const get = () => { + return cookie + } + + const set = (value: Value) => { + setStateCookie(value) + + setCookie(key, JSON.stringify(value), option ?? {}) + } + + const remove = () => { + throw new Error('Not Implemented') + } + + const update = () => { + throw new Error('Not Implemented') + } + + const clear = () => { + throw new Error('Not Implemented') + } + + return { + get, + set, + remove, + update, + clear, + } +} From 5879b4fbbcb2198af5ac82f5f73e4bd45b63208b Mon Sep 17 00:00:00 2001 From: saewookkang Date: Thu, 18 Apr 2024 22:27:06 +0900 Subject: [PATCH 02/39] =?UTF-8?q?feat:=20=EA=B5=AC=EB=8F=85=EC=9D=84?= =?UTF-8?q?=ED=86=B5=ED=95=9C=20=EC=A0=84=EC=97=AD=20=EC=83=81=ED=83=9C=20?= =?UTF-8?q?=EB=AA=A8=EB=93=88=20=EC=8A=A4=ED=86=A0=EC=96=B4=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/common/module/store/store.ts | 35 +++++++++++++++++++++++++++++ src/common/module/store/useStore.ts | 20 +++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 src/common/module/store/store.ts create mode 100644 src/common/module/store/useStore.ts diff --git a/src/common/module/store/store.ts b/src/common/module/store/store.ts new file mode 100644 index 000000000..f3b412884 --- /dev/null +++ b/src/common/module/store/store.ts @@ -0,0 +1,35 @@ +export interface Store { + getState: () => T + setState: (next: T | ((prev: T) => T)) => void + subscribe: (callback: () => void) => () => void +} + +/** + * @summary 스토어를 생성한다. + */ +export const createStore = (initialValue: T): Store => { + let state = initialValue + const callbacks = new Set<() => void>() + + const getState = () => { + return state + } + + const setState = (next: T | ((prev: T) => T)) => { + state = typeof next === 'function' ? (next as (prev: T) => T)(state) : next + + callbacks.forEach((callback) => callback()) + } + + const subscribe = (callback: () => void) => { + callbacks.add(callback) + + return () => callbacks.delete(callback) + } + + return { + getState, + setState, + subscribe, + } +} diff --git a/src/common/module/store/useStore.ts b/src/common/module/store/useStore.ts new file mode 100644 index 000000000..c6a0a8021 --- /dev/null +++ b/src/common/module/store/useStore.ts @@ -0,0 +1,20 @@ +import { useEffect, useState } from 'react' + +import { Store } from './store' + +/** + * @summary 스토어를 리액트에서 상태로 사용할 수 있도록 도와주는 hook + */ +export const useStore = (store: Store) => { + const [state, setState] = useState(store.getState()) + + useEffect(() => { + const unsubscribe = store.subscribe(() => { + setState(store.getState()) + }) + + return unsubscribe + }, [store]) + + return [state, store.setState] as const +} From 6ed879cb2094d8b3d5dc1c2226494e3c25f8a57f Mon Sep 17 00:00:00 2001 From: saewookkang Date: Fri, 19 Apr 2024 22:23:02 +0900 Subject: [PATCH 03/39] =?UTF-8?q?feat(cartListStore.ts):=20=EC=9E=A5?= =?UTF-8?q?=EB=B0=94=EA=B5=AC=EB=8B=88=20=EA=B4=80=EB=A6=AC=20=EC=8A=A4?= =?UTF-8?q?=ED=86=A0=EC=96=B4=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/routes/-common/store/cartListStore.ts | 47 +++++++++++++++++++++++ src/routes/-product-list.api.ts | 2 +- 2 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 src/routes/-common/store/cartListStore.ts diff --git a/src/routes/-common/store/cartListStore.ts b/src/routes/-common/store/cartListStore.ts new file mode 100644 index 000000000..85d639b62 --- /dev/null +++ b/src/routes/-common/store/cartListStore.ts @@ -0,0 +1,47 @@ +import { useEffect } from 'react' + +import { getCookie, setCookie } from '@/common/hooks/useCookieRepository/service' +import { createStore } from '@/common/module/store/store' +import { useStore } from '@/common/module/store/useStore' +import type { Product } from '@/routes/-product-list.api' + +const CARTS_KEY = 'CARTS' + +const initializeCookie = getCookie(CARTS_KEY) + +interface CartItem extends Pick { + count: number +} + +const cartListStore = createStore<{ + cartList: Array +}>({ + cartList: initializeCookie ? JSON.parse(initializeCookie) : [], +}) + +export const useCartListStore = () => { + const [value, setValue] = useStore(cartListStore) + + useEffect(() => { + setCookie(CARTS_KEY, JSON.stringify(value.cartList), {}) + }, [value]) + + const saveProduct = (id: CartItem['id']) => { + const foundProduct = value.cartList.find((product) => product.id === id) + + foundProduct + ? setValue((prev) => ({ + ...prev, + cartList: [ + ...prev.cartList.filter((product) => product.id !== id), + { id, count: foundProduct.count + 1 }, + ], + })) + : setValue((prev) => ({ ...prev, cartList: [...prev.cartList, { id, count: 1 }] })) + } + + return { + cartList: value.cartList, + saveProduct, + } +} diff --git a/src/routes/-product-list.api.ts b/src/routes/-product-list.api.ts index 2d81acfe7..2362a1a1e 100644 --- a/src/routes/-product-list.api.ts +++ b/src/routes/-product-list.api.ts @@ -1,4 +1,4 @@ -interface Product { +export interface Product { id: number name: string price: number From 7e7bd6edca67ba8acd5ef87115a6762fd6f3e387 Mon Sep 17 00:00:00 2001 From: saewookkang Date: Fri, 19 Apr 2024 22:24:12 +0900 Subject: [PATCH 04/39] =?UTF-8?q?feat(ProductCard.tsx):=20=EC=9E=A5?= =?UTF-8?q?=EB=B0=94=EA=B5=AC=EB=8B=88=20=EC=A0=80=EC=9E=A5=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../-common/components/ProductCard/ProductCard.tsx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/routes/-common/components/ProductCard/ProductCard.tsx b/src/routes/-common/components/ProductCard/ProductCard.tsx index 2c9449699..e7e6f4b65 100644 --- a/src/routes/-common/components/ProductCard/ProductCard.tsx +++ b/src/routes/-common/components/ProductCard/ProductCard.tsx @@ -1,17 +1,25 @@ import type { ProductList } from '@/routes/-product-list.api' +import { useCartListStore } from '../../store/cartListStore' + type ProductCardProps = ProductList[number] export const ProductCard = (props: ProductCardProps) => { + const cartListStore = useCartListStore() + return ( <> {props.name} +
{props.name} {props.price.toLocaleString()}
- 장바구니 + +
) From e96cd05241cfc443da6655356c41c56ff6b6e150 Mon Sep 17 00:00:00 2001 From: saewookkang Date: Fri, 19 Apr 2024 22:24:48 +0900 Subject: [PATCH 05/39] =?UTF-8?q?design=20&=20feat(Gnb.tsx):=20=EC=9E=A5?= =?UTF-8?q?=EB=B0=94=EA=B5=AC=EB=8B=88=20=EA=B0=AF=EC=88=98=20=EB=85=B8?= =?UTF-8?q?=EC=B6=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/routes/-common/components/gnb/Gnb.tsx | 67 ++++++++++++++++------- 1 file changed, 48 insertions(+), 19 deletions(-) diff --git a/src/routes/-common/components/gnb/Gnb.tsx b/src/routes/-common/components/gnb/Gnb.tsx index 393b6c143..f4355984a 100644 --- a/src/routes/-common/components/gnb/Gnb.tsx +++ b/src/routes/-common/components/gnb/Gnb.tsx @@ -1,26 +1,55 @@ import { Link } from '@tanstack/react-router' +import { useCartListStore } from '../../store/cartListStore' + /** * @summary 공통으로 사용하는 네비게이션 바 * @detail 메인페이지, 장바구니, 주문목록 페이지 라우팅 */ -export const Gnb = () => ( -
-
+ + + ) +} From 9c83d81910a95af41f1e759d805bf289ff75b3f5 Mon Sep 17 00:00:00 2001 From: saewookkang Date: Sat, 20 Apr 2024 10:44:02 +0900 Subject: [PATCH 06/39] =?UTF-8?q?feat(ProductList.tsx):=20=ED=83=80?= =?UTF-8?q?=EC=9E=85=20=EB=8B=A8=EC=96=B8=EB=AC=B8=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - pr 피드백 반영 --- src/routes/-common/components/ProductList/ProductList.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/-common/components/ProductList/ProductList.tsx b/src/routes/-common/components/ProductList/ProductList.tsx index aacca4040..2af042609 100644 --- a/src/routes/-common/components/ProductList/ProductList.tsx +++ b/src/routes/-common/components/ProductList/ProductList.tsx @@ -24,7 +24,7 @@ export const ProductList = () => { cases={{ success: ( } className="product-container" style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)' }} From bc75bf431c5eac9b31a38f0713c85388a7bf32ab Mon Sep 17 00:00:00 2001 From: saewookkang Date: Sat, 20 Apr 2024 10:46:02 +0900 Subject: [PATCH 07/39] =?UTF-8?q?feat:=20=EC=83=81=ED=92=88=20=EC=83=81?= =?UTF-8?q?=EC=84=B8=20api=20=EB=AA=A8=ED=82=B9=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/mocks/products/products.handlers.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/mocks/products/products.handlers.ts b/src/mocks/products/products.handlers.ts index 527e217c0..6eb2de4c9 100644 --- a/src/mocks/products/products.handlers.ts +++ b/src/mocks/products/products.handlers.ts @@ -14,4 +14,11 @@ export const productsHandlers = [ return HttpResponse.json(Array.from(allProducts.values())) }), + http.get('/products/:id', async ({ params }) => { + await delay(1000) + + const { id } = params + + return HttpResponse.json(allProducts.get(Number(id))) + }), ] From fb9d6450de757d0e33d83eef1750a010c5f4b7bd Mon Sep 17 00:00:00 2001 From: saewookkang Date: Sat, 20 Apr 2024 10:49:01 +0900 Subject: [PATCH 08/39] =?UTF-8?q?design=20&=20feat:=20=EC=83=81=ED=92=88?= =?UTF-8?q?=20=EC=83=81=EC=84=B8=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=EC=9E=91?= =?UTF-8?q?=EC=97=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/routeTree.gen.ts | 13 +++++++ .../-common/components/Product/Product.tsx | 30 +++++++++++++++ src/routes/products/$id/-product-item.api.ts | 19 ++++++++++ src/routes/products/$id/index.lazy.tsx | 37 +++++++++++++++++++ 4 files changed, 99 insertions(+) create mode 100644 src/routes/products/$id/-common/components/Product/Product.tsx create mode 100644 src/routes/products/$id/-product-item.api.ts create mode 100644 src/routes/products/$id/index.lazy.tsx diff --git a/src/routeTree.gen.ts b/src/routeTree.gen.ts index 62b2616a6..2105c1361 100644 --- a/src/routeTree.gen.ts +++ b/src/routeTree.gen.ts @@ -19,6 +19,7 @@ import { Route as rootRoute } from './routes/__root' const IndexLazyImport = createFileRoute('/')() const OrdersIndexLazyImport = createFileRoute('/orders/')() const CartIndexLazyImport = createFileRoute('/cart/')() +const ProductsIdIndexLazyImport = createFileRoute('/products/$id/')() // Create/Update Routes @@ -37,6 +38,13 @@ const CartIndexLazyRoute = CartIndexLazyImport.update({ getParentRoute: () => rootRoute, } as any).lazy(() => import('./routes/cart/index.lazy').then((d) => d.Route)) +const ProductsIdIndexLazyRoute = ProductsIdIndexLazyImport.update({ + path: '/products/$id/', + getParentRoute: () => rootRoute, +} as any).lazy(() => + import('./routes/products/$id/index.lazy').then((d) => d.Route), +) + // Populate the FileRoutesByPath interface declare module '@tanstack/react-router' { @@ -53,6 +61,10 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof OrdersIndexLazyImport parentRoute: typeof rootRoute } + '/products/$id/': { + preLoaderRoute: typeof ProductsIdIndexLazyImport + parentRoute: typeof rootRoute + } } } @@ -62,6 +74,7 @@ export const routeTree = rootRoute.addChildren([ IndexLazyRoute, CartIndexLazyRoute, OrdersIndexLazyRoute, + ProductsIdIndexLazyRoute, ]) /* prettier-ignore-end */ diff --git a/src/routes/products/$id/-common/components/Product/Product.tsx b/src/routes/products/$id/-common/components/Product/Product.tsx new file mode 100644 index 000000000..1481a129d --- /dev/null +++ b/src/routes/products/$id/-common/components/Product/Product.tsx @@ -0,0 +1,30 @@ +import type { Product as ProductResponse } from '../../../-product-item.api' + +interface ProductProps extends ProductResponse { + saveProduct: (id: number) => void +} +export const Product = (props: ProductProps) => { + return ( +
+
+ {props.name} + +
+ {props.name} +
+
+ 금액 + {props.price?.toLocaleString()}원 +
+
+ + +
+
+ ) +} diff --git a/src/routes/products/$id/-product-item.api.ts b/src/routes/products/$id/-product-item.api.ts new file mode 100644 index 000000000..4d9f0364e --- /dev/null +++ b/src/routes/products/$id/-product-item.api.ts @@ -0,0 +1,19 @@ +export interface Product { + id: number + name: string + price: number + imageUrl: string +} + +/** + * @summary 상목목록 API + */ +export const getProduct = async (id: number) => { + const response = await fetch(`/products/${id}`) + + if (!response.ok) { + throw new Error('failed to getProduct') + } + + return response.json() +} diff --git a/src/routes/products/$id/index.lazy.tsx b/src/routes/products/$id/index.lazy.tsx new file mode 100644 index 000000000..c74d4d7b4 --- /dev/null +++ b/src/routes/products/$id/index.lazy.tsx @@ -0,0 +1,37 @@ +import { useQuery } from '@tanstack/react-query' +import { createFileRoute } from '@tanstack/react-router' + +import { SwitchCase } from '@/common/components/SwitchCase/SwitchCase' +import { parseApiStatus } from '@/common/utils/parseApiStatus' +import { useCartListStore } from '@/routes/-common/store/cartListStore' + +import { Product } from './-common/components/Product/Product' +import type { Product as ProductResponse } from './-product-item.api' +import { getProduct } from './-product-item.api' + +export const Route = createFileRoute('/products/$id/')({ + parseParams: (params) => ({ id: Number(params.id) }), + component: ProductDetail, +}) + +function ProductDetail() { + const { id } = Route.useParams() + + const { data, isLoading, isError } = useQuery({ + queryKey: ['product', id], + queryFn: () => getProduct(id), + }) + + const { saveProduct } = useCartListStore() + + return ( + : null, + loading:
loading...
, + error:
error
, + }} + /> + ) +} From 38cf2096469c95f302634e8e14f650f656cbccd9 Mon Sep 17 00:00:00 2001 From: saewookkang Date: Sat, 20 Apr 2024 10:58:36 +0900 Subject: [PATCH 09/39] =?UTF-8?q?feat(ProductCard.tsx):=20=EC=83=81?= =?UTF-8?q?=ED=92=88=20=ED=81=B4=EB=A6=AD=EC=8B=9C=20=EC=83=81=ED=92=88=20?= =?UTF-8?q?=EC=83=81=EC=84=B8=20=EB=9D=BC=EC=9A=B0=ED=8C=85=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/ProductCard/ProductCard.tsx | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/routes/-common/components/ProductCard/ProductCard.tsx b/src/routes/-common/components/ProductCard/ProductCard.tsx index e7e6f4b65..dc50163bd 100644 --- a/src/routes/-common/components/ProductCard/ProductCard.tsx +++ b/src/routes/-common/components/ProductCard/ProductCard.tsx @@ -1,3 +1,5 @@ +import { Link } from '@tanstack/react-router' + import type { ProductList } from '@/routes/-product-list.api' import { useCartListStore } from '../../store/cartListStore' @@ -8,7 +10,7 @@ export const ProductCard = (props: ProductCardProps) => { const cartListStore = useCartListStore() return ( - <> + {props.name}
@@ -17,10 +19,17 @@ export const ProductCard = (props: ProductCardProps) => { {props.price.toLocaleString()}
- - + ) } From a8c417c2d9d89bd0ac0e09b023490e7e60525def Mon Sep 17 00:00:00 2001 From: saewookkang Date: Sat, 20 Apr 2024 11:13:29 +0900 Subject: [PATCH 10/39] =?UTF-8?q?feat=20&=20design(ProductSkeleton.tsx):?= =?UTF-8?q?=20=EC=83=81=ED=92=88=20=EC=83=81=EC=84=B8=20=EB=A1=9C=EB=94=A9?= =?UTF-8?q?=20=EC=8A=A4=EC=BC=88=EB=A0=88=ED=86=A4=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ProductSkeleton/ProductSkeleton.tsx | 15 +++++++++++++++ src/routes/products/$id/index.lazy.tsx | 3 ++- 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 src/routes/products/$id/-common/components/ProductSkeleton/ProductSkeleton.tsx diff --git a/src/routes/products/$id/-common/components/ProductSkeleton/ProductSkeleton.tsx b/src/routes/products/$id/-common/components/ProductSkeleton/ProductSkeleton.tsx new file mode 100644 index 000000000..329dac997 --- /dev/null +++ b/src/routes/products/$id/-common/components/ProductSkeleton/ProductSkeleton.tsx @@ -0,0 +1,15 @@ +import { Skeleton } from '@/common/components/Skeleton/Skeleton' + +export const ProductSkeleton = () => { + return ( +
+
+ +
+
+ ) +} diff --git a/src/routes/products/$id/index.lazy.tsx b/src/routes/products/$id/index.lazy.tsx index c74d4d7b4..d763fe6c8 100644 --- a/src/routes/products/$id/index.lazy.tsx +++ b/src/routes/products/$id/index.lazy.tsx @@ -6,6 +6,7 @@ import { parseApiStatus } from '@/common/utils/parseApiStatus' import { useCartListStore } from '@/routes/-common/store/cartListStore' import { Product } from './-common/components/Product/Product' +import { ProductSkeleton } from './-common/components/ProductSkeleton/ProductSkeleton' import type { Product as ProductResponse } from './-product-item.api' import { getProduct } from './-product-item.api' @@ -29,7 +30,7 @@ function ProductDetail() { value={parseApiStatus({ isLoading, isError })} cases={{ success: data ? : null, - loading:
loading...
, + loading: , error:
error
, }} /> From 8439ea15fa72e00fa9a7b155259c1511b0993f5b Mon Sep 17 00:00:00 2001 From: saewookkang Date: Sat, 20 Apr 2024 11:16:17 +0900 Subject: [PATCH 11/39] =?UTF-8?q?chore(Product.tsx):=20=EC=9E=A5=EB=B0=94?= =?UTF-8?q?=EA=B5=AC=EB=8B=88=20=EB=B2=84=ED=8A=BC=20=ED=8F=AC=EC=9D=B8?= =?UTF-8?q?=ED=8A=B8=20=EC=BB=A4=EC=84=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/routes/products/$id/-common/components/Product/Product.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/products/$id/-common/components/Product/Product.tsx b/src/routes/products/$id/-common/components/Product/Product.tsx index 1481a129d..5dc8d50a0 100644 --- a/src/routes/products/$id/-common/components/Product/Product.tsx +++ b/src/routes/products/$id/-common/components/Product/Product.tsx @@ -20,7 +20,7 @@ export const Product = (props: ProductProps) => { From 34d9cb9f912aad5a97b704b47f2c8bbee982e3a8 Mon Sep 17 00:00:00 2001 From: saewookkang Date: Sat, 20 Apr 2024 15:23:43 +0900 Subject: [PATCH 12/39] =?UTF-8?q?design:=20=EB=B0=98=EC=9D=91=ED=98=95=20?= =?UTF-8?q?=EB=A0=88=EC=9D=B4=EC=95=84=EC=9B=83=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/css/index.css | 2 +- .../components/ProductCard/ProductCard.tsx | 2 +- .../components/ProductList/ProductList.tsx | 8 +++---- .../-common/components/ProductList/index.css | 23 +++++++++++++++++++ 4 files changed, 29 insertions(+), 6 deletions(-) create mode 100644 src/routes/-common/components/ProductList/index.css diff --git a/src/css/index.css b/src/css/index.css index 5f55fca84..0b42bb8c1 100644 --- a/src/css/index.css +++ b/src/css/index.css @@ -2,7 +2,7 @@ @import "./page/index.css"; body { - width: 1920px; + max-width: 1920px; margin: 0 auto 0; } diff --git a/src/routes/-common/components/ProductCard/ProductCard.tsx b/src/routes/-common/components/ProductCard/ProductCard.tsx index dc50163bd..106c33d21 100644 --- a/src/routes/-common/components/ProductCard/ProductCard.tsx +++ b/src/routes/-common/components/ProductCard/ProductCard.tsx @@ -11,7 +11,7 @@ export const ProductCard = (props: ProductCardProps) => { return ( - {props.name} + {props.name}
diff --git a/src/routes/-common/components/ProductList/ProductList.tsx b/src/routes/-common/components/ProductList/ProductList.tsx index 2af042609..6262d2a6d 100644 --- a/src/routes/-common/components/ProductList/ProductList.tsx +++ b/src/routes/-common/components/ProductList/ProductList.tsx @@ -1,3 +1,5 @@ +import './index.css' + import { useQuery } from '@tanstack/react-query' import { RenderPropsList } from '@/common/components/RenderPropsList/RenderPropsList' @@ -24,10 +26,9 @@ export const ProductList = () => { cases={{ success: ( } - className="product-container" - style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)' }} /> ), loading: ( @@ -36,8 +37,7 @@ export const ProductList = () => { id: i, }))} renderItem={() => } - className="product-container" - style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)' }} + className=" product-container2" /> ), error: <>error, diff --git a/src/routes/-common/components/ProductList/index.css b/src/routes/-common/components/ProductList/index.css new file mode 100644 index 000000000..508c863eb --- /dev/null +++ b/src/routes/-common/components/ProductList/index.css @@ -0,0 +1,23 @@ +.product-container2 { + padding: 20px; + + display: grid; + grid-template-columns: 1fr; + gap: 20px; +} + +@media (min-width: 950px) { + .product-container2 { + padding: 50px 200px; + + grid-template-columns: repeat(3, 1fr); + } +} + +@media (min-width: 1200px) { + .product-container2 { + padding: 50px 200px; + + grid-template-columns: repeat(4, 1fr); + } +} From 93ea91d40554dae97b50df86b0ca0d427e4a8da1 Mon Sep 17 00:00:00 2001 From: saewookkang Date: Sat, 20 Apr 2024 16:26:15 +0900 Subject: [PATCH 13/39] =?UTF-8?q?refactor(ProductDetail.tsx):=20SwitchCast?= =?UTF-8?q?=EC=9D=98=20value=20props=20=EA=B0=92=20useQuery=EC=9D=98=20sta?= =?UTF-8?q?tus=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/routes/products/$id/index.lazy.tsx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/routes/products/$id/index.lazy.tsx b/src/routes/products/$id/index.lazy.tsx index d763fe6c8..059031a4c 100644 --- a/src/routes/products/$id/index.lazy.tsx +++ b/src/routes/products/$id/index.lazy.tsx @@ -2,7 +2,6 @@ import { useQuery } from '@tanstack/react-query' import { createFileRoute } from '@tanstack/react-router' import { SwitchCase } from '@/common/components/SwitchCase/SwitchCase' -import { parseApiStatus } from '@/common/utils/parseApiStatus' import { useCartListStore } from '@/routes/-common/store/cartListStore' import { Product } from './-common/components/Product/Product' @@ -18,7 +17,7 @@ export const Route = createFileRoute('/products/$id/')({ function ProductDetail() { const { id } = Route.useParams() - const { data, isLoading, isError } = useQuery({ + const { data, status } = useQuery({ queryKey: ['product', id], queryFn: () => getProduct(id), }) @@ -27,10 +26,10 @@ function ProductDetail() { return ( : null, - loading: , + pending: , error:
error
, }} /> From 3e580e50a4c7a23511b4d40abdfab06c64010fa7 Mon Sep 17 00:00:00 2001 From: saewookkang Date: Sat, 20 Apr 2024 20:57:32 +0900 Subject: [PATCH 14/39] =?UTF-8?q?feat(convertQueryToString):=20=EA=B0=9D?= =?UTF-8?q?=EC=B2=B4=EB=A5=BC=20url=20=EC=BF=BC=EB=A6=AC=20=ED=98=95?= =?UTF-8?q?=ED=83=9C=EB=A1=9C=20=EB=B3=80=ED=99=98=ED=95=98=EB=8A=94=20?= =?UTF-8?q?=ED=95=A8=EC=88=98=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/common/utils/convertQueryToString.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 src/common/utils/convertQueryToString.ts diff --git a/src/common/utils/convertQueryToString.ts b/src/common/utils/convertQueryToString.ts new file mode 100644 index 000000000..0a3e929fc --- /dev/null +++ b/src/common/utils/convertQueryToString.ts @@ -0,0 +1,11 @@ +/** + * @summary object를 key=value 형태의 string으로로 변환한다. + */ +export const convertQueryToString = (query: Record) => { + const queryArray = Object.entries(query) + const queryString = queryArray + .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`) + .join('&') + + return queryString +} From 5a649cf85fcedf46577d67160015e66bbdf2a647 Mon Sep 17 00:00:00 2001 From: saewookkang Date: Sat, 20 Apr 2024 21:03:32 +0900 Subject: [PATCH 15/39] chore(package.json): add react-intersection-observer --- package.json | 1 + yarn.lock | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/package.json b/package.json index d0be7fa67..a1174733a 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "@tanstack/router-vite-plugin": "^1.26.16", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-intersection-observer": "^9.8.2", "typescript-eslint": "^7.0.2" }, "devDependencies": { diff --git a/yarn.lock b/yarn.lock index 901d7e0b2..9d3ed7d35 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2765,6 +2765,11 @@ react-dom@^18.2.0: loose-envify "^1.1.0" scheduler "^0.23.0" +react-intersection-observer@^9.8.2: + version "9.8.2" + resolved "https://registry.yarnpkg.com/react-intersection-observer/-/react-intersection-observer-9.8.2.tgz#a45db2441909a4d2f310de381686e151f016691d" + integrity sha512-901naEiiZmse3p+AmtbQ3NL9xx+gQ8TXLiGDc+8GiE3JKJkNV3vP737aGuWTAXBA+1QqxPrDDE+fIEgYpGDlrQ== + react-refresh@^0.14.0: version "0.14.0" resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.0.tgz#4e02825378a5f227079554d4284889354e5f553e" From 562ef35a23e2df7b4acf72cad19148714d90a60f Mon Sep 17 00:00:00 2001 From: saewookkang Date: Sat, 20 Apr 2024 21:04:50 +0900 Subject: [PATCH 16/39] =?UTF-8?q?feat:=20=EB=AC=B4=ED=95=9C=EC=8A=A4?= =?UTF-8?q?=ED=81=AC=EB=A1=A4=20=EC=9E=91=EC=97=85=EC=9D=84=20=EC=9C=84?= =?UTF-8?q?=ED=95=9C=20=EC=83=81=ED=92=88=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?api=20=EB=AA=A8=ED=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/mocks/const.ts | 4 ++++ src/mocks/products/products.handlers.ts | 25 ++++++++++++++++++++----- 2 files changed, 24 insertions(+), 5 deletions(-) create mode 100644 src/mocks/const.ts diff --git a/src/mocks/const.ts b/src/mocks/const.ts new file mode 100644 index 000000000..bd29c9035 --- /dev/null +++ b/src/mocks/const.ts @@ -0,0 +1,4 @@ +export const PAGE_META = { + DEFAULT_PAGE: '0', + DEFAULT_PER_COUNT: '15', +} as const diff --git a/src/mocks/products/products.handlers.ts b/src/mocks/products/products.handlers.ts index 6eb2de4c9..6f1548f4f 100644 --- a/src/mocks/products/products.handlers.ts +++ b/src/mocks/products/products.handlers.ts @@ -1,18 +1,33 @@ import { delay, http, HttpResponse } from 'msw' -import type { ProductList } from '@/routes/-product-list.api' +import type { ProductListResponse } from '@/routes/-product-list.api' +import { PAGE_META } from '../const' import products from './products.json' -const allProducts = new Map( +const allProducts = new Map( products.map((product) => [product.id, product]) ) export const productsHandlers = [ - http.get('/products', async () => { - await delay(1000) + http.get('/products', async ({ request }) => { + await delay(500) + + const url = new URL(request.url) + + const page = parseInt(url.searchParams.get('page') ?? PAGE_META.DEFAULT_PAGE) + const perCount = parseInt(url.searchParams.get('perCount') ?? PAGE_META.DEFAULT_PER_COUNT) + + const start = page * perCount + const end = start + perCount + + const maxPage = Math.ceil(allProducts.size / perCount) + const nextPage = page < maxPage ? page + 1 : undefined - return HttpResponse.json(Array.from(allProducts.values())) + return HttpResponse.json({ + list: Array.from(allProducts.values()).slice(start, end), + meta: { next_page: nextPage }, + }) }), http.get('/products/:id', async ({ params }) => { await delay(1000) From a4267a5234ec9e82ddd30fc961cc6b35ae28a3be Mon Sep 17 00:00:00 2001 From: saewookkang Date: Sat, 20 Apr 2024 21:05:50 +0900 Subject: [PATCH 17/39] =?UTF-8?q?feat:=20=EC=83=81=ED=92=88=20=EB=A6=AC?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EB=AC=B4=ED=95=9C=20=EC=8A=A4=ED=81=AC?= =?UTF-8?q?=EB=A1=A4=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/MoreButton/MoreButton.tsx | 20 +++++ .../components/ProductCard/ProductCard.tsx | 4 +- .../components/ProductList/ProductList.tsx | 87 +++++++++++++------ src/routes/-product-list.api.ts | 22 ++++- 4 files changed, 101 insertions(+), 32 deletions(-) create mode 100644 src/routes/-common/components/MoreButton/MoreButton.tsx diff --git a/src/routes/-common/components/MoreButton/MoreButton.tsx b/src/routes/-common/components/MoreButton/MoreButton.tsx new file mode 100644 index 000000000..f02c0e653 --- /dev/null +++ b/src/routes/-common/components/MoreButton/MoreButton.tsx @@ -0,0 +1,20 @@ +import { ComponentPropsWithoutRef, forwardRef } from 'react' + +export const MoreButton = forwardRef>( + ({ children, ...props }, ref) => { + return ( + + ) + } +) diff --git a/src/routes/-common/components/ProductCard/ProductCard.tsx b/src/routes/-common/components/ProductCard/ProductCard.tsx index 106c33d21..91dd3c0a1 100644 --- a/src/routes/-common/components/ProductCard/ProductCard.tsx +++ b/src/routes/-common/components/ProductCard/ProductCard.tsx @@ -1,10 +1,10 @@ import { Link } from '@tanstack/react-router' -import type { ProductList } from '@/routes/-product-list.api' +import type { ProductListResponse } from '@/routes/-product-list.api' import { useCartListStore } from '../../store/cartListStore' -type ProductCardProps = ProductList[number] +type ProductCardProps = ProductListResponse['list'][number] export const ProductCard = (props: ProductCardProps) => { const cartListStore = useCartListStore() diff --git a/src/routes/-common/components/ProductList/ProductList.tsx b/src/routes/-common/components/ProductList/ProductList.tsx index 6262d2a6d..64e31ddf6 100644 --- a/src/routes/-common/components/ProductList/ProductList.tsx +++ b/src/routes/-common/components/ProductList/ProductList.tsx @@ -1,47 +1,80 @@ import './index.css' -import { useQuery } from '@tanstack/react-query' +import { useInfiniteQuery } from '@tanstack/react-query' +import { useEffect } from 'react' +import { useInView } from 'react-intersection-observer' import { RenderPropsList } from '@/common/components/RenderPropsList/RenderPropsList' import { Skeleton } from '@/common/components/Skeleton/Skeleton' import { SwitchCase } from '@/common/components/SwitchCase/SwitchCase' -import { parseApiStatus } from '@/common/utils/parseApiStatus' -import type { ProductList as ProductsListType } from '@/routes/-product-list.api' +import type { ProductListResponse } from '@/routes/-product-list.api' import { getProductList } from '@/routes/-product-list.api' +import { MoreButton } from '../MoreButton/MoreButton' import { ProductCard } from '../ProductCard/ProductCard' /** * @summary 상품목록 컴포넌트 */ export const ProductList = () => { - const { data, isLoading, isError } = useQuery({ + const { ref, inView } = useInView() + const { data, status, isFetchingNextPage, hasNextPage, fetchNextPage } = useInfiniteQuery({ queryKey: ['/posts'], - queryFn: getProductList, + queryFn: ({ pageParam }) => { + return getProductList({ + page: pageParam, + }) + }, + initialPageParam: 0, + getNextPageParam: (res: ProductListResponse) => res.meta.next_page, }) + useEffect(() => { + if (inView) { + fetchNextPage() + } + }, [fetchNextPage, inView]) + + const flattedProductList = data?.pages.flatMap((group) => group.list) + return ( - } - /> - ), - loading: ( - ({ - id: i, - }))} - renderItem={() => } - className=" product-container2" - /> - ), - error: <>error, - }} - /> + <> + + } + className="product-container2" + /> + + fetchNextPage()} + disabled={!hasNextPage || isFetchingNextPage} + > + {isFetchingNextPage + ? '더보기' + : hasNextPage + ? 'loading..' + : '더이상 상품이 존재하지 않습니다.'} + + + ), + pending: ( + ({ + id: i, + }))} + renderItem={() => } + className=" product-container2" + /> + ), + error: <>error, + }} + /> + ) } diff --git a/src/routes/-product-list.api.ts b/src/routes/-product-list.api.ts index 2362a1a1e..e0b5d2dd7 100644 --- a/src/routes/-product-list.api.ts +++ b/src/routes/-product-list.api.ts @@ -1,3 +1,5 @@ +import { convertQueryToString } from '@/common/utils/convertQueryToString' + export interface Product { id: number name: string @@ -5,13 +7,27 @@ export interface Product { imageUrl: string } -export type ProductList = Array +type Meta = { + next_page?: number +} + +type PageQuery = { + page?: number + perCount?: number +} + +export type ProductListResponse = { + list: Array + meta: Meta +} + +type ProductListParams = PageQuery /** * @summary 상목목록 API */ -export const getProductList = async () => { - const response = await fetch('/products') +export const getProductList = async (query: ProductListParams): Promise => { + const response = await fetch(`/products` + `?${convertQueryToString(query)}`) if (!response.ok) { throw new Error('failed to getProductList') From 36f6271af61528e02625725d7084d6387533cc3f Mon Sep 17 00:00:00 2001 From: saewookkang Date: Sat, 20 Apr 2024 23:14:07 +0900 Subject: [PATCH 18/39] =?UTF-8?q?feat:=20ScrollRestoration=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/routes/__root.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/routes/__root.tsx b/src/routes/__root.tsx index d2e4d9825..bf1e80e06 100644 --- a/src/routes/__root.tsx +++ b/src/routes/__root.tsx @@ -1,5 +1,5 @@ import { QueryClient } from '@tanstack/react-query' -import { createRootRouteWithContext, Outlet } from '@tanstack/react-router' +import { createRootRouteWithContext, Outlet, ScrollRestoration } from '@tanstack/react-router' import { TanStackRouterDevtools } from '@tanstack/router-devtools' import { Gnb } from './-common/components/Gnb/Gnb' @@ -11,6 +11,7 @@ export const Route = createRootRouteWithContext<{ <> + ), From 47c165b8b5ac181dfb04f4530b262bf1b2c4d7d8 Mon Sep 17 00:00:00 2001 From: saewookkang Date: Sat, 20 Apr 2024 23:14:37 +0900 Subject: [PATCH 19/39] =?UTF-8?q?feat(ProductList.tsx):=20staleTime=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/routes/-common/components/ProductList/ProductList.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/routes/-common/components/ProductList/ProductList.tsx b/src/routes/-common/components/ProductList/ProductList.tsx index 64e31ddf6..127c4f9c7 100644 --- a/src/routes/-common/components/ProductList/ProductList.tsx +++ b/src/routes/-common/components/ProductList/ProductList.tsx @@ -27,6 +27,7 @@ export const ProductList = () => { }, initialPageParam: 0, getNextPageParam: (res: ProductListResponse) => res.meta.next_page, + staleTime: 1000 * 60 * 3, }) useEffect(() => { From b1d58683292d89d687a815ccb429491f0928c4d4 Mon Sep 17 00:00:00 2001 From: saewookkang Date: Sat, 20 Apr 2024 23:19:42 +0900 Subject: [PATCH 20/39] =?UTF-8?q?chore(package.json):=20=EB=B2=84=EA=B7=B8?= =?UTF-8?q?=EB=A1=9C=EC=9D=B8=ED=95=9C=20tantack=20router=20=EC=97=85?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- yarn.lock | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index a1174733a..f6537bbeb 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "dependencies": { "@tanstack/react-query": "^5.29.0", "@tanstack/react-query-devtools": "^5.29.0", - "@tanstack/react-router": "^1.26.18", + "@tanstack/react-router": "^1.29.2", "@tanstack/router-devtools": "^1.26.18", "@tanstack/router-vite-plugin": "^1.26.16", "react": "^18.2.0", diff --git a/yarn.lock b/yarn.lock index 9d3ed7d35..abcfba58e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -818,6 +818,11 @@ resolved "https://registry.yarnpkg.com/@tanstack/history/-/history-1.26.10.tgz#fa67fd8a3e1a93ad626860afc3d6b5073b8be480" integrity sha512-fHx8RQ3liEDhueIemUggBGmqYnK6vOxtxCduolW7r6ExBEQVwKdLEcaUobxp6BxcXLQ7z/qhXAptlOlYi4FFXg== +"@tanstack/history@1.28.9": + version "1.28.9" + resolved "https://registry.yarnpkg.com/@tanstack/history/-/history-1.28.9.tgz#487d4414c242d1fe5eacdff109fa25f08da81e11" + integrity sha512-WgTFJhHaZnGZPyt0H11xFhGGDj1MtA1mrUmdAjB/nhVpmsAYXsSB5O+hkF9N66u7MjbNb405wTb9diBsztvI5w== + "@tanstack/query-core@5.29.0": version "5.29.0" resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-5.29.0.tgz#d0b3d12c07d5a47f42ab0c1ed4f317106f3d4b20" @@ -842,7 +847,7 @@ dependencies: "@tanstack/query-core" "5.29.0" -"@tanstack/react-router@1.27.0", "@tanstack/react-router@^1.26.18": +"@tanstack/react-router@1.27.0": version "1.27.0" resolved "https://registry.yarnpkg.com/@tanstack/react-router/-/react-router-1.27.0.tgz#8fbfd9ad6d901623f4ed37edd57b930f8a7be64e" integrity sha512-tBFGdB7o2z0BIT9fsmsF0I9SrLya86HV0xVdPSUWcwFOVUYy8UtDmVw9rBb0Rze0oW5keNgvECT+kYhD6e1vCg== @@ -852,6 +857,16 @@ tiny-invariant "^1.3.1" tiny-warning "^1.0.3" +"@tanstack/react-router@^1.29.2": + version "1.29.2" + resolved "https://registry.yarnpkg.com/@tanstack/react-router/-/react-router-1.29.2.tgz#49a3a5cfad3bd43fc62631f89016b931abdcab35" + integrity sha512-rSSLyI+AaVg79qeeH5fH6KA8ZQkckinH9mFdLrGUhA4wX2B7Az7eloepha2TqvsFJon0HgeV7heMqPkq9nyAeg== + dependencies: + "@tanstack/history" "1.28.9" + "@tanstack/react-store" "^0.2.1" + tiny-invariant "^1.3.1" + tiny-warning "^1.0.3" + "@tanstack/react-store@^0.2.1": version "0.2.1" resolved "https://registry.yarnpkg.com/@tanstack/react-store/-/react-store-0.2.1.tgz#c1a04c85d403d842e56c6d0709211f013bdd1021" From 368be9de3e19a31752754c3bfe89486cc5d62c12 Mon Sep 17 00:00:00 2001 From: saewookkang Date: Sat, 20 Apr 2024 23:20:06 +0900 Subject: [PATCH 21/39] chore(package.json): add zod --- package.json | 3 ++- yarn.lock | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index f6537bbeb..3208780c4 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,8 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-intersection-observer": "^9.8.2", - "typescript-eslint": "^7.0.2" + "typescript-eslint": "^7.0.2", + "zod": "^3.22.5" }, "devDependencies": { "@types/node": "^20.11.20", diff --git a/yarn.lock b/yarn.lock index abcfba58e..aba36b83c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3410,3 +3410,8 @@ zod@^3.22.4: version "3.22.4" resolved "https://registry.yarnpkg.com/zod/-/zod-3.22.4.tgz#f31c3a9386f61b1f228af56faa9255e845cf3fff" integrity sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg== + +zod@^3.22.5: + version "3.22.5" + resolved "https://registry.yarnpkg.com/zod/-/zod-3.22.5.tgz#b9b09db03f6700b0d0b75bf0dbf0c5fc46155220" + integrity sha512-HqnGsCdVZ2xc0qWPLdO25WnseXThh0kEYKIdV5F/hTHO75hNZFp8thxSeHhiPrHZKrFTo1SOgkAj9po5bexZlw== From 14c2149af202b9f9fcbbe68b14d8fedb7d41bbe8 Mon Sep 17 00:00:00 2001 From: saewookkang Date: Sat, 20 Apr 2024 23:22:36 +0900 Subject: [PATCH 22/39] =?UTF-8?q?fix('/'):=20=EC=8A=A4=ED=81=AC=EB=A1=A4?= =?UTF-8?q?=20=EB=B3=B5=EA=B5=AC=20=EC=95=88=EB=90=98=EB=8A=94=20=ED=98=84?= =?UTF-8?q?=EC=83=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/routes/index.lazy.tsx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/routes/index.lazy.tsx b/src/routes/index.lazy.tsx index e74ab26c8..ab2b7e68e 100644 --- a/src/routes/index.lazy.tsx +++ b/src/routes/index.lazy.tsx @@ -1,9 +1,15 @@ -import { createLazyFileRoute } from '@tanstack/react-router' +import { createFileRoute } from '@tanstack/react-router' +import { z } from 'zod' import { ProductList } from './-common/components/ProductList/ProductList' -export const Route = createLazyFileRoute('/')({ +const homeSearchSchema = z.object({ + page: z.number().catch(1), +}) + +export const Route = createFileRoute('/')({ component: Home, + validateSearch: homeSearchSchema.parse, }) function Home() { From 05e42760c80d712001864ab0722789fc865b7a42 Mon Sep 17 00:00:00 2001 From: saewookkang Date: Sun, 21 Apr 2024 10:38:44 +0900 Subject: [PATCH 23/39] =?UTF-8?q?chore(mocks/products):=20=ED=8F=B4?= =?UTF-8?q?=EB=8D=94=20=EA=B7=9C=EC=B9=99=20=EB=B3=80=EA=B2=BD=EC=97=90=20?= =?UTF-8?q?=EB=94=B0=EB=A5=B8=20=ED=8C=8C=EC=9D=BC=20=EA=B5=AC=EC=A1=B0=20?= =?UTF-8?q?=EB=B0=8F=20readme.md=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/mocks/handlers.ts | 2 +- src/mocks/products/index.handlers.ts | 4 ++++ .../products/{products.json => products.db.json} | 0 src/mocks/products/products.handlers.ts | 14 ++++---------- src/mocks/products/products.repository.ts | 6 ++++++ src/mocks/readme.md | 15 ++++++++++----- 6 files changed, 25 insertions(+), 16 deletions(-) create mode 100644 src/mocks/products/index.handlers.ts rename src/mocks/products/{products.json => products.db.json} (100%) create mode 100644 src/mocks/products/products.repository.ts diff --git a/src/mocks/handlers.ts b/src/mocks/handlers.ts index ebaa4de12..dcb0d20d7 100644 --- a/src/mocks/handlers.ts +++ b/src/mocks/handlers.ts @@ -1,3 +1,3 @@ -import { productsHandlers } from './products/products.handlers' +import { productsHandlers } from './products/index.handlers' export const handlers = [...productsHandlers] diff --git a/src/mocks/products/index.handlers.ts b/src/mocks/products/index.handlers.ts new file mode 100644 index 000000000..3f6c48b0b --- /dev/null +++ b/src/mocks/products/index.handlers.ts @@ -0,0 +1,4 @@ +import { cartHandlers } from './cart.handlers' +import { productsHandlers as productsListHandlers } from './products.handlers' + +export const productsHandlers = [...cartHandlers, ...productsListHandlers] diff --git a/src/mocks/products/products.json b/src/mocks/products/products.db.json similarity index 100% rename from src/mocks/products/products.json rename to src/mocks/products/products.db.json diff --git a/src/mocks/products/products.handlers.ts b/src/mocks/products/products.handlers.ts index 6f1548f4f..a63427521 100644 --- a/src/mocks/products/products.handlers.ts +++ b/src/mocks/products/products.handlers.ts @@ -1,13 +1,7 @@ import { delay, http, HttpResponse } from 'msw' -import type { ProductListResponse } from '@/routes/-product-list.api' - import { PAGE_META } from '../const' -import products from './products.json' - -const allProducts = new Map( - products.map((product) => [product.id, product]) -) +import { productsRepository } from './products.repository' export const productsHandlers = [ http.get('/products', async ({ request }) => { @@ -21,11 +15,11 @@ export const productsHandlers = [ const start = page * perCount const end = start + perCount - const maxPage = Math.ceil(allProducts.size / perCount) + const maxPage = Math.ceil(productsRepository.size / perCount) const nextPage = page < maxPage ? page + 1 : undefined return HttpResponse.json({ - list: Array.from(allProducts.values()).slice(start, end), + list: Array.from(productsRepository.values()).slice(start, end), meta: { next_page: nextPage }, }) }), @@ -34,6 +28,6 @@ export const productsHandlers = [ const { id } = params - return HttpResponse.json(allProducts.get(Number(id))) + return HttpResponse.json(productsRepository.get(Number(id))) }), ] diff --git a/src/mocks/products/products.repository.ts b/src/mocks/products/products.repository.ts new file mode 100644 index 000000000..3575e9f80 --- /dev/null +++ b/src/mocks/products/products.repository.ts @@ -0,0 +1,6 @@ +import { ProductListResponse } from '@/routes/-product-list.api' + +import products from './products.db.json' +export const productsRepository = new Map( + products.map((product) => [product.id, product]) +) diff --git a/src/mocks/readme.md b/src/mocks/readme.md index d1481a15c..352e31879 100644 --- a/src/mocks/readme.md +++ b/src/mocks/readme.md @@ -3,15 +3,20 @@ - mocking 관련 폴더 - 핸들러는 도메인 단위로 폴더를 만든다. - 핸들러의 파일명 규칙은 `[domain name].handlers.ts`로 작성한다. -- 작성한 핸들러는 `handlers.ts`에 추가한다. +- 하나의 도메인에 여러개의 핸들러를 가질 수 있다. (1:N 관계이다.) +- index.handlers에 핸들러를 등록하고 해당 핸들러를 `mocks/handlers.ts`에 추가한다. ## 폴더 구조 ``` 📦mocks - ┣ 📂products # 도메인 단위 - ┃ ┗ 📜products.handlers.ts # 핸들러 - ┣ 📜browser.ts # 진입점 - ┣ 📜handlers.ts # 핸들러 등록 + ┣ 📂products # 도메인 + ┣ ┣ 📜products.db.json # DB + ┣ ┣ 📜products.repository.ts # DB의 CRUD를 담당한다. + ┣ ┣ 📜carts.handlers.ts # 도메인과 핸들러는 1:N 관계이다. + ┣ ┣ 📜products.handlers.ts # 핸들러 + ┃ ┗ 📜index.handlers.ts # 도메인에 작성한 모든 핸들러들을 등록한다. + ┣ 📜browser.ts # 진입점 + ┣ 📜handlers.ts # 핸들러 등록 ┗ 📜readme.md ``` From 28505b06fdacfaef023fc80397c084201e788da7 Mon Sep 17 00:00:00 2001 From: saewookkang Date: Sun, 21 Apr 2024 11:51:20 +0900 Subject: [PATCH 24/39] =?UTF-8?q?feat(cart.handleres.ts):=20=EC=9E=A5?= =?UTF-8?q?=EB=B0=94=EA=B5=AC=EB=8B=88=20=EC=83=81=ED=92=88=20api=20?= =?UTF-8?q?=EB=AA=A8=ED=82=B9=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/mocks/products/cart.handlers.ts | 31 +++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 src/mocks/products/cart.handlers.ts diff --git a/src/mocks/products/cart.handlers.ts b/src/mocks/products/cart.handlers.ts new file mode 100644 index 000000000..cc0e902e6 --- /dev/null +++ b/src/mocks/products/cart.handlers.ts @@ -0,0 +1,31 @@ +import { delay, http, HttpResponse } from 'msw' + +import { Product } from '@/routes/-product-list.api' + +import { productsRepository } from './products.repository' + +export const cartHandlers = [ + http.get('/carts', async ({ cookies }) => { + const cartList = JSON.parse(decodeURIComponent(cookies.CARTS)) as Array<{ + id: number + count: number + }> // TODO: zod로 검증할 것 + + // id에 해당하는 상품 데이터 내려주기 + const res: Array = [] + + cartList.forEach((product) => { + const foundProduct = productsRepository.get(product.id) + + if (foundProduct) { + res.push({ ...foundProduct, count: product.count }) + } + }) + + await delay(300) + + return HttpResponse.json({ + list: res, + }) + }), +] From f28e93a3dc79ebfd98a806cbd82b3c1e668dd972 Mon Sep 17 00:00:00 2001 From: saewookkang Date: Sun, 21 Apr 2024 12:07:33 +0900 Subject: [PATCH 25/39] =?UTF-8?q?=20feat(getCartList.ts):=20=EC=B9=B4?= =?UTF-8?q?=ED=8A=B8=EB=AA=A9=EB=A1=9D=20api=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/routes/cart/-cart-list.api.ts | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/routes/cart/-cart-list.api.ts diff --git a/src/routes/cart/-cart-list.api.ts b/src/routes/cart/-cart-list.api.ts new file mode 100644 index 000000000..bab91d118 --- /dev/null +++ b/src/routes/cart/-cart-list.api.ts @@ -0,0 +1,23 @@ +export interface Product { + id: number + name: string + price: number + imageUrl: string +} + +export type CartListResponse = { + list: Array +} + +/** + * @summary 카트목록 API + */ +export const getCartList = async (): Promise => { + const response = await fetch('/carts') + + if (!response.ok) { + throw new Error('failed to getProductList') + } + + return response.json() +} From f91179043f36d6163d64209a8c71fb645ac12f4c Mon Sep 17 00:00:00 2001 From: saewookkang Date: Sun, 21 Apr 2024 12:22:29 +0900 Subject: [PATCH 26/39] =?UTF-8?q?feat:=20=EC=83=81=ED=92=88=EC=97=90=20?= =?UTF-8?q?=EB=8C=80=ED=95=9C=20=EA=B0=AF=EC=88=98=20=EC=A6=9D=EA=B0=80,?= =?UTF-8?q?=20=EA=B0=90=EC=86=8C=20=EC=82=AD=EC=A0=9C=20=EC=9E=91=EC=97=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/routes/-common/store/cartListStore.ts | 38 +++++++ src/routes/cart/index.lazy.tsx | 130 +++++++++++++++++++++- 2 files changed, 167 insertions(+), 1 deletion(-) diff --git a/src/routes/-common/store/cartListStore.ts b/src/routes/-common/store/cartListStore.ts index 85d639b62..0c5e94f7a 100644 --- a/src/routes/-common/store/cartListStore.ts +++ b/src/routes/-common/store/cartListStore.ts @@ -40,8 +40,46 @@ export const useCartListStore = () => { : setValue((prev) => ({ ...prev, cartList: [...prev.cartList, { id, count: 1 }] })) } + const increaseCount = (id: CartItem['id']) => { + const MAX_COUNT = 20 + + setValue((prev) => ({ + ...prev, + cartList: prev.cartList.map((product) => { + return product.id === id + ? { ...product, count: product.count < MAX_COUNT ? product.count + 1 : MAX_COUNT } + : product + }), + })) + } + + const decreaseCount = (id: CartItem['id']) => { + const MIN_COUNT = 1 + + setValue((prev) => ({ + ...prev, + cartList: prev.cartList + .map((product) => { + return product.id === id + ? { ...product, count: product.count > MIN_COUNT ? product.count - 1 : MIN_COUNT } + : product + }) + .filter((product) => product.count > 0), + })) + } + + const deleteProduct = (id: CartItem['id']) => { + setValue((prev) => ({ + ...prev, + cartList: prev.cartList.filter((product) => product.id !== id), + })) + } + return { cartList: value.cartList, saveProduct, + increaseCount, + decreaseCount, + deleteProduct, } } diff --git a/src/routes/cart/index.lazy.tsx b/src/routes/cart/index.lazy.tsx index 41a597e5a..f2f789cba 100644 --- a/src/routes/cart/index.lazy.tsx +++ b/src/routes/cart/index.lazy.tsx @@ -1,4 +1,9 @@ +import { useQuery } from '@tanstack/react-query' import { createLazyFileRoute } from '@tanstack/react-router' +import { Fragment } from 'react' + +import { useCartListStore } from '../-common/store/cartListStore' +import { getCartList } from './-cart-list.api' export const Route = createLazyFileRoute('/cart/')({ component: Cart, @@ -8,5 +13,128 @@ export const Route = createLazyFileRoute('/cart/')({ * @summary 장바구니 페이지 */ function Cart() { - return
Hello /cart/!
+ const { cartList, increaseCount, decreaseCount, deleteProduct } = useCartListStore() + + const { data, isLoading } = useQuery({ + queryKey: ['carts', cartList], + queryFn: getCartList, + select: (response) => { + const parsed = response.list.map((product) => { + return { + ...product, + totalPrice: `${(product.price * product.count).toLocaleString()}원`, + } + }) + + return { + list: parsed, + totalCount: response.list.reduce((acc, cur) => acc + cur.count, 0), + } + }, + }) + + if (isLoading) return <>loading.. + + return ( +
+
+

장바구니

+
+
+ +
+
+
+
+ {}} + /> + +
+ +
+

든든배송 상품({data?.totalCount}개)

+
+ {data?.list.map((product) => ( + +
+
+ {}} + /> + {product.name} + {product.name} +
+ +
+ + +
+ {}} + /> +
+ + +
+
+ {product.totalPrice} +
+
+
+
+ ))} +
+ +
+
+

결제예상금액

+
+
+
+
+ 결제예상금액 + 21,800원 +
+
+ +
+
+
+
+
+ ) } From b20af40a4a2b7a4aeba4e3c284d0c32810787be1 Mon Sep 17 00:00:00 2001 From: saewookkang Date: Sun, 21 Apr 2024 19:02:31 +0900 Subject: [PATCH 27/39] =?UTF-8?q?fix(mocks/browser.ts):=20msw=20=EB=AA=A8?= =?UTF-8?q?=ED=82=B9=20=EA=B2=BD=EA=B3=A0=20=EB=AC=B8=EA=B5=AC=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/mocks/browser.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/mocks/browser.ts b/src/mocks/browser.ts index d3824e657..9f849ac01 100644 --- a/src/mocks/browser.ts +++ b/src/mocks/browser.ts @@ -1,5 +1,13 @@ +import { http } from 'msw' import { setupWorker } from 'msw/browser' import { handlers } from './handlers' -export const worker = setupWorker(...handlers) +const imageExtensionRegex = /\.(png|jpe?g|gif|svg)$/i +const sourceCodeExtensionRegex = /\.(ts|tsx|js|jsx)$/i + +export const worker = setupWorker( + ...handlers, + http.get(imageExtensionRegex, (req) => {}), + http.get(sourceCodeExtensionRegex, (req) => {}) +) From 6a65c029b126bc3e2792beba34719dd7d94b3428 Mon Sep 17 00:00:00 2001 From: saewookkang Date: Sun, 21 Apr 2024 20:03:58 +0900 Subject: [PATCH 28/39] =?UTF-8?q?feat=20&=20design(/cart):=20=EC=9E=A5?= =?UTF-8?q?=EB=B0=94=EA=B5=AC=EB=8B=88=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hooks/useCookieRepository/service.ts | 4 +- .../components/ProductCard/ProductCard.tsx | 4 +- src/routes/-common/components/gnb/Gnb.tsx | 2 +- src/routes/-common/store/cartListStore.ts | 85 ---------- .../store/cartListStore/cartListStore.ts | 147 ++++++++++++++++++ .../-common/store/cartListStore/const.ts | 4 + src/routes/cart/-useCartVM.ts | 95 +++++++++++ src/routes/cart/index.lazy.tsx | 78 +++++----- src/routes/products/$id/index.lazy.tsx | 6 +- 9 files changed, 294 insertions(+), 131 deletions(-) delete mode 100644 src/routes/-common/store/cartListStore.ts create mode 100644 src/routes/-common/store/cartListStore/cartListStore.ts create mode 100644 src/routes/-common/store/cartListStore/const.ts create mode 100644 src/routes/cart/-useCartVM.ts diff --git a/src/common/hooks/useCookieRepository/service.ts b/src/common/hooks/useCookieRepository/service.ts index c635b544d..08d1e7ff3 100644 --- a/src/common/hooks/useCookieRepository/service.ts +++ b/src/common/hooks/useCookieRepository/service.ts @@ -17,12 +17,12 @@ export function getCookie(name: T) { * @summary 쿠키를 저장한다. * @reference https://developer.mozilla.org/en-US/docs/Web/API/Document/cookie */ -export function setCookie( +export function setCookie( name: Key, value: Value, options: CookieOptions ) { - const cookieString = `${encodeURIComponent(name)}=${encodeURIComponent(value)}` + const cookieString = `${encodeURIComponent(name)}=${encodeURIComponent(JSON.stringify(value))}` // eslint-disable-next-line no-shadow const cookieOptions = Object.entries(options).reduce((prev, [key, value]) => { diff --git a/src/routes/-common/components/ProductCard/ProductCard.tsx b/src/routes/-common/components/ProductCard/ProductCard.tsx index 91dd3c0a1..cc86fabe1 100644 --- a/src/routes/-common/components/ProductCard/ProductCard.tsx +++ b/src/routes/-common/components/ProductCard/ProductCard.tsx @@ -2,7 +2,7 @@ import { Link } from '@tanstack/react-router' import type { ProductListResponse } from '@/routes/-product-list.api' -import { useCartListStore } from '../../store/cartListStore' +import { useCartListStore } from '../../store/cartListStore/cartListStore' type ProductCardProps = ProductListResponse['list'][number] @@ -24,7 +24,7 @@ export const ProductCard = (props: ProductCardProps) => { onClick={(e) => { e.preventDefault() - cartListStore.saveProduct(props.id) + cartListStore.actions.saveProduct(props.id) }} > 장바구니 diff --git a/src/routes/-common/components/gnb/Gnb.tsx b/src/routes/-common/components/gnb/Gnb.tsx index f4355984a..cb4bb6fa7 100644 --- a/src/routes/-common/components/gnb/Gnb.tsx +++ b/src/routes/-common/components/gnb/Gnb.tsx @@ -1,6 +1,6 @@ import { Link } from '@tanstack/react-router' -import { useCartListStore } from '../../store/cartListStore' +import { useCartListStore } from '../../store/cartListStore/cartListStore' /** * @summary 공통으로 사용하는 네비게이션 바 diff --git a/src/routes/-common/store/cartListStore.ts b/src/routes/-common/store/cartListStore.ts deleted file mode 100644 index 0c5e94f7a..000000000 --- a/src/routes/-common/store/cartListStore.ts +++ /dev/null @@ -1,85 +0,0 @@ -import { useEffect } from 'react' - -import { getCookie, setCookie } from '@/common/hooks/useCookieRepository/service' -import { createStore } from '@/common/module/store/store' -import { useStore } from '@/common/module/store/useStore' -import type { Product } from '@/routes/-product-list.api' - -const CARTS_KEY = 'CARTS' - -const initializeCookie = getCookie(CARTS_KEY) - -interface CartItem extends Pick { - count: number -} - -const cartListStore = createStore<{ - cartList: Array -}>({ - cartList: initializeCookie ? JSON.parse(initializeCookie) : [], -}) - -export const useCartListStore = () => { - const [value, setValue] = useStore(cartListStore) - - useEffect(() => { - setCookie(CARTS_KEY, JSON.stringify(value.cartList), {}) - }, [value]) - - const saveProduct = (id: CartItem['id']) => { - const foundProduct = value.cartList.find((product) => product.id === id) - - foundProduct - ? setValue((prev) => ({ - ...prev, - cartList: [ - ...prev.cartList.filter((product) => product.id !== id), - { id, count: foundProduct.count + 1 }, - ], - })) - : setValue((prev) => ({ ...prev, cartList: [...prev.cartList, { id, count: 1 }] })) - } - - const increaseCount = (id: CartItem['id']) => { - const MAX_COUNT = 20 - - setValue((prev) => ({ - ...prev, - cartList: prev.cartList.map((product) => { - return product.id === id - ? { ...product, count: product.count < MAX_COUNT ? product.count + 1 : MAX_COUNT } - : product - }), - })) - } - - const decreaseCount = (id: CartItem['id']) => { - const MIN_COUNT = 1 - - setValue((prev) => ({ - ...prev, - cartList: prev.cartList - .map((product) => { - return product.id === id - ? { ...product, count: product.count > MIN_COUNT ? product.count - 1 : MIN_COUNT } - : product - }) - .filter((product) => product.count > 0), - })) - } - - const deleteProduct = (id: CartItem['id']) => { - setValue((prev) => ({ - ...prev, - cartList: prev.cartList.filter((product) => product.id !== id), - })) - } - - return { - cartList: value.cartList, - saveProduct, - increaseCount, - decreaseCount, - deleteProduct, - } -} diff --git a/src/routes/-common/store/cartListStore/cartListStore.ts b/src/routes/-common/store/cartListStore/cartListStore.ts new file mode 100644 index 000000000..2f0a82130 --- /dev/null +++ b/src/routes/-common/store/cartListStore/cartListStore.ts @@ -0,0 +1,147 @@ +import { ChangeEvent, useEffect } from 'react' + +import { getCookie, setCookie } from '@/common/hooks/useCookieRepository/service' +import { createStore } from '@/common/module/store/store' +import { useStore } from '@/common/module/store/useStore' +import type { Product } from '@/routes/-product-list.api' + +import { CART_COOKIE_KEY, CART_MAX_COUNT, CART_MIN_COUNT } from './const' + +const initializeCookie = getCookie(CART_COOKIE_KEY) + +interface CartItem extends Pick { + count: number +} + +const cartListStore = createStore<{ + cartList: Array +}>({ + cartList: initializeCookie ? JSON.parse(initializeCookie) : [], +}) + +export const useCartListStore = () => { + const [value, setValue] = useStore(cartListStore) + + useEffect(() => { + setCookie(CART_COOKIE_KEY, value.cartList, {}) + }, [value]) + + const saveProduct = (id: CartItem['id']) => { + const foundProduct = value.cartList.find((product) => product.id === id) + + foundProduct + ? setValue((prev) => ({ + ...prev, + cartList: [ + ...prev.cartList.filter((product) => product.id !== id), + { id, count: foundProduct.count + 1 }, + ], + })) + : setValue((prev) => ({ ...prev, cartList: [...prev.cartList, { id, count: 1 }] })) + } + + const increaseCount = (id: CartItem['id']) => { + setValue((prev) => ({ + ...prev, + cartList: prev.cartList.map((product) => { + return product.id === id + ? { + ...product, + // count: product.count < CART_MAX_COUNT ? product.count + 1 : CART_MAX_COUNT, + count: Math.min(product.count + 1, CART_MAX_COUNT), + } + : product + }), + })) + } + + const decreaseCount = (id: CartItem['id']) => { + setValue((prev) => ({ + ...prev, + cartList: prev.cartList + .map((product) => { + return product.id === id + ? { + ...product, + // count: product.count > CART_MIN_COUNT ? product.count - 1 : CART_MIN_COUNT, + count: Math.max(product.count - 1, CART_MIN_COUNT), + } + : product + }) + .filter((product) => product.count > 0), + })) + } + + const deleteProduct = (id: CartItem['id']) => { + setValue((prev) => ({ + ...prev, + cartList: prev.cartList.filter((product) => product.id !== id), + })) + } + + const changeProductCount = (e: ChangeEvent, product: CartItem) => { + if (e.target.valueAsNumber > CART_MAX_COUNT) { + e.target.value = String(CART_MAX_COUNT) + + setValue((prev) => ({ + ...prev, + cartList: prev.cartList.map((item) => { + return item.id === product.id + ? { + ...product, + count: CART_MAX_COUNT, + } + : product + }), + })) + + return + } + + if (e.target.valueAsNumber < CART_MIN_COUNT) { + e.target.value = String(CART_MIN_COUNT) + + setValue((prev) => ({ + ...prev, + cartList: prev.cartList.map((item) => { + return item.id === product.id + ? { + ...product, + count: CART_MIN_COUNT, + } + : product + }), + })) + + return + } + + setValue((prev) => ({ + ...prev, + cartList: prev.cartList.map((item) => { + return item.id === product.id + ? { + ...product, + count: e.target.valueAsNumber, + } + : product + }), + })) + } + + const deleteAllProducts = () => { + setValue((prev) => ({ ...prev, cartList: [] })) + } + + return { + cartList: value.cartList, + actions: { + saveProduct, + increaseCount, + decreaseCount, + deleteProduct, + changeProductCount, + deleteAllProducts, + }, + } +} diff --git a/src/routes/-common/store/cartListStore/const.ts b/src/routes/-common/store/cartListStore/const.ts new file mode 100644 index 000000000..87b7b0c4b --- /dev/null +++ b/src/routes/-common/store/cartListStore/const.ts @@ -0,0 +1,4 @@ +export const CART_MIN_COUNT = 1 +export const CART_MAX_COUNT = 20 + +export const CART_COOKIE_KEY = 'CARTS' diff --git a/src/routes/cart/-useCartVM.ts b/src/routes/cart/-useCartVM.ts new file mode 100644 index 000000000..976f58986 --- /dev/null +++ b/src/routes/cart/-useCartVM.ts @@ -0,0 +1,95 @@ +import { useQuery } from '@tanstack/react-query' +import { useEffect, useState } from 'react' + +import { useCartListStore } from '../-common/store/cartListStore/cartListStore' +import { CartListResponse, getCartList } from './-cart-list.api' + +/** + * @summary 카트 페이지의 view model + */ +export const useCartVM = () => { + const { cartList, actions } = useCartListStore() + + const cartsQuery = useQuery({ + queryKey: ['carts', cartList], + queryFn: getCartList, + select: (response) => { + const parsed = response.list.map((product) => { + return { + ...product, + totalPrice: product.price * product.count, + } + }) + + return { + list: parsed, + hasProduct: parsed.length > 0, + } + }, + }) + + const [selectedProductList, setSelectedProductList] = useState( + () => new Map(cartsQuery.data?.list.map((product) => [product.id, true])) + ) + + useEffect(() => { + setSelectedProductList(() => { + return new Map(cartsQuery.data?.list.map((product) => [product.id, true])) + }) + }, [cartsQuery.data]) + + const toggleProduct = (id: CartListResponse['list'][number]['id']) => { + setSelectedProductList((prev) => { + const newMap = new Map(prev) + + if (newMap.get(id)) { + newMap.delete(id) + + return newMap + } + + newMap.set(id, true) + + return newMap + }) + } + + const isCheckedProduct = (id: CartListResponse['list'][number]['id']) => { + return selectedProductList.get(id) + } + + const totalSelectedCount = selectedProductList.size + const isAllProductChecked = selectedProductList.size === cartsQuery.data?.list.length + + const toggleAll = () => { + if (isAllProductChecked) { + setSelectedProductList(() => new Map()) + + return + } + + setSelectedProductList(() => { + return new Map(cartsQuery.data?.list.map((product) => [product.id, true])) + }) + } + + const paymentTotal = cartsQuery.data?.list + .filter((product) => selectedProductList.get(product.id)) + .reduce((acc, product) => acc + product.totalPrice, 0) + .toLocaleString() + + return { + cartsQuery, + computed: { + isAllProductChecked, + totalSelectedCount, + paymentTotal, + }, + actions: { + toggleProduct, + toggleAll, + isCheckedProduct, + ...actions, + }, + } +} diff --git a/src/routes/cart/index.lazy.tsx b/src/routes/cart/index.lazy.tsx index f2f789cba..e69004683 100644 --- a/src/routes/cart/index.lazy.tsx +++ b/src/routes/cart/index.lazy.tsx @@ -1,9 +1,7 @@ -import { useQuery } from '@tanstack/react-query' import { createLazyFileRoute } from '@tanstack/react-router' import { Fragment } from 'react' -import { useCartListStore } from '../-common/store/cartListStore' -import { getCartList } from './-cart-list.api' +import { useCartVM } from './-useCartVM' export const Route = createLazyFileRoute('/cart/')({ component: Cart, @@ -13,27 +11,9 @@ export const Route = createLazyFileRoute('/cart/')({ * @summary 장바구니 페이지 */ function Cart() { - const { cartList, increaseCount, decreaseCount, deleteProduct } = useCartListStore() + const { actions, cartsQuery, computed } = useCartVM() - const { data, isLoading } = useQuery({ - queryKey: ['carts', cartList], - queryFn: getCartList, - select: (response) => { - const parsed = response.list.map((product) => { - return { - ...product, - totalPrice: `${(product.price * product.count).toLocaleString()}원`, - } - }) - - return { - list: parsed, - totalCount: response.list.reduce((acc, cur) => acc + cur.count, 0), - } - }, - }) - - if (isLoading) return <>loading.. + if (cartsQuery.isLoading) return <>loading.. return (
@@ -50,18 +30,30 @@ function Cart() { className="checkbox" name="checkbox" type="checkbox" - checked={true} - onChange={() => {}} + checked={computed.isAllProductChecked} + onChange={actions.toggleAll} />
- +
-

든든배송 상품({data?.totalCount}개)

+
- {data?.list.map((product) => ( + {cartsQuery.data?.list.map((product) => (
@@ -69,8 +61,10 @@ function Cart() { className="checkbox" name="checkbox" type="checkbox" - checked={true} - onChange={() => {}} + checked={actions.isCheckedProduct(product.id) ?? false} + onChange={() => { + actions.toggleProduct(product.id) + }} /> {product.name} {product.name} @@ -81,7 +75,7 @@ function Cart() { className="pointer" onClick={() => { if (confirm('상품을 삭제하시겠습니까?')) { - deleteProduct(product.id) + actions.deleteProduct(product.id) } }} style={{ alignSelf: 'flex-end' }} @@ -91,27 +85,29 @@ function Cart() {
{}} + // value={product.count} + defaultValue={product.count} + onBlur={(e) => actions.changeProductCount(e, product)} />
- {product.totalPrice} + {product.totalPrice.toLocaleString()}원

@@ -127,10 +123,16 @@ function Cart() {
결제예상금액 - 21,800원 + {computed.paymentTotal}원
- +
diff --git a/src/routes/products/$id/index.lazy.tsx b/src/routes/products/$id/index.lazy.tsx index 059031a4c..39bab7191 100644 --- a/src/routes/products/$id/index.lazy.tsx +++ b/src/routes/products/$id/index.lazy.tsx @@ -2,7 +2,7 @@ import { useQuery } from '@tanstack/react-query' import { createFileRoute } from '@tanstack/react-router' import { SwitchCase } from '@/common/components/SwitchCase/SwitchCase' -import { useCartListStore } from '@/routes/-common/store/cartListStore' +import { useCartListStore } from '@/routes/-common/store/cartListStore/cartListStore' import { Product } from './-common/components/Product/Product' import { ProductSkeleton } from './-common/components/ProductSkeleton/ProductSkeleton' @@ -22,13 +22,13 @@ function ProductDetail() { queryFn: () => getProduct(id), }) - const { saveProduct } = useCartListStore() + const { actions } = useCartListStore() return ( : null, + success: data ? : null, pending: , error:
error
, }} From 14973197ee7df046bff413a36acba94e4edd4a17 Mon Sep 17 00:00:00 2001 From: saewookkang Date: Sun, 21 Apr 2024 22:18:03 +0900 Subject: [PATCH 29/39] =?UTF-8?q?chore:=20loading=EC=8B=9C=20=EC=83=81?= =?UTF-8?q?=EC=9C=84=20UI=20=EB=85=B8=EC=B6=9C=EB=90=A0=20=EC=88=98=20?= =?UTF-8?q?=EC=9E=88=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/routes/cart/index.lazy.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/routes/cart/index.lazy.tsx b/src/routes/cart/index.lazy.tsx index e69004683..6fee09372 100644 --- a/src/routes/cart/index.lazy.tsx +++ b/src/routes/cart/index.lazy.tsx @@ -13,8 +13,6 @@ export const Route = createLazyFileRoute('/cart/')({ function Cart() { const { actions, cartsQuery, computed } = useCartVM() - if (cartsQuery.isLoading) return <>loading.. - return (
From a9b7bd716b982a56541e41fe9abf0f696f1843c3 Mon Sep 17 00:00:00 2001 From: saewookkang Date: Sun, 21 Apr 2024 22:35:05 +0900 Subject: [PATCH 30/39] chore: docs v2 --- docs/assets/highlight.css | 14 ++++++++++++++ docs/assets/navigation.js | 2 +- docs/assets/search.js | 2 +- docs/functions/App.default.html | 2 +- ...rPropsList_RenderPropsList.RenderPropsList.html | 2 +- ...mmon_components_Skeleton_Skeleton.Skeleton.html | 2 +- ...omponents_SwitchCase_SwitchCase.SwitchCase.html | 2 +- ...ooks_useCookieRepository_service.getCookie.html | 3 +++ ...ooks_useCookieRepository_service.setCookie.html | 3 +++ ...ieRepository_useCookieRepository.useCookie.html | 2 ++ .../common_module_store_store.createStore.html | 2 ++ .../common_module_store_useStore.useStore.html | 2 ++ ..._convertQueryToString.convertQueryToString.html | 2 ++ ...common_utils_parseApiStatus.parseApiStatus.html | 2 +- .../routes__common_components_Gnb_Gnb.Gnb.html | 2 +- ...omponents_MoreButton_MoreButton.MoreButton.html | 9 +++++++++ ...onents_ProductCard_ProductCard.ProductCard.html | 2 +- ...onents_ProductList_ProductList.ProductList.html | 2 +- ...rtListStore_cartListStore.useCartListStore.html | 1 + .../routes__product_list_api.getProductList.html | 4 ++-- .../routes_cart__cart_list_api.getCartList.html | 2 ++ .../routes_cart__useCartVM.useCartVM.html | 2 ++ ...ctSkeleton_ProductSkeleton.ProductSkeleton.html | 1 + ..._common_components_Product_Product.Product.html | 1 + ..._products__id__product_item_api.getProduct.html | 2 ++ ...oks_useCookieRepository_type.CookieOptions.html | 14 ++++++++++++++ .../common_module_store_store.Store.html | 4 ++++ .../routes__product_list_api.Product.html | 5 +++++ .../routes_cart__cart_list_api.Product.html | 5 +++++ ...tes_products__id__product_item_api.Product.html | 5 +++++ docs/modules/App.html | 2 +- ...components_RenderPropsList_RenderPropsList.html | 2 +- .../common_components_Skeleton_Skeleton.html | 2 +- .../common_components_SwitchCase_SwitchCase.html | 2 +- .../common_hooks_useCookieRepository_service.html | 3 +++ .../common_hooks_useCookieRepository_type.html | 2 ++ ...ks_useCookieRepository_useCookieRepository.html | 2 ++ docs/modules/common_module_store_store.html | 3 +++ docs/modules/common_module_store_useStore.html | 2 ++ .../modules/common_utils_convertQueryToString.html | 2 ++ docs/modules/common_utils_parseApiStatus.html | 2 +- docs/modules/main.html | 2 +- docs/modules/mocks_browser.html | 2 +- docs/modules/mocks_const.html | 2 ++ docs/modules/mocks_handlers.html | 2 +- docs/modules/mocks_products_cart_handlers.html | 2 ++ docs/modules/mocks_products_index_handlers.html | 2 ++ docs/modules/mocks_products_products_handlers.html | 2 +- .../mocks_products_products_repository.html | 2 ++ docs/modules/routes___root.html | 2 +- ...s__common_components_MoreButton_MoreButton.html | 2 ++ ..._common_components_ProductCard_ProductCard.html | 2 +- ..._common_components_ProductList_ProductList.html | 2 +- ...__common_store_cartListStore_cartListStore.html | 2 ++ .../routes__common_store_cartListStore_const.html | 4 ++++ docs/modules/routes__product_list_api.html | 3 ++- docs/modules/routes_cart__cart_list_api.html | 4 ++++ docs/modules/routes_cart__useCartVM.html | 2 ++ docs/modules/routes_cart_index_lazy.html | 2 +- docs/modules/routes_index_lazy.html | 2 +- docs/modules/routes_orders_index_lazy.html | 2 +- ...components_ProductSkeleton_ProductSkeleton.html | 2 ++ ...cts__id__common_components_Product_Product.html | 2 ++ .../routes_products__id__product_item_api.html | 3 +++ docs/modules/routes_products__id_index_lazy.html | 2 ++ .../routes__product_list_api.ProductList.html | 1 - ...utes__product_list_api.ProductListResponse.html | 1 + ...outes_cart__cart_list_api.CartListResponse.html | 1 + docs/variables/mocks_browser.worker.html | 2 +- docs/variables/mocks_const.PAGE_META.html | 1 + docs/variables/mocks_handlers.handlers.html | 2 +- .../mocks_products_cart_handlers.cartHandlers.html | 1 + ...s_products_index_handlers.productsHandlers.html | 1 + ...roducts_products_handlers.productsHandlers.html | 2 +- ...cts_products_repository.productsRepository.html | 1 + docs/variables/routes___root.Route.html | 2 +- ..._store_cartListStore_const.CART_COOKIE_KEY.html | 1 + ...n_store_cartListStore_const.CART_MAX_COUNT.html | 1 + ...n_store_cartListStore_const.CART_MIN_COUNT.html | 1 + docs/variables/routes_cart_index_lazy.Route.html | 2 +- docs/variables/routes_index_lazy.Route.html | 2 +- docs/variables/routes_orders_index_lazy.Route.html | 2 +- .../routes_products__id_index_lazy.Route.html | 1 + src/mocks/browser.ts | 4 ++-- 84 files changed, 172 insertions(+), 38 deletions(-) create mode 100644 docs/functions/common_hooks_useCookieRepository_service.getCookie.html create mode 100644 docs/functions/common_hooks_useCookieRepository_service.setCookie.html create mode 100644 docs/functions/common_hooks_useCookieRepository_useCookieRepository.useCookie.html create mode 100644 docs/functions/common_module_store_store.createStore.html create mode 100644 docs/functions/common_module_store_useStore.useStore.html create mode 100644 docs/functions/common_utils_convertQueryToString.convertQueryToString.html create mode 100644 docs/functions/routes__common_components_MoreButton_MoreButton.MoreButton.html create mode 100644 docs/functions/routes__common_store_cartListStore_cartListStore.useCartListStore.html create mode 100644 docs/functions/routes_cart__cart_list_api.getCartList.html create mode 100644 docs/functions/routes_cart__useCartVM.useCartVM.html create mode 100644 docs/functions/routes_products__id__common_components_ProductSkeleton_ProductSkeleton.ProductSkeleton.html create mode 100644 docs/functions/routes_products__id__common_components_Product_Product.Product.html create mode 100644 docs/functions/routes_products__id__product_item_api.getProduct.html create mode 100644 docs/interfaces/common_hooks_useCookieRepository_type.CookieOptions.html create mode 100644 docs/interfaces/common_module_store_store.Store.html create mode 100644 docs/interfaces/routes__product_list_api.Product.html create mode 100644 docs/interfaces/routes_cart__cart_list_api.Product.html create mode 100644 docs/interfaces/routes_products__id__product_item_api.Product.html create mode 100644 docs/modules/common_hooks_useCookieRepository_service.html create mode 100644 docs/modules/common_hooks_useCookieRepository_type.html create mode 100644 docs/modules/common_hooks_useCookieRepository_useCookieRepository.html create mode 100644 docs/modules/common_module_store_store.html create mode 100644 docs/modules/common_module_store_useStore.html create mode 100644 docs/modules/common_utils_convertQueryToString.html create mode 100644 docs/modules/mocks_const.html create mode 100644 docs/modules/mocks_products_cart_handlers.html create mode 100644 docs/modules/mocks_products_index_handlers.html create mode 100644 docs/modules/mocks_products_products_repository.html create mode 100644 docs/modules/routes__common_components_MoreButton_MoreButton.html create mode 100644 docs/modules/routes__common_store_cartListStore_cartListStore.html create mode 100644 docs/modules/routes__common_store_cartListStore_const.html create mode 100644 docs/modules/routes_cart__cart_list_api.html create mode 100644 docs/modules/routes_cart__useCartVM.html create mode 100644 docs/modules/routes_products__id__common_components_ProductSkeleton_ProductSkeleton.html create mode 100644 docs/modules/routes_products__id__common_components_Product_Product.html create mode 100644 docs/modules/routes_products__id__product_item_api.html create mode 100644 docs/modules/routes_products__id_index_lazy.html delete mode 100644 docs/types/routes__product_list_api.ProductList.html create mode 100644 docs/types/routes__product_list_api.ProductListResponse.html create mode 100644 docs/types/routes_cart__cart_list_api.CartListResponse.html create mode 100644 docs/variables/mocks_const.PAGE_META.html create mode 100644 docs/variables/mocks_products_cart_handlers.cartHandlers.html create mode 100644 docs/variables/mocks_products_index_handlers.productsHandlers.html create mode 100644 docs/variables/mocks_products_products_repository.productsRepository.html create mode 100644 docs/variables/routes__common_store_cartListStore_const.CART_COOKIE_KEY.html create mode 100644 docs/variables/routes__common_store_cartListStore_const.CART_MAX_COUNT.html create mode 100644 docs/variables/routes__common_store_cartListStore_const.CART_MIN_COUNT.html create mode 100644 docs/variables/routes_products__id_index_lazy.Route.html diff --git a/docs/assets/highlight.css b/docs/assets/highlight.css index 964bdd709..0cf783fd9 100644 --- a/docs/assets/highlight.css +++ b/docs/assets/highlight.css @@ -9,6 +9,10 @@ --dark-hl-3: #CE9178; --light-hl-4: #CD3131; --dark-hl-4: #F44747; + --light-hl-5: #001080; + --dark-hl-5: #9CDCFE; + --light-hl-6: #795E26; + --dark-hl-6: #DCDCAA; --light-code-background: #FFFFFF; --dark-code-background: #1E1E1E; } @@ -19,6 +23,8 @@ --hl-2: var(--light-hl-2); --hl-3: var(--light-hl-3); --hl-4: var(--light-hl-4); + --hl-5: var(--light-hl-5); + --hl-6: var(--light-hl-6); --code-background: var(--light-code-background); } } @@ -28,6 +34,8 @@ --hl-2: var(--dark-hl-2); --hl-3: var(--dark-hl-3); --hl-4: var(--dark-hl-4); + --hl-5: var(--dark-hl-5); + --hl-6: var(--dark-hl-6); --code-background: var(--dark-code-background); } } @@ -37,6 +45,8 @@ --hl-2: var(--light-hl-2); --hl-3: var(--light-hl-3); --hl-4: var(--light-hl-4); + --hl-5: var(--light-hl-5); + --hl-6: var(--light-hl-6); --code-background: var(--light-code-background); } @@ -46,6 +56,8 @@ --hl-2: var(--dark-hl-2); --hl-3: var(--dark-hl-3); --hl-4: var(--dark-hl-4); + --hl-5: var(--dark-hl-5); + --hl-6: var(--dark-hl-6); --code-background: var(--dark-code-background); } @@ -54,4 +66,6 @@ .hl-2 { color: var(--hl-2); } .hl-3 { color: var(--hl-3); } .hl-4 { color: var(--hl-4); } +.hl-5 { color: var(--hl-5); } +.hl-6 { color: var(--hl-6); } pre, code { background: var(--code-background); } diff --git a/docs/assets/navigation.js b/docs/assets/navigation.js index e1e8548c8..d4986d084 100644 --- a/docs/assets/navigation.js +++ b/docs/assets/navigation.js @@ -1 +1 @@ -window.navigationData = "data:application/octet-stream;base64,H4sIAAAAAAAAE61WTW/bIBj+L5yTeOvWTcut6mE77FC1x2pCxKYzCgYEuGk79b8Pf8WYDxtXUWTptXl4Pt4A9uM/oPGLBntwIwTYAIF0aW4qXtQUq8w83JW6ombkSFgB9lcbkJeEFhIzsH88Ty7wE6qpHgmeapZrwllH0Q9Pqb59ff/zvjlT5LyqOANhfjMoOMNMqwjgHrMCyzvJhfpNlM6cez9ZJwdHYuhMce+T+hCVHfuxXnjWiNPFhyOmWHOWDUVK8gF7LpKy+gpzIX2NsJib50R0Xt4ihbOxTMp0RltlWq6AzmyyoFJMtM1nJ6w1oSoTSCp8I8iDRrpW0YAtGE7BSaFi/F6woMKcoBeoQiSw6pqnjlN7Ds+Psa19kPyksAxQNpNgP5zUhROXR5vpGUmCDj5Xh5tSfrmapCwRKyiWgb+qoxrGk3z5ZK6zkS7I65gT0njJtVlWfbFbsjsAx2JVgGHWr8UgM0IuSSCiHVLyWuPYotl2yzlbfHH8ZIfMXH5fOnoI/Q1v4M2V1JgJ9bjZlsk9AedgvOuadYtkkVn1mhzWNLtOyhWUTMkXE40aCOduX/JW/YHc7bvWqtfkjr3c14tGDXjn6rbfH1vaYJEg8cw9EjZIaJAfj6ZfxRxvvH2ffnz/fG0f8X+xTmyepzKdOrs8IJScz6yGdjjtU66ZETrHplQtbPYwzpHUmRnALzuK3l6j3hocbHGwwV3EpMu57DbB6IU9rrLHpfkUVint7JCXNuuzxjyb33/oObC0XQ0AAA==" \ No newline at end of file +window.navigationData = "data:application/octet-stream;base64,H4sIAAAAAAAAE7VZbW/bNhD+L0Y/OtXWtR2Wb54RtEWbJouzoUUxEIrExIJlUaCopNnQ/z5K1AtFHslToiFwQFl3z3PP8e1If/t3Jeh3sTpdbcpytV6VsdjLhyNL65xWkfzy5V4cc/nmkBXp6vTVepXsszzltFidfhucU3ob17kYAW7rIhEZKxRE93oK9fb1j79/rAeIhB2PrFjB+PJlyQpaiMphcEWLlPJLzsrqU1aJyHi2lSk6MgITw8V8RuXBSTvmYz6xNxAji7sDzalgRdQ3MMp726GB0moz+ETaHDCZqechE8l+G1c0GpsoTYO11sTpAni8ykAmF2mrT1e4Z+xQRXVFt7KR0StasioTjD86RnpF+X2WuHPQ4hEAj3SeqCTcUaH8PTkIMw0oVg7Wmp4lmConk55r8Vg+JXGNGypryvOibIMfibJCUH4bJ2iuCY7B/ObtRBI8cOYqBL5DCR78ntR5EOvwXWDaKGlRJZ2oa6Z07+BkqEfSGqn/uNVhCmp3LYC7A9BlN2p7H6exoAa0lUgAWXP0DnyZ1R0+G701dgjMCnwAh1msjq5Flrt2/YQV95SLP2rKH6/ZTvCsuHNKbIEI5ILS6eeyNHvYwiEYvVfGvKKbMtuJWNRVQODUGCXNhe8QZTD4CLvenEzcOAOKkuZbI9bJZE8OrjFww9mD3AUAyMaJdK9ReXhg/KAj3cc8i29sLGU3hfzllVHNFlDVqXDal6iILjfvzsj52fXGHZQCGwy9Ue3jIs0pB4aQwurfo2KzwczQRjgQ1wiu5DKWxFnhJzEXL0MCegzSWM+T03i8D0pyEOjOXpHyO/odL6M1n6ej952hxWAxEVC9htc0NP5vWTbR05RxT2XlouTz6qjeDyriwvo0MhsI0DhdkDmrBXXNupPnHcvfFTeR/Nh5U6SE2Mcpad58UGmbQI+7VRjcIjB23HNZl/xei+YgPTbnqBi9tCZKE8SHkQYzusgNvZdq2GxjnkZae45izU1v47Y5iBIj2kXqDADW3V4Zae0n6G5vbrT2HN2uq6L5pM4ArLK6LcajZt9qjHeeY5Rp48+MKvInPtMn9LkSpnVmJ0xsggauI8ECDkOKru62m6trsr24+PjhjHw8+wot+Wg+A8ta9ddT1vPNF2n95+fr55MOUEHOD58X4+yhgrvbSbcjnuTNnIjLzN2nnSVpLIm0nDOFwRsBJ3Dn5LsS0GbyFa3kvNevI5tLojC87mtQ/fTbrz+/0TvojgrkYmSxTV29k4oQzphnVrWvcRftjYdvHCmo1sx/UJNDzFn7yHfhcdOeBNT/pUcOBI0YO/0qFxg4ELrpihg3vYtn0EBMmqd3zJx0y/Zf54EeGOzm7DA6qiPsEdfBYASsjnh5/A9wXNCB1amrsVtkxJuYrqE/M9SFo0QEOIbHeCoPaREiSmW5dLA2ajjm/gAWvchS/5kqCp6euqkeWSuFoX44CJIs9VSLBF46kKuTNTvmsoLscD0+/IppPD83A8OPkMbznIz4fvZcKBpvdFYlP1Q4maBH7041javfyBu3JTetAAti/xorCnSSLZoR47mL9YRo4RXGhe1evOXff8R+2Lq0IQAA" \ No newline at end of file diff --git a/docs/assets/search.js b/docs/assets/search.js index 1dad9bde7..b1b46c3f1 100644 --- a/docs/assets/search.js +++ b/docs/assets/search.js @@ -1 +1 @@ -window.searchData = "data:application/octet-stream;base64,H4sIAAAAAAAAE61ZTW/bOBD9Lzqrskn6M7eih90F9lC0wF6CQFBsJREiS4IkN9sN/N93qA9rRuLQVJtDYtIavpl5j0OK9LtX5m+Vd3f/7r0m2dG7k76XRafYu/M+F4Xne+cyhfYpP57TuFrAd8FLfUrhwSGNqiqGoZ538fvRm9V1+DF+is5pfYV4OmeHOsmzFqR7agDzvSIq46zuIhiwh8gO+emUZwv4KPIMTKvFtzg7xuXXMi+qv5OqHvcnebQI4YAQjkaM+65Zc46H7Oe7vh0K4mw+N24Mf3+N07iG7/qGA6e96bXhyuLEh42+qReLOytT0xwduXlL6sPLl6iKUdOFn6sxajpzNPVkZcnoy+rWzpUxZwtf5zpJqwUgVvHnIvleR/W54jhqbENq68oL42HCjdHHTZdTTox5mXg4Rcm0aPSX1szQ+PzwWi0e9Xodl1Mg/TTsnloR1QD5lpevCOtHVCbR4xStNbOzQaPj43+JsmMal1PpW5f9Y9cMJnDjHAZAHnmSxhWVz6MoIe5DPTSCG5n1dkNjbq79wD9v5WxxNcZwYcOSqomfMj/XEMqn6ZrxR/ao/yYEtSPCcLpqgbX+c619DD4U/G14swtExO2c5jHxtWXyS1QecXsGM2gUbrsyZXLqwhjn1h6CE5McJ7/EbPOmg9rzmW1exVB7JrPM2998t/YQ5jA74cTGbFfrn1LtNyoSlsDOMNSGIRjad7PlfivW0kpW/bOwwc/mY5KJUbbnuHZTbhIQHfnbMU2kCMMyz/kJ3Dx13UK+6UGGfYOCNVZOiXSxWaI/RGW9gEfxv0Ea/feTS0ObhY1ZqM0+KJ8xqnti47AtGd5O7sPz+qWU3LLJSzgcuiTVGn58blNc9xSnwV8efK/penfv3g94CLUM9jJQwR4AnpI4PerrjzY4v3mp15AP3bN/4kOdl9qiNVksPf9+6SsVyJV8ePDv+xHNg+aLxkxAT5jMBDGT0JMmM0nMFPSUyUwRsxX0ViazFTFbQ29tMlsTsw30NiazDTHbQm9rMtsSsx30diazHTEDUe73JrM9pVezLYw6iJEQjRJmKagWQnMujGoIKofQtAujIIIqIjTzwqiJoKIITb4wyiKoLkLzL4zKCCqN0BKIrS/WwVbufLHz5SqA7ZeOoToJrYcwSiCoVGJP0OXSiE51k1ocaVRDUt2koOjShC5H1dSUk/LlNtitBbWkCkrVocNCsBYADeQE+83Gl+uuRUdTVeWK90NVlVo6adRKUlWllk4aC0lSVaUWTFMigs1qRy2pllILJo1aSqql3POYVEGlZVLGylNUQSVYTEV1U1ocZZwVarQQKh6z1ahZ72Ghr+PjX+26Dyt3pK+y372w2wmW/V707i3h3+UyrPu616PSl+hnOOg96/PlgAMFdQWCMnJF6l7+Dvqgg9oYWaIQoYRmIuu3StwmyHJAhvJxRS6bS+NCXxo36KM+8YAcOONX/dVrdb36HRBXA+LKHbG5lTzoC8qhiVE3A+rGjoqu+OBdveouFgckNA12DNL11xA0e5DEzCg4WnAyouhhJWGGj6brHnnkAh1usdBAJIDgFBgOiijKNYpSMQPbe1HkDc99rj5Hl6FoNKaV43V8FYmGKzScjfjmDSACRBQITih+aiHJuGWgc094Xznwzi09iEDJ0c/NSsSebIrf9yQ3YXrajKyh6S246rSsQSgOLv2yPYag4FEZy20X/L79VKL7tKLRFLbjzcHvlnK/W3h9XpvR0R8FiVAlSwxz9EYwaF5JbikwnG8Rw6hKFTdN+DMlAkLzTXEbhmlXQIXF1ZV54UcUcpt2/8MIkhNta8IYJrx5FEkRp0kGRvcPl8v/AH6un1wfAAA="; \ No newline at end of file +window.searchData = "data:application/octet-stream;base64,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"; \ No newline at end of file diff --git a/docs/functions/App.default.html b/docs/functions/App.default.html index 95511263e..8b967a824 100644 --- a/docs/functions/App.default.html +++ b/docs/functions/App.default.html @@ -1 +1 @@ -default | react-shopping-cart
\ No newline at end of file +default | react-shopping-cart
\ No newline at end of file diff --git a/docs/functions/common_components_RenderPropsList_RenderPropsList.RenderPropsList.html b/docs/functions/common_components_RenderPropsList_RenderPropsList.RenderPropsList.html index 9398fe0b7..e9da29c32 100644 --- a/docs/functions/common_components_RenderPropsList_RenderPropsList.RenderPropsList.html +++ b/docs/functions/common_components_RenderPropsList_RenderPropsList.RenderPropsList.html @@ -1,2 +1,2 @@ RenderPropsList | react-shopping-cart
\ No newline at end of file +
\ No newline at end of file diff --git a/docs/functions/common_components_Skeleton_Skeleton.Skeleton.html b/docs/functions/common_components_Skeleton_Skeleton.Skeleton.html index 31c1e858b..923d380c0 100644 --- a/docs/functions/common_components_Skeleton_Skeleton.Skeleton.html +++ b/docs/functions/common_components_Skeleton_Skeleton.Skeleton.html @@ -1 +1 @@ -Skeleton | react-shopping-cart
\ No newline at end of file +Skeleton | react-shopping-cart
\ No newline at end of file diff --git a/docs/functions/common_components_SwitchCase_SwitchCase.SwitchCase.html b/docs/functions/common_components_SwitchCase_SwitchCase.SwitchCase.html index 626e81fd5..eba9790cf 100644 --- a/docs/functions/common_components_SwitchCase_SwitchCase.SwitchCase.html +++ b/docs/functions/common_components_SwitchCase_SwitchCase.SwitchCase.html @@ -1,3 +1,3 @@ SwitchCase | react-shopping-cart
  • Type Parameters

    • T extends string | number

    Parameters

    • __namedParameters: SwitchCaseProps<T>

    Returns ReactNode

    Summary

    switch문의 컴포넌트 버전

    Detail

    value의 case에 해당하는 컴포넌트 렌더링

    -
\ No newline at end of file +
\ No newline at end of file diff --git a/docs/functions/common_hooks_useCookieRepository_service.getCookie.html b/docs/functions/common_hooks_useCookieRepository_service.getCookie.html new file mode 100644 index 000000000..5d2b4f280 --- /dev/null +++ b/docs/functions/common_hooks_useCookieRepository_service.getCookie.html @@ -0,0 +1,3 @@ +getCookie | react-shopping-cart
\ No newline at end of file diff --git a/docs/functions/common_hooks_useCookieRepository_service.setCookie.html b/docs/functions/common_hooks_useCookieRepository_service.setCookie.html new file mode 100644 index 000000000..6994ba1d3 --- /dev/null +++ b/docs/functions/common_hooks_useCookieRepository_service.setCookie.html @@ -0,0 +1,3 @@ +setCookie | react-shopping-cart
\ No newline at end of file diff --git a/docs/functions/common_hooks_useCookieRepository_useCookieRepository.useCookie.html b/docs/functions/common_hooks_useCookieRepository_useCookieRepository.useCookie.html new file mode 100644 index 000000000..b9629aa6d --- /dev/null +++ b/docs/functions/common_hooks_useCookieRepository_useCookieRepository.useCookie.html @@ -0,0 +1,2 @@ +useCookie | react-shopping-cart
\ No newline at end of file diff --git a/docs/functions/common_module_store_store.createStore.html b/docs/functions/common_module_store_store.createStore.html new file mode 100644 index 000000000..5dd5fb1f4 --- /dev/null +++ b/docs/functions/common_module_store_store.createStore.html @@ -0,0 +1,2 @@ +createStore | react-shopping-cart
\ No newline at end of file diff --git a/docs/functions/common_module_store_useStore.useStore.html b/docs/functions/common_module_store_useStore.useStore.html new file mode 100644 index 000000000..5bb9f125c --- /dev/null +++ b/docs/functions/common_module_store_useStore.useStore.html @@ -0,0 +1,2 @@ +useStore | react-shopping-cart
  • Type Parameters

    • T

    Parameters

    Returns readonly [T, ((next) => void)]

    Summary

    스토어를 리액트에서 상태로 사용할 수 있도록 도와주는 hook

    +
\ No newline at end of file diff --git a/docs/functions/common_utils_convertQueryToString.convertQueryToString.html b/docs/functions/common_utils_convertQueryToString.convertQueryToString.html new file mode 100644 index 000000000..da2871db1 --- /dev/null +++ b/docs/functions/common_utils_convertQueryToString.convertQueryToString.html @@ -0,0 +1,2 @@ +convertQueryToString | react-shopping-cart
  • Parameters

    • query: Record<string, string | number | boolean>

    Returns string

    Summary

    object를 key=value 형태의 string으로로 변환한다.

    +
\ No newline at end of file diff --git a/docs/functions/common_utils_parseApiStatus.parseApiStatus.html b/docs/functions/common_utils_parseApiStatus.parseApiStatus.html index 31527bba7..0e7cca843 100644 --- a/docs/functions/common_utils_parseApiStatus.parseApiStatus.html +++ b/docs/functions/common_utils_parseApiStatus.parseApiStatus.html @@ -1 +1 @@ -parseApiStatus | react-shopping-cart
  • Parameters

    • __namedParameters: {
          isError: boolean;
          isLoading: boolean;
      }
      • isError: boolean
      • isLoading: boolean

    Returns "success" | "error" | "loading"

\ No newline at end of file +parseApiStatus | react-shopping-cart
  • Parameters

    • __namedParameters: {
          isError: boolean;
          isLoading: boolean;
      }
      • isError: boolean
      • isLoading: boolean

    Returns "success" | "error" | "loading"

\ No newline at end of file diff --git a/docs/functions/routes__common_components_Gnb_Gnb.Gnb.html b/docs/functions/routes__common_components_Gnb_Gnb.Gnb.html index e51043dc8..8296cf22d 100644 --- a/docs/functions/routes__common_components_Gnb_Gnb.Gnb.html +++ b/docs/functions/routes__common_components_Gnb_Gnb.Gnb.html @@ -1,3 +1,3 @@ Gnb | react-shopping-cart
  • Returns Element

    Summary

    공통으로 사용하는 네비게이션 바

    Detail

    메인페이지, 장바구니, 주문목록 페이지 라우팅

    -
\ No newline at end of file +
\ No newline at end of file diff --git a/docs/functions/routes__common_components_MoreButton_MoreButton.MoreButton.html b/docs/functions/routes__common_components_MoreButton_MoreButton.MoreButton.html new file mode 100644 index 000000000..a062e580d --- /dev/null +++ b/docs/functions/routes__common_components_MoreButton_MoreButton.MoreButton.html @@ -0,0 +1,9 @@ +MoreButton | react-shopping-cart

Properties

$$typeof: symbol
defaultProps?: Partial<Omit<DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "ref"> & RefAttributes<HTMLButtonElement>>
displayName?: string

Used in debugging messages. You might want to set it +explicitly if you want to display a different name for +debugging purposes.

+
propTypes?: WeakValidationMap<Omit<DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "ref"> & RefAttributes<HTMLButtonElement>>
\ No newline at end of file diff --git a/docs/functions/routes__common_components_ProductCard_ProductCard.ProductCard.html b/docs/functions/routes__common_components_ProductCard_ProductCard.ProductCard.html index c30ca1af2..b9a558b08 100644 --- a/docs/functions/routes__common_components_ProductCard_ProductCard.ProductCard.html +++ b/docs/functions/routes__common_components_ProductCard_ProductCard.ProductCard.html @@ -1 +1 @@ -ProductCard | react-shopping-cart
\ No newline at end of file +ProductCard | react-shopping-cart
\ No newline at end of file diff --git a/docs/functions/routes__common_components_ProductList_ProductList.ProductList.html b/docs/functions/routes__common_components_ProductList_ProductList.ProductList.html index 01e33152b..5430e6f4e 100644 --- a/docs/functions/routes__common_components_ProductList_ProductList.ProductList.html +++ b/docs/functions/routes__common_components_ProductList_ProductList.ProductList.html @@ -1,2 +1,2 @@ ProductList | react-shopping-cart
\ No newline at end of file +
\ No newline at end of file diff --git a/docs/functions/routes__common_store_cartListStore_cartListStore.useCartListStore.html b/docs/functions/routes__common_store_cartListStore_cartListStore.useCartListStore.html new file mode 100644 index 000000000..91fc6c138 --- /dev/null +++ b/docs/functions/routes__common_store_cartListStore_cartListStore.useCartListStore.html @@ -0,0 +1 @@ +useCartListStore | react-shopping-cart
  • Returns {
        actions: {
            changeProductCount: ((e, product) => void);
            decreaseCount: ((id) => void);
            deleteAllProducts: (() => void);
            deleteProduct: ((id) => void);
            increaseCount: ((id) => void);
            saveProduct: ((id) => void);
        };
        cartList: CartItem[];
    }

    • actions: {
          changeProductCount: ((e, product) => void);
          decreaseCount: ((id) => void);
          deleteAllProducts: (() => void);
          deleteProduct: ((id) => void);
          increaseCount: ((id) => void);
          saveProduct: ((id) => void);
      }
      • changeProductCount: ((e, product) => void)
          • (e, product): void
          • Parameters

            • e: ChangeEvent<HTMLInputElement>
            • product: CartItem

            Returns void

      • decreaseCount: ((id) => void)
          • (id): void
          • Parameters

            • id: number

            Returns void

      • deleteAllProducts: (() => void)
          • (): void
          • Returns void

      • deleteProduct: ((id) => void)
          • (id): void
          • Parameters

            • id: number

            Returns void

      • increaseCount: ((id) => void)
          • (id): void
          • Parameters

            • id: number

            Returns void

      • saveProduct: ((id) => void)
          • (id): void
          • Parameters

            • id: number

            Returns void

    • cartList: CartItem[]
\ No newline at end of file diff --git a/docs/functions/routes__product_list_api.getProductList.html b/docs/functions/routes__product_list_api.getProductList.html index db64377e1..695e5620a 100644 --- a/docs/functions/routes__product_list_api.getProductList.html +++ b/docs/functions/routes__product_list_api.getProductList.html @@ -1,2 +1,2 @@ -getProductList | react-shopping-cart
\ No newline at end of file +getProductList | react-shopping-cart
\ No newline at end of file diff --git a/docs/functions/routes_cart__cart_list_api.getCartList.html b/docs/functions/routes_cart__cart_list_api.getCartList.html new file mode 100644 index 000000000..d94002571 --- /dev/null +++ b/docs/functions/routes_cart__cart_list_api.getCartList.html @@ -0,0 +1,2 @@ +getCartList | react-shopping-cart
\ No newline at end of file diff --git a/docs/functions/routes_cart__useCartVM.useCartVM.html b/docs/functions/routes_cart__useCartVM.useCartVM.html new file mode 100644 index 000000000..1b69986fa --- /dev/null +++ b/docs/functions/routes_cart__useCartVM.useCartVM.html @@ -0,0 +1,2 @@ +useCartVM | react-shopping-cart
  • Returns {
        actions: {
            changeProductCount: ((e, product) => void);
            decreaseCount: ((id) => void);
            deleteAllProducts: (() => void);
            deleteProduct: ((id) => void);
            increaseCount: ((id) => void);
            isCheckedProduct: ((id) => undefined | boolean);
            saveProduct: ((id) => void);
            toggleAll: (() => void);
            toggleProduct: ((id) => void);
        };
        cartsQuery: UseQueryResult<{
            hasProduct: boolean;
            list: {
                count: number;
                id: number;
                imageUrl: string;
                name: string;
                price: number;
                totalPrice: number;
            }[];
        }, Error>;
        computed: {
            isAllProductChecked: boolean;
            paymentTotal: undefined | string;
            totalSelectedCount: number;
        };
    }

    • actions: {
          changeProductCount: ((e, product) => void);
          decreaseCount: ((id) => void);
          deleteAllProducts: (() => void);
          deleteProduct: ((id) => void);
          increaseCount: ((id) => void);
          isCheckedProduct: ((id) => undefined | boolean);
          saveProduct: ((id) => void);
          toggleAll: (() => void);
          toggleProduct: ((id) => void);
      }
      • changeProductCount: ((e, product) => void)
          • (e, product): void
          • Parameters

            • e: ChangeEvent<HTMLInputElement>
            • product: CartItem

            Returns void

      • decreaseCount: ((id) => void)
          • (id): void
          • Parameters

            • id: number

            Returns void

      • deleteAllProducts: (() => void)
          • (): void
          • Returns void

      • deleteProduct: ((id) => void)
          • (id): void
          • Parameters

            • id: number

            Returns void

      • increaseCount: ((id) => void)
          • (id): void
          • Parameters

            • id: number

            Returns void

      • isCheckedProduct: ((id) => undefined | boolean)
          • (id): undefined | boolean
          • Parameters

            • id: number

            Returns undefined | boolean

      • saveProduct: ((id) => void)
          • (id): void
          • Parameters

            • id: number

            Returns void

      • toggleAll: (() => void)
          • (): void
          • Returns void

      • toggleProduct: ((id) => void)
          • (id): void
          • Parameters

            • id: number

            Returns void

    • cartsQuery: UseQueryResult<{
          hasProduct: boolean;
          list: {
              count: number;
              id: number;
              imageUrl: string;
              name: string;
              price: number;
              totalPrice: number;
          }[];
      }, Error>
    • computed: {
          isAllProductChecked: boolean;
          paymentTotal: undefined | string;
          totalSelectedCount: number;
      }
      • isAllProductChecked: boolean
      • paymentTotal: undefined | string
      • totalSelectedCount: number

    Summary

    카트 페이지의 view model

    +
\ No newline at end of file diff --git a/docs/functions/routes_products__id__common_components_ProductSkeleton_ProductSkeleton.ProductSkeleton.html b/docs/functions/routes_products__id__common_components_ProductSkeleton_ProductSkeleton.ProductSkeleton.html new file mode 100644 index 000000000..a812e310d --- /dev/null +++ b/docs/functions/routes_products__id__common_components_ProductSkeleton_ProductSkeleton.ProductSkeleton.html @@ -0,0 +1 @@ +ProductSkeleton | react-shopping-cart
\ No newline at end of file diff --git a/docs/functions/routes_products__id__common_components_Product_Product.Product.html b/docs/functions/routes_products__id__common_components_Product_Product.Product.html new file mode 100644 index 000000000..3045e5cda --- /dev/null +++ b/docs/functions/routes_products__id__common_components_Product_Product.Product.html @@ -0,0 +1 @@ +Product | react-shopping-cart
\ No newline at end of file diff --git a/docs/functions/routes_products__id__product_item_api.getProduct.html b/docs/functions/routes_products__id__product_item_api.getProduct.html new file mode 100644 index 000000000..4060a21cb --- /dev/null +++ b/docs/functions/routes_products__id__product_item_api.getProduct.html @@ -0,0 +1,2 @@ +getProduct | react-shopping-cart
\ No newline at end of file diff --git a/docs/interfaces/common_hooks_useCookieRepository_type.CookieOptions.html b/docs/interfaces/common_hooks_useCookieRepository_type.CookieOptions.html new file mode 100644 index 000000000..45e388a09 --- /dev/null +++ b/docs/interfaces/common_hooks_useCookieRepository_type.CookieOptions.html @@ -0,0 +1,14 @@ +CookieOptions | react-shopping-cart
interface CookieOptions {
    domain?: string;
    expires?: Date;
    path?: string;
    [key: string]: unknown;
}

Indexable

[key: string]: unknown

기타 키 정의

+

Properties

Properties

domain?: string

Default

현재 도메인
+
+

Description

미지정시 하위 도메인 접근 불가

+
expires?: Date

Summary

쿠키의

+

Default

세션 쿠기(브라우저 종료시 자동 삭제)
+
+

Description

지정시 영구 쿠기(지정 날짜까지 유지)

+
path?: string

Default

"/"
+
+
\ No newline at end of file diff --git a/docs/interfaces/common_module_store_store.Store.html b/docs/interfaces/common_module_store_store.Store.html new file mode 100644 index 000000000..33741cfac --- /dev/null +++ b/docs/interfaces/common_module_store_store.Store.html @@ -0,0 +1,4 @@ +Store | react-shopping-cart
interface Store<T> {
    getState: (() => T);
    setState: ((next) => void);
    subscribe: ((callback) => (() => void));
}

Type Parameters

  • T

Properties

getState: (() => T)

Type declaration

    • (): T
    • Returns T

setState: ((next) => void)

Type declaration

    • (next): void
    • Parameters

      • next: T | ((prev) => T)

      Returns void

subscribe: ((callback) => (() => void))

Type declaration

    • (callback): (() => void)
    • Parameters

      • callback: (() => void)
          • (): void
          • Returns void

      Returns (() => void)

        • (): void
        • Returns void

\ No newline at end of file diff --git a/docs/interfaces/routes__product_list_api.Product.html b/docs/interfaces/routes__product_list_api.Product.html new file mode 100644 index 000000000..61760b71f --- /dev/null +++ b/docs/interfaces/routes__product_list_api.Product.html @@ -0,0 +1,5 @@ +Product | react-shopping-cart
interface Product {
    id: number;
    imageUrl: string;
    name: string;
    price: number;
}

Properties

Properties

id: number
imageUrl: string
name: string
price: number
\ No newline at end of file diff --git a/docs/interfaces/routes_cart__cart_list_api.Product.html b/docs/interfaces/routes_cart__cart_list_api.Product.html new file mode 100644 index 000000000..8feb43b29 --- /dev/null +++ b/docs/interfaces/routes_cart__cart_list_api.Product.html @@ -0,0 +1,5 @@ +Product | react-shopping-cart
interface Product {
    id: number;
    imageUrl: string;
    name: string;
    price: number;
}

Properties

Properties

id: number
imageUrl: string
name: string
price: number
\ No newline at end of file diff --git a/docs/interfaces/routes_products__id__product_item_api.Product.html b/docs/interfaces/routes_products__id__product_item_api.Product.html new file mode 100644 index 000000000..beea662e2 --- /dev/null +++ b/docs/interfaces/routes_products__id__product_item_api.Product.html @@ -0,0 +1,5 @@ +Product | react-shopping-cart
interface Product {
    id: number;
    imageUrl: string;
    name: string;
    price: number;
}

Properties

Properties

id: number
imageUrl: string
name: string
price: number
\ No newline at end of file diff --git a/docs/modules/App.html b/docs/modules/App.html index b27da97a3..e7ee6718a 100644 --- a/docs/modules/App.html +++ b/docs/modules/App.html @@ -1,2 +1,2 @@ -App | react-shopping-cart

Index

Functions

default +App | react-shopping-cart

Index

Functions

\ No newline at end of file diff --git a/docs/modules/common_components_RenderPropsList_RenderPropsList.html b/docs/modules/common_components_RenderPropsList_RenderPropsList.html index bebd8335e..0fd289ce3 100644 --- a/docs/modules/common_components_RenderPropsList_RenderPropsList.html +++ b/docs/modules/common_components_RenderPropsList_RenderPropsList.html @@ -1,2 +1,2 @@ -common/components/RenderPropsList/RenderPropsList | react-shopping-cart

Module common/components/RenderPropsList/RenderPropsList

Index

Functions

RenderPropsList +common/components/RenderPropsList/RenderPropsList | react-shopping-cart
\ No newline at end of file diff --git a/docs/modules/common_components_Skeleton_Skeleton.html b/docs/modules/common_components_Skeleton_Skeleton.html index 6bf17ee45..52b238139 100644 --- a/docs/modules/common_components_Skeleton_Skeleton.html +++ b/docs/modules/common_components_Skeleton_Skeleton.html @@ -1,2 +1,2 @@ -common/components/Skeleton/Skeleton | react-shopping-cart

Module common/components/Skeleton/Skeleton

Index

Functions

Skeleton +common/components/Skeleton/Skeleton | react-shopping-cart
\ No newline at end of file diff --git a/docs/modules/common_components_SwitchCase_SwitchCase.html b/docs/modules/common_components_SwitchCase_SwitchCase.html index e946d660a..1040c5efa 100644 --- a/docs/modules/common_components_SwitchCase_SwitchCase.html +++ b/docs/modules/common_components_SwitchCase_SwitchCase.html @@ -1,2 +1,2 @@ -common/components/SwitchCase/SwitchCase | react-shopping-cart

Module common/components/SwitchCase/SwitchCase

Index

Functions

SwitchCase +common/components/SwitchCase/SwitchCase | react-shopping-cart
\ No newline at end of file diff --git a/docs/modules/common_hooks_useCookieRepository_service.html b/docs/modules/common_hooks_useCookieRepository_service.html new file mode 100644 index 000000000..5e9a89745 --- /dev/null +++ b/docs/modules/common_hooks_useCookieRepository_service.html @@ -0,0 +1,3 @@ +common/hooks/useCookieRepository/service | react-shopping-cart
\ No newline at end of file diff --git a/docs/modules/common_hooks_useCookieRepository_type.html b/docs/modules/common_hooks_useCookieRepository_type.html new file mode 100644 index 000000000..27192ad49 --- /dev/null +++ b/docs/modules/common_hooks_useCookieRepository_type.html @@ -0,0 +1,2 @@ +common/hooks/useCookieRepository/type | react-shopping-cart
\ No newline at end of file diff --git a/docs/modules/common_hooks_useCookieRepository_useCookieRepository.html b/docs/modules/common_hooks_useCookieRepository_useCookieRepository.html new file mode 100644 index 000000000..a0da16d2f --- /dev/null +++ b/docs/modules/common_hooks_useCookieRepository_useCookieRepository.html @@ -0,0 +1,2 @@ +common/hooks/useCookieRepository/useCookieRepository | react-shopping-cart
\ No newline at end of file diff --git a/docs/modules/common_module_store_store.html b/docs/modules/common_module_store_store.html new file mode 100644 index 000000000..85eedcd30 --- /dev/null +++ b/docs/modules/common_module_store_store.html @@ -0,0 +1,3 @@ +common/module/store/store | react-shopping-cart

Module common/module/store/store

Index

Interfaces

Functions

\ No newline at end of file diff --git a/docs/modules/common_module_store_useStore.html b/docs/modules/common_module_store_useStore.html new file mode 100644 index 000000000..f76b85e89 --- /dev/null +++ b/docs/modules/common_module_store_useStore.html @@ -0,0 +1,2 @@ +common/module/store/useStore | react-shopping-cart

Module common/module/store/useStore

Index

Functions

\ No newline at end of file diff --git a/docs/modules/common_utils_convertQueryToString.html b/docs/modules/common_utils_convertQueryToString.html new file mode 100644 index 000000000..be7d7c583 --- /dev/null +++ b/docs/modules/common_utils_convertQueryToString.html @@ -0,0 +1,2 @@ +common/utils/convertQueryToString | react-shopping-cart
\ No newline at end of file diff --git a/docs/modules/common_utils_parseApiStatus.html b/docs/modules/common_utils_parseApiStatus.html index 808e22da3..64647759b 100644 --- a/docs/modules/common_utils_parseApiStatus.html +++ b/docs/modules/common_utils_parseApiStatus.html @@ -1,2 +1,2 @@ -common/utils/parseApiStatus | react-shopping-cart

Module common/utils/parseApiStatus

Index

Functions

parseApiStatus +common/utils/parseApiStatus | react-shopping-cart
\ No newline at end of file diff --git a/docs/modules/main.html b/docs/modules/main.html index 91e1ff148..4197ea19a 100644 --- a/docs/modules/main.html +++ b/docs/modules/main.html @@ -1 +1 @@ -main | react-shopping-cart
\ No newline at end of file +main | react-shopping-cart
\ No newline at end of file diff --git a/docs/modules/mocks_browser.html b/docs/modules/mocks_browser.html index 51477f477..3d335e80c 100644 --- a/docs/modules/mocks_browser.html +++ b/docs/modules/mocks_browser.html @@ -1,2 +1,2 @@ -mocks/browser | react-shopping-cart

Index

Variables

worker +mocks/browser | react-shopping-cart

Index

Variables

\ No newline at end of file diff --git a/docs/modules/mocks_const.html b/docs/modules/mocks_const.html new file mode 100644 index 000000000..4e2e57aa1 --- /dev/null +++ b/docs/modules/mocks_const.html @@ -0,0 +1,2 @@ +mocks/const | react-shopping-cart

Index

Variables

\ No newline at end of file diff --git a/docs/modules/mocks_handlers.html b/docs/modules/mocks_handlers.html index 0915aee86..ee9591300 100644 --- a/docs/modules/mocks_handlers.html +++ b/docs/modules/mocks_handlers.html @@ -1,2 +1,2 @@ -mocks/handlers | react-shopping-cart

Index

Variables

handlers +mocks/handlers | react-shopping-cart

Index

Variables

\ No newline at end of file diff --git a/docs/modules/mocks_products_cart_handlers.html b/docs/modules/mocks_products_cart_handlers.html new file mode 100644 index 000000000..813722a70 --- /dev/null +++ b/docs/modules/mocks_products_cart_handlers.html @@ -0,0 +1,2 @@ +mocks/products/cart.handlers | react-shopping-cart
\ No newline at end of file diff --git a/docs/modules/mocks_products_index_handlers.html b/docs/modules/mocks_products_index_handlers.html new file mode 100644 index 000000000..445908c35 --- /dev/null +++ b/docs/modules/mocks_products_index_handlers.html @@ -0,0 +1,2 @@ +mocks/products/index.handlers | react-shopping-cart
\ No newline at end of file diff --git a/docs/modules/mocks_products_products_handlers.html b/docs/modules/mocks_products_products_handlers.html index 54d04372b..f530cc4a0 100644 --- a/docs/modules/mocks_products_products_handlers.html +++ b/docs/modules/mocks_products_products_handlers.html @@ -1,2 +1,2 @@ -mocks/products/products.handlers | react-shopping-cart

Module mocks/products/products.handlers

Index

Variables

productsHandlers +mocks/products/products.handlers | react-shopping-cart
\ No newline at end of file diff --git a/docs/modules/mocks_products_products_repository.html b/docs/modules/mocks_products_products_repository.html new file mode 100644 index 000000000..d2c6b6eb1 --- /dev/null +++ b/docs/modules/mocks_products_products_repository.html @@ -0,0 +1,2 @@ +mocks/products/products.repository | react-shopping-cart
\ No newline at end of file diff --git a/docs/modules/routes___root.html b/docs/modules/routes___root.html index c6ec65d70..6904e457c 100644 --- a/docs/modules/routes___root.html +++ b/docs/modules/routes___root.html @@ -1,2 +1,2 @@ -routes/__root | react-shopping-cart

Index

Variables

Route +routes/__root | react-shopping-cart

Index

Variables

\ No newline at end of file diff --git a/docs/modules/routes__common_components_MoreButton_MoreButton.html b/docs/modules/routes__common_components_MoreButton_MoreButton.html new file mode 100644 index 000000000..61ec7b1e3 --- /dev/null +++ b/docs/modules/routes__common_components_MoreButton_MoreButton.html @@ -0,0 +1,2 @@ +routes/-common/components/MoreButton/MoreButton | react-shopping-cart
\ No newline at end of file diff --git a/docs/modules/routes__common_components_ProductCard_ProductCard.html b/docs/modules/routes__common_components_ProductCard_ProductCard.html index 4b149c1e3..0ea4460d7 100644 --- a/docs/modules/routes__common_components_ProductCard_ProductCard.html +++ b/docs/modules/routes__common_components_ProductCard_ProductCard.html @@ -1,2 +1,2 @@ -routes/-common/components/ProductCard/ProductCard | react-shopping-cart

Module routes/-common/components/ProductCard/ProductCard

Index

Functions

ProductCard +routes/-common/components/ProductCard/ProductCard | react-shopping-cart
\ No newline at end of file diff --git a/docs/modules/routes__common_components_ProductList_ProductList.html b/docs/modules/routes__common_components_ProductList_ProductList.html index 9b0d414b2..63501a0d4 100644 --- a/docs/modules/routes__common_components_ProductList_ProductList.html +++ b/docs/modules/routes__common_components_ProductList_ProductList.html @@ -1,2 +1,2 @@ -routes/-common/components/ProductList/ProductList | react-shopping-cart

Module routes/-common/components/ProductList/ProductList

Index

Functions

ProductList +routes/-common/components/ProductList/ProductList | react-shopping-cart
\ No newline at end of file diff --git a/docs/modules/routes__common_store_cartListStore_cartListStore.html b/docs/modules/routes__common_store_cartListStore_cartListStore.html new file mode 100644 index 000000000..5bfe96644 --- /dev/null +++ b/docs/modules/routes__common_store_cartListStore_cartListStore.html @@ -0,0 +1,2 @@ +routes/-common/store/cartListStore/cartListStore | react-shopping-cart
\ No newline at end of file diff --git a/docs/modules/routes__common_store_cartListStore_const.html b/docs/modules/routes__common_store_cartListStore_const.html new file mode 100644 index 000000000..eb8f93bf2 --- /dev/null +++ b/docs/modules/routes__common_store_cartListStore_const.html @@ -0,0 +1,4 @@ +routes/-common/store/cartListStore/const | react-shopping-cart
\ No newline at end of file diff --git a/docs/modules/routes__product_list_api.html b/docs/modules/routes__product_list_api.html index bc2d43e90..1e248288c 100644 --- a/docs/modules/routes__product_list_api.html +++ b/docs/modules/routes__product_list_api.html @@ -1,3 +1,4 @@ -routes/-product-list.api | react-shopping-cart

Module routes/-product-list.api

Index

Type Aliases

ProductList +routes/-product-list.api | react-shopping-cart

Module routes/-product-list.api

Index

Interfaces

Type Aliases

Functions

\ No newline at end of file diff --git a/docs/modules/routes_cart__cart_list_api.html b/docs/modules/routes_cart__cart_list_api.html new file mode 100644 index 000000000..44b6a01b0 --- /dev/null +++ b/docs/modules/routes_cart__cart_list_api.html @@ -0,0 +1,4 @@ +routes/cart/-cart-list.api | react-shopping-cart

Module routes/cart/-cart-list.api

Index

Interfaces

Type Aliases

Functions

\ No newline at end of file diff --git a/docs/modules/routes_cart__useCartVM.html b/docs/modules/routes_cart__useCartVM.html new file mode 100644 index 000000000..7a1443cae --- /dev/null +++ b/docs/modules/routes_cart__useCartVM.html @@ -0,0 +1,2 @@ +routes/cart/-useCartVM | react-shopping-cart

Module routes/cart/-useCartVM

Index

Functions

\ No newline at end of file diff --git a/docs/modules/routes_cart_index_lazy.html b/docs/modules/routes_cart_index_lazy.html index 737e16cd7..ffa17d4d9 100644 --- a/docs/modules/routes_cart_index_lazy.html +++ b/docs/modules/routes_cart_index_lazy.html @@ -1,2 +1,2 @@ -routes/cart/index.lazy | react-shopping-cart

Module routes/cart/index.lazy

Index

Variables

Route +routes/cart/index.lazy | react-shopping-cart

Module routes/cart/index.lazy

Index

Variables

\ No newline at end of file diff --git a/docs/modules/routes_index_lazy.html b/docs/modules/routes_index_lazy.html index abaeabc48..7b545281f 100644 --- a/docs/modules/routes_index_lazy.html +++ b/docs/modules/routes_index_lazy.html @@ -1,2 +1,2 @@ -routes/index.lazy | react-shopping-cart

Module routes/index.lazy

Index

Variables

Route +routes/index.lazy | react-shopping-cart

Module routes/index.lazy

Index

Variables

\ No newline at end of file diff --git a/docs/modules/routes_orders_index_lazy.html b/docs/modules/routes_orders_index_lazy.html index b3031bdb1..2a19e282a 100644 --- a/docs/modules/routes_orders_index_lazy.html +++ b/docs/modules/routes_orders_index_lazy.html @@ -1,2 +1,2 @@ -routes/orders/index.lazy | react-shopping-cart

Module routes/orders/index.lazy

Index

Variables

Route +routes/orders/index.lazy | react-shopping-cart

Module routes/orders/index.lazy

Index

Variables

\ No newline at end of file diff --git a/docs/modules/routes_products__id__common_components_ProductSkeleton_ProductSkeleton.html b/docs/modules/routes_products__id__common_components_ProductSkeleton_ProductSkeleton.html new file mode 100644 index 000000000..70f1c71c5 --- /dev/null +++ b/docs/modules/routes_products__id__common_components_ProductSkeleton_ProductSkeleton.html @@ -0,0 +1,2 @@ +routes/products/$id/-common/components/ProductSkeleton/ProductSkeleton | react-shopping-cart
\ No newline at end of file diff --git a/docs/modules/routes_products__id__common_components_Product_Product.html b/docs/modules/routes_products__id__common_components_Product_Product.html new file mode 100644 index 000000000..ee90b964d --- /dev/null +++ b/docs/modules/routes_products__id__common_components_Product_Product.html @@ -0,0 +1,2 @@ +routes/products/$id/-common/components/Product/Product | react-shopping-cart
\ No newline at end of file diff --git a/docs/modules/routes_products__id__product_item_api.html b/docs/modules/routes_products__id__product_item_api.html new file mode 100644 index 000000000..b60fb1229 --- /dev/null +++ b/docs/modules/routes_products__id__product_item_api.html @@ -0,0 +1,3 @@ +routes/products/$id/-product-item.api | react-shopping-cart

Module routes/products/$id/-product-item.api

Index

Interfaces

Functions

\ No newline at end of file diff --git a/docs/modules/routes_products__id_index_lazy.html b/docs/modules/routes_products__id_index_lazy.html new file mode 100644 index 000000000..304034c39 --- /dev/null +++ b/docs/modules/routes_products__id_index_lazy.html @@ -0,0 +1,2 @@ +routes/products/$id/index.lazy | react-shopping-cart

Module routes/products/$id/index.lazy

Index

Variables

\ No newline at end of file diff --git a/docs/types/routes__product_list_api.ProductList.html b/docs/types/routes__product_list_api.ProductList.html deleted file mode 100644 index d5d5bb9d5..000000000 --- a/docs/types/routes__product_list_api.ProductList.html +++ /dev/null @@ -1 +0,0 @@ -ProductList | react-shopping-cart
\ No newline at end of file diff --git a/docs/types/routes__product_list_api.ProductListResponse.html b/docs/types/routes__product_list_api.ProductListResponse.html new file mode 100644 index 000000000..ce0dab725 --- /dev/null +++ b/docs/types/routes__product_list_api.ProductListResponse.html @@ -0,0 +1 @@ +ProductListResponse | react-shopping-cart
ProductListResponse: {
    list: Product[];
    meta: Meta;
}

Type declaration

\ No newline at end of file diff --git a/docs/types/routes_cart__cart_list_api.CartListResponse.html b/docs/types/routes_cart__cart_list_api.CartListResponse.html new file mode 100644 index 000000000..38a9a09f0 --- /dev/null +++ b/docs/types/routes_cart__cart_list_api.CartListResponse.html @@ -0,0 +1 @@ +CartListResponse | react-shopping-cart
CartListResponse: {
    list: (Product & {
        count: number;
    })[];
}

Type declaration

  • list: (Product & {
        count: number;
    })[]
\ No newline at end of file diff --git a/docs/variables/mocks_browser.worker.html b/docs/variables/mocks_browser.worker.html index f2d67c4a5..561d5ec84 100644 --- a/docs/variables/mocks_browser.worker.html +++ b/docs/variables/mocks_browser.worker.html @@ -1 +1 @@ -worker | react-shopping-cart
worker: SetupWorker = ...
\ No newline at end of file +worker | react-shopping-cart
worker: SetupWorker = ...
\ No newline at end of file diff --git a/docs/variables/mocks_const.PAGE_META.html b/docs/variables/mocks_const.PAGE_META.html new file mode 100644 index 000000000..5b6250e9b --- /dev/null +++ b/docs/variables/mocks_const.PAGE_META.html @@ -0,0 +1 @@ +PAGE_META | react-shopping-cart
PAGE_META: {
    DEFAULT_PAGE: "0";
    DEFAULT_PER_COUNT: "15";
} = ...

Type declaration

  • Readonly DEFAULT_PAGE: "0"
  • Readonly DEFAULT_PER_COUNT: "15"
\ No newline at end of file diff --git a/docs/variables/mocks_handlers.handlers.html b/docs/variables/mocks_handlers.handlers.html index 6ef53211b..64a5b378c 100644 --- a/docs/variables/mocks_handlers.handlers.html +++ b/docs/variables/mocks_handlers.handlers.html @@ -1 +1 @@ -handlers | react-shopping-cart
handlers: HttpHandler[] = ...
\ No newline at end of file +handlers | react-shopping-cart
handlers: HttpHandler[] = ...
\ No newline at end of file diff --git a/docs/variables/mocks_products_cart_handlers.cartHandlers.html b/docs/variables/mocks_products_cart_handlers.cartHandlers.html new file mode 100644 index 000000000..5086219df --- /dev/null +++ b/docs/variables/mocks_products_cart_handlers.cartHandlers.html @@ -0,0 +1 @@ +cartHandlers | react-shopping-cart
cartHandlers: HttpHandler[] = ...
\ No newline at end of file diff --git a/docs/variables/mocks_products_index_handlers.productsHandlers.html b/docs/variables/mocks_products_index_handlers.productsHandlers.html new file mode 100644 index 000000000..abe302f4a --- /dev/null +++ b/docs/variables/mocks_products_index_handlers.productsHandlers.html @@ -0,0 +1 @@ +productsHandlers | react-shopping-cart
productsHandlers: HttpHandler[] = ...
\ No newline at end of file diff --git a/docs/variables/mocks_products_products_handlers.productsHandlers.html b/docs/variables/mocks_products_products_handlers.productsHandlers.html index f52989d8b..85f004b5e 100644 --- a/docs/variables/mocks_products_products_handlers.productsHandlers.html +++ b/docs/variables/mocks_products_products_handlers.productsHandlers.html @@ -1 +1 @@ -productsHandlers | react-shopping-cart
productsHandlers: HttpHandler[] = ...
\ No newline at end of file +productsHandlers | react-shopping-cart
productsHandlers: HttpHandler[] = ...
\ No newline at end of file diff --git a/docs/variables/mocks_products_products_repository.productsRepository.html b/docs/variables/mocks_products_products_repository.productsRepository.html new file mode 100644 index 000000000..42e047840 --- /dev/null +++ b/docs/variables/mocks_products_products_repository.productsRepository.html @@ -0,0 +1 @@ +productsRepository | react-shopping-cart
productsRepository: Map<number, Product> = ...
\ No newline at end of file diff --git a/docs/variables/routes___root.Route.html b/docs/variables/routes___root.Route.html index 507cf1fc6..3eb2e9b1e 100644 --- a/docs/variables/routes___root.Route.html +++ b/docs/variables/routes___root.Route.html @@ -1 +1 @@ -Route | react-shopping-cart
Route: RootRoute<RootSearchSchema, RootSearchSchema, RootSearchSchema, RouteContext, RouteContext, {
    queryClient: QueryClient;
}, {}, unknown, unknown> = ...

Type declaration

  • queryClient: QueryClient

Type declaration

    \ No newline at end of file +Route | react-shopping-cart
    Route: RootRoute<RootSearchSchema, RootSearchSchema, RootSearchSchema, RouteContext, RouteContext, {
        queryClient: QueryClient;
    }, {}, unknown, unknown> = ...

    Type declaration

    • queryClient: QueryClient

    Type declaration

      \ No newline at end of file diff --git a/docs/variables/routes__common_store_cartListStore_const.CART_COOKIE_KEY.html b/docs/variables/routes__common_store_cartListStore_const.CART_COOKIE_KEY.html new file mode 100644 index 000000000..4d2c08716 --- /dev/null +++ b/docs/variables/routes__common_store_cartListStore_const.CART_COOKIE_KEY.html @@ -0,0 +1 @@ +CART_COOKIE_KEY | react-shopping-cart
      \ No newline at end of file diff --git a/docs/variables/routes__common_store_cartListStore_const.CART_MAX_COUNT.html b/docs/variables/routes__common_store_cartListStore_const.CART_MAX_COUNT.html new file mode 100644 index 000000000..a4c121446 --- /dev/null +++ b/docs/variables/routes__common_store_cartListStore_const.CART_MAX_COUNT.html @@ -0,0 +1 @@ +CART_MAX_COUNT | react-shopping-cart
      \ No newline at end of file diff --git a/docs/variables/routes__common_store_cartListStore_const.CART_MIN_COUNT.html b/docs/variables/routes__common_store_cartListStore_const.CART_MIN_COUNT.html new file mode 100644 index 000000000..0b4e4e969 --- /dev/null +++ b/docs/variables/routes__common_store_cartListStore_const.CART_MIN_COUNT.html @@ -0,0 +1 @@ +CART_MIN_COUNT | react-shopping-cart
      \ No newline at end of file diff --git a/docs/variables/routes_cart_index_lazy.Route.html b/docs/variables/routes_cart_index_lazy.Route.html index 08b5fbad5..1575a036c 100644 --- a/docs/variables/routes_cart_index_lazy.Route.html +++ b/docs/variables/routes_cart_index_lazy.Route.html @@ -1 +1 @@ -Route | react-shopping-cart
      Route: LazyRoute<Route<RootRoute<RootSearchSchema, RootSearchSchema, RootSearchSchema, RouteContext, RouteContext, {
          queryClient: QueryClient;
      }, {}, unknown, unknown>, "cart/", "/cart", "/cart/", "/cart/", {}, {}, {}, {}, {}, {}, {}, RouteContext, RouteContext, {
          queryClient: QueryClient;
      }, AnyContext, {}, unknown, unknown, unknown, AnyRoute>> = ...
      \ No newline at end of file +Route | react-shopping-cart
      Route: LazyRoute<Route<RootRoute<RootSearchSchema, RootSearchSchema, RootSearchSchema, RouteContext, RouteContext, {
          queryClient: QueryClient;
      }, {}, unknown, unknown>, "cart/", "/cart", "/cart/", "/cart/", {}, {}, {}, {}, {}, Record<never, string>, Record<never, string>, RouteContext, RouteContext, {
          queryClient: QueryClient;
      }, AnyContext, {}, unknown, unknown, unknown>> = ...
      \ No newline at end of file diff --git a/docs/variables/routes_index_lazy.Route.html b/docs/variables/routes_index_lazy.Route.html index 7dfa0266d..75cec3a1e 100644 --- a/docs/variables/routes_index_lazy.Route.html +++ b/docs/variables/routes_index_lazy.Route.html @@ -1 +1 @@ -Route | react-shopping-cart
      Route: LazyRoute<Route<RootRoute<RootSearchSchema, RootSearchSchema, RootSearchSchema, RouteContext, RouteContext, {
          queryClient: QueryClient;
      }, {}, unknown, unknown>, "", "/", "/", "/", {}, {}, {}, {}, {}, {}, {}, RouteContext, RouteContext, {
          queryClient: QueryClient;
      }, AnyContext, {}, unknown, unknown, unknown, AnyRoute>> = ...
      \ No newline at end of file +Route | react-shopping-cart
      Route: Route<RootRoute<RootSearchSchema, RootSearchSchema, RootSearchSchema, RouteContext, RouteContext, {
          queryClient: QueryClient;
      }, {}, unknown, unknown>, "", "/", "/", "/", AnySearchSchema, {
          page: number;
      }, {
          page: number;
      }, {
          page: number;
      }, {
          page: number;
      }, Record<never, string>, Record<never, string>, RouteContext, RouteContext, {
          queryClient: QueryClient;
      }, AnyContext, {}, unknown, unknown, unknown> = ...

      Type declaration

      • page: number

      Type declaration

      • page: number

      Type declaration

      • page: number

      Type declaration

      • page: number

      Type declaration

      • queryClient: QueryClient

      Type declaration

        \ No newline at end of file diff --git a/docs/variables/routes_orders_index_lazy.Route.html b/docs/variables/routes_orders_index_lazy.Route.html index 947b56f9c..83fc8c4e9 100644 --- a/docs/variables/routes_orders_index_lazy.Route.html +++ b/docs/variables/routes_orders_index_lazy.Route.html @@ -1 +1 @@ -Route | react-shopping-cart
        Route: LazyRoute<Route<RootRoute<RootSearchSchema, RootSearchSchema, RootSearchSchema, RouteContext, RouteContext, {
            queryClient: QueryClient;
        }, {}, unknown, unknown>, "orders/", "/orders", "/orders/", "/orders/", {}, {}, {}, {}, {}, {}, {}, RouteContext, RouteContext, {
            queryClient: QueryClient;
        }, AnyContext, {}, unknown, unknown, unknown, AnyRoute>> = ...
        \ No newline at end of file +Route | react-shopping-cart
        Route: LazyRoute<Route<RootRoute<RootSearchSchema, RootSearchSchema, RootSearchSchema, RouteContext, RouteContext, {
            queryClient: QueryClient;
        }, {}, unknown, unknown>, "orders/", "/orders", "/orders/", "/orders/", {}, {}, {}, {}, {}, Record<never, string>, Record<never, string>, RouteContext, RouteContext, {
            queryClient: QueryClient;
        }, AnyContext, {}, unknown, unknown, unknown>> = ...
        \ No newline at end of file diff --git a/docs/variables/routes_products__id_index_lazy.Route.html b/docs/variables/routes_products__id_index_lazy.Route.html new file mode 100644 index 000000000..4f8e8178a --- /dev/null +++ b/docs/variables/routes_products__id_index_lazy.Route.html @@ -0,0 +1 @@ +Route | react-shopping-cart
        Route: Route<RootRoute<RootSearchSchema, RootSearchSchema, RootSearchSchema, RouteContext, RouteContext, {
            queryClient: QueryClient;
        }, {}, unknown, unknown>, "products/$id/", "/products/$id", "/products/$id/", "/products/$id/", {}, {}, {}, {}, {}, {
            id: number;
        }, {
            id: number;
        }, RouteContext, RouteContext, {
            queryClient: QueryClient;
        }, AnyContext, {}, unknown, unknown, unknown> = ...

        Type declaration

          Type declaration

            Type declaration

              Type declaration

                Type declaration

                  Type declaration

                  • id: number

                  Type declaration

                  • id: number

                  Type declaration

                  • queryClient: QueryClient

                  Type declaration

                    \ No newline at end of file diff --git a/src/mocks/browser.ts b/src/mocks/browser.ts index 9f849ac01..93f9e2693 100644 --- a/src/mocks/browser.ts +++ b/src/mocks/browser.ts @@ -8,6 +8,6 @@ const sourceCodeExtensionRegex = /\.(ts|tsx|js|jsx)$/i export const worker = setupWorker( ...handlers, - http.get(imageExtensionRegex, (req) => {}), - http.get(sourceCodeExtensionRegex, (req) => {}) + http.get(imageExtensionRegex, () => {}), + http.get(sourceCodeExtensionRegex, () => {}) ) From 369e1d82b031ce95ed1d54015f2529dbb7e3697c Mon Sep 17 00:00:00 2001 From: saewookkang Date: Wed, 1 May 2024 13:39:05 +0900 Subject: [PATCH 31/39] =?UTF-8?q?refactor:=20cookie=20get,=20set=20?= =?UTF-8?q?=ED=95=A8=EC=88=98=20utils=20=ED=95=98=EC=9C=84=EB=A1=9C=20?= =?UTF-8?q?=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - pr 피드백 반영 --- src/common/hooks/useCookieRepository/useCookieRepository.ts | 4 ++-- .../useCookieRepository/service.ts => utils/cookie/index.ts} | 0 .../{hooks/useCookieRepository => utils/cookie}/type.ts | 0 src/routes/-common/store/cartListStore/cartListStore.ts | 2 +- 4 files changed, 3 insertions(+), 3 deletions(-) rename src/common/{hooks/useCookieRepository/service.ts => utils/cookie/index.ts} (100%) rename src/common/{hooks/useCookieRepository => utils/cookie}/type.ts (100%) diff --git a/src/common/hooks/useCookieRepository/useCookieRepository.ts b/src/common/hooks/useCookieRepository/useCookieRepository.ts index 6e6a011a5..b744bcebf 100644 --- a/src/common/hooks/useCookieRepository/useCookieRepository.ts +++ b/src/common/hooks/useCookieRepository/useCookieRepository.ts @@ -1,7 +1,7 @@ import { useEffect, useState } from 'react' -import { getCookie, setCookie } from './service' -import { CookieOptions } from './type' +import { getCookie, setCookie } from '../../utils/cookie' +import { CookieOptions } from '../../utils/cookie/type' interface CookieRepository { get(): Value | undefined diff --git a/src/common/hooks/useCookieRepository/service.ts b/src/common/utils/cookie/index.ts similarity index 100% rename from src/common/hooks/useCookieRepository/service.ts rename to src/common/utils/cookie/index.ts diff --git a/src/common/hooks/useCookieRepository/type.ts b/src/common/utils/cookie/type.ts similarity index 100% rename from src/common/hooks/useCookieRepository/type.ts rename to src/common/utils/cookie/type.ts diff --git a/src/routes/-common/store/cartListStore/cartListStore.ts b/src/routes/-common/store/cartListStore/cartListStore.ts index 2f0a82130..fc014f1f5 100644 --- a/src/routes/-common/store/cartListStore/cartListStore.ts +++ b/src/routes/-common/store/cartListStore/cartListStore.ts @@ -1,6 +1,6 @@ import { ChangeEvent, useEffect } from 'react' -import { getCookie, setCookie } from '@/common/hooks/useCookieRepository/service' +import { getCookie, setCookie } from '@/common/utils/cookie' import { createStore } from '@/common/module/store/store' import { useStore } from '@/common/module/store/useStore' import type { Product } from '@/routes/-product-list.api' From 05b9acec0ce46144069dbeb463c6ad0ec81a96b2 Mon Sep 17 00:00:00 2001 From: saewookkang Date: Wed, 1 May 2024 15:39:02 +0900 Subject: [PATCH 32/39] =?UTF-8?q?refactor:=20query=20=EB=AC=B8=EC=9E=90?= =?UTF-8?q?=EC=97=B4=20=ED=8C=8C=EC=8B=B1=20=EA=B8=B0=EB=B3=B8=20API(URLSe?= =?UTF-8?q?archParams)=20=ED=99=9C=EC=9A=A9=EC=9C=BC=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 코드 리뷰 반영 --- src/common/utils/convertQueryToString.ts | 11 ----------- src/routes/-product-list.api.ts | 14 ++++++++++---- 2 files changed, 10 insertions(+), 15 deletions(-) delete mode 100644 src/common/utils/convertQueryToString.ts diff --git a/src/common/utils/convertQueryToString.ts b/src/common/utils/convertQueryToString.ts deleted file mode 100644 index 0a3e929fc..000000000 --- a/src/common/utils/convertQueryToString.ts +++ /dev/null @@ -1,11 +0,0 @@ -/** - * @summary object를 key=value 형태의 string으로로 변환한다. - */ -export const convertQueryToString = (query: Record) => { - const queryArray = Object.entries(query) - const queryString = queryArray - .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`) - .join('&') - - return queryString -} diff --git a/src/routes/-product-list.api.ts b/src/routes/-product-list.api.ts index e0b5d2dd7..e43f44bb4 100644 --- a/src/routes/-product-list.api.ts +++ b/src/routes/-product-list.api.ts @@ -1,5 +1,3 @@ -import { convertQueryToString } from '@/common/utils/convertQueryToString' - export interface Product { id: number name: string @@ -26,8 +24,16 @@ type ProductListParams = PageQuery /** * @summary 상목목록 API */ -export const getProductList = async (query: ProductListParams): Promise => { - const response = await fetch(`/products` + `?${convertQueryToString(query)}`) +export const getProductList = async ({ + page = 0, + perCount = 15, +}: ProductListParams): Promise => { + const urlQueryParams = new URLSearchParams({ + page: page.toString(), + perCount: perCount.toString(), + }) + + const response = await fetch(`/products` + `?${urlQueryParams.toString()}`) if (!response.ok) { throw new Error('failed to getProductList') From 22a14bb440d068eb7c77b38eeea7ca0fef6ba513 Mon Sep 17 00:00:00 2001 From: saewookkang Date: Wed, 1 May 2024 15:47:01 +0900 Subject: [PATCH 33/39] =?UTF-8?q?refactor(ProductCard.tsx):=20button?= =?UTF-8?q?=EC=97=90=20type=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 코드 리뷰 반영 --- src/routes/-common/components/ProductCard/ProductCard.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/routes/-common/components/ProductCard/ProductCard.tsx b/src/routes/-common/components/ProductCard/ProductCard.tsx index cc86fabe1..8ded9988d 100644 --- a/src/routes/-common/components/ProductCard/ProductCard.tsx +++ b/src/routes/-common/components/ProductCard/ProductCard.tsx @@ -26,6 +26,7 @@ export const ProductCard = (props: ProductCardProps) => { cartListStore.actions.saveProduct(props.id) }} + type="button" > 장바구니 From 338b899a7b30918f61041d5d46ca6e921c9212fc Mon Sep 17 00:00:00 2001 From: saewookkang Date: Wed, 1 May 2024 15:51:24 +0900 Subject: [PATCH 34/39] =?UTF-8?q?chore:=20import=20=EC=88=9C=EC=84=9C=20?= =?UTF-8?q?=EC=A0=95=EB=A0=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/routes/-common/store/cartListStore/cartListStore.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/-common/store/cartListStore/cartListStore.ts b/src/routes/-common/store/cartListStore/cartListStore.ts index fc014f1f5..f613bc8b3 100644 --- a/src/routes/-common/store/cartListStore/cartListStore.ts +++ b/src/routes/-common/store/cartListStore/cartListStore.ts @@ -1,8 +1,8 @@ import { ChangeEvent, useEffect } from 'react' -import { getCookie, setCookie } from '@/common/utils/cookie' import { createStore } from '@/common/module/store/store' import { useStore } from '@/common/module/store/useStore' +import { getCookie, setCookie } from '@/common/utils/cookie' import type { Product } from '@/routes/-product-list.api' import { CART_COOKIE_KEY, CART_MAX_COUNT, CART_MIN_COUNT } from './const' From a390d6b66cfaae76514d5ede10dbd3ea5416285b Mon Sep 17 00:00:00 2001 From: saewookkang Date: Wed, 1 May 2024 15:52:32 +0900 Subject: [PATCH 35/39] =?UTF-8?q?refactor(cartListStore.ts):=20=EB=A7=A5?= =?UTF-8?q?=EB=9D=BD=EC=97=90=20=EB=A7=9E=EA=B2=8C=20=EC=82=BC=ED=95=AD?= =?UTF-8?q?=EC=97=B0=EC=82=B0=EC=9E=90(=ED=91=9C=ED=98=84=EC=8B=9D)=20->?= =?UTF-8?q?=20if=20=EB=AC=B8=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 코드 리뷰 반영 --- .../store/cartListStore/cartListStore.ts | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/routes/-common/store/cartListStore/cartListStore.ts b/src/routes/-common/store/cartListStore/cartListStore.ts index f613bc8b3..d97b61baa 100644 --- a/src/routes/-common/store/cartListStore/cartListStore.ts +++ b/src/routes/-common/store/cartListStore/cartListStore.ts @@ -29,15 +29,19 @@ export const useCartListStore = () => { const saveProduct = (id: CartItem['id']) => { const foundProduct = value.cartList.find((product) => product.id === id) - foundProduct - ? setValue((prev) => ({ - ...prev, - cartList: [ - ...prev.cartList.filter((product) => product.id !== id), - { id, count: foundProduct.count + 1 }, - ], - })) - : setValue((prev) => ({ ...prev, cartList: [...prev.cartList, { id, count: 1 }] })) + if (foundProduct) { + setValue((prev) => ({ + ...prev, + cartList: [ + ...prev.cartList.filter((product) => product.id !== id), + { id, count: foundProduct.count + 1 }, + ], + })) + + return + } + + setValue((prev) => ({ ...prev, cartList: [...prev.cartList, { id, count: 1 }] })) } const increaseCount = (id: CartItem['id']) => { From 0922dfd50edd7d83b2c2b6d5291aba53dfb02b49 Mon Sep 17 00:00:00 2001 From: saewookkang Date: Wed, 1 May 2024 15:55:01 +0900 Subject: [PATCH 36/39] =?UTF-8?q?refactor(useCartVM.ts):=20=EA=B0=92?= =?UTF-8?q?=EC=9D=98=20=EC=A1=B4=EC=9E=AC=20=EC=97=AC=EB=B6=80=20=ED=99=95?= =?UTF-8?q?=EC=9D=B8=EC=9D=84=20get=20->=20has=20=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 코드 리뷰 반영 --- src/routes/cart/-useCartVM.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/cart/-useCartVM.ts b/src/routes/cart/-useCartVM.ts index 976f58986..2cb63e27f 100644 --- a/src/routes/cart/-useCartVM.ts +++ b/src/routes/cart/-useCartVM.ts @@ -42,7 +42,7 @@ export const useCartVM = () => { setSelectedProductList((prev) => { const newMap = new Map(prev) - if (newMap.get(id)) { + if (newMap.has(id)) { newMap.delete(id) return newMap From a540fb7d72c197479ea5f4ba507c01dcf6d98183 Mon Sep 17 00:00:00 2001 From: saewookkang Date: Wed, 1 May 2024 16:43:47 +0900 Subject: [PATCH 37/39] =?UTF-8?q?refactor(ProductList.tsx):=20=EC=A0=81?= =?UTF-8?q?=EC=A0=88=ED=95=9C=20=EC=9D=98=EB=AF=B8=EB=A1=9C=20query=20key?= =?UTF-8?q?=20=EB=B3=80=EA=B2=BD=20(/posts=20->=20/products)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 코드 리뷰 반영 --- src/routes/-common/components/ProductList/ProductList.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/-common/components/ProductList/ProductList.tsx b/src/routes/-common/components/ProductList/ProductList.tsx index 127c4f9c7..8e4a5186e 100644 --- a/src/routes/-common/components/ProductList/ProductList.tsx +++ b/src/routes/-common/components/ProductList/ProductList.tsx @@ -19,7 +19,7 @@ import { ProductCard } from '../ProductCard/ProductCard' export const ProductList = () => { const { ref, inView } = useInView() const { data, status, isFetchingNextPage, hasNextPage, fetchNextPage } = useInfiniteQuery({ - queryKey: ['/posts'], + queryKey: ['/products'], queryFn: ({ pageParam }) => { return getProductList({ page: pageParam, From 33e6a475860e15a9abec9920cc039b9168bda672 Mon Sep 17 00:00:00 2001 From: saewookkang Date: Wed, 1 May 2024 18:21:09 +0900 Subject: [PATCH 38/39] =?UTF-8?q?chore(cartListStore.ts):=20=EC=8A=A4?= =?UTF-8?q?=ED=86=A0=EC=96=B4=20=EC=84=A4=EB=AA=85=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/routes/-common/store/cartListStore/cartListStore.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/routes/-common/store/cartListStore/cartListStore.ts b/src/routes/-common/store/cartListStore/cartListStore.ts index d97b61baa..3fc110ede 100644 --- a/src/routes/-common/store/cartListStore/cartListStore.ts +++ b/src/routes/-common/store/cartListStore/cartListStore.ts @@ -19,6 +19,10 @@ const cartListStore = createStore<{ cartList: initializeCookie ? JSON.parse(initializeCookie) : [], }) +/** + * @summary 브라우저의 쿠키 데이터와 장바구니 데이터를 상태로 동기화하는 레파지토리이다. + * @detail 상태 변경시 브라우저의 쿠키 데이터를 업데이트 한다. + */ export const useCartListStore = () => { const [value, setValue] = useStore(cartListStore) From 6ef1c5b6a3eca355fa6ac668d0ecf3a30d47ffa6 Mon Sep 17 00:00:00 2001 From: saewookkang Date: Wed, 1 May 2024 18:25:14 +0900 Subject: [PATCH 39/39] =?UTF-8?q?refactor(useCartVM.ts):=20querykey?= =?UTF-8?q?=EC=97=90=20=EC=A1=B4=EC=9E=AC=ED=95=98=EB=8D=98=20cartList=20?= =?UTF-8?q?=ED=82=A4=20=EC=A0=9C=EA=B1=B0=ED=95=98=EC=97=AC=20=EC=83=81?= =?UTF-8?q?=ED=92=88=20=EB=B3=80=EA=B2=BD=EC=8B=9C=20=EA=B9=9C=EB=B0=95?= =?UTF-8?q?=EC=9E=84=20=ED=98=84=EC=83=81=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - queryClient.invalidateQueries를 활용하여 백그라운드에서 데이터를 가져오도록 수정 - 액션 실행시데이터 호출을 트리거 하기 위해 데코레이터 함수로 액션 함수를 감쌈 --- src/routes/cart/-useCartVM.ts | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/src/routes/cart/-useCartVM.ts b/src/routes/cart/-useCartVM.ts index 2cb63e27f..ba1369b77 100644 --- a/src/routes/cart/-useCartVM.ts +++ b/src/routes/cart/-useCartVM.ts @@ -1,4 +1,4 @@ -import { useQuery } from '@tanstack/react-query' +import { useQuery, useQueryClient } from '@tanstack/react-query' import { useEffect, useState } from 'react' import { useCartListStore } from '../-common/store/cartListStore/cartListStore' @@ -8,10 +8,22 @@ import { CartListResponse, getCartList } from './-cart-list.api' * @summary 카트 페이지의 view model */ export const useCartVM = () => { - const { cartList, actions } = useCartListStore() + const { actions } = useCartListStore() + const queryClient = useQueryClient() + + /** + * @summary cartsQuery를 트리거한다. + */ + const cartQueryTriggerDecorator = (fn: T) => { + queryClient.invalidateQueries({ + queryKey: ['carts'], + }) + + return fn + } const cartsQuery = useQuery({ - queryKey: ['carts', cartList], + queryKey: ['carts'], queryFn: getCartList, select: (response) => { const parsed = response.list.map((product) => { @@ -78,6 +90,16 @@ export const useCartVM = () => { .reduce((acc, product) => acc + product.totalPrice, 0) .toLocaleString() + const decoratedCartListActions = Object.entries(actions).reduce( + (prev, [key, fn]) => { + return { + ...prev, + [key]: cartQueryTriggerDecorator(fn), + } + }, + {} as typeof actions + ) + return { cartsQuery, computed: { @@ -89,7 +111,7 @@ export const useCartVM = () => { toggleProduct, toggleAll, isCheckedProduct, - ...actions, + ...decoratedCartListActions, }, } }