diff options
| author | joonhoekim <26rote@gmail.com> | 2025-09-15 18:58:07 +0900 |
|---|---|---|
| committer | joonhoekim <26rote@gmail.com> | 2025-09-15 18:58:07 +0900 |
| commit | 2b490956c9752c1b756780a3461bc1c37b6fe0a7 (patch) | |
| tree | b0b8a03c8de5dfce4b6c7373a9d608306e9147c0 /lib/avl/components/project-field-components.tsx | |
| parent | e7818a457371849e29519497ebf046f385f05ab6 (diff) | |
(김준회) AVL 관리 및 상세 - 기능 구현 1차
+ docker compose 내 오류 수정
Diffstat (limited to 'lib/avl/components/project-field-components.tsx')
| -rw-r--r-- | lib/avl/components/project-field-components.tsx | 113 |
1 files changed, 113 insertions, 0 deletions
diff --git a/lib/avl/components/project-field-components.tsx b/lib/avl/components/project-field-components.tsx new file mode 100644 index 00000000..95505d08 --- /dev/null +++ b/lib/avl/components/project-field-components.tsx @@ -0,0 +1,113 @@ +"use client" + +import * as React from "react" +import { Input } from "@/components/ui/input" +import { Button } from "@/components/ui/button" +import { + ProjectSearchStatus, + getLabelStatusClassName, + getDisplayElementStatusClassName, + getInputStatusClassName +} from "./project-field-utils" + +// 타입 재내보내기 +export type { ProjectSearchStatus } from "./project-field-utils" + +// 재사용 가능한 필드 컴포넌트들 +export interface ProjectInputFieldProps { + label: string + value: string + onChange: (value: string) => void + placeholder: string + status: ProjectSearchStatus + statusText?: string + minWidth?: string +} + +export const ProjectInputField: React.FC<ProjectInputFieldProps> = ({ + label, + value, + onChange, + placeholder, + status, + statusText, + minWidth = "250px" +}) => ( + <div className="space-y-2 min-w-[250px] flex-shrink-0" style={{ minWidth }}> + <label className={`text-sm font-medium ${getLabelStatusClassName(status)}`}> + {label} + {statusText && <span className="ml-1 text-xs">{statusText}</span>} + </label> + <Input + value={value} + onChange={(e) => onChange(e.target.value)} + placeholder={placeholder} + className={`h-8 text-sm ${getInputStatusClassName(status)}`} + /> + </div> +) + +export interface ProjectDisplayFieldProps { + label: string + value: string + status: ProjectSearchStatus + minWidth?: string + formatter?: (value: string) => string +} + +export const ProjectDisplayField: React.FC<ProjectDisplayFieldProps> = ({ + label, + value, + status, + minWidth = "120px", + formatter +}) => { + const displayValue = status === 'searching' ? '조회 중...' : (formatter ? formatter(value) : (value || '-')) + + return ( + <div className="space-y-2 flex-shrink-0" style={{ minWidth }}> + <label className={`text-sm font-medium ${getLabelStatusClassName(status)}`}> + {label} + {status === 'searching' && <span className="ml-1 text-xs">(조회 중...)</span>} + </label> + <div className={`text-sm font-medium min-h-[32px] flex items-center border rounded-md px-3 bg-background ${getDisplayElementStatusClassName(status)}`}> + {displayValue} + </div> + </div> + ) +} + +export interface ProjectFileFieldProps { + label: string + originalFile: string + onFileUpload: (event: React.ChangeEvent<HTMLInputElement>) => void + minWidth?: string +} + +export const ProjectFileField: React.FC<ProjectFileFieldProps> = ({ + label, + originalFile, + onFileUpload, + minWidth = "200px" +}) => ( + <div className="space-y-2 flex-shrink-0" style={{ minWidth }}> + <label className="text-sm font-medium text-muted-foreground">{label}</label> + <div className="flex items-center gap-2 min-h-[32px]"> + {originalFile ? ( + <span className="text-sm text-blue-600">{originalFile}</span> + ) : ( + <div className="relative"> + <input + type="file" + onChange={onFileUpload} + className="absolute inset-0 w-full h-full opacity-0 cursor-pointer" + accept=".xlsx,.xls,.csv" + /> + <Button variant="outline" size="sm" className="text-xs"> + 파일 선택 + </Button> + </div> + )} + </div> + </div> +) |
