diff --git a/backend/internal/models/job.go b/backend/internal/models/job.go index 4d8f841..d407e51 100755 --- a/backend/internal/models/job.go +++ b/backend/internal/models/job.go @@ -13,10 +13,11 @@ type Job struct { Description string `json:"description" db:"description"` // Salary - SalaryMin *float64 `json:"salaryMin,omitempty" db:"salary_min"` - SalaryMax *float64 `json:"salaryMax,omitempty" db:"salary_max"` - SalaryType *string `json:"salaryType,omitempty" db:"salary_type"` // hourly, daily, weekly, monthly, yearly - Currency *string `json:"currency,omitempty" db:"currency"` // BRL, USD, EUR, GBP, JPY + SalaryMin *float64 `json:"salaryMin,omitempty" db:"salary_min"` + SalaryMax *float64 `json:"salaryMax,omitempty" db:"salary_max"` + SalaryType *string `json:"salaryType,omitempty" db:"salary_type"` // hourly, daily, weekly, monthly, yearly + Currency *string `json:"currency,omitempty" db:"currency"` // BRL, USD, EUR, GBP, JPY + SalaryNegotiable bool `json:"salaryNegotiable" db:"salary_negotiable"` // Candidate proposes salary // Employment EmploymentType *string `json:"employmentType,omitempty" db:"employment_type"` // full-time, part-time, dispatch, contract diff --git a/backend/migrations/030_add_salary_negotiable.sql b/backend/migrations/030_add_salary_negotiable.sql new file mode 100644 index 0000000..2b88cd4 --- /dev/null +++ b/backend/migrations/030_add_salary_negotiable.sql @@ -0,0 +1,6 @@ +-- Migration: Add salary_negotiable column to jobs table +-- Description: When true, salary is hidden and candidate sends proposal + +ALTER TABLE jobs ADD COLUMN IF NOT EXISTS salary_negotiable BOOLEAN DEFAULT false; + +COMMENT ON COLUMN jobs.salary_negotiable IS 'When true, salary is not displayed and candidate proposes their own'; diff --git a/frontend/src/app/post-job/page.tsx b/frontend/src/app/post-job/page.tsx index 9ac624e..d11b95d 100644 --- a/frontend/src/app/post-job/page.tsx +++ b/frontend/src/app/post-job/page.tsx @@ -62,10 +62,15 @@ export default function PostJobPage() { location: "", salaryMin: "", salaryMax: "", + salaryFixed: "", // For fixed salary mode employmentType: "", workMode: "remote", + salaryNegotiable: false, // Candidate proposes salary }); + // Salary mode toggle: 'fixed' | 'range' + const [salaryMode, setSalaryMode] = useState<'fixed' | 'range'>('fixed'); + const formatPhoneForDisplay = (value: string) => { // Simple formatting to just allow numbers and basic separators if needed // For now, just pass through but maybe restrict chars? @@ -135,9 +140,11 @@ export default function PostJobPage() { title: job.title, description: job.description, location: job.location, - salaryMin: job.salaryMin ? parseInt(job.salaryMin) : null, - salaryMax: job.salaryMax ? parseInt(job.salaryMax) : null, - employmentType: job.employmentType, + // Salary logic: if negotiable, send null values + salaryMin: job.salaryNegotiable ? null : (salaryMode === 'fixed' ? (job.salaryFixed ? parseInt(job.salaryFixed) : null) : (job.salaryMin ? parseInt(job.salaryMin) : null)), + salaryMax: job.salaryNegotiable ? null : (salaryMode === 'fixed' ? (job.salaryFixed ? parseInt(job.salaryFixed) : null) : (job.salaryMax ? parseInt(job.salaryMax) : null)), + salaryNegotiable: job.salaryNegotiable, + employmentType: job.employmentType || null, workMode: job.workMode, status: "pending", // Pending review }), @@ -356,25 +363,60 @@ export default function PostJobPage() { /> -
-
- - setJob({ ...job, salaryMin: e.target.value })} - placeholder="5000" - /> -
-
- - setJob({ ...job, salaryMax: e.target.value })} - placeholder="10000" - /> + {/* Salary Section */} +
+
+ +
+ + {!job.salaryNegotiable && ( + <> + {salaryMode === 'fixed' ? ( +
+ setJob({ ...job, salaryFixed: e.target.value })} + placeholder="Valor" + /> +
+ ) : ( +
+ setJob({ ...job, salaryMin: e.target.value })} + placeholder="Mín" + /> + setJob({ ...job, salaryMax: e.target.value })} + placeholder="Máx" + /> +
+ )} + + + )}
@@ -433,8 +475,14 @@ export default function PostJobPage() {

Título: {job.title}

Localização: {job.location || "Não informado"}

-

Salário: {job.salaryMin && job.salaryMax ? `R$ ${job.salaryMin} - R$ ${job.salaryMax}` : "A combinar"}

-

Tipo: {job.employmentType} / {job.workMode}

+

Salário: { + job.salaryNegotiable + ? "Candidato envia proposta" + : salaryMode === 'fixed' + ? (job.salaryFixed ? `R$ ${job.salaryFixed}` : "A combinar") + : (job.salaryMin && job.salaryMax ? `R$ ${job.salaryMin} - R$ ${job.salaryMax}` : "A combinar") + }

+

Tipo: {job.employmentType || "Qualquer"} / {job.workMode}