Merge pull request #15 from rede5/codex/update-page-slugs-and-content-language

Translate UI and rename routes to English
This commit is contained in:
Tiago Yamamoto 2025-12-22 15:30:42 -03:00 committed by GitHub
commit 360393ba15
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
39 changed files with 729 additions and 758 deletions

View file

@ -3,31 +3,31 @@ import { Footer } from "@/components/footer"
import { Card, CardContent } from "@/components/ui/card" import { Card, CardContent } from "@/components/ui/card"
import { Target, Users, Zap, Shield } from "lucide-react" import { Target, Users, Zap, Shield } from "lucide-react"
export default function SobrePage() { export default function AboutPage() {
const values = [ const values = [
{ {
icon: Target, icon: Target,
title: "Missão", title: "Mission",
description: description:
"Conectar talentos excepcionais com oportunidades transformadoras, facilitando o crescimento profissional e empresarial.", "Connect exceptional talent with transformative opportunities, helping professionals and companies grow.",
}, },
{ {
icon: Users, icon: Users,
title: "Comunidade", title: "Community",
description: description:
"Construir uma comunidade inclusiva onde candidatos e empresas encontram o match perfeito para suas necessidades.", "Build an inclusive community where candidates and companies find the right match for their needs.",
}, },
{ {
icon: Zap, icon: Zap,
title: "Eficiência", title: "Efficiency",
description: description:
"Simplificar o processo de recrutamento com tecnologia intuitiva e processos otimizados para economizar tempo.", "Simplify recruiting with intuitive technology and optimized workflows that save time.",
}, },
{ {
icon: Shield, icon: Shield,
title: "Confiança", title: "Trust",
description: description:
"Garantir transparência e segurança em todas as interações, protegendo dados e promovendo relações éticas.", "Ensure transparency and security in every interaction, protecting data and promoting ethical relationships.",
}, },
] ]
@ -41,11 +41,11 @@ export default function SobrePage() {
<div className="container mx-auto px-4 sm:px-6 lg:px-8"> <div className="container mx-auto px-4 sm:px-6 lg:px-8">
<div className="max-w-3xl mx-auto text-center"> <div className="max-w-3xl mx-auto text-center">
<h1 className="text-4xl md:text-5xl font-bold text-foreground mb-6 text-balance"> <h1 className="text-4xl md:text-5xl font-bold text-foreground mb-6 text-balance">
Sobre o Portal de Empregos About the Jobs Portal
</h1> </h1>
<p className="text-lg text-muted-foreground leading-relaxed text-pretty"> <p className="text-lg text-muted-foreground leading-relaxed text-pretty">
Somos uma plataforma dedicada a transformar a forma como pessoas encontram oportunidades profissionais e We are a platform dedicated to transforming how people find professional opportunities and how companies
como empresas descobrem talentos excepcionais. discover exceptional talent.
</p> </p>
</div> </div>
</div> </div>
@ -55,19 +55,19 @@ export default function SobrePage() {
<section className="py-16 md:py-24"> <section className="py-16 md:py-24">
<div className="container mx-auto px-4 sm:px-6 lg:px-8"> <div className="container mx-auto px-4 sm:px-6 lg:px-8">
<div className="max-w-3xl mx-auto"> <div className="max-w-3xl mx-auto">
<h2 className="text-3xl font-bold text-foreground mb-6">Nossa História</h2> <h2 className="text-3xl font-bold text-foreground mb-6">Our Story</h2>
<div className="space-y-4 text-muted-foreground leading-relaxed"> <div className="space-y-4 text-muted-foreground leading-relaxed">
<p> <p>
Fundado em 2025, o Portal de Empregos nasceu da necessidade de simplificar o processo de recrutamento, Founded in 2025, GoHorse Jobs was created to simplify recruiting, making it more transparent,
tornando-o mais transparente, eficiente e acessível para todos. efficient, and accessible to everyone.
</p> </p>
<p> <p>
Acreditamos que encontrar o emprego ideal não deveria ser complicado. Por isso, criamos uma plataforma We believe that finding the right job should be simple. That is why we built a minimalist,
minimalista e intuitiva que coloca candidatos e empresas em primeiro lugar. intuitive platform that puts candidates and companies first.
</p> </p>
<p> <p>
Hoje, conectamos milhares de profissionais com empresas inovadoras, ajudando a construir carreiras de Today, we connect thousands of professionals with innovative companies, helping build successful
sucesso e equipes extraordinárias. careers and extraordinary teams.
</p> </p>
</div> </div>
</div> </div>
@ -78,7 +78,7 @@ export default function SobrePage() {
<section className="py-16 md:py-24 bg-muted/30"> <section className="py-16 md:py-24 bg-muted/30">
<div className="container mx-auto px-4 sm:px-6 lg:px-8"> <div className="container mx-auto px-4 sm:px-6 lg:px-8">
<div className="max-w-5xl mx-auto"> <div className="max-w-5xl mx-auto">
<h2 className="text-3xl font-bold text-foreground mb-12 text-center">Nossos Valores</h2> <h2 className="text-3xl font-bold text-foreground mb-12 text-center">Our Values</h2>
<div className="grid md:grid-cols-2 gap-6"> <div className="grid md:grid-cols-2 gap-6">
{values.map((value, index) => ( {values.map((value, index) => (
<Card key={index}> <Card key={index}>

View file

@ -12,7 +12,7 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/com
import { Label } from "@/components/ui/label" import { Label } from "@/components/ui/label"
import { Mail, MessageSquare, Phone, MapPin } from "lucide-react" import { Mail, MessageSquare, Phone, MapPin } from "lucide-react"
export default function ContatoPage() { export default function ContactPage() {
const [submitted, setSubmitted] = useState(false) const [submitted, setSubmitted] = useState(false)
const handleSubmit = (e: React.FormEvent) => { const handleSubmit = (e: React.FormEvent) => {
@ -30,9 +30,9 @@ export default function ContatoPage() {
<section className="bg-muted/30 py-16 md:py-24"> <section className="bg-muted/30 py-16 md:py-24">
<div className="container mx-auto px-4 sm:px-6 lg:px-8"> <div className="container mx-auto px-4 sm:px-6 lg:px-8">
<div className="max-w-3xl mx-auto text-center"> <div className="max-w-3xl mx-auto text-center">
<h1 className="text-4xl md:text-5xl font-bold text-foreground mb-6 text-balance">Entre em Contato</h1> <h1 className="text-4xl md:text-5xl font-bold text-foreground mb-6 text-balance">Get in Touch</h1>
<p className="text-lg text-muted-foreground text-pretty"> <p className="text-lg text-muted-foreground text-pretty">
Tem alguma dúvida ou sugestão? Estamos aqui para ajudar. Entre em contato conosco. Have a question or suggestion? We are here to help. Reach out anytime.
</p> </p>
</div> </div>
</div> </div>
@ -45,33 +45,33 @@ export default function ContatoPage() {
{/* Contact Form */} {/* Contact Form */}
<Card> <Card>
<CardHeader> <CardHeader>
<CardTitle>Envie uma mensagem</CardTitle> <CardTitle>Send a message</CardTitle>
<CardDescription>Preencha o formulário e retornaremos em breve</CardDescription> <CardDescription>Fill out the form and we will get back to you soon.</CardDescription>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<form onSubmit={handleSubmit} className="space-y-4"> <form onSubmit={handleSubmit} className="space-y-4">
<div className="space-y-2"> <div className="space-y-2">
<Label htmlFor="name">Nome completo</Label> <Label htmlFor="name">Full name</Label>
<Input id="name" placeholder="Seu nome" required /> <Input id="name" placeholder="Your name" required />
</div> </div>
<div className="space-y-2"> <div className="space-y-2">
<Label htmlFor="email">E-mail</Label> <Label htmlFor="email">Email</Label>
<Input id="email" type="email" placeholder="seu@email.com" required /> <Input id="email" type="email" placeholder="you@email.com" required />
</div> </div>
<div className="space-y-2"> <div className="space-y-2">
<Label htmlFor="subject">Assunto</Label> <Label htmlFor="subject">Subject</Label>
<Input id="subject" placeholder="Como podemos ajudar?" required /> <Input id="subject" placeholder="How can we help?" required />
</div> </div>
<div className="space-y-2"> <div className="space-y-2">
<Label htmlFor="message">Mensagem</Label> <Label htmlFor="message">Message</Label>
<Textarea id="message" placeholder="Descreva sua dúvida ou sugestão..." rows={5} required /> <Textarea id="message" placeholder="Describe your question or suggestion..." rows={5} required />
</div> </div>
<Button type="submit" className="w-full cursor-pointer" disabled={submitted}> <Button type="submit" className="w-full cursor-pointer" disabled={submitted}>
{submitted ? "Mensagem enviada!" : "Enviar mensagem"} {submitted ? "Message sent!" : "Send message"}
</Button> </Button>
</form> </form>
</CardContent> </CardContent>
@ -80,15 +80,15 @@ export default function ContatoPage() {
{/* Contact Info */} {/* Contact Info */}
<div className="space-y-8"> <div className="space-y-8">
<div> <div>
<h2 className="text-2xl font-bold mb-6">Outras formas de contato</h2> <h2 className="text-2xl font-bold mb-6">Other ways to reach us</h2>
<div className="space-y-6"> <div className="space-y-6">
<div className="flex items-start gap-4"> <div className="flex items-start gap-4">
<div className="p-3 rounded-lg bg-primary/10"> <div className="p-3 rounded-lg bg-primary/10">
<Mail className="h-5 w-5 text-primary" /> <Mail className="h-5 w-5 text-primary" />
</div> </div>
<div> <div>
<h3 className="font-semibold mb-1">E-mail</h3> <h3 className="font-semibold mb-1">Email</h3>
<p className="text-sm text-muted-foreground">contato@portalempregos.com</p> <p className="text-sm text-muted-foreground">hello@gohorsejobs.com</p>
</div> </div>
</div> </div>
@ -97,7 +97,7 @@ export default function ContatoPage() {
<Phone className="h-5 w-5 text-primary" /> <Phone className="h-5 w-5 text-primary" />
</div> </div>
<div> <div>
<h3 className="font-semibold mb-1">Telefone</h3> <h3 className="font-semibold mb-1">Phone</h3>
<p className="text-sm text-muted-foreground">(11) 9999-9999</p> <p className="text-sm text-muted-foreground">(11) 9999-9999</p>
</div> </div>
</div> </div>
@ -107,9 +107,9 @@ export default function ContatoPage() {
<MapPin className="h-5 w-5 text-primary" /> <MapPin className="h-5 w-5 text-primary" />
</div> </div>
<div> <div>
<h3 className="font-semibold mb-1">Endereço</h3> <h3 className="font-semibold mb-1">Address</h3>
<p className="text-sm text-muted-foreground"> <p className="text-sm text-muted-foreground">
Av. Paulista, 1000 1000 Paulista Ave
<br /> <br />
São Paulo, SP - 01310-100 São Paulo, SP - 01310-100
</p> </p>
@ -121,8 +121,8 @@ export default function ContatoPage() {
<MessageSquare className="h-5 w-5 text-primary" /> <MessageSquare className="h-5 w-5 text-primary" />
</div> </div>
<div> <div>
<h3 className="font-semibold mb-1">Suporte</h3> <h3 className="font-semibold mb-1">Support</h3>
<p className="text-sm text-muted-foreground">Segunda a Sexta, 9h às 18h</p> <p className="text-sm text-muted-foreground">Monday to Friday, 9am to 6pm</p>
</div> </div>
</div> </div>
</div> </div>
@ -130,13 +130,12 @@ export default function ContatoPage() {
<Card className="bg-muted/50"> <Card className="bg-muted/50">
<CardContent className="pt-6"> <CardContent className="pt-6">
<h3 className="font-semibold mb-2">Perguntas Frequentes</h3> <h3 className="font-semibold mb-2">Frequently Asked Questions</h3>
<p className="text-sm text-muted-foreground mb-4"> <p className="text-sm text-muted-foreground mb-4">
Antes de entrar em contato, confira nossa seção de perguntas frequentes. Talvez sua dúvida Before reaching out, check our FAQ section. Your question may already be answered there.
esteja respondida .
</p> </p>
<Button variant="outline" className="w-full cursor-pointer bg-transparent"> <Button variant="outline" className="w-full cursor-pointer bg-transparent">
Ver FAQ View FAQ
</Button> </Button>
</CardContent> </CardContent>
</Card> </Card>

View file

@ -32,33 +32,33 @@ export default function AdminCandidatesPage() {
<div className="space-y-8"> <div className="space-y-8">
{/* Header */} {/* Header */}
<div> <div>
<h1 className="text-3xl font-bold text-foreground">Gestão de Candidatos</h1> <h1 className="text-3xl font-bold text-foreground">Candidate management</h1>
<p className="text-muted-foreground mt-1">Visualize e gerencie todos os candidatos cadastrados</p> <p className="text-muted-foreground mt-1">View and manage all registered candidates</p>
</div> </div>
{/* Stats */} {/* Stats */}
<div className="grid gap-4 md:grid-cols-4"> <div className="grid gap-4 md:grid-cols-4">
<Card> <Card>
<CardHeader className="pb-3"> <CardHeader className="pb-3">
<CardDescription>Total de Candidatos</CardDescription> <CardDescription>Total candidates</CardDescription>
<CardTitle className="text-3xl">{mockCandidates.length}</CardTitle> <CardTitle className="text-3xl">{mockCandidates.length}</CardTitle>
</CardHeader> </CardHeader>
</Card> </Card>
<Card> <Card>
<CardHeader className="pb-3"> <CardHeader className="pb-3">
<CardDescription>Novos (30 dias)</CardDescription> <CardDescription>New (30 days)</CardDescription>
<CardTitle className="text-3xl">24</CardTitle> <CardTitle className="text-3xl">24</CardTitle>
</CardHeader> </CardHeader>
</Card> </Card>
<Card> <Card>
<CardHeader className="pb-3"> <CardHeader className="pb-3">
<CardDescription>Candidaturas Ativas</CardDescription> <CardDescription>Active applications</CardDescription>
<CardTitle className="text-3xl">{"49"}</CardTitle> <CardTitle className="text-3xl">{"49"}</CardTitle>
</CardHeader> </CardHeader>
</Card> </Card>
<Card> <Card>
<CardHeader className="pb-3"> <CardHeader className="pb-3">
<CardDescription>Taxa de Contratação</CardDescription> <CardDescription>Hiring rate</CardDescription>
<CardTitle className="text-3xl">8%</CardTitle> <CardTitle className="text-3xl">8%</CardTitle>
</CardHeader> </CardHeader>
</Card> </Card>
@ -71,7 +71,7 @@ export default function AdminCandidatesPage() {
<div className="relative flex-1"> <div className="relative flex-1">
<Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" /> <Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
<Input <Input
placeholder="Buscar candidatos por nome ou email..." placeholder="Search candidates by name or email..."
value={searchTerm} value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)} onChange={(e) => setSearchTerm(e.target.value)}
className="pl-10" className="pl-10"
@ -83,12 +83,12 @@ export default function AdminCandidatesPage() {
<Table> <Table>
<TableHeader> <TableHeader>
<TableRow> <TableRow>
<TableHead>Candidato</TableHead> <TableHead>Candidate</TableHead>
<TableHead>Email</TableHead> <TableHead>Email</TableHead>
<TableHead>Telefone</TableHead> <TableHead>Phone</TableHead>
<TableHead>Localização</TableHead> <TableHead>Location</TableHead>
<TableHead>Candidaturas</TableHead> <TableHead>Applications</TableHead>
<TableHead className="text-right">Ações</TableHead> <TableHead className="text-right">Actions</TableHead>
</TableRow> </TableRow>
</TableHeader> </TableHeader>
<TableBody> <TableBody>
@ -118,8 +118,8 @@ export default function AdminCandidatesPage() {
</DialogTrigger> </DialogTrigger>
<DialogContent className="max-w-2xl"> <DialogContent className="max-w-2xl">
<DialogHeader> <DialogHeader>
<DialogTitle>Perfil do Candidato</DialogTitle> <DialogTitle>Candidate profile</DialogTitle>
<DialogDescription>Informações detalhadas sobre {candidate.name}</DialogDescription> <DialogDescription>Detailed information about {candidate.name}</DialogDescription>
</DialogHeader> </DialogHeader>
{selectedCandidate && ( {selectedCandidate && (
<div className="space-y-6"> <div className="space-y-6">
@ -166,12 +166,12 @@ export default function AdminCandidatesPage() {
</div> </div>
<div> <div>
<h4 className="font-semibold mb-2">Sobre</h4> <h4 className="font-semibold mb-2">About</h4>
<p className="text-sm text-muted-foreground">{selectedCandidate.bio}</p> <p className="text-sm text-muted-foreground">{selectedCandidate.bio}</p>
</div> </div>
<div> <div>
<h4 className="font-semibold mb-2">Candidaturas Recentes</h4> <h4 className="font-semibold mb-2">Recent applications</h4>
<div className="space-y-2"> <div className="space-y-2">
{selectedCandidate.applications.map((app: any) => ( {selectedCandidate.applications.map((app: any) => (
<div <div
@ -191,9 +191,9 @@ export default function AdminCandidatesPage() {
: "secondary" : "secondary"
} }
> >
{app.status === "pending" && "Pendente"} {app.status === "pending" && "Pending"}
{app.status === "accepted" && "Aceito"} {app.status === "accepted" && "Accepted"}
{app.status === "rejected" && "Rejeitado"} {app.status === "rejected" && "Rejected"}
</Badge> </Badge>
</div> </div>
))} ))}

View file

@ -51,7 +51,7 @@ export default function AdminCompaniesPage() {
setCompanies(data || []) setCompanies(data || [])
} catch (error) { } catch (error) {
console.error("Error loading companies:", error) console.error("Error loading companies:", error)
toast.error("Erro ao carregar empresas") toast.error("Failed to load companies")
} finally { } finally {
setLoading(false) setLoading(false)
} }
@ -61,13 +61,13 @@ export default function AdminCompaniesPage() {
try { try {
setCreating(true) setCreating(true)
await companiesApi.create(formData) await companiesApi.create(formData)
toast.success("Empresa criada com sucesso!") toast.success("Company created successfully!")
setIsDialogOpen(false) setIsDialogOpen(false)
setFormData({ name: "", slug: "", email: "" }) setFormData({ name: "", slug: "", email: "" })
loadCompanies() loadCompanies()
} catch (error) { } catch (error) {
console.error("Error creating company:", error) console.error("Error creating company:", error)
toast.error("Erro ao criar empresa") toast.error("Failed to create company")
} finally { } finally {
setCreating(false) setCreating(false)
} }
@ -93,29 +93,29 @@ export default function AdminCompaniesPage() {
{/* Header */} {/* Header */}
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div> <div>
<h1 className="text-3xl font-bold text-foreground">Gestão de Empresas</h1> <h1 className="text-3xl font-bold text-foreground">Company management</h1>
<p className="text-muted-foreground mt-1">Gerencie todas as empresas cadastradas</p> <p className="text-muted-foreground mt-1">Manage all registered companies</p>
</div> </div>
<div className="flex gap-2"> <div className="flex gap-2">
<Button variant="outline" onClick={loadCompanies} disabled={loading}> <Button variant="outline" onClick={loadCompanies} disabled={loading}>
<RefreshCw className={`h-4 w-4 mr-2 ${loading ? "animate-spin" : ""}`} /> <RefreshCw className={`h-4 w-4 mr-2 ${loading ? "animate-spin" : ""}`} />
Atualizar Refresh
</Button> </Button>
<Dialog open={isDialogOpen} onOpenChange={setIsDialogOpen}> <Dialog open={isDialogOpen} onOpenChange={setIsDialogOpen}>
<DialogTrigger asChild> <DialogTrigger asChild>
<Button className="gap-2"> <Button className="gap-2">
<Plus className="h-4 w-4" /> <Plus className="h-4 w-4" />
Nova Empresa New company
</Button> </Button>
</DialogTrigger> </DialogTrigger>
<DialogContent> <DialogContent>
<DialogHeader> <DialogHeader>
<DialogTitle>Cadastrar Nova Empresa</DialogTitle> <DialogTitle>Create new company</DialogTitle>
<DialogDescription>Preencha os dados da empresa</DialogDescription> <DialogDescription>Fill in the company details</DialogDescription>
</DialogHeader> </DialogHeader>
<div className="grid gap-4 py-4"> <div className="grid gap-4 py-4">
<div className="grid gap-2"> <div className="grid gap-2">
<Label htmlFor="name">Nome da Empresa</Label> <Label htmlFor="name">Company name</Label>
<Input <Input
id="name" id="name"
value={formData.name} value={formData.name}
@ -126,7 +126,7 @@ export default function AdminCompaniesPage() {
slug: generateSlug(e.target.value), slug: generateSlug(e.target.value),
}) })
} }
placeholder="Empresa XYZ" placeholder="Company XYZ"
/> />
</div> </div>
<div className="grid gap-2"> <div className="grid gap-2">
@ -145,15 +145,15 @@ export default function AdminCompaniesPage() {
type="email" type="email"
value={formData.email} value={formData.email}
onChange={(e) => setFormData({ ...formData, email: e.target.value })} onChange={(e) => setFormData({ ...formData, email: e.target.value })}
placeholder="contato@empresa.com" placeholder="hello@company.com"
/> />
</div> </div>
</div> </div>
<DialogFooter> <DialogFooter>
<Button variant="outline" onClick={() => setIsDialogOpen(false)}>Cancelar</Button> <Button variant="outline" onClick={() => setIsDialogOpen(false)}>Cancel</Button>
<Button onClick={handleCreate} disabled={creating}> <Button onClick={handleCreate} disabled={creating}>
{creating && <Loader2 className="h-4 w-4 mr-2 animate-spin" />} {creating && <Loader2 className="h-4 w-4 mr-2 animate-spin" />}
Criar Empresa Create company
</Button> </Button>
</DialogFooter> </DialogFooter>
</DialogContent> </DialogContent>
@ -165,25 +165,25 @@ export default function AdminCompaniesPage() {
<div className="grid gap-4 md:grid-cols-4"> <div className="grid gap-4 md:grid-cols-4">
<Card> <Card>
<CardHeader className="pb-3"> <CardHeader className="pb-3">
<CardDescription>Total de Empresas</CardDescription> <CardDescription>Total companies</CardDescription>
<CardTitle className="text-3xl">{companies.length}</CardTitle> <CardTitle className="text-3xl">{companies.length}</CardTitle>
</CardHeader> </CardHeader>
</Card> </Card>
<Card> <Card>
<CardHeader className="pb-3"> <CardHeader className="pb-3">
<CardDescription>Empresas Ativas</CardDescription> <CardDescription>Active companies</CardDescription>
<CardTitle className="text-3xl">{companies.filter((c) => c.active).length}</CardTitle> <CardTitle className="text-3xl">{companies.filter((c) => c.active).length}</CardTitle>
</CardHeader> </CardHeader>
</Card> </Card>
<Card> <Card>
<CardHeader className="pb-3"> <CardHeader className="pb-3">
<CardDescription>Verificadas</CardDescription> <CardDescription>Verified</CardDescription>
<CardTitle className="text-3xl">{companies.filter((c) => c.verified).length}</CardTitle> <CardTitle className="text-3xl">{companies.filter((c) => c.verified).length}</CardTitle>
</CardHeader> </CardHeader>
</Card> </Card>
<Card> <Card>
<CardHeader className="pb-3"> <CardHeader className="pb-3">
<CardDescription>Pendentes</CardDescription> <CardDescription>Pending</CardDescription>
<CardTitle className="text-3xl">{companies.filter((c) => !c.verified).length}</CardTitle> <CardTitle className="text-3xl">{companies.filter((c) => !c.verified).length}</CardTitle>
</CardHeader> </CardHeader>
</Card> </Card>
@ -196,7 +196,7 @@ export default function AdminCompaniesPage() {
<div className="relative flex-1"> <div className="relative flex-1">
<Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" /> <Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
<Input <Input
placeholder="Buscar empresas por nome ou email..." placeholder="Search companies by name or email..."
value={searchTerm} value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)} onChange={(e) => setSearchTerm(e.target.value)}
className="pl-10" className="pl-10"
@ -213,19 +213,19 @@ export default function AdminCompaniesPage() {
<Table> <Table>
<TableHeader> <TableHeader>
<TableRow> <TableRow>
<TableHead>Empresa</TableHead> <TableHead>Company</TableHead>
<TableHead>Slug</TableHead> <TableHead>Slug</TableHead>
<TableHead>Email</TableHead> <TableHead>Email</TableHead>
<TableHead>Status</TableHead> <TableHead>Status</TableHead>
<TableHead>Verificada</TableHead> <TableHead>Verified</TableHead>
<TableHead>Data Criação</TableHead> <TableHead>Created</TableHead>
</TableRow> </TableRow>
</TableHeader> </TableHeader>
<TableBody> <TableBody>
{filteredCompanies.length === 0 ? ( {filteredCompanies.length === 0 ? (
<TableRow> <TableRow>
<TableCell colSpan={6} className="text-center text-muted-foreground py-8"> <TableCell colSpan={6} className="text-center text-muted-foreground py-8">
Nenhuma empresa encontrada No companies found
</TableCell> </TableCell>
</TableRow> </TableRow>
) : ( ) : (
@ -241,7 +241,7 @@ export default function AdminCompaniesPage() {
<TableCell>{company.email || "-"}</TableCell> <TableCell>{company.email || "-"}</TableCell>
<TableCell> <TableCell>
<Badge variant={company.active ? "default" : "secondary"}> <Badge variant={company.active ? "default" : "secondary"}>
{company.active ? "Ativa" : "Inativa"} {company.active ? "Active" : "Inactive"}
</Badge> </Badge>
</TableCell> </TableCell>
<TableCell> <TableCell>
@ -252,7 +252,7 @@ export default function AdminCompaniesPage() {
)} )}
</TableCell> </TableCell>
<TableCell> <TableCell>
{company.created_at ? new Date(company.created_at).toLocaleDateString("pt-BR") : "-"} {company.created_at ? new Date(company.created_at).toLocaleDateString("en-US") : "-"}
</TableCell> </TableCell>
</TableRow> </TableRow>
)) ))

View file

@ -41,83 +41,83 @@ export default function AdminJobsPage() {
{/* Header */} {/* Header */}
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div> <div>
<h1 className="text-3xl font-bold text-foreground">Gestão de Vagas</h1> <h1 className="text-3xl font-bold text-foreground">Job management</h1>
<p className="text-muted-foreground mt-1">Gerencie todas as vagas publicadas na plataforma</p> <p className="text-muted-foreground mt-1">Manage all jobs posted on the platform</p>
</div> </div>
<Dialog open={isDialogOpen} onOpenChange={setIsDialogOpen}> <Dialog open={isDialogOpen} onOpenChange={setIsDialogOpen}>
<DialogTrigger asChild> <DialogTrigger asChild>
<Button className="gap-2"> <Button className="gap-2">
<Plus className="h-4 w-4" /> <Plus className="h-4 w-4" />
Nova Vaga New job
</Button> </Button>
</DialogTrigger> </DialogTrigger>
<DialogContent className="max-w-2xl"> <DialogContent className="max-w-2xl">
<DialogHeader> <DialogHeader>
<DialogTitle>Criar Nova Vaga</DialogTitle> <DialogTitle>Create new job</DialogTitle>
<DialogDescription>Preencha os detalhes da nova vaga de emprego</DialogDescription> <DialogDescription>Fill in the details for the new job opening</DialogDescription>
</DialogHeader> </DialogHeader>
<div className="grid gap-4 py-4"> <div className="grid gap-4 py-4">
<div className="grid gap-2"> <div className="grid gap-2">
<Label htmlFor="title">Título da Vaga</Label> <Label htmlFor="title">Job title</Label>
<Input id="title" placeholder="Ex: Desenvolvedor Full Stack" /> <Input id="title" placeholder="e.g. Full Stack Developer" />
</div> </div>
<div className="grid gap-2"> <div className="grid gap-2">
<Label htmlFor="company">Empresa</Label> <Label htmlFor="company">Company</Label>
<Input id="company" placeholder="Nome da empresa" /> <Input id="company" placeholder="Company name" />
</div> </div>
<div className="grid grid-cols-2 gap-4"> <div className="grid grid-cols-2 gap-4">
<div className="grid gap-2"> <div className="grid gap-2">
<Label htmlFor="location">Localização</Label> <Label htmlFor="location">Location</Label>
<Input id="location" placeholder="São Paulo, SP" /> <Input id="location" placeholder="São Paulo, SP" />
</div> </div>
<div className="grid gap-2"> <div className="grid gap-2">
<Label htmlFor="type">Tipo</Label> <Label htmlFor="type">Type</Label>
<Select> <Select>
<SelectTrigger> <SelectTrigger>
<SelectValue placeholder="Selecione" /> <SelectValue placeholder="Select" />
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
<SelectItem value="full-time">Tempo Integral</SelectItem> <SelectItem value="full-time">Full time</SelectItem>
<SelectItem value="part-time">Meio Período</SelectItem> <SelectItem value="part-time">Part time</SelectItem>
<SelectItem value="contract">Contrato</SelectItem> <SelectItem value="contract">Contract</SelectItem>
<SelectItem value="Remoto">Remoto</SelectItem> <SelectItem value="remote">Remote</SelectItem>
</SelectContent> </SelectContent>
</Select> </Select>
</div> </div>
</div> </div>
<div className="grid grid-cols-2 gap-4"> <div className="grid grid-cols-2 gap-4">
<div className="grid gap-2"> <div className="grid gap-2">
<Label htmlFor="salary">Salário</Label> <Label htmlFor="salary">Salary</Label>
<Input id="salary" placeholder="R$ 8.000 - R$ 12.000" /> <Input id="salary" placeholder="R$ 8,000 - R$ 12,000" />
</div> </div>
<div className="grid gap-2"> <div className="grid gap-2">
<Label htmlFor="level">vel</Label> <Label htmlFor="level">Level</Label>
<Select> <Select>
<SelectTrigger> <SelectTrigger>
<SelectValue placeholder="Selecione" /> <SelectValue placeholder="Select" />
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
<SelectItem value="junior">Júnior</SelectItem> <SelectItem value="junior">Junior</SelectItem>
<SelectItem value="pleno">Pleno</SelectItem> <SelectItem value="mid">Mid-level</SelectItem>
<SelectItem value="senior">Sênior</SelectItem> <SelectItem value="senior">Senior</SelectItem>
</SelectContent> </SelectContent>
</Select> </Select>
</div> </div>
</div> </div>
<div className="grid gap-2"> <div className="grid gap-2">
<Label htmlFor="description">Descrição</Label> <Label htmlFor="description">Description</Label>
<Textarea <Textarea
id="description" id="description"
placeholder="Descreva as responsabilidades e requisitos da vaga..." placeholder="Describe the responsibilities and requirements..."
rows={4} rows={4}
/> />
</div> </div>
</div> </div>
<DialogFooter> <DialogFooter>
<Button variant="outline" onClick={() => setIsDialogOpen(false)}> <Button variant="outline" onClick={() => setIsDialogOpen(false)}>
Cancelar Cancel
</Button> </Button>
<Button onClick={() => setIsDialogOpen(false)}>Publicar Vaga</Button> <Button onClick={() => setIsDialogOpen(false)}>Publish job</Button>
</DialogFooter> </DialogFooter>
</DialogContent> </DialogContent>
</Dialog> </Dialog>
@ -127,25 +127,25 @@ export default function AdminJobsPage() {
<div className="grid gap-4 md:grid-cols-4"> <div className="grid gap-4 md:grid-cols-4">
<Card> <Card>
<CardHeader className="pb-3"> <CardHeader className="pb-3">
<CardDescription>Total de Vagas</CardDescription> <CardDescription>Total jobs</CardDescription>
<CardTitle className="text-3xl">{jobs.length}</CardTitle> <CardTitle className="text-3xl">{jobs.length}</CardTitle>
</CardHeader> </CardHeader>
</Card> </Card>
<Card> <Card>
<CardHeader className="pb-3"> <CardHeader className="pb-3">
<CardDescription>Vagas Ativas</CardDescription> <CardDescription>Active jobs</CardDescription>
<CardTitle className="text-3xl">{jobs.length}</CardTitle> <CardTitle className="text-3xl">{jobs.length}</CardTitle>
</CardHeader> </CardHeader>
</Card> </Card>
<Card> <Card>
<CardHeader className="pb-3"> <CardHeader className="pb-3">
<CardDescription>Candidaturas</CardDescription> <CardDescription>Applications</CardDescription>
<CardTitle className="text-3xl">{"436"}</CardTitle> <CardTitle className="text-3xl">{"436"}</CardTitle>
</CardHeader> </CardHeader>
</Card> </Card>
<Card> <Card>
<CardHeader className="pb-3"> <CardHeader className="pb-3">
<CardDescription>Taxa de Conversão</CardDescription> <CardDescription>Conversion rate</CardDescription>
<CardTitle className="text-3xl">12%</CardTitle> <CardTitle className="text-3xl">12%</CardTitle>
</CardHeader> </CardHeader>
</Card> </Card>
@ -158,7 +158,7 @@ export default function AdminJobsPage() {
<div className="relative flex-1"> <div className="relative flex-1">
<Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" /> <Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
<Input <Input
placeholder="Buscar vagas por título ou empresa..." placeholder="Search jobs by title or company..."
value={searchTerm} value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)} onChange={(e) => setSearchTerm(e.target.value)}
className="pl-10" className="pl-10"
@ -170,13 +170,13 @@ export default function AdminJobsPage() {
<Table> <Table>
<TableHeader> <TableHeader>
<TableRow> <TableRow>
<TableHead>Vaga</TableHead> <TableHead>Role</TableHead>
<TableHead>Empresa</TableHead> <TableHead>Company</TableHead>
<TableHead>Localização</TableHead> <TableHead>Location</TableHead>
<TableHead>Tipo</TableHead> <TableHead>Type</TableHead>
<TableHead>Candidaturas</TableHead> <TableHead>Applications</TableHead>
<TableHead>Status</TableHead> <TableHead>Status</TableHead>
<TableHead className="text-right">Ações</TableHead> <TableHead className="text-right">Actions</TableHead>
</TableRow> </TableRow>
</TableHeader> </TableHeader>
<TableBody> <TableBody>
@ -190,7 +190,7 @@ export default function AdminJobsPage() {
</TableCell> </TableCell>
<TableCell>{((job.id.charCodeAt(0) * 7) % 50) + 10}</TableCell> <TableCell>{((job.id.charCodeAt(0) * 7) % 50) + 10}</TableCell>
<TableCell> <TableCell>
<Badge variant="default">Ativa</Badge> <Badge variant="default">Active</Badge>
</TableCell> </TableCell>
<TableCell className="text-right"> <TableCell className="text-right">
<div className="flex items-center justify-end gap-2"> <div className="flex items-center justify-end gap-2">

View file

@ -15,7 +15,7 @@ const mockConversations = [
id: "1", id: "1",
name: "Ana Silva", name: "Ana Silva",
avatar: "/professional-woman-diverse.png", avatar: "/professional-woman-diverse.png",
lastMessage: "Obrigada pela resposta sobre a vaga!", lastMessage: "Thanks for the response about the role!",
timestamp: "10:30", timestamp: "10:30",
unread: 2, unread: 2,
}, },
@ -23,16 +23,16 @@ const mockConversations = [
id: "2", id: "2",
name: "Carlos Santos", name: "Carlos Santos",
avatar: "/professional-man.jpg", avatar: "/professional-man.jpg",
lastMessage: "Quando posso esperar um retorno?", lastMessage: "When can I expect an update?",
timestamp: "Ontem", timestamp: "Yesterday",
unread: 0, unread: 0,
}, },
{ {
id: "3", id: "3",
name: "Maria Oliveira", name: "Maria Oliveira",
avatar: "/professional-woman-smiling.png", avatar: "/professional-woman-smiling.png",
lastMessage: "Gostaria de mais informações sobre os benefícios", lastMessage: "I'd like more information about the benefits.",
timestamp: "2 dias", timestamp: "2 days ago",
unread: 1, unread: 1,
}, },
] ]
@ -41,21 +41,21 @@ const mockMessages = [
{ {
id: "1", id: "1",
sender: "Ana Silva", sender: "Ana Silva",
content: "Olá! Gostaria de saber mais sobre a vaga de Desenvolvedor Full Stack.", content: "Hi! I'd like to know more about the Full Stack Developer role.",
timestamp: "10:15", timestamp: "10:15",
isAdmin: false, isAdmin: false,
}, },
{ {
id: "2", id: "2",
sender: "Você", sender: "You",
content: "Olá Ana! Claro, ficarei feliz em ajudar. A vaga é para trabalho remoto e oferece benefícios completos.", content: "Hi Ana! Of course—happy to help. The role is remote and includes full benefits.",
timestamp: "10:20", timestamp: "10:20",
isAdmin: true, isAdmin: true,
}, },
{ {
id: "3", id: "3",
sender: "Ana Silva", sender: "Ana Silva",
content: "Obrigada pela resposta sobre a vaga!", content: "Thanks for the response about the role!",
timestamp: "10:30", timestamp: "10:30",
isAdmin: false, isAdmin: false,
}, },
@ -81,21 +81,21 @@ export default function AdminMessagesPage() {
<div className="space-y-8"> <div className="space-y-8">
{/* Header */} {/* Header */}
<div> <div>
<h1 className="text-3xl font-bold text-foreground">Mensagens</h1> <h1 className="text-3xl font-bold text-foreground">Messages</h1>
<p className="text-muted-foreground mt-1">Comunique-se com candidatos e empresas</p> <p className="text-muted-foreground mt-1">Communicate with candidates and companies</p>
</div> </div>
{/* Stats */} {/* Stats */}
<div className="grid gap-4 md:grid-cols-4"> <div className="grid gap-4 md:grid-cols-4">
<Card> <Card>
<CardHeader className="pb-3"> <CardHeader className="pb-3">
<CardDescription>Total de Conversas</CardDescription> <CardDescription>Total conversations</CardDescription>
<CardTitle className="text-3xl">{mockConversations.length}</CardTitle> <CardTitle className="text-3xl">{mockConversations.length}</CardTitle>
</CardHeader> </CardHeader>
</Card> </Card>
<Card> <Card>
<CardHeader className="pb-3"> <CardHeader className="pb-3">
<CardDescription>Não Lidas</CardDescription> <CardDescription>Unread</CardDescription>
<CardTitle className="text-3xl"> <CardTitle className="text-3xl">
{mockConversations.reduce((acc, conv) => acc + conv.unread, 0)} {mockConversations.reduce((acc, conv) => acc + conv.unread, 0)}
</CardTitle> </CardTitle>
@ -103,13 +103,13 @@ export default function AdminMessagesPage() {
</Card> </Card>
<Card> <Card>
<CardHeader className="pb-3"> <CardHeader className="pb-3">
<CardDescription>Respondidas Hoje</CardDescription> <CardDescription>Replied today</CardDescription>
<CardTitle className="text-3xl">12</CardTitle> <CardTitle className="text-3xl">12</CardTitle>
</CardHeader> </CardHeader>
</Card> </Card>
<Card> <Card>
<CardHeader className="pb-3"> <CardHeader className="pb-3">
<CardDescription>Tempo Médio de Resposta</CardDescription> <CardDescription>Average response time</CardDescription>
<CardTitle className="text-3xl">2h</CardTitle> <CardTitle className="text-3xl">2h</CardTitle>
</CardHeader> </CardHeader>
</Card> </Card>
@ -124,7 +124,7 @@ export default function AdminMessagesPage() {
<div className="relative"> <div className="relative">
<Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" /> <Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
<Input <Input
placeholder="Buscar conversas..." placeholder="Search conversations..."
value={searchTerm} value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)} onChange={(e) => setSearchTerm(e.target.value)}
className="pl-10" className="pl-10"
@ -201,7 +201,7 @@ export default function AdminMessagesPage() {
<Paperclip className="h-4 w-4" /> <Paperclip className="h-4 w-4" />
</Button> </Button>
<Textarea <Textarea
placeholder="Digite sua mensagem..." placeholder="Type your message..."
value={messageText} value={messageText}
onChange={(e) => setMessageText(e.target.value)} onChange={(e) => setMessageText(e.target.value)}
onKeyDown={(e) => { onKeyDown={(e) => {

View file

@ -1,16 +1,10 @@
"use client" "use client"
import { DashboardHeader } from "@/components/dashboard-header" // Keep header if we want consistent layout, though global layout handles it
// Actually global layout handles sidebar/header.
// We just need the content.
// But wait, "My Jobs" page doesn't exist yet!
// I'll create a placeholder for now to prevent 404s on the new links.
export default function MyJobsPage() { export default function MyJobsPage() {
return ( return (
<div className="p-8"> <div className="p-8">
<h1 className="text-2xl font-bold mb-4">Minhas Vagas</h1> <h1 className="text-2xl font-bold mb-4">My jobs</h1>
<p>Funcionalidade em desenvolvimento.</p> <p>Feature in progress.</p>
</div> </div>
) )
} }

View file

@ -53,7 +53,7 @@ export default function AdminUsersPage() {
setUsers(data || []) setUsers(data || [])
} catch (error) { } catch (error) {
console.error("Error loading users:", error) console.error("Error loading users:", error)
toast.error("Erro ao carregar usuários") toast.error("Failed to load users")
} finally { } finally {
setLoading(false) setLoading(false)
} }
@ -63,27 +63,27 @@ export default function AdminUsersPage() {
try { try {
setCreating(true) setCreating(true)
await usersApi.create(formData) await usersApi.create(formData)
toast.success("Usuário criado com sucesso!") toast.success("User created successfully!")
setIsDialogOpen(false) setIsDialogOpen(false)
setFormData({ name: "", email: "", password: "", role: "jobSeeker" }) setFormData({ name: "", email: "", password: "", role: "jobSeeker" })
loadUsers() loadUsers()
} catch (error) { } catch (error) {
console.error("Error creating user:", error) console.error("Error creating user:", error)
toast.error("Erro ao criar usuário") toast.error("Failed to create user")
} finally { } finally {
setCreating(false) setCreating(false)
} }
} }
const handleDelete = async (id: string) => { const handleDelete = async (id: string) => {
if (!confirm("Tem certeza que deseja excluir este usuário?")) return if (!confirm("Are you sure you want to delete this user?")) return
try { try {
await usersApi.delete(id) await usersApi.delete(id)
toast.success("Usuário excluído!") toast.success("User deleted!")
loadUsers() loadUsers()
} catch (error) { } catch (error) {
console.error("Error deleting user:", error) console.error("Error deleting user:", error)
toast.error("Erro ao excluir usuário") toast.error("Failed to delete user")
} }
} }
@ -96,11 +96,11 @@ export default function AdminUsersPage() {
const getRoleBadge = (role: string) => { const getRoleBadge = (role: string) => {
const labels: Record<string, string> = { const labels: Record<string, string> = {
superadmin: "Super Admin", superadmin: "Super Admin",
companyAdmin: "Admin Empresa", companyAdmin: "Company admin",
recruiter: "Recrutador", recruiter: "Recruiter",
jobSeeker: "Candidato", jobSeeker: "Candidate",
admin: "Admin", admin: "Admin",
company: "Empresa" company: "Company"
} }
const colors: Record<string, "default" | "secondary" | "destructive" | "outline"> = { const colors: Record<string, "default" | "secondary" | "destructive" | "outline"> = {
superadmin: "destructive", superadmin: "destructive",
@ -110,7 +110,7 @@ export default function AdminUsersPage() {
admin: "destructive", admin: "destructive",
company: "default" company: "default"
} }
const label = labels[role] || role || "Usuário" const label = labels[role] || role || "User"
return <Badge variant={colors[role] || "outline"}>{label}</Badge> return <Badge variant={colors[role] || "outline"}>{label}</Badge>
} }
@ -119,34 +119,34 @@ export default function AdminUsersPage() {
{/* Header */} {/* Header */}
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div> <div>
<h1 className="text-3xl font-bold text-foreground">Gestão de Usuários</h1> <h1 className="text-3xl font-bold text-foreground">User management</h1>
<p className="text-muted-foreground mt-1">Gerencie todos os usuários da plataforma</p> <p className="text-muted-foreground mt-1">Manage all platform users</p>
</div> </div>
<div className="flex gap-2"> <div className="flex gap-2">
<Button variant="outline" onClick={loadUsers} disabled={loading}> <Button variant="outline" onClick={loadUsers} disabled={loading}>
<RefreshCw className={`h-4 w-4 mr-2 ${loading ? "animate-spin" : ""}`} /> <RefreshCw className={`h-4 w-4 mr-2 ${loading ? "animate-spin" : ""}`} />
Atualizar Refresh
</Button> </Button>
<Dialog open={isDialogOpen} onOpenChange={setIsDialogOpen}> <Dialog open={isDialogOpen} onOpenChange={setIsDialogOpen}>
<DialogTrigger asChild> <DialogTrigger asChild>
<Button className="gap-2"> <Button className="gap-2">
<Plus className="h-4 w-4" /> <Plus className="h-4 w-4" />
Novo Usuário New user
</Button> </Button>
</DialogTrigger> </DialogTrigger>
<DialogContent> <DialogContent>
<DialogHeader> <DialogHeader>
<DialogTitle>Criar Novo Usuário</DialogTitle> <DialogTitle>Create new user</DialogTitle>
<DialogDescription>Preencha os dados do novo usuário</DialogDescription> <DialogDescription>Fill in the new user details</DialogDescription>
</DialogHeader> </DialogHeader>
<div className="grid gap-4 py-4"> <div className="grid gap-4 py-4">
<div className="grid gap-2"> <div className="grid gap-2">
<Label htmlFor="name">Nome</Label> <Label htmlFor="name">Name</Label>
<Input <Input
id="name" id="name"
value={formData.name} value={formData.name}
onChange={(e) => setFormData({ ...formData, name: e.target.value })} onChange={(e) => setFormData({ ...formData, name: e.target.value })}
placeholder="Nome completo" placeholder="Full name"
/> />
</div> </div>
<div className="grid gap-2"> <div className="grid gap-2">
@ -156,39 +156,39 @@ export default function AdminUsersPage() {
type="email" type="email"
value={formData.email} value={formData.email}
onChange={(e) => setFormData({ ...formData, email: e.target.value })} onChange={(e) => setFormData({ ...formData, email: e.target.value })}
placeholder="email@exemplo.com" placeholder="email@example.com"
/> />
</div> </div>
<div className="grid gap-2"> <div className="grid gap-2">
<Label htmlFor="password">Senha</Label> <Label htmlFor="password">Password</Label>
<Input <Input
id="password" id="password"
type="password" type="password"
value={formData.password} value={formData.password}
onChange={(e) => setFormData({ ...formData, password: e.target.value })} onChange={(e) => setFormData({ ...formData, password: e.target.value })}
placeholder="Senha segura" placeholder="Secure password"
/> />
</div> </div>
<div className="grid gap-2"> <div className="grid gap-2">
<Label htmlFor="role">Função</Label> <Label htmlFor="role">Role</Label>
<Select value={formData.role} onValueChange={(v) => setFormData({ ...formData, role: v })}> <Select value={formData.role} onValueChange={(v) => setFormData({ ...formData, role: v })}>
<SelectTrigger> <SelectTrigger>
<SelectValue /> <SelectValue />
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
<SelectItem value="superadmin">Super Admin</SelectItem> <SelectItem value="superadmin">Super Admin</SelectItem>
<SelectItem value="companyAdmin">Admin Empresa</SelectItem> <SelectItem value="companyAdmin">Company admin</SelectItem>
<SelectItem value="recruiter">Recrutador</SelectItem> <SelectItem value="recruiter">Recruiter</SelectItem>
<SelectItem value="jobSeeker">Candidato</SelectItem> <SelectItem value="jobSeeker">Candidate</SelectItem>
</SelectContent> </SelectContent>
</Select> </Select>
</div> </div>
</div> </div>
<DialogFooter> <DialogFooter>
<Button variant="outline" onClick={() => setIsDialogOpen(false)}>Cancelar</Button> <Button variant="outline" onClick={() => setIsDialogOpen(false)}>Cancel</Button>
<Button onClick={handleCreate} disabled={creating}> <Button onClick={handleCreate} disabled={creating}>
{creating && <Loader2 className="h-4 w-4 mr-2 animate-spin" />} {creating && <Loader2 className="h-4 w-4 mr-2 animate-spin" />}
Criar Usuário Create user
</Button> </Button>
</DialogFooter> </DialogFooter>
</DialogContent> </DialogContent>
@ -200,7 +200,7 @@ export default function AdminUsersPage() {
<div className="grid gap-4 md:grid-cols-4"> <div className="grid gap-4 md:grid-cols-4">
<Card> <Card>
<CardHeader className="pb-3"> <CardHeader className="pb-3">
<CardDescription>Total de Usuários</CardDescription> <CardDescription>Total users</CardDescription>
<CardTitle className="text-3xl">{users.length}</CardTitle> <CardTitle className="text-3xl">{users.length}</CardTitle>
</CardHeader> </CardHeader>
</Card> </Card>
@ -214,13 +214,13 @@ export default function AdminUsersPage() {
</Card> </Card>
<Card> <Card>
<CardHeader className="pb-3"> <CardHeader className="pb-3">
<CardDescription>Recrutadores</CardDescription> <CardDescription>Recruiters</CardDescription>
<CardTitle className="text-3xl">{users.filter((u) => u.role === "recruiter").length}</CardTitle> <CardTitle className="text-3xl">{users.filter((u) => u.role === "recruiter").length}</CardTitle>
</CardHeader> </CardHeader>
</Card> </Card>
<Card> <Card>
<CardHeader className="pb-3"> <CardHeader className="pb-3">
<CardDescription>Candidatos</CardDescription> <CardDescription>Candidates</CardDescription>
<CardTitle className="text-3xl">{users.filter((u) => u.role === "jobSeeker").length}</CardTitle> <CardTitle className="text-3xl">{users.filter((u) => u.role === "jobSeeker").length}</CardTitle>
</CardHeader> </CardHeader>
</Card> </Card>
@ -233,7 +233,7 @@ export default function AdminUsersPage() {
<div className="relative flex-1"> <div className="relative flex-1">
<Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" /> <Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
<Input <Input
placeholder="Buscar usuários por nome ou email..." placeholder="Search users by name or email..."
value={searchTerm} value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)} onChange={(e) => setSearchTerm(e.target.value)}
className="pl-10" className="pl-10"
@ -250,19 +250,19 @@ export default function AdminUsersPage() {
<Table> <Table>
<TableHeader> <TableHeader>
<TableRow> <TableRow>
<TableHead>Nome</TableHead> <TableHead>Name</TableHead>
<TableHead>Email</TableHead> <TableHead>Email</TableHead>
<TableHead>Função</TableHead> <TableHead>Role</TableHead>
<TableHead>Status</TableHead> <TableHead>Status</TableHead>
<TableHead>Data Criação</TableHead> <TableHead>Created</TableHead>
<TableHead className="text-right">Ações</TableHead> <TableHead className="text-right">Actions</TableHead>
</TableRow> </TableRow>
</TableHeader> </TableHeader>
<TableBody> <TableBody>
{filteredUsers.length === 0 ? ( {filteredUsers.length === 0 ? (
<TableRow> <TableRow>
<TableCell colSpan={6} className="text-center text-muted-foreground py-8"> <TableCell colSpan={6} className="text-center text-muted-foreground py-8">
Nenhum usuário encontrado No users found
</TableCell> </TableCell>
</TableRow> </TableRow>
) : ( ) : (
@ -273,11 +273,11 @@ export default function AdminUsersPage() {
<TableCell>{getRoleBadge(user.role)}</TableCell> <TableCell>{getRoleBadge(user.role)}</TableCell>
<TableCell> <TableCell>
<Badge variant={user.status === "active" ? "default" : "secondary"}> <Badge variant={user.status === "active" ? "default" : "secondary"}>
{user.status === "active" ? "Ativo" : user.status} {user.status === "active" ? "Active" : user.status}
</Badge> </Badge>
</TableCell> </TableCell>
<TableCell> <TableCell>
{user.created_at ? new Date(user.created_at).toLocaleDateString("pt-BR") : "-"} {user.created_at ? new Date(user.created_at).toLocaleDateString("en-US") : "-"}
</TableCell> </TableCell>
<TableCell className="text-right"> <TableCell className="text-right">
<Button <Button

View file

@ -44,12 +44,12 @@ import { Footer } from "@/components/footer";
import { useNotify } from "@/contexts/notification-context"; import { useNotify } from "@/contexts/notification-context";
import { mockJobs } from "@/lib/mock-data"; import { mockJobs } from "@/lib/mock-data";
// Definição Dos Passos // Step definitions
const steps = [ const steps = [
{ id: 1, title: "Dados Pessoais", icon: User }, { id: 1, title: "Personal Details", icon: User },
{ id: 2, title: "Currículo e Documentos", icon: FileText }, { id: 2, title: "Resume & Documents", icon: FileText },
{ id: 3, title: "Experiência", icon: Briefcase }, { id: 3, title: "Experience", icon: Briefcase },
{ id: 4, title: "Perguntas Adicionais", icon: MessageSquare }, { id: 4, title: "Additional Questions", icon: MessageSquare },
]; ];
@ -66,25 +66,25 @@ export default function JobApplicationPage({
const [currentStep, setCurrentStep] = useState(1); const [currentStep, setCurrentStep] = useState(1);
const [isSubmitting, setIsSubmitting] = useState(false); const [isSubmitting, setIsSubmitting] = useState(false);
// Achar os detalhes da vaga // Find job details
const job = mockJobs.find((j) => j.id === id) || mockJobs[0]; const job = mockJobs.find((j) => j.id === id) || mockJobs[0];
// Estado do formulário // Form state
const [formData, setFormData] = useState({ const [formData, setFormData] = useState({
// Etapa 1 // Step 1
fullName: "", fullName: "",
email: "", email: "",
phone: "", phone: "",
linkedin: "", linkedin: "",
privacyAccepted: false, privacyAccepted: false,
// Etapa 2 // Step 2
resume: null as File | null, resume: null as File | null,
coverLetter: "", coverLetter: "",
portfolioUrl: "", portfolioUrl: "",
// Etapa 3 // Step 3
salaryExpectation: "", salaryExpectation: "",
hasExperience: "", hasExperience: "",
// Etapa 4 // Step 4
whyUs: "", whyUs: "",
availability: [] as string[], availability: [] as string[],
}); });
@ -98,22 +98,22 @@ export default function JobApplicationPage({
case 1: case 1:
if (!formData.fullName || !formData.email || !formData.phone) { if (!formData.fullName || !formData.email || !formData.phone) {
notify.error( notify.error(
"Campos obrigatórios", "Required fields",
"Por favor, preencha todos os campos obrigatórios." "Please fill out all required fields."
); );
return false; return false;
} }
if (!formData.email.includes("@")) { if (!formData.email.includes("@")) {
notify.error( notify.error(
"E-mail inválido", "Invalid email",
"Por favor, insira um e-mail válido." "Please enter a valid email address."
); );
return false; return false;
} }
if (!formData.privacyAccepted) { if (!formData.privacyAccepted) {
notify.error( notify.error(
"Termos de Privacidade", "Privacy policy",
"Você precisa aceitar a política de privacidade para continuar." "You must accept the privacy policy to continue."
); );
return false; return false;
} }
@ -123,8 +123,8 @@ export default function JobApplicationPage({
case 3: case 3:
if (!formData.salaryExpectation || !formData.hasExperience) { if (!formData.salaryExpectation || !formData.hasExperience) {
notify.error( notify.error(
"Campos obrigatórios", "Required fields",
"Por favor, responda todas as perguntas." "Please answer all questions."
); );
return false; return false;
} }
@ -132,8 +132,8 @@ export default function JobApplicationPage({
case 4: case 4:
if (!formData.whyUs || formData.availability.length === 0) { if (!formData.whyUs || formData.availability.length === 0) {
notify.error( notify.error(
"Campos obrigatórios", "Required fields",
"Por favor, preencha o motivo e selecione pelo menos uma disponibilidade." "Please provide your reason and select at least one availability option."
); );
return false; return false;
} }
@ -163,21 +163,21 @@ export default function JobApplicationPage({
const handleSubmit = async () => { const handleSubmit = async () => {
setIsSubmitting(true); setIsSubmitting(true);
// Simular um chamado de API // Simulate API call
await new Promise((resolve) => setTimeout(resolve, 2000)); await new Promise((resolve) => setTimeout(resolve, 2000));
notify.success( notify.success(
"Candidatura enviada com sucesso!", "Application submitted!",
`Boa sorte! Sua candidatura para ${job.title} foi recebida.` `Good luck! Your application for ${job.title} has been received.`
); );
router.push("/dashboard/candidato/candidaturas"); router.push("/dashboard/my-applications");
}; };
const handleSaveDraft = () => { const handleSaveDraft = () => {
notify.info( notify.info(
"Rascunho salvo", "Draft saved",
"Você pode continuar sua candidatura mais tarde." "You can finish your application later."
); );
}; };
@ -198,28 +198,28 @@ export default function JobApplicationPage({
className="inline-flex items-center text-sm text-muted-foreground hover:text-primary mb-4 transition-colors" className="inline-flex items-center text-sm text-muted-foreground hover:text-primary mb-4 transition-colors"
> >
<ArrowLeft className="mr-2 h-4 w-4" /> <ArrowLeft className="mr-2 h-4 w-4" />
Voltar para detalhes da vaga Back to job details
</Link> </Link>
<div className="flex flex-col md:flex-row md:items-center md:justify-between gap-4"> <div className="flex flex-col md:flex-row md:items-center md:justify-between gap-4">
<div> <div>
<h1 className="text-2xl md:text-3xl font-bold text-foreground"> <h1 className="text-2xl md:text-3xl font-bold text-foreground">
Candidatura: {job.title} Application: {job.title}
</h1> </h1>
<p className="text-muted-foreground mt-1"> <p className="text-muted-foreground mt-1">
{job.company} {job.location} {job.company} {job.location}
</p> </p>
</div> </div>
<div className="text-sm font-medium bg-primary/10 text-primary px-3 py-1 rounded-full self-start md:self-center"> <div className="text-sm font-medium bg-primary/10 text-primary px-3 py-1 rounded-full self-start md:self-center">
Tempo estimado: 5 min Estimated time: 5 min
</div> </div>
</div> </div>
</div> </div>
{/* Progresso das etapas */} {/* Step progress */}
<div className="mb-8"> <div className="mb-8">
<div className="flex justify-between mb-2"> <div className="flex justify-between mb-2">
<span className="text-sm font-medium text-muted-foreground"> <span className="text-sm font-medium text-muted-foreground">
Etapa {currentStep} de {steps.length}:{" "} Step {currentStep} of {steps.length}:{" "}
<span className="text-foreground"> <span className="text-foreground">
{steps[currentStep - 1].title} {steps[currentStep - 1].title}
</span> </span>
@ -230,7 +230,7 @@ export default function JobApplicationPage({
</div> </div>
<Progress value={progress} className="h-2" /> <Progress value={progress} className="h-2" />
{/* Indicador de etapas (DESKTOP) */} {/* Step indicator (desktop) */}
<div className="hidden md:flex justify-between mt-4 px-2"> <div className="hidden md:flex justify-between mt-4 px-2">
{steps.map((step) => { {steps.map((step) => {
const Icon = step.icon; const Icon = step.icon;
@ -271,7 +271,7 @@ export default function JobApplicationPage({
</div> </div>
</div> </div>
{/* Conteúdo do formulário */} {/* Form content */}
<div className="grid gap-6"> <div className="grid gap-6">
<AnimatePresence mode="wait"> <AnimatePresence mode="wait">
<motion.div <motion.div
@ -285,20 +285,20 @@ export default function JobApplicationPage({
<CardHeader> <CardHeader>
<CardTitle>{steps[currentStep - 1].title}</CardTitle> <CardTitle>{steps[currentStep - 1].title}</CardTitle>
<CardDescription> <CardDescription>
Preencha as informações abaixo para continuar. Fill in the information below to continue.
</CardDescription> </CardDescription>
</CardHeader> </CardHeader>
<CardContent className="space-y-6"> <CardContent className="space-y-6">
{/* Etapa 1: Dados Pessoais */} {/* Step 1: Personal Details */}
{currentStep === 1 && ( {currentStep === 1 && (
<div className="space-y-4"> <div className="space-y-4">
<div className="grid md:grid-cols-2 gap-4"> <div className="grid md:grid-cols-2 gap-4">
<div className="space-y-2"> <div className="space-y-2">
<Label htmlFor="fullName">Nome Completo *</Label> <Label htmlFor="fullName">Full name *</Label>
<Input <Input
id="fullName" id="fullName"
placeholder="Seu nome completo" placeholder="Your full name"
value={formData.fullName} value={formData.fullName}
onChange={(e) => onChange={(e) =>
handleInputChange("fullName", e.target.value) handleInputChange("fullName", e.target.value)
@ -306,11 +306,11 @@ export default function JobApplicationPage({
/> />
</div> </div>
<div className="space-y-2"> <div className="space-y-2">
<Label htmlFor="email">E-mail *</Label> <Label htmlFor="email">Email *</Label>
<Input <Input
id="email" id="email"
type="email" type="email"
placeholder="seu@email.com" placeholder="you@email.com"
value={formData.email} value={formData.email}
onChange={(e) => onChange={(e) =>
handleInputChange("email", e.target.value) handleInputChange("email", e.target.value)
@ -321,7 +321,7 @@ export default function JobApplicationPage({
<div className="grid md:grid-cols-2 gap-4"> <div className="grid md:grid-cols-2 gap-4">
<div className="space-y-2"> <div className="space-y-2">
<Label htmlFor="phone">Telefone / WhatsApp *</Label> <Label htmlFor="phone">Phone / WhatsApp *</Label>
<Input <Input
id="phone" id="phone"
placeholder="(00) 00000-0000" placeholder="(00) 00000-0000"
@ -335,7 +335,7 @@ export default function JobApplicationPage({
<Label htmlFor="linkedin">LinkedIn (URL)</Label> <Label htmlFor="linkedin">LinkedIn (URL)</Label>
<Input <Input
id="linkedin" id="linkedin"
placeholder="linkedin.com/in/seu-perfil" placeholder="linkedin.com/in/your-profile"
value={formData.linkedin} value={formData.linkedin}
onChange={(e) => onChange={(e) =>
handleInputChange("linkedin", e.target.value) handleInputChange("linkedin", e.target.value)
@ -356,22 +356,21 @@ export default function JobApplicationPage({
htmlFor="privacy" htmlFor="privacy"
className="text-sm font-normal text-muted-foreground" className="text-sm font-normal text-muted-foreground"
> >
Li e concordo com a{" "} I have read and agree to the{" "}
<a href="#" className="text-primary underline"> <Link href="/privacy" className="text-primary underline">
Política de Privacidade Privacy Policy
</a>{" "} </Link>{" "}
e autorizo o tratamento dos meus dados para fins de and authorize the processing of my data for recruitment purposes.
recrutamento.
</Label> </Label>
</div> </div>
</div> </div>
)} )}
{/* Etapa 2: Dccumentos */} {/* Step 2: Documents */}
{currentStep === 2 && ( {currentStep === 2 && (
<div className="space-y-6"> <div className="space-y-6">
<div className="space-y-3"> <div className="space-y-3">
<Label>Currículo (CV) *</Label> <Label>Resume (CV) *</Label>
<div className="border-2 border-dashed border-muted-foreground/25 rounded-lg p-8 text-center hover:bg-muted/50 transition-colors cursor-pointer"> <div className="border-2 border-dashed border-muted-foreground/25 rounded-lg p-8 text-center hover:bg-muted/50 transition-colors cursor-pointer">
<div className="flex flex-col items-center gap-2"> <div className="flex flex-col items-center gap-2">
<div className="p-3 bg-primary/10 rounded-full text-primary"> <div className="p-3 bg-primary/10 rounded-full text-primary">
@ -379,10 +378,10 @@ export default function JobApplicationPage({
</div> </div>
<div className="space-y-1"> <div className="space-y-1">
<p className="text-sm font-medium"> <p className="text-sm font-medium">
Clique para fazer upload ou arraste o arquivo Click to upload or drag the file here
</p> </p>
<p className="text-xs text-muted-foreground"> <p className="text-xs text-muted-foreground">
PDF, DOCX ou TXT (Máx. 5MB) PDF, DOCX, or TXT (Max 5MB)
</p> </p>
</div> </div>
</div> </div>
@ -391,7 +390,7 @@ export default function JobApplicationPage({
<div className="space-y-2"> <div className="space-y-2">
<Label htmlFor="portfolio"> <Label htmlFor="portfolio">
Portfólio / Site Pessoal (Opcional) Portfolio / Personal Website (Optional)
</Label> </Label>
<Input <Input
id="portfolio" id="portfolio"
@ -405,11 +404,11 @@ export default function JobApplicationPage({
<div className="space-y-2"> <div className="space-y-2">
<Label htmlFor="coverLetter"> <Label htmlFor="coverLetter">
Carta de Apresentação (Opcional) Cover Letter (Optional)
</Label> </Label>
<Textarea <Textarea
id="coverLetter" id="coverLetter"
placeholder="Escreva uma breve apresentação sobre você..." placeholder="Write a short introduction about yourself..."
className="min-h-[150px]" className="min-h-[150px]"
value={formData.coverLetter} value={formData.coverLetter}
onChange={(e) => onChange={(e) =>
@ -420,11 +419,11 @@ export default function JobApplicationPage({
</div> </div>
)} )}
{/* Etapa 3: Experiências */} {/* Step 3: Experience */}
{currentStep === 3 && ( {currentStep === 3 && (
<div className="space-y-6"> <div className="space-y-6">
<div className="space-y-2"> <div className="space-y-2">
<Label htmlFor="salary">Pretensão Salarial *</Label> <Label htmlFor="salary">Salary expectation *</Label>
<Select <Select
value={formData.salaryExpectation} value={formData.salaryExpectation}
onValueChange={(val) => onValueChange={(val) =>
@ -432,23 +431,23 @@ export default function JobApplicationPage({
} }
> >
<SelectTrigger> <SelectTrigger>
<SelectValue placeholder="Selecione uma faixa" /> <SelectValue placeholder="Select a range" />
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
<SelectItem value="ate-3k"> <SelectItem value="up-to-3k">
Até R$ 3.000 Up to R$ 3,000
</SelectItem> </SelectItem>
<SelectItem value="3k-5k"> <SelectItem value="3k-5k">
R$ 3.000 - R$ 5.000 R$ 3,000 - R$ 5,000
</SelectItem> </SelectItem>
<SelectItem value="5k-8k"> <SelectItem value="5k-8k">
R$ 5.000 - R$ 8.000 R$ 5,000 - R$ 8,000
</SelectItem> </SelectItem>
<SelectItem value="8k-12k"> <SelectItem value="8k-12k">
R$ 8.000 - R$ 12.000 R$ 8,000 - R$ 12,000
</SelectItem> </SelectItem>
<SelectItem value="12k-plus"> <SelectItem value="12k-plus">
Acima de R$ 12.000 Above R$ 12,000
</SelectItem> </SelectItem>
</SelectContent> </SelectContent>
</Select> </Select>
@ -456,8 +455,8 @@ export default function JobApplicationPage({
<div className="space-y-3"> <div className="space-y-3">
<Label> <Label>
Você possui a experiência mínima requisitada para a Do you have the minimum experience required for the
vaga? * role? *
</Label> </Label>
<div className="flex gap-4"> <div className="flex gap-4">
<div className="flex items-center space-x-2 border p-3 rounded-md flex-1 hover:bg-muted/50 cursor-pointer"> <div className="flex items-center space-x-2 border p-3 rounded-md flex-1 hover:bg-muted/50 cursor-pointer">
@ -475,7 +474,7 @@ export default function JobApplicationPage({
htmlFor="exp-yes" htmlFor="exp-yes"
className="cursor-pointer flex-1" className="cursor-pointer flex-1"
> >
Sim, possuo Yes, I do
</Label> </Label>
</div> </div>
<div className="flex items-center space-x-2 border p-3 rounded-md flex-1 hover:bg-muted/50 cursor-pointer"> <div className="flex items-center space-x-2 border p-3 rounded-md flex-1 hover:bg-muted/50 cursor-pointer">
@ -493,7 +492,7 @@ export default function JobApplicationPage({
htmlFor="exp-no" htmlFor="exp-no"
className="cursor-pointer flex-1" className="cursor-pointer flex-1"
> >
Não possuo Not yet
</Label> </Label>
</div> </div>
</div> </div>
@ -501,16 +500,16 @@ export default function JobApplicationPage({
</div> </div>
)} )}
{/* Etapa 4: Adicional */} {/* Step 4: Additional */}
{currentStep === 4 && ( {currentStep === 4 && (
<div className="space-y-6"> <div className="space-y-6">
<div className="space-y-2"> <div className="space-y-2">
<Label htmlFor="whyUs"> <Label htmlFor="whyUs">
Por que você quer trabalhar na {job.company}? * Why do you want to work at {job.company}? *
</Label> </Label>
<Textarea <Textarea
id="whyUs" id="whyUs"
placeholder="Conte-nos o que te atrai na nossa empresa e nesta vaga..." placeholder="Tell us what attracts you to this company and role..."
className="min-h-[150px]" className="min-h-[150px]"
maxLength={1000} maxLength={1000}
value={formData.whyUs} value={formData.whyUs}
@ -519,18 +518,18 @@ export default function JobApplicationPage({
} }
/> />
<div className="text-xs text-right text-muted-foreground"> <div className="text-xs text-right text-muted-foreground">
{formData.whyUs.length}/1000 caracteres {formData.whyUs.length}/1000 characters
</div> </div>
</div> </div>
<div className="space-y-3"> <div className="space-y-3">
<Label>Disponibilidade *</Label> <Label>Availability *</Label>
<div className="grid gap-2"> <div className="grid gap-2">
{[ {[
"Trabalho Presencial", "On-site work",
"Trabalho Remoto", "Remote work",
"Viagens", "Travel",
"Início Imediato", "Immediate start",
].map((item) => ( ].map((item) => (
<div <div
key={item} key={item}
@ -571,7 +570,7 @@ export default function JobApplicationPage({
disabled={currentStep === 1 || isSubmitting} disabled={currentStep === 1 || isSubmitting}
> >
<ChevronLeft className="mr-2 h-4 w-4" /> <ChevronLeft className="mr-2 h-4 w-4" />
Voltar Back
</Button> </Button>
<div className="flex gap-2"> <div className="flex gap-2">
@ -582,7 +581,7 @@ export default function JobApplicationPage({
className="hidden sm:flex" className="hidden sm:flex"
> >
<Save className="mr-2 h-4 w-4" /> <Save className="mr-2 h-4 w-4" />
Salvar Rascunho Save draft
</Button> </Button>
<Button <Button
@ -591,15 +590,15 @@ export default function JobApplicationPage({
className="min-w-[120px]" className="min-w-[120px]"
> >
{isSubmitting ? ( {isSubmitting ? (
"Enviando..." "Submitting..."
) : currentStep === steps.length ? ( ) : currentStep === steps.length ? (
<> <>
Enviar Candidatura{" "} Submit application{" "}
<CheckCircle2 className="ml-2 h-4 w-4" /> <CheckCircle2 className="ml-2 h-4 w-4" />
</> </>
) : ( ) : (
<> <>
Próxima Etapa{" "} Next step{" "}
<ChevronRight className="ml-2 h-4 w-4" /> <ChevronRight className="ml-2 h-4 w-4" />
</> </>
)} )}

View file

@ -64,12 +64,12 @@ export default function JobDetailPage({
<div className="w-16 h-16 bg-muted rounded-full flex items-center justify-center mx-auto mb-4"> <div className="w-16 h-16 bg-muted rounded-full flex items-center justify-center mx-auto mb-4">
<Briefcase className="w-8 h-8 text-muted-foreground" /> <Briefcase className="w-8 h-8 text-muted-foreground" />
</div> </div>
<h1 className="text-2xl font-bold mb-2">Vaga não encontrada</h1> <h1 className="text-2xl font-bold mb-2">Job not found</h1>
<p className="text-muted-foreground mb-6"> <p className="text-muted-foreground mb-6">
A vaga que você está procurando não existe ou foi removida. The job you are looking for does not exist or has been removed.
</p> </p>
<Link href="/jobs"> <Link href="/jobs">
<Button>Ver todas as vagas</Button> <Button>View all jobs</Button>
</Link> </Link>
</motion.div> </motion.div>
</main> </main>
@ -93,28 +93,28 @@ export default function JobDetailPage({
const diffInMs = now.getTime() - date.getTime(); const diffInMs = now.getTime() - date.getTime();
const diffInDays = Math.floor(diffInMs / (1000 * 60 * 60 * 24)); const diffInDays = Math.floor(diffInMs / (1000 * 60 * 60 * 24));
if (diffInDays === 0) return "Hoje"; if (diffInDays === 0) return "Today";
if (diffInDays === 1) return "Ontem"; if (diffInDays === 1) return "Yesterday";
if (diffInDays < 7) return `${diffInDays} dias atrás`; if (diffInDays < 7) return `${diffInDays} days ago`;
if (diffInDays < 30) return `${Math.floor(diffInDays / 7)} semanas atrás`; if (diffInDays < 30) return `${Math.floor(diffInDays / 7)} weeks ago`;
return `${Math.floor(diffInDays / 30)} meses atrás`; return `${Math.floor(diffInDays / 30)} months ago`;
}; };
const getTypeLabel = (type: string) => { const getTypeLabel = (type: string) => {
const typeLabels: { [key: string]: string } = { const typeLabels: { [key: string]: string } = {
"full-time": "Tempo integral", "full-time": "Full time",
"part-time": "Meio período", "part-time": "Part time",
contract: "Contrato", contract: "Contract",
Remoto: "Remoto", remote: "Remote",
}; };
return typeLabels[type] || type; return typeLabels[type] || type;
}; };
const mockCompanyInfo = { const mockCompanyInfo = {
size: "100-500 funcionários", size: "100-500 employees",
industry: "Tecnologia", industry: "Technology",
founded: "2015", founded: "2015",
website: "www.empresa.com", website: "www.company.com",
rating: 4.5, rating: 4.5,
}; };
@ -134,7 +134,7 @@ export default function JobDetailPage({
<Link href="/jobs"> <Link href="/jobs">
<Button variant="ghost" className="gap-2 hover:bg-muted"> <Button variant="ghost" className="gap-2 hover:bg-muted">
<ArrowLeft className="h-4 w-4" /> <ArrowLeft className="h-4 w-4" />
Voltar para vagas Back to jobs
</Button> </Button>
</Link> </Link>
</motion.div> </motion.div>
@ -224,7 +224,7 @@ export default function JobDetailPage({
: "" : ""
}`} }`}
/> />
{isFavorited ? "Favoritado" : "Favoritar"} {isFavorited ? "Favorited" : "Favorite"}
</Button> </Button>
<Button <Button
variant="outline" variant="outline"
@ -236,7 +236,7 @@ export default function JobDetailPage({
className={`h-4 w-4 mr-1 ${isBookmarked ? "fill-current" : "" className={`h-4 w-4 mr-1 ${isBookmarked ? "fill-current" : ""
}`} }`}
/> />
{isBookmarked ? "Salvo" : "Salvar"} {isBookmarked ? "Saved" : "Save"}
</Button> </Button>
<Button <Button
variant="outline" variant="outline"
@ -284,11 +284,11 @@ export default function JobDetailPage({
{/* Apply Button - Mobile */} {/* Apply Button - Mobile */}
<div className="lg:hidden pt-4"> <div className="lg:hidden pt-4">
<Link <Link
href={`/jobs/${job.id}/candidatura`} href={`/jobs/${job.id}/apply`}
className="w-full" className="w-full"
> >
<Button size="lg" className="w-full cursor-pointer"> <Button size="lg" className="w-full cursor-pointer">
Candidatar-se Apply now
</Button> </Button>
</Link> </Link>
</div> </div>
@ -304,7 +304,7 @@ export default function JobDetailPage({
> >
<Card> <Card>
<CardHeader> <CardHeader>
<CardTitle className="text-xl">Sobre a vaga</CardTitle> <CardTitle className="text-xl">About the role</CardTitle>
</CardHeader> </CardHeader>
<CardContent className="prose prose-sm max-w-none"> <CardContent className="prose prose-sm max-w-none">
<p className="text-muted-foreground leading-relaxed whitespace-pre-line"> <p className="text-muted-foreground leading-relaxed whitespace-pre-line">
@ -322,7 +322,7 @@ export default function JobDetailPage({
> >
<Card> <Card>
<CardHeader> <CardHeader>
<CardTitle className="text-xl">Requisitos</CardTitle> <CardTitle className="text-xl">Requirements</CardTitle>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<div className="grid gap-3"> <div className="grid gap-3">
@ -345,21 +345,21 @@ export default function JobDetailPage({
> >
<Card> <Card>
<CardHeader> <CardHeader>
<CardTitle className="text-xl">Sobre a empresa</CardTitle> <CardTitle className="text-xl">About the company</CardTitle>
</CardHeader> </CardHeader>
<CardContent className="space-y-4"> <CardContent className="space-y-4">
<p className="text-muted-foreground leading-relaxed"> <p className="text-muted-foreground leading-relaxed">
{job.company} é uma empresa líder no mercado, {job.company} is a market leader committed to creating
comprometida em criar um ambiente de trabalho inclusivo an inclusive and innovative workplace. We offer
e inovador. Oferecemos benefícios competitivos e competitive benefits and opportunities for professional
oportunidades de crescimento profissional. growth.
</p> </p>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 pt-4 border-t"> <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 pt-4 border-t">
<div> <div>
<div className="flex items-center gap-2 text-sm text-muted-foreground mb-1"> <div className="flex items-center gap-2 text-sm text-muted-foreground mb-1">
<Users className="h-4 w-4 shrink-0" /> <Users className="h-4 w-4 shrink-0" />
<span>Tamanho</span> <span>Size</span>
</div> </div>
<p className="font-medium text-sm"> <p className="font-medium text-sm">
{mockCompanyInfo.size} {mockCompanyInfo.size}
@ -368,7 +368,7 @@ export default function JobDetailPage({
<div> <div>
<div className="flex items-center gap-2 text-sm text-muted-foreground mb-1"> <div className="flex items-center gap-2 text-sm text-muted-foreground mb-1">
<Building2 className="h-4 w-4 shrink-0" /> <Building2 className="h-4 w-4 shrink-0" />
<span>Setor</span> <span>Industry</span>
</div> </div>
<p className="font-medium text-sm"> <p className="font-medium text-sm">
{mockCompanyInfo.industry} {mockCompanyInfo.industry}
@ -377,7 +377,7 @@ export default function JobDetailPage({
<div> <div>
<div className="flex items-center gap-2 text-sm text-muted-foreground mb-1"> <div className="flex items-center gap-2 text-sm text-muted-foreground mb-1">
<Calendar className="h-4 w-4 shrink-0" /> <Calendar className="h-4 w-4 shrink-0" />
<span>Fundada</span> <span>Founded</span>
</div> </div>
<p className="font-medium text-sm"> <p className="font-medium text-sm">
{mockCompanyInfo.founded} {mockCompanyInfo.founded}
@ -414,19 +414,19 @@ export default function JobDetailPage({
<Card> <Card>
<CardHeader> <CardHeader>
<CardTitle className="text-lg"> <CardTitle className="text-lg">
Interessado na vaga? Interested in this role?
</CardTitle> </CardTitle>
<CardDescription> <CardDescription>
Candidate-se agora e faça parte da nossa equipe! Apply now and join our team!
</CardDescription> </CardDescription>
</CardHeader> </CardHeader>
<CardContent className="space-y-4"> <CardContent className="space-y-4">
<Link <Link
href={`/jobs/${job.id}/candidatura`} href={`/jobs/${job.id}/apply`}
className="w-full" className="w-full"
> >
<Button size="lg" className="w-full cursor-pointer"> <Button size="lg" className="w-full cursor-pointer">
Candidatar-se Apply now
</Button> </Button>
</Link> </Link>
@ -435,7 +435,7 @@ export default function JobDetailPage({
<div className="space-y-3 text-sm"> <div className="space-y-3 text-sm">
<div className="flex items-start justify-between gap-2"> <div className="flex items-start justify-between gap-2">
<span className="text-muted-foreground"> <span className="text-muted-foreground">
Tipo de vaga: Job type:
</span> </span>
<Badge <Badge
variant="outline" variant="outline"
@ -446,7 +446,7 @@ export default function JobDetailPage({
</div> </div>
<div className="flex items-start justify-between gap-2"> <div className="flex items-start justify-between gap-2">
<span className="text-muted-foreground shrink-0"> <span className="text-muted-foreground shrink-0">
Localização: Location:
</span> </span>
<span className="font-medium text-right"> <span className="font-medium text-right">
{job.location} {job.location}
@ -455,7 +455,7 @@ export default function JobDetailPage({
{job.salary && ( {job.salary && (
<div className="flex items-start justify-between gap-2"> <div className="flex items-start justify-between gap-2">
<span className="text-muted-foreground"> <span className="text-muted-foreground">
Salário: Salary:
</span> </span>
<span className="font-medium text-right whitespace-nowrap"> <span className="font-medium text-right whitespace-nowrap">
{job.salary} {job.salary}
@ -464,7 +464,7 @@ export default function JobDetailPage({
)} )}
<div className="flex items-start justify-between gap-2"> <div className="flex items-start justify-between gap-2">
<span className="text-muted-foreground"> <span className="text-muted-foreground">
Publicado: Posted:
</span> </span>
<span className="font-medium text-right whitespace-nowrap"> <span className="font-medium text-right whitespace-nowrap">
{formatTimeAgo(job.postedAt)} {formatTimeAgo(job.postedAt)}
@ -483,7 +483,7 @@ export default function JobDetailPage({
> >
<Card> <Card>
<CardHeader> <CardHeader>
<CardTitle className="text-lg">Vagas similares</CardTitle> <CardTitle className="text-lg">Similar jobs</CardTitle>
</CardHeader> </CardHeader>
<CardContent className="space-y-4"> <CardContent className="space-y-4">
{mockJobs {mockJobs
@ -510,7 +510,7 @@ export default function JobDetailPage({
))} ))}
<Link href="/jobs"> <Link href="/jobs">
<Button variant="outline" size="sm" className="w-full"> <Button variant="outline" size="sm" className="w-full">
Ver todas as vagas View all jobs
</Button> </Button>
</Link> </Link>
</CardContent> </CardContent>

View file

@ -44,7 +44,7 @@ function JobsContent() {
setShowFilters(true) // Show filters if searching setShowFilters(true) // Show filters if searching
} }
if (type === "remoto") { if (type === "remote") {
setWorkModeFilter("remote") setWorkModeFilter("remote")
setShowFilters(true) setShowFilters(true)
} }
@ -69,7 +69,7 @@ function JobsContent() {
setJobs(mappedJobs) setJobs(mappedJobs)
} }
} catch (err) { } catch (err) {
console.error("Erro ao buscar vagas", err) console.error("Error fetching jobs", err)
if (isMounted) { if (isMounted) {
setError(t('jobs.error')) setError(t('jobs.error'))
setJobs(mockJobs) setJobs(mockJobs)
@ -146,6 +146,11 @@ function JobsContent() {
return filtered return filtered
}, [debouncedSearchTerm, locationFilter, typeFilter, workModeFilter, sortBy, jobs]) }, [debouncedSearchTerm, locationFilter, typeFilter, workModeFilter, sortBy, jobs])
const getTypeLabel = (type: string) => {
const label = t(`jobs.types.${type}`)
return label !== `jobs.types.${type}` ? label : type
}
// Pagination Logic // Pagination Logic
const totalPages = Math.ceil(filteredAndSortedJobs.length / ITEMS_PER_PAGE) const totalPages = Math.ceil(filteredAndSortedJobs.length / ITEMS_PER_PAGE)
const paginatedJobs = filteredAndSortedJobs.slice( const paginatedJobs = filteredAndSortedJobs.slice(
@ -256,9 +261,7 @@ function JobsContent() {
<SelectItem value="all">{t('jobs.filters.all')}</SelectItem> <SelectItem value="all">{t('jobs.filters.all')}</SelectItem>
{uniqueTypes.map((type) => ( {uniqueTypes.map((type) => (
<SelectItem key={type} value={type}> <SelectItem key={type} value={type}>
{type === "full-time" ? "Tempo integral" : {getTypeLabel(type)}
type === "part-time" ? "Meio período" :
type === "contract" ? "Contrato" : type}
</SelectItem> </SelectItem>
))} ))}
</SelectContent> </SelectContent>
@ -322,7 +325,7 @@ function JobsContent() {
</span> </span>
{hasActiveFilters && ( {hasActiveFilters && (
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<span>Filtros ativos:</span> <span>Active filters:</span>
{searchTerm && ( {searchTerm && (
<Badge variant="secondary" className="gap-1"> <Badge variant="secondary" className="gap-1">
"{searchTerm}" "{searchTerm}"
@ -349,9 +352,9 @@ function JobsContent() {
)} )}
{workModeFilter !== "all" && ( {workModeFilter !== "all" && (
<Badge variant="secondary" className="gap-1"> <Badge variant="secondary" className="gap-1">
{workModeFilter === "remote" ? "Remoto" : {workModeFilter === "remote" ? t("workMode.remote") :
workModeFilter === "hybrid" ? "Híbrido" : workModeFilter === "hybrid" ? t("workMode.hybrid") :
workModeFilter === "onsite" ? "Presencial" : workModeFilter} workModeFilter === "onsite" ? t("workMode.onsite") : workModeFilter}
<button onClick={() => setWorkModeFilter("all")} className="ml-1"> <button onClick={() => setWorkModeFilter("all")} className="ml-1">
<X className="h-3 w-3" /> <X className="h-3 w-3" />
</button> </button>
@ -448,7 +451,7 @@ function JobsContent() {
) )
} }
export default function VagasPage() { export default function JobsPage() {
return ( return (
<div className="min-h-screen flex flex-col"> <div className="min-h-screen flex flex-col">
<Navbar /> <Navbar />

View file

@ -111,7 +111,7 @@ export default function HomePage() {
<ArrowRight className="ml-2 h-4 w-4" /> <ArrowRight className="ml-2 h-4 w-4" />
</Button> </Button>
</Link> </Link>
<Link href="/cadastro/empresa"> <Link href="/register/company">
<Button size="lg" variant="outline" className="w-full sm:w-auto bg-transparent"> <Button size="lg" variant="outline" className="w-full sm:w-auto bg-transparent">
<Building2 className="mr-2 h-4 w-4" /> <Building2 className="mr-2 h-4 w-4" />
{t('home.hero.imCompany')} {t('home.hero.imCompany')}
@ -277,7 +277,7 @@ export default function HomePage() {
{t('home.cta.subtitle')} {t('home.cta.subtitle')}
</p> </p>
<div> <div>
<Link href="/cadastro/candidato"> <Link href="/register/candidate">
<Button size="lg" variant="secondary"> <Button size="lg" variant="secondary">
{t('home.cta.button')} {t('home.cta.button')}
<ArrowRight className="ml-2 h-4 w-4" /> <ArrowRight className="ml-2 h-4 w-4" />

View file

@ -8,13 +8,13 @@ export default function PrivacyPage() {
<main className="min-h-screen flex flex-col"> <main className="min-h-screen flex flex-col">
<Navbar /> <Navbar />
<div className="container mx-auto px-4 py-12 flex-1"> <div className="container mx-auto px-4 py-12 flex-1">
<h1 className="text-3xl font-bold mb-6">Política de Privacidade</h1> <h1 className="text-3xl font-bold mb-6">Privacy Policy</h1>
<div className="prose max-w-none"> <div className="prose max-w-none">
<p> <p>
Esta Política de Privacidade descreve como coletamos, usamos e protegemos suas informações pessoais. This Privacy Policy describes how we collect, use, and protect your personal information.
</p> </p>
<p className="mt-4"> <p className="mt-4">
Em construção... Coming soon...
</p> </p>
</div> </div>
</div> </div>

View file

@ -39,11 +39,11 @@ export default function ProfilePage() {
const handleSubmit = (e: React.FormEvent) => { const handleSubmit = (e: React.FormEvent) => {
e.preventDefault() e.preventDefault()
updateProfileData(formData) updateProfileData(formData)
alert("✅ Perfil salvo com sucesso no banco local!") alert("✅ Profile saved successfully to local storage!")
} }
const handleClearDatabase = () => { const handleClearDatabase = () => {
if (confirm("⚠️ Tem certeza que deseja limpar todos os dados? Esta ação não pode ser desfeita.")) { if (confirm("⚠️ Are you sure you want to clear all data? This action cannot be undone.")) {
localDB.clearAllData() localDB.clearAllData()
window.location.reload() window.location.reload()
} }
@ -67,7 +67,7 @@ export default function ProfilePage() {
<div className="min-h-screen bg-gray-50 flex items-center justify-center"> <div className="min-h-screen bg-gray-50 flex items-center justify-center">
<div className="text-center"> <div className="text-center">
<Database className="w-12 h-12 mx-auto mb-4 animate-pulse" /> <Database className="w-12 h-12 mx-auto mb-4 animate-pulse" />
<p>Carregando dados do banco local...</p> <p>Loading local data...</p>
</div> </div>
</div> </div>
) )
@ -79,7 +79,7 @@ export default function ProfilePage() {
<div className="mb-6"> <div className="mb-6">
<Link href="/" className="inline-flex items-center text-sm text-muted-foreground hover:text-foreground"> <Link href="/" className="inline-flex items-center text-sm text-muted-foreground hover:text-foreground">
<ArrowLeft className="w-4 h-4 mr-2" /> <ArrowLeft className="w-4 h-4 mr-2" />
Voltar Back
</Link> </Link>
</div> </div>
@ -89,7 +89,7 @@ export default function ProfilePage() {
<div className="flex items-center space-x-2"> <div className="flex items-center space-x-2">
<Database className="w-5 h-5 text-green-600" /> <Database className="w-5 h-5 text-green-600" />
<span className="text-sm font-medium text-green-800"> <span className="text-sm font-medium text-green-800">
Banco Local Ativo Local storage active
</span> </span>
</div> </div>
<div className="flex space-x-2"> <div className="flex space-x-2">
@ -99,7 +99,7 @@ export default function ProfilePage() {
onClick={handleExportData} onClick={handleExportData}
className="text-xs" className="text-xs"
> >
Exportar Export
</Button> </Button>
<Button <Button
size="sm" size="sm"
@ -108,7 +108,7 @@ export default function ProfilePage() {
className="text-xs" className="text-xs"
> >
<Trash2 className="w-3 h-3 mr-1" /> <Trash2 className="w-3 h-3 mr-1" />
Limpar Clear
</Button> </Button>
</div> </div>
</div> </div>
@ -118,10 +118,10 @@ export default function ProfilePage() {
<Card> <Card>
<CardHeader> <CardHeader>
<CardTitle className="text-2xl font-bold text-center"> <CardTitle className="text-2xl font-bold text-center">
Editar Perfil Edit profile
</CardTitle> </CardTitle>
<p className="text-center text-sm text-muted-foreground"> <p className="text-center text-sm text-muted-foreground">
Seus dados são salvos automaticamente no navegador Your data is saved automatically in your browser
</p> </p>
</CardHeader> </CardHeader>
<CardContent className="space-y-6"> <CardContent className="space-y-6">
@ -136,13 +136,13 @@ export default function ProfilePage() {
<form onSubmit={handleSubmit} className="space-y-4"> <form onSubmit={handleSubmit} className="space-y-4">
<div className="grid grid-cols-1 md:grid-cols-2 gap-4"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div> <div>
<Label htmlFor="name">Nome completo</Label> <Label htmlFor="name">Full name</Label>
<Input <Input
id="name" id="name"
type="text" type="text"
value={formData.name} value={formData.name}
onChange={(e) => handleInputChange("name", e.target.value)} onChange={(e) => handleInputChange("name", e.target.value)}
placeholder="Seu nome completo" placeholder="Your full name"
/> />
</div> </div>
<div> <div>
@ -152,13 +152,13 @@ export default function ProfilePage() {
type="email" type="email"
value={formData.email} value={formData.email}
onChange={(e) => handleInputChange("email", e.target.value)} onChange={(e) => handleInputChange("email", e.target.value)}
placeholder="seu@email.com" placeholder="you@email.com"
/> />
</div> </div>
</div> </div>
<div> <div>
<Label htmlFor="phone">Telefone</Label> <Label htmlFor="phone">Phone</Label>
<Input <Input
id="phone" id="phone"
type="tel" type="tel"
@ -169,19 +169,19 @@ export default function ProfilePage() {
</div> </div>
<div> <div>
<Label htmlFor="bio">Biografia</Label> <Label htmlFor="bio">Bio</Label>
<Textarea <Textarea
id="bio" id="bio"
value={formData.bio} value={formData.bio}
onChange={(e) => handleInputChange("bio", e.target.value)} onChange={(e) => handleInputChange("bio", e.target.value)}
placeholder="Conte um pouco sobre você..." placeholder="Tell us a bit about yourself..."
rows={4} rows={4}
/> />
</div> </div>
<Button type="submit" className="w-full" size="lg"> <Button type="submit" className="w-full" size="lg">
<Save className="w-4 h-4 mr-2" /> <Save className="w-4 h-4 mr-2" />
Salvar Perfil Save profile
</Button> </Button>
</form> </form>
</CardContent> </CardContent>
@ -190,13 +190,13 @@ export default function ProfilePage() {
{profileData && ( {profileData && (
<Card className="mt-8"> <Card className="mt-8">
<CardHeader> <CardHeader>
<CardTitle className="text-lg">Dados Salvos no Banco Local</CardTitle> <CardTitle className="text-lg">Saved local data</CardTitle>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<pre className="text-xs bg-gray-100 p-4 rounded overflow-auto"> <pre className="text-xs bg-gray-100 p-4 rounded overflow-auto">
{JSON.stringify({ {JSON.stringify({
...profileData, ...profileData,
profileImage: profileData.profileImage ? "✅ Imagem salva" : "❌ Sem imagem" profileImage: profileData.profileImage ? "✅ Image saved" : "❌ No image"
}, null, 2)} }, null, 2)}
</pre> </pre>
</CardContent> </CardContent>

View file

@ -21,7 +21,7 @@ export default function ProfilePage() {
bio: "" bio: ""
}) })
// Sincronizar dados do perfil com o formulário // Sync profile data with the form
useEffect(() => { useEffect(() => {
if (profileData) { if (profileData) {
setFormData({ setFormData({
@ -40,14 +40,14 @@ export default function ProfilePage() {
const handleSubmit = (e: React.FormEvent) => { const handleSubmit = (e: React.FormEvent) => {
e.preventDefault() e.preventDefault()
// Salvar dados no banco local // Save data to local storage
updateProfileData(formData) updateProfileData(formData)
alert("✅ Perfil salvo com sucesso no banco local!") alert("✅ Profile saved successfully to local storage!")
} }
const handleClearDatabase = () => { const handleClearDatabase = () => {
if (confirm("⚠️ Tem certeza que deseja limpar todos os dados? Esta ação não pode ser desfeita.")) { if (confirm("⚠️ Are you sure you want to clear all data? This action cannot be undone.")) {
localDB.clearAllData() localDB.clearAllData()
window.location.reload() window.location.reload()
} }
@ -71,7 +71,7 @@ export default function ProfilePage() {
<div className="min-h-screen bg-gray-50 flex items-center justify-center"> <div className="min-h-screen bg-gray-50 flex items-center justify-center">
<div className="text-center"> <div className="text-center">
<Database className="w-12 h-12 mx-auto mb-4 animate-pulse" /> <Database className="w-12 h-12 mx-auto mb-4 animate-pulse" />
<p>Carregando dados do banco local...</p> <p>Loading local data...</p>
</div> </div>
</div> </div>
) )
@ -83,18 +83,18 @@ export default function ProfilePage() {
<div className="mb-6"> <div className="mb-6">
<Link href="/" className="inline-flex items-center text-sm text-muted-foreground hover:text-foreground"> <Link href="/" className="inline-flex items-center text-sm text-muted-foreground hover:text-foreground">
<ArrowLeft className="w-4 h-4 mr-2" /> <ArrowLeft className="w-4 h-4 mr-2" />
Voltar Back
</Link> </Link>
</div> </div>
{/* Status do Banco de Dados */} {/* Local storage status */}
<Card className="mb-6 bg-green-50 border-green-200"> <Card className="mb-6 bg-green-50 border-green-200">
<CardContent className="p-4"> <CardContent className="p-4">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div className="flex items-center space-x-2"> <div className="flex items-center space-x-2">
<Database className="w-5 h-5 text-green-600" /> <Database className="w-5 h-5 text-green-600" />
<span className="text-sm font-medium text-green-800"> <span className="text-sm font-medium text-green-800">
Banco Local Ativo Local storage active
</span> </span>
</div> </div>
<div className="flex space-x-2"> <div className="flex space-x-2">
@ -104,7 +104,7 @@ export default function ProfilePage() {
onClick={handleExportData} onClick={handleExportData}
className="text-xs" className="text-xs"
> >
Exportar Export
</Button> </Button>
<Button <Button
size="sm" size="sm"
@ -113,7 +113,7 @@ export default function ProfilePage() {
className="text-xs" className="text-xs"
> >
<Trash2 className="w-3 h-3 mr-1" /> <Trash2 className="w-3 h-3 mr-1" />
Limpar Clear
</Button> </Button>
</div> </div>
</div> </div>
@ -123,14 +123,14 @@ export default function ProfilePage() {
<Card> <Card>
<CardHeader> <CardHeader>
<CardTitle className="text-2xl font-bold text-center"> <CardTitle className="text-2xl font-bold text-center">
Editar Perfil Edit profile
</CardTitle> </CardTitle>
<p className="text-center text-sm text-muted-foreground"> <p className="text-center text-sm text-muted-foreground">
Seus dados são salvos automaticamente no navegador Your data is saved automatically in your browser
</p> </p>
</CardHeader> </CardHeader>
<CardContent className="space-y-6"> <CardContent className="space-y-6">
{/* Upload de foto de perfil com banco de dados */} {/* Profile photo upload with local data */}
<div className="flex justify-center"> <div className="flex justify-center">
<ProfilePictureUpload <ProfilePictureUpload
fallbackText={formData.name ? formData.name.charAt(0).toUpperCase() : "U"} fallbackText={formData.name ? formData.name.charAt(0).toUpperCase() : "U"}
@ -139,17 +139,17 @@ export default function ProfilePage() {
/> />
</div> </div>
{/* Formulário */} {/* Form */}
<form onSubmit={handleSubmit} className="space-y-4"> <form onSubmit={handleSubmit} className="space-y-4">
<div className="grid grid-cols-1 md:grid-cols-2 gap-4"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div> <div>
<Label htmlFor="name">Nome completo</Label> <Label htmlFor="name">Full name</Label>
<Input <Input
id="name" id="name"
type="text" type="text"
value={formData.name} value={formData.name}
onChange={(e) => handleInputChange("name", e.target.value)} onChange={(e) => handleInputChange("name", e.target.value)}
placeholder="Seu nome completo" placeholder="Your full name"
/> />
</div> </div>
<div> <div>
@ -159,13 +159,13 @@ export default function ProfilePage() {
type="email" type="email"
value={formData.email} value={formData.email}
onChange={(e) => handleInputChange("email", e.target.value)} onChange={(e) => handleInputChange("email", e.target.value)}
placeholder="seu@email.com" placeholder="you@email.com"
/> />
</div> </div>
</div> </div>
<div> <div>
<Label htmlFor="phone">Telefone</Label> <Label htmlFor="phone">Phone</Label>
<Input <Input
id="phone" id="phone"
type="tel" type="tel"
@ -176,35 +176,35 @@ export default function ProfilePage() {
</div> </div>
<div> <div>
<Label htmlFor="bio">Biografia</Label> <Label htmlFor="bio">Bio</Label>
<Textarea <Textarea
id="bio" id="bio"
value={formData.bio} value={formData.bio}
onChange={(e) => handleInputChange("bio", e.target.value)} onChange={(e) => handleInputChange("bio", e.target.value)}
placeholder="Conte um pouco sobre você..." placeholder="Tell us a bit about yourself..."
rows={4} rows={4}
/> />
</div> </div>
<Button type="submit" className="w-full" size="lg"> <Button type="submit" className="w-full" size="lg">
<Save className="w-4 h-4 mr-2" /> <Save className="w-4 h-4 mr-2" />
Salvar Perfil Save profile
</Button> </Button>
</form> </form>
</CardContent> </CardContent>
</Card> </Card>
{/* Debug: Dados salvos */} {/* Debug: Saved data */}
{profileData && ( {profileData && (
<Card className="mt-8"> <Card className="mt-8">
<CardHeader> <CardHeader>
<CardTitle className="text-lg">Dados Salvos no Banco Local</CardTitle> <CardTitle className="text-lg">Saved local data</CardTitle>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<pre className="text-xs bg-gray-100 p-4 rounded overflow-auto"> <pre className="text-xs bg-gray-100 p-4 rounded overflow-auto">
{JSON.stringify({ {JSON.stringify({
...profileData, ...profileData,
profileImage: profileData.profileImage ? "✅ Imagem salva" : "❌ Sem imagem" profileImage: profileData.profileImage ? "✅ Image saved" : "❌ No image"
}, null, 2)} }, null, 2)}
</pre> </pre>
</CardContent> </CardContent>

View file

@ -540,11 +540,11 @@ export default function CandidateRegisterPage() {
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
> >
{t("register.candidate.acceptTerms.prefix")}{" "} {t("register.candidate.acceptTerms.prefix")}{" "}
<Link href="/termos" className="text-primary hover:underline"> <Link href="/terms" className="text-primary hover:underline">
{t("register.candidate.acceptTerms.terms")} {t("register.candidate.acceptTerms.terms")}
</Link>{" "} </Link>{" "}
{t("register.candidate.acceptTerms.and")}{" "} {t("register.candidate.acceptTerms.and")}{" "}
<Link href="/privacidade" className="text-primary hover:underline"> <Link href="/privacy" className="text-primary hover:underline">
{t("register.candidate.acceptTerms.privacy")} {t("register.candidate.acceptTerms.privacy")}
</Link> </Link>
</label> </label>

View file

@ -43,26 +43,26 @@ import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod"; import { z } from "zod";
const companySchema = z.object({ const companySchema = z.object({
companyName: z.string().min(2, "Nome da empresa deve ter pelo menos 2 caracteres"), companyName: z.string().min(2, "Company name must be at least 2 characters"),
cnpj: z.string().min(14, "CNPJ deve ter 14 dígitos"), cnpj: z.string().min(14, "CNPJ must have 14 digits"),
email: z.string().email("Email inválido"), email: z.string().email("Invalid email"),
password: z.string().min(6, "Senha deve ter pelo menos 6 caracteres"), password: z.string().min(6, "Password must be at least 6 characters"),
confirmPassword: z.string(), confirmPassword: z.string(),
phone: z.string().min(10, "Telefone deve ter pelo menos 10 dígitos"), phone: z.string().min(10, "Phone must have at least 10 digits"),
website: z.string().url("Website deve ser uma URL válida").optional().or(z.literal("")), website: z.string().url("Website must be a valid URL").optional().or(z.literal("")),
address: z.string().min(5, "Endereço deve ter pelo menos 5 caracteres"), address: z.string().min(5, "Address must be at least 5 characters"),
city: z.string().min(2, "Cidade é obrigatória"), city: z.string().min(2, "City is required"),
state: z.string().min(2, "Estado é obrigatório"), state: z.string().min(2, "State is required"),
zipCode: z.string().min(8, "CEP deve ter 8 dígitos"), zipCode: z.string().min(8, "ZIP code must have 8 digits"),
sector: z.string().min(1, "Setor de atuação é obrigatório"), sector: z.string().min(1, "Industry is required"),
companySize: z.string().min(1, "Tamanho da empresa é obrigatório"), companySize: z.string().min(1, "Company size is required"),
description: z.string().min(20, "Descrição deve ter pelo menos 20 caracteres"), description: z.string().min(20, "Description must be at least 20 characters"),
contactPerson: z.string().min(2, "Nome do responsável é obrigatório"), contactPerson: z.string().min(2, "Contact name is required"),
contactRole: z.string().min(2, "Cargo do responsável é obrigatório"), contactRole: z.string().min(2, "Contact role is required"),
acceptTerms: z.boolean().refine(val => val === true, "Você deve aceitar os termos"), acceptTerms: z.boolean().refine(val => val === true, "You must accept the terms"),
acceptNewsletter: z.boolean().optional(), acceptNewsletter: z.boolean().optional(),
}).refine(data => data.password === data.confirmPassword, { }).refine(data => data.password === data.confirmPassword, {
message: "Senhas não coincidem", message: "Passwords do not match",
path: ["confirmPassword"], path: ["confirmPassword"],
}); });
@ -91,14 +91,14 @@ export default function CompanyRegisterPage() {
const onSubmit = async (data: CompanyFormData) => { const onSubmit = async (data: CompanyFormData) => {
setLoading(true); setLoading(true);
try { try {
// Simular cadastro // Simulate registration
await new Promise(resolve => setTimeout(resolve, 2000)); await new Promise(resolve => setTimeout(resolve, 2000));
console.log("Dados da empresa:", data); console.log("Company data:", data);
// Redirecionar para login após cadastro // Redirect to login after registration
router.push("/login?message=Cadastro realizado com sucesso! Faça login para continuar."); router.push("/login?message=Registration completed successfully! Please sign in to continue.");
} catch (error) { } catch (error) {
console.error("Erro no cadastro:", error); console.error("Registration error:", error);
} finally { } finally {
setLoading(false); setLoading(false);
} }
@ -120,7 +120,7 @@ export default function CompanyRegisterPage() {
return ( return (
<div className="min-h-screen bg-gradient-to-br from-background to-muted/20 flex"> <div className="min-h-screen bg-gradient-to-br from-background to-muted/20 flex">
{/* Left Panel - Informações */} {/* Left Panel - Information */}
<div className="hidden lg:flex lg:flex-1 bg-gradient-to-br from-primary to-primary/80 p-8 flex-col justify-center items-center text-primary-foreground"> <div className="hidden lg:flex lg:flex-1 bg-gradient-to-br from-primary to-primary/80 p-8 flex-col justify-center items-center text-primary-foreground">
<motion.div <motion.div
initial={{ opacity: 0, y: 20 }} initial={{ opacity: 0, y: 20 }}
@ -132,36 +132,36 @@ export default function CompanyRegisterPage() {
</div> </div>
<h1 className="text-4xl font-bold mb-4"> <h1 className="text-4xl font-bold mb-4">
Cadastre sua Empresa Register your company
</h1> </h1>
<p className="text-lg opacity-90 leading-relaxed mb-6"> <p className="text-lg opacity-90 leading-relaxed mb-6">
Encontre os melhores talentos para sua empresa. Find top talent for your company.
Publique vagas e conecte-se com candidatos qualificados. Post jobs and connect with qualified candidates.
</p> </p>
<div className="space-y-4 text-left"> <div className="space-y-4 text-left">
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<div className="w-2 h-2 bg-white rounded-full"></div> <div className="w-2 h-2 bg-white rounded-full"></div>
<span>Publique vagas gratuitamente</span> <span>Post jobs for free</span>
</div> </div>
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<div className="w-2 h-2 bg-white rounded-full"></div> <div className="w-2 h-2 bg-white rounded-full"></div>
<span>Acesso a milhares de candidatos</span> <span>Access thousands of candidates</span>
</div> </div>
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<div className="w-2 h-2 bg-white rounded-full"></div> <div className="w-2 h-2 bg-white rounded-full"></div>
<span>Ferramentas de gestão de candidaturas</span> <span>Application management tools</span>
</div> </div>
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<div className="w-2 h-2 bg-white rounded-full"></div> <div className="w-2 h-2 bg-white rounded-full"></div>
<span>Dashboard completo de recrutamento</span> <span>Complete recruiting dashboard</span>
</div> </div>
</div> </div>
</motion.div> </motion.div>
</div> </div>
{/* Right Panel - Formulário */} {/* Right Panel - Form */}
<div className="flex-1 p-8 flex flex-col justify-center"> <div className="flex-1 p-8 flex flex-col justify-center">
<div className="w-full max-w-md mx-auto"> <div className="w-full max-w-md mx-auto">
{/* Header */} {/* Header */}
@ -171,25 +171,25 @@ export default function CompanyRegisterPage() {
className="inline-flex items-center gap-2 text-muted-foreground hover:text-foreground mb-4 transition-colors" className="inline-flex items-center gap-2 text-muted-foreground hover:text-foreground mb-4 transition-colors"
> >
<ArrowLeft className="w-4 h-4" /> <ArrowLeft className="w-4 h-4" />
Voltar ao Login Back to login
</Link> </Link>
<h2 className="text-2xl font-bold text-foreground mb-2"> <h2 className="text-2xl font-bold text-foreground mb-2">
Criar Conta - Empresa Create account - company
</h2> </h2>
<p className="text-muted-foreground"> <p className="text-muted-foreground">
Preencha os dados da sua empresa Fill in your company details
</p> </p>
</div> </div>
{/* Progress Indicator */} {/* Progress Indicator */}
<div className="mb-8"> <div className="mb-8">
<div className="flex items-center justify-between mb-2"> <div className="flex items-center justify-between mb-2">
<span className="text-sm font-medium">Etapa {currentStep} de 3</span> <span className="text-sm font-medium">Step {currentStep} of 3</span>
<span className="text-sm text-muted-foreground"> <span className="text-sm text-muted-foreground">
{currentStep === 1 && "Dados da Empresa"} {currentStep === 1 && "Company details"}
{currentStep === 2 && "Endereço e Contato"} {currentStep === 2 && "Address & contact"}
{currentStep === 3 && "Informações Adicionais"} {currentStep === 3 && "Additional information"}
</span> </span>
</div> </div>
<div className="w-full bg-muted rounded-full h-2"> <div className="w-full bg-muted rounded-full h-2">
@ -201,7 +201,7 @@ export default function CompanyRegisterPage() {
</div> </div>
<form onSubmit={handleSubmit(onSubmit)} className="space-y-6"> <form onSubmit={handleSubmit(onSubmit)} className="space-y-6">
{/* Step 1: Dados da Empresa */} {/* Step 1: Company details */}
{currentStep === 1 && ( {currentStep === 1 && (
<motion.div <motion.div
key="step1" key="step1"
@ -212,13 +212,13 @@ export default function CompanyRegisterPage() {
className="space-y-4" className="space-y-4"
> >
<div className="space-y-2"> <div className="space-y-2">
<Label htmlFor="companyName">Nome da Empresa</Label> <Label htmlFor="companyName">Company name</Label>
<div className="relative"> <div className="relative">
<Building2 className="absolute left-3 top-3 h-4 w-4 text-muted-foreground" /> <Building2 className="absolute left-3 top-3 h-4 w-4 text-muted-foreground" />
<Input <Input
id="companyName" id="companyName"
type="text" type="text"
placeholder="Nome da sua empresa" placeholder="Your company name"
className="pl-10" className="pl-10"
{...register("companyName")} {...register("companyName")}
/> />
@ -246,13 +246,13 @@ export default function CompanyRegisterPage() {
</div> </div>
<div className="space-y-2"> <div className="space-y-2">
<Label htmlFor="email">Email Corporativo</Label> <Label htmlFor="email">Company email</Label>
<div className="relative"> <div className="relative">
<Mail className="absolute left-3 top-3 h-4 w-4 text-muted-foreground" /> <Mail className="absolute left-3 top-3 h-4 w-4 text-muted-foreground" />
<Input <Input
id="email" id="email"
type="email" type="email"
placeholder="contato@empresa.com" placeholder="hello@company.com"
className="pl-10" className="pl-10"
{...register("email")} {...register("email")}
/> />
@ -263,13 +263,13 @@ export default function CompanyRegisterPage() {
</div> </div>
<div className="space-y-2"> <div className="space-y-2">
<Label htmlFor="password">Senha</Label> <Label htmlFor="password">Password</Label>
<div className="relative"> <div className="relative">
<Lock className="absolute left-3 top-3 h-4 w-4 text-muted-foreground" /> <Lock className="absolute left-3 top-3 h-4 w-4 text-muted-foreground" />
<Input <Input
id="password" id="password"
type={showPassword ? "text" : "password"} type={showPassword ? "text" : "password"}
placeholder="Sua senha" placeholder="Your password"
className="pl-10 pr-10" className="pl-10 pr-10"
{...register("password")} {...register("password")}
/> />
@ -293,13 +293,13 @@ export default function CompanyRegisterPage() {
</div> </div>
<div className="space-y-2"> <div className="space-y-2">
<Label htmlFor="confirmPassword">Confirmar Senha</Label> <Label htmlFor="confirmPassword">Confirm password</Label>
<div className="relative"> <div className="relative">
<Lock className="absolute left-3 top-3 h-4 w-4 text-muted-foreground" /> <Lock className="absolute left-3 top-3 h-4 w-4 text-muted-foreground" />
<Input <Input
id="confirmPassword" id="confirmPassword"
type={showConfirmPassword ? "text" : "password"} type={showConfirmPassword ? "text" : "password"}
placeholder="Confirme sua senha" placeholder="Confirm your password"
className="pl-10 pr-10" className="pl-10 pr-10"
{...register("confirmPassword")} {...register("confirmPassword")}
/> />
@ -323,12 +323,12 @@ export default function CompanyRegisterPage() {
</div> </div>
<Button type="button" onClick={nextStep} className="w-full"> <Button type="button" onClick={nextStep} className="w-full">
Próxima Etapa Next step
</Button> </Button>
</motion.div> </motion.div>
)} )}
{/* Step 2: Endereço e Contato */} {/* Step 2: Address & contact */}
{currentStep === 2 && ( {currentStep === 2 && (
<motion.div <motion.div
key="step2" key="step2"
@ -339,7 +339,7 @@ export default function CompanyRegisterPage() {
className="space-y-4" className="space-y-4"
> >
<div className="space-y-2"> <div className="space-y-2">
<Label htmlFor="phone">Telefone</Label> <Label htmlFor="phone">Phone</Label>
<div className="relative"> <div className="relative">
<Phone className="absolute left-3 top-3 h-4 w-4 text-muted-foreground" /> <Phone className="absolute left-3 top-3 h-4 w-4 text-muted-foreground" />
<Input <Input
@ -356,13 +356,13 @@ export default function CompanyRegisterPage() {
</div> </div>
<div className="space-y-2"> <div className="space-y-2">
<Label htmlFor="website">Website (opcional)</Label> <Label htmlFor="website">Website (optional)</Label>
<div className="relative"> <div className="relative">
<Globe className="absolute left-3 top-3 h-4 w-4 text-muted-foreground" /> <Globe className="absolute left-3 top-3 h-4 w-4 text-muted-foreground" />
<Input <Input
id="website" id="website"
type="url" type="url"
placeholder="https://www.empresa.com" placeholder="https://www.company.com"
className="pl-10" className="pl-10"
{...register("website")} {...register("website")}
/> />
@ -373,13 +373,13 @@ export default function CompanyRegisterPage() {
</div> </div>
<div className="space-y-2"> <div className="space-y-2">
<Label htmlFor="address">Endereço</Label> <Label htmlFor="address">Address</Label>
<div className="relative"> <div className="relative">
<MapPin className="absolute left-3 top-3 h-4 w-4 text-muted-foreground" /> <MapPin className="absolute left-3 top-3 h-4 w-4 text-muted-foreground" />
<Input <Input
id="address" id="address"
type="text" type="text"
placeholder="Rua, número, complemento" placeholder="Street, number, suite"
className="pl-10" className="pl-10"
{...register("address")} {...register("address")}
/> />
@ -391,7 +391,7 @@ export default function CompanyRegisterPage() {
<div className="grid grid-cols-2 gap-4"> <div className="grid grid-cols-2 gap-4">
<div className="space-y-2"> <div className="space-y-2">
<Label htmlFor="city">Cidade</Label> <Label htmlFor="city">City</Label>
<Input <Input
id="city" id="city"
type="text" type="text"
@ -404,10 +404,10 @@ export default function CompanyRegisterPage() {
</div> </div>
<div className="space-y-2"> <div className="space-y-2">
<Label htmlFor="state">Estado</Label> <Label htmlFor="state">State</Label>
<Select onValueChange={(value) => setValue("state", value)}> <Select onValueChange={(value) => setValue("state", value)}>
<SelectTrigger> <SelectTrigger>
<SelectValue placeholder="Estado" /> <SelectValue placeholder="State" />
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
<SelectItem value="AC">Acre</SelectItem> <SelectItem value="AC">Acre</SelectItem>
@ -446,7 +446,7 @@ export default function CompanyRegisterPage() {
</div> </div>
<div className="space-y-2"> <div className="space-y-2">
<Label htmlFor="zipCode">CEP</Label> <Label htmlFor="zipCode">ZIP code</Label>
<Input <Input
id="zipCode" id="zipCode"
type="text" type="text"
@ -460,16 +460,16 @@ export default function CompanyRegisterPage() {
<div className="flex gap-4"> <div className="flex gap-4">
<Button type="button" variant="outline" onClick={prevStep} className="flex-1"> <Button type="button" variant="outline" onClick={prevStep} className="flex-1">
Voltar Back
</Button> </Button>
<Button type="button" onClick={nextStep} className="flex-1"> <Button type="button" onClick={nextStep} className="flex-1">
Próxima Etapa Next step
</Button> </Button>
</div> </div>
</motion.div> </motion.div>
)} )}
{/* Step 3: Informações Adicionais */} {/* Step 3: Additional information */}
{currentStep === 3 && ( {currentStep === 3 && (
<motion.div <motion.div
key="step3" key="step3"
@ -480,26 +480,26 @@ export default function CompanyRegisterPage() {
className="space-y-4" className="space-y-4"
> >
<div className="space-y-2"> <div className="space-y-2">
<Label htmlFor="sector">Setor de Atuação</Label> <Label htmlFor="sector">Industry</Label>
<Select onValueChange={(value) => setValue("sector", value)}> <Select onValueChange={(value) => setValue("sector", value)}>
<SelectTrigger> <SelectTrigger>
<SelectValue placeholder="Selecione o setor" /> <SelectValue placeholder="Select an industry" />
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
<SelectItem value="tecnologia">Tecnologia</SelectItem> <SelectItem value="technology">Technology</SelectItem>
<SelectItem value="financeiro">Financeiro</SelectItem> <SelectItem value="finance">Finance</SelectItem>
<SelectItem value="saude">Saúde</SelectItem> <SelectItem value="healthcare">Healthcare</SelectItem>
<SelectItem value="educacao">Educação</SelectItem> <SelectItem value="education">Education</SelectItem>
<SelectItem value="varejo">Varejo</SelectItem> <SelectItem value="retail">Retail</SelectItem>
<SelectItem value="construcao">Construção</SelectItem> <SelectItem value="construction">Construction</SelectItem>
<SelectItem value="industria">Indústria</SelectItem> <SelectItem value="industry">Industry</SelectItem>
<SelectItem value="servicos">Serviços</SelectItem> <SelectItem value="services">Services</SelectItem>
<SelectItem value="agricultura">Agricultura</SelectItem> <SelectItem value="agriculture">Agriculture</SelectItem>
<SelectItem value="transporte">Transporte</SelectItem> <SelectItem value="transport">Transportation</SelectItem>
<SelectItem value="energia">Energia</SelectItem> <SelectItem value="energy">Energy</SelectItem>
<SelectItem value="consultoria">Consultoria</SelectItem> <SelectItem value="consulting">Consulting</SelectItem>
<SelectItem value="marketing">Marketing</SelectItem> <SelectItem value="marketing">Marketing</SelectItem>
<SelectItem value="outros">Outros</SelectItem> <SelectItem value="other">Other</SelectItem>
</SelectContent> </SelectContent>
</Select> </Select>
{errors.sector && ( {errors.sector && (
@ -508,18 +508,18 @@ export default function CompanyRegisterPage() {
</div> </div>
<div className="space-y-2"> <div className="space-y-2">
<Label htmlFor="companySize">Tamanho da Empresa</Label> <Label htmlFor="companySize">Company size</Label>
<Select onValueChange={(value) => setValue("companySize", value)}> <Select onValueChange={(value) => setValue("companySize", value)}>
<SelectTrigger> <SelectTrigger>
<SelectValue placeholder="Número de funcionários" /> <SelectValue placeholder="Number of employees" />
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
<SelectItem value="1-10">1 a 10 funcionários</SelectItem> <SelectItem value="1-10">1 to 10 employees</SelectItem>
<SelectItem value="11-50">11 a 50 funcionários</SelectItem> <SelectItem value="11-50">11 to 50 employees</SelectItem>
<SelectItem value="51-200">51 a 200 funcionários</SelectItem> <SelectItem value="51-200">51 to 200 employees</SelectItem>
<SelectItem value="201-500">201 a 500 funcionários</SelectItem> <SelectItem value="201-500">201 to 500 employees</SelectItem>
<SelectItem value="501-1000">501 a 1000 funcionários</SelectItem> <SelectItem value="501-1000">501 to 1000 employees</SelectItem>
<SelectItem value="1000+">Mais de 1000 funcionários</SelectItem> <SelectItem value="1000+">More than 1000 employees</SelectItem>
</SelectContent> </SelectContent>
</Select> </Select>
{errors.companySize && ( {errors.companySize && (
@ -528,10 +528,10 @@ export default function CompanyRegisterPage() {
</div> </div>
<div className="space-y-2"> <div className="space-y-2">
<Label htmlFor="description">Descrição da Empresa</Label> <Label htmlFor="description">Company description</Label>
<Textarea <Textarea
id="description" id="description"
placeholder="Descreva sua empresa, cultura, valores e o que oferece aos funcionários..." placeholder="Describe your company, culture, values, and what you offer employees..."
className="min-h-[100px]" className="min-h-[100px]"
{...register("description")} {...register("description")}
/> />
@ -542,11 +542,11 @@ export default function CompanyRegisterPage() {
<div className="grid grid-cols-2 gap-4"> <div className="grid grid-cols-2 gap-4">
<div className="space-y-2"> <div className="space-y-2">
<Label htmlFor="contactPerson">Nome do Responsável</Label> <Label htmlFor="contactPerson">Contact name</Label>
<Input <Input
id="contactPerson" id="contactPerson"
type="text" type="text"
placeholder="Nome completo" placeholder="Full name"
{...register("contactPerson")} {...register("contactPerson")}
/> />
{errors.contactPerson && ( {errors.contactPerson && (
@ -555,11 +555,11 @@ export default function CompanyRegisterPage() {
</div> </div>
<div className="space-y-2"> <div className="space-y-2">
<Label htmlFor="contactRole">Cargo</Label> <Label htmlFor="contactRole">Role</Label>
<Input <Input
id="contactRole" id="contactRole"
type="text" type="text"
placeholder="Ex: RH, Gerente" placeholder="e.g. HR, Manager"
{...register("contactRole")} {...register("contactRole")}
/> />
{errors.contactRole && ( {errors.contactRole && (
@ -580,13 +580,13 @@ export default function CompanyRegisterPage() {
htmlFor="acceptTerms" htmlFor="acceptTerms"
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
> >
Aceito os{" "} I accept the{" "}
<Link href="/termos" className="text-primary hover:underline"> <Link href="/terms" className="text-primary hover:underline">
Termos de Uso Terms of Use
</Link>{" "} </Link>{" "}
e{" "} and{" "}
<Link href="/privacidade" className="text-primary hover:underline"> <Link href="/privacy" className="text-primary hover:underline">
Política de Privacidade Privacy Policy
</Link> </Link>
</label> </label>
</div> </div>
@ -606,7 +606,7 @@ export default function CompanyRegisterPage() {
htmlFor="acceptNewsletter" htmlFor="acceptNewsletter"
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
> >
Quero receber dicas de recrutamento e novidades por email I want to receive recruiting tips and updates by email
</label> </label>
</div> </div>
</div> </div>
@ -614,10 +614,10 @@ export default function CompanyRegisterPage() {
<div className="flex gap-4"> <div className="flex gap-4">
<Button type="button" variant="outline" onClick={prevStep} className="flex-1"> <Button type="button" variant="outline" onClick={prevStep} className="flex-1">
Voltar Back
</Button> </Button>
<Button type="submit" disabled={loading} className="flex-1"> <Button type="submit" disabled={loading} className="flex-1">
{loading ? "Criando conta..." : "Criar Conta"} {loading ? "Creating account..." : "Create account"}
</Button> </Button>
</div> </div>
</motion.div> </motion.div>
@ -626,9 +626,9 @@ export default function CompanyRegisterPage() {
<div className="mt-6 text-center"> <div className="mt-6 text-center">
<p className="text-sm text-muted-foreground"> <p className="text-sm text-muted-foreground">
tem uma conta?{" "} Already have an account?{" "}
<Link href="/login" className="text-primary hover:underline font-medium"> <Link href="/login" className="text-primary hover:underline font-medium">
Faça login Sign in
</Link> </Link>
</p> </p>
</div> </div>

View file

@ -8,13 +8,13 @@ export default function TermsPage() {
<main className="min-h-screen flex flex-col"> <main className="min-h-screen flex flex-col">
<Navbar /> <Navbar />
<div className="container mx-auto px-4 py-12 flex-1"> <div className="container mx-auto px-4 py-12 flex-1">
<h1 className="text-3xl font-bold mb-6">Termos de Uso</h1> <h1 className="text-3xl font-bold mb-6">Terms of Use</h1>
<div className="prose max-w-none"> <div className="prose max-w-none">
<p> <p>
Ao utilizar nosso serviço, você concorda com estes termos. By using our service, you agree to these terms.
</p> </p>
<p className="mt-4"> <p className="mt-4">
Em construção... Coming soon...
</p> </p>
</div> </div>
</div> </div>

View file

@ -1,10 +0,0 @@
import { redirect } from "next/navigation";
export default async function VagasJobApplicationRedirectPage({
params,
}: {
params: Promise<{ id: string }>;
}) {
const { id } = await params;
redirect(`/jobs/${id}/candidatura`);
}

View file

@ -1,10 +0,0 @@
import { redirect } from "next/navigation";
export default async function VagasJobRedirectPage({
params,
}: {
params: Promise<{ id: string }>;
}) {
const { id } = await params;
redirect(`/jobs/${id}`);
}

View file

@ -1,5 +0,0 @@
import { redirect } from "next/navigation";
export default function VagasRedirectPage() {
redirect("/jobs");
}

View file

@ -28,44 +28,44 @@ export function CompanySidebar({ className }: CompanySidebarProps) {
{ {
label: "Dashboard", label: "Dashboard",
icon: LayoutDashboard, icon: LayoutDashboard,
href: "/dashboard/empresa", href: "/dashboard/company",
active: pathname === "/dashboard/empresa", active: pathname === "/dashboard/company",
}, },
{ {
label: "Minhas Vagas", label: "My jobs",
icon: Briefcase, icon: Briefcase,
href: "/dashboard/empresa/vagas", href: "/dashboard/company/jobs",
active: pathname?.startsWith("/dashboard/empresa/vagas"), active: pathname?.startsWith("/dashboard/company/jobs"),
}, },
{ {
label: "Candidaturas", label: "Applications",
icon: Users, icon: Users,
href: "/dashboard/empresa/candidaturas", href: "/dashboard/company/applications",
active: pathname?.startsWith("/dashboard/empresa/candidaturas"), active: pathname?.startsWith("/dashboard/company/applications"),
}, },
{ {
label: "Mensagens", label: "Messages",
icon: MessageSquare, icon: MessageSquare,
href: "/dashboard/empresa/mensagens", href: "/dashboard/company/messages",
active: pathname?.startsWith("/dashboard/empresa/mensagens"), active: pathname?.startsWith("/dashboard/company/messages"),
}, },
{ {
label: "Relatórios", label: "Reports",
icon: BarChart3, icon: BarChart3,
href: "/dashboard/empresa/relatorios", href: "/dashboard/company/reports",
active: pathname?.startsWith("/dashboard/empresa/relatorios"), active: pathname?.startsWith("/dashboard/company/reports"),
}, },
{ {
label: "Perfil da Empresa", label: "Company profile",
icon: Building2, icon: Building2,
href: "/dashboard/empresa/perfil", href: "/dashboard/company/profile",
active: pathname?.startsWith("/dashboard/empresa/perfil"), active: pathname?.startsWith("/dashboard/company/profile"),
}, },
{ {
label: "Configurações", label: "Settings",
icon: Settings, icon: Settings,
href: "/dashboard/empresa/configuracoes", href: "/dashboard/company/settings",
active: pathname?.startsWith("/dashboard/empresa/configuracoes"), active: pathname?.startsWith("/dashboard/company/settings"),
}, },
]; ];
@ -82,14 +82,14 @@ export function CompanySidebar({ className }: CompanySidebarProps) {
</Avatar> </Avatar>
<div className="flex-1 min-w-0"> <div className="flex-1 min-w-0">
<h2 className="text-lg font-semibold truncate">TechCorp</h2> <h2 className="text-lg font-semibold truncate">TechCorp</h2>
<p className="text-xs text-muted-foreground truncate">Empresa</p> <p className="text-xs text-muted-foreground truncate">Company</p>
</div> </div>
</div> </div>
<Link href="/dashboard/empresa/vagas/nova"> <Link href="/dashboard/company/jobs/new">
<Button className="w-full mb-4" size="lg"> <Button className="w-full mb-4" size="lg">
<Plus className="h-4 w-4 mr-2" /> <Plus className="h-4 w-4 mr-2" />
Nova Vaga New job
</Button> </Button>
</Link> </Link>

View file

@ -11,10 +11,10 @@ import { Briefcase, Users, TrendingUp, FileText, Plus, MoreHorizontal } from "lu
import { motion } from "framer-motion" import { motion } from "framer-motion"
const mockCandidates = [ const mockCandidates = [
{ id: "1", name: "João Silva", position: "Desenvolvedor Full Stack", status: "active" }, { id: "1", name: "João Silva", position: "Full Stack Developer", status: "active" },
{ id: "2", name: "Maria Santos", position: "Designer UX/UI", status: "active" }, { id: "2", name: "Maria Santos", position: "UX/UI Designer", status: "active" },
{ id: "3", name: "Carlos Oliveira", position: "Product Manager", status: "pending" }, { id: "3", name: "Carlos Oliveira", position: "Product Manager", status: "pending" },
{ id: "4", name: "Ana Costa", position: "Engenheiro de Dados", status: "active" }, { id: "4", name: "Ana Costa", position: "Data Engineer", status: "active" },
{ id: "5", name: "Pedro Alves", position: "DevOps Engineer", status: "inactive" }, { id: "5", name: "Pedro Alves", position: "DevOps Engineer", status: "inactive" },
] ]
@ -30,7 +30,7 @@ export function AdminDashboardContent() {
transition={{ duration: 0.5 }} transition={{ duration: 0.5 }}
> >
<h1 className="text-3xl font-bold mb-2">Dashboard</h1> <h1 className="text-3xl font-bold mb-2">Dashboard</h1>
<p className="text-muted-foreground">Visão geral do portal de empregos</p> <p className="text-muted-foreground">Overview of the jobs portal</p>
</motion.div> </motion.div>
{/* Stats */} {/* Stats */}
@ -41,24 +41,24 @@ export function AdminDashboardContent() {
className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6" className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6"
> >
<StatsCard <StatsCard
title="Vagas Ativas" title="Active jobs"
value={mockStats.activeJobs} value={mockStats.activeJobs}
icon={Briefcase} icon={Briefcase}
description="Total de vagas publicadas" description="Total posted jobs"
/> />
<StatsCard <StatsCard
title="Total de Candidatos" title="Total candidates"
value={mockStats.totalCandidates} value={mockStats.totalCandidates}
icon={Users} icon={Users}
description="Usuários cadastrados" description="Registered users"
/> />
<StatsCard <StatsCard
title="Novas Candidaturas" title="New applications"
value={mockStats.newApplications} value={mockStats.newApplications}
icon={FileText} icon={FileText}
description="Últimos 7 dias" description="Last 7 days"
/> />
<StatsCard title="Taxa de Conversão" value="12.5%" icon={TrendingUp} description="Candidaturas por vaga" /> <StatsCard title="Conversion rate" value="12.5%" icon={TrendingUp} description="Applications per job" />
</motion.div> </motion.div>
{/* Jobs Management */} {/* Jobs Management */}
@ -69,22 +69,22 @@ export function AdminDashboardContent() {
> >
<Card> <Card>
<CardHeader className="flex flex-row items-center justify-between"> <CardHeader className="flex flex-row items-center justify-between">
<CardTitle>Gestão de Vagas</CardTitle> <CardTitle>Job management</CardTitle>
<Button onClick={() => router.push('/dashboard/jobs')}> <Button onClick={() => router.push('/dashboard/jobs')}>
<Plus className="mr-2 h-4 w-4" /> <Plus className="mr-2 h-4 w-4" />
Adicionar Vaga Add job
</Button> </Button>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<Table> <Table>
<TableHeader> <TableHeader>
<TableRow> <TableRow>
<TableHead>Título</TableHead> <TableHead>Title</TableHead>
<TableHead>Empresa</TableHead> <TableHead>Company</TableHead>
<TableHead>Localização</TableHead> <TableHead>Location</TableHead>
<TableHead>Status</TableHead> <TableHead>Status</TableHead>
<TableHead>Candidaturas</TableHead> <TableHead>Applications</TableHead>
<TableHead className="text-right">Ações</TableHead> <TableHead className="text-right">Actions</TableHead>
</TableRow> </TableRow>
</TableHeader> </TableHeader>
<TableBody> <TableBody>
@ -92,11 +92,11 @@ export function AdminDashboardContent() {
<TableRow key={job.id}> <TableRow key={job.id}>
<TableCell className="font-medium">{job.title}</TableCell> <TableCell className="font-medium">{job.title}</TableCell>
<TableCell>{job.company}</TableCell> <TableCell>{job.company}</TableCell>
<TableCell>{job.location}</TableCell> <TableCell>{job.location}</TableCell>
<TableCell> <TableCell>
<Badge variant="secondary">Ativa</Badge> <Badge variant="secondary">Active</Badge>
</TableCell> </TableCell>
<TableCell>{((job.id.charCodeAt(0) * 7) % 50) + 10}</TableCell> <TableCell>{((job.id.charCodeAt(0) * 7) % 50) + 10}</TableCell>
<TableCell className="text-right"> <TableCell className="text-right">
<Button variant="ghost" size="icon"> <Button variant="ghost" size="icon">
<MoreHorizontal className="h-4 w-4" /> <MoreHorizontal className="h-4 w-4" />
@ -118,16 +118,16 @@ export function AdminDashboardContent() {
> >
<Card> <Card>
<CardHeader> <CardHeader>
<CardTitle>Gestão de Candidatos</CardTitle> <CardTitle>Candidate management</CardTitle>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<Table> <Table>
<TableHeader> <TableHeader>
<TableRow> <TableRow>
<TableHead>Nome</TableHead> <TableHead>Name</TableHead>
<TableHead>Cargo Pretendido</TableHead> <TableHead>Desired role</TableHead>
<TableHead>Status</TableHead> <TableHead>Status</TableHead>
<TableHead className="text-right">Ações</TableHead> <TableHead className="text-right">Actions</TableHead>
</TableRow> </TableRow>
</TableHeader> </TableHeader>
<TableBody> <TableBody>
@ -136,9 +136,9 @@ export function AdminDashboardContent() {
<TableCell className="font-medium">{candidate.name}</TableCell> <TableCell className="font-medium">{candidate.name}</TableCell>
<TableCell>{candidate.position}</TableCell> <TableCell>{candidate.position}</TableCell>
<TableCell> <TableCell>
{candidate.status === "active" && <Badge className="bg-green-500">Ativo</Badge>} {candidate.status === "active" && <Badge className="bg-green-500">Active</Badge>}
{candidate.status === "pending" && <Badge variant="secondary">Pendente</Badge>} {candidate.status === "pending" && <Badge variant="secondary">Pending</Badge>}
{candidate.status === "inactive" && <Badge variant="outline">Inativo</Badge>} {candidate.status === "inactive" && <Badge variant="outline">Inactive</Badge>}
</TableCell> </TableCell>
<TableCell className="text-right"> <TableCell className="text-right">
<Button variant="ghost" size="icon"> <Button variant="ghost" size="icon">

View file

@ -37,35 +37,35 @@ export function CandidateDashboardContent() {
return ( return (
<Badge variant="secondary"> <Badge variant="secondary">
<Clock className="h-3 w-3 mr-1" /> <Clock className="h-3 w-3 mr-1" />
Em análise Under review
</Badge> </Badge>
) )
case "reviewing": case "reviewing":
return ( return (
<Badge variant="secondary"> <Badge variant="secondary">
<AlertCircle className="h-3 w-3 mr-1" /> <AlertCircle className="h-3 w-3 mr-1" />
Em análise Under review
</Badge> </Badge>
) )
case "interview": case "interview":
return ( return (
<Badge className="bg-blue-500 hover:bg-blue-600"> <Badge className="bg-blue-500 hover:bg-blue-600">
<CheckCircle className="h-3 w-3 mr-1" /> <CheckCircle className="h-3 w-3 mr-1" />
Entrevista Interview
</Badge> </Badge>
) )
case "accepted": case "accepted":
return ( return (
<Badge className="bg-green-500 hover:bg-green-600"> <Badge className="bg-green-500 hover:bg-green-600">
<CheckCircle className="h-3 w-3 mr-1" /> <CheckCircle className="h-3 w-3 mr-1" />
Aprovado Accepted
</Badge> </Badge>
) )
case "rejected": case "rejected":
return ( return (
<Badge variant="destructive"> <Badge variant="destructive">
<XCircle className="h-3 w-3 mr-1" /> <XCircle className="h-3 w-3 mr-1" />
Rejeitado Rejected
</Badge> </Badge>
) )
default: default:
@ -85,12 +85,12 @@ export function CandidateDashboardContent() {
<CardContent className="pt-6"> <CardContent className="pt-6">
<div className="flex flex-col md:flex-row md:items-center md:justify-between gap-6"> <div className="flex flex-col md:flex-row md:items-center md:justify-between gap-6">
<div className="flex-1"> <div className="flex-1">
<h1 className="text-2xl font-bold mb-2">Olá, {user?.name || "Candidato"}!</h1> <h1 className="text-2xl font-bold mb-2">Hi, {user?.name || "Candidate"}!</h1>
<p className="text-muted-foreground">{user?.area || "Desenvolvimento"}</p> <p className="text-muted-foreground">{user?.area || "Engineering"}</p>
</div> </div>
<Button className="cursor-pointer"> <Button className="cursor-pointer">
<Edit className="mr-2 h-4 w-4" /> <Edit className="mr-2 h-4 w-4" />
Editar Perfil Edit profile
</Button> </Button>
</div> </div>
</CardContent> </CardContent>
@ -105,26 +105,26 @@ export function CandidateDashboardContent() {
className="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8" className="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8"
> >
<StatsCard <StatsCard
title="Candidaturas" title="Applications"
value={mockApplications.length} value={mockApplications.length}
icon={FileText} icon={FileText}
description="Total de vagas aplicadas" description="Total jobs applied to"
/> />
<StatsCard <StatsCard
title="Em processo" title="In progress"
value={ value={
mockApplications.filter( mockApplications.filter(
(a) => a.status === "reviewing" || a.status === "interview" (a) => a.status === "reviewing" || a.status === "interview"
).length ).length
} }
icon={Clock} icon={Clock}
description="Aguardando resposta" description="Awaiting a response"
/> />
<StatsCard <StatsCard
title="Notificações" title="Notifications"
value={unreadNotifications.length} value={unreadNotifications.length}
icon={Bell} icon={Bell}
description="Novas atualizações" description="New updates"
/> />
</motion.div> </motion.div>
@ -139,7 +139,7 @@ export function CandidateDashboardContent() {
> >
<Card> <Card>
<CardHeader> <CardHeader>
<CardTitle>Vagas recomendadas</CardTitle> <CardTitle>Recommended jobs</CardTitle>
</CardHeader> </CardHeader>
<CardContent className="space-y-4"> <CardContent className="space-y-4">
{recommendedJobs.map((job) => ( {recommendedJobs.map((job) => (
@ -157,16 +157,16 @@ export function CandidateDashboardContent() {
> >
<Card> <Card>
<CardHeader> <CardHeader>
<CardTitle>Minhas candidaturas</CardTitle> <CardTitle>My applications</CardTitle>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<Table> <Table>
<TableHeader> <TableHeader>
<TableRow> <TableRow>
<TableHead>Vaga</TableHead> <TableHead>Role</TableHead>
<TableHead>Empresa</TableHead> <TableHead>Company</TableHead>
<TableHead>Status</TableHead> <TableHead>Status</TableHead>
<TableHead>Data</TableHead> <TableHead>Date</TableHead>
</TableRow> </TableRow>
</TableHeader> </TableHeader>
<TableBody> <TableBody>
@ -181,7 +181,7 @@ export function CandidateDashboardContent() {
</TableCell> </TableCell>
<TableCell className="text-muted-foreground"> <TableCell className="text-muted-foreground">
{new Date(application.appliedAt).toLocaleDateString( {new Date(application.appliedAt).toLocaleDateString(
"pt-BR" "en-US"
)} )}
</TableCell> </TableCell>
</TableRow> </TableRow>

View file

@ -36,35 +36,35 @@ export function CompanyDashboardContent() {
const recentJobs = [ const recentJobs = [
{ {
id: "1", id: "1",
title: "Desenvolvedor Full Stack Sênior", title: "Senior Full Stack Developer",
type: "Tempo Integral", type: "Full Time",
location: "São Paulo, SP", location: "São Paulo, SP",
salary: "R$ 12.000 - R$ 18.000", salary: "R$ 12,000 - R$ 18,000",
applications: 45, applications: 45,
views: 320, views: 320,
postedAt: "2 dias atrás", postedAt: "2 days ago",
status: "active", status: "active",
}, },
{ {
id: "2", id: "2",
title: "Designer UX/UI", title: "Designer UX/UI",
type: "Remoto", type: "Remote",
location: "Remoto", location: "Remote",
salary: "R$ 8.000 - R$ 12.000", salary: "R$ 8,000 - R$ 12,000",
applications: 32, applications: 32,
views: 256, views: 256,
postedAt: "5 dias atrás", postedAt: "5 days ago",
status: "active", status: "active",
}, },
{ {
id: "3", id: "3",
title: "Product Manager", title: "Product Manager",
type: "Tempo Integral", type: "Full Time",
location: "São Paulo, SP", location: "São Paulo, SP",
salary: "R$ 15.000 - R$ 20.000", salary: "R$ 15,000 - R$ 20,000",
applications: 28, applications: 28,
views: 189, views: 189,
postedAt: "1 semana atrás", postedAt: "1 week ago",
status: "active", status: "active",
}, },
] ]
@ -74,8 +74,8 @@ export function CompanyDashboardContent() {
id: "1", id: "1",
candidateName: "Ana Silva", candidateName: "Ana Silva",
candidateAvatar: "", candidateAvatar: "",
jobTitle: "Desenvolvedor Full Stack Sênior", jobTitle: "Senior Full Stack Developer",
appliedAt: "Há 2 horas", appliedAt: "2 hours ago",
status: "pending", status: "pending",
}, },
{ {
@ -83,7 +83,7 @@ export function CompanyDashboardContent() {
candidateName: "Carlos Santos", candidateName: "Carlos Santos",
candidateAvatar: "", candidateAvatar: "",
jobTitle: "Designer UX/UI", jobTitle: "Designer UX/UI",
appliedAt: "Há 5 horas", appliedAt: "5 hours ago",
status: "pending", status: "pending",
}, },
{ {
@ -91,7 +91,7 @@ export function CompanyDashboardContent() {
candidateName: "Maria Oliveira", candidateName: "Maria Oliveira",
candidateAvatar: "", candidateAvatar: "",
jobTitle: "Product Manager", jobTitle: "Product Manager",
appliedAt: "Há 1 dia", appliedAt: "1 day ago",
status: "reviewing", status: "reviewing",
}, },
] ]
@ -112,13 +112,13 @@ export function CompanyDashboardContent() {
Dashboard Dashboard
</h1> </h1>
<p className="text-muted-foreground"> <p className="text-muted-foreground">
Bem-vindo de volta, TechCorp! 👋 Welcome back, TechCorp! 👋
</p> </p>
</div> </div>
<Link href="/dashboard/my-jobs"> <Link href="/dashboard/my-jobs">
<Button size="lg" className="w-full sm:w-auto"> <Button size="lg" className="w-full sm:w-auto">
<Plus className="h-5 w-5 mr-2" /> <Plus className="h-5 w-5 mr-2" />
Nova Vaga New job
</Button> </Button>
</Link> </Link>
</div> </div>
@ -128,7 +128,7 @@ export function CompanyDashboardContent() {
<Card> <Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2"> <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium"> <CardTitle className="text-sm font-medium">
Vagas Ativas Active jobs
</CardTitle> </CardTitle>
<Briefcase className="h-4 w-4 text-muted-foreground" /> <Briefcase className="h-4 w-4 text-muted-foreground" />
</CardHeader> </CardHeader>
@ -137,7 +137,7 @@ export function CompanyDashboardContent() {
{companyStats.activeJobs} {companyStats.activeJobs}
</div> </div>
<p className="text-xs text-muted-foreground mt-1"> <p className="text-xs text-muted-foreground mt-1">
Publicadas no momento Live right now
</p> </p>
</CardContent> </CardContent>
</Card> </Card>
@ -145,7 +145,7 @@ export function CompanyDashboardContent() {
<Card> <Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2"> <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium"> <CardTitle className="text-sm font-medium">
Candidaturas Applications
</CardTitle> </CardTitle>
<Users className="h-4 w-4 text-muted-foreground" /> <Users className="h-4 w-4 text-muted-foreground" />
</CardHeader> </CardHeader>
@ -154,7 +154,7 @@ export function CompanyDashboardContent() {
{companyStats.totalApplications} {companyStats.totalApplications}
</div> </div>
<p className="text-xs text-muted-foreground mt-1"> <p className="text-xs text-muted-foreground mt-1">
+{companyStats.thisMonth} este mês +{companyStats.thisMonth} this month
</p> </p>
</CardContent> </CardContent>
</Card> </Card>
@ -162,7 +162,7 @@ export function CompanyDashboardContent() {
<Card> <Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2"> <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium"> <CardTitle className="text-sm font-medium">
Visualizações Views
</CardTitle> </CardTitle>
<Eye className="h-4 w-4 text-muted-foreground" /> <Eye className="h-4 w-4 text-muted-foreground" />
</CardHeader> </CardHeader>
@ -171,7 +171,7 @@ export function CompanyDashboardContent() {
{companyStats.totalViews} {companyStats.totalViews}
</div> </div>
<p className="text-xs text-muted-foreground mt-1"> <p className="text-xs text-muted-foreground mt-1">
Nas suas vagas On your postings
</p> </p>
</CardContent> </CardContent>
</Card> </Card>
@ -179,34 +179,34 @@ export function CompanyDashboardContent() {
<Card> <Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2"> <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium"> <CardTitle className="text-sm font-medium">
Taxa de Conversão Conversion rate
</CardTitle> </CardTitle>
<TrendingUp className="h-4 w-4 text-muted-foreground" /> <TrendingUp className="h-4 w-4 text-muted-foreground" />
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<div className="text-2xl font-bold">15.2%</div> <div className="text-2xl font-bold">15.2%</div>
<p className="text-xs text-green-600 mt-1"> <p className="text-xs text-green-600 mt-1">
+2.5% vs mês passado +2.5% vs last month
</p> </p>
</CardContent> </CardContent>
</Card> </Card>
</div> </div>
<div className="grid lg:grid-cols-3 gap-6"> <div className="grid lg:grid-cols-3 gap-6">
{/* Vagas Recentes */} {/* Recent jobs */}
<div className="lg:col-span-2"> <div className="lg:col-span-2">
<Card> <Card>
<CardHeader> <CardHeader>
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div> <div>
<CardTitle>Vagas Recentes</CardTitle> <CardTitle>Recent jobs</CardTitle>
<CardDescription> <CardDescription>
Suas últimas vagas publicadas Your latest job postings
</CardDescription> </CardDescription>
</div> </div>
<Link href="/dashboard/jobs"> <Link href="/dashboard/jobs">
<Button variant="ghost" size="sm"> <Button variant="ghost" size="sm">
Ver todas View all
</Button> </Button>
</Link> </Link>
</div> </div>
@ -243,11 +243,11 @@ export function CompanyDashboardContent() {
<div className="flex flex-wrap gap-4 text-sm"> <div className="flex flex-wrap gap-4 text-sm">
<span className="flex items-center gap-1"> <span className="flex items-center gap-1">
<Users className="h-4 w-4" /> <Users className="h-4 w-4" />
{job.applications} candidaturas {job.applications} applications
</span> </span>
<span className="flex items-center gap-1"> <span className="flex items-center gap-1">
<Eye className="h-4 w-4" /> <Eye className="h-4 w-4" />
{job.views} visualizações {job.views} views
</span> </span>
<span className="flex items-center gap-1"> <span className="flex items-center gap-1">
<Calendar className="h-4 w-4" /> <Calendar className="h-4 w-4" />
@ -269,18 +269,18 @@ export function CompanyDashboardContent() {
</Card> </Card>
</div> </div>
{/* Candidaturas Recentes */} {/* Recent applications */}
<div> <div>
<Card> <Card>
<CardHeader> <CardHeader>
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div> <div>
<CardTitle>Candidaturas</CardTitle> <CardTitle>Applications</CardTitle>
<CardDescription>Novas candidaturas</CardDescription> <CardDescription>New applications</CardDescription>
</div> </div>
<Link href="/dashboard/candidates"> <Link href="/dashboard/candidates">
<Button variant="ghost" size="sm"> <Button variant="ghost" size="sm">
Ver todas View all
</Button> </Button>
</Link> </Link>
</div> </div>

View file

@ -13,7 +13,7 @@ import {
DropdownMenuSeparator, DropdownMenuSeparator,
DropdownMenuTrigger, DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"; } from "@/components/ui/dropdown-menu";
import { Briefcase, LogOut, User, Settings } from "lucide-react"; import { LogOut, User } from "lucide-react";
import { logout, getCurrentUser } from "@/lib/auth"; import { logout, getCurrentUser } from "@/lib/auth";
import { NotificationDropdown } from "@/components/notification-dropdown"; import { NotificationDropdown } from "@/components/notification-dropdown";
@ -78,7 +78,7 @@ export function DashboardHeader() {
<DropdownMenuLabel className="font-normal"> <DropdownMenuLabel className="font-normal">
<div className="flex flex-col space-y-1"> <div className="flex flex-col space-y-1">
<p className="text-sm font-medium leading-none"> <p className="text-sm font-medium leading-none">
{user?.name || "Usuário"} {user?.name || "User"}
</p> </p>
<p className="text-xs leading-none text-muted-foreground"> <p className="text-xs leading-none text-muted-foreground">
{user?.email} {user?.email}
@ -88,12 +88,12 @@ export function DashboardHeader() {
<DropdownMenuSeparator /> <DropdownMenuSeparator />
<DropdownMenuItem onClick={handleProfileClick}> <DropdownMenuItem onClick={handleProfileClick}>
<User className="mr-2 h-4 w-4" /> <User className="mr-2 h-4 w-4" />
<span>Perfil</span> <span>Profile</span>
</DropdownMenuItem> </DropdownMenuItem>
<DropdownMenuSeparator /> <DropdownMenuSeparator />
<DropdownMenuItem onClick={handleLogout}> <DropdownMenuItem onClick={handleLogout}>
<LogOut className="mr-2 h-4 w-4" /> <LogOut className="mr-2 h-4 w-4" />
<span>Sair</span> <span>Sign out</span>
</DropdownMenuItem> </DropdownMenuItem>
</DropdownMenuContent> </DropdownMenuContent>
</DropdownMenu> </DropdownMenu>

View file

@ -25,21 +25,21 @@ export function Footer() {
<ul className="space-y-2 text-sm text-muted-foreground"> <ul className="space-y-2 text-sm text-muted-foreground">
<li> <li>
<Link href="/jobs?tech=python" className="hover:text-foreground transition-colors"> <Link href="/jobs?tech=python" className="hover:text-foreground transition-colors">
Desenvolvedor Python Python Developer
</Link> </Link>
</li> </li>
<li> <li>
<Link href="/jobs?tech=react" className="hover:text-foreground transition-colors"> <Link href="/jobs?tech=react" className="hover:text-foreground transition-colors">
Desenvolvedor React React Developer
</Link> </Link>
</li> </li>
<li> <li>
<Link href="/jobs?tech=dados" className="hover:text-foreground transition-colors"> <Link href="/jobs?tech=data" className="hover:text-foreground transition-colors">
Analista de Dados Data Analyst
</Link> </Link>
</li> </li>
<li> <li>
<Link href="/jobs?type=remoto" className="hover:text-foreground transition-colors"> <Link href="/jobs?type=remote" className="hover:text-foreground transition-colors">
{t('workMode.remote')} {t('workMode.remote')}
</Link> </Link>
</li> </li>
@ -50,12 +50,12 @@ export function Footer() {
<h3 className="font-semibold mb-4">{t('footer.company')}</h3> <h3 className="font-semibold mb-4">{t('footer.company')}</h3>
<ul className="space-y-2 text-sm text-muted-foreground"> <ul className="space-y-2 text-sm text-muted-foreground">
<li> <li>
<Link href="/sobre" className="hover:text-foreground transition-colors"> <Link href="/about" className="hover:text-foreground transition-colors">
{t('footer.about')} {t('footer.about')}
</Link> </Link>
</li> </li>
<li> <li>
<Link href="/contato" className="hover:text-foreground transition-colors"> <Link href="/contact" className="hover:text-foreground transition-colors">
{t('nav.contact')} {t('nav.contact')}
</Link> </Link>
</li> </li>
@ -71,12 +71,12 @@ export function Footer() {
<h3 className="font-semibold mb-4">{t('footer.legal')}</h3> <h3 className="font-semibold mb-4">{t('footer.legal')}</h3>
<ul className="space-y-2 text-sm text-muted-foreground"> <ul className="space-y-2 text-sm text-muted-foreground">
<li> <li>
<Link href="/privacidade" className="hover:text-foreground transition-colors"> <Link href="/privacy" className="hover:text-foreground transition-colors">
{t('footer.privacy')} {t('footer.privacy')}
</Link> </Link>
</li> </li>
<li> <li>
<Link href="/termos" className="hover:text-foreground transition-colors"> <Link href="/terms" className="hover:text-foreground transition-colors">
{t('footer.terms')} {t('footer.terms')}
</Link> </Link>
</li> </li>
@ -91,4 +91,3 @@ export function Footer() {
</footer> </footer>
) )
} }

View file

@ -58,7 +58,7 @@ export function JobCard({ job }: JobCardProps) {
return "secondary"; return "secondary";
case "contract": case "contract":
return "outline"; return "outline";
case "Remoto": case "remote":
return "default"; return "default";
default: default:
return "outline"; return "outline";
@ -81,7 +81,7 @@ export function JobCard({ job }: JobCardProps) {
t('jobs.favorites.added.title'), t('jobs.favorites.added.title'),
t('jobs.favorites.added.desc', { title: job.title }), t('jobs.favorites.added.desc', { title: job.title }),
{ {
actionUrl: "/dashboard/candidato/favoritos", actionUrl: "/dashboard/favorites",
actionLabel: t('jobs.favorites.action'), actionLabel: t('jobs.favorites.action'),
} }
); );
@ -201,7 +201,7 @@ export function JobCard({ job }: JobCardProps) {
{t('jobs.card.viewDetails')} {t('jobs.card.viewDetails')}
</Button> </Button>
</Link> </Link>
<Link href={`/jobs/${job.id}/candidatura`} className="flex-1"> <Link href={`/jobs/${job.id}/apply`} className="flex-1">
<Button className="w-full cursor-pointer">{t('jobs.card.apply')}</Button> <Button className="w-full cursor-pointer">{t('jobs.card.apply')}</Button>
</Link> </Link>
</div> </div>

View file

@ -17,8 +17,8 @@ export function Navbar() {
const navigationItems = [ const navigationItems = [
{ href: "/jobs", label: t('nav.jobs') }, { href: "/jobs", label: t('nav.jobs') },
{ href: "/sobre", label: t('nav.about') }, { href: "/about", label: t('nav.about') },
{ href: "/contato", label: t('nav.contact') }, { href: "/contact", label: t('nav.contact') },
] ]
return ( return (
@ -63,7 +63,7 @@ export function Navbar() {
{t('nav.login')} {t('nav.login')}
</Button> </Button>
</Link> </Link>
<Link href="/cadastro/candidato"> <Link href="/register/candidate">
<Button className="gap-2"> <Button className="gap-2">
<User className="w-4 h-4" /> <User className="w-4 h-4" />
{t('nav.register')} {t('nav.register')}
@ -114,7 +114,7 @@ export function Navbar() {
{t('nav.login')} {t('nav.login')}
</Button> </Button>
</Link> </Link>
<Link href="/cadastro/candidato" onClick={() => setIsOpen(false)}> <Link href="/register/candidate" onClick={() => setIsOpen(false)}>
<Button className="w-full justify-start gap-2"> <Button className="w-full justify-start gap-2">
<User className="w-4 h-4" /> <User className="w-4 h-4" />
{t('nav.register')} {t('nav.register')}

View file

@ -26,16 +26,16 @@ import {
AlertTriangle, AlertTriangle,
} from "lucide-react"; } from "lucide-react";
import { formatDistanceToNow } from "date-fns"; import { formatDistanceToNow } from "date-fns";
import { ptBR } from "date-fns/locale"; import { enUS } from "date-fns/locale";
import Link from "next/link"; import Link from "next/link";
import { motion, AnimatePresence } from "framer-motion"; import { motion, AnimatePresence } from "framer-motion";
export function NotificationDropdown() { export function NotificationDropdown() {
const pathname = usePathname(); const pathname = usePathname();
const isCompanyDashboard = pathname?.startsWith("/dashboard/empresa"); const isCompanyDashboard = pathname?.startsWith("/dashboard/company");
const notificationsUrl = isCompanyDashboard const notificationsUrl = isCompanyDashboard
? "/dashboard/empresa/notificacoes" ? "/dashboard/company/notifications"
: "/dashboard/candidato/notificacoes"; : "/dashboard/candidate/notifications";
const { const {
notifications, notifications,
unreadCount, unreadCount,
@ -89,7 +89,7 @@ export function NotificationDropdown() {
<DropdownMenuContent align="end" className="w-80"> <DropdownMenuContent align="end" className="w-80">
<DropdownMenuLabel className="flex items-center justify-between"> <DropdownMenuLabel className="flex items-center justify-between">
<span>Notificações</span> <span>Notifications</span>
{unreadCount > 0 && ( {unreadCount > 0 && (
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Button <Button
@ -99,7 +99,7 @@ export function NotificationDropdown() {
className="h-6 px-2 text-xs" className="h-6 px-2 text-xs"
> >
<CheckCheck className="h-3 w-3 mr-1" /> <CheckCheck className="h-3 w-3 mr-1" />
Marcar todas Mark all
</Button> </Button>
</div> </div>
)} )}
@ -110,7 +110,7 @@ export function NotificationDropdown() {
{recentNotifications.length === 0 ? ( {recentNotifications.length === 0 ? (
<div className="p-4 text-center text-sm text-muted-foreground"> <div className="p-4 text-center text-sm text-muted-foreground">
<Bell className="h-8 w-8 mx-auto mb-2 opacity-50" /> <Bell className="h-8 w-8 mx-auto mb-2 opacity-50" />
Nenhuma notificação No notifications
</div> </div>
) : ( ) : (
<ScrollArea className="h-80"> <ScrollArea className="h-80">
@ -194,7 +194,7 @@ export function NotificationDropdown() {
new Date(notification.createdAt), new Date(notification.createdAt),
{ {
addSuffix: true, addSuffix: true,
locale: ptBR, locale: enUS,
} }
)} )}
</span> </span>
@ -243,7 +243,7 @@ export function NotificationDropdown() {
className="flex-1 text-xs" className="flex-1 text-xs"
> >
<Trash2 className="h-3 w-3 mr-1" /> <Trash2 className="h-3 w-3 mr-1" />
Limpar todas Clear all
</Button> </Button>
<Link href={notificationsUrl} className="flex-1"> <Link href={notificationsUrl} className="flex-1">
<Button <Button
@ -252,7 +252,7 @@ export function NotificationDropdown() {
className="w-full text-xs" className="w-full text-xs"
onClick={() => setIsOpen(false)} onClick={() => setIsOpen(false)}
> >
Ver todas View all
</Button> </Button>
</Link> </Link>
</div> </div>

View file

@ -115,7 +115,7 @@ export function ProfilePictureUpload({
<CardContent className="p-6"> <CardContent className="p-6">
<div className="flex flex-col items-center space-y-4"> <div className="flex flex-col items-center space-y-4">
<div className="text-sm font-medium text-center"> <div className="text-sm font-medium text-center">
Foto de Perfil Profile Photo
</div> </div>
<div <div

View file

@ -133,7 +133,7 @@ export function ProfilePictureUpload({
<Card className={cn("w-fit", className)}> <Card className={cn("w-fit", className)}>
<CardContent className="p-6"> <CardContent className="p-6">
<div className="flex flex-col items-center space-y-4"> <div className="flex flex-col items-center space-y-4">
<div className="text-sm font-medium text-center">Foto de Perfil</div> <div className="text-sm font-medium text-center">Profile Photo</div>
<div <div
className={cn( className={cn(

View file

@ -14,27 +14,27 @@ const adminItems = [
icon: LayoutDashboard, icon: LayoutDashboard,
}, },
{ {
title: "Vagas", title: "Jobs",
href: "/dashboard/jobs", href: "/dashboard/jobs",
icon: Briefcase, icon: Briefcase,
}, },
{ {
title: "Candidatos", title: "Candidates",
href: "/dashboard/candidates", href: "/dashboard/candidates",
icon: Users, icon: Users,
}, },
{ {
title: "Usuários", title: "Users",
href: "/dashboard/users", href: "/dashboard/users",
icon: Users, icon: Users,
}, },
{ {
title: "Empresas", title: "Companies",
href: "/dashboard/companies", href: "/dashboard/companies",
icon: Building2, icon: Building2,
}, },
{ {
title: "Mensagens", title: "Messages",
href: "/dashboard/messages", href: "/dashboard/messages",
icon: MessageSquare, icon: MessageSquare,
}, },
@ -47,12 +47,12 @@ const companyItems = [
icon: LayoutDashboard, icon: LayoutDashboard,
}, },
{ {
title: "Minhas Vagas", title: "My jobs",
href: "/dashboard/my-jobs", href: "/dashboard/my-jobs",
icon: Briefcase, icon: Briefcase,
}, },
{ {
title: "Candidaturas", title: "Applications",
href: "/dashboard/applications", href: "/dashboard/applications",
icon: Users, icon: Users,
}, },
@ -65,12 +65,12 @@ const candidateItems = [
icon: LayoutDashboard, icon: LayoutDashboard,
}, },
{ {
title: "Vagas", title: "Jobs",
href: "/jobs", // Public search href: "/jobs", // Public search
icon: Briefcase, icon: Briefcase,
}, },
{ {
title: "Minhas Candidaturas", title: "My applications",
href: "/dashboard/my-applications", href: "/dashboard/my-applications",
icon: FileText, icon: FileText,
}, },

View file

@ -47,7 +47,7 @@
"loading": "Loading jobs...", "loading": "Loading jobs...",
"error": "Could not load jobs right now. Showing examples.", "error": "Could not load jobs right now. Showing examples.",
"card": { "viewDetails": "View details", "apply": "Apply now", "perMonth": "/month", "postedAgo": "Posted {time} ago" }, "card": { "viewDetails": "View details", "apply": "Apply now", "perMonth": "/month", "postedAgo": "Posted {time} ago" },
"types": { "full-time": "Full Time", "part-time": "Part Time", "contract": "Contract", "freelance": "Freelance" }, "types": { "full-time": "Full Time", "part-time": "Part Time", "contract": "Contract", "freelance": "Freelance", "remote": "Remote" },
"confidential": "Confidential Company", "confidential": "Confidential Company",
"salary": { "negotiable": "Negotiable" }, "salary": { "negotiable": "Negotiable" },
"posted": { "today": "Today", "yesterday": "Yesterday", "daysAgo": "{count} days ago", "weeksAgo": "{count} weeks ago", "monthsAgo": "{count} months ago" }, "posted": { "today": "Today", "yesterday": "Yesterday", "daysAgo": "{count} days ago", "weeksAgo": "{count} weeks ago", "monthsAgo": "{count} months ago" },

View file

@ -47,7 +47,7 @@
"loading": "Cargando empleos...", "loading": "Cargando empleos...",
"error": "No se pudieron cargar los empleos ahora. Mostrando ejemplos.", "error": "No se pudieron cargar los empleos ahora. Mostrando ejemplos.",
"card": { "viewDetails": "Ver detalles", "apply": "Postularse", "perMonth": "/mes", "postedAgo": "Publicado hace {time}" }, "card": { "viewDetails": "Ver detalles", "apply": "Postularse", "perMonth": "/mes", "postedAgo": "Publicado hace {time}" },
"types": { "full-time": "Tiempo completo", "part-time": "Medio tiempo", "contract": "Contrato", "freelance": "Freelance" }, "types": { "full-time": "Tiempo completo", "part-time": "Medio tiempo", "contract": "Contrato", "freelance": "Freelance", "remote": "Remoto" },
"confidential": "Empresa Confidencial", "confidential": "Empresa Confidencial",
"salary": { "negotiable": "A convenir" }, "salary": { "negotiable": "A convenir" },
"posted": { "today": "Hoy", "yesterday": "Ayer", "daysAgo": "hace {count} días", "weeksAgo": "hace {count} semanas", "monthsAgo": "hace {count} meses" }, "posted": { "today": "Hoy", "yesterday": "Ayer", "daysAgo": "hace {count} días", "weeksAgo": "hace {count} semanas", "monthsAgo": "hace {count} meses" },

View file

@ -47,7 +47,7 @@
"loading": "Carregando vagas...", "loading": "Carregando vagas...",
"error": "Não foi possível carregar as vagas agora. Exibindo exemplos.", "error": "Não foi possível carregar as vagas agora. Exibindo exemplos.",
"card": { "viewDetails": "Ver detalhes", "apply": "Candidatar-se", "perMonth": "/mês", "postedAgo": "Publicada há {time}" }, "card": { "viewDetails": "Ver detalhes", "apply": "Candidatar-se", "perMonth": "/mês", "postedAgo": "Publicada há {time}" },
"types": { "full-time": "Tempo Integral", "part-time": "Meio Período", "contract": "Contrato", "freelance": "Freelance" }, "types": { "full-time": "Tempo Integral", "part-time": "Meio Período", "contract": "Contrato", "freelance": "Freelance", "remote": "Remoto" },
"confidential": "Empresa Confidencial", "confidential": "Empresa Confidencial",
"salary": { "negotiable": "A combinar" }, "salary": { "negotiable": "A combinar" },
"posted": { "today": "Hoje", "yesterday": "Ontem", "daysAgo": "{count} dias atrás", "weeksAgo": "{count} semanas atrás", "monthsAgo": "{count} meses atrás" }, "posted": { "today": "Hoje", "yesterday": "Ontem", "daysAgo": "{count} dias atrás", "weeksAgo": "{count} semanas atrás", "monthsAgo": "{count} meses atrás" },

View file

@ -152,20 +152,22 @@ export function transformApiJobToFrontend(apiJob: ApiJob): import('./types').Job
// Format salary // Format salary
let salary: string | undefined; let salary: string | undefined;
if (apiJob.salaryMin && apiJob.salaryMax) { if (apiJob.salaryMin && apiJob.salaryMax) {
salary = `R$ ${apiJob.salaryMin.toLocaleString('pt-BR')} - R$ ${apiJob.salaryMax.toLocaleString('pt-BR')}`; salary = `R$ ${apiJob.salaryMin.toLocaleString('en-US')} - R$ ${apiJob.salaryMax.toLocaleString('en-US')}`;
} else if (apiJob.salaryMin) { } else if (apiJob.salaryMin) {
salary = `A partir de R$ ${apiJob.salaryMin.toLocaleString('pt-BR')}`; salary = `From R$ ${apiJob.salaryMin.toLocaleString('en-US')}`;
} else if (apiJob.salaryMax) { } else if (apiJob.salaryMax) {
salary = `Até R$ ${apiJob.salaryMax.toLocaleString('pt-BR')}`; salary = `Up to R$ ${apiJob.salaryMax.toLocaleString('en-US')}`;
} }
// Determine type // Determine type
type JobType = 'full-time' | 'part-time' | 'contract' | 'Remoto' | 'Tempo Integral'; type JobType = 'full-time' | 'part-time' | 'contract' | 'remote';
let type: JobType = 'Tempo Integral'; let type: JobType = 'full-time';
if (apiJob.employmentType === 'full-time') type = 'Tempo Integral'; if (apiJob.employmentType === 'full-time') type = 'full-time';
else if (apiJob.employmentType === 'part-time') type = 'part-time'; else if (apiJob.employmentType === 'part-time') type = 'part-time';
else if (apiJob.employmentType === 'contract') type = 'contract'; else if (apiJob.employmentType === 'contract') type = 'contract';
else if (apiJob.location?.toLowerCase().includes('remoto')) type = 'Remoto'; else if (apiJob.workMode === 'remote' || apiJob.location?.toLowerCase().includes('remote') || apiJob.location?.toLowerCase().includes('remoto')) {
type = 'remote';
}
// Extract requirements // Extract requirements
const requirements: string[] = []; const requirements: string[] = [];
@ -180,13 +182,13 @@ export function transformApiJobToFrontend(apiJob: ApiJob): import('./types').Job
return { return {
id: String(apiJob.id), id: String(apiJob.id),
title: apiJob.title, title: apiJob.title,
company: apiJob.companyName || 'Empresa', company: apiJob.companyName || 'Company',
location: apiJob.location || apiJob.cityName || 'Localização não informada', location: apiJob.location || apiJob.cityName || 'Location not provided',
type, type,
workMode: apiJob.workMode as any, workMode: apiJob.workMode as any,
salary, salary,
description: apiJob.description, description: apiJob.description,
requirements: requirements.length > 0 ? requirements : ['Ver detalhes'], requirements: requirements.length > 0 ? requirements : ['View details'],
postedAt: apiJob.createdAt?.split('T')[0] || new Date().toISOString().split('T')[0], postedAt: apiJob.createdAt?.split('T')[0] || new Date().toISOString().split('T')[0],
}; };
} }

View file

@ -10,41 +10,41 @@ import type {
export const mockJobs: Job[] = [ export const mockJobs: Job[] = [
{ {
id: "1", id: "1",
title: "Desenvolvedor Full Stack Sênior", title: "Senior Full Stack Developer",
company: "TechCorp", company: "TechCorp",
location: "São Paulo, SP", location: "São Paulo, SP",
type: "Tempo Integral", type: "full-time",
salary: "R$ 12.000 - R$ 18.000", salary: "R$ 12,000 - R$ 18,000",
description: description:
"Buscamos um desenvolvedor full stack experiente para liderar projetos inovadores.", "We are looking for an experienced full stack developer to lead innovative projects.",
requirements: ["React", "Node.js", "TypeScript", "5+ anos de experiência"], requirements: ["React", "Node.js", "TypeScript", "5+ years of experience"],
postedAt: "2025-10-15", postedAt: "2025-10-15",
}, },
{ {
id: "2", id: "2",
title: "Designer UX/UI", title: "UX/UI Designer",
company: "DesignHub", company: "DesignHub",
location: "São Paulo, SP", location: "São Paulo, SP",
type: "Remoto", type: "remote",
salary: "R$ 8.000 - R$ 12.000", salary: "R$ 8,000 - R$ 12,000",
description: description:
"Procuramos designer criativo para criar experiências incríveis.", "We are looking for a creative designer to craft incredible experiences.",
requirements: [ requirements: [
"Figma", "Figma",
"Adobe XD", "Adobe XD",
"Portfolio forte", "Strong portfolio",
"3+ anos de experiência", "3+ years of experience",
], ],
postedAt: "2025-10-14", postedAt: "2025-10-14",
}, },
{ {
id: "3", id: "3",
title: "Engenheiro de Dados", title: "Data Engineer",
company: "DataFlow", company: "DataFlow",
location: "Rio de Janeiro, RJ", location: "Rio de Janeiro, RJ",
type: "Tempo Integral", type: "full-time",
salary: "R$ 15.000 - R$ 22.000", salary: "R$ 15,000 - R$ 22,000",
description: "Oportunidade para trabalhar com big data e machine learning.", description: "Opportunity to work with big data and machine learning.",
requirements: ["Python", "SQL", "Spark", "AWS"], requirements: ["Python", "SQL", "Spark", "AWS"],
postedAt: "2025-10-13", postedAt: "2025-10-13",
}, },
@ -53,21 +53,21 @@ export const mockJobs: Job[] = [
title: "Product Manager", title: "Product Manager",
company: "InnovateLab", company: "InnovateLab",
location: "Belo Horizonte, MG", location: "Belo Horizonte, MG",
type: "Tempo Integral", type: "full-time",
salary: "R$ 10.000 - R$ 16.000", salary: "R$ 10,000 - R$ 16,000",
description: "Lidere o desenvolvimento de produtos digitais inovadores.", description: "Lead the development of innovative digital products.",
requirements: ["Gestão de produtos", "Agile", "Análise de dados"], requirements: ["Product management", "Agile", "Data analysis"],
postedAt: "2025-10-12", postedAt: "2025-10-12",
}, },
{ {
id: "5", id: "5",
title: "Desenvolvedor Mobile", title: "Mobile Developer",
company: "AppMakers", company: "AppMakers",
location: "São Paulo, SP", location: "São Paulo, SP",
type: "Remoto", type: "remote",
salary: "R$ 9.000 - R$ 14.000", salary: "R$ 9,000 - R$ 14,000",
description: "Desenvolva aplicativos mobile de alta qualidade.", description: "Build high-quality mobile applications.",
requirements: ["React Native", "iOS", "Android", "3+ anos"], requirements: ["React Native", "iOS", "Android", "3+ years"],
postedAt: "2025-10-11", postedAt: "2025-10-11",
}, },
{ {
@ -75,9 +75,9 @@ export const mockJobs: Job[] = [
title: "DevOps Engineer", title: "DevOps Engineer",
company: "CloudTech", company: "CloudTech",
location: "São Paulo, SP", location: "São Paulo, SP",
type: "Tempo Integral", type: "full-time",
salary: "R$ 13.000 - R$ 19.000", salary: "R$ 13,000 - R$ 19,000",
description: "Gerencie infraestrutura cloud e pipelines de CI/CD.", description: "Manage cloud infrastructure and CI/CD pipelines.",
requirements: ["Docker", "Kubernetes", "AWS", "Terraform"], requirements: ["Docker", "Kubernetes", "AWS", "Terraform"],
postedAt: "2025-10-10", postedAt: "2025-10-10",
}, },
@ -87,7 +87,7 @@ export const mockApplications: Application[] = [
{ {
id: "1", id: "1",
jobId: "1", jobId: "1",
jobTitle: "Desenvolvedor Full Stack Sênior", jobTitle: "Senior Full Stack Developer",
company: "TechCorp", company: "TechCorp",
status: "reviewing", status: "reviewing",
appliedAt: "2025-10-16", appliedAt: "2025-10-16",
@ -95,7 +95,7 @@ export const mockApplications: Application[] = [
{ {
id: "2", id: "2",
jobId: "2", jobId: "2",
jobTitle: "Designer UX/UI", jobTitle: "UX/UI Designer",
company: "DesignHub", company: "DesignHub",
status: "interview", status: "interview",
appliedAt: "2025-10-15", appliedAt: "2025-10-15",
@ -123,16 +123,16 @@ export const mockUser: User = {
name: "João Silva", name: "João Silva",
email: "joao@example.com", email: "joao@example.com",
role: "candidate", role: "candidate",
area: "Desenvolvimento Full Stack", area: "Full Stack Development",
profileComplete: 85, profileComplete: 85,
}; };
export const mockNotifications: Notification[] = [ export const mockNotifications: Notification[] = [
{ {
id: "1", id: "1",
title: "Nova vaga recomendada", title: "New recommended job",
message: message:
"Encontramos uma vaga que combina com seu perfil: Desenvolvedor Full Stack Sênior", "We found a role that matches your profile: Senior Full Stack Developer",
type: "info", type: "info",
read: false, read: false,
createdAt: "2025-11-19T10:30:00", createdAt: "2025-11-19T10:30:00",
@ -140,8 +140,8 @@ export const mockNotifications: Notification[] = [
}, },
{ {
id: "2", id: "2",
title: "Atualização de candidatura", title: "Application update",
message: "Sua candidatura para Designer UX/UI foi movida para entrevista", message: "Your application for UX/UI Designer moved to interview",
type: "success", type: "success",
read: false, read: false,
createdAt: "2025-11-18T14:20:00", createdAt: "2025-11-18T14:20:00",
@ -149,9 +149,9 @@ export const mockNotifications: Notification[] = [
}, },
{ {
id: "3", id: "3",
title: "Candidatura aprovada!", title: "Application approved!",
message: message:
"Parabéns! Sua candidatura para Product Manager foi aprovada pela empresa InnovateLab", "Congratulations! Your application for Product Manager was approved by InnovateLab",
type: "success", type: "success",
read: false, read: false,
createdAt: "2025-11-18T09:15:00", createdAt: "2025-11-18T09:15:00",
@ -159,8 +159,8 @@ export const mockNotifications: Notification[] = [
}, },
{ {
id: "4", id: "4",
title: "Nova mensagem", title: "New message",
message: "A empresa TechCorp enviou uma mensagem sobre sua candidatura", message: "TechCorp sent you a message about your application",
type: "info", type: "info",
read: true, read: true,
createdAt: "2025-11-17T16:45:00", createdAt: "2025-11-17T16:45:00",
@ -168,9 +168,9 @@ export const mockNotifications: Notification[] = [
}, },
{ {
id: "5", id: "5",
title: "Complete seu perfil", title: "Complete your profile",
message: message:
"Adicione mais informações ao seu perfil para aumentar suas chances em 40%", "Add more information to your profile to boost your chances by 40%",
type: "warning", type: "warning",
read: true, read: true,
createdAt: "2025-11-17T08:00:00", createdAt: "2025-11-17T08:00:00",
@ -178,9 +178,9 @@ export const mockNotifications: Notification[] = [
}, },
{ {
id: "6", id: "6",
title: "Lembrete de entrevista", title: "Interview reminder",
message: message:
"Você tem uma entrevista agendada para amanhã às 15h com a DesignHub", "You have an interview scheduled tomorrow at 3 PM with DesignHub",
type: "warning", type: "warning",
read: false, read: false,
createdAt: "2025-11-16T11:00:00", createdAt: "2025-11-16T11:00:00",
@ -188,9 +188,9 @@ export const mockNotifications: Notification[] = [
}, },
{ {
id: "7", id: "7",
title: "Nova vaga disponível", title: "New job available",
message: message:
"5 novas vagas de Desenvolvedor foram publicadas hoje na sua região", "5 new developer jobs were posted today in your area",
type: "info", type: "info",
read: true, read: true,
createdAt: "2025-11-15T07:30:00", createdAt: "2025-11-15T07:30:00",
@ -198,8 +198,8 @@ export const mockNotifications: Notification[] = [
}, },
{ {
id: "8", id: "8",
title: "Perfil visualizado", title: "Profile viewed",
message: "3 empresas visualizaram seu perfil nas últimas 24 horas", message: "3 companies viewed your profile in the last 24 hours",
type: "success", type: "success",
read: true, read: true,
createdAt: "2025-11-14T18:20:00", createdAt: "2025-11-14T18:20:00",
@ -210,9 +210,9 @@ export const mockNotifications: Notification[] = [
export const mockCompanyNotifications: Notification[] = [ export const mockCompanyNotifications: Notification[] = [
{ {
id: "1", id: "1",
title: "Nova candidatura recebida", title: "New application received",
message: message:
"Ana Silva se candidatou para a vaga de Desenvolvedor Full Stack Sênior", "Ana Silva applied for the Senior Full Stack Developer role",
type: "info", type: "info",
read: false, read: false,
createdAt: "2025-11-19T10:30:00", createdAt: "2025-11-19T10:30:00",
@ -220,8 +220,8 @@ export const mockCompanyNotifications: Notification[] = [
}, },
{ {
id: "2", id: "2",
title: "Candidato aceitou entrevista", title: "Candidate accepted interview",
message: "Carlos Santos confirmou presença na entrevista de amanhã às 14h", message: "Carlos Santos confirmed attendance for tomorrow at 2 PM",
type: "success", type: "success",
read: false, read: false,
createdAt: "2025-11-18T14:20:00", createdAt: "2025-11-18T14:20:00",
@ -229,9 +229,9 @@ export const mockCompanyNotifications: Notification[] = [
}, },
{ {
id: "3", id: "3",
title: "Vaga com alta demanda", title: "High-demand role",
message: message:
"A vaga de Designer UX/UI recebeu 15 novas candidaturas nas últimas 24h", "The UX/UI Designer role received 15 new applications in the last 24 hours",
type: "success", type: "success",
read: false, read: false,
createdAt: "2025-11-18T09:15:00", createdAt: "2025-11-18T09:15:00",
@ -239,8 +239,8 @@ export const mockCompanyNotifications: Notification[] = [
}, },
{ {
id: "4", id: "4",
title: "Nova mensagem de candidato", title: "New candidate message",
message: "Maria Oliveira enviou uma mensagem sobre a vaga de Product Manager", message: "Maria Oliveira sent a message about the Product Manager role",
type: "info", type: "info",
read: true, read: true,
createdAt: "2025-11-17T16:45:00", createdAt: "2025-11-17T16:45:00",
@ -248,9 +248,9 @@ export const mockCompanyNotifications: Notification[] = [
}, },
{ {
id: "5", id: "5",
title: "Complete o perfil da empresa", title: "Complete your company profile",
message: message:
"Adicione logo e informações sobre benefícios para atrair mais candidatos", "Add a logo and benefits details to attract more candidates",
type: "warning", type: "warning",
read: true, read: true,
createdAt: "2025-11-17T08:00:00", createdAt: "2025-11-17T08:00:00",
@ -258,9 +258,9 @@ export const mockCompanyNotifications: Notification[] = [
}, },
{ {
id: "6", id: "6",
title: "Lembrete: Entrevista agendada", title: "Reminder: interviews scheduled",
message: message:
"Você tem 2 entrevistas agendadas para amanhã. Confira os horários", "You have 2 interviews scheduled for tomorrow. Check the times",
type: "warning", type: "warning",
read: false, read: false,
createdAt: "2025-11-16T11:00:00", createdAt: "2025-11-16T11:00:00",
@ -268,9 +268,9 @@ export const mockCompanyNotifications: Notification[] = [
}, },
{ {
id: "7", id: "7",
title: "Vaga próxima de expirar", title: "Job expiring soon",
message: message:
"A vaga de DevOps Engineer expira em 3 dias. Renove para continuar recebendo candidaturas", "The DevOps Engineer role expires in 3 days. Renew it to keep receiving applications",
type: "warning", type: "warning",
read: true, read: true,
createdAt: "2025-11-15T07:30:00", createdAt: "2025-11-15T07:30:00",
@ -278,8 +278,8 @@ export const mockCompanyNotifications: Notification[] = [
}, },
{ {
id: "8", id: "8",
title: "Perfil empresarial visualizado", title: "Company profile viewed",
message: "45 candidatos visualizaram o perfil da sua empresa esta semana", message: "45 candidates viewed your company profile this week",
type: "success", type: "success",
read: true, read: true,
createdAt: "2025-11-14T18:20:00", createdAt: "2025-11-14T18:20:00",
@ -298,9 +298,9 @@ export const mockTestimonials = [
{ {
id: "1", id: "1",
name: "Maria Santos", name: "Maria Santos",
role: "Desenvolvedora", role: "Developer",
content: content:
"Encontrei meu emprego dos sonhos em apenas 2 semanas. Plataforma incrível!", "I found my dream job in just 2 weeks. Incredible platform!",
avatar: "/professional-woman-diverse.png", avatar: "/professional-woman-diverse.png",
}, },
{ {
@ -308,7 +308,7 @@ export const mockTestimonials = [
name: "Carlos Oliveira", name: "Carlos Oliveira",
role: "Designer", role: "Designer",
content: content:
"Interface simples e vagas de qualidade. Recomendo para todos os profissionais.", "Simple interface and high-quality roles. I recommend it to every professional.",
avatar: "/professional-man.jpg", avatar: "/professional-man.jpg",
}, },
{ {
@ -316,7 +316,7 @@ export const mockTestimonials = [
name: "Ana Costa", name: "Ana Costa",
role: "Product Manager", role: "Product Manager",
content: content:
"O processo foi rápido e transparente. Consegui várias entrevistas rapidamente.", "The process was fast and transparent. I landed several interviews quickly.",
avatar: "/professional-woman-smiling.png", avatar: "/professional-woman-smiling.png",
}, },
]; ];
@ -328,16 +328,16 @@ export const mockCandidates: Candidate[] = [
email: "ana.silva@example.com", email: "ana.silva@example.com",
phone: "+55 11 98765-4321", phone: "+55 11 98765-4321",
location: "São Paulo, SP", location: "São Paulo, SP",
title: "Desenvolvedora Full Stack", title: "Full Stack Developer",
experience: "5 anos de experiência", experience: "5 years of experience",
avatar: "/professional-woman-diverse.png", avatar: "/professional-woman-diverse.png",
bio: "Desenvolvedora apaixonada por criar soluções inovadoras. Experiência em React, Node.js e cloud computing.", bio: "Developer passionate about building innovative solutions. Experience in React, Node.js, and cloud computing.",
skills: ["React", "Node.js", "TypeScript", "AWS", "Docker"], skills: ["React", "Node.js", "TypeScript", "AWS", "Docker"],
applications: [ applications: [
{ {
id: "1", id: "1",
jobId: "1", jobId: "1",
jobTitle: "Desenvolvedor Full Stack Sênior", jobTitle: "Senior Full Stack Developer",
company: "TechCorp", company: "TechCorp",
status: "pending", status: "pending",
appliedAt: "2025-10-16", appliedAt: "2025-10-16",
@ -345,7 +345,7 @@ export const mockCandidates: Candidate[] = [
{ {
id: "2", id: "2",
jobId: "2", jobId: "2",
jobTitle: "Desenvolvedor Mobile", jobTitle: "Mobile Developer",
company: "AppMakers", company: "AppMakers",
status: "accepted", status: "accepted",
appliedAt: "2025-10-10", appliedAt: "2025-10-10",
@ -358,16 +358,16 @@ export const mockCandidates: Candidate[] = [
email: "carlos.santos@example.com", email: "carlos.santos@example.com",
phone: "+55 11 91234-5678", phone: "+55 11 91234-5678",
location: "Rio de Janeiro, RJ", location: "Rio de Janeiro, RJ",
title: "Designer UX/UI", title: "UX/UI Designer",
experience: "3 anos de experiência", experience: "3 years of experience",
avatar: "/professional-man.jpg", avatar: "/professional-man.jpg",
bio: "Designer focado em criar experiências memoráveis. Especialista em design systems e prototipagem.", bio: "Designer focused on creating memorable experiences. Specialist in design systems and prototyping.",
skills: ["Figma", "Adobe XD", "UI Design", "Prototyping", "Design Systems"], skills: ["Figma", "Adobe XD", "UI Design", "Prototyping", "Design Systems"],
applications: [ applications: [
{ {
id: "3", id: "3",
jobId: "3", jobId: "3",
jobTitle: "Designer UX/UI", jobTitle: "UX/UI Designer",
company: "DesignHub", company: "DesignHub",
status: "pending", status: "pending",
appliedAt: "2025-10-15", appliedAt: "2025-10-15",
@ -380,10 +380,10 @@ export const mockCandidates: Candidate[] = [
email: "maria.oliveira@example.com", email: "maria.oliveira@example.com",
phone: "+55 21 99876-5432", phone: "+55 21 99876-5432",
location: "Belo Horizonte, MG", location: "Belo Horizonte, MG",
title: "Engenheira de Dados", title: "Data Engineer",
experience: "7 anos de experiência", experience: "7 years of experience",
avatar: "/professional-woman-smiling.png", avatar: "/professional-woman-smiling.png",
bio: "Engenheira de dados com forte background em machine learning e big data. Apaixonada por transformar dados em insights.", bio: "Data engineer with a strong background in machine learning and big data. Passionate about turning data into insights.",
skills: [ skills: [
"Python", "Python",
"SQL", "SQL",
@ -395,7 +395,7 @@ export const mockCandidates: Candidate[] = [
{ {
id: "4", id: "4",
jobId: "4", jobId: "4",
jobTitle: "Engenheiro de Dados", jobTitle: "Data Engineer",
company: "DataFlow", company: "DataFlow",
status: "accepted", status: "accepted",
appliedAt: "2025-10-13", appliedAt: "2025-10-13",
@ -417,9 +417,9 @@ export const mockCandidates: Candidate[] = [
phone: "+55 31 98765-1234", phone: "+55 31 98765-1234",
location: "Curitiba, PR", location: "Curitiba, PR",
title: "Product Manager", title: "Product Manager",
experience: "6 anos de experiência", experience: "6 years of experience",
avatar: "/placeholder.svg?height=100&width=100", avatar: "/placeholder.svg?height=100&width=100",
bio: "Product Manager com experiência em produtos digitais e metodologias ágeis. Focado em entregar valor ao usuário.", bio: "Product Manager with experience in digital products and agile methodologies. Focused on delivering user value.",
skills: [ skills: [
"Product Management", "Product Management",
"Agile", "Agile",
@ -445,9 +445,9 @@ export const mockCandidates: Candidate[] = [
phone: "+55 41 91234-8765", phone: "+55 41 91234-8765",
location: "Porto Alegre, RS", location: "Porto Alegre, RS",
title: "DevOps Engineer", title: "DevOps Engineer",
experience: "4 anos de experiência", experience: "4 years of experience",
avatar: "/placeholder.svg?height=100&width=100", avatar: "/placeholder.svg?height=100&width=100",
bio: "DevOps engineer especializada em automação e infraestrutura cloud. Experiência com Kubernetes e CI/CD.", bio: "DevOps engineer specialized in automation and cloud infrastructure. Experience with Kubernetes and CI/CD.",
skills: ["Docker", "Kubernetes", "AWS", "Terraform", "CI/CD"], skills: ["Docker", "Kubernetes", "AWS", "Terraform", "CI/CD"],
applications: [ applications: [
{ {
@ -468,9 +468,9 @@ export const mockAdminUser = {
email: "admin@portal.com", email: "admin@portal.com",
role: "admin" as const, role: "admin" as const,
phone: "+55 11 99999-9999", phone: "+55 11 99999-9999",
department: "Recursos Humanos", department: "Human Resources",
position: "Gerente de RH", position: "HR Manager",
joinedAt: "2023-06-15", joinedAt: "2023-06-15",
avatar: "/placeholder.svg?height=200&width=200", avatar: "/placeholder.svg?height=200&width=200",
bio: "Gerente de RH com mais de 10 anos de experiência em recrutamento e seleção. Apaixonado por conectar talentos com oportunidades.", bio: "HR manager with over 10 years of experience in recruiting and selection. Passionate about connecting talent with opportunities.",
}; };

View file

@ -3,7 +3,7 @@ export interface Job {
title: string; title: string;
company: string; company: string;
location: string; location: string;
type: "full-time" | "part-time" | "contract" | "Remoto" | "Tempo Integral"; type: "full-time" | "part-time" | "contract" | "remote";
workMode?: "onsite" | "hybrid" | "remote"; workMode?: "onsite" | "hybrid" | "remote";
salary?: string; salary?: string;
description: string; description: string;