photum/frontend/pages/Register.tsx

373 lines
13 KiB
TypeScript

import React, { useState, useEffect } from "react";
import { Button } from "../components/Button";
import { Input } from "../components/Input";
import { useAuth } from "../contexts/AuthContext";
import { getCompanies } from "../services/apiService";
interface RegisterProps {
onNavigate: (page: string) => void;
}
export const Register: React.FC<RegisterProps> = ({ onNavigate }) => {
const { register } = useAuth();
const [companies, setCompanies] = useState<
Array<{ id: string; nome: string }>
>([]);
const [isLoadingCompanies, setIsLoadingCompanies] = useState(true);
const [formData, setFormData] = useState({
name: "",
email: "",
phone: "",
password: "",
confirmPassword: "",
empresaId: "",
});
const [agreedToTerms, setAgreedToTerms] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState("");
const [isPending, setIsPending] = useState(false);
useEffect(() => {
const loadCompanies = async () => {
setIsLoadingCompanies(true);
const result = await getCompanies();
if (result.data) {
setCompanies(result.data);
}
setIsLoadingCompanies(false);
};
loadCompanies();
}, []);
// Verifica se tem empresa pré-selecionada via URL (código de acesso)
useEffect(() => {
const urlParams = new URLSearchParams(window.location.search);
const empresaId = urlParams.get('empresa_id');
const empresaNome = urlParams.get('empresa_nome');
if (empresaId) {
setFormData(prev => ({ ...prev, empresaId }));
// Limpa os parâmetros da URL após usar
window.history.replaceState({}, document.title, window.location.pathname);
}
}, [companies]);
const handleChange = (field: string, value: string | boolean) => {
setFormData((prev) => ({ ...prev, [field]: value }));
setError("");
};
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setIsLoading(true);
setError("");
// Validação do checkbox de termos
if (!agreedToTerms) {
setError("Você precisa concordar com os termos de uso para continuar");
setIsLoading(false);
return;
}
// Validações
if (formData.password !== formData.confirmPassword) {
setError("As senhas não coincidem");
setIsLoading(false);
return;
}
if (formData.password.length < 6) {
setError("A senha deve ter no mínimo 6 caracteres");
setIsLoading(false);
return;
}
try {
await register({
nome: formData.name,
email: formData.email,
senha: formData.password,
telefone: formData.phone,
role: "EVENT_OWNER", // Client Role
empresaId: formData.empresaId,
});
// Limpar dados de sessão após cadastro bem-sucedido
sessionStorage.removeItem('accessCodeValidated');
sessionStorage.removeItem('accessCodeData');
setIsLoading(false);
setIsPending(true);
} catch (err: any) {
setIsLoading(false);
setError(err.message || "Erro ao realizar cadastro");
}
};
if (isPending) {
return (
<div className="min-h-screen flex items-center justify-center bg-white">
<div className="text-center fade-in max-w-md px-4">
<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
da empresa.
</p>
<p className="text-gray-600 mb-6">
Você receberá um e-mail assim que seu cadastro for aprovado e poderá
acessar o sistema.
</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">
<div className="w-full max-w-md fade-in relative z-10">
<div className="bg-white rounded-2xl shadow-xl border border-gray-100 p-6 sm:p-8">
{/* Logo dentro do card */}
<div className="flex justify-center mb-4">
<img
src="/logo.png"
alt="Photum Formaturas"
className="h-18 sm:h-30 w-auto max-w-[200px] object-contain"
/>
</div>
<div className="text-center">
<span
className="font-bold tracking-widest uppercase text-[10px] sm:text-xs"
style={{ color: "#B9CF33" }}
>
Comece agora
</span>
<h2 className="mt-1.5 sm:mt-2 text-xl sm:text-2xl md:text-3xl font-serif font-bold text-gray-900">
Crie sua conta
</h2>
<p className="mt-1.5 sm:mt-2 text-xs sm:text-sm text-gray-600">
tem uma conta?{" "}
<button
onClick={() => onNavigate("entrar")}
className="font-medium hover:opacity-80 transition-opacity"
style={{ color: "#B9CF33" }}
>
Faça login
</button>
</p>
</div>
<form
className="mt-5 sm:mt-6 space-y-3 sm:space-y-4"
onSubmit={handleSubmit}
>
<div className="flex items-start bg-blue-50 border border-blue-200 rounded-lg p-2.5 sm:p-3 md:p-4 mb-3 sm:mb-4">
<div className="flex-1">
<p className="text-xs sm:text-sm text-gray-700">
<span className="font-medium text-xs sm:text-sm">
Você é um profissional?
</span>
</p>
<button
type="button"
onClick={() => onNavigate("cadastro-profissional")}
className="text-xs sm:text-sm mt-1 hover:opacity-80 transition-opacity underline font-medium"
style={{ color: "#B9CF33" }}
>
Clique aqui para se cadastrar como profissional
</button>
</div>
</div>
<div className="space-y-3">
<Input
label="Nome Completo"
type="text"
required
placeholder="João Silva"
value={formData.name}
onChange={(e) => handleChange("name", e.target.value)}
/>
<Input
label="E-mail"
type="email"
required
placeholder="nome@exemplo.com"
value={formData.email}
onChange={(e) => handleChange("email", e.target.value)}
/>
<Input
label="Telefone"
type="tel"
required
placeholder="(00) 00000-0000"
value={formData.phone}
onChange={(e) => handleChange("phone", e.target.value)}
mask="phone"
/>
<div>
<label className="block text-[10px] sm:text-xs md:text-sm font-medium text-gray-700 mb-1">
Empresa *
</label>
<p className="text-[10px] text-gray-500 mb-2 leading-tight">
Se a sua empresa não estiver listada, entre em contato com a
administração e selecione <strong>"Não Cadastrado"</strong>{" "}
abaixo.
</p>
{formData.empresaId && companies.find(c => c.id === formData.empresaId) && (
<p className="text-[10px] text-green-600 mb-2 leading-tight">
Empresa pré-selecionada baseada no seu código de acesso
</p>
)}
{isLoadingCompanies ? (
<p className="text-xs sm:text-sm text-gray-500">
Carregando empresas...
</p>
) : (
<select
required
value={formData.empresaId}
onChange={(e) => handleChange("empresaId", e.target.value)}
className="w-full px-2.5 sm:px-3 md:px-4 py-1.5 sm:py-2 text-xs sm:text-sm border border-gray-300 rounded-lg focus:ring-2 focus:border-transparent"
style={{ focusRing: "2px solid #B9CF33" }}
disabled={!!formData.empresaId && !!companies.find(c => c.id === formData.empresaId)}
>
<option value="">
{formData.empresaId ? "Empresa selecionada" : "Selecione uma empresa"}
</option>
{companies
.sort((a, b) => {
const nameA = a.nome.toLowerCase();
const nameB = b.nome.toLowerCase();
if (nameA.includes("não cadastrado") || nameA.includes("nao cadastrado")) return -1;
if (nameB.includes("não cadastrado") || nameB.includes("nao cadastrado")) return 1;
return nameA.localeCompare(nameB);
})
.map((company) => (
<option key={company.id} value={company.id}>
{company.nome}
</option>
))}
</select>
)}
</div>
<Input
label="Senha"
type="password"
required
placeholder="••••••••"
value={formData.password}
onChange={(e) => handleChange("password", e.target.value)}
/>
<Input
label="Confirmar Senha"
type="password"
required
placeholder="••••••••"
value={formData.confirmPassword}
onChange={(e) =>
handleChange("confirmPassword", e.target.value)
}
error={
error &&
(error.includes("senha") || error.includes("coincidem"))
? error
: undefined
}
/>
</div>
<div>
<div className="flex items-start">
<input
type="checkbox"
checked={agreedToTerms}
onChange={(e) => setAgreedToTerms(e.target.checked)}
className="mt-0.5 sm:mt-1 h-4 w-4 flex-shrink-0 border-gray-300 rounded focus:ring-2"
style={{ accentColor: "#B9CF33" }}
/>
<label className="ml-2 text-xs sm:text-sm text-gray-600">
Concordo com os{" "}
<button
type="button"
onClick={() => onNavigate("termos")}
className="hover:opacity-80 transition-opacity underline"
style={{ color: "#B9CF33" }}
>
termos de uso
</button>{" "}
e{" "}
<button
type="button"
onClick={() => onNavigate("privacidade")}
className="hover:opacity-80 transition-opacity underline"
style={{ color: "#B9CF33" }}
>
política de privacidade
</button>
</label>
</div>
{error && error.includes("termos") && (
<span className="text-xs text-red-500 mt-1 block ml-6">
{error}
</span>
)}
</div>
{error &&
!error.includes("termos") &&
!error.includes("senha") &&
!error.includes("coincidem") && (
<div className="bg-red-50 border border-red-200 text-red-600 px-4 py-3 rounded-lg text-sm mb-4">
{error}
</div>
)}
<Button
type="submit"
className="w-full"
size="lg"
isLoading={isLoading}
>
Criar Conta
</Button>
</form>
</div>
</div>
</div>
);
};