Update src/app/applications/page.tsx

This commit is contained in:
2026-03-08 22:37:13 +00:00
parent f69459c79e
commit bc899d6e44

View File

@@ -3,16 +3,15 @@
import { ThemeProvider } from "@/providers/themeProvider/ThemeProvider";
import NavbarStyleCentered from "@/components/navbar/NavbarStyleCentered/NavbarStyleCentered";
import FooterBase from "@/components/sections/footer/FooterBase";
import { FileText, Clock, CheckCircle, XCircle, Mail } from "lucide-react";
import { useState } from "react";
import { Briefcase, Clock, CheckCircle, AlertCircle, MapPin, DollarSign, Building2, Calendar, ArrowRight } from "lucide-react";
const navItems = [
{ name: "Search Jobs", id: "search" },
{ name: "Post a Job", id: "post-job" },
{ name: "Admin", id: "admin-login" },
{ name: "Post a Job", id: "/post-job" },
{ name: "Applications", id: "/applications" },
{ name: "Browse", id: "browse" },
{ name: "Contact", id: "contact" },
{ name: "Applications", id: "/applications" },
];
const footerColumns = [
@@ -20,7 +19,7 @@ const footerColumns = [
title: "Product", items: [
{ label: "Search Jobs", href: "/search" },
{ label: "Post a Job", href: "/post-job" },
{ label: "Browse by Province", href: "#provinces" },
{ label: "My Applications", href: "/applications" },
{ label: "For Employers", href: "#" },
],
},
@@ -46,80 +45,70 @@ interface Application {
id: string;
jobTitle: string;
company: string;
location: string;
salary: string;
status: "pending" | "reviewing" | "accepted" | "rejected";
appliedDate: string;
status: "pending" | "reviewed" | "accepted" | "rejected";
logoSrc?: string;
lastUpdate: string;
applicantName: string;
email: string;
appliedPosition?: string;
}
const mockApplications: Application[] = [
{
id: "1", jobTitle: "Senior React Developer", company: "TechFlow Solutions", location: "Amsterdam, Netherlands", salary: "€65,000 - €80,000", appliedDate: "2025-01-15", status: "reviewed", logoSrc: "https://api.dicebear.com/7.x/initials/svg?seed=TF"},
id: "1", jobTitle: "Senior Frontend Developer", company: "Tech Innovations BV", status: "reviewing", appliedDate: "2025-01-15", lastUpdate: "2025-01-18", applicantName: "John Doe", email: "john.doe@example.com"},
{
id: "2", jobTitle: "UX/UI Designer", company: "Creative Studios Amsterdam", location: "Amsterdam, Netherlands", salary: "€50,000 - €65,000", appliedDate: "2025-01-10", status: "accepted", logoSrc: "https://api.dicebear.com/7.x/initials/svg?seed=CSA"},
id: "2", jobTitle: "Product Manager", company: "Digital Solutions Inc", status: "pending", appliedDate: "2025-01-20", lastUpdate: "2025-01-20", applicantName: "Jane Smith", email: "jane.smith@example.com"},
{
id: "3", jobTitle: "Full Stack Developer", company: "Innovate Inc", location: "Rotterdam, Netherlands", salary: "€55,000 - €70,000", appliedDate: "2025-01-12", status: "pending", logoSrc: "https://api.dicebear.com/7.x/initials/svg?seed=II"},
id: "3", jobTitle: "UX/UI Designer", company: "Creative Studio Amsterdam", status: "accepted", appliedDate: "2025-01-10", lastUpdate: "2025-01-17", applicantName: "Alice Johnson", email: "alice.johnson@example.com"},
{
id: "4", jobTitle: "Marketing Manager", company: "Digital Growth Partners", location: "Utrecht, Netherlands", salary: "€48,000 - €60,000", appliedDate: "2025-01-08", status: "rejected", logoSrc: "https://api.dicebear.com/7.x/initials/svg?seed=DGP"},
id: "4", jobTitle: "Data Scientist", company: "AI Labs Netherlands", status: "rejected", appliedDate: "2025-01-05", lastUpdate: "2025-01-16", applicantName: "Bob Wilson", email: "bob.wilson@example.com"},
{
id: "5", jobTitle: "Data Scientist", company: "Analytics Pro", location: "The Hague, Netherlands", salary: "€60,000 - €75,000", appliedDate: "2025-01-05", status: "reviewed", logoSrc: "https://api.dicebear.com/7.x/initials/svg?seed=AP"},
{
id: "6", jobTitle: "Product Manager", company: "Tech Ventures", location: "Eindhoven, Netherlands", salary: "€65,000 - €85,000", appliedDate: "2025-01-02", status: "pending", logoSrc: "https://api.dicebear.com/7.x/initials/svg?seed=TV"},
id: "5", jobTitle: "Backend Developer", company: "Cloud Systems Ltd", status: "reviewing", appliedDate: "2025-01-12", lastUpdate: "2025-01-19", applicantName: "Charlie Brown", email: "charlie.brown@example.com"},
];
const getStatusColor = (status: string) => {
switch (status) {
case "accepted":
return "bg-green-100 text-green-800";
case "rejected":
return "bg-red-100 text-red-800";
case "reviewed":
return "bg-blue-100 text-blue-800";
case "pending":
return "bg-yellow-100 text-yellow-800";
default:
return "bg-gray-100 text-gray-800";
}
};
const getStatusIcon = (status: string) => {
switch (status) {
case "accepted":
return <CheckCircle className="w-4 h-4" />;
case "rejected":
return <AlertCircle className="w-4 h-4" />;
case "reviewed":
return <Clock className="w-4 h-4" />;
case "pending":
return <Clock className="w-4 h-4" />;
default:
return <Clock className="w-4 h-4" />;
}
};
const getStatusLabel = (status: string) => {
switch (status) {
case "accepted":
return "Accepted";
case "rejected":
return "Rejected";
case "reviewed":
return "Under Review";
case "pending":
return "Pending";
default:
return status;
}
};
export default function ApplicationsPage() {
const [selectedApplication, setSelectedApplication] = useState<Application | null>(null);
const [statusFilter, setStatusFilter] = useState<string>("all");
const [applications, setApplications] = useState<Application[]>(mockApplications);
const [filterStatus, setFilterStatus] = useState<string>("all");
const [selectedApp, setSelectedApp] = useState<Application | null>(null);
const filteredApplications = statusFilter === "all"
? mockApplications
: mockApplications.filter(app => app.status === statusFilter);
const filteredApplications =
filterStatus === "all"
? applications
: applications.filter((app) => app.status === filterStatus);
const getStatusIcon = (status: string) => {
switch (status) {
case "pending":
return <Clock className="w-5 h-5 text-yellow-600" />;
case "reviewing":
return <FileText className="w-5 h-5 text-blue-600" />;
case "accepted":
return <CheckCircle className="w-5 h-5 text-green-600" />;
case "rejected":
return <XCircle className="w-5 h-5 text-red-600" />;
default:
return null;
}
};
const getStatusBadgeColor = (status: string) => {
switch (status) {
case "pending":
return "bg-yellow-100 text-yellow-800";
case "reviewing":
return "bg-blue-100 text-blue-800";
case "accepted":
return "bg-green-100 text-green-800";
case "rejected":
return "bg-red-100 text-red-800";
default:
return "bg-slate-100 text-slate-800";
}
};
const getStatusLabel = (status: string) => {
return status.charAt(0).toUpperCase() + status.slice(1);
};
return (
<ThemeProvider
@@ -143,206 +132,159 @@ export default function ApplicationsPage() {
/>
</div>
<main className="min-h-screen bg-gradient-to-br from-background via-card to-background">
<div className="container mx-auto px-4 py-16">
{/* Header Section */}
<div className="mb-12">
<div className="min-h-screen bg-gradient-to-b from-slate-50 to-slate-100 pt-32 pb-20">
<div className="max-w-6xl mx-auto px-4">
<div className="mb-8">
<div className="flex items-center gap-3 mb-4">
<Briefcase className="w-8 h-8 text-primary-cta" />
<h1 className="text-4xl md:text-5xl font-bold text-foreground">My Applications</h1>
<Mail className="w-6 h-6 text-blue-600" />
<span className="text-sm font-semibold text-blue-600 uppercase tracking-wide">
My Applications
</span>
</div>
<p className="text-lg text-foreground/70 mb-8">
Track and manage all your job applications in one place. Monitor your application status and stay updated on opportunities.
<h1 className="text-4xl md:text-5xl font-bold text-slate-900 mb-3">
Track Your Applications
</h1>
<p className="text-lg text-slate-600">
Monitor the status of all your job applications and stay updated on each
opportunity.
</p>
{/* Status Filter */}
<div className="flex flex-wrap gap-2">
<button
onClick={() => setStatusFilter("all")}
className={`px-6 py-2 rounded-full font-medium transition-all ${
statusFilter === "all"
? "bg-primary-cta text-white"
: "bg-card border border-accent/30 text-foreground hover:border-accent"
}`}
>
All Applications ({mockApplications.length})
</button>
<button
onClick={() => setStatusFilter("pending")}
className={`px-6 py-2 rounded-full font-medium transition-all ${
statusFilter === "pending"
? "bg-yellow-500 text-white"
: "bg-card border border-accent/30 text-foreground hover:border-accent"
}`}
>
Pending
</button>
<button
onClick={() => setStatusFilter("reviewed")}
className={`px-6 py-2 rounded-full font-medium transition-all ${
statusFilter === "reviewed"
? "bg-blue-500 text-white"
: "bg-card border border-accent/30 text-foreground hover:border-accent"
}`}
>
Under Review
</button>
<button
onClick={() => setStatusFilter("accepted")}
className={`px-6 py-2 rounded-full font-medium transition-all ${
statusFilter === "accepted"
? "bg-green-500 text-white"
: "bg-card border border-accent/30 text-foreground hover:border-accent"
}`}
>
Accepted
</button>
<button
onClick={() => setStatusFilter("rejected")}
className={`px-6 py-2 rounded-full font-medium transition-all ${
statusFilter === "rejected"
? "bg-red-500 text-white"
: "bg-card border border-accent/30 text-foreground hover:border-accent"
}`}
>
Rejected
</button>
</div>
</div>
{/* Applications Grid */}
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
{/* Application List */}
<div className="lg:col-span-2">
<div className="space-y-4">
{filteredApplications.length === 0 ? (
<div className="bg-card border border-accent/20 rounded-2xl p-8 text-center">
<Briefcase className="w-12 h-12 text-foreground/30 mx-auto mb-4" />
<p className="text-foreground/60">No applications found with this status.</p>
</div>
) : (
filteredApplications.map((app) => (
<div
key={app.id}
onClick={() => setSelectedApplication(app)}
className={`bg-card border border-accent/20 rounded-2xl p-6 cursor-pointer transition-all hover:border-accent/50 hover:shadow-lg ${
selectedApplication?.id === app.id ? "border-primary-cta" : ""
}`}
>
<div className="flex gap-4">
{/* Company Logo */}
<div className="flex-shrink-0">
<div className="w-16 h-16 bg-gradient-to-br from-primary-cta/20 to-accent/20 rounded-xl flex items-center justify-center">
<Building2 className="w-8 h-8 text-primary-cta" />
</div>
</div>
{/* Filter Tabs */}
<div className="mb-8 flex flex-wrap gap-3">
{[
{ label: "All", value: "all", count: applications.length },
{
label: "Pending", value: "pending", count: applications.filter((a) => a.status === "pending").length,
},
{
label: "Reviewing", value: "reviewing", count: applications.filter((a) => a.status === "reviewing").length,
},
{
label: "Accepted", value: "accepted", count: applications.filter((a) => a.status === "accepted").length,
},
{
label: "Rejected", value: "rejected", count: applications.filter((a) => a.status === "rejected").length,
},
].map((filter) => (
<button
key={filter.value}
onClick={() => setFilterStatus(filter.value)}
className={`px-4 py-2 rounded-lg font-semibold transition ${
filterStatus === filter.value
? "bg-blue-600 text-white"
: "bg-white text-slate-700 hover:bg-slate-100"
}`}
>
{filter.label} ({filter.count})
</button>
))}
</div>
{/* Application Info */}
<div className="flex-grow">
<div className="flex items-start justify-between mb-2">
<div>
<h3 className="text-lg font-bold text-foreground">{app.jobTitle}</h3>
<p className="text-sm text-foreground/60">{app.company}</p>
</div>
<span
className={`px-3 py-1 rounded-full text-xs font-medium flex items-center gap-1 ${
getStatusColor(app.status)
}`}
>
{getStatusIcon(app.status)}
{getStatusLabel(app.status)}
</span>
</div>
<div className="flex flex-wrap gap-4 text-sm text-foreground/60 mt-3">
<div className="flex items-center gap-1">
<MapPin className="w-4 h-4" />
{app.location}
</div>
<div className="flex items-center gap-1">
<DollarSign className="w-4 h-4" />
{app.salary}
</div>
<div className="flex items-center gap-1">
<Calendar className="w-4 h-4" />
{new Date(app.appliedDate).toLocaleDateString()}
</div>
</div>
</div>
{/* Arrow Icon */}
<div className="flex-shrink-0 flex items-center">
<ArrowRight className="w-5 h-5 text-foreground/30" />
</div>
</div>
</div>
))
)}
{/* Applications List */}
<div className="space-y-4">
{filteredApplications.length === 0 ? (
<div className="text-center py-12 bg-white rounded-lg">
<p className="text-slate-600 text-lg">No applications found</p>
</div>
</div>
{/* Application Details Panel */}
<div className="lg:col-span-1">
{selectedApplication ? (
<div className="bg-card border border-accent/20 rounded-2xl p-6 sticky top-24">
<div className="mb-6">
<h2 className="text-2xl font-bold text-foreground mb-2">{selectedApplication.jobTitle}</h2>
<p className="text-foreground/60 mb-4">{selectedApplication.company}</p>
<span
className={`inline-flex items-center gap-2 px-4 py-2 rounded-full text-sm font-medium ${
getStatusColor(selectedApplication.status)
}`}
>
{getStatusIcon(selectedApplication.status)}
{getStatusLabel(selectedApplication.status)}
</span>
</div>
<div className="space-y-4 border-t border-accent/10 pt-6">
<div>
<p className="text-xs font-semibold text-foreground/50 uppercase tracking-wide mb-2">Location</p>
<div className="flex items-center gap-2">
<MapPin className="w-4 h-4 text-primary-cta" />
<p className="text-foreground">{selectedApplication.location}</p>
) : (
filteredApplications.map((app) => (
<div
key={app.id}
className="bg-white rounded-lg shadow hover:shadow-md transition p-6 cursor-pointer"
onClick={() => setSelectedApp(app)}
>
<div className="flex items-start justify-between">
<div className="flex-1">
<div className="flex items-center gap-3 mb-2">
<h3 className="text-xl font-bold text-slate-900">{app.jobTitle}</h3>
<div
className={`flex items-center gap-1 px-3 py-1 rounded-full text-sm font-semibold ${
getStatusBadgeColor(app.status)
}`}
>
{getStatusIcon(app.status)}
{getStatusLabel(app.status)}
</div>
</div>
<p className="text-slate-600 mb-2">{app.company}</p>
<div className="text-sm text-slate-500 space-y-1">
<p>Applied: {new Date(app.appliedDate).toLocaleDateString()}</p>
<p>Last Update: {new Date(app.lastUpdate).toLocaleDateString()}</p>
</div>
</div>
<div>
<p className="text-xs font-semibold text-foreground/50 uppercase tracking-wide mb-2">Salary Range</p>
<div className="flex items-center gap-2">
<DollarSign className="w-4 h-4 text-primary-cta" />
<p className="text-foreground">{selectedApplication.salary}</p>
</div>
</div>
<div>
<p className="text-xs font-semibold text-foreground/50 uppercase tracking-wide mb-2">Applied Date</p>
<div className="flex items-center gap-2">
<Calendar className="w-4 h-4 text-primary-cta" />
<p className="text-foreground">{new Date(selectedApplication.appliedDate).toLocaleDateString()}</p>
</div>
</div>
</div>
<div className="mt-6 space-y-2">
<button className="w-full bg-primary-cta text-white py-3 rounded-lg font-medium hover:opacity-90 transition-opacity">
View Application
</button>
<button className="w-full bg-card border border-accent/30 text-foreground py-3 rounded-lg font-medium hover:border-accent transition-colors">
Contact Company
</button>
</div>
</div>
) : (
<div className="bg-card border border-accent/20 rounded-2xl p-6 text-center">
<Briefcase className="w-12 h-12 text-foreground/30 mx-auto mb-4" />
<p className="text-foreground/60">Select an application to view details</p>
</div>
)}
</div>
))
)}
</div>
</div>
</main>
{/* Detail Modal */}
{selectedApp && (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center p-4 z-50">
<div className="bg-white rounded-lg max-w-2xl w-full max-h-96 overflow-y-auto">
<div className="p-8">
<div className="flex items-start justify-between mb-6">
<div>
<h2 className="text-2xl font-bold text-slate-900 mb-2">
{selectedApp.jobTitle}
</h2>
<p className="text-slate-600 text-lg">{selectedApp.company}</p>
</div>
<div
className={`flex items-center gap-2 px-4 py-2 rounded-full font-semibold ${
getStatusBadgeColor(selectedApp.status)
}`}
>
{getStatusIcon(selectedApp.status)}
{getStatusLabel(selectedApp.status)}
</div>
</div>
<div className="border-t pt-6 space-y-4">
<div>
<p className="text-sm text-slate-600">Applicant Name</p>
<p className="text-lg font-semibold text-slate-900">{selectedApp.applicantName}</p>
</div>
<div>
<p className="text-sm text-slate-600">Email Address</p>
<p className="text-lg font-semibold text-slate-900">{selectedApp.email}</p>
</div>
<div className="grid grid-cols-2 gap-4">
<div>
<p className="text-sm text-slate-600">Applied Date</p>
<p className="text-lg font-semibold text-slate-900">
{new Date(selectedApp.appliedDate).toLocaleDateString()}
</p>
</div>
<div>
<p className="text-sm text-slate-600">Last Update</p>
<p className="text-lg font-semibold text-slate-900">
{new Date(selectedApp.lastUpdate).toLocaleDateString()}
</p>
</div>
</div>
</div>
<div className="border-t mt-6 pt-6">
<div className="flex gap-3">
<button
onClick={() => setSelectedApp(null)}
className="flex-1 bg-slate-200 hover:bg-slate-300 text-slate-900 font-semibold py-2 rounded-lg transition"
>
Close
</button>
<button className="flex-1 bg-blue-600 hover:bg-blue-700 text-white font-semibold py-2 rounded-lg transition">
View Full Details
</button>
</div>
</div>
</div>
</div>
</div>
)}
</div>
<div id="footer" data-section="footer">
<FooterBase