22import { Tilt } from "react-tilt" ;
33import { motion } from "framer-motion" ;
44import { useTranslation } from 'react-i18next' ;
5+ import { useEffect , useState } from 'react' ;
56
67import { styles } from "../../styles" ; // Importing styles
78import { github , githubFallback } from "../../assets" ; // Importing GitHub icon
89import { SectionWrapper } from "../../hoc" ; // Importing a section wrapper HOC
9- import generateData from "../../constants" ; // Importing data (projects)
1010import { fadeIn , textVariant } from "../../utils/motion" ; // Importing motion-related utilities
1111
1212// ProjectCard component for displaying individual project cards
1313const ProjectCard = ( {
1414 index,
1515 name,
1616 description,
17- tags,
18- image,
19- imageFallback,
20- source_code_link,
17+ html_url,
18+ updated_at,
2119} ) => {
2220 return (
2321 < motion . div variants = { fadeIn ( "up" , "spring" , index * 0.5 , 0.75 ) } >
@@ -33,18 +31,9 @@ const ProjectCard = ({
3331 { /* Container for the project image */ }
3432 < div className = 'relative w-full h-[230px]' >
3533 { /* Project image */ }
36- < img
37- src = { image }
38- srcSet = { `${ image } 1x, ${ imageFallback } 2x` }
39- alt = 'project_image'
40- className = 'w-full h-full object-cover rounded-2xl'
41- loading = "lazy"
42- />
43-
44- { /* GitHub icon for the source code link */ }
4534 < div className = 'absolute inset-0 flex justify-end m-3 card-img_hover' >
4635 < div
47- onClick = { ( ) => window . open ( source_code_link , "_blank" ) }
36+ onClick = { ( ) => window . open ( html_url , "_blank" ) }
4837 className = 'black-gradient w-10 h-10 rounded-full flex justify-center items-center cursor-pointer'
4938 >
5039 < img
@@ -61,19 +50,8 @@ const ProjectCard = ({
6150 { /* Project details */ }
6251 < div className = 'mt-5' >
6352 < h1 className = 'text-textColor font-bold text-[24px]' > { name } </ h1 >
64- < p className = 'mt-2 dark:text-secondary text-textColor text-[14px]' > { description } </ p >
65- </ div >
66-
67- { /* Project tags */ }
68- < div className = 'mt-4 flex flex-wrap gap-2' >
69- { tags . map ( ( tag ) => (
70- < p
71- key = { `${ name } -${ tag . name } ` }
72- className = { `text-[14px] ${ tag . color } ` }
73- >
74- #{ tag . name }
75- </ p >
76- ) ) }
53+ < p className = 'mt-2 dark:text-secondary text-textColor text-[14px]' > { description || 'No description available' } </ p >
54+ < p className = 'mt-2 text-sm text-gray-500' > Last updated: { new Date ( updated_at ) . toLocaleDateString ( ) } </ p >
7755 </ div >
7856 </ Tilt >
7957 </ motion . div >
@@ -83,7 +61,34 @@ const ProjectCard = ({
8361// Works component displaying a section with a list of projects
8462const Works = ( ) => {
8563 const { t } = useTranslation ( ) ;
86- const { projects } = generateData ( ) ; // Fetching projects data from constants
64+ const [ projects , setProjects ] = useState ( [ ] ) ;
65+ const [ loading , setLoading ] = useState ( true ) ;
66+ const [ error , setError ] = useState ( null ) ;
67+
68+ useEffect ( ( ) => {
69+ const fetchLatestProjects = async ( ) => {
70+ try {
71+ const response = await fetch ( 'https://api.github.com/users/clementbobin/repos?sort=updated&direction=desc&per_page=3' , {
72+ headers : {
73+ 'Accept' : 'application/vnd.github.v3+json'
74+ }
75+ } ) ;
76+
77+ if ( ! response . ok ) {
78+ throw new Error ( `Failed to fetch GitHub projects: ${ response . status } ` ) ;
79+ }
80+
81+ const data = await response . json ( ) ;
82+ setProjects ( data ) ;
83+ } catch ( err ) {
84+ setError ( err . message ) ;
85+ } finally {
86+ setLoading ( false ) ;
87+ }
88+ } ;
89+
90+ fetchLatestProjects ( ) ;
91+ } , [ ] ) ;
8792
8893 return (
8994 < section >
@@ -103,12 +108,17 @@ const Works = () => {
103108 </ motion . p >
104109 </ div >
105110
106- { /* Displaying individual project cards */ }
107- < div className = 'mt-20 flex flex-wrap gap-7' >
108- { projects . map ( ( project , index ) => (
109- < ProjectCard key = { `project-${ index } ` } index = { index } { ...project } />
110- ) ) }
111- </ div >
111+ { loading ? (
112+ < div className = "mt-20" > Loading latest projects...</ div >
113+ ) : error ? (
114+ < div className = "mt-20 text-red-500" > Error: { error } </ div >
115+ ) : (
116+ < div className = 'mt-20 flex flex-wrap gap-7' >
117+ { projects . map ( ( project , index ) => (
118+ < ProjectCard key = { `project-${ index } ` } index = { index } { ...project } />
119+ ) ) }
120+ </ div >
121+ ) }
112122 </ section >
113123 ) ;
114124} ;
0 commit comments