Add:
- Menambahkan folder : /admin/collaboration , /admin/investmen
- NavbarMenu

### No Issue
This commit is contained in:
2025-08-06 11:53:33 +08:00
parent c4c16f19c1
commit caf250c5ca
14 changed files with 276 additions and 74 deletions

View File

@@ -1,20 +1,12 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import {
ClickableCustom,
DrawerCustom,
StackCustom,
TextCustom,
} from "@/components";
import { StackCustom } from "@/components";
import DrawerAdmin from "@/components/Drawer/DrawerAdmin";
import NavbarMenu from "@/components/Drawer/NavbarMenu";
import SidebarMenu from "@/components/Drawer/SidebarMenu";
import NavbarMenu, { NavbarItem } from "@/components/Drawer/NavbarMenu";
import { AccentColor, MainColor } from "@/constants/color-palet";
import { ICON_SIZE_SMALL } from "@/constants/constans-value";
import { GStyles } from "@/styles/global-styles";
import { FontAwesome6, Ionicons } from "@expo/vector-icons";
import { router, Stack } from "expo-router";
import { Stack } from "expo-router";
import { useState } from "react";
import { View } from "react-native";
export default function AdminLayout() {
const [openDrawer, setOpenDrawer] = useState(false);
@@ -45,17 +37,37 @@ export default function AdminLayout() {
),
}}
>
<Stack.Screen name="dashboard" options={{ title: "Dashboard" }} />
<Stack.Screen name="dashboard" options={{ title: "Main Dashboard" }} />
<Stack.Screen name="investment/index" options={{ title: "Dashboard Investasi" }} />
<Stack.Screen name="investment/publish" options={{ title: "Investasi Publish" }} />
<Stack.Screen name="investment/review" options={{ title: "Investasi Review" }} />
<Stack.Screen name="investment/reject" options={{ title: "Investasi Reject" }} />
<Stack.Screen name="maps" options={{ title: "Maps" }} />
<Stack.Screen name="information" options={{ title: "Information" }} />
<Stack.Screen name="job/index" options={{ title: "Job" }} />
<Stack.Screen name="job/index" options={{ title: "Dashboard Job" }} />
<Stack.Screen name="job/publish" options={{ title: "Job Publish" }} />
<Stack.Screen name="job/review" options={{ title: "Job Review" }} />
<Stack.Screen name="job/reject" options={{ title: "Job Reject" }} />
<Stack.Screen
name="collaboration/index"
options={{ title: "Dashboard Collaboration" }}
/>
<Stack.Screen
name="collaboration/publish"
options={{ title: "Collaboration Publish" }}
/>
<Stack.Screen
name="collaboration/group"
options={{ title: "Collaboration Group" }}
/>
<Stack.Screen
name="collaboration/reject"
options={{ title: "Collaboration Reject" }}
/>
</Stack>
<DrawerAdmin isVisible={openDrawer} onClose={() => setOpenDrawer(false)}>
<StackCustom gap={"lg"}>
<StackCustom gap={"xs"}>
<Ionicons
name="close"
size={ICON_SIZE_SMALL}
@@ -64,31 +76,102 @@ export default function AdminLayout() {
style={{ alignSelf: "flex-end" }}
/>
<NavbarMenu
items={[
{ label: "Dashboard", icon: "home", link: "/admin/dashboard" },
{ label: "Maps", icon: "map", link: "/admin/maps" },
{
label: "Information",
icon: "information-circle",
link: "/admin/information",
},
{
label: "Job",
icon: "calendar",
links: [
{ label: "Summary", link: "/admin/job" },
{ label: "Publish", link: "/admin/job/publish" },
{ label: "Review", link: "/admin/job/review" },
{ label: "Reject", link: "/admin/job/reject" },
],
},
]}
onClose={() => setOpenDrawer(false)}
/>
<NavbarMenu items={listItem} onClose={() => setOpenDrawer(false)} />
</StackCustom>
</DrawerAdmin>
</>
);
}
const listItem: NavbarItem[] = [
{
label: "Main Dashboard",
icon: "home",
link: "/admin/dashboard",
},
{
label: "Investasi",
icon: "wallet",
links: [
{ label: "Dashboard", link: "/admin/investment" },
{ label: "Publish", link: "/admin/investment/publish" },
{ label: "Review", link: "/admin/investment/review" },
{ label: "Reject", link: "/admin/investment/reject" },
],
},
{
label: "Donasi",
icon: "hand-right",
links: [
{ label: "Dashboard", link: "/admin/donasi" },
{ label: "Publish", link: "/admin/donasi/publish" },
{ label: "Review", link: "/admin/donasi/review" },
{ label: "Reject", link: "/admin/donasi/reject" },
{ label: "Kategori", link: "/admin/donasi/kategori" },
],
},
{
label: "Event",
icon: "calendar-clear",
links: [
{ label: "Dashboard", link: "/admin/event" },
{ label: "Publish", link: "/admin/event/publish" },
{ label: "Review", link: "/admin/event/review" },
{ label: "Reject", link: "/admin/event/reject" },
{ label: "Tipe Acara", link: "/admin/event/tipe-acara" },
{ label: "Riwayat", link: "/admin/event/riwayat" },
],
},
{
label: "Voting",
icon: "accessibility-outline",
links: [
{ label: "Dashboard", link: "/admin/voting" },
{ label: "Publish", link: "/admin/voting/publish" },
{ label: "Review", link: "/admin/voting/review" },
{ label: "Reject", link: "/admin/voting/reject" },
{ label: "Riwayat", link: "/admin/voting/riwayat" },
],
},
{
label: "Job",
icon: "desktop-outline",
links: [
{ label: "Dashboard", link: "/admin/job" },
{ label: "Publish", link: "/admin/job/publish" },
{ label: "Review", link: "/admin/job/review" },
{ label: "Reject", link: "/admin/job/reject" },
],
},
{
label: "Forum",
icon: "chatbubble-ellipses-outline",
links: [
{ label: "Dashboard", link: "/admin/forum" },
{ label: "Posting", link: "/admin/forum/publish" },
{ label: "Report Posting", link: "/admin/forum/review" },
{ label: "Report Comment", link: "/admin/forum/reject" },
],
},
{
label: "Collaboration",
icon: "people",
links: [
{ label: "Dashboard", link: "/admin/collaboration" },
{ label: "Publish", link: "/admin/collaboration/publish" },
{ label: "Group", link: "/admin/collaboration/group" },
{ label: "Reject", link: "/admin/collaboration/reject" },
],
},
{ label: "Maps", icon: "map", link: "/admin/maps" },
{
label: "App Information",
icon: "information-circle",
link: "/admin/information",
},
{
label: "User Access",
icon: "people",
link: "/admin/user-access",
},
];

View File

@@ -0,0 +1,11 @@
import { TextCustom, ViewWrapper } from "@/components";
export default function AdminCollaborationGroup() {
return (
<>
<ViewWrapper>
<TextCustom>Admin Collaboration Group</TextCustom>
</ViewWrapper>
</>
);
}

View File

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

View File

@@ -0,0 +1,11 @@
import { TextCustom, ViewWrapper } from "@/components";
export default function AdminCollaborationPublish() {
return (
<>
<ViewWrapper>
<TextCustom>Admin Collaboration Publish</TextCustom>
</ViewWrapper>
</>
);
}

View File

@@ -0,0 +1,11 @@
import { TextCustom, ViewWrapper } from "@/components";
export default function AdminCollaborationReject() {
return (
<>
<ViewWrapper>
<TextCustom>Admin Collaboration Reject</TextCustom>
</ViewWrapper>
</>
);
}

View File

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

View File

@@ -0,0 +1,11 @@
import { TextCustom, ViewWrapper } from "@/components";
export default function AdminInvestmentPublish() {
return (
<>
<ViewWrapper>
<TextCustom>Admin Investment Publish</TextCustom>
</ViewWrapper>
</>
);
}

View File

@@ -0,0 +1,11 @@
import { TextCustom, ViewWrapper } from "@/components";
export default function AdminInvestmentReject() {
return (
<>
<ViewWrapper>
<TextCustom>Admin Investment Reject</TextCustom>
</ViewWrapper>
</>
);
}

View File

@@ -0,0 +1,11 @@
import { TextCustom, ViewWrapper } from "@/components";
export default function AdminInvestmentReview() {
return (
<>
<ViewWrapper>
<TextCustom>Admin Investment Review</TextCustom>
</ViewWrapper>
</>
);
}

View File

@@ -1,10 +1,10 @@
import React, { useEffect, useRef } from "react";
import {
Animated,
Dimensions,
InteractionManager,
PanResponder,
StyleSheet
Animated,
Dimensions,
InteractionManager,
PanResponder,
StyleSheet,
} from "react-native";
import { AccentColor, MainColor } from "@/constants/color-palet";
@@ -107,9 +107,15 @@ export default function DrawerAdmin({
{...panResponder.panHandlers}
>
{/* Handle Bar (opsional) */}
{/* <View style={styles.handleBar} /> */}
<SafeAreaView>{children}</SafeAreaView>
<SafeAreaView
edges={["top", "bottom"]}
style={{
flex: 1,
}}
>
{children}
{/* <Spacing/> */}
</SafeAreaView>
</Animated.View>
</>
);

View File

@@ -1,17 +1,17 @@
import { AccentColor, MainColor } from "@/constants/color-palet";
import { Ionicons } from "@expo/vector-icons";
import { router, usePathname } from "expo-router";
import React, { useRef, useState } from "react";
import React, { useEffect, useRef, useState } from "react";
import {
Animated,
ScrollView,
StyleSheet,
Text,
TouchableOpacity,
View,
} from "react-native";
import TextCustom from "../Text/TextCustom";
interface NavbarItem {
export interface NavbarItem {
label: string;
icon?: keyof typeof Ionicons.glyphMap;
color?: string;
@@ -33,6 +33,17 @@ export default function NavbarMenu({ items, onClose }: NavbarMenuProps) {
const [activeLink, setActiveLink] = useState<string | null>(null);
const [openKeys, setOpenKeys] = useState<string[]>([]); // Untuk kontrol dropdown
// Normalisasi path: hapus trailing slash
const normalizePath = (path: string) => path.replace(/\/+$/, "");
const normalizedPathname = pathname ? normalizePath(pathname) : "";
// Set activeLink saat pathname berubah
useEffect(() => {
if (normalizedPathname) {
setActiveLink(normalizedPathname);
}
}, [normalizedPathname]);
// Toggle dropdown
const toggleOpen = (label: string) => {
setOpenKeys((prev) =>
@@ -40,21 +51,34 @@ export default function NavbarMenu({ items, onClose }: NavbarMenuProps) {
);
};
return (
<View style={styles.container}>
{items.map((item) => (
<MenuItem
key={item.label}
item={item}
onClose={onClose}
activeLink={activeLink}
setActiveLink={setActiveLink}
isOpen={openKeys.includes(item.label)}
toggleOpen={() => toggleOpen(item.label)}
/>
))}
</View>
);
return (
<View
style={{
// flex: 1,
// backgroundColor: MainColor.black,
marginBottom: 20,
}}
>
<ScrollView
contentContainerStyle={{
paddingVertical: 10, // Opsional: tambahkan padding
}}
// showsVerticalScrollIndicator={false} // Opsional: sembunyikan indikator scroll
>
{items.map((item) => (
<MenuItem
key={item.label}
item={item}
onClose={onClose}
activeLink={activeLink}
setActiveLink={setActiveLink}
isOpen={openKeys.includes(item.label)}
toggleOpen={() => toggleOpen(item.label)}
/>
))}
</ScrollView>
</View>
);
}
// Komponen Item Menu
@@ -83,7 +107,7 @@ function MenuItem({
duration: 200,
useNativeDriver: false,
}).start();
}, [isOpen, item.links]);
}, [isOpen, item.links, animatedHeight]);
// Jika ada submenu
if (item.links && item.links.length > 0) {
@@ -93,7 +117,7 @@ function MenuItem({
<TouchableOpacity style={styles.parentItem} onPress={toggleOpen}>
<Ionicons
name={item.icon}
size={20}
size={16}
color={MainColor.white}
style={styles.icon}
/>
@@ -135,7 +159,7 @@ function MenuItem({
}}
>
<Ionicons
name="caret-forward-sharp"
name="radio-button-on-outline"
size={16}
color={isSubActive ? MainColor.yellow : MainColor.white}
style={styles.icon}
@@ -168,7 +192,7 @@ function MenuItem({
>
<Ionicons
name={item.icon}
size={20}
size={16}
color={isActive ? MainColor.yellow : MainColor.white}
style={styles.icon}
/>
@@ -186,14 +210,14 @@ function MenuItem({
// Styles
const styles = StyleSheet.create({
container: {
marginTop: 20,
marginBottom: 5,
},
parentItem: {
flexDirection: "row",
alignItems: "center",
paddingVertical: 12,
paddingHorizontal: 10,
backgroundColor: AccentColor.darkblue,
// backgroundColor: AccentColor.darkblue,
borderRadius: 8,
marginBottom: 5,
justifyContent: "space-between",
@@ -210,7 +234,7 @@ const styles = StyleSheet.create({
alignItems: "center",
paddingVertical: 12,
paddingHorizontal: 10,
backgroundColor: AccentColor.darkblue,
// backgroundColor: AccentColor.darkblue,
borderRadius: 8,
marginBottom: 5,
},
@@ -246,6 +270,7 @@ const styles = StyleSheet.create({
},
subText: {
color: MainColor.white,
fontSize: 14,
fontSize: 16,
fontWeight: "500",
},
});

View File

@@ -1,4 +1,4 @@
import React, { useRef, useState, useEffect } from "react";
import React, { useEffect, useRef, useState } from "react";
import {
Animated,
Dimensions,

View File

@@ -32,7 +32,7 @@ export default function LoginView() {
// router.navigate("/verification");
// router.navigate(`/(application)/(user)/profile/${id}`);
// router.navigate("/(application)/(user)/home");
router.navigate("/(application)/(user)/home");
// router.navigate(`/(application)/profile/${id}/edit`);
// router.navigate(`/(application)/(user)/portofolio/${id}`)
// router.navigate(`/(application)/(image)/preview-image/${id}`);
@@ -40,7 +40,7 @@ export default function LoginView() {
// router.replace("/(application)/coba");
// router.navigate("/investment/(tabs)")1
// router.navigate("/crowdfunding")
router.navigate("/admin/dashboard")
// router.navigate("/admin/dashboard")
}
return (

View File

@@ -61,7 +61,7 @@ export const drawerItemsProfile = ({
/>
),
label: "Dashboard Admin",
path: `/(application)/(admin)/dashboard`,
path: `/(application)/admin/dashboard`,
},
{
icon: (