Massive/EditPlan.tsx
Brandon Presley 95681c0b3d Save plan before starting it
Also after saving it makes more sense to just
navigate to PlanList instead of calling
navigation.goBack(). This way we can make sure
we have up-to-date data.

The old way would typically lead to us seeing
stale data. E.g.
1. Tap on a plan
2. Tap on edit
3. Change details of the plan
4. Press save
5. See old plan

Now when we save we instead see the original list of plans.
2023-07-31 15:54:32 +12:00

149 lines
4.2 KiB
TypeScript

import {
NavigationProp,
RouteProp,
useNavigation,
useRoute,
} from '@react-navigation/native'
import { useCallback, useEffect, useState } from 'react'
import { ScrollView, StyleSheet, View } from 'react-native'
import { Button, IconButton, Text } from 'react-native-paper'
import { MARGIN, PADDING } from './constants'
import { planRepo, setRepo } from './db'
import { defaultSet } from './gym-set'
import { PlanPageParams } from './plan-page-params'
import StackHeader from './StackHeader'
import Switch from './Switch'
import { DAYS } from './time'
export default function EditPlan() {
const { params } = useRoute<RouteProp<PlanPageParams, 'EditPlan'>>()
const { plan } = params
const [days, setDays] = useState<string[]>(
plan.days ? plan.days.split(',') : [],
)
const [workouts, setWorkouts] = useState<string[]>(
plan.workouts ? plan.workouts.split(',') : [],
)
const [names, setNames] = useState<string[]>([])
const navigation = useNavigation<NavigationProp<PlanPageParams>>()
useEffect(() => {
setRepo
.createQueryBuilder()
.select('name')
.distinct(true)
.orderBy('name')
.getRawMany()
.then((values) => {
console.log(EditPlan.name, { values })
setNames(values.map((value) => value.name))
})
}, [])
const save = useCallback(async () => {
console.log(`${EditPlan.name}.save`, { days, workouts, plan })
if (!days || !workouts) return
const newWorkouts = workouts.filter((workout) => workout).join(',')
const newDays = days.filter((day) => day).join(',')
await planRepo.save({ days: newDays, workouts: newWorkouts, id: plan.id })
}, [days, workouts, plan])
const toggleWorkout = useCallback(
(on: boolean, name: string) => {
if (on) {
setWorkouts([...workouts, name])
} else {
setWorkouts(workouts.filter((workout) => workout !== name))
}
},
[setWorkouts, workouts],
)
const toggleDay = useCallback(
(on: boolean, day: string) => {
if (on) {
setDays([...days, day])
} else {
setDays(days.filter((d) => d !== day))
}
},
[setDays, days],
)
return (
<>
<StackHeader
title={typeof plan.id === 'number' ? 'Edit plan' : 'Add plan'}
>
{typeof plan.id === 'number' && (
<IconButton
onPress={async () => {
await save()
const newPlan = await planRepo.findOne({ where: { id: plan.id } })
let first = await setRepo.findOne({
where: { name: workouts[0] },
order: { created: 'desc' },
})
if (!first) first = { ...defaultSet, name: workouts[0] }
delete first.id
navigation.navigate('StartPlan', { plan: newPlan, first })
}}
icon='play-arrow'
/>
)}
</StackHeader>
<View style={{ padding: PADDING, flex: 1 }}>
<ScrollView style={{ flex: 1 }}>
<Text style={styles.title}>Days</Text>
{DAYS.map((day) => (
<Switch
key={day}
onChange={(value) => toggleDay(value, day)}
value={days.includes(day)}
title={day}
/>
))}
<Text style={[styles.title, { marginTop: MARGIN }]}>Workouts</Text>
{names.length === 0
? (
<View>
<Text>No workouts found.</Text>
</View>
)
: (
names.map((name) => (
<Switch
key={name}
onChange={(value) => toggleWorkout(value, name)}
value={workouts.includes(name)}
title={name}
/>
))
)}
</ScrollView>
<Button
disabled={workouts.length === 0 && days.length === 0}
style={styles.button}
mode='outlined'
icon='save'
onPress={async () => {
await save()
navigation.navigate('PlanList')
}}
>
Save
</Button>
</View>
</>
)
}
const styles = StyleSheet.create({
title: {
fontSize: 20,
marginBottom: MARGIN,
},
button: {},
})