diff --git a/.DS_Store b/.DS_Store index 6ba79a2b..89f97c4e 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/app/api/gameplay/communityStations/projects/31011/route.ts b/app/api/gameplay/communityStations/projects/31011/route.ts new file mode 100644 index 00000000..a2986909 --- /dev/null +++ b/app/api/gameplay/communityStations/projects/31011/route.ts @@ -0,0 +1,60 @@ +import { NextRequest, NextResponse } from 'next/server'; + +interface Project { + id: string; + name: string; + identifier: string; + missionRoute: number; +}; + +interface Mission { + id: string; + name: string; + type: string; + project: string; + missionRouteId?: number; +}; + +interface CommunityStationConfig { + stationName: string; + inventoryItemId: number; + projects: Project[]; + missions: Mission[]; +}; + +const greenhouseStation: CommunityStationConfig = { + stationName: "Greenhouse", + inventoryItemId: 31011, + projects: [ + { + id: "1", + name: "Wildwatch Burrowing Owls", + identifier: "zoodex-burrOwls", + missionRoute: 3000002, + }, + { + id: "2", + name: "Iguanas from Above", + identifier: "zoodex-iguanasFromAbove", + missionRoute: 3000004, + }, + ], + missions: [ + { + id: "1", + name: "Spot an owl in the wild", + type: "Upload", + project: "1", + }, + { + id: "2", + name: "Track iguana movement", + type: "Analysis", + project: "2", + }, + ], +}; + +export async function GET(req: NextRequest) { + return NextResponse.json(greenhouseStation); +}; \ No newline at end of file diff --git a/app/api/gameplay/communityStations/projects/route.ts b/app/api/gameplay/communityStations/projects/route.ts new file mode 100644 index 00000000..3afab814 --- /dev/null +++ b/app/api/gameplay/communityStations/projects/route.ts @@ -0,0 +1,110 @@ +import { NextRequest, NextResponse } from 'next/server'; +import React from 'react'; + +import { BurrowingOwl } from '@/components/Projects/Zoodex/burrowingOwls'; +import { ZoodexIguanas } from '@/components/Projects/Zoodex/iguanasFromAbove'; + +interface Project { + id: string; + name: string; + identifier: string; + component: React.ComponentType; + missionRoute: number; + structure: string; + // isUnlocked: boolean; // Uncomment if needed + // level: number; // Uncomment if needed +} + +interface Mission { + id: string; + name: string; + type: string; + // completionRate: number; // Uncomment if needed + project: string; + // level: number; // Uncomment if needed + // isUnlocked: boolean; // Uncomment if needed +} + +interface CommunityStationConfig { + stationName: string; + inventoryItemId: number; + projects: Project[]; + missions: Mission[]; +} + +const greenhouseStation: CommunityStationConfig = { + stationName: "Greenhouse", + inventoryItemId: 31011, + projects: [ + { + id: "1", + name: "Wildwatch Burrowing Owls", + identifier: "zoodex-burrowingOwls", + component: BurrowingOwl, + structure: "Zoodex", + missionRoute: 3000002, + }, + { + id: "2", + name: "Iguanas from Above", + identifier: "zoodex-iguanasFromAbove", + component: ZoodexIguanas, + structure: "Zoodex", + missionRoute: 3000004, + }, + ], + missions: [ + { + id: "1", + name: "Spot an owl in the wild", + type: "Upload", + project: "1", + }, + { + id: "2", + name: "Track iguana movement", + type: "Analysis", + project: "2", + }, + ], +}; + +const weatherBalloonStation: CommunityStationConfig = { + stationName: "Weather balloon", + inventoryItemId: 31012, + projects: [], + missions: [ + { + id: "1", + name: "Determine planet type to allow for population of relevant anomalies, and then attribute some clouds", + type: "Upload", + project: "1", + }, + ], +}; + +const spaceTelescopeStation: CommunityStationConfig = { + stationName: "Space telescope", + inventoryItemId: 31013, + projects: [], + missions: [ + { + id: "1", + name: "Map planet type based on lightcurve information", // and then we can attribute/participate other missions/projects", + type: "Upload", + project: "1", + }, + ], +}; + +export async function GET(req: NextRequest) { + const response = { + stations: [ + greenhouseStation, + weatherBalloonStation, + spaceTelescopeStation, + ], + }; + + return NextResponse.json(response); +}; \ No newline at end of file diff --git a/app/api/gameplay/inventory/route.ts b/app/api/gameplay/inventory/route.ts index 30da3551..6d24ecae 100644 --- a/app/api/gameplay/inventory/route.ts +++ b/app/api/gameplay/inventory/route.ts @@ -10,7 +10,7 @@ export interface InventoryItem { description: string; cost?: number; icon_url: string; - ItemCategory: string; + ItemCategory: string; parentItem?: number | null; itemLevel?: number; locationType?: string; @@ -84,6 +84,32 @@ const inventoryItems: InventoryItem[] = [ ItemCategory: "Structure", locationType: 'Surface', }, + + // Community stations + { + id: 31011, + name: "Greenhouse", + description: "Collect and study biological anomalies across multiple locations", + icon_url: "/assets/Items/Greenhouse.png", + ItemCategory: 'CommunityStation', + locationType: 'Surface', + }, + { + id: 31012, + name: "Weather balloon", + description: "Collect and study weather events and entities more closely in your planet's atmosphere", + icon_url: "/assets/Items/WeatherBalloon.png", + ItemCategory: 'CommunityStation', + locationType: 'Atmosphere', + }, + { + id: 31013, + name: "Space Telescope", + description: "Collect & compare discoveries more readily per-location", // to-update + icon_url: "/assets/Items/SpaceTelescope.png", + ItemCategory: 'CommunityStation', + locationType: 'Orbital', + }, // Tests { diff --git a/app/auth/onlineUsers.tsx b/app/auth/onlineUsers.tsx new file mode 100644 index 00000000..8c40caae --- /dev/null +++ b/app/auth/onlineUsers.tsx @@ -0,0 +1,49 @@ +'use client'; + +import React, { useState, useEffect } from "react"; +import { useSupabaseClient, useSession } from "@supabase/auth-helpers-react"; + +export default function OnlineUserList() { + const supabase = useSupabaseClient(); + const session = useSession(); // Session must be loaded first + const [onlineUsers, setOnlineUsers] = useState(0); + + useEffect(() => { + // Wait until session is ready + if (!session?.user?.id) return; + + const roomOne = supabase.channel('room_01', { + config: { + presence: { + key: session.user.id, // Ensure session user id is used correctly + }, + }, + }); + + roomOne + .on('presence', { event: 'sync' }, () => { + const currentPresenceState = roomOne.presenceState(); + const onlineUsersCount = Object.keys(currentPresenceState).length; + setOnlineUsers(onlineUsersCount); + }) + .on('presence', { event: 'join' }, ({ key, newPresences }) => { + console.log('User joined:', key, newPresences); + }) + .on('presence', { event: 'leave' }, ({ key, leftPresences }) => { + console.log('User left:', key, leftPresences); + }) + .subscribe(); + + // Clean up the subscription on unmount + return () => { + roomOne.unsubscribe(); + }; + }, [session?.user?.id, supabase]); + + return ( +
+
+

{onlineUsers} Online

+
+ ); +}; \ No newline at end of file diff --git a/app/layout.tsx b/app/layout.tsx index dc7f076e..01d8ab5f 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -14,10 +14,11 @@ import { Analytics } from "@vercel/analytics/react" import { MissionProvider } from "@/context/MissionContext"; import TutorialPopup from "../content/Dialogue/helpButton"; import AppLayout from "@/components/Layout/Layout"; +import Header from "@/components/ui/Header"; interface RootLayoutProps { children: ReactNode; -} +}; export default function RootLayout({ children }: RootLayoutProps) { const [supabaseClient] = useState(() => createPagesBrowserClient()); diff --git a/app/page.tsx b/app/page.tsx index 2700eace..4fc6b970 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,8 +1,6 @@ "use client" -import { OnboardingLayout } from "@/components/Template"; import { useSession, useSupabaseClient } from "@supabase/auth-helpers-react"; -import { Landing } from "@/components/landing"; import { useEffect, useState } from "react"; import LoginPage from "./auth/LoginModal"; import OnboardingWindow from "../components/(scenes)/chapters/(onboarding)/window"; diff --git a/app/scenes/globe/Structures.tsx b/app/scenes/globe/Structures.tsx index 277c587d..75d935e8 100644 --- a/app/scenes/globe/Structures.tsx +++ b/app/scenes/globe/Structures.tsx @@ -8,6 +8,7 @@ import { StructuresConfigForSandbox } from "@/constants/Structures/SandboxProper import { InventoryStructureItem, StructureItemDetail } from "@/types/Items"; import { useActivePlanet } from "@/context/ActivePlanet"; import "../../../styles/Anims/StarterStructureAnimations.css"; +import { CreateCommunityStation } from "@/components/Structures/Build/MakeCommunityStation"; interface StructuresOnPlanetProps { onStructuresFetch: ( @@ -105,6 +106,9 @@ export default function StructuresOnPlanet({ onStructuresFetch }: StructuresOnPl return (
+
+ +
{userStructuresOnPlanet.map((structure) => { const itemDetail = itemDetails.get(structure.item); @@ -136,7 +140,11 @@ export default function StructuresOnPlanet({ onStructuresFetch }: StructuresOnPl onClose={handleClose} /> )} - +
+
+ +
+
); }; \ No newline at end of file diff --git a/app/scenes/mining/page.tsx b/app/scenes/mining/page.tsx index b033ac3c..040b4616 100644 --- a/app/scenes/mining/page.tsx +++ b/app/scenes/mining/page.tsx @@ -8,6 +8,7 @@ import MineralsInventoryGrid from "@/components/Inventory/mineralsPanel"; import { MiningComponentComponent } from "@/components/Structures/Mining/Mining"; import { Card } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; +import StarnetLayout from "@/components/Layout/Starnet"; enum Step { MineralDeposits = "MINERAL_DEPOSITS", @@ -16,12 +17,14 @@ enum Step { export default function Mining() { return ( -
-
+ +
+
-
- -
+
+ +
+ ); }; @@ -42,28 +45,30 @@ function MiningScene() { }; return ( -
- {currentStep === Step.MineralDeposits && ( -
-
- + +
+ {currentStep === Step.MineralDeposits && ( +
+
+ +
-
- )} + )} - {currentStep === Step.MineralDetails && selectedDeposit && ( -
-
- - + {currentStep === Step.MineralDetails && selectedDeposit && ( +
+
+ + +
-
- )} -
+ )} +
+ ); }; \ No newline at end of file diff --git a/app/scenes/travel/page.tsx b/app/scenes/travel/page.tsx index 4c670e3b..58bd6e22 100644 --- a/app/scenes/travel/page.tsx +++ b/app/scenes/travel/page.tsx @@ -4,11 +4,14 @@ import React, { useEffect, useState, useCallback } from "react"; import { useSupabaseClient, useSession } from "@supabase/auth-helpers-react"; import { useActivePlanet } from "@/context/ActivePlanet"; import SwitchPlanet from "@/components/(scenes)/travel/SolarSystem"; +import StarnetLayout from "@/components/Layout/Starnet"; export default function Travel() { return ( -
-
-
+ +
+
+
+
) }; \ No newline at end of file diff --git a/app/starnet/consensus/page.tsx b/app/starnet/consensus/page.tsx new file mode 100644 index 00000000..a9a446e1 --- /dev/null +++ b/app/starnet/consensus/page.tsx @@ -0,0 +1,18 @@ +"use client"; + +import React, { useEffect, useState } from "react"; +import StarnetLayout from "@/components/Layout/Starnet"; +import { ExoplanetTransitHunter } from "@/components/Projects/Telescopes/ExoplanetC23"; +import MissionPathway from "@/components/Missions/Pathway"; +import ProfileCardModal from "@/components/profile/form"; +import { CommunityScienceStation } from "@/components/Structures/Community/StationModal"; +import { CreateCommunityStation } from "@/components/Structures/Build/MakeCommunityStation"; +import StationsOnPlanet from "@/components/Structures/Community/ViewAllStations"; + +export default function TestPage() { + return ( + + + + ); +}; \ No newline at end of file diff --git a/app/starnet/feed/page.tsx b/app/starnet/feed/page.tsx index d467a823..04f7f825 100644 --- a/app/starnet/feed/page.tsx +++ b/app/starnet/feed/page.tsx @@ -25,8 +25,9 @@ export default function Starnet() { try { const { data, error } = await supabase .from("classifications") - .select("*") - .eq("author", session.user.id); + .select("*, classificationConfiguration, classificationtype") + .eq("author", session.user.id) + .order("created_at", { ascending: false }); if (error) throw error; @@ -40,7 +41,9 @@ export default function Starnet() { images.push(media.uploadUrl); } - return { ...classification, images }; + const votes = classification.classificationConfiguration?.votes || 0; + + return { ...classification, images, votes }; }); setClassifications(processedData); @@ -76,7 +79,7 @@ export default function Starnet() { setClassifications((prevClassifications) => prevClassifications.map((classification) => classification.id === classificationId - ? { ...classification, votes: currentVotes + 1 } + ? { ...classification, votes: updatedConfig.votes } : classification ) ); @@ -105,6 +108,9 @@ export default function Starnet() { category={classification.category} tags={classification.tags || []} images={classification.images || []} + anomalyId={classification.anomaly} + classificationConfig={classification.classificationConfiguration} + classificationType={classification.classificationtype} // Pass classificationtype to child onVote={() => handleVote(classification.id, classification.classificationConfiguration)} /> )) diff --git a/app/starnet/requests/page.tsx b/app/starnet/requests/page.tsx index 570b5b7d..409969c0 100644 --- a/app/starnet/requests/page.tsx +++ b/app/starnet/requests/page.tsx @@ -1,6 +1,6 @@ import React from "react"; import StarnetLayout from "@/components/Layout/Starnet"; -import CommunityMissionList from "@/components/Missions/CommunityMissionsList"; +import CommunityMissionList from "@/components/Missions/Requests"; export default function CMEPage() { return ( diff --git a/app/tests/page.tsx b/app/tests/page.tsx index 66521667..f76a39ca 100644 --- a/app/tests/page.tsx +++ b/app/tests/page.tsx @@ -2,14 +2,25 @@ import React, { useEffect, useState } from "react"; import StarnetLayout from "@/components/Layout/Starnet"; -import { ExoplanetTransitHunter } from "@/components/Projects/Telescopes/ExoplanetC23"; -import MissionPathway from "@/components/Missions/Pathway"; -import ProfileCardModal from "@/components/profile/form"; +import ImageAnnotation from "@/components/Projects/(classifications)/Annotation"; export default function TestPage() { return ( - + <> ); -}; \ No newline at end of file +}; + +/* + + anomalies = {[ + { + id: "1", + name: "Hardened owl", + description: + "A hardened owl that is ready to be transported to another lush location.", + }, + ]} /> + +*/ \ No newline at end of file diff --git a/citizen b/citizen index 68080cc8..7a5bab54 160000 --- a/citizen +++ b/citizen @@ -1 +1 @@ -Subproject commit 68080cc89af4f173732e0cb40f99c9d2cfcc4feb +Subproject commit 7a5bab54fd4226707d5c6e647a4566ec9705a269 diff --git a/components/(scenes)/chapters/(onboarding)/window.tsx b/components/(scenes)/chapters/(onboarding)/window.tsx index d3949ee1..527a3c93 100644 --- a/components/(scenes)/chapters/(onboarding)/window.tsx +++ b/components/(scenes)/chapters/(onboarding)/window.tsx @@ -141,7 +141,6 @@ const OnboardingWindow = () => { return (
- {/* Left Panel - Desktop */}
{steps.map((step) => ( @@ -161,17 +160,11 @@ const OnboardingWindow = () => { ))}
- - {/* Right Panel */}
- {/* Header Component for Desktop */} -
- {/*
*/} -
- +
{currentStep ? ( ({}); - const [planetStats, setPlanetStats] = useState([]); - - useEffect(() => { - const fetchVisitedPlanets = async () => { - if (session?.user?.id) { - try { - const { data: missions, error } = await supabase - .from('missions') - .select('mission') - .eq('user', session.user.id); - - if (error) throw error; - - const visited = missions.reduce((acc: { [key: number]: boolean }, mission: { mission: number }) => { - acc[mission.mission] = true; - return acc; - }, {}); - - setVisitedPlanets(visited); - } catch (error: any) { - console.error('Error fetching missions:', error.message); - } - } - }; - - fetchVisitedPlanets(); - - const fetchPlanetStats = async () => { - try { - const response = await fetch('/api/gameplay/missions/planets/solarsystem/stats'); - const data = await response.json(); - setPlanetStats(data); - console.log(planetStats); - } catch (error) { - console.error('Error fetching planet stats:', error); - }; - }; - - fetchPlanetStats(); - }, [session, supabase]); - - const handleKeyDown = (e: KeyboardEvent) => { - if (e.key === 'ArrowLeft') { - setSelectedIndex((prev) => (prev === 0 ? planets.length - 1 : prev - 1)); - } else if (e.key === 'ArrowRight') { - setSelectedIndex((prev) => (prev === planets.length - 1 ? 0 : prev + 1)); - }; - }; - - useEffect(() => { - window.addEventListener('keydown', handleKeyDown); - return () => window.removeEventListener('keydown', handleKeyDown); - }, []); - - const selectedPlanet = planets[selectedIndex]; - - const getPosition = (index: number) => { - const totalPlanets = planets.length; - const angle = ((index - selectedIndex + totalPlanets) % totalPlanets) / totalPlanets * Math.PI; - const x = 50 - Math.cos(angle) * 50; - const y = 50 - Math.sin(angle) * 25; - return { x, y }; - }; - - const hasVisited = visitedPlanets[selectedPlanet.initialisationMissionId]; - const planetDetails = planetStats?.find((planet) => planet.id === selectedPlanet.initialisationMissionId); - - return ( -
-

Let's book your trip to

-
- - - -
- {planets.map((planet, index) => { - const { x, y } = getPosition(index); - return ( - - - {planet.name[0]} - - - ); - })} -
- - -
- - -

{selectedPlanet.name.toUpperCase()}

- {planetDetails ? ( -
-

Mass: {planetDetails.mass}

- {/*

Radius: {planetDetails.radius}

-

Average Temperature: {planetDetails.temperature.average}

-

Orbital Period: {planetDetails.orbitalPeriod}

-

Distance from Sun: {planetDetails.distanceFromSunOrPlanet}

*/} -

Planet type: {planetDetails.planetType}

- -

- {hasVisited ? "You've already visited this planet!" : "You haven't visited this planet yet."} -

- -

Available missions:


- -
- ) : ( -

Loading planet details...

- )} -
-
-
- - - -
- - - -
- ); -}; \ No newline at end of file diff --git a/components/(scenes)/planetScene/layout.tsx b/components/(scenes)/planetScene/layout.tsx index a42bfc06..5d50a917 100644 --- a/components/(scenes)/planetScene/layout.tsx +++ b/components/(scenes)/planetScene/layout.tsx @@ -10,14 +10,15 @@ import { mining, } from "@/constants/backgrounds"; import backgroundImage from "@/public/assets/Backdrops/Negotiations.jpg"; +import Header from "@/components/ui/Header"; interface PlanetViewLayoutProps { children: React.ReactNode[]; -} +}; interface PlanetViewLayoutProps { children: React.ReactNode[]; -} +}; const PlanetViewLayout: React.FC = ({ children }) => { const [expandedSection, setExpandedSection] = useState(null); @@ -61,7 +62,6 @@ const PlanetViewLayout: React.FC = ({ children }) => { loop muted /> - {/*
*/}
{children.slice(0, 2).map((child, index) => ( diff --git a/components/(scenes)/planetScene/planet.tsx b/components/(scenes)/planetScene/planet.tsx deleted file mode 100644 index e69de29b..00000000 diff --git a/components/Inventory/fetchId.tsx b/components/Inventory/fetchId.tsx index b9c3b8bc..028e4521 100644 --- a/components/Inventory/fetchId.tsx +++ b/components/Inventory/fetchId.tsx @@ -12,7 +12,8 @@ interface InventoryIdFetcherProps { export const InventoryIdFetcher: React.FC = ({ structureId, onInventoryIdFetched }) => { const supabase = useSupabaseClient(); - const session = useSession(); + const session = useSession(); + const { activePlanet } = useActivePlanet(); useEffect(() => { diff --git a/components/Inventory/items/ItemsOnPlanet.tsx b/components/Inventory/items/ItemsOnPlanet.tsx index 943dba89..3eb50b70 100644 --- a/components/Inventory/items/ItemsOnPlanet.tsx +++ b/components/Inventory/items/ItemsOnPlanet.tsx @@ -1,13 +1,6 @@ import { useEffect, useState } from 'react'; import { useSession, useSupabaseClient } from '@supabase/auth-helpers-react'; - -interface InventoryItem { - id: number; - name: string; - description: string; - icon_url: string; - ItemCategory: string; -} +import { InventoryItem } from '@/types/Items'; interface SupabaseInventoryItem { id: number; diff --git a/components/Inventory/mineralsPanel.tsx b/components/Inventory/mineralsPanel.tsx index 22988521..2940464f 100644 --- a/components/Inventory/mineralsPanel.tsx +++ b/components/Inventory/mineralsPanel.tsx @@ -1,6 +1,7 @@ import { useEffect, useState } from "react"; import { useSession, useSupabaseClient } from "@supabase/auth-helpers-react"; import { useActivePlanet } from "@/context/ActivePlanet"; +import { InventoryItem } from "@/types/Items"; interface Item { id: number; @@ -12,15 +13,7 @@ interface Item { parentItem: number | null; itemLevel: number; recipe?: { [key: string]: number }; -} - -interface InventoryItem { - id: number; - item: number; - owner: string; - quantity: number; - anomaly: number; -} +}; const MineralsInventoryGrid = () => { const supabase = useSupabaseClient(); diff --git a/components/Layout/BottomMenu.tsx b/components/Layout/BottomMenu.tsx index 949c2dde..138eea23 100644 --- a/components/Layout/BottomMenu.tsx +++ b/components/Layout/BottomMenu.tsx @@ -2,6 +2,7 @@ import { Globe, Rss, HelpCircle, Star } from "lucide-react"; import { usePathname } from "next/navigation"; import Link from "next/link"; import { useState } from "react"; +import Header from "../ui/Header"; const menuItems = [ { icon: Globe, label: "Planet", href: "/" }, diff --git a/components/Layout/Sidebar.tsx b/components/Layout/Sidebar.tsx deleted file mode 100644 index 60f0238e..00000000 --- a/components/Layout/Sidebar.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import Link from 'next/link'; -import { Rocket, User, Globe, List } from 'lucide-react'; - -export function Sidebar() { - return ( - - ); -}; \ No newline at end of file diff --git a/components/Layout/Starnet.tsx b/components/Layout/Starnet.tsx index a5302a74..38aa9c27 100644 --- a/components/Layout/Starnet.tsx +++ b/components/Layout/Starnet.tsx @@ -49,7 +49,7 @@ export default function StarnetLayout({ children }: { children: React.ReactNode
-

Starnet

+

Starnet

) : (
+ {filteredMissions.map((mission) => (
) : ( <> - +
+ +
+
+ +
Mission in progress {/* Accept Mission */} diff --git a/components/Projects/(classifications)/Annotation.tsx b/components/Projects/(classifications)/Annotation.tsx index 7385c255..e0136744 100644 --- a/components/Projects/(classifications)/Annotation.tsx +++ b/components/Projects/(classifications)/Annotation.tsx @@ -4,10 +4,11 @@ import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/com import * as markerjs2 from "markerjs2"; interface ImageProps { - src: string -}; + src: string; + onUpload: (dataUrl: string) => Promise; +} -export default function ImageAnnotation({ src }: ImageProps) { +export default function ImageAnnotation({ src, onUpload }: ImageProps) { const imageRef = useRef(null); const [markerArea, setMarkerArea] = useState(null); const [annotationState, setAnnotationState] = useState(null); @@ -17,7 +18,6 @@ export default function ImageAnnotation({ src }: ImageProps) { const ma = new markerjs2.MarkerArea(imageRef.current); setMarkerArea(ma); - // Add render event listener to update the image after annotations ma.addEventListener("render", (event) => { if (imageRef.current) { setAnnotationState(JSON.stringify(ma.getState())); @@ -25,62 +25,48 @@ export default function ImageAnnotation({ src }: ImageProps) { } }); - // Add close event listener to save the annotation state ma.addEventListener("close", () => { setAnnotationState(JSON.stringify(ma.getState())); }); + + ma.show(); // Automatically show the marker area when initialized } }, []); - // Show MarkerArea to start annotation process const showMarkerArea = () => { if (markerArea) { if (annotationState) { - markerArea.restoreState(JSON.parse(annotationState)); // Restore previous annotations + markerArea.restoreState(JSON.parse(annotationState)); } markerArea.show(); } }; - // Download the annotated image - const downloadImage = () => { + const downloadImage = async () => { if (imageRef.current) { - const dataUrl = imageRef.current.src; - if (dataUrl.startsWith('data:image')) { - const link = document.createElement('a'); - link.href = dataUrl; - link.download = 'annotated_image.png'; - document.body.appendChild(link); - link.click(); - document.body.removeChild(link); - } else { - console.error('No base64 data to download'); - }; - }; + const dataUrl = imageRef.current.src; // Get the annotated image data URL + await onUpload(dataUrl); + } }; return ( - + - Image - Annotate the image using marker.js + Annotate Image + Click the button to start annotating the image. - -
- - -
-
- {/* Ensure this image tag is used for annotation */} + +
Annotation + +
); -}; \ No newline at end of file +} \ No newline at end of file diff --git a/components/Projects/(classifications)/Collections/Classification.tsx b/components/Projects/(classifications)/Collections/Classification.tsx index 7117d82d..6c8b7ffc 100644 --- a/components/Projects/(classifications)/Collections/Classification.tsx +++ b/components/Projects/(classifications)/Collections/Classification.tsx @@ -18,7 +18,6 @@ import { zoodexSouthCoastFaunaRecovery, diskDetectorClassificationOptions, zoodexIguanasFromAboveClassificationOptions, zoodexBurrowingOwlClassificationOptions, - sunspotsConfigurationTemporary } from '@/content/Classifications/Options'; interface KeyStat { @@ -166,50 +165,4 @@ export function DiscoveryCardSingle({ classificationId }: DiscoveryCardSinglePro interface ClassificationConfiguration { [key: string]: string | number | boolean; -} - -const ClassificationOptions: React.FC<{ classificationConfiguration: ClassificationConfiguration }> = ({ classificationConfiguration }) => { - const getRelevantOptions = (config: ClassificationConfiguration) => { - const options = [ - cloudClassificationOptions, - planetClassificationOptions, - planktonPortalClassificationOptions, - diskDetectorClassificationOptions, - penguinWatchClassificationOptions, - roverImgClassificationOptions, - initialCloudClassificationOptions, - lidarEarthCloudsReadClassificationOptions, - lidarEarthCloudsUploadClassificationOptions, - zoodexBurrowingOwlClassificationOptions, - zoodexIguanasFromAboveClassificationOptions, - sunspotsConfigurationTemporary, - ]; - - const allOptions = options.flat(); - - const configValues = Object.values(config).filter(value => typeof value === 'string') as string[]; - - return allOptions.filter(option => - configValues.some(configValue => option.text.includes(configValue)) - ); - }; - const relevantOptions = getRelevantOptions(classificationConfiguration); - - return ( -
-

Classification Configuration:

-
{JSON.stringify(classificationConfiguration, null, 2)}
- -

Classification Options:

-
    - {relevantOptions.length > 0 ? ( - relevantOptions.map(option => ( -
  • {option.text}
  • - )) - ) : ( -
  • No relevant options found
  • - )} -
-
- ); -}; \ No newline at end of file +} \ No newline at end of file diff --git a/components/Projects/(classifications)/PostForm.tsx b/components/Projects/(classifications)/PostForm.tsx index 6cca86fc..e3736920 100644 --- a/components/Projects/(classifications)/PostForm.tsx +++ b/components/Projects/(classifications)/PostForm.tsx @@ -9,21 +9,17 @@ import { ClassificationOutput } from "./ClassificationResults"; import { zoodexSouthCoastFaunaRecovery, - cloudClassificationOptions, - initialCloudClassificationOptions, roverImgClassificationOptions, lidarEarthCloudsReadClassificationOptions, - lidarEarthCloudsUploadClassificationOptions, planetClassificationOptions, planktonPortalClassificationOptions, - penguinWatchClassificationOptions, diskDetectorClassificationOptions, zoodexIguanasFromAboveClassificationOptions, zoodexBurrowingOwlClassificationOptions, - sunspotsConfigurationTemporary, - cloudClassificationOptionsThree, - cloudClassificationOptionsTwo, - cloudClassificationOptionsOne, + cloudClassificationOptionsOne, cloudClassificationOptionsTwo, cloudClassificationOptionsThree, + automatonaiForMarsOptions, + DailyMinorPlanetOptions, + PlanetFourOptions, } from "@/content/Classifications/Options"; // import UserAvatar, { UserAvatarNullUpload } from "@/components/Profile/Avatar"; @@ -83,8 +79,12 @@ const ClassificationForm: React.FC = ({ return "Describe the number and behaviour of the penguins..."; case "zoodex-planktonPortal": return "Describe the plankton you see and their behaviour..."; + case "satellite-planetFour": + return 'Describe any additional details you notice about the terrain. How could these features impact future construction or exploration efforts?'; case "lidar-earthCloudRead": return "Describe the type of cloud you see..."; + case "automaton-aiForMars": + return "What surface types do you see from your rover?"; case "telescope-minorPlanet": return "Does the highlighted object move smoothly through the images? What do you see...?" default: @@ -117,8 +117,13 @@ const ClassificationForm: React.FC = ({ case "lidar-earthCloudRead": return [lidarEarthCloudsReadClassificationOptions]; case "sunspot": - // return sunspotsConfigurationTemporary; return []; + case "satellite-planetFour": + return [PlanetFourOptions]; + case "telescope-minorPlanet": + return [DailyMinorPlanetOptions]; + case "automaton-aiForMars": + return [automatonaiForMarsOptions]; case "zoodex-nestQuestGo": return []; default: @@ -128,30 +133,6 @@ const ClassificationForm: React.FC = ({ const showTextArea = classificationOptions.length === 0; - const [hasClassified, setHasClassified] = useState(false); - -// useEffect(() => { -// const checkUserClassification = async () => { -// if (!session?.user?.id || !anomalyId) return; - -// const { data, error } = await supabase -// .from("classifications") -// .select("id") -// .eq("author", session.user.id) -// .eq("anomaly", anomalyId) -// .single(); - -// if (data) { -// setHasClassified(true); -// } -// if (error) { -// console.error("Error checking classification:", error.message); -// } -// }; - -// checkUserClassification(); -// }, [session?.user?.id, anomalyId, supabase]); - useEffect(() => { const fetchUserProfile = async () => { if (!session) return; @@ -343,10 +324,11 @@ const ClassificationForm: React.FC = ({ // if (postSubmitted && showResearch) { // return ( - // <> // {showModal && } - // // ); + // if (postSubmitted) { + // return ; + // }; // }; const addMedia = async (e: React.ChangeEvent) => { @@ -376,10 +358,6 @@ const ClassificationForm: React.FC = ({ } }; - if (postSubmitted) { - return ; - } - const [additionalFields, setAdditionalFields] = useState<{ [key: string]: string; }>({}); @@ -443,13 +421,12 @@ const ClassificationForm: React.FC = ({ You need to repair the structure's durability before you can use it.
) : ( -
+
{classificationOptions.length > 0 ? ( -
- {/* Multiple Choice Buttons */} + <>
{classificationOptions.map((optionSet, setIndex) => ( -
+

Option Set {setIndex + 1}

{optionSet.map((option) => ( @@ -470,8 +447,7 @@ const ClassificationForm: React.FC = ({ ))}
- {/* Text Area Inputs */} -
+