Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 2 additions & 6 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,9 @@
],
"eslint.workingDirectories": [
{
"mode": "auto",
"mode": "auto"
}
],
"cSpell.words": [
"kakao",
"signup",
"webp"
],
"cSpell.words": ["kakao", "signup", "webp"],
"editor.tabSize": 2
}
6 changes: 3 additions & 3 deletions apps/client/src/ModalPortal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ interface ModalPortalProps {
}

export const ModalPortal: React.FC<ModalPortalProps> = ({ 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);
};
25 changes: 15 additions & 10 deletions apps/client/src/apis/axios.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,34 @@
import axios, { AxiosError } from 'axios';
import axios, { AxiosError } from "axios";

const axiosInstance = axios.create({
baseURL: process.env.SERVER_URL,
withCredentials: true,
});

axiosInstance.interceptors.response.use(
response => {
(response) => {
return response;
},
async error => {
async (error) => {
const customError = error as AxiosError;
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) ||
/^\/letter\/choose\/[^/]+$/.test(window.location.pathname) ||
/^\/letter\/create\/[^/]+$/.test(window.location.pathname)
) {
return Promise.reject(error);
}
window.location.replace("/");
return Promise.reject(error);
}

// 500 에러 응답
if (axiosError === 500) {
console.log('서버 오류');
console.log("서버 오류");
return Promise.reject(error);
}

Expand All @@ -30,10 +37,8 @@ axiosInstance.interceptors.response.use(
return Promise.reject(error);
}


return Promise.reject(error);
},
}
);


export default axiosInstance;
1 change: 1 addition & 0 deletions apps/client/src/apis/cake/useGetCakeLetters.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
});
}
3 changes: 2 additions & 1 deletion apps/client/src/apis/cake/useGetYear.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ async function fetchYear() {
export const useGetYear = () => {
return useSuspenseQuery({
queryKey: ['get-year'],
queryFn: () => fetchYear()
queryFn: () => fetchYear(),
staleTime: 1000 * 60 * 5,
})
}
4 changes: 2 additions & 2 deletions apps/client/src/assets/icons/GridIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ const GridIcon = (props: SVGProps<SVGSVGElement>) => {
xmlns="http://www.w3.org/2000/svg"
>
<path
fill-rule="evenodd"
clip-rule="evenodd"
fillRule="evenodd"
clipRule="evenodd"
d="M6.75 11.0833C7.32464 11.0833 7.87574 11.3116 8.28206 11.7179C8.68839 12.1243 8.91667 12.6754 8.91667 13.25V17.5833C8.91667 18.158 8.68839 18.7091 8.28206 19.1154C7.87574 19.5217 7.32464 19.75 6.75 19.75H2.41667C1.84203 19.75 1.29093 19.5217 0.884602 19.1154C0.478273 18.7091 0.25 18.158 0.25 17.5833V13.25C0.25 12.6754 0.478273 12.1243 0.884602 11.7179C1.29093 11.3116 1.84203 11.0833 2.41667 11.0833H6.75ZM17.5833 11.0833C18.158 11.0833 18.7091 11.3116 19.1154 11.7179C19.5217 12.1243 19.75 12.6754 19.75 13.25V17.5833C19.75 18.158 19.5217 18.7091 19.1154 19.1154C18.7091 19.5217 18.158 19.75 17.5833 19.75H13.25C12.6754 19.75 12.1243 19.5217 11.7179 19.1154C11.3116 18.7091 11.0833 18.158 11.0833 17.5833V13.25C11.0833 12.6754 11.3116 12.1243 11.7179 11.7179C12.1243 11.3116 12.6754 11.0833 13.25 11.0833H17.5833ZM6.75 0.25C7.32464 0.25 7.87574 0.478273 8.28206 0.884602C8.68839 1.29093 8.91667 1.84203 8.91667 2.41667V6.75C8.91667 7.32464 8.68839 7.87574 8.28206 8.28206C7.87574 8.68839 7.32464 8.91667 6.75 8.91667H2.41667C1.84203 8.91667 1.29093 8.68839 0.884602 8.28206C0.478273 7.87574 0.25 7.32464 0.25 6.75V2.41667C0.25 1.84203 0.478273 1.29093 0.884602 0.884602C1.29093 0.478273 1.84203 0.25 2.41667 0.25H6.75ZM17.5833 0.25C18.158 0.25 18.7091 0.478273 19.1154 0.884602C19.5217 1.29093 19.75 1.84203 19.75 2.41667V6.75C19.75 7.32464 19.5217 7.87574 19.1154 8.28206C18.7091 8.68839 18.158 8.91667 17.5833 8.91667H13.25C12.6754 8.91667 12.1243 8.68839 11.7179 8.28206C11.3116 7.87574 11.0833 7.32464 11.0833 6.75V2.41667C11.0833 1.84203 11.3116 1.29093 11.7179 0.884602C12.1243 0.478273 12.6754 0.25 13.25 0.25H17.5833Z"
/>
</svg>
Expand Down
6 changes: 3 additions & 3 deletions apps/client/src/assets/icons/PrevIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ const PrevIcon = (props: SVGProps<SVGSVGElement>) => {
<svg
{...props}
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
width="24px"
height="24px"
viewBox="0 0 24 24"
fill="none"
>
<path
d="M14 7L9 12L14 17" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
d="M14 7L9 12L14 17" stroke="white" strokeWidth="2"
/>
</svg>
);
Expand Down
80 changes: 14 additions & 66 deletions apps/client/src/components/cake/CakeHeader.tsx
Original file line number Diff line number Diff line change
@@ -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.h1`
color: var(--orange-500);
display: inline;
`;

const Phrase = styled.h1`
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,
Expand All @@ -66,25 +14,25 @@ const CakeHeader = ({
const navigate = useNavigate();
const isPC = useIsPC(1024);
return (
<HeaderContainer>
<TitleContainer>
<Title>
<Nickname>{nickname}</Nickname>
<Phrase>님의 케이크</Phrase>
</Title>
<C.HeaderContainer>
<C.TitleContainer>
<C.Title>
<C.Nickname>{nickname}</C.Nickname>
<C.Phrase>님의 케이크</C.Phrase>
</C.Title>
{isMyCake && (
<MyPageButton
<C.MyPageButton
onClick={() => {
navigate('/mypage');
}}
>
{!isPC && (<PersonIcon width={'100%'} height={'100%'} viewBox="0 0 31 38" />)}
</MyPageButton>
{!isPC && (<PersonIcon viewBox="0 0 31 38" />)}
</C.MyPageButton>
)}
</TitleContainer>
{isMyCake && <SubTitle>장식초를 눌러 편지를 확인해보세요✉️</SubTitle>}
{!isMyCake && <SubTitle>친구의 케이크를 꾸며보세요❤️</SubTitle>}
</HeaderContainer>
</C.TitleContainer>
{isMyCake && <C.SubTitle>장식초를 눌러 편지를 확인해보세요✉️</C.SubTitle>}
{!isMyCake && <C.SubTitle>친구의 케이크를 꾸며보세요❤️</C.SubTitle>}
</C.HeaderContainer>
);
};

Expand Down
73 changes: 35 additions & 38 deletions apps/client/src/components/cake/CakeInfo.tsx
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -9,22 +10,34 @@ 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;
creamColor: CakeColorType | null;
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<CakeInfoProps> = ({
year,
sheetColor,
Expand All @@ -41,21 +54,25 @@ const CakeInfo: React.FC<CakeInfoProps> = ({
totalPage: 1,
});
const queryClient = useQueryClient();
const { data: cakeLettersData } = useGetCakeLetters(ownerId!, year, pageData.currentPage);

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 {
const result = getCakeLettersRes.parse(cakeLettersData);
setCakeData(result.data);
setPageData({
currentPage: result.currentPage,
totalPage: result.totalPage === 0 ? result.totalPage + 1 : result.totalPage,
totalPage:
result.totalPage === 0 ? result.totalPage + 1 : result.totalPage,
});
}
}, [cakeLettersData]);
Expand Down Expand Up @@ -84,32 +101,22 @@ const CakeInfo: React.FC<CakeInfoProps> = ({
});
};

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 (
<CakeContainer>
<CakeInfoWrapper isMyCake={isMyCake}>
<C.CakeContainer>
<C.CakeInfoWrapper isMyCake={isMyCake}>
<RenderCake
sheetColor={sheetColor}
creamColor={creamColor}
candles={candles}
handleClick={openLetter}
/>
</CakeInfoWrapper>
</C.CakeInfoWrapper>
<Pagenation
currentPage={pageData.currentPage}
totalPage={pageData.totalPage}
Expand All @@ -125,8 +132,10 @@ const CakeInfo: React.FC<CakeInfoProps> = ({
keyword={selectedItem?.keyword ?? ''}
/>
)}
<Modal open={open}>
<span>편지 내용은 생일 이후에 확인할 수 있어요!{'\n'}두근두근...👉👈</span>
<Modal open={open} onClose={() => setOpen(false)}>
<span id="modal-description">
편지 내용은 생일 이후에 확인할 수 있어요!{'\n'}두근두근...👉👈
</span>
<Button
type="default"
onClick={() => {
Expand All @@ -136,20 +145,8 @@ const CakeInfo: React.FC<CakeInfoProps> = ({
확인
</Button>
</Modal>
</CakeContainer>
</C.CakeContainer>
);
};

export default CakeInfo;

const CakeContainer = styled.div`
margin-top: 50px;
`;

const CakeInfoWrapper = styled.div<{ isMyCake?: boolean }>`
${({ isMyCake }) =>
isMyCake === false &&
css`
pointer-events: none;
`}
`;
Loading