diff --git a/app/(application)/profile/[id].tsx b/app/(application)/profile/[id].tsx index 5d5f93d..0bc1a54 100644 --- a/app/(application)/profile/[id].tsx +++ b/app/(application)/profile/[id].tsx @@ -1,23 +1,27 @@ import ViewWrapper from "@/components/_ShareComponent/ViewWrapper"; -import { MainColor } from "@/constants/color-palet"; +import { AccentColor, MainColor } from "@/constants/color-palet"; import { Styles } from "@/styles/global-styles"; import { Ionicons } from "@expo/vector-icons"; import { router, Stack, useLocalSearchParams } from "expo-router"; +import React, { useRef, useState } from "react"; import { + Alert, + Animated, + PanResponder, + StyleSheet, Text, TouchableOpacity, View, - Animated, - PanResponder, } from "react-native"; -import React, { useRef, useState } from "react"; +const DRAWER_HEIGHT = 300; // tinggi drawer export default function Profile() { const { id } = useLocalSearchParams(); const [isDrawerOpen, setIsDrawerOpen] = useState(false); + const [showLogoutAlert, setShowLogoutAlert] = useState(false); // Animasi menggunakan translateY (lebih kompatibel) - const drawerAnim = useRef(new Animated.Value(200)).current; // mulai di luar bawah layar + const drawerAnim = useRef(new Animated.Value(DRAWER_HEIGHT)).current; // mulai di luar bawah layar const openDrawer = () => { setIsDrawerOpen(true); @@ -30,22 +34,31 @@ export default function Profile() { const closeDrawer = () => { Animated.timing(drawerAnim, { - toValue: 200, + toValue: DRAWER_HEIGHT, // sesuaikan dengan tinggi drawer Anda duration: 300, useNativeDriver: true, - }).start(() => setIsDrawerOpen(false)); + }).start(() => { + setIsDrawerOpen(false); // baru ganti state setelah animasi selesai + }); }; const panResponder = useRef( PanResponder.create({ onMoveShouldSetPanResponder: (_, gestureState) => { - return gestureState.dy < -10; // gesek ke atas untuk tutup + return gestureState.dy > 10; // gesek ke bawah + }, + onPanResponderMove: (_, gestureState) => { + const offset = gestureState.dy; + if (offset >= 0 && offset <= DRAWER_HEIGHT) { + drawerAnim.setValue(offset); // batasi hingga max 500 + } }, onPanResponderRelease: (_, gestureState) => { - if (gestureState.dy < -50) { - closeDrawer(); // tutup jika gesek cukup tinggi + if (gestureState.dy > 200) { + // Tutup drawer sepenuhnya jika gesek lebih dari 200 + closeDrawer(); } else { - // kembali ke posisi awal + // Reset ke posisi awal jika gesek kurang Animated.spring(drawerAnim, { toValue: 0, useNativeDriver: true, @@ -57,7 +70,7 @@ export default function Profile() { return ( <> - + Profile {id} + {/* Overlay Gelap */} + {isDrawerOpen && ( + + + + )} + {/* Custom Bottom Drawer */} {isDrawerOpen && ( { alert("Pilihan 1 diklik"); closeDrawer(); @@ -126,7 +136,7 @@ export default function Profile() { { alert("Pilihan 2 diklik"); closeDrawer(); @@ -135,11 +145,163 @@ export default function Profile() { Menu Item 2 - - Tutup + setShowLogoutAlert(true)} + > + Logout Custom + + + + Alert.alert( + "Konfirmasi Logout", + "Apakah Anda sudah yakin?", + [ + { + text: "Batal", + onPress: () => console.log("Batal logout"), + style: "cancel", + }, + { + text: "Ya", + onPress: () => { + console.log("Logout dipilih"); + // Di sini Anda bisa tambahkan fungsi logout seperti clear token, redirect, dll + closeDrawer(); + }, + }, + ], + { cancelable: true } + ) + } + > + Keluar )} + + {showLogoutAlert && ( + + + Konfirmasi Logout + Apakah Anda sudah yakin? + + setShowLogoutAlert(false)} + > + Batal + + { + console.log("Logout dipilih"); + setShowLogoutAlert(false); + closeDrawer(); + }} + > + Ya + + + + + )} ); } + +const stylesDrawer = StyleSheet.create({ + overlay: { + position: "absolute", + top: 0, + left: 0, + right: 0, + bottom: 0, + backgroundColor: "black", + opacity: 0.4, + }, + drawer: { + position: "absolute", + left: 0, + right: 0, + bottom: 0, + height: DRAWER_HEIGHT, + backgroundColor: AccentColor.darkblue, + borderTopLeftRadius: 20, + borderTopRightRadius: 20, + padding: 20, + shadowColor: "#000", + shadowOffset: { width: 0, height: -2 }, + shadowOpacity: 0.2, + elevation: 5, + }, + headerBar: { + width: 40, + height: 5, + backgroundColor: MainColor.white, + borderRadius: 5, + alignSelf: "center", + marginVertical: 10, + }, + menuItem: { + padding: 15, + }, +}); + +const styles = StyleSheet.create({ + alertOverlay: { + position: "absolute", + top: 0, + left: 0, + right: 0, + bottom: 0, + backgroundColor: "rgba(0,0,0,0.5)", + justifyContent: "center", + alignItems: "center", + zIndex: 999, + }, + alertBox: { + width: "80%", + backgroundColor: "white", + borderRadius: 10, + padding: 20, + alignItems: "center", + shadowColor: "#000", + shadowOffset: { width: 0, height: 2 }, + shadowOpacity: 0.25, + elevation: 5, + }, + alertTitle: { + fontSize: 18, + fontWeight: "bold", + marginBottom: 10, + }, + alertMessage: { + textAlign: "center", + marginBottom: 20, + }, + alertButtons: { + flexDirection: "row", + justifyContent: "space-between", + width: "100%", + }, + alertButton: { + flex: 1, + padding: 10, + borderRadius: 5, + marginHorizontal: 5, + alignItems: "center", + }, + cancelButton: { + backgroundColor: "#ccc", + }, + confirmButton: { + backgroundColor: "red", + }, + buttonText: { + color: "white", + fontWeight: "bold", + }, +}); diff --git a/app/_layout.tsx b/app/_layout.tsx index b7a0950..cca9aac 100644 --- a/app/_layout.tsx +++ b/app/_layout.tsx @@ -1,35 +1,71 @@ -import "react-native-gesture-handler"; import { MainColor } from "@/constants/color-palet"; import { Stack } from "expo-router"; +import "react-native-gesture-handler"; import { SafeAreaProvider } from "react-native-safe-area-context"; export default function RootLayout() { return ( - - - - - - - - + <> + + + + + + + + + + // + // + // + // + // + // + // + // + // + // ); } diff --git a/components/_ShareComponent/ViewWrapper.tsx b/components/_ShareComponent/ViewWrapper.tsx index c132330..c214f34 100644 --- a/components/_ShareComponent/ViewWrapper.tsx +++ b/components/_ShareComponent/ViewWrapper.tsx @@ -1,6 +1,7 @@ +import { MainColor } from "@/constants/color-palet"; import { Styles } from "@/styles/global-styles"; import { ImageBackground, ScrollView, View } from "react-native"; -import { SafeAreaProvider, SafeAreaView } from "react-native-safe-area-context"; +import { SafeAreaView } from "react-native-safe-area-context"; interface ViewWrapperProps { children: React.ReactNode; @@ -16,7 +17,7 @@ const ViewWrapper = ({ const assetBackground = require("../../assets/images/main-background.png"); return ( - + <> @@ -42,7 +44,36 @@ const ViewWrapper = ({ {tabBarComponent} - + + + // + // + // + // {withBackground ? ( + // + // {children} + // + // ) : ( + // {children} + // )} + // + // {tabBarComponent} + // + // ); }; diff --git a/screens/Authentication/RegisterView.tsx b/screens/Authentication/RegisterView.tsx index 317e788..aa064a1 100644 --- a/screens/Authentication/RegisterView.tsx +++ b/screens/Authentication/RegisterView.tsx @@ -42,7 +42,7 @@ export default function RegisterView() { router.push("/(application)/home") )} /> - + {/* + /> */}