Files
sam-react-prod/src/components/items/DynamicItemForm/fields/DropdownField.tsx

123 lines
3.3 KiB
TypeScript
Raw Normal View History

/**
* (Select)
* ItemForm과 100%
*/
'use client';
import { Label } from '@/components/ui/label';
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '@/components/ui/select';
import type { DynamicFieldRendererProps } from '../types';
// 옵션을 {label, value} 형태로 정규화
function normalizeOptions(rawOptions: unknown): Array<{ label: string; value: string }> {
if (!rawOptions) return [];
// 문자열인 경우: 콤마로 분리
if (typeof rawOptions === 'string') {
return rawOptions.split(',').map(o => {
const trimmed = o.trim();
return { label: trimmed, value: trimmed };
});
}
// 배열인 경우
if (Array.isArray(rawOptions)) {
return rawOptions.map(item => {
// 이미 {label, value} 형태
if (typeof item === 'object' && item !== null && 'value' in item) {
return {
label: String(item.label || item.value),
value: String(item.value),
};
}
// 문자열 배열
const str = String(item);
return { label: str, value: str };
});
}
return [];
}
export function DropdownField({
field,
value,
onChange,
error,
disabled,
unitOptions,
}: DynamicFieldRendererProps) {
const fieldKey = field.field_key || `field_${field.id}`;
const stringValue = value !== null && value !== undefined ? String(value) : '';
// field_key 또는 field_name이 '단위'/'unit' 관련이면 unitOptions 사용
const isUnitField =
fieldKey.toLowerCase().includes('unit') ||
fieldKey.includes('단위') ||
field.field_name.includes('단위') ||
field.field_name.toLowerCase().includes('unit');
// 옵션 목록 결정
let options: Array<{ label: string; value: string }> = [];
if (isUnitField && unitOptions && unitOptions.length > 0) {
options = unitOptions.map((u) => ({
label: `${u.label} (${u.value})`,
value: u.value,
}));
} else {
// field.options를 정규화
options = normalizeOptions(field.options);
}
// 옵션이 없으면 드롭다운을 disabled로 표시
const hasOptions = options.length > 0;
return (
<div>
<Label htmlFor={fieldKey}>
{field.field_name}
{field.is_required && <span className="text-red-500"> *</span>}
</Label>
<Select
value={stringValue}
onValueChange={onChange}
disabled={disabled || !hasOptions}
>
<SelectTrigger
id={fieldKey}
className={error ? 'border-red-500' : ''}
>
<SelectValue placeholder={
hasOptions
? (field.placeholder || `${field.field_name}을(를) 선택하세요`)
: '옵션이 없습니다'
} />
</SelectTrigger>
<SelectContent>
{options.map((option, index) => (
<SelectItem key={`${option.value}-${index}`} value={option.value}>
{option.label}
</SelectItem>
))}
</SelectContent>
</Select>
{error && (
<p className="text-xs text-red-500 mt-1">{error}</p>
)}
{!error && field.description && (
<p className="text-xs text-muted-foreground mt-1">
* {field.description}
</p>
)}
</div>
);
}