필수 체크 로직 변경
This commit is contained in:
parent
5f778d9a2b
commit
76920c4ec0
plm-app/src
@ -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>
|
||||
|
@ -155,6 +155,7 @@ const OemMngPage = () => {
|
||||
{
|
||||
accessorKey: "oem_code",
|
||||
header: "업체명/고객사",
|
||||
size: 120,
|
||||
},
|
||||
{
|
||||
accessorKey: "oem_name",
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
};
|
||||
}
|
Loading…
Reference in New Issue
Block a user