2025-09-02 18:25:44 +09:00
|
|
|
"use client";
|
|
|
|
|
|
|
|
|
|
import React from "react";
|
|
|
|
|
import { Button } from "@/components/ui/button";
|
|
|
|
|
import { Badge } from "@/components/ui/badge";
|
|
|
|
|
import { Edit, Trash2 } from "lucide-react";
|
|
|
|
|
import { cn } from "@/lib/utils";
|
|
|
|
|
import { useUpdateCategory } from "@/hooks/queries/useCategories";
|
|
|
|
|
import type { CategoryInfo } from "@/types/commonCode";
|
|
|
|
|
|
|
|
|
|
interface CategoryItemProps {
|
|
|
|
|
category: CategoryInfo;
|
|
|
|
|
isSelected: boolean;
|
|
|
|
|
onSelect: () => void;
|
|
|
|
|
onEdit: () => void;
|
|
|
|
|
onDelete: () => void;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function CategoryItem({ category, isSelected, onSelect, onEdit, onDelete }: CategoryItemProps) {
|
|
|
|
|
const updateCategoryMutation = useUpdateCategory();
|
|
|
|
|
|
|
|
|
|
// 활성/비활성 토글 핸들러
|
|
|
|
|
const handleToggleActive = async (checked: boolean) => {
|
|
|
|
|
try {
|
|
|
|
|
await updateCategoryMutation.mutateAsync({
|
|
|
|
|
categoryCode: category.category_code,
|
|
|
|
|
data: {
|
|
|
|
|
categoryName: category.category_name,
|
|
|
|
|
categoryNameEng: category.category_name_eng || "",
|
|
|
|
|
description: category.description || "",
|
|
|
|
|
sortOrder: category.sort_order,
|
|
|
|
|
isActive: checked ? "Y" : "N",
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("카테고리 활성 상태 변경 실패:", error);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div
|
|
|
|
|
className={cn(
|
2025-10-22 14:52:13 +09:00
|
|
|
"cursor-pointer rounded-lg border bg-card p-4 shadow-sm transition-all",
|
|
|
|
|
isSelected
|
|
|
|
|
? "shadow-md"
|
|
|
|
|
: "hover:shadow-md",
|
2025-09-02 18:25:44 +09:00
|
|
|
)}
|
|
|
|
|
onClick={onSelect}
|
|
|
|
|
>
|
2025-10-22 14:52:13 +09:00
|
|
|
<div className="flex items-start justify-between gap-2">
|
2025-09-02 18:25:44 +09:00
|
|
|
<div className="min-w-0 flex-1">
|
|
|
|
|
<div className="flex items-center gap-2">
|
2025-10-22 14:52:13 +09:00
|
|
|
<h4 className="text-sm font-semibold">{category.category_name}</h4>
|
2025-09-02 18:25:44 +09:00
|
|
|
<Badge
|
|
|
|
|
variant={category.is_active === "Y" ? "default" : "secondary"}
|
|
|
|
|
className={cn(
|
2025-10-22 14:52:13 +09:00
|
|
|
"cursor-pointer text-xs transition-colors",
|
2025-09-02 18:25:44 +09:00
|
|
|
updateCategoryMutation.isPending && "cursor-not-allowed opacity-50",
|
|
|
|
|
)}
|
|
|
|
|
onClick={(e) => {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
e.stopPropagation();
|
|
|
|
|
if (!updateCategoryMutation.isPending) {
|
|
|
|
|
handleToggleActive(category.is_active !== "Y");
|
|
|
|
|
}
|
|
|
|
|
}}
|
|
|
|
|
onPointerDown={(e) => e.stopPropagation()}
|
|
|
|
|
onMouseDown={(e) => e.stopPropagation()}
|
|
|
|
|
>
|
|
|
|
|
{category.is_active === "Y" ? "활성" : "비활성"}
|
|
|
|
|
</Badge>
|
|
|
|
|
</div>
|
2025-10-22 14:52:13 +09:00
|
|
|
<p className="mt-1 text-xs text-muted-foreground">{category.category_code}</p>
|
|
|
|
|
{category.description && <p className="mt-1 text-xs text-muted-foreground">{category.description}</p>}
|
2025-09-02 18:25:44 +09:00
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* 액션 버튼 */}
|
|
|
|
|
{isSelected && (
|
|
|
|
|
<div className="flex items-center gap-1" onClick={(e) => e.stopPropagation()}>
|
2025-10-22 14:52:13 +09:00
|
|
|
<Button variant="ghost" size="sm" onClick={onEdit}>
|
2025-09-02 18:25:44 +09:00
|
|
|
<Edit className="h-3 w-3" />
|
|
|
|
|
</Button>
|
2025-10-22 14:52:13 +09:00
|
|
|
<Button variant="ghost" size="sm" onClick={onDelete}>
|
2025-09-02 18:25:44 +09:00
|
|
|
<Trash2 className="h-3 w-3" />
|
|
|
|
|
</Button>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|