Side attribute editable for Unilateral exercises

This commit is contained in:
AG
2025-12-10 19:58:42 +02:00
parent 9243fec947
commit 3df4abba47
11 changed files with 190 additions and 52 deletions

View File

@@ -60,6 +60,8 @@ const ActiveSessionView: React.FC<ActiveSessionViewProps> = ({ tracker, activeSe
setEditDistance,
editHeight,
setEditHeight,
editSide,
setEditSide,
handleCancelEdit,
handleSaveEdit,
handleEditSet,
@@ -243,6 +245,39 @@ const ActiveSessionView: React.FC<ActiveSessionViewProps> = ({ tracker, activeSe
placeholder="Height (cm)"
/>
)}
{(() => {
const exDef = exercises.find(e => e.name === set.exerciseName); // Best effort matching by name since set might not have exerciseId deeply populated in some contexts, but id is safer.
// Actually set has exerciseId usually. Let's try to match by ID if possible, else name.
// But wait, ActiveSession sets might not have exerciseId if created ad-hoc? No, they should.
// Let's assume we can look up by name if id missing, or just check set.side presence.
// Detailed look: The session object has sets.
// Ideally check exDef.isUnilateral.
const isUnilateral = set.side || (exercises.find(e => e.name === set.exerciseName)?.isUnilateral);
if (isUnilateral) {
return (
<div className="col-span-2 flex bg-surface-container-high rounded p-0.5">
{(['LEFT', 'ALTERNATELY', 'RIGHT'] as const).map((side) => {
const labelMap: Record<string, string> = { LEFT: 'L', RIGHT: 'R', ALTERNATELY: 'A' };
return (
<button
key={side}
onClick={() => setEditSide(side)}
title={t(side.toLowerCase() as any, lang)}
className={`flex-1 text-[10px] py-1 rounded transition-colors ${editSide === side
? 'bg-primary/10 text-primary font-bold'
: 'text-on-surface-variant hover:bg-surface-container'
}`}
>
{labelMap[side]}
</button>
);
})}
</div>
)
}
return null;
})()}
</div>
</div>
) : (

View File

@@ -101,24 +101,27 @@ const SetLogger: React.FC<SetLoggerProps> = ({ tracker, lang, onLogSet, isSporad
<div className="flex items-center gap-2 bg-surface-container rounded-full p-1">
<button
onClick={() => setUnilateralSide('LEFT')}
title={t('left', lang)}
className={`w-full text-center px-4 py-2 rounded-full text-sm font-medium transition-colors ${unilateralSide === 'LEFT' ? 'bg-primary-container text-on-primary-container' : 'text-on-surface-variant hover:bg-surface-container-high'
}`}
>
{t('left', lang)}
L
</button>
<button
onClick={() => setUnilateralSide('ALTERNATELY')}
title={t('alternately', lang)}
className={`w-full text-center px-4 py-2 rounded-full text-sm font-medium transition-colors ${unilateralSide === 'ALTERNATELY' ? 'bg-tertiary-container text-on-tertiary-container' : 'text-on-surface-variant hover:bg-surface-container-high'
}`}
>
{t('alternately', lang) || 'Alternately'}
A
</button>
<button
onClick={() => setUnilateralSide('RIGHT')}
title={t('right', lang)}
className={`w-full text-center px-4 py-2 rounded-full text-sm font-medium transition-colors ${unilateralSide === 'RIGHT' ? 'bg-secondary-container text-on-secondary-container' : 'text-on-surface-variant hover:bg-surface-container-high'
}`}
>
{t('right', lang)}
R
</button>
</div>
)}

View File

@@ -143,6 +143,39 @@ const SporadicView: React.FC<SporadicViewProps> = ({ tracker, lang }) => {
</button>
</div>
<div className="space-y-4">
{/* Side Selector */}
{(() => {
const exDef = exercises.find(e => e.name === editingSet.exerciseName);
const isUnilateral = editingSet.side || exDef?.isUnilateral;
if (isUnilateral) {
return (
<div className="bg-surface-container-high rounded-lg p-2">
<label className="text-sm text-on-surface-variant block mb-2">{t('unilateral', lang)}</label>
<div className="flex bg-surface-container rounded p-0.5">
{(['LEFT', 'ALTERNATELY', 'RIGHT'] as const).map((side) => {
const labelMap: Record<string, string> = { LEFT: 'L', RIGHT: 'R', ALTERNATELY: 'A' };
return (
<button
key={side}
onClick={() => setEditingSet({ ...editingSet, side })}
title={t(side.toLowerCase() as any, lang)}
className={`flex-1 text-xs py-2 rounded transition-colors ${editingSet.side === side
? 'bg-primary/10 text-primary font-bold'
: 'text-on-surface-variant hover:bg-surface-container-high'
}`}
>
{labelMap[side]}
</button>
);
})}
</div>
</div>
)
}
return null;
})()}
{(editingSet.type === 'STRENGTH' || editingSet.type === 'BODYWEIGHT') && (
<>
<div>

View File

@@ -226,6 +226,7 @@ export const useTracker = (props: any) => { // Props ignored/removed
editDuration: form.editDuration, setEditDuration: form.setEditDuration,
editDistance: form.editDistance, setEditDistance: form.setEditDistance,
editHeight: form.editHeight, setEditHeight: form.setEditHeight,
editSide: form.editSide, setEditSide: form.setEditSide,
isSporadicMode, setIsSporadicMode,
sporadicSuccess,