diff --git a/frontend/src/app/dashboard/my-jobs/page.tsx b/frontend/src/app/dashboard/my-jobs/page.tsx index 686c4b8..9f245fa 100644 --- a/frontend/src/app/dashboard/my-jobs/page.tsx +++ b/frontend/src/app/dashboard/my-jobs/page.tsx @@ -1,10 +1,9 @@ "use client" -import { useState } from "react" +import { useEffect, useState, useCallback } from "react" import { Card, CardContent, - CardDescription, CardHeader, CardTitle, } from "@/components/ui/card" @@ -37,6 +36,7 @@ import { Pause, Play, Zap, + Loader2, } from "lucide-react" import Link from "next/link" import { @@ -46,81 +46,18 @@ import { DropdownMenuSeparator, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu" - -// Mock data - in production this would come from API -const mockJobs = [ - { - id: "1", - title: "Senior Full Stack Developer", - type: "Full Time", - location: "São Paulo, SP", - workMode: "hybrid", - salary: "R$ 12,000 - R$ 18,000", - applications: 45, - views: 320, - postedAt: "2 days ago", - expiresAt: "28 days left", - status: "active", - }, - { - id: "2", - title: "Designer UX/UI", - type: "Full Time", - location: "Remote", - workMode: "remote", - salary: "R$ 8,000 - R$ 12,000", - applications: 32, - views: 256, - postedAt: "5 days ago", - expiresAt: "25 days left", - status: "active", - }, - { - id: "3", - title: "Product Manager", - type: "Full Time", - location: "São Paulo, SP", - workMode: "onsite", - salary: "R$ 15,000 - R$ 20,000", - applications: 28, - views: 189, - postedAt: "1 week ago", - expiresAt: "21 days left", - status: "active", - }, - { - id: "4", - title: "DevOps Engineer", - type: "Full Time", - location: "São Paulo, SP", - workMode: "hybrid", - salary: "R$ 14,000 - R$ 20,000", - applications: 15, - views: 98, - postedAt: "2 weeks ago", - expiresAt: "14 days left", - status: "paused", - }, - { - id: "5", - title: "Junior Frontend Developer", - type: "Full Time", - location: "São Paulo, SP", - workMode: "onsite", - salary: "R$ 4,000 - R$ 6,000", - applications: 120, - views: 450, - postedAt: "1 month ago", - expiresAt: "Expired", - status: "closed", - }, -] +import { toast } from "sonner" +import { authApi, jobsApi, ApiJob, ApiUser } from "@/lib/api" +import { formatDistanceToNow } from "date-fns" +import { ptBR } from "date-fns/locale" const statusConfig = { active: { label: "Active", color: "bg-green-100 text-green-800 border-green-200" }, paused: { label: "Paused", color: "bg-yellow-100 text-yellow-800 border-yellow-200" }, closed: { label: "Closed", color: "bg-gray-100 text-gray-800 border-gray-200" }, draft: { label: "Draft", color: "bg-blue-100 text-blue-800 border-blue-200" }, + published: { label: "Active", color: "bg-green-100 text-green-800 border-green-200" }, // Mapping published to active style + open: { label: "Active", color: "bg-green-100 text-green-800 border-green-200" }, } const workModeConfig = { @@ -130,10 +67,46 @@ const workModeConfig = { } export default function MyJobsPage() { - const [jobs] = useState(mockJobs) + const [jobs, setJobs] = useState([]) + const [isLoading, setIsLoading] = useState(true) + const [user, setUser] = useState(null) const [statusFilter, setStatusFilter] = useState("all") const [searchTerm, setSearchTerm] = useState("") + const fetchJobs = useCallback(async () => { + try { + setIsLoading(true) + // 1. Get User to know Company ID + const currentUser = await authApi.getCurrentUser() + setUser(currentUser) + + if (!currentUser.companyId) { + // If user has no company, they shouldn't see jobs or should be prompted to create one + // For now just show empty list + setJobs([]) + return + } + + // 2. Fetch Jobs for that Company + const response = await jobsApi.list({ + companyId: currentUser.companyId, + limit: 100 // Fetch all for now to client-side filter + }) + setJobs(response.data) + + } catch (error) { + console.error("Error fetching jobs:", error) + toast.error("Failed to load jobs") + } finally { + setIsLoading(false) + } + }, []) + + useEffect(() => { + fetchJobs() + }, [fetchJobs]) + + const filteredJobs = jobs.filter((job) => { const matchesStatus = statusFilter === "all" || job.status === statusFilter const matchesSearch = @@ -144,9 +117,25 @@ export default function MyJobsPage() { const stats = { total: jobs.length, - active: jobs.filter((j) => j.status === "active").length, - applications: jobs.reduce((acc, j) => acc + j.applications, 0), - views: jobs.reduce((acc, j) => acc + j.views, 0), + active: jobs.filter((j) => j.status === "published" || j.status === "open").length, + applications: jobs.reduce((acc, j) => acc + (j.applicationCount || 0), 0), + views: 0, // Backend does not strictly track views yet per ApiJob interface + } + + // Helper to format currency + const formatSalary = (min?: number, max?: number) => { + if (!min && !max) return "Negotiable" + if (min && max) return `R$ ${min.toLocaleString()} - R$ ${max.toLocaleString()}` + if (min) return `From R$ ${min.toLocaleString()}` + return `Up to R$ ${max?.toLocaleString()}` + } + + if (isLoading) { + return ( +
+ +
+ ) } return ( @@ -158,13 +147,15 @@ export default function MyJobsPage() { My Jobs

- Manage your job postings + Manage your job postings for {user?.companyId ? "your company" : "..."}

- + + + {/* Stats */} @@ -232,10 +223,9 @@ export default function MyJobsPage() { All Status - Active - Paused - Closed + Active (Published) Draft + Closed @@ -247,11 +237,13 @@ export default function MyJobsPage() {

No jobs found

-

Start by posting your first job.

- +

Start by posting your first job using the button above.

+ + +
) : ( @@ -266,15 +258,15 @@ export default function MyJobsPage() {

{job.title}

- {statusConfig[job.status as keyof typeof statusConfig].label} + {statusConfig[job.status as keyof typeof statusConfig]?.label || job.status} - {workModeConfig[job.workMode as keyof typeof workModeConfig].label} + {workModeConfig[job.workMode as keyof typeof workModeConfig]?.label || job.workMode} @@ -309,17 +301,17 @@ export default function MyJobsPage() { - {job.status === "active" ? ( + {job.status === "published" || job.status === "open" ? ( Pause - ) : job.status === "paused" ? ( + ) : ( Activate - ) : null} + )} Delete @@ -335,28 +327,30 @@ export default function MyJobsPage() { - {job.salary} + {formatSalary(job.salaryMin, job.salaryMax)} - {job.expiresAt} + Posted {formatDistanceToNow(new Date(job.createdAt), { addSuffix: true })}
- {job.applications} + {job.applicationCount || 0} applications
- {job.views} + {0} views
- Posted {job.postedAt} + + Created {new Date(job.createdAt).toLocaleDateString()} +
@@ -369,10 +363,12 @@ export default function MyJobsPage() { Applications - + + +