Files
compras/resources/js/pages/preview/inventory-demo.tsx
T

345 lines
16 KiB
TypeScript

import { useState } from 'react';
import { InventoryNotice, ReceiptProgressTable } from '@/components/inventory';
import { Panel, controlClass } from '@/components/procurement';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
} from '@/components/ui/dialog';
import { quantity } from '@/types/inventory';
import type { ReceiptProgress } from '@/types/inventory';
const progress: ReceiptProgress = {
state: 'partial',
has_divergences: true,
lines: [
{
id: 1,
description: 'Papel A4 de demonstração',
unit: 'cx',
purchase_type: 'consumable',
ordered_milli: 10000,
received_milli: 6000,
accepted_milli: 5000,
rejected_milli: 1000,
delivery_pending_milli: 4000,
acceptance_pending_milli: 5000,
},
{
id: 2,
description: 'Tinteiro de demonstração',
unit: 'un',
purchase_type: 'consumable',
ordered_milli: 3000,
received_milli: 3000,
accepted_milli: 3000,
rejected_milli: 0,
delivery_pending_milli: 0,
acceptance_pending_milli: 0,
},
],
};
const examples = [
{
code: 'DEMO-A4',
name: 'Papel A4 de demonstração',
unit: 'cx',
quantity_milli: 5000,
warehouse: 'Armazém de demonstração',
receipt: 'REC-DEMO-001',
note: 'Uma caixa rejeitada por danos; só cinco caixas aceites entraram em stock.',
},
{
code: 'DEMO-TINTA',
name: 'Tinteiro de demonstração',
unit: 'un',
quantity_milli: 3000,
warehouse: 'Armazém de demonstração',
receipt: 'REC-DEMO-001',
note: 'Três unidades recebidas e aceites integralmente.',
},
];
export default function InventoryDemo({
screen,
}: {
screen: 'receipts' | 'stock';
}) {
const [search, setSearch] = useState('');
const [detail, setDetail] = useState<(typeof examples)[number] | null>(
null,
);
const [quality, setQuality] = useState('reservations');
const [notice, setNotice] = useState(false);
const visible = examples.filter((example) =>
`${example.code} ${example.name}`
.toLowerCase()
.includes(search.toLowerCase()),
);
return (
<>
<InventoryNotice />
{screen === 'receipts' ? (
<>
<Panel
title="OC-DEMO-001 · Recepção parcial"
description="Exemplo fictício: seis caixas conferidas, cinco aceites e uma rejeitada. Existem quatro caixas por entregar."
>
<ReceiptProgressTable progress={progress} />
<p className="mt-4 text-sm text-muted-foreground">
Emitente: Comprador de exemplo · Recepção: Armazém
de exemplo. São pessoas distintas.
</p>
</Panel>
<Panel
title="Conferência de qualidade"
description="Experimente os campos. Este formulário é local, não é enviado e não confirma recepções reais."
>
<form
className="space-y-4"
onSubmit={(event) => {
event.preventDefault();
setNotice(true);
}}
>
<div className="grid gap-4 md:grid-cols-3">
<div className="space-y-2">
<Label htmlFor="demo-guide">
Guia fictícia
</Label>
<Input
id="demo-guide"
defaultValue="GR-DEMO-001"
/>
</div>
<div className="space-y-2">
<Label htmlFor="demo-received">
Quantidade recebida
</Label>
<Input
id="demo-received"
type="number"
min="0.001"
step="0.001"
defaultValue="6"
/>
</div>
<div className="space-y-2">
<Label htmlFor="demo-quality">
Qualidade
</Label>
<select
id="demo-quality"
className={controlClass}
value={quality}
onChange={(event) =>
setQuality(event.target.value)
}
>
<option value="compliant">
Conforme
</option>
<option value="reservations">
Conforme com reservas
</option>
<option value="nonconforming">
Não conforme
</option>
</select>
</div>
<div className="space-y-2">
<Label htmlFor="demo-accepted">
Quantidade aceite
</Label>
<Input
id="demo-accepted"
type="number"
min="0"
step="0.001"
defaultValue="5"
/>
</div>
<div className="space-y-2">
<Label htmlFor="demo-location">
Destino fictício
</Label>
<select
id="demo-location"
className={controlClass}
>
<option>Armazém de demonstração</option>
</select>
</div>
<div className="space-y-2">
<Label htmlFor="demo-article">
Artigo fictício
</Label>
<select
id="demo-article"
className={controlClass}
>
<option>
DEMO-A4 · Papel A4 de demonstração
</option>
</select>
</div>
</div>
<div className="space-y-2">
<Label htmlFor="demo-divergence">
Divergências
</Label>
<textarea
id="demo-divergence"
className={`${controlClass} h-24 py-3`}
defaultValue="Uma caixa com danos na embalagem e humidade. Rejeitada e sem entrada em stock."
/>
</div>
<Button>Pré-visualizar conferência fictícia</Button>
{notice && (
<p
role="status"
className="text-sm text-teal-700 dark:text-teal-400"
>
Demonstração local: nenhum dado foi
guardado. No módulo autenticado, o servidor
verifica quantidades, segregação e
duplicações.
</p>
)}
</form>
</Panel>
</>
) : (
<>
<Panel
title="Existências fictícias"
description="Somente quantidades aceites. Pesquise e abra os detalhes para rever a apresentação."
>
<Input
aria-label="Pesquisar artigos fictícios"
placeholder="Pesquisar código ou artigo de demonstração"
value={search}
onChange={(event) => setSearch(event.target.value)}
className="mb-5 max-w-sm"
/>
<div className="overflow-x-auto">
<table className="w-full text-left text-sm">
<thead className="border-b text-muted-foreground">
<tr>
<th className="pr-4 pb-3">Artigo</th>
<th className="pr-4">Armazém</th>
<th className="pr-4">Em stock</th>
<th>Histórico</th>
</tr>
</thead>
<tbody>
{visible.map((example) => (
<tr
className="border-b last:border-0"
key={example.code}
>
<td className="py-4 pr-4">
<strong>{example.code}</strong>
<p className="mt-1 text-muted-foreground">
{example.name}
</p>
</td>
<td className="pr-4">
{example.warehouse}
</td>
<td className="pr-4">
{quantity(
example.quantity_milli,
)}{' '}
{example.unit}
</td>
<td>
<Button
variant="outline"
onClick={() =>
setDetail(example)
}
>
Ver movimentos
</Button>
</td>
</tr>
))}
</tbody>
</table>
</div>
{visible.length === 0 && (
<p className="py-5 text-sm text-muted-foreground">
Nenhum exemplo corresponde à pesquisa.
</p>
)}
</Panel>
<Panel title="Histórico de entradas fictícias">
<div className="space-y-3">
{visible.map((example) => (
<button
type="button"
onClick={() => setDetail(example)}
key={example.code}
className="w-full rounded-lg border p-4 text-left text-sm"
>
<strong>
+{quantity(example.quantity_milli)}{' '}
{example.unit} · {example.code}
</strong>
<p className="mt-1 text-muted-foreground">
{example.receipt} · OC-DEMO-001 · Guia
GR-DEMO-001
</p>
</button>
))}
</div>
<p className="mt-4 text-xs text-muted-foreground">
Os exemplos não correspondem a existências da
empresa. Consulte Saídas e inventários para rever os
novos exemplos fictícios.
</p>
</Panel>
</>
)}
<Dialog
open={detail !== null}
onOpenChange={(open) => {
if (!open) setDetail(null);
}}
>
<DialogContent>
<DialogHeader>
<DialogTitle>
{detail?.code} · Entrada fictícia
</DialogTitle>
<DialogDescription>
Histórico ilustrativo, sem acesso aos registos
reais.
</DialogDescription>
</DialogHeader>
{detail && (
<div className="space-y-3 text-sm">
<p>
{detail.name} · +
{quantity(detail.quantity_milli)} {detail.unit}
</p>
<p>{detail.receipt} · OC-DEMO-001 · GR-DEMO-001</p>
<p>{detail.note}</p>
<p>
Confirmado por Armazém de exemplo, distinto do
emitente.
</p>
</div>
)}
</DialogContent>
</Dialog>
</>
);
}