diff --git a/EditSet.tsx b/EditSet.tsx index 30f14ee..73aa6f4 100644 --- a/EditSet.tsx +++ b/EditSet.tsx @@ -1,84 +1,85 @@ -import { DateTimePickerAndroid } from '@react-native-community/datetimepicker' +import { DateTimePickerAndroid } from "@react-native-community/datetimepicker"; import { RouteProp, useFocusEffect, useNavigation, useRoute, -} from '@react-navigation/native' -import { format } from 'date-fns' -import { useCallback, useRef, useState } from 'react' -import { NativeModules, TextInput, View } from 'react-native' -import DocumentPicker from 'react-native-document-picker' -import { Button, Card, TouchableRipple } from 'react-native-paper' -import AppInput from './AppInput' -import ConfirmDialog from './ConfirmDialog' -import { MARGIN, PADDING } from './constants' -import { getNow, setRepo, settingsRepo } from './db' -import GymSet from './gym-set' -import { HomePageParams } from './home-page-params' -import Settings from './settings' -import StackHeader from './StackHeader' -import { toast } from './toast' +} from "@react-navigation/native"; +import { format } from "date-fns"; +import { useCallback, useRef, useState } from "react"; +import { NativeModules, TextInput, View } from "react-native"; +import DocumentPicker from "react-native-document-picker"; +import { Button, Card, TouchableRipple } from "react-native-paper"; +import AppInput from "./AppInput"; +import ConfirmDialog from "./ConfirmDialog"; +import { MARGIN, PADDING } from "./constants"; +import { getNow, setRepo, settingsRepo } from "./db"; +import GymSet from "./gym-set"; +import { HomePageParams } from "./home-page-params"; +import Settings from "./settings"; +import StackHeader from "./StackHeader"; +import { toast } from "./toast"; +import { fixNumeric } from "./fix-numeric"; export default function EditSet() { - const { params } = useRoute>() - const { set } = params - const navigation = useNavigation() - const [settings, setSettings] = useState({} as Settings) - const [name, setName] = useState(set.name) - const [reps, setReps] = useState(set.reps?.toString()) - const [weight, setWeight] = useState(set.weight?.toString()) - const [newImage, setNewImage] = useState(set.image) - const [unit, setUnit] = useState(set.unit) + const { params } = useRoute>(); + const { set } = params; + const navigation = useNavigation(); + const [settings, setSettings] = useState({} as Settings); + const [name, setName] = useState(set.name); + const [reps, setReps] = useState(set.reps?.toString()); + const [weight, setWeight] = useState(set.weight?.toString()); + const [newImage, setNewImage] = useState(set.image); + const [unit, setUnit] = useState(set.unit); const [created, setCreated] = useState( - set.created ? new Date(set.created) : new Date(), - ) - const [createdDirty, setCreatedDirty] = useState(false) - const [showRemove, setShowRemove] = useState(false) - const [removeImage, setRemoveImage] = useState(false) - const weightRef = useRef(null) - const repsRef = useRef(null) - const unitRef = useRef(null) + set.created ? new Date(set.created) : new Date() + ); + const [createdDirty, setCreatedDirty] = useState(false); + const [showRemove, setShowRemove] = useState(false); + const [removeImage, setRemoveImage] = useState(false); + const weightRef = useRef(null); + const repsRef = useRef(null); + const unitRef = useRef(null); const [selection, setSelection] = useState({ start: 0, end: set.reps?.toString().length, - }) + }); useFocusEffect( useCallback(() => { - settingsRepo.findOne({ where: {} }).then(setSettings) - }, []), - ) + settingsRepo.findOne({ where: {} }).then(setSettings); + }, []) + ); const startTimer = useCallback( async (value: string) => { - if (!settings.alarm) return - const first = await setRepo.findOne({ where: { name: value } }) - const milliseconds = (first?.minutes ?? 3) * 60 * 1000 + - (first?.seconds ?? 0) * 1000 - if (milliseconds) NativeModules.AlarmModule.timer(milliseconds) + if (!settings.alarm) return; + const first = await setRepo.findOne({ where: { name: value } }); + const milliseconds = + (first?.minutes ?? 3) * 60 * 1000 + (first?.seconds ?? 0) * 1000; + if (milliseconds) NativeModules.AlarmModule.timer(milliseconds); }, - [settings], - ) + [settings] + ); const added = useCallback( async (value: GymSet) => { - startTimer(value.name) - console.log(`${EditSet.name}.add`, { set: value }) - if (!settings.notify) return + startTimer(value.name); + console.log(`${EditSet.name}.add`, { set: value }); + if (!settings.notify) return; if ( value.weight > set.weight || (value.reps > set.reps && value.weight === set.weight) ) { - toast('Great work King! That\'s a new record.') + toast("Great work King! That's a new record."); } }, - [startTimer, set, settings], - ) + [startTimer, set, settings] + ); const handleSubmit = async () => { - if (!name) return + if (!name) return; const newSet: Partial = { id: set.id, @@ -90,63 +91,63 @@ export default function EditSet() { seconds: Number(set.seconds ?? 30), sets: set.sets ?? 3, hidden: false, - } + }; - newSet.image = newImage + newSet.image = newImage; if (!newImage && !removeImage) { - newSet.image = await setRepo.findOne({ where: { name } }).then((s) => - s?.image - ) + newSet.image = await setRepo + .findOne({ where: { name } }) + .then((s) => s?.image); } - if (createdDirty) newSet.created = created.toISOString() - if (typeof set.id !== 'number') newSet.created = await getNow() + if (createdDirty) newSet.created = created.toISOString(); + if (typeof set.id !== "number") newSet.created = await getNow(); - const saved = await setRepo.save(newSet) - if (typeof set.id !== 'number') added(saved) - navigation.goBack() - } + const saved = await setRepo.save(newSet); + if (typeof set.id !== "number") added(saved); + navigation.goBack(); + }; const changeImage = useCallback(async () => { const { fileCopyUri } = await DocumentPicker.pickSingle({ type: DocumentPicker.types.images, - copyTo: 'documentDirectory', - }) - if (fileCopyUri) setNewImage(fileCopyUri) - }, []) + copyTo: "documentDirectory", + }); + if (fileCopyUri) setNewImage(fileCopyUri); + }, []); const handleRemove = useCallback(async () => { - setNewImage('') - setRemoveImage(true) - setShowRemove(false) - }, []) + setNewImage(""); + setRemoveImage(true); + setShowRemove(false); + }, []); const pickDate = useCallback(() => { DateTimePickerAndroid.open({ value: created, onChange: (_, date) => { - if (date === created) return - setCreated(date) - setCreatedDirty(true) + if (date === created) return; + setCreated(date); + setCreatedDirty(true); DateTimePickerAndroid.open({ value: date, onChange: (__, time) => setCreated(time), - mode: 'time', - }) + mode: "time", + }); }, - mode: 'date', - }) - }, [created]) + mode: "date", + }); + }, [created]); return ( <> { + const fixed = fixNumeric(newReps); + setReps(fixed); + if (fixed.length !== newReps.length) toast("Reps must be a number"); + }} onSubmitEditing={() => weightRef.current?.focus()} selection={selection} onSelectionChange={(e) => setSelection(e.nativeEvent.selection)} @@ -166,18 +171,23 @@ export default function EditSet() { /> { + const fixed = fixNumeric(newWeight); + setWeight(fixed); + if (fixed.length !== newWeight.length) + toast("Weight must be a number"); + }} onSubmitEditing={handleSubmit} innerRef={weightRef} /> {settings.showUnit && ( )} @@ -206,7 +216,7 @@ export default function EditSet() { @@ -215,8 +225,8 @@ export default function EditSet() { - ) + ); } diff --git a/fix-numeric.ts b/fix-numeric.ts new file mode 100644 index 0000000..c02a97b --- /dev/null +++ b/fix-numeric.ts @@ -0,0 +1,11 @@ +export const fixNumeric = (text: string) => { + let newText = text.replace(/[^0-9.-]/g, ""); + let parts = newText.split("."); + if (parts.length > 2) { + newText = parts[0] + "." + parts.slice(1).join(""); + } + if (newText.startsWith("-")) { + newText = "-" + newText.slice(1).replace(/-/g, ""); + } + return newText; +};