frontend: linting some specific components + sleep/new
Parents:
0e69b393 file(s) changed
- frontend/app/sleep/new.tsx +37 -39
- frontend/components/ui/DatePickerField.tsx +26 -15
- frontend/components/ui/EmojiSelectors.tsx +23 -22
frontend/app/sleep/new.tsx
@@ -3,63 +3,63 @@ 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
@@ -81,19 +81,18 @@ 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
@@ -111,11 +110,10 @@ 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,
@@ -124,25 +122,25 @@ 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,18 +1,28 @@
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
@@ -22,7 +32,7 @@ }, [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) {
@@ -37,10 +47,12 @@ 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 && (
@@ -55,16 +67,16 @@ />
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",
@@ -87,4 +99,3 @@ fontSize: 16,
87 99 fontWeight: "600",
88 100 },
89 101 });
90 -
frontend/components/ui/EmojiSelectors.tsx
@@ -1,4 +1,4 @@
1 - import React from 'react';
1 + import React from "react";
2 2 import {
3 3 View,
4 4 Pressable,
@@ -7,15 +7,15 @@ 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;
@@ -33,39 +33,39 @@ 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,
@@ -77,13 +77,14 @@ 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]}>