Skip to content

Commit

Permalink
Merge pull request #130 from themoment-team/develop
Browse files Browse the repository at this point in the history
�Release v1.5.0
  • Loading branch information
frorong authored Apr 13, 2024
2 parents 8f30c28 + afccbcc commit 5df2b56
Show file tree
Hide file tree
Showing 122 changed files with 2,456 additions and 181 deletions.
52 changes: 52 additions & 0 deletions src/apis/board/comment/getCommentDetail.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { cookies } from 'next/headers';
import { redirect } from 'next/navigation';

import { commentUrl } from '@/libs';
import type { CommentType } from '@/types';

const AUTH_REFRESH_PATH = '/auth/refresh' as const;

/**
* commentId에 따른 comment 정보를 조회합니다.
*
* @returns comment 정보를 반환합니다. comment 정보가 없다면 null을 반환합니다.
*/
export const getCommentDetail = async (
redirectUrl: string,
commentId: string
): Promise<CommentType | null> => {
const accessToken = cookies().get('accessToken')?.value;

if (!accessToken) return redirect(`/auth/refresh?redirect=${redirectUrl}`);

const response = await fetch(
new URL(
`/api/v1${commentUrl.getCommentDetail(commentId)}`,
process.env.BASE_URL
),
{
method: 'GET',
headers: {
Cookie: `accessToken=${accessToken}`,
},
}
);

const commentDetail = await response.json();
const isUnauthorized = response.status === 401;
const isNotFound = response.status === 404;

if (isNotFound) {
return null;
}

if (isUnauthorized) {
return redirect(`${AUTH_REFRESH_PATH}?redirect=${redirectUrl}`);
}

if (!response.ok) {
return redirect(redirectUrl);
}

return commentDetail;
};
1 change: 1 addition & 0 deletions src/apis/board/comment/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './getCommentDetail';
49 changes: 49 additions & 0 deletions src/apis/board/getBoardDetail.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { cookies } from 'next/headers';
import { redirect } from 'next/navigation';

import { boardUrl } from '@/libs';
import type { BoardType } from '@/types';

const AUTH_REFRESH_PATH = '/auth/refresh' as const;

/**
* boardId에 따른 board 정보를 조회합니다.
*
* @returns board 정보를 반환합니다. board 정보가 없다면 null을 반환합니다.
*/
export const getBoardDetail = async (
redirectUrl: string,
boardId: string
): Promise<BoardType | null> => {
const accessToken = cookies().get('accessToken')?.value;

if (!accessToken) return redirect(`/auth/refresh?redirect=${redirectUrl}`);

const response = await fetch(
new URL(`/api/v1${boardUrl.getBoardDetail(boardId)}`, process.env.BASE_URL),
{
method: 'GET',
headers: {
Cookie: `accessToken=${accessToken}`,
},
}
);

const boardDetail = await response.json();
const isUnauthorized = response.status === 401;
const isNotFound = response.status === 404;

if (isNotFound) {
return null;
}

if (isUnauthorized) {
return redirect(`${AUTH_REFRESH_PATH}?redirect=${redirectUrl}`);
}

if (!response.ok) {
return redirect(redirectUrl);
}

return boardDetail;
};
2 changes: 2 additions & 0 deletions src/apis/board/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './comment';
export * from './getBoardDetail';
1 change: 1 addition & 0 deletions src/apis/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './board';
export * from './mentee';
export * from './mentor';
1 change: 1 addition & 0 deletions src/apis/mentee/getMyMenteeInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export const getMyMenteeInfo = async (
return redirect(`${Path.AUTH_REFRESH_PATH}?redirect=${redirectUrl}`);
}


// 403의 경우 멘토일 수 있습니다.
if (!response.ok && !isForbidden) {
return redirect(Path.SIGN_PATH);
Expand Down
16 changes: 16 additions & 0 deletions src/app/community/board/[boardId]/[commentId]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { getCommentDetail } from '@/apis';
import { AddComment } from '@/pageContainer';

interface Params {
params: {
commentId: string;
};
}

const AddCommentPage: React.FC<Params> = async ({ params: { commentId } }) => {
const commentDetail = await getCommentDetail('/board', commentId);

return <AddComment initialData={commentDetail} commentId={commentId} />;
};

export default AddCommentPage;
16 changes: 16 additions & 0 deletions src/app/community/board/[boardId]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { getBoardDetail } from '@/apis';
import { BoardDetail } from '@/pageContainer';

interface Params {
params: {
boardId: string;
};
}

const BoardDetailPage: React.FC<Params> = async ({ params: { boardId } }) => {
const boardDetail = await getBoardDetail('/board', boardId);

return <BoardDetail initialData={boardDetail} boardId={boardId} />;
};

export default BoardDetailPage;
47 changes: 47 additions & 0 deletions src/app/community/board/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { cookies } from 'next/headers';
import { redirect } from 'next/navigation';

import { boardUrl } from '@/libs';
import { Board } from '@/pageContainer';
import type { BoardInfoType } from '@/types';

import type { Metadata } from 'next';

export const metadata: Metadata = {
title: '게시판',
description: '게시판 페이지입니다.',
};

const BoardPage = async () => {
const boardList = await getBoardList();

return <Board initialData={[...boardList]} />;
};

const getBoardList = async (): Promise<BoardInfoType[]> => {
const accessToken = cookies().get('accessToken')?.value;

if (!accessToken) return redirect('/auth/refresh');

const response = await fetch(
new URL(`/api/v1${boardUrl.getBoardList(0)}`, process.env.BASE_URL),
{
method: 'GET',
headers: { Cookie: `accessToken=${accessToken}` },
}
);

if (response.status === 401) {
return redirect('/auth/refresh');
}

if (!response.ok) {
return redirect('/auth/signin');
}

const boardList: BoardInfoType[] = await response.json();

return boardList;
};

export default BoardPage;
5 changes: 5 additions & 0 deletions src/app/community/write/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { CommunityWrite } from '@/pageContainer';

const CommunityWritePage = () => <CommunityWrite />;

export default CommunityWritePage;
Binary file added src/app/favicon.ico
Binary file not shown.
8 changes: 1 addition & 7 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,5 @@ const getMentorList = async (): Promise<WorkerType[]> => {

const mentorList = await response.json();

return addTemporaryImgNumber(mentorList);
return mentorList;
};

const addTemporaryImgNumber = (mentorList: WorkerType[]) =>
mentorList.map((worker) => ({
...worker,
temporaryImgNumber: Math.floor(Math.random() * 5),
}));
14 changes: 3 additions & 11 deletions src/app/providers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,17 @@ import React, { useState } from 'react';

import { ThemeProvider } from '@emotion/react';

import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { QueryClientProvider } from '@tanstack/react-query';

import QueryClient from '@/app/queryClient';
import { theme } from '@/styles';

interface Props {
children: React.ReactNode;
}

const Providers: React.FC<Props> = ({ children }) => {
const [queryClient] = useState(
() =>
new QueryClient({
defaultOptions: {
queries: {
retry: false,
},
},
})
);
const [queryClient] = useState(() => QueryClient);

return (
<ThemeProvider theme={theme}>
Expand Down
15 changes: 15 additions & 0 deletions src/app/queryClient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { QueryClient } from '@tanstack/react-query';

const queryClient = new QueryClient({
defaultOptions: {
queries: {
retry: false,
},
},
});

export const invalidateQueries = (query: string[]) => {
queryClient.invalidateQueries({ queryKey: query });
};

export default queryClient;
25 changes: 25 additions & 0 deletions src/assets/FilterNotFoundIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
const FilterNotFoundIcon = () => (
<svg
width='15.25rem'
height='12.625rem'
viewBox='0 0 244 202'
fill='none'
xmlns='http://www.w3.org/2000/svg'
>
<path
d='M239 30.9897V134.948C239 149.302 227.359 160.938 213 160.938H103.26C102.77 160.938 102.298 161.118 101.932 161.443L65.6367 193.692C57.253 201.141 44 195.192 44 183.98V162.938C44 161.833 43.1046 160.938 42 160.938H31C16.6406 160.938 5 149.302 5 134.948V30.9896C5 16.636 16.6406 5 31 5H213C227.359 5 239 16.636 239 30.9897Z'
stroke='#F5F6F8'
strokeWidth='0.625rem'
/>
<path
d='M44 69.1667C44 65.4848 49.783 62.5 56.9167 62.5H186.083C193.217 62.5 199 65.4848 199 69.1667C199 72.8486 193.217 75.8333 186.083 75.8333H56.9167C49.783 75.8333 44 72.8486 44 69.1667Z'
fill='#F5F6F8'
/>
<path
d='M44 95.8333C44 92.1514 49.783 89.1667 56.9167 89.1667H186.083C193.217 89.1667 199 92.1514 199 95.8333C199 99.5152 193.217 102.5 186.083 102.5H56.9167C49.783 102.5 44 99.5152 44 95.8333Z'
fill='#F5F6F8'
/>
</svg>
);

export default FilterNotFoundIcon;
20 changes: 20 additions & 0 deletions src/assets/WriteIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
const WriteButton = () => (
<svg
width='1.125rem'
height='1.125rem'
viewBox='0 0 18 18'
fill='none'
xmlns='http://www.w3.org/2000/svg'
>
<path
d='M0.932822 14.2687L0.404226 16.3831C0.221131 17.1155 0.884524 17.7789 1.6169 17.5958L3.73129 17.0672C3.90712 17.0232 4.0677 16.9323 4.19586 16.8041L17.2929 3.70711C17.6834 3.31658 17.6834 2.68342 17.2929 2.29289L15.7071 0.707107C15.3166 0.316583 14.6834 0.316583 14.2929 0.707107L1.19586 13.8041C1.0677 13.9323 0.97678 14.0929 0.932822 14.2687Z'
fill='white'
/>
<path
d='M17 15H8C7.44772 15 7 15.4477 7 16V17C7 17.5523 7.44771 18 8 18H17C17.5523 18 18 17.5523 18 17V16C18 15.4477 17.5523 15 17 15Z'
fill='#94CCFF'
/>
</svg>
);

export default WriteButton;
2 changes: 2 additions & 0 deletions src/assets/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export { default as DeleteIcon } from './DeleteIcon';
export { default as EmailIcon } from './EmailIcon';
export { default as ExitIcon } from './ExitIcon';
export { default as FilterIcon } from './FilterIcon';
export { default as FilterNotFoundIcon } from './FilterNotFoundIcon';
export { default as FoldIcon } from './FoldIcon';
export { default as GoBackIcon } from './GoBackIcon';
export { default as GoogleIcon } from './GoogleIcon';
Expand Down Expand Up @@ -32,3 +33,4 @@ export { default as SearchNotFoundIcon } from './SearchNotFoundIcon';
export { default as SendIcon } from './SendIcon';
export { default as TriangleIcon } from './TriangleIcon';
export { default as UploadIcon } from './UploadIcon';
export { default as WriteIcon } from './WriteIcon';
18 changes: 18 additions & 0 deletions src/components/BoardCard/index.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import BoardCard from '.';

import type { Meta, StoryObj } from '@storybook/react';

const meta: Meta<typeof BoardCard> = {
component: BoardCard,
parameters: {
layout: 'padded',
},
};

export default meta;

type Story = StoryObj<typeof BoardCard>;

export const Primary: Story = {
args: {},
};
37 changes: 37 additions & 0 deletions src/components/BoardCard/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
'use client';

import * as S from './style';

import type { BoardInfoType } from '@/types';
import { ReverseCategoryType } from '@/types';
import { parseDateString } from '@/utils';

const BoardCard: React.FC<BoardInfoType> = ({
id,
createdAt,
title,
authorName,
boardCategory,
}) => {
const { monthDay, time } = parseDateString(createdAt);

return (
<S.ContentBox href={`/community/board/${id}`}>
<S.BoardCard>
<S.ContentHeader>
<S.HeaderTitle>
<S.Name>{authorName}</S.Name>
<S.DateAndTime>
<S.Date>{monthDay}</S.Date>
<S.Time>{time}</S.Time>
</S.DateAndTime>
</S.HeaderTitle>
<S.Tag>#{ReverseCategoryType[boardCategory]}</S.Tag>
</S.ContentHeader>
<S.Content>{title}</S.Content>
</S.BoardCard>
</S.ContentBox>
);
};

export default BoardCard;
Loading

0 comments on commit 5df2b56

Please sign in to comment.