aboutsummaryrefslogtreecommitdiff
path: root/src/screens/salary-screen.tsx
diff options
context:
space:
mode:
authorLucas Faria Mendes <lucas.fariamo08@gmail.com>2026-08-14 18:06:35 +0000
committerLucas Faria Mendes <lucas.fariamo08@gmail.com>2026-08-14 18:06:35 +0000
commit2c2dfba45357bbd205a59145ae55a2779c911ae0 (patch)
tree0736b848aed56ec2da3c2489c49da0519447703d /src/screens/salary-screen.tsx
downloadyaba-2c2dfba45357bbd205a59145ae55a2779c911ae0.tar.gz
yaba-2c2dfba45357bbd205a59145ae55a2779c911ae0.zip
remake
Signed-off-by: Lucas Faria Mendes <lucas.fariamo08@gmail.com>
Diffstat (limited to 'src/screens/salary-screen.tsx')
-rw-r--r--src/screens/salary-screen.tsx232
1 files changed, 232 insertions, 0 deletions
diff --git a/src/screens/salary-screen.tsx b/src/screens/salary-screen.tsx
new file mode 100644
index 0000000..6847c4b
--- /dev/null
+++ b/src/screens/salary-screen.tsx
@@ -0,0 +1,232 @@
+import { useState } from 'react';
+import {
+ Alert,
+ ScrollView,
+ StyleSheet,
+ Text,
+ View,
+} from 'react-native';
+import Animated, { FadeInDown, LinearTransition } from 'react-native-reanimated';
+import { useSafeAreaInsets } from 'react-native-safe-area-context';
+import * as Haptics from 'expo-haptics';
+import { Button } from '@/components/ui/button';
+import { Input } from '@/components/ui/input';
+import { Card, Divider, SectionLabel } from '@/components/ui/primitives';
+import { useSalaryCalculator } from '@/hooks/use-app-hooks';
+import { Colors, Spacing, Typography } from '@/constants/theme';
+import { formatCurrency } from '@/utils/tax-calculator';
+import { updateUserSalary } from '@/services/api';
+import { useAuth } from '@/contexts/AuthContext';
+import { useIsFocused } from "expo-router/react-navigation";
+
+export default function SalaryScreen() {
+ const insets = useSafeAreaInsets();
+ const { user, updateUser } = useAuth();
+ const isFocused = useIsFocused();
+
+ const [grossStr, setGrossStr] = useState(user?.gross_salary ? String(user.gross_salary) : '');
+ const [netOverrideStr, setNetOverrideStr] = useState(
+ user?.net_salary_override ? String(user.net_salary_override) : ''
+ );
+ const [isOverriding, setIsOverriding] = useState(!!user?.net_salary_override);
+
+ const result = useSalaryCalculator(grossStr);
+
+ const effectiveNet = isOverriding
+ ? parseFloat(netOverrideStr.replace(',', '.')) || 0
+ : (result?.salarioLiquidoCalculado ?? 0);
+
+ const [isSaving, setIsSaving] = useState(false);
+ const [saved, setSaved] = useState(false);
+
+ async function handleSave() {
+ if (!result || !user) return;
+ try {
+ setIsSaving(true);
+ setSaved(false);
+ const updatedUser = await updateUserSalary(user.id, {
+ gross_salary: result.salarioBruto,
+ net_salary_override: isOverriding ? effectiveNet : null,
+ });
+ await updateUser(updatedUser);
+ Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success);
+ setSaved(true);
+ setTimeout(() => setSaved(false), 2500);
+ } catch (err) {
+ Alert.alert('Erro', 'Não foi possível salvar o salário.');
+ } finally {
+ setIsSaving(false);
+ }
+ }
+
+ function handleToggleOverride() {
+ if (isOverriding) {
+ setNetOverrideStr('');
+ setIsOverriding(false);
+ } else {
+ setNetOverrideStr(result?.salarioLiquidoCalculado.toFixed(2) ?? '');
+ setIsOverriding(true);
+ }
+ }
+
+ return (
+ <View style={[styles.container, { paddingTop: insets.top }]}>
+ {isFocused && (
+ <ScrollView
+ contentContainerStyle={[
+ styles.scroll,
+ { paddingBottom: insets.bottom + Spacing.xxl },
+ ]}
+ keyboardShouldPersistTaps="handled"
+ showsVerticalScrollIndicator={false}
+ >
+ <Animated.View entering={FadeInDown.duration(400)}>
+ <Text style={styles.title}>Meu Salário</Text>
+ <Text style={styles.subtitle}>
+ Informe seu salário bruto e ajuste o líquido se necessário.
+ </Text>
+ </Animated.View>
+
+ <Animated.View entering={FadeInDown.delay(100).duration(400)}>
+ <Input
+ id="salary-gross-input"
+ label="Salário Bruto"
+ prefix="R$"
+ value={grossStr}
+ onChangeText={setGrossStr}
+ keyboardType="decimal-pad"
+ placeholder="0,00"
+ hint="Valor antes dos descontos (INSS, IRRF)"
+ />
+ </Animated.View>
+
+ {result && (
+ <Animated.View entering={FadeInDown.delay(150).duration(400)} layout={LinearTransition.springify()}>
+ <Card style={styles.resultCard}>
+ <SectionLabel text="Cálculo Automático" />
+
+ <View style={styles.resultRow}>
+ <Text style={styles.resultLabel}>Salário Bruto</Text>
+ <Text style={[styles.resultValue, { color: Colors.textPrimary }]}>
+ {formatCurrency(result.salarioBruto)}
+ </Text>
+ </View>
+
+ <View style={styles.resultRow}>
+ <Text style={styles.resultLabel}>Desconto INSS</Text>
+ <Text style={[styles.resultValue, { color: Colors.negative }]}>
+ - {formatCurrency(result.descontoINSS)}
+ </Text>
+ </View>
+
+ <View style={styles.resultRow}>
+ <Text style={styles.resultLabel}>Desconto IRRF</Text>
+ <Text style={[styles.resultValue, { color: Colors.negative }]}>
+ - {formatCurrency(result.descontoIRRF)}
+ </Text>
+ </View>
+
+ <Divider />
+
+ <View style={styles.resultRow}>
+ <Text style={[styles.resultLabel, { color: Colors.textPrimary }]}>
+ Salário Líquido
+ </Text>
+ <Text style={[styles.resultValue, { color: Colors.positive }]}>
+ {formatCurrency(result.salarioLiquidoCalculado)}
+ </Text>
+ </View>
+ </Card>
+ </Animated.View>
+ )}
+
+ {result && (
+ <Animated.View
+ entering={FadeInDown.delay(200).duration(400)}
+ layout={LinearTransition.springify()}
+ style={styles.overrideSection}
+ >
+ <Button
+ label={
+ isOverriding
+ ? 'Usar valor calculado'
+ : 'Tenho outros descontos (ajustar manualmente)'
+ }
+ variant="ghost"
+ onPress={handleToggleOverride}
+ />
+
+ {isOverriding && (
+ <Animated.View entering={FadeInDown.duration(300)}>
+ <Input
+ id="salary-net-override-input"
+ label="Salário Líquido Real"
+ prefix="R$"
+ value={netOverrideStr}
+ onChangeText={setNetOverrideStr}
+ keyboardType="decimal-pad"
+ placeholder="0,00"
+ hint="Descontos extras: plano de saúde, VT, previdência privada, etc."
+ />
+ </Animated.View>
+ )}
+ </Animated.View>
+ )}
+
+ {result && (
+ <Animated.View entering={FadeInDown.delay(300).duration(400)} layout={LinearTransition.springify()}>
+ <Button
+ id="salary-save-button"
+ label={saved ? 'Salvo com sucesso! ✓' : 'Salvar Salário'}
+ fullWidth
+ onPress={handleSave}
+ disabled={!result || isSaving || saved}
+ loading={isSaving}
+ style={saved ? { backgroundColor: Colors.positive } : undefined}
+ />
+ </Animated.View>
+ )}
+ </ScrollView>
+ )}
+ </View>
+ );
+}
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ backgroundColor: Colors.background,
+ },
+ scroll: {
+ padding: Spacing.md,
+ gap: Spacing.lg,
+ },
+ title: {
+ ...Typography.h1,
+ color: Colors.textPrimary,
+ marginBottom: Spacing.xs,
+ },
+ subtitle: {
+ ...Typography.body,
+ color: Colors.textSecondary,
+ },
+ resultCard: {
+ gap: Spacing.sm,
+ },
+ resultRow: {
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ alignItems: 'center',
+ },
+ resultLabel: {
+ ...Typography.body,
+ color: Colors.textSecondary,
+ },
+ resultValue: {
+ ...Typography.body,
+ fontFamily: 'DMSans_600SemiBold',
+ },
+ overrideSection: {
+ gap: Spacing.md,
+ },
+});