--- globs: src/app/(main)/**/*.tsx, src/app/(auth)/**/*.tsx, src/app/admin-panel/**/*.tsx --- # 페이지 코딩 규칙 ## 기본 구조 모든 페이지는 `"use client"` 클라이언트 컴포넌트: ```tsx "use client"; import { useState, useCallback } from "react"; import { DataGrid, GridColumn } from "@/components/grid/data-grid"; import { SearchForm, SearchField } from "@/components/layout/search-form"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { CodeSelect } from "@/components/ui/code-select"; import Swal from "sweetalert2"; ``` ## 페이지 레이아웃 순서 1. 제목: `

{제목}

` 2. 검색 폼: `` + `` 3. 버튼 영역: 조회/등록/삭제 4. 데이터 그리드: `` + `` ## 데이터 조회 ```tsx const [data, setData] = useState[]>([]); const fetchData = useCallback(async () => { const res = await fetch("/api/{domain}/{resource}", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ year, category_cd }), }); if (res.ok) { const json = await res.json(); setData(json.RESULTLIST || []); } }, [year, category_cd]); ``` ## 팝업 ```tsx const left = (window.screen.width - 1200) / 2; const top = (window.screen.height - 550) / 2; window.open(url, "formPopup", `width=1200,height=550,left=${left},top=${top}`); ``` ## 삭제 확인 ```tsx if (selectedRows.length === 0) { Swal.fire("알림", "삭제할 항목을 선택하세요.", "warning"); return; } ``` ## DataGrid 높이 페이지별 `calc(100vh - 350px)` ~ `calc(100vh - 400px)` 사용. ## 년도 필터 (자주 사용) ```tsx Array.from({ length: 5 }, (_, i) => new Date().getFullYear() - i) ```