Skip to content

Commit 8cdcacf

Browse files
committed
🦴⏰ ↝ [SSC-56 SSC-57]: CoM (Base) project now working for C1
1 parent c721521 commit 8cdcacf

File tree

7 files changed

+334
-12
lines changed

7 files changed

+334
-12
lines changed

components/Structures/Missions/Astronomers/DailyMinorPlanet/DMPVote.tsx

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export default function VoteDMPClassifications() {
2828
setError("User session not found.");
2929
setLoading(false);
3030
return;
31-
}
31+
};
3232

3333
setLoading(true);
3434
setError(null);
@@ -45,15 +45,12 @@ export default function VoteDMPClassifications() {
4545
const media = classification.media;
4646
let images: string[] = [];
4747

48-
// Check if media is an array with at least 2 elements (array structure like [[], [...image URLs]])
4948
if (Array.isArray(media) && media.length > 1) {
50-
// Extract the image URLs from the second element if it's an array of URLs
5149
images = media[1] && Array.isArray(media[1]) ? media[1] : [];
5250
}
53-
// Check if there's a single image URL (media is not an array but an object with uploadUrl)
5451
else if (media && typeof media === "object" && media.uploadUrl) {
5552
images.push(media.uploadUrl);
56-
}
53+
}''
5754

5855
const votes = classification.classificationConfiguration?.votes || 0;
5956

@@ -66,7 +63,7 @@ export default function VoteDMPClassifications() {
6663
setError("Failed to load classifications.");
6764
} finally {
6865
setLoading(false);
69-
}
66+
}''
7067
};
7168

7269
useEffect(() => {
@@ -100,7 +97,7 @@ export default function VoteDMPClassifications() {
10097
}
10198
} catch (error) {
10299
console.error("Error voting:", error);
103-
}
100+
};
104101
};
105102

106103
return (

components/Structures/Missions/Astronomers/DailyMinorPlanet/DailyMinorPlanet.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,8 @@ const DailyMinorPlanetMissions = () => {
120120
const [currentChapter, setCurrentChapter] = useState(1);
121121

122122
const maxUnlockedChapter = Math.max(
123-
Math.floor(experiencePoints / 9) + 1, // Based on experience points
124-
Math.max(...missions.map(mission => mission.chapter)) // Ensure higher chapters are unlocked if there are missions in them
123+
Math.floor(experiencePoints / 9) + 1,
124+
Math.max(...missions.map(mission => mission.chapter))
125125
);
126126

127127
useEffect(() => {

components/Structures/Missions/Astronomers/PlanetHunters/PHVote.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export default function VotePlanetClassifictions() {
2828
if (!session?.user) {
2929
setError("User session not found.");
3030
setLoading(false);
31-
return;
31+
return;
3232
};
3333

3434
setLoading(true);
Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
import { useEffect, useState } from "react";
2+
import { useSupabaseClient, useSession } from "@supabase/auth-helpers-react";
3+
import MissionShell from "../../BasePlate";
4+
import { CloudCogIcon, FolderCog, Vote } from "lucide-react";
5+
import { StarterLidar } from "@/components/Projects/Lidar/Clouds";
6+
import VoteCoMClassifications from "./CoMVote";
7+
8+
const CloudspottingOnMars = () => {
9+
const supabase = useSupabaseClient();
10+
const session = useSession();
11+
12+
const [missions, setMissions] = useState([
13+
{
14+
id: 1,
15+
chapter: 1,
16+
title: "Make a cloud classification",
17+
description:
18+
"Use your weather balloon & LIDAR technologies to discover properties about Martian clouds",
19+
icon: CloudCogIcon,
20+
points: 2,
21+
completedCount: 0,
22+
internalComponent: () => <StarterLidar />,
23+
color: 'text-blue-500',
24+
shadow: false,
25+
action: () => {},
26+
},
27+
{
28+
id: 2,
29+
chapter: 1,
30+
title: "Propose a cloud in your classifications",
31+
description: "Make a classification indicating a positive cloud candidate",
32+
icon: FolderCog,
33+
points: 1,
34+
completedCount: 0,
35+
internalComponent: () => <StarterLidar />,
36+
color: 'text-cyan-300',
37+
shadow: false,
38+
action: () => {},
39+
},
40+
{
41+
id: 3,
42+
chapter: 1,
43+
title: "Comment or vote on a cloud classification",
44+
description:
45+
"Collaborate with other players to rate proposed cloud candidates and behaviour",
46+
icon: Vote,
47+
points: 1,
48+
completedCount: 0,
49+
internalComponent: () => <VoteCoMClassifications />,
50+
color: 'text-green-700',
51+
shadow: false,
52+
action: () => []
53+
},
54+
{
55+
id: 4,
56+
chapter: 2,
57+
title: "Have a cloud candidate confirmed",
58+
description:
59+
"Validate the presence of a cloud candidate by confirming it through analysis and collaboration.",
60+
icon: CloudCogIcon,
61+
points: 3,
62+
completedCount: 0,
63+
internalComponent: () => <div></div>,
64+
color: 'text-red-500',
65+
shadow: false,
66+
action: () => {}
67+
},
68+
{
69+
id: 5,
70+
chapter: 2,
71+
title: "Connect to a planet (terrestrial list)",
72+
description:
73+
"Establish a connection to a planet within the terrestrial list and begin analyzing cloud patterns.",
74+
icon: FolderCog,
75+
points: 2,
76+
completedCount: 0,
77+
internalComponent: () => <div></div>,
78+
color: 'text-yellow-500',
79+
shadow: false,
80+
action: () => {}
81+
},
82+
{
83+
id: 6,
84+
chapter: 2,
85+
title: "Propose temperature range",
86+
description:
87+
"Submit your proposed temperature range for cloud formation based on your data and observations.",
88+
icon: CloudCogIcon,
89+
points: 2,
90+
completedCount: 0,
91+
internalComponent: () => <div></div>,
92+
color: 'text-blue-300',
93+
shadow: false,
94+
action: () => {}
95+
},
96+
{
97+
id: 7,
98+
chapter: 2,
99+
title: "Make a CoM shapes classification",
100+
description:
101+
"Classify cloud formations based on their Center of Mass (CoM) shapes to identify patterns.",
102+
icon: CloudCogIcon,
103+
points: 2,
104+
completedCount: 0,
105+
internalComponent: () => <div></div>,
106+
color: 'text-green-300',
107+
shadow: false,
108+
action: () => {}
109+
},
110+
{
111+
id: 8,
112+
chapter: 2,
113+
title: "Comment/vote on a shapes classification",
114+
description:
115+
"Engage with other players by commenting on or voting for cloud shapes classifications to improve the system.",
116+
icon: Vote,
117+
points: 1,
118+
completedCount: 0,
119+
internalComponent: () => <div></div>,
120+
color: 'text-pink-500',
121+
shadow: false,
122+
action: () => {}
123+
},
124+
{
125+
id: 9,
126+
chapter: 2,
127+
title: "Propose cloud type (1 of the 6 major ones)",
128+
description:
129+
"Propose a cloud type (from the 6 major types) and include the corresponding temperature range, outputting a shape classification.",
130+
icon: FolderCog,
131+
points: 3,
132+
completedCount: 0,
133+
internalComponent: () => <div></div>,
134+
color: 'text-orange-500',
135+
shadow: false,
136+
action: () => {}
137+
},
138+
{
139+
id: 10,
140+
chapter: 2,
141+
title: "Connect a cloud shape with type to a regular cloud",
142+
description:
143+
"Link a cloud shape classification to a regular cloud type, verifying its characteristics.",
144+
icon: CloudCogIcon,
145+
points: 2,
146+
completedCount: 0,
147+
internalComponent: () => <div></div>,
148+
color: 'text-purple-500',
149+
shadow: false,
150+
action: () => {}
151+
}
152+
]);
153+
154+
const [experiencePoints, setExperiencePoints] = useState(0);
155+
const [level, setLevel] = useState(1);
156+
const [currentChapter, setCurrentChapter] = useState(1);
157+
158+
const maxUnlockedChapter = Math.max(
159+
Math.floor(experiencePoints / 9) + 1,
160+
Math.max(...missions.map(mission => mission.chapter))
161+
);
162+
163+
useEffect(() => {
164+
if (!session) {
165+
return;
166+
};
167+
168+
const fetchMissionData = async () => {
169+
// Fetch and update mission data from Supabase if needed
170+
}
171+
}, [supabase, session]);
172+
173+
const handlePreviousChapter = () => {
174+
if (currentChapter > 1) setCurrentChapter(currentChapter - 1);
175+
};
176+
177+
const handleNextChapter = () => {
178+
if (currentChapter < maxUnlockedChapter) setCurrentChapter(currentChapter + 1);
179+
};
180+
181+
return (
182+
<MissionShell
183+
missions={missions.filter((mission) => mission.chapter === currentChapter)}
184+
experiencePoints={experiencePoints}
185+
level={level}
186+
currentChapter={currentChapter}
187+
maxUnlockedChapter={maxUnlockedChapter}
188+
onPreviousChapter={handlePreviousChapter}
189+
onNextChapter={handleNextChapter}
190+
/>
191+
);
192+
};
193+
194+
export default CloudspottingOnMars;
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
'use client';
2+
3+
import React, { useEffect, useState } from "react";
4+
import { PostCardSingle } from "@/content/Posts/PostSingle";
5+
import { useSession, useSupabaseClient } from "@supabase/auth-helpers-react";
6+
import StarnetLayout from "@/components/Layout/Starnet";
7+
8+
interface Classification {
9+
id: number;
10+
created_at: string;
11+
content: string | null;
12+
author: string | null;
13+
anomaly: number | null;
14+
media: any | null;
15+
classificationtype: string | null;
16+
classificationConfiguration: any | null;
17+
};
18+
19+
export default function VotePlanetClassifictions() {
20+
const supabase = useSupabaseClient();
21+
const session = useSession();
22+
23+
const [classifications, setClassifications] = useState<any[]>([]);
24+
const [loading, setLoading] = useState<boolean>(true);
25+
const [error, setError] = useState<string | null>(null);
26+
27+
const fetchClassifications = async () => {
28+
if (!session?.user) {
29+
setError("User session not found.");
30+
setLoading(false);
31+
return;
32+
};
33+
34+
setLoading(true);
35+
setError(null);
36+
try {
37+
const { data, error } = await supabase
38+
.from('classifications')
39+
.select('*')
40+
.eq('classificationtype', 'cloud')
41+
.order('created_at', { ascending: false }) as { data: Classification[]; error: any };
42+
43+
if (error) throw error;
44+
45+
const processedData = data.map((classification) => {
46+
const media = classification.media;
47+
let images: string[] = [];
48+
49+
if (Array.isArray(media) && media.length === 2 && typeof media[1] === "string") {
50+
images.push(media[1]);
51+
} else if (media && media.uploadUrl) {
52+
images.push(media.uploadUrl);
53+
}
54+
55+
const votes = classification.classificationConfiguration?.votes || 0;
56+
57+
return { ...classification, images, votes };
58+
});
59+
60+
setClassifications(processedData);
61+
} catch (error) {
62+
console.error("Error fetching classifications:", error);
63+
setError("Failed to load classifications.");
64+
} finally {
65+
setLoading(false);
66+
};
67+
};
68+
69+
useEffect(() => {
70+
fetchClassifications();
71+
}, [session])
72+
73+
const handleVote = async (classificationId: number, currentConfig: any) => {
74+
try {
75+
const currentVotes = currentConfig?.votes || 0;
76+
77+
const updatedConfig = {
78+
...currentConfig,
79+
votes: currentVotes + 1,
80+
};
81+
82+
const { error } = await supabase
83+
.from("classifications")
84+
.update({ classificationConfiguration: updatedConfig })
85+
.eq("id", classificationId);
86+
87+
if (error) {
88+
console.error("Error updating classificationConfiguration:", error);
89+
} else {
90+
setClassifications((prevClassifications) =>
91+
prevClassifications.map((classification) =>
92+
classification.id === classificationId
93+
? { ...classification, votes: updatedConfig.votes }
94+
: classification
95+
)
96+
);
97+
}
98+
} catch (error) {
99+
console.error("Error voting:", error);
100+
};
101+
};
102+
103+
return (
104+
<div className="space-y-8">
105+
{loading ? (
106+
<p>Loading classifications...</p>
107+
) : error ? (
108+
<p>{error}</p>
109+
) : (
110+
classifications.map((classification) => (
111+
<PostCardSingle
112+
key={classification.id}
113+
classificationId={classification.id}
114+
title={classification.title}
115+
author={classification.author}
116+
content={classification.content}
117+
votes={classification.votes || 0}
118+
category={classification.category}
119+
tags={classification.tags || []}
120+
images={classification.images || []}
121+
anomalyId={classification.anomaly}
122+
classificationConfig={classification.classificationConfiguration}
123+
classificationType={classification.classificationtype}
124+
onVote={() => handleVote(classification.id, classification.classificationConfiguration)}
125+
/>
126+
))
127+
)}
128+
</div>
129+
);
130+
};

0 commit comments

Comments
 (0)