From f99a69b82b21c40434aa55666fca555ab9cd6b89 Mon Sep 17 00:00:00 2001 From: J'aimemin <61978339+Kim-Jaemin420@users.noreply.github.com> Date: Fri, 9 Feb 2024 04:51:15 +0900 Subject: [PATCH] =?UTF-8?q?[#121]=20Feat:=20=EB=9E=9C=EB=8D=A4=20=EB=96=A1?= =?UTF-8?q?=EA=B5=AD=20=EB=B0=A9=EB=AC=B8=20=EA=B5=AC=ED=98=84=20=EB=B0=8F?= =?UTF-8?q?=20=EB=96=A1=EA=B5=AD=20=EC=A0=9C=EC=9E=91=20=EC=84=B1=EA=B3=B5?= =?UTF-8?q?=20=EB=AA=A8=EB=8B=AC=20=EA=B5=AC=ED=98=84=20(#123)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/apis/core.ts | 6 ++ src/apis/tteokguk.ts | 2 + src/assets/svg/activity.svg | 7 -- src/assets/svg/big-activity.svg | 7 ++ src/assets/svg/small-activity.svg | 7 ++ src/components/common/TteokgukImage.tsx | 3 +- src/components/shared/GuideModal.tsx | 2 +- .../SuccessfulTteokgukCreationModal.tsx | 90 +++++++++++++++++++ src/components/shared/WelcomeModal.tsx | 7 +- src/pages/EmailLoginPage.tsx | 2 +- src/pages/MyPage.tsx | 6 +- src/pages/TteokgukCookingPage.tsx | 21 +++-- src/pages/TteokgukPage.tsx | 19 +++- src/store/tteokguk.ts | 11 ++- src/types/myActivity.ts | 3 +- src/types/tteokguk.dto.ts | 26 +----- src/types/tteokguk.ts | 6 +- 17 files changed, 171 insertions(+), 54 deletions(-) delete mode 100644 src/assets/svg/activity.svg create mode 100644 src/assets/svg/big-activity.svg create mode 100644 src/assets/svg/small-activity.svg create mode 100644 src/components/shared/SuccessfulTteokgukCreationModal.tsx diff --git a/src/apis/core.ts b/src/apis/core.ts index 04633bbf..aa612cbd 100644 --- a/src/apis/core.ts +++ b/src/apis/core.ts @@ -40,6 +40,10 @@ const setAuthHeader = async (request: Request) => { }; const getToken = async (accessToken: string, refreshToken: string) => { + if (!accessToken) { + return; + } + if (!isExpiredToken(accessToken)) { return accessToken; } @@ -50,6 +54,8 @@ const getToken = async (accessToken: string, refreshToken: string) => { removeLocalStorage("accessToken"); removeLocalStorage("refreshToken"); + + window.location.href = "/"; }; const refreshAccessToken = async (token: string) => { diff --git a/src/apis/tteokguk.ts b/src/apis/tteokguk.ts index f7f4ce97..004e4339 100644 --- a/src/apis/tteokguk.ts +++ b/src/apis/tteokguk.ts @@ -24,3 +24,5 @@ export const postTteokguk = (tteokguk: PostTteokgukRequest) => http.post("api/v1/tteokguk", tteokguk); export const deleteTteokguk = (id: number) => http.delete(`api/v1/tteokguk/${id}`); + +export const getRandomTteokguk = () => http.get("api/v1/tteokguk/random"); diff --git a/src/assets/svg/activity.svg b/src/assets/svg/activity.svg deleted file mode 100644 index a4733d3a..00000000 --- a/src/assets/svg/activity.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/src/assets/svg/big-activity.svg b/src/assets/svg/big-activity.svg new file mode 100644 index 00000000..caf08468 --- /dev/null +++ b/src/assets/svg/big-activity.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/assets/svg/small-activity.svg b/src/assets/svg/small-activity.svg new file mode 100644 index 00000000..caf08468 --- /dev/null +++ b/src/assets/svg/small-activity.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/components/common/TteokgukImage.tsx b/src/components/common/TteokgukImage.tsx index c6e65be1..f399baa2 100644 --- a/src/components/common/TteokgukImage.tsx +++ b/src/components/common/TteokgukImage.tsx @@ -5,13 +5,14 @@ import classNames from "classnames"; import { css } from "@styled-system/css"; import { IngredientKey } from "@/types/ingredient"; +import { TteokgukBackgroudColor } from "@/types/tteokguk"; import { BACKGROUND_COLOR, GARNISHES } from "@/constants/garnish"; import { INGREDIENT_NAME_BY_KEY } from "@/constants/ingredient"; interface Props { completion: boolean; - backgroundColor: "BLUE" | "GREEN" | "PINK" | "YELLOW"; + backgroundColor: TteokgukBackgroudColor; frontGarnish: IngredientKey; backGarnish: IngredientKey; } diff --git a/src/components/shared/GuideModal.tsx b/src/components/shared/GuideModal.tsx index e8a47d6b..12d6baa9 100644 --- a/src/components/shared/GuideModal.tsx +++ b/src/components/shared/GuideModal.tsx @@ -79,11 +79,11 @@ const styles = { display: "flex", flexDirection: "column", alignItems: "center", + width: "100%", }), content: css({ fontSize: "1.4rem", textAlign: "center", - paddingX: "3rem", whiteSpace: "pre-line", }), imageContainer: css({ diff --git a/src/components/shared/SuccessfulTteokgukCreationModal.tsx b/src/components/shared/SuccessfulTteokgukCreationModal.tsx new file mode 100644 index 00000000..b46895ec --- /dev/null +++ b/src/components/shared/SuccessfulTteokgukCreationModal.tsx @@ -0,0 +1,90 @@ +import { css } from "@styled-system/css"; + +import { TteokgukBackgroudColor } from "@/types/tteokguk"; +import { IngredientKey } from "@/types/ingredient"; + +import Button from "../common/Button"; + +import TteokgukImage from "@/components/common/TteokgukImage"; +import Modal from "@/components/common/modal/Modal"; +import useRouter from "@/routes/useRouter"; + +interface Props { + isOpen: boolean; + onClose: () => void; + tteokgukId?: number; + isCompletion?: boolean; + nickname?: string; + tteokgukBackgroundColor: TteokgukBackgroudColor; + frontGarnish: IngredientKey; + backGarnish: IngredientKey; +} + +const SuccessfulTteokgukCreationModal = ({ + isOpen, + onClose, + tteokgukId, + isCompletion = false, + nickname, + tteokgukBackgroundColor, + frontGarnish, + backGarnish, +}: Props) => { + const router = useRouter(); + + const handleClickButton = () => { + onClose(); + + if (!isCompletion && tteokgukId) { + router.push(`/tteokguks/${tteokgukId}`); + } + }; + + return ( + isOpen && ( + + + {isCompletion ? "소원 떡국이 완성되었어요!" : "소원 떡국 제작 성공!"} + + +
+
+ {isCompletion + ? `${nickname}님의 새해 소원, 이루어져라 얍✨` + : "내 재료와 친구들의 응원으로 떡국을 완성해보세요!"} +
+
+ +
+ +
+
+
+ ) + ); +}; + +export default SuccessfulTteokgukCreationModal; + +const styles = { + description: css({ + fontSize: "1.4rem", + marginTop: "0.8rem", + }), + imageContainer: css({ + position: "relative", + width: "100%", + height: "21rem", + overflow: "hidden", + borderRadius: "0.8rem", + marginTop: "2.4rem", + marginBottom: "3.8rem", + }), +}; diff --git a/src/components/shared/WelcomeModal.tsx b/src/components/shared/WelcomeModal.tsx index 684ce577..8755bf00 100644 --- a/src/components/shared/WelcomeModal.tsx +++ b/src/components/shared/WelcomeModal.tsx @@ -88,6 +88,7 @@ const styles = { display: "flex", flexDirection: "column", alignItems: "center", + width: "100%", }), content: css({ fontSize: "1.4rem", @@ -106,8 +107,8 @@ const styles = { marginBottom: "2rem", }), icon: css({ - width: "100%", // 컨테이너의 너비에 맞춤 - height: "100%", // 컨테이너의 높이에 맞춤 - objectFit: "contain", // 아이콘의 원래 비율을 유지 + width: "100%", + height: "100%", + objectFit: "contain", }), }; diff --git a/src/pages/EmailLoginPage.tsx b/src/pages/EmailLoginPage.tsx index 2cdcb215..8baea821 100644 --- a/src/pages/EmailLoginPage.tsx +++ b/src/pages/EmailLoginPage.tsx @@ -94,7 +94,7 @@ const styles = { position: "relative", display: "flex", flexDirection: "column", - marginY: "auto", + marginTop: "0.8rem", }), emailInput: css({ marginBottom: "1.6rem", diff --git a/src/pages/MyPage.tsx b/src/pages/MyPage.tsx index 591b0c2a..c48a41c1 100644 --- a/src/pages/MyPage.tsx +++ b/src/pages/MyPage.tsx @@ -20,7 +20,7 @@ import IconButton from "@/components/common/IconButton"; import TteokgukList from "@/components/common/TteokgukList"; import IngredientList from "@/components/Mypage/IngredientList"; import VisitIcon from "@/assets/svg/visit.svg"; -import ActivityIcon from "@/assets/svg/activity.svg"; +import BigActivityIcon from "@/assets/svg/big-activity.svg"; import Loading from "@/components/common/Loading"; const MyPage = () => { @@ -29,7 +29,7 @@ const MyPage = () => { const { mutate: deleteLoggedInUser } = useAtomValue($deleteLoggedInUser); const { refetch: refetchRandomUserDetails } = useAtomValue($getRandomUserDetails); const { invalidateQueries } = useAtomValue(queryClientAtom); - const { confirm } = useDialog(); + const { confirm, alert } = useDialog(); if (isPending) { return ( @@ -164,7 +164,7 @@ const MyPage = () => { - + 활동 내역 diff --git a/src/pages/TteokgukCookingPage.tsx b/src/pages/TteokgukCookingPage.tsx index 6060beae..fbceb753 100644 --- a/src/pages/TteokgukCookingPage.tsx +++ b/src/pages/TteokgukCookingPage.tsx @@ -2,13 +2,12 @@ import { ChangeEvent, FormEvent, useState } from "react"; import { useAtomValue } from "jotai"; import { toast } from "sonner"; +import { useOverlay } from "@toss/use-overlay"; import { css } from "@styled-system/css"; import { IngredientKey } from "@/types/ingredient"; -import { PostTteokgukResponse } from "@/types/tteokguk.dto"; -import useRouter from "@/routes/useRouter"; import { $postTteokguk } from "@/store/tteokguk"; import Button from "@/components/common/Button"; import Header from "@/components/common/Header"; @@ -23,13 +22,14 @@ import { INGREDIENT_KEYS, INGREDIENT_NAME_BY_KEY, } from "@/constants/ingredient"; +import SuccessfulTteokgukCreationModal from "@/components/shared/SuccessfulTteokgukCreationModal"; const MAX_WISH_TEXT_LENGTH = 100; const MAX_INGREDIENTS = 5; const TteokgukCookingPage = () => { - const router = useRouter(); const { mutate: createTteokguk, isPending } = useAtomValue($postTteokguk); + const successfulCreationTteokgukOverlay = useOverlay(); const [wishText, setWishText] = useState(""); const [selectedIngredients, setSelectedIngredients] = useState([]); @@ -73,10 +73,17 @@ const TteokgukCookingPage = () => { access: !isPrivate, }, { - onSuccess: (createdTteokguk: PostTteokgukResponse) => { - const { tteokgukId } = createdTteokguk; - - router.push(`/tteokguks/${tteokgukId}`); + onSuccess: ({ tteokgukId, backgroundColor, frontGarnish, backGarnish }) => { + successfulCreationTteokgukOverlay.open(({ isOpen, close }) => ( + + )); }, }, ); diff --git a/src/pages/TteokgukPage.tsx b/src/pages/TteokgukPage.tsx index 8a3b710f..8e339890 100644 --- a/src/pages/TteokgukPage.tsx +++ b/src/pages/TteokgukPage.tsx @@ -21,9 +21,9 @@ import Button from "@/components/common/Button"; import Ingredient from "@/components/common/Ingredient"; import TteokgukImage from "@/components/common/TteokgukImage"; import { $getLoggedInUserDetails } from "@/store/user"; -import { $deleteTteokguk, $getTteokguk } from "@/store/tteokguk"; +import { $deleteTteokguk, $getRandomTteokguk, $getTteokguk } from "@/store/tteokguk"; import { INGREDIENT_ICON_BY_KEY, INGREDIENT_NAME_BY_KEY } from "@/constants/ingredient"; -import ActivityIcon from "@/assets/svg/activity.svg"; +import SmallActivityIcon from "@/assets/svg/small-activity.svg"; import MeterialIcon from "@/assets/svg/material.svg"; import Loading from "@/components/common/Loading"; @@ -38,6 +38,7 @@ const TteokgukPage = () => { const { data: loggedInUserDetails } = useAtomValue($getLoggedInUserDetails); const { mutate: deleteTteokguk } = useAtomValue($deleteTteokguk); const { data: tteokguk, isPending, isError, refetch } = useAtomValue($getTteokguk(Number(id))); + const { refetch: refetchRandomTteokguk } = useAtomValue($getRandomTteokguk); if (isPending) { return ( @@ -120,6 +121,14 @@ const TteokgukPage = () => { }); }; + const handleClickRandomVisitButton = async () => { + const { data: randomTteokguk } = await refetchRandomTteokguk(); + + if (randomTteokguk) { + router.push(`/tteokguks/${randomTteokguk.tteokgukId}`); + } + }; + return (
@@ -129,10 +138,12 @@ const TteokgukPage = () => {
- + {nickname}님의 떡국
- +
{ mutationFn: (tteokgukId: number) => deleteTteokguk(tteokgukId), }; }); + +export const $getRandomTteokguk = atomWithQuery(() => ({ + queryKey: ["randomTteokguk"], + queryFn: getRandomTteokguk, + enabled: false, +})); diff --git a/src/types/myActivity.ts b/src/types/myActivity.ts index 62124f2c..b496fbc0 100644 --- a/src/types/myActivity.ts +++ b/src/types/myActivity.ts @@ -1,4 +1,5 @@ import { IngredientKey } from "./ingredient"; +import { TteokgukBackgroudColor } from "./tteokguk"; export interface ReceivedIngredient { id: number; @@ -17,5 +18,5 @@ export interface MySupportedTteokguk { completion: boolean; frontGarnish: IngredientKey; backGarnish: IngredientKey; - backgroundColor: "BLUE" | "GREEN" | "PINK" | "YELLOW"; + backgroundColor: TteokgukBackgroudColor; } diff --git a/src/types/tteokguk.dto.ts b/src/types/tteokguk.dto.ts index 99601c8e..b66acb9a 100644 --- a/src/types/tteokguk.dto.ts +++ b/src/types/tteokguk.dto.ts @@ -1,5 +1,5 @@ import { IngredientKey } from "./ingredient"; -import { Tteokguk } from "./tteokguk"; +import { Tteokguk, TteokgukBackgroudColor } from "./tteokguk"; export interface GetNewTteokguksReponse { data: Tteokguk[]; @@ -18,34 +18,16 @@ export interface GetTteokgukResponse { completion: boolean; ingredients: IngredientKey[]; usedIngredients: IngredientKey[]; - backgroundColor: "BLUE" | "GREEN" | "PINK" | "YELLOW"; + requiredIngredients: IngredientKey[]; + backgroundColor: TteokgukBackgroudColor; frontGarnish: IngredientKey; backGarnish: IngredientKey; } -export interface GetTteokgukResponse { - tteokgukId: number; - memberId: number; - nickname: string; - wish: string; - access: boolean; - completino: boolean; - ingredients: IngredientKey[]; - usedIngredients: IngredientKey[]; - requiredIngredients: IngredientKey[]; -} - export interface PostTteokgukRequest { wish: string; ingredients: IngredientKey[]; access: boolean; } -export interface PostTteokgukResponse { - tteokgukId: number; - memberId: number; - wish: string; - access: boolean; - completion: boolean; - ingredients: IngredientKey[]; -} +export type PostTteokgukResponse = GetTteokgukResponse; diff --git a/src/types/tteokguk.ts b/src/types/tteokguk.ts index c8b254cd..277158f4 100644 --- a/src/types/tteokguk.ts +++ b/src/types/tteokguk.ts @@ -10,7 +10,7 @@ export interface Tteokguk { ingredients: IngredientKey[]; usedIngredients: IngredientKey[]; requiredIngredients: IngredientKey[]; - backgroundColor: "BLUE" | "GREEN" | "PINK" | "YELLOW"; + backgroundColor: TteokgukBackgroudColor; frontGarnish: IngredientKey; backGarnish: IngredientKey; hasIngredient: boolean; @@ -22,7 +22,9 @@ export interface UserTteokguk { completion: boolean; access: boolean; tteokgukIngredients: IngredientKey[]; - backgroundColor: "BLUE" | "GREEN" | "PINK" | "YELLOW"; + backgroundColor: TteokgukBackgroudColor; frontGarnish: IngredientKey; backGarnish: IngredientKey; } + +export type TteokgukBackgroudColor = "BLUE" | "GREEN" | "PINK" | "YELLOW";