Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
2341700
design : 카테고리 버튼 사이즈 full로 변경
wldnjs990 Feb 20, 2025
83500ef
design : 옵션 슬라이드 바텀시트 애니메이션 구현(약간 미완)
wldnjs990 Feb 20, 2025
b585b4a
refactor:관리자 / 모바일용 레이아웃 분리
wldnjs990 Feb 20, 2025
eed708a
design : 관리자 페이지 퍼블리싱
wldnjs990 Feb 20, 2025
4e709cc
Merge branch 'develop' of https://github.com/prgrms-web-devcourse-fin…
wldnjs990 Feb 21, 2025
f3180fc
Merge branch 'develop' of https://github.com/prgrms-web-devcourse-fin…
wldnjs990 Feb 21, 2025
0a4f949
Merge branch 'develop' of https://github.com/prgrms-web-devcourse-fin…
wldnjs990 Feb 21, 2025
38757ae
design:관리자 페이지 퍼블리싱
wldnjs990 Feb 21, 2025
a181914
refactor : 폰트 선택 모달 아이콘 svgr 변경 + 목API 형식에 맞춰 타입 수정 + API 연결 작업 90% 완료
wldnjs990 Feb 21, 2025
45b0434
feat:글작성 페이지 쿼리스트링으로 이전편지 가져오기 API연결
wldnjs990 Feb 22, 2025
dce8d2e
feat:편지 상세 페이지 API 데이터바인딩 90%완료(유저 우편번호 데이터 필요)
wldnjs990 Feb 22, 2025
b0d7161
feat:편지삭제 api 생성
wldnjs990 Feb 23, 2025
45bdda0
feat:글작성, 상세 페이지 뒤로가기 버튼 + 상세페이지 글 삭제 버튼 추가
wldnjs990 Feb 24, 2025
6227d93
refactor : ResultLetter 타입 변경
wldnjs990 Feb 24, 2025
29a67a9
feat:글 작성 페이지 네비게이션 가드 테스트
wldnjs990 Feb 24, 2025
c3135aa
fix:코드리뷰 수정사항 반영
wldnjs990 Feb 24, 2025
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: 7 additions & 1 deletion src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ import { Route, Routes } from 'react-router';

import useViewport from './hooks/useViewport';
import Layout from './layouts/Layout';
import MobileLayout from './layouts/MobileLayout';
import AdminPage from './pages/Admin';
import ReportManage from './pages/Admin/Report';
import Home from './pages/Home';
import Landing from './pages/Landing';
import LetterBoardPage from './pages/LetterBoard';
Expand All @@ -22,7 +25,7 @@ const App = () => {

return (
<Routes>
<Route>
<Route element={<MobileLayout />}>
<Route index element={<Home />} />
<Route path="login" element={<LoginPage />} />
<Route path="landing" element={<Landing />} />
Expand All @@ -49,6 +52,9 @@ const App = () => {
<Route path="notifications" element={<NotificationsPage />} />
</Route>
</Route>
<Route path="admin" element={<AdminPage />}>
<Route path="report" element={<ReportManage />} />
</Route>
</Routes>
);
};
Expand Down
26 changes: 26 additions & 0 deletions src/apis/letterDetail.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { client } from './client';

const getLetter = async (
letterId: string,
setLetterState: React.Dispatch<React.SetStateAction<LetterDetail | null>>,
) => {
try {
const res = await client.get(`/api/letters/${letterId}`);
setLetterState(res.data.data);
console.log(res);
} catch (error) {
console.error(error);
}
};

const deleteLetter = async (letterId: string) => {
try {
console.log(`/api/letters/${letterId}`);
const res = await client.delete(`/api/letters/${letterId}`);
console.log(res);
} catch (error) {
console.error(error);
}
};

export { getLetter, deleteLetter };
29 changes: 29 additions & 0 deletions src/apis/write.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { client } from './client';

const postLetter = async (
data: LetterRequest,
setState?: React.Dispatch<React.SetStateAction<boolean>>,
) => {
try {
const res = await client.post('/api/letters', data);
if (setState) setState(true);
console.log(res);
} catch (error) {
console.error(error);
}
};

const getPrevLetter = async (
setPrevLetterState: React.Dispatch<React.SetStateAction<PrevLetter[]>>,
letterId: string,
) => {
try {
const res = await client.get(`/api/letters/${letterId}/previous`);
setPrevLetterState(res.data.data);
console.log(res);
} catch (error) {
console.error(error);
}
};

export { postLetter, getPrevLetter };
3 changes: 3 additions & 0 deletions src/assets/icons/arrow-down.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 17 additions & 0 deletions src/assets/icons/check.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions src/assets/icons/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import AlarmIcon from './alarm.svg?react';
import ArrowDownIcon from './arrow-down.svg?react';
import ArrowLeftIcon from './arrow-left.svg?react';
import BoardIcon from './board.svg?react';
import CheckIcon from './check.svg?react';
import CloudIcon from './cloud.svg?react';
import DeleteIcon from './delete.svg?react';
import EnvelopeIcon from './envelope.svg?react';
import GoogleIcon from './google.svg?react';
import InformationIcon from './information.svg?react';
import KakaoIcon from './kakao.svg?react';
import KebobMenuIcon from './kebob-menu.svg?react';
import LikeFilledIcon from './like-filled.svg?react';
import LikeOutlinedIcon from './like-outlined.svg?react';
import NaverIcon from './naver.svg?react';
Expand All @@ -26,9 +29,12 @@ export {
GoogleIcon,
StampIcon,
AlarmIcon,
CheckIcon,
ArrowDownIcon,
PersonIcon,
ArrowLeftIcon,
InformationIcon,
KebobMenuIcon,
EnvelopeIcon,
BoardIcon,
RestartIcon,
Expand Down
3 changes: 3 additions & 0 deletions src/assets/icons/kebob-menu.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 12 additions & 0 deletions src/components/BackButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { useNavigate } from 'react-router';

import { ArrowLeftIcon } from '@/assets/icons';

export default function BackButton() {
const navigate = useNavigate();
return (
<button onClick={() => navigate(-1)} aria-label="뒤로 가기">
<ArrowLeftIcon className="text-primary-1 h-6 w-6" />
</button>
);
}
10 changes: 5 additions & 5 deletions src/components/ResultLetter.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import letterPink from '@/assets/images/letter-pink.png';

import { STAMPS } from '../pages/Write/constants';
import { CATEGORYS } from '../pages/Write/constants';

export default function ResultLetter({
stampName = '위로와 공감',
categoryName = 'CONSOLATION',
title,
}: {
stampName: Stamp;
categoryName: Category;
title: string;
}) {
const address = '1A3E2';
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

address는 prop으로 전달해야겠네요!

Expand All @@ -15,15 +15,15 @@ export default function ResultLetter({

return (
<div
className="flex w-full flex-col gap-[35px] p-4"
className="flex w-full max-w-[300px] flex-col gap-[35px] p-4"
style={{ backgroundImage: `url(${letterPink})` }}
>
<div className="flex justify-between gap-3">
<div className="flex flex-col gap-2.5">
<span className="caption-b text-gray-60">따숨이님께</span>
<span className="caption-r text-gray-80 line-clamp-3 break-all">{title}</span>
</div>
<img src={STAMPS[stampName]} alt="우표" />
<img src={CATEGORYS[categoryName]} alt="우표" />
</div>
<div className="flex flex-col gap-[5px]">
<span className="caption-sb text-gray-60">{today}</span>
Expand Down
12 changes: 12 additions & 0 deletions src/layouts/MobileLayout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Outlet } from 'react-router';

const MobileLayout = () => {
return (
<div className="mobile-bg">
<div className="mobile-layout">
<Outlet />
</div>
</div>
);
};
export default MobileLayout;
139 changes: 139 additions & 0 deletions src/pages/Admin/Report.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
import { useEffect, useState } from 'react';

import { client } from '@/apis/client';
import { AlarmIcon } from '@/assets/icons';

import DetailFrame from './components/DetailFrame';
import ListItem from './components/ListItem';
import WrapperFrame from './components/WrapperFrame';

export default function ReportManage() {
const [detailModalOpen, setDetailModalOpen] = useState<boolean>(false);
// {
// id: '001',
// reporterEmail: '[email protected]',
// targetEmail: '[email protected]',
// reportedAt: new Date(2025, 1, 20),
// letterId:2001,
// sharePostId:null,
// eventId:null,
// reportType:'LETTER',
// reason:"ABUSE",
// reasonDetail:null,
// status: 'PENDING',
// },
const DUMMY = [
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

어떤 더미 데이터인지 적어주시는 게 직관적일 것 같아요 ex) DUMMY_REPORTS

{
id: '001',
reporterEmail: '[email protected]',
targetEmail: '[email protected]',
reportedAt: new Date(2020, 12, 4),
reason: '욕설',
},
{
id: '002',
reporterEmail: '[email protected]',
targetEmail: '[email protected]',
reportedAt: new Date(2020, 12, 4),
reason: '욕설',
},
{
id: '003',
reporterEmail: '[email protected]',
targetEmail: '[email protected]',
reportedAt: new Date(2000, 6, 23),
reason: '욕설',
},
{
id: '004',
reporterEmail: '[email protected]',
targetEmail: '[email protected]',
reportedAt: new Date(1080, 11, 5),
reason: '욕설',
},
{
id: '005',
reporterEmail: '[email protected]',
targetEmail: '[email protected]',
reportedAt: new Date(2040, 1, 2),
reason: '욕설',
},
{
id: '006',
reporterEmail: '[email protected]',
targetEmail: '[email protected]',
reportedAt: new Date(2025, 1, 23),
reason: '욕설',
},
];
const modalContents = [
{
title: '신고 목록 삭제',
onClick: () => {
console.log('삭제');
},
},
{
title: '작성자 활동 정지',
onClick: () => {
console.log('정지');
},
},
];
// const [allReports, setAllReports] = useState();
useEffect(() => {
const getAllReports = async () => {
const res = await client.get('/api/reports');
console.log(res);
};
getAllReports();
const getReportDetail = async () => {
const res = await client.get('/api/reports/2');
console.log(res);
};
getReportDetail();
const postReport = async () => {
const res = await client.post('/api/reports', {
letterId: 2010,
reportType: 'POST',
reason: 'HARASSMENT',
reasonDetail: '테스트용',
});
console.log(res);
};
postReport();
}, []);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

useEffect에서 getAllReports, getReportDetail, postReport가 한 번에 호출되고 있는데 필요한 시점에 호출되도록 분리하면 성능이 더 좋아질 것 같아요!

return (
<WrapperFrame>
<span className="h3-sb flex items-center gap-4.5">
<AlarmIcon className="h-9 w-9"></AlarmIcon> 신고 편지 목록
</span>
<section className="mt-5 flex flex-col">
<div className="bg-primary-3 flex w-full border-b px-6 py-4">
<div className="flex w-[80%] items-center">
<span className="ml-4 flex basis-1/10 overflow-ellipsis">ID</span>
<span className="ml-4 flex basis-2/10">제보자 이메일</span>
<span className="ml-4 flex basis-2/10">작성자 이메일</span>
<span className="ml-4 flex basis-2/10">제보 일자</span>
<span className="ml-4 flex basis-3/10">제보 사유</span>
</div>
</div>
{DUMMY.map((data, idx) => (
<ListItem
data={data}
modalContents={modalContents}
key={idx}
setDetailModalOpen={setDetailModalOpen}
/>
))}
</section>
{detailModalOpen && (
<DetailFrame closeEvent={setDetailModalOpen}>
<>
<span className="h2-sb">제보 편지 상세 조회</span>
</>
</DetailFrame>
)}
</WrapperFrame>
);
}
31 changes: 31 additions & 0 deletions src/pages/Admin/admin.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
interface Report {
id: number;
reporterEmail: string;
targetEmail: string;
reportedAt: Date;
letterId: number | null;
comment: string | null;
sharePostId: number | null;
reportType: 'LETTER' | 'POST' | 'COMMENT';
reason: 'ABUSE' | 'DEFAMATION' | 'HARASSMENT' | 'THREATS' | 'ETC';
reasonDetail: string | null;
status: 'PENDING' | 'RESOLVED' | 'REJECTED';
}

interface ReportDetail {
id: number;
memberId: number | null;
letterId: number | null;
sharePostId: number | null;
eventId: number | null;
reportType: 'LETTER' | 'POST' | 'COMMENT' | 'EVENT';
reason: 'ABUSE' | 'DEFAMATION' | 'HARASSMENT' | 'THREATS' | 'ETC';
reasonDetail: string | null;
status: 'PENDING' | 'RESOLVED' | 'REJECTED';
reportedAt: Date;
createdAt: Date;
letterDetail: {
title: string;
content: string;
};
}
Loading