summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
author0-Zz-ang <s1998319@gmail.com>2025-11-21 12:01:13 +0900
committer0-Zz-ang <s1998319@gmail.com>2025-11-21 12:01:13 +0900
commiteacfa3f36274e495838a7114d68ff80a0f257a6a (patch)
tree7044bcf0b8608ca8ff63a3d06d25b2d00ef20864 /lib
parent935fd22e17afc034a472bc2d159de7b9f5e5dcae (diff)
(박서영)모든상태 레코드 활성화
Diffstat (limited to 'lib')
-rw-r--r--lib/compliance/services.ts50
-rw-r--r--lib/compliance/table/compliance-survey-templates-table.tsx77
-rw-r--r--lib/compliance/validations.ts36
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>>
+