diff --git a/.gitignore b/.gitignore index 26e3ecc2..2c627d0b 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,6 @@ target/ node_modules .df test_status.json -/apps/landing/public/test-status/ .venv __pycache__ .pytest_cache diff --git a/apps/landing/src/app/test-case/page.tsx b/apps/landing/src/app/test-case/page.tsx index ddbcf7f8..80d522a9 100644 --- a/apps/landing/src/app/test-case/page.tsx +++ b/apps/landing/src/app/test-case/page.tsx @@ -34,7 +34,7 @@ import { TEST_CASE_FILTERS, TEST_CASE_FILTERS_MAP, } from '@/constants' -import type { TestStatusMap, TestStatusPageManifest } from '@/types' +import type { TestStatusMap } from '@/types' export const metadata: Metadata = { title: '테스트 케이스 - 한국·영어 점자 표준 검증', @@ -83,16 +83,13 @@ export const metadata: Metadata = { } export default async function TestCasePage() { - const [testStatus, ruleMap, testStatusPageManifest] = await Promise.all([ + const [testStatus, ruleMap] = await Promise.all([ readFile('../../test_status.json', 'utf-8').then((data) => JSON.parse(data), ) as Promise, readFile('../../rule_map.json', 'utf-8').then((data) => JSON.parse(data), ) as Promise>, - readFile('public/test-status/manifest.json', 'utf-8').then((data) => - JSON.parse(data), - ) as Promise, ]) // Dynamically create filter map based on rule_map keys @@ -175,10 +172,8 @@ export default async function TestCasePage() { {currentClause !== nextClause && ( @@ -190,11 +185,7 @@ export default async function TestCasePage() { }) return ( - + const TestCaseContext = createContext<{ - testStatusMap: TestStatusMap filterMap: FilterMap filterTotalMap: FilterTotalMap options: TestCaseOptions @@ -48,12 +45,10 @@ export function useTestCase() { } export function TestCaseProvider({ - testStatusMap, filterMap, filterTotalMap, children, }: { - testStatusMap: TestStatusMap filterMap: FilterMap filterTotalMap: FilterTotalMap children: React.ReactNode @@ -74,7 +69,6 @@ export function TestCaseProvider({ filterTotalMap, onChangeOptions: handleChangeOptions, options, - testStatusMap, }} > {children} diff --git a/apps/landing/src/components/test-case/TestCaseResults.tsx b/apps/landing/src/components/test-case/TestCaseResults.tsx index 766a3f02..0a331837 100644 --- a/apps/landing/src/components/test-case/TestCaseResults.tsx +++ b/apps/landing/src/components/test-case/TestCaseResults.tsx @@ -1,73 +1,31 @@ 'use client' import { Button, Flex, Text, VStack } from '@devup-ui/react' -import { useEffect, useState } from 'react' +import { useState } from 'react' -import type { TestStatus, TestStatusPageInfo } from '@/types' +import type { TestStatus } from '@/types' import { TestCaseList } from './list/TestCaseList' import { TestCaseTable } from './table/TestCaseTable' import { useTestCase } from './TestCaseProvider' interface TestCaseResultsProps { - pageInfo?: TestStatusPageInfo + pageSize?: number results: TestStatus[6] - statusKey: string - total: number } /** - * Displays inline test results or lazily loads every page of a large result set. + * Prerenders test results from the build-generated status data and paginates + * large result sets locally without additional network requests. */ -export function TestCaseResults({ - pageInfo, - results, - statusKey, - total, -}: TestCaseResultsProps) { +export function TestCaseResults({ pageSize, results }: TestCaseResultsProps) { const { options } = useTestCase() const [page, setPage] = useState(1) - const [pagedResults, setPagedResults] = useState([]) - const [isLoading, setIsLoading] = useState(Boolean(pageInfo)) - const [error, setError] = useState('') - - useEffect(() => { - if (!pageInfo) return - - const abortController = new AbortController() - const encodedStatusKey = statusKey - .split('/') - .map((segment) => encodeURIComponent(segment)) - .join('/') - - setIsLoading(true) - setError('') - fetch(`/test-status/${encodedStatusKey}/page-${page}.json`, { - signal: abortController.signal, - }) - .then((response) => { - if (!response.ok) { - throw new Error(`HTTP ${response.status}`) - } - return response.json() as Promise - }) - .then((nextResults) => { - setPagedResults(nextResults) - setIsLoading(false) - }) - .catch((fetchError: unknown) => { - if ( - fetchError instanceof DOMException && - fetchError.name === 'AbortError' - ) { - return - } - setError('테스트 케이스를 불러오지 못했습니다.') - setIsLoading(false) - }) - - return () => abortController.abort() - }, [page, pageInfo, statusKey]) + const pageCount = pageSize ? Math.ceil(results.length / pageSize) : 1 + const startIndex = pageSize ? (page - 1) * pageSize : 0 + const visibleResults = pageSize + ? results.slice(startIndex, startIndex + pageSize) + : results function handleFirstPage() { setPage(1) @@ -78,21 +36,16 @@ export function TestCaseResults({ } function handleNextPage() { - if (!pageInfo) return - setPage((currentPage) => Math.min(pageInfo.pageCount, currentPage + 1)) + setPage((currentPage) => Math.min(pageCount, currentPage + 1)) } function handleLastPage() { - if (!pageInfo) return - setPage(pageInfo.pageCount) + setPage(pageCount) } - const visibleResults = pageInfo ? pagedResults : results - const startIndex = pageInfo ? (page - 1) * pageInfo.pageSize : 0 - return ( - {pageInfo ? ( + {pageSize ? ( - {startIndex + 1}–{Math.min(startIndex + pageInfo.pageSize, total)} /{' '} - {total.toLocaleString()}건 + {startIndex + 1}–{Math.min(startIndex + pageSize, results.length)} /{' '} + {results.length.toLocaleString()}건