feat(gehege): Reinigungszyklus (Maße, Kapazität, letzte/nächste Reinigung)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -7,17 +7,27 @@ import { useMemo, useState } from 'react'
|
||||
import { Link, useNavigate, useParams } from 'react-router-dom'
|
||||
import { de } from '../strings/de'
|
||||
import { ApiError } from '../api/client'
|
||||
import { deleteEnclosure, getEnclosure } from '../api/enclosures'
|
||||
import { deleteEnclosure, getEnclosure, markEnclosureCleaned } from '../api/enclosures'
|
||||
import { listGerbils } from '../api/gerbils'
|
||||
import { listColorVarieties } from '../api/lookups'
|
||||
import { condition } from '../api/gridify'
|
||||
import { useApi, useMutation } from '../hooks/useApi'
|
||||
import { formatDate } from '../format/labels'
|
||||
import { useToast } from '../components/toast'
|
||||
import EnclosurePhotosSection from '../components/EnclosurePhotosSection'
|
||||
|
||||
/** true, wenn die nächste fällige Reinigung am/vor heute liegt. */
|
||||
function isCleaningDue(nextCleaningDate: string | null): boolean {
|
||||
if (!nextCleaningDate) return false
|
||||
const today = new Date().toISOString().slice(0, 10)
|
||||
return nextCleaningDate <= today
|
||||
}
|
||||
|
||||
export default function BeckenDetailPage() {
|
||||
const t = de.pages.becken
|
||||
const { id = '' } = useParams()
|
||||
const navigate = useNavigate()
|
||||
const toast = useToast()
|
||||
const [deleteError, setDeleteError] = useState<string | null>(null)
|
||||
|
||||
const enclosure = useApi(() => getEnclosure(id), [id])
|
||||
@@ -39,6 +49,17 @@ export default function BeckenDetailPage() {
|
||||
)
|
||||
|
||||
const removal = useMutation(() => deleteEnclosure(id))
|
||||
const cleaning = useMutation(() => markEnclosureCleaned(id))
|
||||
|
||||
async function onMarkCleaned() {
|
||||
const result = await cleaning.run()
|
||||
if (result.ok) {
|
||||
toast.success(t.cleaning.marked)
|
||||
enclosure.reload()
|
||||
} else {
|
||||
toast.error(result.error)
|
||||
}
|
||||
}
|
||||
|
||||
async function onDelete() {
|
||||
if (!window.confirm(t.delete.confirmMessage)) return
|
||||
@@ -101,15 +122,62 @@ export default function BeckenDetailPage() {
|
||||
|
||||
{deleteError && <div className="alert alert--error">{deleteError}</div>}
|
||||
|
||||
{e.notes && (
|
||||
{(e.notes || e.size || e.capacity != null) && (
|
||||
<dl className="def-list">
|
||||
<div className="def-row">
|
||||
<dt>{t.fields.notes}</dt>
|
||||
<dd>{e.notes}</dd>
|
||||
</div>
|
||||
{e.notes && (
|
||||
<div className="def-row">
|
||||
<dt>{t.fields.notes}</dt>
|
||||
<dd>{e.notes}</dd>
|
||||
</div>
|
||||
)}
|
||||
{e.size && (
|
||||
<div className="def-row">
|
||||
<dt>{t.fields.size}</dt>
|
||||
<dd>{e.size}</dd>
|
||||
</div>
|
||||
)}
|
||||
{e.capacity != null && (
|
||||
<div className="def-row">
|
||||
<dt>{t.fields.capacity}</dt>
|
||||
<dd>{t.cleaning.capacityUnit(e.capacity)}</dd>
|
||||
</div>
|
||||
)}
|
||||
</dl>
|
||||
)}
|
||||
|
||||
<h3>{t.cleaning.title}</h3>
|
||||
{isCleaningDue(e.nextCleaningDate) && (
|
||||
<div className="alert alert--warning" role="status">
|
||||
{e.nextCleaningDate
|
||||
? t.cleaning.dueSince(formatDate(e.nextCleaningDate))
|
||||
: t.cleaning.due}
|
||||
</div>
|
||||
)}
|
||||
<dl className="def-list">
|
||||
<div className="def-row">
|
||||
<dt>{t.fields.lastCleanedDate}</dt>
|
||||
<dd>{e.lastCleanedDate ? formatDate(e.lastCleanedDate) : t.cleaning.neverCleaned}</dd>
|
||||
</div>
|
||||
<div className="def-row">
|
||||
<dt>{t.fields.cleaningCycleDays}</dt>
|
||||
<dd>{e.cleaningCycleDays != null ? t.cleaning.cycleUnit(e.cleaningCycleDays) : t.cleaning.noCycle}</dd>
|
||||
</div>
|
||||
{e.nextCleaningDate && (
|
||||
<div className="def-row">
|
||||
<dt>{t.fields.nextCleaningDate}</dt>
|
||||
<dd>{formatDate(e.nextCleaningDate)}</dd>
|
||||
</div>
|
||||
)}
|
||||
</dl>
|
||||
<button
|
||||
type="button"
|
||||
className="btn"
|
||||
onClick={onMarkCleaned}
|
||||
disabled={cleaning.pending}
|
||||
>
|
||||
{cleaning.pending ? t.cleaning.marking : t.cleaning.markCleaned}
|
||||
</button>
|
||||
|
||||
<h3>{t.photosTitle}</h3>
|
||||
<EnclosurePhotosSection enclosureId={e.id} />
|
||||
|
||||
|
||||
Reference in New Issue
Block a user