Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: 커뮤니티 관련 API를 연결했습니다. #97

Merged
merged 12 commits into from
Oct 13, 2023
Merged
52 changes: 52 additions & 0 deletions src/components/community/BoardList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { css } from '@emotion/react';
import { useEffect, useState } from 'react';
import { CharacterInfo } from '@/types/characterInfo';
import { findAllBoards } from '@/utils/api/boards';
import Loading from '../common/dialog/Loading';
import FriendInfo from '../friends/friend/FriendInfo';
import FriendWrapper from '../friends/friend/FriendWrapper';

const BoardList = () => {
const [characterInfoList, setCharacterInfoList] = useState<CharacterInfo[]>([]);

useEffect(() => {
findAllBoards()
.then((data) => setCharacterInfoList(data))
.catch((error) => {
console.error('Error fetching post:', error);
});
}, []);

return (
<section css={boardListWrapperCSS}>
{characterInfoList ? (
characterInfoList.map((characterInfo) => (
<div key={characterInfo.id}>
<FriendWrapper
key={characterInfo.characterId}
linkUrl={`/community/${characterInfo.characterId}`}
>
<FriendInfo
characterName={characterInfo.name}
// TODO: 백엔드는 이미지를 뿌려라!
// imageUrl={characterInfo.profileUrl}
message={`임시 정보 입니다. ${characterInfo.hashtags}`}
imageUrl="/leeyj.png"
/>
</FriendWrapper>
</div>
))
) : <Loading />}
</section>
);
};

export default BoardList;

const boardListWrapperCSS = css`
display: flex;
flex-direction: column;
word-break: keep-all;
padding: 0.375rem;
padding-top: 1.25rem;
`;
69 changes: 61 additions & 8 deletions src/pages/community/[character_id]/[post_id]/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,20 @@ import BottomNavBar from '@/components/common/bottomNavBar/BottomNavBar';
import SEO from '@/components/common/head/SEO';
import { useEffect, useState } from 'react';
import { useRouter } from 'next/router';
import { findBoardsById } from '@/utils/api/boards';
import { findPostById } from '@/utils/api/boards';
import Loading from '@/components/common/dialog/Loading';
import color from '@/styles/color';
import { postDetailDateParse } from '@/utils/services/date';
import { PostData } from '@/types/post';

const Board = () => {
const Post = () => {
const router = useRouter();
const { character_id: characterId, post_id: postId } = router.query;
const [post, setPost] = useState({});
const [post, setPost] = useState<PostData>();
useEffect(() => {
if (typeof characterId === 'string' && typeof postId === 'string') {
findBoardsById(characterId, postId).then((data) => {
console.log(data);
findPostById(characterId, postId).then((data) => {
setPost(data);
console.log(post);
}).catch((error) => {
console.error('Error fetching post:', error);
});
Expand All @@ -25,13 +27,28 @@ const Board = () => {
<>
<SEO title="Community - Post" />
<section css={pageCSS}>
게시글이 만들어질 예정입니다.
<div css={postCSS}>
{post ? (
<div>
{/* TODO: 게시글 쓴 사람의 이미지가 필요함 */}
<div css={postInfoCSS}>
<div css={writerNameCSS}>{post.writerName}</div>
<div css={dateCSS}>{postDetailDateParse(post.createdAt)}</div>
</div>
<div css={postMainCSS}>
<div css={titleCSS}>{post.title}</div>
<div css={contentCSS}>{post.content}</div>
</div>
</div>
)
: <Loading />}
</div>
</section>
<BottomNavBar pageName="Community" />
</>
);
};
export default Board;
export default Post;

const pageCSS = css`
height: 100vh;
Expand All @@ -41,3 +58,39 @@ const pageCSS = css`
align-items: center;
padding: 0.5rem;
`;

const postCSS = css`
`;

const titleCSS = css`
font-size: 1rem;
font-weight:bold;
color:${color.black};

padding-bottom: 0.3rem
`;

const contentCSS = css`
font-size: 0.75rem;
color:${color.gray};
`;

const postInfoCSS = css`
padding: 0.2rem 0 0.2rem 0;
`;

const writerNameCSS = css`
font-size: 0.75rem;
font-weight:bold;
color:${color.black};
padding-bottom: 0.2rem;
`;

const dateCSS = css`
font-size: 0.6rem;
color:${color.gray};
`;

const postMainCSS = css`
padding: 0.2rem 0 0.2rem 0;
`;
7 changes: 4 additions & 3 deletions src/pages/community/[character_id]/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,17 @@ import { css } from '@emotion/react';
import BottomNavBar from '@/components/common/bottomNavBar/BottomNavBar';
import SEO from '@/components/common/head/SEO';
import { useEffect, useState } from 'react';
import { findAllBoards } from '@/utils/api/boards';
import { findBoardById } from '@/utils/api/boards';
import { useRouter } from 'next/router';
import { PostData } from '@/types/post';

const Board = () => {
const router = useRouter();
const [postList, setPostList] = useState([]);
const [postList, setPostList] = useState<PostData[]>([]);
const { character_id: characterId } = router.query;
useEffect(() => {
if (characterId && typeof characterId === 'string') {
findAllBoards(characterId).then((data) => {
findBoardById(characterId).then((data) => {
setPostList(data);
console.log(data);
console.log(postList);
Expand Down
55 changes: 37 additions & 18 deletions src/pages/community/index.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,28 @@
import { css } from '@emotion/react';
import BottomNavBar from '@/components/common/bottomNavBar/BottomNavBar';
import SEO from '@/components/common/head/SEO';
import { useEffect } from 'react';
import { findAllBoards, findBoardsById } from '@/utils/api/boards';
import SectionTitle from '@/components/common/sectionTitle/SectionTitle';
import SearchBar from '@/components/common/searchBar/SearchBar';
import BoardList from '@/components/community/BoardList';

const Community = () => {
useEffect(() => {
findAllBoards('1');
findBoardsById('1', '1');
}, []);

return (
<>
<SEO title="Community" />
<section css={pageCSS}>
커뮤니티 기능은 추후 제공될 예정입니다.
</section>
const Community = () => (
<>
<SEO title="Community" />
<section css={pageCSS}>
<header css={css`width:100%; padding-top:0.6rem;`}>
<div css={titleSectionCSS}>
<SectionTitle>Community</SectionTitle>
<SearchBar />
</div>
</header>
<main css={mainCSS}>
<BoardList />
</main>
<BottomNavBar pageName="Community" />
</>
);
};
</section>
</>
);

export default Community;

const pageCSS = css`
Expand All @@ -28,5 +31,21 @@ const pageCSS = css`
flex-direction: column;
justify-content: space-between;
align-items: center;
padding: 0.5rem;
padding: 0.625rem;
padding-bottom: 0;
`;

const titleSectionCSS = css`
width:100%;
display:flex;
justify-content:space-between;
align-items: center;
padding-left: 1.25rem;
padding-right: 0.6rem;
padding-top: 0.6rem;
`;

const mainCSS = css`
width: 100%;
height: 100%;
`;
9 changes: 9 additions & 0 deletions src/types/characterInfo.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export interface CharacterInfo {
backgroundUrl: string,
characterId: string,
hashtags: string,
id: number,
name: string,
profileUrl: string,
stateMessage: string
}
10 changes: 10 additions & 0 deletions src/types/post.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export interface PostData {
characterId : string
content : string
createdAt : string
id : number
title : string
updatedAt : string | null
writerId : number
writerName : string
}
15 changes: 10 additions & 5 deletions src/utils/api/boards.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import boardInstance from '@/utils/axiosInstance/boardInstance';
import webServerInstance from '@/utils/axiosInstance/webServerInstance';

export const findAllBoards = async (characterId: string) => {
const result = await boardInstance.get(characterId);
export const findAllBoards = async () => {
const result = await webServerInstance.get('/characters');
return result.data;
};

export const findBoardsById = async (characterId: string, postId: string) => {
const result = await boardInstance.get(`${characterId}/${postId}`);
export const findBoardById = async (characterId: string) => {
const result = await webServerInstance.get(`boards/${characterId}`);
return result.data;
};

export const findPostById = async (characterId: string, postId: string) => {
const result = await webServerInstance.get(`boards/${characterId}/${postId}`);
return result.data;
};
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import axios, { AxiosError } from 'axios';
import { getSession } from 'next-auth/react';

const boardInstance = axios.create({
baseURL: `${process.env.NEXT_PUBLIC_SERVER_URL || 'http://localhost:8080/'}api/boards/`,
const webServerInstance = axios.create({
baseURL: `${process.env.NEXT_PUBLIC_SERVER_URL || 'http://localhost:8080/'}api/`,
// headers: { 'Content-Type': 'application/json' },
});

boardInstance.interceptors.response.use((response) => response, (error: AxiosError) => {
webServerInstance.interceptors.response.use((response) => response, (error: AxiosError) => {
console.error('ERROR', error.toJSON());
if (error.response && error.response.status === 401) {
console.error('ERROR', error.toJSON());
}
return Promise.reject(error);
});

boardInstance.interceptors.request.use(
webServerInstance.interceptors.request.use(
async (config) => {
const session = await getSession();
const token = session?.accessToken;
Expand All @@ -29,4 +29,4 @@ boardInstance.interceptors.request.use(
(error) => Promise.reject(error),
);

export default boardInstance;
export default webServerInstance;
49 changes: 49 additions & 0 deletions src/utils/services/date.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// eslint-disable-next-line import/prefer-default-export
export const postDetailDateParse = (data: string) => {
const date = new Date(data);
const now = new Date();

const currentYear = now.getFullYear();
const postYear = date.getFullYear();

const formattedMonth = (date.getMonth() + 1).toString().padStart(2, '0');
const formattedDay = date.getDate().toString().padStart(2, '0');
const formattedHour = date.getHours().toString().padStart(2, '0');
const formattedMinute = date.getMinutes().toString().padStart(2, '0');

if (currentYear === postYear) {
return `${formattedMonth}/${formattedDay} ${formattedHour}:${formattedMinute}`;
}
const lastTwoDigitsOfYear = postYear.toString().slice(-2); // 연도의 마지막 두 자리
return `${lastTwoDigitsOfYear}/${formattedMonth}/${formattedDay} ${formattedHour}:${formattedMinute}`;
};

export const postDateParse = (data: string) => {
const now = new Date();
const date = new Date(data);
const diff = now.getTime() - date.getTime();

const ONE_MINUTE = 60 * 1000;
const ONE_HOUR = 60 * ONE_MINUTE;
const ONE_DAY = 24 * ONE_HOUR;

if (diff < ONE_HOUR) {
const minutes = Math.floor(diff / ONE_MINUTE);
return `${minutes}분 전`;
}

if (diff < ONE_DAY) {
const hours = Math.floor(diff / ONE_HOUR);
return `${hours}시간 전`;
}

const currentYear = now.getFullYear();
const postYear = date.getFullYear();
const formattedMonth = (date.getMonth() + 1).toString().padStart(2, '0');
const formattedDay = date.getDate().toString().padStart(2, '0');

if (currentYear === postYear) {
return `${formattedMonth}/${formattedDay}`;
}
return `${postYear}년`;
};