History added to Quick Log. Some minor fixes.

This commit is contained in:
AG
2025-11-29 19:53:26 +02:00
parent 3d6fd001cb
commit 1de50e32c3
5 changed files with 57 additions and 11 deletions

View File

@@ -235,6 +235,7 @@ function App() {
userWeight={currentUser.profile?.weight} userWeight={currentUser.profile?.weight}
activeSession={activeSession} activeSession={activeSession}
activePlan={activePlan} activePlan={activePlan}
sporadicSets={sporadicSets}
onSessionStart={handleStartSession} onSessionStart={handleStartSession}
onSessionEnd={handleEndSession} onSessionEnd={handleEndSession}
onSessionQuit={handleQuitSession} onSessionQuit={handleQuitSession}

View File

@@ -1,6 +1,6 @@
import React from 'react'; import React, { useState, useEffect } from 'react';
import { Dumbbell, Scale, Activity, Timer as TimerIcon, ArrowRight, ArrowUp, Plus, CheckCircle } from 'lucide-react'; import { Dumbbell, Scale, Activity, Timer as TimerIcon, ArrowRight, ArrowUp, Plus, CheckCircle, Edit, Trash2 } from 'lucide-react';
import { ExerciseType, Language } from '../../types'; import { ExerciseType, Language, SporadicSet } from '../../types';
import { t } from '../../services/i18n'; import { t } from '../../services/i18n';
import FilledInput from '../FilledInput'; import FilledInput from '../FilledInput';
import ExerciseModal from '../ExerciseModal'; import ExerciseModal from '../ExerciseModal';
@@ -9,9 +9,10 @@ import { useTracker } from './useTracker';
interface SporadicViewProps { interface SporadicViewProps {
tracker: ReturnType<typeof useTracker>; tracker: ReturnType<typeof useTracker>;
lang: Language; lang: Language;
sporadicSets?: SporadicSet[];
} }
const SporadicView: React.FC<SporadicViewProps> = ({ tracker, lang }) => { const SporadicView: React.FC<SporadicViewProps> = ({ tracker, lang, sporadicSets }) => {
const { const {
searchQuery, searchQuery,
setSearchQuery, setSearchQuery,
@@ -40,6 +41,27 @@ const SporadicView: React.FC<SporadicViewProps> = ({ tracker, lang }) => {
resetForm resetForm
} = tracker; } = tracker;
const [todaysSets, setTodaysSets] = useState<SporadicSet[]>([]);
useEffect(() => {
if (sporadicSets) {
const startOfDay = new Date();
startOfDay.setHours(0, 0, 0, 0);
const todayS = sporadicSets.filter(s => s.timestamp >= startOfDay.getTime());
setTodaysSets(todayS.sort((a, b) => b.timestamp - a.timestamp));
}
}, [sporadicSets]);
const renderSetMetrics = (set: SporadicSet) => {
const metrics: string[] = [];
if (set.weight) metrics.push(`${set.weight} ${t('weight_kg', lang)}`);
if (set.reps) metrics.push(`${set.reps} ${t('reps', lang)}`);
if (set.durationSeconds) metrics.push(`${set.durationSeconds} ${t('time_sec', lang)}`);
if (set.distanceMeters) metrics.push(`${set.distanceMeters} ${t('dist_m', lang)}`);
if (set.height) metrics.push(`${set.height} ${t('height_cm', lang)}`);
return metrics.join(' / ');
};
return ( return (
<div className="flex flex-col h-full max-h-full overflow-hidden relative bg-surface"> <div className="flex flex-col h-full max-h-full overflow-hidden relative bg-surface">
<div className="px-4 py-3 bg-surface-container shadow-elevation-1 z-20 flex justify-between items-center"> <div className="px-4 py-3 bg-surface-container shadow-elevation-1 z-20 flex justify-between items-center">
@@ -50,7 +72,7 @@ const SporadicView: React.FC<SporadicViewProps> = ({ tracker, lang }) => {
}} }}
className="text-error font-medium text-sm hover:opacity-80 transition-opacity" className="text-error font-medium text-sm hover:opacity-80 transition-opacity"
> >
{t('cancel', lang)} {t('quit', lang)}
</button> </button>
<div className="flex flex-col items-center"> <div className="flex flex-col items-center">
<h2 className="text-title-medium text-on-surface flex items-center gap-2 font-medium"> <h2 className="text-title-medium text-on-surface flex items-center gap-2 font-medium">
@@ -102,7 +124,7 @@ const SporadicView: React.FC<SporadicViewProps> = ({ tracker, lang }) => {
<button <button
key={ex.id} key={ex.id}
onMouseDown={(e) => { onMouseDown={(e) => {
e.preventDefault(); // Prevent input blur e.preventDefault();
setSelectedExercise(ex); setSelectedExercise(ex);
setSearchQuery(ex.name); setSearchQuery(ex.name);
setShowSuggestions(false); setShowSuggestions(false);
@@ -178,6 +200,26 @@ const SporadicView: React.FC<SporadicViewProps> = ({ tracker, lang }) => {
</button> </button>
</div> </div>
)} )}
{/* History Section */}
{todaysSets.length > 0 && (
<div className="mt-6">
<h3 className="text-title-medium font-medium mb-3">{t('history_section', lang)}</h3>
<div className="space-y-2">
{todaysSets.map(set => (
<div key={set.id} className="bg-surface-container rounded-lg p-3 flex items-center justify-between shadow-elevation-1 animate-in fade-in">
<div>
<p className="font-medium text-on-surface">{set.exerciseName}</p>
<p className="text-sm text-on-surface-variant">{renderSetMetrics(set)}</p>
</div>
<div className="flex items-center gap-2">
{/* Edit and Delete buttons can be added here in the future */}
</div>
</div>
))}
</div>
</div>
)}
</div> </div>
{isCreating && ( {isCreating && (

View File

@@ -1,5 +1,6 @@
import React from 'react'; import React from 'react';
import { WorkoutSession, WorkoutSet, WorkoutPlan, Language } from '../../types'; import { WorkoutSession, WorkoutSet, WorkoutPlan, Language, SporadicSet } from '../../types';
import { useTracker } from './useTracker'; import { useTracker } from './useTracker';
import IdleView from './IdleView'; import IdleView from './IdleView';
import SporadicView from './SporadicView'; import SporadicView from './SporadicView';
@@ -10,6 +11,7 @@ interface TrackerProps {
userWeight?: number; userWeight?: number;
activeSession: WorkoutSession | null; activeSession: WorkoutSession | null;
activePlan: WorkoutPlan | null; activePlan: WorkoutPlan | null;
sporadicSets?: SporadicSet[];
onSessionStart: (plan?: WorkoutPlan, startWeight?: number) => void; onSessionStart: (plan?: WorkoutPlan, startWeight?: number) => void;
onSessionEnd: () => void; onSessionEnd: () => void;
onSessionQuit: () => void; onSessionQuit: () => void;
@@ -23,7 +25,7 @@ interface TrackerProps {
const Tracker: React.FC<TrackerProps> = (props) => { const Tracker: React.FC<TrackerProps> = (props) => {
const tracker = useTracker(props); const tracker = useTracker(props);
const { isSporadicMode } = tracker; const { isSporadicMode } = tracker;
const { activeSession, lang, onSessionEnd, onSessionQuit, onRemoveSet } = props; const { activeSession, lang, onSessionEnd, onSessionQuit, onRemoveSet, sporadicSets } = props;
if (activeSession) { if (activeSession) {
return ( return (
@@ -39,7 +41,7 @@ const Tracker: React.FC<TrackerProps> = (props) => {
} }
if (isSporadicMode) { if (isSporadicMode) {
return <SporadicView tracker={tracker} lang={lang} />; return <SporadicView tracker={tracker} lang={lang} sporadicSets={sporadicSets} />;
} }
return <IdleView tracker={tracker} lang={lang} />; return <IdleView tracker={tracker} lang={lang} />;

Binary file not shown.

View File

@@ -48,6 +48,7 @@ const translations = {
prep_title: 'Preparation', prep_title: 'Preparation',
prep_no_instructions: 'No specific instructions.', prep_no_instructions: 'No specific instructions.',
cancel: 'Cancel', cancel: 'Cancel',
quit: 'Quit',
start: 'Start', start: 'Start',
finish: 'Finish', finish: 'Finish',
finish_confirm_title: 'Finish Workout?', finish_confirm_title: 'Finish Workout?',
@@ -104,7 +105,7 @@ const translations = {
// Plans // Plans
plans_empty: 'No plans created', plans_empty: 'No plans created',
plan_editor: 'Plan Editor', plan_editor: 'Plan Editor',
plan_name_ph: 'E.g. Leg Day', plan_name_ph: 'E.g. Full-body Routine',
plan_desc_ph: 'Describe preparation...', plan_desc_ph: 'Describe preparation...',
exercises_list: 'Exercises', exercises_list: 'Exercises',
weighted: 'Weighted', weighted: 'Weighted',
@@ -263,7 +264,7 @@ const translations = {
// Plans // Plans
plans_empty: 'Нет созданных планов', plans_empty: 'Нет созданных планов',
plan_editor: 'Редактор плана', plan_editor: 'Редактор плана',
plan_name_ph: 'Например: День ног', plan_name_ph: 'Например: Комплекс на всё тело',
plan_desc_ph: 'Опишите подготовку...', plan_desc_ph: 'Опишите подготовку...',
exercises_list: 'Упражнения', exercises_list: 'Упражнения',
weighted: 'С отягощением', weighted: 'С отягощением',