update
This commit is contained in:
144
frontEnd/components/pages/career/CareerBanner.tsx
Normal file
144
frontEnd/components/pages/career/CareerBanner.tsx
Normal 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;
|
||||
65
frontEnd/components/pages/career/CareerInitAnimations.tsx
Normal file
65
frontEnd/components/pages/career/CareerInitAnimations.tsx
Normal 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;
|
||||
@@ -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;
|
||||
1128
frontEnd/components/pages/career/JobApplicationForm.tsx
Normal file
1128
frontEnd/components/pages/career/JobApplicationForm.tsx
Normal file
File diff suppressed because it is too large
Load Diff
681
frontEnd/components/pages/career/JobSingle.tsx
Normal file
681
frontEnd/components/pages/career/JobSingle.tsx
Normal 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;
|
||||
121
frontEnd/components/pages/career/OpenPosition.tsx
Normal file
121
frontEnd/components/pages/career/OpenPosition.tsx
Normal 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;
|
||||
85
frontEnd/components/pages/career/Thrive.tsx
Normal file
85
frontEnd/components/pages/career/Thrive.tsx
Normal 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'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;
|
||||
Reference in New Issue
Block a user