Kantongku: hapus onboarding & splash screen (langsung ke Beranda)
This commit is contained in:
@@ -1,20 +1,16 @@
|
|||||||
import { StatusBar } from 'expo-status-bar';
|
import { StatusBar } from 'expo-status-bar';
|
||||||
import * as SplashScreen from 'expo-splash-screen';
|
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { ActivityIndicator, StyleSheet, Text, View } from 'react-native';
|
import { ActivityIndicator, StyleSheet, Text, View } from 'react-native';
|
||||||
import { SafeAreaProvider } from 'react-native-safe-area-context';
|
import { SafeAreaProvider } from 'react-native-safe-area-context';
|
||||||
import { NavigationContainer } from '@react-navigation/native';
|
import { NavigationContainer } from '@react-navigation/native';
|
||||||
import { initDatabase } from './src/db/database';
|
import { initDatabase } from './src/db/database';
|
||||||
import { checkRecurringDue, getSetting } from './src/db/repositories';
|
import { checkRecurringDue } from './src/db/repositories';
|
||||||
import { RootNavigator } from './src/navigation';
|
import { RootNavigator } from './src/navigation';
|
||||||
import { colors } from './src/theme/colors';
|
import { colors } from './src/theme/colors';
|
||||||
|
|
||||||
SplashScreen.preventAutoHideAsync().catch(() => {});
|
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
const [ready, setReady] = useState(false);
|
const [ready, setReady] = useState(false);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
const [initialRoute, setInitialRoute] = useState<'Main' | 'Onboarding'>('Onboarding');
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
initDatabase()
|
initDatabase()
|
||||||
@@ -25,10 +21,7 @@ export default function App() {
|
|||||||
} catch {
|
} catch {
|
||||||
// jangan sampai mengganggu startup
|
// jangan sampai mengganggu startup
|
||||||
}
|
}
|
||||||
const onboarded = await getSetting('onboarded');
|
|
||||||
setInitialRoute(onboarded === '1' ? 'Main' : 'Onboarding');
|
|
||||||
setReady(true);
|
setReady(true);
|
||||||
SplashScreen.hideAsync().catch(() => {});
|
|
||||||
})
|
})
|
||||||
.catch((e) => setError(String(e)));
|
.catch((e) => setError(String(e)));
|
||||||
}, []);
|
}, []);
|
||||||
@@ -54,7 +47,7 @@ export default function App() {
|
|||||||
return (
|
return (
|
||||||
<SafeAreaProvider>
|
<SafeAreaProvider>
|
||||||
<NavigationContainer>
|
<NavigationContainer>
|
||||||
<RootNavigator initialRoute={initialRoute} />
|
<RootNavigator />
|
||||||
</NavigationContainer>
|
</NavigationContainer>
|
||||||
<StatusBar style="dark" />
|
<StatusBar style="dark" />
|
||||||
</SafeAreaProvider>
|
</SafeAreaProvider>
|
||||||
|
|||||||
@@ -24,16 +24,7 @@
|
|||||||
},
|
},
|
||||||
"plugins": [
|
"plugins": [
|
||||||
"expo-sqlite",
|
"expo-sqlite",
|
||||||
"expo-sharing",
|
"expo-sharing"
|
||||||
[
|
|
||||||
"expo-splash-screen",
|
|
||||||
{
|
|
||||||
"backgroundColor": "#0D9488",
|
|
||||||
"image": "./assets/splash-logo.png",
|
|
||||||
"imageWidth": 220,
|
|
||||||
"resizeMode": "contain"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 112 KiB |
Generated
-15
@@ -18,7 +18,6 @@
|
|||||||
"expo-file-system": "~57.0.4",
|
"expo-file-system": "~57.0.4",
|
||||||
"expo-linear-gradient": "~57.0.1",
|
"expo-linear-gradient": "~57.0.1",
|
||||||
"expo-sharing": "~57.0.12",
|
"expo-sharing": "~57.0.12",
|
||||||
"expo-splash-screen": "~57.0.6",
|
|
||||||
"expo-sqlite": "~57.0.1",
|
"expo-sqlite": "~57.0.1",
|
||||||
"expo-status-bar": "~57.0.1",
|
"expo-status-bar": "~57.0.1",
|
||||||
"react": "19.2.3",
|
"react": "19.2.3",
|
||||||
@@ -3065,20 +3064,6 @@
|
|||||||
"react-native": "*"
|
"react-native": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/expo-splash-screen": {
|
|
||||||
"version": "57.0.6",
|
|
||||||
"resolved": "https://registry.npmjs.org/expo-splash-screen/-/expo-splash-screen-57.0.6.tgz",
|
|
||||||
"integrity": "sha512-FY0E7hMyXVAsNh18yGzIjdooPXdjafalEb6mk2EcqNPjXspHuu+pVEhUscEunw4wF8F/w6MOpT7UfOwHVWez9g==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@expo/config-plugins": "~57.0.7",
|
|
||||||
"@expo/image-utils": "^0.11.4",
|
|
||||||
"xml2js": "0.6.0"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"expo": "*"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/expo-sqlite": {
|
"node_modules/expo-sqlite": {
|
||||||
"version": "57.0.1",
|
"version": "57.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/expo-sqlite/-/expo-sqlite-57.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/expo-sqlite/-/expo-sqlite-57.0.1.tgz",
|
||||||
|
|||||||
@@ -13,7 +13,6 @@
|
|||||||
"expo-file-system": "~57.0.4",
|
"expo-file-system": "~57.0.4",
|
||||||
"expo-linear-gradient": "~57.0.1",
|
"expo-linear-gradient": "~57.0.1",
|
||||||
"expo-sharing": "~57.0.12",
|
"expo-sharing": "~57.0.12",
|
||||||
"expo-splash-screen": "~57.0.6",
|
|
||||||
"expo-sqlite": "~57.0.1",
|
"expo-sqlite": "~57.0.1",
|
||||||
"expo-status-bar": "~57.0.1",
|
"expo-status-bar": "~57.0.1",
|
||||||
"react": "19.2.3",
|
"react": "19.2.3",
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import { EditTransactionScreen } from '../screens/EditTransactionScreen';
|
|||||||
import { RecurringFormScreen } from '../screens/RecurringFormScreen';
|
import { RecurringFormScreen } from '../screens/RecurringFormScreen';
|
||||||
import { TargetFormScreen } from '../screens/TargetFormScreen';
|
import { TargetFormScreen } from '../screens/TargetFormScreen';
|
||||||
import { CategoryFormScreen } from '../screens/CategoryFormScreen';
|
import { CategoryFormScreen } from '../screens/CategoryFormScreen';
|
||||||
import { OnboardingScreen } from '../screens/OnboardingScreen';
|
|
||||||
import { SavingsScreen } from '../screens/SavingsScreen';
|
import { SavingsScreen } from '../screens/SavingsScreen';
|
||||||
import { SettingsScreen } from '../screens/SettingsScreen';
|
import { SettingsScreen } from '../screens/SettingsScreen';
|
||||||
import type { TransactionType } from '../types';
|
import type { TransactionType } from '../types';
|
||||||
@@ -25,7 +24,6 @@ export type RootTabParamList = {
|
|||||||
|
|
||||||
export type RootStackParamList = {
|
export type RootStackParamList = {
|
||||||
Main: undefined;
|
Main: undefined;
|
||||||
Onboarding: undefined;
|
|
||||||
EditTransaksi: { transactionId: number };
|
EditTransaksi: { transactionId: number };
|
||||||
RecurringForm: undefined;
|
RecurringForm: undefined;
|
||||||
TargetForm: undefined;
|
TargetForm: undefined;
|
||||||
@@ -134,18 +132,10 @@ function MainTabs() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function RootNavigator({
|
export function RootNavigator() {
|
||||||
initialRoute = 'Main',
|
|
||||||
}: {
|
|
||||||
initialRoute?: 'Main' | 'Onboarding';
|
|
||||||
}) {
|
|
||||||
return (
|
return (
|
||||||
<Stack.Navigator
|
<Stack.Navigator screenOptions={{ headerShown: false }}>
|
||||||
initialRouteName={initialRoute}
|
|
||||||
screenOptions={{ headerShown: false }}
|
|
||||||
>
|
|
||||||
<Stack.Screen name="Main" component={MainTabs} />
|
<Stack.Screen name="Main" component={MainTabs} />
|
||||||
<Stack.Screen name="Onboarding" component={OnboardingScreen} />
|
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
name="EditTransaksi"
|
name="EditTransaksi"
|
||||||
component={EditTransactionScreen}
|
component={EditTransactionScreen}
|
||||||
|
|||||||
@@ -1,193 +0,0 @@
|
|||||||
import { Ionicons } from '@expo/vector-icons';
|
|
||||||
import { LinearGradient } from 'expo-linear-gradient';
|
|
||||||
import { useNavigation } from '@react-navigation/native';
|
|
||||||
import type { NativeStackNavigationProp } from '@react-navigation/native-stack';
|
|
||||||
import { Image, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native';
|
|
||||||
import { SafeAreaView } from 'react-native-safe-area-context';
|
|
||||||
import { colors } from '../theme/colors';
|
|
||||||
import { setSetting } from '../db/repositories';
|
|
||||||
import type { RootStackParamList } from '../navigation';
|
|
||||||
|
|
||||||
const FEATURES = [
|
|
||||||
{
|
|
||||||
icon: 'create-outline' as const,
|
|
||||||
title: 'Catat dengan cepat',
|
|
||||||
desc: 'Pemasukan & pengeluaran, langsung terformat rupiah.',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: 'lock-closed-outline' as const,
|
|
||||||
title: 'Auto-sisih otomatis',
|
|
||||||
desc: '10% dari setiap pemasukan langsung masuk tabungan.',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: 'phone-portrait-outline' as const,
|
|
||||||
title: 'Offline & privat',
|
|
||||||
desc: 'Semua data tersimpan di HP-mu. Tanpa server, tanpa internet.',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: 'trophy-outline' as const,
|
|
||||||
title: 'Tetap semangat',
|
|
||||||
desc: 'Target, badge, dan streak yang bikin kamu terus menabung.',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
export function OnboardingScreen() {
|
|
||||||
const navigation =
|
|
||||||
useNavigation<NativeStackNavigationProp<RootStackParamList>>();
|
|
||||||
|
|
||||||
const handleStart = async () => {
|
|
||||||
await setSetting('onboarded', '1');
|
|
||||||
navigation.replace('Main');
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<SafeAreaView style={styles.safe}>
|
|
||||||
<ScrollView contentContainerStyle={styles.content}>
|
|
||||||
<LinearGradient
|
|
||||||
colors={[colors.primary, colors.primaryDark]}
|
|
||||||
start={{ x: 0, y: 0 }}
|
|
||||||
end={{ x: 1, y: 1 }}
|
|
||||||
style={styles.hero}
|
|
||||||
>
|
|
||||||
<View style={styles.ornCircleLarge} />
|
|
||||||
<View style={styles.ornCircleSmall} />
|
|
||||||
<Image
|
|
||||||
source={require('../../assets/wallet-3d-teal-logo.png')}
|
|
||||||
style={styles.logo}
|
|
||||||
resizeMode="contain"
|
|
||||||
/>
|
|
||||||
<Text style={styles.heroTitle}>Kantongku</Text>
|
|
||||||
<Text style={styles.heroSub}>
|
|
||||||
Asisten keuangan pribadi yang bikin kamu semangat menabung.
|
|
||||||
</Text>
|
|
||||||
</LinearGradient>
|
|
||||||
|
|
||||||
<View style={styles.featureList}>
|
|
||||||
{FEATURES.map((f) => (
|
|
||||||
<View key={f.title} style={styles.featureRow}>
|
|
||||||
<View style={styles.featureIcon}>
|
|
||||||
<Ionicons name={f.icon} size={20} color={colors.primaryDark} />
|
|
||||||
</View>
|
|
||||||
<View style={styles.featureInfo}>
|
|
||||||
<Text style={styles.featureTitle}>{f.title}</Text>
|
|
||||||
<Text style={styles.featureDesc}>{f.desc}</Text>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
))}
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<Pressable
|
|
||||||
style={({ pressed }) => [styles.startBtn, pressed && styles.pressed]}
|
|
||||||
onPress={handleStart}
|
|
||||||
>
|
|
||||||
<LinearGradient
|
|
||||||
colors={[colors.primary, colors.primaryDark]}
|
|
||||||
start={{ x: 0, y: 0 }}
|
|
||||||
end={{ x: 1, y: 1 }}
|
|
||||||
style={styles.startGradient}
|
|
||||||
>
|
|
||||||
<Text style={styles.startText}>Mulai Pakai Kantongku</Text>
|
|
||||||
</LinearGradient>
|
|
||||||
</Pressable>
|
|
||||||
<Text style={styles.footerNote}>
|
|
||||||
Kategori bisa diatur kapan saja di menu Pengaturan.
|
|
||||||
</Text>
|
|
||||||
</ScrollView>
|
|
||||||
</SafeAreaView>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
|
||||||
safe: { flex: 1, backgroundColor: colors.background },
|
|
||||||
content: { paddingBottom: 32 },
|
|
||||||
hero: {
|
|
||||||
marginHorizontal: 16,
|
|
||||||
marginTop: 16,
|
|
||||||
borderRadius: 24,
|
|
||||||
padding: 24,
|
|
||||||
overflow: 'hidden',
|
|
||||||
alignItems: 'center',
|
|
||||||
shadowColor: colors.primaryDark,
|
|
||||||
shadowOpacity: 0.25,
|
|
||||||
shadowRadius: 12,
|
|
||||||
shadowOffset: { width: 0, height: 6 },
|
|
||||||
elevation: 6,
|
|
||||||
},
|
|
||||||
ornCircleLarge: {
|
|
||||||
position: 'absolute',
|
|
||||||
right: -40,
|
|
||||||
top: -50,
|
|
||||||
width: 160,
|
|
||||||
height: 160,
|
|
||||||
borderRadius: 80,
|
|
||||||
backgroundColor: 'rgba(255,255,255,0.07)',
|
|
||||||
},
|
|
||||||
ornCircleSmall: {
|
|
||||||
position: 'absolute',
|
|
||||||
left: -30,
|
|
||||||
bottom: -40,
|
|
||||||
width: 110,
|
|
||||||
height: 110,
|
|
||||||
borderRadius: 55,
|
|
||||||
backgroundColor: 'rgba(255,255,255,0.06)',
|
|
||||||
},
|
|
||||||
logo: { width: 84, height: 84, marginBottom: 10 },
|
|
||||||
heroTitle: {
|
|
||||||
fontSize: 26,
|
|
||||||
fontWeight: '800',
|
|
||||||
color: colors.white,
|
|
||||||
},
|
|
||||||
heroSub: {
|
|
||||||
fontSize: 13,
|
|
||||||
color: 'rgba(255,255,255,0.9)',
|
|
||||||
textAlign: 'center',
|
|
||||||
lineHeight: 19,
|
|
||||||
marginTop: 6,
|
|
||||||
},
|
|
||||||
featureList: { marginHorizontal: 16, marginTop: 20, gap: 4 },
|
|
||||||
featureRow: {
|
|
||||||
flexDirection: 'row',
|
|
||||||
alignItems: 'center',
|
|
||||||
backgroundColor: colors.surface,
|
|
||||||
borderWidth: 1,
|
|
||||||
borderColor: colors.border,
|
|
||||||
borderRadius: 16,
|
|
||||||
padding: 14,
|
|
||||||
marginBottom: 8,
|
|
||||||
},
|
|
||||||
featureIcon: {
|
|
||||||
width: 40,
|
|
||||||
height: 40,
|
|
||||||
borderRadius: 20,
|
|
||||||
backgroundColor: colors.primarySoft,
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center',
|
|
||||||
marginRight: 12,
|
|
||||||
},
|
|
||||||
featureInfo: { flex: 1 },
|
|
||||||
featureTitle: { fontSize: 14, fontWeight: '700', color: colors.text },
|
|
||||||
featureDesc: { fontSize: 12, color: colors.textMuted, marginTop: 2, lineHeight: 17 },
|
|
||||||
startBtn: {
|
|
||||||
marginHorizontal: 16,
|
|
||||||
marginTop: 20,
|
|
||||||
borderRadius: 14,
|
|
||||||
shadowColor: colors.primaryDark,
|
|
||||||
shadowOpacity: 0.25,
|
|
||||||
shadowRadius: 8,
|
|
||||||
shadowOffset: { width: 0, height: 4 },
|
|
||||||
elevation: 4,
|
|
||||||
},
|
|
||||||
startGradient: {
|
|
||||||
borderRadius: 14,
|
|
||||||
paddingVertical: 16,
|
|
||||||
alignItems: 'center',
|
|
||||||
},
|
|
||||||
startText: { color: colors.white, fontWeight: '800', fontSize: 16 },
|
|
||||||
footerNote: {
|
|
||||||
fontSize: 11,
|
|
||||||
color: colors.textMuted,
|
|
||||||
textAlign: 'center',
|
|
||||||
marginTop: 10,
|
|
||||||
},
|
|
||||||
pressed: { opacity: 0.85 },
|
|
||||||
});
|
|
||||||
Reference in New Issue
Block a user