267 lines
13 KiB
TypeScript
267 lines
13 KiB
TypeScript
import { Head, Link } from '@inertiajs/react';
|
|
import {
|
|
ArrowRight,
|
|
CheckCheck,
|
|
ChevronDown,
|
|
ClipboardList,
|
|
Clock3,
|
|
Plus,
|
|
Wallet,
|
|
} from 'lucide-react';
|
|
import { useState } from 'react';
|
|
import { Button } from '@/components/ui/button';
|
|
import {
|
|
DropdownMenu,
|
|
DropdownMenuContent,
|
|
DropdownMenuItem,
|
|
DropdownMenuTrigger,
|
|
} from '@/components/ui/dropdown-menu';
|
|
|
|
const href = (screen: string) =>
|
|
screen.startsWith('?') ? `/consulta${screen}` : `/consulta/${screen}`;
|
|
const requests = [
|
|
{
|
|
number: 'REQ-DEMO-024',
|
|
description: 'Material de escritório',
|
|
department: 'Administração',
|
|
amount: '24 500,00 MT',
|
|
status: 'Em aprovação',
|
|
},
|
|
{
|
|
number: 'REQ-DEMO-023',
|
|
description: 'Peças para manutenção',
|
|
department: 'Produção',
|
|
amount: '86 200,00 MT',
|
|
status: 'Aprovada',
|
|
},
|
|
{
|
|
number: 'REQ-DEMO-022',
|
|
description: 'Consumíveis de limpeza',
|
|
department: 'Operações',
|
|
amount: '12 800,00 MT',
|
|
status: 'Rascunho',
|
|
},
|
|
];
|
|
|
|
export default function PrincipalProposal() {
|
|
const [filter, setFilter] = useState('Todos os estados');
|
|
const visible = requests.filter(
|
|
(request) => filter === 'Todos os estados' || request.status === filter,
|
|
);
|
|
return (
|
|
<>
|
|
<Head title="Proposta de ecrã principal" />
|
|
<div className="min-h-screen bg-slate-50 text-slate-900">
|
|
<div className="mx-auto flex max-w-7xl flex-col gap-7 px-5 py-8 lg:px-8 lg:py-10">
|
|
<section className="flex flex-wrap items-end justify-between gap-5">
|
|
<div>
|
|
<p className="text-xs font-semibold tracking-widest text-red-700 uppercase">
|
|
O seu espaço de trabalho
|
|
</p>
|
|
<h1 className="mt-2 text-3xl font-semibold tracking-tight">
|
|
As compras, numa só vista.
|
|
</h1>
|
|
<p className="mt-3 max-w-xl text-sm leading-6 text-slate-500">
|
|
Veja o que precisa da sua atenção e avance para
|
|
a próxima tarefa.
|
|
</p>
|
|
</div>
|
|
<Button
|
|
asChild
|
|
className="bg-[#ed1c24] text-white hover:bg-[#b91c1c]"
|
|
>
|
|
<Link href="/consulta/requisicoes">
|
|
<Plus className="size-4" />
|
|
Explorar requisições
|
|
</Link>
|
|
</Button>
|
|
</section>
|
|
<section
|
|
aria-label="Indicadores de demonstração"
|
|
className="grid gap-4 sm:grid-cols-2 xl:grid-cols-4"
|
|
>
|
|
{[
|
|
{
|
|
label: 'Requisições',
|
|
value: '24',
|
|
detail: 'Pedidos neste exemplo',
|
|
icon: ClipboardList,
|
|
},
|
|
{
|
|
label: 'Em aprovação',
|
|
value: '6',
|
|
detail: '2 aguardam a sua decisão',
|
|
icon: Clock3,
|
|
},
|
|
{
|
|
label: 'Aprovadas',
|
|
value: '15',
|
|
detail: 'Com circuito concluído',
|
|
icon: CheckCheck,
|
|
},
|
|
{
|
|
label: 'Valor aprovado',
|
|
value: '428 500 MT',
|
|
detail: 'Estimativa de demonstração, com IVA',
|
|
icon: Wallet,
|
|
},
|
|
].map((card) => (
|
|
<div
|
|
key={card.label}
|
|
className="rounded-2xl border border-slate-200 bg-white p-5 shadow-xs"
|
|
>
|
|
<div className="flex items-center justify-between text-sm text-slate-500">
|
|
{card.label}
|
|
<card.icon className="size-4 text-red-700" />
|
|
</div>
|
|
<p className="mt-5 text-3xl font-semibold tracking-tight">
|
|
{card.value}
|
|
</p>
|
|
<p className="mt-2 text-xs text-slate-500">
|
|
{card.detail}
|
|
</p>
|
|
</div>
|
|
))}
|
|
</section>
|
|
<div className="grid items-start gap-6 lg:grid-cols-[minmax(0,1fr)_320px]">
|
|
<section className="overflow-hidden rounded-2xl border border-slate-200 bg-white">
|
|
<div className="flex flex-wrap items-center justify-between gap-4 border-b border-slate-100 p-5">
|
|
<div>
|
|
<h2 className="font-semibold">
|
|
Requisições recentes
|
|
</h2>
|
|
<p className="mt-1 text-xs text-slate-400">
|
|
Exemplos para avaliar a organização do
|
|
ecrã
|
|
</p>
|
|
</div>
|
|
<DropdownMenu>
|
|
<DropdownMenuTrigger asChild>
|
|
<Button
|
|
variant="outline"
|
|
size="sm"
|
|
className="border-slate-200 bg-white text-slate-700"
|
|
>
|
|
{filter}
|
|
<ChevronDown className="size-4" />
|
|
</Button>
|
|
</DropdownMenuTrigger>
|
|
<DropdownMenuContent align="end">
|
|
{[
|
|
'Todos os estados',
|
|
'Em aprovação',
|
|
'Aprovada',
|
|
'Rascunho',
|
|
].map((status) => (
|
|
<DropdownMenuItem
|
|
key={status}
|
|
onSelect={() =>
|
|
setFilter(status)
|
|
}
|
|
>
|
|
{status}
|
|
{filter === status && (
|
|
<CheckCheck className="ml-auto size-4" />
|
|
)}
|
|
</DropdownMenuItem>
|
|
))}
|
|
</DropdownMenuContent>
|
|
</DropdownMenu>
|
|
</div>
|
|
<div className="divide-y divide-slate-100">
|
|
{visible.map((request) => (
|
|
<Link
|
|
key={request.number}
|
|
href="/consulta/requisicoes"
|
|
className="flex flex-wrap items-center justify-between gap-4 p-5 transition-colors hover:bg-slate-50"
|
|
>
|
|
<div>
|
|
<p className="text-xs font-medium text-red-700">
|
|
{request.number}
|
|
</p>
|
|
<p className="mt-1 text-sm font-medium">
|
|
{request.description}
|
|
</p>
|
|
<p className="mt-1 text-xs text-slate-400">
|
|
{request.department}
|
|
</p>
|
|
</div>
|
|
<div className="text-right">
|
|
<p className="text-sm font-semibold">
|
|
{request.amount}
|
|
</p>
|
|
<span
|
|
className={`mt-2 inline-flex rounded-full px-2.5 py-1 text-xs ${request.status === 'Aprovada' ? 'bg-red-50 text-[#ed1c24]' : request.status === 'Em aprovação' ? 'bg-amber-50 text-amber-800' : 'bg-slate-100 text-slate-600'}`}
|
|
>
|
|
{request.status}
|
|
</span>
|
|
</div>
|
|
</Link>
|
|
))}
|
|
</div>
|
|
<Link
|
|
href="/consulta/requisicoes"
|
|
className="flex items-center justify-center gap-2 border-t border-slate-100 p-4 text-sm font-medium text-[#ed1c24]"
|
|
>
|
|
Ver todas as requisições
|
|
<ArrowRight className="size-4" />
|
|
</Link>
|
|
</section>
|
|
<aside className="flex flex-col gap-5">
|
|
<section className="rounded-2xl border-t-4 border-[#ed1c24] bg-[#090909] p-6 text-white">
|
|
<span className="inline-flex rounded-xl bg-white/10 p-2.5">
|
|
<Clock3 className="size-5" />
|
|
</span>
|
|
<h2 className="mt-4 text-lg font-semibold">
|
|
A sua atenção faz a diferença
|
|
</h2>
|
|
<p className="mt-2 text-sm leading-6 text-slate-200">
|
|
Neste exemplo, 2 pedidos aguardam a sua
|
|
decisão. Consulte os detalhes antes de
|
|
aprovar.
|
|
</p>
|
|
<Button
|
|
asChild
|
|
className="mt-5 w-full bg-white text-[#b91c1c] hover:bg-red-50"
|
|
>
|
|
<Link href="/consulta/requisicoes">
|
|
Consultar pedidos
|
|
<ArrowRight className="size-4" />
|
|
</Link>
|
|
</Button>
|
|
</section>
|
|
<section className="rounded-2xl border border-slate-200 bg-white p-5">
|
|
<h2 className="font-semibold">
|
|
Acessos rápidos
|
|
</h2>
|
|
<div className="mt-3 space-y-1">
|
|
{[
|
|
['Conferir entregas', 'recepcoes'],
|
|
[
|
|
'Consultar reforços',
|
|
'?ecra=reinforcements',
|
|
],
|
|
[
|
|
'Encontrar fornecedor',
|
|
'fornecedores',
|
|
],
|
|
].map(([label, screen]) => (
|
|
<Link
|
|
key={screen}
|
|
href={href(screen)}
|
|
className="flex items-center justify-between rounded-lg py-3 text-sm text-slate-600 hover:bg-slate-50 hover:text-[#ed1c24]"
|
|
>
|
|
{label}
|
|
<ArrowRight className="size-4" />
|
|
</Link>
|
|
))}
|
|
</div>
|
|
</section>
|
|
</aside>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</>
|
|
);
|
|
}
|