Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
junghaesung79 committed Jan 27, 2025
2 parents f83a879 + 4cb559f commit d37bf9a
Show file tree
Hide file tree
Showing 194 changed files with 4,717 additions and 2,659 deletions.
94 changes: 52 additions & 42 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
/* eslint-disable */
import { useEffect, ReactNode, Suspense } from 'react';
import {
Routes,
Route,
useLocation,
Navigate,
} from 'react-router-dom';
import AuthPage from 'pages/Auth/AuthPage';
import LoginPage from 'pages/Auth/LoginPage';
import BoardPage from 'pages/BoardPage';
import StorePage from 'pages/Store/StorePage';
import NoticePage from 'pages/Notice/NoticePage';
import NoticeListPage from 'pages/Notice/NoticeListPage';
import NoticeDetailPage from 'pages/Notice/NoticeDetailPage';
import ArticlesPage from 'pages/Articles/ArticlesPage';
import ArticleListPage from 'pages/Articles/ArticleListPage';
import ArticlesDetailPage from 'pages/Articles/ArticlesDetailPage';
import Toast from 'components/common/Toast';
import LogPage from 'components/common/LogPage';
import SignupPage from 'pages/Auth/SignupPage';
Expand All @@ -27,27 +29,39 @@ import TimetablePage from 'pages/TimetablePage/MainTimetablePage';
import CafeteriaPage from 'pages/Cafeteria';
import MetaHelmet from 'components/common/MetaHelmet';
import ModifyInfoPage from 'pages/Auth/ModifyInfoPage';
import PrivateRoute from 'components/common/PrivateRoute';
import AddReviewPage from 'pages/StoreReviewPage/AddReviewPage';
import EditReviewPage from 'pages/StoreReviewPage/EditReviewPage';
import ReviewReportingPage from 'pages/Store/StoreDetailPage/Review/components/ReviewReporting';
import ModifyTimetablePage from 'pages/TimetablePage/ModifyTimetablePage';
import PageNotFound from 'pages/Error/PageNotFound';
import PolicyPage from 'pages/PolicyPage';
import ROUTES from 'static/routes';
import LostItemWritePage from 'pages/Articles/LostItemWritePage';
import LostItemDetailPage from 'pages/Articles/LostItemDetailPage';
import useTokenState from 'utils/hooks/state/useTokenState';

interface HelmetWrapperProps {
interface WrapperProps {
title: string;
element: ReactNode;
needAuth?: boolean;
}

function HelmetWrapper({ title, element }: HelmetWrapperProps) {
function Wrapper({
title,
element,
needAuth = false, // 로그인이 필요한 라우트
}: WrapperProps) {
const location = useLocation();
const token = useTokenState();

useEffect(() => {
document.title = title;
document.title = `코인 - ${title}`;
}, [title, location]);

if (needAuth && !token) {
return <Navigate replace to={ROUTES.Main()} />;
}

return (
<>
<MetaHelmet title={title} />
Expand All @@ -64,47 +78,43 @@ function App() {
<>
<Routes>
<Route path={ROUTES.Main()} element={<BoardPage />}>
<Route path={ROUTES.Timetable()} element={<HelmetWrapper title="코인 - 시간표" element={<TimetablePage />} />} />
<Route path={ROUTES.TimetableRegular({ isLink: false })} element={<HelmetWrapper title="코인 - 시간표 수정" element={<ModifyTimetablePage />} />} />
<Route path={ROUTES.TimetableDirect({ isLink: false })} element={<HelmetWrapper title="코인 - 시간표 수정" element={<ModifyTimetablePage />} />} />
<Route path={ROUTES.Main()} element={<HelmetWrapper title="코인 - 한기대 커뮤니티" element={<IndexPage />} />} />
<Route path={ROUTES.Store()} element={<HelmetWrapper title="코인 - 상점" element={<StorePage />} />} />
<Route path={ROUTES.BenefitStore()} element={<HelmetWrapper title="코인 - 전화 혜택" element={<StoreBenefitPage />} />} />
<Route path={ROUTES.StoreDetail({ isLink: false })} element={<HelmetWrapper title="코인 - 상점 상세" element={<StoreDetailPage />} />} />
<Route path={ROUTES.BusRoute()} element={<HelmetWrapper title="코인 - 버스" element={<BusRoutePage />} />} />
<Route path={ROUTES.BusCourse()} element={<HelmetWrapper title="코인 - 버스" element={<BusCoursePage />} />} />
<Route path={ROUTES.Cafeteria()} element={<HelmetWrapper title="코인 - 식단" element={<CafeteriaPage />} />} />
<Route path={ROUTES.PrivatePolicy()} element={<HelmetWrapper title="코인 - 개인정보 처리방침" element={<PolicyPage />} />} />
<Route path={ROUTES.BoardNotice()} element={<HelmetWrapper title="코인 - 공지사항" element={<NoticePage />} />}>
<Route path={ROUTES.BoardNotice()} element={<NoticeListPage />} />
<Route path={ROUTES.BoardNoticeDetail({ isLink: false })} element={<HelmetWrapper title="코인 - 공지사항 상세" element={<NoticeDetailPage />} />} />
<Route index element={<Wrapper title="한기대 커뮤니티" element={<IndexPage />} />} />
<Route path={ROUTES.PrivatePolicy()} element={<Wrapper title="개인정보 처리방침" element={<PolicyPage />} />} />

<Route path={ROUTES.Timetable()} element={<Wrapper title="시간표" element={<TimetablePage />} />} />
<Route path={ROUTES.TimetableRegular({ isLink: false })} element={<Wrapper title="시간표 수정" element={<ModifyTimetablePage />} />} />
<Route path={ROUTES.TimetableDirect({ isLink: false })} element={<Wrapper title="시간표 수정" element={<ModifyTimetablePage />} />} />

<Route path={ROUTES.Store()} element={<Wrapper title="상점" element={<StorePage />} />} />
<Route path={ROUTES.BenefitStore()} element={<Wrapper title="전화 혜택" element={<StoreBenefitPage />} />} />
<Route path={ROUTES.StoreDetail({ isLink: false })} element={<Wrapper title="상점 상세" element={<StoreDetailPage />} />} />
<Route path={ROUTES.Review({ isLink: false })} element={<Wrapper needAuth title="상점 리뷰" element={<AddReviewPage />} />} />
<Route path={ROUTES.ReviewEdit({ isLink: false })} element={<Wrapper needAuth title="상점 리뷰" element={<EditReviewPage />} />} />
<Route path={ROUTES.ReviewReport({ isLink: false })} element={<Wrapper needAuth title="리뷰 신고" element={<ReviewReportingPage />} />} />
<Route path={ROUTES.Room()} element={<Wrapper title="복덕방" element={<RoomPage />} />} />
<Route path={ROUTES.RoomDetail({ isLink: false })} element={<Wrapper title="복덕방 상세" element={<RoomDetailPage />} />} />

<Route path={ROUTES.BusRoute()} element={<Wrapper title="버스" element={<BusRoutePage />} />} />
<Route path={ROUTES.BusCourse()} element={<Wrapper title="버스" element={<BusCoursePage />} />} />
<Route path={ROUTES.Cafeteria()} element={<Wrapper title="식단" element={<CafeteriaPage />} />} />
<Route path={ROUTES.Articles()} element={<Wrapper title="공지사항" element={<ArticlesPage />} />}>
<Route index element={<ArticleListPage />} />
<Route path={ROUTES.ArticlesDetail({ isLink: false })} element={<Wrapper title="공시사항 상세" element={<ArticlesDetailPage />} />} />
<Route path={ROUTES.LostItemDetail({ isLink: false })} element={<Wrapper title="분실물 상세" element={<LostItemDetailPage />} />} />
</Route>
<Route path={ROUTES.Room()} element={<HelmetWrapper title="코인 - 복덕방" element={<RoomPage />} />} />
<Route path={ROUTES.RoomDetail({ isLink: false })} element={<HelmetWrapper title="코인 - 복덕방 상세" element={<RoomDetailPage />} />} />
<Route path={ROUTES.CampusInfo()} element={<HelmetWrapper title="코인 - 교내 시설물 정보" element={<CampusInfo />} />} />
<Route path={ROUTES.LostItemFound()} element={<Wrapper needAuth title="분실물 글쓰기" element={<LostItemWritePage />} />} />
<Route path={ROUTES.LostItemLost()} element={<Wrapper needAuth title="분실물 글쓰기" element={<LostItemWritePage />} />} />
<Route path={ROUTES.CampusInfo()} element={<Wrapper title="교내 시설물 정보" element={<CampusInfo />} />} />
</Route>
<Route
path={ROUTES.Auth()}
element={<PrivateRoute requireAuthentication={false} element={<AuthPage />} />}
>
<Route index element={<HelmetWrapper title="코인 - 로그인" element={<LoginPage />} />} />
<Route path={ROUTES.AuthSignup()} element={<HelmetWrapper title="코인 - 회원가입" element={<SignupPage />} />} />
<Route path={ROUTES.AuthFindPW()} element={<HelmetWrapper title="코인 - 비밀번호 찾기" element={<FindPasswordPage />} />} />
</Route>
<Route path={ROUTES.Main()} element={<BoardPage />}>
<Route path={ROUTES.Review({ isLink: false })} element={<PrivateRoute requireAuthentication element={<HelmetWrapper title="코인 - 상점 리뷰" element={<AddReviewPage />} />} />} />
<Route path={ROUTES.ReviewEdit({ isLink: false })} element={<PrivateRoute requireAuthentication element={<HelmetWrapper title="코인 - 상점 리뷰" element={<EditReviewPage />} />} />} />
<Route path={ROUTES.ReviewReport({ isLink: false })} element={<PrivateRoute requireAuthentication element={<HelmetWrapper title="코인 - 리뷰 신고" element={<ReviewReportingPage />} />} />} />

</Route>
<Route path={ROUTES.Auth()} element={<AuthPage />}>
<Route path={ROUTES.AuthModifyInfo()} element={<PrivateRoute requireAuthentication element={<HelmetWrapper title="코인 - 유저 정보변경" element={<ModifyInfoPage />} />} />} />
<Route index element={<Wrapper title="로그인" element={<LoginPage />} />} />
<Route path={ROUTES.AuthSignup()} element={<Wrapper title="회원가입" element={<SignupPage />} />} />
<Route path={ROUTES.AuthFindPW()} element={<Wrapper title="비밀번호 찾기" element={<FindPasswordPage />} />} />
<Route path={ROUTES.AuthModifyInfo()} element={<Wrapper needAuth title="유저 정보변경" element={<ModifyInfoPage />} />} />
</Route>

<Route path={ROUTES.Webview()}>
<Route path={ROUTES.WebviewCampusInfo()} element={<HelmetWrapper title="코인 - 교내 시설물 정보" element={<CampusInfo />} />} />
</Route>
<Route path={ROUTES.NotFound()} element={<HelmetWrapper title="코인 - 404 Not Found" element={<PageNotFound />} />} />
<Route path={ROUTES.NotFound()} element={<Wrapper title="404 Not Found" element={<PageNotFound />} />} />
</Routes>
<Toast />
</>
Expand Down
89 changes: 89 additions & 0 deletions src/api/articles/APIDetail.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { APIRequest, HTTP_METHOD } from 'interfaces/APIRequest';
import {
ArticlesResponse,
ArticleResponse,
HotArticlesResponse,
SingleLostItemArticleResponseDTO,
LostItemArticlesResponseDTO,
LostItemResponse,
LostItemArticlesRequestDTO,
} from './entity';

export class GetArticles<R extends ArticlesResponse> implements APIRequest<R> {
method = HTTP_METHOD.GET;

path: string;

response!: R;

constructor(page: string | undefined) {
this.path = `/articles?page=${page}&limit=10`;
}
}

export class GetArticle<R extends ArticleResponse> implements APIRequest<R> {
method = HTTP_METHOD.GET;

path: string;

response!: R;

constructor(id: string | undefined) {
this.path = `/articles/${id}`;
}
}

export class GetHotArticles<R extends HotArticlesResponse> implements APIRequest<R> {
method = HTTP_METHOD.GET;

path = '/articles/hot';

response!: R;
}

export class GetLostItemArticles<R extends LostItemArticlesResponseDTO> implements APIRequest<R> {
method = HTTP_METHOD.GET;

path = '/articles/lost-item';

response!: R;
}

export class GetSingleLostItemArticle<R
extends SingleLostItemArticleResponseDTO> implements APIRequest<R> {
method = HTTP_METHOD.GET;

path: string;

response!: R;

constructor(id: number) {
this.path = `/articles/lost-item/${id}`;
}
}

export class PostLostItemArticles<R extends LostItemResponse> implements APIRequest<R> {
method = HTTP_METHOD.POST;

path = '/articles/lost-item';

response!: R;

auth = true;

constructor(public authorization: string, public data: LostItemArticlesRequestDTO) { }
}

export class DeleteLostItemArticle<R extends LostItemResponse> implements APIRequest<R> {
method = HTTP_METHOD.DELETE;

path: string;

response!: R;

auth = true;

constructor(public authorization: string, id: number) {
this.path = `/articles/lost-item/${id}`;
}
}
118 changes: 118 additions & 0 deletions src/api/articles/entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import { APIResponse } from 'interfaces/APIResponse';

export interface GetArticlesRequest {
boardId: string
page: string
}

export interface Article {
id: number
board_id: number
title: string
author: string
hit: number
registered_at: string // yyyy-MM-dd 아우누리에 게시판에 등록된 날짜
updated_at: string // yyyy-MM-dd HH:mm:ss 이하 형식 동일
}

export interface Attachment {
id: 1,
name: string,
url: string,
created_at: string,
updated_at: string,
}

export interface PaginationInfo {
total_count: number
current_count: number
total_page: number
current_page: number
}

export interface PaginatedResponse<T> extends PaginationInfo, APIResponse {
articles: T[];
}

export type ArticlesResponse = PaginatedResponse<Article>;
export type ArticlesSearchResponse = PaginatedResponse<Article>;

export interface ArticleResponse extends Article, APIResponse {
content: string;
attachments: Attachment[];
prev_id: number;
next_id: number;
}

export interface HotArticle extends Article { }

export type HotArticlesResponse = HotArticle[];

// GET /articles/lost-item
interface LostItemArticleForGetDTO {
id: number;
board_id: number;
category: string;
found_place: string;
found_date: string;
content: string;
author: string;
registered_at: string;
updated_at: string;
}

export interface LostItemArticlesResponseDTO extends APIResponse {
articles: LostItemArticleForGetDTO[];
total_count: number;
current_count: number;
total_page: number;
current_page: number;
}

interface ImageDTO {
id: number;
image_url: string;
}

export interface SingleLostItemArticleResponseDTO extends APIResponse {
id: number;
board_id: number;
category: string;
found_place: string;
found_date: string;
content: string;
author: string;
images: ImageDTO[];
prev_id: number | null;
next_id: number | null;
registered_at: string; // yyyy-MM-dd
updated_at: string; // yyyy-MM-dd HH:mm:ss
}

export interface LostItemResponse extends APIResponse {
id: number;
board_id: number;
category: string;
found_place: string;
found_date: string;
content: string;
author: string;
images: ImageDTO[];
prev_id: number | null;
next_id: number | null;
registered_at: string;
updated_at: string;
}

// POST /articles/lost-item
interface LostItemArticleForPostDTO {
category: string;
found_place: string;
found_date: string; // yyyy-MM-dd
content: string;
images: string[];
}

export interface LostItemArticlesRequestDTO {
articles: Array<LostItemArticleForPostDTO>;
}
24 changes: 24 additions & 0 deletions src/api/articles/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import APIClient from 'utils/ts/apiClient';
import {
GetArticles,
GetHotArticles,
GetArticle,
GetLostItemArticles,
GetSingleLostItemArticle,
DeleteLostItemArticle,
PostLostItemArticles,
} from './APIDetail';

export const getArticles = APIClient.of(GetArticles);

export const getArticle = APIClient.of(GetArticle);

export const getHotArticles = APIClient.of(GetHotArticles);

export const getLostItemArticles = APIClient.of(GetLostItemArticles);

export const getSingleLostItemArticle = APIClient.of(GetSingleLostItemArticle);

export const postLostItemArticle = APIClient.of(PostLostItemArticles);

export const deleteLostItemArticle = APIClient.of(DeleteLostItemArticle);
13 changes: 7 additions & 6 deletions src/api/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
export * as abTest from './abTest';
export * as auth from './auth';
export * as store from './store';
export * as dept from './dept';
export * as timetable from './timetable';
export * as bus from './bus';
export * as notice from './notice';
export * as room from './room';
export * as cafeteria from './cafeteria';
export * as coopshop from './coopshop';
export * as dept from './dept';
export * as articles from './articles';
export * as review from './review';
export * as abTest from './abTest';
export * as room from './room';
export * as store from './store';
export * as timetable from './timetable';
export * as uploadFile from './uploadFile';
Loading

0 comments on commit d37bf9a

Please sign in to comment.