commit
32a36cceff
444 files changed
+67186
No files matched your search
@@ -0,0 +1,71 @@
|
||||
import React from 'react';
|
||||
import { LiveCount } from '../../types';
|
||||
import { formatNumber } from '../../utils/formatters.ts';
|
||||
|
||||
const statusConfig: {
|
||||
[key in LiveCount['status']]: { text: string; bg: string; pulse: boolean; icon: string };
|
||||
} = {
|
||||
online: { text: 'Menghitung', bg: 'bg-green-500', pulse: true, icon: 'fa-video' },
|
||||
offline: { text: 'Offline', bg: 'bg-gray-500', pulse: false, icon: 'fa-video-slash' },
|
||||
processing: { text: 'Memproses', bg: 'bg-blue-500', pulse: true, icon: 'fa-cogs' },
|
||||
};
|
||||
|
||||
const CameraCountCard: React.FC<{ liveCount: LiveCount }> = ({ liveCount }) => {
|
||||
const status = statusConfig[liveCount.status];
|
||||
|
||||
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 overflow-hidden group">
|
||||
<img
|
||||
src={liveCount.imageUrl}
|
||||
alt={liveCount.cameraName}
|
||||
className="w-full h-full object-cover transition-transform duration-300 group-hover:scale-105"
|
||||
/>
|
||||
<div className="absolute inset-0 bg-black/30"></div>
|
||||
|
||||
<div className="absolute top-2 left-2 flex items-center space-x-2">
|
||||
<span
|
||||
className={`flex items-center text-xs font-semibold text-white px-2 py-0.5 rounded-full ${status.bg}`}
|
||||
>
|
||||
{status.pulse && (
|
||||
<span className="relative flex h-2 w-2 mr-1.5">
|
||||
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-white/75 opacity-75"></span>
|
||||
<span className="relative inline-flex rounded-full h-2 w-2 bg-white"></span>
|
||||
</span>
|
||||
)}
|
||||
{status.text}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{liveCount.status === 'online' && (
|
||||
<div className="absolute inset-0 flex flex-col items-center justify-center">
|
||||
<p
|
||||
className="text-white text-4xl font-bold drop-shadow-lg"
|
||||
style={{ textShadow: '0 2px 4px rgba(0,0,0,0.5)' }}
|
||||
>
|
||||
{formatNumber(liveCount.count)}
|
||||
</p>
|
||||
<p className="text-white/80 text-sm font-semibold drop-shadow-md">ekor terdeteksi</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{liveCount.status !== 'online' && (
|
||||
<div className="absolute inset-0 flex flex-col items-center justify-center bg-black/50">
|
||||
<i className={`fa-solid ${status.icon} text-4xl text-white/70`}></i>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="p-3">
|
||||
<h3 className="font-bold text-gray-800 truncate" title={liveCount.cameraName}>
|
||||
{liveCount.cameraName}
|
||||
</h3>
|
||||
<p className="text-xs text-gray-500 truncate" title={liveCount.locationName}>
|
||||
<i className="fa-solid fa-map-marker-alt mr-1.5"></i>
|
||||
{liveCount.locationName}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CameraCountCard;
|
||||
Reference in new issue
Block a user