feat: complete administration and reporting
This commit is contained in:
112
resources/js/pages/admin/reservation-policy.tsx
Normal file
112
resources/js/pages/admin/reservation-policy.tsx
Normal file
@@ -0,0 +1,112 @@
|
||||
import { Head, useForm } from '@inertiajs/react';
|
||||
import { Clock3, Save, ShieldCheck } from 'lucide-react';
|
||||
import type { FormEvent } from 'react';
|
||||
import InputError from '@/components/input-error';
|
||||
import { PageHeading } from '@/components/page-heading';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { Input } from '@/components/ui/input';
|
||||
|
||||
type Definition = {
|
||||
label: string;
|
||||
description: string;
|
||||
default: number;
|
||||
min: number;
|
||||
max: number;
|
||||
unit: string;
|
||||
};
|
||||
|
||||
export default function ReservationPolicyPage({
|
||||
definitions,
|
||||
values,
|
||||
}: {
|
||||
definitions: Record<string, Definition>;
|
||||
values: Record<string, number>;
|
||||
}) {
|
||||
const form = useForm(values);
|
||||
|
||||
function submit(event: FormEvent) {
|
||||
event.preventDefault();
|
||||
form.put('/administracao/regras', { preserveScroll: true });
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Head title="Regras de reserva" />
|
||||
<main className="mx-auto flex w-full max-w-5xl flex-1 flex-col gap-7 p-5 sm:p-8">
|
||||
<PageHeading
|
||||
eyebrow="Administração"
|
||||
title="Regras de reserva"
|
||||
description="Parâmetros aplicados centralmente a novos pedidos, conflitos temporais e prazos de aprovação."
|
||||
/>
|
||||
|
||||
<div className="flex gap-3 rounded-xl border border-sky-200 bg-sky-50 p-4 text-sm text-sky-900 dark:bg-sky-950/30 dark:text-sky-100">
|
||||
<ShieldCheck className="mt-0.5 size-5 shrink-0" />
|
||||
<p>
|
||||
As margens já gravadas permanecem associadas às reservas
|
||||
existentes. Alterações entram em vigor imediatamente
|
||||
para novas requisições.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<form onSubmit={submit} className="space-y-5">
|
||||
<div className="grid gap-4 md:grid-cols-2">
|
||||
{Object.entries(definitions).map(
|
||||
([key, definition]) => (
|
||||
<Card key={key} className="gap-4 shadow-none">
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2 text-base">
|
||||
<Clock3 className="size-4 text-primary" />
|
||||
{definition.label}
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-3">
|
||||
<p className="min-h-10 text-sm text-muted-foreground">
|
||||
{definition.description}
|
||||
</p>
|
||||
<div className="flex items-center gap-3">
|
||||
<Input
|
||||
type="number"
|
||||
min={definition.min}
|
||||
max={definition.max}
|
||||
value={form.data[key]}
|
||||
onChange={(event) =>
|
||||
form.setData(
|
||||
key,
|
||||
Number(
|
||||
event.target.value,
|
||||
),
|
||||
)
|
||||
}
|
||||
/>
|
||||
<span className="min-w-24 text-sm text-muted-foreground">
|
||||
{definition.unit}
|
||||
</span>
|
||||
</div>
|
||||
<InputError
|
||||
message={form.errors[key]}
|
||||
/>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
Intervalo permitido:{' '}
|
||||
{definition.min}–{definition.max}
|
||||
</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
),
|
||||
)}
|
||||
</div>
|
||||
<Button type="submit" disabled={form.processing}>
|
||||
<Save /> Guardar e aplicar regras
|
||||
</Button>
|
||||
</form>
|
||||
</main>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
ReservationPolicyPage.layout = {
|
||||
breadcrumbs: [
|
||||
{ title: 'Administração', href: '/administracao/regras' },
|
||||
{ title: 'Regras de reserva', href: '/administracao/regras' },
|
||||
],
|
||||
};
|
||||
Reference in New Issue
Block a user