From ccffcd7adc85f136cd4da267ecb0b6ca2d8ac75c Mon Sep 17 00:00:00 2001
From: Gizmotronn
Date: Mon, 16 Dec 2024 13:08:22 +0800
Subject: [PATCH] =?UTF-8?q?=F0=9F=AA=97=E3=80=A0=20=E2=86=9D=20[SSC-45=20S?=
=?UTF-8?q?SC-51=20SSG-59=20SSG-85]:=20Improved=20tutorial/project=20intro?=
=?UTF-8?q?duction=20and=20relation=20context?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
app/page.tsx | 4 +-
app/tests/missionsUnlocked.tsx | 80 ++++++
app/tests/page.tsx | 7 +-
app/tests/singleMissionGuide.tsx | 240 ++++++++++++++++++
components/Missions/mission-selector.tsx | 2 +-
.../PlanetHunters/PlanetHunters.tsx | 71 +++---
constants/Structures/Properties.tsx | 5 -
7 files changed, 362 insertions(+), 47 deletions(-)
create mode 100644 app/tests/missionsUnlocked.tsx
create mode 100644 app/tests/singleMissionGuide.tsx
diff --git a/app/page.tsx b/app/page.tsx
index a5ccedfc..b9f88ae8 100644
--- a/app/page.tsx
+++ b/app/page.tsx
@@ -36,6 +36,7 @@ import { EarthViewLayout } from "@/components/(scenes)/planetScene/layout";
import Onboarding from "./scenes/onboarding/page";
import VerticalToolbar from "@/components/Layout/Toolbar";
import StructureMissionGuide from "@/components/Layout/Guide";
+import SimpleeMissionGuide from "./tests/singleMissionGuide";
export default function Home() {
const session = useSession();
@@ -94,7 +95,8 @@ export default function Home() {
-
+ {/*
*/}
+
// 60:
,
diff --git a/app/tests/missionsUnlocked.tsx b/app/tests/missionsUnlocked.tsx
new file mode 100644
index 00000000..82cab240
--- /dev/null
+++ b/app/tests/missionsUnlocked.tsx
@@ -0,0 +1,80 @@
+import { useEffect, useState } from "react";
+import { useSupabaseClient, useSession } from "@supabase/auth-helpers-react";
+
+interface InventoryItem {
+ id: number;
+ configuration: {
+ "missions unlocked"?: string[];
+ [key: string]: any; // Allow other properties in configuration
+ };
+}
+
+const UserMissions = () => {
+ const supabase = useSupabaseClient();
+ const session = useSession();
+
+ const [missions, setMissions] = useState
([]);
+ const [loading, setLoading] = useState(true);
+ const [error, setError] = useState(null);
+
+ useEffect(() => {
+ if (!session?.user) return;
+
+ const fetchUserMissions = async () => {
+ setLoading(true);
+ setError(null);
+
+ try {
+ // Query inventory for items owned by the user and containing missions unlocked
+ const { data, error } = await supabase
+ .from("inventory")
+ .select("id, configuration")
+ .eq("owner", session.user.id)
+ .not("configuration->missions unlocked", "is", null); // Ensure "missions unlocked" exists
+
+ if (error) throw error;
+
+ // Extract and deduplicate all "missions unlocked"
+ const unlockedMissions = data
+ ?.flatMap((item: InventoryItem) => item.configuration["missions unlocked"] || [])
+ .filter((mission: string) => mission); // Filter out empty values
+
+ const uniqueMissions = Array.from(new Set(unlockedMissions));
+
+ setMissions(uniqueMissions);
+ } catch (err) {
+ console.error("Error fetching user missions:", err);
+ setError("Failed to fetch missions. Please try again.");
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ fetchUserMissions();
+ }, [session?.user, supabase]);
+
+ if (!session?.user) return Please log in to see your missions.
;
+
+ if (loading) return Loading missions...
;
+
+ if (error) return {error}
;
+
+ if (missions.length === 0) {
+ return No missions unlocked yet.
;
+ }
+
+ return (
+
+
Missions Unlocked
+
+ {missions.map((mission, index) => (
+ -
+ {mission}
+
+ ))}
+
+
+ );
+};
+
+export default UserMissions;
\ No newline at end of file
diff --git a/app/tests/page.tsx b/app/tests/page.tsx
index 6da77a5d..06f4328e 100644
--- a/app/tests/page.tsx
+++ b/app/tests/page.tsx
@@ -6,15 +6,16 @@ import { MiningComponentComponent } from "@/components/(scenes)/mining/mining-co
import Greenhouse from "@/page.test";
import BigMap from "@/components/(scenes)/planetScene/bigMap";
import DiscoveriesPage from "@/content/Classifications/minimalDiscoveries";
-import PlanetHuntersSteps from "@/components/Structures/Missions/Astronomers/PlanetHunters/PlanetHunters";
+import UserMissions from "./missionsUnlocked";
+import SimpleeMissionGuide from "./singleMissionGuide";
// import { TopographicMap } from "@/components/topographic-map";
export default function TestPage() {
return (
//
<>
-
-
+
+
{/* */}
{/* */}
{/* */}
diff --git a/app/tests/singleMissionGuide.tsx b/app/tests/singleMissionGuide.tsx
new file mode 100644
index 00000000..1a6f9006
--- /dev/null
+++ b/app/tests/singleMissionGuide.tsx
@@ -0,0 +1,240 @@
+import React, { useEffect, useState } from "react";
+import { Button } from "@/components/ui/button";
+import { Card, CardContent } from "@/components/ui/card";
+import { CloudDrizzleIcon, LightbulbIcon, Telescope, ArrowUpIcon, ArrowDownIcon } from "lucide-react";
+import { motion, AnimatePresence } from "framer-motion";
+import { useSupabaseClient, useSession } from "@supabase/auth-helpers-react";
+
+// Define Mission and other types
+export interface Mission {
+ id: number;
+ name: string;
+ description: string;
+ additionalDescription: string; // New property for additional context
+ icon: React.ElementType;
+ color: string;
+ identifier: string;
+}
+
+const projects: Record = {
+ "Refracting Telescope": [
+ {
+ id: 1,
+ name: "Planet Hunting",
+ description: "Click on the Telescope structure icon to rate different transit events and find planets.",
+ additionalDescription: "You'll work alongside other users to classify and verify planet candidates. Once they've been confirmed, you'll be able to visit them, determine their properties and start construction & exploration surveys.",
+ icon: Telescope,
+ color: "text-cyan-300",
+ identifier: "planet"
+ },
+ {
+ id: 2,
+ name: "Asteroid Detection",
+ description: "Click on the Telescope structure icon to discover new asteroids in your telescope's data.",
+ additionalDescription: "Using the latest telescope data, you will identify potential asteroids that might pose a threat to the Earth or serve as future targets for exploration. Additionally, exo-asteroids can be discovered and tracked to identify their interactions with planets discovered in the Planet Hunters project",
+ icon: Telescope,
+ color: "text-green-300",
+ identifier: "asteroid"
+ },
+ {
+ id: 3,
+ name: "Sunspot Observations",
+ description: "Click on the Telescope structure icon to keep track of our sun's health & electrical storms",
+ additionalDescription: "This mission requires monitoring sunspots and solar activity to understand how these phenomena affect space weather and our planet's magnetosphere. Sunspots can trigger electrical outages here on Earth (and on any planets in the firing line) - so we need to be prepared",
+ icon: Telescope,
+ color: "text-yellow-300",
+ identifier: "sunspot"
+ },
+ ],
+ Biodome: [
+ {
+ id: 4,
+ name: "Wildwatch Burrowing Owls",
+ description: "Click on the Biodome structure icon to classify pictures of burrowing owls in captivity.",
+ additionalDescription: "Help track the health and behavior of burrowing owls by classifying pictures from the Biodome. You will analyze the owls' nesting and foraging behaviors.",
+ icon: LightbulbIcon,
+ color: "text-cyan-300",
+ identifier: "burrowingOwl"
+ },
+ {
+ id: 5,
+ name: "Iguanas from Above",
+ description: "Count Galapagos Marine Iguanas from aerial photos that have been sent to your Biodome structure.",
+ additionalDescription: "Use aerial images to count and classify marine iguanas on the Galapagos Islands. This is important for conservation efforts to track their population.",
+ icon: LightbulbIcon,
+ color: "text-green-300",
+ identifier: "iguana"
+ },
+ ],
+ WeatherBalloon: [
+ {
+ id: 6,
+ name: "Martian Cloud Survey",
+ description: "Use your Weather Balloon to identify clouds & cloud behaviour on Mars & Mars-like planets",
+ additionalDescription: "Analyze cloud patterns on Mars and other planets. This mission will involve classifying clouds based on their shape, size, and movement. We can use this information to understand more about the composition and climate cycle on these planets",
+ icon: CloudDrizzleIcon,
+ color: "text-blue-400",
+ identifier: "martianClouds"
+ },
+ {
+ id: 7,
+ name: "Jovian Vortx Hunters",
+ description: "Classify storms & storm behaviour on gas giant planets using data collected in your Weather Balloon",
+ additionalDescription: "Study the massive storms on gas giants like Jupiter, tracking their movements and behaviors to understand their atmospheric dynamics, composition and climate.",
+ icon: CloudDrizzleIcon,
+ color: "text-yellow-400",
+ identifier: "jovianStorms"
+ },
+ ],
+};
+
+const defaultMission: Mission = {
+ id: 0,
+ name: "Welcome to Star Sailors",
+ description: "You've been given some basic structures to start your journey. Click on their icons to classify the data they've collected for you. New data & projects are being added weekly.",
+ additionalDescription: "You'll get to explore various missions, starting with basic tasks such as classifying objects in the sky and on Earth. Each task you complete unlocks new insights. Next week (22nd December) you'll be able to upload your own discoveries and clips",
+ icon: LightbulbIcon,
+ color: "text-blue-400",
+ identifier: "default-starting-mission",
+};
+
+const structureTitles: Record = {
+ "Refracting Telescope": "Astronomer Missions",
+ Biodome: "Ecology Missions",
+ WeatherBalloon: "Meteorology Missions",
+};
+
+const SimpleeMissionGuide = () => {
+ const supabase = useSupabaseClient();
+ const session = useSession();
+
+ const [completedIdentifiers, setCompletedIdentifiers] = useState([]);
+ const [activeStructure, setActiveStructure] = useState("Refracting Telescope");
+ const [isMinimized, setIsMinimized] = useState(false);
+
+ // Modal state
+ const [isModalOpen, setIsModalOpen] = useState(false);
+ const [selectedMission, setSelectedMission] = useState(null);
+
+ useEffect(() => {
+ const fetchClassifications = async () => {
+ if (!session?.user) return;
+
+ try {
+ const { data, error } = await supabase
+ .from("classifications")
+ .select("classificationtype, author")
+ .eq("author", session.user.id);
+
+ if (error) throw error;
+
+ const identifiers = data.map((item: any) => item.classificationtype).filter(Boolean);
+ setCompletedIdentifiers(identifiers);
+ } catch (err) {
+ console.error("Error fetching classifications:", err);
+ }
+ };
+
+ fetchClassifications();
+ }, [session?.user, supabase]);
+
+ const allStructures = Object.keys(projects);
+ const currentMissions = projects[activeStructure] || [];
+
+ const handlePrevStructure = () => {
+ const currentIndex = allStructures.indexOf(activeStructure);
+ const prevIndex = (currentIndex - 1 + allStructures.length) % allStructures.length;
+ setActiveStructure(allStructures[prevIndex]);
+ };
+
+ const handleNextStructure = () => {
+ const currentIndex = allStructures.indexOf(activeStructure);
+ const nextIndex = (currentIndex + 1) % allStructures.length;
+ setActiveStructure(allStructures[nextIndex]);
+ };
+
+ const renderMission = (mission: Mission) => {
+ const isCompleted = completedIdentifiers.includes(mission.identifier);
+
+ return (
+
+
+
+
+
{mission.name}
+
{mission.description}
+
+
+
+
+ );
+ };
+
+ const closeModal = () => {
+ setIsModalOpen(false);
+ setSelectedMission(null);
+ };
+
+ return (
+
+
+ {!isMinimized &&
}
+
+
{structureTitles[activeStructure]}
+
+
+ {!isMinimized &&
}
+
+
+
+ {!isMinimized && (
+
+ {renderMission(defaultMission)}
+ {currentMissions.map((mission) => renderMission(mission))}
+
+ )}
+
+
+ {isModalOpen && selectedMission && (
+
+
+
{selectedMission.name}
+
{selectedMission.additionalDescription}
{/* Display additional description */}
+
+
+
+ )}
+
+ );
+};
+
+export default SimpleeMissionGuide;
\ No newline at end of file
diff --git a/components/Missions/mission-selector.tsx b/components/Missions/mission-selector.tsx
index ecf9e933..d339dbd7 100644
--- a/components/Missions/mission-selector.tsx
+++ b/components/Missions/mission-selector.tsx
@@ -53,7 +53,7 @@ const structures: Structure[] = [
{
name: 'Refracting Telescope',
icon: Rocket,
- description: 'Browse & classify space-based observations & classifications',
+ description: 'Browse & classify space-based observations & classifications',
bgColor: 'bg-indigo-900',
accentColor: 'text-purple-400',
shape: ,
diff --git a/components/Structures/Missions/Astronomers/PlanetHunters/PlanetHunters.tsx b/components/Structures/Missions/Astronomers/PlanetHunters/PlanetHunters.tsx
index 024a5f3b..c949efd6 100644
--- a/components/Structures/Missions/Astronomers/PlanetHunters/PlanetHunters.tsx
+++ b/components/Structures/Missions/Astronomers/PlanetHunters/PlanetHunters.tsx
@@ -41,34 +41,54 @@ const PlanetHuntersSteps = () => {
const fetchMissionData = async () => {
try {
- const { data: classificationsData } = await supabase
+ // Fetch classifications data
+ const { data: classificationsData, error: classificationsError } = await supabase
.from("classifications")
.select("*")
.eq("classificationtype", "planet")
.eq("author", session.user.id);
+ if (classificationsError) throw classificationsError;
+
+ // Mission 1: Count all classifications of type 'planet'
const mission1CompletedCount = classificationsData?.length || 0;
- const mission2Data = classificationsData?.filter((classification) => {
- const config = classification.classificationConfiguration;
- return config && !config["1"] && (config["2"] || config["3"] || config["4"]);
- }) || [];
+ // Mission 2: Filter classifications based on classificationConfiguration logic
+ const mission2Data =
+ classificationsData?.filter((classification) => {
+ const config = classification.classificationConfiguration;
+ if (!config) return false;
+
+ const options = config.classificationOptions?.[""] || {};
+ return (
+ !options["1"] && // Ensure '1' is NOT selected
+ (options["2"] || options["3"] || options["4"]) // Ensure at least one of 2, 3, or 4 is selected
+ );
+ }) || [];
const mission2CompletedCount = mission2Data.length;
- const { data: commentsData } = await supabase
+ // Fetch comments data
+ const { data: commentsData, error: commentsError } = await supabase
.from("comments")
.select("*")
.eq("author", session.user.id);
+ if (commentsError) throw commentsError;
+
+ // Mission 3: Comments with planet type proposals
const mission3CompletedCount = commentsData?.filter(
(comment) => comment.configuration?.planetType
).length || 0;
- const { data: votesData } = await supabase
+ // Fetch votes data
+ const { data: votesData, error: votesError } = await supabase
.from("votes")
.select("*")
.eq("user_id", session.user.id);
+ if (votesError) throw votesError;
+
+ // Mission 4: Votes on planet classifications
const planetVotes = votesData?.filter((vote) =>
classificationsData?.some(
(classification) =>
@@ -76,9 +96,9 @@ const PlanetHuntersSteps = () => {
classification.classificationtype === "planet"
)
) || [];
-
const mission4CompletedCount = planetVotes.length;
+ // Mission 5: Comments linked to classifications
const mission5CompletedCount = commentsData?.filter(
(comment) =>
comment.classification_id &&
@@ -89,6 +109,7 @@ const PlanetHuntersSteps = () => {
)
).length || 0;
+ // Calculate total points and level
const totalPoints = (
mission1CompletedCount * missionPoints[1] +
mission2CompletedCount * missionPoints[2] +
@@ -97,10 +118,11 @@ const PlanetHuntersSteps = () => {
mission5CompletedCount * missionPoints[5]
);
- const newLevel = Math.floor(totalPoints / 8) + 1; // Every 8 points = level up
+ const newLevel = Math.floor(totalPoints / 9) + 1; // Every 8 points = level up
setLevel(newLevel);
setExperiencePoints(totalPoints);
+ // Update mission steps
setSteps([
{
id: 1,
@@ -129,15 +151,6 @@ const PlanetHuntersSteps = () => {
completedCount: mission3CompletedCount,
color: "text-green-500",
},
- // {
- // id: 4,
- // title: "Vote on Planet Classifications",
- // description: "Review and vote on another user's planet classification.",
- // icon: PersonStandingIcon,
- // action: () => {},
- // completedCount: mission4CompletedCount,
- // color: "text-yellow-500",
- // },
{
id: 5,
title: "Comment & vote on Planet Classifications",
@@ -151,6 +164,7 @@ const PlanetHuntersSteps = () => {
setLoading(false);
} catch (error) {
+ console.error("Error fetching mission data:", error);
setLoading(false);
}
};
@@ -175,33 +189,18 @@ const PlanetHuntersSteps = () => {
{selectedMission.id === 1 && }
{selectedMission.id === 2 && }
{selectedMission.id === 3 && }
- {/* {selectedMission.id === 4 && } */}
{selectedMission.id === 5 && }
);
- };
+ };
return (
- {/* */}
Chapter {currentChapter}
- {/* */}
{/* Experience Bar */}
@@ -209,7 +208,7 @@ const PlanetHuntersSteps = () => {
@@ -217,7 +216,6 @@ const PlanetHuntersSteps = () => {
Level {level} ({experiencePoints} points)
-
{steps.map((step) => (
{
))}
-
);
};
diff --git a/constants/Structures/Properties.tsx b/constants/Structures/Properties.tsx
index 1da64c86..d6d69dcf 100644
--- a/constants/Structures/Properties.tsx
+++ b/constants/Structures/Properties.tsx
@@ -48,7 +48,6 @@ interface IndividualStructureProps {
dynamicComponent?: React.ReactNode;
sizePercentage?: number;
showInNoModal?: boolean;
- onClick?: () => void;
}[];
modals?: {
icon: React.ReactNode;
@@ -167,10 +166,6 @@ export const StructuresConfig: StructureConfig = {
text: "Discover planets", // Transit events, microlensing, etc
// dynamicComponent: ,
// dynamicComponent: ,
- onClick: () => {
- const router = useRouter();
- router.push("/tests"); // Redirect to the "/tests" route
- },
dynamicComponent: ,
sizePercentage: 95,
showInNoModal: true,