201 lines
7.1 KiB
TypeScript
201 lines
7.1 KiB
TypeScript
import { Head, Link, useForm } from '@inertiajs/react';
|
|
import {
|
|
PageTitle,
|
|
Panel,
|
|
FormErrors,
|
|
controlClass,
|
|
} from '@/components/procurement';
|
|
import { Button } from '@/components/ui/button';
|
|
|
|
type Entry = {
|
|
id: number;
|
|
code: string;
|
|
name: string;
|
|
unit: string;
|
|
stock_basis: string;
|
|
version: number;
|
|
category: string;
|
|
purchase_type: string;
|
|
published: boolean;
|
|
source_current: boolean;
|
|
};
|
|
function EntryForm({ entry }: { entry: Entry }) {
|
|
const form = useForm({
|
|
version: entry.version,
|
|
stock_basis: entry.stock_basis,
|
|
category: entry.category,
|
|
purchase_type: entry.purchase_type,
|
|
published: entry.published,
|
|
reason: '',
|
|
});
|
|
return (
|
|
<form
|
|
className="space-y-3"
|
|
onSubmit={(event) => {
|
|
event.preventDefault();
|
|
form.post(`/stock/catalogo/${entry.id}`, {
|
|
preserveScroll: true,
|
|
});
|
|
}}
|
|
>
|
|
<FormErrors errors={form.errors} />
|
|
<label className="grid gap-1">
|
|
Categoria
|
|
<input
|
|
className={controlClass}
|
|
required
|
|
maxLength={100}
|
|
value={form.data.category}
|
|
onChange={(event) =>
|
|
form.setData('category', event.target.value)
|
|
}
|
|
/>
|
|
</label>
|
|
<label className="grid gap-1">
|
|
Tipo de compra
|
|
<select
|
|
className={controlClass}
|
|
value={form.data.purchase_type}
|
|
onChange={(event) =>
|
|
form.setData('purchase_type', event.target.value)
|
|
}
|
|
>
|
|
<option value="consumable">Insumos / matéria-prima</option>
|
|
<option value="other">Outro bem</option>
|
|
</select>
|
|
</label>
|
|
<label className="flex items-center gap-2">
|
|
<input
|
|
type="checkbox"
|
|
checked={form.data.published}
|
|
onChange={(event) =>
|
|
form.setData('published', event.target.checked)
|
|
}
|
|
/>
|
|
Disponível para seleccionar nas requisições da empresa
|
|
</label>
|
|
<label className="grid gap-1">
|
|
Motivo
|
|
<textarea
|
|
className={controlClass}
|
|
required
|
|
minLength={10}
|
|
maxLength={4000}
|
|
value={form.data.reason}
|
|
onChange={(event) =>
|
|
form.setData('reason', event.target.value)
|
|
}
|
|
/>
|
|
</label>
|
|
<Button disabled={form.processing}>
|
|
Guardar versão do catálogo
|
|
</Button>
|
|
</form>
|
|
);
|
|
}
|
|
export default function Catalogue({
|
|
records,
|
|
filters,
|
|
ready,
|
|
canManage,
|
|
}: {
|
|
records: {
|
|
data: Entry[];
|
|
total: number;
|
|
prev_page_url: string | null;
|
|
next_page_url: string | null;
|
|
};
|
|
filters: { search?: string };
|
|
ready: boolean;
|
|
canManage: boolean;
|
|
}) {
|
|
const search = useForm({ search: filters.search ?? '' });
|
|
return (
|
|
<>
|
|
<Head title="Catálogo para requisições" />
|
|
<div className="mx-auto max-w-5xl space-y-6 p-5 lg:p-8">
|
|
<PageTitle
|
|
eyebrow="Armazém e compras"
|
|
title="Catálogo para requisições"
|
|
description="Reutilize o cadastro de artigos. Publique apenas os bens que os solicitantes podem seleccionar, preservando os dados de cada pedido."
|
|
/>
|
|
<Link className="underline" href="/stock">
|
|
Cadastro e existências
|
|
</Link>
|
|
<Panel title="Pesquisar artigos">
|
|
<form
|
|
className="flex gap-3"
|
|
onSubmit={(event) => {
|
|
event.preventDefault();
|
|
search.get('/stock/catalogo', {
|
|
preserveState: true,
|
|
});
|
|
}}
|
|
>
|
|
<input
|
|
className={controlClass}
|
|
aria-label="Código ou nome"
|
|
maxLength={100}
|
|
value={search.data.search}
|
|
onChange={(event) =>
|
|
search.setData('search', event.target.value)
|
|
}
|
|
/>
|
|
<Button>Pesquisar</Button>
|
|
</form>
|
|
</Panel>
|
|
{!ready && (
|
|
<p>Instalação do catálogo pendente neste ambiente.</p>
|
|
)}
|
|
{records.data.map((entry) => (
|
|
<Panel
|
|
key={`${entry.id}-${entry.version}-${entry.stock_basis}`}
|
|
title={`${entry.code} · ${entry.name}`}
|
|
>
|
|
<p className="mb-3 text-sm">
|
|
Unidade: {entry.unit} · versão {entry.version} ·{' '}
|
|
{entry.published ? 'Publicado' : 'Não publicado'}
|
|
</p>
|
|
{!entry.source_current && (
|
|
<p className="mb-3 text-sm">
|
|
O cadastro mudou. Confira e guarde uma nova
|
|
versão antes de novas utilizações.
|
|
</p>
|
|
)}
|
|
{ready && canManage && <EntryForm entry={entry} />}
|
|
</Panel>
|
|
))}
|
|
{!records.total && (
|
|
<p>
|
|
Sem artigos neste âmbito. Registe o artigo no cadastro
|
|
de stock antes de o publicar.
|
|
</p>
|
|
)}
|
|
<div className="flex gap-4">
|
|
{records.prev_page_url && (
|
|
<Link
|
|
className="underline"
|
|
href={records.prev_page_url}
|
|
>
|
|
Anterior
|
|
</Link>
|
|
)}
|
|
{records.next_page_url && (
|
|
<Link
|
|
className="underline"
|
|
href={records.next_page_url}
|
|
>
|
|
Seguinte
|
|
</Link>
|
|
)}
|
|
</div>
|
|
<p className="text-sm">
|
|
A publicação não divulga saldos ou movimentos. Equipamentos
|
|
e sobressalentes mantêm o seu roteiro técnico; serviços
|
|
continuam no preenchimento próprio.
|
|
</p>
|
|
</div>
|
|
</>
|
|
);
|
|
}
|