mirror of
https://github.com/OwethuManagedServices/oms-website-nextjs.git
synced 2025-12-18 05:28:08 +00:00
feature: contact us fixed
This commit is contained in:
239
app/(website)/vacancies/page.tsx
Normal file
239
app/(website)/vacancies/page.tsx
Normal file
@ -0,0 +1,239 @@
|
||||
"use client"; // <-- Add this line to use state
|
||||
|
||||
import Link from "next/link";
|
||||
import { useState } from "react"; // <-- Import useState
|
||||
import {
|
||||
FaMapMarkerAlt,
|
||||
FaBriefcase,
|
||||
FaPaperPlane,
|
||||
FaArrowRight,
|
||||
FaRegClock,
|
||||
FaSearch,
|
||||
} from "react-icons/fa";
|
||||
import { demoVacancies } from "@/lib/demo-data/vacancies";
|
||||
import { Vacancy } from "@/types";
|
||||
import Button from "@/components/ui/Button";
|
||||
import Modal from "@/components/ui/Modal"; // <-- Import your Modal component
|
||||
import { COLORS } from "@/constants";
|
||||
import VacancyApplicationForm from "@/components/VacancyApplicationForm";
|
||||
|
||||
// Metadata object might need adjustment depending on your setup with client components
|
||||
// If using App Router, keep it, Next.js handles it.
|
||||
/*
|
||||
export const metadata: Metadata = {
|
||||
title: "Current Vacancies | OMS",
|
||||
description:
|
||||
"Explore exciting career opportunities at OMS. Find your perfect role or submit your CV for future consideration.",
|
||||
};
|
||||
*/
|
||||
|
||||
// Define gold color for consistency (if COLORS.primary is not '#e1c44a', adjust accordingly)
|
||||
const goldColor = COLORS.primary || "#e1c44a"; // Use COLORS.primary or fallback
|
||||
|
||||
// --- VacancyCard Component (no changes needed here) ---
|
||||
interface VacancyCardProps {
|
||||
vacancy: Vacancy;
|
||||
}
|
||||
|
||||
function VacancyCard({ vacancy }: VacancyCardProps) {
|
||||
const formatDate = (dateString: string | undefined) => {
|
||||
if (!dateString) return "Date N/A";
|
||||
try {
|
||||
return new Date(dateString).toLocaleDateString("en-US", {
|
||||
year: "numeric",
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
});
|
||||
} catch {
|
||||
return "Invalid Date";
|
||||
}
|
||||
};
|
||||
const postedDate = formatDate(vacancy.postedDate);
|
||||
|
||||
return (
|
||||
<Link
|
||||
href={`/vacancies/${vacancy.slug}`}
|
||||
className="group block w-full transform transition duration-300 ease-in-out hover:-translate-y-1" // Add subtle lift on hover
|
||||
>
|
||||
<div
|
||||
className="relative flex flex-col h-full overflow-hidden rounded-lg bg-white dark:bg-gray-800 p-6 shadow-md transition-shadow duration-300 hover:shadow-xl border-l-4 dark:border-l-yellow-500" // Card base style + left border + dark mode
|
||||
style={{ borderColor: goldColor }} // Apply gold border color (consider dark mode alternative if needed)
|
||||
>
|
||||
<div className="flex-grow">
|
||||
<h3 className="mb-2 text-xl font-bold font-poppins text-gray-900 dark:text-gray-100 transition-colors group-hover:text-gray-700 dark:group-hover:text-gray-300">
|
||||
{vacancy.title}
|
||||
</h3>
|
||||
<div className="mb-4 flex flex-col space-y-2 text-sm text-gray-600 dark:text-gray-400 font-poppins">
|
||||
<span className="inline-flex items-center gap-2">
|
||||
<FaMapMarkerAlt
|
||||
className="h-4 w-4 flex-shrink-0"
|
||||
style={{ color: goldColor }} // Keep gold or use dark:text-yellow-400
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<span>
|
||||
{vacancy.location.city}{" "}
|
||||
{vacancy.location.remote && (
|
||||
<span className="ml-1 rounded bg-gray-200 dark:bg-gray-700 px-1.5 py-0.5 text-xs font-medium text-gray-700 dark:text-gray-300">
|
||||
Remote
|
||||
</span>
|
||||
)}
|
||||
</span>
|
||||
</span>
|
||||
<span className="inline-flex items-center gap-2">
|
||||
<FaBriefcase
|
||||
className="h-4 w-4 flex-shrink-0"
|
||||
style={{ color: goldColor }} // Keep gold or use dark:text-yellow-400
|
||||
aria-hidden="true"
|
||||
/>
|
||||
{vacancy.employmentType}
|
||||
</span>
|
||||
{vacancy.postedDate && (
|
||||
<span className="inline-flex items-center gap-2">
|
||||
<FaRegClock
|
||||
className="h-4 w-4 flex-shrink-0"
|
||||
style={{ color: goldColor }} // Keep gold or use dark:text-yellow-400
|
||||
aria-hidden="true"
|
||||
/>
|
||||
Posted: {postedDate}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-auto pt-4 border-t border-gray-100 dark:border-gray-700">
|
||||
<span
|
||||
className="inline-flex items-center text-sm font-medium font-poppins"
|
||||
style={{ color: goldColor }} // Keep gold or use dark:text-yellow-400
|
||||
>
|
||||
View Details
|
||||
<FaArrowRight
|
||||
className="ml-1 h-4 w-4 transition-transform duration-300 group-hover:translate-x-1"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
// --- End Vacancy Card Component ---
|
||||
|
||||
// --- Vacancies Page ---
|
||||
export default function VacanciesPage() {
|
||||
// TODO: Replace demoVacancies with actual API call if needed client-side,
|
||||
// or fetch server-side and pass as props if using Pages Router.
|
||||
// For App Router, `async function` fetches server-side by default.
|
||||
const vacancies = demoVacancies;
|
||||
|
||||
// --- State for the "Future Positions" Modal ---
|
||||
const [isFuturePositionModalOpen, setIsFuturePositionModalOpen] =
|
||||
useState(false);
|
||||
|
||||
const handleOpenFuturePositionModal = () =>
|
||||
setIsFuturePositionModalOpen(true);
|
||||
const handleCloseFuturePositionModal = () =>
|
||||
setIsFuturePositionModalOpen(false);
|
||||
// --- End State ---
|
||||
|
||||
return (
|
||||
<div className="bg-gray-50 dark:bg-gray-900 text-gray-800 dark:text-gray-200 overflow-x-hidden font-poppins">
|
||||
{/* Section 1: Hero / Page Header */}
|
||||
<section className="relative bg-gradient-to-r from-gray-800 via-gray-700 to-gray-800 dark:from-gray-900 dark:via-gray-800 dark:to-gray-900 text-white py-20 md:py-28">
|
||||
<div className="absolute inset-0 bg-black opacity-30 dark:opacity-50"></div>
|
||||
<div className="container mx-auto px-6 text-center relative z-10">
|
||||
<h1
|
||||
className="text-4xl md:text-5xl lg:text-6xl font-bold mb-4 font-poppins drop-shadow-md"
|
||||
style={{ color: goldColor }} // Keep gold or use dark:text-yellow-400
|
||||
>
|
||||
Career Opportunities
|
||||
</h1>
|
||||
<p className="text-lg md:text-xl max-w-3xl mx-auto leading-relaxed text-gray-200 dark:text-gray-300 font-poppins">
|
||||
Join our team of innovators and experts. Explore current openings at
|
||||
OMS or submit your CV for future consideration.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Section 2: Vacancy List */}
|
||||
<section className="py-16 md:py-24">
|
||||
<div className="container mx-auto px-6">
|
||||
<h2 className="text-3xl md:text-4xl font-bold font-poppins text-gray-900 dark:text-gray-100 mb-12 text-center">
|
||||
Current Openings
|
||||
</h2>
|
||||
{vacancies.length > 0 ? (
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
|
||||
{vacancies.map((vacancy) => (
|
||||
<VacancyCard key={vacancy.id} vacancy={vacancy} />
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div className="mt-10 max-w-2xl mx-auto rounded-lg border border-dashed border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-800 p-10 text-center shadow-sm">
|
||||
<FaSearch
|
||||
className="mx-auto mb-5 h-12 w-12"
|
||||
style={{ color: goldColor }} // Keep gold or use dark:text-yellow-400
|
||||
/>
|
||||
<h3 className="text-xl font-semibold text-gray-800 dark:text-gray-100 font-poppins mb-2">
|
||||
No Open Vacancies Right Now
|
||||
</h3>
|
||||
<p className="text-gray-600 dark:text-gray-400 font-poppins">
|
||||
We're not actively hiring for specific roles at the moment,
|
||||
but we're always looking for passionate and talented
|
||||
individuals. Check back soon or submit your CV below!
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Section 3: Future Positions / CV Submission */}
|
||||
<section
|
||||
className="py-16 md:py-24 text-gray-900 dark:text-gray-800" // Adjust text color for dark mode contrast on gold bg
|
||||
style={{ backgroundColor: goldColor }} // Keep gold background
|
||||
>
|
||||
<div className="container mx-auto px-6 text-center">
|
||||
<FaPaperPlane className="text-5xl mx-auto mb-5 text-gray-800 dark:text-gray-900" />{" "}
|
||||
{/* Ensure icon contrast */}
|
||||
<h2 className="text-3xl md:text-4xl font-bold mb-4 font-poppins text-gray-900 dark:text-gray-900">
|
||||
{" "}
|
||||
{/* Ensure heading contrast */}
|
||||
Don't See the Right Fit?
|
||||
</h2>
|
||||
<p className="text-lg md:text-xl max-w-3xl mx-auto leading-relaxed font-poppins text-gray-800 dark:text-gray-800">
|
||||
{" "}
|
||||
{/* Ensure text contrast */}
|
||||
We're always looking for talented individuals to join our
|
||||
journey. Submit your CV, and we'll keep you in mind for future
|
||||
openings that match your profile.
|
||||
</p>
|
||||
<div className="mt-10">
|
||||
{/* --- Updated Button --- */}
|
||||
<Button
|
||||
type="button"
|
||||
onClick={handleOpenFuturePositionModal}
|
||||
variant="secondary"
|
||||
size="lg"
|
||||
className="inline-flex items-center gap-2 group font-poppins bg-gray-800 text-black hover:bg-gray-900 dark:bg-gray-100 dark:text-gray-900 dark:hover:bg-gray-200" // Adjusted dark mode button colors
|
||||
>
|
||||
Submit Your CV
|
||||
<FaArrowRight className="h-4 w-4 transition-transform duration-200 group-hover:translate-x-1" />
|
||||
</Button>
|
||||
{/* --- End Updated Button --- */}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* --- Modal for Future Position Application --- */}
|
||||
<Modal
|
||||
isOpen={isFuturePositionModalOpen}
|
||||
onClose={handleCloseFuturePositionModal}
|
||||
title="Apply for Future Positions"
|
||||
size="4xl"
|
||||
>
|
||||
<VacancyApplicationForm
|
||||
vacancyId="future-position"
|
||||
vacancyTitle="General Application / Future Position"
|
||||
onClose={handleCloseFuturePositionModal}
|
||||
/>
|
||||
</Modal>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user