eletrotupi / tcc/ commit / a2d0b31

frontend: add daily energy widget

Pedro Lucas Porcellis porcellis@eletrotupi.com 1 month ago a2d0b31fb95ea93e87b5ebca20daa4402d0a5b99
Parents: 05053ef
2 file(s) changed
  • frontend/app/(tabs)/new/index.tsx +34 -45
  • frontend/components/ui/DailyEnergyWidget.tsx +99 -0
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";
▸ 17 unchanged lines
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 });
▸ 5 unchanged lines
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}
▸ 32 unchanged lines
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

▸ 48 unchanged lines
189 178
    fontSize: 11,
190 179
    fontWeight: 600,
191 180
    lineHeight: 16.5,
192 181
  },
193 182
});
frontend/components/ui/DailyEnergyWidget.tsx
@@ -0,0 +1,99 @@
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 + });