Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions react-ystemandchess/src/core/services/activitiesApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,24 @@ export async function completeActivity(username: string, token: string, activity
);
if (!res.ok) throw new Error("Failed to update activity");
return res.json();
}

/**
* Resolves the activity name matching a taskId by fetching the user's
* activities. Needed because the ?taskId= deep link carries the catalog
* taskId, but PUT /activities/:username/activity matches on activities.name.
*
* @param {string} username
* @param {string} token
* @param {string} taskId
* @returns {Promise<string | undefined>} Matching activity name, if found
*/
export async function getActivityNameByTaskId(username: string, token: string, taskId: string) {
const res = await fetch(`${environment.urls.middlewareURL}/activities/${username}`, {
headers: { Authorization: `Bearer ${token}` },
});
if (!res.ok) throw new Error("Failed to fetch activities");
const json = await res.json();
const match = json.activities?.activities?.find((a: any) => a.taskId === taskId);
return match?.name;
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ import { ReactComponent as BackIconInactive } from '../../../../assets/images/ic
import { ReactComponent as NextIcon } from '../../../../assets/images/icons/icon_next.svg';
import { ReactComponent as NextIconInactive } from '../../../../assets/images/icons/icon_next_inactive.svg';

import { SetPermissionLevel } from "../../../../globals";
import { checkAndAward } from "../../../../core/services/badgesApi";
import { completeActivity, getActivityNameByTaskId } from "../../../../core/services/activitiesApi";

type LessonOverlayProps = {
propPieceName?: any;
propLessonNumber?: any;
Expand Down Expand Up @@ -907,6 +911,23 @@ const LessonOverlay: React.FC<LessonOverlayProps> = ({
const nextNum = lessonNum + 1;
await updateCompletion(); // backend update for logged-in users

try {
const uInfo = await SetPermissionLevel(cookies);
if (!uInfo?.error && uInfo.username) {
const taskId = new URLSearchParams(location.search).get("taskId");
if (taskId) {
getActivityNameByTaskId(uInfo.username, cookies.login, taskId)
.then((name) => name && completeActivity(uInfo.username, cookies.login, name))
.catch((err) => console.error("Failed to update activity:", err));
}
checkAndAward(uInfo.username, cookies.login).catch((err) =>
console.error("Failed to check/award badges:", err)
);
}
} catch (err) {
console.error("Post-completion calls failed:", err);
}

if (nextNum >= totalLessons) {
setAllLessonsDone(true);
return;
Expand Down
16 changes: 16 additions & 0 deletions react-ystemandchess/src/features/puzzles/Puzzles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ import ChessBoard, {
} from "../../components/ChessBoard/ChessBoard";
import { useChessSocket } from "../lessons/piece-lessons/lesson-overlay/hooks/useChessSocket";
import { Move } from "../../core/types/chess";
import { useSearchParams } from "react-router-dom";
import { checkAndAward } from "../../core/services/badgesApi";
import { completeActivity, getActivityNameByTaskId } from "../../core/services/activitiesApi";

type PuzzlesProps = {
student?: any;
Expand Down Expand Up @@ -95,6 +98,9 @@ const Puzzles: React.FC<PuzzlesProps> = ({
const studentId = student || cookies.login?.studentId || uuidv4();
const mentorId = mentor || "puzzle_mentor_" + studentId;

const [searchParams] = useSearchParams();
const taskId = searchParams.get("taskId");

// ============================================================================
// PUZZLE LOADING
// ============================================================================
Expand Down Expand Up @@ -378,6 +384,16 @@ const Puzzles: React.FC<PuzzlesProps> = ({
if (moveListRef.current.length === 0) {
isPuzzleEndRef.current = true;
socket.sendMessage("puzzle completed");
if (role === "student" && username) {
if (taskId) {
getActivityNameByTaskId(username, cookies.login, taskId)
.then((name) => name && completeActivity(username, cookies.login, name))
.catch((err) => console.error("Failed to update activity:", err));
}
checkAndAward(username, cookies.login).catch((err) =>
console.error("Failed to check/award badges:", err)
);
}
reportPuzzleSolved();
setTimeout(() => {
setModal({
Expand Down
Loading