|
@@ -1,7 +1,9 @@
|
|
|
import { Plus, Minus, Trash2 } from "lucide-react";
|
|
|
|
|
|
import { useI18n } from "locales/client";
|
|
|
+import { AVAILABLE_WORKOUT_SET_TYPES, MAX_WORKOUT_SET_COLUMNS } from "@/shared/constants/workout-set-types";
|
|
|
import { WorkoutSet, WorkoutSetType, WorkoutSetUnit } from "@/features/workout-session/types/workout-set";
|
|
|
+import { getWorkoutSetTypeLabels } from "@/features/workout-session/lib/workout-set-labels";
|
|
|
import { Button } from "@/components/ui/button";
|
|
|
|
|
|
interface WorkoutSetRowProps {
|
|
@@ -15,7 +17,7 @@ interface WorkoutSetRowProps {
|
|
|
export function WorkoutSessionSet({ set, setIndex, onChange, onFinish, onRemove }: WorkoutSetRowProps) {
|
|
|
const t = useI18n();
|
|
|
const types = set.types || [];
|
|
|
- const maxColumns = 4;
|
|
|
+ const typeLabels = getWorkoutSetTypeLabels(t);
|
|
|
|
|
|
const handleTypeChange = (columnIndex: number) => (e: React.ChangeEvent<HTMLSelectElement>) => {
|
|
|
const newTypes = [...types];
|
|
@@ -42,9 +44,12 @@ export function WorkoutSessionSet({ set, setIndex, onChange, onFinish, onRemove
|
|
|
};
|
|
|
|
|
|
const addColumn = () => {
|
|
|
- if (types.length < maxColumns) {
|
|
|
- const newTypes = [...types, "REPS" as WorkoutSetType];
|
|
|
- onChange(setIndex, { types: newTypes });
|
|
|
+ if (types.length < MAX_WORKOUT_SET_COLUMNS) {
|
|
|
+ const firstAvailableType = AVAILABLE_WORKOUT_SET_TYPES.find((t) => !types.includes(t));
|
|
|
+ if (firstAvailableType) {
|
|
|
+ const newTypes = [...types, firstAvailableType];
|
|
|
+ onChange(setIndex, { types: newTypes });
|
|
|
+ }
|
|
|
}
|
|
|
};
|
|
|
|
|
@@ -169,38 +174,44 @@ export function WorkoutSessionSet({ set, setIndex, onChange, onFinish, onRemove
|
|
|
|
|
|
{/* Columns of types, stack vertical on mobile, horizontal on md+ */}
|
|
|
<div className="flex flex-col md:flex-row gap-6 md:gap-2 w-full">
|
|
|
- {types.map((type, columnIndex) => (
|
|
|
- <div className="flex flex-col w-full md:w-auto" key={columnIndex}>
|
|
|
- <div className="flex items-center w-full gap-1 mb-1">
|
|
|
- <select
|
|
|
- className="border border-black dark:border-slate-700 rounded font-bold px-1 py-2 text-base w-full bg-white dark:bg-slate-800 dark:text-gray-200 min-w-0 h-10 "
|
|
|
- disabled={set.completed}
|
|
|
- onChange={handleTypeChange(columnIndex)}
|
|
|
- value={type}
|
|
|
- >
|
|
|
- <option value="TIME">{t("workout_builder.session.time")}</option>
|
|
|
- <option value="WEIGHT">{t("workout_builder.session.weight")}</option>
|
|
|
- <option value="REPS">{t("workout_builder.session.reps")}</option>
|
|
|
- <option value="BODYWEIGHT">{t("workout_builder.session.bodyweight")}</option>
|
|
|
- </select>
|
|
|
- {types.length > 1 && (
|
|
|
- <Button
|
|
|
- className="p-1 h-auto bg-red-500 hover:bg-red-600 dark:bg-red-900 dark:hover:bg-red-800 flex-shrink-0"
|
|
|
- onClick={() => removeColumn(columnIndex)}
|
|
|
- size="small"
|
|
|
- variant="destructive"
|
|
|
+ {types.map((type, columnIndex) => {
|
|
|
+ // An option is available if it's not used by another column, OR it's the current column's type.
|
|
|
+ const availableTypes = AVAILABLE_WORKOUT_SET_TYPES.filter((option) => !types.includes(option) || option === type);
|
|
|
+
|
|
|
+ return (
|
|
|
+ <div className="flex flex-col w-full md:w-auto" key={columnIndex}>
|
|
|
+ <div className="flex items-center w-full gap-1 mb-1">
|
|
|
+ <select
|
|
|
+ className="border border-black dark:border-slate-700 rounded font-bold px-1 py-2 text-base w-full bg-white dark:bg-slate-800 dark:text-gray-200 min-w-0 h-10 "
|
|
|
+ disabled={set.completed}
|
|
|
+ onChange={handleTypeChange(columnIndex)}
|
|
|
+ value={type}
|
|
|
>
|
|
|
- <Minus className="h-3 w-3" />
|
|
|
- </Button>
|
|
|
- )}
|
|
|
+ {availableTypes.map((availableType) => (
|
|
|
+ <option key={availableType} value={availableType}>
|
|
|
+ {typeLabels[availableType]}
|
|
|
+ </option>
|
|
|
+ ))}
|
|
|
+ </select>
|
|
|
+ {types.length > 1 && (
|
|
|
+ <Button
|
|
|
+ className="p-1 h-auto bg-red-500 hover:bg-red-600 dark:bg-red-900 dark:hover:bg-red-800 flex-shrink-0"
|
|
|
+ onClick={() => removeColumn(columnIndex)}
|
|
|
+ size="small"
|
|
|
+ variant="destructive"
|
|
|
+ >
|
|
|
+ <Minus className="h-3 w-3" />
|
|
|
+ </Button>
|
|
|
+ )}
|
|
|
+ </div>
|
|
|
+ {renderInputForType(type, columnIndex)}
|
|
|
</div>
|
|
|
- {renderInputForType(type, columnIndex)}
|
|
|
- </div>
|
|
|
- ))}
|
|
|
+ );
|
|
|
+ })}
|
|
|
</div>
|
|
|
|
|
|
{/* Add column button */}
|
|
|
- {types.length < maxColumns && !set.completed && (
|
|
|
+ {types.length < MAX_WORKOUT_SET_COLUMNS && !set.completed && (
|
|
|
<div className="flex w-full justify-start mt-1">
|
|
|
<Button
|
|
|
className="font-bold px-4 py-2 text-sm rounded-xl w-full md:w-auto mt-2"
|