70 lines
2.9 KiB
TypeScript
70 lines
2.9 KiB
TypeScript
import React from 'react';
|
|
import { Camera, CameraType } from '../../types.ts';
|
|
|
|
interface CameraCardProps {
|
|
camera: Camera;
|
|
onEdit: () => void;
|
|
onDelete: () => void;
|
|
}
|
|
|
|
const statusConfig: {
|
|
[key in Camera['status']]: { text: string; bg: string; pulseClass: string };
|
|
} = {
|
|
online: { text: 'Online', bg: 'bg-green-500', pulseClass: 'bg-green-300 animate-pulse' },
|
|
offline: { text: 'Offline', bg: 'bg-gray-500', pulseClass: 'bg-gray-300' },
|
|
error: { text: 'Error', bg: 'bg-red-500', pulseClass: 'bg-red-300' },
|
|
};
|
|
|
|
const typeConfig: { [key in CameraType]: { icon: string; color: string } } = {
|
|
[CameraType.STANDARD]: { icon: 'fa-video', color: 'text-gray-500' },
|
|
[CameraType.INFRARED]: { icon: 'fa-moon', color: 'text-purple-500' },
|
|
[CameraType.THERMAL]: { icon: 'fa-temperature-high', color: 'text-orange-500' },
|
|
[CameraType.THREE_D]: { icon: 'fa-cube', color: 'text-blue-500' },
|
|
};
|
|
|
|
const CameraCard: React.FC<CameraCardProps> = ({ camera, onEdit, onDelete }) => {
|
|
const status = statusConfig[camera.status];
|
|
const typeInfo = typeConfig[camera.cameraType] || typeConfig[CameraType.STANDARD];
|
|
|
|
return (
|
|
<div className="bg-white rounded-xl shadow-sm transition-all duration-300 hover:shadow-lg flex flex-col border border-gray-200">
|
|
<div className="relative aspect-video bg-black rounded-t-xl flex items-center justify-center">
|
|
<i className={`fa-solid ${typeInfo.icon} text-5xl ${typeInfo.color}`}></i>
|
|
<span
|
|
className={`absolute top-2 right-2 flex items-center text-xs font-semibold text-white px-2 py-0.5 rounded-full ${status.bg}`}
|
|
>
|
|
<span className={`w-2 h-2 rounded-full mr-1.5 ${status.pulseClass}`}></span>
|
|
{status.text}
|
|
</span>
|
|
</div>
|
|
<div className="p-4 flex-grow">
|
|
<h3 className="font-bold text-lg text-gray-800 truncate" title={camera.name}>
|
|
{camera.name}
|
|
</h3>
|
|
<p className="text-sm font-semibold text-gray-600">{camera.cameraType}</p>
|
|
<p className="text-xs text-gray-500 mt-1 truncate" title={camera.model}>
|
|
{camera.model}
|
|
</p>
|
|
</div>
|
|
<div className="p-3 bg-gray-50 border-t border-gray-100 rounded-b-xl flex items-center justify-end space-x-2">
|
|
<button
|
|
onClick={onEdit}
|
|
className="text-sm text-gray-600 hover:text-blue-600 font-medium px-3 py-1 rounded-md hover:bg-gray-200 transition-colors"
|
|
aria-label={`Edit ${camera.name}`}
|
|
>
|
|
<i className="fa-solid fa-pencil mr-1"></i> Edit
|
|
</button>
|
|
<button
|
|
onClick={onDelete}
|
|
className="text-sm text-gray-600 hover:text-red-600 font-medium px-3 py-1 rounded-md hover:bg-gray-200 transition-colors"
|
|
aria-label={`Delete ${camera.name}`}
|
|
>
|
|
<i className="fa-solid fa-trash mr-1"></i> Hapus
|
|
</button>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default CameraCard;
|