Pause adding multi-edit to workouts
Got up to the point where i'm find/replacing the old names with new names, and I got confused about the purpose of this feature.
This commit is contained in:
parent
79cde3a219
commit
dc5434991a
|
@ -23,16 +23,16 @@ export default function EditWorkout() {
|
||||||
const { params } = useRoute<RouteProp<WorkoutsPageParams, "EditWorkout">>();
|
const { params } = useRoute<RouteProp<WorkoutsPageParams, "EditWorkout">>();
|
||||||
const [removeImage, setRemoveImage] = useState(false);
|
const [removeImage, setRemoveImage] = useState(false);
|
||||||
const [showRemove, setShowRemove] = useState(false);
|
const [showRemove, setShowRemove] = useState(false);
|
||||||
const [name, setName] = useState(params.value.name);
|
const [name, setName] = useState(params.gymSet.name);
|
||||||
const [steps, setSteps] = useState(params.value.steps);
|
const [steps, setSteps] = useState(params.gymSet.steps);
|
||||||
const [uri, setUri] = useState(params.value.image);
|
const [uri, setUri] = useState(params.gymSet.image);
|
||||||
const [minutes, setMinutes] = useState(
|
const [minutes, setMinutes] = useState(
|
||||||
params.value.minutes?.toString() ?? "3"
|
params.gymSet.minutes?.toString() ?? "3"
|
||||||
);
|
);
|
||||||
const [seconds, setSeconds] = useState(
|
const [seconds, setSeconds] = useState(
|
||||||
params.value.seconds?.toString() ?? "30"
|
params.gymSet.seconds?.toString() ?? "30"
|
||||||
);
|
);
|
||||||
const [sets, setSets] = useState(params.value.sets?.toString() ?? "3");
|
const [sets, setSets] = useState(params.gymSet.sets?.toString() ?? "3");
|
||||||
const navigation = useNavigation();
|
const navigation = useNavigation();
|
||||||
const setsRef = useRef<TextInput>(null);
|
const setsRef = useRef<TextInput>(null);
|
||||||
const stepsRef = useRef<TextInput>(null);
|
const stepsRef = useRef<TextInput>(null);
|
||||||
|
@ -48,9 +48,9 @@ export default function EditWorkout() {
|
||||||
|
|
||||||
const update = async () => {
|
const update = async () => {
|
||||||
await setRepo.update(
|
await setRepo.update(
|
||||||
{ name: params.value.name },
|
{ name: params.gymSet.name },
|
||||||
{
|
{
|
||||||
name: name || params.value.name,
|
name: name || params.gymSet.name,
|
||||||
sets: Number(sets),
|
sets: Number(sets),
|
||||||
minutes: +minutes,
|
minutes: +minutes,
|
||||||
seconds: +seconds,
|
seconds: +seconds,
|
||||||
|
@ -62,7 +62,7 @@ export default function EditWorkout() {
|
||||||
`UPDATE plans
|
`UPDATE plans
|
||||||
SET workouts = REPLACE(workouts, $1, $2)
|
SET workouts = REPLACE(workouts, $1, $2)
|
||||||
WHERE workouts LIKE $3`,
|
WHERE workouts LIKE $3`,
|
||||||
[params.value.name, name, `%${params.value.name}%`]
|
[params.gymSet.name, name, `%${params.gymSet.name}%`]
|
||||||
);
|
);
|
||||||
navigation.goBack();
|
navigation.goBack();
|
||||||
};
|
};
|
||||||
|
@ -84,7 +84,7 @@ export default function EditWorkout() {
|
||||||
};
|
};
|
||||||
|
|
||||||
const save = async () => {
|
const save = async () => {
|
||||||
if (params.value.name) return update();
|
if (params.gymSet.name) return update();
|
||||||
return add();
|
return add();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -109,7 +109,9 @@ export default function EditWorkout() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<StackHeader title={params.value.name ? "Edit workout" : "Add workout"} />
|
<StackHeader
|
||||||
|
title={params.gymSet.name ? "Edit workout" : "Add workout"}
|
||||||
|
/>
|
||||||
<View style={{ padding: PADDING, flex: 1 }}>
|
<View style={{ padding: PADDING, flex: 1 }}>
|
||||||
<ScrollView style={{ flex: 1 }}>
|
<ScrollView style={{ flex: 1 }}>
|
||||||
<AppInput
|
<AppInput
|
||||||
|
|
223
EditWorkouts.tsx
Normal file
223
EditWorkouts.tsx
Normal file
|
@ -0,0 +1,223 @@
|
||||||
|
import {
|
||||||
|
RouteProp,
|
||||||
|
useFocusEffect,
|
||||||
|
useNavigation,
|
||||||
|
useRoute,
|
||||||
|
} from "@react-navigation/native";
|
||||||
|
import { useCallback, useRef, useState } from "react";
|
||||||
|
import { ScrollView, TextInput, View } from "react-native";
|
||||||
|
import DocumentPicker from "react-native-document-picker";
|
||||||
|
import { Button, Card, TouchableRipple } from "react-native-paper";
|
||||||
|
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 { fixNumeric } from "./fix-numeric";
|
||||||
|
import { defaultSet } from "./gym-set";
|
||||||
|
import Settings from "./settings";
|
||||||
|
import StackHeader from "./StackHeader";
|
||||||
|
import { toast } from "./toast";
|
||||||
|
import { WorkoutsPageParams } from "./WorkoutsPage";
|
||||||
|
|
||||||
|
export default function EditWorkouts() {
|
||||||
|
const { params } = useRoute<RouteProp<WorkoutsPageParams, "EditWorkouts">>();
|
||||||
|
const [removeImage, setRemoveImage] = useState(false);
|
||||||
|
const [showRemove, setShowRemove] = useState(false);
|
||||||
|
const [name, setName] = useState("");
|
||||||
|
const [oldNames, setOldNames] = useState(params.names.join(", "));
|
||||||
|
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 setsRef = useRef<TextInput>(null);
|
||||||
|
const stepsRef = useRef<TextInput>(null);
|
||||||
|
const minutesRef = useRef<TextInput>(null);
|
||||||
|
const secondsRef = useRef<TextInput>(null);
|
||||||
|
const [settings, setSettings] = useState<Settings>();
|
||||||
|
|
||||||
|
useFocusEffect(
|
||||||
|
useCallback(() => {
|
||||||
|
settingsRepo.findOne({ where: {} }).then(setSettings);
|
||||||
|
setRepo
|
||||||
|
.createQueryBuilder()
|
||||||
|
.select()
|
||||||
|
.where("name IN (:...names)", { names: params.names })
|
||||||
|
.groupBy("name")
|
||||||
|
.getMany()
|
||||||
|
.then((gymSets) => {
|
||||||
|
console.log({ gymSets });
|
||||||
|
setOldNames(gymSets.map((set) => set.name).join(", "));
|
||||||
|
setOldSteps(gymSets.map((set) => set.steps).join(", "));
|
||||||
|
setOldUri(gymSets.map((set) => set.steps).join(", "));
|
||||||
|
});
|
||||||
|
}, [params.names])
|
||||||
|
);
|
||||||
|
|
||||||
|
const update = async () => {
|
||||||
|
await setRepo.update(
|
||||||
|
{ name: In(params.names) },
|
||||||
|
{
|
||||||
|
name: name || undefined,
|
||||||
|
sets: sets ? Number(sets) : undefined,
|
||||||
|
minutes: minutes ? Number(minutes) : undefined,
|
||||||
|
seconds: seconds ? Number(seconds) : undefined,
|
||||||
|
steps: steps || undefined,
|
||||||
|
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();
|
||||||
|
};
|
||||||
|
|
||||||
|
const changeImage = useCallback(async () => {
|
||||||
|
const { fileCopyUri } = await DocumentPicker.pickSingle({
|
||||||
|
type: DocumentPicker.types.images,
|
||||||
|
copyTo: "documentDirectory",
|
||||||
|
});
|
||||||
|
if (fileCopyUri) setUri(fileCopyUri);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleRemove = useCallback(async () => {
|
||||||
|
setUri("");
|
||||||
|
setRemoveImage(true);
|
||||||
|
setShowRemove(false);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const submitName = () => {
|
||||||
|
if (settings.steps) stepsRef.current?.focus();
|
||||||
|
else setsRef.current?.focus();
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<StackHeader
|
||||||
|
title={params.gymSet.name ? "Edit workout" : "Add workout"}
|
||||||
|
/>
|
||||||
|
<View style={{ padding: PADDING, flex: 1 }}>
|
||||||
|
<ScrollView style={{ flex: 1 }}>
|
||||||
|
<AppInput
|
||||||
|
autoFocus
|
||||||
|
label="Name"
|
||||||
|
value={name}
|
||||||
|
onChangeText={setName}
|
||||||
|
onSubmitEditing={submitName}
|
||||||
|
/>
|
||||||
|
{settings?.steps && (
|
||||||
|
<AppInput
|
||||||
|
innerRef={stepsRef}
|
||||||
|
selectTextOnFocus={false}
|
||||||
|
value={steps}
|
||||||
|
onChangeText={setSteps}
|
||||||
|
label="Steps"
|
||||||
|
multiline
|
||||||
|
onSubmitEditing={() => setsRef.current?.focus()}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<AppInput
|
||||||
|
innerRef={setsRef}
|
||||||
|
value={sets}
|
||||||
|
onChangeText={(newSets) => {
|
||||||
|
const fixed = fixNumeric(newSets);
|
||||||
|
setSets(fixed);
|
||||||
|
if (fixed.length !== newSets.length)
|
||||||
|
toast("Sets must be a number");
|
||||||
|
}}
|
||||||
|
label="Sets per workout"
|
||||||
|
keyboardType="numeric"
|
||||||
|
onSubmitEditing={() => minutesRef.current?.focus()}
|
||||||
|
/>
|
||||||
|
{settings?.alarm && (
|
||||||
|
<>
|
||||||
|
<AppInput
|
||||||
|
innerRef={minutesRef}
|
||||||
|
onSubmitEditing={() => secondsRef.current?.focus()}
|
||||||
|
value={minutes}
|
||||||
|
onChangeText={(newMinutes) => {
|
||||||
|
const fixed = fixNumeric(newMinutes);
|
||||||
|
setMinutes(fixed);
|
||||||
|
if (fixed.length !== newMinutes.length)
|
||||||
|
toast("Reps must be a number");
|
||||||
|
}}
|
||||||
|
label="Rest minutes"
|
||||||
|
keyboardType="numeric"
|
||||||
|
/>
|
||||||
|
<AppInput
|
||||||
|
innerRef={secondsRef}
|
||||||
|
value={seconds}
|
||||||
|
onChangeText={setSeconds}
|
||||||
|
label="Rest seconds"
|
||||||
|
keyboardType="numeric"
|
||||||
|
blurOnSubmit
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{settings?.images && uri && (
|
||||||
|
<TouchableRipple
|
||||||
|
style={{ marginBottom: MARGIN }}
|
||||||
|
onPress={changeImage}
|
||||||
|
onLongPress={() => setShowRemove(true)}
|
||||||
|
>
|
||||||
|
<Card.Cover source={{ uri }} />
|
||||||
|
</TouchableRipple>
|
||||||
|
)}
|
||||||
|
{settings?.images && !uri && (
|
||||||
|
<Button
|
||||||
|
style={{ marginBottom: MARGIN }}
|
||||||
|
onPress={changeImage}
|
||||||
|
icon="add-photo-alternate"
|
||||||
|
>
|
||||||
|
Image
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</ScrollView>
|
||||||
|
<Button disabled={!name} mode="outlined" icon="save" onPress={save}>
|
||||||
|
Save
|
||||||
|
</Button>
|
||||||
|
<ConfirmDialog
|
||||||
|
title="Remove image"
|
||||||
|
onOk={handleRemove}
|
||||||
|
show={showRemove}
|
||||||
|
setShow={setShowRemove}
|
||||||
|
>
|
||||||
|
Are you sure you want to remove the image?
|
||||||
|
</ConfirmDialog>
|
||||||
|
</View>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
|
@ -11,11 +11,11 @@ export default function ListMenu({
|
||||||
ids,
|
ids,
|
||||||
}: {
|
}: {
|
||||||
onEdit: () => void;
|
onEdit: () => void;
|
||||||
onCopy: () => void;
|
onCopy?: () => void;
|
||||||
onClear: () => void;
|
onClear: () => void;
|
||||||
onDelete: () => void;
|
onDelete: () => void;
|
||||||
onSelect: () => void;
|
onSelect: () => void;
|
||||||
ids?: number[];
|
ids?: unknown[];
|
||||||
}) {
|
}) {
|
||||||
const [showMenu, setShowMenu] = useState(false);
|
const [showMenu, setShowMenu] = useState(false);
|
||||||
const [showRemove, setShowRemove] = useState(false);
|
const [showRemove, setShowRemove] = useState(false);
|
||||||
|
@ -64,12 +64,14 @@ export default function ListMenu({
|
||||||
onPress={edit}
|
onPress={edit}
|
||||||
disabled={ids?.length === 0}
|
disabled={ids?.length === 0}
|
||||||
/>
|
/>
|
||||||
|
{onCopy && (
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
leadingIcon="content-copy"
|
leadingIcon="content-copy"
|
||||||
title="Copy"
|
title="Copy"
|
||||||
onPress={copy}
|
onPress={copy}
|
||||||
disabled={ids?.length === 0}
|
disabled={ids?.length === 0}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
<Divider />
|
<Divider />
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
leadingIcon="delete"
|
leadingIcon="delete"
|
||||||
|
|
|
@ -16,7 +16,6 @@ export default function SetItem({
|
||||||
setIds,
|
setIds,
|
||||||
}: {
|
}: {
|
||||||
item: GymSet;
|
item: GymSet;
|
||||||
onRemove: () => void;
|
|
||||||
settings: Settings;
|
settings: Settings;
|
||||||
ids: number[];
|
ids: number[];
|
||||||
setIds: (value: number[]) => void;
|
setIds: (value: number[]) => void;
|
||||||
|
|
|
@ -52,12 +52,11 @@ export default function SetList() {
|
||||||
settings={settings}
|
settings={settings}
|
||||||
item={item}
|
item={item}
|
||||||
key={item.id}
|
key={item.id}
|
||||||
onRemove={() => refresh(term)}
|
|
||||||
ids={ids}
|
ids={ids}
|
||||||
setIds={setIds}
|
setIds={setIds}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
[refresh, term, settings, ids]
|
[settings, ids]
|
||||||
);
|
);
|
||||||
|
|
||||||
const next = useCallback(async () => {
|
const next = useCallback(async () => {
|
||||||
|
|
|
@ -1,39 +1,26 @@
|
||||||
import { NavigationProp, useNavigation } from "@react-navigation/native";
|
import { NavigationProp, useNavigation } from "@react-navigation/native";
|
||||||
import { useCallback, useMemo, useState } from "react";
|
import { useCallback, useMemo } from "react";
|
||||||
import { GestureResponderEvent, Image } from "react-native";
|
import { Image } from "react-native";
|
||||||
import { List, Menu, Text } from "react-native-paper";
|
import { List } from "react-native-paper";
|
||||||
import ConfirmDialog from "./ConfirmDialog";
|
import { DARK_RIPPLE } from "./constants";
|
||||||
import { setRepo } from "./db";
|
import { LIGHT_RIPPLE } from "./constants";
|
||||||
import GymSet from "./gym-set";
|
import GymSet from "./gym-set";
|
||||||
|
import useDark from "./use-dark";
|
||||||
import { WorkoutsPageParams } from "./WorkoutsPage";
|
import { WorkoutsPageParams } from "./WorkoutsPage";
|
||||||
|
|
||||||
export default function WorkoutItem({
|
export default function WorkoutItem({
|
||||||
item,
|
item,
|
||||||
onRemove,
|
setNames,
|
||||||
|
names,
|
||||||
images,
|
images,
|
||||||
}: {
|
}: {
|
||||||
item: GymSet;
|
item: GymSet;
|
||||||
onRemove: () => void;
|
|
||||||
images: boolean;
|
images: boolean;
|
||||||
|
setNames: (value: string[]) => void;
|
||||||
|
names: string[];
|
||||||
}) {
|
}) {
|
||||||
const [showMenu, setShowMenu] = useState(false);
|
|
||||||
const [anchor, setAnchor] = useState({ x: 0, y: 0 });
|
|
||||||
const [showRemove, setShowRemove] = useState("");
|
|
||||||
const navigation = useNavigation<NavigationProp<WorkoutsPageParams>>();
|
const navigation = useNavigation<NavigationProp<WorkoutsPageParams>>();
|
||||||
|
const dark = useDark();
|
||||||
const remove = useCallback(async () => {
|
|
||||||
await setRepo.delete({ name: item.name });
|
|
||||||
setShowMenu(false);
|
|
||||||
onRemove();
|
|
||||||
}, [setShowMenu, onRemove, item.name]);
|
|
||||||
|
|
||||||
const longPress = useCallback(
|
|
||||||
(e: GestureResponderEvent) => {
|
|
||||||
setAnchor({ x: e.nativeEvent.pageX, y: e.nativeEvent.pageY });
|
|
||||||
setShowMenu(true);
|
|
||||||
},
|
|
||||||
[setShowMenu, setAnchor]
|
|
||||||
);
|
|
||||||
|
|
||||||
const description = useMemo(() => {
|
const description = useMemo(() => {
|
||||||
const seconds = item.seconds?.toString().padStart(2, "0");
|
const seconds = item.seconds?.toString().padStart(2, "0");
|
||||||
|
@ -47,50 +34,33 @@ export default function WorkoutItem({
|
||||||
);
|
);
|
||||||
}, [item.image, images]);
|
}, [item.image, images]);
|
||||||
|
|
||||||
const right = useCallback(() => {
|
const long = useCallback(() => {
|
||||||
return (
|
if (names.length > 0) return;
|
||||||
<Text
|
setNames([item.name]);
|
||||||
style={{
|
}, [names.length, item.name, setNames]);
|
||||||
alignSelf: "center",
|
|
||||||
}}
|
const backgroundColor = useMemo(() => {
|
||||||
>
|
if (!names.includes(item.name)) return;
|
||||||
<Menu
|
if (dark) return DARK_RIPPLE;
|
||||||
anchor={anchor}
|
return LIGHT_RIPPLE;
|
||||||
visible={showMenu}
|
}, [dark, names, item.name]);
|
||||||
onDismiss={() => setShowMenu(false)}
|
|
||||||
>
|
const press = useCallback(() => {
|
||||||
<Menu.Item
|
if (names.length === 0)
|
||||||
leadingIcon="delete"
|
return navigation.navigate("EditWorkout", { gymSet: item });
|
||||||
onPress={() => {
|
const removing = names.find((name) => name === item.name);
|
||||||
setShowRemove(item.name);
|
if (removing) setNames(names.filter((name) => name !== item.name));
|
||||||
setShowMenu(false);
|
else setNames([...names, item.name]);
|
||||||
}}
|
}, [names, item, navigation, setNames]);
|
||||||
title="Delete"
|
|
||||||
/>
|
|
||||||
</Menu>
|
|
||||||
</Text>
|
|
||||||
);
|
|
||||||
}, [anchor, showMenu, item.name]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
|
||||||
<List.Item
|
<List.Item
|
||||||
onPress={() => navigation.navigate("EditWorkout", { value: item })}
|
onPress={press}
|
||||||
title={item.name}
|
title={item.name}
|
||||||
description={description}
|
description={description}
|
||||||
onLongPress={longPress}
|
onLongPress={long}
|
||||||
left={left}
|
left={left}
|
||||||
right={right}
|
style={{ backgroundColor }}
|
||||||
/>
|
/>
|
||||||
<ConfirmDialog
|
|
||||||
title={`Delete ${showRemove}`}
|
|
||||||
show={!!showRemove}
|
|
||||||
setShow={(show) => (show ? null : setShowRemove(""))}
|
|
||||||
onOk={remove}
|
|
||||||
>
|
|
||||||
This irreversibly deletes ALL sets related to this workout. Are you
|
|
||||||
sure?
|
|
||||||
</ConfirmDialog>
|
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import { LIMIT } from "./constants";
|
||||||
import { setRepo, settingsRepo } from "./db";
|
import { setRepo, settingsRepo } from "./db";
|
||||||
import DrawerHeader from "./DrawerHeader";
|
import DrawerHeader from "./DrawerHeader";
|
||||||
import GymSet from "./gym-set";
|
import GymSet from "./gym-set";
|
||||||
|
import ListMenu from "./ListMenu";
|
||||||
import Page from "./Page";
|
import Page from "./Page";
|
||||||
import SetList from "./SetList";
|
import SetList from "./SetList";
|
||||||
import Settings from "./settings";
|
import Settings from "./settings";
|
||||||
|
@ -22,6 +23,7 @@ export default function WorkoutList() {
|
||||||
const [term, setTerm] = useState("");
|
const [term, setTerm] = useState("");
|
||||||
const [end, setEnd] = useState(false);
|
const [end, setEnd] = useState(false);
|
||||||
const [settings, setSettings] = useState<Settings>();
|
const [settings, setSettings] = useState<Settings>();
|
||||||
|
const [names, setNames] = useState<string[]>([]);
|
||||||
const navigation = useNavigation<NavigationProp<WorkoutsPageParams>>();
|
const navigation = useNavigation<NavigationProp<WorkoutsPageParams>>();
|
||||||
|
|
||||||
const refresh = useCallback(async (value: string) => {
|
const refresh = useCallback(async (value: string) => {
|
||||||
|
@ -52,13 +54,14 @@ export default function WorkoutList() {
|
||||||
images={settings?.images}
|
images={settings?.images}
|
||||||
item={item}
|
item={item}
|
||||||
key={item.name}
|
key={item.name}
|
||||||
onRemove={() => refresh(term)}
|
names={names}
|
||||||
|
setNames={setNames}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
[refresh, term, settings?.images]
|
[settings?.images, names]
|
||||||
);
|
);
|
||||||
|
|
||||||
const next = useCallback(async () => {
|
const next = async () => {
|
||||||
if (end) return;
|
if (end) return;
|
||||||
const newOffset = offset + LIMIT;
|
const newOffset = offset + LIMIT;
|
||||||
console.log(`${SetList.name}.next:`, {
|
console.log(`${SetList.name}.next:`, {
|
||||||
|
@ -81,11 +84,11 @@ export default function WorkoutList() {
|
||||||
setWorkouts([...workouts, ...newWorkouts]);
|
setWorkouts([...workouts, ...newWorkouts]);
|
||||||
if (newWorkouts.length < LIMIT) return setEnd(true);
|
if (newWorkouts.length < LIMIT) return setEnd(true);
|
||||||
setOffset(newOffset);
|
setOffset(newOffset);
|
||||||
}, [term, end, offset, workouts]);
|
};
|
||||||
|
|
||||||
const onAdd = useCallback(async () => {
|
const onAdd = useCallback(async () => {
|
||||||
navigation.navigate("EditWorkout", {
|
navigation.navigate("EditWorkout", {
|
||||||
value: new GymSet(),
|
gymSet: new GymSet(),
|
||||||
});
|
});
|
||||||
}, [navigation]);
|
}, [navigation]);
|
||||||
|
|
||||||
|
@ -97,9 +100,33 @@ export default function WorkoutList() {
|
||||||
[refresh]
|
[refresh]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const clear = useCallback(() => {
|
||||||
|
setNames([]);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const remove = async () => {
|
||||||
|
setNames([]);
|
||||||
|
await setRepo.delete(names.length > 0 ? names : {});
|
||||||
|
await refresh(term);
|
||||||
|
};
|
||||||
|
|
||||||
|
const select = () => {
|
||||||
|
setNames(workouts.map((workout) => workout.name));
|
||||||
|
};
|
||||||
|
|
||||||
|
const edit = useCallback(() => {}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<DrawerHeader name="Workouts" />
|
<DrawerHeader name="Workouts">
|
||||||
|
<ListMenu
|
||||||
|
onClear={clear}
|
||||||
|
onDelete={remove}
|
||||||
|
onEdit={edit}
|
||||||
|
ids={names}
|
||||||
|
onSelect={select}
|
||||||
|
/>
|
||||||
|
</DrawerHeader>
|
||||||
<Page onAdd={onAdd} term={term} search={search}>
|
<Page onAdd={onAdd} term={term} search={search}>
|
||||||
{workouts?.length === 0 ? (
|
{workouts?.length === 0 ? (
|
||||||
<List.Item
|
<List.Item
|
||||||
|
|
|
@ -6,7 +6,10 @@ import WorkoutList from "./WorkoutList";
|
||||||
export type WorkoutsPageParams = {
|
export type WorkoutsPageParams = {
|
||||||
WorkoutList: {};
|
WorkoutList: {};
|
||||||
EditWorkout: {
|
EditWorkout: {
|
||||||
value: GymSet;
|
gymSet: GymSet;
|
||||||
|
};
|
||||||
|
EditWorkouts: {
|
||||||
|
names: string[];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
import { createStackNavigator } from '@react-navigation/stack'
|
import { createStackNavigator } from "@react-navigation/stack";
|
||||||
import React from 'react'
|
import React from "react";
|
||||||
import 'react-native'
|
import "react-native";
|
||||||
import { render, waitFor } from '@testing-library/react-native'
|
import { render, waitFor } from "@testing-library/react-native";
|
||||||
import EditWorkout from '../EditWorkout'
|
import EditWorkout from "../EditWorkout";
|
||||||
import GymSet from '../gym-set'
|
import GymSet from "../gym-set";
|
||||||
import { MockProviders } from '../mock-providers'
|
import { MockProviders } from "../mock-providers";
|
||||||
import Settings from '../settings'
|
import Settings from "../settings";
|
||||||
import { WorkoutsPageParams } from '../WorkoutsPage'
|
import { WorkoutsPageParams } from "../WorkoutsPage";
|
||||||
|
|
||||||
jest.mock('../db.ts', () => ({
|
jest.mock("../db.ts", () => ({
|
||||||
settingsRepo: {
|
settingsRepo: {
|
||||||
findOne: () =>
|
findOne: () =>
|
||||||
Promise.resolve({
|
Promise.resolve({
|
||||||
|
@ -16,28 +16,28 @@ jest.mock('../db.ts', () => ({
|
||||||
alarm: true,
|
alarm: true,
|
||||||
} as Settings),
|
} as Settings),
|
||||||
},
|
},
|
||||||
}))
|
}));
|
||||||
|
|
||||||
test('renders correctly', async () => {
|
test("renders correctly", async () => {
|
||||||
const Stack = createStackNavigator<WorkoutsPageParams>()
|
const Stack = createStackNavigator<WorkoutsPageParams>();
|
||||||
const { getByText, getAllByText } = render(
|
const { getByText, getAllByText } = render(
|
||||||
<MockProviders>
|
<MockProviders>
|
||||||
<Stack.Navigator>
|
<Stack.Navigator>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
initialParams={{
|
initialParams={{
|
||||||
value: { name: 'Bench press' } as GymSet,
|
gymSet: { name: "Bench press" } as GymSet,
|
||||||
}}
|
}}
|
||||||
name='EditWorkout'
|
name="EditWorkout"
|
||||||
component={EditWorkout}
|
component={EditWorkout}
|
||||||
/>
|
/>
|
||||||
</Stack.Navigator>
|
</Stack.Navigator>
|
||||||
</MockProviders>,
|
</MockProviders>
|
||||||
)
|
);
|
||||||
const title = await waitFor(() => getByText(/Edit workout/i))
|
const title = await waitFor(() => getByText(/Edit workout/i));
|
||||||
expect(title).toBeDefined()
|
expect(title).toBeDefined();
|
||||||
expect(getAllByText(/Name/i).length).toBeGreaterThan(0)
|
expect(getAllByText(/Name/i).length).toBeGreaterThan(0);
|
||||||
expect(getAllByText(/Sets/i).length).toBeGreaterThan(0)
|
expect(getAllByText(/Sets/i).length).toBeGreaterThan(0);
|
||||||
expect(getAllByText(/Minutes/i).length).toBeGreaterThan(0)
|
expect(getAllByText(/Minutes/i).length).toBeGreaterThan(0);
|
||||||
expect(getAllByText(/Seconds/i).length).toBeGreaterThan(0)
|
expect(getAllByText(/Seconds/i).length).toBeGreaterThan(0);
|
||||||
expect(getAllByText(/Save/i).length).toBeGreaterThan(0)
|
expect(getAllByText(/Save/i).length).toBeGreaterThan(0);
|
||||||
})
|
});
|
||||||
|
|
Loading…
Reference in New Issue
Block a user