frontend: initialize the edit forms from the loaded record
Pedro Lucas Porcellis porcellis@eletrotupi.com · 12 days ago
2e426df100e36abc7649699899f84bf7ee3b906b Browse filesParents
6b0e21cChanged files
3
Additions
+70
Deletions
-67
frontend/app/medicine-regimens/[id].tsx
1 1
import {
2 2
View,
3 3
StyleSheet,
4 4
KeyboardAvoidingView,
5 5
ScrollView,
6 6
TouchableOpacity,
7 7
ActivityIndicator,
8 8
} from "react-native";
9 9
import { Text } from "@/components/ui/Text";
10 -
import { useEffect, useState } from "react";
10 +
import { useState } from "react";
11 11
import { router, useLocalSearchParams } from "expo-router";
12 12
import { Card } from "@/components/ui/Cards";
13 13
import { Input } from "@/components/ui/Input";
14 14
import { Button } from "@/components/ui/Button";
15 15
import { Section, SectionHeader } from "@/components/ui/Sections";
16 16
import { Spacing, Typography, Colors, BorderRadius } from "@/constants/theme";
17 17
import { TimePicker } from "@/components/ui/TimePicker";
18 18
import { useMedicineRegimen, useUpdateMedicineRegimen } from "@/hooks";
19 -
import { MedicinePeriodicity } from "@/lib/api";
19 +
import type { MedicinePeriodicity, MedicineRegimen } from "@/lib/api";
20 20
21 21
const PERIODICITY_OPTIONS: { label: string; value: MedicinePeriodicity }[] = [
22 22
{ label: "Uma vez", value: "ONCE" },
23 23
{ label: "Diário", value: "DAILY" },
24 24
{ label: "2x ao dia", value: "TWICE_DAILY" },
48 48
}
49 49
50 50
export default function MedicineRegimenEdit() {
51 51
const { id } = useLocalSearchParams<{ id: string }>();
52 52
const { data, isLoading } = useMedicineRegimen(id);
53 +
54 +
if (isLoading) {
55 +
return (
56 +
<View style={styles.center}>
57 +
<ActivityIndicator color={Colors.light.tint} />
58 +
</View>
59 +
);
60 +
}
61 +
62 +
if (!data?.regimen) {
63 +
return null;
64 +
}
65 +
66 +
return <MedicineRegimenForm id={id} regimen={data.regimen} />;
67 +
}
68 +
69 +
function MedicineRegimenForm({ id, regimen }: { id: string; regimen: MedicineRegimen }) {
53 70
const updateRegimen = useUpdateMedicineRegimen();
54 71
55 -
const [name, setName] = useState("");
56 -
const [dosage, setDosage] = useState("");
57 -
const [periodicity, setPeriodicity] = useState<MedicinePeriodicity>("DAILY");
58 -
const [scheduledTimes, setScheduledTimes] = useState<Date[]>([]);
59 -
const [initialized, setInitialized] = useState(false);
60 -
61 -
useEffect(() => {
62 -
if (data?.regimen && !initialized) {
63 -
const r = data.regimen;
64 -
setName(r.name);
65 -
setDosage(r.dosage);
66 -
setPeriodicity(r.periodicity as MedicinePeriodicity);
67 -
setScheduledTimes(timesToDates(r.scheduledAt));
68 -
setInitialized(true);
69 -
}
70 -
}, [data, initialized]);
72 +
const [name, setName] = useState(regimen.name);
73 +
const [dosage, setDosage] = useState(regimen.dosage);
74 +
const [periodicity, setPeriodicity] = useState<MedicinePeriodicity>(regimen.periodicity);
75 +
const [scheduledTimes, setScheduledTimes] = useState<Date[]>(
76 +
timesToDates(regimen.scheduledAt),
77 +
);
71 78
72 79
const handleSave = async () => {
73 80
const count = getTimePickerCount(periodicity);
74 81
const scheduledAt = scheduledTimes.slice(0, count).map(
75 82
(d) =>
80 87
id,
81 88
payload: { name, dosage, periodicity, scheduledAt },
82 89
});
83 90
router.back();
84 91
};
85 -
86 -
if (isLoading || !initialized) {
87 -
return (
88 -
<View style={styles.center}>
89 -
<ActivityIndicator color={Colors.light.tint} />
90 -
</View>
91 -
);
92 -
}
93 92
94 93
return (
95 94
<KeyboardAvoidingView behavior="height" style={styles.keyboardView}>
96 95
<ScrollView scrollEventThrottle={16}>
97 96
<View style={styles.container}>
230 229
periodicityChipLabelActive: {
231 230
fontWeight: "600",
232 231
color: Colors.light.text,
233 232
},
234 233
});
frontend/app/sleep/edit/[id].tsx
1 1
import {
2 2
View,
3 3
StyleSheet,
4 4
KeyboardAvoidingView,
5 5
ScrollView,
6 +
ActivityIndicator,
6 7
} from "react-native";
7 8
import { Text } from "@/components/ui/Text";
8 -
import { useState, useEffect } from "react";
9 +
import { useState } from "react";
9 10
import { router, useLocalSearchParams, Stack } from "expo-router";
10 11
11 12
import { Card } from "@/components/ui/Cards";
12 13
import { TextArea } from "@/components/ui/Input";
13 14
import { Button } from "@/components/ui/Button";
15 16
import { Ionicons } from "@expo/vector-icons";
16 17
import { DatePickerField } from "@/components/ui/DatePickerField";
17 18
import { ScaleSlider } from "@/components/ui/ScaleSlider";
18 19
import { useSleepRecord, useUpdateSleepRecord } from "@/hooks";
19 20
import { parseDateOnly } from "@/lib/utils/time";
20 -
import { ActivityIndicator, View as ActivityView } from "react-native";
21 +
import type { SleepRecord } from "@/lib/api";
21 22
22 23
export default function EditSleepRecord() {
23 24
const { id } = useLocalSearchParams<{ id: string }>();
24 25
const { data: sleepRecord, isLoading } = useSleepRecord(id);
25 -
const updateSleepRecord = useUpdateSleepRecord();
26 26
27 -
const [date, setDate] = useState(new Date());
28 -
const [annotations, setAnnotations] = useState("");
29 -
const [average, setAverage] = useState(7.5);
27 +
if (isLoading) {
28 +
return (
29 +
<View style={styles.centered}>
30 +
<ActivityIndicator size="large" color={Colors.light.tint} />
31 +
</View>
32 +
);
33 +
}
30 34
31 -
useEffect(() => {
32 -
if (sleepRecord) {
33 -
setDate(parseDateOnly(sleepRecord.date));
34 -
setAnnotations(sleepRecord.annotations || "");
35 -
setAverage(sleepRecord.average);
36 -
}
37 -
}, [sleepRecord]);
35 +
if (!sleepRecord) {
36 +
return null;
37 +
}
38 +
39 +
return <EditSleepForm id={id} sleepRecord={sleepRecord} />;
40 +
}
41 +
42 +
function EditSleepForm({ id, sleepRecord }: { id: string; sleepRecord: SleepRecord }) {
43 +
const updateSleepRecord = useUpdateSleepRecord();
44 +
45 +
const [date, setDate] = useState(parseDateOnly(sleepRecord.date));
46 +
const [annotations, setAnnotations] = useState(sleepRecord.annotations || "");
47 +
const [average, setAverage] = useState(sleepRecord.average);
38 48
39 49
const formatValue = (value: number): string => {
40 50
return String(value).replaceAll(".", ",");
41 51
};
42 52
48 58
};
49 59
50 60
await updateSleepRecord.mutateAsync({ id: String(id), payload: data });
51 61
router.back();
52 62
};
53 -
54 -
if (isLoading) {
55 -
return (
56 -
<ActivityView style={styles.centered}>
57 -
<ActivityIndicator size="large" color={Colors.light.tint} />
58 -
</ActivityView>
59 -
);
60 -
}
61 63
62 64
return (
63 65
<KeyboardAvoidingView behavior="height" style={styles.keyboardView}>
64 66
<Stack.Screen options={{ title: "Editar Registro" }} />
65 67
<ScrollView scrollEventThrottle={16}>
172 174
flex: 1,
173 175
justifyContent: "center",
174 176
alignItems: "center",
175 177
},
176 178
});
frontend/app/triggers/edit/[id].tsx
1 1
import {
2 2
View,
3 3
StyleSheet,
4 4
KeyboardAvoidingView,
5 5
ScrollView,
6 6
ActivityIndicator,
7 7
} from "react-native";
8 8
import { Text } from "@/components/ui/Text";
9 -
import { useState, useEffect } from "react";
9 +
import { useState } from "react";
10 10
import { router, useLocalSearchParams, Stack } from "expo-router";
11 11
12 12
import { Card } from "@/components/ui/Cards";
13 13
import { TextArea } from "@/components/ui/Input";
14 14
import { Button } from "@/components/ui/Button";
18 18
import { useUpdateTrigger, useTrigger } from "@/hooks";
19 19
import { CategoryChips, CategoryOption } from "@/components/ui/CategoryChips";
20 20
import { TriggerCategory } from "@/constants/triggers";
21 21
import { TRIGGER_CATEGORY_DEFINITIONS } from "@/constants/trigger-categories";
22 22
import { TimePicker } from "@/components/ui/TimePicker";
23 +
import type { Trigger } from "@/lib/api";
23 24
24 25
const TRIGGER_CATEGORIES: CategoryOption<TriggerCategory>[] =
25 26
TRIGGER_CATEGORY_DEFINITIONS.map((d) => ({
26 27
label: d.label,
27 28
value: d.id,
29 30
}));
30 31
31 32
export default function EditTrigger() {
32 33
const { id } = useLocalSearchParams<{ id: string }>();
33 34
const { data: trigger, isLoading } = useTrigger(id);
34 -
const updateTrigger = useUpdateTrigger();
35 35
36 -
const [moment, setMoment] = useState(new Date());
37 -
const [comment, setComment] = useState("");
38 -
const [category, setCategory] = useState("WORK");
36 +
if (isLoading) {
37 +
return (
38 +
<View style={styles.centered}>
39 +
<ActivityIndicator size="large" color={Colors.light.tint} />
40 +
</View>
41 +
);
42 +
}
39 43
40 -
useEffect(() => {
41 -
if (trigger) {
42 -
setMoment(new Date(trigger.moment));
43 -
setComment(trigger.comment || "");
44 -
setCategory(trigger.category);
45 -
}
46 -
}, [trigger]);
44 +
if (!trigger) {
45 +
return null;
46 +
}
47 +
48 +
return <EditTriggerForm id={id} trigger={trigger} />;
49 +
}
50 +
51 +
function EditTriggerForm({ id, trigger }: { id: string; trigger: Trigger }) {
52 +
const updateTrigger = useUpdateTrigger();
53 +
54 +
const [moment, setMoment] = useState(new Date(trigger.moment));
55 +
const [comment, setComment] = useState(trigger.comment || "");
56 +
const [category, setCategory] = useState(trigger.category);
47 57
48 58
const save = async () => {
49 59
const data = {
50 60
moment,
51 61
comment,
53 63
};
54 64
55 65
await updateTrigger.mutateAsync({ id: String(id), payload: data });
56 66
router.back();
57 67
};
58 -
59 -
if (isLoading) {
60 -
return (
61 -
<View style={styles.centered}>
62 -
<ActivityIndicator size="large" color={Colors.light.tint} />
63 -
</View>
64 -
);
65 -
}
66 68
67 69
return (
68 70
<KeyboardAvoidingView behavior="height" style={styles.keyboardView}>
69 71
<Stack.Screen options={{ title: "Editar Registro" }} />
70 72
<ScrollView scrollEventThrottle={16}>
175 177
flex: 1,
176 178
justifyContent: "center",
177 179
alignItems: "center",
178 180
},
179 181
});