eletrotupi / tcc/ commit / b996777

frontend: rework settings page

Pedro Lucas Porcellis porcellis@eletrotupi.com 1 month ago b996777000e11000717aefd4afbdde6ac3c4c587
Parents: de5e5ec
1 file(s) changed
  • frontend/app/(tabs)/settings.tsx +279 -99
frontend/app/(tabs)/settings.tsx
1 -
import { TouchableOpacity, StyleSheet, Text, SectionList, View, Alert } from 'react-native';
2 -
import { SafeAreaView, SafeAreaProvider } from 'react-native-safe-area-context';
3 -
import { useState } from 'react';
4 -
import ParallaxScrollView from '@/components/misc/parallax-scroll-view';
5 -
import { Link } from 'expo-router'
6 -
import { StatusBar } from 'expo-status-bar';
1 +
import {
2 +
  TouchableOpacity,
3 +
  StyleSheet,
4 +
  Text,
5 +
  SectionList,
6 +
  View,
7 +
  Alert,
8 +
  Switch,
9 +
  Pressable,
10 +
} from "react-native";
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";
7 21

8 -
import { ThemedText } from '@/components/misc/themed-text';
9 -
import { ThemedView } from '@/components/misc/themed-view';
10 -
import { IconSymbol } from '@/components/ui/icon-symbol';
11 -
import { Fonts } from '@/constants/theme';
12 -
import { useThemeColor } from '@/hooks/use-theme-color';
13 -
import { useAuth } from '@/context/AuthContext';
22 +
export default function Settings() {
23 +
  const { user, logout } = useAuth();
24 +
  const [allowNotifications, setAllowNotifications] = useState(false);
25 +
  const [allowWeeklyInsights, setAllowWeeklyInsights] = useState(false);
14 26

15 -
const SECTIONS = [
16 -
  {
17 -
    title: 'Geral',
18 -
    data: [{
19 -
      title: 'Perfil & Senha',
20 -
      path: '/profile'
21 -
    }]
22 -
  },
23 -
  {
24 -
    title: 'Sobre',
25 -
    data: [
27 +
  const textColor = useThemeColor({}, "text");
28 +

29 +
  const onNotificationPress = () => {};
30 +

31 +
  const handleLogout = async () => {
32 +
    Alert.alert("Sair", "Tem certeza que quer sair?", [
33 +
      { text: "Cancelar", style: "cancel" },
26 34
      {
27 -
        title: 'Sobre o aplicativo',
28 -
        path: '/about'
29 -
      },
30 -
      {
31 -
        title: 'O que acontece com seus dados?',
32 -
        path: '/data'
35 +
        text: "Sair",
36 +
        style: "destructive",
37 +
        onPress: logout,
33 38
      },
34 -
      {
35 -
        title: 'Sair',
36 -
        path: '/logout',
37 -
        logout: true
38 -
      }
39 -
    ]
40 -
  }
41 -
]
39 +
    ]);
40 +
  };
42 41

43 -
export default function Settings() {
44 -
  const { user, logout } = useAuth();
45 -
  const [options] = useState([
46 -
    { id: 'profile', name: 'Perfil', path: '/profile'}
47 -
  ])
42 +
  const handleProfilePress = () => {
43 +
    router.push("/profile");
44 +
  };
48 45

49 -
  const textColor = useThemeColor({}, 'text');
50 -
  const tintColor = useThemeColor({}, 'tint');
46 +
  const handleInvisibleMode = () => {};
51 47

52 -
  const handleLogout = async () => {
53 -
    Alert.alert(
54 -
      'Sair',
55 -
      'Tem certeza que quer sair?',
56 -
      [
57 -
        { text: 'Cancelar', style: 'cancel' },
58 -
        {
59 -
          text: 'Sair',
60 -
          style: 'destructive',
61 -
          onPress: logout
48 +
  const handleDataExport = () => {
49 +
    Alert.alert("Exportar dados", "Deseja exportar seus dados?", [
50 +
      { text: "Cancelar", style: "cancel" },
51 +
      {
52 +
        text: "Exportar",
53 +
        style: "destructive",
54 +
        onPress: () => {
55 +
          Alert.alert(
56 +
            "Exportar dados",
57 +
            "Você receberá um e-mail com os dados exportados.",
58 +
            [{ text: "OK", style: "default" }],
59 +
          );
62 60
        },
63 -
      ]
64 -
    );
61 +
      },
62 +
    ]);
65 63
  };
66 64

67 -
  const renderItem = ({item}) => {
68 -
    const itemStyle = [
69 -
      styles.item,
70 -
    ]
65 +
  return (
66 +
    <ScreenLayout
67 +
      userName={user.firstName}
68 +
      userAvatar={user.avatarURL}
69 +
      onNotificationPress={onNotificationPress}
70 +
      showNotificationBadge={true}
71 +
    >
72 +
      <Section>
73 +
        <SectionHeader title="Perfil" />
71 74

72 -
    const itemColor = { color: item.logout ? '#FF2C2C' : textColor }
75 +
        <Card style={{ padding: Spacing.cardGap }} onPress={handleProfilePress}>
76 +
          <View
77 +
            style={{
78 +
              flexDirection: "row",
79 +
              alignItems: "center",
80 +
              justifyContent: "space-between",
81 +
            }}
82 +
          >
83 +
            <View
84 +
              style={{
85 +
                flexDirection: "column",
86 +
                alignItems: "center",
87 +
                justifyContent: "space-between",
88 +
              }}
89 +
            >
90 +
              <Text style={styles.cardTitle}>Dados Pessoais</Text>
91 +
              <Text style={styles.cardSubtitle}>Nome, Email e senha</Text>
92 +
            </View>
73 93

74 -
    if (item.logout) {
75 -
      return (
76 -
        <TouchableOpacity onPress={handleLogout} style={itemStyle}>
77 -
          <Text style={itemColor}>
78 -
            Sair
79 -
          </Text>
80 -
        </TouchableOpacity>
81 -
      )
82 -
    }
94 +
            <Ionicons name="chevron-forward" size={24} color={textColor} />
95 +
          </View>
96 +
        </Card>
97 +
      </Section>
98 +

99 +
      <Section>
100 +
        <SectionHeader title="Notificações" />
101 +

102 +
        <Card style={{ padding: Spacing.cardGap }}>
103 +
          <View
104 +
            style={{
105 +
              flexDirection: "row",
106 +
              alignItems: "center",
107 +
              justifyContent: "space-between",
108 +
            }}
109 +
          >
110 +
            <View
111 +
              style={[
112 +
                styles.cardIcon,
113 +
                { backgroundColor: Colors.light.accentBlue },
114 +
              ]}
115 +
            >
116 +
              <Ionicons
117 +
                name="notifications-outline"
118 +
                size={20}
119 +
                color={Colors.light.black}
120 +
              />
121 +
            </View>
83 122

84 -
    return (
85 -
      <View>
86 -
        <Link key={item.id} href={item.path} asChild style={itemStyle}>
87 -
          <TouchableOpacity>
88 -
            <Text style={itemColor}>
89 -
              {item.title}
90 -
            </Text>
123 +
            <View
124 +
              style={{
125 +
                flexDirection: "column",
126 +
                alignItems: "flex-start",
127 +
                justifyContent: "space-between",
128 +
                marginLeft: 12,
129 +
                flex: 1,
130 +
              }}
131 +
            >
132 +
              <Text style={styles.cardTitle}>Notificações</Text>
133 +
              <Text>Diário as 20:00</Text>
134 +
            </View>
135 +

136 +
            <Switch
137 +
              onValueChange={setAllowNotifications}
138 +
              thumbColor={Colors.light.tint}
139 +
              trackColor={{
140 +
                false: Colors.light.disabled,
141 +
                true: Colors.light.gray,
142 +
              }}
143 +
              value={allowNotifications}
144 +
            />
145 +
          </View>
146 +

147 +
          <View style={styles.divider} />
148 +

149 +
          <View
150 +
            style={{
151 +
              flexDirection: "row",
152 +
              alignItems: "center",
153 +
              justifyContent: "space-between",
154 +
            }}
155 +
          >
156 +
            <View
157 +
              style={[
158 +
                styles.cardIcon,
159 +
                { backgroundColor: Colors.light.accentPurple },
160 +
              ]}
161 +
            >
162 +
              <Ionicons name="sparkles" size={20} color={Colors.light.black} />
163 +
            </View>
164 +

165 +
            <View
166 +
              style={{
167 +
                flexDirection: "column",
168 +
                alignItems: "flex-start",
169 +
                justifyContent: "space-between",
170 +
                marginLeft: 12,
171 +
                flex: 1,
172 +
              }}
173 +
            >
174 +
              <Text style={styles.cardTitle}>Indicadores semanais</Text>
175 +
              <Text>Relatórios de progressos</Text>
176 +
            </View>
177 +

178 +
            <Switch
179 +
              onValueChange={setAllowWeeklyInsights}
180 +
              value={allowWeeklyInsights}
181 +
              thumbColor={Colors.light.tint}
182 +
              trackColor={{
183 +
                false: Colors.light.disabled,
184 +
                true: Colors.light.gray,
185 +
              }}
186 +
            />
187 +
          </View>
188 +
        </Card>
189 +
      </Section>
190 +

191 +
      <Section>
192 +
        <SectionHeader title="Privacidade" />
193 +

194 +
        <Card style={{ padding: Spacing.cardGap }}>
195 +
          <TouchableOpacity
196 +
            style={{
197 +
              flexDirection: "row",
198 +
              alignItems: "center",
199 +
              justifyContent: "space-between",
200 +
            }}
201 +
            onPress={handleInvisibleMode}
202 +
          >
203 +
            <View style={{ flexDirection: "row", alignItems: "center" }}>
204 +
              <MaterialIcons
205 +
                name="lock"
206 +
                size={24}
207 +
                color={Colors.light.textSecondary}
208 +
              />
209 +

210 +
              <Text
211 +
                style={{
212 +
                  marginLeft: 8,
213 +
                  color: Colors.light.text,
214 +
                  fontSize: 14,
215 +
                  fontWeight: "500" as const,
216 +
                }}
217 +
              >
218 +
                Modo Invisível
219 +
              </Text>
220 +
            </View>
221 +

222 +
            <Ionicons name="chevron-forward" size={24} color={textColor} />
91 223
          </TouchableOpacity>
92 -
        </Link>
93 -
      </View>
94 -
    )
95 -
  }
96 224

97 -
  return (
98 -
    <SafeAreaProvider>
99 -
      <SafeAreaView style={styles.container} edges={['top']}>
100 -
        <StatusBar style="dark" />
101 -
        <SectionList
102 -
          sections={SECTIONS}
103 -
          keyExtractor={(item, index) => item.title + index}
104 -
          renderItem={renderItem}
105 -
          renderSectionHeader={({section: {title}}) => (
106 -
            <ThemedText style={styles.header}>{title}</ThemedText>
107 -
          )} />
108 -
      </SafeAreaView>
109 -
    </SafeAreaProvider>
110 -
  )
225 +
          <View style={styles.divider} />
226 +

227 +
          <TouchableOpacity
228 +
            style={{
229 +
              flexDirection: "row",
230 +
              alignItems: "center",
231 +
              justifyContent: "space-between",
232 +
            }}
233 +
            onPress={handleDataExport}
234 +
          >
235 +
            <View style={{ flexDirection: "row", alignItems: "center" }}>
236 +
              <MaterialIcons
237 +
                name="storage"
238 +
                size={24}
239 +
                color={Colors.light.textSecondary}
240 +
              />
241 +

242 +
              <Text
243 +
                style={{
244 +
                  marginLeft: 8,
245 +
                  color: Colors.light.text,
246 +
                  fontSize: 14,
247 +
                  fontWeight: "500" as const,
248 +
                }}
249 +
              >
250 +
                Exportar Meus Dados
251 +
              </Text>
252 +
            </View>
253 +

254 +
            <MaterialIcons
255 +
              name="file-download"
256 +
              size={24}
257 +
              color={Colors.light.textSecondary}
258 +
            />
259 +
          </TouchableOpacity>
260 +
        </Card>
261 +
      </Section>
262 +

263 +
      <Button
264 +
        title="Sair da Conta"
265 +
        onPress={handleLogout}
266 +
        variant="outline"
267 +
        style={{ borderColor: Colors.light.danger }}
268 +
        textStyle={{ color: Colors.light.danger }}
269 +
      />
270 +
    </ScreenLayout>
271 +
  );
111 272
}
112 273

113 274
const styles = StyleSheet.create({
114 275
  container: {
115 276
    flex: 1,
116 277
    marginHorizontal: 16,
117 -
    paddingTop: 10
278 +
    paddingTop: 10,
118 279
  },
119 280
  item: {
120 281
    paddingTop: 20,
121 282
    paddingBottom: 20,
122 283
  },
123 284
  header: {
124 285
    fontSize: 22,
125 -
    fontWeight: 'bold'
286 +
    fontWeight: "bold",
287 +
  },
288 +
  cardIcon: {
289 +
    paddingVertical: 15,
290 +
    paddingHorizontal: 14,
291 +
    width: 48,
292 +
    borderRadius: BorderRadius.md,
293 +
  },
294 +
  cardTitle: {
295 +
    fontSize: 16,
296 +
    fontWeight: "bold",
297 +
  },
298 +
  cardSubtitle: {
299 +
    fontSize: 12,
300 +
    color: Colors.light.textSecondary,
126 301
  },
127 302
  logout: {
128 -
    textColor: '#FF2C2C'
129 -
  }
303 +
    color: "#FF2C2C",
304 +
  },
305 +
  divider: {
306 +
    height: StyleSheet.hairlineWidth,
307 +
    backgroundColor: "#D1D5DB",
308 +
    marginVertical: 16,
309 +
  },
130 310
});