diff options
| author | 0-Zz-ang <s1998319@gmail.com> | 2025-11-21 12:01:13 +0900 |
|---|---|---|
| committer | 0-Zz-ang <s1998319@gmail.com> | 2025-11-21 12:01:13 +0900 |
| commit | eacfa3f36274e495838a7114d68ff80a0f257a6a (patch) | |
| tree | 7044bcf0b8608ca8ff63a3d06d25b2d00ef20864 /lib/compliance | |
| parent | 935fd22e17afc034a472bc2d159de7b9f5e5dcae (diff) | |
(박서영)모든상태 레코드 활성화
Diffstat (limited to 'lib/compliance')
| -rw-r--r-- | lib/compliance/services.ts | 50 | ||||
| -rw-r--r-- | lib/compliance/table/compliance-survey-templates-table.tsx | 77 | ||||
| -rw-r--r-- | lib/compliance/validations.ts | 36 |
3 files changed, 103 insertions, 60 deletions
diff --git a/lib/compliance/services.ts b/lib/compliance/services.ts index 8dc8e916..6541bdd1 100644 --- a/lib/compliance/services.ts +++ b/lib/compliance/services.ts @@ -1,8 +1,10 @@ 'use server' import db from "@/db/db"; -import { eq, desc, count, and, ne, or, ilike, asc, inArray } from "drizzle-orm"; +import { eq, desc, count, and, ne, or, ilike, asc, inArray, type SQL } from "drizzle-orm"; import { revalidatePath } from "next/cache"; +import { filterColumns } from "@/lib/filter-columns"; +import type { Filter, JoinOperator } from "@/types/table"; import { complianceSurveyTemplates, complianceQuestions, @@ -90,35 +92,48 @@ export async function getComplianceSurveyTemplatesWithSorting(sort?: { id: strin } } -// items 서비스와 동일한 구조의 함수 추가 +// items 서비스와 동일한 구조의 함수 추가 (vendor-candidates 패턴 적용) export async function getComplianceSurveyTemplates(input: { page: number; perPage: number; search?: string; - filters?: Array<{ id: string; value: string }>; - joinOperator?: 'and' | 'or'; + filters?: Filter<typeof complianceSurveyTemplates>[]; + joinOperator?: JoinOperator; sort?: { id: string; desc: boolean }[]; }) { try { const safePerPage = Math.min(input.perPage, 100); const offset = (input.page - 1) * safePerPage; - let whereClause = eq(complianceSurveyTemplates.isActive, true); + // 1) Advanced filters + const advancedWhere = filterColumns({ + table: complianceSurveyTemplates, + filters: input.filters || [], + joinOperator: input.joinOperator || 'and', + }); - // 검색 기능 + // 2) Global search + let globalWhere; if (input.search) { const searchTerm = `%${input.search}%`; - whereClause = and( - eq(complianceSurveyTemplates.isActive, true), - or( - ilike(complianceSurveyTemplates.name, searchTerm), - ilike(complianceSurveyTemplates.description, searchTerm), - ilike(complianceSurveyTemplates.version, searchTerm) - ) - )!; + globalWhere = or( + ilike(complianceSurveyTemplates.name, searchTerm), + ilike(complianceSurveyTemplates.description, searchTerm), + ilike(complianceSurveyTemplates.version, searchTerm) + ); } - // 정렬 - 안전한 방식으로 처리 + // 3) Combine finalWhere + const whereConditions: (SQL | undefined)[] = []; + if (advancedWhere) whereConditions.push(advancedWhere); + if (globalWhere) whereConditions.push(globalWhere); + + const validConditions = whereConditions.filter((c): c is SQL => c !== undefined); + const finalWhere = validConditions.length > 0 + ? and(...validConditions)! + : undefined; // 필터가 없으면 전체 데이터 조회 + + // 4) Sorting let orderBy = [desc(complianceSurveyTemplates.createdAt)]; if (input.sort && input.sort.length > 0) { @@ -149,10 +164,11 @@ export async function getComplianceSurveyTemplates(input: { } } + // 5) Query & count const templates = await db .select() .from(complianceSurveyTemplates) - .where(whereClause) + .where(finalWhere) .orderBy(...orderBy) .limit(safePerPage) .offset(offset); @@ -160,7 +176,7 @@ export async function getComplianceSurveyTemplates(input: { const totalCount = await db .select({ count: count() }) .from(complianceSurveyTemplates) - .where(whereClause); + .where(finalWhere); const total = totalCount[0]?.count || 0; const pageCount = Math.ceil(total / safePerPage); diff --git a/lib/compliance/table/compliance-survey-templates-table.tsx b/lib/compliance/table/compliance-survey-templates-table.tsx index c2e441ec..185474cc 100644 --- a/lib/compliance/table/compliance-survey-templates-table.tsx +++ b/lib/compliance/table/compliance-survey-templates-table.tsx @@ -1,6 +1,7 @@ "use client"; import * as React from "react"; +import { useQueryState } from "nuqs"; import { useDataTable } from "@/hooks/use-data-table"; import { DataTable } from "@/components/data-table/data-table"; import { DataTableAdvancedToolbar } from "@/components/data-table/data-table-advanced-toolbar"; @@ -8,33 +9,56 @@ import type { DataTableAdvancedFilterField, DataTableRowAction, DataTableFilterField, + Filter, } from "@/types/table" import { getColumns } from "./compliance-survey-templates-columns"; import { ComplianceTemplateEditSheet } from "./compliance-template-edit-sheet"; import { DeleteComplianceTemplatesDialog } from "./delete-compliance-templates-dialog"; import { ComplianceSurveyTemplatesToolbarActions } from "./compliance-survey-templates-toolbar"; import { complianceSurveyTemplates } from "@/db/schema/compliance"; -import { getComplianceSurveyTemplatesWithSorting } from "../services"; +import { getFiltersStateParser } from "@/lib/parsers"; interface ComplianceSurveyTemplatesTableProps { promises?: Promise<[{ data: typeof complianceSurveyTemplates.$inferSelect[]; pageCount: number }] >; } export function ComplianceSurveyTemplatesTable({ promises }: ComplianceSurveyTemplatesTableProps) { - // 페이지네이션 모드 데이터 + // 서버에서 받은 데이터 사용 const paginationData = promises ? React.use(promises) : null; - const initialData = paginationData ? paginationData[0].data : []; - const pageCount = paginationData ? paginationData[0].pageCount : 0; - + const [{ data, pageCount }] = paginationData + ? paginationData + : [{ data: [], pageCount: 0 }]; const [rowAction, setRowAction] = React.useState<DataTableRowAction<typeof complianceSurveyTemplates.$inferSelect> | null>(null); - const [data, setData] = React.useState(initialData); - const [currentSorting, setCurrentSorting] = React.useState<{ id: string; desc: boolean }[]>([]); - // 초기 데이터가 변경되면 data 상태 업데이트 + // 기본 필터 설정 (isActive = true) + const defaultFilter: Filter<typeof complianceSurveyTemplates.$inferSelect>[] = React.useMemo(() => [ + { + id: "isActive", + operator: "eq" as const, + value: "true", + type: "select" as const, + rowId: "default-isActive-filter", + } + ], []); + + // URL에서 필터 읽기 + const [filters, setFilters] = useQueryState( + "filters", + getFiltersStateParser<typeof complianceSurveyTemplates.$inferSelect>().withDefault([]).withOptions({ + clearOnDefault: true, + shallow: false, + }) + ); + + // 초기 마운트 시 필터가 없으면 기본 필터 설정 + const hasInitialized = React.useRef(false); React.useEffect(() => { - setData(initialData); - }, [initialData]); + if (!hasInitialized.current && filters.length === 0) { + hasInitialized.current = true; + setFilters(defaultFilter); + } + }, [filters.length, setFilters, defaultFilter]); // 컬럼 설정 - 외부 파일에서 가져옴 const columns = React.useMemo( @@ -84,39 +108,6 @@ export function ComplianceSurveyTemplatesTable({ promises }: ComplianceSurveyTem clearOnDefault: true, }) - // 정렬 상태 변경 감지 - React.useEffect(() => { - const newSorting = table.getState().sorting; - if (JSON.stringify(newSorting) !== JSON.stringify(currentSorting)) { - setCurrentSorting(newSorting); - } - }, [table.getState().sorting, currentSorting]); - - // 정렬이 변경될 때 데이터 다시 로드 - React.useEffect(() => { - const loadData = async () => { - try { - console.log("🔄 정렬 변경으로 데이터 다시 로드:", currentSorting); - - // 정렬 상태가 있으면 정렬된 데이터 가져오기 - if (currentSorting && currentSorting.length > 0) { - const result = await getComplianceSurveyTemplatesWithSorting(currentSorting); - setData(result.data); - } else { - // 기본 정렬로 데이터 가져오기 - const result = await getComplianceSurveyTemplatesWithSorting(); - setData(result.data); - } - } catch (error) { - console.error("데이터 로드 오류:", error); - } - }; - - if (currentSorting.length > 0) { - loadData(); - } - }, [currentSorting]); - return ( <> <DataTable table={table}> diff --git a/lib/compliance/validations.ts b/lib/compliance/validations.ts new file mode 100644 index 00000000..605270fa --- /dev/null +++ b/lib/compliance/validations.ts @@ -0,0 +1,36 @@ +import { complianceSurveyTemplates } from "@/db/schema/compliance" +import { + createSearchParamsCache, + parseAsArrayOf, + parseAsInteger, + parseAsString, + parseAsStringEnum, +} from "nuqs/server" +import * as z from "zod" +import { getFiltersStateParser, getSortingStateParser } from "@/lib/parsers" + +export const searchParamsComplianceCache = createSearchParamsCache({ + // Common flags + flags: parseAsArrayOf(z.enum(["advancedTable", "floatingBar"])).withDefault([]), + from: parseAsString.withDefault(""), + to: parseAsString.withDefault(""), + // Paging + page: parseAsInteger.withDefault(1), + perPage: parseAsInteger.withDefault(10), + + // Sorting + sort: getSortingStateParser<typeof complianceSurveyTemplates.$inferSelect>().withDefault([ + { id: "createdAt", desc: true }, + ]), + + // Advanced filter + filters: getFiltersStateParser<typeof complianceSurveyTemplates.$inferSelect>().withDefault([]), + joinOperator: parseAsStringEnum(["and", "or"]).withDefault("and"), + + // Global search + search: parseAsString.withDefault(""), +}) + +// Export the type you can use in your server action: +export type GetComplianceSurveyTemplatesSchema = Awaited<ReturnType<typeof searchParamsComplianceCache.parse>> + |
