import { type GtcClause } from "@/db/schema/gtc" import { createSearchParamsCache, parseAsArrayOf, parseAsInteger, parseAsString, parseAsStringEnum, } from "nuqs/server" import * as z from "zod" import { getFiltersStateParser, getSortingStateParser } from "@/lib/parsers" export const searchParamsCache = createSearchParamsCache({ flags: parseAsArrayOf(z.enum(["advancedTable", "floatingBar"])).withDefault( [] ), page: parseAsInteger.withDefault(1), perPage: parseAsInteger.withDefault(20), sort: getSortingStateParser().withDefault([ { id: "sortOrder", desc: false }, ]), // 검색 필터들 category: parseAsString.withDefault(""), depth: parseAsInteger.withDefault(0), parentId: parseAsInteger.withDefault(0), // advanced filter filters: getFiltersStateParser().withDefault([]), joinOperator: parseAsStringEnum(["and", "or"]).withDefault("and"), search: parseAsString.withDefault(""), }) const clauseImageSchema = z.object({ id: z.string(), url: z.string().url(), fileName: z.string(), size: z.number().positive(), }) export const createGtcClauseSchema = z.object({ documentId: z.number(), parentId: z.number().nullable().optional(), itemNumber: z.string().min(1, "채번을 입력해주세요"), category: z.string().optional(), subtitle: z.string().min(1, "소제목을 입력해주세요"), images: z.array(clauseImageSchema).optional(), // ✅ 이미지 배열 추가 content: z.string().optional(), // 그룹핑용 조항은 내용이 없을 수 있음 sortOrder: z.number().default(0), editReason: z.string().optional(), }).superRefine(async (data, ctx) => { // 채번 형식 검증 (숫자, 문자 모두 허용하되 특수문자 제한) const itemNumberRegex = /^[a-zA-Z0-9._-]+$/ if (!itemNumberRegex.test(data.itemNumber)) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: "채번은 영문, 숫자, 점(.), 하이픈(-), 언더스코어(_)만 사용 가능합니다", path: ["itemNumber"], }) } }) export const updateGtcClauseSchema = z.object({ itemNumber: z.string().min(1, "채번을 입력해주세요").optional(), category: z.string().optional(), subtitle: z.string().min(1, "소제목을 입력해주세요").optional(), content: z.string().optional(), // 내용도 nullable sortOrder: z.number().optional(), images: z.array(clauseImageSchema).optional(), // ✅ 이미지 배열 추가 isActive: z.boolean().optional(), editReason: z.string().optional(), }).superRefine(async (data, ctx) => { // 채번 형식 검증 if (data.itemNumber) { const itemNumberRegex = /^[a-zA-Z0-9._-]+$/ if (!itemNumberRegex.test(data.itemNumber)) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: "채번은 영문, 숫자, 점(.), 하이픈(-), 언더스코어(_)만 사용 가능합니다", path: ["itemNumber"], }) } } }) export const reorderGtcClausesSchema = z.object({ clauses: z.array(z.object({ id: z.number(), sortOrder: z.number(), parentId: z.number().nullable(), depth: z.number(), fullPath: z.string().optional(), })), editReason: z.string().optional(), }) export const bulkUpdateGtcClausesSchema = z.object({ clauseIds: z.array(z.number()).min(1, "수정할 조항을 선택해주세요"), updates: z.object({ category: z.string().optional(), isActive: z.boolean().optional(), }), editReason: z.string().min(1, "편집 사유를 입력해주세요"), }) export const generateVariableNamesSchema = z.object({ documentId: z.number(), prefix: z.string().default("CLAUSE"), includeVendorCode: z.boolean().default(false), vendorCode: z.string().optional(), }).superRefine(async (data, ctx) => { if (data.includeVendorCode && !data.vendorCode) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: "벤더 코드 포함 시 벤더 코드를 입력해주세요", path: ["vendorCode"], }) } }) export type GetGtcClausesSchema = Awaited> export type CreateGtcClauseSchema = z.infer export type UpdateGtcClauseSchema = z.infer export type ReorderGtcClausesSchema = z.infer export type BulkUpdateGtcClausesSchema = z.infer export type GenerateVariableNamesSchema = z.infer