Commit inicial - upload de todos os arquivos da pasta

This commit is contained in:
2026-06-13 17:32:41 -03:00
commit 759e2663ec
311 changed files with 31868 additions and 0 deletions

View File

@@ -0,0 +1,187 @@
import { DollarSign } from 'lucide-react';
import { ContractItemType } from '../../../types/contract-item.types';
import { DELIVERABLE_TYPE_LABELS, DeliverableType } from '../../../constants/deliverable-type';
import type { DeliverableDetail } from '../../../types/deliverable.types';
interface Props {
deliverable: DeliverableDetail;
}
function formatCurrency(value: number): string {
return value.toLocaleString('pt-BR', {
style: 'currency',
currency: 'BRL',
});
}
function formatNumber(value: number): string {
return value.toLocaleString('pt-BR', {
minimumFractionDigits: 0,
maximumFractionDigits: 2,
});
}
function resolveTimebox(deliverable: DeliverableDetail): {
value: number | null;
source: 'CONTRACT_ITEM' | 'DELIVERABLE' | null;
} {
if (deliverable.type === DeliverableType.MANUTENCAO) {
return { value: deliverable.timeboxManutencao ?? null, source: 'DELIVERABLE' };
}
const ci = deliverable.contractItem;
if (!ci) return { value: null, source: null };
switch (deliverable.type) {
case DeliverableType.DESCOBERTA:
return { value: ci.timeboxDescoberta, source: 'CONTRACT_ITEM' };
case DeliverableType.DESIGN:
return { value: ci.timeboxDesign, source: 'CONTRACT_ITEM' };
case DeliverableType.ARQUITETURA:
return { value: ci.timeboxArquitetura, source: 'CONTRACT_ITEM' };
case DeliverableType.CONSTRUCAO:
return { value: ci.timeboxConstrucao, source: 'CONTRACT_ITEM' };
default:
return { value: null, source: null };
}
}
export function EntregavelValuationCard({ deliverable }: Props) {
const ci = deliverable.contractItem;
const isSaas = ci?.itemType === ContractItemType.SAAS_LICENSE;
const { value: timebox, source } = resolveTimebox(deliverable);
const totalValueNumber = deliverable.totalValue != null ? Number(deliverable.totalValue) : null;
if (deliverable.type === DeliverableType.LICENCA) {
if (totalValueNumber == null || ci?.ustValue == null) {
return (
<ValuationWarning
title="Item de contrato sem valor da UST"
description="Configure o valor da UST no Item de Contrato vinculado para calcular o valor da licença."
/>
);
}
return (
<div className="rounded-lg border border-border bg-card p-5">
<div className="flex items-start gap-3">
<div className="flex h-10 w-10 items-center justify-center rounded-lg bg-isis-blue/10">
<DollarSign className="h-5 w-5 text-isis-blue" />
</div>
<div className="flex flex-1 flex-col gap-2">
<div>
<p className="text-[11px] font-medium uppercase tracking-wider text-text-muted">
Valor Total
</p>
<p className="text-2xl font-bold text-isis-blue">
{formatCurrency(totalValueNumber)}
</p>
</div>
<p className="text-small text-text-secondary">
1 licença × R$ {formatNumber(ci.ustValue)}/unidade
</p>
</div>
</div>
</div>
);
}
if (isSaas) {
return (
<div className="rounded-lg border border-border bg-card p-5">
<div className="flex items-center gap-3">
<div className="flex h-10 w-10 items-center justify-center rounded-lg bg-warning/10">
<DollarSign className="h-5 w-5 text-warning" />
</div>
<div className="flex flex-1 flex-col gap-1">
<p className="text-[11px] font-medium uppercase tracking-wider text-text-muted">
Valor Total
</p>
<p className="text-2xl font-bold text-warning">R$ 0,00</p>
<span className="mt-1 inline-flex w-fit rounded-md bg-warning/20 px-2 py-0.5 text-xs font-medium text-warning">
Licença SaaS faturamento via OS Mãe
</span>
</div>
</div>
</div>
);
}
if (deliverable.type === DeliverableType.MANUTENCAO && deliverable.timeboxManutencao == null) {
return (
<ValuationWarning
title="Time-box de manutenção não informado"
description="Informe o time-box no formulário de edição do Entregável para calcular o valor."
/>
);
}
if (deliverable.type !== DeliverableType.MANUTENCAO && timebox == null) {
return (
<ValuationWarning
title={`Item de contrato sem time-box configurado para o tipo ${DELIVERABLE_TYPE_LABELS[deliverable.type]}`}
description="Configure o time-box correspondente no Item de Contrato vinculado."
/>
);
}
if (totalValueNumber == null || timebox == null || ci?.ustValue == null) {
return (
<div className="rounded-lg border border-border bg-card p-5">
<div className="flex items-center gap-3">
<div className="flex h-10 w-10 items-center justify-center rounded-lg bg-isis-blue/10">
<DollarSign className="h-5 w-5 text-isis-blue" />
</div>
<div>
<p className="text-[11px] font-medium uppercase tracking-wider text-text-muted">
Valor Total
</p>
<p className="text-body text-text-muted">Não valorado</p>
</div>
</div>
</div>
);
}
return (
<div className="rounded-lg border border-border bg-card p-5">
<div className="flex items-start gap-3">
<div className="flex h-10 w-10 items-center justify-center rounded-lg bg-isis-blue/10">
<DollarSign className="h-5 w-5 text-isis-blue" />
</div>
<div className="flex flex-1 flex-col gap-2">
<div>
<p className="text-[11px] font-medium uppercase tracking-wider text-text-muted">
Valor Total
</p>
<p className="text-2xl font-bold text-isis-blue">{formatCurrency(totalValueNumber)}</p>
</div>
<p className="text-small text-text-secondary">
{formatNumber(timebox)}h × {deliverable.numWeeks} sem × R$ {formatNumber(ci.ustValue)}
/UST
</p>
<p className="text-xs text-text-muted">
Time-box{' '}
{source === 'DELIVERABLE'
? '(definido no Entregável)'
: '(definido no Item de Contrato)'}
</p>
</div>
</div>
</div>
);
}
function ValuationWarning({ title, description }: { title: string; description: string }) {
return (
<div className="rounded-lg border border-warning/30 bg-warning/10 p-5">
<div className="flex items-start gap-3">
<div className="flex h-10 w-10 items-center justify-center rounded-lg bg-warning/20">
<DollarSign className="h-5 w-5 text-warning" />
</div>
<div>
<p className="text-body font-medium text-warning">{title}</p>
<p className="mt-1 text-small text-text-secondary">{description}</p>
</div>
</div>
</div>
);
}