Files
tickte-system/src/pages/PlanboardPage.jsx
T

82 lines
3.4 KiB
React

import { useState, useMemo } from 'react'
import { Link } from 'react-router-dom'
import { addDays, startOfWeek, isSameDay } from 'date-fns'
import { PageHeader, Button } from '../components/ui'
import { useWorkorders } from '../hooks/useWorkorders'
import { useEmployees } from '../hooks/useEmployees'
import { groupAppointmentsByDay, countInRange, dayKey } from '../lib/planboard'
import { ticketPath, ticketRef } from '../lib/ticketRoutes'
import {
planboardSubtitle, dayLabels, appointmentClass, appointmentTimeLabel, appointmentOwnerLabel, appointmentTitle,
} from '../lib/planboardView'
/* Termine haengen an den Tickets (startDate/startTime/endTime/assignedTo);
die Aufbereitung steckt in src/lib/planboard.js, die Texte in src/lib/planboardView.js. */
export default function PlanboardPage() {
const [currentWeek, setCurrentWeek] = useState(startOfWeek(new Date(), { weekStartsOn: 1 }))
const { workorders, loading } = useWorkorders({ limit: 500 })
const { employees } = useEmployees()
const weekDays = Array.from({ length: 7 }, (_, i) => addDays(currentWeek, i))
const navigateWeek = (dir) => setCurrentWeek((prev) => addDays(prev, dir * 7))
const goToday = () => setCurrentWeek(startOfWeek(new Date(), { weekStartsOn: 1 }))
const byDay = useMemo(() => groupAppointmentsByDay(workorders || [], employees || []), [workorders, employees])
const weekCount = countInRange(byDay, weekDays)
return (
<div className="page">
<PageHeader
title="Planboard"
subtitle={planboardSubtitle({ weekStart: currentWeek, count: weekCount, loading })}
actions={
<>
<Button variant="quiet" aria-label="Vorherige Woche" onClick={() => navigateWeek(-1)}>←</Button>
<Button onClick={goToday}>Heute</Button>
<Button variant="quiet" aria-label="Nächste Woche" onClick={() => navigateWeek(1)}>→</Button>
</>
}
/>
<div className="week">
{weekDays.map((day, index) => {
const entries = byDay[dayKey(day)] || []
const today = isSameDay(day, new Date())
const labels = dayLabels(day)
return (
<div
key={day.toISOString()}
className={`day${today ? ' today' : ''}${index >= 5 ? ' weekend' : ''}`}
role="group"
aria-label={labels.full}
aria-current={today ? 'date' : undefined}
>
<div className="day-head">
<span className="wd">{labels.weekday}</span>
<span className="dn">{labels.number}</span>
</div>
{entries.length === 0 && <div className="none">Keine Termine</div>}
{entries.map((entry) => (
<Link
key={entry.id}
className={appointmentClass(entry.type)}
to={ticketPath(ticketRef({ woid: entry.woid, $id: entry.id }))}
title={appointmentTitle(entry)}
>
<div className="tm">{appointmentTimeLabel(entry)}</div>
<div className="tt">{entry.customerName || entry.topic}</div>
{entry.customerName && <div className="cu">{entry.topic}</div>}
<div className="cu">{appointmentOwnerLabel(entry)}</div>
</Link>
))}
</div>
)
})}
</div>
</div>
)
}