Files
compras/resources/js/pages/requisitions/index.tsx
T
nala 413c201d97
tests / ci (push) Canceled after 0s
commit5
2026-10-29 22:03:09 +02:00

160 lines
6.6 KiB
TypeScript

import { Head, Link, useForm } from '@inertiajs/react';
import { Plus, Search } from 'lucide-react';
import {
PageTitle,
Panel,
RequisitionTable,
controlClass,
} from '@/components/procurement';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { statusLabels } from '@/types/procurement';
import type { Requisition } from '@/types/procurement';
type Props = {
requisitions: {
data: Requisition[];
current_page: number;
last_page: number;
prev_page_url: string | null;
next_page_url: string | null;
total: number;
};
filters: { search?: string; status?: string; view?: string };
};
export default function Index({ requisitions, filters }: Props) {
const form = useForm({
search: filters.search ?? '',
status: filters.status ?? '',
view: filters.view ?? 'all',
});
const views: Record<string, { title: string; description: string }> = {
all: {
title: 'Requisições autorizadas',
description:
'Consulte os pedidos disponíveis para o seu perfil e acompanhe o estado de cada processo.',
},
mine: {
title:
filters.status === 'draft'
? 'Os meus rascunhos'
: 'Minhas requisições',
description:
'Pedidos criados por si, desde o rascunho até à decisão.',
},
approvals: {
title: 'Pendentes para mim',
description:
'Pedidos em que a próxima etapa pode ser decidida por si. A elegibilidade é conferida pelo servidor.',
},
decided: {
title: 'Minhas decisões',
description:
'Histórico dos pedidos em que registou uma aprovação ou rejeição.',
},
};
const view = views[filters.view ?? 'all'] ?? views.all;
return (
<>
<Head title={view.title} />
<div className="mx-auto flex w-full max-w-7xl flex-col gap-7 p-5 lg:p-8">
<PageTitle
eyebrow="Compras"
title={view.title}
description={view.description}
action={
<Button asChild>
<Link href="/requisicoes/criar">
<Plus className="size-4" />
Nova requisição
</Link>
</Button>
}
/>
<Panel title="Pedidos de compra">
<form
className="mb-6 flex flex-wrap gap-3"
onSubmit={(e) => {
e.preventDefault();
form.get('/requisicoes', { preserveState: true });
}}
>
<select
className={`${controlClass} max-w-60`}
aria-label="Conjunto de pedidos"
value={form.data.view}
onChange={(e) =>
form.setData('view', e.target.value)
}
>
<option value="all">Todas as autorizadas</option>
<option value="mine">Minhas requisições</option>
<option value="approvals">
Pendentes para mim
</option>
<option value="decided">Minhas decisões</option>
</select>
<Input
className="max-w-xs"
aria-label="Pesquisar pela referência"
placeholder="Pesquisar referência…"
value={form.data.search}
onChange={(e) =>
form.setData('search', e.target.value)
}
/>
<select
className={`${controlClass} max-w-48`}
aria-label="Filtrar por estado"
value={form.data.status}
onChange={(e) =>
form.setData('status', e.target.value)
}
>
<option value="">Todos os estados</option>
{Object.entries(statusLabels).map(
([key, label]) => (
<option key={key} value={key}>
{label}
</option>
),
)}
</select>
<Button variant="outline" disabled={form.processing}>
<Search className="size-4" />
Filtrar
</Button>
</form>
<RequisitionTable rows={requisitions.data} />
<div className="mt-5 flex flex-wrap items-center justify-between gap-3 border-t pt-4 text-sm text-muted-foreground">
<p>
{requisitions.total} pedidos · Página{' '}
{requisitions.current_page} de{' '}
{requisitions.last_page}
</p>
<div className="flex gap-2">
{requisitions.prev_page_url && (
<Button asChild variant="outline" size="sm">
<Link href={requisitions.prev_page_url}>
Anterior
</Link>
</Button>
)}
{requisitions.next_page_url && (
<Button asChild variant="outline" size="sm">
<Link href={requisitions.next_page_url}>
Seguinte
</Link>
</Button>
)}
</div>
</div>
</Panel>
</div>
</>
);
}
Index.layout = {
breadcrumbs: [{ title: 'Requisições', href: '/requisicoes' }],
};