feat: enhance job form with currency, salary periods, contract types, and add ER diagram docs

This commit is contained in:
Tiago Yamamoto 2025-12-23 22:49:33 -03:00
parent 80d38ee615
commit 42e9f81f48
7 changed files with 316 additions and 92 deletions

View file

@ -7,8 +7,9 @@ type CreateJobRequest struct {
Description string `json:"description" validate:"required,min=20"` Description string `json:"description" validate:"required,min=20"`
SalaryMin *float64 `json:"salaryMin,omitempty"` SalaryMin *float64 `json:"salaryMin,omitempty"`
SalaryMax *float64 `json:"salaryMax,omitempty"` SalaryMax *float64 `json:"salaryMax,omitempty"`
SalaryType *string `json:"salaryType,omitempty" validate:"omitempty,oneof=hourly monthly yearly"` SalaryType *string `json:"salaryType,omitempty" validate:"omitempty,oneof=hourly daily weekly monthly yearly"`
EmploymentType *string `json:"employmentType,omitempty" validate:"omitempty,oneof=full-time part-time dispatch contract"` Currency *string `json:"currency,omitempty" validate:"omitempty,oneof=BRL USD EUR GBP JPY"`
EmploymentType *string `json:"employmentType,omitempty" validate:"omitempty,oneof=full-time part-time dispatch contract temporary training voluntary permanent"`
WorkingHours *string `json:"workingHours,omitempty"` WorkingHours *string `json:"workingHours,omitempty"`
Location *string `json:"location,omitempty"` Location *string `json:"location,omitempty"`
RegionID *int `json:"regionId,omitempty"` RegionID *int `json:"regionId,omitempty"`
@ -26,8 +27,9 @@ type UpdateJobRequest struct {
Description *string `json:"description,omitempty" validate:"omitempty,min=20"` Description *string `json:"description,omitempty" validate:"omitempty,min=20"`
SalaryMin *float64 `json:"salaryMin,omitempty"` SalaryMin *float64 `json:"salaryMin,omitempty"`
SalaryMax *float64 `json:"salaryMax,omitempty"` SalaryMax *float64 `json:"salaryMax,omitempty"`
SalaryType *string `json:"salaryType,omitempty" validate:"omitempty,oneof=hourly monthly yearly"` SalaryType *string `json:"salaryType,omitempty" validate:"omitempty,oneof=hourly daily weekly monthly yearly"`
EmploymentType *string `json:"employmentType,omitempty" validate:"omitempty,oneof=full-time part-time dispatch contract"` Currency *string `json:"currency,omitempty" validate:"omitempty,oneof=BRL USD EUR GBP JPY"`
EmploymentType *string `json:"employmentType,omitempty" validate:"omitempty,oneof=full-time part-time dispatch contract temporary training voluntary permanent"`
WorkingHours *string `json:"workingHours,omitempty"` WorkingHours *string `json:"workingHours,omitempty"`
Location *string `json:"location,omitempty"` Location *string `json:"location,omitempty"`
RegionID *int `json:"regionId,omitempty"` RegionID *int `json:"regionId,omitempty"`

View file

@ -15,7 +15,8 @@ type Job struct {
// Salary // Salary
SalaryMin *float64 `json:"salaryMin,omitempty" db:"salary_min"` SalaryMin *float64 `json:"salaryMin,omitempty" db:"salary_min"`
SalaryMax *float64 `json:"salaryMax,omitempty" db:"salary_max"` SalaryMax *float64 `json:"salaryMax,omitempty" db:"salary_max"`
SalaryType *string `json:"salaryType,omitempty" db:"salary_type"` // hourly, monthly, yearly 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
// Employment // Employment
EmploymentType *string `json:"employmentType,omitempty" db:"employment_type"` // full-time, part-time, dispatch, contract EmploymentType *string `json:"employmentType,omitempty" db:"employment_type"` // full-time, part-time, dispatch, contract

View file

@ -0,0 +1,21 @@
-- Migration: Add currency to jobs and expand options
-- Description: Adds currency field and expands salary_type and employment_type options
-- Add currency column
ALTER TABLE jobs ADD COLUMN IF NOT EXISTS currency VARCHAR(3) DEFAULT 'BRL';
-- Update salary_type constraint to include more options
ALTER TABLE jobs DROP CONSTRAINT IF EXISTS jobs_salary_type_check;
ALTER TABLE jobs ADD CONSTRAINT jobs_salary_type_check
CHECK (salary_type IN ('hourly', 'daily', 'weekly', 'monthly', 'yearly'));
-- Update employment_type constraint to include more options
ALTER TABLE jobs DROP CONSTRAINT IF EXISTS jobs_employment_type_check;
ALTER TABLE jobs ADD CONSTRAINT jobs_employment_type_check
CHECK (employment_type IN ('full-time', 'part-time', 'contract', 'temporary', 'training', 'voluntary', 'dispatch', 'permanent'));
-- Add index for currency filtering
CREATE INDEX IF NOT EXISTS idx_jobs_currency ON jobs(currency);
-- Comments
COMMENT ON COLUMN jobs.currency IS 'Currency code (BRL, USD, EUR, GBP, JPY, etc.)';

View file

@ -1,108 +1,279 @@
# Database Schema Documentation # Database Schema Documentation
This document outlines the database schema for the GoHorseJobs platform, based on the backend Go models. This document outlines the database schema for the GoHorseJobs platform.
## Entity Relationship Diagram
```mermaid
erDiagram
users {
int id PK
varchar identifier UK
varchar password_hash
varchar role
varchar full_name
varchar language
boolean active
timestamp created_at
timestamp updated_at
timestamp last_login_at
}
companies {
int id PK
varchar name
varchar slug UK
varchar type
varchar document
varchar address
int region_id FK
int city_id FK
varchar phone
varchar email
varchar website
varchar logo_url
text description
boolean active
boolean verified
timestamp created_at
timestamp updated_at
}
jobs {
int id PK
int company_id FK
int created_by FK
varchar title
text description
decimal salary_min
decimal salary_max
varchar salary_type
varchar currency
varchar employment_type
varchar work_mode
varchar working_hours
varchar location
int region_id FK
int city_id FK
jsonb requirements
jsonb benefits
boolean visa_support
varchar language_level
varchar status
boolean is_featured
timestamp created_at
timestamp updated_at
}
applications {
int id PK
int job_id FK
int user_id FK
varchar name
varchar email
varchar phone
varchar line_id
varchar whatsapp
text message
varchar resume_url
jsonb documents
varchar status
text notes
timestamp created_at
timestamp updated_at
}
regions {
int id PK
varchar name
varchar country_code
varchar code
}
cities {
int id PK
int region_id FK
varchar name
}
user_companies {
int id PK
int user_id FK
int company_id FK
varchar role
jsonb permissions
}
favorite_jobs {
int id PK
int user_id FK
int job_id FK
}
users ||--o{ user_companies : "belongs to"
companies ||--o{ user_companies : "has members"
companies ||--o{ jobs : "posts"
users ||--o{ jobs : "creates"
jobs ||--o{ applications : "receives"
users ||--o{ applications : "submits"
regions ||--o{ cities : "contains"
regions ||--o{ companies : "located in"
cities ||--o{ companies : "located in"
regions ||--o{ jobs : "located in"
cities ||--o{ jobs : "located in"
users ||--o{ favorite_jobs : "saves"
jobs ||--o{ favorite_jobs : "saved by"
```
## Core Tables ## Core Tables
### Users (`users`) ### Users (`users`)
Represents system users including Candidates, Recruiters, and Admins. Represents system users including Candidates, Recruiters, and Admins.
- **id**: `INTEGER` (PK)
- **identifier**: `VARCHAR` (Unique, Email or Username) | Column | Type | Description |
- **password_hash**: `VARCHAR` |--------|------|-------------|
- **role**: `VARCHAR` (superadmin, companyAdmin, recruiter, jobSeeker) | id | INTEGER | Primary key |
- **full_name**: `VARCHAR` | identifier | VARCHAR | Unique, Email or Username |
- **language**: `VARCHAR` (Default: 'pt') | password_hash | VARCHAR | Bcrypt hash |
- **active**: `BOOLEAN` | role | VARCHAR | `superadmin`, `companyAdmin`, `recruiter`, `jobSeeker` |
- **created_at**, **updated_at**, **last_login_at**: `TIMESTAMP` | full_name | VARCHAR | Display name |
| language | VARCHAR | Default: 'pt' |
| active | BOOLEAN | Account status |
| created_at | TIMESTAMP | Creation time |
| updated_at | TIMESTAMP | Last update |
| last_login_at | TIMESTAMP | Last login |
---
### Companies (`companies`) ### Companies (`companies`)
Represents employer organizations. Represents employer organizations.
- **id**: `INTEGER` (PK)
- **name**: `VARCHAR` | Column | Type | Description |
- **slug**: `VARCHAR` (Unique) |--------|------|-------------|
- **type**: `VARCHAR` | id | INTEGER | Primary key |
- **document**: `VARCHAR` (Houjin Bangou / CNPJ) | name | VARCHAR | Company name |
- **address**, **region_id**, **city_id**, **phone**, **email**, **website**: Contact info | slug | VARCHAR | URL-friendly identifier |
- **logo_url**, **description**: Branding | type | VARCHAR | Company type |
- **active**, **verified**: `BOOLEAN` | document | VARCHAR | Houjin Bangou / CNPJ |
- **created_at**, **updated_at**: `TIMESTAMP` | address | VARCHAR | Physical address |
| region_id | INTEGER | FK → regions.id |
| city_id | INTEGER | FK → cities.id |
| phone, email, website | VARCHAR | Contact info |
| logo_url | VARCHAR | Logo image URL |
| description | TEXT | Company description |
| active | BOOLEAN | Active status |
| verified | BOOLEAN | Verification status |
---
### Jobs (`jobs`) ### Jobs (`jobs`)
Represents job postings. Represents job postings.
- **id**: `INTEGER` (PK)
- **company_id**: `INTEGER` (FK -> companies.id) | Column | Type | Description |
- **created_by**: `INTEGER` (FK -> users.id) |--------|------|-------------|
- **title**: `VARCHAR` | id | INTEGER | Primary key |
- **description**: `TEXT` | company_id | INTEGER | FK → companies.id |
- **salary_min**, **salary_max**: `DECIMAL` | created_by | INTEGER | FK → users.id |
- **salary_type**: `VARCHAR` (hourly, monthly, yearly) | title | VARCHAR | Job title |
- **employment_type**: `VARCHAR` (full-time, part-time, etc.) | description | TEXT | Full job description |
- **work_mode**: `VARCHAR` (onsite, hybrid, remote) | salary_min | DECIMAL | Minimum salary |
- **location**, **region_id**, **city_id**: Location details | salary_max | DECIMAL | Maximum salary |
- **requirements**, **benefits**: `JSONB` | salary_type | VARCHAR | `hourly`, `daily`, `weekly`, `monthly`, `yearly` |
- **visa_support**: `BOOLEAN` | currency | VARCHAR | `BRL`, `USD`, `EUR`, `GBP`, `JPY` |
- **language_level**: `VARCHAR` | employment_type | VARCHAR | `full-time`, `part-time`, `contract`, `temporary`, `training`, `voluntary`, `permanent`, `dispatch` |
- **status**: `VARCHAR` (draft, published, closed, etc.) | work_mode | VARCHAR | `onsite`, `hybrid`, `remote` |
- **is_featured**: `BOOLEAN` | working_hours | VARCHAR | e.g. "9:00-18:00" |
- **created_at**, **updated_at**: `TIMESTAMP` | location | VARCHAR | Location string |
| region_id | INTEGER | FK → regions.id |
| city_id | INTEGER | FK → cities.id |
| requirements | JSONB | Skills/requirements array |
| benefits | JSONB | Benefits array |
| visa_support | BOOLEAN | Visa sponsorship |
| language_level | VARCHAR | `N5`, `N4`, `N3`, `N2`, `N1`, `beginner`, `none` |
| status | VARCHAR | `draft`, `open`, `closed`, `published`, `paused`, `expired`, `archived`, `reported`, `review` |
| is_featured | BOOLEAN | Featured job flag |
---
### Applications (`applications`) ### Applications (`applications`)
Represents job applications. Represents job applications.
- **id**: `INTEGER` (PK)
- **job_id**: `INTEGER` (FK -> jobs.id) | Column | Type | Description |
- **user_id**: `INTEGER` (FK -> users.id, Nullable for guests) |--------|------|-------------|
- **name**, **email**, **phone**, **line_id**, **whatsapp**: Applicant info | id | INTEGER | Primary key |
- **message**: `TEXT` | job_id | INTEGER | FK → jobs.id |
- **resume_url**: `VARCHAR` | user_id | INTEGER | FK → users.id (nullable for guests) |
- **documents**: `JSONB` | name | VARCHAR | Applicant name |
- **status**: `VARCHAR` (pending, reviewed, hired, etc.) | email | VARCHAR | Contact email |
- **notes**: `TEXT` | phone | VARCHAR | Phone number |
- **created_at**, **updated_at**: `TIMESTAMP` | line_id | VARCHAR | LINE ID |
| whatsapp | VARCHAR | WhatsApp number |
| message | TEXT | Cover message |
| resume_url | VARCHAR | Resume file URL |
| documents | JSONB | Additional documents |
| status | VARCHAR | `pending`, `reviewed`, `shortlisted`, `rejected`, `hired` |
| notes | TEXT | Recruiter notes |
---
## Reference Tables ## Reference Tables
### Regions (`regions`) ### Regions (`regions`)
- **id**: `INTEGER` (PK) | Column | Type | Description |
- **name**: `VARCHAR` |--------|------|-------------|
- **country_code**: `VARCHAR` | id | INTEGER | Primary key |
- **code**: `VARCHAR` | name | VARCHAR | Region name |
| country_code | VARCHAR | e.g. "JP", "BR" |
| code | VARCHAR | Region code |
### Cities (`cities`) ### Cities (`cities`)
- **id**: `INTEGER` (PK) | Column | Type | Description |
- **region_id**: `INTEGER` (FK -> regions.id) |--------|------|-------------|
- **name**: `VARCHAR` | id | INTEGER | Primary key |
| region_id | INTEGER | FK → regions.id |
| name | VARCHAR | City name |
### Tags (`tags`) ---
- **id**: `INTEGER` (PK)
- **name**: `VARCHAR`
- **category**: `VARCHAR`
- **active**: `BOOLEAN`
## Relations & Logs ## Junction Tables
### User Companies (`user_companies`) ### User Companies (`user_companies`)
Maps Users to Companies (N:M). Maps users to companies (N:M relationship).
- **id**: `INTEGER` (PK)
- **user_id**: `INTEGER` (FK -> users.id) | Column | Type | Description |
- **company_id**: `INTEGER` (FK -> companies.id) |--------|------|-------------|
- **role**: `VARCHAR` (companyAdmin, recruiter) | id | INTEGER | Primary key |
- **permissions**: `JSONB` | user_id | INTEGER | FK → users.id |
| company_id | INTEGER | FK → companies.id |
| role | VARCHAR | `companyAdmin`, `recruiter` |
| permissions | JSONB | Custom permissions |
### Favorite Jobs (`favorite_jobs`) ### Favorite Jobs (`favorite_jobs`)
- **id**: `INTEGER` (PK) | Column | Type | Description |
- **user_id**: `INTEGER` |--------|------|-------------|
- **job_id**: `INTEGER` | id | INTEGER | Primary key |
| user_id | INTEGER | FK → users.id |
| job_id | INTEGER | FK → jobs.id |
---
## Audit Tables
### Login Audits (`login_audits`) ### Login Audits (`login_audits`)
- **id**: `INTEGER` (PK) | Column | Type | Description |
- **user_id**: `VARCHAR` |--------|------|-------------|
- **identifier**: `VARCHAR` | id | INTEGER | Primary key |
- **ip_address**, **user_agent**: Metadata | user_id | VARCHAR | User identifier |
- **created_at**: `TIMESTAMP` | identifier | VARCHAR | Login identifier used |
| ip_address | VARCHAR | Client IP |
| user_agent | VARCHAR | Browser/client info |
| created_at | TIMESTAMP | Login time |
### Password Resets (`password_resets`) ### Password Resets (`password_resets`)
- **id**: `INTEGER` (PK) | Column | Type | Description |
- **user_id**: `INTEGER` |--------|------|-------------|
- **token**: `VARCHAR` | id | INTEGER | Primary key |
- **expires_at**: `TIMESTAMP` | user_id | INTEGER | FK → users.id |
- **used**: `BOOLEAN` | token | VARCHAR | Reset token |
| expires_at | TIMESTAMP | Token expiry |
| used | BOOLEAN | Token used status |

View file

@ -36,6 +36,7 @@ export default function NewJobPage() {
salaryMin: "", salaryMin: "",
salaryMax: "", salaryMax: "",
salaryType: "", salaryType: "",
currency: "BRL",
workingHours: "", workingHours: "",
}) })
@ -89,6 +90,7 @@ export default function NewJobPage() {
salaryMin: formData.salaryMin ? parseFloat(formData.salaryMin) : undefined, salaryMin: formData.salaryMin ? parseFloat(formData.salaryMin) : undefined,
salaryMax: formData.salaryMax ? parseFloat(formData.salaryMax) : undefined, salaryMax: formData.salaryMax ? parseFloat(formData.salaryMax) : undefined,
salaryType: formData.salaryType as CreateJobPayload['salaryType'] || undefined, salaryType: formData.salaryType as CreateJobPayload['salaryType'] || undefined,
currency: formData.currency as CreateJobPayload['currency'] || undefined,
workingHours: formData.workingHours || undefined, workingHours: formData.workingHours || undefined,
status: "published", status: "published",
} }
@ -251,30 +253,51 @@ export default function NewJobPage() {
/> />
</div> </div>
</div> </div>
<div className="grid grid-cols-2 gap-4"> <div className="grid grid-cols-3 gap-4">
<div className="space-y-2"> <div className="space-y-2">
<Label>Salary Type</Label> <Label>Currency</Label>
<Select value={formData.currency} onValueChange={(v) => updateField("currency", v)}>
<SelectTrigger>
<SelectValue placeholder="Currency" />
</SelectTrigger>
<SelectContent>
<SelectItem value="BRL">R$ (BRL)</SelectItem>
<SelectItem value="USD">$ (USD)</SelectItem>
<SelectItem value="EUR"> (EUR)</SelectItem>
<SelectItem value="GBP">£ (GBP)</SelectItem>
<SelectItem value="JPY">¥ (JPY)</SelectItem>
</SelectContent>
</Select>
</div>
<div className="space-y-2">
<Label>Salary Period</Label>
<Select value={formData.salaryType} onValueChange={(v) => updateField("salaryType", v)}> <Select value={formData.salaryType} onValueChange={(v) => updateField("salaryType", v)}>
<SelectTrigger> <SelectTrigger>
<SelectValue placeholder="Select period" /> <SelectValue placeholder="Select period" />
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
<SelectItem value="hourly">Per hour</SelectItem> <SelectItem value="hourly">Per hour</SelectItem>
<SelectItem value="daily">Per day</SelectItem>
<SelectItem value="weekly">Per week</SelectItem>
<SelectItem value="monthly">Per month</SelectItem> <SelectItem value="monthly">Per month</SelectItem>
<SelectItem value="yearly">Per year</SelectItem> <SelectItem value="yearly">Per year</SelectItem>
</SelectContent> </SelectContent>
</Select> </Select>
</div> </div>
<div className="space-y-2"> <div className="space-y-2">
<Label>Employment Type</Label> <Label>Contract Type</Label>
<Select value={formData.employmentType} onValueChange={(v) => updateField("employmentType", v)}> <Select value={formData.employmentType} onValueChange={(v) => updateField("employmentType", v)}>
<SelectTrigger> <SelectTrigger>
<SelectValue placeholder="Select type" /> <SelectValue placeholder="Select type" />
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
<SelectItem value="permanent">Permanent</SelectItem>
<SelectItem value="full-time">Full-time</SelectItem> <SelectItem value="full-time">Full-time</SelectItem>
<SelectItem value="part-time">Part-time</SelectItem> <SelectItem value="part-time">Part-time</SelectItem>
<SelectItem value="contract">Contract</SelectItem> <SelectItem value="contract">Contract</SelectItem>
<SelectItem value="temporary">Temporary</SelectItem>
<SelectItem value="training">Training</SelectItem>
<SelectItem value="voluntary">Voluntary</SelectItem>
<SelectItem value="dispatch">Dispatch</SelectItem> <SelectItem value="dispatch">Dispatch</SelectItem>
</SelectContent> </SelectContent>
</Select> </Select>
@ -348,7 +371,7 @@ export default function NewJobPage() {
<p className="text-sm text-muted-foreground">Salary</p> <p className="text-sm text-muted-foreground">Salary</p>
<p className="font-medium"> <p className="font-medium">
{formData.salaryMin || formData.salaryMax {formData.salaryMin || formData.salaryMax
? `R$ ${formData.salaryMin || "?"} - R$ ${formData.salaryMax || "?"} ${formData.salaryType ? `(${formData.salaryType})` : ""}` ? `${formData.currency} ${formData.salaryMin || "?"} - ${formData.salaryMax || "?"} ${formData.salaryType ? `(${formData.salaryType})` : ""}`
: "-"} : "-"}
</p> </p>
</div> </div>

View file

@ -290,8 +290,9 @@ export interface CreateJobPayload {
description: string; description: string;
salaryMin?: number; salaryMin?: number;
salaryMax?: number; salaryMax?: number;
salaryType?: 'hourly' | 'monthly' | 'yearly'; salaryType?: 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly';
employmentType?: 'full-time' | 'part-time' | 'dispatch' | 'contract'; currency?: 'BRL' | 'USD' | 'EUR' | 'GBP' | 'JPY';
employmentType?: 'full-time' | 'part-time' | 'dispatch' | 'contract' | 'temporary' | 'training' | 'voluntary' | 'permanent';
workingHours?: string; workingHours?: string;
location?: string; location?: string;
status: 'draft' | 'published' | 'open'; status: 'draft' | 'published' | 'open';

View file

@ -93,15 +93,19 @@ export async function seedJobs() {
const salaryMin = template.salaryRange[0] + getRandomInt(-2000, 2000); const salaryMin = template.salaryRange[0] + getRandomInt(-2000, 2000);
const salaryMax = template.salaryRange[1] + getRandomInt(-2000, 3000); const salaryMax = template.salaryRange[1] + getRandomInt(-2000, 3000);
const employmentTypes = ['full-time', 'part-time', 'contract']; const employmentTypes = ['full-time', 'part-time', 'contract', 'permanent', 'temporary', 'training'];
const employmentType = employmentTypes[i % employmentTypes.length]; // Deterministic variety const currencies = ['BRL', 'BRL', 'BRL', 'BRL', 'BRL', 'BRL', 'BRL', 'USD', 'USD', 'EUR']; // 70% BRL, 20% USD, 10% EUR
const salaryTypes = ['hourly', 'daily', 'weekly', 'monthly', 'yearly'];
const employmentType = employmentTypes[i % employmentTypes.length];
const currency = currencies[i % currencies.length];
const salaryType = salaryTypes[i % salaryTypes.length];
const jobId = crypto.randomUUID(); const jobId = crypto.randomUUID();
await pool.query(` await pool.query(`
INSERT INTO jobs (id, company_id, created_by, title, description, INSERT INTO jobs (id, company_id, created_by, title, description,
salary_min, salary_max, salary_type, employment_type, working_hours, salary_min, salary_max, salary_type, currency, employment_type, working_hours,
location, requirements, benefits, visa_support, language_level, status, work_mode) location, requirements, benefits, visa_support, language_level, status, work_mode)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18)
`, [ `, [
jobId, jobId,
company.id, company.id,
@ -110,7 +114,8 @@ export async function seedJobs() {
`We are looking for a talented ${title} to join our ${company.name} team. Your role as ${level} will be crucial.`, `We are looking for a talented ${title} to join our ${company.name} team. Your role as ${level} will be crucial.`,
salaryMin, salaryMin,
salaryMax, salaryMax,
'monthly', salaryType,
currency,
employmentType, employmentType,
workMode === 'remote' ? 'Flexible' : '9:00-18:00', workMode === 'remote' ? 'Flexible' : '9:00-18:00',
workMode === 'remote' ? 'Remote (Global)' : internationalLocations[i % internationalLocations.length], workMode === 'remote' ? 'Remote (Global)' : internationalLocations[i % internationalLocations.length],