Allow editing of multiple workouts

This commit is contained in:
Brandon Presley 2023-08-14 16:03:07 +12:00
parent 9fbae74a01
commit 8e42e9c3e4
4 changed files with 49 additions and 55 deletions

View File

@ -1,4 +1,5 @@
import {
NavigationProp,
RouteProp,
useFocusEffect,
useNavigation,
@ -12,9 +13,8 @@ import { In } from "typeorm";
import AppInput from "./AppInput";
import ConfirmDialog from "./ConfirmDialog";
import { MARGIN, PADDING } from "./constants";
import { getNow, planRepo, setRepo, settingsRepo } from "./db";
import { planRepo, setRepo, settingsRepo } from "./db";
import { fixNumeric } from "./fix-numeric";
import { defaultSet } from "./gym-set";
import Settings from "./settings";
import StackHeader from "./StackHeader";
import { toast } from "./toast";
@ -29,14 +29,13 @@ export default function EditWorkouts() {
const [steps, setSteps] = useState("");
const [oldSteps, setOldSteps] = useState("");
const [uri, setUri] = useState("");
const [oldUri, setOldUri] = useState("");
const [minutes, setMinutes] = useState("");
const [oldMinutes, setOldMinutes] = useState("");
const [seconds, setSeconds] = useState("");
const [oldSeconds, setOldSeconds] = useState("");
const [sets, setSets] = useState("");
const [oldSets, setOldSets] = useState("");
const navigation = useNavigation();
const navigation = useNavigation<NavigationProp<WorkoutsPageParams>>();
const setsRef = useRef<TextInput>(null);
const stepsRef = useRef<TextInput>(null);
const minutesRef = useRef<TextInput>(null);
@ -56,7 +55,9 @@ export default function EditWorkouts() {
console.log({ gymSets });
setOldNames(gymSets.map((set) => set.name).join(", "));
setOldSteps(gymSets.map((set) => set.steps).join(", "));
setOldUri(gymSets.map((set) => set.steps).join(", "));
setOldMinutes(gymSets.map((set) => set.minutes).join(", "));
setOldSeconds(gymSets.map((set) => set.seconds).join(", "));
setOldSets(gymSets.map((set) => set.sets).join(", "));
});
}, [params.names])
);
@ -73,36 +74,17 @@ export default function EditWorkouts() {
image: removeImage ? "" : uri,
}
);
await planRepo
.createQueryBuilder()
.update()
.set({
workouts: () => `REPLACE(workouts, '${params.gymSet.name}', '${name}')`,
})
.where("workouts LIKE :name", { name: `%${params.gymSet.name}%` })
.execute();
navigation.goBack();
};
const add = async () => {
const now = await getNow();
await setRepo.save({
...defaultSet,
name,
hidden: true,
image: uri,
minutes: minutes ? +minutes : 3,
seconds: seconds ? +seconds : 30,
sets: sets ? +sets : 3,
steps,
created: now,
});
navigation.goBack();
};
const save = async () => {
if (params.gymSet.name) return update();
return add();
for (const oldName of params.names) {
await planRepo
.createQueryBuilder()
.update()
.set({
workouts: () => `REPLACE(workouts, '${oldName}', '${name}')`,
})
.where("workouts LIKE :name", { name: `%${oldName}%` })
.execute();
}
navigation.navigate("WorkoutList", { clearNames: true });
};
const changeImage = useCallback(async () => {
@ -126,14 +108,12 @@ export default function EditWorkouts() {
return (
<>
<StackHeader
title={params.gymSet.name ? "Edit workout" : "Add workout"}
/>
<StackHeader title={`Edit ${params.names.length} workouts`} />
<View style={{ padding: PADDING, flex: 1 }}>
<ScrollView style={{ flex: 1 }}>
<AppInput
autoFocus
label="Name"
label={`Names: ${oldNames}`}
value={name}
onChangeText={setName}
onSubmitEditing={submitName}
@ -144,7 +124,7 @@ export default function EditWorkouts() {
selectTextOnFocus={false}
value={steps}
onChangeText={setSteps}
label="Steps"
label={`Steps: ${oldSteps}`}
multiline
onSubmitEditing={() => setsRef.current?.focus()}
/>
@ -158,7 +138,7 @@ export default function EditWorkouts() {
if (fixed.length !== newSets.length)
toast("Sets must be a number");
}}
label="Sets per workout"
label={`Sets: ${oldSets}`}
keyboardType="numeric"
onSubmitEditing={() => minutesRef.current?.focus()}
/>
@ -174,14 +154,14 @@ export default function EditWorkouts() {
if (fixed.length !== newMinutes.length)
toast("Reps must be a number");
}}
label="Rest minutes"
label={`Rest minutes: ${oldMinutes}`}
keyboardType="numeric"
/>
<AppInput
innerRef={secondsRef}
value={seconds}
onChangeText={setSeconds}
label="Rest seconds"
label={`Rest seconds: ${oldSeconds}`}
keyboardType="numeric"
blurOnSubmit
/>
@ -206,7 +186,7 @@ export default function EditWorkouts() {
</Button>
)}
</ScrollView>
<Button disabled={!name} mode="outlined" icon="save" onPress={save}>
<Button disabled={!name} mode="outlined" icon="save" onPress={update}>
Save
</Button>
<ConfirmDialog

View File

@ -25,7 +25,7 @@ export default function WorkoutItem({
const description = useMemo(() => {
const seconds = item.seconds?.toString().padStart(2, "0");
return `${item.sets} x ${item.minutes || 0}:${seconds}`;
}, [item]);
}, [item.sets, item.minutes, item.seconds]);
const left = useCallback(() => {
if (!images || !item.image) return null;
@ -34,10 +34,10 @@ export default function WorkoutItem({
);
}, [item.image, images]);
const long = useCallback(() => {
const long = () => {
if (names.length > 0) return;
setNames([item.name]);
}, [names.length, item.name, setNames]);
};
const backgroundColor = useMemo(() => {
if (!names.includes(item.name)) return;
@ -45,13 +45,14 @@ export default function WorkoutItem({
return LIGHT_RIPPLE;
}, [dark, names, item.name]);
const press = useCallback(() => {
const press = () => {
console.log({ names });
if (names.length === 0)
return navigation.navigate("EditWorkout", { gymSet: item });
const removing = names.find((name) => name === item.name);
if (removing) setNames(names.filter((name) => name !== item.name));
else setNames([...names, item.name]);
}, [names, item, navigation, setNames]);
};
return (
<List.Item

View File

@ -1,11 +1,14 @@
import {
NavigationProp,
RouteProp,
useFocusEffect,
useNavigation,
useRoute,
} from "@react-navigation/native";
import { useCallback, useState } from "react";
import { FlatList } from "react-native";
import { List } from "react-native-paper";
import { In } from "typeorm";
import { LIMIT } from "./constants";
import { setRepo, settingsRepo } from "./db";
import DrawerHeader from "./DrawerHeader";
@ -25,6 +28,7 @@ export default function WorkoutList() {
const [settings, setSettings] = useState<Settings>();
const [names, setNames] = useState<string[]>([]);
const navigation = useNavigation<NavigationProp<WorkoutsPageParams>>();
const { params } = useRoute<RouteProp<WorkoutsPageParams, "WorkoutList">>();
const refresh = useCallback(async (value: string) => {
const newWorkouts = await setRepo
@ -45,7 +49,8 @@ export default function WorkoutList() {
useCallback(() => {
refresh(term);
settingsRepo.findOne({ where: {} }).then(setSettings);
}, [refresh, term])
if (params?.clearNames) setNames([]);
}, [refresh, term, params])
);
const renderItem = useCallback(
@ -106,7 +111,7 @@ export default function WorkoutList() {
const remove = async () => {
setNames([]);
await setRepo.delete(names.length > 0 ? names : {});
if (names.length > 0) await setRepo.delete({ name: In(names) });
await refresh(term);
};
@ -114,11 +119,15 @@ export default function WorkoutList() {
setNames(workouts.map((workout) => workout.name));
};
const edit = useCallback(() => {}, []);
const edit = () => {
navigation.navigate("EditWorkouts", { names });
};
return (
<>
<DrawerHeader name="Workouts">
<DrawerHeader
name={names.length > 0 ? `${names.length} selected` : "Workouts"}
>
<ListMenu
onClear={clear}
onDelete={remove}
@ -131,7 +140,7 @@ export default function WorkoutList() {
{workouts?.length === 0 ? (
<List.Item
title="No workouts yet."
description="A workout is something you do at the gym. For example Deadlifts are a workout."
description="A workout is something you do at the gym. E.g. Deadlifts"
/>
) : (
<FlatList

View File

@ -1,10 +1,13 @@
import { createStackNavigator } from "@react-navigation/stack";
import EditWorkout from "./EditWorkout";
import EditWorkouts from "./EditWorkouts";
import GymSet from "./gym-set";
import WorkoutList from "./WorkoutList";
export type WorkoutsPageParams = {
WorkoutList: {};
WorkoutList: {
clearNames?: boolean;
};
EditWorkout: {
gymSet: GymSet;
};
@ -22,6 +25,7 @@ export default function WorkoutsPage() {
>
<Stack.Screen name="WorkoutList" component={WorkoutList} />
<Stack.Screen name="EditWorkout" component={EditWorkout} />
<Stack.Screen name="EditWorkouts" component={EditWorkouts} />
</Stack.Navigator>
);
}