Files
compras/resources/js/lib/procurement-navigation.ts
T
nala 413c201d97
tests / ci (push) Canceled after 0s
commit5
2026-10-29 22:03:09 +02:00

268 lines
8.3 KiB
TypeScript

import {
BadgeCheck,
ClipboardList,
Scale,
ShieldCheck,
Users,
Wallet,
Warehouse,
} from 'lucide-react';
import type { LucideIcon } from 'lucide-react';
export type ProcurementEntry = {
id: string;
label: string;
path: string;
roles?: string[];
fullPage?: boolean;
};
export type ProcurementGroup = {
id: string;
label: string;
icon: LucideIcon;
entries: ProcurementEntry[];
};
const readers = ['admin', 'procurement', 'finance', 'department_head'];
const finance = ['admin', 'finance'];
const inventory = [...readers, 'warehouse'];
export function procurementNavigation(
role: string,
payables: boolean,
): ProcurementGroup[] {
const groups: ProcurementGroup[] = [
{
id: 'requests',
label: 'Requisições',
icon: ClipboardList,
entries: [
{
id: 'new_request',
label: 'Nova requisição',
path: '/requisicoes/criar',
},
{
id: 'my_requests',
label: 'Minhas requisições',
path: '/requisicoes?view=mine',
},
{
id: 'my_drafts',
label: 'Os meus rascunhos',
path: '/requisicoes?view=mine&status=draft',
},
{
id: 'all_requests',
label: 'Todas as autorizadas',
path: '/requisicoes?view=all',
},
{ id: 'planning', label: 'Planeamento', path: '/planeamento' },
],
},
{
id: 'approvals',
label: 'Aprovações',
icon: BadgeCheck,
entries: [
{
id: 'pending_approvals',
label: 'Pendentes para mim',
path: '/requisicoes?view=approvals',
roles: readers,
},
{
id: 'decisions',
label: 'Minhas decisões',
path: '/requisicoes?view=decided',
roles: readers,
},
],
},
{
id: 'sourcing',
label: 'Consultas e adjudicações',
icon: Scale,
entries: [
{
id: 'quotations',
label: 'Cotações e comparação',
path: '/cotacoes',
roles: readers,
},
{
id: 'orders',
label: 'Adjudicações e ordens',
path: '/ordens',
roles: readers,
},
{
id: 'purchase_review',
label: 'Revisão e cancelamento',
path: '/revisao-compras',
},
],
},
{
id: 'suppliers',
label: 'Fornecedores',
icon: Users,
entries: [
{
id: 'suppliers',
label: 'Cadastro e documentos',
path: '/fornecedores',
roles: readers,
},
],
},
{
id: 'receiving',
label: 'Recepções e armazém',
icon: Warehouse,
entries: [
{
id: 'receipts',
label: 'Recepções e divergências',
path: '/recepcoes',
roles: inventory,
},
{
id: 'stock',
label: 'Artigos e stock',
path: '/stock',
roles: ['admin', 'procurement', 'finance', 'warehouse'],
},
{
id: 'stock_operations',
label: 'Saídas e inventários',
path: '/stock/operacoes',
roles: ['admin', 'procurement', 'finance', 'warehouse'],
},
{
id: 'equipment',
label: 'Equipamentos e peças',
path: '/equipamentos',
roles: inventory,
},
],
},
{
id: 'finance',
label: 'Finanças',
icon: Wallet,
entries: [
{
id: 'invoices',
label: 'Facturas e conferência',
path: '/facturas',
roles: finance,
},
...(payables
? [
{
id: 'payables',
label: 'Obrigações a fornecedores',
path: '/obrigacoes-fornecedores',
roles: finance,
fullPage: true,
},
]
: []),
{
id: 'payments',
label: 'Pagamentos externos',
path: '/pagamentos',
roles: finance,
},
{
id: 'budgets',
label: 'Orçamentos e reforços',
path: '/orcamentos',
roles: finance,
},
{
id: 'investment',
label: 'Regras de investimento',
path: '/regras-investimento',
roles: ['admin', 'procurement', 'finance'],
},
],
},
{
id: 'administration',
label: 'Administração e controlo',
icon: ShieldCheck,
entries: [
{
id: 'company',
label: 'Empresa, equipa e centros',
path: '/empresa',
roles: ['admin'],
},
{
id: 'admission_policy',
label: 'Política de admissão',
path: '/politica-admissao',
roles: ['admin'],
},
{
id: 'recommendation_policy',
label: 'Política de recomendação',
path: '/politica-recomendacao',
roles: ['admin'],
},
{
id: 'conflicts',
label: 'Conflitos de interesses',
path: '/conflitos',
},
],
},
];
return groups
.map((group) => ({
...group,
entries: group.entries.filter(
(entry) => !entry.roles || entry.roles.includes(role),
),
}))
.filter((group) => group.entries.length);
}
export function activeProcurementEntry(
groups: ProcurementGroup[],
url: string,
): string | undefined {
const current = new URL(url, 'http://local');
if (/^\/ordens\/\d+\/recepcoes/.test(current.pathname)) return 'receipts';
if (/^\/requisicoes\/\d+\/adjudicacao(?:\/|$)/.test(current.pathname))
return 'orders';
if (
/^\/requisicoes\/\d+\/(cotacoes|abertura|qualificacao|admissao|recomendacao|relatorio)(?:\/|$)/.test(
current.pathname,
)
)
return 'quotations';
const matches = groups
.flatMap((group) => group.entries)
.filter((entry) => {
const target = new URL(entry.path, 'http://local');
if (
current.pathname !== target.pathname &&
!current.pathname.startsWith(target.pathname + '/')
)
return false;
return [...target.searchParams].every(
([key, value]) =>
(current.searchParams.get(key) ??
(key === 'view' ? 'all' : null)) === value,
);
});
const specificity = (path: string) => {
const target = new URL(path, 'http://local');
return target.pathname.length * 100 + target.searchParams.size;
};
matches.sort((a, b) => specificity(b.path) - specificity(a.path));
return matches[0]?.id;
}