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/screens/salary-screen.tsx | |
| download | yaba-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.tsx | 232 |
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, + }, +}); |