This commit is contained in:
kjs
2025-11-06 14:46:15 +09:00
parent 832e80cd7f
commit 786576bb76
4 changed files with 172 additions and 80 deletions

View File

@@ -49,25 +49,33 @@ export const CategoryValueManager: React.FC<CategoryValueManagerProps> = ({
const [editingValue, setEditingValue] = useState<TableCategoryValue | null>(
null
);
const [showInactive, setShowInactive] = useState(false); // 비활성 항목 표시 옵션 (기본: 숨김)
// 카테고리 값 로드
useEffect(() => {
loadCategoryValues();
}, [tableName, columnName]);
// 검색 필터링
// 검색 필터링 + 비활성 필터링
useEffect(() => {
let filtered = values;
// 비활성 항목 필터링 (기본: 활성만 표시, 체크하면 비활성도 표시)
if (!showInactive) {
filtered = filtered.filter((v) => v.isActive !== false);
}
// 검색어 필터링
if (searchQuery) {
const filtered = values.filter(
filtered = filtered.filter(
(v) =>
v.valueCode.toLowerCase().includes(searchQuery.toLowerCase()) ||
v.valueLabel.toLowerCase().includes(searchQuery.toLowerCase())
);
setFilteredValues(filtered);
} else {
setFilteredValues(values);
}
}, [searchQuery, values]);
setFilteredValues(filtered);
}, [searchQuery, values, showInactive]);
const loadCategoryValues = async () => {
setIsLoading(true);
@@ -264,10 +272,27 @@ export const CategoryValueManager: React.FC<CategoryValueManagerProps> = ({
{filteredValues.length}
</p>
</div>
<Button onClick={() => setIsAddDialogOpen(true)} size="sm">
<Plus className="mr-2 h-4 w-4" />
</Button>
<div className="flex items-center gap-3">
{/* 비활성 항목 표시 옵션 */}
<div className="flex items-center gap-2">
<Checkbox
id="show-inactive"
checked={showInactive}
onCheckedChange={(checked) => setShowInactive(checked as boolean)}
/>
<label
htmlFor="show-inactive"
className="text-sm text-muted-foreground cursor-pointer whitespace-nowrap"
>
</label>
</div>
<Button onClick={() => setIsAddDialogOpen(true)} size="sm">
<Plus className="mr-2 h-4 w-4" />
</Button>
</div>
</div>
{/* 검색바 */}
@@ -294,73 +319,90 @@ export const CategoryValueManager: React.FC<CategoryValueManagerProps> = ({
</div>
) : (
<div className="space-y-2">
{filteredValues.map((value) => (
<div
key={value.valueId}
className="flex items-center gap-3 rounded-md border bg-card p-3 transition-colors hover:bg-accent"
>
<Checkbox
checked={selectedValueIds.includes(value.valueId!)}
onCheckedChange={() => handleSelectValue(value.valueId!)}
/>
<div className="flex flex-1 items-center gap-2">
<Badge variant="outline" className="text-xs">
{value.valueCode}
</Badge>
<span className="text-sm font-medium">
{value.valueLabel}
</span>
{value.description && (
<span className="text-xs text-muted-foreground">
- {value.description}
</span>
)}
{value.isDefault && (
<Badge variant="secondary" className="text-[10px]">
</Badge>
)}
{value.color && (
<div
className="h-4 w-4 rounded-full border"
style={{ backgroundColor: value.color }}
/>
)}
</div>
<div className="flex items-center gap-2">
<Switch
checked={value.isActive !== false}
onCheckedChange={() =>
handleToggleActive(
value.valueId!,
value.isActive !== false
)
}
className="data-[state=checked]:bg-emerald-500"
{filteredValues.map((value) => {
const isInactive = value.isActive === false;
return (
<div
key={value.valueId}
className={`flex items-center gap-3 rounded-md border bg-card p-3 transition-colors hover:bg-accent ${
isInactive ? "opacity-50" : ""
}`}
>
<Checkbox
checked={selectedValueIds.includes(value.valueId!)}
onCheckedChange={() => handleSelectValue(value.valueId!)}
/>
<Button
variant="ghost"
size="icon"
onClick={() => setEditingValue(value)}
className="h-8 w-8"
>
<Edit2 className="h-3 w-3" />
</Button>
<div className="flex flex-1 items-center gap-2">
{/* 색상 표시 (앞쪽으로 이동) */}
{value.color && (
<div
className="h-4 w-4 rounded-full border flex-shrink-0"
style={{ backgroundColor: value.color }}
/>
)}
{/* 라벨 */}
<span className={`text-sm font-medium ${isInactive ? "line-through" : ""}`}>
{value.valueLabel}
</span>
{/* 설명 */}
{value.description && (
<span className="text-xs text-muted-foreground">
- {value.description}
</span>
)}
{/* 기본값 배지 */}
{value.isDefault && (
<Badge variant="secondary" className="text-[10px]">
</Badge>
)}
{/* 비활성 배지 */}
{isInactive && (
<Badge variant="outline" className="text-[10px] text-muted-foreground">
</Badge>
)}
</div>
<Button
variant="ghost"
size="icon"
onClick={() => handleDeleteValue(value.valueId!)}
className="h-8 w-8 text-destructive"
>
<Trash2 className="h-3 w-3" />
</Button>
<div className="flex items-center gap-2">
<Switch
checked={value.isActive !== false}
onCheckedChange={() =>
handleToggleActive(
value.valueId!,
value.isActive !== false
)
}
className="data-[state=checked]:bg-emerald-500"
/>
<Button
variant="ghost"
size="icon"
onClick={() => setEditingValue(value)}
className="h-8 w-8"
>
<Edit2 className="h-3 w-3" />
</Button>
<Button
variant="ghost"
size="icon"
onClick={() => handleDeleteValue(value.valueId!)}
className="h-8 w-8 text-destructive"
>
<Trash2 className="h-3 w-3" />
</Button>
</div>
</div>
</div>
))}
);
})}
</div>
)}
</div>