From 8fbb54c977fbedf2630b4a9920c4c4c6e55ec0a7 Mon Sep 17 00:00:00 2001 From: Tiago Yamamoto Date: Tue, 17 Feb 2026 09:42:31 -0300 Subject: [PATCH] refactor job posting routes and add dashboard job creation page --- docs/TASKS.md | 2 +- docs/publicar-vaga-routes.md | 11 +- frontend/FRONTEND.md | 4 +- frontend/src/app/about/page.tsx | 2 +- frontend/src/app/contact/page.tsx | 2 +- frontend/src/app/dashboard/jobs/new/page.tsx | 294 ++++++++++++++- frontend/src/app/dashboard/jobs/page.tsx | 2 +- frontend/src/app/dashboard/my-jobs/page.tsx | 4 +- .../app/{post-job => jobs/new}/page.test.tsx | 0 .../src/app/{post-job => jobs/new}/page.tsx | 0 .../{post-job => jobs/new}/translations.ts | 0 frontend/src/app/publicar-vaga/page.tsx | 349 +----------------- frontend/src/components/company-sidebar.tsx | 2 +- frontend/src/components/footer.tsx | 2 +- 14 files changed, 310 insertions(+), 364 deletions(-) rename frontend/src/app/{post-job => jobs/new}/page.test.tsx (100%) rename frontend/src/app/{post-job => jobs/new}/page.tsx (100%) rename frontend/src/app/{post-job => jobs/new}/translations.ts (100%) diff --git a/docs/TASKS.md b/docs/TASKS.md index 6b97bc9..e52e171 100644 --- a/docs/TASKS.md +++ b/docs/TASKS.md @@ -24,7 +24,7 @@ Lista detalhada de tarefas para evitar retrabalho. - Frontend: profileApi.uploadAvatar - [x] **Public Job Posting** - - Frontend: `/post-job` page + - Frontend: `/jobs/new` page - 3-step wizard (Company + Job + Confirm) - [x] **Documentation** diff --git a/docs/publicar-vaga-routes.md b/docs/publicar-vaga-routes.md index 67adb68..f73f32f 100644 --- a/docs/publicar-vaga-routes.md +++ b/docs/publicar-vaga-routes.md @@ -2,11 +2,12 @@ As principais rotas usadas para publicar vagas no projeto são: -1. `/publicar-vaga` — landing/formulário público de anúncio de vaga. -2. `/post-job` — fluxo principal multi-etapas para publicação com dados da empresa e da vaga. -3. `/register/job` — formulário público alternativo para criação de vaga. +1. `/jobs/new` — fluxo público principal (multi-etapas) para publicação com dados da empresa e da vaga. +2. `/publicar-vaga` — rota legada redirecionando para `/jobs/new`. +3. `/dashboard/jobs/new` — fluxo interno no dashboard para cadastro rápido de vaga (design system do dashboard). +4. `/register/job` — formulário público alternativo para criação de vaga. ## Pontos de entrada no sistema -- Link para `/publicar-vaga` na página **About** e no **Footer**. -- Link para `/post-job` na página **Contact**. +- Link para `/jobs/new` na página **About**, **Footer** e **Contact**. +- Link para `/dashboard/jobs/new` nas páginas internas do dashboard (Jobs, My Jobs e sidebar da empresa). diff --git a/frontend/FRONTEND.md b/frontend/FRONTEND.md index 4af7b1f..2af81b4 100644 --- a/frontend/FRONTEND.md +++ b/frontend/FRONTEND.md @@ -72,7 +72,7 @@ src/ │ ├── page.tsx # Landing page │ ├── login/ # Autenticação │ ├── register/ # Registro (candidate, company) -│ ├── post-job/ # **NEW** Wizard público +│ ├── jobs/new/ # **NEW** Wizard público │ ├── jobs/ # Listagem e detalhes │ │ ├── page.tsx # Listagem │ │ ├── [id]/page.tsx # Detalhes @@ -143,7 +143,7 @@ src/ | `/login` | Login | | `/register/candidate` | Registro candidato | | `/register/company` | Registro empresa | -| `/post-job` | **NEW** Wizard público (registro + vaga) | +| `/jobs/new` | **NEW** Wizard público (registro + vaga) | | `/about` | Sobre | | `/contact` | Contato | | `/faq` | FAQ | diff --git a/frontend/src/app/about/page.tsx b/frontend/src/app/about/page.tsx index f43761a..7b0f157 100644 --- a/frontend/src/app/about/page.tsx +++ b/frontend/src/app/about/page.tsx @@ -243,7 +243,7 @@ export default function AboutPage() { {t('about.cta.findJobs')} {t('about.cta.postJob')} diff --git a/frontend/src/app/contact/page.tsx b/frontend/src/app/contact/page.tsx index 648388b..2925f20 100644 --- a/frontend/src/app/contact/page.tsx +++ b/frontend/src/app/contact/page.tsx @@ -152,7 +152,7 @@ export default function ContactPage() { - +
diff --git a/frontend/src/app/dashboard/jobs/new/page.tsx b/frontend/src/app/dashboard/jobs/new/page.tsx index 642716a..1b15f29 100644 --- a/frontend/src/app/dashboard/jobs/new/page.tsx +++ b/frontend/src/app/dashboard/jobs/new/page.tsx @@ -1,5 +1,293 @@ -import { redirect } from "next/navigation" +"use client" -export default function DashboardNewJobRedirectPage() { - redirect("/publicar-vaga") +import { useEffect, useState } from "react" +import { Loader2, PlusCircle } from "lucide-react" +import { toast } from "sonner" + +import { Button } from "@/components/ui/button" +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" +import { Input } from "@/components/ui/input" +import { Label } from "@/components/ui/label" +import { Textarea } from "@/components/ui/textarea" +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select" +import { adminCompaniesApi, jobsApi, type AdminCompany, type CreateJobPayload } from "@/lib/api" + +export default function DashboardNewJobPage() { + const [loading, setLoading] = useState(false) + const [loadingCompanies, setLoadingCompanies] = useState(true) + const [companies, setCompanies] = useState([]) + + const [formData, setFormData] = useState({ + title: "", + description: "", + location: "", + salaryMin: "", + salaryMax: "", + salaryType: "monthly", + currency: "BRL", + employmentType: "", + workingHours: "", + companyId: "", + }) + + useEffect(() => { + const loadCompanies = async () => { + try { + setLoadingCompanies(true) + const data = await adminCompaniesApi.list(undefined, 1, 100) + setCompanies(data.data ?? []) + } catch (error) { + console.error("Falha ao carregar empresas:", error) + toast.error("Falha ao carregar empresas") + } finally { + setLoadingCompanies(false) + } + } + + loadCompanies() + }, []) + + const canSubmit = + formData.title.trim().length >= 5 && + formData.description.trim().length >= 20 && + formData.companyId !== "" + + const handleInputChange = (field: string, value: string) => { + setFormData((prev) => ({ ...prev, [field]: value })) + } + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault() + + if (!canSubmit) { + toast.error("Preencha os campos obrigatórios") + return + } + + setLoading(true) + try { + const payload: CreateJobPayload = { + companyId: formData.companyId, + title: formData.title, + description: formData.description, + location: formData.location || undefined, + employmentType: + (formData.employmentType as CreateJobPayload["employmentType"]) || undefined, + salaryMin: formData.salaryMin ? parseFloat(formData.salaryMin) : undefined, + salaryMax: formData.salaryMax ? parseFloat(formData.salaryMax) : undefined, + salaryType: (formData.salaryType as CreateJobPayload["salaryType"]) || undefined, + currency: (formData.currency as CreateJobPayload["currency"]) || undefined, + workingHours: formData.workingHours || undefined, + status: "draft", + } + + await jobsApi.create(payload) + toast.success("Vaga cadastrada no dashboard com sucesso") + setFormData({ + title: "", + description: "", + location: "", + salaryMin: "", + salaryMax: "", + salaryType: "monthly", + currency: "BRL", + employmentType: "", + workingHours: "", + companyId: "", + }) + } catch (error: any) { + console.error("Falha ao cadastrar vaga:", error) + toast.error(error.message || "Falha ao cadastrar vaga") + } finally { + setLoading(false) + } + } + + return ( +
+
+
+

Nova vaga

+

+ Cadastre vagas usando o padrão visual do dashboard. +

+
+
+ + + + + Dados da vaga + + + Informe os detalhes obrigatórios para criar a vaga em rascunho. + + + +
+
+ + handleInputChange("title", e.target.value)} + /> +
+ +
+ +