Skip to content

Commit aeedda6

Browse files
committed
🎿🖇️ ↝ [SSM-62 SSM-57]: Voting now works for uploads, and research is combined with data modals
1 parent e03c966 commit aeedda6

File tree

6 files changed

+488
-75
lines changed

6 files changed

+488
-75
lines changed

app/scenes/research/page.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import React from "react";
44
import ModernTechTree from "@/components/Structures/Research/TechTree";
5+
import { AdvancedTechTreeComponent } from "@/components/Structures/Research/OldTechTree";
56

67
export default function ResearchPage() {
78
return (
@@ -11,7 +12,7 @@ export default function ResearchPage() {
1112
src="/assets/Backdrops/Earth.png"
1213
/>
1314
<div className="relative">
14-
<ModernTechTree />
15+
<AdvancedTechTreeComponent />
1516
</div>
1617
</div>
1718
);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
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+
};

components/Structures/Research/TechTree.tsx

+13-12
Original file line numberDiff line numberDiff line change
@@ -30,33 +30,34 @@ type Technology = {
3030
category: TechCategory
3131
requiresMission?: number
3232
item?: number
33-
}
33+
};
3434

3535
type SupabaseInventoryItem = {
3636
id: number
3737
item: number
3838
owner: string
3939
quantity: number
4040
anomaly: number
41-
}
41+
};
4242

4343
export default function ModernTechTree() {
44-
const supabase = useSupabaseClient()
45-
const session = useSession()
46-
const { activePlanet } = useActivePlanet()
44+
const supabase = useSupabaseClient();
45+
const session = useSession();
46+
47+
const { activePlanet } = useActivePlanet();
4748

48-
const [technologies, setTechnologies] = React.useState<Technology[]>([])
49-
const [unlockedTechs, setUnlockedTechs] = React.useState<number[]>([])
50-
const [filteredItems, setFilteredItems] = React.useState<SupabaseInventoryItem[]>([])
51-
const [openTech, setOpenTech] = React.useState<number | null>(null)
49+
const [technologies, setTechnologies] = React.useState<Technology[]>([]);
50+
const [unlockedTechs, setUnlockedTechs] = React.useState<number[]>([]);
51+
const [filteredItems, setFilteredItems] = React.useState<SupabaseInventoryItem[]>([]);
52+
const [openTech, setOpenTech] = React.useState<number | null>(null);
5253

5354
const sections = [
5455
{ id: "discovery", name: "Discovery Stations", icon: Microscope },
5556
{ id: "spacecraft", name: "Spacecraft", icon: Rocket },
5657
{ id: "resources", name: "Resource Management", icon: BarChart3 },
5758
{ id: "structures", name: "Structures", icon: Building },
5859
{ id: "automatons", name: "Automatons", icon: Cpu },
59-
]
60+
];
6061

6162
const fetchTechnologies = async () => {
6263
const structuresRes = await fetch("/api/gameplay/research/structures")
@@ -100,13 +101,13 @@ export default function ModernTechTree() {
100101
if (researchError) {
101102
console.error("Error fetching user structures:", researchError)
102103
return
103-
}
104+
};
104105

105106
const structureIds = researchData.map((item: any) => item.tech_id)
106107
const researchedTech = new Set(structureIds)
107108

108109
setUnlockedTechs(Array.from(researchedTech))
109-
}
110+
};
110111

111112
const fetchPlanetsWithItem = async (itemId: number) => {
112113
if (!session?.user?.id) return

0 commit comments

Comments
 (0)