import React, { useState, useEffect } from "react"; import { Customer } from "../src/services/customer.service"; import { customerService } from "../src/services/customer.service"; import { validateCustomerForm, validateCPForCNPJ, validateCEP, validatePhone, } from "../lib/utils"; import ConfirmDialog from "./ConfirmDialog"; interface CreateCustomerDialogProps { isOpen: boolean; onClose: () => void; onSuccess: (customer: Customer) => void; } const CreateCustomerDialog: React.FC = ({ isOpen, onClose, onSuccess, }) => { const [isAnimating, setIsAnimating] = useState(false); const [shouldRender, setShouldRender] = useState(false); const [isSubmitting, setIsSubmitting] = useState(false); const [isSearchingCustomer, setIsSearchingCustomer] = useState(false); const [showCustomerFoundDialog, setShowCustomerFoundDialog] = useState(false); const [foundCustomer, setFoundCustomer] = useState(null); const [formData, setFormData] = useState({ name: "", document: "", cellPhone: "", cep: "", address: "", number: "", city: "", state: "", complement: "", }); const [errors, setErrors] = useState>({}); useEffect(() => { if (isOpen) { setShouldRender(true); setTimeout(() => setIsAnimating(true), 10); // Limpar formulário ao abrir setFormData({ name: "", document: "", cellPhone: "", cep: "", address: "", number: "", city: "", state: "", complement: "", }); setErrors({}); } else { setIsAnimating(false); const timer = setTimeout(() => setShouldRender(false), 300); return () => clearTimeout(timer); } }, [isOpen]); if (!shouldRender) return null; const handleInputChange = (field: string, value: string) => { setFormData((prev) => ({ ...prev, [field]: value })); // Limpar erro do campo ao digitar if (errors[field]) { setErrors((prev) => { const newErrors = { ...prev }; delete newErrors[field]; return newErrors; }); } }; /** * Busca cliente por CPF/CNPJ ao sair do campo (blur) * Similar ao searchCustomerByDocument() do Angular */ const handleSearchCustomerByDocument = async () => { const document = formData.document; // Remover caracteres não numéricos para a busca const cleanDocument = document.replace(/[^\d]/g, ""); // Validar se tem pelo menos 11 dígitos (CPF mínimo) ou 14 (CNPJ) if (!cleanDocument || cleanDocument.length < 11) { return; } setIsSearchingCustomer(true); try { const customer = await customerService.getCustomerByCpf(cleanDocument); if (customer) { // Cliente encontrado - preencher formulário setFoundCustomer(customer); populateCustomerForm(customer); setShowCustomerFoundDialog(true); } } catch (error) { console.error("Erro ao buscar cliente por CPF/CNPJ:", error); // Não mostrar erro se o cliente não foi encontrado (é esperado para novos clientes) } finally { setIsSearchingCustomer(false); } }; /** * Preenche o formulário com os dados do cliente encontrado * Similar ao populateCustomer() do Angular */ const populateCustomerForm = (customer: Customer) => { setFormData({ name: customer.name || "", document: customer.cpfCnpj || customer.document || "", cellPhone: customer.cellPhone || customer.phone || "", cep: customer.zipCode || customer.cep || "", address: customer.address || "", number: customer.addressNumber || customer.number || "", city: customer.city || "", state: customer.state || "", complement: customer.complement || "", }); }; /** * Fecha o dialog de cliente encontrado * O usuário pode continuar editando o formulário ou usar o cliente encontrado */ const handleCloseCustomerFoundDialog = () => { setShowCustomerFoundDialog(false); }; /** * Usa o cliente encontrado diretamente (sem editar) */ const handleUseFoundCustomer = () => { setShowCustomerFoundDialog(false); if (foundCustomer) { // Chamar onSuccess com o cliente encontrado onSuccess(foundCustomer); onClose(); } }; const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); // Validar formulário const validation = validateCustomerForm(formData); if (!validation.isValid) { setErrors(validation.errors); return; } setIsSubmitting(true); try { const newCustomer = await customerService.createCustomer(formData); if (newCustomer) { setIsAnimating(false); setTimeout(() => { onSuccess(newCustomer); onClose(); }, 300); } else { setErrors({ submit: "Não foi possível cadastrar o cliente. Tente novamente.", }); } } catch (error: any) { setErrors({ submit: error.message || "Erro ao cadastrar cliente. Tente novamente.", }); } finally { setIsSubmitting(false); } }; const handleClose = () => { setIsAnimating(false); setTimeout(() => { onClose(); setFormData({ name: "", document: "", cellPhone: "", cep: "", address: "", number: "", city: "", state: "", complement: "", }); setErrors({}); }, 300); }; return (
{/* Overlay */}
{/* Dialog */}
{/* Header */}

Novo Cliente

Cadastro

{/* Content */}
{/* Nome do Cliente */}
handleInputChange("name", e.target.value)} className={`w-full px-4 py-3 bg-slate-50 rounded-xl font-bold text-[#002147] border ${ errors.name ? "border-red-500" : "border-slate-200" } focus:outline-none focus:ring-2 focus:ring-orange-500/20`} placeholder="Digite o nome completo" /> {errors.name && (

{errors.name}

)}
{/* CPF/CNPJ e Contato */}
handleInputChange("document", e.target.value) } onBlur={handleSearchCustomerByDocument} className={`w-full px-4 py-3 bg-slate-50 rounded-xl font-bold text-[#002147] border ${ errors.document ? "border-red-500" : "border-slate-200" } focus:outline-none focus:ring-2 focus:ring-orange-500/20`} placeholder="000.000.000-00" disabled={isSearchingCustomer} /> {isSearchingCustomer && (
)}
{errors.document && (

{errors.document}

)}
handleInputChange("cellPhone", e.target.value) } className={`w-full px-4 py-3 bg-slate-50 rounded-xl font-bold text-[#002147] border ${ errors.cellPhone ? "border-red-500" : "border-slate-200" } focus:outline-none focus:ring-2 focus:ring-orange-500/20`} placeholder="(00) 00000-0000" /> {errors.cellPhone && (

{errors.cellPhone}

)}
{/* CEP e Endereço */}
handleInputChange("cep", e.target.value)} className={`w-full px-4 py-3 bg-slate-50 rounded-xl font-bold text-[#002147] border ${ errors.cep ? "border-red-500" : "border-slate-200" } focus:outline-none focus:ring-2 focus:ring-orange-500/20`} placeholder="00000-000" /> {errors.cep && (

{errors.cep}

)}
handleInputChange("address", e.target.value)} className={`w-full px-4 py-3 bg-slate-50 rounded-xl font-bold text-[#002147] border ${ errors.address ? "border-red-500" : "border-slate-200" } focus:outline-none focus:ring-2 focus:ring-orange-500/20`} placeholder="Rua, Avenida, etc." /> {errors.address && (

{errors.address}

)}
{/* Número, Cidade e Estado */}
handleInputChange("number", e.target.value)} className={`w-full px-4 py-3 bg-slate-50 rounded-xl font-bold text-[#002147] border ${ errors.number ? "border-red-500" : "border-slate-200" } focus:outline-none focus:ring-2 focus:ring-orange-500/20`} placeholder="123" /> {errors.number && (

{errors.number}

)}
handleInputChange("city", e.target.value)} className={`w-full px-4 py-3 bg-slate-50 rounded-xl font-bold text-[#002147] border ${ errors.city ? "border-red-500" : "border-slate-200" } focus:outline-none focus:ring-2 focus:ring-orange-500/20`} placeholder="Nome da cidade" /> {errors.city && (

{errors.city}

)}
handleInputChange("state", e.target.value)} maxLength={2} className={`w-full px-4 py-3 bg-slate-50 rounded-xl font-bold text-[#002147] border ${ errors.state ? "border-red-500" : "border-slate-200" } focus:outline-none focus:ring-2 focus:ring-orange-500/20 uppercase`} placeholder="PA" /> {errors.state && (

{errors.state}

)}
{/* Complemento */}
handleInputChange("complement", e.target.value) } className="w-full px-4 py-3 bg-slate-50 rounded-xl font-bold text-[#002147] border border-slate-200 focus:outline-none focus:ring-2 focus:ring-orange-500/20" placeholder="Apto, Bloco, etc. (opcional)" />
{/* Erro de submit */} {errors.submit && (

{errors.submit}

)}
{/* Actions */}
{/* Dialog de Cliente Encontrado */}
); }; export default CreateCustomerDialog;