blakeblackshear.frigate/web/src/routes/Event.jsx

134 lines
4.1 KiB
React
Raw Normal View History

import { h, Fragment } from 'preact';
import { useCallback, useState } from 'preact/hooks';
import { route } from 'preact-router';
2021-02-07 22:46:05 +01:00
import ActivityIndicator from '../components/ActivityIndicator';
import Button from '../components/Button';
import Delete from '../icons/Delete'
import Dialog from '../components/Dialog';
2021-02-07 22:46:05 +01:00
import Heading from '../components/Heading';
import Link from '../components/Link';
import { FetchStatus, useApiHost, useEvent } from '../api';
import { Table, Thead, Tbody, Th, Tr, Td } from '../components/Table';
2021-01-09 18:26:46 +01:00
export default function Event({ eventId }) {
2021-01-26 16:04:03 +01:00
const apiHost = useApiHost();
const { data, status } = useEvent(eventId);
const [showDialog, setShowDialog] = useState(false);
const [deleteStatus, setDeleteStatus] = useState(FetchStatus.NONE);
const handleClickDelete = () => {
setShowDialog(true);
};
const handleDismissDeleteDialog = () => {
setShowDialog(false);
};
const handleClickDeleteDialog = useCallback(async () => {
let success;
try {
const response = await fetch(`${apiHost}/api/events/${eventId}`, { method: 'DELETE' });
success = await (response.status < 300 ? response.json() : { success: true });
setDeleteStatus(success ? FetchStatus.LOADED : FetchStatus.ERROR);
} catch (e) {
setDeleteStatus(FetchStatus.ERROR);
}
if (success) {
setDeleteStatus(FetchStatus.LOADED);
setShowDialog(false);
route('/events', true);
}
}, [apiHost, eventId, setShowDialog]);
2021-01-09 18:26:46 +01:00
if (status !== FetchStatus.LOADED) {
return <ActivityIndicator />
2021-01-09 18:26:46 +01:00
}
const startime = new Date(data.start_time * 1000);
const endtime = new Date(data.end_time * 1000);
2021-01-09 18:26:46 +01:00
return (
<div className="space-y-4">
<div className="flex">
<Heading className="flex-grow">
{data.camera} {data.label} <span className="text-sm">{startime.toLocaleString()}</span>
</Heading>
<Button className="self-start" color="red" onClick={handleClickDelete}>
<Delete className="w-6" /> Delete event
</Button>
{showDialog ? (
<Dialog
onDismiss={handleDismissDeleteDialog}
title="Delete Event?"
text="This event will be permanently deleted along with any related clips and snapshots"
actions={[
deleteStatus !== FetchStatus.LOADING
? { text: 'Delete', color: 'red', onClick: handleClickDeleteDialog }
: { text: 'Deleting…', color: 'red', disabled: true },
{ text: 'Cancel', onClick: handleDismissDeleteDialog },
]}
/>
) : null}
</div>
2021-02-05 01:24:04 +01:00
<Table class="w-full">
<Thead>
<Th>Key</Th>
<Th>Value</Th>
</Thead>
<Tbody>
<Tr>
<Td>Camera</Td>
<Td>
<Link href={`/cameras/${data.camera}`}>{data.camera}</Link>
</Td>
</Tr>
<Tr index={1}>
<Td>Timeframe</Td>
<Td>
{startime.toLocaleString()} {endtime.toLocaleString()}
</Td>
</Tr>
<Tr>
<Td>Score</Td>
<Td>{(data.top_score * 100).toFixed(2)}%</Td>
</Tr>
<Tr index={1}>
<Td>Zones</Td>
<Td>{data.zones.join(', ')}</Td>
</Tr>
</Tbody>
</Table>
2021-02-05 01:24:04 +01:00
{data.has_clip ? (
<Fragment>
<Heading size="sm">Clip</Heading>
2021-02-14 05:00:45 +01:00
<video
aria-label={`Clip for event ${data.id}`}
autoPlay
className="w-100"
src={`${apiHost}/clips/${data.camera}-${eventId}.mp4`}
controls
/>
2021-02-05 01:24:04 +01:00
</Fragment>
) : (
<p>No clip available</p>
)}
2021-02-05 01:24:04 +01:00
<Heading size="sm">{data.has_snapshot ? 'Best image' : 'Thumbnail'}</Heading>
<img
src={
data.has_snapshot
? `${apiHost}/clips/${data.camera}-${eventId}.jpg`
: `data:image/jpeg;base64,${data.thumbnail}`
}
alt={`${data.label} at ${(data.top_score * 100).toFixed(1)}% confidence`}
/>
2021-01-09 18:26:46 +01:00
</div>
);
}