Skip to content

Commit

Permalink
[#121] Feat: 랜덤 떡국 방문 구현 및 떡국 제작 성공 모달 구현 (#123)
Browse files Browse the repository at this point in the history
  • Loading branch information
Kim-Jaemin420 authored Feb 8, 2024
1 parent efee62c commit f99a69b
Show file tree
Hide file tree
Showing 17 changed files with 171 additions and 54 deletions.
6 changes: 6 additions & 0 deletions src/apis/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ const setAuthHeader = async (request: Request) => {
};

const getToken = async (accessToken: string, refreshToken: string) => {
if (!accessToken) {
return;
}

if (!isExpiredToken(accessToken)) {
return accessToken;
}
Expand All @@ -50,6 +54,8 @@ const getToken = async (accessToken: string, refreshToken: string) => {

removeLocalStorage("accessToken");
removeLocalStorage("refreshToken");

window.location.href = "/";
};

const refreshAccessToken = async (token: string) => {
Expand Down
2 changes: 2 additions & 0 deletions src/apis/tteokguk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,5 @@ export const postTteokguk = (tteokguk: PostTteokgukRequest) =>
http.post<PostTteokgukResponse>("api/v1/tteokguk", tteokguk);

export const deleteTteokguk = (id: number) => http.delete(`api/v1/tteokguk/${id}`);

export const getRandomTteokguk = () => http.get<GetTteokgukResponse>("api/v1/tteokguk/random");
7 changes: 0 additions & 7 deletions src/assets/svg/activity.svg

This file was deleted.

7 changes: 7 additions & 0 deletions src/assets/svg/big-activity.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 7 additions & 0 deletions src/assets/svg/small-activity.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion src/components/common/TteokgukImage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
2 changes: 1 addition & 1 deletion src/components/shared/GuideModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand Down
90 changes: 90 additions & 0 deletions src/components/shared/SuccessfulTteokgukCreationModal.tsx
Original file line number Diff line number Diff line change
@@ -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 && (
<Modal>
<Modal.Header>
{isCompletion ? "소원 떡국이 완성되었어요!" : "소원 떡국 제작 성공!"}
</Modal.Header>
<Modal.Body>
<div>
<div className={styles.description}>
{isCompletion
? `${nickname}님의 새해 소원, 이루어져라 얍✨`
: "내 재료와 친구들의 응원으로 떡국을 완성해보세요!"}
</div>
<div className={styles.imageContainer}>
<TteokgukImage
completion
backgroundColor={tteokgukBackgroundColor}
frontGarnish={frontGarnish}
backGarnish={backGarnish}
/>
</div>
<Button onClick={handleClickButton}>
{isCompletion ? "확인" : "소원 떡국 페이지로 가기"}
</Button>
</div>
</Modal.Body>
</Modal>
)
);
};

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",
}),
};
7 changes: 4 additions & 3 deletions src/components/shared/WelcomeModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ const styles = {
display: "flex",
flexDirection: "column",
alignItems: "center",
width: "100%",
}),
content: css({
fontSize: "1.4rem",
Expand All @@ -106,8 +107,8 @@ const styles = {
marginBottom: "2rem",
}),
icon: css({
width: "100%", // 컨테이너의 너비에 맞춤
height: "100%", // 컨테이너의 높이에 맞춤
objectFit: "contain", // 아이콘의 원래 비율을 유지
width: "100%",
height: "100%",
objectFit: "contain",
}),
};
2 changes: 1 addition & 1 deletion src/pages/EmailLoginPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ const styles = {
position: "relative",
display: "flex",
flexDirection: "column",
marginY: "auto",
marginTop: "0.8rem",
}),
emailInput: css({
marginBottom: "1.6rem",
Expand Down
6 changes: 3 additions & 3 deletions src/pages/MyPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 = () => {
Expand All @@ -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 (
Expand Down Expand Up @@ -164,7 +164,7 @@ const MyPage = () => {
<Link to="/my-page/activity" className={styles.full}>
<IconButton color="primary.45" applyColorTo="outline">
<IconButton.Icon>
<ActivityIcon />
<BigActivityIcon />
</IconButton.Icon>
활동 내역
</IconButton>
Expand Down
21 changes: 14 additions & 7 deletions src/pages/TteokgukCookingPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -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<IngredientKey[]>([]);
Expand Down Expand Up @@ -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 }) => (
<SuccessfulTteokgukCreationModal
isOpen={isOpen}
onClose={close}
tteokgukId={tteokgukId}
tteokgukBackgroundColor={backgroundColor}
frontGarnish={frontGarnish}
backGarnish={backGarnish}
/>
));
},
},
);
Expand Down
19 changes: 15 additions & 4 deletions src/pages/TteokgukPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand All @@ -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 (
Expand Down Expand Up @@ -120,6 +121,14 @@ const TteokgukPage = () => {
});
};

const handleClickRandomVisitButton = async () => {
const { data: randomTteokguk } = await refetchRandomTteokguk();

if (randomTteokguk) {
router.push(`/tteokguks/${randomTteokguk.tteokgukId}`);
}
};

return (
<Fragment>
<Header showBackButton actionIcon="profile">
Expand All @@ -129,10 +138,12 @@ const TteokgukPage = () => {
<article>
<div className={styles.titleContainer}>
<div className={styles.title}>
<ActivityIcon />
<SmallActivityIcon />
{nickname}님의 떡국
</div>
<button className={styles.randomVisitButton}>랜덤 방문</button>
<button onClick={handleClickRandomVisitButton} className={styles.randomVisitButton}>
랜덤 방문
</button>
</div>
<div className={styles.imageContainer}>
<TteokgukImage
Expand Down
11 changes: 9 additions & 2 deletions src/store/tteokguk.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { atomWithInfiniteQuery, atomWithMutation } from "jotai-tanstack-query";
import { atomWithInfiniteQuery, atomWithMutation, atomWithQuery } from "jotai-tanstack-query";
import { atomFamily } from "jotai/utils";
import { atom } from "jotai";

Expand All @@ -8,11 +8,12 @@ import {
getNewTteokguks,
postTteokguk,
deleteTteokguk,
getRandomTteokguk,
} from "@/apis/tteokguk";

import { atomFamilyWithQuery } from "@/utils/jotai";

import { PostTteokgukRequest } from "@/types/tteokguk.dto";
import { GetTteokgukResponse, PostTteokgukRequest } from "@/types/tteokguk.dto";
import { IngredientKey } from "@/types/ingredient";

import { $getLoggedInUserDetails } from "./user";
Expand Down Expand Up @@ -89,3 +90,9 @@ export const $deleteTteokguk = atomWithMutation(() => {
mutationFn: (tteokgukId: number) => deleteTteokguk(tteokgukId),
};
});

export const $getRandomTteokguk = atomWithQuery<GetTteokgukResponse>(() => ({
queryKey: ["randomTteokguk"],
queryFn: getRandomTteokguk,
enabled: false,
}));
3 changes: 2 additions & 1 deletion src/types/myActivity.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { IngredientKey } from "./ingredient";
import { TteokgukBackgroudColor } from "./tteokguk";

export interface ReceivedIngredient {
id: number;
Expand All @@ -17,5 +18,5 @@ export interface MySupportedTteokguk {
completion: boolean;
frontGarnish: IngredientKey;
backGarnish: IngredientKey;
backgroundColor: "BLUE" | "GREEN" | "PINK" | "YELLOW";
backgroundColor: TteokgukBackgroudColor;
}
Loading

0 comments on commit f99a69b

Please sign in to comment.