1
+ import React , { useState , useEffect } from "react" ;
2
+ import { ScrollArea } from "@/components/ui/scroll-area" ;
3
+ import { Tabs , TabsContent , TabsList , TabsTrigger } from "@/components/ui/tabs" ;
4
+ import { Rocket , Microscope , BarChart3 , Atom , Satellite , Zap , Globe , CircleDot , Building , Cpu , ChevronDownCircle } from "lucide-react" ;
5
+ import { useSession , useSupabaseClient } from "@supabase/auth-helpers-react" ;
6
+ import { useActivePlanet } from "@/context/ActivePlanet" ;
7
+ import { DataSourcesModal } from "@/components/Data/unlockNewDataSources" ;
8
+
9
+ const techIcons = {
10
+ "Advanced Propulsion" : Rocket ,
11
+ "Quantum Computing" : Atom ,
12
+ "Nano-fabrication" : Zap ,
13
+ "Fusion Reactor" : Satellite ,
14
+ "Dark Matter Detector" : Microscope ,
15
+ "Asteroid Mining" : Globe ,
16
+ } ;
17
+
18
+ type TechCategory = 'Structures' | 'Automatons' ;
19
+
20
+ type Technology = {
21
+ id : number ;
22
+ name : string ;
23
+ description : string ;
24
+ icon : React . ReactNode ;
25
+ requiredTech : number | null ;
26
+ category : TechCategory ;
27
+ requiresMission ?: number ;
28
+ item ?: number ;
29
+ } ;
30
+
31
+ interface SupabaseInventoryItem {
32
+ id : number ;
33
+ item : number ;
34
+ owner : string ;
35
+ quantity : number ;
36
+ anomaly : number ;
37
+ } ;
38
+
39
+ export function AdvancedTechTreeComponent ( ) {
40
+ const supabase = useSupabaseClient ( ) ;
41
+ const session = useSession ( ) ;
42
+
43
+ const { activePlanet } = useActivePlanet ( ) ;
44
+
45
+ const [ technologies , setTechnologies ] = useState < Technology [ ] > ( [ ] ) ;
46
+ const [ unlockedTechs , setUnlockedTechs ] = useState < number [ ] > ( [ ] ) ;
47
+ const [ filteredItems , setFilteredItems ] = useState < SupabaseInventoryItem [ ] > ( [ ] ) ;
48
+ const [ planetsWithItem , setPlanetsWithItem ] = useState < Array < { id : number ; content : string } > > ( [ ] ) ;
49
+
50
+ const fetchTechnologies = async ( ) => {
51
+ const structuresRes = await fetch ( "/api/gameplay/research/structures" ) ;
52
+ const structuresData = await structuresRes . json ( ) ;
53
+
54
+ const automatonsRes = await fetch ( "/api/gameplay/research/automatons" ) ;
55
+ const automatonsData = await automatonsRes . json ( ) ;
56
+
57
+ const combinedTechnologies : Technology [ ] = [
58
+ ...structuresData . map ( ( structure : any ) => ( {
59
+ id : structure . id ,
60
+ name : structure . name ,
61
+ description : structure . description || "No description available" ,
62
+ icon : < Building className = "w-6 h-6" /> ,
63
+ requiredTech : structure . requires || null ,
64
+ category : "Structures" as TechCategory ,
65
+ requiresMission : structure . requiresMission || null ,
66
+ item : structure . item ,
67
+ } ) ) ,
68
+ ...automatonsData . map ( ( automaton : any ) => ( {
69
+ id : automaton . id ,
70
+ name : automaton . name ,
71
+ description : "Automaton component or ability" ,
72
+ icon : < Cpu className = "w-6 h-6" /> ,
73
+ requiredTech : automaton . requires || null ,
74
+ category : "Automatons" as TechCategory ,
75
+ requiresMission : automaton . requiresMission || null ,
76
+ } ) ) ,
77
+ ] ;
78
+
79
+ setTechnologies ( combinedTechnologies ) ;
80
+ } ;
81
+
82
+ const fetchUserStructures = async ( ) => {
83
+ if ( ! session ?. user . id || ! activePlanet ?. id ) return ;
84
+
85
+ const { data : researchData , error : researchError } = await supabase
86
+ . from ( "researched" )
87
+ . select ( "tech_type, tech_id" )
88
+ . eq ( "user_id" , session ?. user . id ) ;
89
+
90
+ if ( researchError ) {
91
+ console . error ( "Error fetching user structures:" , researchError ) ;
92
+ return ;
93
+ }
94
+
95
+ const structureIds = researchData . map ( ( item : any ) => item . tech_id ) ;
96
+ const researchedTech = new Set ( structureIds ) ;
97
+
98
+ setUnlockedTechs ( Array . from ( researchedTech ) ) ;
99
+ } ;
100
+
101
+ const fetchPlanetsWithItem = async ( itemId : number ) => {
102
+ if ( ! session ?. user ?. id ) return ;
103
+
104
+ const { data, error } = await supabase
105
+ . from ( 'inventory' )
106
+ . select ( 'anomaly' )
107
+ . eq ( 'owner' , session . user . id )
108
+ . eq ( 'item' , itemId ) ;
109
+
110
+ if ( error ) {
111
+ console . error ( 'Error fetching planets with item:' , error ) ;
112
+ return ;
113
+ }
114
+
115
+ const anomalies = data ?. map ( ( inventoryItem : { anomaly : number } ) => inventoryItem . anomaly ) || [ ] ;
116
+
117
+ const { data : planetsData , error : planetsError } = await supabase
118
+ . from ( 'anomalies' )
119
+ . select ( 'id, content' )
120
+ . in ( 'id' , anomalies ) ;
121
+
122
+ if ( planetsError ) {
123
+ console . error ( 'Error fetching planet names:' , planetsError ) ;
124
+ return ;
125
+ }
126
+
127
+ const planetNames = planetsData . map ( ( planet : { id : number ; content : string } ) => ( {
128
+ id : planet . id ,
129
+ content : planet . content ,
130
+ } ) ) ;
131
+ setPlanetsWithItem ( planetNames ) ;
132
+ } ;
133
+
134
+ const canUnlock = ( techId : number ) => {
135
+ const tech = technologies . find ( ( t ) => t . id === techId ) ;
136
+ return tech ?. requiredTech === null || ( tech ?. requiredTech && unlockedTechs . includes ( tech . requiredTech ) ) ;
137
+ } ;
138
+
139
+ useEffect ( ( ) => {
140
+ fetchTechnologies ( ) ;
141
+ fetchUserStructures ( ) ;
142
+ } , [ session ?. user . id , activePlanet ] ) ;
143
+
144
+ return (
145
+ < div className = "bg-gradient-to-br from-[#2C4F64] to-[#303F51] text-[#F7F5E9] container mx-auto p-4 " >
146
+ < h1 className = "text-4xl font-bold mb-6 text-transparent bg-clip-text bg-gradient-to-r from-[#5FCBC3] to-[#FF695D]" >
147
+ Research Station
148
+ </ h1 >
149
+ < Tabs defaultValue = "Structures" className = "w-full" >
150
+ < TabsList className = "grid w-full grid-cols-3 bg-gradient-to-r from-[#2C4F64] to-[#3A5A6D]" >
151
+ < TabsTrigger value = "Structures" > Structures</ TabsTrigger >
152
+ < TabsTrigger value = "Automatons" > Automatons</ TabsTrigger >
153
+ < TabsTrigger value = "DataSources" > Data Sources</ TabsTrigger >
154
+ </ TabsList >
155
+
156
+ < TabsContent value = "Structures" >
157
+ < ScrollArea className = "h-[calc(100vh-200px)] rounded-md border border-[#5FCBC3] p-4" >
158
+ < div className = "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4" >
159
+ { technologies
160
+ . filter ( ( tech ) => tech . category === "Structures" )
161
+ . map ( ( tech ) => (
162
+ < div
163
+ key = { tech . id }
164
+ className = { `p-4 rounded-md ${ unlockedTechs . includes ( tech . id ) ? 'bg-green-500' : 'bg-red-500' } ` }
165
+ onClick = { ( ) => fetchPlanetsWithItem ( tech . item ?? 0 ) }
166
+ >
167
+ < div className = "flex items-center space-x-4" >
168
+ { tech . icon }
169
+ < h3 className = "text-xl font-bold" > { tech . name } </ h3 >
170
+ </ div >
171
+ < p > { tech . description } </ p >
172
+ < button
173
+ className = "text-xs px-2 py-1 rounded bg-[#5FCBC3] text-[#303F51]"
174
+ disabled = { ! canUnlock ( tech . id ) }
175
+ >
176
+ { unlockedTechs . includes ( tech . id ) ? "Researched" : "Research" }
177
+ </ button >
178
+
179
+ < ChevronDownCircle className = "mt-1" />
180
+
181
+ { planetsWithItem . length > 0 && (
182
+ < div className = "mt-4 p-2 bg-[#F7F5E9] text-[#303F51] rounded-md" >
183
+ < h4 className = "text-md font-semibold mb-2" > Planets with this technology:</ h4 >
184
+ < ul >
185
+ { planetsWithItem . map ( ( planet ) => (
186
+ < li key = { planet . id } > Planet: { planet . content } (ID: { planet . id } )</ li >
187
+ ) ) }
188
+ </ ul >
189
+ </ div >
190
+ ) }
191
+ </ div >
192
+ ) ) }
193
+
194
+ </ div >
195
+ </ ScrollArea >
196
+ </ TabsContent >
197
+
198
+ < TabsContent value = "Automatons" >
199
+ < ScrollArea className = "h-[calc(100vh-200px)] rounded-md border border-[#5FCBC3] p-4" >
200
+ < div className = "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4" >
201
+ { technologies
202
+ . filter ( ( tech ) => tech . category === "Automatons" )
203
+ . map ( ( tech ) => (
204
+ < div
205
+ key = { tech . id }
206
+ className = { `p-4 rounded-md ${ unlockedTechs . includes ( tech . id ) ? 'bg-green-500' : 'bg-red-500' } ` }
207
+ onClick = { ( ) => fetchPlanetsWithItem ( tech . item ?? 0 ) }
208
+ >
209
+ < div className = "flex items-center space-x-4" >
210
+ { tech . icon }
211
+ < h3 className = "text-xl font-bold" > { tech . name } </ h3 >
212
+ </ div >
213
+ < p > { tech . description } </ p >
214
+ < button
215
+ className = "text-xs px-2 py-1 rounded bg-[#5FCBC3] text-[#303F51]"
216
+ disabled = { ! canUnlock ( tech . id ) }
217
+ >
218
+ { unlockedTechs . includes ( tech . id ) ? "Researched" : "Research" }
219
+ </ button >
220
+ </ div >
221
+ ) ) }
222
+ </ div >
223
+ </ ScrollArea >
224
+ </ TabsContent >
225
+ < TabsContent value = "DataSources" >
226
+ < ScrollArea className = "h-[calc(100vh-200px)] rounded-md border border-[#5FCBC3] p-4" >
227
+ < DataSourcesModal structureId = "3102" structure = "Rover" />
228
+ < DataSourcesModal structureId = "3103" structure = "Telescope" />
229
+ < DataSourcesModal structureId = "3104" structure = "Zoodex" />
230
+ < DataSourcesModal structureId = "3105" structure = "LIDAR" />
231
+ </ ScrollArea >
232
+ </ TabsContent >
233
+ </ Tabs >
234
+ </ div >
235
+ ) ;
236
+ } ;
0 commit comments