diff --git a/app/(tabs)/_layout.tsx b/app/(tabs)/_layout.tsx index 54e11d0..f3c9aa7 100644 --- a/app/(tabs)/_layout.tsx +++ b/app/(tabs)/_layout.tsx @@ -1,35 +1,49 @@ -import { Tabs } from 'expo-router'; -import React from 'react'; - -import { HapticTab } from '@/components/haptic-tab'; -import { IconSymbol } from '@/components/ui/icon-symbol'; -import { Colors } from '@/constants/theme'; -import { useColorScheme } from '@/hooks/use-color-scheme'; +import { Tabs } from "expo-router"; +import { Ionicons } from "@expo/vector-icons"; export default function TabLayout() { - const colorScheme = useColorScheme(); - return ( + tabBarActiveTintColor: "#2563EB", + tabBarInactiveTintColor: "#9CA3AF", + tabBarStyle: { + height: 65, + paddingBottom: 8, + paddingTop: 8, + }, + }} + > , + title: "Home", + tabBarIcon: ({ color, size }) => ( + + ), }} /> + , + title: "History", + tabBarIcon: ({ color, size }) => ( + + ), + }} + /> + + ( + + ), }} /> ); -} +} \ No newline at end of file diff --git a/app/(tabs)/explore.tsx b/app/(tabs)/explore.tsx deleted file mode 100644 index 71518f9..0000000 --- a/app/(tabs)/explore.tsx +++ /dev/null @@ -1,112 +0,0 @@ -import { Image } from 'expo-image'; -import { Platform, StyleSheet } from 'react-native'; - -import { Collapsible } from '@/components/ui/collapsible'; -import { ExternalLink } from '@/components/external-link'; -import ParallaxScrollView from '@/components/parallax-scroll-view'; -import { ThemedText } from '@/components/themed-text'; -import { ThemedView } from '@/components/themed-view'; -import { IconSymbol } from '@/components/ui/icon-symbol'; -import { Fonts } from '@/constants/theme'; - -export default function TabTwoScreen() { - return ( - - }> - - - Explore - - - This app includes example code to help you get started. - - - This app has two screens:{' '} - app/(tabs)/index.tsx and{' '} - app/(tabs)/explore.tsx - - - The layout file in app/(tabs)/_layout.tsx{' '} - sets up the tab navigator. - - - Learn more - - - - - You can open this project on Android, iOS, and the web. To open the web version, press{' '} - w in the terminal running this project. - - - - - For static images, you can use the @2x and{' '} - @3x suffixes to provide files for - different screen densities - - - - Learn more - - - - - This template has light and dark mode support. The{' '} - useColorScheme() hook lets you inspect - what the user's current color scheme is, and so you can adjust UI colors accordingly. - - - Learn more - - - - - This template includes an example of an animated component. The{' '} - components/HelloWave.tsx component uses - the powerful{' '} - - react-native-reanimated - {' '} - library to create a waving hand animation. - - {Platform.select({ - ios: ( - - The components/ParallaxScrollView.tsx{' '} - component provides a parallax effect for the header image. - - ), - })} - - - ); -} - -const styles = StyleSheet.create({ - headerImage: { - color: '#808080', - bottom: -90, - left: -35, - position: 'absolute', - }, - titleContainer: { - flexDirection: 'row', - gap: 8, - }, -}); diff --git a/app/(tabs)/history.tsx b/app/(tabs)/history.tsx new file mode 100644 index 0000000..07d2bda --- /dev/null +++ b/app/(tabs)/history.tsx @@ -0,0 +1,166 @@ +import { View, Text, StyleSheet, ScrollView } from "react-native"; +import { Ionicons } from "@expo/vector-icons"; + +export default function HistoryScreen() { + const transactions = [ + { + id: 1, + title: "Gaji Bulanan", + amount: "Rp 5.000.000", + type: "income", + date: "12 April 2026", + icon: "wallet", + }, + { + id: 2, + title: "Makan Siang", + amount: "Rp 50.000", + type: "expense", + date: "13 April 2026", + icon: "restaurant", + }, + { + id: 3, + title: "Transport", + amount: "Rp 20.000", + type: "expense", + date: "14 April 2026", + icon: "car", + }, + { + id: 4, + title: "Freelance Project", + amount: "Rp 1.500.000", + type: "income", + date: "15 April 2026", + icon: "briefcase", + }, + ]; + + return ( + + Riwayat Transaksi + + Semua pemasukan dan pengeluaran kamu + + + {transactions.map((item) => ( + + + + + + + + {item.title} + {item.date} + + + + + {item.type === "income" ? "+" : "-"} {item.amount} + + + ))} + + ); +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + backgroundColor: "#F5F7FA", + padding: 20, + paddingTop: 55, + }, + + title: { + fontSize: 30, + fontWeight: "bold", + marginBottom: 6, + }, + + subtitle: { + fontSize: 15, + color: "#666", + marginBottom: 28, + }, + + card: { + backgroundColor: "#FFFFFF", + borderRadius: 18, + padding: 18, + marginBottom: 16, + flexDirection: "row", + justifyContent: "space-between", + alignItems: "center", + shadowColor: "#000", + shadowOpacity: 0.05, + shadowRadius: 6, + elevation: 3, + }, + + leftSection: { + flexDirection: "row", + alignItems: "center", + gap: 14, + }, + + iconContainer: { + width: 48, + height: 48, + borderRadius: 14, + justifyContent: "center", + alignItems: "center", + }, + + incomeBg: { + backgroundColor: "#DCFCE7", + }, + + expenseBg: { + backgroundColor: "#FEE2E2", + }, + + transactionTitle: { + fontSize: 16, + fontWeight: "600", + marginBottom: 4, + }, + + transactionDate: { + fontSize: 13, + color: "#777", + }, + + amount: { + fontSize: 15, + fontWeight: "700", + }, + + incomeText: { + color: "#16A34A", + }, + + expenseText: { + color: "#DC2626", + }, +}); \ No newline at end of file diff --git a/app/(tabs)/index.tsx b/app/(tabs)/index.tsx index 786b736..d13641e 100644 --- a/app/(tabs)/index.tsx +++ b/app/(tabs)/index.tsx @@ -1,98 +1,136 @@ -import { Image } from 'expo-image'; -import { Platform, StyleSheet } from 'react-native'; - -import { HelloWave } from '@/components/hello-wave'; -import ParallaxScrollView from '@/components/parallax-scroll-view'; -import { ThemedText } from '@/components/themed-text'; -import { ThemedView } from '@/components/themed-view'; -import { Link } from 'expo-router'; +import { View, Text, StyleSheet, TouchableOpacity } from "react-native"; +import { router } from "expo-router"; +import { Ionicons } from "@expo/vector-icons"; export default function HomeScreen() { return ( - - }> - - Welcome! - - - - Step 1: Try it - - Edit app/(tabs)/index.tsx to see changes. - Press{' '} - - {Platform.select({ - ios: 'cmd + d', - android: 'cmd + m', - web: 'F12', - })} - {' '} - to open developer tools. - - - - - - Step 2: Explore - - - - alert('Action pressed')} /> - alert('Share pressed')} - /> - - alert('Delete pressed')} - /> - - - + + Tabungan H.Hadi + Kelola pemasukan & pengeluaranmu untuk nikah - - {`Tap the Explore tab to learn more about what's included in this starter app.`} - - - - Step 3: Get a fresh start - - {`When you're ready, run `} - npm run reset-project to get a fresh{' '} - app directory. This will move the current{' '} - app to{' '} - app-example. - - - + + Total Saldo + Rp 500.000.000.000 + + + + + + Income + Rp 7.000.000 + + + + + Expense + Rp 2.000.000 + + + + router.push("/add-income")} + > + + Tambah Pemasukan + + + router.push("/add-expense")} + > + - Tambah Pengeluaran + + ); } const styles = StyleSheet.create({ - titleContainer: { - flexDirection: 'row', - alignItems: 'center', - gap: 8, + container: { + flex: 1, + backgroundColor: "#F5F7FA", + padding: 24, + paddingTop: 60, }, - stepContainer: { - gap: 8, + + title: { + fontSize: 30, + fontWeight: "bold", marginBottom: 8, }, - reactLogo: { - height: 178, - width: 290, - bottom: 0, - left: 0, - position: 'absolute', + + subtitle: { + fontSize: 16, + color: "#666", + marginBottom: 28, }, -}); + + balanceCard: { + backgroundColor: "#2563EB", + borderRadius: 20, + padding: 24, + marginBottom: 24, + }, + + balanceLabel: { + color: "#E0E7FF", + fontSize: 16, + marginBottom: 8, + }, + + balanceAmount: { + color: "#FFFFFF", + fontSize: 32, + fontWeight: "bold", + }, + + summaryContainer: { + flexDirection: "row", + justifyContent: "space-between", + marginBottom: 32, + }, + + summaryCard: { + backgroundColor: "#FFFFFF", + width: "48%", + padding: 20, + borderRadius: 16, + alignItems: "center", + shadowColor: "#000", + shadowOpacity: 0.05, + shadowRadius: 6, + elevation: 3, + }, + + summaryTitle: { + marginTop: 10, + fontSize: 15, + color: "#666", + }, + + summaryAmount: { + marginTop: 6, + fontSize: 16, + fontWeight: "600", + }, + + buttonIncome: { + backgroundColor: "#16A34A", + paddingVertical: 16, + borderRadius: 14, + alignItems: "center", + marginBottom: 16, + }, + + buttonExpense: { + backgroundColor: "#DC2626", + paddingVertical: 16, + borderRadius: 14, + alignItems: "center", + }, + + buttonText: { + color: "#FFFFFF", + fontSize: 16, + fontWeight: "600", + }, +}); \ No newline at end of file diff --git a/app/(tabs)/profile.tsx b/app/(tabs)/profile.tsx new file mode 100644 index 0000000..2b7f685 --- /dev/null +++ b/app/(tabs)/profile.tsx @@ -0,0 +1,137 @@ +import { View, Text, StyleSheet, TouchableOpacity } from "react-native"; +import { Ionicons } from "@expo/vector-icons"; + +export default function ProfileScreen() { + return ( + + {/* Header */} + Profile + Informasi pengguna aplikasi + + {/* Profile Card */} + + + + + + Fahrul + fahrul@email.com + + + {/* Info Card */} + + + + Aplikasi: Hitung Duit + + + + + Versi: 1.0.0 + + + + + Project Tugas Mobile Programming + + + + {/* Logout Button */} + + + Logout + + + ); +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + backgroundColor: "#F5F7FA", + padding: 24, + paddingTop: 60, + }, + + title: { + fontSize: 30, + fontWeight: "bold", + marginBottom: 6, + }, + + subtitle: { + fontSize: 15, + color: "#666", + marginBottom: 28, + }, + + profileCard: { + backgroundColor: "#2563EB", + borderRadius: 20, + padding: 28, + alignItems: "center", + marginBottom: 24, + }, + + avatar: { + width: 80, + height: 80, + borderRadius: 40, + backgroundColor: "rgba(255,255,255,0.25)", + justifyContent: "center", + alignItems: "center", + marginBottom: 16, + }, + + name: { + fontSize: 24, + fontWeight: "bold", + color: "#FFFFFF", + marginBottom: 6, + }, + + email: { + fontSize: 14, + color: "#DBEAFE", + }, + + infoCard: { + backgroundColor: "#FFFFFF", + borderRadius: 18, + padding: 20, + marginBottom: 28, + shadowColor: "#000", + shadowOpacity: 0.05, + shadowRadius: 6, + elevation: 3, + }, + + infoRow: { + flexDirection: "row", + alignItems: "center", + gap: 12, + marginBottom: 18, + }, + + infoText: { + fontSize: 15, + color: "#333", + flex: 1, + }, + + logoutButton: { + backgroundColor: "#DC2626", + paddingVertical: 16, + borderRadius: 14, + flexDirection: "row", + justifyContent: "center", + alignItems: "center", + gap: 10, + }, + + logoutText: { + color: "#FFFFFF", + fontSize: 16, + fontWeight: "600", + }, +}); \ No newline at end of file diff --git a/app/_layout.tsx b/app/_layout.tsx index f518c9b..0a6866d 100644 --- a/app/_layout.tsx +++ b/app/_layout.tsx @@ -1,24 +1,16 @@ -import { DarkTheme, DefaultTheme, ThemeProvider } from '@react-navigation/native'; -import { Stack } from 'expo-router'; -import { StatusBar } from 'expo-status-bar'; -import 'react-native-reanimated'; - -import { useColorScheme } from '@/hooks/use-color-scheme'; - -export const unstable_settings = { - anchor: '(tabs)', -}; +import { Stack } from "expo-router"; +import { StatusBar } from "expo-status-bar"; export default function RootLayout() { - const colorScheme = useColorScheme(); - return ( - - - - + <> + + + + + - + ); -} +} \ No newline at end of file diff --git a/app/add-expense.tsx b/app/add-expense.tsx new file mode 100644 index 0000000..08b373b --- /dev/null +++ b/app/add-expense.tsx @@ -0,0 +1,97 @@ +import { useState } from "react"; +import { + View, + Text, + TextInput, + StyleSheet, + TouchableOpacity, +} from "react-native"; +import { router } from "expo-router"; + +export default function AddExpenseScreen() { + const [amount, setAmount] = useState(""); + + const formatRupiah = (value: string) => { + const numberString = value.replace(/[^,\d]/g, ""); + const split = numberString.split(","); + const sisa = split[0].length % 3; + + let rupiah = split[0].substring(0, sisa); + const ribuan = split[0].substring(sisa).match(/\d{3}/gi); + + if (ribuan) { + const separator = sisa ? "." : ""; + rupiah += separator + ribuan.join("."); + } + + return rupiah ? `Rp ${rupiah}` : ""; + }; + + const handleAmountChange = (value: string) => { + setAmount(formatRupiah(value)); + }; + + return ( + + Tambah Pengeluaran + + + + + + router.back()} + > + Simpan + + + ); +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + padding: 24, + backgroundColor: "#fff", + justifyContent: "center", + }, + + title: { + fontSize: 28, + fontWeight: "bold", + marginBottom: 24, + textAlign: "center", + }, + + input: { + borderWidth: 1, + borderColor: "#ddd", + padding: 16, + borderRadius: 12, + marginBottom: 16, + fontSize: 16, + }, + + button: { + backgroundColor: "#DC2626", + padding: 16, + borderRadius: 12, + alignItems: "center", + }, + + buttonText: { + color: "#fff", + fontWeight: "600", + fontSize: 16, + }, +}); \ No newline at end of file diff --git a/app/add-income.tsx b/app/add-income.tsx new file mode 100644 index 0000000..b4375f1 --- /dev/null +++ b/app/add-income.tsx @@ -0,0 +1,97 @@ +import { useState } from "react"; +import { + View, + Text, + TextInput, + StyleSheet, + TouchableOpacity, +} from "react-native"; +import { router } from "expo-router"; + +export default function AddIncomeScreen() { + const [amount, setAmount] = useState(""); + + const formatRupiah = (value: string) => { + const numberString = value.replace(/[^,\d]/g, ""); + const split = numberString.split(","); + const sisa = split[0].length % 3; + + let rupiah = split[0].substring(0, sisa); + const ribuan = split[0].substring(sisa).match(/\d{3}/gi); + + if (ribuan) { + const separator = sisa ? "." : ""; + rupiah += separator + ribuan.join("."); + } + + return rupiah ? `Rp ${rupiah}` : ""; + }; + + const handleAmountChange = (value: string) => { + setAmount(formatRupiah(value)); + }; + + return ( + + Tambah Pemasukan + + + + + + router.back()} + > + Simpan + + + ); +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + padding: 24, + backgroundColor: "#fff", + justifyContent: "center", + }, + + title: { + fontSize: 28, + fontWeight: "bold", + marginBottom: 24, + textAlign: "center", + }, + + input: { + borderWidth: 1, + borderColor: "#ddd", + padding: 16, + borderRadius: 12, + marginBottom: 16, + fontSize: 16, + }, + + button: { + backgroundColor: "#16A34A", + padding: 16, + borderRadius: 12, + alignItems: "center", + }, + + buttonText: { + color: "#fff", + fontWeight: "600", + fontSize: 16, + }, +}); \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 59c8a09..3963783 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5811,6 +5811,7 @@ "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.9",