From be60493b27513a903421e65e5e41c1c194b4b871 Mon Sep 17 00:00:00 2001 From: sruju333 Date: Sat, 19 Sep 2026 14:42:20 -0400 Subject: [PATCH] Week 1: check and award API implementation --- .../src/core/services/activitiesApi.ts | 27 +++++++++++++++++ .../src/core/services/badgesApi.ts | 29 +++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 react-ystemandchess/src/core/services/activitiesApi.ts diff --git a/react-ystemandchess/src/core/services/activitiesApi.ts b/react-ystemandchess/src/core/services/activitiesApi.ts new file mode 100644 index 00000000..1297fa94 --- /dev/null +++ b/react-ystemandchess/src/core/services/activitiesApi.ts @@ -0,0 +1,27 @@ +import { environment } from "../../environments/environment"; + +/** + * Marks a specific activity as completed for the given user via + * PUT /activities/:username/activity. + * + * @param {string} username - User's own username (must match the JWT) + * @param {string} token - Bearer token (e.g. from the 'login' cookie) + * @param {string} activityId - ID of the activity being completed + * @returns {Promise} Updated activities payload + * @throws {Error} If the API request fails + */ +export async function completeActivity(username: string, token: string, activityName: string) { + const res = await fetch( + `${environment.urls.middlewareURL}/activities/${username}/activity`, + { + method: "PUT", + headers: { + Authorization: `Bearer ${token}`, + "Content-Type": "application/json", + }, + body: JSON.stringify({ activityName }), + } + ); + if (!res.ok) throw new Error("Failed to update activity"); + return res.json(); +} \ No newline at end of file diff --git a/react-ystemandchess/src/core/services/badgesApi.ts b/react-ystemandchess/src/core/services/badgesApi.ts index 57c044ad..c8edc90d 100644 --- a/react-ystemandchess/src/core/services/badgesApi.ts +++ b/react-ystemandchess/src/core/services/badgesApi.ts @@ -47,3 +47,32 @@ export async function getUserBadges(userId: string, token: string) { if (!res.ok) throw new Error("Failed to fetch earned badges"); return (await res.json()).earned; } + +/** + * Triggers a server-side check of the user's current stats and awards + * any badges they've newly qualified for. Server-authoritative — it + * recomputes stats itself and does not accept client-supplied predicates. + * + * The backend only permits a caller to check/award their own badges + * (:userId must match the authenticated JWT's username), so token is + * required here. + * + * @param {string} userId - User's own username (must match the JWT) + * @param {string} token - Bearer token (e.g. from the 'login' cookie) + * @returns {Promise} Array of newly-awarded badge objects + * @throws {Error} If the API request fails + */ +export async function checkAndAward(userId: string, token: string) { + // Auth is carried by the Bearer header, not cookies — omit + // credentials: "include" for the same reason noted in getBadgeCatalog + // above (wildcard-origin CORS rejects credentialed requests). + const res = await fetch( + `${environment.urls.middlewareURL}/badges/${userId}/check-and-award`, + { + method: "POST", + headers: { Authorization: `Bearer ${token}` }, + } + ); + if (!res.ok) throw new Error("Failed to check and award badges"); + return (await res.json()).awarded; +}