feat(fitness): surface period projection on stats page
PeriodTracker gains an optional mode prop ('entry' | 'projection' |
'full') that gates which sections render. The measure page keeps the
full tracker for the user's own cycle (logging plus calendar). The
stats page now mirrors it in projection mode and is the sole home
for shared cycles, which used to clutter the measure page.
This commit is contained in:
@@ -1,13 +1,12 @@
|
||||
import type { PageServerLoad } from './$types';
|
||||
|
||||
export const load: PageServerLoad = async ({ fetch }) => {
|
||||
const [latestRes, listRes, goalRes, periodRes, shareRes, sharedRes] = await Promise.all([
|
||||
const [latestRes, listRes, goalRes, periodRes, shareRes] = await Promise.all([
|
||||
fetch('/api/fitness/measurements/latest'),
|
||||
fetch('/api/fitness/measurements?limit=200'),
|
||||
fetch('/api/fitness/goal'),
|
||||
fetch('/api/fitness/period').catch(() => null),
|
||||
fetch('/api/fitness/period/share').catch(() => null),
|
||||
fetch('/api/fitness/period/shared').catch(() => null)
|
||||
fetch('/api/fitness/period/share').catch(() => null)
|
||||
]);
|
||||
|
||||
return {
|
||||
@@ -15,7 +14,6 @@ export const load: PageServerLoad = async ({ fetch }) => {
|
||||
measurements: await listRes.json(),
|
||||
profile: goalRes.ok ? await goalRes.json() : {},
|
||||
periods: periodRes?.ok ? (await periodRes.json()).entries : [],
|
||||
periodSharedWith: shareRes?.ok ? (await shareRes.json()).sharedWith : [],
|
||||
sharedPeriods: sharedRes?.ok ? (await sharedRes.json()).shared : []
|
||||
periodSharedWith: shareRes?.ok ? (await shareRes.json()).sharedWith : []
|
||||
};
|
||||
};
|
||||
|
||||
@@ -353,10 +353,6 @@
|
||||
<PeriodTracker periods={data.periods ?? []} {lang} sharedWith={data.periodSharedWith ?? []} />
|
||||
{/if}
|
||||
|
||||
{#each data.sharedPeriods ?? [] as shared (shared.owner)}
|
||||
<PeriodTracker periods={shared.entries} {lang} readOnly ownerName={shared.owner} />
|
||||
{/each}
|
||||
|
||||
<div class="page-footer-actions">
|
||||
<button type="button" class="edit-profile-link" onclick={openProfileEdit}>
|
||||
<UserCog size={14} />
|
||||
|
||||
@@ -2,17 +2,21 @@ import type { PageServerLoad } from './$types';
|
||||
|
||||
export const load: PageServerLoad = async ({ fetch, locals }) => {
|
||||
const session = await locals.auth();
|
||||
const [res, goalRes, heatmapRes, nutritionRes, latestRes] = await Promise.all([
|
||||
const [res, goalRes, heatmapRes, nutritionRes, latestRes, periodRes, sharedRes] = await Promise.all([
|
||||
fetch('/api/fitness/stats/overview'),
|
||||
fetch('/api/fitness/goal'),
|
||||
fetch('/api/fitness/stats/muscle-heatmap?weeks=8'),
|
||||
fetch('/api/fitness/stats/nutrition'),
|
||||
fetch('/api/fitness/measurements/latest')
|
||||
fetch('/api/fitness/measurements/latest'),
|
||||
fetch('/api/fitness/period').catch(() => null),
|
||||
fetch('/api/fitness/period/shared').catch(() => null)
|
||||
]);
|
||||
const stats = await res.json();
|
||||
const goal = goalRes.ok ? await goalRes.json() : { weeklyWorkouts: null, streak: 0 };
|
||||
const muscleHeatmap = heatmapRes.ok ? await heatmapRes.json() : { weeks: [], totals: {}, muscleGroups: [] };
|
||||
const nutritionStats = nutritionRes.ok ? await nutritionRes.json() : null;
|
||||
const latest = latestRes.ok ? await latestRes.json() : {};
|
||||
return { session, stats, goal, muscleHeatmap, nutritionStats, latest };
|
||||
const periods = periodRes?.ok ? (await periodRes.json()).entries : [];
|
||||
const sharedPeriods = sharedRes?.ok ? (await sharedRes.json()).shared : [];
|
||||
return { session, stats, goal, muscleHeatmap, nutritionStats, latest, periods, sharedPeriods };
|
||||
};
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
import MuscleHeatmap from '$lib/components/fitness/MuscleHeatmap.svelte';
|
||||
import { Dumbbell, Route, Flame, Weight, Beef, Droplet, Wheat, Scale, Target, Info, Ruler } from '@lucide/svelte';
|
||||
import FitnessStreakAura from '$lib/components/fitness/FitnessStreakAura.svelte';
|
||||
import PeriodTracker from '$lib/components/fitness/PeriodTracker.svelte';
|
||||
import { onMount } from 'svelte';
|
||||
import { detectFitnessLang, fitnessSlugs, t } from '$lib/js/fitnessI18n';
|
||||
import { toast } from '$lib/js/toast.svelte';
|
||||
@@ -429,6 +430,14 @@
|
||||
</div>
|
||||
</section>
|
||||
{/if}
|
||||
|
||||
{#if data.goal?.sex === 'female'}
|
||||
<PeriodTracker periods={data.periods ?? []} {lang} mode="projection" />
|
||||
{/if}
|
||||
|
||||
{#each data.sharedPeriods ?? [] as shared (shared.owner)}
|
||||
<PeriodTracker periods={shared.entries} {lang} readOnly ownerName={shared.owner} mode="projection" />
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
||||
Reference in New Issue
Block a user