Days off workouts on Tracker view
This commit is contained in:
@@ -18,9 +18,64 @@ const IdleView: React.FC<IdleViewProps> = ({ tracker, lang }) => {
|
||||
plans,
|
||||
showPlanPrep,
|
||||
setShowPlanPrep,
|
||||
confirmPlanStart
|
||||
confirmPlanStart,
|
||||
lastWorkoutDate
|
||||
} = tracker;
|
||||
|
||||
// Calculate days off
|
||||
const getDaysOffContent = () => {
|
||||
if (!lastWorkoutDate) {
|
||||
return {
|
||||
title: t('first_workout_prompt', lang),
|
||||
subtitle: null,
|
||||
colorClass: 'text-on-surface'
|
||||
};
|
||||
}
|
||||
|
||||
const now = new Date();
|
||||
now.setHours(0, 0, 0, 0);
|
||||
const last = new Date(lastWorkoutDate);
|
||||
last.setHours(0, 0, 0, 0);
|
||||
|
||||
const diffTime = Math.abs(now.getTime() - last.getTime());
|
||||
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
|
||||
|
||||
if (diffDays === 0) {
|
||||
return {
|
||||
title: t('last_workout_today', lang),
|
||||
subtitle: null,
|
||||
colorClass: 'text-on-surface'
|
||||
};
|
||||
}
|
||||
|
||||
const prefix = t('days_off', lang);
|
||||
|
||||
if (diffDays === 1) {
|
||||
return {
|
||||
title: `${prefix} ${diffDays}`,
|
||||
subtitle: null,
|
||||
colorClass: 'text-green-500' // 1 is green
|
||||
};
|
||||
}
|
||||
|
||||
if (diffDays >= 5) {
|
||||
return {
|
||||
title: `${prefix} ${diffDays}`,
|
||||
subtitle: null,
|
||||
colorClass: 'text-red-500' // 5 and more is red
|
||||
};
|
||||
}
|
||||
|
||||
// Gradient for 2-4
|
||||
return {
|
||||
title: `${prefix} ${diffDays}`,
|
||||
subtitle: null,
|
||||
colorClass: 'bg-gradient-to-r from-green-500 to-red-500 bg-clip-text text-transparent'
|
||||
};
|
||||
};
|
||||
|
||||
const content = getDaysOffContent();
|
||||
|
||||
return (
|
||||
<div className="flex flex-col h-full p-4 md:p-8 overflow-y-auto relative">
|
||||
<div className="flex-1 flex flex-col items-center justify-center space-y-12">
|
||||
@@ -29,8 +84,8 @@ const IdleView: React.FC<IdleViewProps> = ({ tracker, lang }) => {
|
||||
<Dumbbell size={40} />
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<h1 className="text-3xl font-normal text-on-surface">{t('ready_title', lang)}</h1>
|
||||
<p className="text-on-surface-variant text-sm">{t('ready_subtitle', lang)}</p>
|
||||
<h1 className={`text-3xl font-normal ${content.colorClass}`}>{content.title}</h1>
|
||||
<p className="text-on-surface-variant text-sm">{content.subtitle}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -51,6 +51,9 @@ export const useTracker = (props: any) => { // Props ignored/removed
|
||||
const [isSporadicMode, setIsSporadicMode] = useState(false);
|
||||
const [sporadicSuccess, setSporadicSuccess] = useState(false);
|
||||
|
||||
// Last Workout State
|
||||
const [lastWorkoutDate, setLastWorkoutDate] = useState<Date | null>(null);
|
||||
|
||||
// Hooks
|
||||
const elapsedTime = useSessionTimer(activeSession);
|
||||
// useWorkoutForm needs onUpdateSet. But context updateSet signature might be different?
|
||||
@@ -93,6 +96,17 @@ export const useTracker = (props: any) => { // Props ignored/removed
|
||||
setUserBodyWeight(userWeight.toString());
|
||||
}
|
||||
|
||||
try {
|
||||
const lastSessionRes = await api.get<any>('/sessions/active/last');
|
||||
if (lastSessionRes.success && lastSessionRes.data?.session?.endTime) {
|
||||
setLastWorkoutDate(new Date(lastSessionRes.data.session.endTime));
|
||||
} else {
|
||||
setLastWorkoutDate(null);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Failed to load last session", err);
|
||||
}
|
||||
|
||||
loadQuickLogSession();
|
||||
};
|
||||
loadData();
|
||||
@@ -265,7 +279,8 @@ export const useTracker = (props: any) => { // Props ignored/removed
|
||||
onRemoveSet: removeSet,
|
||||
updateSet: handleUpdateSetWrapper,
|
||||
activeSession, // Need this in view
|
||||
timer // Expose timer to views
|
||||
timer, // Expose timer to views
|
||||
lastWorkoutDate
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user