import { Dialog, DialogContent, DialogHeader, DialogTitle, } from "@/Components/ui/dialog"; import { Badge } from "@/Components/ui/badge"; import { ScrollArea } from "@/Components/ui/scroll-area"; import { User, Clock, Package, Activity as ActivityIcon } from "lucide-react"; interface Activity { id: number; description: string; subject_type: string; event: string; causer: string; created_at: string; properties: { attributes?: Record; old?: Record; }; } interface Props { open: boolean; onOpenChange: (open: boolean) => void; activity: Activity | null; } // Field translation map const fieldLabels: Record = { name: '名稱', code: '代碼', description: '描述', price: '價格', cost: '成本', stock: '庫存', category_id: '分類', unit_id: '單位', is_active: '啟用狀態', conversion_rate: '換算率', specification: '規格', brand: '品牌', base_unit_id: '基本單位', large_unit_id: '大單位', purchase_unit_id: '採購單位', email: 'Email', password: '密碼', phone: '電話', address: '地址', role_id: '角色', // Snapshot fields category_name: '分類名稱', base_unit_name: '基本單位名稱', large_unit_name: '大單位名稱', purchase_unit_name: '採購單位名稱', // Warehouse & Inventory fields warehouse_name: '倉庫名稱', product_name: '商品名稱', warehouse_id: '倉庫', product_id: '商品', quantity: '數量', safety_stock: '安全庫存', location: '儲位', }; export default function ActivityDetailDialog({ open, onOpenChange, activity }: Props) { if (!activity) return null; const attributes = activity.properties?.attributes || {}; const old = activity.properties?.old || {}; // Get all keys from both attributes and old to ensure we show all changes const allKeys = Array.from(new Set([...Object.keys(attributes), ...Object.keys(old)])); // Filter out internal keys often logged but not useful for users const filteredKeys = allKeys.filter(key => !['created_at', 'updated_at', 'deleted_at', 'id'].includes(key) ); const getEventBadgeClass = (event: string) => { switch (event) { case 'created': return 'bg-green-100 text-green-700 hover:bg-green-200 border-green-200'; case 'updated': return 'bg-blue-100 text-blue-700 hover:bg-blue-200 border-blue-200'; case 'deleted': return 'bg-red-100 text-red-700 hover:bg-red-200 border-red-200'; default: return 'bg-gray-100 text-gray-700 hover:bg-gray-200 border-gray-200'; } }; const getEventLabel = (event: string) => { switch (event) { case 'created': return '新增'; case 'updated': return '更新'; case 'deleted': return '刪除'; default: return event; } }; const formatValue = (key: string, value: any) => { if (value === null || value === undefined) return -; // Special handling for boolean values based on key if (typeof value === 'boolean') { if (key === 'is_active') return value ? '啟用' : '停用'; return value ? '是' : '否'; } if (typeof value === 'object') return JSON.stringify(value); return String(value); }; const getFieldName = (key: string) => { return fieldLabels[key] || key.charAt(0).toUpperCase() + key.slice(1).replace(/_/g, ' '); }; // Helper to check if a key is a snapshot name field const isSnapshotField = (key: string) => { return ['category_name', 'base_unit_name', 'large_unit_name', 'purchase_unit_name', 'warehouse_name', 'product_name'].includes(key); }; // Helper to get formatted value (merging ID and Name if available) const getFormattedValue = (key: string, value: any, allData: Record) => { // If it's an ID field, check if we have a corresponding name snapshot if (key.endsWith('_id')) { const nameKey = key.replace('_id', '_name'); const nameValue = allData[nameKey]; if (nameValue) { return `${nameValue}`; } } return formatValue(key, value); }; return ( 操作詳情 {getEventLabel(activity.event)} {/* Modern Metadata Strip */}
{activity.causer}
{activity.created_at}
{activity.subject_type}
{/* Only show 'description' if it differs from event name (unlikely but safe) */} {activity.description !== getEventLabel(activity.event) && activity.description !== 'created' && activity.description !== 'updated' && (
{activity.description}
)}
{activity.event === 'created' ? (
欄位
初始內容
{filteredKeys .filter(key => attributes[key] !== null && attributes[key] !== '' && !isSnapshotField(key)) .map((key) => (
{getFieldName(key)}
{getFormattedValue(key, attributes[key], attributes)}
))} {filteredKeys.filter(key => attributes[key] !== null && attributes[key] !== '' && !isSnapshotField(key)).length === 0 && (
無初始資料
)}
) : (
欄位
異動前
異動後
{filteredKeys.some(key => !isSnapshotField(key)) ? (
{filteredKeys .filter(key => !isSnapshotField(key)) .map((key) => { const oldValue = old[key]; const newValue = attributes[key]; const isChanged = JSON.stringify(oldValue) !== JSON.stringify(newValue); return (
{getFieldName(key)}
{getFormattedValue(key, oldValue, old)}
{activity.event === 'deleted' ? '-' : getFormattedValue(key, newValue, attributes)}
); })}
) : (
無詳細異動內容
)}
)}
); }