Update src/app/post-job/page.tsx
This commit is contained in:
@@ -1,48 +1,130 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { ThemeProvider } from "@/providers/themeProvider/ThemeProvider";
|
||||
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 Link from "next/link";
|
||||
import { Briefcase, Mail, MapPin, Sparkles } from "lucide-react";
|
||||
import Input from "@/components/form/Input";
|
||||
import { Upload, CheckCircle, X } 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: "#" },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
interface FormData {
|
||||
jobTitle: string;
|
||||
companyName: string;
|
||||
location: string;
|
||||
jobType: string;
|
||||
salary: string;
|
||||
description: string;
|
||||
requirements: string;
|
||||
benefits: string;
|
||||
contactEmail: string;
|
||||
}
|
||||
|
||||
interface FormErrors {
|
||||
[key: string]: string;
|
||||
}
|
||||
|
||||
export default function PostJobPage() {
|
||||
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 [formData, setFormData] = useState<FormData>({
|
||||
jobTitle: "", companyName: "", location: "", jobType: "Full-time", salary: "", description: "", requirements: "", benefits: "", contactEmail: ""});
|
||||
|
||||
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 [errors, setErrors] = useState<FormErrors>({});
|
||||
const [submitted, setSubmitted] = useState(false);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
const validateForm = (): boolean => {
|
||||
const newErrors: FormErrors = {};
|
||||
|
||||
if (!formData.jobTitle.trim()) {
|
||||
newErrors.jobTitle = "Job title is required";
|
||||
}
|
||||
if (!formData.companyName.trim()) {
|
||||
newErrors.companyName = "Company name is required";
|
||||
}
|
||||
if (!formData.location.trim()) {
|
||||
newErrors.location = "Location is required";
|
||||
}
|
||||
if (!formData.salary.trim()) {
|
||||
newErrors.salary = "Salary range is required";
|
||||
}
|
||||
if (!formData.description.trim() || formData.description.trim().length < 20) {
|
||||
newErrors.description = "Job description must be at least 20 characters";
|
||||
}
|
||||
if (!formData.requirements.trim() || formData.requirements.trim().length < 20) {
|
||||
newErrors.requirements = "Requirements must be at least 20 characters";
|
||||
}
|
||||
if (!formData.contactEmail.trim()) {
|
||||
newErrors.contactEmail = "Contact email is required";
|
||||
} else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(formData.contactEmail)) {
|
||||
newErrors.contactEmail = "Please enter a valid email address";
|
||||
}
|
||||
|
||||
setErrors(newErrors);
|
||||
return Object.keys(newErrors).length === 0;
|
||||
};
|
||||
|
||||
const handleInputChange = (field: keyof FormData, value: string) => {
|
||||
setFormData((prev) => ({ ...prev, [field]: value }));
|
||||
if (errors[field]) {
|
||||
setErrors((prev) => {
|
||||
const newErrors = { ...prev };
|
||||
delete newErrors[field];
|
||||
return newErrors;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
if (!validateForm()) return;
|
||||
|
||||
setIsLoading(true);
|
||||
try {
|
||||
await new Promise((resolve) => setTimeout(resolve, 2000));
|
||||
setSubmitted(true);
|
||||
setFormData({
|
||||
jobTitle: "", companyName: "", location: "", jobType: "Full-time", salary: "", description: "", requirements: "", benefits: "", contactEmail: ""});
|
||||
setTimeout(() => setSubmitted(false), 5000);
|
||||
} catch (error) {
|
||||
console.error("Submission error:", error);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<ThemeProvider
|
||||
@@ -59,65 +141,230 @@ export default function PostJobPage() {
|
||||
>
|
||||
<div id="nav" data-section="nav">
|
||||
<NavbarStyleCentered
|
||||
navItems={navItems}
|
||||
button={{ text: "Post a Job", href: "/post-job" }}
|
||||
brandName="Jobee"
|
||||
navItems={navItems}
|
||||
button={{
|
||||
text: "Post a Job", href: "/post-job"}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div id="features" data-section="features">
|
||||
<FeatureCardEight
|
||||
features={[
|
||||
{
|
||||
id: 1,
|
||||
title: "Create a Job Posting", description:
|
||||
"Fill in job details, requirements, and salary information. Our intuitive form guides you through every step to create a compelling job listing.", imageSrc:
|
||||
"http://img.b2bpic.net/free-vector/professional-recruitment-plan-diversity-general-infographic-template_23-2148947635.jpg?_wi=4", imageAlt: "Job posting creation interface"},
|
||||
{
|
||||
id: 2,
|
||||
title: "Reach Qualified Candidates", description:
|
||||
"Your job posting is automatically distributed across our network of active job seekers across all 12 Dutch provinces.", imageSrc:
|
||||
"http://img.b2bpic.net/free-photo/homepage-concept-with-search-bar_23-2150040187.jpg?_wi=5", imageAlt: "Candidate reach visualization"},
|
||||
{
|
||||
id: 3,
|
||||
title: "Review Applications", description:
|
||||
"Manage all incoming applications in one centralized dashboard. Review resumes, cover letters, and candidate profiles easily.", imageSrc:
|
||||
"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 className="min-h-screen bg-background py-16 md:py-24">
|
||||
<div className="mx-auto w-full max-w-2xl px-4 md:px-8">
|
||||
{/* Header */}
|
||||
<div className="mb-12 text-center">
|
||||
<h1 className="mb-4 text-4xl md:text-5xl font-bold text-foreground">
|
||||
Post a Job
|
||||
</h1>
|
||||
<p className="text-lg text-foreground/75">
|
||||
Reach thousands of qualified job seekers across the Netherlands
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div id="contact" data-section="contact">
|
||||
<ContactCenter
|
||||
tag="Newsletter"
|
||||
title="Get Notified About Top Talent"
|
||||
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"
|
||||
background={{ variant: "animated-grid" }}
|
||||
useInvertedBackground={false}
|
||||
inputPlaceholder="Enter your company email"
|
||||
buttonText="Subscribe"
|
||||
termsText="We respect your privacy. Unsubscribe anytime from our notifications."
|
||||
/>
|
||||
{/* Success Message */}
|
||||
{submitted && (
|
||||
<div className="mb-8 flex items-center gap-3 rounded-lg bg-green-50 p-4 text-green-700 border border-green-200">
|
||||
<CheckCircle size={20} />
|
||||
<div>
|
||||
<p className="font-semibold">Job posted successfully!</p>
|
||||
<p className="text-sm">Your job listing will be live shortly.</p>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => setSubmitted(false)}
|
||||
className="ml-auto p-1 hover:bg-green-100 rounded"
|
||||
>
|
||||
<X size={16} />
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Form */}
|
||||
<form
|
||||
onSubmit={handleSubmit}
|
||||
className="rounded-xl bg-card p-8 md:p-12 border border-accent/20 shadow-lg"
|
||||
>
|
||||
{/* Job Title */}
|
||||
<div className="mb-6">
|
||||
<label className="block mb-2 text-sm font-semibold text-foreground">
|
||||
Job Title *
|
||||
</label>
|
||||
<Input
|
||||
value={formData.jobTitle}
|
||||
onChange={(value) => handleInputChange("jobTitle", value)}
|
||||
placeholder="e.g., Senior Software Engineer"
|
||||
required
|
||||
/>
|
||||
{errors.jobTitle && (
|
||||
<p className="mt-1 text-sm text-red-600">{errors.jobTitle}</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Company Name */}
|
||||
<div className="mb-6">
|
||||
<label className="block mb-2 text-sm font-semibold text-foreground">
|
||||
Company Name *
|
||||
</label>
|
||||
<Input
|
||||
value={formData.companyName}
|
||||
onChange={(value) => handleInputChange("companyName", value)}
|
||||
placeholder="Your company name"
|
||||
required
|
||||
/>
|
||||
{errors.companyName && (
|
||||
<p className="mt-1 text-sm text-red-600">{errors.companyName}</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Location */}
|
||||
<div className="mb-6">
|
||||
<label className="block mb-2 text-sm font-semibold text-foreground">
|
||||
Location *
|
||||
</label>
|
||||
<Input
|
||||
value={formData.location}
|
||||
onChange={(value) => handleInputChange("location", value)}
|
||||
placeholder="e.g., Amsterdam, Netherlands"
|
||||
required
|
||||
/>
|
||||
{errors.location && (
|
||||
<p className="mt-1 text-sm text-red-600">{errors.location}</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Job Type and Salary */}
|
||||
<div className="mb-6 grid gap-6 md:grid-cols-2">
|
||||
<div>
|
||||
<label className="block mb-2 text-sm font-semibold text-foreground">
|
||||
Job Type *
|
||||
</label>
|
||||
<select
|
||||
value={formData.jobType}
|
||||
onChange={(e) => handleInputChange("jobType", e.target.value)}
|
||||
className="w-full rounded-lg bg-secondary-button px-4 py-2.5 text-foreground placeholder-foreground/75 border border-accent/20 focus:outline-none focus:ring-2 focus:ring-primary-cta"
|
||||
>
|
||||
<option>Full-time</option>
|
||||
<option>Part-time</option>
|
||||
<option>Contract</option>
|
||||
<option>Temporary</option>
|
||||
<option>Internship</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block mb-2 text-sm font-semibold text-foreground">
|
||||
Salary Range *
|
||||
</label>
|
||||
<Input
|
||||
value={formData.salary}
|
||||
onChange={(value) => handleInputChange("salary", value)}
|
||||
placeholder="e.g., €50,000 - €80,000"
|
||||
required
|
||||
/>
|
||||
{errors.salary && (
|
||||
<p className="mt-1 text-sm text-red-600">{errors.salary}</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Job Description */}
|
||||
<div className="mb-6">
|
||||
<label className="block mb-2 text-sm font-semibold text-foreground">
|
||||
Job Description *
|
||||
</label>
|
||||
<textarea
|
||||
value={formData.description}
|
||||
onChange={(e) => handleInputChange("description", e.target.value)}
|
||||
placeholder="Describe the role, responsibilities, and key details..."
|
||||
rows={6}
|
||||
className="w-full rounded-lg bg-secondary-button px-4 py-2.5 text-foreground placeholder-foreground/75 border border-accent/20 focus:outline-none focus:ring-2 focus:ring-primary-cta resize-none"
|
||||
required
|
||||
/>
|
||||
{errors.description && (
|
||||
<p className="mt-1 text-sm text-red-600">{errors.description}</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Requirements */}
|
||||
<div className="mb-6">
|
||||
<label className="block mb-2 text-sm font-semibold text-foreground">
|
||||
Requirements *
|
||||
</label>
|
||||
<textarea
|
||||
value={formData.requirements}
|
||||
onChange={(e) => handleInputChange("requirements", e.target.value)}
|
||||
placeholder="List the key requirements and qualifications (e.g., skills, experience, education)..."
|
||||
rows={5}
|
||||
className="w-full rounded-lg bg-secondary-button px-4 py-2.5 text-foreground placeholder-foreground/75 border border-accent/20 focus:outline-none focus:ring-2 focus:ring-primary-cta resize-none"
|
||||
required
|
||||
/>
|
||||
{errors.requirements && (
|
||||
<p className="mt-1 text-sm text-red-600">{errors.requirements}</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Benefits */}
|
||||
<div className="mb-6">
|
||||
<label className="block mb-2 text-sm font-semibold text-foreground">
|
||||
Benefits (Optional)
|
||||
</label>
|
||||
<textarea
|
||||
value={formData.benefits}
|
||||
onChange={(e) => handleInputChange("benefits", e.target.value)}
|
||||
placeholder="Highlight benefits such as remote work, flexible hours, health insurance, training, etc."
|
||||
rows={4}
|
||||
className="w-full rounded-lg bg-secondary-button px-4 py-2.5 text-foreground placeholder-foreground/75 border border-accent/20 focus:outline-none focus:ring-2 focus:ring-primary-cta resize-none"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Contact Email */}
|
||||
<div className="mb-8">
|
||||
<label className="block mb-2 text-sm font-semibold text-foreground">
|
||||
Contact Email *
|
||||
</label>
|
||||
<Input
|
||||
value={formData.contactEmail}
|
||||
onChange={(value) => handleInputChange("contactEmail", value)}
|
||||
type="email"
|
||||
placeholder="your-email@company.com"
|
||||
required
|
||||
/>
|
||||
{errors.contactEmail && (
|
||||
<p className="mt-1 text-sm text-red-600">{errors.contactEmail}</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Submit Button */}
|
||||
<button
|
||||
type="submit"
|
||||
disabled={isLoading}
|
||||
className="w-full rounded-lg bg-primary-cta px-6 py-3 font-semibold text-white hover:opacity-90 disabled:opacity-50 disabled:cursor-not-allowed transition-opacity flex items-center justify-center gap-2"
|
||||
>
|
||||
{isLoading ? (
|
||||
<>
|
||||
<div className="h-5 w-5 animate-spin rounded-full border-2 border-white border-t-transparent"></div>
|
||||
Posting...
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Upload size={18} />
|
||||
Post Job
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
|
||||
{/* Form Info */}
|
||||
<p className="mt-4 text-center text-sm text-foreground/60">
|
||||
* Required fields. Your job will be reviewed before going live.
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="footer" data-section="footer">
|
||||
<FooterBase
|
||||
columns={footerColumns}
|
||||
logoText="Jobee"
|
||||
copyrightText="© 2025 Jobee | Dutch Job Listing Platform"
|
||||
columns={footerColumns}
|
||||
/>
|
||||
</div>
|
||||
</ThemeProvider>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user