feature & fix

deskripsi:
- perubahan komponen drawer
- penambahan list page drawer portofolio
- new file portofolio: edit, edit logo, edit sosmed
- new file maps: edit, custom-pin
#No Issue
This commit is contained in:
2025-07-10 10:27:30 +08:00
parent ee7efaef6a
commit 71ea0ca5f2
13 changed files with 183 additions and 68 deletions

View File

@@ -32,7 +32,7 @@ export default function UserLayout() {
}} }}
/> />
{/* Profile */} {/* ========== Profile Section ========= */}
<Stack.Screen <Stack.Screen
name="profile" name="profile"
options={{ options={{
@@ -40,7 +40,7 @@ export default function UserLayout() {
}} }}
/> />
{/* Portofolio */} {/* ========== Portofolio Section ========= */}
<Stack.Screen <Stack.Screen
name="portofolio" name="portofolio"
options={{ options={{
@@ -48,7 +48,7 @@ export default function UserLayout() {
}} }}
/> />
{/* User Search */} {/* ========== User Search Section ========= */}
<Stack.Screen <Stack.Screen
name="user-search/index" name="user-search/index"
options={{ options={{
@@ -57,7 +57,7 @@ export default function UserLayout() {
}} }}
/> />
{/* Notification */} {/* ========== Notification Section ========= */}
<Stack.Screen <Stack.Screen
name="notifications/index" name="notifications/index"
options={{ options={{
@@ -66,7 +66,7 @@ export default function UserLayout() {
}} }}
/> />
{/* Event */} {/* ========== Event Section ========= */}
<Stack.Screen <Stack.Screen
name="event/(tabs)" name="event/(tabs)"
options={{ options={{
@@ -85,7 +85,7 @@ export default function UserLayout() {
}} }}
/> />
{/* Forum */} {/* ========== Forum Section ========= */}
<Stack.Screen <Stack.Screen
name="forum/index" name="forum/index"
options={{ options={{
@@ -94,7 +94,7 @@ export default function UserLayout() {
}} }}
/> />
{/* Maps */} {/* ========== Maps Section ========= */}
<Stack.Screen <Stack.Screen
name="maps/index" name="maps/index"
options={{ options={{
@@ -109,8 +109,22 @@ export default function UserLayout() {
headerLeft: () => <BackButton />, headerLeft: () => <BackButton />,
}} }}
/> />
<Stack.Screen
name="maps/[id]/edit"
options={{
title: "Edit Maps",
headerLeft: () => <BackButton />,
}}
/>
<Stack.Screen
name="maps/[id]/custom-pin"
options={{
title: "Custom Pin Maps",
headerLeft: () => <BackButton />,
}}
/>
{/* Marketplace */} {/* ========== Marketplace Section ========= */}
<Stack.Screen <Stack.Screen
name="marketplace/index" name="marketplace/index"
options={{ options={{

View File

@@ -0,0 +1,11 @@
import { TextCustom, ViewWrapper } from "@/components";
export default function MapsCustomPin() {
return (
<>
<ViewWrapper>
<TextCustom>Maps Custom Pin</TextCustom>
</ViewWrapper>
</>
);
}

View File

@@ -0,0 +1,11 @@
import { TextCustom, ViewWrapper } from "@/components";
export default function MapsEdit() {
return (
<>
<ViewWrapper>
<TextCustom>Maps Edit</TextCustom>
</ViewWrapper>
</>
);
}

View File

@@ -0,0 +1,11 @@
import { TextCustom, ViewWrapper } from "@/components";
export default function PortofolioEditLogo() {
return (
<>
<ViewWrapper>
<TextCustom>Portofolio Edit Logo</TextCustom>
</ViewWrapper>
</>
);
}

View File

@@ -0,0 +1,11 @@
import { TextCustom, ViewWrapper } from "@/components";
export default function PortofolioEditSocialMedia() {
return (
<>
<ViewWrapper>
<TextCustom>Portofolio Edit Social Media</TextCustom>
</ViewWrapper>
</>
);
}

View File

@@ -0,0 +1,11 @@
import { TextCustom, ViewWrapper } from "@/components";
export default function PortofolioEdit() {
return (
<>
<ViewWrapper>
<TextCustom>Portofolio Edit</TextCustom>
</ViewWrapper>
</>
);
}

View File

@@ -1,47 +1,26 @@
import { DrawerCustom, TextCustom } from "@/components"; import { DrawerCustom } from "@/components";
import LeftButtonCustom from "@/components/Button/BackButton"; import LeftButtonCustom from "@/components/Button/BackButton";
import { IMenuDrawerItem } from "@/components/_Interface/types";
import ViewWrapper from "@/components/_ShareComponent/ViewWrapper"; import ViewWrapper from "@/components/_ShareComponent/ViewWrapper";
import { MainColor } from "@/constants/color-palet"; import { MainColor } from "@/constants/color-palet";
import { DRAWER_HEIGHT } from "@/constants/constans-value"; import { drawerItemsPortofolio } from "@/screens/Portofolio/ListPage";
import { drawerItems } from "@/screens/Profile/ListPage"; import Portofolio_MenuDrawerSection from "@/screens/Portofolio/MenuDrawer";
import Profile_MenuDrawerSection from "@/screens/Profile/MenuDrawerSection";
import { GStyles } from "@/styles/global-styles"; import { GStyles } from "@/styles/global-styles";
import { Ionicons } from "@expo/vector-icons"; import { Ionicons } from "@expo/vector-icons";
import { Stack, useLocalSearchParams } from "expo-router"; import { Stack, useLocalSearchParams } from "expo-router";
import { useRef, useState } from "react"; import { useState } from "react";
import { import {
Animated,
InteractionManager,
Text, Text,
TouchableOpacity, TouchableOpacity
} from "react-native"; } from "react-native";
export default function Portofolio() { export default function Portofolio() {
const { id } = useLocalSearchParams(); const { id } = useLocalSearchParams();
const [isDrawerOpen, setIsDrawerOpen] = useState(false); const [isDrawerOpen, setIsDrawerOpen] = useState(false);
const [showLogoutAlert, setShowLogoutAlert] = useState(false);
const drawerAnim = useRef(new Animated.Value(DRAWER_HEIGHT)).current;
const openDrawer = () => { const openDrawer = () => {
setIsDrawerOpen(true); setIsDrawerOpen(true);
Animated.timing(drawerAnim, {
toValue: 0,
duration: 300,
useNativeDriver: true,
}).start();
}; };
const closeDrawer = () => { const closeDrawer = () => {
Animated.timing(drawerAnim, {
toValue: DRAWER_HEIGHT, // sesuaikan dengan tinggi drawer Anda
duration: 300,
useNativeDriver: true,
}).start(() => {
InteractionManager.runAfterInteractions(() => {
setIsDrawerOpen(false); // baru ganti state setelah animasi selesai
});
});
setIsDrawerOpen(false); setIsDrawerOpen(false);
}; };
return ( return (
@@ -72,12 +51,10 @@ export default function Portofolio() {
<DrawerCustom <DrawerCustom
isVisible={isDrawerOpen} isVisible={isDrawerOpen}
closeDrawer={closeDrawer} closeDrawer={closeDrawer}
drawerAnim={drawerAnim}
height={350} height={350}
> >
<Profile_MenuDrawerSection <Portofolio_MenuDrawerSection
drawerItems={drawerItems({ id: id as string })} drawerItems={drawerItemsPortofolio({ id: id as string })}
setShowLogoutAlert={setShowLogoutAlert}
setIsDrawerOpen={setIsDrawerOpen} setIsDrawerOpen={setIsDrawerOpen}
/> />
</DrawerCustom> </DrawerCustom>

View File

@@ -20,6 +20,12 @@ export default function PortofolioLayout() {
name="[id]/list" name="[id]/list"
options={{ title: "Daftar Portofolio" }} options={{ title: "Daftar Portofolio" }}
/> />
<Stack.Screen name="[id]/edit" options={{ title: "Edit Portofolio" }} />
<Stack.Screen name="[id]/edit-logo" options={{ title: "Edit Logo " }} />
<Stack.Screen
name="[id]/edit-social-media"
options={{ title: "Edit Social Media" }}
/>
</Stack> </Stack>
</> </>
); );

View File

@@ -3,43 +3,26 @@ import AlertCustom from "@/components/Alert/AlertCustom";
import LeftButtonCustom from "@/components/Button/BackButton"; import LeftButtonCustom from "@/components/Button/BackButton";
import DrawerCustom from "@/components/Drawer/DrawerCustom"; import DrawerCustom from "@/components/Drawer/DrawerCustom";
import { MainColor } from "@/constants/color-palet"; import { MainColor } from "@/constants/color-palet";
import { DRAWER_HEIGHT } from "@/constants/constans-value"; import { drawerItemsProfile } from "@/screens/Profile/ListPage";
import { drawerItems } from "@/screens/Profile/ListPage";
import Profile_MenuDrawerSection from "@/screens/Profile/MenuDrawerSection"; import Profile_MenuDrawerSection from "@/screens/Profile/MenuDrawerSection";
import ProfilSection from "@/screens/Profile/ProfilSection"; import ProfilSection from "@/screens/Profile/ProfilSection";
import { GStyles } from "@/styles/global-styles"; import { GStyles } from "@/styles/global-styles";
import { Ionicons } from "@expo/vector-icons"; import { Ionicons } from "@expo/vector-icons";
import { router, Stack, useLocalSearchParams } from "expo-router"; import { router, Stack, useLocalSearchParams } from "expo-router";
import React, { useRef, useState } from "react"; import React, { useState } from "react";
import { Animated, InteractionManager, TouchableOpacity } from "react-native"; import { TouchableOpacity } from "react-native";
export default function Profile() { export default function Profile() {
const { id } = useLocalSearchParams(); const { id } = useLocalSearchParams();
const [isDrawerOpen, setIsDrawerOpen] = useState(false); const [isDrawerOpen, setIsDrawerOpen] = useState(false);
const [showLogoutAlert, setShowLogoutAlert] = useState(false); const [showLogoutAlert, setShowLogoutAlert] = useState(false);
// Animasi menggunakan translateY (lebih kompatibel)
const drawerAnim = useRef(new Animated.Value(DRAWER_HEIGHT)).current; // mulai di luar bawah layar
const openDrawer = () => { const openDrawer = () => {
setIsDrawerOpen(true); setIsDrawerOpen(true);
Animated.timing(drawerAnim, {
toValue: 0,
duration: 300,
useNativeDriver: true,
}).start();
}; };
const closeDrawer = () => { const closeDrawer = () => {
Animated.timing(drawerAnim, { setIsDrawerOpen(false);
toValue: DRAWER_HEIGHT, // sesuaikan dengan tinggi drawer Anda
duration: 300,
useNativeDriver: true,
}).start(() => {
InteractionManager.runAfterInteractions(() => {
setIsDrawerOpen(false); // baru ganti state setelah animasi selesai
});
});
}; };
const handleLogout = () => { const handleLogout = () => {
@@ -76,11 +59,10 @@ export default function Profile() {
<DrawerCustom <DrawerCustom
height={350} height={350}
isVisible={isDrawerOpen} isVisible={isDrawerOpen}
drawerAnim={drawerAnim}
closeDrawer={closeDrawer} closeDrawer={closeDrawer}
> >
<Profile_MenuDrawerSection <Profile_MenuDrawerSection
drawerItems={drawerItems({ id: id as string })} drawerItems={drawerItemsProfile({ id: id as string })}
setShowLogoutAlert={setShowLogoutAlert} setShowLogoutAlert={setShowLogoutAlert}
setIsDrawerOpen={setIsDrawerOpen} setIsDrawerOpen={setIsDrawerOpen}
/> />

View File

@@ -1,4 +1,4 @@
import React, { useRef } from "react"; import React, { useEffect, useRef } from "react";
import { import {
Animated, Animated,
PanResponder, PanResponder,
@@ -14,7 +14,7 @@ interface DrawerCustomProps {
children?: React.ReactNode; children?: React.ReactNode;
height?: number; height?: number;
isVisible: boolean; isVisible: boolean;
drawerAnim: Animated.Value; drawerAnim?: Animated.Value;
closeDrawer: () => void; closeDrawer: () => void;
// openLogoutAlert: () => void; // openLogoutAlert: () => void;
} }
@@ -33,6 +33,26 @@ export default function DrawerCustom({
closeDrawer, closeDrawer,
}: // openLogoutAlert, }: // openLogoutAlert,
DrawerCustomProps) { DrawerCustomProps) {
const drawerAnima = useRef(
new Animated.Value(height || DRAWER_HEIGHT)
).current;
// Efek untuk handle open/close drawer
useEffect(() => {
if (isVisible) {
Animated.timing(drawerAnima, {
toValue: 0,
duration: 300,
useNativeDriver: true,
}).start();
} else {
Animated.timing(drawerAnima, {
toValue: height || DRAWER_HEIGHT,
duration: 300,
useNativeDriver: true,
}).start();
}
}, [isVisible, drawerAnim, height, closeDrawer, drawerAnima]);
const panResponder = useRef( const panResponder = useRef(
PanResponder.create({ PanResponder.create({
onMoveShouldSetPanResponder: (_, gestureState) => { onMoveShouldSetPanResponder: (_, gestureState) => {
@@ -41,7 +61,7 @@ DrawerCustomProps) {
onPanResponderMove: (_, gestureState) => { onPanResponderMove: (_, gestureState) => {
const offset = gestureState.dy; const offset = gestureState.dy;
if (offset >= 0 && offset <= DRAWER_HEIGHT) { if (offset >= 0 && offset <= DRAWER_HEIGHT) {
drawerAnim.setValue(offset); drawerAnima.setValue(offset);
} }
}, },
onPanResponderRelease: (_, gestureState) => { onPanResponderRelease: (_, gestureState) => {
@@ -50,7 +70,7 @@ DrawerCustomProps) {
closeDrawer(); closeDrawer();
}); });
} else { } else {
Animated.spring(drawerAnim, { Animated.spring(drawerAnima, {
toValue: 0, toValue: 0,
useNativeDriver: true, useNativeDriver: true,
}).start(); }).start();
@@ -80,7 +100,7 @@ DrawerCustomProps) {
styles.drawer, styles.drawer,
{ {
height: height || DRAWER_HEIGHT, height: height || DRAWER_HEIGHT,
transform: [{ translateY: drawerAnim }], transform: [{ translateY: drawerAnima }],
}, },
]} ]}
{...panResponder.panHandlers} {...panResponder.panHandlers}

View File

@@ -0,0 +1,33 @@
import { IMenuDrawerItem } from "@/components/_Interface/types";
export const drawerItemsPortofolio = ({
id,
}: {
id: string;
}): IMenuDrawerItem[] => [
{
icon: "create",
label: "Edit portofolio",
path: `/(application)/portofolio/${id}/edit`,
},
{
icon: "camera",
label: "Edit logo ",
path: `/(application)/portofolio/${id}/edit-logo`,
},
{
icon: "image",
label: "Edit social media ",
path: `/(application)/portofolio/${id}/edit-social-media`,
},
{
icon: "add-circle",
label: "Edit Map",
path: `/(application)/maps/${id}/edit`,
},
{
icon: "create-outline",
label: "Custom Pin Map",
path: `/(application)/maps/${id}/custom-pin`,
},
];

View File

@@ -0,0 +1,28 @@
import { IMenuDrawerItem } from "@/components/_Interface/types";
import MenuDrawerDynamicGrid from "@/components/Drawer/MenuDrawerDynamicGird";
import { router } from "expo-router";
export default function Portofolio_MenuDrawerSection({
drawerItems,
setIsDrawerOpen,
}: {
drawerItems: IMenuDrawerItem[];
setIsDrawerOpen: (value: boolean) => void;
}) {
const handlePress = (item: IMenuDrawerItem) => {
console.log("PATH >> ", item.path);
router.push(item.path as any);
setIsDrawerOpen(false);
};
return (
<>
{/* Menu Items */}
<MenuDrawerDynamicGrid
data={drawerItems}
columns={4} // Ubah ke 2 jika ingin 2 kolom per baris
onPressItem={handlePress}
/>
</>
);
}

View File

@@ -1,6 +1,6 @@
import { IMenuDrawerItem } from "@/components/_Interface/types"; import { IMenuDrawerItem } from "@/components/_Interface/types";
export const drawerItems = ({ id }: { id: string }): IMenuDrawerItem[] => [ export const drawerItemsProfile = ({ id }: { id: string }): IMenuDrawerItem[] => [
{ {
icon: "create", icon: "create",
label: "Edit profile", label: "Edit profile",