126 Commits

Author SHA1 Message Date
5cefbc80c8 Merge version_2 into main
Merge version_2 into main
2026-03-08 22:43:44 +00:00
cf649b28ae Update src/app/page.tsx 2026-03-08 22:43:40 +00:00
7519b0ea41 Merge version_2 into main
Merge version_2 into main
2026-03-08 22:42:38 +00:00
3e408f08c9 Update src/app/layout.tsx 2026-03-08 22:41:33 +00:00
546d020d5a Update src/app/layout.tsx 2026-03-08 22:39:59 +00:00
849ff046b9 Update src/app/styles/variables.css 2026-03-08 22:38:55 +00:00
a4f5c9df37 Update src/app/search/page.tsx 2026-03-08 22:38:54 +00:00
18e1e5d5ef Update src/app/post-job/page.tsx 2026-03-08 22:38:54 +00:00
96b46b5ec5 Update src/app/page.tsx 2026-03-08 22:38:53 +00:00
84e66b850a Update src/app/layout.tsx 2026-03-08 22:38:53 +00:00
f08bc17768 Add src/app/jobs/page.tsx 2026-03-08 22:38:52 +00:00
c2dae3421e Add src/app/applications/page.tsx 2026-03-08 22:38:52 +00:00
df14b5ba70 Add src/app/admin/page.tsx 2026-03-08 22:38:52 +00:00
41ba7a7546 Update src/app/styles/variables.css 2026-03-08 22:37:18 +00:00
b0a6f0dbb7 Update src/app/search/page.tsx 2026-03-08 22:37:17 +00:00
8b60177ad1 Update src/app/post-job/page.tsx 2026-03-08 22:37:16 +00:00
e800be26cd Update src/app/page.tsx 2026-03-08 22:37:15 +00:00
9d8b850abc Update src/app/layout.tsx 2026-03-08 22:37:14 +00:00
fbcc591b0e Add src/app/jobs/page.tsx 2026-03-08 22:37:13 +00:00
bc899d6e44 Update src/app/applications/page.tsx 2026-03-08 22:37:13 +00:00
f69459c79e Update src/app/admin/page.tsx 2026-03-08 22:37:12 +00:00
586649b40a Switch to version 1: remove src/app/applications/page.tsx 2026-03-08 22:35:44 +00:00
d2a346810e Switch to version 1: remove src/app/admin/page.tsx 2026-03-08 22:35:43 +00:00
ca4fb5dc2c Switch to version 1: modified src/app/search/page.tsx 2026-03-08 22:35:43 +00:00
f22cc27581 Switch to version 1: modified src/app/post-job/page.tsx 2026-03-08 22:35:42 +00:00
3cbb3ffe27 Switch to version 1: modified src/app/page.tsx 2026-03-08 22:35:42 +00:00
0d1a2fc89e Switch to version 1: modified src/app/layout.tsx 2026-03-08 22:35:41 +00:00
921cdb60cb Switch to version 1: modified src/app/apply/page.tsx 2026-03-08 22:35:41 +00:00
5bfc5eda31 Update src/app/page.tsx 2026-03-08 22:32:14 +00:00
c696694318 Update src/app/page.tsx 2026-03-08 22:30:40 +00:00
8e582cdfd5 Update src/app/post-job/page.tsx 2026-03-08 22:29:18 +00:00
e13c33c514 Update src/app/page.tsx 2026-03-08 22:29:17 +00:00
93e5bd31ac Update src/app/layout.tsx 2026-03-08 22:29:17 +00:00
36b2c55b8d Update src/app/post-job/page.tsx 2026-03-08 22:27:43 +00:00
0f5ae59296 Update src/app/page.tsx 2026-03-08 22:27:42 +00:00
352af2b1b6 Update src/app/layout.tsx 2026-03-08 22:27:41 +00:00
bb21d51d0c Merge version_3 into main
Merge version_3 into main
2026-03-08 22:27:27 +00:00
282ec7c7ea Update src/app/search/page.tsx 2026-03-08 22:27:23 +00:00
3ddd1d149b Update src/app/post-job/page.tsx 2026-03-08 22:27:22 +00:00
480f9310c6 Update src/app/page.tsx 2026-03-08 22:27:22 +00:00
4ff558d745 Update src/app/layout.tsx 2026-03-08 22:27:21 +00:00
4f745c93c3 Update src/app/apply/page.tsx 2026-03-08 22:27:21 +00:00
6373b5ea06 Update src/app/search/page.tsx 2026-03-08 22:26:12 +00:00
4d2b3e17b5 Update src/app/post-job/page.tsx 2026-03-08 22:26:11 +00:00
493be55972 Update src/app/page.tsx 2026-03-08 22:26:10 +00:00
3a886ec207 Update src/app/layout.tsx 2026-03-08 22:26:10 +00:00
1be6979ab5 Add src/app/applications/page.tsx 2026-03-08 22:26:09 +00:00
80ab56121a Add src/app/admin/page.tsx 2026-03-08 22:26:08 +00:00
44a13a952f Update src/app/search/page.tsx 2026-03-08 22:24:34 +00:00
abf5473f6e Update src/app/post-job/page.tsx 2026-03-08 22:24:33 +00:00
00b122afac Update src/app/page.tsx 2026-03-08 22:24:33 +00:00
03f62ec21d Update src/app/layout.tsx 2026-03-08 22:24:32 +00:00
3782a4c02d Update src/app/apply/page.tsx 2026-03-08 22:24:32 +00:00
ef348208d8 Update src/app/applications/page.tsx 2026-03-08 22:24:32 +00:00
0d569ac586 Update src/app/admin/page.tsx 2026-03-08 22:24:31 +00:00
ca6084197d Switch to version 1: remove src/app/applications/page.tsx 2026-03-08 22:23:35 +00:00
65acbd32ab Switch to version 1: remove src/app/admin/page.tsx 2026-03-08 22:23:35 +00:00
421a0d4dbe Switch to version 1: modified src/lib/api/product.ts 2026-03-08 22:23:34 +00:00
d21ebfd001 Switch to version 1: modified src/hooks/useProducts.ts 2026-03-08 22:23:34 +00:00
51bcffe909 Switch to version 1: modified src/hooks/useProductDetail.ts 2026-03-08 22:23:33 +00:00
7a51c13052 Switch to version 1: modified src/hooks/useProductCatalog.ts 2026-03-08 22:23:33 +00:00
7a96daee1c Switch to version 1: modified src/hooks/useProduct.ts 2026-03-08 22:23:33 +00:00
67978193ba Switch to version 1: modified src/hooks/useCheckout.ts 2026-03-08 22:23:32 +00:00
9b94d81876 Switch to version 1: modified src/components/sections/product/ProductCardTwo.tsx 2026-03-08 22:23:32 +00:00
2dade11252 Switch to version 1: modified src/components/sections/product/ProductCardThree.tsx 2026-03-08 22:23:31 +00:00
133cfea674 Switch to version 1: modified src/components/sections/product/ProductCardOne.tsx 2026-03-08 22:23:31 +00:00
99d4f8ce22 Switch to version 1: modified src/components/sections/product/ProductCardFour.tsx 2026-03-08 22:23:30 +00:00
405b18fb28 Switch to version 1: modified src/components/sections/pricing/PricingCardEight.tsx 2026-03-08 22:23:30 +00:00
4a49487c77 Switch to version 1: modified src/components/sections/contact/ContactSplitForm.tsx 2026-03-08 22:23:30 +00:00
4591aa0eca Switch to version 1: modified src/components/sections/contact/ContactSplit.tsx 2026-03-08 22:23:29 +00:00
9346a0f432 Switch to version 1: modified src/components/sections/contact/ContactCenter.tsx 2026-03-08 22:23:29 +00:00
2095c0060e Switch to version 1: modified src/components/cardStack/layouts/timelines/TimelineBase.tsx 2026-03-08 22:23:28 +00:00
8d99e049e6 Switch to version 1: modified src/components/cardStack/hooks/useDepth3DAnimation.ts 2026-03-08 22:23:28 +00:00
e2f8bd0110 Switch to version 1: modified src/components/cardStack/hooks/useCardAnimation.ts 2026-03-08 22:23:27 +00:00
89ceb71096 Switch to version 1: modified src/components/cardStack/CardStack.tsx 2026-03-08 22:23:27 +00:00
4b3707c37b Switch to version 1: modified src/app/search/page.tsx 2026-03-08 22:23:27 +00:00
880d6203a7 Switch to version 1: modified src/app/post-job/page.tsx 2026-03-08 22:23:26 +00:00
e71c5c0f8b Switch to version 1: modified src/app/page.tsx 2026-03-08 22:23:26 +00:00
77c71a315d Switch to version 1: modified src/app/layout.tsx 2026-03-08 22:23:25 +00:00
72f424682a Switch to version 1: modified src/app/apply/page.tsx 2026-03-08 22:23:25 +00:00
0514de31b6 Merge version_2 into main
Merge version_2 into main
2026-03-08 22:22:31 +00:00
47d6d223c3 Update src/components/cardStack/CardStack.tsx 2026-03-08 22:22:26 +00:00
67c5d07b7b Update src/app/page.tsx 2026-03-08 22:22:25 +00:00
035db5c023 Merge version_2 into main
Merge version_2 into main
2026-03-08 22:21:23 +00:00
d3dac0cee3 Update src/lib/api/product.ts 2026-03-08 22:21:19 +00:00
184c822595 Update src/hooks/useProducts.ts 2026-03-08 22:21:19 +00:00
82b0c18e52 Update src/hooks/useProduct.ts 2026-03-08 22:21:18 +00:00
61fd21c259 Update src/components/sections/product/ProductCardTwo.tsx 2026-03-08 22:21:18 +00:00
636a3a4c15 Update src/components/sections/product/ProductCardThree.tsx 2026-03-08 22:21:17 +00:00
d38cd3c458 Update src/components/sections/product/ProductCardOne.tsx 2026-03-08 22:21:17 +00:00
b8710b24a0 Update src/components/sections/product/ProductCardFour.tsx 2026-03-08 22:21:17 +00:00
cd9915cd6e Update src/components/cardStack/hooks/useDepth3DAnimation.ts 2026-03-08 22:21:16 +00:00
4af8479479 Update src/components/cardStack/hooks/useCardAnimation.ts 2026-03-08 22:21:16 +00:00
c813799e97 Update src/components/cardStack/CardStack.tsx 2026-03-08 22:21:15 +00:00
3981f7d98b Update src/app/page.tsx 2026-03-08 22:21:15 +00:00
bf27ffa4ae Update src/app/admin/page.tsx 2026-03-08 22:21:14 +00:00
4e877df3bf Merge version_2 into main
Merge version_2 into main
2026-03-08 22:19:49 +00:00
d90c038218 Update src/lib/api/product.ts 2026-03-08 22:19:45 +00:00
99ec17545c Update src/hooks/useProductDetail.ts 2026-03-08 22:19:45 +00:00
de4853edae Update src/hooks/useProductCatalog.ts 2026-03-08 22:19:45 +00:00
a9c024cee2 Update src/hooks/useCheckout.ts 2026-03-08 22:19:44 +00:00
6a0b735d77 Update src/components/sections/pricing/PricingCardEight.tsx 2026-03-08 22:19:44 +00:00
0346a28661 Update src/components/sections/contact/ContactSplitForm.tsx 2026-03-08 22:19:43 +00:00
8f4c4a9a8d Update src/components/sections/contact/ContactSplit.tsx 2026-03-08 22:19:43 +00:00
5cc569fcbe Update src/components/sections/contact/ContactCenter.tsx 2026-03-08 22:19:43 +00:00
7a29becc6e Update src/components/cardStack/layouts/timelines/TimelineBase.tsx 2026-03-08 22:19:42 +00:00
c522614a4f Update src/components/cardStack/hooks/useDepth3DAnimation.ts 2026-03-08 22:19:42 +00:00
97524956d7 Update src/app/search/page.tsx 2026-03-08 22:19:41 +00:00
442db37238 Update src/app/apply/page.tsx 2026-03-08 22:19:41 +00:00
4ba0c81193 Update src/app/applications/page.tsx 2026-03-08 22:19:41 +00:00
61d3a35d93 Update src/app/admin/page.tsx 2026-03-08 22:19:40 +00:00
2509960b1c Merge version_2 into main
Merge version_2 into main
2026-03-08 22:16:05 +00:00
f232aa4e8f Update src/app/admin/page.tsx 2026-03-08 22:16:01 +00:00
109159b5f8 Merge version_2 into main
Merge version_2 into main
2026-03-08 22:13:48 +00:00
e1bb3ad20b Update src/app/layout.tsx 2026-03-08 22:13:44 +00:00
a47a53417b Update src/app/admin/page.tsx 2026-03-08 22:13:44 +00:00
96ab94d27e Merge version_2 into main
Merge version_2 into main
2026-03-08 22:12:44 +00:00
e28c7a74c3 Update src/app/search/page.tsx 2026-03-08 22:12:40 +00:00
46c8201b2e Update src/app/post-job/page.tsx 2026-03-08 22:12:39 +00:00
ba33e12e8d Update src/app/page.tsx 2026-03-08 22:12:39 +00:00
c3e170a160 Update src/app/layout.tsx 2026-03-08 22:12:39 +00:00
f49320b8db Add src/app/applications/page.tsx 2026-03-08 22:12:38 +00:00
d87884fca5 Add src/app/admin/page.tsx 2026-03-08 22:12:38 +00:00
29d059a2a8 Merge version_1 into main
Merge version_1 into main
2026-03-08 20:07:57 +00:00
f5dad3e157 Merge version_1 into main
Merge version_1 into main
2026-03-08 20:07:06 +00:00
d1c3983b8e Merge version_1 into main
Merge version_1 into main
2026-03-08 20:05:33 +00:00
8 changed files with 1711 additions and 1608 deletions

349
src/app/admin/page.tsx Normal file
View File

@@ -0,0 +1,349 @@
"use client";
import { useState } from "react";
import { ThemeProvider } from "@/providers/themeProvider/ThemeProvider";
import NavbarStyleCentered from "@/components/navbar/NavbarStyleCentered/NavbarStyleCentered";
import FooterBase from "@/components/sections/footer/FooterBase";
import { Users, Briefcase, BarChart3, ChevronDown, Plus, Trash2, Edit2 } from "lucide-react";
const navItems = [
{ name: "Dashboard", id: "/admin" },
{ name: "Jobs", id: "/admin" },
{ name: "Users", id: "/admin" },
{ name: "Analytics", id: "/admin" },
{ name: "Home", id: "/" },
];
const footerColumns = [
{
title: "Product", items: [
{ label: "Search Jobs", href: "/search" },
{ label: "Post a Job", href: "/post-job" },
{ label: "Browse by Province", href: "#provinces" },
{ label: "For Employers", href: "#" },
],
},
{
title: "Company", items: [
{ label: "About Jobee", href: "#about" },
{ label: "Careers", href: "#" },
{ label: "Contact Us", href: "#contact" },
{ label: "Blog", href: "#" },
],
},
{
title: "Resources", items: [
{ label: "Privacy Policy", href: "#" },
{ label: "Terms of Service", href: "#" },
{ label: "FAQ", href: "#" },
{ label: "Support", href: "#" },
],
},
];
interface Job {
id: string;
title: string;
company: string;
location: string;
status: "active" | "closed";
applications: number;
postedDate: string;
}
interface User {
id: string;
name: string;
email: string;
role: "job_seeker" | "employer";
joinDate: string;
status: "active" | "inactive";
}
interface AnalyticsData {
totalJobs: number;
totalUsers: number;
activeApplications: number;
successfulPlacements: number;
}
export default function AdminDashboard() {
const [activeTab, setActiveTab] = useState<"dashboard" | "jobs" | "users">("dashboard");
const [jobs, setJobs] = useState<Job[]>([
{
id: "1", title: "Senior React Developer", company: "TechCorp", location: "Amsterdam", status: "active", applications: 24,
postedDate: "2025-01-10"},
{
id: "2", title: "UX Designer", company: "DesignStudio", location: "Rotterdam", status: "active", applications: 18,
postedDate: "2025-01-08"},
{
id: "3", title: "Backend Engineer", company: "DataSystems", location: "Utrecht", status: "closed", applications: 42,
postedDate: "2024-12-20"},
]);
const [users, setUsers] = useState<User[]>([
{
id: "1", name: "Alice Johnson", email: "alice@example.com", role: "job_seeker", joinDate: "2024-11-15", status: "active"},
{
id: "2", name: "Bob Smith", email: "bob@example.com", role: "employer", joinDate: "2024-10-20", status: "active"},
{
id: "3", name: "Carol White", email: "carol@example.com", role: "job_seeker", joinDate: "2024-09-05", status: "inactive"},
]);
const [analytics] = useState<AnalyticsData>({
totalJobs: 156,
totalUsers: 3245,
activeApplications: 892,
successfulPlacements: 142,
});
const handleDeleteJob = (id: string) => {
setJobs(jobs.filter((job) => job.id !== id));
};
const handleDeleteUser = (id: string) => {
setUsers(users.filter((user) => user.id !== id));
};
return (
<ThemeProvider
defaultButtonVariant="text-stagger"
defaultTextAnimation="reveal-blur"
borderRadius="pill"
contentWidth="smallMedium"
sizing="mediumLargeSizeLargeTitles"
background="circleGradient"
cardStyle="gradient-radial"
primaryButtonStyle="double-inset"
secondaryButtonStyle="glass"
headingFontWeight="bold"
>
<div id="nav" data-section="nav">
<NavbarStyleCentered
brandName="Jobee Admin"
navItems={navItems}
button={{
text: "Logout", onClick: () => console.log("Logout"),
}}
/>
</div>
<div className="min-h-screen bg-gradient-to-b from-slate-50 to-slate-100 py-16 px-4">
<div className="max-w-7xl mx-auto">
{/* Header */}
<div className="mb-12">
<h1 className="text-4xl font-bold text-slate-900 mb-2">Admin Dashboard</h1>
<p className="text-slate-600">Manage jobs, users, and view analytics</p>
</div>
{/* Tab Navigation */}
<div className="flex gap-4 mb-8">
<button
onClick={() => setActiveTab("dashboard")}
className={`px-6 py-3 rounded-lg font-semibold transition-all ${
activeTab === "dashboard"
? "bg-blue-600 text-white shadow-lg"
: "bg-white text-slate-700 hover:bg-slate-100"
}`}
>
<BarChart3 className="inline mr-2" size={20} />
Dashboard
</button>
<button
onClick={() => setActiveTab("jobs")}
className={`px-6 py-3 rounded-lg font-semibold transition-all ${
activeTab === "jobs"
? "bg-blue-600 text-white shadow-lg"
: "bg-white text-slate-700 hover:bg-slate-100"
}`}
>
<Briefcase className="inline mr-2" size={20} />
Jobs ({jobs.length})
</button>
<button
onClick={() => setActiveTab("users")}
className={`px-6 py-3 rounded-lg font-semibold transition-all ${
activeTab === "users"
? "bg-blue-600 text-white shadow-lg"
: "bg-white text-slate-700 hover:bg-slate-100"
}`}
>
<Users className="inline mr-2" size={20} />
Users ({users.length})
</button>
</div>
{/* Dashboard Tab */}
{activeTab === "dashboard" && (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8">
<div className="bg-white rounded-lg p-6 shadow-md">
<div className="flex items-center justify-between">
<div>
<p className="text-slate-600 text-sm font-medium">Total Jobs</p>
<p className="text-3xl font-bold text-slate-900 mt-2">{analytics.totalJobs}</p>
</div>
<Briefcase className="text-blue-600" size={40} />
</div>
</div>
<div className="bg-white rounded-lg p-6 shadow-md">
<div className="flex items-center justify-between">
<div>
<p className="text-slate-600 text-sm font-medium">Total Users</p>
<p className="text-3xl font-bold text-slate-900 mt-2">{analytics.totalUsers}</p>
</div>
<Users className="text-green-600" size={40} />
</div>
</div>
<div className="bg-white rounded-lg p-6 shadow-md">
<div className="flex items-center justify-between">
<div>
<p className="text-slate-600 text-sm font-medium">Active Applications</p>
<p className="text-3xl font-bold text-slate-900 mt-2">{analytics.activeApplications}</p>
</div>
<ChevronDown className="text-purple-600" size={40} />
</div>
</div>
<div className="bg-white rounded-lg p-6 shadow-md">
<div className="flex items-center justify-between">
<div>
<p className="text-slate-600 text-sm font-medium">Successful Placements</p>
<p className="text-3xl font-bold text-slate-900 mt-2">{analytics.successfulPlacements}</p>
</div>
<BarChart3 className="text-orange-600" size={40} />
</div>
</div>
</div>
)}
{/* Jobs Tab */}
{activeTab === "jobs" && (
<div className="bg-white rounded-lg shadow-md overflow-hidden">
<div className="p-6 border-b border-slate-200 flex justify-between items-center">
<h2 className="text-2xl font-bold text-slate-900">Job Management</h2>
<button className="flex items-center gap-2 px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-all">
<Plus size={20} />
Add Job
</button>
</div>
<div className="overflow-x-auto">
<table className="w-full">
<thead className="bg-slate-50 border-b border-slate-200">
<tr>
<th className="px-6 py-3 text-left text-sm font-semibold text-slate-900">Title</th>
<th className="px-6 py-3 text-left text-sm font-semibold text-slate-900">Company</th>
<th className="px-6 py-3 text-left text-sm font-semibold text-slate-900">Location</th>
<th className="px-6 py-3 text-left text-sm font-semibold text-slate-900">Status</th>
<th className="px-6 py-3 text-left text-sm font-semibold text-slate-900">Applications</th>
<th className="px-6 py-3 text-left text-sm font-semibold text-slate-900">Actions</th>
</tr>
</thead>
<tbody>
{jobs.map((job) => (
<tr key={job.id} className="border-b border-slate-200 hover:bg-slate-50 transition-colors">
<td className="px-6 py-4 text-slate-900 font-medium">{job.title}</td>
<td className="px-6 py-4 text-slate-600">{job.company}</td>
<td className="px-6 py-4 text-slate-600">{job.location}</td>
<td className="px-6 py-4">
<span
className={`px-3 py-1 rounded-full text-sm font-medium ${
job.status === "active"
? "bg-green-100 text-green-800"
: "bg-red-100 text-red-800"
}`}
>
{job.status.charAt(0).toUpperCase() + job.status.slice(1)}
</span>
</td>
<td className="px-6 py-4 text-slate-600">{job.applications}</td>
<td className="px-6 py-4 flex gap-2">
<button className="p-2 text-blue-600 hover:bg-blue-50 rounded transition-colors">
<Edit2 size={18} />
</button>
<button
onClick={() => handleDeleteJob(job.id)}
className="p-2 text-red-600 hover:bg-red-50 rounded transition-colors"
>
<Trash2 size={18} />
</button>
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
)}
{/* Users Tab */}
{activeTab === "users" && (
<div className="bg-white rounded-lg shadow-md overflow-hidden">
<div className="p-6 border-b border-slate-200 flex justify-between items-center">
<h2 className="text-2xl font-bold text-slate-900">User Management</h2>
<button className="flex items-center gap-2 px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-all">
<Plus size={20} />
Add User
</button>
</div>
<div className="overflow-x-auto">
<table className="w-full">
<thead className="bg-slate-50 border-b border-slate-200">
<tr>
<th className="px-6 py-3 text-left text-sm font-semibold text-slate-900">Name</th>
<th className="px-6 py-3 text-left text-sm font-semibold text-slate-900">Email</th>
<th className="px-6 py-3 text-left text-sm font-semibold text-slate-900">Role</th>
<th className="px-6 py-3 text-left text-sm font-semibold text-slate-900">Join Date</th>
<th className="px-6 py-3 text-left text-sm font-semibold text-slate-900">Status</th>
<th className="px-6 py-3 text-left text-sm font-semibold text-slate-900">Actions</th>
</tr>
</thead>
<tbody>
{users.map((user) => (
<tr key={user.id} className="border-b border-slate-200 hover:bg-slate-50 transition-colors">
<td className="px-6 py-4 text-slate-900 font-medium">{user.name}</td>
<td className="px-6 py-4 text-slate-600">{user.email}</td>
<td className="px-6 py-4 text-slate-600">
<span className="capitalize">{user.role.replace("_", " ")}</span>
</td>
<td className="px-6 py-4 text-slate-600">{user.joinDate}</td>
<td className="px-6 py-4">
<span
className={`px-3 py-1 rounded-full text-sm font-medium ${
user.status === "active"
? "bg-green-100 text-green-800"
: "bg-gray-100 text-gray-800"
}`}
>
{user.status.charAt(0).toUpperCase() + user.status.slice(1)}
</span>
</td>
<td className="px-6 py-4 flex gap-2">
<button className="p-2 text-blue-600 hover:bg-blue-50 rounded transition-colors">
<Edit2 size={18} />
</button>
<button
onClick={() => handleDeleteUser(user.id)}
className="p-2 text-red-600 hover:bg-red-50 rounded transition-colors"
>
<Trash2 size={18} />
</button>
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
)}
</div>
</div>
<div id="footer" data-section="footer">
<FooterBase
logoText="Jobee"
copyrightText="© 2025 Jobee | Dutch Job Listing Platform"
columns={footerColumns}
/>
</div>
</ThemeProvider>
);
}

View File

@@ -0,0 +1,298 @@
"use client";
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";
const navItems = [
{ name: "Search Jobs", id: "search" },
{ name: "Post a Job", id: "/post-job" },
{ name: "Applications", id: "/applications" },
{ name: "Browse", id: "browse" },
{ name: "Contact", id: "contact" },
];
const footerColumns = [
{
title: "Product", items: [
{ label: "Search Jobs", href: "/search" },
{ label: "Post a Job", href: "/post-job" },
{ label: "My Applications", href: "/applications" },
{ label: "For Employers", href: "#" },
],
},
{
title: "Company", items: [
{ label: "About Jobee", href: "#about" },
{ label: "Careers", href: "#" },
{ label: "Contact Us", href: "#contact" },
{ label: "Blog", href: "#" },
],
},
{
title: "Resources", items: [
{ label: "Privacy Policy", href: "#" },
{ label: "Terms of Service", href: "#" },
{ label: "FAQ", href: "#" },
{ label: "Support", href: "#" },
],
},
];
interface Application {
id: string;
jobTitle: string;
company: string;
status: "pending" | "reviewing" | "accepted" | "rejected";
appliedDate: string;
lastUpdate: string;
applicantName: string;
email: string;
appliedPosition?: string;
}
const mockApplications: Application[] = [
{
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: "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: "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: "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: "Backend Developer", company: "Cloud Systems Ltd", status: "reviewing", appliedDate: "2025-01-12", lastUpdate: "2025-01-19", applicantName: "Charlie Brown", email: "charlie.brown@example.com"},
];
export default function ApplicationsPage() {
const [applications, setApplications] = useState<Application[]>(mockApplications);
const [filterStatus, setFilterStatus] = useState<string>("all");
const [selectedApp, setSelectedApp] = useState<Application | null>(null);
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
defaultButtonVariant="text-stagger"
defaultTextAnimation="reveal-blur"
borderRadius="pill"
contentWidth="smallMedium"
sizing="mediumLargeSizeLargeTitles"
background="circleGradient"
cardStyle="gradient-radial"
primaryButtonStyle="double-inset"
secondaryButtonStyle="glass"
headingFontWeight="bold"
>
<div id="nav" data-section="nav">
<NavbarStyleCentered
brandName="Jobee"
navItems={navItems}
button={{
text: "Post a Job", href: "/post-job"}}
/>
</div>
<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">
<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>
<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>
</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>
{/* 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>
) : (
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>
</div>
))
)}
</div>
</div>
{/* 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
logoText="Jobee"
copyrightText="© 2025 Jobee | Dutch Job Listing Platform"
columns={footerColumns}
/>
</div>
</ThemeProvider>
);
}

380
src/app/jobs/page.tsx Normal file
View File

@@ -0,0 +1,380 @@
"use client";
import { useState } from "react";
import { ThemeProvider } from "@/providers/themeProvider/ThemeProvider";
import NavbarStyleCentered from "@/components/navbar/NavbarStyleCentered/NavbarStyleCentered";
import FooterBase from "@/components/sections/footer/FooterBase";
import { MapPin, DollarSign, Briefcase, Heart } from "lucide-react";
const navItems = [
{ name: "Search Jobs", id: "/search" },
{ name: "Post a Job", id: "/post-job" },
{ name: "Admin", id: "/admin-login" },
{ name: "Browse", id: "browse" },
{ name: "Contact", id: "contact" },
];
const footerColumns = [
{
title: "Product", items: [
{ label: "Search Jobs", href: "/search" },
{ label: "Post a Job", href: "/post-job" },
{ label: "Browse by Province", href: "#provinces" },
{ label: "For Employers", href: "#" },
],
},
{
title: "Company", items: [
{ label: "About Jobee", href: "#about" },
{ label: "Careers", href: "#" },
{ label: "Contact Us", href: "#contact" },
{ label: "Blog", href: "#" },
],
},
{
title: "Resources", items: [
{ label: "Privacy Policy", href: "#" },
{ label: "Terms of Service", href: "#" },
{ label: "FAQ", href: "#" },
{ label: "Support", href: "#" },
],
},
];
const mockJobs = [
{
id: "1", title: "Senior Software Engineer", company: "TechCorp Amsterdam", location: "Amsterdam", province: "North Holland", salary: "€80,000 - €120,000", salaryMin: 80000,
salaryMax: 120000,
jobType: "Full-time", category: "Technology", description:
"Join our innovative team as a Senior Software Engineer. We\'re looking for experienced developers with expertise in React, Node.js, and cloud technologies.", fullDescription:
"Join our innovative team as a Senior Software Engineer. We\'re looking for experienced developers with expertise in React, Node.js, and cloud technologies. This role offers the opportunity to work on cutting-edge projects, mentor junior developers, and contribute to architectural decisions.", requirements: [
"5+ years of software development experience", "Proficiency in React, Node.js, and TypeScript", "Experience with cloud platforms (AWS, GCP, Azure)", "Strong understanding of software design patterns", "Excellent communication skills"],
benefits: [
"Competitive salary and bonus structure", "Health insurance and wellness programs", "Flexible working hours and remote work options", "Professional development opportunities", "Modern office in Amsterdam city center"],
logo: "http://img.b2bpic.net/free-vector/tech-company-logo_23-2148947635.jpg", postedDate: "2 days ago"},
{
id: "2", title: "Marketing Manager", company: "Creative Solutions Rotterdam", location: "Rotterdam", province: "South Holland", salary: "€60,000 - €85,000", salaryMin: 60000,
salaryMax: 85000,
jobType: "Full-time", category: "Marketing", description:
"Lead our marketing initiatives and drive brand growth. We seek a strategic marketer with experience in digital marketing and campaign management.", fullDescription:
"Lead our marketing initiatives and drive brand growth. We seek a strategic marketer with experience in digital marketing and campaign management. You\'ll oversee a team of marketing professionals and develop comprehensive marketing strategies to achieve business objectives.", requirements: [
"7+ years of marketing management experience", "Proven track record in digital marketing campaigns", "Strong analytical and data-driven decision making", "Leadership and team management experience", "Proficiency in marketing automation tools"],
benefits: [
"Competitive salary package", "Team leadership opportunities", "Conference and training budget", "Flexible working arrangement", "Performance-based bonuses"],
logo: "http://img.b2bpic.net/free-vector/marketing-logo_23-2148947635.jpg", postedDate: "5 days ago"},
{
id: "3", title: "Data Scientist", company: "Analytics Pro Utrecht", location: "Utrecht", province: "Utrecht", salary: "€70,000 - €110,000", salaryMin: 70000,
salaryMax: 110000,
jobType: "Full-time", category: "Data Science", description:
"Develop advanced analytics solutions for our global clients. Expertise in Python, machine learning, and big data technologies required.", fullDescription:
"Develop advanced analytics solutions for our global clients. Expertise in Python, machine learning, and big data technologies required. Work on complex data challenges, build predictive models, and transform raw data into actionable insights.", requirements: [
"Advanced degree in Computer Science, Mathematics, or related field", "Proficiency in Python and machine learning libraries", "Experience with big data technologies (Spark, Hadoop)", "Strong SQL and database knowledge", "Experience with data visualization tools"],
benefits: [
"Excellent salary and benefits", "State-of-the-art computing resources", "Continuous learning opportunities", "Collaborative research environment", "Publication opportunities"],
logo: "http://img.b2bpic.net/free-vector/analytics-logo_23-2148947635.jpg", postedDate: "1 week ago"},
{
id: "4", title: "UX/UI Designer", company: "Design Studios The Hague", location: "The Hague", province: "South Holland", salary: "€55,000 - €75,000", salaryMin: 55000,
salaryMax: 75000,
jobType: "Full-time", category: "Design", description:
"Create beautiful and intuitive user experiences for our web and mobile applications. Portfolio required.", fullDescription:
"Create beautiful and intuitive user experiences for our web and mobile applications. Portfolio required. Collaborate with product teams, conduct user research, and iterate on designs based on user feedback and analytics.", requirements: [
"4+ years of UX/UI design experience", "Proficiency in design tools (Figma, Adobe XD)", "Strong portfolio showcasing design work", "Understanding of user research and testing methodologies", "Knowledge of responsive design principles"],
benefits: [
"Creative and collaborative work environment", "Access to latest design tools and technologies", "Design conference attendance budget", "Flexible work schedule", "Health and wellness benefits"],
logo: "http://img.b2bpic.net/free-vector/design-logo_23-2148947635.jpg", postedDate: "3 days ago"},
{
id: "5", title: "Sales Executive", company: "Enterprise Solutions Groningen", location: "Groningen", province: "Groningen", salary: "€45,000 - €70,000", salaryMin: 45000,
salaryMax: 70000,
jobType: "Full-time", category: "Sales", description:
"Grow our sales pipeline and build strong client relationships. Commission and bonus structure available.", fullDescription:
"Grow our sales pipeline and build strong client relationships. Commission and bonus structure available. Manage a portfolio of accounts, identify new business opportunities, and achieve sales targets.", requirements: [
"3+ years of B2B sales experience", "Strong negotiation and closing skills", "CRM software proficiency", "Excellent communication abilities", "Self-motivated and target-driven"],
benefits: [
"Competitive base salary plus commission", "Performance bonuses", "Sales training and development", "Company car or allowance", "International travel opportunities"],
logo: "http://img.b2bpic.net/free-vector/sales-logo_23-2148947635.jpg", postedDate: "4 days ago"},
{
id: "6", title: "HR Specialist", company: "People First Leiden", location: "Leiden", province: "South Holland", salary: "€50,000 - €65,000", salaryMin: 50000,
salaryMax: 65000,
jobType: "Part-time", category: "Human Resources", description:
"Support our HR team in recruitment, onboarding, and employee development initiatives.", fullDescription:
"Support our HR team in recruitment, onboarding, and employee development initiatives. Handle administrative HR tasks, coordinate interviews, and support employee relations.", requirements: [
"3+ years of HR experience", "Knowledge of Dutch employment law", "Proficiency in HR management systems", "Strong organizational skills", "Excellent interpersonal abilities"],
benefits: [
"Competitive part-time salary", "Flexible working hours", "Professional HR certifications support", "Health insurance", "Staff development programs"],
logo: "http://img.b2bpic.net/free-vector/hr-logo_23-2148947635.jpg", postedDate: "1 week ago"},
{
id: "7", title: "DevOps Engineer", company: "Cloud Innovations Eindhoven", location: "Eindhoven", province: "North Brabant", salary: "€75,000 - €105,000", salaryMin: 75000,
salaryMax: 105000,
jobType: "Full-time", category: "Technology", description:
"Manage and optimize our cloud infrastructure. Experience with Docker, Kubernetes, and CI/CD pipelines required.", fullDescription:
"Manage and optimize our cloud infrastructure. Experience with Docker, Kubernetes, and CI/CD pipelines required. Build and maintain deployment pipelines, monitor system performance, and implement security best practices.", requirements: [
"5+ years of DevOps experience", "Expert knowledge of Docker and Kubernetes", "CI/CD pipeline implementation experience", "Strong Linux administration skills", "Cloud platform experience (AWS/GCP/Azure)"],
benefits: [
"High competitive salary", "Remote work options", "Technical certification support", "Modern tech stack", "Collaborative engineering team"],
logo: "http://img.b2bpic.net/free-vector/devops-logo_23-2148947635.jpg", postedDate: "6 days ago"},
{
id: "8", title: "Product Manager", company: "Innovation Lab Delft", location: "Delft", province: "South Holland", salary: "€70,000 - €95,000", salaryMin: 70000,
salaryMax: 95000,
jobType: "Full-time", category: "Product", description:
"Lead product strategy and roadmap development for our SaaS platform. Experience with agile methodologies required.", fullDescription:
"Lead product strategy and roadmap development for our SaaS platform. Experience with agile methodologies required. Work cross-functionally with engineering, design, and marketing teams to deliver customer-centric solutions.", requirements: [
"5+ years of product management experience", "Expertise in SaaS business models", "Proficiency in product management tools", "Strong analytical skills", "Experience with agile and Scrum methodologies"],
benefits: [
"Attractive salary and equity", "Leadership development programs", "Industry conference attendance", "Flexible work arrangement", "Collaborative innovation environment"],
logo: "http://img.b2bpic.net/free-vector/product-logo_23-2148947635.jpg", postedDate: "2 days ago"},
];
interface JobCardProps {
job: (typeof mockJobs)[0];
isFavorited: boolean;
onFavorite: (id: string) => void;
onClick: () => void;
}
function JobCard({ job, isFavorited, onFavorite, onClick }: JobCardProps) {
return (
<div
onClick={onClick}
className="p-6 rounded-xl bg-card border border-accent/20 hover:border-accent/50 transition-all duration-300 hover:shadow-lg cursor-pointer group"
>
<div className="flex items-start justify-between mb-4">
<div className="flex items-start gap-4 flex-1">
<div className="w-16 h-16 rounded-lg bg-gradient-to-br from-primary-cta to-secondary-cta flex items-center justify-center text-white font-bold text-xl flex-shrink-0 group-hover:shadow-lg transition-shadow">
{job.company.charAt(0)}
</div>
<div className="flex-1">
<h3 className="text-xl font-bold text-foreground mb-1 group-hover:text-primary-cta transition-colors">
{job.title}
</h3>
<p className="text-sm text-foreground/70 mb-2">{job.company}</p>
<div className="flex items-center gap-4 text-sm text-foreground/60">
<div className="flex items-center gap-1">
<MapPin size={16} />
{job.location}
</div>
<div className="flex items-center gap-1">
<Briefcase size={16} />
{job.jobType}
</div>
</div>
</div>
</div>
<button
onClick={(e) => {
e.stopPropagation();
onFavorite(job.id);
}}
className="p-2 rounded-full hover:bg-accent/10 transition-colors flex-shrink-0"
>
<Heart
size={20}
className={isFavorited ? "fill-primary-cta text-primary-cta" : "text-foreground/50"}
/>
</button>
</div>
<p className="text-sm text-foreground/70 mb-4 line-clamp-2">
{job.description}
</p>
<div className="flex items-center justify-between">
<div className="flex gap-2 items-center">
<span className="inline-block px-3 py-1 rounded-lg text-xs bg-background text-foreground/70">
{job.category}
</span>
<span className="text-sm font-semibold text-primary-cta flex items-center gap-1">
<DollarSign size={14} />
{job.salary}
</span>
</div>
<button className="px-4 py-2 rounded-full bg-primary-cta text-white font-semibold hover:opacity-90 transition-opacity text-sm">
Apply Now
</button>
</div>
</div>
);
}
export default function JobListingPage() {
const [selectedJob, setSelectedJob] = useState<(typeof mockJobs)[0] | null>(null);
const [favorites, setFavorites] = useState<Set<string>>(new Set());
const handleFavorite = (jobId: string) => {
const newFavorites = new Set(favorites);
if (newFavorites.has(jobId)) {
newFavorites.delete(jobId);
} else {
newFavorites.add(jobId);
}
setFavorites(newFavorites);
};
return (
<ThemeProvider
defaultButtonVariant="text-stagger"
defaultTextAnimation="reveal-blur"
borderRadius="pill"
contentWidth="smallMedium"
sizing="mediumLargeSizeLargeTitles"
background="circleGradient"
cardStyle="gradient-radial"
primaryButtonStyle="double-inset"
secondaryButtonStyle="glass"
headingFontWeight="bold"
>
<div id="nav" data-section="nav">
<NavbarStyleCentered
brandName="Jobee"
navItems={navItems}
button={{
text: "Post a Job", href: "/post-job"}}
/>
</div>
<div className="min-h-screen bg-gradient-to-b from-background to-background-accent pt-20 pb-20">
<div className="max-w-7xl mx-auto px-4">
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
{/* Job Listings Column */}
<div className="lg:col-span-2">
<div className="mb-8">
<h1 className="text-4xl md:text-5xl font-bold text-foreground mb-2">
Latest Job Listings
</h1>
<p className="text-lg text-foreground/70">
{mockJobs.length} positions available
</p>
</div>
<div className="space-y-4">
{mockJobs.map((job) => (
<JobCard
key={job.id}
job={job}
isFavorited={favorites.has(job.id)}
onFavorite={handleFavorite}
onClick={() => setSelectedJob(job)}
/>
))}
</div>
</div>
{/* Job Details Column */}
<div className="lg:col-span-1">
{selectedJob ? (
<div className="sticky top-28 p-6 rounded-xl bg-card border border-accent/20">
<div className="mb-6">
<div className="w-20 h-20 rounded-lg bg-gradient-to-br from-primary-cta to-secondary-cta flex items-center justify-center text-white font-bold text-2xl mb-4">
{selectedJob.company.charAt(0)}
</div>
<h2 className="text-2xl font-bold text-foreground mb-2">
{selectedJob.title}
</h2>
<p className="text-foreground/70 mb-4">{selectedJob.company}</p>
<p className="text-2xl font-bold text-primary-cta mb-4">
{selectedJob.salary}
</p>
<button
onClick={(e) => {
e.stopPropagation();
handleFavorite(selectedJob.id);
}}
className="w-full py-3 rounded-full bg-primary-cta/10 text-primary-cta font-semibold hover:bg-primary-cta/20 transition-colors flex items-center justify-center gap-2 mb-3"
>
<Heart
size={18}
className={favorites.has(selectedJob.id) ? "fill-primary-cta" : ""}
/>
{favorites.has(selectedJob.id) ? "Saved" : "Save Job"}
</button>
<button className="w-full py-3 rounded-full bg-primary-cta text-white font-semibold hover:opacity-90 transition-opacity">
Apply Now
</button>
</div>
<div className="border-t border-accent/20 pt-6">
<h3 className="text-lg font-bold text-foreground mb-4">
Job Details
</h3>
<div className="space-y-3 text-sm">
<div>
<p className="text-foreground/60 mb-1">Posted</p>
<p className="text-foreground font-semibold">
{selectedJob.postedDate}
</p>
</div>
<div>
<p className="text-foreground/60 mb-1">Location</p>
<p className="text-foreground font-semibold">
{selectedJob.location}, {selectedJob.province}
</p>
</div>
<div>
<p className="text-foreground/60 mb-1">Job Type</p>
<p className="text-foreground font-semibold">
{selectedJob.jobType}
</p>
</div>
<div>
<p className="text-foreground/60 mb-1">Category</p>
<p className="text-foreground font-semibold">
{selectedJob.category}
</p>
</div>
</div>
</div>
<div className="border-t border-accent/20 pt-6 mt-6">
<h3 className="text-lg font-bold text-foreground mb-4">
Requirements
</h3>
<ul className="space-y-2 text-sm">
{selectedJob.requirements.map((req, idx) => (
<li key={idx} className="flex gap-3 text-foreground/70">
<span className="text-primary-cta font-bold flex-shrink-0">
</span>
<span>{req}</span>
</li>
))}
</ul>
</div>
<div className="border-t border-accent/20 pt-6 mt-6">
<h3 className="text-lg font-bold text-foreground mb-4">
Benefits
</h3>
<ul className="space-y-2 text-sm">
{selectedJob.benefits.map((benefit, idx) => (
<li key={idx} className="flex gap-3 text-foreground/70">
<span className="text-primary-cta font-bold flex-shrink-0">
</span>
<span>{benefit}</span>
</li>
))}
</ul>
</div>
</div>
) : (
<div className="sticky top-28 p-6 rounded-xl bg-card border border-accent/20 border-dashed text-center">
<p className="text-foreground/60">
Select a job to view full details
</p>
</div>
)}
</div>
</div>
</div>
</div>
<div id="footer" data-section="footer">
<FooterBase
logoText="Jobee"
copyrightText="© 2025 Jobee | Dutch Job Listing Platform"
columns={footerColumns}
/>
</div>
</ThemeProvider>
);
}

File diff suppressed because it is too large Load Diff

View File

@@ -12,7 +12,7 @@ import { Briefcase, Sparkles, Mail, Quote } from "lucide-react";
const navItems = [ const navItems = [
{ name: "Search Jobs", id: "search" }, { name: "Search Jobs", id: "search" },
{ name: "Post a Job", id: "post-job" }, { name: "Post a Job", id: "post-job" },
{ name: "Admin", id: "admin-login" }, { name: "Admin", id: "/admin" },
{ name: "Browse", id: "browse" }, { name: "Browse", id: "browse" },
{ name: "Contact", id: "contact" }, { name: "Contact", id: "contact" },
]; ];
@@ -63,7 +63,8 @@ export default function HomePage() {
brandName="Jobee" brandName="Jobee"
navItems={navItems} navItems={navItems}
button={{ button={{
text: "Post a Job", href: "/post-job"}} text: "Post a Job", href: "/post-job"
}}
/> />
</div> </div>
@@ -75,40 +76,43 @@ export default function HomePage() {
tagIcon={Briefcase} tagIcon={Briefcase}
tagAnimation="slide-up" tagAnimation="slide-up"
background={{ background={{
variant: "animated-grid"}} variant: "animated-grid"
}}
leftCarouselItems={[ leftCarouselItems={[
{ {
imageSrc: imageSrc: "http://img.b2bpic.net/free-vector/professional-bookkeeping-postcard-template_23-2149341358.jpg?_wi=1", imageAlt: "Job Listing Card Design"
"http://img.b2bpic.net/free-vector/professional-bookkeeping-postcard-template_23-2149341358.jpg?_wi=1", imageAlt: "Job Listing Card Design"}, },
{ {
imageSrc: imageSrc: "http://img.b2bpic.net/free-photo/homepage-concept-with-search-bar_23-2150040187.jpg?_wi=1", imageAlt: "Advanced Search Filter Interface"
"http://img.b2bpic.net/free-photo/homepage-concept-with-search-bar_23-2150040187.jpg?_wi=1", imageAlt: "Advanced Search Filter Interface"}, },
{ {
imageSrc: imageSrc: "http://img.b2bpic.net/free-vector/professional-recruitment-plan-diversity-general-infographic-template_23-2148947635.jpg?_wi=1", imageAlt: "Admin Dashboard Management"
"http://img.b2bpic.net/free-vector/professional-recruitment-plan-diversity-general-infographic-template_23-2148947635.jpg?_wi=1", imageAlt: "Admin Dashboard Management"}, },
{ {
imageSrc: imageSrc: "http://img.b2bpic.net/free-photo/personal-information-form-identity-concept_53876-137622.jpg?_wi=1", imageAlt: "Application Process Flow"
"http://img.b2bpic.net/free-photo/personal-information-form-identity-concept_53876-137622.jpg?_wi=1", imageAlt: "Application Process Flow"}, },
]} ]}
rightCarouselItems={[ rightCarouselItems={[
{ {
imageSrc: imageSrc: "http://img.b2bpic.net/free-photo/corporate-workers-brainstorming-together_23-2148804568.jpg?_wi=1", imageAlt: "Professional Job Search Workspace"
"http://img.b2bpic.net/free-photo/corporate-workers-brainstorming-together_23-2148804568.jpg?_wi=1", imageAlt: "Professional Job Search Workspace"}, },
{ {
imageSrc: imageSrc: "http://img.b2bpic.net/free-photo/personal-information-form-identity-concept_53876-137622.jpg?_wi=2", imageAlt: "Recruitment Application Steps"
"http://img.b2bpic.net/free-photo/personal-information-form-identity-concept_53876-137622.jpg?_wi=2", imageAlt: "Recruitment Application Steps"}, },
{ {
imageSrc: imageSrc: "http://img.b2bpic.net/free-vector/professional-recruitment-plan-diversity-general-infographic-template_23-2148947635.jpg?_wi=2", imageAlt: "Recruitment Analytics Dashboard"
"http://img.b2bpic.net/free-vector/professional-recruitment-plan-diversity-general-infographic-template_23-2148947635.jpg?_wi=2", imageAlt: "Recruitment Analytics Dashboard"}, },
{ {
imageSrc: imageSrc: "http://img.b2bpic.net/free-photo/homepage-concept-with-search-bar_23-2150040187.jpg?_wi=2", imageAlt: "Job Search Filter Options"
"http://img.b2bpic.net/free-photo/homepage-concept-with-search-bar_23-2150040187.jpg?_wi=2", imageAlt: "Job Search Filter Options"}, },
]} ]}
buttons={[ buttons={[
{ {
text: "Start Searching", href: "/search"}, text: "Start Searching", href: "/search"
},
{ {
text: "Post a Job", href: "/post-job"}, text: "Post a Job", href: "/post-job"
},
]} ]}
buttonAnimation="slide-up" buttonAnimation="slide-up"
carouselPosition="right" carouselPosition="right"
@@ -127,28 +131,25 @@ export default function HomePage() {
features={[ features={[
{ {
id: 1, id: 1,
title: "Search & Filter", description: title: "Search & Filter", description: "Browse thousands of jobs across all Dutch provinces with advanced filtering by location, salary, job type, and category.", imageSrc: "http://img.b2bpic.net/free-photo/homepage-concept-with-search-bar_23-2150040187.jpg?_wi=3", imageAlt: "Advanced search interface"
"Browse thousands of jobs across all Dutch provinces with advanced filtering by location, salary, job type, and category.", imageSrc: },
"http://img.b2bpic.net/free-photo/homepage-concept-with-search-bar_23-2150040187.jpg?_wi=3", imageAlt: "Advanced search interface"},
{ {
id: 2, id: 2,
title: "Apply Easily", description: title: "Apply Easily", description: "Submit your application with your resume, cover letter, and personal information in just minutes.", imageSrc: "http://img.b2bpic.net/free-photo/personal-information-form-identity-concept_53876-137622.jpg?_wi=3", imageAlt: "Application form process"
"Submit your application with your resume, cover letter, and personal information in just minutes.", imageSrc: },
"http://img.b2bpic.net/free-photo/personal-information-form-identity-concept_53876-137622.jpg?_wi=3", imageAlt: "Application form process"},
{ {
id: 3, id: 3,
title: "Connect with Employers", description: title: "Connect with Employers", description: "Get matched with top Dutch companies actively hiring and receive direct opportunities from recruiters.", imageSrc: "http://img.b2bpic.net/free-photo/corporate-workers-brainstorming-together_23-2148804568.jpg?_wi=2", imageAlt: "Professional networking"
"Get matched with top Dutch companies actively hiring and receive direct opportunities from recruiters.", imageSrc: },
"http://img.b2bpic.net/free-photo/corporate-workers-brainstorming-together_23-2148804568.jpg?_wi=2", imageAlt: "Professional networking"},
{ {
id: 4, id: 4,
title: "Land Your Dream Job", description: title: "Land Your Dream Job", description: "Track your applications, receive updates, and secure your next career opportunity with confidence.", imageSrc: "http://img.b2bpic.net/free-vector/professional-recruitment-plan-diversity-general-infographic-template_23-2148947635.jpg?_wi=3", imageAlt: "Dashboard tracking"
"Track your applications, receive updates, and secure your next career opportunity with confidence.", imageSrc: },
"http://img.b2bpic.net/free-vector/professional-recruitment-plan-diversity-general-infographic-template_23-2148947635.jpg?_wi=3", imageAlt: "Dashboard tracking"},
]} ]}
buttons={[ buttons={[
{ {
text: "Browse Jobs", href: "/search"}, text: "Browse Jobs", href: "/search"
},
]} ]}
buttonAnimation="slide-up" buttonAnimation="slide-up"
/> />
@@ -166,21 +167,17 @@ export default function HomePage() {
animationType="slide-up" animationType="slide-up"
testimonials={[ testimonials={[
{ {
id: "1", name: "Sarah van der Berg", role: "Software Developer", testimonial: id: "1", name: "Sarah van der Berg", role: "Software Developer", testimonial: "I found my perfect job within 2 weeks using Jobee. The search filters made it easy to find remote opportunities in Amsterdam that matched my skill set.", imageSrc: "http://img.b2bpic.net/free-photo/front-view-smiley-man-posing_23-2150171293.jpg?_wi=1", imageAlt: "Sarah van der Berg"
"I found my perfect job within 2 weeks using Jobee. The search filters made it easy to find remote opportunities in Amsterdam that matched my skill set.", imageSrc: },
"http://img.b2bpic.net/free-photo/front-view-smiley-man-posing_23-2150171293.jpg?_wi=1", imageAlt: "Sarah van der Berg"},
{ {
id: "2", name: "Jan Pieterzoon", role: "HR Manager", testimonial: id: "2", name: "Jan Pieterzoon", role: "HR Manager", testimonial: "As a recruiter, Jobee has revolutionized how we post jobs and connect with talented candidates across the Netherlands. The platform is intuitive and effective.", imageSrc: "http://img.b2bpic.net/free-photo/smiling-face-gorgeous-latin-american-woman_1262-5766.jpg?_wi=1", imageAlt: "Jan Pieterzoon"
"As a recruiter, Jobee has revolutionized how we post jobs and connect with talented candidates across the Netherlands. The platform is intuitive and effective.", imageSrc: },
"http://img.b2bpic.net/free-photo/smiling-face-gorgeous-latin-american-woman_1262-5766.jpg?_wi=1", imageAlt: "Jan Pieterzoon"},
{ {
id: "3", name: "Emma Dijkstra", role: "Marketing Specialist", testimonial: id: "3", name: "Emma Dijkstra", role: "Marketing Specialist", testimonial: "The application process on Jobee is so smooth. I applied for 5 positions and received 3 interview invitations within a week. Highly recommended!", imageSrc: "http://img.b2bpic.net/free-photo/smiling-senior-businessman-pointing-with-finger_1262-3108.jpg?_wi=1", imageAlt: "Emma Dijkstra"
"The application process on Jobee is so smooth. I applied for 5 positions and received 3 interview invitations within a week. Highly recommended!", imageSrc: },
"http://img.b2bpic.net/free-photo/smiling-senior-businessman-pointing-with-finger_1262-3108.jpg?_wi=1", imageAlt: "Emma Dijkstra"},
{ {
id: "4", name: "Michael Houtstra", role: "Finance Director", testimonial: id: "4", name: "Michael Houtstra", role: "Finance Director", testimonial: "We've hired 12 excellent team members through Jobee in the past year. The quality of candidates is outstanding and the platform is incredibly easy to use.", imageSrc: "http://img.b2bpic.net/free-photo/studio-portrait-elegant-black-american-male-dressed-suit-grey-vignette-background_613910-9543.jpg?_wi=1", imageAlt: "Michael Houtstra"
"We've hired 12 excellent team members through Jobee in the past year. The quality of candidates is outstanding and the platform is incredibly easy to use.", imageSrc: },
"http://img.b2bpic.net/free-photo/studio-portrait-elegant-black-american-male-dressed-suit-grey-vignette-background_613910-9543.jpg?_wi=1", imageAlt: "Michael Houtstra"},
]} ]}
buttonAnimation="slide-up" buttonAnimation="slide-up"
/> />
@@ -194,7 +191,8 @@ export default function HomePage() {
tagIcon={Mail} tagIcon={Mail}
tagAnimation="slide-up" tagAnimation="slide-up"
background={{ background={{
variant: "animated-grid"}} variant: "animated-grid"
}}
useInvertedBackground={false} useInvertedBackground={false}
inputPlaceholder="Enter your email address" inputPlaceholder="Enter your email address"
buttonText="Subscribe" buttonText="Subscribe"

View File

@@ -2,47 +2,70 @@
import { ThemeProvider } from "@/providers/themeProvider/ThemeProvider"; import { ThemeProvider } from "@/providers/themeProvider/ThemeProvider";
import NavbarStyleCentered from "@/components/navbar/NavbarStyleCentered/NavbarStyleCentered"; import NavbarStyleCentered from "@/components/navbar/NavbarStyleCentered/NavbarStyleCentered";
import FeatureCardEight from "@/components/sections/feature/FeatureCardEight";
import ContactCenter from "@/components/sections/contact/ContactCenter";
import FooterBase from "@/components/sections/footer/FooterBase"; import FooterBase from "@/components/sections/footer/FooterBase";
import Link from "next/link"; import { Briefcase, Mail } from "lucide-react";
import { Briefcase, Mail, MapPin, Sparkles } from "lucide-react"; import { useState } from "react";
const navItems = [
{ name: "Search Jobs", id: "search" },
{ name: "Post a Job", id: "/post-job" },
{ name: "Applications", id: "/applications" },
{ name: "Browse", id: "browse" },
{ name: "Contact", id: "contact" },
];
const footerColumns = [
{
title: "Product", items: [
{ label: "Search Jobs", href: "/search" },
{ label: "Post a Job", href: "/post-job" },
{ label: "My Applications", href: "/applications" },
{ label: "For Employers", href: "#" },
],
},
{
title: "Company", items: [
{ label: "About Jobee", href: "#about" },
{ label: "Careers", href: "#" },
{ label: "Contact Us", href: "#contact" },
{ label: "Blog", href: "#" },
],
},
{
title: "Resources", items: [
{ label: "Privacy Policy", href: "#" },
{ label: "Terms of Service", href: "#" },
{ label: "FAQ", href: "#" },
{ label: "Support", href: "#" },
],
},
];
export default function PostJobPage() { export default function PostJobPage() {
const navItems = [ const [formData, setFormData] = useState({
{ name: "Search Jobs", id: "search" }, jobTitle: "", company: "", location: "", province: "", jobType: "Full-Time", salaryRange: "", description: "", requirements: "", contactEmail: "", benefits: ""});
{ name: "Post a Job", id: "post-job" },
{ name: "Admin", id: "admin-login" },
{ name: "Browse", id: "browse" },
{ name: "Contact", id: "contact" },
];
const footerColumns = [ const [submitted, setSubmitted] = useState(false);
{
title: "Product", items: [ const handleChange = (
{ label: "Search Jobs", href: "/search" }, e: React.ChangeEvent<
{ label: "Post a Job", href: "/post-job" }, HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement
{ label: "Browse by Province", href: "#provinces" }, >
{ label: "For Employers", href: "#" }, ) => {
], const { name, value } = e.target;
}, setFormData((prev) => ({ ...prev, [name]: value }));
{ };
title: "Company", items: [
{ label: "About Jobee", href: "#about" }, const handleSubmit = (e: React.FormEvent) => {
{ label: "Careers", href: "#" }, e.preventDefault();
{ label: "Contact Us", href: "#contact" }, console.log("Job Posted:", formData);
{ label: "Blog", href: "#" }, setSubmitted(true);
], setTimeout(() => {
}, setFormData({
{ jobTitle: "", company: "", location: "", province: "", jobType: "Full-Time", salaryRange: "", description: "", requirements: "", contactEmail: "", benefits: ""});
title: "Resources", items: [ setSubmitted(false);
{ label: "Privacy Policy", href: "#" }, }, 2000);
{ label: "Terms of Service", href: "#" }, };
{ label: "FAQ", href: "#" },
{ label: "Support", href: "#" },
],
},
];
return ( return (
<ThemeProvider <ThemeProvider
@@ -59,63 +82,263 @@ export default function PostJobPage() {
> >
<div id="nav" data-section="nav"> <div id="nav" data-section="nav">
<NavbarStyleCentered <NavbarStyleCentered
navItems={navItems}
button={{ text: "Post a Job", href: "/post-job" }}
brandName="Jobee" brandName="Jobee"
navItems={navItems}
button={{
text: "Post a Job", href: "/post-job"}}
/> />
</div> </div>
<div id="features" data-section="features"> <div className="min-h-screen bg-gradient-to-b from-slate-50 to-slate-100 pt-32 pb-20">
<FeatureCardEight <div className="max-w-2xl mx-auto px-4">
features={[ <div className="mb-8">
{ <div className="flex items-center gap-3 mb-4">
id: 1, <Briefcase className="w-6 h-6 text-blue-600" />
title: "Create a Job Posting", description: <span className="text-sm font-semibold text-blue-600 uppercase tracking-wide">
"Fill in job details, requirements, and salary information. Our intuitive form guides you through every step to create a compelling job listing.", imageSrc: Post Your Job
"http://img.b2bpic.net/free-vector/professional-recruitment-plan-diversity-general-infographic-template_23-2148947635.jpg?_wi=4", imageAlt: "Job posting creation interface"}, </span>
{ </div>
id: 2, <h1 className="text-4xl md:text-5xl font-bold text-slate-900 mb-3">
title: "Reach Qualified Candidates", description: Create Your Job Listing
"Your job posting is automatically distributed across our network of active job seekers across all 12 Dutch provinces.", imageSrc: </h1>
"http://img.b2bpic.net/free-photo/homepage-concept-with-search-bar_23-2150040187.jpg?_wi=5", imageAlt: "Candidate reach visualization"}, <p className="text-lg text-slate-600">
{ Fill in the details below to post your job opening and reach qualified candidates
id: 3, across the Netherlands.
title: "Review Applications", description: </p>
"Manage all incoming applications in one centralized dashboard. Review resumes, cover letters, and candidate profiles easily.", imageSrc: </div>
"http://img.b2bpic.net/free-photo/personal-information-form-identity-concept_53876-137622.jpg?_wi=4", imageAlt: "Application review dashboard"},
]}
title="Post a Job in Three Easy Steps"
description="Reach thousands of qualified job seekers across the Netherlands and build your dream team."
tag="Simple Process"
tagIcon={Sparkles}
tagAnimation="slide-up"
textboxLayout="default"
useInvertedBackground={false}
buttons={[{ text: "Start Posting", href: "/post-job" }]}
buttonAnimation="slide-up"
/>
</div>
<div id="contact" data-section="contact"> {submitted && (
<ContactCenter <div className="mb-6 p-4 bg-green-50 border border-green-200 rounded-lg">
tag="Newsletter" <p className="text-green-800 font-semibold"> Job posted successfully!</p>
title="Get Notified About Top Talent" </div>
description="Subscribe to receive alerts when qualified candidates match your job requirements. Stay ahead of the competition and hire the best talent." )}
tagIcon={Mail}
tagAnimation="slide-up" <form
background={{ variant: "animated-grid" }} onSubmit={handleSubmit}
useInvertedBackground={false} className="bg-white rounded-lg shadow-lg p-8 space-y-6"
inputPlaceholder="Enter your company email" >
buttonText="Subscribe" {/* Job Title */}
termsText="We respect your privacy. Unsubscribe anytime from our notifications." <div>
/> <label htmlFor="jobTitle" className="block text-sm font-semibold text-slate-900 mb-2">
Job Title *
</label>
<input
type="text"
id="jobTitle"
name="jobTitle"
value={formData.jobTitle}
onChange={handleChange}
required
placeholder="e.g., Senior Software Developer"
className="w-full px-4 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
/>
</div>
{/* Company */}
<div>
<label htmlFor="company" className="block text-sm font-semibold text-slate-900 mb-2">
Company Name *
</label>
<input
type="text"
id="company"
name="company"
value={formData.company}
onChange={handleChange}
required
placeholder="Your company name"
className="w-full px-4 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
/>
</div>
{/* Location */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label htmlFor="location" className="block text-sm font-semibold text-slate-900 mb-2">
City *
</label>
<input
type="text"
id="location"
name="location"
value={formData.location}
onChange={handleChange}
required
placeholder="e.g., Amsterdam"
className="w-full px-4 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
/>
</div>
<div>
<label htmlFor="province" className="block text-sm font-semibold text-slate-900 mb-2">
Province *
</label>
<select
id="province"
name="province"
value={formData.province}
onChange={handleChange}
required
className="w-full px-4 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
>
<option value="">Select Province</option>
<option value="North Holland">North Holland</option>
<option value="South Holland">South Holland</option>
<option value="Utrecht">Utrecht</option>
<option value="Gelderland">Gelderland</option>
<option value="North Brabant">North Brabant</option>
<option value="Overijssel">Overijssel</option>
<option value="Flevoland">Flevoland</option>
<option value="Friesland">Friesland</option>
<option value="Groningen">Groningen</option>
<option value="Drenthe">Drenthe</option>
<option value="Limburg">Limburg</option>
<option value="Zeeland">Zeeland</option>
</select>
</div>
</div>
{/* Job Type */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label htmlFor="jobType" className="block text-sm font-semibold text-slate-900 mb-2">
Job Type *
</label>
<select
id="jobType"
name="jobType"
value={formData.jobType}
onChange={handleChange}
className="w-full px-4 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
>
<option value="Full-Time">Full-Time</option>
<option value="Part-Time">Part-Time</option>
<option value="Contract">Contract</option>
<option value="Temporary">Temporary</option>
<option value="Internship">Internship</option>
</select>
</div>
<div>
<label htmlFor="salaryRange" className="block text-sm font-semibold text-slate-900 mb-2">
Salary Range
</label>
<input
type="text"
id="salaryRange"
name="salaryRange"
value={formData.salaryRange}
onChange={handleChange}
placeholder="e.g., €2,000 - €3,500"
className="w-full px-4 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
/>
</div>
</div>
{/* Description */}
<div>
<label htmlFor="description" className="block text-sm font-semibold text-slate-900 mb-2">
Job Description *
</label>
<textarea
id="description"
name="description"
value={formData.description}
onChange={handleChange}
required
rows={4}
placeholder="Describe the role, responsibilities, and key tasks..."
className="w-full px-4 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
/>
</div>
{/* Requirements */}
<div>
<label htmlFor="requirements" className="block text-sm font-semibold text-slate-900 mb-2">
Requirements *
</label>
<textarea
id="requirements"
name="requirements"
value={formData.requirements}
onChange={handleChange}
required
rows={4}
placeholder="List the required skills, experience, education, and qualifications..."
className="w-full px-4 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
/>
</div>
{/* Benefits */}
<div>
<label htmlFor="benefits" className="block text-sm font-semibold text-slate-900 mb-2">
Benefits & Perks
</label>
<textarea
id="benefits"
name="benefits"
value={formData.benefits}
onChange={handleChange}
rows={3}
placeholder="List benefits such as health insurance, remote work, stock options, etc..."
className="w-full px-4 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
/>
</div>
{/* Contact Email */}
<div>
<label htmlFor="contactEmail" className="block text-sm font-semibold text-slate-900 mb-2">
Contact Email *
</label>
<input
type="email"
id="contactEmail"
name="contactEmail"
value={formData.contactEmail}
onChange={handleChange}
required
placeholder="recruiter@company.com"
className="w-full px-4 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
/>
</div>
{/* Submit Button */}
<div className="flex gap-4 pt-6">
<button
type="submit"
className="flex-1 bg-blue-600 hover:bg-blue-700 text-white font-semibold py-3 rounded-lg transition duration-200"
>
Post Job
</button>
<button
type="button"
onClick={() =>
setFormData({
jobTitle: "", company: "", location: "", province: "", jobType: "Full-Time", salaryRange: "", description: "", requirements: "", contactEmail: "", benefits: ""})
}
className="flex-1 bg-slate-200 hover:bg-slate-300 text-slate-900 font-semibold py-3 rounded-lg transition duration-200"
>
Clear Form
</button>
</div>
</form>
<div className="mt-8 p-6 bg-blue-50 border border-blue-200 rounded-lg">
<h3 className="text-lg font-semibold text-slate-900 mb-2"> Tips for a Great Job Listing</h3>
<ul className="text-slate-700 space-y-1">
<li> Use clear, descriptive job titles</li>
<li> Include specific requirements and qualifications</li>
<li> Highlight company culture and benefits</li>
<li> Provide accurate salary ranges</li>
<li> Ensure contact information is correct</li>
</ul>
</div>
</div>
</div> </div>
<div id="footer" data-section="footer"> <div id="footer" data-section="footer">
<FooterBase <FooterBase
columns={footerColumns}
logoText="Jobee" logoText="Jobee"
copyrightText="© 2025 Jobee | Dutch Job Listing Platform" copyrightText="© 2025 Jobee | Dutch Job Listing Platform"
columns={footerColumns}
/> />
</div> </div>
</ThemeProvider> </ThemeProvider>

View File

@@ -1,16 +1,15 @@
"use client"; "use client";
import { useState, useMemo } from "react";
import { ThemeProvider } from "@/providers/themeProvider/ThemeProvider"; import { ThemeProvider } from "@/providers/themeProvider/ThemeProvider";
import NavbarStyleCentered from "@/components/navbar/NavbarStyleCentered/NavbarStyleCentered"; import NavbarStyleCentered from "@/components/navbar/NavbarStyleCentered/NavbarStyleCentered";
import FeatureCardEight from "@/components/sections/feature/FeatureCardEight";
import ContactCenter from "@/components/sections/contact/ContactCenter";
import FooterBase from "@/components/sections/footer/FooterBase"; import FooterBase from "@/components/sections/footer/FooterBase";
import { Sparkles, Mail } from "lucide-react"; import { Search, ChevronDown, MapPin, DollarSign, Briefcase } from "lucide-react";
const navItems = [ const navItems = [
{ name: "Search Jobs", id: "search" }, { name: "Search Jobs", id: "/search" },
{ name: "Post a Job", id: "post-job" }, { name: "Post a Job", id: "/post-job" },
{ name: "Admin", id: "admin-login" }, { name: "Admin", id: "/admin-login" },
{ name: "Browse", id: "browse" }, { name: "Browse", id: "browse" },
{ name: "Contact", id: "contact" }, { name: "Contact", id: "contact" },
]; ];
@@ -42,7 +41,115 @@ const footerColumns = [
}, },
]; ];
const mockJobs = [
{
id: "1", title: "Senior Software Engineer", company: "TechCorp Amsterdam", location: "Amsterdam", province: "North Holland", salary: "€80,000 - €120,000", salaryMin: 80000,
salaryMax: 120000,
jobType: "Full-time", category: "Technology", description:
"Join our innovative team as a Senior Software Engineer. We\'re looking for experienced developers with expertise in React, Node.js, and cloud technologies.", logo: "http://img.b2bpic.net/free-vector/tech-company-logo_23-2148947635.jpg"},
{
id: "2", title: "Marketing Manager", company: "Creative Solutions Rotterdam", location: "Rotterdam", province: "South Holland", salary: "€60,000 - €85,000", salaryMin: 60000,
salaryMax: 85000,
jobType: "Full-time", category: "Marketing", description:
"Lead our marketing initiatives and drive brand growth. We seek a strategic marketer with experience in digital marketing and campaign management.", logo: "http://img.b2bpic.net/free-vector/marketing-logo_23-2148947635.jpg"},
{
id: "3", title: "Data Scientist", company: "Analytics Pro Utrecht", location: "Utrecht", province: "Utrecht", salary: "€70,000 - €110,000", salaryMin: 70000,
salaryMax: 110000,
jobType: "Full-time", category: "Data Science", description:
"Develop advanced analytics solutions for our global clients. Expertise in Python, machine learning, and big data technologies required.", logo: "http://img.b2bpic.net/free-vector/analytics-logo_23-2148947635.jpg"},
{
id: "4", title: "UX/UI Designer", company: "Design Studios The Hague", location: "The Hague", province: "South Holland", salary: "€55,000 - €75,000", salaryMin: 55000,
salaryMax: 75000,
jobType: "Full-time", category: "Design", description:
"Create beautiful and intuitive user experiences for our web and mobile applications. Portfolio required.", logo: "http://img.b2bpic.net/free-vector/design-logo_23-2148947635.jpg"},
{
id: "5", title: "Sales Executive", company: "Enterprise Solutions Groningen", location: "Groningen", province: "Groningen", salary: "€45,000 - €70,000", salaryMin: 45000,
salaryMax: 70000,
jobType: "Full-time", category: "Sales", description:
"Grow our sales pipeline and build strong client relationships. Commission and bonus structure available.", logo: "http://img.b2bpic.net/free-vector/sales-logo_23-2148947635.jpg"},
{
id: "6", title: "HR Specialist", company: "People First Leiden", location: "Leiden", province: "South Holland", salary: "€50,000 - €65,000", salaryMin: 50000,
salaryMax: 65000,
jobType: "Part-time", category: "Human Resources", description:
"Support our HR team in recruitment, onboarding, and employee development initiatives.", logo: "http://img.b2bpic.net/free-vector/hr-logo_23-2148947635.jpg"},
{
id: "7", title: "DevOps Engineer", company: "Cloud Innovations Eindhoven", location: "Eindhoven", province: "North Brabant", salary: "€75,000 - €105,000", salaryMin: 75000,
salaryMax: 105000,
jobType: "Full-time", category: "Technology", description:
"Manage and optimize our cloud infrastructure. Experience with Docker, Kubernetes, and CI/CD pipelines required.", logo: "http://img.b2bpic.net/free-vector/devops-logo_23-2148947635.jpg"},
{
id: "8", title: "Product Manager", company: "Innovation Lab Delft", location: "Delft", province: "South Holland", salary: "€70,000 - €95,000", salaryMin: 70000,
salaryMax: 95000,
jobType: "Full-time", category: "Product", description:
"Lead product strategy and roadmap development for our SaaS platform. Experience with agile methodologies required.", logo: "http://img.b2bpic.net/free-vector/product-logo_23-2148947635.jpg"},
];
const provinces = [
"All Provinces", "North Holland", "South Holland", "Utrecht", "Groningen", "North Brabant", "Limburg", "Friesland", "Drenthe", "Flevoland", "Overijssel", "Gelderland"];
const categories = [
"All Categories", "Technology", "Marketing", "Sales", "Design", "Data Science", "Human Resources", "Product"];
const jobTypes = ["All Types", "Full-time", "Part-time", "Contract", "Freelance"];
export default function SearchPage() { export default function SearchPage() {
const [searchQuery, setSearchQuery] = useState("");
const [selectedProvince, setSelectedProvince] = useState("All Provinces");
const [selectedCategory, setSelectedCategory] = useState("All Categories");
const [selectedJobType, setSelectedJobType] = useState("All Types");
const [sortBy, setSortBy] = useState("relevant");
const [minSalary, setMinSalary] = useState(0);
const [maxSalary, setMaxSalary] = useState(150000);
const filteredJobs = useMemo(() => {
let filtered = mockJobs.filter((job) => {
const matchesSearch =
job.title.toLowerCase().includes(searchQuery.toLowerCase()) ||
job.company.toLowerCase().includes(searchQuery.toLowerCase()) ||
job.description.toLowerCase().includes(searchQuery.toLowerCase());
const matchesProvince =
selectedProvince === "All Provinces" ||
job.province === selectedProvince;
const matchesCategory =
selectedCategory === "All Categories" ||
job.category === selectedCategory;
const matchesJobType =
selectedJobType === "All Types" || job.jobType === selectedJobType;
const matchesSalary =
job.salaryMin >= minSalary && job.salaryMax <= maxSalary;
return (
matchesSearch &&
matchesProvince &&
matchesCategory &&
matchesJobType &&
matchesSalary
);
});
if (sortBy === "salary-high") {
filtered.sort((a, b) => b.salaryMax - a.salaryMax);
} else if (sortBy === "salary-low") {
filtered.sort((a, b) => a.salaryMin - b.salaryMin);
} else if (sortBy === "recent") {
filtered.reverse();
}
return filtered;
}, [
searchQuery,
selectedProvince,
selectedCategory,
selectedJobType,
minSalary,
maxSalary,
sortBy,
]);
return ( return (
<ThemeProvider <ThemeProvider
defaultButtonVariant="text-stagger" defaultButtonVariant="text-stagger"
@@ -65,54 +172,188 @@ export default function SearchPage() {
/> />
</div> </div>
<div id="features" data-section="features"> <div className="min-h-screen bg-gradient-to-b from-background to-background-accent pt-20 pb-20">
<FeatureCardEight <div className="max-w-7xl mx-auto px-4">
title="Search & Browse Jobs Across the Netherlands" {/* Search Header */}
description="Explore our comprehensive job search experience with advanced filters, diverse listings, and tailored opportunities for every career stage." <div className="mb-12">
tag="Advanced Search" <h1 className="text-4xl md:text-5xl font-bold text-foreground mb-4">
tagIcon={Sparkles} Find Your Dream Job
tagAnimation="slide-up" </h1>
textboxLayout="default" <p className="text-lg text-foreground/70 mb-8">
useInvertedBackground={false} Discover thousands of opportunities across the Netherlands
features={[ </p>
{
id: 1,
title: "Filter by Province", description:
"Search jobs from all 12 Dutch provinces including Amsterdam, Rotterdam, Utrecht, and beyond. Find opportunities near you or explore remote positions nationwide.", imageSrc:
"http://img.b2bpic.net/free-photo/homepage-concept-with-search-bar_23-2150040187.jpg?_wi=4", imageAlt: "Province filter interface"},
{
id: 2,
title: "Refine by Category", description:
"Browse across multiple industries: Technology, Healthcare, Finance, Engineering, Marketing, Sales, and more. Find roles that match your expertise and interests.", imageSrc:
"http://img.b2bpic.net/free-vector/professional-bookkeeping-postcard-template_23-2149341358.jpg?_wi=2", imageAlt: "Job category options"},
{
id: 3,
title: "Salary & Experience Level", description:
"Filter by salary range, job type (full-time, part-time, contract), and experience level (entry-level, mid-career, senior) to find the perfect match for your career goals.", imageSrc:
"http://img.b2bpic.net/free-photo/corporate-workers-brainstorming-together_23-2148804568.jpg?_wi=3", imageAlt: "Salary and level filters"},
]}
buttons={[
{
text: "Start Your Search", href: "/search"},
]}
buttonAnimation="slide-up"
/>
</div>
<div id="contact" data-section="contact"> {/* Main Search Bar */}
<ContactCenter <div className="relative mb-8">
tag="Save Your Search" <Search className="absolute left-4 top-1/2 transform -translate-y-1/2 text-foreground/50" />
title="Get Personalized Job Recommendations" <input
description="Create an account and set up job alerts. We'll notify you about new positions matching your criteria so you never miss an opportunity." type="text"
tagIcon={Mail} placeholder="Search by job title, company, or keywords..."
tagAnimation="slide-up" value={searchQuery}
background={{ onChange={(e) => setSearchQuery(e.target.value)}
variant: "animated-grid"}} className="w-full pl-12 pr-4 py-4 rounded-full bg-card border border-accent/20 text-foreground placeholder-foreground/50 focus:outline-none focus:ring-2 focus:ring-primary-cta"
useInvertedBackground={false} />
inputPlaceholder="Enter your email to get started" </div>
buttonText="Create Alert"
termsText="Your preferences are private and secure. Manage your alerts anytime." {/* Filter Bar */}
/> <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-5 gap-4 mb-8">
{/* Province Filter */}
<div className="relative">
<select
value={selectedProvince}
onChange={(e) => setSelectedProvince(e.target.value)}
className="w-full px-4 py-3 rounded-lg bg-card border border-accent/20 text-foreground cursor-pointer appearance-none pr-10 focus:outline-none focus:ring-2 focus:ring-primary-cta"
>
{provinces.map((province) => (
<option key={province} value={province}>
{province}
</option>
))}
</select>
<MapPin className="absolute right-3 top-1/2 transform -translate-y-1/2 text-foreground/50 pointer-events-none" />
</div>
{/* Category Filter */}
<div className="relative">
<select
value={selectedCategory}
onChange={(e) => setSelectedCategory(e.target.value)}
className="w-full px-4 py-3 rounded-lg bg-card border border-accent/20 text-foreground cursor-pointer appearance-none pr-10 focus:outline-none focus:ring-2 focus:ring-primary-cta"
>
{categories.map((category) => (
<option key={category} value={category}>
{category}
</option>
))}
</select>
<Briefcase className="absolute right-3 top-1/2 transform -translate-y-1/2 text-foreground/50 pointer-events-none" />
</div>
{/* Job Type Filter */}
<div className="relative">
<select
value={selectedJobType}
onChange={(e) => setSelectedJobType(e.target.value)}
className="w-full px-4 py-3 rounded-lg bg-card border border-accent/20 text-foreground cursor-pointer appearance-none pr-10 focus:outline-none focus:ring-2 focus:ring-primary-cta"
>
{jobTypes.map((type) => (
<option key={type} value={type}>
{type}
</option>
))}
</select>
<ChevronDown className="absolute right-3 top-1/2 transform -translate-y-1/2 text-foreground/50 pointer-events-none" />
</div>
{/* Salary Range */}
<div className="flex items-center gap-2">
<DollarSign className="text-foreground/50" />
<input
type="range"
min="0"
max="150000"
step="10000"
value={maxSalary}
onChange={(e) => setMaxSalary(parseInt(e.target.value))}
className="w-full"
/>
</div>
{/* Sort By */}
<div className="relative">
<select
value={sortBy}
onChange={(e) => setSortBy(e.target.value)}
className="w-full px-4 py-3 rounded-lg bg-card border border-accent/20 text-foreground cursor-pointer appearance-none pr-10 focus:outline-none focus:ring-2 focus:ring-primary-cta"
>
<option value="relevant">Most Relevant</option>
<option value="recent">Most Recent</option>
<option value="salary-high">Highest Salary</option>
<option value="salary-low">Lowest Salary</option>
</select>
<ChevronDown className="absolute right-3 top-1/2 transform -translate-y-1/2 text-foreground/50 pointer-events-none" />
</div>
</div>
{/* Results Count */}
<p className="text-sm text-foreground/60">
Showing {filteredJobs.length} of {mockJobs.length} jobs
</p>
</div>
{/* Job Listings */}
<div className="grid grid-cols-1 gap-4">
{filteredJobs.length > 0 ? (
filteredJobs.map((job) => (
<div
key={job.id}
className="p-6 rounded-xl bg-card border border-accent/20 hover:border-accent/50 transition-all duration-300 hover:shadow-lg cursor-pointer"
>
<div className="flex items-start justify-between mb-4">
<div className="flex items-start gap-4 flex-1">
<div className="w-16 h-16 rounded-lg bg-gradient-to-br from-primary-cta to-secondary-cta flex items-center justify-center text-white font-bold text-xl flex-shrink-0">
{job.company.charAt(0)}
</div>
<div className="flex-1">
<h3 className="text-xl font-bold text-foreground mb-1">
{job.title}
</h3>
<p className="text-sm text-foreground/70 mb-2">
{job.company}
</p>
<p className="text-sm text-foreground/60">
{job.location}, {job.province}
</p>
</div>
</div>
<div className="text-right">
<p className="text-lg font-bold text-primary-cta mb-2">
{job.salary}
</p>
<span className="inline-block px-3 py-1 rounded-full text-xs font-semibold bg-primary-cta/10 text-primary-cta">
{job.jobType}
</span>
</div>
</div>
<p className="text-sm text-foreground/70 mb-4 line-clamp-2">
{job.description}
</p>
<div className="flex items-center justify-between">
<div className="flex gap-2">
<span className="inline-block px-3 py-1 rounded-lg text-xs bg-background text-foreground/70">
{job.category}
</span>
</div>
<button className="px-4 py-2 rounded-full bg-primary-cta text-white font-semibold hover:opacity-90 transition-opacity">
View Details
</button>
</div>
</div>
))
) : (
<div className="text-center py-12">
<p className="text-lg text-foreground/60 mb-4">
No jobs found matching your criteria.
</p>
<button
onClick={() => {
setSearchQuery("");
setSelectedProvince("All Provinces");
setSelectedCategory("All Categories");
setSelectedJobType("All Types");
setMinSalary(0);
setMaxSalary(150000);
}}
className="px-6 py-2 rounded-full bg-primary-cta text-white font-semibold hover:opacity-90 transition-opacity"
>
Clear Filters
</button>
</div>
)}
</div>
</div>
</div> </div>
<div id="footer" data-section="footer"> <div id="footer" data-section="footer">

View File

@@ -10,15 +10,15 @@
--accent: #ffffff; --accent: #ffffff;
--background-accent: #ffffff; */ --background-accent: #ffffff; */
--background: #f5f5f5; --background: #ffffff;
--card: #ffffff; --card: #f9f9f9;
--foreground: #1c1c1c; --foreground: #000612e6;
--primary-cta: #1c1c1c; --primary-cta: #15479c;
--primary-cta-text: #f5f5f5; --primary-cta-text: #f5f5f5;
--secondary-cta: #ffffff; --secondary-cta: #f9f9f9;
--secondary-cta-text: #1c1c1c; --secondary-cta-text: #1c1c1c;
--accent: #15479c; --accent: #e2e2e2;
--background-accent: #a8cce8; --background-accent: #c4c4c4;
/* text sizing - set by ThemeProvider */ /* text sizing - set by ThemeProvider */
/* --text-2xs: clamp(0.465rem, 0.62vw, 0.62rem); /* --text-2xs: clamp(0.465rem, 0.62vw, 0.62rem);