Skip to content

Commit

Permalink
♻️ 관리자 페이지 리팩터링 (#160)
Browse files Browse the repository at this point in the history
* feat: AdminPage SSR로 수정

* refactor: useSWR 제거

* refactor: admin쪽 훅 분리
  • Loading branch information
yeolyi authored Mar 10, 2024
1 parent 80ebe77 commit ae32753
Show file tree
Hide file tree
Showing 22 changed files with 137 additions and 307 deletions.
26 changes: 12 additions & 14 deletions actions/admin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { revalidateTag } from 'next/cache';

import { patchMultipleImportants, patchMultipleSlides } from '@/apis/adminServer';
import { patchMultipleImportants, patchMultipleSlides } from '@/apis/admin';

import { ImportantPostIdentifier } from '@/types/admin';

Expand All @@ -13,25 +13,23 @@ import { revalidateSeminarTag } from './seminar';
export const batchUnslideAction = async (ids: Set<number>) => {
try {
await patchMultipleSlides(Array.from(ids));
revalidateSlideTag();
revalidateNewsTag();
} catch (error) {
console.log(error instanceof Error ? error.message : error);
return { error };
} catch (e) {
return e;
}
revalidateSlideTag();
revalidateNewsTag();
};

export const batchUnimportantAction = async (infos: ImportantPostIdentifier[]) => {
try {
await patchMultipleImportants(Array.from(infos));
revalidateImportantTag();
revalidateNoticeTag();
revalidateNewsTag();
revalidateSeminarTag();
} catch (error) {
console.log(error instanceof Error ? error.message : error);
return { error };
await patchMultipleImportants(infos);
} catch (e) {
return e;
}
revalidateImportantTag();
revalidateNoticeTag();
revalidateNewsTag();
revalidateSeminarTag();
};

const revalidateSlideTag = () => {
Expand Down
19 changes: 2 additions & 17 deletions apis/academicsServer.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// TODO: 서버에서 제공되면 파일 삭제

import { getMockDegreeRequirements } from '@/data/objects';
import {
getMockCurriculum,
Expand All @@ -15,20 +17,3 @@ export const getGeneralStudiesRequirements = getMockGeneralStudiesRequirements;
export const getUndergraduateScholarshipList = getMockUndergraduateScholarshipList;

export const getScholarship = getMockScholarship;

// export const getDegreeRequirements = () =>
// getRequest(`/academics/undergraduate/degree-requirements`) as Promise<DegreeRequirements[]>;

// export const getCurriculum = () =>
// getRequest(`/academics/undergraduate/curriculum`) as Promise<Curriculum[]>;

// export const getGeneralStudiesRequirements = () =>
// getRequest(
// `/academics/undergraduate/general-studies-requirements`,
// ) as Promise<GeneralStudiesRequirements>;

// export const getUndergraduateScholarshipList = () =>
// getRequest('/academics/undergraduate/general-studies-requirements') as Promise<ScholarshipList>;

// export const getScholarship = (id: number) =>
// getRequest('/academics/undergraduate/general-studies-requirements') as Promise<Scholarship>;
60 changes: 20 additions & 40 deletions apis/admin.ts
Original file line number Diff line number Diff line change
@@ -1,53 +1,33 @@
'use server';

import { ImportantPreview, SlidePreview } from '@/types/admin';

import { getRequest } from './network/client';
import { getRequest, patchRequest } from './network/server';

// GET

export const getSlides = (pageNum: number) =>
getRequest(
'/admin/slide',
{ pageNum },
{
next: { tags: ['slide'] },
},
) as Promise<{
getRequest('/admin/slide', { pageNum }, { next: { tags: ['slide'] } }) as Promise<{
slides: SlidePreview[];
total: number;
}>;

export const getImportants = (pageNum: number) =>
getRequest(
'/admin/important',
{ pageNum },
{
next: { tags: ['important'] },
},
) as Promise<{
getRequest('/admin/important', { pageNum }, { next: { tags: ['important'] } }) as Promise<{
importants: ImportantPreview[];
total: number;
}>;

// export const getSlides = async (
// pageNum: number,
// ): Promise<{ slides: SlidePreview[]; total: number }> => ({
// slides: [],
// total: 0,
// });

// export const getImportants = async (
// pageNum: number,
// ): Promise<{ importants: ImportantPreview[]; total: number }> => ({
// importants: [],
// total: 0,
// });

// export const patchMultipleSlides = (newsIdList: number[]) =>
// patchRequest('/admin/slide', {
// headers: { 'Content-Type': 'application/json' },
// body: JSON.stringify({ newsIdList }),
// });

// export const patchMultipleImportants = (targetInfos: { id: number; category: string }[]) =>
// patchRequest('/admin/important', {
// headers: { 'Content-Type': 'application/json' },
// body: JSON.stringify({ targetInfos }),
// });
// PATCH

export const patchMultipleSlides = (newsIdList: number[]) =>
patchRequest('/admin/slide', {
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ newsIdList }),
});

export const patchMultipleImportants = (targetInfos: { id: number; category: string }[]) =>
patchRequest('/admin/important', {
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ targetInfos }),
});
28 changes: 0 additions & 28 deletions apis/adminServer.ts

This file was deleted.

File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,85 +1,50 @@
'use client';

import { useRouter } from 'next/navigation';
import { useReducer } from 'react';
import { useSWRConfig } from 'swr';

import { batchUnimportantAction } from '@/actions/admin';

import { StraightNode } from '@/components/common/Nodes';
import Pagination from '@/components/common/Pagination';
import AlertModal from '@/components/modal/AlertModal';

import {
ADMIN_MENU,
ImportantCategory,
ImportantPostIdentifier,
ImportantPreview,
} from '@/types/admin';
import { ADMIN_MENU_SLIDE, ImportantPreview } from '@/types/admin';

import useModal from '@/utils/hooks/useModal';
import { replaceSpaceWithDash } from '@/utils/string';
import { errorToast, successToast } from '@/utils/toast';

import ImportantList from './ImportantList';
import useImportantSelect from './useImportantSelect';
import BatchAction from '../BatchAction';
import TotalPostsCount from '../TotalPostsCount';

const POST_LIMIT = 40;

interface ImportantManagementProps {
posts: ImportantPreview[];
page: number;
total: number;
}

const POST_LIMIT = 40;

type ReducerAction =
| {
type: 'ADD' | 'DELETE';
identifier: { id: number; category: ImportantCategory };
}
| {
type: 'RESET';
};

const reducer = (state: ImportantPostIdentifier[], action: ReducerAction) => {
switch (action.type) {
case 'ADD':
return [...state, action.identifier];
case 'DELETE':
return state.filter(
(info) =>
!(info.id === action.identifier.id && info.category === action.identifier.category),
);
case 'RESET':
return [];
default:
throw new Error('undefined action');
}
};

export default function ImportantManagement({ posts, page, total }: ImportantManagementProps) {
const [selectedPostIdentifiers, changeSelectedIdentifiers] = useReducer(reducer, []);
const [ids, dispatchIds] = useImportantSelect();
const { openModal } = useModal();
const router = useRouter();
const { mutate } = useSWRConfig();

const resetSelectedPosts = () => changeSelectedIdentifiers({ type: 'RESET' });

const changePage = (newPage: number) => {
const selectedMenuWithDash = replaceSpaceWithDash(ADMIN_MENU.slide);
resetSelectedPosts();
const selectedMenuWithDash = replaceSpaceWithDash(ADMIN_MENU_SLIDE);
dispatchIds({ type: 'RESET' });
router.push(`/admin?selected=${selectedMenuWithDash}&page=${newPage}`);
};

const handleBatchUnimportant = async () => {
const result = await batchUnimportantAction(selectedPostIdentifiers);
if (result?.error) {
const result = await batchUnimportantAction(ids);
if (result) {
errorToast('중요 안내를 해제하지 못했습니다.');
} else {
successToast('중요 안내를 해제했습니다.');
resetSelectedPosts();
mutate('/admin');
dispatchIds({ type: 'RESET' });
}
};

Expand All @@ -90,8 +55,8 @@ export default function ImportantManagement({ posts, page, total }: ImportantMan
<TotalPostsCount count={total} />
<ImportantList
posts={posts}
selectedPostIdentifiers={selectedPostIdentifiers}
changeSelectedIdentifiers={changeSelectedIdentifiers}
selectedPostIdentifiers={ids}
changeSelectedIdentifiers={dispatchIds}
/>
<Pagination
totalPostsCount={total}
Expand All @@ -100,7 +65,7 @@ export default function ImportantManagement({ posts, page, total }: ImportantMan
setCurrentPage={changePage}
/>
<BatchAction
selectedCount={selectedPostIdentifiers.length}
selectedCount={ids.length}
buttonText="일괄 중요 안내 해제"
onClickButton={() =>
openModal(
Expand Down
28 changes: 28 additions & 0 deletions app/[locale]/admin/helper/important/useImportantSelect.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { useReducer } from 'react';

import { ImportantCategory, ImportantPostIdentifier } from '@/types/admin';

export default function useImportantSelect() {
const value = useReducer(reducer, []);
return value;
}

type ReducerAction =
| { type: 'ADD' | 'DELETE'; identifier: { id: number; category: ImportantCategory } }
| { type: 'RESET' };

const reducer = (state: ImportantPostIdentifier[], action: ReducerAction) => {
switch (action.type) {
case 'ADD':
return [...state, action.identifier];
case 'DELETE':
return state.filter(
(info) =>
!(info.id === action.identifier.id && info.category === action.identifier.category),
);
case 'RESET':
return [];
default:
throw new Error('undefined action');
}
};
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loading

0 comments on commit ae32753

Please sign in to comment.