eletrotupi / tcc/ frontend/app/(tabs)/settings.tsx04014530b375f804d5915e2e5f879a0663a8c709
10.4 KB | 374 lines Raw
1
import {
2
  TouchableOpacity,
3
  StyleSheet,
4
  SectionList,
5
  View,
6
  Alert,
7
  Switch,
8
  Pressable,
9
} from "react-native";
10
import { Text } from '@/components/ui/Text';
11
import { useState } from "react";
12
import { router } from "expo-router";
13
import { Card } from "@/components/ui/Cards";
14
import ScreenLayout from "@/components/ui/ScreenLayout";
15
import { BorderRadius, Colors, Fonts, Spacing } from "@/constants/theme";
16
import { useThemeColor } from "@/hooks/use-theme-color";
17
import { useAuth } from "@/context/AuthContext";
18
import { Section, SectionHeader } from "@/components/ui/Sections";
19
import { Ionicons, MaterialIcons } from "@expo/vector-icons";
20
import { Button } from "@/components/ui/Button";
21
import { ConfirmModal } from "@/components/ui/ConfirmModal";
22
import { TimePicker } from "@/components/ui/TimePicker";
23
import { usePatchUserMe } from "@/hooks/useUserPreferences.queries";
24
import { useToast } from '@/context/ToastContext';
25

26
export default function Settings() {
27
  const { user, logout, updateAuthUser } = useAuth();
28
  const [allowWeeklyInsights, setAllowWeeklyInsights] = useState(false);
29
  const [logoutVisible, setLogoutVisible] = useState(false);
30
  const { showToast } = useToast();
31

32
  const notificationsEnabled = user?.notificationsEnabled ?? true;
33
  const dailyReminderTime = user?.dailyReminderTime ?? "20:00";
34

35
  const patchUserMe = usePatchUserMe((updatedUser) => {
36
    updateAuthUser(updatedUser);
37
  });
38

39
  const handleNotificationToggle = (value: boolean) => {
40
    patchUserMe.mutate({ notificationsEnabled: value });
41
  };
42

43
  const handleTimeChange = (date: Date) => {
44
    const time = `${date.getHours().toString().padStart(2, "0")}:${date.getMinutes().toString().padStart(2, "0")}`;
45
    patchUserMe.mutate({ dailyReminderTime: time });
46
  };
47

48
  const textColor = useThemeColor({}, "text");
49

50
  const handleLogout = () => {
51
    setLogoutVisible(true);
52
  };
53

54
  const handleProfilePress = () => {
55
    router.push("/profile");
56
  };
57

58
  const handleInvisibleMode = () => {};
59

60
  const handleDataExport = () => {
61
    Alert.alert("Exportar dados", "Deseja exportar seus dados?", [
62
      { text: "Cancelar", style: "cancel" },
63
      {
64
        text: "Exportar",
65
        style: "destructive",
66
        onPress: () => {
67
          showToast("Você receberá um e-mail com os dados exportados", "success")
68
        },
69
      },
70
    ]);
71
  };
72

73
  return (
74
    <ScreenLayout
75
      userName={user.firstName}
76
      userAvatar={user.avatarURL}
77
      showNotificationBadge={true}
78
    >
79
      <Section>
80
        <SectionHeader title="Perfil" />
81

82
        <Card style={{ padding: Spacing.cardGap }} onPress={handleProfilePress}>
83
          <View
84
            style={{
85
              flexDirection: "row",
86
              alignItems: "center",
87
              justifyContent: "space-between",
88
            }}
89
          >
90
            <View
91
              style={{
92
                flexDirection: "column",
93
                alignItems: "center",
94
                justifyContent: "space-between",
95
              }}
96
            >
97
              <Text style={styles.cardTitle}>Dados Pessoais</Text>
98
              <Text style={styles.cardSubtitle}>Nome, Email e senha</Text>
99
            </View>
100

101
            <Ionicons name="chevron-forward" size={24} color={textColor} />
102
          </View>
103
        </Card>
104
      </Section>
105

106
      <Section>
107
        <SectionHeader title="Notificações" />
108

109
        <Card style={{ padding: Spacing.cardGap }}>
110
          <View
111
            style={{
112
              flexDirection: "row",
113
              alignItems: "center",
114
              justifyContent: "space-between",
115
            }}
116
          >
117
            <View
118
              style={[
119
                styles.cardIcon,
120
                { backgroundColor: Colors.light.accentBlue, marginBottom: 5 },
121
              ]}
122
            >
123
              <Ionicons
124
                name="notifications-outline"
125
                size={20}
126
                color={Colors.light.black}
127
              />
128
            </View>
129

130
            <View
131
              style={{
132
                flexDirection: "column",
133
                alignItems: "flex-start",
134
                justifyContent: "space-between",
135
                marginLeft: 12,
136
                flex: 1,
137
              }}
138
            >
139
              <Text style={styles.cardTitle}>Lembrete diário de humor</Text>
140
              <Text>{notificationsEnabled ? `Diário às ${dailyReminderTime}` : "Desativado"}</Text>
141
            </View>
142

143
            <Switch
144
              onValueChange={handleNotificationToggle}
145
              thumbColor={Colors.light.tint}
146
              trackColor={{
147
                false: Colors.light.disabled,
148
                true: Colors.light.gray,
149
              }}
150
              value={notificationsEnabled}
151
              disabled={patchUserMe.isPending}
152
            />
153
          </View>
154

155
          {notificationsEnabled && (
156
            <TimePicker
157
              value={(() => {
158
                const [h, m] = dailyReminderTime.split(":").map(Number);
159
                const d = new Date();
160
                d.setHours(h, m, 0, 0);
161
                return d;
162
              })()}
163
              onChange={handleTimeChange}
164
            />
165
          )}
166

167
          <View style={styles.divider} />
168

169
          <View
170
            style={{
171
              flexDirection: "row",
172
              alignItems: "center",
173
              justifyContent: "space-between",
174
            }}
175
          >
176
            <View
177
              style={[
178
                styles.cardIcon,
179
                { backgroundColor: Colors.light.accentPurple },
180
              ]}
181
            >
182
              <Ionicons name="sparkles" size={20} color={Colors.light.black} />
183
            </View>
184

185
            <View
186
              style={{
187
                flexDirection: "column",
188
                alignItems: "flex-start",
189
                justifyContent: "space-between",
190
                marginLeft: 12,
191
                flex: 1,
192
              }}
193
            >
194
              <Text style={styles.cardTitle}>Indicadores semanais</Text>
195
              <Text>Relatórios de progressos</Text>
196
            </View>
197

198
            <Switch
199
              onValueChange={setAllowWeeklyInsights}
200
              value={allowWeeklyInsights}
201
              thumbColor={Colors.light.tint}
202
              trackColor={{
203
                false: Colors.light.disabled,
204
                true: Colors.light.gray,
205
              }}
206
            />
207
          </View>
208
        </Card>
209
      </Section>
210

211
      <Section>
212
        <SectionHeader title="Relatório" />
213
        <Card
214
          style={{ padding: Spacing.cardGap }}
215
          onPress={() => router.push("/report")}
216
        >
217
          <View
218
            style={{
219
              flexDirection: "row",
220
              alignItems: "center",
221
              justifyContent: "space-between",
222
            }}
223
          >
224
            <View style={{ flexDirection: "row", alignItems: "center" }}>
225
              <MaterialIcons
226
                name="picture-as-pdf"
227
                size={24}
228
                color={Colors.light.textSecondary}
229
              />
230
              <Text style={{ marginLeft: 8, ...styles.cardTitle }}>
231
                Gerar Relatório
232
              </Text>
233
            </View>
234
            <Ionicons name="chevron-forward" size={24} color={textColor} />
235
          </View>
236
        </Card>
237
      </Section>
238

239
      <Section>
240
        <SectionHeader title="Privacidade" />
241

242
        <Card style={{ padding: Spacing.cardGap }}>
243
          <TouchableOpacity
244
            style={{
245
              flexDirection: "row",
246
              alignItems: "center",
247
              justifyContent: "space-between",
248
            }}
249
            onPress={handleInvisibleMode}
250
          >
251
            <View style={{ flexDirection: "row", alignItems: "center" }}>
252
              <MaterialIcons
253
                name="lock"
254
                size={24}
255
                color={Colors.light.textSecondary}
256
              />
257

258
              <Text
259
                style={{
260
                  marginLeft: 8,
261
                  color: Colors.light.text,
262
                  fontSize: 14,
263
                  fontWeight: "500" as const,
264
                }}
265
              >
266
                Privacidade
267
              </Text>
268
            </View>
269

270
            <Ionicons name="chevron-forward" size={24} color={textColor} />
271
          </TouchableOpacity>
272

273
          <View style={styles.divider} />
274

275
          <TouchableOpacity
276
            style={{
277
              flexDirection: "row",
278
              alignItems: "center",
279
              justifyContent: "space-between",
280
            }}
281
            onPress={handleDataExport}
282
          >
283
            <View style={{ flexDirection: "row", alignItems: "center" }}>
284
              <MaterialIcons
285
                name="storage"
286
                size={24}
287
                color={Colors.light.textSecondary}
288
              />
289

290
              <Text
291
                style={{
292
                  marginLeft: 8,
293
                  color: Colors.light.text,
294
                  fontSize: 14,
295
                  fontWeight: "500" as const,
296
                }}
297
              >
298
                Exportar Meus Dados
299
              </Text>
300
            </View>
301

302
            <MaterialIcons
303
              name="file-download"
304
              size={24}
305
              color={Colors.light.textSecondary}
306
            />
307
          </TouchableOpacity>
308
        </Card>
309
      </Section>
310

311
      <Button
312
        title="Sair da Conta"
313
        onPress={handleLogout}
314
        variant="outline"
315
        style={{ borderColor: Colors.light.danger }}
316
        testID="button-logout"
317
        textStyle={{ color: Colors.light.danger }}
318
      />
319

320
      <ConfirmModal
321
        visible={logoutVisible}
322
        title="Sair da conta"
323
        message="Tem certeza que quer sair?"
324
        confirmLabel="Sair"
325
        cancelLabel="Cancelar"
326
        destructive
327
        onCancel={() => setLogoutVisible(false)}
328
        onConfirm={() => {
329
          setLogoutVisible(false);
330
          logout();
331
        }}
332
        testID="logout-confirm"
333
      />
334
    </ScreenLayout>
335
  );
336
}
337

338
const styles = StyleSheet.create({
339
  container: {
340
    flex: 1,
341
    marginHorizontal: 16,
342
    paddingTop: 10,
343
  },
344
  item: {
345
    paddingTop: 20,
346
    paddingBottom: 20,
347
  },
348
  header: {
349
    fontSize: 22,
350
    fontWeight: "bold",
351
  },
352
  cardIcon: {
353
    paddingVertical: 15,
354
    paddingHorizontal: 14,
355
    width: 48,
356
    borderRadius: BorderRadius.md,
357
  },
358
  cardTitle: {
359
    fontSize: 16,
360
    fontWeight: "bold",
361
  },
362
  cardSubtitle: {
363
    fontSize: 12,
364
    color: Colors.light.textSecondary,
365
  },
366
  logout: {
367
    color: "#FF2C2C",
368
  },
369
  divider: {
370
    height: StyleSheet.hairlineWidth,
371
    backgroundColor: "#D1D5DB",
372
    marginVertical: 16,
373
  },
374
});