92 lines
2.9 KiB
TypeScript
92 lines
2.9 KiB
TypeScript
import React from 'react';
|
|
import { FeedSackLogEntry } from '../../types.ts';
|
|
|
|
const BoundingBox: React.FC<{
|
|
top: string;
|
|
left: string;
|
|
width: string;
|
|
height: string;
|
|
delay: string;
|
|
color: string;
|
|
}> = ({ top, left, width, height, delay, color }) => (
|
|
<div
|
|
className={`absolute border-2 bg-opacity-20 rounded-sm animate-pulse`}
|
|
style={{
|
|
top,
|
|
left,
|
|
width,
|
|
height,
|
|
animationDelay: delay,
|
|
borderColor: color,
|
|
backgroundColor: color,
|
|
}}
|
|
></div>
|
|
);
|
|
|
|
interface LiveFeedViewProps {
|
|
mode: 'inbound' | 'usage';
|
|
latestLog?: FeedSackLogEntry;
|
|
}
|
|
|
|
const LiveFeedView: React.FC<LiveFeedViewProps> = ({ mode, latestLog }) => {
|
|
const config = {
|
|
inbound: {
|
|
title: 'Kamera Pintu Masuk Gudang',
|
|
image: 'https://i.imgur.com/rLd7gP9.jpg', // Warehouse entrance
|
|
color: '#22c55e', // green-500
|
|
textColor: 'text-green-400',
|
|
boxes: [
|
|
{ top: '40%', left: '55%', width: '12%', height: '25%', delay: '0s' },
|
|
{ top: '42%', left: '40%', width: '12%', height: '26%', delay: '0.2s' },
|
|
{ top: '45%', left: '25%', width: '12%', height: '24%', delay: '0.4s' },
|
|
],
|
|
},
|
|
usage: {
|
|
title: 'Kamera Area Feeder',
|
|
image: 'https://i.imgur.com/8p8Yq3g.jpg', // Coop interior
|
|
color: '#f97316', // orange-500
|
|
textColor: 'text-orange-400',
|
|
boxes: [{ top: '60%', left: '20%', width: '15%', height: '28%', delay: '0.1s' }],
|
|
},
|
|
};
|
|
|
|
const currentConfig = config[mode];
|
|
const count = latestLog ? latestLog.count : 0;
|
|
|
|
return (
|
|
<div className="bg-white p-6 rounded-xl shadow-sm">
|
|
<div className="flex justify-between items-center mb-4">
|
|
<h2 className="text-xl font-bold">{currentConfig.title}</h2>
|
|
<div className="flex items-center space-x-2">
|
|
<span className="relative flex h-3 w-3">
|
|
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-red-400 opacity-75"></span>
|
|
<span className="relative inline-flex rounded-full h-3 w-3 bg-red-500"></span>
|
|
</span>
|
|
<span className="text-red-600 font-semibold">LIVE</span>
|
|
</div>
|
|
</div>
|
|
<div className="relative w-full aspect-video bg-gray-800 rounded-lg overflow-hidden shadow-inner">
|
|
<img
|
|
src={currentConfig.image}
|
|
alt="Live camera feed"
|
|
className="w-full h-full object-cover opacity-80"
|
|
/>
|
|
|
|
{currentConfig.boxes.map((box, i) => (
|
|
<BoundingBox key={i} {...box} color={currentConfig.color} />
|
|
))}
|
|
|
|
<div className="absolute bottom-2 right-2 bg-black/60 backdrop-blur-sm text-white p-2 rounded-lg text-sm font-mono">
|
|
<p>
|
|
Terdeteksi:{' '}
|
|
<span className={`font-bold ${currentConfig.textColor}`}>{count} karung</span>
|
|
</p>
|
|
<p>Lokasi: {latestLog?.location || 'N/A'}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default LiveFeedView;
|