Multi-department fault log: NewBook-synced room locations + manual locations with categories, six-state task flow (submitted/in progress/ hold-parts/hold-later/temporary fix/fixed), photos per stage, priorities with unusable flag and per-task NewBook out-of-order push, costs on resolve, comment/audit thread, recurring task templates with note-to-template carryover, asset register, contractor register with document attachments, staff/contractor allocation, occupancy-aware summary filter, searchable history with CSV export, email notifications. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
44 lines
1.4 KiB
TypeScript
44 lines
1.4 KiB
TypeScript
import { AlertTriangle } from 'lucide-react'
|
|
import type { Priority, TaskStatus } from '../types'
|
|
import { PRIORITY_LABELS, STATUS_LABELS } from '../types'
|
|
|
|
export function PriorityBadge({ priority }: { priority: Priority }) {
|
|
return <span className={`badge badge-prio-${priority}`}>{PRIORITY_LABELS[priority]}</span>
|
|
}
|
|
|
|
export function StatusBadge({ status }: { status: TaskStatus }) {
|
|
return <span className={`badge badge-st-${status}`}>{STATUS_LABELS[status]}</span>
|
|
}
|
|
|
|
export function UnusableBadge() {
|
|
return (
|
|
<span className="badge badge-unusable">
|
|
<AlertTriangle size={11} strokeWidth={1.75} />
|
|
Unusable
|
|
</span>
|
|
)
|
|
}
|
|
|
|
export function formatDate(iso: string | null | undefined): string {
|
|
if (!iso) return '—'
|
|
const d = new Date(iso)
|
|
return d.toLocaleDateString('en-GB', { day: 'numeric', month: 'short', year: 'numeric' })
|
|
}
|
|
|
|
export function formatDateTime(iso: string | null | undefined): string {
|
|
if (!iso) return '—'
|
|
const d = new Date(iso)
|
|
return d.toLocaleDateString('en-GB', { day: 'numeric', month: 'short' }) + ' ' +
|
|
d.toLocaleTimeString('en-GB', { hour: '2-digit', minute: '2-digit' })
|
|
}
|
|
|
|
export function daysOpen(createdAt: string): number {
|
|
return Math.floor((Date.now() - new Date(createdAt).getTime()) / 86400000)
|
|
}
|
|
|
|
export function ageLabel(createdAt: string): string {
|
|
const days = daysOpen(createdAt)
|
|
if (days === 0) return 'today'
|
|
if (days === 1) return '1 day'
|
|
return `${days} days`
|
|
}
|