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 ,
2025-05-27 11:12:21 +07:00
startDate : "Sep 2023" ,
endDate : "Jan 2024" ,
company : "Universitas Negeri Malang" ,
position : "Assistant Lecturer" ,
type : "Seasonal" ,
location : "Malang, Indonesia" ,
2025-05-26 23:09:29 +07:00
description :
2025-05-27 11:12:21 +07:00
"Assisted in teaching and mentoring students in algorithms and data structures, focusing on practical applications and problem-solving techniques. Developed course materials and provided support in lab sessions." ,
2025-05-27 17:46:46 +07:00
skills : [ "Python" , "C" , "Algorithms" , "Data Structures" , "Mentoring" ] ,
2025-05-26 23:09:29 +07:00
} ,
{
id : 2 ,
2025-05-27 11:12:21 +07:00
startDate : "Jul 2024" ,
endDate : "Jan 2025" ,
company : "Outlier AI" ,
2025-05-26 23:09:29 +07:00
position : "AI Trainer" ,
2025-05-27 11:12:21 +07:00
type : "Freelance (Remote)" ,
location : "Oakland, California" ,
2025-05-26 23:09:29 +07:00
description :
2025-05-27 11:12:21 +07:00
"Trained LLM models using RLFH, focusing on enhancing their understanding of human language and improving their response accuracy. Collaborated with a team of AI specialists to refine model performance and ensure high-quality outputs." ,
skills : [ "Generative AI" , "RLFH" , "LLM" , "Prompt Engineering" , "Teamwork" ] ,
2025-05-26 23:09:29 +07:00
} ,
{
id : 3 ,
startDate : "Jun 2023" ,
2025-05-27 11:12:21 +07:00
endDate : "Feb 2025" ,
company : "PUI-PT DLI" ,
position : "Fullstack Developer" ,
2025-05-26 23:09:29 +07:00
type : "Freelance" ,
2025-05-27 11:12:21 +07:00
location : "Malang, Indonesia" ,
2025-05-26 23:09:29 +07:00
description :
2025-05-27 11:12:21 +07:00
"Crafted and maintained web applications using Laravel, ensuring high performance and responsiveness. Collaborated with designers and other developers to create seamless user experiences." ,
skills : [ "Laravel" , "MySQL" , "PHP" , "JavaScript" , "Teamwork" ] ,
2025-05-26 23:09:29 +07:00
} ,
{
id : 4 ,
2025-05-27 11:12:21 +07:00
startDate : "Apr 2025" ,
endDate : "Jul 2025" ,
company : "Vektorian Labophase" ,
position : "Front-end Developer" ,
type : "Freelance" ,
location : "Malang, Indonesia" ,
2025-05-26 23:09:29 +07:00
description :
2025-05-27 11:12:21 +07:00
"Developed and maintained web applications using Next.js. Focused on creating responsive and user-friendly interfaces while ensuring backend functionality. Collaborated with backend and designers to implement modern UI/UX principles." ,
skills : [ "Next.js" , "Typescript" , "Teamwork" ] ,
2025-05-26 23:09:29 +07:00
} ,
{
id : 5 ,
2025-05-27 11:12:21 +07:00
startDate : "Apr 2023" ,
endDate : "Present" ,
company : "Self-Employed" ,
position : "Web Developer & AI Consultant" ,
type : "Freelance" ,
location : "Malang, Indonesia" ,
description :
"Developed 15+ web applications using Next.js, React, and Laravel. Provided AI consulting services, including creating custom LLMs. Focused on delivering high-quality, user-friendly applications and AI solutions." ,
skills : [
"Next.js" ,
"React" ,
"Laravel" ,
"MySQL" ,
"PostgreSQL" ,
"MongoDB" ,
"JavaScript" ,
"TypeScript" ,
"Gemini AI" ,
] ,
} ,
{
id : 6 ,
startDate : "Aug 2023" ,
endDate : "Present" ,
company : "PT Hafdzamedia Teknologi Aplikasi" ,
position : "Fullstack Web Developer" ,
type : "Part-time" ,
location : "Malang, Indonesia" ,
2025-05-26 23:09:29 +07:00
description :
2025-05-27 11:12:21 +07:00
"Developed and maintained web applications using React, Next.js, and Laravel. Focused on creating responsive and user-friendly interfaces while ensuring backend functionality." ,
skills : [
"React" ,
"Next.js" ,
"Laravel" ,
"MySQL" ,
"JavaScript" ,
"TypeScript" ,
"Teamwork" ,
] ,
} ,
{
id : 7 ,
startDate : "Feb 2025" ,
endDate : "Present" ,
company : "Joki Proyek" ,
position : "IT Implementation Specialist" ,
type : "Internship (Remote)" ,
location : "Malang, Indonesia" ,
description :
"Developed and maintained current internal web applications using Next.js & and Laravel. Fixed bugs and implemented new features to enhance user experience. Collaborated with the team to ensure smooth deployment and functionality of applications." ,
skills : [
"Next.js" ,
"Laravel" ,
"MySQL" ,
"PostgreSQL" ,
"JavaScript" ,
"TypeScript" ,
"MongoDB" ,
"Docker" ,
"Teamwork" ,
] ,
2025-05-26 23:09:29 +07:00
} ,
] ;
2025-01-15 12:08:54 +07:00
2025-05-27 11:12:21 +07:00
experiences . reverse ( ) ;
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 } }
2025-05-27 11:12:21 +07:00
className = { ` flex ps-10 md:ps-0 ${
2025-05-26 23:09:29 +07:00
isEven
2025-05-27 11:12:21 +07:00
? "md:justify-center md:translate-x-68"
: "md:justify-center md:-translate-x-68"
2025-05-26 23:09:29 +07:00
} 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-05-27 11:12:21 +07:00
< / div > < div className = "w-px h-8 bg-gray-500" > < / div >
2025-05-26 23:09:29 +07:00
< div className = "text-center" >
< div className = "text-sm font-medium text-gray-400" >
2025-05-27 11:12:21 +07:00
{ experience . location }
2025-05-26 23:09:29 +07:00
< / div >
2025-05-27 11:12:21 +07:00
< div className = "text-xs text-gray-300" > Location < / div >
2025-05-26 23:09:29 +07:00
< / 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
2025-05-27 11:12:21 +07:00
left - 0 - translate - x - 1 / 2 top - 5 ` }
2025-05-26 23:09:29 +07:00
/ >
{ /* 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
) ;
}