Initialize fresh project without Clerk

This commit is contained in:
2026-03-14 22:57:39 -03:00
commit 6898297935
401 changed files with 71631 additions and 0 deletions

View File

@@ -0,0 +1,174 @@
import React, { useRef, useLayoutEffect } from 'react';
import { format, min, max, isValid } from 'date-fns';
import type { Project, Inspection } from '../../types';
import '../../styles/reports.css';
interface GeneralProjectReportProps {
projects: Project[];
inspections?: Inspection[];
title: string;
logoUrl?: string;
}
const ProgressFill: React.FC<{ progress: number }> = ({ progress }) => {
const fillRef = useRef<HTMLDivElement>(null);
useLayoutEffect(() => {
if (fillRef.current) {
fillRef.current.style.setProperty('--progress', `${progress}%`);
}
}, [progress]);
return <div ref={fillRef} className="evol-fill" />;
};
export const GeneralProjectReport: React.FC<GeneralProjectReportProps> = ({ projects, inspections = [], title, logoUrl }) => {
// Cálculos globais
const totalWeight = projects.reduce((acc, p) => acc + (p.weightKg || 0), 0);
const calculateProjectProgress = (project: Project) => {
const projectInspections = inspections.filter(i => i.projectId === project.id);
const sumWeight = projectInspections.reduce((acc, curr) => acc + (curr.weightKg || 0), 0);
const totalW = project.weightKg || 0;
return totalW > 0 ? Math.min((sumWeight / totalW) * 100, 100) : 0;
};
const avgProgress = projects.length > 0
? projects.reduce((acc, p) => acc + calculateProjectProgress(p), 0) / projects.length
: 0;
// Período (Min/Max das datas)
const allDates = projects.flatMap(p => [
p.startDate ? new Date(p.startDate) : null,
p.endDate ? new Date(p.endDate) : null
]).filter((d): d is Date => d !== null && isValid(d));
const periodStart = allDates.length > 0 ? format(min(allDates), 'MM/yyyy') : '--/----';
const periodEnd = allDates.length > 0 ? format(max(allDates), 'MM/yyyy') : '--/----';
return (
<div className="report-container print:block hidden" id="general-project-report">
<header className="report-header">
<div className="brand">
{logoUrl ? (
<img src={logoUrl} alt="Logo" className="brand-logo" />
) : (
<div className="logo-placeholder"></div>
)}
</div>
<div className="text-center">
<div className="brand-title">{title.toUpperCase()}</div>
<div className="brand-subtitle">
Obras / Projetos Situação de produção e pintura
</div>
</div>
<div className="meta">
<div><strong>Data:</strong> {format(new Date(), 'dd/MM/yyyy')}</div>
<div><strong>Responsável:</strong> ________________</div>
</div>
</header>
<section className="summary">
<div className="summary-item">
<div className="summary-label">Total de obras</div>
<div className="summary-value">{projects.length}</div>
<div className="summary-sub">Listadas neste relatório</div>
</div>
<div className="summary-item">
<div className="summary-label">Peso total (kgf)</div>
<div className="summary-value">{totalWeight.toLocaleString('pt-BR')}</div>
<div className="summary-sub">Soma dos projetos</div>
</div>
<div className="summary-item">
<div className="summary-label">Evolução média</div>
<div className="summary-value">{avgProgress.toFixed(1).replace('.', ',')}%</div>
<div className="summary-sub">Estimativa geral</div>
</div>
<div className="summary-item">
<div className="summary-label">Período</div>
<div className="summary-value">{periodStart} {periodEnd}</div>
<div className="summary-sub">Previsão de execução</div>
</div>
</section>
<div className="section-title">
<h2>OBRAS / PROJETOS</h2>
<span>Visão geral por cronograma, peso e sistema de pintura</span>
</div>
<table className="table">
<thead>
<tr>
<th className="col-obra">Obra / Projeto</th>
<th className="col-evol">Evol.</th>
<th className="col-cron">Cronograma</th>
<th className="col-peso text-center">Peso (kgf)</th>
<th className="col-tinta">Tinta</th>
<th className="col-cor">Cor</th>
</tr>
</thead>
<tbody>
{projects.map((project) => {
const progress = calculateProjectProgress(project);
const schemes = project.paintingSchemes || [];
return (
<tr key={project.id}>
<td className="col-obra">
<div className="obra-nome">{project.name.toUpperCase()}</div>
<div className="obra-cliente">Cliente: {project.client}</div>
<div className="obra-cliente">Gestor: {project.technician || '--'}</div>
</td>
<td className="col-evol">
<div className="font-bold">{Math.round(progress)}%</div>
<div className="evol-bar">
<ProgressFill progress={progress} />
</div>
</td>
<td className="col-cron">
<div className="cron">
<strong>Início:</strong> {project.startDate ? format(new Date(project.startDate), 'dd/MM/yyyy') : '--/--/----'}<br />
<strong>Término:</strong> {project.endDate ? format(new Date(project.endDate), 'dd/MM/yyyy') : '--/--/----'}
</div>
</td>
<td className="col-peso text-center">
<div className="font-bold">
{(project.weightKg || 0).toLocaleString('pt-BR')}
<span className="block text-[7pt] text-gray-400 font-normal">Est. total</span>
</div>
</td>
<td className="col-tinta">
<div className="tinta">
{schemes.length > 0 ? schemes.slice(0, 2).map((s, idx) => (
<React.Fragment key={idx}>
<strong>{s.name.toUpperCase()}</strong>
{s.coat || s.type || 'Esquema'}{idx < schemes.length - 1 && <br />}
</React.Fragment>
)) : <span className="text-gray-400 italic">Sem esquema</span>}
</div>
</td>
<td className="col-cor">
<div className="text-[8pt] leading-tight">
{schemes.length > 0 ? schemes.slice(0, 2).map((s, idx) => (
<div key={idx}>{s.color || '-'}</div>
)) : '-'}
</div>
</td>
</tr>
);
})}
</tbody>
</table>
<footer className="report-footer">
<div className="system-title">
SteelPaint - Gestão de Pintura Industrial
</div>
<div>
Gerado em {format(new Date(), 'dd/MM/yyyy')} às {format(new Date(), 'HH:mm')}h
</div>
<div className="sig-group">
<div className="sig-line">Responsável Qualidade<span></span></div>
</div>
</footer>
</div>
);
};