Allow editing of multiple workouts
This commit is contained in:
parent
9fbae74a01
commit
8e42e9c3e4
|
@ -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,
|
||||
}
|
||||
);
|
||||
for (const oldName of params.names) {
|
||||
await planRepo
|
||||
.createQueryBuilder()
|
||||
.update()
|
||||
.set({
|
||||
workouts: () => `REPLACE(workouts, '${params.gymSet.name}', '${name}')`,
|
||||
workouts: () => `REPLACE(workouts, '${oldName}', '${name}')`,
|
||||
})
|
||||
.where("workouts LIKE :name", { name: `%${params.gymSet.name}%` })
|
||||
.where("workouts LIKE :name", { name: `%${oldName}%` })
|
||||
.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();
|
||||
}
|
||||
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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user