필수 체크 로직 변경

This commit is contained in:
chpark 2024-12-24 11:07:18 +09:00
parent 5f778d9a2b
commit 76920c4ec0
4 changed files with 68 additions and 119 deletions
plm-app/src
app/(admin)/common/oemmng
components/ui
lib

View File

@ -1,23 +1,9 @@
import React from "react";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import * as z from "zod";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import {
Select,
SelectTrigger,
SelectContent,
SelectItem,
SelectValue,
} from "@/components/ui/select";
import { Switch } from "@/components/ui/switch";
import { api } from "@/lib/api";
import { useQuery } from "@tanstack/react-query";
import { oemMng, Role } from "@/types/common/oemmng/oemmng";
import { useAuthStore } from "@/stores/auth";
import { AxiosError } from "axios";
import { useToast } from "@/hooks/use-toast";
import { oemMng} from "@/types/common/oemmng/oemmng";
import {
Form,
FormControl,
@ -27,19 +13,6 @@ import {
FormMessage,
} from "@/components/ui/form";
import { createValidationSchema } from "@/lib/utils"; // createValidationSchema 함수 임포트
const fields = [
{ name: 'oem_code', required: true, type: 'string' },
{ name: 'oem_name', required: true, type: 'string' },
{ name: 'oem_no', required: true, type: 'string' },
{ name: 'isActive', required: false, type: 'boolean' },
];
const formSchema = createValidationSchema(fields);
type FormSchema = z.infer<typeof formSchema>;
interface OemFormProps {
initialData?: Partial<oemMng>;
onSubmit: (data: Partial<oemMng>) => void;
@ -51,12 +24,7 @@ export const OemMngForm: React.FC<OemFormProps> = ({
onSubmit,
onCancel,
}) => {
//const { token, user } = useAuthStore();
const { toast } = useToast();
// Initialize the form with react-hook-form and zod resolver
const form = useForm<FormSchema>({
resolver: zodResolver(formSchema),
const form = useForm({
defaultValues: {
oem_code: initialData?.oem_code || "",
oem_name: initialData?.oem_name || "",
@ -65,58 +33,39 @@ export const OemMngForm: React.FC<OemFormProps> = ({
},
});
// Reset form when initialData changes
React.useEffect(() => {
if (initialData) {
form.reset({
oem_code: initialData.oem_code || "",
oem_name: initialData.oem_name || "",
oem_no: initialData.oem_no || "",
isActive: initialData.isActive || false,
});
}
}, [initialData, form]);
const handleSubmit = async (data: FormSchema) => {
try {
await onSubmit(data);
} catch (error) {
const err = error as AxiosError;
toast({
title: "에러",
description:
(err.response?.data as { message: string })?.message ||
"에러가 발생했습니다.",
variant: "destructive",
});
}
};
return (
<Form {...form}>
<form onSubmit={form.handleSubmit(handleSubmit)} className="space-y-4">
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
<FormField
control={form.control}
name="oem_code"
validation={{
required: "OEM 코드는 필수 입력값입니다",
maxLength: { value: 10, message: "최대 10자까지 입력 가능합니다" }
}}
render={({ field }) => (
<FormItem>
<FormLabel>OEM_CODE</FormLabel>
<FormLabel>OEM </FormLabel>
<FormControl>
<Input {...field} value={field.value || ""} />
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="oem_name"
validation={{
required: "OEM 이름은 필수 입력값입니다",
maxLength: { value: 64, message: "최대 64자까지 입력 가능합니다" }
}}
render={({ field }) => (
<FormItem>
<FormLabel>OEM_NAME</FormLabel>
<FormLabel>OEM </FormLabel>
<FormControl>
<Input {...field} value={field.value || ""} />
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
@ -126,11 +75,15 @@ export const OemMngForm: React.FC<OemFormProps> = ({
<FormField
control={form.control}
name="oem_no"
validation={{
required: "OEM 번호는 필수 입력값입니다",
maxLength: { value: 32, message: "최대 32자까지 입력 가능합니다" }
}}
render={({ field }) => (
<FormItem>
<FormLabel></FormLabel>
<FormLabel>OEM </FormLabel>
<FormControl>
<Input {...field} value={field.value || ""} />
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
@ -141,24 +94,28 @@ export const OemMngForm: React.FC<OemFormProps> = ({
control={form.control}
name="isActive"
render={({ field }) => (
<FormItem className="flex items-center space-x-2">
<FormControl>
<Switch
checked={field.value}
onCheckedChange={field.onChange}
/>
</FormControl>
<FormLabel> </FormLabel>
<FormItem>
<div className="flex items-center gap-2">
<FormLabel></FormLabel>
<FormControl>
<Switch
checked={field.value}
onCheckedChange={field.onChange}
/>
</FormControl>
</div>
<FormMessage />
</FormItem>
)}
/>
<div className="flex justify-end space-x-2">
<div className="flex justify-end gap-2">
<Button type="button" variant="outline" onClick={onCancel}>
</Button>
<Button type="submit"></Button>
<Button type="submit">
{initialData ? "수정" : "생성"}
</Button>
</div>
</form>
</Form>

View File

@ -155,6 +155,7 @@ const OemMngPage = () => {
{
accessorKey: "oem_code",
header: "업체명/고객사",
size: 120,
},
{
accessorKey: "oem_name",

View File

@ -28,18 +28,44 @@ const FormFieldContext = React.createContext<FormFieldContextValue>(
{} as FormFieldContextValue
)
// 유효성 검사 규칙 타입 정의
type FormFieldRules = {
required?: boolean | string;
maxLength?: number | { value: number; message: string };
minLength?: number | { value: number; message: string };
pattern?: RegExp | { value: RegExp; message: string };
};
// FormField 컴포넌트 수정
const FormField = <
TFieldValues extends FieldValues = FieldValues,
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
>({
validation,
...props
}: ControllerProps<TFieldValues, TName>) => {
}: ControllerProps<TFieldValues, TName> & {
validation?: FormFieldRules;
}) => {
// 기존 rules와 새로운 validation 규칙 병합
const combinedRules = {
...props.rules,
...(validation && {
required: typeof validation.required === 'string'
? { value: true, message: validation.required }
: validation.required,
maxLength: validation.maxLength,
minLength: validation.minLength,
pattern: validation.pattern,
}),
};
return (
<FormFieldContext.Provider value={{ name: props.name }}>
<Controller {...props} />
<Controller {...props} rules={combinedRules} />
</FormFieldContext.Provider>
)
}
);
};
const useFormField = () => {
const fieldContext = React.useContext(FormFieldContext)

View File

@ -1,6 +1,5 @@
import { clsx, type ClassValue } from "clsx";
import { twMerge } from "tailwind-merge";
import { z, ZodTypeAny } from 'zod';
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
@ -8,38 +7,4 @@ export function cn(...inputs: ClassValue[]) {
export function formatNumber(num: number): string {
return new Intl.NumberFormat("ko-KR").format(num);
}
interface Field {
name: string;
required: boolean;
type: 'string' | 'number' | 'email' | 'phone' | 'boolean';
}
export const createValidationSchema = (fields: Field[]) => {
const schema: Record<string, ZodTypeAny> = {};
fields.forEach((field) => {
switch (field.type) {
case 'string':
schema[field.name] = z.string().min(field.required ? 1 : 0, `${field.name}은 필수입니다.`);
break;
case 'number':
schema[field.name] = z.number().min(field.required ? 1 : 0, `${field.name}은 필수입니다.`);
break;
case 'email':
schema[field.name] = z.string().email(`${field.name}은 유효한 이메일 형식이어야 합니다.`);
break;
case 'phone':
schema[field.name] = z.string().regex(/^[0-9-]+$/, `${field.name}은 올바른 전화번호 형식이어야 합니다.`);
break;
case 'boolean':
schema[field.name] = z.boolean();
break;
default:
throw new Error(`Unsupported field type: ${field.type}`);
}
});
return z.object(schema);
};
}