fix: five dashboard improvements across booking, vehicles, profile, and UI

- fix(auth): guard extractNames() against Authentik sending full name in
  given_name field (e.g. "Matthias Hochmeister" + family_name "Hochmeister");
  detect by checking given_name ends with family_name suffix, fall through
  to name-splitting so Vorname/Nachname display correctly in Profile

- fix(db): add migration 018 to repair broken BEFORE UPDATE triggers on
  veranstaltungen and veranstaltung_kategorien; old triggers called
  update_updated_at_column() which references NEW.updated_at, but both
  tables use aktualisiert_am, causing every category/event edit to fail

- feat(booking): open vehicle booking creation to all authenticated users;
  only dashboard_admin / dashboard_moderator can change the Buchungsart
  (type select disabled for regular members); edit and cancel still
  restricted to WRITE_GROUPS

- feat(vehicles): VehicleDashboardCard now fetches equipment warnings via
  equipmentApi.getVehicleWarnings() in parallel and shows an alert when
  any vehicle equipment is not einsatzbereit

- fix(ui): add MuiTextField defaultProps (InputLabelProps.shrink=true) and
  MuiOutlinedInput notch legend font-size override to theme to eliminate
  floating-label / border conflict on click

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Matthias Hochmeister
2026-03-03 11:04:57 +01:00
parent 2306741c4d
commit 3101f1a9c5
6 changed files with 79 additions and 10 deletions

View File

@@ -81,6 +81,7 @@ const EMPTY_FORM: CreateBuchungInput = {
};
const WRITE_GROUPS = ['dashboard_admin', 'dashboard_fahrmeister', 'dashboard_moderator'];
const MANAGE_ART_GROUPS = ['dashboard_admin', 'dashboard_moderator'];
// ---------------------------------------------------------------------------
// Main Page
@@ -89,8 +90,11 @@ const WRITE_GROUPS = ['dashboard_admin', 'dashboard_fahrmeister', 'dashboard_mod
function FahrzeugBuchungen() {
const { user } = useAuth();
const notification = useNotification();
const canCreate = !!user; // All authenticated users can create bookings
const canWrite =
user?.groups?.some((g) => WRITE_GROUPS.includes(g)) ?? false;
user?.groups?.some((g) => WRITE_GROUPS.includes(g)) ?? false; // Can edit/cancel
const canChangeBuchungsArt =
user?.groups?.some((g) => MANAGE_ART_GROUPS.includes(g)) ?? false; // Can change booking type
// ── Week navigation ────────────────────────────────────────────────────────
const [currentWeekStart, setCurrentWeekStart] = useState<Date>(() =>
@@ -194,7 +198,7 @@ function FahrzeugBuchungen() {
};
const handleCellClick = (vehicleId: string, day: Date) => {
if (!canWrite) return;
if (!canCreate) return;
const dateStr = format(day, "yyyy-MM-dd'T'08:00");
const dateEndStr = format(day, "yyyy-MM-dd'T'17:00");
setEditingBooking(null);
@@ -339,7 +343,7 @@ function FahrzeugBuchungen() {
>
Kalender
</Button>
{canWrite && (
{canCreate && (
<Button
startIcon={<Add />}
onClick={openCreateDialog}
@@ -442,8 +446,8 @@ function FahrzeugBuchungen() {
}
sx={{
bgcolor: isFree ? 'success.50' : undefined,
cursor: isFree && canWrite ? 'pointer' : 'default',
'&:hover': isFree && canWrite
cursor: isFree && canCreate ? 'pointer' : 'default',
'&:hover': isFree && canCreate
? { bgcolor: 'success.100' }
: {},
p: 0.5,
@@ -534,7 +538,7 @@ function FahrzeugBuchungen() {
)}
{/* ── FAB ── */}
{canWrite && (
{canCreate && (
<Fab
color="primary"
aria-label="Buchung erstellen"
@@ -706,6 +710,7 @@ function FahrzeugBuchungen() {
<InputLabel>Buchungsart</InputLabel>
<Select
value={form.buchungsArt}
disabled={!canChangeBuchungsArt}
onChange={(e) =>
setForm((f) => ({
...f,