This commit is contained in:
Iliyan Angelov
2025-11-24 03:52:08 +02:00
parent dfcaebaf8c
commit 366f28677a
18241 changed files with 865352 additions and 567 deletions

View File

@@ -0,0 +1,144 @@
"use client";
import { useEffect } from "react";
import gsap from "gsap";
import { ScrollTrigger } from "gsap/dist/ScrollTrigger";
import Link from "next/link";
const CareerBanner = () => {
useEffect(() => {
gsap.registerPlugin(ScrollTrigger);
if (document.querySelector(".career-banner")) {
const tl = gsap.timeline({
scrollTrigger: {
trigger: ".career-banner",
start: "center center",
end: "+=100%",
scrub: true,
pin: false,
},
});
tl.to(".cp-banner-thumb", {
opacity: 0.1,
y: "40%",
duration: 2,
});
tl.to(
".career-banner",
{
"--scale": 3,
duration: 2,
},
0
);
}
}, []);
return (
<section className="career-banner fix-top bg-black position-relative overflow-hidden" style={{ minHeight: '50vh', paddingTop: '100px', paddingBottom: '60px' }}>
<div className="container">
<div className="row justify-content-center align-items-center">
<div className="col-12 col-lg-10">
<div className="cp-banner__content text-center">
<h2 className="mt-8 fw-7 text-xxl title-anim text-white mb-5">
Build Your Career with Enterprise Excellence
</h2>
<p className="text-quinary fs-5 mb-5" style={{ maxWidth: '700px', margin: '0 auto 2rem' }}>
Join our global team of innovators, problem-solvers, and tech leaders building the future of digital solutions
</p>
</div>
</div>
</div>
{/* Job Categories with Icons */}
<div className="row justify-content-center mt-5 pt-4">
<div className="col-6 col-md-3 text-center mb-4">
<div className="job-category-card" style={{
padding: '2rem 1rem',
background: 'rgba(255,255,255,0.05)',
borderRadius: '12px',
border: '1px solid rgba(255,255,255,0.1)',
transition: 'all 0.3s ease'
}}>
<div className="icon-wrapper mb-3" style={{ fontSize: '3rem', color: '#00d4ff' }}>
<i className="fa-solid fa-code"></i>
</div>
<h5 className="text-white fw-6 mb-2">Engineering</h5>
</div>
</div>
<div className="col-6 col-md-3 text-center mb-4">
<div className="job-category-card" style={{
padding: '2rem 1rem',
background: 'rgba(255,255,255,0.05)',
borderRadius: '12px',
border: '1px solid rgba(255,255,255,0.1)',
transition: 'all 0.3s ease'
}}>
<div className="icon-wrapper mb-3" style={{ fontSize: '3rem', color: '#ff6b9d' }}>
<i className="fa-solid fa-palette"></i>
</div>
<h5 className="text-white fw-6 mb-2">Design</h5>
</div>
</div>
<div className="col-6 col-md-3 text-center mb-4">
<div className="job-category-card" style={{
padding: '2rem 1rem',
background: 'rgba(255,255,255,0.05)',
borderRadius: '12px',
border: '1px solid rgba(255,255,255,0.1)',
transition: 'all 0.3s ease'
}}>
<div className="icon-wrapper mb-3" style={{ fontSize: '3rem', color: '#ffd93d' }}>
<i className="fa-solid fa-chart-line"></i>
</div>
<h5 className="text-white fw-6 mb-2">Business</h5>
</div>
</div>
<div className="col-6 col-md-3 text-center mb-4">
<div className="job-category-card" style={{
padding: '2rem 1rem',
background: 'rgba(255,255,255,0.05)',
borderRadius: '12px',
border: '1px solid rgba(255,255,255,0.1)',
transition: 'all 0.3s ease'
}}>
<div className="icon-wrapper mb-3" style={{ fontSize: '3rem', color: '#a78bfa' }}>
<i className="fa-solid fa-users"></i>
</div>
<h5 className="text-white fw-6 mb-2">Operations</h5>
</div>
</div>
</div>
</div>
<ul className="social">
<li>
<Link
href="https://www.linkedin.com/company/gnxtech"
target="_blank"
aria-label="connect with us on linkedin"
>
<i className="fa-brands fa-linkedin-in"></i>
</Link>
</li>
<li>
<Link
href="https://github.com/gnxtech"
target="_blank"
aria-label="view our code on github"
>
<i className="fa-brands fa-github"></i>
</Link>
</li>
</ul>
<Link href="#scroll-to" className="scroll-to">
Scroll
<span className="arrow"></span>
</Link>
<span className="sm-c"></span>
<span className="sm-c sm-cl"></span>
</section>
);
};
export default CareerBanner;

View File

@@ -0,0 +1,65 @@
"use client";
import dynamic from "next/dynamic";
const SmoothScroll = dynamic(() => import("../../shared/layout/animations/SmoothScroll"), {
ssr: false,
});
const ParallaxImage = dynamic(() => import("../../shared/layout/animations/ParallaxImage"), {
ssr: false,
});
const FadeImageBottom = dynamic(() => import("../../shared/layout/animations/FadeImageBottom"), {
ssr: false,
});
const ButtonHoverAnimation = dynamic(
() => import("../../shared/layout/animations/ButtonHoverAnimation"),
{
ssr: false,
}
);
const VanillaTiltHover = dynamic(
() => import("../../shared/layout/animations/VanillaTiltHover"),
{
ssr: false,
}
);
const SplitTextAnimations = dynamic(
() => import("../../shared/layout/animations/SplitTextAnimations"),
{
ssr: false,
}
);
const ScrollToElement = dynamic(() => import("../../shared/layout/animations/ScrollToElement"), {
ssr: false,
});
const AppearDown = dynamic(() => import("../../shared/layout/animations/AppearDown"), {
ssr: false,
});
const FadeAnimations = dynamic(() => import("../../shared/layout/animations/FadeAnimations"), {
ssr: false,
});
const CareerInitAnimations = () => {
return (
<>
<SmoothScroll />
<ParallaxImage />
<FadeImageBottom />
<ButtonHoverAnimation />
<VanillaTiltHover />
<SplitTextAnimations />
<ScrollToElement />
<AppearDown />
<FadeAnimations />
</>
);
};
export default CareerInitAnimations;

View File

@@ -0,0 +1,67 @@
"use client";
import { useState, useEffect, useRef } from "react";
const CareerScrollProgressButton = () => {
useEffect(() => {
window.scroll(0, 0);
}, []);
const [scrollProgress, setScrollProgress] = useState(0);
const [isActive, setIsActive] = useState(false);
const scrollRef = useRef<HTMLButtonElement>(null);
const handleScroll = () => {
const totalHeight = document.body.scrollHeight - window.innerHeight;
const progress = (window.scrollY / totalHeight) * 100;
setScrollProgress(progress);
setIsActive(window.scrollY > 50);
};
const handleProgressClick = () => {
window.scrollTo({
top: 0,
behavior: "smooth",
});
};
useEffect(() => {
window.scrollTo(0, 0);
window.addEventListener("scroll", handleScroll);
handleScroll();
return () => {
window.removeEventListener("scroll", handleScroll);
};
}, []);
return (
<button
ref={scrollRef}
className={`progress-wrap ${isActive ? " active-progress" : " "}`}
onClick={handleProgressClick}
title="Go To Top"
>
<span></span>
<svg
className="progress-circle svg-content"
width="100%"
height="100%"
viewBox="-1 -1 102 102"
>
<path
d="M50,1 a49,49 0 0,1 0,98 a49,49 0 0,1 0,-98"
stroke="#3887FE"
strokeWidth="4"
fill="none"
style={{
strokeDasharray: "308.66px",
strokeDashoffset: `${308.66 - scrollProgress * 3.0866}px`,
}}
/>
</svg>
</button>
);
};
export default CareerScrollProgressButton;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,681 @@
"use client";
import { useState, useEffect } from "react";
import { JobPosition } from "@/lib/api/careerService";
import JobApplicationForm from "./JobApplicationForm";
interface JobSingleProps {
job: JobPosition;
}
const JobSingle = ({ job }: JobSingleProps) => {
const [showApplicationForm, setShowApplicationForm] = useState(false);
// Prevent body scroll when modal is open
useEffect(() => {
if (showApplicationForm) {
// Get scrollbar width to prevent layout shift
const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;
// Save current scroll position
const scrollY = window.scrollY;
// Prevent background scroll
document.body.style.position = 'fixed';
document.body.style.top = `-${scrollY}px`;
document.body.style.left = '0';
document.body.style.right = '0';
document.body.style.overflow = 'hidden';
if (scrollbarWidth > 0) {
document.body.style.paddingRight = `${scrollbarWidth}px`;
}
} else {
// Get the scroll position from body top
const scrollY = parseInt(document.body.style.top || '0') * -1;
// Restore scroll
document.body.style.position = '';
document.body.style.top = '';
document.body.style.left = '';
document.body.style.right = '';
document.body.style.overflow = '';
document.body.style.paddingRight = '';
// Restore scroll position
window.scrollTo(0, scrollY);
}
// Cleanup on unmount
return () => {
const scrollY = parseInt(document.body.style.top || '0') * -1;
document.body.style.position = '';
document.body.style.top = '';
document.body.style.left = '';
document.body.style.right = '';
document.body.style.overflow = '';
document.body.style.paddingRight = '';
if (scrollY > 0) {
window.scrollTo(0, scrollY);
}
};
}, [showApplicationForm]);
const formatSalary = () => {
if (job.salary_min && job.salary_max) {
return `${job.salary_currency} ${job.salary_min}-${job.salary_max} ${job.salary_period}`;
} else if (job.salary_min) {
return `From ${job.salary_currency} ${job.salary_min} ${job.salary_period}`;
} else if (job.salary_max) {
return `Up to ${job.salary_currency} ${job.salary_max} ${job.salary_period}`;
}
return "Competitive";
};
const scrollToForm = () => {
setShowApplicationForm(true);
setTimeout(() => {
const formElement = document.getElementById('application-form');
if (formElement) {
formElement.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
}, 100);
};
return (
<>
{/* Job Header Banner */}
<section className="job-header pt-80 pt-md-100 pt-lg-120 pb-60 pb-md-70 pb-lg-80" style={{
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
position: 'relative'
}}>
<div className="container">
<div className="row">
<div className="col-12">
<div className="job-header-content" style={{ color: '#ffffff' }}>
<div className="mb-12 mb-md-16">
<span className="badge" style={{
backgroundColor: 'rgba(255,255,255,0.2)',
color: '#ffffff',
padding: '6px 12px',
borderRadius: '20px',
fontSize: '12px',
fontWeight: '500',
textTransform: 'none',
letterSpacing: '1px',
display: 'inline-block'
}}>
{job.department || 'Career Opportunity'}
</span>
</div>
<h1 className="fw-7 mb-16 mb-md-20 mb-lg-24" style={{
fontSize: 'clamp(1.75rem, 5vw, 3.5rem)',
lineHeight: '1.2',
color: '#ffffff'
}}>
{job.title}
</h1>
<div className="job-meta d-flex flex-wrap" style={{
fontSize: 'clamp(13px, 2vw, 16px)',
gap: 'clamp(12px, 2vw, 16px)'
}}>
<div className="meta-item d-flex align-items-center">
<span className="material-symbols-outlined me-1 me-md-2" style={{ fontSize: 'clamp(18px, 3vw, 24px)' }}>location_on</span>
<span>{job.location}</span>
</div>
<div className="meta-item d-flex align-items-center">
<span className="material-symbols-outlined me-1 me-md-2" style={{ fontSize: 'clamp(18px, 3vw, 24px)' }}>work</span>
<span className="d-none d-sm-inline">{job.employment_type.replace('-', ' ').replace(/\b\w/g, l => l.toUpperCase())}</span>
<span className="d-sm-none">
{job.employment_type.split('-')[0].charAt(0).toUpperCase() + job.employment_type.split('-')[0].slice(1)}
</span>
</div>
<div className="meta-item d-flex align-items-center">
<span className="material-symbols-outlined me-1 me-md-2" style={{ fontSize: 'clamp(18px, 3vw, 24px)' }}>group</span>
<span className="d-none d-sm-inline">{job.open_positions} {job.open_positions === 1 ? 'Position' : 'Positions'}</span>
<span className="d-sm-none">{job.open_positions} {job.open_positions === 1 ? 'Pos' : 'Pos'}</span>
</div>
{job.experience_required && (
<div className="meta-item d-flex align-items-center d-none d-md-flex">
<span className="material-symbols-outlined me-2">school</span>
<span>{job.experience_required}</span>
</div>
)}
</div>
</div>
</div>
</div>
</div>
</section>
{/* Job Content Section */}
<section className="job-single pb-80 pb-md-100 pb-lg-120 sticky-wrapper" style={{ marginTop: 'clamp(-30px, -5vw, -40px)' }}>
<div className="container">
<div className="row vertical-column-gap">
<div className="col-12 col-lg-8 mb-4 mb-lg-0">
<div className="j-d-content" style={{
backgroundColor: 'white',
borderRadius: 'clamp(8px, 2vw, 12px)',
padding: 'clamp(20px, 4vw, 40px)',
boxShadow: '0 10px 40px rgba(0,0,0,0.08)'
}}>
<div className="intro" style={{
borderBottom: '2px solid #f0f0f0',
paddingBottom: 'clamp(20px, 3vw, 30px)',
marginBottom: 'clamp(20px, 3vw, 30px)'
}}>
<h3 className="fw-6 mb-12 mb-md-16 text-secondary" style={{ fontSize: 'clamp(18px, 3vw, 24px)' }}>
About This Position
</h3>
{job.short_description && (
<p style={{
color: '#666',
lineHeight: '1.8',
fontSize: 'clamp(14px, 2vw, 16px)'
}}>
{job.short_description}
</p>
)}
</div>
{job.about_role && (
<div className="group mb-32 mb-md-40">
<div className="d-flex align-items-center mb-16 mb-md-20">
<span className="material-symbols-outlined me-2" style={{
color: '#667eea',
fontSize: 'clamp(22px, 4vw, 28px)'
}}>info</span>
<h4 className="mt-8 text-secondary fw-6 mb-0" style={{ fontSize: 'clamp(16px, 3vw, 20px)' }}>
About This Role
</h4>
</div>
<p style={{
color: '#555',
lineHeight: '1.8',
fontSize: 'clamp(14px, 2vw, 16px)'
}}>{job.about_role}</p>
</div>
)}
{job.requirements && job.requirements.length > 0 && (
<div className="group mb-32 mb-md-40">
<div className="d-flex align-items-center mb-16 mb-md-20">
<span className="material-symbols-outlined me-2" style={{
color: '#667eea',
fontSize: 'clamp(22px, 4vw, 28px)'
}}>task_alt</span>
<h4 className="mt-8 text-secondary fw-6 mb-0" style={{ fontSize: 'clamp(16px, 3vw, 20px)' }}>
Requirements
</h4>
</div>
<ul style={{ listStyle: 'none', padding: 0 }}>
{job.requirements.map((req, index) => (
<li key={index} className="mb-2" style={{
paddingLeft: 'clamp(20px, 4vw, 30px)',
position: 'relative',
color: '#555',
lineHeight: '1.8',
fontSize: 'clamp(14px, 2vw, 16px)'
}}>
<span style={{
position: 'absolute',
left: '0',
top: 'clamp(6px, 1.5vw, 8px)',
width: 'clamp(5px, 1vw, 6px)',
height: 'clamp(5px, 1vw, 6px)',
backgroundColor: '#667eea',
borderRadius: '50%'
}}></span>
{req}
</li>
))}
</ul>
</div>
)}
{job.responsibilities && job.responsibilities.length > 0 && (
<div className="group mb-32 mb-md-40">
<div className="d-flex align-items-center mb-16 mb-md-20">
<span className="material-symbols-outlined me-2" style={{ color: '#667eea', fontSize: 'clamp(22px, 4vw, 28px)' }}>assignment</span>
<h4 className="mt-8 text-secondary fw-6 mb-0" style={{ fontSize: 'clamp(16px, 3vw, 20px)' }}>
Key Responsibilities
</h4>
</div>
<ul style={{ listStyle: 'none', padding: 0 }}>
{job.responsibilities.map((resp, index) => (
<li key={index} className="mb-2" style={{
paddingLeft: 'clamp(20px, 4vw, 30px)',
position: 'relative',
color: '#555',
lineHeight: '1.8',
fontSize: 'clamp(14px, 2vw, 16px)'
}}>
<span style={{
position: 'absolute',
left: '0',
top: 'clamp(6px, 1.5vw, 8px)',
width: 'clamp(5px, 1vw, 6px)',
height: 'clamp(5px, 1vw, 6px)',
backgroundColor: '#667eea',
borderRadius: '50%'
}}></span>
{resp}
</li>
))}
</ul>
</div>
)}
{job.qualifications && job.qualifications.length > 0 && (
<div className="group mb-32 mb-md-40">
<div className="d-flex align-items-center mb-16 mb-md-20">
<span className="material-symbols-outlined me-2" style={{ color: '#667eea', fontSize: 'clamp(22px, 4vw, 28px)' }}>workspace_premium</span>
<h4 className="mt-8 text-secondary fw-6 mb-0" style={{ fontSize: 'clamp(16px, 3vw, 20px)' }}>
Qualifications
</h4>
</div>
<ul style={{ listStyle: 'none', padding: 0 }}>
{job.qualifications.map((qual, index) => (
<li key={index} className="mb-2" style={{
paddingLeft: 'clamp(20px, 4vw, 30px)',
position: 'relative',
color: '#555',
lineHeight: '1.8',
fontSize: 'clamp(14px, 2vw, 16px)'
}}>
<span style={{
position: 'absolute',
left: '0',
top: 'clamp(6px, 1.5vw, 8px)',
width: 'clamp(5px, 1vw, 6px)',
height: 'clamp(5px, 1vw, 6px)',
backgroundColor: '#667eea',
borderRadius: '50%'
}}></span>
{qual}
</li>
))}
</ul>
</div>
)}
{job.bonus_points && job.bonus_points.length > 0 && (
<div className="group mb-32 mb-md-40">
<div className="d-flex align-items-center mb-16 mb-md-20">
<span className="material-symbols-outlined me-2" style={{ color: '#667eea', fontSize: 'clamp(22px, 4vw, 28px)' }}>stars</span>
<h4 className="mt-8 text-secondary fw-6 mb-0" style={{ fontSize: 'clamp(16px, 3vw, 20px)' }}>
Nice to Have
</h4>
</div>
<ul style={{ listStyle: 'none', padding: 0 }}>
{job.bonus_points.map((bonus, index) => (
<li key={index} className="mb-2" style={{
paddingLeft: 'clamp(20px, 4vw, 30px)',
position: 'relative',
color: '#555',
lineHeight: '1.8',
fontSize: 'clamp(14px, 2vw, 16px)'
}}>
<span style={{
position: 'absolute',
left: '0',
top: 'clamp(6px, 1.5vw, 8px)',
width: 'clamp(5px, 1vw, 6px)',
height: 'clamp(5px, 1vw, 6px)',
backgroundColor: '#667eea',
borderRadius: '50%'
}}></span>
{bonus}
</li>
))}
</ul>
</div>
)}
{job.benefits && job.benefits.length > 0 && (
<div className="group mb-32 mb-md-40">
<div className="d-flex align-items-center mb-16 mb-md-20">
<span className="material-symbols-outlined me-2" style={{ color: '#667eea', fontSize: 'clamp(22px, 4vw, 28px)' }}>card_giftcard</span>
<h4 className="mt-8 text-secondary fw-6 mb-0" style={{ fontSize: 'clamp(16px, 3vw, 20px)' }}>
What We Offer
</h4>
</div>
<ul style={{ listStyle: 'none', padding: 0 }}>
{job.benefits.map((benefit, index) => (
<li key={index} className="mb-2" style={{
paddingLeft: 'clamp(20px, 4vw, 30px)',
position: 'relative',
color: '#555',
lineHeight: '1.8',
fontSize: 'clamp(14px, 2vw, 16px)'
}}>
<span style={{
position: 'absolute',
left: '0',
top: 'clamp(6px, 1.5vw, 8px)',
width: 'clamp(5px, 1vw, 6px)',
height: 'clamp(5px, 1vw, 6px)',
backgroundColor: '#667eea',
borderRadius: '50%'
}}></span>
{benefit}
</li>
))}
</ul>
</div>
)}
</div>
</div>
<div className="col-12 col-lg-4">
<div className="j-d-sidebar" style={{
backgroundColor: 'white',
borderRadius: 'clamp(8px, 2vw, 12px)',
padding: 'clamp(20px, 4vw, 30px)',
boxShadow: '0 10px 40px rgba(0,0,0,0.08)',
position: 'sticky',
top: '20px'
}}>
<div className="intro mb-20 mb-md-30" style={{
borderBottom: '2px solid #f0f0f0',
paddingBottom: 'clamp(16px, 3vw, 20px)'
}}>
<span className="text-uppercase" style={{
color: '#667eea',
fontSize: 'clamp(11px, 2vw, 12px)',
fontWeight: '600',
letterSpacing: '2px'
}}>
JOB DETAILS
</span>
</div>
<div className="content">
<div className="detail-item mb-16 mb-md-24">
<div className="d-flex align-items-center mb-6 mb-md-8">
<span className="material-symbols-outlined me-2" style={{
color: '#667eea',
fontSize: 'clamp(18px, 3vw, 20px)'
}}>payments</span>
<p className="fw-6 mb-0" style={{
color: '#333',
fontSize: 'clamp(14px, 2vw, 15px)'
}}>Salary Range</p>
</div>
<p className="fw-5 mb-0" style={{
color: '#667eea',
fontSize: 'clamp(16px, 3vw, 18px)'
}}>
{formatSalary()}
</p>
{job.salary_additional && (
<p className="mt-6 mt-md-8" style={{
color: '#666',
fontSize: 'clamp(12px, 2vw, 14px)'
}}>
{job.salary_additional}
</p>
)}
</div>
<div className="detail-item mb-16 mb-md-24">
<div className="d-flex align-items-center mb-6 mb-md-8">
<span className="material-symbols-outlined me-2" style={{
color: '#667eea',
fontSize: 'clamp(18px, 3vw, 20px)'
}}>work</span>
<p className="fw-6 mb-0" style={{
color: '#333',
fontSize: 'clamp(14px, 2vw, 15px)'
}}>Employment Type</p>
</div>
<p style={{
color: '#666',
fontSize: 'clamp(13px, 2vw, 14px)'
}}>
{job.employment_type.replace('-', ' ').replace(/\b\w/g, l => l.toUpperCase())}
</p>
</div>
<div className="detail-item mb-16 mb-md-24">
<div className="d-flex align-items-center mb-6 mb-md-8">
<span className="material-symbols-outlined me-2" style={{
color: '#667eea',
fontSize: 'clamp(18px, 3vw, 20px)'
}}>location_on</span>
<p className="fw-6 mb-0" style={{
color: '#333',
fontSize: 'clamp(14px, 2vw, 15px)'
}}>Location</p>
</div>
<p style={{
color: '#666',
fontSize: 'clamp(13px, 2vw, 14px)'
}}>{job.location}</p>
</div>
<div className="detail-item mb-16 mb-md-24">
<div className="d-flex align-items-center mb-6 mb-md-8">
<span className="material-symbols-outlined me-2" style={{
color: '#667eea',
fontSize: 'clamp(18px, 3vw, 20px)'
}}>event</span>
<p className="fw-6 mb-0" style={{
color: '#333',
fontSize: 'clamp(14px, 2vw, 15px)'
}}>Start Date</p>
</div>
<p style={{
color: '#666',
fontSize: 'clamp(13px, 2vw, 14px)'
}}>{job.start_date}</p>
</div>
<div className="detail-item mb-16 mb-md-24">
<div className="d-flex align-items-center mb-6 mb-md-8">
<span className="material-symbols-outlined me-2" style={{
color: '#667eea',
fontSize: 'clamp(18px, 3vw, 20px)'
}}>groups</span>
<p className="fw-6 mb-0" style={{
color: '#333',
fontSize: 'clamp(14px, 2vw, 15px)'
}}>Openings</p>
</div>
<p style={{
color: '#666',
fontSize: 'clamp(13px, 2vw, 14px)'
}}>
{job.open_positions} {job.open_positions === 1 ? 'Position' : 'Positions'} Available
</p>
</div>
</div>
<div className="cta mt-20 mt-md-30">
<button
onClick={scrollToForm}
className="btn w-100 apply-btn"
style={{
backgroundColor: 'white',
color: '#333',
border: '2px solid #667eea',
padding: 'clamp(12px, 2vw, 15px) clamp(20px, 4vw, 30px)',
fontSize: 'clamp(14px, 2vw, 16px)',
fontWeight: '600',
borderRadius: 'clamp(6px, 1.5vw, 8px)',
transition: 'all 0.3s ease',
cursor: 'pointer'
}}
onMouseEnter={(e) => {
e.currentTarget.style.backgroundColor = '#FFD700';
e.currentTarget.style.borderColor = '#FFD700';
e.currentTarget.style.color = '#333';
e.currentTarget.style.transform = 'translateY(-2px)';
}}
onMouseLeave={(e) => {
e.currentTarget.style.backgroundColor = 'white';
e.currentTarget.style.borderColor = '#667eea';
e.currentTarget.style.color = '#333';
e.currentTarget.style.transform = 'translateY(0)';
}}
>
<span className="d-none d-sm-inline">Apply for This Position</span>
<span className="d-sm-none">Apply Now</span>
</button>
<p className="text-center mt-12 mt-md-16" style={{
color: '#999',
fontSize: 'clamp(11px, 2vw, 13px)'
}}>
<span className="d-none d-sm-inline">Application takes ~5 minutes</span>
<span className="d-sm-none">~5 min</span>
</p>
<a
href="/career"
className="btn w-100 mt-12 mt-md-16"
style={{
backgroundColor: 'transparent',
color: '#667eea',
border: '2px solid #e0e0e0',
padding: 'clamp(10px, 2vw, 12px) clamp(20px, 4vw, 30px)',
fontSize: 'clamp(13px, 2vw, 14px)',
fontWeight: '500',
borderRadius: 'clamp(6px, 1.5vw, 8px)',
transition: 'all 0.3s ease',
cursor: 'pointer',
textDecoration: 'none',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
gap: 'clamp(6px, 1.5vw, 8px)'
}}
onMouseEnter={(e) => {
e.currentTarget.style.backgroundColor = '#f5f5f5';
e.currentTarget.style.borderColor = '#667eea';
}}
onMouseLeave={(e) => {
e.currentTarget.style.backgroundColor = 'transparent';
e.currentTarget.style.borderColor = '#e0e0e0';
}}
>
<span className="material-symbols-outlined" style={{ fontSize: 'clamp(16px, 3vw, 18px)' }}>arrow_back</span>
<span className="d-none d-sm-inline">Back to Career Page</span>
<span className="d-sm-none">Back</span>
</a>
</div>
</div>
</div>
</div>
</div>
</section>
{/* Application Form Modal/Popup */}
{showApplicationForm && (
<>
{/* Backdrop Overlay */}
<div
style={{
position: 'fixed',
top: 0,
left: 0,
right: 0,
bottom: 0,
backgroundColor: 'rgba(0, 0, 0, 0.6)',
zIndex: 9998,
animation: 'fadeIn 0.3s ease-in-out'
}}
onClick={() => setShowApplicationForm(false)}
aria-hidden="true"
/>
{/* Modal Container */}
<div
role="dialog"
aria-modal="true"
aria-labelledby="application-form-title"
tabIndex={-1}
style={{
position: 'fixed',
top: 0,
left: 0,
right: 0,
bottom: 0,
zIndex: 9999,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
padding: 'clamp(10px, 2vw, 20px)',
overflow: 'hidden',
animation: 'fadeIn 0.3s ease-in-out'
}}
onClick={(e) => {
// Close when clicking the container background
if (e.target === e.currentTarget) {
setShowApplicationForm(false);
}
}}
onKeyDown={(e) => {
// Close on ESC key
if (e.key === 'Escape') {
setShowApplicationForm(false);
}
}}
ref={(el) => {
if (el) {
setTimeout(() => el.focus(), 100);
}
}}
>
<div
style={{
backgroundColor: 'white',
borderRadius: '16px',
width: '100%',
maxWidth: '900px',
maxHeight: '90vh',
display: 'flex',
flexDirection: 'column',
boxShadow: '0 20px 60px rgba(0,0,0,0.3)',
position: 'relative',
animation: 'slideUp 0.3s ease-out',
outline: 'none',
overflow: 'hidden',
touchAction: 'none'
}}
onClick={(e) => e.stopPropagation()}
onTouchStart={(e) => e.stopPropagation()}
onTouchMove={(e) => e.stopPropagation()}
>
<JobApplicationForm job={job} onClose={() => setShowApplicationForm(false)} />
</div>
</div>
{/* Animation Styles */}
<style>{`
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes slideUp {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
`}</style>
</>
)}
</>
);
};
export default JobSingle;

View File

@@ -0,0 +1,121 @@
"use client";
import Link from "next/link";
import { useJobs } from "@/lib/hooks/useCareer";
const OpenPosition = () => {
const { jobs, loading, error } = useJobs();
if (loading) {
return (
<section className="op-position pt-120 pb-120" id="scroll-to">
<div className="container">
<div className="row">
<div className="col-12">
<div className="intro mb-60">
<h2 className="mt-8 fw-7 title-anim text-secondary">
Open Positions
</h2>
</div>
</div>
<div className="col-12 mt-60">
<p className="text-center">Loading positions...</p>
</div>
</div>
</div>
</section>
);
}
if (error) {
return (
<section className="op-position pt-120 pb-120" id="scroll-to">
<div className="container">
<div className="row">
<div className="col-12">
<div className="intro mb-60">
<h2 className="mt-8 fw-7 title-anim text-secondary">
Open Positions
</h2>
</div>
</div>
<div className="col-12 mt-60">
<p className="text-center text-danger">Error loading positions. Please try again later.</p>
</div>
</div>
</div>
</section>
);
}
if (jobs.length === 0) {
return (
<section className="op-position pt-120 pb-120" id="scroll-to">
<div className="container">
<div className="row">
<div className="col-12">
<div className="intro mb-60">
<h2 className="mt-8 fw-7 title-anim text-secondary">
Open Positions
</h2>
</div>
</div>
<div className="col-12 mt-60">
<p className="text-center">No open positions at the moment. Please check back later.</p>
</div>
</div>
</div>
</section>
);
}
return (
<section className="op-position pt-120 pb-120" id="scroll-to">
<div className="container">
<div className="row">
<div className="col-12">
<div className="intro mb-60">
<h2 className="mt-8 fw-7 title-anim text-secondary">
Open Positions
</h2>
</div>
</div>
<div className="col-12 mt-60">
{jobs.map((job, index) => (
<div key={job.id} className="op-position-single appear-down">
<div className="row vertical-column-gap align-items-center">
<div className="col-12 col-sm-2">
<span className="fw-7 text-xl text-tertiary">
{String(index + 1).padStart(2, '0')}
</span>
</div>
<div className="col-12 col-sm-5">
<h4 className="fw-7">
<Link href={`/career/${job.slug}`}>{job.title}</Link>
</h4>
</div>
<div className="col-12 col-sm-3">
<div className="roles">
<span className="text-tertiary fw-5 text-xl">
({job.open_positions.toString().padStart(2, '0')} Open {job.open_positions === 1 ? 'Role' : 'Roles'})
</span>
</div>
</div>
<div className="col-12 col-sm-2">
<div className="cta text-start text-sm-end">
<Link href={`/career/${job.slug}`}>
<span className="material-symbols-outlined">east</span>
</Link>
</div>
</div>
</div>
</div>
))}
</div>
</div>
</div>
</section>
);
};
export default OpenPosition;

View File

@@ -0,0 +1,85 @@
import Image from "next/legacy/image";
import time from "@/public/images/time.png";
import trans from "@/public/images/trans.png";
import support from "@/public/images/support.png";
import skill from "@/public/images/skill.png";
const Thrive = () => {
return (
<section className="thrive pt-120 pb-120 bg-black fade-wrapper">
<div className="container">
<div className="row">
<div className="col-12">
<div className="intro">
<h2 className="mt-8 fw-7 title-anim text-white">
What lets us thrive together
</h2>
</div>
</div>
</div>
<div className="row vertical-column-gap-lg mt-60">
<div className="col-12 col-md-6 fade-top">
<div className="thumb">
<Image src={time} alt="Image" width={80} height={80} />
</div>
<div className="content mt-40">
<h4 className="mt-8 title-anim fw-7 text-white mb-16">
Flexible workday
</h4>
<p className="cur-lg text-quinary">
We understand that productivity thrives in balance. Our flexible work arrangements
empower you to structure your day for optimal performance while maintaining work-life
harmony. Whether remote, hybrid, or on-site, we trust our teams to deliver excellence.
</p>
</div>
</div>
<div className="col-12 col-md-6 fade-top">
<div className="thumb">
<Image src={trans} alt="Image" width={80} height={80} />
</div>
<div className="content mt-40">
<h4 className="mt-8 title-anim fw-7 text-white mb-16">
Transparency
</h4>
<p className="cur-lg text-quinary">
Open communication is the foundation of our culture. We believe in clear goal-setting,
honest feedback, and accessible leadership. Every team member has visibility into
company objectives, strategic decisions, and how their contributions drive enterprise success.
</p>
</div>
</div>
<div className="col-12 col-md-6 fade-top">
<div className="thumb">
<Image src={support} alt="Image" width={80} height={80} />
</div>
<div className="content mt-40">
<h4 className="mt-8 title-anim fw-7 text-white mb-16">Support</h4>
<p className="cur-lg text-quinary">
Your success is our priority. From comprehensive onboarding to continuous mentorship,
we provide enterprise-grade resources, cutting-edge tools, and dedicated support systems.
Our collaborative environment ensures you&apos;re never alone in tackling complex challenges.
</p>
</div>
</div>
<div className="col-12 col-md-6 fade-top">
<div className="thumb">
<Image src={skill} alt="Image" width={80} height={80} />
</div>
<div className="content mt-40">
<h4 className="mt-8 title-anim fw-7 text-white mb-16">
Growth Skill
</h4>
<p className="cur-lg text-quinary">
Invest in your future with our comprehensive professional development programs. Access
industry certifications, advanced training workshops, and leadership development initiatives.
We champion continuous learning and provide clear pathways for career advancement.
</p>
</div>
</div>
</div>
</div>
</section>
);
};
export default Thrive;