diff options
| author | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-08-21 06:57:36 +0000 |
|---|---|---|
| committer | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-08-21 06:57:36 +0000 |
| commit | 02b1cf005cf3e1df64183d20ba42930eb2767a9f (patch) | |
| tree | e932c54d5260b0e6fda2b46be2a6ba1c3ee30434 /lib/basic-contract/template/update-basicContract-sheet.tsx | |
| parent | d78378ecd7ceede1429359f8058c7a99ac34b1b7 (diff) | |
(대표님, 최겸) 설계메뉴추가, 작업사항 업데이트
설계메뉴 - 문서관리
설계메뉴 - 벤더 데이터
gtc 메뉴 업데이트
정보시스템 - 메뉴리스트 및 정보 업데이트
파일 라우트 업데이트
엑셀임포트 개선
기본계약 개선
벤더 가입과정 변경 및 개선
벤더 기본정보 - pq
돌체 오류 수정 및 개선
벤더 로그인 과정 이메일 오류 수정
Diffstat (limited to 'lib/basic-contract/template/update-basicContract-sheet.tsx')
| -rw-r--r-- | lib/basic-contract/template/update-basicContract-sheet.tsx | 245 |
1 files changed, 46 insertions, 199 deletions
diff --git a/lib/basic-contract/template/update-basicContract-sheet.tsx b/lib/basic-contract/template/update-basicContract-sheet.tsx index 07bac31b..0236fda5 100644 --- a/lib/basic-contract/template/update-basicContract-sheet.tsx +++ b/lib/basic-contract/template/update-basicContract-sheet.tsx @@ -8,7 +8,6 @@ import { toast } from "sonner" import * as z from "zod" import { Button } from "@/components/ui/button" -import { Checkbox } from "@/components/ui/checkbox" import { Switch } from "@/components/ui/switch" import { Form, @@ -20,14 +19,6 @@ import { FormDescription, } from "@/components/ui/form" import { - Select, - SelectContent, - SelectGroup, - SelectItem, - SelectTrigger, - SelectValue, -} from "@/components/ui/select" -import { Sheet, SheetClose, SheetContent, @@ -45,45 +36,14 @@ import { DropzoneInput } from "@/components/ui/dropzone" import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" -import { Separator } from "@/components/ui/separator" import { Badge } from "@/components/ui/badge" import { updateTemplate } from "../service" import { BasicContractTemplate } from "@/db/schema" -import { BUSINESS_UNITS, scopeHelpers } from "@/config/basicContractColumnsConfig" - -// 템플릿 이름 옵션 정의 -const TEMPLATE_NAME_OPTIONS = [ - "준법서약 (한글)", - "준법서약 (영문)", - "기술자료 요구서", - "비밀유지 계약서", - "표준하도급기본 계약서", - "GTC", - "안전보건관리 약정서", - "동반성장", - "윤리규범 준수 서약서", - "기술자료 동의서", - "내국신용장 미개설 합의서", - "직납자재 하도급대급등 연동제 의향서" -] as const; +import { scopeHelpers } from "@/config/basicContractColumnsConfig" -// 업데이트 템플릿 스키마 정의 (리비전 필드 제거, 워드파일만 허용) +// 업데이트 템플릿 스키마 정의 (파일 업데이트 중심) export const updateTemplateSchema = z.object({ - templateName: z.enum(TEMPLATE_NAME_OPTIONS, { - required_error: "템플릿 이름을 선택해주세요.", - }), legalReviewRequired: z.boolean(), - - // 적용 범위 - shipBuildingApplicable: z.boolean(), - windApplicable: z.boolean(), - pcApplicable: z.boolean(), - nbApplicable: z.boolean(), - rcApplicable: z.boolean(), - gyApplicable: z.boolean(), - sysApplicable: z.boolean(), - infraApplicable: z.boolean(), - file: z .instanceof(File, { message: "파일을 업로드해주세요." }) .refine((file) => file.size <= 100 * 1024 * 1024, { @@ -96,15 +56,6 @@ export const updateTemplateSchema = z.object({ { message: "워드 파일(.doc, .docx)만 업로드 가능합니다." } ) .optional(), -}).refine((data) => { - // 적어도 하나의 적용 범위는 선택되어야 함 - const hasAnyScope = BUSINESS_UNITS.some(unit => - data[unit.key as keyof typeof data] as boolean - ); - return hasAnyScope; -}, { - message: "적어도 하나의 적용 범위를 선택해야 합니다.", - path: ["shipBuildingApplicable"], }); export type UpdateTemplateSchema = z.infer<typeof updateTemplateSchema> @@ -122,16 +73,7 @@ export function UpdateTemplateSheet({ template, onSuccess, ...props }: UpdateTem const form = useForm<UpdateTemplateSchema>({ resolver: zodResolver(updateTemplateSchema), defaultValues: { - templateName: template?.templateName as typeof TEMPLATE_NAME_OPTIONS[number] ?? "준법서약 (한글)", legalReviewRequired: template?.legalReviewRequired ?? false, - shipBuildingApplicable: template?.shipBuildingApplicable ?? false, - windApplicable: template?.windApplicable ?? false, - pcApplicable: template?.pcApplicable ?? false, - nbApplicable: template?.nbApplicable ?? false, - rcApplicable: template?.rcApplicable ?? false, - gyApplicable: template?.gyApplicable ?? false, - sysApplicable: template?.sysApplicable ?? false, - infraApplicable: template?.infraApplicable ?? false, }, mode: "onChange" }) @@ -145,52 +87,23 @@ export function UpdateTemplateSheet({ template, onSuccess, ...props }: UpdateTem } }; - // 모든 적용 범위 선택/해제 - const handleSelectAllScopes = (checked: boolean | "indeterminate") => { - const value = checked === true; - BUSINESS_UNITS.forEach(unit => { - form.setValue(unit.key as keyof UpdateTemplateSchema, value); - }); - }; - // 템플릿 변경 시 폼 값 업데이트 React.useEffect(() => { if (template) { form.reset({ - templateName: template.templateName as typeof TEMPLATE_NAME_OPTIONS[number], legalReviewRequired: template.legalReviewRequired ?? false, - shipBuildingApplicable: template.shipBuildingApplicable ?? false, - windApplicable: template.windApplicable ?? false, - pcApplicable: template.pcApplicable ?? false, - nbApplicable: template.nbApplicable ?? false, - rcApplicable: template.rcApplicable ?? false, - gyApplicable: template.gyApplicable ?? false, - sysApplicable: template.sysApplicable ?? false, - infraApplicable: template.infraApplicable ?? false, }); } }, [template, form]); - // 현재 선택된 적용 범위 수 - const selectedScopesCount = BUSINESS_UNITS.filter(unit => - form.watch(unit.key as keyof UpdateTemplateSchema) - ).length; - function onSubmit(input: UpdateTemplateSchema) { startUpdateTransition(async () => { if (!template) return // FormData 객체 생성하여 파일과 데이터를 함께 전송 const formData = new FormData(); - formData.append("templateName", input.templateName); formData.append("legalReviewRequired", input.legalReviewRequired.toString()); - // 적용 범위 추가 - BUSINESS_UNITS.forEach(unit => { - const value = input[unit.key as keyof UpdateTemplateSchema] as boolean; - formData.append(unit.key, value.toString()); - }); - if (input.file) { formData.append("file", input.file); } @@ -221,24 +134,14 @@ export function UpdateTemplateSheet({ template, onSuccess, ...props }: UpdateTem if (!template) return null; - const scopeSelected = BUSINESS_UNITS.some( - (unit) => form.watch(unit.key as keyof UpdateTemplateSchema) - ); - - const isDisabled = - isUpdatePending || - !form.watch("templateName") || - !scopeSelected; - return ( <Sheet {...props}> - <SheetContent className="sm:max-w-[600px] h-[100vh] flex flex-col p-0"> + <SheetContent className="sm:max-w-[500px] h-[100vh] flex flex-col p-0"> {/* 고정된 헤더 */} <SheetHeader className="p-6 pb-4 border-b"> <SheetTitle>템플릿 업데이트</SheetTitle> <SheetDescription> - 템플릿 정보를 수정하고 변경사항을 저장하세요 - <span className="text-red-500 mt-1 block text-sm">* 표시된 항목은 필수 입력사항입니다.</span> + 템플릿 파일을 업데이트하고 설정을 변경하세요 </SheetDescription> </SheetHeader> @@ -249,51 +152,49 @@ export function UpdateTemplateSheet({ template, onSuccess, ...props }: UpdateTem onSubmit={form.handleSubmit(onSubmit)} className="space-y-6 py-4" > - {/* 기본 정보 */} + {/* 템플릿 정보 표시 */} <Card> <CardHeader> - <CardTitle className="text-lg">기본 정보</CardTitle> + <CardTitle className="text-lg">템플릿 정보</CardTitle> <CardDescription> - 현재 리비전: <Badge variant="outline">v{template.revision}</Badge> - <br /> - 현재 적용 범위: {scopeHelpers.getScopeDisplayText(template)} + 현재 템플릿의 기본 정보입니다 </CardDescription> </CardHeader> <CardContent className="space-y-4"> <div className="grid grid-cols-1 gap-4"> - <FormField - control={form.control} - name="templateName" - render={({ field }) => ( - <FormItem> - <FormLabel> - 템플릿 이름 <span className="text-red-500">*</span> - </FormLabel> - <Select onValueChange={field.onChange} defaultValue={field.value}> - <FormControl> - <SelectTrigger> - <SelectValue placeholder="템플릿 이름을 선택하세요" /> - </SelectTrigger> - </FormControl> - <SelectContent> - <SelectGroup> - {TEMPLATE_NAME_OPTIONS.map((option) => ( - <SelectItem key={option} value={option}> - {option} - </SelectItem> - ))} - </SelectGroup> - </SelectContent> - </Select> - <FormDescription> - 미리 정의된 템플릿 중에서 선택 - </FormDescription> - <FormMessage /> - </FormItem> - )} - /> + <div className="space-y-2"> + <label className="text-sm font-medium">템플릿 이름</label> + <div className="px-3 py-2 border rounded-md bg-gray-50"> + {template.templateName} + </div> + </div> + + <div className="space-y-2"> + <label className="text-sm font-medium">현재 리비전</label> + <div className="px-3 py-2 border rounded-md bg-gray-50"> + <Badge variant="outline">v{template.revision}</Badge> + </div> + </div> + + <div className="space-y-2"> + <label className="text-sm font-medium">현재 파일</label> + <div className="px-3 py-2 border rounded-md bg-gray-50"> + {template.fileName} + </div> + </div> </div> + </CardContent> + </Card> + {/* 설정 */} + <Card> + <CardHeader> + <CardTitle className="text-lg">설정</CardTitle> + <CardDescription> + 템플릿 관련 설정을 변경할 수 있습니다 + </CardDescription> + </CardHeader> + <CardContent> <FormField control={form.control} name="legalReviewRequired" @@ -317,69 +218,12 @@ export function UpdateTemplateSheet({ template, onSuccess, ...props }: UpdateTem </CardContent> </Card> - {/* 적용 범위 */} - <Card> - <CardHeader> - <CardTitle className="text-lg"> - 적용 범위 <span className="text-red-500">*</span> - </CardTitle> - <CardDescription> - 이 템플릿이 적용될 사업부를 선택하세요. ({selectedScopesCount}개 선택됨) - </CardDescription> - </CardHeader> - <CardContent className="space-y-4"> - <div className="flex items-center space-x-2"> - <Checkbox - id="select-all" - checked={selectedScopesCount === BUSINESS_UNITS.length} - onCheckedChange={handleSelectAllScopes} - /> - <label htmlFor="select-all" className="text-sm font-medium"> - 전체 선택 - </label> - </div> - - <Separator /> - - <div className="grid grid-cols-2 md:grid-cols-4 gap-4"> - {BUSINESS_UNITS.map((unit) => ( - <FormField - key={unit.key} - control={form.control} - name={unit.key as keyof UpdateTemplateSchema} - render={({ field }) => ( - <FormItem className="flex flex-row items-start space-x-3 space-y-0"> - <FormControl> - <Checkbox - checked={field.value as boolean} - onCheckedChange={field.onChange} - /> - </FormControl> - <div className="space-y-1 leading-none"> - <FormLabel className="text-sm font-normal"> - {unit.label} - </FormLabel> - </div> - </FormItem> - )} - /> - ))} - </div> - - {form.formState.errors.shipBuildingApplicable && ( - <p className="text-sm text-destructive"> - {form.formState.errors.shipBuildingApplicable.message} - </p> - )} - </CardContent> - </Card> - {/* 파일 업데이트 */} <Card> <CardHeader> <CardTitle className="text-lg">파일 업데이트</CardTitle> <CardDescription> - 현재 파일: {template.fileName} + 새로운 템플릿 파일을 업로드하세요 </CardDescription> </CardHeader> <CardContent> @@ -388,7 +232,7 @@ export function UpdateTemplateSheet({ template, onSuccess, ...props }: UpdateTem name="file" render={() => ( <FormItem> - <FormLabel>템플릿 파일 (선택사항)</FormLabel> + <FormLabel>새 템플릿 파일 (선택사항)</FormLabel> <FormControl> <Dropzone onDrop={handleFileChange} @@ -402,7 +246,7 @@ export function UpdateTemplateSheet({ template, onSuccess, ...props }: UpdateTem <DropzoneTitle> {selectedFile ? selectedFile.name - : "새 워드 파일을 드래그하세요 (선택사항)"} + : "새 워드 파일을 드래그하세요"} </DropzoneTitle> <DropzoneDescription> {selectedFile @@ -413,6 +257,9 @@ export function UpdateTemplateSheet({ template, onSuccess, ...props }: UpdateTem </DropzoneZone> </Dropzone> </FormControl> + <FormDescription> + 파일을 업로드하지 않으면 기존 파일이 유지됩니다 + </FormDescription> <FormMessage /> </FormItem> )} @@ -433,12 +280,12 @@ export function UpdateTemplateSheet({ template, onSuccess, ...props }: UpdateTem <Button type="button" onClick={form.handleSubmit(onSubmit)} - disabled={isDisabled} + disabled={isUpdatePending} > {isUpdatePending && ( <Loader className="mr-2 size-4 animate-spin" aria-hidden="true" /> )} - 저장 + 업데이트 </Button> </SheetFooter> </SheetContent> |
