feat(jobs/new): add user account registration and fix companyId in job payload
- Add password + confirm-password fields to billing step (Step 3) so the recruiter creates their account credentials during the job posting flow - Validate password length (≥8) and confirmation match before proceeding - Extract company `id` from POST /auth/register/company response and send it as `companyId` in the job creation payload (was missing — caused 400) - Pass `contact` (full name) to company registration endpoint - Remove hardcoded "Temp@123456" password; use the user-provided one - Remove hardcoded "+55" phone prefix; send raw digits with "+" prefix - Add translations (pt-BR, en, es) for password fields and error messages Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
61d64d846a
commit
2686b69506
1 changed files with 67 additions and 4 deletions
|
|
@ -179,6 +179,12 @@ const contentByLocale = {
|
||||||
phonePlaceholder: "(00) 0000-0000",
|
phonePlaceholder: "(00) 0000-0000",
|
||||||
mobile: "Celular",
|
mobile: "Celular",
|
||||||
mobilePlaceholder: "(00) 00000-0000",
|
mobilePlaceholder: "(00) 00000-0000",
|
||||||
|
accountTitle: "Dados de acesso à conta",
|
||||||
|
accountHint: "Você usará este e-mail e senha para acessar o painel da empresa.",
|
||||||
|
password: "Senha *",
|
||||||
|
passwordPlaceholder: "Mínimo 8 caracteres",
|
||||||
|
confirmPassword: "Confirmar senha *",
|
||||||
|
confirmPasswordPlaceholder: "Repita a senha",
|
||||||
termsAccept: "Li e aceito as",
|
termsAccept: "Li e aceito as",
|
||||||
termsLink: "Condições Legais",
|
termsLink: "Condições Legais",
|
||||||
termsAnd: "e a",
|
termsAnd: "e a",
|
||||||
|
|
@ -218,6 +224,8 @@ const contentByLocale = {
|
||||||
paymentRequired: "Selecione um método de pagamento.",
|
paymentRequired: "Selecione um método de pagamento.",
|
||||||
registerError: "Erro ao registrar empresa",
|
registerError: "Erro ao registrar empresa",
|
||||||
unexpectedError: "Erro inesperado ao publicar vaga",
|
unexpectedError: "Erro inesperado ao publicar vaga",
|
||||||
|
passwordRequired: "Informe uma senha com ao menos 8 caracteres.",
|
||||||
|
passwordMismatch: "As senhas não coincidem.",
|
||||||
},
|
},
|
||||||
success: "Vaga cadastrada com sucesso!",
|
success: "Vaga cadastrada com sucesso!",
|
||||||
},
|
},
|
||||||
|
|
@ -335,6 +343,12 @@ const contentByLocale = {
|
||||||
phonePlaceholder: "(00) 0000-0000",
|
phonePlaceholder: "(00) 0000-0000",
|
||||||
mobile: "Mobile",
|
mobile: "Mobile",
|
||||||
mobilePlaceholder: "(00) 00000-0000",
|
mobilePlaceholder: "(00) 00000-0000",
|
||||||
|
accountTitle: "Account access details",
|
||||||
|
accountHint: "You will use this email and password to access the company dashboard.",
|
||||||
|
password: "Password *",
|
||||||
|
passwordPlaceholder: "Minimum 8 characters",
|
||||||
|
confirmPassword: "Confirm password *",
|
||||||
|
confirmPasswordPlaceholder: "Repeat password",
|
||||||
termsAccept: "I have read and accept the",
|
termsAccept: "I have read and accept the",
|
||||||
termsLink: "Legal Terms",
|
termsLink: "Legal Terms",
|
||||||
termsAnd: "and the",
|
termsAnd: "and the",
|
||||||
|
|
@ -374,6 +388,8 @@ const contentByLocale = {
|
||||||
paymentRequired: "Please select a payment method.",
|
paymentRequired: "Please select a payment method.",
|
||||||
registerError: "Error registering company",
|
registerError: "Error registering company",
|
||||||
unexpectedError: "Unexpected error publishing job",
|
unexpectedError: "Unexpected error publishing job",
|
||||||
|
passwordRequired: "Please enter a password with at least 8 characters.",
|
||||||
|
passwordMismatch: "Passwords do not match.",
|
||||||
},
|
},
|
||||||
success: "Job posted successfully!",
|
success: "Job posted successfully!",
|
||||||
},
|
},
|
||||||
|
|
@ -491,6 +507,12 @@ const contentByLocale = {
|
||||||
phonePlaceholder: "(00) 0000-0000",
|
phonePlaceholder: "(00) 0000-0000",
|
||||||
mobile: "Celular",
|
mobile: "Celular",
|
||||||
mobilePlaceholder: "(00) 00000-0000",
|
mobilePlaceholder: "(00) 00000-0000",
|
||||||
|
accountTitle: "Datos de acceso a la cuenta",
|
||||||
|
accountHint: "Usará este correo y contraseña para acceder al panel de la empresa.",
|
||||||
|
password: "Contraseña *",
|
||||||
|
passwordPlaceholder: "Mínimo 8 caracteres",
|
||||||
|
confirmPassword: "Confirmar contraseña *",
|
||||||
|
confirmPasswordPlaceholder: "Repita la contraseña",
|
||||||
termsAccept: "He leído y acepto las",
|
termsAccept: "He leído y acepto las",
|
||||||
termsLink: "Condiciones Legales",
|
termsLink: "Condiciones Legales",
|
||||||
termsAnd: "y la",
|
termsAnd: "y la",
|
||||||
|
|
@ -530,6 +552,8 @@ const contentByLocale = {
|
||||||
paymentRequired: "Seleccione un método de pago.",
|
paymentRequired: "Seleccione un método de pago.",
|
||||||
registerError: "Error al registrar empresa",
|
registerError: "Error al registrar empresa",
|
||||||
unexpectedError: "Error inesperado al publicar vacante",
|
unexpectedError: "Error inesperado al publicar vacante",
|
||||||
|
passwordRequired: "Ingrese una contraseña con al menos 8 caracteres.",
|
||||||
|
passwordMismatch: "Las contraseñas no coinciden.",
|
||||||
},
|
},
|
||||||
success: "¡Vacante publicada con éxito!",
|
success: "¡Vacante publicada con éxito!",
|
||||||
},
|
},
|
||||||
|
|
@ -593,6 +617,8 @@ export default function PostJobPage() {
|
||||||
contactEmail: "",
|
contactEmail: "",
|
||||||
contactPhone: "",
|
contactPhone: "",
|
||||||
contactMobile: "",
|
contactMobile: "",
|
||||||
|
password: "",
|
||||||
|
confirmPassword: "",
|
||||||
acceptTerms: false,
|
acceptTerms: false,
|
||||||
acceptMarketing: false,
|
acceptMarketing: false,
|
||||||
});
|
});
|
||||||
|
|
@ -655,6 +681,14 @@ export default function PostJobPage() {
|
||||||
toast.error(c.errors.billingEmailInvalid);
|
toast.error(c.errors.billingEmailInvalid);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (!billing.password || billing.password.length < 8) {
|
||||||
|
toast.error(c.errors.passwordRequired);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (billing.password !== billing.confirmPassword) {
|
||||||
|
toast.error(c.errors.passwordMismatch);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (!billing.acceptTerms) {
|
if (!billing.acceptTerms) {
|
||||||
toast.error(c.errors.termsRequired);
|
toast.error(c.errors.termsRequired);
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -688,8 +722,8 @@ export default function PostJobPage() {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
try {
|
try {
|
||||||
const apiBase = process.env.NEXT_PUBLIC_API_URL || "";
|
const apiBase = process.env.NEXT_PUBLIC_API_URL || "";
|
||||||
const password = "Temp@123456";
|
|
||||||
const billingPhone = cleanDigits(billing.contactMobile || billing.contactPhone || job.applicationPhone);
|
const billingPhone = cleanDigits(billing.contactMobile || billing.contactPhone || job.applicationPhone);
|
||||||
|
const contactFullName = [billing.contactName, billing.contactLastName].filter(Boolean).join(" ");
|
||||||
|
|
||||||
const registerRes = await fetch(`${apiBase}/api/v1/auth/register/company`, {
|
const registerRes = await fetch(`${apiBase}/api/v1/auth/register/company`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
|
|
@ -697,9 +731,10 @@ export default function PostJobPage() {
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
companyName: company.name,
|
companyName: company.name,
|
||||||
email: billing.contactEmail,
|
email: billing.contactEmail,
|
||||||
|
contact: contactFullName || null,
|
||||||
document: cleanDigits(company.document) || null,
|
document: cleanDigits(company.document) || null,
|
||||||
password,
|
password: billing.password,
|
||||||
phone: billingPhone ? `+55${billingPhone}` : null,
|
phone: billingPhone ? `+${billingPhone}` : null,
|
||||||
website: company.website || null,
|
website: company.website || null,
|
||||||
employeeCount: company.employeeCount || null,
|
employeeCount: company.employeeCount || null,
|
||||||
foundedYear: company.foundedYear ? Number(company.foundedYear) : null,
|
foundedYear: company.foundedYear ? Number(company.foundedYear) : null,
|
||||||
|
|
@ -712,7 +747,7 @@ export default function PostJobPage() {
|
||||||
throw new Error(err.message || c.errors.registerError);
|
throw new Error(err.message || c.errors.registerError);
|
||||||
}
|
}
|
||||||
|
|
||||||
const { token } = await registerRes.json();
|
const { id: companyId, token } = await registerRes.json();
|
||||||
|
|
||||||
const salaryMin = job.salaryMode === "fixed" ? Number(job.salaryFixed || 0) : Number(job.salaryMin || 0);
|
const salaryMin = job.salaryMode === "fixed" ? Number(job.salaryFixed || 0) : Number(job.salaryMin || 0);
|
||||||
const salaryMax = job.salaryMode === "fixed" ? Number(job.salaryFixed || 0) : Number(job.salaryMax || 0);
|
const salaryMax = job.salaryMode === "fixed" ? Number(job.salaryFixed || 0) : Number(job.salaryMax || 0);
|
||||||
|
|
@ -724,6 +759,7 @@ export default function PostJobPage() {
|
||||||
Authorization: `Bearer ${token}`,
|
Authorization: `Bearer ${token}`,
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
|
companyId,
|
||||||
title: job.title,
|
title: job.title,
|
||||||
description: job.description,
|
description: job.description,
|
||||||
location: `${job.location}, ${job.country}`,
|
location: `${job.location}, ${job.country}`,
|
||||||
|
|
@ -1227,6 +1263,33 @@ export default function PostJobPage() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className="border rounded-lg p-4 space-y-4 bg-gray-50">
|
||||||
|
<div>
|
||||||
|
<h4 className="font-semibold text-[#1d2c44]">{c.billing.accountTitle}</h4>
|
||||||
|
<p className="text-xs text-muted-foreground mt-1">{c.billing.accountHint}</p>
|
||||||
|
</div>
|
||||||
|
<div className="grid md:grid-cols-2 gap-4">
|
||||||
|
<div>
|
||||||
|
<Label>{c.billing.password}</Label>
|
||||||
|
<Input
|
||||||
|
type="password"
|
||||||
|
placeholder={c.billing.passwordPlaceholder}
|
||||||
|
value={billing.password}
|
||||||
|
onChange={(e) => setBilling({ ...billing, password: e.target.value })}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<Label>{c.billing.confirmPassword}</Label>
|
||||||
|
<Input
|
||||||
|
type="password"
|
||||||
|
placeholder={c.billing.confirmPasswordPlaceholder}
|
||||||
|
value={billing.confirmPassword}
|
||||||
|
onChange={(e) => setBilling({ ...billing, confirmPassword: e.target.value })}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<Label>{c.billing.billingAddress}</Label>
|
<Label>{c.billing.billingAddress}</Label>
|
||||||
<textarea
|
<textarea
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue