frontend: add daily energy widget
Pedro Lucas Porcellis porcellis@eletrotupi.com · 4 months ago
a2d0b31fb95ea93e87b5ebca20daa4402d0a5b99 Browse filesParents
05053efChanged files
2
Additions
+133
Deletions
-45
frontend/app/(tabs)/new/index.tsx
1 1
import { useEffect, useState } from "react";
2 2
import { StyleSheet, View, Text, ActivityIndicator } from "react-native";
3 3
4 4
import { ThemedText } from "@/components/misc/themed-text";
5 5
import { ThemedView } from "@/components/misc/themed-view";
23 23
import { MoodDefinition, MOODS } from "@/constants/moods";
24 24
25 25
import { useThemeColor, useMoodEntries } from "@/hooks";
26 26
27 27
import MoodEntryLog from "@/components/ui/MoodEntryLog";
28 +
import { DailyEnergyWidget } from "@/components/ui/DailyEnergyWidget";
28 29
29 30
export default function New() {
30 31
const { user } = useAuth();
31 32
const [mood, setMood] = useState<string>("good");
32 33
const { data, isLoading } = useMoodEntries({ limit: 5 });
38 39
// TODO: Set down on camelCase vs kebab case
39 40
router.navigate(`/new/entry?initialMood=${mood}`);
40 41
};
41 42
42 43
const onNotificationPress = () => {
43 -
router.push('/notifications');
44 -
}
44 +
router.push("/notifications");
45 +
};
45 46
46 47
return (
47 48
<ScreenLayout
48 49
userName={user.firstName}
49 50
userAvatar={user.avatarURL}
82 83
</Card>
83 84
</Section>
84 85
85 86
{/* TODO: Check whether we gonna have to generate these on demand */}
86 87
<Section>
87 -
<Grid gap={4}>
88 -
<Card style={{ padding: Spacing.cardGap }}>
89 -
<View
90 -
style={{
91 -
flex: 1,
92 -
flexDirection: "row",
93 -
flexGrow: 0,
94 -
paddingVertical: 10,
95 -
}}
96 -
>
97 -
<Ionicons name="flash" size={20} color="#64748B" />
88 +
<View
89 +
style={[
90 +
{
91 +
flexDirection: "row",
92 +
gap: 16,
93 +
},
94 +
]}
95 +
>
96 +
<View style={{ flex: 1 }}>
97 +
<DailyEnergyWidget />
98 +
</View>
98 99
99 -
<Text style={{ ...Typography.headlineMd, marginBottom: 10 }}>
100 -
Energia
101 -
</Text>
102 -
</View>
100 +
<View style={{ flex: 1 }}>
101 +
<Card style={{ padding: Spacing.cardGap }}>
102 +
<View
103 +
style={{
104 +
flex: 1,
105 +
flexDirection: "row",
106 +
flexGrow: 0,
107 +
paddingVertical: 10,
108 +
}}
109 +
>
110 +
<Ionicons name="moon" size={20} color="#64748B" />
103 111
104 -
<Text style={{ ...Typography.headlineMd, marginBottom: 10 }}>
105 -
Média Alta
106 -
</Text>
107 -
108 -
<View style={styles.lineTrack}>
109 -
<View style={[styles.lineFill, { width: `35%` }]} />
110 -
</View>
111 -
</Card>
112 -
113 -
<Card style={{ padding: Spacing.cardGap }}>
114 -
<View
115 -
style={{
116 -
flex: 1,
117 -
flexDirection: "row",
118 -
flexGrow: 0,
119 -
paddingVertical: 10,
120 -
}}
121 -
>
122 -
<Ionicons name="moon-outline" size={20} color="#64748B" />
112 +
<Text style={{ ...Typography.headlineMd, marginBottom: 10 }}>
113 +
Sono
114 +
</Text>
115 +
</View>
123 116
124 117
<Text style={{ ...Typography.headlineMd, marginBottom: 10 }}>
125 -
Sono
118 +
7h 30m
126 119
</Text>
127 -
</View>
128 120
129 -
<Text style={{ ...Typography.headlineMd, marginBottom: 10 }}>
130 -
7h 30m
131 -
</Text>
132 -
133 -
<Text style={styles.indicatorGreen}>+45min que ontem</Text>
134 -
</Card>
135 -
</Grid>
121 +
<Text style={styles.indicatorGreen}>+45min que ontem</Text>
122 +
</Card>
123 +
</View>
124 +
</View>
136 125
</Section>
137 126
138 127
<Section>
139 128
<SectionHeader title="Registros recentes" />
140 129
189 178
fontSize: 11,
190 179
fontWeight: 600,
191 180
lineHeight: 16.5,
192 181
},
193 182
});
/dev/null → frontend/components/ui/DailyEnergyWidget.tsx
1 +
import { ActivityIndicator, StyleSheet, Text, View } from "react-native";
2 +
import { Card } from "@/components/ui/Cards";
3 +
import { useInsight } from "@/hooks/useInsights.queries";
4 +
import { Ionicons } from "@expo/vector-icons";
5 +
import { Typography, Spacing, Colors, BorderRadius } from "@/constants/theme";
6 +
7 +
export const DailyEnergyWidget = () => {
8 +
const { data: insight, isLoading } = useInsight("DAILY_ENERGY", 0);
9 +
10 +
const metadata = insight?.metadata as {
11 +
peak: number;
12 +
trough: number;
13 +
entryCount: number;
14 +
avgEnergy: number;
15 +
};
16 +
17 +
const avgEnergy = metadata?.avgEnergy;
18 +
const peak = metadata?.peak;
19 +
20 +
const energyWidth = (avgEnergy / peak) * 100;
21 +
const energySummary = () => {
22 +
if (avgEnergy < 3) return "Energia baixa";
23 +
if (avgEnergy < 5) return "Media baixa";
24 +
if (avgEnergy < 7.5) return "Média Alta";
25 +
return "Energia alta";
26 +
};
27 +
28 +
return (
29 +
<Card style={styles.container}>
30 +
<View
31 +
style={{
32 +
flex: 1,
33 +
flexDirection: "row",
34 +
flexGrow: 0,
35 +
paddingVertical: 10,
36 +
}}
37 +
>
38 +
<Ionicons name="flash" size={20} color="#64748B" />
39 +
40 +
<Text style={{ ...Typography.headlineMd, marginBottom: 10 }}>
41 +
Energia
42 +
</Text>
43 +
</View>
44 +
45 +
<View style={{ flex: 1 }}>
46 +
{isLoading ? (
47 +
<View style={styles.empty}>
48 +
<ActivityIndicator size="small" />
49 +
</View>
50 +
) : insight ? (
51 +
<>
52 +
<Text style={{ ...Typography.headlineMd, marginBottom: 10 }}>
53 +
{energySummary()}
54 +
</Text>
55 +
56 +
<View style={styles.lineTrack}>
57 +
<View style={[styles.lineFill, { width: `${energyWidth}%` }]} />
58 +
</View>
59 +
</>
60 +
) : (
61 +
<>
62 +
<Text style={styles.empty}>
63 +
Não há dados disponíveis para o dia de hoje
64 +
</Text>
65 +
</>
66 +
)}
67 +
</View>
68 +
</Card>
69 +
);
70 +
};
71 +
72 +
const styles = StyleSheet.create({
73 +
container: {
74 +
flex: 1,
75 +
padding: Spacing.cardGap,
76 +
},
77 +
empty: {
78 +
...Typography.labelSm,
79 +
opacity: 0.5,
80 +
},
81 +
lineTrack: {
82 +
height: 6,
83 +
backgroundColor: Colors.light.divider,
84 +
borderRadius: BorderRadius.full,
85 +
marginBottom: 4,
86 +
overflow: "hidden",
87 +
},
88 +
lineFill: {
89 +
height: "100%",
90 +
backgroundColor: Colors.light.tint,
91 +
borderRadius: BorderRadius.full,
92 +
},
93 +
indicatorGreen: {
94 +
color: Colors.light.tint,
95 +
fontSize: 11,
96 +
fontWeight: 600,
97 +
lineHeight: 16.5,
98 +
},
99 +
});