2025-05-26 23:09:29 +07:00
"use client" ;
2025-01-15 12:08:54 +07:00
import Hr from "@/components/Hr" ;
2025-05-26 23:09:29 +07:00
import { motion , AnimatePresence } from "framer-motion" ;
import { useState } from "react" ;
const experiences = [
{
id : 1 ,
period : "2023 - Present" ,
startDate : "Jan 2023" ,
endDate : "Present" ,
company : "PT Hafdzamedia Teknologi Aplikasi" ,
position : "Fullstack Web Developer" ,
type : "Part-time" ,
description :
"Responsible for building and maintaining scalable web applications using the latest technologies. Collaborated with cross-functional teams to deliver high-quality solutions that meet business requirements." ,
skills : [ "React" , "Next.js" , "Laravel" , "MySql" ] ,
} ,
{
id : 2 ,
period : "2024 - Present" ,
startDate : "Mar 2024" ,
endDate : "Present" ,
company : "Outlier" ,
position : "AI Trainer" ,
type : "Freelance" ,
description :
"Crafted and refined chatbot prompts using prompt engineering and RLHF techniques to improve the AI responses in English and Indonesian, leading to more accurate and contextually relevant interactions." ,
skills : [ "Generative AI" , "Prompt Engineering" , "Problem Solving" ] ,
} ,
{
id : 3 ,
period : "2023 - Present" ,
startDate : "Jun 2023" ,
endDate : "Present" ,
company : "Self-Employed" ,
position : "Web Developer" ,
type : "Freelance" ,
description :
"Specialized in crafting innovative solutions using Laravel and Next.js, enhancing client satisfaction and project efficiency. Contributed expertise in both frontend and backend development during collaborative team projects." ,
skills : [ "React" , "Next.js" , "Laravel" , "MySql" ] ,
} ,
{
id : 4 ,
period : "2022 - 2023" ,
startDate : "Sep 2022" ,
endDate : "Aug 2023" ,
company : "TechStart Solutions" ,
position : "Frontend Developer" ,
type : "Internship" ,
description :
"Developed responsive user interfaces using React and TypeScript. Worked closely with UX designers to implement pixel-perfect designs and improved website performance by 40%." ,
skills : [ "React" , "TypeScript" , "CSS3" , "Figma" ] ,
} ,
{
id : 5 ,
period : "2021 - 2022" ,
startDate : "Oct 2021" ,
endDate : "Sep 2022" ,
company : "Digital Innovation Labs" ,
position : "Junior Developer" ,
type : "Contract" ,
description :
"Built REST APIs using Node.js and Express. Implemented database schemas and optimized queries for better performance. Participated in code reviews and agile development processes." ,
skills : [ "Node.js" , "Express" , "MongoDB" , "Git" ] ,
} ,
] ;
2025-01-15 12:08:54 +07:00
function Title ( ) {
return (
< div className = "mt-16 flex flex-col justify-start items-center w-full pl-10 md:pl-32" >
< div className = "flex justify-center items-center flex-col my-5 self-start" >
< Hr variant = "long" > < / Hr >
< motion.h1
className = "text-3xl font-bold mt-3"
initial = { {
opacity : 0 ,
x : - 200 ,
} }
whileInView = { {
opacity : 1 ,
x : 0 ,
} }
transition = { {
delay : 0.7 ,
type : "spring" ,
} } >
Profesional Experience
< / motion.h1 >
< / div >
< / div >
) ;
}
2025-05-26 23:09:29 +07:00
function TimelineCard ( { experience , index , isEven } ) {
2025-01-15 12:08:54 +07:00
return (
2025-05-26 23:09:29 +07:00
< motion.div
initial = { { opacity : 0 , y : - 20 } }
whileInView = { { opacity : 1 , y : 0 } }
transition = { { delay : index * 0.15 , duration : 0.5 } }
className = { ` flex ps-5 md:ps-0 ${
isEven
? "md:justify-center md:translate-x-60"
: "md:justify-center md:-translate-x-60"
} justify - center mb - 4 ` }>
< div className = "bg-gradient-to-r from-black to-gray-800 text-white px-12 py-3 rounded-xl shadow-lg border border-gray-600 min-w-max" >
< div className = "flex items-center justify-center gap-6" >
< div className = "text-center" >
< div className = "text-sm font-bold" > { experience . startDate } < / div >
< div className = "text-xs text-gray-300" > Start < / div >
< / div >
< div className = "w-px h-8 bg-gray-500" > < / div >
< div className = "text-center" >
< div className = "text-sm font-bold" > { experience . endDate } < / div >
< div className = "text-xs text-gray-300" > End < / div >
2025-01-15 12:08:54 +07:00
< / div >
2025-05-26 23:09:29 +07:00
< div className = "w-px h-8 bg-gray-500" > < / div >
< div className = "text-center" >
< div className = "text-sm font-medium text-gray-400" >
{ experience . type }
< / div >
< div className = "text-xs text-gray-300" > Type < / div >
< / div >
< / div >
< / div >
< / motion.div >
) ;
}
function ExperienceCard ( { experience , index , isEven } ) {
return (
< motion.div
initial = { { opacity : 0 , y : 50 } }
whileInView = { { opacity : 1 , y : 0 } }
transition = { { delay : index * 0.2 , duration : 0.6 } }
className = { ` relative group ${
isEven ? "md:ml-auto md:pl-12" : "md:mr-auto md:pr-12"
} md : w - 1 / 2 ` }>
{ " " }
{ /* Card */ }
< div
className = { ` bg-white/20 backdrop-blur-sm border border-gray-300/30 rounded-2xl p-6 shadow-lg
hover : shadow - xl hover : bg - white / 30 transition - all duration - 300 ml - 12 md : ml - 0 ` }>
{ /* Company & Position */ }
< div className = "mb-4" >
< h3 className = "font-bold text-xl text-black mb-1" >
{ experience . company }
< / h3 >
< h4 className = "font-medium text-lg text-gray-700" >
{ experience . position }
< span className = "text-sm font-normal text-gray-500 ml-2" >
• { experience . type }
< / span >
< / h4 >
< / div >
{ /* Description */ }
< p className = "text-gray-600 text-justify leading-relaxed mb-4" >
{ experience . description }
< / p >
{ /* Skills */ }
< div className = "flex flex-wrap gap-2" >
{ experience . skills . map ( ( skill , idx ) => (
< span
key = { idx }
className = "bg-gray-200/60 hover:bg-gray-300/60 border border-gray-400/40 text-black px-3 py-1 rounded-full text-sm font-medium transition-all duration-300 backdrop-blur-sm hover:scale-105" >
{ skill }
< / span >
) ) }
< / div >
< / div >
< / motion.div >
) ;
}
function Wrapper ( { children } ) {
return (
< div className = "mx-auto container px-6 py-10" >
< div
className = "flex justify-center items-center flex-col" >
{ children }
< / div >
2025-01-15 12:08:54 +07:00
< / div >
) ;
}
2024-08-30 15:19:08 +07:00
export default function Experience ( ) {
2025-05-26 23:09:29 +07:00
const [ showAll , setShowAll ] = useState ( false ) ;
const displayedExperiences = showAll ? experiences : experiences . slice ( 0 , 3 ) ;
2024-08-30 15:19:08 +07:00
return (
2025-01-15 12:08:54 +07:00
< >
2025-05-26 23:09:29 +07:00
< Title / >
2025-01-15 12:08:54 +07:00
< Wrapper >
2025-05-26 23:09:29 +07:00
{ " " }
< div className = "relative w-full max-w-6xl mx-auto" >
{ " " }
{ /* Timeline line - hidden on mobile, visible on md+ */ }
< div className = "hidden md:block absolute left-1/2 transform -translate-x-1/2 w-1 bg-gradient-to-b from-black via-gray-400 to-transparent h-full" > < / div >
{ /* Mobile timeline line */ }
< div className = "md:hidden absolute left-0 w-1 bg-gradient-to-b from-black via-gray-400 to-transparent h-full" > < / div > { " " }
{ /* Experience cards */ }
< div className = "space-y-12 md:space-y-16 relative" >
< AnimatePresence >
{ displayedExperiences . map ( ( experience , index ) => (
< div key = { experience . id } className = "relative" >
{ /* Timeline period card - flows naturally above content */ }
< TimelineCard
experience = { experience }
index = { index }
isEven = { index % 2 === 1 }
/ >
2024-08-30 15:19:08 +07:00
2025-05-26 23:09:29 +07:00
{ /* Timeline dot - positioned at the start of the experience card */ }
< div
className = { ` absolute w-6 h-6 bg-black rounded-full border-4 border-white shadow-lg z-30
md : left - 1 / 2 md : - translate - x - 1 / 2 md : top - 4
left - 0 - translate - x - 1 / 2 top - 2 ` }
/ >
{ /* Experience content card */ }
< ExperienceCard
experience = { experience }
index = { index }
isEven = { index % 2 === 1 }
/ >
< / div >
) ) }
< / AnimatePresence >
2024-08-30 15:19:08 +07:00
< / div >
2025-05-26 23:09:29 +07:00
{ /* Expand/Collapse button */ }
{ experiences . length > 3 && (
< motion.div
className = "flex justify-center mt-12"
initial = { { opacity : 0 } }
whileInView = { { opacity : 1 } }
transition = { { delay : 0.5 } } >
< button
onClick = { ( ) => setShowAll ( ! showAll ) }
className = " bg - black hover : bg - gray - 800 text - white px - 8 py - 3 rounded - full font - medium
transition - all duration - 300 hover : scale - 105 shadow - lg flex items - center gap - 2 " >
{ showAll ? (
< >
Show Less
< svg
className = "w-4 h-4 transform rotate-180"
fill = "none"
stroke = "currentColor"
viewBox = "0 0 24 24" >
< path
strokeLinecap = "round"
strokeLinejoin = "round"
strokeWidth = { 2 }
d = "M19 9l-7 7-7-7"
/ >
< / svg >
< / >
) : (
< >
View More Experience
< svg
className = "w-4 h-4"
fill = "none"
stroke = "currentColor"
viewBox = "0 0 24 24" >
< path
strokeLinecap = "round"
strokeLinejoin = "round"
strokeWidth = { 2 }
d = "M19 9l-7 7-7-7"
/ >
< / svg >
< / >
) }
< / button >
< / motion.div >
) } { " " }
{ /* Gradient fade effect at bottom */ }
{ ! showAll && (
< div className = "absolute bottom-0 left-0 right-0 h-32 bg-gradient-to-t from-stale-300 to-transparent pointer-events-none" > < / div >
) }
2024-08-30 15:19:08 +07:00
< / div >
2025-01-15 12:08:54 +07:00
< / Wrapper >
< / >
2024-08-30 15:19:08 +07:00
) ;
}