Revert "fix(fitness): mirror finish overview to other devices via SSE"

This reverts commit e87b8bd864.
This commit is contained in:
2026-05-12 17:30:02 +02:00
parent 5ac56db46c
commit 8c09b0b2f4
4 changed files with 12 additions and 71 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "homepage",
"version": "1.70.0",
"version": "1.70.1",
"private": true,
"type": "module",
"scripts": {
+5 -23
View File
@@ -37,7 +37,6 @@ export function createWorkoutSync() {
let status: SyncStatus = $state('idle');
let serverVersion = $state(0);
let lastFinishedSession: any = $state(null);
let eventSource: EventSource | null = null;
let debounceTimer: ReturnType<typeof setTimeout> | null = null;
let reconnectTimer: ReturnType<typeof setTimeout> | null = null;
@@ -167,15 +166,8 @@ export function createWorkoutSync() {
} catch {}
});
eventSource.addEventListener('finished', (e) => {
// Another device finished the workout. If they passed along the saved
// session, expose it so the active page can build the completion overview.
try {
const data = JSON.parse(e.data);
lastFinishedSession = data?.session ?? null;
} catch {
lastFinishedSession = null;
}
eventSource.addEventListener('finished', () => {
// Another device finished the workout
workout.cancel();
disconnectSSE();
});
@@ -225,22 +217,14 @@ export function createWorkoutSync() {
connectSSE();
}
/** Called when workout finishes or is cancelled — clean up server state.
* Pass the just-saved session id so other devices receive it via SSE
* and can render the finish overview. */
async function onWorkoutEnd(sessionId?: string | null) {
/** Called when workout finishes or is cancelled — clean up server state */
async function onWorkoutEnd() {
disconnectSSE();
try {
const qs = sessionId ? `?sessionId=${encodeURIComponent(sessionId)}` : '';
await fetch(`/api/fitness/workout/active${qs}`, { method: 'DELETE' });
await fetch('/api/fitness/workout/active', { method: 'DELETE' });
} catch {}
}
/** Clear the finished-session payload after the page has consumed it. */
function clearFinishedSession() {
lastFinishedSession = null;
}
/** Called on app load — reconcile local vs server state */
async function init() {
try {
@@ -306,11 +290,9 @@ export function createWorkoutSync() {
return {
get status() { return status; },
get serverVersion() { return serverVersion; },
get lastFinishedSession() { return lastFinishedSession; },
init,
onWorkoutStart,
onWorkoutEnd,
clearFinishedSession,
notifyChange,
destroy
};
@@ -2,7 +2,6 @@ import { json } from '@sveltejs/kit';
import type { RequestHandler } from './$types';
import { dbConnect } from '$utils/db';
import { ActiveWorkout } from '$models/ActiveWorkout';
import { WorkoutSession } from '$models/WorkoutSession';
import { broadcast } from '$lib/server/sseManager';
// GET /api/fitness/workout/active — fetch current active workout
@@ -92,9 +91,7 @@ export const PUT: RequestHandler = async ({ request, locals }) => {
};
// DELETE /api/fitness/workout/active — clear active workout (finish/cancel)
// Optional ?sessionId=<id> attaches the just-saved session to the broadcast so
// other devices can render the finish overview instead of a blank page.
export const DELETE: RequestHandler = async ({ locals, url }) => {
export const DELETE: RequestHandler = async ({ locals }) => {
const session = locals.session ?? await locals.auth();
if (!session?.user?.nickname) {
return json({ error: 'Unauthorized' }, { status: 401 });
@@ -105,17 +102,8 @@ export const DELETE: RequestHandler = async ({ locals, url }) => {
const userId = session.user.nickname;
await ActiveWorkout.deleteOne({ userId });
const sessionId = url.searchParams.get('sessionId');
let sessionDoc: unknown = null;
if (sessionId) {
try {
sessionDoc = await WorkoutSession.findOne({ _id: sessionId, createdBy: userId }).lean();
} catch {
sessionDoc = null;
}
}
broadcast(userId, 'finished', { active: false, session: sessionDoc });
// Notify all devices that workout is finished
broadcast(userId, 'finished', { active: false });
return json({ ok: true });
} catch (error) {
@@ -161,36 +161,8 @@
let templateDiffs = $state([]);
let templateUpdateStatus = $state('idle'); // 'idle' | 'updating' | 'done'
// Track whether we've ever observed an active workout on this page so the
// remote-end redirect doesn't fire during the brief gap before localStorage
// + server hydration completes on initial mount.
let _everActive = false;
// Mirror the finish overview when another device finishes the workout.
// Sync surfaces the saved session via SSE; treat it like the local finish path.
$effect(() => {
const remoteSession = sync.lastFinishedSession;
if (!remoteSession || completionData) return;
completionData = buildCompletion(remoteSession, remoteSession);
computeTemplateDiff(completionData);
sync.clearFinishedSession();
});
// If the workout ends remotely without a session payload (cancel from another
// device, or that device couldn't post the session), exit cleanly instead of
// leaving this device on a blank active page.
$effect(() => {
if (workout.active) {
_everActive = true;
return;
}
if (!_everActive || completionData || sync.lastFinishedSession) return;
goto(`/fitness/${sl.workout}`);
});
// Celebratory fanfare on workout completion. Fires once, regardless of
// whether completionData was populated by the local finish path or by the
// remote-finish sync effect above.
// Celebratory fanfare on workout completion. Fires once when completionData
// becomes truthy after a successful finish.
let _completionSoundPlayed = false;
$effect(() => {
if (completionData && !_completionSoundPlayed) {
@@ -786,16 +758,15 @@
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(sessionData)
});
await sync.onWorkoutEnd();
if (res.ok) {
const d = await res.json();
completionData = buildCompletion(sessionData, d.session);
computeTemplateDiff(completionData);
await sync.onWorkoutEnd(d.session?._id);
} else {
await queueSession(sessionData);
offlineQueued = true;
completionData = buildCompletion(sessionData, { _id: null });
await sync.onWorkoutEnd();
}
} catch {
await queueSession(sessionData);