eletrotupi / tcc/ commit / 3f30f22

frontend: add logo to login

Pedro Lucas Porcellis porcellis@eletrotupi.com 1 month ago 3f30f227c553a8bbfa76d48b984cb7d697312d9d
Parents: 4db43b4
1 file(s) changed
  • frontend/app/auth/login.tsx +48 -1
frontend/app/auth/login.tsx
1 -
import React, { useState } from "react";
1 +
import React, { useState, useEffect, useRef } from "react";
2 2
import {
3 3
  View,
4 4
  Text,
5 5
  StyleSheet,
6 6
  ScrollView,
7 7
  KeyboardAvoidingView,
8 8
  Platform,
9 9
  Alert,
10 +
  Animated,
11 +
  Easing
10 12
} from "react-native";
11 13
import { Link, router } from "expo-router";
14 +
import { Image } from "react-native";
12 15
import { SafeAreaView } from "react-native-safe-area-context";
16 +
import { StatusBar } from "expo-status-bar";
13 17
import { useThemeColor } from "@/hooks/use-theme-color";
14 18
import { Button, Input } from "@/components/ui";
15 19
import { useAuth } from "@/context/AuthContext";
16 20
import { apiClient, User } from "@/lib/api";
17 21
import { registerForPushNotifications } from "@/hooks/useRegisterPushToken";
▸ 8 unchanged lines
26 30
  const { login, updateAuthUser, isLoading } = useAuth();
27 31
  const textColor = useThemeColor({}, "text");
28 32
  const backgroundColor = useThemeColor({}, "background");
29 33
  const tintColor = useThemeColor({}, "tint");
30 34

35 +
  const spinValue = useRef(new Animated.Value(0)).current;
36 +
  useEffect(() => {
37 +
    const animation = Animated.loop(
38 +
      Animated.timing(spinValue, {
39 +
        toValue: 1,
40 +
        duration: 12000, // 12s per full turn (slow)
41 +
        easing: Easing.linear,
42 +
        useNativeDriver: true,
43 +
      })
44 +
    );
45 +

46 +
    animation.start();
47 +

48 +
    return () => {
49 +
      animation.stop();
50 +
    };
51 +
  }, [spinValue]);
52 +

53 +
  const spin = spinValue.interpolate({
54 +
    inputRange: [0, 1],
55 +
    outputRange: ["0deg", "360deg"],
56 +
  });
57 +

31 58
  const validateForm = () => {
32 59
    const newErrors: { email?: string; password?: string } = {};
33 60

34 61
    if (!email) {
35 62
      newErrors.email = "Email é obrigatório";
▸ 39 unchanged lines
75 102
  };
76 103

77 104
  return (
78 105
    <SafeAreaView style={[styles.container, { backgroundColor }]}>
79 106
      <KeyboardAvoidingView behavior="height" style={styles.keyboardView}>
107 +
        <StatusBar style={'dark'} />
80 108
        <ScrollView
81 109
          contentContainerStyle={styles.scrollContainer}
82 110
          showsVerticalScrollIndicator={false}
83 111
        >
112 +
          <View style={styles.logoContainer}>
113 +
            <Animated.View style={{ transform: [{ rotate: spin }] }}>
114 +
              <Image
115 +
                source={require("@/assets/images/logo.png")}
116 +
                style={styles.logo}
117 +
                resizeMode="contain"
118 +
              />
119 +
            </Animated.View>
120 +
          </View>
121 +

84 122
          <View style={styles.header}>
85 123
            <Text style={[styles.title, { color: textColor }]}>
86 124
              Bem vindo de volta
87 125
            </Text>
88 126
            <Text style={[styles.subtitle, { color: textColor, opacity: 0.7 }]}>
▸ 71 unchanged lines
160 198
  container: {
161 199
    flex: 1,
162 200
  },
163 201
  keyboardView: {
164 202
    flex: 1,
203 +
  },
204 +
  logoContainer: {
205 +
    alignItems: "center",
206 +
    marginBottom: 40,
207 +
    marginTop: 10,
208 +
  },
209 +
  logo: {
210 +
    width: 120,
211 +
    height: 120,
165 212
  },
166 213
  scrollContainer: {
167 214
    flexGrow: 1,
168 215
    paddingHorizontal: 24,
169 216
    justifyContent: "center",
▸ 33 unchanged lines
203 250
  },
204 251
  footerText: {
205 252
    fontSize: 14,
206 253
  },
207 254
});