diff options
| author | Lucas Faria Mendes <lucas.fariamo08@gmail.com> | 2026-08-14 18:06:35 +0000 |
|---|---|---|
| committer | Lucas Faria Mendes <lucas.fariamo08@gmail.com> | 2026-08-14 18:06:35 +0000 |
| commit | 2c2dfba45357bbd205a59145ae55a2779c911ae0 (patch) | |
| tree | 0736b848aed56ec2da3c2489c49da0519447703d /src/app/(app) | |
| download | yaba-2c2dfba45357bbd205a59145ae55a2779c911ae0.tar.gz yaba-2c2dfba45357bbd205a59145ae55a2779c911ae0.zip | |
remake
Signed-off-by: Lucas Faria Mendes <lucas.fariamo08@gmail.com>
Diffstat (limited to 'src/app/(app)')
| -rw-r--r-- | src/app/(app)/(tabs)/_layout.tsx | 169 | ||||
| -rw-r--r-- | src/app/(app)/(tabs)/expenses.tsx | 2 | ||||
| -rw-r--r-- | src/app/(app)/(tabs)/index.tsx | 2 | ||||
| -rw-r--r-- | src/app/(app)/(tabs)/recurring.tsx | 2 | ||||
| -rw-r--r-- | src/app/(app)/(tabs)/salary.tsx | 2 | ||||
| -rw-r--r-- | src/app/(app)/_layout.tsx | 21 |
6 files changed, 198 insertions, 0 deletions
diff --git a/src/app/(app)/(tabs)/_layout.tsx b/src/app/(app)/(tabs)/_layout.tsx new file mode 100644 index 0000000..5033232 --- /dev/null +++ b/src/app/(app)/(tabs)/_layout.tsx @@ -0,0 +1,169 @@ +import React from 'react'; +import { Platform, StyleSheet, TouchableOpacity, View } from 'react-native'; +import { Tabs } from 'expo-router'; +import { BlurView } from 'expo-blur'; +import { Feather } from '@expo/vector-icons'; +import Animated, { + useAnimatedStyle, + withSpring, + withTiming, +} from 'react-native-reanimated'; +import * as Haptics from 'expo-haptics'; +import { Colors, Spacing } from '@/constants/theme'; + +function TabBarIcon({ + name, + isFocused, +}: { + name: keyof typeof Feather.glyphMap; + isFocused: boolean; +}) { + const animatedIconStyle = useAnimatedStyle(() => { + return { + transform: [ + { scale: withSpring(isFocused ? 1.15 : 1, { damping: 12, stiffness: 300 }) }, + ], + }; + }); + + const animatedIndicatorStyle = useAnimatedStyle(() => { + return { + opacity: withTiming(isFocused ? 1 : 0, { duration: 200 }), + transform: [ + { scale: withSpring(isFocused ? 1 : 0.5, { damping: 15, stiffness: 300 }) }, + ], + }; + }); + + return ( + <View style={styles.iconContainer}> + <Animated.View style={animatedIconStyle}> + <Feather + name={name} + size={22} + color={isFocused ? Colors.primaryLight : Colors.textMuted} + /> + </Animated.View> + <Animated.View style={[styles.indicator, animatedIndicatorStyle]} /> + </View> + ); +} + +function CustomTabBar({ state, descriptors, navigation }: any) { + return ( + <View style={styles.tabBarContainer}> + <BlurView + intensity={Platform.OS === 'ios' ? 80 : 100} + tint="dark" + style={styles.blurView} + > + {state.routes.map((route: any, index: number) => { + const { options } = descriptors[route.key]; + const isFocused = state.index === index; + + const onPress = () => { + const event = navigation.emit({ + type: 'tabPress', + target: route.key, + canPreventDefault: true, + }); + + if (!isFocused && !event.defaultPrevented) { + Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light); + navigation.navigate(route.name); + } + }; + + let iconName: keyof typeof Feather.glyphMap = 'home'; + if (route.name === 'index') iconName = 'pie-chart'; + else if (route.name === 'salary') iconName = 'dollar-sign'; + else if (route.name === 'recurring') iconName = 'repeat'; + else if (route.name === 'expenses') iconName = 'plus-square'; + + return ( + <TouchableOpacity + key={route.key} + accessibilityRole="button" + accessibilityState={isFocused ? { selected: true } : {}} + accessibilityLabel={options.tabBarAccessibilityLabel} + onPress={onPress} + style={styles.tabItem} + activeOpacity={1} + > + <TabBarIcon name={iconName} isFocused={isFocused} /> + </TouchableOpacity> + ); + })} + </BlurView> + </View> + ); +} + +export default function TabsLayout() { + return ( + <Tabs + tabBar={(props) => <CustomTabBar {...props} />} + screenOptions={{ + headerShown: false, + }} + > + <Tabs.Screen name="index" options={{ title: 'Dashboard' }} /> + <Tabs.Screen name="salary" options={{ title: 'Salário' }} /> + <Tabs.Screen name="recurring" options={{ title: 'Gastos Fixos' }} /> + <Tabs.Screen name="expenses" options={{ title: 'Gastos do Mês' }} /> + </Tabs> + ); +} + +const styles = StyleSheet.create({ + tabBarContainer: { + position: 'absolute', + bottom: Platform.OS === 'ios' ? 30 : 20, + left: 24, + right: 24, + borderRadius: 32, + ...Platform.select({ + ios: { + shadowColor: '#000', + shadowOffset: { width: 0, height: 8 }, + shadowOpacity: 0.5, + shadowRadius: 16, + }, + android: { + elevation: 10, + }, + }), + }, + blurView: { + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'space-around', + borderRadius: 32, + backgroundColor: 'rgba(22, 27, 34, 0.75)', + borderWidth: 1, + borderColor: 'rgba(255, 255, 255, 0.08)', + overflow: 'hidden', + height: 64, + paddingHorizontal: Spacing.sm, + }, + tabItem: { + flex: 1, + alignItems: 'center', + justifyContent: 'center', + height: '100%', + }, + iconContainer: { + alignItems: 'center', + justifyContent: 'center', + width: 44, + height: 44, + }, + indicator: { + position: 'absolute', + bottom: -2, + width: 4, + height: 4, + borderRadius: 2, + backgroundColor: Colors.primaryLight, + }, +}); diff --git a/src/app/(app)/(tabs)/expenses.tsx b/src/app/(app)/(tabs)/expenses.tsx new file mode 100644 index 0000000..c313dc6 --- /dev/null +++ b/src/app/(app)/(tabs)/expenses.tsx @@ -0,0 +1,2 @@ +import OneTimeExpensesScreen from '@/screens/one-time-expenses-screen'; +export default OneTimeExpensesScreen; diff --git a/src/app/(app)/(tabs)/index.tsx b/src/app/(app)/(tabs)/index.tsx new file mode 100644 index 0000000..73bede0 --- /dev/null +++ b/src/app/(app)/(tabs)/index.tsx @@ -0,0 +1,2 @@ +import DashboardScreen from '@/screens/dashboard-screen'; +export default DashboardScreen; diff --git a/src/app/(app)/(tabs)/recurring.tsx b/src/app/(app)/(tabs)/recurring.tsx new file mode 100644 index 0000000..c5340ed --- /dev/null +++ b/src/app/(app)/(tabs)/recurring.tsx @@ -0,0 +1,2 @@ +import RecurringExpensesScreen from '@/screens/recurring-expenses-screen'; +export default RecurringExpensesScreen; diff --git a/src/app/(app)/(tabs)/salary.tsx b/src/app/(app)/(tabs)/salary.tsx new file mode 100644 index 0000000..1d30bb1 --- /dev/null +++ b/src/app/(app)/(tabs)/salary.tsx @@ -0,0 +1,2 @@ +import SalaryScreen from '@/screens/salary-screen'; +export default SalaryScreen; diff --git a/src/app/(app)/_layout.tsx b/src/app/(app)/_layout.tsx new file mode 100644 index 0000000..6099274 --- /dev/null +++ b/src/app/(app)/_layout.tsx @@ -0,0 +1,21 @@ +import { Colors } from "@/constants/theme"; +import { useAuth } from "@/contexts/AuthContext"; +import { Redirect, Slot } from "expo-router"; +import { ActivityIndicator, View } from "react-native"; + +export default function AppLayout() { + const { user, isLoading } = useAuth(); + + if (isLoading) { + return ( + <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: Colors.background }}> + <ActivityIndicator size="large" color={Colors.primary} /> + </View> + ); + } + + if (!user) + return <Redirect href="/login" />; + + return <Slot />; +}
\ No newline at end of file |