Massive/EditWeight.tsx

166 lines
4.9 KiB
TypeScript
Raw Normal View History

2023-10-19 05:28:56 +00:00
import { DateTimePickerAndroid } from "@react-native-community/datetimepicker";
import {
NavigationProp,
RouteProp,
useFocusEffect,
useNavigation,
useRoute,
} from "@react-navigation/native";
import { format } from "date-fns";
import { useCallback, useRef, useState } from "react";
2023-10-20 22:57:31 +00:00
import { TextInput, View } from "react-native";
import { IconButton } from "react-native-paper";
2023-10-19 05:28:56 +00:00
import AppInput from "./AppInput";
import { StackParams } from "./AppStack";
2023-10-19 05:28:56 +00:00
import ConfirmDialog from "./ConfirmDialog";
import PrimaryButton from "./PrimaryButton";
import Select from "./Select";
import StackHeader from "./StackHeader";
2023-10-19 05:28:56 +00:00
import { MARGIN, PADDING } from "./constants";
import { AppDataSource } from "./data-source";
2023-10-20 22:57:31 +00:00
import { getNow, settingsRepo, weightRepo } from "./db";
import { DrawerParams } from "./drawer-params";
2023-10-19 05:28:56 +00:00
import Settings from "./settings";
import { toast } from "./toast";
2023-10-20 22:57:31 +00:00
import Weight from "./weight";
2023-10-19 05:28:56 +00:00
export default function EditWeight() {
const { params } = useRoute<RouteProp<StackParams, "EditWeight">>();
2023-10-20 22:57:31 +00:00
const { weight } = params;
const { navigate } = useNavigation<NavigationProp<DrawerParams>>();
const { navigate: stackNavigate, goBack } = useNavigation<NavigationProp<StackParams>>();
2023-10-19 05:28:56 +00:00
const [settings, setSettings] = useState<Settings>({} as Settings);
2023-10-20 22:57:31 +00:00
const [value, setValue] = useState(weight.value?.toString());
const [unit, setUnit] = useState(weight.unit);
2023-10-19 05:28:56 +00:00
const [created, setCreated] = useState<Date>(
2023-10-20 22:57:31 +00:00
weight.created ? new Date(weight.created) : new Date()
2023-10-19 05:28:56 +00:00
);
2023-10-20 22:57:31 +00:00
const [showDelete, setShowDelete] = useState(false);
2023-10-19 05:28:56 +00:00
const [createdDirty, setCreatedDirty] = useState(false);
const unitRef = useRef<TextInput>(null);
useFocusEffect(
useCallback(() => {
settingsRepo.findOne({ where: {} }).then(setSettings);
}, [])
);
2023-10-24 03:16:42 +00:00
const submit = async () => {
2023-10-20 22:57:31 +00:00
if (!value) return;
2023-10-19 05:28:56 +00:00
2023-10-20 22:57:31 +00:00
const newWeight: Partial<Weight> = {
id: weight.id,
value: Number(value),
2023-10-19 05:28:56 +00:00
unit,
};
2023-10-20 22:57:31 +00:00
if (createdDirty) newWeight.created = created.toISOString();
else if (typeof weight.id !== "number") newWeight.created = await getNow();
2023-10-19 05:28:56 +00:00
2023-10-20 22:57:31 +00:00
await weightRepo.save(newWeight);
if (settings.notify) await checkWeekly();
goBack();
stackNavigate("ViewWeightGraph");
2023-10-19 05:28:56 +00:00
};
const checkWeekly = async () => {
const select = `
WITH weekly_weights AS (
SELECT
strftime('%W', created) AS week_number,
AVG(value) AS weekly_average
FROM weights
WHERE strftime('%W', created) = strftime('%W', 'now')
GROUP BY week_number
)
SELECT
((SELECT value FROM weights WHERE strftime('%W', created) = strftime('%W', 'now') ORDER BY created LIMIT 1) - weekly_weights.weekly_average) / (SELECT value FROM weights WHERE strftime('%W', created) = strftime('%W', 'now') ORDER BY created LIMIT 1) * 100 AS loss
FROM weekly_weights
WHERE week_number = strftime('%W', 'now')
`;
const result = await AppDataSource.manager.query(select);
console.log(`${EditWeight.name}.checkWeekly:`, result);
if (result.length && result[0].loss > 1)
toast("Weight loss should be <= 1% per week.");
};
2023-10-19 05:28:56 +00:00
const pickDate = useCallback(() => {
DateTimePickerAndroid.open({
value: created,
onChange: (_, date) => {
if (date === created) return;
setCreated(date);
setCreatedDirty(true);
},
mode: "date",
});
}, [created]);
const remove = async () => {
2023-10-20 22:57:31 +00:00
if (!weight.id) return;
await weightRepo.delete(weight.id);
navigate("Weight");
2023-10-19 05:28:56 +00:00
};
return (
<>
2023-10-20 22:57:31 +00:00
<StackHeader
title={typeof weight.id === "number" ? "Edit weight" : "Add weight"}
>
{typeof weight.id === "number" ? (
2023-10-19 05:28:56 +00:00
<IconButton onPress={() => setShowDelete(true)} icon="delete" />
) : null}
</StackHeader>
<ConfirmDialog
2023-10-20 22:57:31 +00:00
title="Delete weight"
2023-10-19 05:28:56 +00:00
show={showDelete}
onOk={remove}
setShow={setShowDelete}
>
2023-10-20 22:57:31 +00:00
<>Are you sure you want to delete {value}</>
2023-10-19 05:28:56 +00:00
</ConfirmDialog>
<View style={{ padding: PADDING, flex: 1 }}>
<AppInput
2023-10-24 03:16:42 +00:00
label="Weight"
2023-10-20 22:57:31 +00:00
value={value}
onChangeText={setValue}
keyboardType="numeric"
2023-10-24 03:16:42 +00:00
onSubmitEditing={submit}
2023-10-26 23:36:41 +00:00
autoFocus
2023-10-19 05:28:56 +00:00
/>
{settings.showUnit && (
<Select
2023-10-19 05:28:56 +00:00
value={unit}
onChange={setUnit}
items={[
{ label: "kg", value: "kg" },
{ label: "lb", value: "lb" },
{ label: "stone", value: "stone" },
]}
label="Unit"
2023-10-19 05:28:56 +00:00
/>
)}
{settings.showDate && (
<AppInput
label="Created"
2023-11-21 06:14:53 +00:00
value={format(created, settings.date || "Pp")}
2023-10-19 05:28:56 +00:00
onPressOut={pickDate}
/>
)}
</View>
<PrimaryButton
2023-10-20 22:57:31 +00:00
disabled={!value}
icon="content-save"
2023-10-19 05:28:56 +00:00
style={{ margin: MARGIN }}
2023-10-24 03:16:42 +00:00
onPress={submit}
2023-10-19 05:28:56 +00:00
>
Save
</PrimaryButton>
2023-10-19 05:28:56 +00:00
</>
);
}