Migrate from Drawer -> Stacks to Stack -> Drawer

This simplifies our codebase greatly by
only having a single stack navigator and
a single drawer navigator. Previously we had
a stack navigator for every main page on the drawer.
This commit is contained in:
Brandon Presley 2023-10-28 15:59:03 +13:00
parent b4154b336f
commit e8ee4a253e
40 changed files with 172 additions and 963 deletions

View File

@ -15,9 +15,10 @@ import MaterialIcon from "react-native-vector-icons/MaterialCommunityIcons";
import { AppDataSource } from "./data-source"; import { AppDataSource } from "./data-source";
import { settingsRepo } from "./db"; import { settingsRepo } from "./db";
import { emitter } from "./emitter"; import { emitter } from "./emitter";
import Routes from "./Routes"; import AppDrawer from "./AppDrawer";
import { TOAST } from "./toast"; import { TOAST } from "./toast";
import { ThemeContext } from "./use-theme"; import { ThemeContext } from "./use-theme";
import AppStack from "./AppStack";
export const CombinedDefaultTheme = { export const CombinedDefaultTheme = {
...NavigationDefaultTheme, ...NavigationDefaultTheme,
@ -105,7 +106,7 @@ const App = () => {
setDarkColor, setDarkColor,
}} }}
> >
<Routes /> <AppStack />
</ThemeContext.Provider> </ThemeContext.Provider>
)} )}
</NavigationContainer> </NavigationContainer>

View File

@ -1,19 +1,19 @@
import { createDrawerNavigator } from "@react-navigation/drawer"; import { createDrawerNavigator } from "@react-navigation/drawer";
import { IconButton } from "react-native-paper"; import { IconButton } from "react-native-paper";
import GraphsPage from "./GraphsPage"; import GraphsList from "./GraphsList";
import { DrawerParamList } from "./drawer-param-list"; import InsightsPage from "./InsightsPage";
import HomePage from "./HomePage"; import PlanList from "./PlanList";
import PlanPage from "./PlanPage"; import SetList from "./SetList";
import SettingsPage from "./SettingsPage"; import SettingsPage from "./SettingsPage";
import TimerPage from "./TimerPage"; import TimerPage from "./TimerPage";
import WeightList from "./WeightList";
import WorkoutList from "./WorkoutList";
import { DrawerParams } from "./drawer-param-list";
import useDark from "./use-dark"; import useDark from "./use-dark";
import WorkoutsPage from "./WorkoutsPage";
import WeightPage from "./WeightPage";
import InsightsPage from "./InsightsPage";
const Drawer = createDrawerNavigator<DrawerParamList>(); const Drawer = createDrawerNavigator<DrawerParams>();
export default function Routes() { export default function AppDrawer() {
const dark = useDark(); const dark = useDark();
return ( return (
@ -26,24 +26,24 @@ export default function Routes() {
> >
<Drawer.Screen <Drawer.Screen
name="Home" name="Home"
component={HomePage} component={SetList}
options={{ drawerIcon: () => <IconButton icon="home-outline" /> }} options={{ drawerIcon: () => <IconButton icon="home-outline" /> }}
/> />
<Drawer.Screen <Drawer.Screen
name="Plans" name="Plans"
component={PlanPage} component={PlanList}
options={{ drawerIcon: () => <IconButton icon="calendar-outline" /> }} options={{ drawerIcon: () => <IconButton icon="calendar-outline" /> }}
/> />
<Drawer.Screen <Drawer.Screen
name="Graphs" name="Graphs"
component={GraphsPage} component={GraphsList}
options={{ options={{
drawerIcon: () => <IconButton icon="chart-bell-curve-cumulative" />, drawerIcon: () => <IconButton icon="chart-bell-curve-cumulative" />,
}} }}
/> />
<Drawer.Screen <Drawer.Screen
name="Workouts" name="Workouts"
component={WorkoutsPage} component={WorkoutList}
options={{ drawerIcon: () => <IconButton icon="dumbbell" /> }} options={{ drawerIcon: () => <IconButton icon="dumbbell" /> }}
/> />
<Drawer.Screen <Drawer.Screen
@ -53,7 +53,7 @@ export default function Routes() {
/> />
<Drawer.Screen <Drawer.Screen
name="Weight" name="Weight"
component={WeightPage} component={WeightList}
options={{ drawerIcon: () => <IconButton icon="scale-bathroom" /> }} options={{ drawerIcon: () => <IconButton icon="scale-bathroom" /> }}
/> />
<Drawer.Screen <Drawer.Screen

65
AppStack.tsx Normal file
View File

@ -0,0 +1,65 @@
import { createStackNavigator } from "@react-navigation/stack";
import AppDrawer from "./AppDrawer";
import EditPlan from "./EditPlan";
import EditSet from "./EditSet";
import EditSets from "./EditSets";
import EditWeight from "./EditWeight";
import EditWorkout from "./EditWorkout";
import EditWorkouts from "./EditWorkouts";
import StartPlan from "./StartPlan";
import ViewGraph from "./ViewGraph";
import ViewWeightGraph from "./ViewWeightGraph";
import GymSet from "./gym-set";
import { Plan } from "./plan";
import Weight from "./weight";
export type StackParams = {
Drawer: {};
EditSet: {
set: GymSet;
};
EditSets: {
ids: number[];
};
EditPlan: {
plan: Plan;
};
StartPlan: {
plan: Plan;
first?: GymSet;
};
ViewGraph: {
name: string;
};
EditWeight: {
weight: Weight;
};
ViewWeightGraph: {};
EditWorkout: {
gymSet: GymSet;
};
EditWorkouts: {
names: string[];
};
};
const Stack = createStackNavigator<StackParams>();
export default function AppStack() {
return (
<Stack.Navigator
screenOptions={{ headerShown: false, animationEnabled: false }}
>
<Stack.Screen name="Drawer" component={AppDrawer} />
<Stack.Screen name="EditSet" component={EditSet} />
<Stack.Screen name="EditSets" component={EditSets} />
<Stack.Screen name="EditPlan" component={EditPlan} />
<Stack.Screen name="StartPlan" component={StartPlan} />
<Stack.Screen name="ViewGraph" component={ViewGraph} />
<Stack.Screen name="EditWeight" component={EditWeight} />
<Stack.Screen name="ViewWeightGraph" component={ViewWeightGraph} />
<Stack.Screen name="EditWorkout" component={EditWorkout} />
<Stack.Screen name="EditWorkouts" component={EditWorkouts} />
</Stack.Navigator>
);
}

View File

@ -1,7 +1,7 @@
import { DrawerNavigationProp } from "@react-navigation/drawer"; import { DrawerNavigationProp } from "@react-navigation/drawer";
import { useNavigation } from "@react-navigation/native"; import { useNavigation } from "@react-navigation/native";
import { Appbar, IconButton } from "react-native-paper"; import { Appbar, IconButton } from "react-native-paper";
import { DrawerParamList } from "./drawer-param-list"; import { DrawerParams } from "./drawer-param-list";
export default function DrawerHeader({ export default function DrawerHeader({
name, name,
@ -10,7 +10,7 @@ export default function DrawerHeader({
name: string; name: string;
children?: JSX.Element | JSX.Element[]; children?: JSX.Element | JSX.Element[];
}) { }) {
const navigation = useNavigation<DrawerNavigationProp<DrawerParamList>>(); const navigation = useNavigation<DrawerNavigationProp<DrawerParams>>();
return ( return (
<Appbar.Header> <Appbar.Header>

View File

@ -10,14 +10,15 @@ import { Button, IconButton, Text } from "react-native-paper";
import { MARGIN, PADDING } from "./constants"; import { MARGIN, PADDING } from "./constants";
import { planRepo, setRepo } from "./db"; import { planRepo, setRepo } from "./db";
import { defaultSet } from "./gym-set"; import { defaultSet } from "./gym-set";
import { PlanPageParams } from "./plan-page-params";
import StackHeader from "./StackHeader"; import StackHeader from "./StackHeader";
import Switch from "./Switch"; import Switch from "./Switch";
import { DAYS } from "./time"; import { DAYS } from "./time";
import AppInput from "./AppInput"; import AppInput from "./AppInput";
import { StackParams } from "./AppStack";
import { DrawerParams } from "./drawer-param-list";
export default function EditPlan() { export default function EditPlan() {
const { params } = useRoute<RouteProp<PlanPageParams, "EditPlan">>(); const { params } = useRoute<RouteProp<StackParams, "EditPlan">>();
const { plan } = params; const { plan } = params;
const [title, setTitle] = useState<string>(plan?.title); const [title, setTitle] = useState<string>(plan?.title);
const [days, setDays] = useState<string[]>( const [days, setDays] = useState<string[]>(
@ -27,7 +28,10 @@ export default function EditPlan() {
plan.workouts ? plan.workouts.split(",") : [] plan.workouts ? plan.workouts.split(",") : []
); );
const [names, setNames] = useState<string[]>([]); const [names, setNames] = useState<string[]>([]);
const navigation = useNavigation<NavigationProp<PlanPageParams>>(); const { navigate: drawerNavigate } =
useNavigation<NavigationProp<DrawerParams>>();
const { navigate: stackNavigate } =
useNavigation<NavigationProp<StackParams>>();
useEffect(() => { useEffect(() => {
setRepo setRepo
@ -95,7 +99,7 @@ export default function EditPlan() {
}); });
if (!first) first = { ...defaultSet, name: workouts[0] }; if (!first) first = { ...defaultSet, name: workouts[0] };
delete first.id; delete first.id;
navigation.navigate("StartPlan", { plan: newPlan, first }); stackNavigate("StartPlan", { plan: newPlan, first });
}} }}
icon="play" icon="play"
/> />
@ -141,7 +145,7 @@ export default function EditPlan() {
icon="content-save" icon="content-save"
onPress={async () => { onPress={async () => {
await save(); await save();
navigation.navigate("PlanList"); drawerNavigate("Plans");
}} }}
> >
Save Save

View File

@ -28,15 +28,16 @@ import GymSet, {
GYM_SET_DELETED, GYM_SET_DELETED,
GYM_SET_UPDATED, GYM_SET_UPDATED,
} from "./gym-set"; } from "./gym-set";
import { HomePageParams } from "./home-page-params";
import Settings from "./settings"; import Settings from "./settings";
import StackHeader from "./StackHeader"; import StackHeader from "./StackHeader";
import { toast } from "./toast"; import { toast } from "./toast";
import { DrawerParams } from "./drawer-param-list";
import { StackParams } from "./AppStack";
export default function EditSet() { export default function EditSet() {
const { params } = useRoute<RouteProp<HomePageParams, "EditSet">>(); const { params } = useRoute<RouteProp<StackParams, "EditSet">>();
const { set } = params; const { set } = params;
const { navigate } = useNavigation<NavigationProp<HomePageParams>>(); const { goBack } = useNavigation<NavigationProp<DrawerParams>>();
const [settings, setSettings] = useState<Settings>({} as Settings); const [settings, setSettings] = useState<Settings>({} as Settings);
const [name, setName] = useState(set.name); const [name, setName] = useState(set.name);
const [reps, setReps] = useState(set.reps?.toString()); const [reps, setReps] = useState(set.reps?.toString());
@ -79,7 +80,7 @@ export default function EditSet() {
); );
const notify = (value: Partial<GymSet>) => { const notify = (value: Partial<GymSet>) => {
if (!settings.notify) return navigate("Sets"); if (!settings.notify) return goBack();
if ( if (
value.weight > set.weight || value.weight > set.weight ||
(value.reps > set.reps && value.weight === set.weight) (value.reps > set.reps && value.weight === set.weight)
@ -121,9 +122,9 @@ export default function EditSet() {
const saved = await setRepo.save(newSet); const saved = await setRepo.save(newSet);
notify(newSet); notify(newSet);
if (typeof set.id !== "number") return added(saved); if (typeof set.id !== "number") added(saved);
else emitter.emit(GYM_SET_UPDATED, saved); else emitter.emit(GYM_SET_UPDATED, saved);
navigate("Sets"); goBack();
}; };
const changeImage = useCallback(async () => { const changeImage = useCallback(async () => {
@ -160,7 +161,7 @@ export default function EditSet() {
const remove = async () => { const remove = async () => {
await setRepo.delete(set.id); await setRepo.delete(set.id);
emitter.emit(GYM_SET_DELETED); emitter.emit(GYM_SET_DELETED);
navigate("Sets"); goBack();
}; };
const openMenu = async () => { const openMenu = async () => {

View File

@ -16,14 +16,15 @@ import { MARGIN, PADDING } from "./constants";
import { setRepo, settingsRepo } from "./db"; import { setRepo, settingsRepo } from "./db";
import { emitter } from "./emitter"; import { emitter } from "./emitter";
import GymSet, { GYM_SET_CREATED } from "./gym-set"; import GymSet, { GYM_SET_CREATED } from "./gym-set";
import { HomePageParams } from "./home-page-params";
import Settings from "./settings"; import Settings from "./settings";
import StackHeader from "./StackHeader"; import StackHeader from "./StackHeader";
import { StackParams } from "./AppStack";
import { DrawerParams } from "./drawer-param-list";
export default function EditSets() { export default function EditSets() {
const { params } = useRoute<RouteProp<HomePageParams, "EditSets">>(); const { params } = useRoute<RouteProp<StackParams, "EditSets">>();
const { ids } = params; const { ids } = params;
const { navigate } = useNavigation<NavigationProp<HomePageParams>>(); const { navigate } = useNavigation<NavigationProp<DrawerParams>>();
const [settings, setSettings] = useState<Settings>({} as Settings); const [settings, setSettings] = useState<Settings>({} as Settings);
const [name, setName] = useState(""); const [name, setName] = useState("");
const [reps, setReps] = useState(""); const [reps, setReps] = useState("");
@ -63,7 +64,7 @@ export default function EditSets() {
if (newImage) update.image = newImage; if (newImage) update.image = newImage;
if (Object.keys(update).length > 0) await setRepo.update(ids, update); if (Object.keys(update).length > 0) await setRepo.update(ids, update);
emitter.emit(GYM_SET_CREATED); emitter.emit(GYM_SET_CREATED);
navigate("Sets"); navigate("Home");
}; };
const changeImage = useCallback(async () => { const changeImage = useCallback(async () => {

View File

@ -11,20 +11,21 @@ import { useCallback, useRef, useState } from "react";
import { TextInput, View } from "react-native"; import { TextInput, View } from "react-native";
import { Button, IconButton } from "react-native-paper"; import { Button, IconButton } from "react-native-paper";
import AppInput from "./AppInput"; import AppInput from "./AppInput";
import { StackParams } from "./AppStack";
import ConfirmDialog from "./ConfirmDialog"; import ConfirmDialog from "./ConfirmDialog";
import StackHeader from "./StackHeader";
import { MARGIN, PADDING } from "./constants"; import { MARGIN, PADDING } from "./constants";
import { AppDataSource } from "./data-source"; import { AppDataSource } from "./data-source";
import { getNow, settingsRepo, weightRepo } from "./db"; import { getNow, settingsRepo, weightRepo } from "./db";
import { DrawerParams } from "./drawer-param-list";
import Settings from "./settings"; import Settings from "./settings";
import StackHeader from "./StackHeader";
import { toast } from "./toast"; import { toast } from "./toast";
import Weight from "./weight"; import Weight from "./weight";
import { WeightPageParams } from "./WeightPage";
export default function EditWeight() { export default function EditWeight() {
const { params } = useRoute<RouteProp<WeightPageParams, "EditWeight">>(); const { params } = useRoute<RouteProp<StackParams, "EditWeight">>();
const { weight } = params; const { weight } = params;
const { navigate } = useNavigation<NavigationProp<WeightPageParams>>(); const { navigate } = useNavigation<NavigationProp<DrawerParams>>();
const [settings, setSettings] = useState<Settings>({} as Settings); const [settings, setSettings] = useState<Settings>({} as Settings);
const [value, setValue] = useState(weight.value?.toString()); const [value, setValue] = useState(weight.value?.toString());
const [unit, setUnit] = useState(weight.unit); const [unit, setUnit] = useState(weight.unit);
@ -55,7 +56,7 @@ export default function EditWeight() {
await weightRepo.save(newWeight); await weightRepo.save(newWeight);
if (settings.notify) await checkWeekly(); if (settings.notify) await checkWeekly();
navigate("Weights"); navigate("Weight");
}; };
const checkWeekly = async () => { const checkWeekly = async () => {
@ -94,7 +95,7 @@ export default function EditWeight() {
const remove = async () => { const remove = async () => {
if (!weight.id) return; if (!weight.id) return;
await weightRepo.delete(weight.id); await weightRepo.delete(weight.id);
navigate("Weights"); navigate("Weight");
}; };
return ( return (

View File

@ -19,10 +19,11 @@ import GymSet, { defaultSet, GYM_SET_CREATED } from "./gym-set";
import Settings from "./settings"; import Settings from "./settings";
import StackHeader from "./StackHeader"; import StackHeader from "./StackHeader";
import { toast } from "./toast"; import { toast } from "./toast";
import { WorkoutsPageParams } from "./WorkoutsPage"; import { DrawerParams } from "./drawer-param-list";
import { StackParams } from "./AppStack";
export default function EditWorkout() { export default function EditWorkout() {
const { params } = useRoute<RouteProp<WorkoutsPageParams, "EditWorkout">>(); const { params } = useRoute<RouteProp<StackParams, "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.gymSet.name); const [name, setName] = useState(params.gymSet.name);
@ -35,7 +36,7 @@ export default function EditWorkout() {
params.gymSet.seconds?.toString() ?? "30" params.gymSet.seconds?.toString() ?? "30"
); );
const [sets, setSets] = useState(params.gymSet.sets?.toString() ?? "3"); const [sets, setSets] = useState(params.gymSet.sets?.toString() ?? "3");
const { navigate } = useNavigation<NavigationProp<WorkoutsPageParams>>(); const { navigate } = useNavigation<NavigationProp<DrawerParams>>();
const setsRef = useRef<TextInput>(null); const setsRef = useRef<TextInput>(null);
const stepsRef = useRef<TextInput>(null); const stepsRef = useRef<TextInput>(null);
const minutesRef = useRef<TextInput>(null); const minutesRef = useRef<TextInput>(null);
@ -64,7 +65,7 @@ export default function EditWorkout() {
WHERE workouts LIKE $3`, WHERE workouts LIKE $3`,
[params.gymSet.name, name, `%${params.gymSet.name}%`] [params.gymSet.name, name, `%${params.gymSet.name}%`]
); );
navigate("WorkoutList", { update: newWorkout }); navigate("Workouts", { update: newWorkout });
}; };
const add = async () => { const add = async () => {
@ -81,7 +82,7 @@ export default function EditWorkout() {
created: now, created: now,
}); });
emitter.emit(GYM_SET_CREATED); emitter.emit(GYM_SET_CREATED);
navigate("WorkoutList", { reset: new Date().getTime() }); navigate("Workouts", { reset: new Date().getTime() });
}; };
const save = async () => { const save = async () => {
@ -184,13 +185,18 @@ export default function EditWorkout() {
<Button <Button
style={{ marginBottom: MARGIN }} style={{ marginBottom: MARGIN }}
onPress={changeImage} onPress={changeImage}
icon="add-photo-alternate" icon="image-plus"
> >
Image Image
</Button> </Button>
)} )}
</ScrollView> </ScrollView>
<Button disabled={!name} mode="outlined" icon="save" onPress={save}> <Button
disabled={!name}
mode="outlined"
icon="content-save"
onPress={save}
>
Save Save
</Button> </Button>
<ConfirmDialog <ConfirmDialog

View File

@ -16,7 +16,6 @@ export default function GraphsPage() {
screenOptions={{ headerShown: false, animationEnabled: false }} screenOptions={{ headerShown: false, animationEnabled: false }}
> >
<Stack.Screen name="GraphsList" component={GraphsList} /> <Stack.Screen name="GraphsList" component={GraphsList} />
<Stack.Screen name="ViewGraph" component={ViewGraph} />
</Stack.Navigator> </Stack.Navigator>
); );
} }

View File

@ -1,19 +0,0 @@
import { createStackNavigator } from "@react-navigation/stack";
import EditSet from "./EditSet";
import EditSets from "./EditSets";
import { HomePageParams } from "./home-page-params";
import SetList from "./SetList";
const Stack = createStackNavigator<HomePageParams>();
export default function HomePage() {
return (
<Stack.Navigator
screenOptions={{ headerShown: false, animationEnabled: false }}
>
<Stack.Screen name="Sets" component={SetList} />
<Stack.Screen name="EditSet" component={EditSet} />
<Stack.Screen name="EditSets" component={EditSets} />
</Stack.Navigator>
);
}

View File

@ -10,9 +10,9 @@ import { DARK_RIPPLE, LIGHT_RIPPLE } from "./constants";
import { setRepo } from "./db"; import { setRepo } from "./db";
import { defaultSet } from "./gym-set"; import { defaultSet } from "./gym-set";
import { Plan } from "./plan"; import { Plan } from "./plan";
import { PlanPageParams } from "./plan-page-params";
import { DAYS } from "./time"; import { DAYS } from "./time";
import useDark from "./use-dark"; import useDark from "./use-dark";
import { StackParams } from "./AppStack";
export default function PlanItem({ export default function PlanItem({
item, item,
@ -26,7 +26,7 @@ export default function PlanItem({
const [today, setToday] = useState<string>(); const [today, setToday] = useState<string>();
const dark = useDark(); const dark = useDark();
const days = useMemo(() => item.days.split(","), [item.days]); const days = useMemo(() => item.days.split(","), [item.days]);
const navigation = useNavigation<NavigationProp<PlanPageParams>>(); const navigation = useNavigation<NavigationProp<StackParams>>();
useFocusEffect( useFocusEffect(
useCallback(() => { useCallback(() => {

View File

@ -12,14 +12,14 @@ import DrawerHeader from "./DrawerHeader";
import ListMenu from "./ListMenu"; import ListMenu from "./ListMenu";
import Page from "./Page"; import Page from "./Page";
import { Plan } from "./plan"; import { Plan } from "./plan";
import { PlanPageParams } from "./plan-page-params";
import PlanItem from "./PlanItem"; import PlanItem from "./PlanItem";
import { StackParams } from "./AppStack";
export default function PlanList() { export default function PlanList() {
const [term, setTerm] = useState(""); const [term, setTerm] = useState("");
const [plans, setPlans] = useState<Plan[]>(); const [plans, setPlans] = useState<Plan[]>();
const [ids, setIds] = useState<number[]>([]); const [ids, setIds] = useState<number[]>([]);
const navigation = useNavigation<NavigationProp<PlanPageParams>>(); const navigation = useNavigation<NavigationProp<StackParams>>();
const refresh = useCallback(async (value: string) => { const refresh = useCallback(async (value: string) => {
console.log(`${PlanList.name}.refresh:`, value); console.log(`${PlanList.name}.refresh:`, value);

View File

@ -1,23 +0,0 @@
import { createStackNavigator } from "@react-navigation/stack";
import EditPlan from "./EditPlan";
import EditSet from "./EditSet";
import { PlanPageParams } from "./plan-page-params";
import PlanList from "./PlanList";
import StartPlan from "./StartPlan";
import ViewGraph from "./ViewGraph";
const Stack = createStackNavigator<PlanPageParams>();
export default function PlanPage() {
return (
<Stack.Navigator
screenOptions={{ headerShown: false, animationEnabled: false }}
>
<Stack.Screen name="PlanList" component={PlanList} />
<Stack.Screen name="EditPlan" component={EditPlan} />
<Stack.Screen name="StartPlan" component={StartPlan} />
<Stack.Screen name="EditSet" component={EditSet} />
<Stack.Screen name="ViewGraph" component={ViewGraph} />
</Stack.Navigator>
);
}

View File

@ -5,9 +5,9 @@ import { Image } from "react-native";
import { List, Text } from "react-native-paper"; import { List, Text } from "react-native-paper";
import { DARK_RIPPLE, LIGHT_RIPPLE } from "./constants"; import { DARK_RIPPLE, LIGHT_RIPPLE } from "./constants";
import GymSet from "./gym-set"; import GymSet from "./gym-set";
import { HomePageParams } from "./home-page-params";
import Settings from "./settings"; import Settings from "./settings";
import useDark from "./use-dark"; import useDark from "./use-dark";
import { StackParams } from "./AppStack";
export default function SetItem({ export default function SetItem({
item, item,
@ -21,7 +21,7 @@ export default function SetItem({
setIds: (value: number[]) => void; setIds: (value: number[]) => void;
}) { }) {
const dark = useDark(); const dark = useDark();
const navigation = useNavigation<NavigationProp<HomePageParams>>(); const navigation = useNavigation<NavigationProp<StackParams>>();
const longPress = useCallback(() => { const longPress = useCallback(() => {
if (ids.length > 0) return; if (ids.length > 0) return;

View File

@ -18,11 +18,12 @@ import GymSet, {
GYM_SET_DELETED, GYM_SET_DELETED,
GYM_SET_UPDATED, GYM_SET_UPDATED,
} from "./gym-set"; } from "./gym-set";
import { HomePageParams } from "./home-page-params";
import ListMenu from "./ListMenu"; import ListMenu from "./ListMenu";
import Page from "./Page"; import Page from "./Page";
import SetItem from "./SetItem"; import SetItem from "./SetItem";
import Settings, { SETTINGS } from "./settings"; import Settings, { SETTINGS } from "./settings";
import { StackParams } from "./AppStack";
import { DrawerParams } from "./drawer-param-list";
export default function SetList() { export default function SetList() {
const [refreshing, setRefreshing] = useState(false); const [refreshing, setRefreshing] = useState(false);
@ -31,8 +32,8 @@ export default function SetList() {
const [end, setEnd] = useState(false); const [end, setEnd] = useState(false);
const [settings, setSettings] = useState<Settings>(); const [settings, setSettings] = useState<Settings>();
const [ids, setIds] = useState<number[]>([]); const [ids, setIds] = useState<number[]>([]);
const navigation = useNavigation<NavigationProp<HomePageParams>>(); const navigation = useNavigation<NavigationProp<StackParams>>();
const { params } = useRoute<RouteProp<HomePageParams, "Sets">>(); const { params } = useRoute<RouteProp<DrawerParams, "Home">>();
const [term, setTerm] = useState(params?.search || ""); const [term, setTerm] = useState(params?.search || "");
const reset = useCallback( const reset = useCallback(

View File

@ -9,7 +9,7 @@ import ConfirmDialog from "./ConfirmDialog";
import { MARGIN } from "./constants"; import { MARGIN } from "./constants";
import { AppDataSource } from "./data-source"; import { AppDataSource } from "./data-source";
import { setRepo, settingsRepo } from "./db"; import { setRepo, settingsRepo } from "./db";
import { DrawerParamList } from "./drawer-param-list"; import { DrawerParams } from "./drawer-param-list";
import DrawerHeader from "./DrawerHeader"; import DrawerHeader from "./DrawerHeader";
import Input from "./input"; import Input from "./input";
import { darkOptions, lightOptions, themeOptions } from "./options"; import { darkOptions, lightOptions, themeOptions } from "./options";
@ -46,7 +46,7 @@ export default function SettingsPage() {
const [formatOptions, setFormatOptions] = useState<string[]>(twelveHours); const [formatOptions, setFormatOptions] = useState<string[]>(twelveHours);
const [importing, setImporting] = useState(false); const [importing, setImporting] = useState(false);
const [deleting, setDeleting] = useState(false); const [deleting, setDeleting] = useState(false);
const { reset } = useNavigation<NavigationProp<DrawerParamList>>(); const { reset } = useNavigation<NavigationProp<DrawerParams>>();
const { watch, setValue } = useForm<Settings>({ const { watch, setValue } = useForm<Settings>({
defaultValues: () => settingsRepo.findOne({ where: {} }), defaultValues: () => settingsRepo.findOne({ where: {} }),

View File

@ -17,14 +17,14 @@ import { getNow, setRepo, settingsRepo } from "./db";
import { emitter } from "./emitter"; import { emitter } from "./emitter";
import { fixNumeric } from "./fix-numeric"; import { fixNumeric } from "./fix-numeric";
import GymSet, { GYM_SET_CREATED } from "./gym-set"; import GymSet, { GYM_SET_CREATED } from "./gym-set";
import { PlanPageParams } from "./plan-page-params";
import Settings from "./settings"; import Settings from "./settings";
import StackHeader from "./StackHeader"; import StackHeader from "./StackHeader";
import StartPlanItem from "./StartPlanItem"; import StartPlanItem from "./StartPlanItem";
import { toast } from "./toast"; import { toast } from "./toast";
import { StackParams } from "./AppStack";
export default function StartPlan() { export default function StartPlan() {
const { params } = useRoute<RouteProp<PlanPageParams, "StartPlan">>(); const { params } = useRoute<RouteProp<StackParams, "StartPlan">>();
const [reps, setReps] = useState(params.first?.reps.toString() || "0"); const [reps, setReps] = useState(params.first?.reps.toString() || "0");
const [weight, setWeight] = useState(params.first?.weight.toString() || "0"); const [weight, setWeight] = useState(params.first?.weight.toString() || "0");
const [unit, setUnit] = useState<string>(params.first?.unit || "kg"); const [unit, setUnit] = useState<string>(params.first?.unit || "kg");
@ -35,7 +35,7 @@ export default function StartPlan() {
const repsRef = useRef<TextInput>(null); const repsRef = useRef<TextInput>(null);
const unitRef = useRef<TextInput>(null); const unitRef = useRef<TextInput>(null);
const workouts = useMemo(() => params.plan.workouts.split(","), [params]); const workouts = useMemo(() => params.plan.workouts.split(","), [params]);
const navigation = useNavigation<NavigationProp<PlanPageParams>>(); const navigation = useNavigation<NavigationProp<StackParams>>();
const [selection, setSelection] = useState({ const [selection, setSelection] = useState({
start: 0, start: 0,

View File

@ -3,13 +3,12 @@ import React, { useCallback, useState } from "react";
import { GestureResponderEvent, ListRenderItemInfo, View } from "react-native"; import { GestureResponderEvent, ListRenderItemInfo, View } from "react-native";
import { List, Menu, RadioButton, useTheme } from "react-native-paper"; import { List, Menu, RadioButton, useTheme } from "react-native-paper";
import { Like } from "typeorm"; import { Like } from "typeorm";
import { StackParams } from "./AppStack";
import CountMany from "./count-many"; import CountMany from "./count-many";
import { getNow, setRepo } from "./db"; import { getNow, setRepo } from "./db";
import { DrawerParams } from "./drawer-param-list";
import { emitter } from "./emitter"; import { emitter } from "./emitter";
import { GraphsPageParams } from "./GraphsPage";
import { GYM_SET_DELETED } from "./gym-set"; import { GYM_SET_DELETED } from "./gym-set";
import { HomePageParams } from "./home-page-params";
import { PlanPageParams } from "./plan-page-params";
import { toast } from "./toast"; import { toast } from "./toast";
interface Props extends ListRenderItemInfo<CountMany> { interface Props extends ListRenderItemInfo<CountMany> {
@ -23,11 +22,10 @@ export default function StartPlanItem(props: Props) {
const { colors } = useTheme(); const { colors } = useTheme();
const [anchor, setAnchor] = useState({ x: 0, y: 0 }); const [anchor, setAnchor] = useState({ x: 0, y: 0 });
const [showMenu, setShowMenu] = useState(false); const [showMenu, setShowMenu] = useState(false);
const { navigate } = useNavigation<NavigationProp<PlanPageParams>>(); const { navigate: stackNavigate } =
const { navigate: navigateHome } = useNavigation<NavigationProp<StackParams>>();
useNavigation<NavigationProp<HomePageParams>>(); const { navigate: drawerNavigate } =
const { navigate: navigateGraph } = useNavigation<NavigationProp<DrawerParams>>();
useNavigation<NavigationProp<GraphsPageParams>>();
const undo = useCallback(async () => { const undo = useCallback(async () => {
const now = await getNow(); const now = await getNow();
@ -68,18 +66,18 @@ export default function StartPlanItem(props: Props) {
}); });
setShowMenu(false); setShowMenu(false);
if (!first) return toast("Nothing to edit."); if (!first) return toast("Nothing to edit.");
navigate("EditSet", { set: first }); stackNavigate("EditSet", { set: first });
}, [item.name, navigate]); }, [item.name, stackNavigate]);
const view = useCallback(() => { const view = useCallback(() => {
setShowMenu(false); setShowMenu(false);
navigateHome("Sets", { search: item.name }); drawerNavigate("Home", { search: item.name });
}, [item.name, navigateHome]); }, [item.name, drawerNavigate]);
const graph = useCallback(() => { const graph = useCallback(() => {
setShowMenu(false); setShowMenu(false);
navigateGraph("ViewGraph", { name: item.name }); stackNavigate("ViewGraph", { name: item.name });
}, [item.name, navigateGraph]); }, [item.name, stackNavigate]);
const left = useCallback( const left = useCallback(
() => ( () => (

View File

@ -1,13 +1,13 @@
import { useFocusEffect } from "@react-navigation/native"; import { useFocusEffect } from "@react-navigation/native";
import React, { useCallback, useMemo, useState } from "react"; import React, { useCallback, useMemo, useState } from "react";
import { Dimensions, NativeModules, View } from "react-native"; import { Dimensions, NativeModules, View } from "react-native";
import { Button, FAB, Text, useTheme } from "react-native-paper"; import { FAB, Text, useTheme } from "react-native-paper";
import { ProgressCircle } from "react-native-svg-charts"; import { ProgressCircle } from "react-native-svg-charts";
import AppFab from "./AppFab"; import AppFab from "./AppFab";
import DrawerHeader from "./DrawerHeader";
import { darkenRgba } from "./colors"; import { darkenRgba } from "./colors";
import { MARGIN, PADDING } from "./constants"; import { MARGIN, PADDING } from "./constants";
import { settingsRepo } from "./db"; import { settingsRepo } from "./db";
import DrawerHeader from "./DrawerHeader";
import Settings from "./settings"; import Settings from "./settings";
import useTimer from "./use-timer"; import useTimer from "./use-timer";

View File

@ -20,8 +20,6 @@ export default function WeightPage() {
screenOptions={{ headerShown: false, animationEnabled: false }} screenOptions={{ headerShown: false, animationEnabled: false }}
> >
<Stack.Screen name="Weights" component={WeightList} /> <Stack.Screen name="Weights" component={WeightList} />
<Stack.Screen name="EditWeight" component={EditWeight} />
<Stack.Screen name="ViewWeightGraph" component={ViewWeightGraph} />
</Stack.Navigator> </Stack.Navigator>
); );
} }

View File

@ -18,7 +18,7 @@ import Page from "./Page";
import SetList from "./SetList"; import SetList from "./SetList";
import Settings, { SETTINGS } from "./settings"; import Settings, { SETTINGS } from "./settings";
import WorkoutItem from "./WorkoutItem"; import WorkoutItem from "./WorkoutItem";
import { WorkoutsPageParams } from "./WorkoutsPage"; import { DrawerParams } from "./drawer-param-list";
export default function WorkoutList() { export default function WorkoutList() {
const [workouts, setWorkouts] = useState<GymSet[]>(); const [workouts, setWorkouts] = useState<GymSet[]>();
@ -28,8 +28,8 @@ export default function WorkoutList() {
const [settings, setSettings] = useState<Settings>(); const [settings, setSettings] = useState<Settings>();
const [names, setNames] = useState<string[]>([]); const [names, setNames] = useState<string[]>([]);
const [refreshing, setRefreshing] = useState(false); const [refreshing, setRefreshing] = useState(false);
const navigation = useNavigation<NavigationProp<WorkoutsPageParams>>(); const navigation = useNavigation<NavigationProp<DrawerParams>>();
const { params } = useRoute<RouteProp<WorkoutsPageParams, "WorkoutList">>(); const { params } = useRoute<RouteProp<DrawerParams, "Workouts">>();
const update = (newWorkout: GymSet) => { const update = (newWorkout: GymSet) => {
console.log(`${WorkoutList.name}.update:`, newWorkout); console.log(`${WorkoutList.name}.update:`, newWorkout);

View File

@ -1,9 +1,18 @@
export type DrawerParamList = { import GymSet from "./gym-set";
Home: {};
export type DrawerParams = {
Home: {
search?: string;
};
Settings: {}; Settings: {};
Graphs: {}; Graphs: {};
Plans: {}; Plans: {};
Workouts: {}; Workouts: {
clearNames?: boolean;
search?: string;
update?: GymSet;
reset?: number;
};
Timer: {}; Timer: {};
Weight: {}; Weight: {};
Insights: {}; Insights: {};

View File

@ -1,13 +0,0 @@
import GymSet from "./gym-set";
export type HomePageParams = {
Sets: {
search?: string;
};
EditSet: {
set: GymSet;
};
EditSets: {
ids: number[];
};
};

View File

@ -1,19 +0,0 @@
import GymSet from "./gym-set";
import { Plan } from "./plan";
export type PlanPageParams = {
PlanList: {};
EditPlan: {
plan: Plan;
};
StartPlan: {
plan: Plan;
first?: GymSet;
};
EditSet: {
set: GymSet;
};
ViewGraph: {
name: string;
};
};

View File

@ -1,7 +1,7 @@
import { DrawerParamList } from "./drawer-param-list"; import { DrawerParams } from "./drawer-param-list";
export default interface Route { export default interface Route {
name: keyof DrawerParamList; name: keyof DrawerParams;
component: React.ComponentType<any>; component: React.ComponentType<any>;
icon: string; icon: string;
} }

View File

@ -1,24 +0,0 @@
import { render, waitFor } from '@testing-library/react-native'
import React from 'react'
import 'react-native'
import App from '../App'
import Settings from '../settings'
jest.mock('../db.ts', () => ({
settingsRepo: {
findOne: () => Promise.resolve({} as Settings),
},
}))
jest.mock('../data-source.ts', () => ({
AppDataSource: {
isInitialized: false,
initialize: jest.fn(),
},
}))
test('renders correctly', async () => {
const { getAllByText } = render(<App />)
const title = await waitFor(() => getAllByText('Home'))
expect(title.length).toBeGreaterThan(0)
})

View File

@ -1,53 +0,0 @@
import { createStackNavigator } from '@react-navigation/stack'
import React from 'react'
import 'react-native'
import { render, waitFor } from '@testing-library/react-native'
import EditPlan from '../EditPlan'
import { MockProviders } from '../mock-providers'
import { Plan } from '../plan'
import { PlanPageParams } from '../plan-page-params'
jest.mock('../db.ts', () => ({
setRepo: {
createQueryBuilder: () => ({
select: jest.fn().mockReturnThis(),
distinct: jest.fn().mockReturnThis(),
orderBy: jest.fn().mockReturnThis(),
getRawMany: jest.fn(() =>
Promise.resolve([
{ name: 'Bench press' },
{ name: 'Bicep curls' },
{ name: 'Rows' },
])
),
}),
},
}))
test('renders correctly', async () => {
const Stack = createStackNavigator<PlanPageParams>()
const { getByText, getAllByText } = render(
<MockProviders>
<Stack.Navigator>
<Stack.Screen
initialParams={{
plan: {
workouts: 'Bench,Rows,Curls',
days: 'Monday,Tuesday,Thursday',
id: 1,
} as Plan,
}}
name='EditPlan'
component={EditPlan}
/>
</Stack.Navigator>
</MockProviders>,
)
const title = await waitFor(() => getByText(/Edit plan/i))
expect(title).toBeDefined()
expect(getAllByText('Days').length).toBeGreaterThan(0)
expect(getAllByText('Monday').length).toBeGreaterThan(0)
expect(getAllByText('Workouts').length).toBeGreaterThan(0)
expect(getAllByText('Bench press').length).toBeGreaterThan(0)
expect(getAllByText('Save').length).toBeGreaterThan(0)
})

View File

@ -1,89 +0,0 @@
import { createStackNavigator } from '@react-navigation/stack'
import React from 'react'
import 'react-native'
import { fireEvent, render, waitFor } from '@testing-library/react-native'
import EditSet from '../EditSet'
import GymSet from '../gym-set'
import { HomePageParams } from '../home-page-params'
import { MockProviders } from '../mock-providers'
import SetList from '../SetList'
import Settings from '../settings'
jest.mock('../db.ts', () => ({
getNow: () => Promise.resolve(new Date().toISOString()),
setRepo: {
findOne: () => Promise.resolve({}),
save: jest.fn(() => Promise.resolve({})),
},
settingsRepo: {
findOne: () =>
Promise.resolve({
showUnit: true,
showDate: true,
images: true,
} as Settings),
},
}))
test('renders correctly', async () => {
const Stack = createStackNavigator<HomePageParams>()
const { getByText, getAllByText } = render(
<MockProviders>
<Stack.Navigator>
<Stack.Screen
initialParams={{
set: {
created: '2023-01-01T01:45:13.238Z',
id: 1,
} as GymSet,
}}
name='EditSet'
component={EditSet}
/>
</Stack.Navigator>
</MockProviders>,
)
const title = await waitFor(() => getByText('Edit set'))
expect(title).toBeDefined()
expect(getAllByText('Name').length).toBeGreaterThan(0)
expect(getAllByText('Reps').length).toBeGreaterThan(0)
expect(getAllByText('Weight').length).toBeGreaterThan(0)
expect(getAllByText('Unit').length).toBeGreaterThan(0)
expect(getAllByText('Created').length).toBeGreaterThan(0)
expect(getAllByText('Image').length).toBeGreaterThan(0)
})
test('saves', async () => {
const Stack = createStackNavigator<HomePageParams>()
const { getByText, getAllByText, getByTestId } = render(
<MockProviders>
<Stack.Navigator>
<Stack.Screen name='Sets' component={SetList} />
<Stack.Screen
initialParams={{
set: {
created: '2023-01-01T01:45:13.238Z',
id: 1,
} as GymSet,
}}
name='EditSet'
component={EditSet}
/>
</Stack.Navigator>
</MockProviders>,
)
const add = await waitFor(() => getByTestId('add'))
fireEvent.press(add)
const names = await waitFor(() => getAllByText('Name'))
fireEvent.changeText(names[0], 'Bench Press')
const reps = await waitFor(() => getAllByText('Reps'))
fireEvent.changeText(reps[0], '10')
const weights = await waitFor(() => getAllByText('Weight'))
fireEvent.changeText(weights[0], '60')
const units = await waitFor(() => getAllByText('Unit'))
fireEvent.changeText(units[0], 'lb')
const save = getByText('Save')
fireEvent.press(save)
const home = await waitFor(() => getByText('Home'))
expect(home).toBeDefined()
})

View File

@ -1,86 +0,0 @@
import { createStackNavigator } from '@react-navigation/stack'
import React from 'react'
import 'react-native'
import { fireEvent, render, waitFor } from '@testing-library/react-native'
import EditSets from '../EditSets'
import { HomePageParams } from '../home-page-params'
import { MockProviders } from '../mock-providers'
const mockGoBack = jest.fn()
jest.mock('@react-navigation/native', () => ({
...jest.requireActual('@react-navigation/native'),
useNavigation: () => ({
goBack: mockGoBack,
}),
}))
jest.mock('../db.ts', () => ({
getNow: () => Promise.resolve(new Date().toISOString()),
setRepo: {
find: () =>
Promise.resolve([
{ name: 'Bench press', reps: 8, weight: 60, id: 1 },
{ name: 'Bench press', reps: 6, weight: 70, id: 2 },
{ name: 'Bench press', reps: 4, weight: 85, id: 3 },
]),
update: jest.fn(() => Promise.resolve()),
},
settingsRepo: {
findOne: () =>
Promise.resolve({
showUnit: true,
showDate: true,
images: true,
}),
},
}))
test('renders correctly', async () => {
const Stack = createStackNavigator<HomePageParams>()
const { getByText, getAllByText } = render(
<MockProviders>
<Stack.Navigator>
<Stack.Screen
initialParams={{ ids: [1, 2, 3] }}
name='EditSets'
component={EditSets}
/>
</Stack.Navigator>
</MockProviders>,
)
const title = await waitFor(() => getByText('Edit 3 sets'))
expect(title).toBeDefined()
expect(getAllByText(/Names/i).length).toBeGreaterThan(0)
expect(getAllByText(/Reps/i).length).toBeGreaterThan(0)
expect(getAllByText(/Weights/i).length).toBeGreaterThan(0)
expect(getAllByText(/Units/i).length).toBeGreaterThan(0)
expect(getAllByText(/Image/i).length).toBeGreaterThan(0)
})
test('saves', async () => {
const Stack = createStackNavigator<HomePageParams>()
const { getByText, getAllByText } = render(
<MockProviders>
<Stack.Navigator>
<Stack.Screen
initialParams={{ ids: [1, 2, 3] }}
name='EditSets'
component={EditSets}
/>
</Stack.Navigator>
</MockProviders>,
)
const items = await waitFor(() => getAllByText(/Bench press/i))
fireEvent.changeText(items[0], 'Shoulder press')
const reps = await waitFor(() => getAllByText(/Reps/i))
fireEvent.changeText(reps[0], '10')
const weights = await waitFor(() => getAllByText(/Weights/i))
fireEvent.changeText(weights[0], '60')
const units = await waitFor(() => getAllByText(/Units/i))
fireEvent.changeText(units[0], 'lb')
const save = getByText('Save')
fireEvent.press(save)
await waitFor(() => getByText('Save'))
expect(mockGoBack).toHaveBeenCalled()
})

View File

@ -1,43 +0,0 @@
import { createStackNavigator } from "@react-navigation/stack";
import React from "react";
import "react-native";
import { render, waitFor } from "@testing-library/react-native";
import EditWorkout from "../EditWorkout";
import GymSet from "../gym-set";
import { MockProviders } from "../mock-providers";
import Settings from "../settings";
import { WorkoutsPageParams } from "../WorkoutsPage";
jest.mock("../db.ts", () => ({
settingsRepo: {
findOne: () =>
Promise.resolve({
showSets: true,
alarm: true,
} as Settings),
},
}));
test("renders correctly", async () => {
const Stack = createStackNavigator<WorkoutsPageParams>();
const { getByText, getAllByText } = render(
<MockProviders>
<Stack.Navigator>
<Stack.Screen
initialParams={{
gymSet: { name: "Bench press" } as GymSet,
}}
name="EditWorkout"
component={EditWorkout}
/>
</Stack.Navigator>
</MockProviders>
);
const title = await waitFor(() => getByText(/Edit workout/i));
expect(title).toBeDefined();
expect(getAllByText(/Name/i).length).toBeGreaterThan(0);
expect(getAllByText(/Sets/i).length).toBeGreaterThan(0);
expect(getAllByText(/Minutes/i).length).toBeGreaterThan(0);
expect(getAllByText(/Seconds/i).length).toBeGreaterThan(0);
expect(getAllByText(/Save/i).length).toBeGreaterThan(0);
});

View File

@ -1,67 +0,0 @@
import React from 'react'
import 'react-native'
import { fireEvent, render, waitFor } from '@testing-library/react-native'
import GraphsPage from '../GraphsPage'
import { MockProviders } from '../mock-providers'
import Settings from '../settings'
jest.mock('../db.ts', () => ({
setRepo: {
createQueryBuilder: () => ({
select: jest.fn().mockReturnThis(),
addSelect: jest.fn().mockReturnThis(),
where: jest.fn().mockReturnThis(),
andWhere: jest.fn().mockReturnThis(),
groupBy: jest.fn().mockReturnThis(),
distinct: jest.fn().mockReturnThis(),
getMany: jest.fn(() =>
Promise.resolve([
{
name: 'Bench press',
weight: 60,
reps: 8,
image: 'https://picsum.photos/id/10/1000/600',
},
{
name: 'Bicep curls',
weight: 20,
reps: 10,
image: 'https://picsum.photos/id/0/1000/600',
},
{
name: 'Rows',
weight: 100,
reps: 10,
image: 'https://picsum.photos/id/1/1000/600',
},
])
),
}),
},
settingsRepo: {
findOne: () => Promise.resolve({ images: true } as Settings),
},
}))
test('renders correctly', async () => {
const { getByText } = render(
<MockProviders>
<GraphsPage />
</MockProviders>,
)
const title = await waitFor(() => getByText('Graphs'))
expect(title).toBeDefined()
})
test('searches', async () => {
const { getByDisplayValue, getByPlaceholderText } = render(
<MockProviders>
<GraphsPage />
</MockProviders>,
)
const search = await waitFor(() => getByPlaceholderText('Search'))
expect(search).toBeDefined()
fireEvent.changeText(search, 'SearchValue')
const value = await waitFor(() => getByDisplayValue('SearchValue'))
expect(value).toBeDefined()
})

View File

@ -1,25 +0,0 @@
import React from 'react'
import 'react-native'
import { render, waitFor } from '@testing-library/react-native'
import { Repository } from 'typeorm'
import GymSet from '../gym-set'
import HomePage from '../HomePage'
import { MockProviders } from '../mock-providers'
import Settings from '../settings'
jest.mock('../db.ts', () => ({
setRepo: { find: () => Promise.resolve([]) } as Repository<GymSet>,
settingsRepo: {
findOne: () => Promise.resolve({} as Settings),
},
}))
test('renders correctly', async () => {
const { getByText } = render(
<MockProviders>
<HomePage />
</MockProviders>,
)
const title = await waitFor(() => getByText('Home'))
expect(title).toBeDefined()
})

View File

@ -1,68 +0,0 @@
import React from 'react'
import 'react-native'
import { fireEvent, render, waitFor } from '@testing-library/react-native'
import { MockProviders } from '../mock-providers'
import { Plan } from '../plan'
import PlanPage from '../PlanPage'
jest.mock('../db.ts', () => ({
setRepo: {
createQueryBuilder: () => ({
select: jest.fn().mockReturnThis(),
addSelect: jest.fn().mockReturnThis(),
where: jest.fn().mockReturnThis(),
andWhere: jest.fn().mockReturnThis(),
orderBy: jest.fn().mockReturnThis(),
groupBy: jest.fn().mockReturnThis(),
distinct: jest.fn().mockReturnThis(),
getRawMany: jest.fn(() =>
Promise.resolve([
{
name: 'Bench press',
},
{
name: 'Bicep curls',
},
{
name: 'Rows',
},
])
),
}),
},
planRepo: {
find: () =>
Promise.resolve([
{
days: 'Monday,Tuesday,Wednesday',
workouts: 'Bench press,Side raises, Bicep curls',
id: 1,
},
{
days: 'Thursday,Friday,Saturday',
workouts: 'Deadlifts,Barbell rows,Pull ups',
id: 2,
},
] as Plan[]),
},
}))
test('renders correctly', async () => {
const { getByText } = render(
<MockProviders>
<PlanPage />
</MockProviders>,
)
const title = await waitFor(() => getByText('Plans'))
expect(title).toBeDefined()
})
test('adds', async () => {
const { getByTestId, getByText } = render(
<MockProviders>
<PlanPage />
</MockProviders>,
)
fireEvent.press(await waitFor(() => getByTestId('add')))
expect(await waitFor(() => getByText('Add plan'))).toBeDefined()
})

View File

@ -1,25 +0,0 @@
import React from 'react'
import 'react-native'
import { render, waitFor } from '@testing-library/react-native'
import { Repository } from 'typeorm'
import GymSet from '../gym-set'
import { MockProviders } from '../mock-providers'
import PlanPage from '../PlanPage'
import Settings from '../settings'
jest.mock('../db.ts', () => ({
setRepo: { find: () => Promise.resolve([]) } as Repository<GymSet>,
settingsRepo: {
findOne: () => Promise.resolve({} as Settings),
},
}))
test('renders correctly', async () => {
const { getByText } = render(
<MockProviders>
<PlanPage />
</MockProviders>,
)
const title = await waitFor(() => getByText('Plans'))
expect(title).toBeDefined()
})

View File

@ -1,30 +0,0 @@
import React from 'react'
import 'react-native'
import { render, waitFor } from '@testing-library/react-native'
import { Repository } from 'typeorm'
import GymSet from '../gym-set'
import { MockProviders } from '../mock-providers'
import Settings from '../settings'
import SettingsPage from '../SettingsPage'
jest.mock('../db.ts', () => ({
setRepo: { find: () => Promise.resolve([]) } as Repository<GymSet>,
settingsRepo: {
findOne: () => Promise.resolve({} as Settings),
},
}))
test('renders correctly', async () => {
const { getByText, getAllByText } = render(
<MockProviders>
<SettingsPage />
</MockProviders>,
)
const title = await waitFor(() => getByText('Settings'))
expect(title).toBeDefined()
expect(getByText(/timers/i)).toBeDefined()
expect(getByText(/vibrate/i)).toBeDefined()
expect(getByText(/notifications/i)).toBeDefined()
expect(getByText(/images/i)).toBeDefined()
expect(getAllByText(/theme/i).length).toBeGreaterThan(0)
})

View File

@ -1,100 +0,0 @@
import { createStackNavigator } from '@react-navigation/stack'
import React from 'react'
import 'react-native'
import { fireEvent, render, waitFor } from '@testing-library/react-native'
import GymSet from '../gym-set'
import { MockProviders } from '../mock-providers'
import { Plan } from '../plan'
import { PlanPageParams } from '../plan-page-params'
import Settings from '../settings'
import StartPlan from '../StartPlan'
jest.mock('../best.service.ts', () => ({
getBestSet: () => Promise.resolve({}),
}))
jest.mock('../db.ts', () => ({
getNow: () => Promise.resolve(new Date().toISOString()),
setRepo: {
findOne: () => Promise.resolve({}),
save: () => Promise.resolve(),
},
settingsRepo: {
findOne: () =>
Promise.resolve({
showUnit: true,
showDate: true,
images: true,
} as Settings),
},
}))
jest.mock('../data-source.ts', () => ({
AppDataSource: {
manager: {
query: jest.fn(() =>
Promise.resolve([
{ name: 'Bench', total: 0 },
{ name: 'Rows', total: 0 },
{ name: 'Curls', total: 0 },
])
),
},
},
}))
test('renders correctly', async () => {
const Stack = createStackNavigator<PlanPageParams>()
const { getByText, getAllByText } = render(
<MockProviders>
<Stack.Navigator>
<Stack.Screen
initialParams={{
first: { reps: 0, weight: 0 } as GymSet,
plan: {
workouts: 'Bench,Rows,Curls',
days: 'Monday,Tuesday,Thursday',
} as Plan,
}}
name='StartPlan'
component={StartPlan}
/>
</Stack.Navigator>
</MockProviders>,
)
const title = await waitFor(() => getByText(/Monday/i))
expect(title).toBeDefined()
expect(getAllByText('Reps').length).toBeGreaterThan(0)
expect(getAllByText('Weight').length).toBeGreaterThan(0)
expect(getAllByText('Unit').length).toBeGreaterThan(0)
expect(getAllByText('Bench').length).toBeGreaterThan(0)
expect(getAllByText('Rows').length).toBeGreaterThan(0)
expect(getAllByText('Curls').length).toBeGreaterThan(0)
expect(getAllByText('Save').length).toBeGreaterThan(0)
})
test('saves', async () => {
const Stack = createStackNavigator<PlanPageParams>()
const { getByText } = render(
<MockProviders>
<Stack.Navigator>
<Stack.Screen
initialParams={{
first: { reps: 0, weight: 0 } as GymSet,
plan: {
workouts: 'Bench,Rows,Curls',
days: 'Monday,Tuesday,Thursday',
} as Plan,
}}
name='StartPlan'
component={StartPlan}
/>
</Stack.Navigator>
</MockProviders>,
)
const save = await waitFor(() => getByText('Save'))
expect(save).toBeDefined()
fireEvent.press(save)
const save2 = await waitFor(() => getByText('Save'))
expect(save2).toBeDefined()
})

View File

@ -1,25 +0,0 @@
import React from 'react'
import 'react-native'
import { render, waitFor } from '@testing-library/react-native'
import { Repository } from 'typeorm'
import GymSet from '../gym-set'
import { MockProviders } from '../mock-providers'
import Settings from '../settings'
import TimerPage from '../TimerPage'
jest.mock('../db.ts', () => ({
setRepo: { find: () => Promise.resolve([]) } as Repository<GymSet>,
settingsRepo: {
findOne: () => Promise.resolve({} as Settings),
},
}))
test('renders correctly', async () => {
const { getByText } = render(
<MockProviders>
<TimerPage />
</MockProviders>,
)
const title = await waitFor(() => getByText('Timer'))
expect(title).toBeDefined()
})

View File

@ -1,141 +0,0 @@
import React from 'react'
import 'react-native'
import { fireEvent, render, waitFor } from '@testing-library/react-native'
import GraphsPage from '../GraphsPage'
import { MockProviders } from '../mock-providers'
import Settings from '../settings'
jest.mock('../db.ts', () => ({
setRepo: {
createQueryBuilder: () => ({
select: jest.fn().mockReturnThis(),
addSelect: jest.fn().mockReturnThis(),
where: jest.fn().mockReturnThis(),
andWhere: jest.fn().mockReturnThis(),
groupBy: jest.fn().mockReturnThis(),
addGroupBy: jest.fn().mockReturnThis(),
distinct: jest.fn().mockReturnThis(),
getRawMany: jest.fn(() =>
Promise.resolve([
{
name: 'Bench press',
value: 16,
created: '2023-01-05T03:58:02.565Z',
weight: 18,
},
{
name: 'Bench press',
value: 48,
created: '2022-01-05T03:58:02.565Z',
weight: 48,
},
{
name: 'Bench press',
value: 30,
created: '2021-01-05T03:58:02.565Z',
weight: 28,
},
])
),
getMany: jest.fn(() =>
Promise.resolve([
{
name: 'Bench press',
weight: 60,
reps: 8,
image: 'https://picsum.photos/id/10/1000/600',
},
{
name: 'Bicep curls',
weight: 20,
reps: 10,
image: 'https://picsum.photos/id/0/1000/600',
},
{
name: 'Rows',
weight: 100,
reps: 10,
image: 'https://picsum.photos/id/1/1000/600',
},
])
),
}),
},
settingsRepo: {
findOne: () => Promise.resolve({ images: true } as Settings),
},
}))
test('renders correctly', async () => {
const { getAllByText, getByText } = render(
<MockProviders>
<GraphsPage />
</MockProviders>,
)
const benches = await waitFor(() => getAllByText('Bench press'))
expect(benches).toBeDefined()
fireEvent.press(benches[0])
const bench = await waitFor(() => getByText('Metric'))
expect(bench).toBeDefined()
expect(getByText('Period')).toBeDefined()
})
test('volume', async () => {
const { getAllByText, getByText } = render(
<MockProviders>
<GraphsPage />
</MockProviders>,
)
const benches = await waitFor(() => getAllByText('Bench press'))
expect(benches).toBeDefined()
fireEvent.press(benches[0])
const bestWeight = await waitFor(() => getByText('Best weight'))
fireEvent.press(bestWeight)
const volume = await waitFor(() => getByText('Volume'))
fireEvent.press(volume)
expect(await waitFor(() => getByText('Volume'))).toBeDefined()
})
test('one rep max', async () => {
const { getAllByText, getByText } = render(
<MockProviders>
<GraphsPage />
</MockProviders>,
)
const benches = await waitFor(() => getAllByText(/Bench press/i))
expect(benches).toBeDefined()
fireEvent.press(benches[0])
const bestWeight = await waitFor(() => getByText(/Best weight/i))
fireEvent.press(bestWeight)
const volume = await waitFor(() => getByText(/One rep max/i))
fireEvent.press(volume)
expect(await waitFor(() => getByText(/One rep max/i))).toBeDefined()
})
test('this week', async () => {
const { getAllByText, getByText } = render(
<MockProviders>
<GraphsPage />
</MockProviders>,
)
const benches = await waitFor(() => getAllByText(/Bench press/i))
expect(benches).toBeDefined()
fireEvent.press(benches[0])
fireEvent.press(await waitFor(() => getByText(/This month/i)))
fireEvent.press(await waitFor(() => getByText(/This week/i)))
expect(await waitFor(() => getByText(/This week/i))).toBeDefined()
})
test('this year', async () => {
const { getAllByText, getByText } = render(
<MockProviders>
<GraphsPage />
</MockProviders>,
)
const benches = await waitFor(() => getAllByText(/Bench press/i))
expect(benches).toBeDefined()
fireEvent.press(benches[0])
fireEvent.press(await waitFor(() => getByText(/This month/i)))
fireEvent.press(await waitFor(() => getByText(/This year/i)))
expect(await waitFor(() => getByText(/This year/i))).toBeDefined()
})

View File

@ -1,25 +0,0 @@
import React from 'react'
import 'react-native'
import { render, waitFor } from '@testing-library/react-native'
import { Repository } from 'typeorm'
import GymSet from '../gym-set'
import { MockProviders } from '../mock-providers'
import Settings from '../settings'
import WorkoutsPage from '../WorkoutsPage'
jest.mock('../db.ts', () => ({
setRepo: { find: () => Promise.resolve([]) } as Repository<GymSet>,
settingsRepo: {
findOne: () => Promise.resolve({} as Settings),
},
}))
test('renders correctly', async () => {
const { getByText } = render(
<MockProviders>
<WorkoutsPage />
</MockProviders>,
)
const title = await waitFor(() => getByText('Workouts'))
expect(title).toBeDefined()
})