photum/frontend/pages/ProfessionalRegister.tsx
NANDO9322 cd196a0275 feat(auth): adiciona tipo profissional ao schema e corrige avatar
- Adiciona coluna `tipo_profissional` à tabela `usuarios`
- Atualiza handlers e services do Backend Go para persistir o tipo
- Atualiza registro no Frontend para enviar o nome da função (ex: "Cinegrafista")
- Corrige uploads S3 para compatibilidade com Civo (PathStyle)
- Script para definir política pública de leitura no bucket S3
- Adiciona fallback para imagens de avatar na Navbar
2025-12-22 12:37:42 -03:00

164 lines
6.2 KiB
TypeScript

import React, { useState } from "react";
import {
ProfessionalForm,
ProfessionalData,
} from "../components/ProfessionalForm";
import { useAuth } from "../contexts/AuthContext";
interface ProfessionalRegisterProps {
onNavigate: (page: string) => void;
}
export const ProfessionalRegister: React.FC<ProfessionalRegisterProps> = ({
onNavigate,
}) => {
const { register } = useAuth();
const [isSuccess, setIsSuccess] = useState(false);
const handleSubmit = async (professionalData: ProfessionalData) => {
try {
// 1. Cadastrar Usuário (Auth) e Logar Automaticamente
const authResult = await register({
nome: professionalData.nome,
email: professionalData.email,
senha: professionalData.senha,
telefone: professionalData.whatsapp,
role: "PHOTOGRAPHER", // Role fixa para profissionais
tipo_profissional: professionalData.funcaoLabel || "", // Envia o nome da função (ex: Cinegrafista)
});
if (!authResult.success) {
throw new Error("Falha no cadastro de usuário.");
}
// 2. Criar Perfil Profissional (autenticado)
const { createProfessional, getUploadURL, uploadFileToSignedUrl } = await import("../services/apiService");
let avatarUrl = "";
// Upload de Avatar (se existir)
if (professionalData.avatar) {
try {
console.log("Iniciando upload do avatar...");
const uploadRes = await getUploadURL(professionalData.avatar.name, professionalData.avatar.type);
if (uploadRes.error || !uploadRes.data) {
throw new Error(uploadRes.error || "Erro ao obter URL de upload");
}
await uploadFileToSignedUrl(uploadRes.data.upload_url, professionalData.avatar);
avatarUrl = uploadRes.data.public_url;
console.log("Upload concluído. URL:", avatarUrl);
} catch (err) {
console.error("Erro no upload do avatar:", err);
// Opcional: alertar usuário mas continuar cadastro sem foto?
// alert("Erro ao enviar foto. O cadastro prosseguirá sem foto.");
// Ou falhar tudo?
throw new Error("Falha ao enviar foto de perfil: " + (err instanceof Error ? err.message : "Erro desconhecido"));
}
}
// Mapear dados do formulário para o payload esperado pelo backend
// Mapear dados do formulário para o payload esperado pelo backend
// O curl fornecido pelo usuário mostra campos underscore (snake_case)
const payload: any = {
nome: professionalData.nome,
agencia: professionalData.agencia,
banco: professionalData.banco,
carro_disponivel: professionalData.carroDisponivel === "sim",
cidade: professionalData.cidade,
conta_pix: professionalData.pix, // Usando o campo PIX separado
cpf_cnpj_titular: professionalData.cpfCnpj,
endereco: `${professionalData.cep}, ${professionalData.rua}, ${professionalData.numero} - ${professionalData.bairro}`,
equipamentos: professionalData.equipamentos,
extra_por_equipamento: false, // Default
funcao_profissional_id: professionalData.funcaoId,
observacao: professionalData.observacao,
qtd_estudio: parseInt(professionalData.qtdEstudios) || 0,
tem_estudio: professionalData.possuiEstudio === "sim",
tipo_cartao: professionalData.tipoCartao,
uf: professionalData.uf,
whatsapp: professionalData.whatsapp,
// Campos numéricos default
desempenho_evento: 0,
disp_horario: 0,
educacao_simpatia: 0,
qual_tec: 0,
tabela_free: "",
avatar_url: avatarUrl,
};
const profResult = await createProfessional(payload, authResult.token);
if (profResult.error) {
// Se falhar o perfil, o usuário foi criado :/
// Idealmente limparíamos ou avisaríamos para completar perfil depois
throw new Error("Usuário criado, mas erro ao salvar dados profissionais: " + profResult.error);
}
console.log("Profissional cadastrado com sucesso!");
setIsSuccess(true);
} catch (error: any) {
console.error("Erro ao cadastrar profissional:", error);
alert(error.message || "Erro ao cadastrar profissional. Tente novamente.");
}
};
if (isSuccess) {
return (
<div
className="min-h-screen flex items-center justify-center"
style={{ backgroundColor: "#B9CF33" }}
>
<div className="text-center fade-in max-w-md px-4 py-8 bg-white rounded-2xl shadow-xl">
<div className="w-16 h-16 bg-yellow-500 rounded-full flex items-center justify-center mx-auto mb-4">
<svg
className="w-8 h-8 text-white"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
/>
</svg>
</div>
<h2 className="text-2xl font-bold text-gray-900 mb-2">
Cadastro Pendente de Aprovação
</h2>
<p className="text-gray-600 mb-4">
Seu cadastro foi realizado com sucesso e está aguardando aprovação.
</p>
<div className="bg-yellow-50 border border-yellow-200 rounded-lg p-4 mb-6">
<p className="text-sm text-yellow-800">
<strong>Atenção:</strong> Enquanto seu cadastro não for aprovado,
você não terá acesso ao sistema.
</p>
</div>
<button
onClick={() => {
window.location.href = "/";
}}
className="w-full px-6 py-2 text-white font-semibold rounded-lg hover:bg-opacity-90 transition-colors"
style={{ backgroundColor: "#B9CF33" }}
>
OK
</button>
</div>
</div>
);
}
return (
<div className="min-h-screen flex items-center justify-center bg-gradient-to-br from-gray-50 to-white p-4 py-8 pt-24">
<ProfessionalForm
onSubmit={handleSubmit}
onCancel={() => onNavigate("cadastro")}
/>
</div>
);
};