Skip to content
This repository was archived by the owner on Jan 2, 2026. It is now read-only.

Commit 488d544

Browse files
authored
✨ 학생회 활동보고 편집 페이지 구현 (#323)
1 parent 235c546 commit 488d544

File tree

12 files changed

+118
-33
lines changed

12 files changed

+118
-33
lines changed

actions/council.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
putCouncilMinute,
1010
} from '@/apis/v2/council/meeting-minute';
1111
import { postCouncilReport } from '@/apis/v2/council/report';
12+
import { deleteCouncilReport, putCouncilReport } from '@/apis/v2/council/report/[id]';
1213
import {
1314
FETCH_TAG_COUNCIL_INTRO,
1415
FETCH_TAG_COUNCIL_MINUTE,
@@ -67,3 +68,19 @@ export const postCouncilReportAction = withErrorHandler(async (formData: FormDat
6768
revalidateTag(FETCH_TAG_COUNCIL_REPORT);
6869
redirectKo(councilReportPath);
6970
});
71+
72+
export const putCouncilReportAction = withErrorHandler(async (id: number, formData: FormData) => {
73+
await putCouncilReport(id, formData);
74+
revalidateTag(FETCH_TAG_COUNCIL_REPORT);
75+
redirectKo(`${councilReportPath}/${id}`);
76+
});
77+
78+
export const deleteCouncilReportAction = async (id: number) => {
79+
try {
80+
await deleteCouncilReport(id);
81+
revalidateTag(FETCH_TAG_COUNCIL_REPORT);
82+
} catch (error) {
83+
return { message: error instanceof Error ? error.message : '알 수 없는 에러: ' + error };
84+
}
85+
redirectKo(councilReportPath);
86+
};

apis/types/council.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,5 @@ export interface CouncilReport {
1717
prevTitle: string;
1818
nextId: number;
1919
nextTitle: string;
20+
imageURL: string;
2021
}

apis/v2/council/report/[id].ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,5 @@ export const putCouncilReport = (id: number, formData: FormData) =>
1313
jsessionID: true,
1414
});
1515

16-
export const deleteCouncilReport = (id: number) => {
17-
return deleteRequest(`/v2/council/report/${id}`, { jsessionID: true });
18-
};
16+
export const deleteCouncilReport = (id: number) =>
17+
deleteRequest(`/v2/council/report/${id}`, { jsessionID: true });

app/[locale]/community/components/PostDeleteButton.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import { useTransition } from 'react';
44

5+
import { deleteCouncilReportAction } from '@/actions/council';
56
import { deleteNewsAction } from '@/actions/news';
67
import { deleteNoticeAction } from '@/actions/notice';
78
import { deleteSeminarAction } from '@/actions/seminar';
@@ -27,6 +28,8 @@ export default function PostDeleteButton({ postType, id }: { postType: string; i
2728
return deleteNewsAction;
2829
case 'seminar':
2930
return deleteSeminarAction;
31+
case 'council/report':
32+
return deleteCouncilReportAction;
3033
}
3134
};
3235

app/[locale]/community/components/PostFooter.tsx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { useTranslations } from 'next-intl';
33
import { CouncilReport } from '@/apis/types/council';
44
import { News } from '@/apis/types/news';
55
import { Notice } from '@/apis/types/notice';
6+
import { Role } from '@/apis/types/role';
67
import { Seminar } from '@/apis/types/seminar';
78
import LoginVisible from '@/components/common/LoginVisible';
89
import { Link } from '@/i18n/routing';
@@ -15,6 +16,7 @@ type PostFooterProps = {
1516
post: Notice | News | Seminar | CouncilReport;
1617
id?: string;
1718
margin?: string;
19+
role?: Role[] | Role;
1820
};
1921

2022
type AdjPost = {
@@ -25,7 +27,13 @@ type AdjPost = {
2527
type PostType = 'notice' | 'seminar' | 'news' | 'council/report';
2628
type RowType = 'next' | 'prev';
2729

28-
export default function PostFooter({ post, margin = '', postType, id }: PostFooterProps) {
30+
export default function PostFooter({
31+
post,
32+
margin = '',
33+
postType,
34+
id,
35+
role = 'ROLE_STAFF',
36+
}: PostFooterProps) {
2937
const nextPost =
3038
post.nextId && post.nextTitle ? { id: post.nextId, title: post.nextTitle } : null;
3139
const prevPost =
@@ -36,7 +44,7 @@ export default function PostFooter({ post, margin = '', postType, id }: PostFoot
3644
{nextPost && <Row post={nextPost} type="next" postType={postType} />}
3745
{prevPost && <Row post={prevPost} type="prev" postType={postType} />}
3846
<div className="mt-16 flex justify-end">
39-
<LoginVisible staff>
47+
<LoginVisible role={role}>
4048
{id && (
4149
<>
4250
<PostDeleteButton postType={postType} id={id} />
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
'use client';
2+
3+
import { putCouncilReportAction } from '@/actions/council';
4+
import CouncilReportEditor, {
5+
CouncilReportEditorContent,
6+
} from '@/app/[locale]/community/council/report/components/CouncilReportEditor';
7+
import PageLayout from '@/components/layout/pageLayout/PageLayout';
8+
import { councilReportList } from '@/constants/segmentNode';
9+
import { useRouter } from '@/i18n/routing';
10+
import { contentToFormData } from '@/utils/formData';
11+
import { getPath } from '@/utils/page';
12+
13+
const councilReportListPath = getPath(councilReportList);
14+
15+
export default function CouncilReportEditPageContent({
16+
id,
17+
defaultValues,
18+
}: {
19+
id: number;
20+
defaultValues: CouncilReportEditorContent;
21+
}) {
22+
const router = useRouter();
23+
24+
const onCancel = () => {
25+
router.push(`${councilReportListPath}/${id}`);
26+
};
27+
28+
const onSubmit = async ({ mainImage: image, ...requestObject }: CouncilReportEditorContent) => {
29+
const formData = contentToFormData('EDIT', { requestObject, image });
30+
await putCouncilReportAction(id, formData);
31+
};
32+
33+
return (
34+
<PageLayout title="활동 보고 수정" titleType="big" titleMargin="mb-[2.75rem]" hideNavbar>
35+
<CouncilReportEditor onCancel={onCancel} onSubmit={onSubmit} defaultValues={defaultValues} />
36+
</PageLayout>
37+
);
38+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { getCouncilReport } from '@/apis/v2/council/report/[id]';
2+
import CouncilReportEditPageContent from '@/app/[locale]/community/council/report/[id]/edit/client';
3+
4+
export default async function CouncilReportEditPage({
5+
params,
6+
}: {
7+
params: Promise<{ id: string }>;
8+
}) {
9+
const { id } = await params;
10+
const parsedId = parseInt(id);
11+
if (isNaN(parsedId)) throw new Error(`잘못된 아이디: ${id}`);
12+
13+
const report = await getCouncilReport(parsedId);
14+
15+
return (
16+
<CouncilReportEditPageContent
17+
id={parsedId}
18+
defaultValues={{ ...report, mainImage: { type: 'UPLOADED_IMAGE', url: report.imageURL } }}
19+
/>
20+
);
21+
}

app/[locale]/community/council/report/[id]/page.tsx

Lines changed: 13 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import 'dayjs/locale/ko';
33
import dayjs from 'dayjs';
44
import { getTranslations } from 'next-intl/server';
55

6-
import { CouncilReport } from '@/apis/types/council';
6+
import { getCouncilReport } from '@/apis/v2/council/report/[id]';
77
import PostFooter from '@/app/[locale]/community/components/PostFooter';
88
import { StraightNode } from '@/components/common/Nodes';
99
import HTMLViewer from '@/components/form/html/HTMLViewer';
@@ -12,27 +12,13 @@ import PageLayout from '@/components/layout/pageLayout/PageLayout';
1212
import { councilReportList } from '@/constants/segmentNode';
1313
import { getMetadata } from '@/utils/metadata';
1414

15-
const council: CouncilReport = {
16-
id: 2,
17-
title: 'title',
18-
description: 'description',
19-
sequence: 1,
20-
name: 'name',
21-
createdAt: '2022-01-01T00:00:00.000Z',
22-
prevId: 1,
23-
prevTitle: 'prevTitle',
24-
nextId: 3,
25-
nextTitle: 'nextTitle',
26-
};
27-
2815
interface Props {
2916
params: Promise<{ id: number; locale: string }>;
3017
}
3118

3219
export async function generateMetadata({ params }: Props) {
33-
const { locale } = await params;
34-
// const { title } = await getCouncilReport(id);
35-
const { title } = council;
20+
const { locale, id } = await params;
21+
const { title } = await getCouncilReport(id);
3622

3723
return await getMetadata({
3824
locale,
@@ -42,10 +28,9 @@ export async function generateMetadata({ params }: Props) {
4228
}
4329

4430
export default async function CouncilReportPage({ params }: Props) {
45-
const { id, locale } = await params;
46-
const t = await getTranslations({ locale });
47-
48-
// const council = await getCouncilReport(id);
31+
const { id } = await params;
32+
const t = await getTranslations('Content');
33+
const council = await getCouncilReport(id);
4934

5035
const { title, description, sequence, name, createdAt } = council;
5136
const author = `제${sequence}대 학생회 ${name}`;
@@ -70,7 +55,13 @@ export default async function CouncilReportPage({ params }: Props) {
7055
>
7156
<HTMLViewer htmlContent={description} wrapperClassName="mb-10" />
7257
<StraightNode />
73-
<PostFooter post={council} postType="council/report" id={id.toString()} margin="mt-12" />
58+
<PostFooter
59+
post={council}
60+
postType="council/report"
61+
id={id.toString()}
62+
margin="mt-12"
63+
role={['ROLE_COUNCIL', 'ROLE_STAFF']}
64+
/>
7465
</div>
7566
</PageLayout>
7667
);

app/[locale]/community/council/report/components/CouncilReportEditor.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,11 @@ export interface CouncilReportEditorContent {
1515
interface Props {
1616
onCancel: () => void;
1717
onSubmit: (content: CouncilReportEditorContent) => Promise<void>;
18+
defaultValues?: CouncilReportEditorContent;
1819
}
1920

20-
export default function CouncilReportEditor({ onCancel, onSubmit }: Props) {
21-
const methods = useForm<CouncilReportEditorContent>();
21+
export default function CouncilReportEditor({ onCancel, onSubmit, defaultValues }: Props) {
22+
const methods = useForm<CouncilReportEditorContent>({ defaultValues });
2223
const { handleSubmit } = methods;
2324

2425
return (

app/[locale]/community/council/report/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export default async function CouncilReportList() {
2424
<Tile key={report.id} {...report} />
2525
))}
2626
</div>
27-
<LoginVisible>
27+
<LoginVisible role={['ROLE_COUNCIL', 'ROLE_STAFF']}>
2828
<div className="mt-[40px] flex justify-end">
2929
<Link href={`${path}/create`}>
3030
<button

0 commit comments

Comments
 (0)