From dca23fd29ec96095613f2fc4b51bb6b30a3071c6 Mon Sep 17 00:00:00 2001 From: Park Nayoung <139189221+im-na0@users.noreply.github.com> Date: Thu, 30 May 2024 17:25:24 +0900 Subject: [PATCH 01/23] =?UTF-8?q?feat:=20wishlist=20=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=A7=80=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/constants/path.ts | 1 + src/pages/wishListPage/WishList.tsx | 5 +++++ src/routes/lazy.ts | 2 ++ src/routes/router.tsx | 6 +++++- 4 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 src/pages/wishListPage/WishList.tsx diff --git a/src/constants/path.ts b/src/constants/path.ts index a0a993f9..7a57e59e 100644 --- a/src/constants/path.ts +++ b/src/constants/path.ts @@ -26,4 +26,5 @@ export const PATH = { RELOAD: 0, PAYMENT: (productId: string) => `/payment/${productId}`, PAYMENT_SUCCESS: (productId: string) => `/payment/${productId}/success`, + WISHLIST: "/wishlist", } as const; diff --git a/src/pages/wishListPage/WishList.tsx b/src/pages/wishListPage/WishList.tsx new file mode 100644 index 00000000..8ba1288a --- /dev/null +++ b/src/pages/wishListPage/WishList.tsx @@ -0,0 +1,5 @@ +const WishList = () => { + return
; +}; + +export default WishList; diff --git a/src/routes/lazy.ts b/src/routes/lazy.ts index 7955add4..ebb8b647 100644 --- a/src/routes/lazy.ts +++ b/src/routes/lazy.ts @@ -66,3 +66,5 @@ export const VerificationPage = lazy( export const RoomMap = lazy( () => import("@/pages/roomDetailPage/RoomDetailMap"), ); + +export const WishList = lazy(() => import("@/pages/wishListPage/WishList")); diff --git a/src/routes/router.tsx b/src/routes/router.tsx index 18233667..c31378e7 100644 --- a/src/routes/router.tsx +++ b/src/routes/router.tsx @@ -357,7 +357,7 @@ const AppRouter = () => { ), children: [ { - path: "", + index: true, element: , }, { @@ -379,6 +379,10 @@ const AppRouter = () => { }, ], }, + { + path: PATH.WISHLIST, + element: , + }, ], }, ]); From 77ade7f80e1e2b85f1939e086aad11c6c1d07b2b Mon Sep 17 00:00:00 2001 From: Park Nayoung <139189221+im-na0@users.noreply.github.com> Date: Thu, 30 May 2024 18:40:49 +0900 Subject: [PATCH 02/23] =?UTF-8?q?feat:=20heart-fill,=20heart=20svg=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/assets/icons/{ic_heart-fill.svg => heart-fill.svg} | 0 src/assets/icons/heart.svg | 3 +++ 2 files changed, 3 insertions(+) rename src/assets/icons/{ic_heart-fill.svg => heart-fill.svg} (100%) create mode 100644 src/assets/icons/heart.svg diff --git a/src/assets/icons/ic_heart-fill.svg b/src/assets/icons/heart-fill.svg similarity index 100% rename from src/assets/icons/ic_heart-fill.svg rename to src/assets/icons/heart-fill.svg diff --git a/src/assets/icons/heart.svg b/src/assets/icons/heart.svg new file mode 100644 index 00000000..392e255a --- /dev/null +++ b/src/assets/icons/heart.svg @@ -0,0 +1,3 @@ + + + From 9a14ab05eae1d69b664e1226b8b09ceb9a3178e8 Mon Sep 17 00:00:00 2001 From: Park Nayoung <139189221+im-na0@users.noreply.github.com> Date: Thu, 30 May 2024 18:41:36 +0900 Subject: [PATCH 03/23] =?UTF-8?q?feat:=20Layout=20=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=EB=84=8C=ED=8A=B8=20padding=20=ED=94=84=EB=A1=9C=ED=8D=BC?= =?UTF-8?q?=ED=8B=B0=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/layout/Layout.style.ts | 37 +++++++++++++++++-- src/components/layout/Layout.tsx | 21 ++++++----- src/components/layout/navBottom/NavBottom.tsx | 7 ++-- 3 files changed, 49 insertions(+), 16 deletions(-) diff --git a/src/components/layout/Layout.style.ts b/src/components/layout/Layout.style.ts index 979dfad9..9f25156d 100644 --- a/src/components/layout/Layout.style.ts +++ b/src/components/layout/Layout.style.ts @@ -2,9 +2,32 @@ import { styled } from "styled-components"; import type { ColorKeys } from "@/styles/theme.ts"; +import { remCalc } from "@/utils/styleFormatter.ts"; + +export type LayoutStyleProps = { + bg?: ColorKeys; + /** + * padding-top + */ + pt?: number; + /** + * padding-bottom + */ + pb?: number; + /** + * padding-block + */ + paddingBlock?: number; + /** + * padding-inline + */ + paddingInline?: number; +}; + export const Wrapper = styled.div.withConfig({ - shouldForwardProp: (prop) => prop !== "bg", -})<{ bg: ColorKeys }>` + shouldForwardProp: (prop) => + !["bg", "pt", "pb", "paddingBlock", "paddingInline"].includes(prop), +})` width: 100%; min-height: 100%; max-width: 768px; @@ -12,5 +35,13 @@ export const Wrapper = styled.div.withConfig({ position: relative; margin: 0 auto; - background-color: ${({ theme, bg }) => theme.color[bg]}; + background-color: ${({ theme, bg }) => + bg ? theme.color[bg] : theme.color.white}; + padding-top: ${({ pt }) => (pt ? `calc(56px + ${remCalc(pt)})` : undefined)}; + padding-bottom: ${({ pb }) => + pb ? `calc(78px + ${remCalc(pb)})` : undefined}; + padding-block: ${({ paddingBlock }) => + paddingBlock ? remCalc(paddingBlock) : undefined}; + padding-inline: ${({ paddingInline }) => + paddingInline ? remCalc(paddingInline) : undefined}; `; diff --git a/src/components/layout/Layout.tsx b/src/components/layout/Layout.tsx index 15b2ccd6..96011613 100644 --- a/src/components/layout/Layout.tsx +++ b/src/components/layout/Layout.tsx @@ -5,28 +5,29 @@ import * as S from "./Layout.style"; import BottomNav from "./navBottom/NavBottom"; import { A2HS } from "../A2HS/A2HS"; -import { ColorKeys } from "@/styles/theme.ts"; +import type { LayoutStyleProps } from "./Layout.style"; + import { isMobile } from "@/utils/isMobile"; -interface ChildrenProps { +interface ChildrenProps extends LayoutStyleProps { children: React.ReactNode; isHeaderOn?: boolean; isBottomNavOn?: boolean; - bg?: ColorKeys; } -const Layout = ({ - children, - isHeaderOn = false, - isBottomNavOn = false, - bg = "white", -}: ChildrenProps) => { +const Layout = (props: ChildrenProps) => { const isMobileDevice = isMobile(); + const { + isHeaderOn = false, + isBottomNavOn = false, + children, + ...rest + } = props; return ( <> {isHeaderOn &&
} - + {children} diff --git a/src/components/layout/navBottom/NavBottom.tsx b/src/components/layout/navBottom/NavBottom.tsx index 7c295c37..21b090ce 100644 --- a/src/components/layout/navBottom/NavBottom.tsx +++ b/src/components/layout/navBottom/NavBottom.tsx @@ -1,10 +1,11 @@ -import { PATH } from "@/constants/path"; -import useTooltip from "@/hooks/common/useTooltip"; import { useLocation } from "react-router-dom"; import * as S from "./NavBottom.style"; import ToolTip from "./toolTip/ToolTip"; +import { PATH } from "@/constants/path"; +import useTooltip from "@/hooks/common/useTooltip"; + interface BottomNavProps { isMobile: boolean; } @@ -18,7 +19,7 @@ const BottomNav = ({ isMobile }: BottomNavProps) => { id: 1, name: "홈", path: PATH.ROOT, - icon: , + icon: , }, { id: 2, From 32329aada8235bd51ecf3f2262ef2f696cf6bbd8 Mon Sep 17 00:00:00 2001 From: Park Nayoung <139189221+im-na0@users.noreply.github.com> Date: Thu, 30 May 2024 18:42:01 +0900 Subject: [PATCH 04/23] =?UTF-8?q?design:=20=EC=9C=84=EC=8B=9C=EB=A6=AC?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=EB=A7=88?= =?UTF-8?q?=ED=81=AC=EC=97=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/roomNavBar/RoomNavBar.style.ts | 2 +- src/pages/wishListPage/WishList.tsx | 134 +++++++++++++++++- 2 files changed, 134 insertions(+), 2 deletions(-) diff --git a/src/pages/roomDetailPage/components/roomNavBar/RoomNavBar.style.ts b/src/pages/roomDetailPage/components/roomNavBar/RoomNavBar.style.ts index 442b439f..1fdf2d0b 100644 --- a/src/pages/roomDetailPage/components/roomNavBar/RoomNavBar.style.ts +++ b/src/pages/roomDetailPage/components/roomNavBar/RoomNavBar.style.ts @@ -1,6 +1,6 @@ import styled, { css, DefaultTheme } from "styled-components"; -import IconHeart from "@/assets/icons/ic_heart-fill.svg?react"; +import IconHeart from "@/assets/icons/heart-fill.svg?react"; import { hexToRgba } from "@/utils/styleFormatter"; export { Text } from "@/pages/roomDetailPage/RoomDetail.style"; diff --git a/src/pages/wishListPage/WishList.tsx b/src/pages/wishListPage/WishList.tsx index 8ba1288a..4bc40d9a 100644 --- a/src/pages/wishListPage/WishList.tsx +++ b/src/pages/wishListPage/WishList.tsx @@ -1,5 +1,137 @@ +import styled from "styled-components"; + +import Header from "@/components/layout/header/HeaderTop.tsx"; +import Layout from "@/components/layout/Layout.tsx"; +import WishCard from "@/pages/wishListPage/components/wishCard/WishCard.tsx"; +import { WishDataType } from "@/types/wish.ts"; +import { remCalc } from "@/utils/styleFormatter.ts"; + const WishList = () => { - return
; + return ( + <> +
+ + + {mock.products.map((product, index) => ( + + ))} + + + + ); }; export default WishList; + +const ListWrapper = styled.div` + display: flex; + flex-direction: column; + gap: ${remCalc(16)}; +`; + +const mock: WishDataType = { + products: [ + { + hotelName: "롯데시그니엘", + roomType: "스탠다드 더블", + imageUrl: "https://via.placeholder.com/150", + checkInDate: "2023-11-12", + checkOutDate: "2023-11-14", + price: 2400000, + }, + { + hotelName: "롯데시그니엘", + roomType: "디럭스 트윈", + imageUrl: "https://via.placeholder.com/150", + checkInDate: "2023-11-15", + checkOutDate: "2023-11-17", + price: 2800000, + }, + { + hotelName: "신라호텔", + roomType: "스탠다드 더블", + imageUrl: "https://via.placeholder.com/150", + checkInDate: "2023-12-01", + checkOutDate: "2023-12-03", + price: 2200000, + }, + { + hotelName: "신라호텔", + roomType: "디럭스 더블", + imageUrl: "https://via.placeholder.com/150", + checkInDate: "2023-12-04", + checkOutDate: "2023-12-06", + price: 2600000, + }, + { + hotelName: "파라다이스시티", + roomType: "스탠다드 더블", + imageUrl: "https://via.placeholder.com/150", + checkInDate: "2023-11-20", + checkOutDate: "2023-11-22", + price: 2300000, + }, + { + hotelName: "파라다이스시티", + roomType: "디럭스 더블", + imageUrl: "https://via.placeholder.com/150", + checkInDate: "2023-11-25", + checkOutDate: "2023-11-27", + price: 2700000, + }, + { + hotelName: "그랜드조선", + roomType: "스탠다드 더블", + imageUrl: "https://via.placeholder.com/150", + checkInDate: "2023-11-30", + checkOutDate: "2023-12-02", + price: 2500000, + }, + { + hotelName: "그랜드조선", + roomType: "디럭스 더블", + imageUrl: "https://via.placeholder.com/150", + checkInDate: "2023-12-05", + checkOutDate: "2023-12-07", + price: 2900000, + }, + { + hotelName: "인터컨티넨탈", + roomType: "스탠다드 더블", + imageUrl: "https://via.placeholder.com/150", + checkInDate: "2023-11-18", + checkOutDate: "2023-11-20", + price: 2400000, + }, + { + hotelName: "인터컨티넨탈", + roomType: "디럭스 더블", + imageUrl: "https://via.placeholder.com/150", + checkInDate: "2023-12-08", + checkOutDate: "2023-12-10", + price: 2800000, + }, + { + hotelName: "포시즌스", + roomType: "스탠다드 더블", + imageUrl: "https://via.placeholder.com/150", + checkInDate: "2023-11-28", + checkOutDate: "2023-11-30", + price: 2600000, + }, + { + hotelName: "포시즌스", + roomType: "디럭스 더블", + imageUrl: "https://via.placeholder.com/150", + checkInDate: "2023-12-12", + checkOutDate: "2023-12-14", + price: 3000000, + }, + ], +}; From 5df34ada05260061761fddffd7b3ddb1101dffbf Mon Sep 17 00:00:00 2001 From: Park Nayoung <139189221+im-na0@users.noreply.github.com> Date: Thu, 30 May 2024 18:42:20 +0900 Subject: [PATCH 05/23] =?UTF-8?q?feat:=20=EC=B0=9C=20=EC=A1=B0=ED=9A=8C=20?= =?UTF-8?q?api=20=EC=9D=B8=ED=84=B0=ED=8E=98=EC=9D=B4=EC=8A=A4=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 --- src/types/wish.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 src/types/wish.ts diff --git a/src/types/wish.ts b/src/types/wish.ts new file mode 100644 index 00000000..4f1944b3 --- /dev/null +++ b/src/types/wish.ts @@ -0,0 +1,12 @@ +export interface WishDataType { + products: ProductType[]; +} + +export interface ProductType { + hotelName: string; + roomType: string; + imageUrl: string; + checkInDate: string; + checkOutDate: string; + price: number; +} From 25ea53408fec7e787455720bab397f46d4fb7980 Mon Sep 17 00:00:00 2001 From: Park Nayoung <139189221+im-na0@users.noreply.github.com> Date: Thu, 30 May 2024 18:42:46 +0900 Subject: [PATCH 06/23] =?UTF-8?q?design:=20=EC=9C=84=EC=8B=9C=EB=A6=AC?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=83=81=ED=92=88=EC=B9=B4=EB=93=9C=20?= =?UTF-8?q?=EB=A7=88=ED=81=AC=EC=97=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/wishCard/WishCard.styles.ts | 58 +++++++++++++++++++ .../components/wishCard/WishCard.tsx | 56 ++++++++++++++++++ 2 files changed, 114 insertions(+) create mode 100644 src/pages/wishListPage/components/wishCard/WishCard.styles.ts create mode 100644 src/pages/wishListPage/components/wishCard/WishCard.tsx diff --git a/src/pages/wishListPage/components/wishCard/WishCard.styles.ts b/src/pages/wishListPage/components/wishCard/WishCard.styles.ts new file mode 100644 index 00000000..d60e7b12 --- /dev/null +++ b/src/pages/wishListPage/components/wishCard/WishCard.styles.ts @@ -0,0 +1,58 @@ +import styled from "styled-components"; + +import { remCalc } from "@/utils/styleFormatter.ts"; + +export const CardContainer = styled.div` + border-radius: 12px; + background-color: ${({ theme }) => theme.color.white}; + + padding-block: ${remCalc(24)}; + padding-inline: ${remCalc(20)}; +`; + +export const CardWrapper = styled.div` + display: flex; + gap: 16px; +`; + +export const InfoWrapper = styled.div` + display: flex; + flex-direction: column; + justify-content: space-between; + gap: 16px; + + width: 100%; +`; + +export const Img = styled.img` + width: 100%; + height: 100%; + object-fit: cover; +`; + +export const ImgWrapper = styled.div` + max-width: 88px; + max-height: 88px; + + border-radius: 8px; + overflow: hidden; +`; + +export const TextWrapper = styled.div` + display: flex; + flex-direction: column; + gap: 4px; +`; + +export const TitleWrapper = styled.div` + display: flex; + justify-content: space-between; + align-items: flex-start; +`; + +export const LikeButton = styled.button` + & > svg { + width: 24px; + height: 24px; + } +`; diff --git a/src/pages/wishListPage/components/wishCard/WishCard.tsx b/src/pages/wishListPage/components/wishCard/WishCard.tsx new file mode 100644 index 00000000..09cd3091 --- /dev/null +++ b/src/pages/wishListPage/components/wishCard/WishCard.tsx @@ -0,0 +1,56 @@ +import { useState } from "react"; + +import * as S from "./WishCard.styles.ts"; + +import type { ProductType } from "@/types/wish.ts"; + +import HeartFill from "@/assets/icons/heart-fill.svg?react"; +import Heart from "@/assets/icons/heart.svg?react"; +import ProgressiveImg from "@/components/progressiveImg/ProgressiveImg.tsx"; +import { Typo } from "@/components/ui/typo"; +import { formatDateWithoutTime } from "@/utils/dateFormatter.ts"; + +const WishCard = ({ product }: { product: ProductType }) => { + const [likes, setLikes] = useState(true); + + const checkInDate = formatDateWithoutTime(product.checkInDate); + const checkOutDate = formatDateWithoutTime(product.checkOutDate); + + const handleToggleLike = () => { + setLikes((prev) => !prev); + }; + + return ( + + + + + + + + + {product.hotelName} + {product.roomType} + + + {likes ? : } + + + + + {checkInDate} ~ {checkOutDate} + + + {product.price.toLocaleString()}원 + + + + + + ); +}; + +export default WishCard; From 8003d8d04e7749e3a6973880943d051bf8201351 Mon Sep 17 00:00:00 2001 From: Park Nayoung <139189221+im-na0@users.noreply.github.com> Date: Thu, 30 May 2024 19:00:00 +0900 Subject: [PATCH 07/23] =?UTF-8?q?feat:=20=EC=B0=9C=20=EB=93=B1=EB=A1=9D,?= =?UTF-8?q?=20=EC=82=AD=EC=A0=9C=20api=20=EB=B0=8F=20=EC=BF=BC=EB=A6=AC=20?= =?UTF-8?q?=ED=9B=85=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/apis/fetchWish.ts | 18 ++++++++++++++++++ src/constants/api.ts | 2 ++ src/hooks/api/useWishQuery.ts | 18 ++++++++++++++++++ 3 files changed, 38 insertions(+) create mode 100644 src/apis/fetchWish.ts create mode 100644 src/hooks/api/useWishQuery.ts diff --git a/src/apis/fetchWish.ts b/src/apis/fetchWish.ts new file mode 100644 index 00000000..e2408c1c --- /dev/null +++ b/src/apis/fetchWish.ts @@ -0,0 +1,18 @@ +import type { ResponseData } from "@/types/responseType.ts"; +import type { WishDataType } from "@/types/wish.ts"; + +import { axiosInstance } from "@/apis/axiosInstance.ts"; +import { BASE_URL, END_POINTS } from "@/constants/api.ts"; + +export const deleteWish = async (productId: string): Promise => { + return await axiosInstance.delete( + `${BASE_URL}${END_POINTS.WISH(productId)}`, + ); +}; + +export const getWish = async (): Promise => { + const { data } = await axiosInstance.get>( + `${BASE_URL}${END_POINTS.WISH_LIST}`, + ); + return data.data; +}; diff --git a/src/constants/api.ts b/src/constants/api.ts index 539a11a3..f5b89bc4 100644 --- a/src/constants/api.ts +++ b/src/constants/api.ts @@ -32,6 +32,8 @@ export const END_POINTS = { SEARCH: "/v1/products/search", CHANGE_NAME: "/v1/members/name", CHANGE_NUMBER: "/v1/members/phone", + WISH_LIST: "/v1/favorites", + WISH: (productId: string) => `/v1/favorites/${productId}`, } as const; export const STATUS_CODE = { diff --git a/src/hooks/api/useWishQuery.ts b/src/hooks/api/useWishQuery.ts new file mode 100644 index 00000000..b98284f5 --- /dev/null +++ b/src/hooks/api/useWishQuery.ts @@ -0,0 +1,18 @@ +import { useMutation, useSuspenseQuery } from "@tanstack/react-query"; + +import { deleteWish, getWish } from "@/apis/fetchWish.ts"; + +export function useWishQuery() { + return useSuspenseQuery({ + queryKey: ["wish"], + queryFn: getWish, + }); +} + +export function useDeleteWishMutation() { + const { mutate } = useMutation({ + mutationFn: deleteWish, + }); + + return { deleteWish: mutate }; +} From c739886f3c4eeb5b8fbe09433c2ed27b0d60bc52 Mon Sep 17 00:00:00 2001 From: Park Nayoung <139189221+im-na0@users.noreply.github.com> Date: Thu, 30 May 2024 20:22:58 +0900 Subject: [PATCH 08/23] =?UTF-8?q?chore:=20=EB=8D=94=EB=AF=B8=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=84=B0=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/data/dummyRoomDetail.json | 32 +++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/src/mocks/data/dummyRoomDetail.json b/src/mocks/data/dummyRoomDetail.json index 6b601883..64e5a6e5 100644 --- a/src/mocks/data/dummyRoomDetail.json +++ b/src/mocks/data/dummyRoomDetail.json @@ -1,11 +1,11 @@ { "data": { "hotelName": "호텔 인 나인 강남", - "hotelImageUrl": [ - "https://yaimg.yanolja.com/v5/2023/05/17/12/1280/6464c1e2d8acc7.52423534.jpg", - "https://yaimg.yanolja.com/v5/2022/06/08/18/1280/62a0ead93af4c0.61900529.jpg" + "hotelImageUrlList":[ + "ankjdanskdnasd.jpg", + "yjptmpbtpbpe.jpg" ], - "roomName": "스탠다드 더블", + "roomName":"스탠다드 더블", "checkIn": "2023-12-24T15:00:00", "checkOut": "2023-12-25T10:00:00", "originalPrice": 400000, @@ -22,7 +22,27 @@ "hotelAddress": "서울특별시 강남구 테헤란로 99길 9", "hotelInfoUrl": "https://place-site.yanolja.com/places/3001615", "saleStatus": true, - "isSeller": false + "isSeller": false, + "roomAllRating": 4.5, + "hotelLevel": "5성급", + "sellerCommentList": [ + "사주세요", + "ㅠㅠ", + "사주세요", + "ㅠㅠ", + "사주세요", + "ㅠㅠ", + "사주세요", + "ㅠㅠ", + "사주세요", + "ㅠㅠ", + "사주세요", + "ㅠㅠ", + "사주세요", + "ㅠㅠ" + ], + "facilityInformation": "에어컨\nTV\n냉장고\n커피포트", + "isLike": true }, "message": "상품 조회에 성공했습니다." -} +} \ No newline at end of file From 32e1c7db208a2cf55259d5394ccfdb97380a2c20 Mon Sep 17 00:00:00 2001 From: Park Nayoung <139189221+im-na0@users.noreply.github.com> Date: Thu, 30 May 2024 20:23:15 +0900 Subject: [PATCH 09/23] =?UTF-8?q?chore:=20msw=20=EB=93=B1=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main.tsx | 6 ++++++ src/mocks/handlers/payment.ts | 3 ++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main.tsx b/src/main.tsx index 144117ad..2fcf33cc 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -8,6 +8,12 @@ import AppRouter from "./routes/router"; import { GlobalStyle } from "./styles/globalStyle"; import { theme } from "./styles/theme"; +import { worker } from "@/mocks/broswer.ts"; + +if (process.env.NODE_ENV === "development") { + worker.start(); +} + const queryClient = new QueryClient({ defaultOptions: { queries: { diff --git a/src/mocks/handlers/payment.ts b/src/mocks/handlers/payment.ts index e993a1b3..03ffe9df 100644 --- a/src/mocks/handlers/payment.ts +++ b/src/mocks/handlers/payment.ts @@ -1,7 +1,8 @@ +import { http, HttpResponse } from "msw"; + import { BASE_URL, END_POINTS } from "@/constants/api"; import dummyPaymentInfo from "@/mocks/data/dummyPaymentInfo.json"; import dummyPaymentSuccess from "@/mocks/data/dummyPaymentSuccess.json"; -import { http, HttpResponse } from "msw"; export const paymentHandler = [ http.get(`${BASE_URL + END_POINTS.PAYMENT(":productId")}`, () => { From 082145da4b03455169d68d196733319213446e08 Mon Sep 17 00:00:00 2001 From: Park Nayoung <139189221+im-na0@users.noreply.github.com> Date: Thu, 30 May 2024 20:24:19 +0900 Subject: [PATCH 10/23] =?UTF-8?q?design:=20=EA=B0=80=EA=B2=A9=EC=A0=9C?= =?UTF-8?q?=EC=95=88=20=ED=94=BC=EB=B4=87=20=E2=86=92=20=EB=94=94=EC=9E=90?= =?UTF-8?q?=EC=9D=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/roomDetailPage/RoomDetail.tsx | 2 +- .../components/roomNavBar/RoomNavBar.style.ts | 56 ++++++------ .../components/roomNavBar/RoomNavBar.tsx | 86 ++++++++----------- 3 files changed, 68 insertions(+), 76 deletions(-) diff --git a/src/pages/roomDetailPage/RoomDetail.tsx b/src/pages/roomDetailPage/RoomDetail.tsx index 2c7ff9fb..6c327d32 100644 --- a/src/pages/roomDetailPage/RoomDetail.tsx +++ b/src/pages/roomDetailPage/RoomDetail.tsx @@ -44,7 +44,7 @@ const RoomDetail = () => { draggable={true} /> - + ); }; diff --git a/src/pages/roomDetailPage/components/roomNavBar/RoomNavBar.style.ts b/src/pages/roomDetailPage/components/roomNavBar/RoomNavBar.style.ts index 1fdf2d0b..964f4bef 100644 --- a/src/pages/roomDetailPage/components/roomNavBar/RoomNavBar.style.ts +++ b/src/pages/roomDetailPage/components/roomNavBar/RoomNavBar.style.ts @@ -1,18 +1,19 @@ import styled, { css, DefaultTheme } from "styled-components"; -import IconHeart from "@/assets/icons/heart-fill.svg?react"; -import { hexToRgba } from "@/utils/styleFormatter"; +import breakpoints from "@/styles/breakpoints.ts"; +import { hexToRgba, remCalc } from "@/utils/styleFormatter"; export { Text } from "@/pages/roomDetailPage/RoomDetail.style"; export const Wrapper = styled.section` width: 100%; max-width: 768px; + max-height: 78px; - padding-block-start: 0.825rem; - padding-block-end: 1.875rem; + padding-block-start: ${remCalc(24)}; + padding-block-end: ${remCalc(30)}; - padding-inline: 1.25rem; + padding-inline: ${remCalc(20)}; position: fixed; bottom: 0; @@ -30,20 +31,6 @@ export const Wrapper = styled.section` z-index: 10; `; -export const Flex = styled.div` - display: flex; -`; - -export const ColWrapper = styled(Flex)` - flex-direction: column; - gap: 0.375rem; - flex: 1; -`; - -export const Row2 = styled(Flex)` - gap: 0.5rem; -`; - export type TButtonVariant = keyof ReturnType; const variantStyles = (theme: DefaultTheme) => ({ @@ -92,19 +79,34 @@ export const Button = styled.button.withConfig({ export const ButtonWrapper = styled.div` display: flex; gap: 8px; + width: 45%; - width: 70%; - - @media (max-width: ${({ theme }) => theme.breakpoints.md}) { - width: 75%; + @media (max-width: ${breakpoints.sm}) { + width: 40%; } +`; - @media (max-width: ${({ theme }) => theme.breakpoints.sm}) { - width: 100%; - } +export const TextWrapper = styled.div` + display: flex; + flex-direction: column; + gap: 2px; `; -export const Heart = styled(IconHeart)` +export const PriceWrapper = styled.div` display: flex; align-items: center; + gap: 6px; +`; + +export const Infowrapper = styled.div` + display: flex; + flex: 1; + justify-content: space-between; +`; + +export const LikeButtonWrapper = styled.div` + display: inline-flex; + align-items: center; + padding-right: 1rem; + border-right: 1px solid ${({ theme }) => theme.color.greyScale6}; `; diff --git a/src/pages/roomDetailPage/components/roomNavBar/RoomNavBar.tsx b/src/pages/roomDetailPage/components/roomNavBar/RoomNavBar.tsx index d13e2c79..a4eac288 100644 --- a/src/pages/roomDetailPage/components/roomNavBar/RoomNavBar.tsx +++ b/src/pages/roomDetailPage/components/roomNavBar/RoomNavBar.tsx @@ -5,9 +5,10 @@ import * as S from "./RoomNavBar.style"; import type { RoomNavBarData } from "@/types/room"; -import IconInfoMark from "@/assets/icons/ic_question-mark.svg?react"; +import HeartFillIcon from "@/assets/icons/heart-fill.svg?react"; import { ResponseError } from "@/components/error/Error"; import { Button } from "@/components/ui/button"; +import { Typo } from "@/components/ui/typo"; import { STATUS_CODE } from "@/constants/api"; import { PATH } from "@/constants/path"; import { useStockQuery } from "@/hooks/api/useStockQuery"; @@ -17,9 +18,10 @@ import useAuthStore from "@/store/authStore"; interface RoomNavBarProps { room: RoomNavBarData; roomId: string; + discount: string; } -const RoomNavBar = ({ room, roomId }: RoomNavBarProps) => { +const RoomNavBar = ({ room, roomId, discount }: RoomNavBarProps) => { const navigate = useNavigate(); const [error, setError] = useState(null); const isLoggedIn = useAuthStore((state) => state.isLoggedIn); @@ -64,25 +66,13 @@ const RoomNavBar = ({ room, roomId }: RoomNavBarProps) => { }; const buttonConfig = { - propose: { - buyer: { - text: "가격 제안", - action: () => console.log("가격 제안 페이지로 이동"), - }, - seller: { - text: "받은 가격 제안", - action: () => console.log("받은 가격 제안으로 이동"), - }, + buyer: { + text: "즉시 구매", + action: handlePurchaseClick, }, - purchase: { - buyer: { - text: "즉시 구매", - action: handlePurchaseClick, - }, - seller: { - text: "판매 취소", - action: () => console.log("판매 취소 로직"), - }, + seller: { + text: "판매 취소", + action: () => console.log("판매 취소 로직"), }, }; @@ -96,34 +86,34 @@ const RoomNavBar = ({ room, roomId }: RoomNavBarProps) => { return ( - - - - - + + + + + + + + {discount}% + + + {room.originalPrice.toLocaleString()}원 + + + {room.sellingPrice.toLocaleString()}원 + + + + + ); }; From cbb54d93f570ba0808c570013a49d9cb196032a9 Mon Sep 17 00:00:00 2001 From: Park Nayoung <139189221+im-na0@users.noreply.github.com> Date: Fri, 31 May 2024 01:31:27 +0900 Subject: [PATCH 11/23] =?UTF-8?q?feat:=20dialog=20ui=20=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=EB=84=8C=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/ui/dialog/dialog-content.tsx | 31 +++++++ src/components/ui/dialog/dialog-context.tsx | 21 +++++ .../ui/dialog/dialog-description.tsx | 14 +++ src/components/ui/dialog/dialog-footer.tsx | 36 ++++++++ src/components/ui/dialog/dialog-root.tsx | 86 +++++++++++++++++++ src/components/ui/dialog/dialog-title.tsx | 20 +++++ src/components/ui/dialog/dialog.styles.ts | 51 +++++++++++ src/components/ui/dialog/index.ts | 13 +++ src/components/ui/dialog/types.ts | 7 ++ 9 files changed, 279 insertions(+) create mode 100644 src/components/ui/dialog/dialog-content.tsx create mode 100644 src/components/ui/dialog/dialog-context.tsx create mode 100644 src/components/ui/dialog/dialog-description.tsx create mode 100644 src/components/ui/dialog/dialog-footer.tsx create mode 100644 src/components/ui/dialog/dialog-root.tsx create mode 100644 src/components/ui/dialog/dialog-title.tsx create mode 100644 src/components/ui/dialog/dialog.styles.ts create mode 100644 src/components/ui/dialog/index.ts create mode 100644 src/components/ui/dialog/types.ts diff --git a/src/components/ui/dialog/dialog-content.tsx b/src/components/ui/dialog/dialog-content.tsx new file mode 100644 index 00000000..23f0afd4 --- /dev/null +++ b/src/components/ui/dialog/dialog-content.tsx @@ -0,0 +1,31 @@ +import { ElementType, forwardRef, useContext } from "react"; + +import { DialogContext } from "./dialog-context.tsx"; +import { StyledDialogContent } from "./dialog.styles.ts"; + +import { + PolymorphicComponentPropsWithRef, + PolymorphicRef, +} from "@/components/ui/polymorphic"; + +type BottomSheetContentProps = + PolymorphicComponentPropsWithRef; + +export const DialogContent = forwardRef(function DialogContent< + C extends ElementType = "div", +>(props: BottomSheetContentProps, ref?: PolymorphicRef) { + const { as, children, ...rest } = props; + + const bottomSheetContext = useContext(DialogContext); + + if (!bottomSheetContext) + throw new Error( + "BottomSheet.Content must be rendered within a BottomSheet.Root.", + ); + + return ( + + {children} + + ); +}); diff --git a/src/components/ui/dialog/dialog-context.tsx b/src/components/ui/dialog/dialog-context.tsx new file mode 100644 index 00000000..ba6efdf3 --- /dev/null +++ b/src/components/ui/dialog/dialog-context.tsx @@ -0,0 +1,21 @@ +import { createContext, ReactNode, useMemo } from "react"; + +interface DialogContextProps { + onClose: () => void; +} +export const DialogContext = createContext(null); + +interface DialogProviderProps { + children: ReactNode; + onClose: () => void; +} + +export const DialogProvider = ({ children, onClose }: DialogProviderProps) => { + const ContextValue = useMemo(() => ({ onClose }), [onClose]); + + return ( + + {children} + + ); +}; diff --git a/src/components/ui/dialog/dialog-description.tsx b/src/components/ui/dialog/dialog-description.tsx new file mode 100644 index 00000000..d326d2e9 --- /dev/null +++ b/src/components/ui/dialog/dialog-description.tsx @@ -0,0 +1,14 @@ +import type { PropsWithChildren } from "react"; + +import { StyledSpaing } from "@/components/ui/dialog/dialog.styles.ts"; +import { Typo } from "@/components/ui/typo"; + +export const DialogDescription = ({ children }: PropsWithChildren) => { + return ( + + + {children} + + + ); +}; diff --git a/src/components/ui/dialog/dialog-footer.tsx b/src/components/ui/dialog/dialog-footer.tsx new file mode 100644 index 00000000..ae606d2e --- /dev/null +++ b/src/components/ui/dialog/dialog-footer.tsx @@ -0,0 +1,36 @@ +import { ElementType, forwardRef, useContext } from "react"; + +import { DialogContext } from "@/components/ui/dialog/dialog-context.tsx"; +import { StyledDialogFooter } from "@/components/ui/dialog/dialog.styles.ts"; +import { DirectionType } from "@/components/ui/dialog/types.ts"; +import { + PolymorphicComponentPropsWithRef, + PolymorphicRef, +} from "@/components/ui/polymorphic"; + +type DialogFooterProps = + PolymorphicComponentPropsWithRef & { + direction?: DirectionType; + }; + +export const DialogFooter = forwardRef(function DialogFooter< + C extends ElementType = "div", +>(props: DialogFooterProps, ref?: PolymorphicRef) { + const { as, children, direction = "horizontal", ...rest } = props; + + const dialogContext = useContext(DialogContext); + + if (!dialogContext) + throw new Error("Dialog.Footer must be rendered within a Dialog"); + + return ( + + {children} + + ); +}); diff --git a/src/components/ui/dialog/dialog-root.tsx b/src/components/ui/dialog/dialog-root.tsx new file mode 100644 index 00000000..9bb870a6 --- /dev/null +++ b/src/components/ui/dialog/dialog-root.tsx @@ -0,0 +1,86 @@ +import { AnimatePresence, motion } from "framer-motion"; +import { type ElementType, forwardRef, MouseEventHandler } from "react"; + +import { Portal } from "../portal"; + +import type { BgType } from "./types"; +import type { + PolymorphicComponentPropsWithRef, + PolymorphicRef, +} from "../polymorphic"; + +import { Dimmer } from "@/components/ui/bottom-sheet/styles.ts"; +import { DialogProvider } from "@/components/ui/dialog/dialog-context.tsx"; +import { StyledDialog } from "@/components/ui/dialog/dialog.styles.ts"; +import { + dialogAnimationVariants, + dimmerAnimationVariants, +} from "@/styles/animation"; + +type DialogProps = + PolymorphicComponentPropsWithRef< + C, + { + isOpen: boolean; + onClose: () => void; + closeOnClickDim?: boolean; + dimmer?: boolean; + bg?: BgType; + } + >; + +export const DialogRoot = forwardRef(function DialogRoot< + C extends ElementType = "div", +>(props: DialogProps, ref?: PolymorphicRef) { + const { + children, + isOpen, + closeOnClickDim = false, + onClose, + bg = "white", + ...rest + } = props; + + const onClickDimDefault: MouseEventHandler = (e): void => { + if (e.target === e.currentTarget) onClose(); + }; + + const dialogRoot = ( + + {children} + + ); + return ( + + + {isOpen && ( + + + )} + + + ); +}); diff --git a/src/components/ui/dialog/dialog-title.tsx b/src/components/ui/dialog/dialog-title.tsx new file mode 100644 index 00000000..205cdfd8 --- /dev/null +++ b/src/components/ui/dialog/dialog-title.tsx @@ -0,0 +1,20 @@ +import type { PropsWithChildren } from "react"; + +import { TextProps, Typo } from "@/components/ui/typo"; + +export const DialogTitle = ({ + children, + ...props +}: PropsWithChildren) => { + return ( + + {children} + + ); +}; diff --git a/src/components/ui/dialog/dialog.styles.ts b/src/components/ui/dialog/dialog.styles.ts new file mode 100644 index 00000000..3a4756a0 --- /dev/null +++ b/src/components/ui/dialog/dialog.styles.ts @@ -0,0 +1,51 @@ +import styled from "styled-components"; + +import { StyledFooter } from "@/components/ui/bottom-sheet/styles.ts"; +import { + BgMap, + type BgType, + type DirectionType, +} from "@/components/ui/dialog/types.ts"; +import breakpoints from "@/styles/breakpoints.ts"; +import { remCalc } from "@/utils/styleFormatter.ts"; + +export const StyledDialog = styled.div.withConfig({ + shouldForwardProp: (prop) => !["bg"].includes(prop), +})<{ bg?: BgType }>` + position: fixed; + top: 40%; + left: 0; + right: 0; + width: ${({ theme }) => theme.sizes.dialog}; + max-width: 360px; + margin-left: auto; + margin-right: auto; + + border-radius: 16px; + + background-color: ${({ theme, bg }) => + bg ? theme.color[BgMap[bg]] : theme.color.white}; + + color: ${({ theme, bg }) => + bg === BgMap.black ? theme.color.white : theme.color.black}; + box-shadow: 0px -2px 5px rgba(0, 0, 0, 0.2); + z-index: 10; + + @media (min-width: ${breakpoints.sm}) { + width: 360px; + } +`; + +export const StyledDialogContent = styled.div` + padding: ${remCalc("40px")} ${remCalc("20px")}; +`; + +export const StyledDialogFooter = styled(StyledFooter).withConfig({ + shouldForwardProp: (prop) => !["direction"].includes(prop), +})<{ direction?: DirectionType }>` + padding-bottom: 0; +`; + +export const StyledSpaing = styled.div` + margin-top: 1rem; +`; diff --git a/src/components/ui/dialog/index.ts b/src/components/ui/dialog/index.ts new file mode 100644 index 00000000..2076e899 --- /dev/null +++ b/src/components/ui/dialog/index.ts @@ -0,0 +1,13 @@ +import { DialogContent as Content } from "./dialog-content.tsx"; +import { DialogDescription as Desc } from "./dialog-description.tsx"; +import { DialogFooter as Footer } from "./dialog-footer.tsx"; +import { DialogRoot as Root } from "./dialog-root.tsx"; +import { DialogTitle as Title } from "./dialog-title.tsx"; + +export const Dialog = { + Root, + Title, + Content, + Footer, + Desc, +}; diff --git a/src/components/ui/dialog/types.ts b/src/components/ui/dialog/types.ts new file mode 100644 index 00000000..09176eff --- /dev/null +++ b/src/components/ui/dialog/types.ts @@ -0,0 +1,7 @@ +export type BgType = "white" | "black"; +export const BgMap: Record = { + white: "white", + black: "black", +}; + +export type DirectionType = "vertical" | "horizontal"; From faeb450f751c3d4ec80312bb5364e9cfb998f46a Mon Sep 17 00:00:00 2001 From: Park Nayoung <139189221+im-na0@users.noreply.github.com> Date: Fri, 31 May 2024 01:31:45 +0900 Subject: [PATCH 12/23] =?UTF-8?q?docs:=20dialog=20=EC=8A=A4=ED=86=A0?= =?UTF-8?q?=EB=A6=AC=EB=B6=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/dialog/stories/dialog.stories.tsx | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 src/components/ui/dialog/stories/dialog.stories.tsx diff --git a/src/components/ui/dialog/stories/dialog.stories.tsx b/src/components/ui/dialog/stories/dialog.stories.tsx new file mode 100644 index 00000000..b69d28ff --- /dev/null +++ b/src/components/ui/dialog/stories/dialog.stories.tsx @@ -0,0 +1,72 @@ +import { Meta, StoryFn } from "@storybook/react"; +import { useState } from "react"; + +import { Button } from "../../button"; + +import { Dialog } from "@/components/ui/dialog"; + +export default { + title: "Components/Dialog", + component: Dialog.Root, + parameters: { layout: "centered" }, + tags: ["autodocs"], + argTypes: { + closeOnClickDim: { + control: "boolean", + defaultValue: true, + }, + bg: { + control: "select", + options: ["white", "black"], + defaultValue: "white", + }, + direction: { + control: "select", + options: ["vertical", "horizontal"], + defaultValue: "horizontal", + }, + }, +} as Meta; + +const Template: StoryFn = (args) => { + const [isOpen, setIsOpen] = useState(false); + + return ( + <> + + setIsOpen(false)} + bg={args.bg} + closeOnClickDim={args.closeOnClickDim} + > + + Example Dialog + Here's some content in the dialog. + + + + + + + + ); +}; + +export const Default = Template.bind({}); From 36784d20e9fcdd160f8c1be9fa9c868f998349e6 Mon Sep 17 00:00:00 2001 From: Park Nayoung <139189221+im-na0@users.noreply.github.com> Date: Fri, 31 May 2024 01:32:10 +0900 Subject: [PATCH 13/23] =?UTF-8?q?feat:=20dialog=20animation=20=EC=83=81?= =?UTF-8?q?=EC=88=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/styles/animation.ts | 28 ++++++++++++++++++++++++++++ src/styles/sizes.ts | 1 + 2 files changed, 29 insertions(+) diff --git a/src/styles/animation.ts b/src/styles/animation.ts index 57d2d0af..b54532d7 100644 --- a/src/styles/animation.ts +++ b/src/styles/animation.ts @@ -3,6 +3,7 @@ import { Variants } from "framer-motion"; export const dimmerAnimationVariants = { initial: { opacity: 0, transition: { duration: 0.15 } }, animate: { opacity: 1, transition: { duration: 0.15 } }, + exit: { opacity: 0, transition: { duration: 0.15 } }, }; export const bottomSheetTransition = { @@ -28,3 +29,30 @@ export const bottomSheetAnimationVariants: Variants = { willChange: "y", }, }; + +export const dialogTransition = { + opacity: { duration: 0.15 }, + transform: { + duration: 0.25, + type: "tween", + ease: [0.32, 0.72, 0, 1], + }, +}; + +export const dialogAnimationVariants: Variants = { + animate: { + opacity: 1, + transform: "translate3d(0, 0, 0) scale3d(1, 1, 1)", + transition: dialogTransition, + }, + exit: { + opacity: 0, + transform: "translate3d(0, 10px, 0) scale3d(0.95, 0.95, 0.95)", + transition: dialogTransition, + }, + initial: { + opacity: 1, + transform: "translate3d(0, -10px, 0) scale3d(0.95, 0.95, 0.95)", + transition: dialogTransition, + }, +}; diff --git a/src/styles/sizes.ts b/src/styles/sizes.ts index 6c583cb2..df7a3f8a 100644 --- a/src/styles/sizes.ts +++ b/src/styles/sizes.ts @@ -2,6 +2,7 @@ import { spacing } from "./spacing"; const overlay = { sheet: "518px", + dialog: "240px", }; const container = { From 887854035be2ddfe3c635f24963db9409e51622d Mon Sep 17 00:00:00 2001 From: Park Nayoung <139189221+im-na0@users.noreply.github.com> Date: Fri, 31 May 2024 01:32:30 +0900 Subject: [PATCH 14/23] =?UTF-8?q?chore:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=EB=A1=9C=EA=B9=85=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/ui/button/styles/colorScheme.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/ui/button/styles/colorScheme.ts b/src/components/ui/button/styles/colorScheme.ts index e5791cb2..7c3950db 100644 --- a/src/components/ui/button/styles/colorScheme.ts +++ b/src/components/ui/button/styles/colorScheme.ts @@ -1,5 +1,5 @@ import { type ElementType } from "react"; -import { type CSSProp, css } from "styled-components"; +import { css, type CSSProp } from "styled-components"; import { type ButtonColorScheme, @@ -169,7 +169,6 @@ export const getColorScheme = ( >["colorScheme"] = "orange", variant: Pick, "variant">["variant"] = "solid", ) => { - console.log("Color Scheme:", colorScheme, "Variant:", variant); return BUTTON_COLOR_SCHEME_MAP[colorScheme as ButtonColorScheme][ variant as keyof ColorSchemeWithVariant ]; From 9bf427e4d9341ec5aa8154fa4496eaba0c74f32d Mon Sep 17 00:00:00 2001 From: im-na0 <139189221+im-na0@users.noreply.github.com> Date: Sun, 9 Jun 2024 19:35:16 +0900 Subject: [PATCH 15/23] =?UTF-8?q?design:=20dialog=20bg=20=EA=B4=80?= =?UTF-8?q?=EB=A6=AC=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/ui/dialog/dialog-content.tsx | 15 ++++++++-- src/components/ui/dialog/dialog-context.tsx | 12 ++++++-- src/components/ui/dialog/dialog-root.tsx | 3 +- src/components/ui/dialog/dialog.styles.ts | 32 +++++++++++---------- 4 files changed, 40 insertions(+), 22 deletions(-) diff --git a/src/components/ui/dialog/dialog-content.tsx b/src/components/ui/dialog/dialog-content.tsx index 23f0afd4..733ca8ec 100644 --- a/src/components/ui/dialog/dialog-content.tsx +++ b/src/components/ui/dialog/dialog-content.tsx @@ -1,4 +1,5 @@ import { ElementType, forwardRef, useContext } from "react"; +import { type CSSProp } from "styled-components"; import { DialogContext } from "./dialog-context.tsx"; import { StyledDialogContent } from "./dialog.styles.ts"; @@ -9,12 +10,14 @@ import { } from "@/components/ui/polymorphic"; type BottomSheetContentProps = - PolymorphicComponentPropsWithRef; + PolymorphicComponentPropsWithRef & { + css?: CSSProp; + }; export const DialogContent = forwardRef(function DialogContent< C extends ElementType = "div", >(props: BottomSheetContentProps, ref?: PolymorphicRef) { - const { as, children, ...rest } = props; + const { as, children, css, ...rest } = props; const bottomSheetContext = useContext(DialogContext); @@ -24,7 +27,13 @@ export const DialogContent = forwardRef(function DialogContent< ); return ( - + {children} ); diff --git a/src/components/ui/dialog/dialog-context.tsx b/src/components/ui/dialog/dialog-context.tsx index ba6efdf3..fcd27397 100644 --- a/src/components/ui/dialog/dialog-context.tsx +++ b/src/components/ui/dialog/dialog-context.tsx @@ -1,17 +1,25 @@ import { createContext, ReactNode, useMemo } from "react"; +import { type BgType } from "./types"; + interface DialogContextProps { onClose: () => void; + bg: BgType; } export const DialogContext = createContext(null); interface DialogProviderProps { children: ReactNode; onClose: () => void; + bg: BgType; } -export const DialogProvider = ({ children, onClose }: DialogProviderProps) => { - const ContextValue = useMemo(() => ({ onClose }), [onClose]); +export const DialogProvider = ({ + children, + onClose, + bg, +}: DialogProviderProps) => { + const ContextValue = useMemo(() => ({ onClose, bg }), [onClose, bg]); return ( diff --git a/src/components/ui/dialog/dialog-root.tsx b/src/components/ui/dialog/dialog-root.tsx index 9bb870a6..1ef7691c 100644 --- a/src/components/ui/dialog/dialog-root.tsx +++ b/src/components/ui/dialog/dialog-root.tsx @@ -50,7 +50,6 @@ export const DialogRoot = forwardRef(function DialogRoot< role="dialog" tabindex="-1" ref={ref} - bg={bg} as={motion.div} key="dialog" initial="initial" @@ -66,7 +65,7 @@ export const DialogRoot = forwardRef(function DialogRoot< {isOpen && ( - + !["bg"].includes(prop), -})<{ bg?: BgType }>` +export const StyledDialog = styled.div` position: fixed; - top: 40%; + top: 50%; left: 0; right: 0; width: ${({ theme }) => theme.sizes.dialog}; @@ -21,14 +19,7 @@ export const StyledDialog = styled.div.withConfig({ margin-left: auto; margin-right: auto; - border-radius: 16px; - - background-color: ${({ theme, bg }) => - bg ? theme.color[BgMap[bg]] : theme.color.white}; - - color: ${({ theme, bg }) => - bg === BgMap.black ? theme.color.white : theme.color.black}; - box-shadow: 0px -2px 5px rgba(0, 0, 0, 0.2); + transform: translateY(-50%); z-index: 10; @media (min-width: ${breakpoints.sm}) { @@ -36,8 +27,19 @@ export const StyledDialog = styled.div.withConfig({ } `; -export const StyledDialogContent = styled.div` +export const StyledDialogContent = styled.div.withConfig({ + shouldForwardProp: (prop) => !["css", "bg"].includes(prop), +})<{ css?: CSSProp; bg?: BgType }>` + background-color: ${({ theme, bg }) => + bg ? theme.color[BgMap[bg]] : theme.color.white}; + color: ${({ theme, bg }) => + bg === BgMap.black ? theme.color.white : theme.color.black}; + padding: ${remCalc("40px")} ${remCalc("20px")}; + border-radius: 16px; + box-shadow: 0px -2px 5px rgba(0, 0, 0, 0.2); + + ${({ css }) => css}; `; export const StyledDialogFooter = styled(StyledFooter).withConfig({ @@ -46,6 +48,6 @@ export const StyledDialogFooter = styled(StyledFooter).withConfig({ padding-bottom: 0; `; -export const StyledSpaing = styled.div` +export const StyledSpacing = styled.div` margin-top: 1rem; `; From e867b3b070923f7e5a2284ea6a1e31cc4b105ca8 Mon Sep 17 00:00:00 2001 From: im-na0 <139189221+im-na0@users.noreply.github.com> Date: Sun, 9 Jun 2024 19:36:37 +0900 Subject: [PATCH 16/23] =?UTF-8?q?refactor:=20dialog=20default=20props=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/ui/dialog/dialog-description.tsx | 16 ++++++++++------ src/components/ui/dialog/dialog-title.tsx | 13 ++++--------- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/components/ui/dialog/dialog-description.tsx b/src/components/ui/dialog/dialog-description.tsx index d326d2e9..b32eb801 100644 --- a/src/components/ui/dialog/dialog-description.tsx +++ b/src/components/ui/dialog/dialog-description.tsx @@ -1,14 +1,18 @@ import type { PropsWithChildren } from "react"; -import { StyledSpaing } from "@/components/ui/dialog/dialog.styles.ts"; -import { Typo } from "@/components/ui/typo"; +import { StyledSpacing } from "@/components/ui/dialog/dialog.styles.ts"; +import { type TextProps, Typo } from "@/components/ui/typo"; -export const DialogDescription = ({ children }: PropsWithChildren) => { +export const DialogDescription = ({ + children, + ...props +}: PropsWithChildren>) => { + const { typo = "body2", color = "greyScale3" } = props; return ( - - + + {children} - + ); }; diff --git a/src/components/ui/dialog/dialog-title.tsx b/src/components/ui/dialog/dialog-title.tsx index 205cdfd8..2f87b052 100644 --- a/src/components/ui/dialog/dialog-title.tsx +++ b/src/components/ui/dialog/dialog-title.tsx @@ -1,19 +1,14 @@ import type { PropsWithChildren } from "react"; -import { TextProps, Typo } from "@/components/ui/typo"; +import { type TextProps, Typo } from "@/components/ui/typo"; export const DialogTitle = ({ children, ...props -}: PropsWithChildren) => { +}: PropsWithChildren>) => { + const { typo = "title3", color = "greyScale1" } = props; return ( - + {children} ); From b6d2681a6b99e1ff924788d150b641752e7eedd8 Mon Sep 17 00:00:00 2001 From: im-na0 <139189221+im-na0@users.noreply.github.com> Date: Sun, 9 Jun 2024 19:36:55 +0900 Subject: [PATCH 17/23] =?UTF-8?q?design:=20dimmer=20width,=20height=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/ui/bottom-sheet/styles.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/components/ui/bottom-sheet/styles.ts b/src/components/ui/bottom-sheet/styles.ts index 2a427bdc..1fe1a7de 100644 --- a/src/components/ui/bottom-sheet/styles.ts +++ b/src/components/ui/bottom-sheet/styles.ts @@ -138,8 +138,6 @@ export const Dimmer = styled.div` bottom: 0; left: 0; right: 0; - width: 100%; - height: 100%; overflow: hidden; outline: 0; From 8abeb7221422e0274421bb1f8717315425be1f65 Mon Sep 17 00:00:00 2001 From: im-na0 <139189221+im-na0@users.noreply.github.com> Date: Sun, 9 Jun 2024 19:37:13 +0900 Subject: [PATCH 18/23] =?UTF-8?q?feat:=20mini-alert-dialog=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/dialog/templates/mini-alert-dialog.tsx | 134 ++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 src/components/ui/dialog/templates/mini-alert-dialog.tsx diff --git a/src/components/ui/dialog/templates/mini-alert-dialog.tsx b/src/components/ui/dialog/templates/mini-alert-dialog.tsx new file mode 100644 index 00000000..5129d66e --- /dev/null +++ b/src/components/ui/dialog/templates/mini-alert-dialog.tsx @@ -0,0 +1,134 @@ +import styled, { css } from "styled-components"; + +import { Dialog } from "@/components/ui/dialog"; +import { Typo } from "@/components/ui/typo"; + +interface DialogProps { + isOpen: boolean; + onClose: () => void; + title: string; + description?: string; + closeText?: string; + closeFn?: () => void; + actionText: string; + actionFn: () => void; +} + +const MiniAlertDialog = ({ + isOpen, + onClose, + title, + description, + actionText, + actionFn, + closeText, + closeFn, +}: DialogProps) => { + return ( + + + + {title} + + {description && ( + + + {description} + + + )} + + + + {closeText && ( + + )} + + + ); +}; + +export default MiniAlertDialog; + +const DialogContentStyle = css` + padding: 1.25rem 1.5rem 1rem; + border-top-right-radius: 12px; + border-top-left-radius: 12px; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +`; + +const getVariants = (variant: "action" | "close") => { + switch (variant) { + case "action": + return css` + background-color: ${({ theme }) => theme.color.percentOrange}; + color: ${({ theme }) => theme.color.white}; + + &:hover { + background-color: ${({ theme }) => theme.color.darkOrange}; + } + `; + case "close": + return css` + background-color: ${({ theme }) => theme.color.greyScale6}; + color: ${({ theme }) => theme.color.greyScale1}; + + &:hover { + background-color: ${({ theme }) => theme.color.greyScale5}; + } + `; + default: + } +}; + +const ButtonGroup = styled.div` + display: flex; +`; + +const Button = styled.button.withConfig({ + shouldForwardProp: (prop) => !["variants", "roundedCorners"].includes(prop), +})<{ variants: "action" | "close"; roundedCorners: "left" | "right" | "both" }>` + flex: 1; + padding: 10px 20px; + ${({ theme }) => theme.typo.button4}; + ${({ variants }) => getVariants(variants)}; + border: none; + cursor: pointer; + + ${({ roundedCorners }) => { + switch (roundedCorners) { + case "both": + return css` + border-radius: 12px; + `; + case "left": + return css` + border-bottom-left-radius: 12px; + `; + case "right": + return css` + border-bottom-right-radius: 12px; + `; + default: + return css``; + } + }} +`; + +const Spacing = styled.div` + margin-top: 8px; +`; From dd7127779f0eaec8c92389e7d9455b84395682c0 Mon Sep 17 00:00:00 2001 From: im-na0 <139189221+im-na0@users.noreply.github.com> Date: Sun, 9 Jun 2024 19:37:39 +0900 Subject: [PATCH 19/23] =?UTF-8?q?docs:=20mini-alert-dialog=20=EC=8A=A4?= =?UTF-8?q?=ED=86=A0=EB=A6=AC=EB=B6=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/dialog/stories/dialog.stories.tsx | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/src/components/ui/dialog/stories/dialog.stories.tsx b/src/components/ui/dialog/stories/dialog.stories.tsx index b69d28ff..41a2e686 100644 --- a/src/components/ui/dialog/stories/dialog.stories.tsx +++ b/src/components/ui/dialog/stories/dialog.stories.tsx @@ -2,6 +2,7 @@ import { Meta, StoryFn } from "@storybook/react"; import { useState } from "react"; import { Button } from "../../button"; +import MiniAlertDialog from "../templates/mini-alert-dialog"; import { Dialog } from "@/components/ui/dialog"; @@ -28,7 +29,7 @@ export default { }, } as Meta; -const Template: StoryFn = (args) => { +const DefaultTemplate: StoryFn = (args) => { const [isOpen, setIsOpen] = useState(false); return ( @@ -69,4 +70,30 @@ const Template: StoryFn = (args) => { ); }; -export const Default = Template.bind({}); +export const Default = DefaultTemplate.bind({}); + +const MiniAlertTemplate: StoryFn = () => { + const [isOpen, setIsOpen] = useState(false); + + return ( + <> + + setIsOpen(false)} + title={"판매를 취소할까요?"} + description={ + "판매를 취소하시면 판매내역을 조회하거나 복구할 수 없어요." + } + actionFn={() => alert("확인했습니다")} + actionText={"확인"} + closeFn={() => setIsOpen(false)} + closeText={"닫기"} + /> + + ); +}; + +export const MiniAlert = MiniAlertTemplate.bind({}); From 3ea9a0ef2748bcc5e15d3c4918136a54f6e8ee47 Mon Sep 17 00:00:00 2001 From: im-na0 <139189221+im-na0@users.noreply.github.com> Date: Sun, 9 Jun 2024 19:38:02 +0900 Subject: [PATCH 20/23] =?UTF-8?q?design:=20dialog=20variants=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/styles/animation.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/styles/animation.ts b/src/styles/animation.ts index b54532d7..75f1ca5c 100644 --- a/src/styles/animation.ts +++ b/src/styles/animation.ts @@ -39,20 +39,20 @@ export const dialogTransition = { }, }; -export const dialogAnimationVariants: Variants = { +export const dialogAnimationVariants = { animate: { opacity: 1, - transform: "translate3d(0, 0, 0) scale3d(1, 1, 1)", + transform: "translate3d(0, -50%, 0) scale3d(1, 1, 1)", transition: dialogTransition, }, exit: { opacity: 0, - transform: "translate3d(0, 10px, 0) scale3d(0.95, 0.95, 0.95)", + transform: "translate3d(0, -48%, 0) scale3d(0.95, 0.95, 0.95)", transition: dialogTransition, }, initial: { opacity: 1, - transform: "translate3d(0, -10px, 0) scale3d(0.95, 0.95, 0.95)", + transform: "translate3d(0, -48%, 0) scale3d(0.95, 0.95, 0.95)", transition: dialogTransition, }, }; From 044ccc60d79afc5845ee5637326112b1a051f6e4 Mon Sep 17 00:00:00 2001 From: im-na0 <139189221+im-na0@users.noreply.github.com> Date: Sun, 9 Jun 2024 19:38:15 +0900 Subject: [PATCH 21/23] =?UTF-8?q?design:=20greyScale1=20=EA=B0=92=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/styles/color.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/styles/color.ts b/src/styles/color.ts index cf84b85a..177ace04 100644 --- a/src/styles/color.ts +++ b/src/styles/color.ts @@ -13,7 +13,7 @@ const color = { yanoljaPink: "#FF3478", cautionRed: "#FF4949", - greyScale1: "hsl(240 3.8% 46.1%)", + greyScale1: "#404040", greyScale2: "#686868", greyScale3: "#999999", greyScale4: "#B8B8B8", From c81f56276134af049df59745ff4a96be80a7181d Mon Sep 17 00:00:00 2001 From: im-na0 <139189221+im-na0@users.noreply.github.com> Date: Sun, 9 Jun 2024 19:39:07 +0900 Subject: [PATCH 22/23] =?UTF-8?q?chore:=20use-overlay=20=EC=9D=98=EC=A1=B4?= =?UTF-8?q?=EC=84=B1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 10 ++++++++++ package.json | 1 + src/main.tsx | 5 ++++- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index 94301634..0e1f07f8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -45,6 +45,7 @@ "@tanstack/react-query-devtools": "^5.17.9", "@testing-library/jest-dom": "^6.1.6", "@testing-library/react": "^14.1.2", + "@toss/use-overlay": "^1.4.0", "@types/jest": "^29.5.11", "@types/node": "^20.10.5", "@types/react": "^18.2.43", @@ -6668,6 +6669,15 @@ "@testing-library/dom": ">=7.21.4" } }, + "node_modules/@toss/use-overlay": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@toss/use-overlay/-/use-overlay-1.4.0.tgz", + "integrity": "sha512-1fkKRwUWaPn1fPTHeYiOdnQu4j6sHLDfJZS1smsarPxWxUlr1+FikNIjzYQGAVXgNjxw0cqNfKR4HvVSsM5w3A==", + "dev": true, + "peerDependencies": { + "react": "^16.8 || ^17 || ^18" + } + }, "node_modules/@tsconfig/node10": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", diff --git a/package.json b/package.json index a5d1e145..6dd12118 100644 --- a/package.json +++ b/package.json @@ -62,6 +62,7 @@ "@tanstack/react-query-devtools": "^5.17.9", "@testing-library/jest-dom": "^6.1.6", "@testing-library/react": "^14.1.2", + "@toss/use-overlay": "^1.4.0", "@types/jest": "^29.5.11", "@types/node": "^20.10.5", "@types/react": "^18.2.43", diff --git a/src/main.tsx b/src/main.tsx index 2fcf33cc..e9017fbc 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -1,5 +1,6 @@ import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { ReactQueryDevtools } from "@tanstack/react-query-devtools"; +import { OverlayProvider } from "@toss/use-overlay"; import ReactDOM from "react-dom/client"; import { HelmetProvider } from "react-helmet-async"; import { ThemeProvider } from "styled-components"; @@ -46,7 +47,9 @@ if (rootElement?.hasChildNodes()) { - + + + From c723d6deb51f031067135bce74da44fc98a9d68b Mon Sep 17 00:00:00 2001 From: im-na0 <139189221+im-na0@users.noreply.github.com> Date: Thu, 13 Jun 2024 23:15:09 +0900 Subject: [PATCH 23/23] =?UTF-8?q?chore:=20package-lock.json=20=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-lock.json | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0e1f07f8..8ea8a90b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2442,22 +2442,6 @@ "react": ">=16.8.0" } }, - "node_modules/@esbuild/win32-x64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.11.tgz", - "integrity": "sha512-vfkhltrjCAb603XaFhqhAF4LGDi2M4OrCRrFusyQ+iTLQ/o60QQXxc9cZC/FFpihBI9N1Grn6SMKVJ4KP7Fuiw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",