From 39eeba3efbc04d9785217a0822dbc5715949f6c5 Mon Sep 17 00:00:00 2001 From: kyr4601 Date: Mon, 6 Jan 2025 18:37:59 +0900 Subject: [PATCH 01/10] =?UTF-8?q?Fix:=20ios=20=EC=95=84=EC=9D=B4=EC=BD=98?= =?UTF-8?q?=20=EC=98=A4=EB=A5=98=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/client/src/assets/icons/GridIcon.tsx | 4 ++-- apps/client/src/assets/icons/PrevIcon.tsx | 6 +++--- apps/client/src/components/cake/CakeHeader.tsx | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/client/src/assets/icons/GridIcon.tsx b/apps/client/src/assets/icons/GridIcon.tsx index ab621d7..cdf8e1e 100644 --- a/apps/client/src/assets/icons/GridIcon.tsx +++ b/apps/client/src/assets/icons/GridIcon.tsx @@ -7,8 +7,8 @@ const GridIcon = (props: SVGProps) => { xmlns="http://www.w3.org/2000/svg" > diff --git a/apps/client/src/assets/icons/PrevIcon.tsx b/apps/client/src/assets/icons/PrevIcon.tsx index c6c9e76..9139974 100644 --- a/apps/client/src/assets/icons/PrevIcon.tsx +++ b/apps/client/src/assets/icons/PrevIcon.tsx @@ -5,13 +5,13 @@ const PrevIcon = (props: SVGProps) => { ); diff --git a/apps/client/src/components/cake/CakeHeader.tsx b/apps/client/src/components/cake/CakeHeader.tsx index e24ba89..1be6f07 100644 --- a/apps/client/src/components/cake/CakeHeader.tsx +++ b/apps/client/src/components/cake/CakeHeader.tsx @@ -29,12 +29,12 @@ const SubTitle = styled.h2` margin-top: 0.5rem; `; -const Nickname = styled.h1` +const Nickname = styled.p` color: var(--orange-500); display: inline; `; -const Phrase = styled.h1` +const Phrase = styled.p` display: inline; `; @@ -78,7 +78,7 @@ const CakeHeader = ({ navigate('/mypage'); }} > - {!isPC && ()} + {!isPC && ()} )} From 7e1974480d60d60d255af80c134edbdd924607ed Mon Sep 17 00:00:00 2001 From: kyr4601 Date: Mon, 6 Jan 2025 20:59:33 +0900 Subject: [PATCH 02/10] =?UTF-8?q?Fix:=20=ED=8E=B8=EC=A7=80=EC=9E=91?= =?UTF-8?q?=EC=84=B1=20=EA=B8=B0=EC=A4=80=2030=EC=9D=BC=EC=97=90=EC=84=9C?= =?UTF-8?q?=207=EC=9D=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 --- apps/client/src/ModalPortal.ts | 6 +++--- apps/server/src/routes/cake.ts | 6 +++--- apps/server/src/service/letter.ts | 15 ++++++--------- 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/apps/client/src/ModalPortal.ts b/apps/client/src/ModalPortal.ts index afd79b6..6c87cd0 100644 --- a/apps/client/src/ModalPortal.ts +++ b/apps/client/src/ModalPortal.ts @@ -6,9 +6,9 @@ interface ModalPortalProps { } export const ModalPortal: React.FC = ({ children }) => { - const el = document.getElementById('modal'); - if (!el) { + const modalElement = document.getElementById('modal'); + if (!modalElement) { return null; } - return ReactDOM.createPortal(children, el); + return ReactDOM.createPortal(children, modalElement); }; diff --git a/apps/server/src/routes/cake.ts b/apps/server/src/routes/cake.ts index 04af0b6..ea04b0d 100644 --- a/apps/server/src/routes/cake.ts +++ b/apps/server/src/routes/cake.ts @@ -85,14 +85,14 @@ router.get('/cake/:ownerId', async (req, res) => { const today = new Date(); const birthday = cakeUserData.birthday; - const thisYearBdayAfter30 = new Date( + const thisYearBdayAfter7 = new Date( today.getFullYear(), birthday.getMonth(), - birthday.getDate() + 30, + birthday.getDate() + 7, ); const year = - today > thisYearBdayAfter30 + today > thisYearBdayAfter7 ? today.getFullYear() + 1 : today.getFullYear(); diff --git a/apps/server/src/service/letter.ts b/apps/server/src/service/letter.ts index a92be20..9884742 100644 --- a/apps/server/src/service/letter.ts +++ b/apps/server/src/service/letter.ts @@ -1,16 +1,13 @@ export function getLetterYearBasedOnBirthday(birthday: Date): number { const today = new Date(); - const thisYearBirthday = new Date( + + const thisYearBdayAfter7 = new Date( today.getFullYear(), birthday.getMonth(), - birthday.getDate(), + birthday.getDate() + 7, ); - // 생일 기준으로 30일 이후인지 확인 - const timeDifference = thisYearBirthday.getTime() - today.getTime(); - const daysUntilBirthday = timeDifference / (1000 * 60 * 60 * 24); - - return daysUntilBirthday <= 30 && daysUntilBirthday >= 0 - ? today.getFullYear() - : today.getFullYear() + 1; + return today > thisYearBdayAfter7 + ? today.getFullYear() + 1 + : today.getFullYear(); } From 927c4845f6bc0cabb7f2cd66c3a98c89ad4d7cb5 Mon Sep 17 00:00:00 2001 From: kyr4601 Date: Sun, 19 Jan 2025 15:12:51 +0900 Subject: [PATCH 03/10] =?UTF-8?q?Fix:=20react=20query=20staletime=20?= =?UTF-8?q?=EC=A1=B0=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/client/src/apis/cake/useGetCakeLetters.tsx | 1 + apps/client/src/apis/cake/useGetYear.tsx | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/client/src/apis/cake/useGetCakeLetters.tsx b/apps/client/src/apis/cake/useGetCakeLetters.tsx index 1462668..3af0ad3 100644 --- a/apps/client/src/apis/cake/useGetCakeLetters.tsx +++ b/apps/client/src/apis/cake/useGetCakeLetters.tsx @@ -13,5 +13,6 @@ export const useGetCakeLetters = (ownerId: string, year: string, page: number) = return useSuspenseQuery({ queryKey: ['cake-letters', ownerId, year, page], queryFn: () => fetchCakeLetters(ownerId, year, page), + staleTime: 1000 * 60, }); } diff --git a/apps/client/src/apis/cake/useGetYear.tsx b/apps/client/src/apis/cake/useGetYear.tsx index 9d184a4..a8572e8 100644 --- a/apps/client/src/apis/cake/useGetYear.tsx +++ b/apps/client/src/apis/cake/useGetYear.tsx @@ -10,6 +10,7 @@ async function fetchYear() { export const useGetYear = () => { return useSuspenseQuery({ queryKey: ['get-year'], - queryFn: () => fetchYear() + queryFn: () => fetchYear(), + staleTime: 1000 * 60 * 5, }) } From 37215b660b74e7748f9f9f7e76a3ebed70fe3992 Mon Sep 17 00:00:00 2001 From: kyr4601 Date: Wed, 12 Feb 2025 18:34:16 +0900 Subject: [PATCH 04/10] =?UTF-8?q?fix:=20axios=20interceptor=20401=20?= =?UTF-8?q?=EC=97=90=EB=9F=AC=EC=B2=98=EB=A6=AC=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/client/src/apis/axios.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/apps/client/src/apis/axios.ts b/apps/client/src/apis/axios.ts index 7844298..3d6e249 100644 --- a/apps/client/src/apis/axios.ts +++ b/apps/client/src/apis/axios.ts @@ -14,8 +14,12 @@ axiosInstance.interceptors.response.use( const axiosError = customError.response?.status as number; - // 401 에러 응답 - if (axiosError === 401) { + // 401 에러 응답 (인가 미들웨어에서 모든 토큰이 만료되었을때 401 리턴 -> 로그인 유도) + if ((axiosError === 401) && (window.location.pathname !== '/')) { + if (/^\/cake\/[^/]+$/.test(window.location.pathname)) { + return Promise.reject(error); + } + window.location.replace('/'); return Promise.reject(error); } @@ -30,7 +34,6 @@ axiosInstance.interceptors.response.use( return Promise.reject(error); } - return Promise.reject(error); }, ); From aa78124bd1eba5aa3c86ed8aa94d111b9bd0e778 Mon Sep 17 00:00:00 2001 From: kyr4601 Date: Thu, 13 Feb 2025 00:41:18 +0900 Subject: [PATCH 05/10] =?UTF-8?q?Chore:=20cake=20=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=A7=80=20=EA=B4=80=EB=A0=A8=20=EC=BB=B4=ED=8F=AC=EB=84=8C?= =?UTF-8?q?=ED=8A=B8=20=EC=8A=A4=ED=83=80=EC=9D=BC=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../client/src/components/cake/CakeHeader.tsx | 78 ++--------- apps/client/src/components/cake/CakeInfo.tsx | 59 ++++----- .../src/components/cake/ColorSelector.tsx | 45 +------ apps/client/src/components/cake/MyCake.tsx | 22 +--- .../client/src/components/cake/SharedCake.tsx | 30 +---- apps/client/src/styles/CakeStyle.tsx | 124 ++++++++++++++++++ 6 files changed, 176 insertions(+), 182 deletions(-) create mode 100644 apps/client/src/styles/CakeStyle.tsx diff --git a/apps/client/src/components/cake/CakeHeader.tsx b/apps/client/src/components/cake/CakeHeader.tsx index 1be6f07..1ff3aa6 100644 --- a/apps/client/src/components/cake/CakeHeader.tsx +++ b/apps/client/src/components/cake/CakeHeader.tsx @@ -1,61 +1,9 @@ import React from 'react'; -import styled from 'styled-components'; +import * as C from '#styles/CakeStyle.tsx'; import { useNavigate } from 'react-router-dom'; import { PersonIcon } from '#icons'; import useIsPC from '#hooks/useIsPc.tsx'; -const HeaderContainer = styled.div` - display: flex; - flex-direction: column; - justify-content: start; - align-items: start; - width: 100%; - padding-bottom: 20px; -`; - -const TitleContainer = styled.div` - display: flex; - flex-direction: row; - justify-content: space-between; - align-items: center; - width: 100%; -`; - -const Title = styled.h1` - font-weight: bold; -`; - -const SubTitle = styled.h2` - margin-top: 0.5rem; -`; - -const Nickname = styled.p` - color: var(--orange-500); - display: inline; -`; - -const Phrase = styled.p` - display: inline; -`; - -const MyPageButton = styled.button` - width: 2.6rem; - height: 2.6rem; - border-radius: 50%; - border-width: 0; - overflow: hidden; - cursor: pointer; - display: flex; - flex-direction: row; - justify-content: right; - align-items: center; - background-color: transparent; - - &:hover { - opacity: 0.8; - } -`; - const CakeHeader = ({ nickname, isMyCake, @@ -66,25 +14,25 @@ const CakeHeader = ({ const navigate = useNavigate(); const isPC = useIsPC(1024); return ( - - - - <Nickname>{nickname}</Nickname> - <Phrase>님의 케이크</Phrase> - + + + + {nickname} + 님의 케이크 + {isMyCake && ( - { navigate('/mypage'); }} > {!isPC && ()} - + )} - - {isMyCake && 장식초를 눌러 편지를 확인해보세요✉️} - {!isMyCake && 친구의 케이크를 꾸며보세요❤️} - + + {isMyCake && 장식초를 눌러 편지를 확인해보세요✉️} + {!isMyCake && 친구의 케이크를 꾸며보세요❤️} + ); }; diff --git a/apps/client/src/components/cake/CakeInfo.tsx b/apps/client/src/components/cake/CakeInfo.tsx index 3f766f9..cc07ced 100644 --- a/apps/client/src/components/cake/CakeInfo.tsx +++ b/apps/client/src/components/cake/CakeInfo.tsx @@ -1,6 +1,7 @@ import React, { useEffect, useState } from 'react'; -import styled, { css } from 'styled-components'; import { useParams } from 'react-router-dom'; +import * as C from '#styles/CakeStyle.tsx'; + import { CakeColorType } from '@isttp/types/all'; import { getCakeDataRes, @@ -9,15 +10,18 @@ import { getLetterRes, getCakeNoDataRes, } from '@isttp/schemas/all'; + import Pagenation from '#components/cake/Pagenation.tsx'; import RenderCake from '#components/cake/RenderCake.tsx'; import ReadLetter from '#components/letter/ReadLetter.tsx'; -import { useGetCakeLetters } from '#apis/cake/useGetCakeLetters.tsx'; -import { useGetLetter } from '#apis/letter/useGetLetter.tsx'; -import { useQueryClient } from '@tanstack/react-query'; import Modal from '#components/modal/Modal.tsx'; import Button from '#components/common/Button.tsx'; +import { useQueryClient } from '@tanstack/react-query'; +import { useGetCakeLetters } from '#apis/cake/useGetCakeLetters.tsx'; +import { useGetLetter } from '#apis/letter/useGetLetter.tsx'; + + interface CakeInfoProps { year: string; sheetColor: CakeColorType | null; @@ -25,6 +29,16 @@ interface CakeInfoProps { isMyCake?: boolean; } +const CandlePositions = [ + { top: 2, left: 30 }, + { top: 6, left: 50 }, + { top: 2, left: 70 }, + { top: 40, left: 20 }, + { top: 47, left: 40 }, + { top: 47, left: 60 }, + { top: 40, left: 80 }, +]; + const CakeInfo: React.FC = ({ year, sheetColor, @@ -42,12 +56,11 @@ const CakeInfo: React.FC = ({ }); const queryClient = useQueryClient(); const { data: cakeLettersData } = useGetCakeLetters(ownerId!, year, pageData.currentPage); - const { data: letterData } = useGetLetter(selectedLetterId!); useEffect(() => { - const noDataResult = getCakeNoDataRes.safeParse(cakeLettersData); - if (noDataResult.success && noDataResult.data.noData) { + const checkNoData = getCakeNoDataRes.safeParse(cakeLettersData); + if (checkNoData.success && checkNoData.data.noData) { setCakeData([]); setPageData({ currentPage: 1, totalPage: 1 }); } else { @@ -84,32 +97,22 @@ const CakeInfo: React.FC = ({ }); }; - const candlePositions = [ - { top: 2, left: 30 }, - { top: 6, left: 50 }, - { top: 2, left: 70 }, - { top: 40, left: 20 }, - { top: 47, left: 40 }, - { top: 47, left: 60 }, - { top: 40, left: 80 }, - ]; - const candles = cakeData.map((cake, index) => ({ candleImageUrl: cake.candleImageUrl, nickname: cake.nickname, - position: candlePositions[index % candlePositions.length], + position: CandlePositions[index % CandlePositions.length], })); return ( - - + + - + = ({ 확인 - + ); }; export default CakeInfo; - -const CakeContainer = styled.div` - margin-top: 50px; -`; - -const CakeInfoWrapper = styled.div<{ isMyCake?: boolean }>` - ${({ isMyCake }) => - isMyCake === false && - css` - pointer-events: none; - `} -`; diff --git a/apps/client/src/components/cake/ColorSelector.tsx b/apps/client/src/components/cake/ColorSelector.tsx index dbf12ba..ed9b73e 100644 --- a/apps/client/src/components/cake/ColorSelector.tsx +++ b/apps/client/src/components/cake/ColorSelector.tsx @@ -1,42 +1,7 @@ import React, { SetStateAction } from 'react'; -import styled from 'styled-components'; - +import * as C from '#styles/CakeStyle.tsx'; import { CakeColorType } from '@isttp/types/all'; -const ColorContainer = styled.div` - width: 100%; - display: flex; - justify-content: center; - flex-wrap: wrap; - background-color: rgba(222, 222, 222, 0.5); - padding: 0.6rem; - border-radius: 0.5rem; -`; - -const ColorOption = styled.div<{ $color: string; selected: boolean }>` - display: flex; - flex-direction: row; - justify-content: center; - align-items: center; - width: 2.5rem; - height: 2.5rem; - margin: 0.5rem; - border-radius: 50%; - background-color: var(--${(props) => props.$color === 'white' ? 'white' : `${props.$color}-100`}); - cursor: pointer; - transition: border 0.1s; - - &:hover { - border: 5px solid var(--${(props) => props.$color === 'white' ? 'gray-400' : `${props.$color}-200`}); - } - - @media (max-width: 429px) { - width: 2rem; - height: 2rem; - margin: 0.5rem; - } -`; - type ColorSelectorProps = { selectedColor: string | null; setSelectedColor: React.Dispatch>; @@ -56,18 +21,18 @@ const ColorSelector: React.FC = ({ ]; return ( - + {colors.map((color, index) => ( - setSelectedColor(color)} > {selectedColor === color && } - + ))} - + ); }; diff --git a/apps/client/src/components/cake/MyCake.tsx b/apps/client/src/components/cake/MyCake.tsx index 21c6c31..c645a6f 100644 --- a/apps/client/src/components/cake/MyCake.tsx +++ b/apps/client/src/components/cake/MyCake.tsx @@ -1,15 +1,18 @@ import React, { useState, useEffect } from 'react'; -import styled from 'styled-components'; import { useNavigate } from 'react-router-dom'; +import * as C from '#styles/CakeStyle.tsx'; + import Toggle from '#components/common/Toggle.tsx'; import GridInfo from '#components/cake/GridInfo.tsx'; import CakeInfo from '#components/cake/CakeInfo.tsx'; import Button from '#components/common/Button.tsx'; import ShareUrlModal from '#components/modal/ShareUrlModal.tsx'; import CakeHeader from '#components/cake/CakeHeader.tsx'; + import { CakeUserTypeResponse } from '@isttp/types/all'; import useToggleStore from '../../store/useToggleStore'; + type MyCakeProps = { ownerId: string; data: CakeUserTypeResponse; @@ -39,7 +42,7 @@ const MyCake: React.FC = ({ ownerId, data }) => { <> - {data.isBirthday &&

happy birthday!

} + {data.isBirthday && happy birthday!} {toggle ? ( ) : ( @@ -67,18 +70,3 @@ const MyCake: React.FC = ({ ownerId, data }) => { }; export default MyCake; - -const H1 = styled.h1` - background: linear-gradient(90deg, #FF3E3E 0%, #582599 100%); - background-clip: text; - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - text-align: center; - font-family: "sansita"; - font-size: 2.125rem; - font-style: normal; - font-weight: 400; - line-height: normal; - text-transform: uppercase; - margin-top: 2rem; -`; diff --git a/apps/client/src/components/cake/SharedCake.tsx b/apps/client/src/components/cake/SharedCake.tsx index 9dcdea1..507bc26 100644 --- a/apps/client/src/components/cake/SharedCake.tsx +++ b/apps/client/src/components/cake/SharedCake.tsx @@ -1,6 +1,6 @@ import React, { useState } from 'react'; import { useNavigate } from 'react-router-dom'; -import styled from 'styled-components'; +import * as C from '#styles/CakeStyle.tsx' import CakeHeader from '#components/cake/CakeHeader.tsx'; import CakeInfo from '#components/cake/CakeInfo.tsx'; @@ -63,14 +63,14 @@ const SharedCake: React.FC = ({ ownerId, data }) => { return ( <> - {data.isBirthday &&

happy birthday!

} + {data.isBirthday && happy birthday!} - + - + 편지를 작성하면 포인트를 얻을 수 있어요.{'\n'}로그인 하시겠어요? - - - 편지를 작성하면 포인트를 얻을 수 있어요.{'\n'}로그인 하시겠어요? + setOpen(false)}> + + 편지를 작성하면 포인트를 얻을 수 있어요.{'\n'}로그인 하시겠어요? + @@ -87,4 +87,4 @@ const ShareBox = styled.div` justify-content: center; align-items: center; gap: 24px; -` +`; diff --git a/apps/client/src/pages/ChooseCandle.tsx b/apps/client/src/pages/ChooseCandle.tsx index 395ee3c..5c138e8 100644 --- a/apps/client/src/pages/ChooseCandle.tsx +++ b/apps/client/src/pages/ChooseCandle.tsx @@ -48,7 +48,7 @@ const ChooseCandle = () => { try { // 선택한 장식초 정보 가져오기 const candleResponse = await axiosInstance.get( - `/candle/${candleId}`, + `/candle/${candleId}` ); if (candleResponse.status === 200) { const data = CandleType.parse(candleResponse.data); @@ -118,7 +118,7 @@ const ChooseCandle = () => { if (candle.point === 0) { // 무료 장식초: 편지 페이지로 이동 navigate( - `/letter/create/${ownerId}?candleId=${candle.candleId}`, + `/letter/create/${ownerId}?candleId=${candle.candleId}` ); } else { // 유료 장식초: 결제 혹은 로그인 유도 모달 띄우기 @@ -135,7 +135,7 @@ const ChooseCandle = () => { ))} - + { gap: '1rem', }} > - - + setOpenSuccess(false)}> { setOpen(false)}> - + 편지를 작성하면 포인트를 얻을 수 있어요.{'\n'}로그인 하시겠어요?