1- "use client"
1+ "use client" ;
22
33import React , { useEffect , useRef , useState } from "react" ;
44import { ScrollArea } from "@/components/ui/scroll-area" ;
@@ -9,94 +9,91 @@ import { Achievement } from "@/types/achievement";
99import "../timeline.css" ;
1010
1111interface Props {
12- userAchievements : PrsimaAchievement [ ] ;
13- allAchievements : Achievement [ ] ;
12+ userAchievements : PrsimaAchievement [ ] ;
13+ allAchievements : Achievement [ ] ;
1414}
1515
1616export default function AchievementProgress ( {
17- userAchievements,
18- allAchievements,
17+ userAchievements,
18+ allAchievements,
1919} : Props ) {
20- const updatedAllAch = [
21- ...allAchievements ,
22- {
23- type : "MORE_TO_COME" ,
24- image : "/static/first.png" ,
25- name : "More to come!" ,
26- } ,
27- {
28- type : "MORE_TO_COME_2" ,
29- image : "/static/first.png" ,
30- name : "More to come!" ,
31- } ,
32- ] ;
20+ const updatedAllAch = [
21+ ...allAchievements ,
22+ {
23+ type : "MORE_TO_COME" ,
24+ image : "/static/first.png" ,
25+ name : "More to come!" ,
26+ } ,
27+ {
28+ type : "MORE_TO_COME_2" ,
29+ image : "/static/first.png" ,
30+ name : "More to come!" ,
31+ } ,
32+ ] ;
3333
34- const timelineRef = useRef < HTMLDivElement > ( null ) ;
35- const [ animatedItems , setAnimatedItems ] = useState < string [ ] > ( [ ] ) ;
34+ return (
35+ < ScrollArea className = "rounded-md h-[300px] border-2 border-primary p-4 mt-10" >
36+ < h3 className = "text-primary font-special" > Achievement Progress</ h3 >
37+ < div className = "timeline" >
38+ { updatedAllAch . map ( ( achievement ) => {
39+ const timelineItemRef = useRef < HTMLDivElement > ( null ) ;
3640
37- useEffect ( ( ) => {
38- const observer = new IntersectionObserver (
39- ( entries ) => {
40- const inViewItems = entries
41- . filter ( ( entry ) => entry . isIntersecting )
42- . map ( ( entry ) => entry . target . id ) ;
41+ const [ isVisible , setIsVisible ] = useState < boolean > ( false ) ;
4342
44- setAnimatedItems ( ( prevItems ) => [ ...prevItems , ...inViewItems ] ) ;
45- } ,
46- {
43+ useEffect ( ( ) => {
44+ const observer = new IntersectionObserver (
45+ ( entries ) => {
46+ const [ entry ] = entries ;
47+ setIsVisible ( entry . isIntersecting ) ;
48+ } ,
49+ {
4750 root : null ,
48- rootMargin : "0px" ,
49- threshold : 0.5 , // Adjust this threshold as per your needs
50- }
51- ) ;
52-
53- const timelineItems = timelineRef . current ?. querySelectorAll ( ".timeline-item" ) ;
54- if ( timelineItems ) {
55- timelineItems . forEach ( ( item ) => observer . observe ( item ) ) ;
56- }
51+ rootMargin : "-20px" ,
52+ threshold : 0.1 , // Adjust this threshold as per your needs
53+ }
54+ ) ;
5755
58- return ( ) => {
59- if ( timelineItems ) {
60- timelineItems . forEach ( ( item ) => observer . unobserve ( item ) ) ;
56+ if ( timelineItemRef . current ) {
57+ observer . observe ( timelineItemRef . current ) ;
6158 }
62- } ;
63- } , [ ] ) ;
6459
60+ return ( ) => {
61+ if ( timelineItemRef . current ) {
62+ observer . unobserve ( timelineItemRef . current ) ;
63+ }
64+ } ;
65+ } , [ timelineItemRef ] ) ;
6566
66- return (
67- < ScrollArea className = "rounded-md h-[300px] border-2 border-primary p-4" >
68- < h3 className = "text-primary font-special" > Achievement Progress</ h3 >
69- < div className = "timeline" ref = { timelineRef } >
70- { updatedAllAch . map ( ( achievement ) => {
71- const isUnlocked = userAchievements . some (
72- ( userAchievement ) => userAchievement . achievementType === achievement . type
73- ) ;
67+ const isUnlocked = userAchievements . some (
68+ ( userAchievement ) =>
69+ userAchievement . achievementType === achievement . type
70+ ) ;
7471
75- const itemId = `achievement-${ achievement . type } ` ;
72+ const itemId = `achievement-${ achievement . type } ` ;
7673
77- return (
78- < div
79- key = { achievement . type }
80- id = { itemId }
81- className = { `timeline-item
82- ${ isUnlocked ? "unlocked" : "locked"
83- } shadow-lg shadow-accent opacity-100
84- ${ animatedItems . includes ( itemId ) ? "animate-fade" : "" } hover:animate-bounce hover:cursor-pointer` }
85- >
86- < div className = "timeline-content" >
87- { isUnlocked ? (
88- < Avatar >
89- < AvatarImage src = { achievement . image } />
90- </ Avatar >
91- ) : (
92- < BanIcon className = "text-primary" />
93- ) }
94- < p > { achievement . name } </ p >
95- </ div >
96- </ div >
97- ) ;
98- } ) }
74+ return (
75+ < div
76+ ref = { timelineItemRef }
77+ key = { achievement . type }
78+ id = { itemId }
79+ className = { `timeline-item ${ isUnlocked ? "unlocked" : "locked" } ${
80+ isVisible && "animate-fade"
81+ } shadow-lg shadow-accent opacity-100 `}
82+ >
83+ < div className = "timeline-content" >
84+ { isUnlocked ? (
85+ < Avatar >
86+ < AvatarImage src = { achievement . image } />
87+ </ Avatar >
88+ ) : (
89+ < BanIcon className = "text-primary" />
90+ ) }
91+ < p > { achievement . name } </ p >
92+ </ div >
9993 </ div >
100- </ ScrollArea >
101- ) ;
94+ ) ;
95+ } ) }
96+ </ div >
97+ </ ScrollArea >
98+ ) ;
10299}
0 commit comments