1- import { useState } from 'react' ;
1+ import { useState , useEffect } from 'react' ;
22import { mockAliens } from '../data/mockAliens' ;
33import type { AlienProfile } from '../data/mockAliens' ;
44import { useAppContext } from '../context/AppContext' ;
55import ProfileModal from './ProfileModal' ;
66import MatchOverlay from './MatchOverlay' ;
77
88export default function OrbitSystem ( ) {
9- const { preferences, addMatch } = useAppContext ( ) ;
9+ const { preferences, addMatch, matches } = useAppContext ( ) ;
1010 const [ selectedAlien , setSelectedAlien ] = useState < AlienProfile | null > ( null ) ;
1111 const [ matchedAlien , setMatchedAlien ] = useState < AlienProfile | null > ( null ) ;
12+ const [ dismissedIds , setDismissedIds ] = useState < Set < string > > ( new Set ( ) ) ;
13+
14+ // Keep exactly 5 slots for the 5 orbit tracks
15+ const [ activeIds , setActiveIds ] = useState < ( string | null ) [ ] > ( [ null , null , null , null , null ] ) ;
16+
17+ useEffect ( ( ) => {
18+ if ( ! preferences ) return ;
19+
20+ // Available aliens are those within distance, not matched, not dismissed, and not currently active
21+ const available = mockAliens . filter ( a =>
22+ a . distanceAU <= preferences . maxDistanceAU &&
23+ ! matches . find ( m => m . id === a . id ) &&
24+ ! dismissedIds . has ( a . id ) &&
25+ ! activeIds . includes ( a . id )
26+ ) ;
27+
28+ let changed = false ;
29+ const newActiveIds = [ ...activeIds ] ;
30+
31+ // Check each of the 5 tracks
32+ for ( let i = 0 ; i < 5 ; i ++ ) {
33+ const currentId = newActiveIds [ i ] ;
34+ // Check if the current alien in this track is still valid
35+ const isStillValid = currentId &&
36+ mockAliens . find ( a => a . id === currentId && a . distanceAU <= preferences . maxDistanceAU ) &&
37+ ! matches . find ( m => m . id === currentId ) &&
38+ ! dismissedIds . has ( currentId ) ;
39+
40+ if ( ! isStillValid ) {
41+ // The slot is empty or invalid, pull a new alien from available pool
42+ const nextAlien = available . shift ( ) ;
43+ newActiveIds [ i ] = nextAlien ? nextAlien . id : null ;
44+ changed = true ;
45+ }
46+ }
47+
48+ if ( changed ) {
49+ setActiveIds ( newActiveIds ) ;
50+ }
51+ } , [ preferences , matches , dismissedIds , activeIds ] ) ;
1252
1353 if ( ! preferences ) return null ;
1454
15- // Filter aliens based on max distance
16- const visibleAliens = mockAliens . filter ( a => a . distanceAU <= preferences . maxDistanceAU ) ;
17-
1855 const handleMatch = ( alien : AlienProfile ) => {
1956 addMatch ( alien ) ;
2057 setSelectedAlien ( null ) ;
2158 setMatchedAlien ( alien ) ;
2259 } ;
2360
61+ const handleDismiss = ( alien : AlienProfile ) => {
62+ setDismissedIds ( prev => {
63+ const newSet = new Set ( prev ) ;
64+ newSet . add ( alien . id ) ;
65+ return newSet ;
66+ } ) ;
67+ setSelectedAlien ( null ) ;
68+ } ;
69+
70+ const visibleAliens = mockAliens . filter ( a => activeIds . includes ( a . id ) ) ;
71+
2472 return (
2573 < >
2674 < style > { `
2775 @keyframes orbit {
28- from { transform: rotate(0deg) translateX(var(--radius)) rotate(0deg) ; }
29- to { transform: rotate(360deg) translateX(var(--radius)) rotate(-360deg) ; }
76+ from { offset-distance: 0% ; }
77+ to { offset-distance: 100% ; }
3078 }
3179 .orbit-ring {
3280 position: absolute;
@@ -39,14 +87,14 @@ export default function OrbitSystem() {
3987 }
4088 .orbit-item {
4189 position: absolute;
42- top: 50%;
43- left: 50%;
44- margin-top: -30px;
45- margin-left: -30px;
4690 width: 60px;
4791 height: 60px;
92+ margin-top: -30px; /* Center relative to offset path */
93+ margin-left: -30px;
4894 border-radius: 50%;
4995 cursor: pointer;
96+ offset-path: ellipse(var(--rx) var(--ry) at 50% 50%);
97+ offset-rotate: 0deg;
5098 animation: orbit var(--duration) linear infinite;
5199 }
52100 .orbit-avatar {
@@ -69,7 +117,7 @@ export default function OrbitSystem() {
69117 }
70118 ` } </ style >
71119
72- < div style = { { position : 'relative' , width : '100%' , maxWidth : '800px' , height : '600px ' , display : 'flex' , alignItems : 'center' , justifyContent : 'center' , overflow : 'hidden' } } >
120+ < div style = { { position : 'relative' , width : '100%' , maxWidth : '800px' , height : '500px ' , display : 'flex' , alignItems : 'center' , justifyContent : 'center' , overflow : 'hidden' } } >
73121
74122 { /* User Center */ }
75123 < div style = { {
@@ -90,27 +138,34 @@ export default function OrbitSystem() {
90138 </ div >
91139
92140 { /* Orbit Rings and Aliens */ }
93- { visibleAliens . map ( ( alien , i ) => {
94- // Calculate radius based on distance (min 80px, max 280px)
95- const radiusRatio = preferences . maxDistanceAU > 0 ? alien . distanceAU / preferences . maxDistanceAU : 1 ;
96- const radius = 80 + ( radiusRatio * 200 ) ;
97- const duration = 15 + ( radius / 10 ) ; // Slower orbit for further objects
98- const startAngle = ( i * ( 360 / visibleAliens . length ) ) ;
141+ { activeIds . map ( ( id , i ) => {
142+ if ( ! id ) return null ; // If no alien is available for this slot, don't render it
143+
144+ const alien = mockAliens . find ( a => a . id === id ) ;
145+ if ( ! alien ) return null ;
146+
147+ // Assign each slot to a distinct track (0 to 4)
148+ const rx = 120 + ( i * 65 ) ;
149+ const ry = 80 + ( i * 40 ) ;
150+ const duration = 15 + ( i * 8 ) ;
151+
152+ const delay = - 1 * ( i * ( duration / 5 ) ) ;
99153
100154 return (
101- < div key = { alien . id } >
155+ < div key = { `track- ${ i } - ${ alien . id } ` } >
102156 { /* Ring */ }
103- < div className = "orbit-ring" style = { { width : `${ radius * 2 } px` , height : `${ radius * 2 } px` } } />
157+ < div className = "orbit-ring" style = { { width : `${ rx * 2 } px` , height : `${ ry * 2 } px` } } />
104158
105159 { /* Profile */ }
106160 < div
107161 className = "orbit-item"
108162 onClick = { ( ) => setSelectedAlien ( alien ) }
109163 style = { {
110164 // @ts -ignore
111- '--radius' : `${ radius } px` ,
165+ '--rx' : `${ rx } px` ,
166+ '--ry' : `${ ry } px` ,
112167 '--duration' : `${ duration } s` ,
113- animationDelay : `- ${ startAngle } s` // Stagger start positions
168+ animationDelay : `${ delay } s`
114169 } }
115170 title = { `${ alien . name } (${ alien . distanceAU } AU)` }
116171 >
@@ -126,6 +181,7 @@ export default function OrbitSystem() {
126181 alien = { selectedAlien }
127182 onClose = { ( ) => setSelectedAlien ( null ) }
128183 onMatch = { handleMatch }
184+ onDismiss = { handleDismiss }
129185 />
130186 ) }
131187
0 commit comments