import type { Metadata } from 'next'; import { verifySession } from '@/lib/auth/dal'; import { fetchCodeDetails, fetchCodeGroups, } from '@/lib/data/repositories/common-code-repository'; import type { CommonCodeGroup } from '@/lib/domain/common-code'; import { COMMON_CODE_DETAIL_PAGE_SIZE, COMMON_CODE_PAGE_SIZE, parseCommonCodeQuery, type CommonCodeQuery, } from '@/lib/domain/common-code-query'; import { CodeManagement } from './_components/code-management'; export const metadata: Metadata = { title: '코드관리', }; // cookies()로 이미 동적이지만, 정적 프리렌더로 데이터가 빌드 산출물에 박히는 경로를 // 원천 차단하기 위해 명시적으로 강제한다. export const dynamic = 'force-dynamic'; interface PageProps { searchParams: Promise>; } /** 부분일치 검색 — 백엔드가 완전일치만 지원해 여기서 거른다(Repository 주석 참조). */ function filterGroups( groups: CommonCodeGroup[], query: CommonCodeQuery ): CommonCodeGroup[] { const keyword = query.keyword.trim().toLowerCase(); if (!keyword) { return groups; } return groups.filter((group) => { const target = query.searchField === 'comCd' ? group.comCd : group.name; return target.toLowerCase().includes(keyword); }); } /** 1-based 페이지를 잘라낸다. 범위를 벗어난 페이지는 마지막 페이지로 맞춘다. */ function paginate(rows: T[], page: number, pageSize: number) { const totalPages = Math.max(1, Math.ceil(rows.length / pageSize)); const currentPage = Math.min(Math.max(page, 1), totalPages); const offset = (currentPage - 1) * pageSize; return { rows: rows.slice(offset, offset + pageSize), currentPage, totalPages, totalCount: rows.length, }; } /** * 코드관리 — 기획 SYS_COD_001, 시안 관리자페이지(QsFVFFUKGH68xAPVkF3SJ9) 5402:13399 * * 좌측 공통코드를 고르면 우측 상세코드 목록이 그 그룹으로 갱신된다. 선택·검색·두 목록의 페이지가 * 모두 URL에 실려, 이 서버 컴포넌트가 매 요청 그 조건대로 데이터를 만들어 넘긴다. * * **검색·페이징을 서버에서 처리한다** — 백엔드가 두 목록 모두 전체를 반환하고 검색도 완전일치라 * (Repository 주석 참조), 부분일치 필터와 페이지 자르기를 여기서 한다. 전체를 받으므로 총건수는 * 정확하다(다른 목록 화면의 하한값 보정이 여기에는 필요 없다). * * **선택된 공통코드가 목록에 없으면 첫 행으로 대체한다** — 검색으로 걸러졌거나 삭제된 코드가 * URL에 남아 있으면 우측이 영영 비어 보이기 때문이다. */ export default async function Page({ searchParams }: PageProps) { await verifySession(); const query = parseCommonCodeQuery(await searchParams); const groups = filterGroups(await fetchCodeGroups(), query); const groupPage = paginate(groups, query.page, COMMON_CODE_PAGE_SIZE); const selectedComCd = groups.find((group) => group.comCd === query.comCd)?.comCd ?? groupPage.rows[0]?.comCd ?? null; const details = selectedComCd ? await fetchCodeDetails(selectedComCd) : []; const detailPage = paginate( details, query.detailPage, COMMON_CODE_DETAIL_PAGE_SIZE ); return ( ); }