Files
tracksteel_app/src/pages/CadastroOF.tsx
T

850 lines
35 KiB
TypeScript

import React, { useState, useEffect } from 'react';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Button } from '@/components/ui/button';
import { Textarea } from '@/components/ui/textarea';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { Checkbox } from '@/components/ui/checkbox';
import { toast } from 'sonner';
import { Save, FileText, User, MapPin, Settings2, Eye, Download, Search, Building2 } from 'lucide-react';
import { useSearchParams } from 'react-router-dom';
import { AlteracoesPopup } from '@/components/forms/AlteracoesPopup';
import { FichaTecnicaPreview } from '@/components/forms/FichaTecnicaPreview';
import { useThemeConfig } from '@/hooks/useThemeConfig';
import { useFichaTecnica, FichaTecnicaData } from '@/hooks/useFichaTecnica';
import { useUserManagement } from '@/hooks/useUserManagement';
interface InfoCalculoEstrutural {
e: boolean;
c: boolean;
na: boolean;
info: string;
}
interface FormData extends FichaTecnicaData {
data_inicio: string;
data_termino_prev: string;
status: string;
prioridade: string;
}
const initialFormData: FormData = {
of_number: '',
gestor: '',
projetista: '',
revisao: '0',
quantidade: 0,
data_inicio: '',
data_termino_prev: '',
status: 'aberta',
prioridade: 'media',
// Dados do Cliente
cliente: '',
cnpj: '',
ie: '',
endereco: '',
cidade: '',
estado: '',
cep: '',
contato_contrato: '',
fone_contrato: '',
cel_contrato: '',
email_contrato: '',
contato_obra: '',
fone_obra: '',
cel_obra: '',
email_obra: '',
contato_qualid: '',
fone_qualid: '',
cel_qualid: '',
email_qualid: '',
// Dados da Obra
eng_responsavel: '',
telefone_obra: '',
email_obra_responsavel: '',
endereco_obra: '',
cep_obra: '',
bairro_obra: '',
cidade_obra: '',
estado_obra: '',
observacoes_obra: '',
// Dados do Projeto
descricao_resumida: '',
endereco_projeto: '',
bairro_projeto: '',
cep_projeto: '',
cidade_projeto: '',
estado_projeto: '',
horarios_trabalho: '',
condicoes_acesso: '',
// Tipos de Projeto
tipo_estrutural: false,
tipo_residencial: false,
tipo_espacial: false,
tipo_comercial: false,
tipo_grades: false,
tipo_industrial: false,
tipo_cobertura: false,
tipo_com_montagem: false,
// Documentos Fornecidos
doc_calculo: false,
doc_projeto: false,
doc_detalhamento: false,
doc_cronograma: false,
doc_normas: false,
doc_especif_tecnicas: false,
doc_catalogo: false,
doc_fotos: false,
// Informações Técnicas
info_calculo_estrutural: { e: false, c: false, na: false, info: '' },
info_projeto_basico: { e: false, c: false, na: false, info: '' },
info_detalhamento: { e: false, c: false, na: false, info: '' },
info_materia_prima: { e: false, c: false, na: false, info: '' },
info_fabricacao: { e: false, c: false, na: false, info: '' },
info_grades_piso: { e: false, c: false, na: false, info: '' },
info_jateamento: { e: false, c: false, na: false, info: '' },
info_pintura_base: { e: false, c: false, na: false, info: '' },
info_pintura_inter: { e: false, c: false, na: false, info: '' },
info_pintura_acabamento: { e: false, c: false, na: false, info: '' },
info_galvanizacao: { e: false, c: false, na: false, info: '' },
info_embalagem: { e: false, c: false, na: false, info: '' },
info_transporte: { e: false, c: false, na: false, info: '' },
info_inspecao: { e: false, c: false, na: false, info: '' },
info_ensaios_lab: { e: false, c: false, na: false, info: '' },
info_databook: { e: false, c: false, na: false, info: '' },
info_pre_montagem: { e: false, c: false, na: false, info: '' },
info_placa_engenetal: { e: false, c: false, na: false, info: '' },
info_parafusos: { e: false, c: false, na: false, info: '' },
info_chumbadores: { e: false, c: false, na: false, info: '' },
info_stud_bolt: { e: false, c: false, na: false, info: '' },
info_fornec_telhas: { e: false, c: false, na: false, info: '' },
info_montagem_telhas: { e: false, c: false, na: false, info: '' },
info_forn_calhas: { e: false, c: false, na: false, info: '' },
info_mont_calhas: { e: false, c: false, na: false, info: '' },
info_steel_deck: { e: false, c: false, na: false, info: '' },
info_fornec_wall: { e: false, c: false, na: false, info: '' },
info_mont_wall: { e: false, c: false, na: false, info: '' },
info_outros_materiais: { e: false, c: false, na: false, info: '' },
// Validação
necessita_validacao_pos_detalh: false,
// Grades
grades_modelo: '',
grades_padrao_comercial: false,
grades_padrao_sa2: false,
grades_padrao_sa2_meio: false,
grades_padrao_sa3: false,
// Requisitos
req_ambientais_existem: false,
req_ambientais_quais: '',
req_saude_seguranca_existem: false,
req_saude_seguranca_quais: '',
// Alterações
alteracao_descritivo: '',
alteracao_motivo: '',
alteracao_impacto: '',
alteracao_custo: 0,
alteracao_cronograma: '',
alteracao_pecas_prontas: '',
alteracao_detalh_projeto: '',
// Cronograma
cronograma_semanas: {},
// Vistos
visto_gestor: '',
visto_pcp: '',
visto_eng: '',
visto_fab: '',
visto_exp: '',
visto_qual: '',
visto_colunas: { '1': false, '2': false, '3': false, '4': false },
};
const CadastroOF = () => {
const [searchParams] = useSearchParams();
const ofId = searchParams.get('id');
const isEditing = Boolean(ofId);
const { themeConfig } = useThemeConfig();
const { buscarFichaTecnica, salvarFichaTecnica, loading: fichaTecnicaLoading } = useFichaTecnica();
const { users } = useUserManagement();
const [formData, setFormData] = useState<FormData>(initialFormData);
const [isSaving, setIsSaving] = useState(false);
const [showPreview, setShowPreview] = useState(false);
const [searchOfNumber, setSearchOfNumber] = useState('');
// Apply theme config on component mount
useEffect(() => {
if (themeConfig) {
const root = document.documentElement;
const isDark = root.classList.contains('dark');
const theme = isDark ? themeConfig.dark_theme : themeConfig.light_theme;
Object.entries(theme).forEach(([key, value]) => {
root.style.setProperty(`--${key}`, value);
});
}
}, [themeConfig]);
const handleLoadOF = async () => {
if (!searchOfNumber.trim()) {
toast.error('Digite o número da OF para carregar');
return;
}
try {
const data = await buscarFichaTecnica(searchOfNumber.trim());
if (data) {
const parseJsonField = (field: any) => {
if (typeof field === 'string') {
try {
return JSON.parse(field);
} catch {
return { e: false, c: false, na: false, info: '' };
}
}
return field || { e: false, c: false, na: false, info: '' };
};
setFormData({
...initialFormData,
...data,
data_inicio: data.data_inicio || '',
data_termino_prev: data.data_termino_prev || '',
status: 'aberta',
prioridade: 'media',
quantidade: data.quantidade || 0,
info_calculo_estrutural: parseJsonField(data.info_calculo_estrutural),
info_projeto_basico: parseJsonField(data.info_projeto_basico),
info_detalhamento: parseJsonField(data.info_detalhamento),
info_materia_prima: parseJsonField(data.info_materia_prima),
info_fabricacao: parseJsonField(data.info_fabricacao),
info_grades_piso: parseJsonField(data.info_grades_piso),
info_jateamento: parseJsonField(data.info_jateamento),
info_pintura_base: parseJsonField(data.info_pintura_base),
info_pintura_inter: parseJsonField(data.info_pintura_inter),
info_pintura_acabamento: parseJsonField(data.info_pintura_acabamento),
info_galvanizacao: parseJsonField(data.info_galvanizacao),
info_embalagem: parseJsonField(data.info_embalagem),
info_transporte: parseJsonField(data.info_transporte),
info_inspecao: parseJsonField(data.info_inspecao),
info_ensaios_lab: parseJsonField(data.info_ensaios_lab),
info_databook: parseJsonField(data.info_databook),
info_pre_montagem: parseJsonField(data.info_pre_montagem),
info_placa_engenetal: parseJsonField(data.info_placa_engenetal),
info_parafusos: parseJsonField(data.info_parafusos),
info_chumbadores: parseJsonField(data.info_chumbadores),
info_stud_bolt: parseJsonField(data.info_stud_bolt),
info_fornec_telhas: parseJsonField(data.info_fornec_telhas),
info_montagem_telhas: parseJsonField(data.info_montagem_telhas),
info_forn_calhas: parseJsonField(data.info_forn_calhas),
info_mont_calhas: parseJsonField(data.info_mont_calhas),
info_steel_deck: parseJsonField(data.info_steel_deck),
info_fornec_wall: parseJsonField(data.info_fornec_wall),
info_mont_wall: parseJsonField(data.info_mont_wall),
info_outros_materiais: parseJsonField(data.info_outros_materiais),
});
toast.success('OF carregada com sucesso!');
} else {
toast.error('OF não encontrada');
}
} catch (error) {
toast.error('Erro ao carregar OF');
}
};
const handleChange = (field: keyof FormData, value: any) => {
setFormData(prev => ({
...prev,
[field]: value,
}));
};
const handleTechnicalInfoChange = (field: keyof FormData, key: keyof InfoCalculoEstrutural, value: any) => {
setFormData(prev => ({
...prev,
[field]: {
...(prev[field] as InfoCalculoEstrutural),
[key]: value,
},
}));
};
const handleSave = async () => {
if (!formData.of_number) {
toast.error('Número da OF é obrigatório');
return;
}
setIsSaving(true);
try {
const success = await salvarFichaTecnica(formData);
if (success && !isEditing) {
setFormData(initialFormData);
}
} catch (error) {
console.error('Erro ao salvar:', error);
toast.error('Erro ao salvar a OF');
} finally {
setIsSaving(false);
}
};
const renderTechnicalInfoField = (
label: string,
fieldName: keyof FormData,
info: InfoCalculoEstrutural
) => (
<div className="space-y-2">
<Label className="text-sm font-medium text-muted-foreground">{label}</Label>
<div className="flex gap-2 mb-2">
<div className="flex items-center space-x-1">
<Checkbox
checked={info.e}
onCheckedChange={(checked) =>
handleTechnicalInfoChange(fieldName, 'e', checked as boolean)
}
/>
<Label className="text-xs">E</Label>
</div>
<div className="flex items-center space-x-1">
<Checkbox
checked={info.c}
onCheckedChange={(checked) =>
handleTechnicalInfoChange(fieldName, 'c', checked as boolean)
}
/>
<Label className="text-xs">C</Label>
</div>
<div className="flex items-center space-x-1">
<Checkbox
checked={info.na}
onCheckedChange={(checked) =>
handleTechnicalInfoChange(fieldName, 'na', checked as boolean)
}
/>
<Label className="text-xs">N/A</Label>
</div>
</div>
<Textarea
value={info.info}
onChange={(e) =>
handleTechnicalInfoChange(fieldName, 'info', e.target.value)
}
placeholder="Informações adicionais"
className="min-h-[60px] text-xs bg-input border-border text-foreground"
/>
</div>
);
return (
<div className="container mx-auto p-4 space-y-4 bg-background text-foreground">
<div className="flex items-center justify-between mb-6">
<h1 className="text-2xl font-bold text-primary flex items-center gap-2">
<FileText className="w-6 h-6" />
Ficha Técnica da OF
</h1>
<div className="flex items-center gap-2">
<Button
onClick={handleSave}
disabled={isSaving}
className="bg-primary hover:bg-primary/90 text-primary-foreground"
>
<Save className="w-4 h-4 mr-2" />
{isSaving ? 'Salvando...' : 'Salvar'}
</Button>
<Button
variant="outline"
className="border-border"
onClick={() => setShowPreview(true)}
disabled={!formData.of_number}
>
<Eye className="w-4 h-4 mr-2" />
Preview
</Button>
</div>
</div>
{/* Seção para Carregar OF */}
<Card className="bg-card border-border">
<CardHeader className="pb-3">
<CardTitle className="text-lg flex items-center gap-2 text-card-foreground">
<Search className="w-5 h-5" />
Carregar OF Existente
</CardTitle>
</CardHeader>
<CardContent>
<div className="flex gap-2">
<Input
placeholder="Digite o número da OF"
value={searchOfNumber}
onChange={(e) => setSearchOfNumber(e.target.value)}
className="bg-input border-border text-foreground"
/>
<Button
onClick={handleLoadOF}
disabled={fichaTecnicaLoading}
variant="outline"
className="border-border"
>
<Search className="w-4 h-4 mr-2" />
{fichaTecnicaLoading ? 'Carregando...' : 'Carregar OF'}
</Button>
</div>
</CardContent>
</Card>
<div className="space-y-4">
{/* Informações Básicas */}
<Card className="bg-card border-border">
<CardHeader className="pb-3">
<CardTitle className="text-lg flex items-center gap-2 text-card-foreground">
<FileText className="w-5 h-5" />
Informações Básicas
</CardTitle>
</CardHeader>
<CardContent>
<div className="grid grid-cols-1 md:grid-cols-4 gap-3">
<div>
<Label htmlFor="of_number" className="text-sm font-medium text-muted-foreground">Número OF</Label>
<Input
id="of_number"
value={formData.of_number}
onChange={(e) => handleChange('of_number', e.target.value)}
className="mt-1 bg-input border-border text-foreground"
/>
</div>
<div>
<Label htmlFor="gestor" className="text-sm font-medium text-muted-foreground">Gestor da OF</Label>
<Select value={formData.gestor || ''} onValueChange={(value) => handleChange('gestor', value)}>
<SelectTrigger className="mt-1 bg-input border-border text-foreground">
<SelectValue placeholder="Selecione o gestor" />
</SelectTrigger>
<SelectContent className="bg-popover border-border">
{users.filter(user => user.status === 'active').map((user) => (
<SelectItem key={user.id} value={user.full_name || user.email || ''}>
{user.full_name || user.email}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
<div>
<Label htmlFor="projetista" className="text-sm font-medium text-muted-foreground">Projetista da OF</Label>
<Select value={formData.projetista || ''} onValueChange={(value) => handleChange('projetista', value)}>
<SelectTrigger className="mt-1 bg-input border-border text-foreground">
<SelectValue placeholder="Selecione o projetista" />
</SelectTrigger>
<SelectContent className="bg-popover border-border">
{users.filter(user => user.status === 'active').map((user) => (
<SelectItem key={user.id} value={user.full_name || user.email || ''}>
{user.full_name || user.email}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
<div>
<Label htmlFor="revisao" className="text-sm font-medium text-muted-foreground">Revisão</Label>
<Input
id="revisao"
value={formData.revisao || '0'}
onChange={(e) => handleChange('revisao', e.target.value)}
className="mt-1 bg-input border-border text-foreground"
/>
</div>
<div>
<Label htmlFor="data_inicio" className="text-sm font-medium text-muted-foreground">Data Início</Label>
<Input
id="data_inicio"
type="date"
value={formData.data_inicio}
onChange={(e) => handleChange('data_inicio', e.target.value)}
className="mt-1 bg-input border-border text-foreground"
/>
</div>
<div>
<Label htmlFor="data_termino_prev" className="text-sm font-medium text-muted-foreground">Data Prazo</Label>
<Input
id="data_termino_prev"
type="date"
value={formData.data_termino_prev}
onChange={(e) => handleChange('data_termino_prev', e.target.value)}
className="mt-1 bg-input border-border text-foreground"
/>
</div>
<div>
<Label htmlFor="quantidade" className="text-sm font-medium text-muted-foreground">Quantidade (kg)</Label>
<Input
id="quantidade"
type="number"
value={formData.quantidade || ''}
onChange={(e) => handleChange('quantidade', parseFloat(e.target.value) || 0)}
className="mt-1 bg-input border-border text-foreground"
/>
</div>
<div>
<Label htmlFor="descricao_resumida" className="text-sm font-medium text-muted-foreground">Descrição Resumida</Label>
<Input
id="descricao_resumida"
value={formData.descricao_resumida || ''}
onChange={(e) => handleChange('descricao_resumida', e.target.value)}
className="mt-1 bg-input border-border text-foreground"
/>
</div>
</div>
</CardContent>
</Card>
{/* Status e Prioridade */}
<Card className="bg-card border-border">
<CardHeader className="pb-3">
<CardTitle className="text-lg flex items-center gap-2 text-card-foreground">
<Settings2 className="w-5 h-5" />
Status
</CardTitle>
</CardHeader>
<CardContent className="space-y-3">
<div>
<Label className="text-sm font-medium text-muted-foreground">Status Atual</Label>
<Select value={formData.status} onValueChange={(value) => handleChange('status', value)}>
<SelectTrigger className="mt-1 bg-input border-border text-foreground">
<SelectValue />
</SelectTrigger>
<SelectContent className="bg-popover border-border">
<SelectItem value="aberta">Aberta</SelectItem>
<SelectItem value="em_andamento">Em Andamento</SelectItem>
<SelectItem value="concluida">Concluída</SelectItem>
<SelectItem value="arquivada">Arquivada</SelectItem>
</SelectContent>
</Select>
</div>
<div>
<Label className="text-sm font-medium text-muted-foreground">Prioridade</Label>
<Select value={formData.prioridade} onValueChange={(value) => handleChange('prioridade', value)}>
<SelectTrigger className="mt-1 bg-input border-border text-foreground">
<SelectValue />
</SelectTrigger>
<SelectContent className="bg-popover border-border">
<SelectItem value="baixa">Baixa</SelectItem>
<SelectItem value="media">Média</SelectItem>
<SelectItem value="alta">Alta</SelectItem>
<SelectItem value="urgente">Urgente</SelectItem>
</SelectContent>
</Select>
</div>
</CardContent>
</Card>
{/* Informações do Cliente */}
<Card className="bg-card border-border">
<CardHeader className="pb-3">
<CardTitle className="text-lg flex items-center gap-2 text-card-foreground">
<User className="w-5 h-5" />
Informações do Cliente
</CardTitle>
</CardHeader>
<CardContent>
<div className="grid grid-cols-1 md:grid-cols-4 gap-3">
<div className="md:col-span-2">
<Label htmlFor="cliente" className="text-sm font-medium text-muted-foreground">Cliente</Label>
<Input
id="cliente"
value={formData.cliente || ''}
onChange={(e) => handleChange('cliente', e.target.value)}
className="mt-1 bg-input border-border text-foreground"
/>
</div>
<div>
<Label htmlFor="cnpj" className="text-sm font-medium text-muted-foreground">CNPJ</Label>
<Input
id="cnpj"
value={formData.cnpj || ''}
onChange={(e) => handleChange('cnpj', e.target.value)}
className="mt-1 bg-input border-border text-foreground"
/>
</div>
<div>
<Label htmlFor="ie" className="text-sm font-medium text-muted-foreground">IE</Label>
<Input
id="ie"
value={formData.ie || ''}
onChange={(e) => handleChange('ie', e.target.value)}
className="mt-1 bg-input border-border text-foreground"
/>
</div>
<div className="md:col-span-2">
<Label htmlFor="endereco" className="text-sm font-medium text-muted-foreground">Endereço</Label>
<Input
id="endereco"
value={formData.endereco || ''}
onChange={(e) => handleChange('endereco', e.target.value)}
className="mt-1 bg-input border-border text-foreground"
/>
</div>
<div>
<Label htmlFor="cidade" className="text-sm font-medium text-muted-foreground">Cidade</Label>
<Input
id="cidade"
value={formData.cidade || ''}
onChange={(e) => handleChange('cidade', e.target.value)}
className="mt-1 bg-input border-border text-foreground"
/>
</div>
<div>
<Label htmlFor="estado" className="text-sm font-medium text-muted-foreground">Estado</Label>
<Input
id="estado"
value={formData.estado || ''}
onChange={(e) => handleChange('estado', e.target.value)}
className="mt-1 bg-input border-border text-foreground"
/>
</div>
</div>
</CardContent>
</Card>
{/* Informações da Obra */}
<Card className="bg-card border-border">
<CardHeader className="pb-3">
<CardTitle className="text-lg flex items-center gap-2 text-card-foreground">
<Building2 className="w-5 h-5" />
Informações da Obra
</CardTitle>
</CardHeader>
<CardContent>
<div className="grid grid-cols-1 md:grid-cols-4 gap-3">
<div>
<Label htmlFor="eng_responsavel" className="text-sm font-medium text-muted-foreground">Eng. Responsável</Label>
<Input
id="eng_responsavel"
value={formData.eng_responsavel || ''}
onChange={(e) => handleChange('eng_responsavel', e.target.value)}
className="mt-1 bg-input border-border text-foreground"
/>
</div>
<div>
<Label htmlFor="telefone_obra" className="text-sm font-medium text-muted-foreground">Telefone</Label>
<Input
id="telefone_obra"
value={formData.telefone_obra || ''}
onChange={(e) => handleChange('telefone_obra', e.target.value)}
className="mt-1 bg-input border-border text-foreground"
/>
</div>
<div className="md:col-span-2">
<Label htmlFor="email_obra_responsavel" className="text-sm font-medium text-muted-foreground">E-mail</Label>
<Input
id="email_obra_responsavel"
type="email"
value={formData.email_obra_responsavel || ''}
onChange={(e) => handleChange('email_obra_responsavel', e.target.value)}
className="mt-1 bg-input border-border text-foreground"
/>
</div>
<div className="md:col-span-2">
<Label htmlFor="endereco_obra" className="text-sm font-medium text-muted-foreground">Endereço da Obra</Label>
<Input
id="endereco_obra"
value={formData.endereco_obra || ''}
onChange={(e) => handleChange('endereco_obra', e.target.value)}
className="mt-1 bg-input border-border text-foreground"
/>
</div>
<div>
<Label htmlFor="cep_obra" className="text-sm font-medium text-muted-foreground">CEP</Label>
<Input
id="cep_obra"
value={formData.cep_obra || ''}
onChange={(e) => handleChange('cep_obra', e.target.value)}
className="mt-1 bg-input border-border text-foreground"
/>
</div>
<div>
<Label htmlFor="bairro_obra" className="text-sm font-medium text-muted-foreground">Bairro</Label>
<Input
id="bairro_obra"
value={formData.bairro_obra || ''}
onChange={(e) => handleChange('bairro_obra', e.target.value)}
className="mt-1 bg-input border-border text-foreground"
/>
</div>
<div>
<Label htmlFor="cidade_obra" className="text-sm font-medium text-muted-foreground">Cidade</Label>
<Input
id="cidade_obra"
value={formData.cidade_obra || ''}
onChange={(e) => handleChange('cidade_obra', e.target.value)}
className="mt-1 bg-input border-border text-foreground"
/>
</div>
<div>
<Label htmlFor="estado_obra" className="text-sm font-medium text-muted-foreground">Estado (UF)</Label>
<Input
id="estado_obra"
value={formData.estado_obra || ''}
onChange={(e) => handleChange('estado_obra', e.target.value)}
className="mt-1 bg-input border-border text-foreground"
/>
</div>
<div className="md:col-span-4">
<Label htmlFor="observacoes_obra" className="text-sm font-medium text-muted-foreground">Observações Gerais</Label>
<Textarea
id="observacoes_obra"
value={formData.observacoes_obra || ''}
onChange={(e) => handleChange('observacoes_obra', e.target.value)}
className="mt-1 bg-input border-border text-foreground"
rows={3}
/>
</div>
</div>
</CardContent>
</Card>
{/* Tipos de Projetos */}
<Card className="bg-card border-border">
<CardHeader className="pb-3">
<CardTitle className="text-lg flex items-center gap-2 text-card-foreground">
<Settings2 className="w-5 h-5" />
Tipos de Projetos
</CardTitle>
</CardHeader>
<CardContent>
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
{[
{ key: 'tipo_estrutural', label: 'Estrutural' },
{ key: 'tipo_residencial', label: 'Residencial' },
{ key: 'tipo_espacial', label: 'Espacial' },
{ key: 'tipo_comercial', label: 'Comercial' },
{ key: 'tipo_grades', label: 'Grades' },
{ key: 'tipo_industrial', label: 'Industrial' },
{ key: 'tipo_cobertura', label: 'Cobertura' },
{ key: 'tipo_com_montagem', label: 'Com Montagem' },
].map(({ key, label }) => (
<div key={key} className="flex items-center space-x-2">
<Checkbox
checked={formData[key as keyof FormData] as boolean || false}
onCheckedChange={(checked) => handleChange(key as keyof FormData, checked)}
/>
<Label className="text-sm">{label}</Label>
</div>
))}
</div>
</CardContent>
</Card>
{/* Documentos Fornecidos */}
<Card className="bg-card border-border">
<CardHeader className="pb-3">
<CardTitle className="text-lg flex items-center gap-2 text-card-foreground">
<FileText className="w-5 h-5" />
Documentos Fornecidos
</CardTitle>
</CardHeader>
<CardContent>
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
{[
{ key: 'doc_calculo', label: 'Cálculo' },
{ key: 'doc_projeto', label: 'Projeto' },
{ key: 'doc_detalhamento', label: 'Detalhamento' },
{ key: 'doc_cronograma', label: 'Cronograma' },
{ key: 'doc_normas', label: 'Normas' },
{ key: 'doc_especif_tecnicas', label: 'Especif. Técnicas' },
{ key: 'doc_catalogo', label: 'Catálogo' },
{ key: 'doc_fotos', label: 'Fotos' },
].map(({ key, label }) => (
<div key={key} className="flex items-center space-x-2">
<Checkbox
checked={formData[key as keyof FormData] as boolean || false}
onCheckedChange={(checked) => handleChange(key as keyof FormData, checked)}
/>
<Label className="text-sm">{label}</Label>
</div>
))}
</div>
</CardContent>
</Card>
{/* Alterações - Como botão popup */}
<Card className="bg-card border-border">
<CardHeader className="pb-3">
<CardTitle className="text-lg flex items-center gap-2 text-card-foreground">
<Settings2 className="w-5 h-5" />
Alterações da OF
</CardTitle>
</CardHeader>
<CardContent>
<AlteracoesPopup formData={formData} setFormData={setFormData} />
</CardContent>
</Card>
{/* Informações Técnicas Completas */}
<Card className="bg-card border-border">
<CardHeader className="pb-3">
<CardTitle className="text-lg flex items-center gap-2 text-card-foreground">
<Settings2 className="w-5 h-5" />
Informações Técnicas
</CardTitle>
</CardHeader>
<CardContent>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{renderTechnicalInfoField('Cálculo Estrutural', 'info_calculo_estrutural', formData.info_calculo_estrutural)}
{renderTechnicalInfoField('Projeto Básico', 'info_projeto_basico', formData.info_projeto_basico)}
{renderTechnicalInfoField('Detalhamento', 'info_detalhamento', formData.info_detalhamento)}
{renderTechnicalInfoField('Matéria Prima', 'info_materia_prima', formData.info_materia_prima)}
{renderTechnicalInfoField('Fabricação', 'info_fabricacao', formData.info_fabricacao)}
{renderTechnicalInfoField('Grades de Piso', 'info_grades_piso', formData.info_grades_piso)}
{renderTechnicalInfoField('Jateamento', 'info_jateamento', formData.info_jateamento)}
{renderTechnicalInfoField('Pintura Base', 'info_pintura_base', formData.info_pintura_base)}
{renderTechnicalInfoField('Pintura Intermediária', 'info_pintura_inter', formData.info_pintura_inter)}
{renderTechnicalInfoField('Pintura Acabamento', 'info_pintura_acabamento', formData.info_pintura_acabamento)}
{renderTechnicalInfoField('Galvanização', 'info_galvanizacao', formData.info_galvanizacao)}
{renderTechnicalInfoField('Embalagem', 'info_embalagem', formData.info_embalagem)}
{renderTechnicalInfoField('Transporte', 'info_transporte', formData.info_transporte)}
{renderTechnicalInfoField('Inspeção', 'info_inspecao', formData.info_inspecao)}
{renderTechnicalInfoField('Ensaios de Laboratório', 'info_ensaios_lab', formData.info_ensaios_lab)}
{renderTechnicalInfoField('Databook', 'info_databook', formData.info_databook)}
{renderTechnicalInfoField('Pré-montagem', 'info_pre_montagem', formData.info_pre_montagem)}
{renderTechnicalInfoField('Placa Engenetal', 'info_placa_engenetal', formData.info_placa_engenetal)}
{renderTechnicalInfoField('Parafusos', 'info_parafusos', formData.info_parafusos)}
{renderTechnicalInfoField('Chumbadores', 'info_chumbadores', formData.info_chumbadores)}
{renderTechnicalInfoField('Stud Bolt', 'info_stud_bolt', formData.info_stud_bolt)}
{renderTechnicalInfoField('Fornecimento Telhas', 'info_fornec_telhas', formData.info_fornec_telhas)}
{renderTechnicalInfoField('Montagem Telhas', 'info_montagem_telhas', formData.info_montagem_telhas)}
{renderTechnicalInfoField('Fornecimento Calhas', 'info_forn_calhas', formData.info_forn_calhas)}
{renderTechnicalInfoField('Montagem Calhas', 'info_mont_calhas', formData.info_mont_calhas)}
{renderTechnicalInfoField('Steel Deck', 'info_steel_deck', formData.info_steel_deck)}
{renderTechnicalInfoField('Fornecimento Wall', 'info_fornec_wall', formData.info_fornec_wall)}
{renderTechnicalInfoField('Montagem Wall', 'info_mont_wall', formData.info_mont_wall)}
{renderTechnicalInfoField('Outros Materiais', 'info_outros_materiais', formData.info_outros_materiais)}
</div>
</CardContent>
</Card>
</div>
{/* Preview Modal */}
<FichaTecnicaPreview
isOpen={showPreview}
onClose={() => setShowPreview(false)}
data={formData}
/>
</div>
);
};
export default CadastroOF;