feat: Quickstart, Benutzerverwaltung und Orion-Ergebnisbox
This commit is contained in:
parent
4f669a3426
commit
e9e46f2cb4
404 changed files with 1032 additions and 600 deletions
|
|
@ -6,6 +6,7 @@ import Link from "next/link";
|
|||
import { useAuth } from "@/components/auth";
|
||||
import { apiGet } from "@/lib/api";
|
||||
import { BrandLogo } from "@/components/brand/brand-logo";
|
||||
import { ValidationResultBadge } from "@/lib/validation-result";
|
||||
|
||||
type DashboardData = {
|
||||
customers: number;
|
||||
|
|
@ -18,6 +19,10 @@ type DashboardData = {
|
|||
validation_approved: number;
|
||||
validation_completed: number;
|
||||
validation_overdue: number;
|
||||
validation_result_open: number;
|
||||
validation_result_passed: number;
|
||||
validation_result_conditional: number;
|
||||
validation_result_failed: number;
|
||||
equipment_green: number;
|
||||
equipment_yellow: number;
|
||||
equipment_red: number;
|
||||
|
|
@ -105,6 +110,16 @@ export default function DashboardPage() {
|
|||
<Link href="/validations?status=ABGESCHLOSSEN" className="rounded-lg border border-border bg-surface p-6 shadow-soft transition hover:border-primary/40 hover:bg-background">
|
||||
<h2 className="text-xl font-semibold">Letzte Berichte</h2>
|
||||
<p className="mt-4 text-3xl font-semibold text-text">{query.data?.validation_completed ?? 0}</p>
|
||||
<div className="mt-4 flex flex-wrap gap-2">
|
||||
<ValidationResultBadge value="BESTANDEN" className="text-[11px]" />
|
||||
<span className="text-sm font-semibold text-text">{query.data?.validation_result_passed ?? 0}</span>
|
||||
<ValidationResultBadge value="BESTANDEN_MIT_AUFLAGEN" className="text-[11px]" />
|
||||
<span className="text-sm font-semibold text-text">{query.data?.validation_result_conditional ?? 0}</span>
|
||||
<ValidationResultBadge value="NICHT_BESTANDEN" className="text-[11px]" />
|
||||
<span className="text-sm font-semibold text-text">{query.data?.validation_result_failed ?? 0}</span>
|
||||
<ValidationResultBadge value="OFFEN" className="text-[11px]" />
|
||||
<span className="text-sm font-semibold text-text">{query.data?.validation_result_open ?? 0}</span>
|
||||
</div>
|
||||
</Link>
|
||||
</section>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import Link from "next/link";
|
|||
import { useEffect, useMemo, useState } from "react";
|
||||
import { useAuth } from "@/components/auth";
|
||||
import { API_BASE, apiDelete, apiGet, apiSend, Customer, Device, Paginated, ValidationItem } from "@/lib/api";
|
||||
import { ValidationResultBadge, validationResultValues, getValidationResultPresentation } from "@/lib/validation-result";
|
||||
|
||||
const statusLabels: Record<string, string> = {
|
||||
ENTWURF: "Entwurf",
|
||||
|
|
@ -94,7 +95,7 @@ export default function ValidationsPage() {
|
|||
{ accessorKey: "performed_on", header: "Pruefdatum" },
|
||||
{ accessorKey: "next_validation_on", header: "Naechste Validierung" },
|
||||
{ accessorKey: "examiner_name", header: "Pruefer" },
|
||||
{ accessorKey: "result", header: "Ergebnis" },
|
||||
{ accessorKey: "result", header: "Ergebnis", cell: ({ row }) => <ValidationResultBadge value={row.original.result} /> },
|
||||
{ accessorKey: "updated_at", header: "Zuletzt geaendert" },
|
||||
{ accessorKey: "status", header: "Status", cell: ({ row }) => <span className={`rounded-full px-3 py-1 text-xs font-semibold ${statusClass[row.original.status] ?? statusClass.ENTWURF}`}>{statusLabels[row.original.status] ?? row.original.status}</span> },
|
||||
{ id: "actions", header: "Aktionen", enableSorting: false, cell: ({ row }) => {
|
||||
|
|
@ -128,7 +129,7 @@ export default function ValidationsPage() {
|
|||
<select value={validationType} onChange={(event) => setValidationType(event.target.value)} className="h-12 rounded-lg border border-border px-3"><option value="">Alle Arten</option><option>Erstvalidierung</option><option>Revalidierung</option><option>Leistungsbeurteilung</option><option>Sonderpruefung</option></select>
|
||||
<select value={customerId} onChange={(event) => setCustomerId(event.target.value)} className="h-12 rounded-lg border border-border px-3"><option value="">Alle Kunden</option>{(customers.data?.items ?? []).map((item) => <option key={item.id} value={item.id}>{item.name}</option>)}</select>
|
||||
<select value={deviceId} onChange={(event) => setDeviceId(event.target.value)} className="h-12 rounded-lg border border-border px-3"><option value="">Alle Geraete</option>{(devices.data?.items ?? []).map((item) => <option key={item.id} value={item.id}>{item.manufacturer} {item.model}</option>)}</select>
|
||||
<select value={result} onChange={(event) => setResult(event.target.value)} className="h-12 rounded-lg border border-border px-3"><option value="">Alle Ergebnisse</option><option value="offen">Offen</option><option value="bestanden">Bestanden</option><option value="nicht_bestanden">Nicht bestanden</option><option value="mit_auflagen">Mit Auflagen</option></select>
|
||||
<select value={result} onChange={(event) => setResult(event.target.value)} className="h-12 rounded-lg border border-border px-3"><option value="">Alle Ergebnisse</option>{validationResultValues.map((value) => <option key={value} value={value}>{getValidationResultPresentation(value).label}</option>)}</select>
|
||||
<input type="date" value={dateFrom} onChange={(event) => setDateFrom(event.target.value)} className="h-12 rounded-lg border border-border px-3" />
|
||||
<input type="date" value={dateTo} onChange={(event) => setDateTo(event.target.value)} className="h-12 rounded-lg border border-border px-3" />
|
||||
<label className="flex h-12 items-center gap-3 rounded-lg border border-border px-3"><input type="checkbox" checked={overdueOnly} onChange={(event) => setOverdueOnly(event.target.checked)} /> ueberfaellige Revalidierungen</label>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue