frontend: linting some specific components + sleep/new
Pedro Lucas Porcellis porcellis@eletrotupi.com · 4 months ago
3c48957da540557e7d3a844d97efd318222a1371 Browse filesParents
0e69b39Changed files
3
Additions
+86
Deletions
-76
frontend/app/sleep/new.tsx
1 1
import {
2 2
View,
3 3
Text,
4 4
StyleSheet,
5 5
KeyboardAvoidingView,
6 -
ScrollView
7 -
} from 'react-native';
8 -
import { useEffect, useState } from 'react';
9 -
import { router } from 'expo-router';
6 +
ScrollView,
7 +
} from "react-native";
8 +
import { useState } from "react";
9 +
import { router } from "expo-router";
10 10
11 -
import { Card } from '@/components/ui/Cards';
12 -
import { Input, TextArea } from '@/components/ui/Input';
13 -
import { Button } from '@/components/ui/Button';
14 -
import { Spacing, Typography, Colors, BorderRadius } from '@/constants/theme';
15 -
import { Ionicons } from '@expo/vector-icons';
16 -
import DatePickerField from '@/components/ui/DatePickerField';
17 -
import { ScaleSlider } from '@/components/ui/ScaleSlider';
18 -
import { useCreateSleepRecord } from '@/hooks';
11 +
import { Card } from "@/components/ui/Cards";
12 +
import { TextArea } from "@/components/ui/Input";
13 +
import { Button } from "@/components/ui/Button";
14 +
import { Spacing, Typography, Colors, BorderRadius } from "@/constants/theme";
15 +
import { Ionicons } from "@expo/vector-icons";
16 +
import { DatePickerField } from "@/components/ui/DatePickerField";
17 +
import { ScaleSlider } from "@/components/ui/ScaleSlider";
18 +
import { useCreateSleepRecord } from "@/hooks";
19 19
20 20
export default function NewSleepRecord() {
21 -
const [date, setDate] = useState(new Date())
22 -
const [annotations, setAnnotations] = useState();
21 +
const [date, setDate] = useState(new Date());
22 +
const [annotations, setAnnotations] = useState("");
23 23
const [average, setAverage] = useState(7.5);
24 24
const createSleepRecord = useCreateSleepRecord();
25 25
26 26
const formatValue = (value: number): string => {
27 -
return String(value).replaceAll('.', ',');
27 +
return String(value).replaceAll(".", ",");
28 28
};
29 29
30 30
const save = async () => {
31 31
const data = {
32 32
date,
33 33
annotations,
34 -
average
34 +
average,
35 35
};
36 36
37 -
console.log("Sleep record:", data)
38 -
await createSleepRecord.mutateAsync(data)
39 -
router.replace("/")
37 +
console.log("Sleep record:", data);
38 +
await createSleepRecord.mutateAsync(data);
39 +
router.replace("/");
40 40
};
41 41
42 42
return (
43 -
<KeyboardAvoidingView
44 -
behavior='height'
45 -
style={styles.keyboardView}>
43 +
<KeyboardAvoidingView behavior="height" style={styles.keyboardView}>
46 44
<ScrollView scrollEventThrottle={16}>
47 45
<View style={styles.container}>
48 46
<View style={styles.header}>
49 47
<View style={styles.innerHeaderWrapper}>
50 -
<View style={[styles.headerIcon, { backgroundColor: '#EFF6FF' }]}>
48 +
<View style={[styles.headerIcon, { backgroundColor: "#EFF6FF" }]}>
51 49
<Ionicons name="moon-outline" size={20} color="#2563EB" />
52 50
</View>
53 51
54 52
<View style={styles.headerTitleSubtitle}>
55 53
<Text style={styles.headerTitle}>Bom descanso</Text>
56 -
<Text style={styles.headerSubtitle}>Registre sua noite de sono</Text>
54 +
<Text style={styles.headerSubtitle}>
55 +
Registre sua noite de sono
56 +
</Text>
57 57
</View>
58 58
</View>
59 59
60 60
<Text style={styles.description}>
61 -
Acompanhar seu sono ajuda a entender como seu corpo se recupera
62 -
e melhora sua performance diária.
61 +
Acompanhar seu sono ajuda a entender como seu corpo se recupera e
62 +
melhora sua performance diária.
63 63
</Text>
64 64
</View>
65 65
66 66
<Card style={styles.mainCard}>
67 67
<DatePickerField
79 79
onValueFormat={formatValue}
80 80
step={0.5}
81 81
min={0.0}
82 82
max={15.0}
83 83
minLabel="0h"
84 -
maxLabel="15h" />
84 +
maxLabel="15h"
85 +
/>
85 86
</View>
86 87
87 88
<TextArea
88 89
label="Notas sobre a qualidade"
89 -
type="text"
90 90
variant="darkGhost"
91 91
onChangeText={(val) => setAnnotations(val)}
92 92
value={annotations}
93 93
minRows={5}
94 94
maxRows={10}
95 95
placeholder="Como você se sentiu ao acordar? Teve sonhos marcantes?"
96 -
style={styles.notes}
97 96
/>
98 97
</Card>
99 98
100 99
<Button title="Salvar Registro" onPress={save} />
101 100
</View>
109 108
gap: 24,
110 109
paddingHorizontal: Spacing.containerPadding,
111 110
paddingVertical: Spacing.sectionGap,
112 111
},
113 112
mainCard: {
114 -
padding: Spacing.cardGap
113 +
padding: Spacing.cardGap,
115 114
},
116 115
// Header
117 -
header: {
118 -
},
116 +
header: {},
119 117
headerIcon: {
120 118
paddingVertical: 15,
121 119
paddingHorizontal: 14,
122 120
width: 48,
123 121
borderRadius: BorderRadius.md,
124 122
},
125 123
innerHeaderWrapper: {
126 124
flex: 1,
127 -
flexDirection: 'row',
128 -
alignItems: 'center'
125 +
flexDirection: "row",
126 +
alignItems: "center",
129 127
},
130 128
headerTitleSubtitle: {
131 -
marginLeft: 10
129 +
marginLeft: 10,
132 130
},
133 131
headerTitle: {
134 -
...Typography.headlineMd
132 +
...Typography.headlineMd,
135 133
},
136 134
headerSubtitle: {
137 135
...Typography.bodyMd,
138 -
color: Colors.light.textSecondary
136 +
color: Colors.light.textSecondary,
139 137
},
140 138
description: {
141 139
...Typography.bodyMd,
142 140
color: Colors.light.textSecondary,
143 -
marginTop: 20
141 +
marginTop: 20,
144 142
},
145 143
keyboardView: {
146 144
flex: 1,
147 145
},
148 -
})
146 +
});
frontend/components/ui/DatePickerField.tsx
1 1
import { useState, useEffect } from "react";
2 -
import { View, Text, Pressable, StyleSheet, Platform } from "react-native";
3 -
import DateTimePicker from "@react-native-community/datetimepicker";
2 +
import { View, Text, Pressable, StyleSheet } from "react-native";
3 +
import DateTimePicker, {
4 +
DateTimePickerEvent,
5 +
} from "@react-native-community/datetimepicker";
4 6
import { format } from "date-fns";
5 -
import MaterialCommunityIcons from "react-native-vector-icons/MaterialCommunityIcons";
6 -
import { Colors } from '@/constants/theme';
7 -
import { Label } from '@/components/ui/Input';
7 +
import { MaterialIcons } from "@expo/vector-icons";
8 +
import { Colors } from "@/constants/theme";
9 +
import { Label } from "@/components/ui/Input";
10 +
11 +
interface DatePickerProps {
12 +
label: string;
13 +
initialDate?: Date;
14 +
onChange: (date: Date) => void;
15 +
minimumDate?: Date;
16 +
maximumDate?: Date;
17 +
}
8 18
9 -
export default function DatePickerField({
19 +
export const DatePickerField: React.FC<DatePickerProps> = ({
10 20
label,
11 21
initialDate = new Date(),
12 22
onChange,
13 23
minimumDate,
14 24
maximumDate,
15 -
}) {
25 +
}) => {
16 26
const [date, setDate] = useState(initialDate);
17 27
const [show, setShow] = useState(false);
18 28
19 29
useEffect(() => {
20 30
setDate(initialDate);
21 31
}, [initialDate]);
22 32
23 33
const openPicker = () => setShow(true);
24 34
25 -
const handleChange = (event, selectedDate) => {
35 +
const handleChange = (event: DateTimePickerEvent, selectedDate?: Date) => {
26 36
setShow(false);
27 37
28 38
if (selectedDate) {
29 39
setDate(selectedDate);
30 40
if (onChange) onChange(selectedDate);
35 45
36 46
return (
37 47
<View>
38 48
<Label text={label} />
39 49
40 -
<Pressable onPress={openPicker}
41 -
style={({ pressed }) => [styles.container, pressed && styles.pressed]}>
50 +
<Pressable
51 +
onPress={openPicker}
52 +
style={({ pressed }) => [styles.container, pressed && styles.pressed]}
53 +
>
42 54
<Text style={styles.dateText}>{formatted}</Text>
43 -
<MaterialCommunityIcons name="calendar-outline" size={22} color="#6B7280" />
55 +
<MaterialIcons name="calendar-month" size={22} color="#6B7280" />
44 56
</Pressable>
45 57
46 58
{show && (
47 59
<DateTimePicker
48 60
value={date}
53 65
maximumDate={maximumDate}
54 66
/>
55 67
)}
56 68
</View>
57 69
);
58 -
}
70 +
};
59 71
60 72
const styles = StyleSheet.create({
61 73
label: {
62 -
fontWeight: '500',
74 +
fontWeight: "500",
63 75
color: Colors.light.textSecondary,
64 76
fontSize: 12,
65 77
marginBottom: 8,
66 78
letterSpacing: 0.5,
67 -
textTransform: 'uppercase'
79 +
textTransform: "uppercase",
68 80
},
69 81
container: {
70 82
flexDirection: "row",
71 83
alignItems: "center",
72 84
justifyContent: "space-between",
85 97
color: "#111827",
86 98
fontSize: 16,
87 99
fontWeight: "600",
88 100
},
89 101
});
90 -
frontend/components/ui/EmojiSelectors.tsx
1 -
import React from 'react';
1 +
import React from "react";
2 2
import {
3 3
View,
4 4
Pressable,
5 5
StyleSheet,
6 6
Image,
7 7
Text,
8 8
ImageSourcePropType,
9 9
ViewStyle,
10 -
} from 'react-native';
11 -
import { Spacing, Typography, BorderRadius } from '@/constants/theme';
12 -
import { useThemeColor } from '@/hooks/use-theme-color';
10 +
} from "react-native";
11 +
import { Spacing, Typography, BorderRadius } from "@/constants/theme";
12 +
import { useThemeColor } from "@/hooks/use-theme-color";
13 13
14 14
type IconSource = string | ImageSourcePropType; // either string or a svg
15 15
16 16
// Specialized variant with labels below
17 17
interface MoodSelectorProps {
18 -
items: Array<{
18 +
items: T<{
19 19
id: string;
20 20
icon: IconSource;
21 21
label: string;
22 22
}>;
23 23
value?: string;
31 31
value,
32 32
onSelect,
33 33
disabled = false,
34 34
style,
35 35
}) => {
36 -
const accentBlueColor = useThemeColor({}, 'accentBlue');
37 -
const tintColor = useThemeColor({}, 'tint');
38 -
const surfaceColor = useThemeColor({}, 'surface');
39 -
const dividerColor = useThemeColor({}, 'divider');
40 -
const textSecondaryColor = useThemeColor({}, 'textSecondary');
36 +
const accentBlueColor = useThemeColor({}, "accentBlue");
37 +
const tintColor = useThemeColor({}, "tint");
38 +
const surfaceColor = useThemeColor({}, "surface");
39 +
const dividerColor = useThemeColor({}, "divider");
40 +
const textSecondaryColor = useThemeColor({}, "textSecondary");
41 41
42 42
const styles = StyleSheet.create({
43 43
container: {
44 -
flexDirection: 'row',
44 +
flexDirection: "row",
45 45
gap: Spacing.inlineGapSm,
46 -
justifyContent: 'space-around',
47 -
alignItems: 'flex-start',
48 -
flexWrap: 'wrap',
46 +
justifyContent: "space-around",
47 +
alignItems: "flex-start",
48 +
flexWrap: "wrap",
49 49
},
50 50
itemWrapper: {
51 -
alignItems: 'center',
51 +
alignItems: "center",
52 52
gap: 8,
53 53
flex: 1,
54 -
minWidth: '8%',
54 +
minWidth: "8%",
55 55
},
56 56
itemButton: {
57 57
width: 50,
58 58
height: 50,
59 59
borderRadius: BorderRadius.lg,
60 -
justifyContent: 'center',
61 -
alignItems: 'center',
60 +
justifyContent: "center",
61 +
alignItems: "center",
62 62
backgroundColor: surfaceColor,
63 63
borderWidth: 1,
64 64
borderColor: dividerColor,
65 65
},
66 66
itemButtonActive: {
67 67
backgroundColor: accentBlueColor,
68 -
borderColor: 'transparent',
68 +
borderColor: "transparent",
69 69
},
70 70
icon: {
71 71
fontSize: 48,
72 72
lineHeight: 48,
73 73
},
75 75
fontSize: 36,
76 76
lineHeight: 40,
77 77
},
78 78
label: {
79 79
fontSize: Typography.labelSm.fontSize,
80 -
fontWeight: '500',
80 +
fontWeight: "500",
81 81
color: textSecondaryColor,
82 -
textAlign: 'center',
82 +
textAlign: "center",
83 83
},
84 84
});
85 85
86 -
const isEmoji = (icon: IconSource): icon is string => typeof icon === 'string';
86 +
const isEmoji = (icon: IconSource): icon is string =>
87 +
typeof icon === "string";
87 88
88 89
return (
89 90
<View style={[styles.container, style]}>
90 91
{items.map((item) => {
91 92
const isSelected = value === item.id;
120 121
);
121 122
})}
122 123
</View>
123 124
);
124 125
};