Compare commits

...

12 Commits

Author SHA1 Message Date
d47fff469b Admin
App-Information
Add:
- screens/Admin/App-Information
- _ShareComponent/Admin
- app/(application)/admin/app-information

### No Issue
2025-08-06 17:35:30 +08:00
bcc0e02581 Admin
Add:
- screens/Admin/
- admin/notification/

Component
Add:
-  components/_ShareComponent/GridSectionView.tsx

### No Issue
2025-08-06 15:02:47 +08:00
caf250c5ca Admin
Add:
- Menambahkan folder : /admin/collaboration , /admin/investmen
- NavbarMenu

### No Issue
2025-08-06 11:53:33 +08:00
c4c16f19c1 Admin
Add:"
- app/(application)/admin/

## NO Issue
2025-08-05 17:40:46 +08:00
48c34aa26c Admin
Add:
- app/(application)/(admin)/

## No Issue
2025-08-05 12:11:25 +08:00
e16b0c2fce Donation
Add:
- [transaction]/success.tsx
- [transaction]/failed.tsx

Fix:
- InformationBox : props type di tambah React.ReactNode
- /donation/create && /donation/create-story : fix route

### No Issue
2025-08-05 11:01:41 +08:00
ca48dd2c6c Donation
Add:
- donation/[id]/(transaction-flow)

### No Issue
2025-08-04 17:44:20 +08:00
b858c7d297 Donation
Add:
- donation/[id]/fund-disbursement.tsx
- donation/[id]/(news)/list-of-news.tsx

Fix:
screens/Donation/ProgressSection.tsx

### No Issue
2025-08-04 16:59:21 +08:00
f9b9211a5c Donation
Add:
- list-of-donatur.tsx
- donation/[id]/(news)

Fix:
- /donation/[id]/index.tsx

## No Issue
2025-08-04 15:14:17 +08:00
3bcadbf643 Donation
Add:
- ProgressSection.tsx
- ComponentInfoFundrising.tsx
- donation/[id]/infromation-fundrising.tsx
- donation/[id]/detail-story.tsx

Fix:
- Donation/ComponentStoryFunrising.tsx
- Donation/ComponentBoxDetailData.tsx

## No Issue
2025-08-04 14:06:40 +08:00
d437365b5e Donation
Add:
- screens/Donation/
- donation/[id]/

Fix:
- donation/(tabs)/status.tsx
- donation/create-story.tsx
- donation/create.tsx

## No Issue
2025-08-04 11:28:21 +08:00
25e495cdf1 Donation
Add:
- lib/dummy-data/donasi
- donation/(tabs)/
- donation/create-story.tsx

Fix:
- app/(application)/(user)/_layout.tsx
- app/(application)/(user)/crowdfunding/index.tsx
- app/(application)/(user)/donation/create.tsx
- screens/Authentication/LoginView.tsx

## No Issue
2025-08-01 17:32:05 +08:00
78 changed files with 3815 additions and 38 deletions

View File

@@ -340,6 +340,14 @@ export default function UserLayout() {
{/* ========== End Investment Section ========= */}
{/* ========== Donation Section ========= */}
<Stack.Screen
name="donation/(tabs)"
options={{
title: "Donasi",
headerLeft: () => <BackButton path="/crowdfunding" />,
}}
/>
<Stack.Screen
name="donation/create"
options={{
@@ -347,6 +355,142 @@ export default function UserLayout() {
headerLeft: () => <BackButton />,
}}
/>
<Stack.Screen
name="donation/create-story"
options={{
title: "Tambah Donasi",
headerLeft: () => <BackButton />,
}}
/>
<Stack.Screen
name="donation/[id]/edit"
options={{
title: "Edit Donasi",
headerLeft: () => <BackButton />,
}}
/>
<Stack.Screen
name="donation/[id]/edit-story"
options={{
title: "Edit Donasi",
headerLeft: () => <BackButton />,
}}
/>
<Stack.Screen
name="donation/[id]/edit-rekening"
options={{
title: "Edit Rekening",
headerLeft: () => <BackButton />,
}}
/>
<Stack.Screen
name="donation/[id]/detail-story"
options={{
title: "Cerita Penggalang",
headerLeft: () => <BackButton />,
}}
/>
<Stack.Screen
name="donation/[id]/infromation-fundrising"
options={{
title: "Informasi Penggalang Dana",
headerLeft: () => <BackButton />,
}}
/>
<Stack.Screen
name="donation/[id]/list-of-donatur"
options={{
title: "Daftar Donatur",
headerLeft: () => <BackButton />,
}}
/>
<Stack.Screen
name="donation/[id]/fund-disbursement"
options={{
title: "Pencairan Dana",
headerLeft: () => <BackButton />,
}}
/>
<Stack.Screen
name="donation/[id]/(news)/recap-of-news"
options={{
title: "Rekap Kabar",
headerLeft: () => <BackButton />,
}}
/>
<Stack.Screen
name="donation/[id]/(news)/add-news"
options={{
title: "Tambah Berita",
headerLeft: () => <BackButton />,
}}
/>
<Stack.Screen
name="donation/[id]/(news)/[news]/edit-news"
options={{
title: "Edit Berita",
headerLeft: () => <BackButton />,
}}
/>
<Stack.Screen
name="donation/[id]/(transaction-flow)/index"
options={{
title: "Donasi",
headerLeft: () => <BackButton />,
}}
/>
<Stack.Screen
name="donation/[id]/(transaction-flow)/select-bank"
options={{
title: "Pilih Bank",
headerLeft: () => <BackButton />,
}}
/>
<Stack.Screen
name="donation/[id]/(transaction-flow)/[transaction]/invoice"
options={{
title: "Invoice",
headerLeft: () => (
<Ionicons
name="close"
size={ICON_SIZE_SMALL}
color={MainColor.yellow}
onPress={() => router.navigate(`/donation/(tabs)/my-donation`)}
/>
),
}}
/>
<Stack.Screen
name="donation/[id]/(transaction-flow)/[transaction]/process"
options={{
title: "Proses",
headerLeft: () => (
<Ionicons
name="close"
size={ICON_SIZE_SMALL}
color={MainColor.yellow}
onPress={() => router.navigate(`/donation/(tabs)/my-donation`)}
/>
),
}}
/>
<Stack.Screen
name="donation/[id]/(transaction-flow)/[transaction]/success"
options={{
title: "Donasi Berhasil",
headerLeft: () => <BackButton />,
}}
/>
<Stack.Screen
name="donation/[id]/(transaction-flow)/[transaction]/failed"
options={{
title: "Donasi Gagal",
headerLeft: () => <BackButton />,
}}
/>
{/* ========== End Donation Section ========= */}

View File

@@ -20,7 +20,7 @@ export default function Crowdfunding() {
{
title: "Donasi",
desc: "Berbagi info untuk berdonasi lebih luas dan lebih efisien.",
path: "donation/create",
path: "donation/(tabs)",
},
];

View File

@@ -0,0 +1,37 @@
import { IconHome, IconStatus } from "@/components/_Icon";
import { ICON_SIZE_SMALL } from "@/constants/constans-value";
import { TabsStyles } from "@/styles/tabs-styles";
import {
FontAwesome5
} from "@expo/vector-icons";
import { Tabs } from "expo-router";
export default function InvestmentTabsLayout() {
return (
<Tabs screenOptions={TabsStyles}>
<Tabs.Screen
name="index"
options={{
title: "Beranda",
tabBarIcon: ({ color }) => <IconHome color={color} />,
}}
/>
<Tabs.Screen
name="status"
options={{
title: "Galang Dana",
tabBarIcon: ({ color }) => <IconStatus color={color} />,
}}
/>
<Tabs.Screen
name="my-donation"
options={{
title: "Donasi Saya",
tabBarIcon: ({ color }) => (
<FontAwesome5 name="donate" color={color} size={ICON_SIZE_SMALL} />
),
}}
/>
</Tabs>
);
}

View File

@@ -0,0 +1,21 @@
import {
FloatingButton,
ViewWrapper
} from "@/components";
import Donation_BoxPublish from "@/screens/Donation/BoxPublish";
import { router } from "expo-router";
export default function DonationBeranda() {
return (
<ViewWrapper
hideFooter
floatingButton={
<FloatingButton onPress={() => router.push("/donation/create")} />
}
>
{Array.from({ length: 10 }).map((_, index) => (
<Donation_BoxPublish key={index} id={index.toString()}/>
))}
</ViewWrapper>
);
}

View File

@@ -0,0 +1,76 @@
import {
BadgeCustom,
BaseBox,
DummyLandscapeImage,
Grid,
StackCustom,
TextCustom,
ViewWrapper,
} from "@/components";
import { dummyMasterStatusTransaction } from "@/lib/dummy-data/_master/status-transaction";
import { router } from "expo-router";
import { View } from "react-native";
export default function DonationMyDonation() {
const randomStatusData = Array.from({ length: 10 }, () => {
const randomIndex = Math.floor(
Math.random() * dummyMasterStatusTransaction.length
);
return dummyMasterStatusTransaction[randomIndex];
});
const handlePress = (value: string) => {
if (value === "menunggu") {
router.push(`/donation/${value}/(transaction-flow)/123/invoice`);
} else if (value === "proses") {
router.push(`/donation/${value}/(transaction-flow)/123/process`);
} else if (value === "berhasil") {
router.push(`/donation/${value}/(transaction-flow)/123/success`);
} else if (value === "gagal") {
router.push(`/donation/${value}/(transaction-flow)/123/failed`);
}
};
return (
<ViewWrapper hideFooter>
{randomStatusData.map((item, index) => (
<BaseBox
key={index}
paddingTop={7}
paddingBottom={7}
onPress={() => {
handlePress(item.value);
}}
>
<Grid>
<Grid.Col span={5}>
<DummyLandscapeImage height={100} unClickPath />
</Grid.Col>
<Grid.Col span={1}>
<View />
</Grid.Col>
<Grid.Col span={6}>
<StackCustom gap={"sm"}>
<View>
<TextCustom truncate>
Judul Donasi: Lorem ipsum dolor sit amet consectetur
adipisicing elit.
</TextCustom>
</View>
<View>
<TextCustom>Donasi Saya</TextCustom>
<TextCustom bold color="yellow">
Rp. 7.500.000
</TextCustom>
</View>
<BadgeCustom variant="light" color={item.color} fullWidth>
{item.label}
</BadgeCustom>
</StackCustom>
</Grid.Col>
</Grid>
</BaseBox>
))}
</ViewWrapper>
);
}

View File

@@ -0,0 +1,38 @@
import { ScrollableCustom, ViewWrapper } from "@/components";
import { dummyMasterStatus } from "@/lib/dummy-data/_master/status";
import Donasi_BoxStatus from "@/screens/Donation/BoxStatus";
import { useState } from "react";
export default function DonationStatus() {
const [activeCategory, setActiveCategory] = useState<string | null>(
"publish"
);
const handlePress = (item: any) => {
setActiveCategory(item.value);
// tambahkan logika lain seperti filter dsb.
};
const scrollComponent = (
<ScrollableCustom
data={dummyMasterStatus.map((e, i) => ({
id: i,
label: e.label,
value: e.value,
}))}
onButtonPress={handlePress}
activeId={activeCategory as any}
/>
);
return (
<ViewWrapper hideFooter headerComponent={scrollComponent}>
{Array.from({ length: 10 }).map((_, index) => (
<Donasi_BoxStatus
key={index}
id={index.toString()}
status={activeCategory as string}
/>
))}
</ViewWrapper>
);
}

View File

@@ -0,0 +1,54 @@
import {
ButtonCenteredOnly,
ButtonCustom,
InformationBox,
LandscapeFrameUploaded,
Spacing,
StackCustom,
TextAreaCustom,
TextInputCustom,
ViewWrapper,
} from "@/components";
import { router } from "expo-router";
export default function DonationEditNews() {
return (
<ViewWrapper>
<StackCustom gap={"xs"}>
<InformationBox text="Upload gambar bersifat opsional untuk melengkapi kabar terkait donasi Anda." />
<LandscapeFrameUploaded />
<ButtonCenteredOnly
onPress={() => {
router.push("/(application)/(image)/take-picture/123");
}}
icon="upload"
>
Upload
</ButtonCenteredOnly>
<Spacing />
<TextInputCustom
label="Judul Berita"
placeholder="Masukan judul berita"
required
/>
<TextAreaCustom
label="Deskripsi Berita"
placeholder="Masukan deskripsi berita"
required
showCount
maxLength={1000}
/>
<Spacing />
<ButtonCustom
onPress={() => {
router.back();
}}
>
Update
</ButtonCustom>
</StackCustom>
<Spacing />
</ViewWrapper>
);
}

View File

@@ -0,0 +1,95 @@
import {
AlertDefaultSystem,
BackButton,
BaseBox,
DotButton,
DrawerCustom,
DummyLandscapeImage,
MenuDrawerDynamicGrid,
StackCustom,
TextCustom,
ViewWrapper,
} from "@/components";
import { IconEdit } from "@/components/_Icon";
import { IconTrash } from "@/components/_Icon/IconTrash";
import dayjs from "dayjs";
import { router, Stack, useLocalSearchParams } from "expo-router";
import { useState } from "react";
export default function DonationNews() {
const { id, news } = useLocalSearchParams();
const [openDrawer, setOpenDrawer] = useState(false);
return (
<>
<Stack.Screen
options={{
title: "Detail Kabar",
headerLeft: () => <BackButton />,
headerRight: () => <DotButton onPress={() => setOpenDrawer(true)} />,
}}
/>
<ViewWrapper>
<BaseBox>
<StackCustom>
<TextCustom style={{ alignSelf: "flex-end" }}>
{dayjs().format("DD MMM YYYY")}
</TextCustom>
<DummyLandscapeImage />
<TextCustom bold size="large" align="center">
Judul Berita
</TextCustom>
<TextCustom>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Sapiente
est id temporibus perferendis eos reiciendis reprehenderit tempora
ut quibusdam dolores facilis rerum exercitationem recusandae quis
neque, adipisci dolorum, aspernatur labore?
</TextCustom>
</StackCustom>
</BaseBox>
</ViewWrapper>
<DrawerCustom
isVisible={openDrawer}
closeDrawer={() => setOpenDrawer(false)}
height={"auto"}
>
<MenuDrawerDynamicGrid
data={[
{
icon: <IconEdit />,
label: "Edit Berita",
path: `/donation/${id}/(news)/${news}/edit-news` as any,
},
{
icon: <IconTrash />,
label: "Hapus Berita",
path: `` as any,
color: "red",
},
]}
onPressItem={(item) => {
if ((item.path as any) === "") {
setOpenDrawer(false);
AlertDefaultSystem({
title: "Hapus Berita",
message: "Apakah Anda yakin ingin menghapus berita ini?",
textLeft: "Batal",
textRight: "Hapus",
onPressRight: () => {
router.back();
},
});
} else {
router.navigate(item.path as any);
setOpenDrawer(false);
}
}}
/>
</DrawerCustom>
</>
);
}

View File

@@ -0,0 +1,54 @@
import {
ButtonCenteredOnly,
ButtonCustom,
InformationBox,
LandscapeFrameUploaded,
Spacing,
StackCustom,
TextAreaCustom,
TextInputCustom,
ViewWrapper,
} from "@/components";
import { router } from "expo-router";
export default function DonationAddNews() {
return (
<ViewWrapper>
<StackCustom gap={"xs"}>
<InformationBox text="Upload gambar bersifat opsional untuk melengkapi kabar terkait donasi Anda." />
<LandscapeFrameUploaded />
<ButtonCenteredOnly
onPress={() => {
router.push("/(application)/(image)/take-picture/123");
}}
icon="upload"
>
Upload
</ButtonCenteredOnly>
<Spacing />
<TextInputCustom
label="Judul Berita"
placeholder="Masukan judul berita"
required
/>
<TextAreaCustom
label="Deskripsi Berita"
placeholder="Masukan deskripsi berita"
required
showCount
maxLength={1000}
/>
<Spacing />
<ButtonCustom
onPress={() => {
router.back();
}}
>
Simpan
</ButtonCustom>
</StackCustom>
<Spacing />
</ViewWrapper>
);
}

View File

@@ -0,0 +1,67 @@
import {
BackButton,
BaseBox,
DrawerCustom,
Grid,
MenuDrawerDynamicGrid,
TextCustom,
ViewWrapper
} from "@/components";
import { IconPlus } from "@/components/_Icon";
import dayjs from "dayjs";
import { router, Stack, useLocalSearchParams } from "expo-router";
import { useState } from "react";
export default function DonationRecapOfNews() {
const { id } = useLocalSearchParams();
const [openDrawer, setOpenDrawer] = useState(false);
return (
<>
<Stack.Screen
options={{
title: "Daftar Kabar",
headerLeft: () => <BackButton />, }}
/>
<ViewWrapper>
{Array.from({ length: 15 }).map((_, index) => (
<BaseBox key={index} href={`/donation/${id}/(news)/${index}`}>
<Grid>
<Grid.Col span={8}>
<TextCustom truncate bold>
Lorem ipsum dolor, sit amet consectetur adipisicing elit.
</TextCustom>
</Grid.Col>
<Grid.Col span={4} style={{ alignItems: "flex-end" }}>
<TextCustom size="small">
{dayjs().format("DD MMM YYYY")}
</TextCustom>
</Grid.Col>
</Grid>
</BaseBox>
))}
</ViewWrapper>
<DrawerCustom
isVisible={openDrawer}
closeDrawer={() => setOpenDrawer(false)}
height={"auto"}
>
<MenuDrawerDynamicGrid
data={[
{
icon: <IconPlus />,
label: "Tambah Berita",
path: `/donation/${id}/(news)/add-news`,
},
]}
onPressItem={(item) => {
console.log("PATH ", item.path);
router.navigate(item.path as any);
setOpenDrawer(false);
}}
/>
</DrawerCustom>
</>
);
}

View File

@@ -0,0 +1,68 @@
import {
BackButton,
BaseBox,
DotButton,
DrawerCustom,
Grid,
MenuDrawerDynamicGrid,
TextCustom,
ViewWrapper,
} from "@/components";
import { IconPlus } from "@/components/_Icon";
import dayjs from "dayjs";
import { router, Stack, useLocalSearchParams } from "expo-router";
import { useState } from "react";
export default function DonationRecapOfNews() {
const { id } = useLocalSearchParams();
const [openDrawer, setOpenDrawer] = useState(false);
return (
<>
<Stack.Screen
options={{
title: "Rekap Kabar",
headerLeft: () => <BackButton />,
headerRight: () => <DotButton onPress={() => setOpenDrawer(true)} />,
}}
/>
<ViewWrapper>
{Array.from({ length: 15 }).map((_, index) => (
<BaseBox key={index} href={`/donation/${id}/(news)/${index}`}>
<Grid>
<Grid.Col span={8}>
<TextCustom truncate bold>
Lorem ipsum dolor, sit amet consectetur adipisicing elit.
</TextCustom>
</Grid.Col>
<Grid.Col span={4} style={{ alignItems: "flex-end" }}>
<TextCustom size="small">{dayjs().format("DD MMM YYYY")}</TextCustom>
</Grid.Col>
</Grid>
</BaseBox>
))}
</ViewWrapper>
<DrawerCustom
isVisible={openDrawer}
closeDrawer={() => setOpenDrawer(false)}
height={"auto"}
>
<MenuDrawerDynamicGrid
data={[
{
icon: <IconPlus />,
label: "Tambah Berita",
path: `/donation/${id}/(news)/add-news`,
},
]}
onPressItem={(item) => {
console.log("PATH ", item.path);
router.navigate(item.path as any);
setOpenDrawer(false);
}}
/>
</DrawerCustom>
</>
);
}

View File

@@ -0,0 +1,83 @@
import {
BaseBox,
Grid,
Spacing,
StackCustom,
TextCustom,
ViewWrapper,
} from "@/components";
import { MainColor } from "@/constants/color-palet";
import { GStyles } from "@/styles/global-styles";
import { FontAwesome6 } from "@expo/vector-icons";
import dayjs from "dayjs";
export default function DonasiFailed() {
return (
<ViewWrapper>
<StackCustom>
<BaseBox>
<StackCustom>
<TextCustom bold align="center">
Transaksi anda gagal karena bukti transfer tidak sesuai dengan
data kami. Jika ini masalah khusus silahkan hubungi pada kontak
whatsapp kami.
</TextCustom>
<FontAwesome6
name="whatsapp"
size={50}
color={MainColor.green}
style={GStyles.alignSelfCenter}
/>
</StackCustom>
</BaseBox>
<BaseBox>
<TextCustom bold align="center" size="large">
Detail Transaksi
</TextCustom>
<Spacing />
<StackCustom>
{listData.map((item, i) => (
<Grid key={i}>
<Grid.Col span={5}>
<TextCustom bold>{item.label}</TextCustom>
</Grid.Col>
<Grid.Col span={7}>
<TextCustom style={{ paddingLeft: 10 }}>
{item.value}
</TextCustom>
</Grid.Col>
</Grid>
))}
</StackCustom>
</BaseBox>
</StackCustom>
</ViewWrapper>
);
}
const listData = [
{
label: "Bank",
value: " BCA",
},
{
label: "Rekening Penerima",
value: "Himpunan Pengusaha Muda Indonesia",
},
{
label: "No Rekening",
value: "2304235678854332",
},
{
label: "Jumlah Donasi",
value: "Rp. 750.000",
},
{
label: "Tanggal",
value: `${dayjs(new Date()).format("DD/MM/YYYY")}`,
},
];

View File

@@ -0,0 +1,110 @@
import {
BaseBox,
ButtonCenteredOnly,
ButtonCustom,
Grid,
InformationBox,
Spacing,
StackCustom,
TextCustom,
ViewWrapper,
} from "@/components";
import { MainColor } from "@/constants/color-palet";
import { router, useLocalSearchParams } from "expo-router";
export default function DonationInvoice() {
const { id, transaction } = useLocalSearchParams();
return (
<>
<ViewWrapper>
<StackCustom>
<InformationBox text={`Mohon transfer donasi anda ke rekening dibawah dengan Id: ${transaction}`} />
<BaseBox>
<StackCustom gap={"xs"}>
<TextCustom>Nama BANK</TextCustom>
<TextCustom>Nama Penerima</TextCustom>
<Spacing height={10} />
<BaseBox backgroundColor={MainColor.soft_darkblue}>
<Grid containerStyle={{ justifyContent: "center" }}>
<Grid.Col
span={8}
style={{
justifyContent: "center",
}}
>
<TextCustom size="xlarge" bold color="yellow">
4567898765433567
</TextCustom>
</Grid.Col>
<Grid.Col
span={4}
style={{
alignItems: "flex-end",
}}
>
<ButtonCustom>Salin</ButtonCustom>
</Grid.Col>
</Grid>
</BaseBox>
</StackCustom>
</BaseBox>
<BaseBox>
<StackCustom gap={"xs"}>
<TextCustom>Jumlah Transaksi</TextCustom>
<Spacing height={10} />
<BaseBox backgroundColor={MainColor.soft_darkblue}>
<Grid containerStyle={{ justifyContent: "center" }}>
<Grid.Col
span={8}
style={{
justifyContent: "center",
}}
>
<TextCustom size="xlarge" bold color="yellow">
Rp. 1.000.000
</TextCustom>
</Grid.Col>
<Grid.Col
span={4}
style={{
alignItems: "flex-end",
}}
>
<ButtonCustom>Salin</ButtonCustom>
</Grid.Col>
</Grid>
</BaseBox>
</StackCustom>
</BaseBox>
<BaseBox>
<StackCustom>
<TextCustom>Upload bukti transfer anda.</TextCustom>
<ButtonCenteredOnly
onPress={() => {
router.push("/(application)/(image)/take-picture/123");
}}
icon="upload"
>
Upload
</ButtonCenteredOnly>
</StackCustom>
</BaseBox>
<ButtonCustom
onPress={() => {
router.push(`/donation/${id}/(transaction-flow)/process`);
}}
>
Saya Sudah Transfer
</ButtonCustom>
</StackCustom>
<Spacing />
</ViewWrapper>
</>
);
}

View File

@@ -0,0 +1,45 @@
import {
BaseBox,
Grid,
StackCustom,
TextCustom,
ViewWrapper,
} from "@/components";
import { MainColor } from "@/constants/color-palet";
import { Ionicons } from "@expo/vector-icons";
import { ActivityIndicator } from "react-native";
export default function DonationProcess() {
return (
<>
<ViewWrapper>
<BaseBox>
<StackCustom>
<TextCustom align="center" bold>
Admin sedang memproses transaksi donasimu
</TextCustom>
<ActivityIndicator size="large" color={MainColor.yellow} />
</StackCustom>
</BaseBox>
<BaseBox>
<Grid>
<Grid.Col span={10} style={{ justifyContent: "center" }}>
<TextCustom size="small">
Hubungi admin jika tidak kunjung di proses! Klik pada logo
Whatsapp ini.
</TextCustom>
</Grid.Col>
<Grid.Col span={2} style={{ alignItems: "flex-end" }}>
<Ionicons
name="logo-whatsapp"
size={50}
color={MainColor.green}
/>
</Grid.Col>
</Grid>
</BaseBox>
</ViewWrapper>
</>
);
}

View File

@@ -0,0 +1,83 @@
import {
BaseBox,
Grid,
Spacing,
StackCustom,
TextCustom,
ViewWrapper,
} from "@/components";
import { MainColor } from "@/constants/color-palet";
import { GStyles } from "@/styles/global-styles";
import { FontAwesome6 } from "@expo/vector-icons";
import dayjs from "dayjs";
export default function DonationSuccess() {
return (
<ViewWrapper>
<StackCustom>
<BaseBox>
<StackCustom>
<FontAwesome6
name="money-bill-wave"
size={100}
color={MainColor.green}
style={GStyles.alignSelfCenter}
/>
<TextCustom bold align="center">
Terimakasih telah percaya pada kami untuk mengelola dana anda!
Info mengenai update Penggalian Dana ini bisa di lihat di kolom
berita.
</TextCustom>
</StackCustom>
</BaseBox>
<BaseBox>
<TextCustom bold align="center" size="large">
Detail Transaksi
</TextCustom>
<Spacing />
<StackCustom>
{listData.map((item, i) => (
<Grid key={i}>
<Grid.Col span={5}>
<TextCustom bold>{item.label}</TextCustom>
</Grid.Col>
<Grid.Col span={7}>
<TextCustom style={{ paddingLeft: 10 }}>
{item.value}
</TextCustom>
</Grid.Col>
</Grid>
))}
</StackCustom>
</BaseBox>
</StackCustom>
</ViewWrapper>
);
}
const listData = [
{
label: "Bank",
value: " BCA",
},
{
label: "Rekening Penerima",
value: "Himpunan Pengusaha Muda Indonesia",
},
{
label: "No Rekening",
value: "2304235678854332",
},
{
label: "Jumlah Donasi",
value: "Rp. 750.000",
},
{
label: "Tanggal",
value: `${dayjs(new Date()).format("DD/MM/YYYY")}`,
},
];

View File

@@ -0,0 +1,81 @@
import {
BaseBox,
BoxButtonOnFooter,
ButtonCustom,
Grid,
TextCustom,
TextInputCustom,
ViewWrapper,
} from "@/components";
import { MainColor } from "@/constants/color-palet";
import { ICON_SIZE_SMALL } from "@/constants/constans-value";
import { Ionicons } from "@expo/vector-icons";
import { router, useLocalSearchParams } from "expo-router";
export default function InvestmentInputDonation() {
const { id } = useLocalSearchParams();
const bottomComponent = (
<BoxButtonOnFooter>
<ButtonCustom
onPress={() => router.replace(`/donation/${id}/select-bank`)}
>
Lanjutan
</ButtonCustom>
</BoxButtonOnFooter>
);
return (
<>
<ViewWrapper footerComponent={bottomComponent}>
{listData.map((item, i) => (
<BaseBox key={i}>
<Grid>
<Grid.Col span={8}>
<TextCustom bold size="large">
Rp. {item.label}
</TextCustom>
</Grid.Col>
<Grid.Col span={4}>
<Ionicons
name="chevron-forward"
size={ICON_SIZE_SMALL}
color={MainColor.yellow}
style={{ alignSelf: "flex-end" }}
/>
</Grid.Col>
</Grid>
</BaseBox>
))}
<BaseBox>
<TextInputCustom
label="Nominal lainnya"
placeholder="0"
iconLeft="Rp."
/>
<TextCustom size="small" color="gray">
Minimal donasi Rp. 10.000
</TextCustom>
</BaseBox>
</ViewWrapper>
</>
);
}
const listData = [
{
label: "25.000",
value: 25000,
},
{
label: "50.000",
value: 50000,
},
{
label: "100.000",
value: 100000,
},
{
label: "250.000",
value: 250000,
},
];

View File

@@ -0,0 +1,44 @@
import {
BaseBox,
BoxButtonOnFooter,
ButtonCustom,
ViewWrapper,
} from "@/components";
import { RadioCustom, RadioGroup } from "@/components/Radio/RadioCustom";
import { dummyMasterBank } from "@/lib/dummy-data/_master/bank";
import { router, useLocalSearchParams } from "expo-router";
import { useState } from "react";
export default function DonationSelectBank() {
const { id, transaction } = useLocalSearchParams();
const [value, setValue] = useState<any | number>("");
const buttonSubmit = () => {
return (
<>
<BoxButtonOnFooter>
<ButtonCustom
onPress={() =>
router.replace(
`/(application)/(user)/donation/${id}/(transaction-flow)/${transaction}/invoice`
)
}
>
Pilih
</ButtonCustom>
</BoxButtonOnFooter>
</>
);
};
return (
<ViewWrapper footerComponent={buttonSubmit()}>
<RadioGroup value={value} onChange={setValue}>
{dummyMasterBank.map((item) => (
<BaseBox key={item.name}>
<RadioCustom label={item.name} value={item.code} />
</BaseBox>
))}
</RadioGroup>
</ViewWrapper>
);
}

View File

@@ -0,0 +1,115 @@
import {
BackButton,
DotButton,
DrawerCustom,
MenuDrawerDynamicGrid,
Spacing,
ViewWrapper,
} from "@/components";
import { IconEdit, IconNews } from "@/components/_Icon";
import { IMenuDrawerItem } from "@/components/_Interface/types";
import { MainColor } from "@/constants/color-palet";
import { ICON_SIZE_SMALL } from "@/constants/constans-value";
import Donation_ButtonStatusSection from "@/screens/Donation/ButtonStatusSection";
import Donation_ComponentBoxDetailData from "@/screens/Donation/ComponentBoxDetailData";
import Donation_ComponentStoryFunrising from "@/screens/Donation/ComponentStoryFunrising";
import Donation_ProgressSection from "@/screens/Donation/ProgressSection";
import { FontAwesome6 } from "@expo/vector-icons";
import { router, Stack, useLocalSearchParams } from "expo-router";
import _ from "lodash";
import { useState } from "react";
export default function DonasiDetailStatus() {
const { id, status } = useLocalSearchParams();
const [openDrawer, setOpenDrawer] = useState(false);
const [openDrawerPublish, setOpenDrawerPublish] = useState(false);
const handlePress = (item: IMenuDrawerItem) => {
console.log("PATH ", item.path);
router.navigate(item.path as any);
setOpenDrawer(false);
};
return (
<>
<Stack.Screen
options={{
title: `Detail ${_.startCase(status as string)}`,
headerLeft: () => <BackButton />,
headerRight: () =>
status === "draft" ? (
<DotButton onPress={() => setOpenDrawer(true)} />
) : status === "publish" ? (
<DotButton onPress={() => setOpenDrawerPublish(true)} />
) : null,
}}
/>
<ViewWrapper>
<Donation_ComponentBoxDetailData
bottomSection={
status === "publish" && <Donation_ProgressSection id={id as string} />
}
/>
<Donation_ComponentStoryFunrising id={id as string} />
<Spacing />
<Donation_ButtonStatusSection status={status as string} />
<Spacing />
</ViewWrapper>
<DrawerCustom
isVisible={openDrawer}
closeDrawer={() => setOpenDrawer(false)}
height={"auto"}
>
<MenuDrawerDynamicGrid
data={[
{
icon: <IconEdit />,
label: "Edit Donasi",
path: `/donation/${id}/edit`,
},
{
icon: <IconEdit />,
label: "Edit Cerita",
path: `/donation/${id}/edit-story`,
},
{
icon: (
<FontAwesome6
name="credit-card"
color={MainColor.white}
size={ICON_SIZE_SMALL}
/>
),
label: "Edit Rekening",
path: `/donation/${id}/edit-rekening`,
},
]}
columns={4}
onPressItem={handlePress as any}
/>
</DrawerCustom>
<DrawerCustom
isVisible={openDrawerPublish}
closeDrawer={() => setOpenDrawerPublish(false)}
height={"auto"}
>
<MenuDrawerDynamicGrid
data={[
{
icon: <IconNews />,
label: "Rekap Kabar",
path: `/donation/${id}/(news)/recap-of-news`,
},
]}
onPressItem={(item) => {
console.log("PATH ", item.path);
router.navigate(item.path as any);
setOpenDrawerPublish(false);
}}
/>
</DrawerCustom>
</>
);
}

View File

@@ -0,0 +1,28 @@
import {
DummyLandscapeImage,
StackCustom,
TextCustom,
ViewWrapper,
} from "@/components";
import { useLocalSearchParams } from "expo-router";
export default function DonationDetailStory() {
const { id } = useLocalSearchParams();
return (
<ViewWrapper>
<StackCustom>
<TextCustom>
Lorem {id} ipsum dolor, sit amet consectetur adipisicing elit. Fuga
quasi nam nesciunt nisi corporis alias modi, pariatur sit totam rem
fugiat ex similique magni, aliquam maiores officiis iure at adipisci.
</TextCustom>
<DummyLandscapeImage />
<TextCustom>
Lorem {id} ipsum dolor, sit amet consectetur adipisicing elit. Fuga
quasi nam nesciunt nisi corporis alias modi, pariatur sit totam rem
fugiat ex similique magni, aliquam maiores officiis iure at adipisci.
</TextCustom>
</StackCustom>
</ViewWrapper>
);
}

View File

@@ -0,0 +1,32 @@
import { ViewWrapper, StackCustom, InformationBox, TextInputCustom, Spacing, ButtonCustom } from "@/components";
import { router } from "expo-router";
export default function DonationEditRekening() {
return (
<ViewWrapper>
<StackCustom gap={"xs"}>
<InformationBox text="Pastikan Anda mengisi nama bank dan nomor rekening dengan benar. Informasi ini akan membantu admin memverifikasi dan memproses penggalangan dana Anda dengan cepat dan tepat setelah penggalangan dana dipublikasikan." />
<TextInputCustom
label="Nama Bank"
placeholder="Masukkan nama bank"
required
/>
<TextInputCustom
label="Nomor Rekening"
placeholder="Masukkan nomor rekening"
required
/>
<Spacing />
<ButtonCustom
onPress={() => {
router.back();
}}
>
Update
</ButtonCustom>
</StackCustom>
<Spacing />
</ViewWrapper>
);
}

View File

@@ -0,0 +1,56 @@
import {
ButtonCenteredOnly,
ButtonCustom,
InformationBox,
LandscapeFrameUploaded,
Spacing,
StackCustom,
TextAreaCustom,
ViewWrapper
} from "@/components";
import { router } from "expo-router";
export default function DonationEditStory() {
return (
<ViewWrapper>
<StackCustom gap={"xs"}>
<InformationBox text="Cerita Anda adalah kunci untuk menginspirasi kebaikan. Jelaskan dengan jujur dan jelas tujuan penggalangan dana ini agar calon donatur memahami dampak positif yang dapat mereka wujudkan melalui kontribusi mereka." />
<TextAreaCustom
label="Pembukaan Cerita"
placeholder="Masukkan pembukaan cerita"
required
showCount
maxLength={1000}
/>
<LandscapeFrameUploaded />
<ButtonCenteredOnly
onPress={() => {
router.push("/(application)/(image)/take-picture/123");
}}
icon="upload"
>
Upload
</ButtonCenteredOnly>
<Spacing />
<TextAreaCustom
label="Tujuan Donasi"
placeholder="Masukkan tujuan donasi"
required
showCount
maxLength={1000}
/>
<Spacing height={40} />
<ButtonCustom
onPress={() => {
router.back();
}}
>
Update
</ButtonCustom>
</StackCustom>
<Spacing />
</ViewWrapper>
);
}

View File

@@ -0,0 +1,79 @@
import {
ButtonCenteredOnly,
ButtonCustom,
InformationBox,
LandscapeFrameUploaded,
SelectCustom,
Spacing,
StackCustom,
TextInputCustom,
ViewWrapper,
} from "@/components";
import { dummyDonasiDurasi } from "@/lib/dummy-data/donasi/durasi";
import { dummyDonasiKategori } from "@/lib/dummy-data/donasi/kategori";
import { router } from "expo-router";
export default function DonationEdit() {
return (
<ViewWrapper>
<StackCustom gap={"xs"}>
<InformationBox text="Lengkapi semua data di bawah untuk selanjutnya mengisi cerita penggalangan dana." />
<TextInputCustom
label="Judul Donasi"
placeholder="Masukkan Judul Donasi"
required
/>
<TextInputCustom
label="Target Donasi"
placeholder="Masukkan Target Donasi"
required
keyboardType="numeric"
/>
<LandscapeFrameUploaded />
<ButtonCenteredOnly
onPress={() => {
router.push("/(application)/(image)/take-picture/123");
}}
icon="upload"
>
Upload
</ButtonCenteredOnly>
<Spacing />
<SelectCustom
data={dummyDonasiKategori.map((item) => ({
label: item.label,
value: item.value,
}))}
onChange={(value) => console.log(value)}
label="Pilih Kategori Donasi"
placeholder="Pilih Kategori Donasi"
required
/>
<SelectCustom
data={dummyDonasiDurasi.map((item) => ({
label: item.label,
value: item.value,
}))}
onChange={(value) => console.log(value)}
label="Pilih Durasi Donasi"
placeholder="Pilih Durasi Donasi"
required
/>
<Spacing />
<ButtonCustom
onPress={() => {
router.back();
}}
>
Update
</ButtonCustom>
</StackCustom>
<Spacing />
</ViewWrapper>
);
}

View File

@@ -0,0 +1,67 @@
import {
BaseBox,
ButtonCenteredOnly,
Grid,
InformationBox,
StackCustom,
TextCustom,
ViewWrapper,
} from "@/components";
import dayjs from "dayjs";
import { router, useLocalSearchParams } from "expo-router";
export default function DonationFundDisbursement() {
const { id } = useLocalSearchParams();
return (
<>
<ViewWrapper>
<InformationBox text="Pencairan dana akan dilakukan oleh Admin HIPMI tanpa campur tangan pihak manapun, jika berita pencairan dana dibawah tidak sesuai dengan kabar yang diberikan oleh PENGGALANG DANA. Maka pegguna lain dapat melaporkannya pada Admin HIPMI !" />
<BaseBox>
<Grid>
<Grid.Col span={6}>
<TextCustom bold color="yellow">
Rp. 0
</TextCustom>
<TextCustom size="small">Total Pencairan Dana</TextCustom>
</Grid.Col>
<Grid.Col span={6}>
<TextCustom bold color="yellow">
0 kali
</TextCustom>
<TextCustom size="small">Akumulasi Pencairan</TextCustom>
</Grid.Col>
</Grid>
</BaseBox>
{Array.from({ length: 10 }).map((_, index) => (
<BaseBox key={index}>
<StackCustom>
<Grid>
<Grid.Col span={8}>
<TextCustom bold>Pencairan ke - {index + 1}</TextCustom>
</Grid.Col>
<Grid.Col span={4} style={{ alignItems: "flex-end" }}>
<TextCustom>{dayjs().format("DD MMM YYYY")}</TextCustom>
</Grid.Col>
</Grid>
<TextCustom>
Lorem ipsum dolor sit amet consectetur adipisicing elit.
Nesciunt dolor ad sit? Eaque rem nihil natus, id, esse possimus
perferendis provident velit illo consectetur distinctio ab
accusantium quis earum omnis!
</TextCustom>
<ButtonCenteredOnly
onPress={() => {
router.navigate(`/(application)/(file)/${id}`);
}}
icon="file-text"
>
Bukti Transaksi
</ButtonCenteredOnly>
</StackCustom>
</BaseBox>
))}
</ViewWrapper>
</>
);
}

View File

@@ -0,0 +1,78 @@
import {
BackButton,
BoxButtonOnFooter,
ButtonCustom,
DotButton,
DrawerCustom,
MenuDrawerDynamicGrid,
StackCustom,
ViewWrapper,
} from "@/components";
import { IconNews } from "@/components/_Icon";
import Donation_ComponentBoxDetailData from "@/screens/Donation/ComponentBoxDetailData";
import Donation_ComponentInfoFundrising from "@/screens/Donation/ComponentInfoFundrising";
import Donation_ComponentStoryFunrising from "@/screens/Donation/ComponentStoryFunrising";
import Donation_ProgressSection from "@/screens/Donation/ProgressSection";
import { router, Stack, useLocalSearchParams } from "expo-router";
import { useState } from "react";
export default function DonasiDetailBeranda() {
const { id } = useLocalSearchParams();
const [openDrawer, setOpenDrawer] = useState(false);
const buttonSection = (
<>
<BoxButtonOnFooter>
<ButtonCustom
onPress={() =>
router.navigate(`/donation/${id}/(transaction-flow)`)
}
>
Donasi
</ButtonCustom>
</BoxButtonOnFooter>
</>
);
return (
<>
<Stack.Screen
options={{
title: `Detail Donasi`,
headerLeft: () => <BackButton />,
headerRight: () => <DotButton onPress={() => setOpenDrawer(true)} />,
}}
/>
<ViewWrapper footerComponent={buttonSection}>
<StackCustom>
<Donation_ComponentBoxDetailData
bottomSection={<Donation_ProgressSection id={id as string} />}
/>
<Donation_ComponentInfoFundrising id={id as string} />
<Donation_ComponentStoryFunrising id={id as string} />
</StackCustom>
</ViewWrapper>
<DrawerCustom
isVisible={openDrawer}
closeDrawer={() => setOpenDrawer(false)}
height={"auto"}
>
<MenuDrawerDynamicGrid
data={[
{
icon: <IconNews />,
label: "Rekap Kabar",
path: `/donation/${id}/(news)/recap-of-news`,
},
]}
onPressItem={(item) => {
console.log("PATH ", item.path);
router.navigate(item.path as any);
setOpenDrawer(false);
}}
/>
</DrawerCustom>
</>
);
}

View File

@@ -0,0 +1,44 @@
import {
AvatarCustom,
BaseBox,
ButtonCustom,
CenterCustom,
Grid,
Spacing,
TextCustom,
ViewWrapper
} from "@/components";
import Donation_BoxPublish from "@/screens/Donation/BoxPublish";
import React from "react";
export default function DonationInformationFunrising() {
return (
<>
<ViewWrapper>
<BaseBox>
<Grid>
<Grid.Col span={6} style={{ justifyContent: "center" }}>
<CenterCustom>
<AvatarCustom size="lg" />
<TextCustom bold size="large" truncate>
@Username
</TextCustom>
</CenterCustom>
</Grid.Col>
<Grid.Col span={6} style={{ justifyContent: "center" }}>
<ButtonCustom href={`/profile/1234`}>
Kunjungi Profile
</ButtonCustom>
</Grid.Col>
</Grid>
</BaseBox>
<Spacing />
{Array.from({ length: 10 }).map((_, index) => (
<Donation_BoxPublish key={index} id={index.toString()} />
))}
</ViewWrapper>
</>
);
}

View File

@@ -0,0 +1,47 @@
import {
BaseBox,
Grid,
StackCustom,
TextCustom,
ViewWrapper,
} from "@/components";
import { MainColor } from "@/constants/color-palet";
import { FontAwesome6 } from "@expo/vector-icons";
import dayjs from "dayjs";
export default function Donation_ListOfDonatur() {
return (
<>
<ViewWrapper>
{Array.from({ length: 10 }).map((_, index) => (
<BaseBox key={index}>
<Grid>
<Grid.Col
span={3}
style={{ alignItems: "center", justifyContent: "center" }}
>
<FontAwesome6
name="face-smile-wink"
size={50}
style={{ color: MainColor.yellow }}
/>
</Grid.Col>
<Grid.Col span={9}>
<StackCustom gap={"xs"}>
<TextCustom bold size="large">
Username
</TextCustom>
<TextCustom>Berdonas sebesar </TextCustom>
<TextCustom bold size="large" color="yellow">
Rp. 100.000
</TextCustom>
<TextCustom>{dayjs().format("DD MMM YYYY")}</TextCustom>
</StackCustom>
</Grid.Col>
</Grid>
</BaseBox>
))}
</ViewWrapper>
</>
);
}

View File

@@ -0,0 +1,69 @@
import {
ButtonCenteredOnly,
ButtonCustom,
InformationBox,
LandscapeFrameUploaded,
Spacing,
StackCustom,
TextAreaCustom,
TextInputCustom,
ViewWrapper,
} from "@/components";
import { router } from "expo-router";
export default function DonationCreateStory() {
return (
<ViewWrapper>
<StackCustom gap={"xs"}>
<InformationBox text="Cerita Anda adalah kunci untuk menginspirasi kebaikan. Jelaskan dengan jujur dan jelas tujuan penggalangan dana ini agar calon donatur memahami dampak positif yang dapat mereka wujudkan melalui kontribusi mereka." />
<TextAreaCustom
label="Pembukaan Cerita"
placeholder="Masukkan pembukaan cerita"
required
showCount
maxLength={1000}
/>
<TextAreaCustom
label="Tujuan Donasi"
placeholder="Masukkan tujuan donasi"
required
showCount
maxLength={1000}
/>
<LandscapeFrameUploaded />
<ButtonCenteredOnly
onPress={() => {
router.push("/(application)/(image)/take-picture/123");
}}
icon="upload"
>
Upload
</ButtonCenteredOnly>
<Spacing height={40} />
<InformationBox text="Pastikan Anda mengisi nama bank dan nomor rekening dengan benar. Informasi ini akan membantu admin memverifikasi dan memproses penggalangan dana Anda dengan cepat dan tepat setelah penggalangan dana dipublikasikan." />
<TextInputCustom
label="Nama Bank"
placeholder="Masukkan nama bank"
required
/>
<TextInputCustom
label="Nomor Rekening"
placeholder="Masukkan nomor rekening"
required
/>
<Spacing />
<ButtonCustom
onPress={() => {
router.replace(`/donation/(tabs)/status`);
}}
>
Simpan
</ButtonCustom>
</StackCustom>
<Spacing />
</ViewWrapper>
);
}

View File

@@ -1,11 +1,79 @@
import { TextCustom, ViewWrapper } from "@/components";
import {
ButtonCenteredOnly,
ButtonCustom,
InformationBox,
LandscapeFrameUploaded,
SelectCustom,
Spacing,
StackCustom,
TextInputCustom,
ViewWrapper,
} from "@/components";
import { dummyDonasiDurasi } from "@/lib/dummy-data/donasi/durasi";
import { dummyDonasiKategori } from "@/lib/dummy-data/donasi/kategori";
import { router } from "expo-router";
export default function DonationCreate() {
return (
<ViewWrapper>
<TextCustom bold size="large">
Coming Soon !
</TextCustom>
<StackCustom gap={"xs"}>
<InformationBox text="Lengkapi semua data di bawah untuk selanjutnya mengisi cerita penggalangan dana." />
<TextInputCustom
label="Judul Donasi"
placeholder="Masukkan Judul Donasi"
required
/>
<TextInputCustom
label="Target Donasi"
placeholder="Masukkan Target Donasi"
required
keyboardType="numeric"
/>
<LandscapeFrameUploaded />
<ButtonCenteredOnly
onPress={() => {
router.push("/(application)/(image)/take-picture/123");
}}
icon="upload"
>
Upload
</ButtonCenteredOnly>
<Spacing />
<SelectCustom
data={dummyDonasiKategori.map((item) => ({
label: item.label,
value: item.value,
}))}
onChange={(value) => console.log(value)}
label="Pilih Kategori Donasi"
placeholder="Pilih Kategori Donasi"
required
/>
<SelectCustom
data={dummyDonasiDurasi.map((item) => ({
label: item.label,
value: item.value,
}))}
onChange={(value) => console.log(value)}
label="Pilih Durasi Donasi"
placeholder="Pilih Durasi Donasi"
required
/>
<Spacing />
<ButtonCustom
onPress={() => {
router.replace("/donation/create-story");
}}
>
Selanjutnya
</ButtonCustom>
<Spacing />
</StackCustom>
<Spacing />
</ViewWrapper>
);
}

View File

@@ -16,7 +16,7 @@ export default function InvestmentProcess() {
<BaseBox>
<StackCustom>
<TextCustom align="center" bold>
Admin sedang memproses transaksimu
Admin sedang memproses transaksi investasimu
</TextCustom>
<ActivityIndicator size="large" color={MainColor.yellow} />
</StackCustom>

View File

@@ -7,6 +7,8 @@ export default function ApplicationLayout() {
<>
<Stack screenOptions={HeaderStyles}>
<Stack.Screen name="(user)" options={{ headerShown: false }} />
<Stack.Screen name="admin" options={{ headerShown: false }} />
{/* Take Picture */}
<Stack.Screen

View File

@@ -0,0 +1,227 @@
import {
AlertDefaultSystem,
DrawerCustom,
GridComponentView,
MenuDrawerDynamicGrid,
StackCustom,
TextCustom,
} from "@/components";
import DrawerAdmin from "@/components/Drawer/DrawerAdmin";
import NavbarMenu from "@/components/Drawer/NavbarMenu";
import { AccentColor, MainColor } from "@/constants/color-palet";
import { ICON_SIZE_SMALL } from "@/constants/constans-value";
import { adminListMenu } from "@/screens/Admin/listPageAdmin";
import { GStyles } from "@/styles/global-styles";
import { FontAwesome6, Ionicons } from "@expo/vector-icons";
import { router, Stack } from "expo-router";
import { useState } from "react";
export default function AdminLayout() {
const [openDrawerNavbar, setOpenDrawerNavbar] = useState(false);
const [openDrawerUser, setOpenDrawerUser] = useState(false);
return (
<>
<Stack
screenOptions={{
title: "HIPMI DASHBOARD",
headerStyle: GStyles.headerStyle,
headerTitleStyle: GStyles.headerTitleStyle,
headerTitleAlign: "center",
contentStyle: {
borderBottomColor: AccentColor.blue,
},
headerLeft: () => (
<Ionicons
name="menu"
size={ICON_SIZE_SMALL}
color={MainColor.white}
onPress={() => setOpenDrawerNavbar(true)}
/>
),
headerRight: () => (
<FontAwesome6
name="circle-user"
size={ICON_SIZE_SMALL}
color={MainColor.white}
onPress={() => setOpenDrawerUser(true)}
/>
),
}}
>
<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="app-information/index"
// options={{ title: "Information" }}
/>
<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={openDrawerNavbar}
onClose={() => setOpenDrawerNavbar(false)}
>
<StackCustom gap={"xs"}>
<Ionicons
name="close"
size={ICON_SIZE_SMALL}
color={MainColor.white}
onPress={() => setOpenDrawerNavbar(false)}
style={{ alignSelf: "flex-end" }}
/>
<NavbarMenu
items={adminListMenu}
onClose={() => setOpenDrawerNavbar(false)}
/>
</StackCustom>
</DrawerAdmin>
<DrawerCustom
isVisible={openDrawerUser}
closeDrawer={() => setOpenDrawerUser(false)}
height={"auto"}
>
<StackCustom>
<GridComponentView
leftIcon={
<Ionicons
name="person"
size={ICON_SIZE_SMALL}
color={MainColor.white}
/>
}
>
<TextCustom>Username</TextCustom>
</GridComponentView>
<GridComponentView
leftIcon={
<Ionicons
name="ribbon-outline"
size={ICON_SIZE_SMALL}
color={MainColor.white}
/>
}
>
<TextCustom>User Role</TextCustom>
</GridComponentView>
<MenuDrawerDynamicGrid
columns={3}
data={[
{
label: "Notifikasi",
value: "notification",
icon: (
<Ionicons
name="notifications"
size={ICON_SIZE_SMALL}
color={MainColor.white}
/>
),
path: "/admin/notification",
},
{
label: "Kembali ke User",
value: "back-to-user",
icon: (
<Ionicons
name="git-compare"
size={ICON_SIZE_SMALL}
color={MainColor.white}
/>
),
path: "" as any,
},
{
label: "Keluar",
value: "logout",
icon: (
<Ionicons
name="log-out"
size={ICON_SIZE_SMALL}
color={MainColor.white}
/>
),
path: "" as any,
color: MainColor.red,
},
]}
onPressItem={(item) => {
if (item.value === "notification") {
router.push("/admin/notification");
setOpenDrawerUser(false);
} else if (item.value === "back-to-user") {
AlertDefaultSystem({
title: "Kembali ke User",
message: "Apakah Anda yakin ingin kembali ke user?",
textLeft: "Batal",
textRight: "Ya",
onPressRight: () => {
router.replace(`/(application)/(user)/profile/${123}`);
},
});
} else if (item.value === "logout") {
AlertDefaultSystem({
title: "Keluar",
message: "Apakah Anda yakin ingin keluar?",
textLeft: "Batal",
textRight: "Keluar",
onPressRight: () => {
router.replace("/");
},
});
}
}}
/>
</StackCustom>
</DrawerCustom>
</>
);
}

View File

@@ -0,0 +1,62 @@
import {
ScrollableCustom,
ViewWrapper
} from "@/components";
import AdminAppInformation_BusinessFieldSection from "@/screens/Admin/App-Information/BusinessFieldSection";
import AdminAppInformation_Bank from "@/screens/Admin/App-Information/InformationBankSection";
import AdminAppInformation_StickerSection from "@/screens/Admin/App-Information/StickerSection";
import { useState } from "react";
export default function AdminInformation() {
const [activeCategory, setActiveCategory] = useState<string | null>("bank");
const handlePress = (item: any) => {
setActiveCategory(item.value);
// tambahkan logika lain seperti filter dsb.
};
const scrollComponent = (
<ScrollableCustom
data={[
{
id: "1",
label: "Informasi Bank",
value: "bank",
},
{
id: "2",
label: "Bidang Bisnis",
value: "business",
},
{
id: "3",
label: "Stiker",
value: "sticker",
},
]}
onButtonPress={handlePress}
activeId={activeCategory as any}
/>
);
const renderContent = () => {
switch (activeCategory) {
case "bank":
return <AdminAppInformation_Bank />;
case "business":
return <AdminAppInformation_BusinessFieldSection />;
case "sticker":
return <AdminAppInformation_StickerSection />;
default:
return <AdminAppInformation_Bank />;
}
};
return (
<>
<ViewWrapper headerComponent={scrollComponent}>
{renderContent()}
</ViewWrapper>
</>
);
}

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,40 @@
import {
StackCustom,
TextCustom,
ViewWrapper
} from "@/components";
import AdminComp_BoxDashboard from "@/components/_ShareComponent/Admin/BoxDashboard";
import { MainColor } from "@/constants/color-palet";
import { Ionicons } from "@expo/vector-icons";
export default function AdminDashboard() {
return (
<>
<ViewWrapper>
<StackCustom>
<TextCustom bold size={30}>
Main Dashboard
</TextCustom>
{listData.map((item, i) => (
<AdminComp_BoxDashboard key={i} item={item} />
))}
</StackCustom>
</ViewWrapper>
</>
);
}
const listData = [
{
label: "User",
value: 4,
icon: <Ionicons name="people" size={30} color={MainColor.yellow} />,
},
{
label: "Portofolio",
value: 7,
icon: (
<Ionicons name="id-card-outline" size={30} color={MainColor.yellow} />
),
},
];

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

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,11 @@
import { MapCustom, ViewWrapper } from "@/components";
export default function AdminMaps() {
return (
<>
<ViewWrapper>
<MapCustom height={"100%"} />
</ViewWrapper>
</>
);
}

View File

@@ -0,0 +1,20 @@
import { BackButton, TextCustom, ViewWrapper } from "@/components";
import { Stack } from "expo-router";
export default function AdminNotification() {
return (
<>
<Stack.Screen
options={{
title: "Admin Notifikasi",
headerLeft: () => <BackButton />,
headerRight: () => <></>,
}}
/>
<ViewWrapper>
<TextCustom>Notification</TextCustom>
</ViewWrapper>
</>
);
}

View File

@@ -14,7 +14,10 @@ export default function RootLayout() {
headerTitleAlign: "center",
}}
>
<Stack.Screen name="index" options={{ title: "" }} />
<Stack.Screen
name="index"
options={{ title: "", headerBackVisible: false }}
/>
<Stack.Screen name="+not-found" options={{ title: "" }} />
<Stack.Screen
name="verification"

View File

@@ -3,8 +3,9 @@ import { Ionicons } from "@expo/vector-icons";
import Grid from "../Grid/GridCustom";
import TextCustom from "../Text/TextCustom";
import BaseBox from "./BaseBox";
import React from "react";
export default function InformationBox({ text }: { text: string }) {
export default function InformationBox({ text }: { text: React.ReactNode | string }) {
return (
<>
<BaseBox paddingTop={5} paddingBottom={5}>

View File

@@ -7,7 +7,7 @@ import ButtonCustom from "./ButtonCustom";
interface ButtonCenteredOnlyProps {
children?: React.ReactNode;
icon?: "plus" | "upload";
icon?: "plus" | "upload" | string;
onPress: () => void;
}
export default function ButtonCenteredOnly({
@@ -19,7 +19,7 @@ export default function ButtonCenteredOnly({
<ButtonCustom
onPress={onPress}
iconLeft={
<Feather name={icon} size={ICON_SIZE_BUTTON} color={MainColor.black} />
<Feather name={icon as any} size={ICON_SIZE_BUTTON} color={MainColor.black} />
}
style={[GStyles.buttonCentered50Percent]}
>

View File

@@ -1,22 +1,28 @@
import { MainColor } from "@/constants/color-palet";
import React from "react";
import { StyleSheet, TextInput, View } from "react-native";
import { StyleProp, StyleSheet, TextInput, View, ViewStyle } from "react-native";
interface CircularInputProps {
value: string | number;
onChange?: (value: string) => void;
value?: string | number
onChange?: (value: string | number) => void;
icon?: React.ReactNode;
style?: StyleProp<ViewStyle>
}
const CircularInput: React.FC<CircularInputProps> = ({ value, onChange }) => {
const CircularInput: React.FC<CircularInputProps> = ({ value, onChange, icon, style }) => {
return (
<View style={styles.circleContainer}>
<TextInput
value={String(value)}
onChangeText={onChange}
style={styles.input}
keyboardType="numeric"
maxLength={2} // Batasan maksimal karakter
/>
<View style={[styles.circleContainer, style]}>
{icon ? (
icon
) : (
<TextInput
value={String(value)}
onChangeText={onChange}
style={styles.input}
keyboardType="numeric"
maxLength={2} // Batasan maksimal karakter
/>
)}
</View>
);
};

View File

@@ -2,8 +2,8 @@ import { AccentColor } from "@/constants/color-palet";
import { View } from "react-native";
export default function Divider({
color = AccentColor.blue,
size = 1,
color = AccentColor.white,
size = 0.5,
marginTop= 12,
marginBottom= 12,
}: {

View File

@@ -0,0 +1,157 @@
import React, { useEffect, useRef } from "react";
import {
Animated,
Dimensions,
InteractionManager,
PanResponder,
StyleSheet,
} from "react-native";
import { AccentColor, MainColor } from "@/constants/color-palet";
import { SafeAreaView } from "react-native-safe-area-context";
// Lebar drawer (bisa di-pass sebagai prop)
const DRAWER_WIDTH = Dimensions.get("window").width * 0.8; // 80% lebar layar
interface DrawerAdminProps {
children?: React.ReactNode;
width?: number; // lebar drawer
isVisible: boolean;
onClose: () => void; // ganti nama dari closeDrawer agar lebih jelas
}
export default function DrawerAdmin({
children,
width = DRAWER_WIDTH,
isVisible,
onClose,
}: DrawerAdminProps) {
const drawerAnim = useRef(new Animated.Value(-width)).current; // mulai dari kiri (tersembunyi)
// Efek untuk handle animasi saat isVisible berubah
useEffect(() => {
if (isVisible) {
Animated.timing(drawerAnim, {
toValue: 0,
duration: 300,
useNativeDriver: true,
}).start();
} else {
Animated.timing(drawerAnim, {
toValue: -width,
duration: 300,
useNativeDriver: true,
}).start();
}
}, [isVisible, width, onClose, drawerAnim]);
const panResponder = useRef(
PanResponder.create({
onMoveShouldSetPanResponder: (_, gestureState) => {
return Math.abs(gestureState.dx) > 10; // deteksi gesek horizontal
},
onPanResponderMove: (_, gestureState) => {
let newAnim = gestureState.dx; // geser ke kanan = dx positif → drawerAnim negatif
newAnim = Math.max(-width, Math.min(0, newAnim)); // batas antara -width dan 0
drawerAnim.setValue(newAnim);
},
onPanResponderRelease: (_, gestureState) => {
if (gestureState.dx > 100) {
// gesek kencang ke kiri → tutup
InteractionManager.runAfterInteractions(() => {
onClose();
});
} else {
// kembali ke posisi terbuka penuh
Animated.spring(drawerAnim, {
toValue: 0,
useNativeDriver: true,
}).start();
}
},
})
).current;
if (!isVisible) return null;
return (
<>
{/* Overlay Gelap */}
<Animated.View
style={[
styles.overlay,
{
opacity: drawerAnim.interpolate({
inputRange: [-width, 0],
outputRange: [0, 0.6],
extrapolate: "clamp",
}),
},
]}
onTouchStart={() => {
InteractionManager.runAfterInteractions(() => {
onClose();
});
}}
/>
{/* Left Drawer */}
<Animated.View
style={[
styles.drawer,
{
width,
transform: [{ translateX: drawerAnim }],
},
]}
{...panResponder.panHandlers}
>
{/* Handle Bar (opsional) */}
<SafeAreaView
edges={["top", "bottom"]}
style={{
flex: 1,
}}
>
{children}
{/* <Spacing/> */}
</SafeAreaView>
</Animated.View>
</>
);
}
const styles = StyleSheet.create({
overlay: {
position: "absolute",
top: 0,
left: 0,
right: 0,
bottom: 0,
backgroundColor: "black",
zIndex: 998,
},
drawer: {
position: "absolute",
top: 0,
bottom: 0,
left: 0,
backgroundColor: AccentColor.darkblue,
// borderRadius: 20, // opsional
shadowColor: "#000",
shadowOffset: { width: 2, height: 0 },
shadowOpacity: 0.2,
shadowRadius: 5,
elevation: 5,
zIndex: 999,
padding: 20,
},
handleBar: {
width: 10,
height: 5,
backgroundColor: MainColor.yellow,
borderRadius: 5,
alignSelf: "flex-start",
marginBottom: 20,
},
});

View File

@@ -7,6 +7,7 @@ import { Href } from "expo-router";
type IMenuDrawerItemProps = {
icon: React.ReactNode;
label: string;
value?: string;
path?: Href;
color?: string;
}

View File

@@ -0,0 +1,276 @@
import { AccentColor, MainColor } from "@/constants/color-palet";
import { Ionicons } from "@expo/vector-icons";
import { router, usePathname } from "expo-router";
import React, { useEffect, useRef, useState } from "react";
import {
Animated,
ScrollView,
StyleSheet,
Text,
TouchableOpacity,
View,
} from "react-native";
export interface NavbarItem {
label: string;
icon?: keyof typeof Ionicons.glyphMap;
color?: string;
link?: string;
links?: {
label: string;
link: string;
}[];
initiallyOpened?: boolean;
}
interface NavbarMenuProps {
items: NavbarItem[];
onClose?: () => void;
}
export default function NavbarMenu({ items, onClose }: NavbarMenuProps) {
const pathname = usePathname();
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) =>
prev.includes(label) ? prev.filter((key) => key !== label) : [label]
);
};
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
function MenuItem({
item,
onClose,
activeLink,
setActiveLink,
isOpen,
toggleOpen,
}: {
item: NavbarItem;
onClose?: () => void;
activeLink: string | null;
setActiveLink: (link: string | null) => void;
isOpen: boolean;
toggleOpen: () => void;
}) {
const isActive = activeLink === item.link;
const animatedHeight = useRef(new Animated.Value(0)).current;
// Animasi saat isOpen berubah
React.useEffect(() => {
Animated.timing(animatedHeight, {
toValue: isOpen ? (item.links ? item.links.length * 40 : 0) : 0,
duration: 200,
useNativeDriver: false,
}).start();
}, [isOpen, item.links, animatedHeight]);
// Jika ada submenu
if (item.links && item.links.length > 0) {
return (
<View>
{/* Parent Item */}
<TouchableOpacity style={styles.parentItem} onPress={toggleOpen}>
<Ionicons
name={item.icon}
size={16}
color={MainColor.white}
style={styles.icon}
/>
<Text style={styles.parentText}>{item.label}</Text>
<Ionicons
name={isOpen ? "chevron-up" : "chevron-down"}
size={16}
color={MainColor.white}
/>
</TouchableOpacity>
{/* Submenu (Animated) */}
<Animated.View
style={[
styles.submenu,
// {
// backgroundColor: "red",
// },
{
height: animatedHeight,
opacity: animatedHeight.interpolate({
inputRange: [0, item.links.length * 40],
outputRange: [0, 1],
extrapolate: "clamp",
}),
},
]}
>
{item.links.map((subItem, index) => {
const isSubActive = activeLink === subItem.link;
return (
<TouchableOpacity
key={index}
style={[styles.subItem, isSubActive && styles.subItemActive]}
onPress={() => {
setActiveLink(subItem.link);
onClose?.();
router.push(subItem.link as any);
}}
>
<Ionicons
name="radio-button-on-outline"
size={16}
color={isSubActive ? MainColor.yellow : MainColor.white}
style={styles.icon}
/>
<Text
style={[
styles.subText,
isSubActive && { color: MainColor.yellow },
]}
>
{subItem.label}
</Text>
</TouchableOpacity>
);
})}
</Animated.View>
</View>
);
}
// Menu tanpa submenu
return (
<TouchableOpacity
style={[styles.singleItem, isActive && styles.singleItemActive]}
onPress={() => {
setActiveLink(item.link || null);
onClose?.();
router.push(item.link as any);
}}
>
<Ionicons
name={item.icon}
size={16}
color={isActive ? MainColor.yellow : MainColor.white}
style={styles.icon}
/>
<Text
style={[
styles.singleText,
{ color: isActive ? MainColor.yellow : MainColor.white },
]}
>
{item.label}
</Text>
</TouchableOpacity>
);
}
// Styles
const styles = StyleSheet.create({
container: {
marginBottom: 5,
},
parentItem: {
flexDirection: "row",
alignItems: "center",
paddingVertical: 12,
paddingHorizontal: 10,
// backgroundColor: AccentColor.darkblue,
borderRadius: 8,
marginBottom: 5,
justifyContent: "space-between",
},
parentText: {
flex: 1,
fontSize: 16,
fontWeight: "500",
marginLeft: 10,
color: MainColor.white,
},
singleItem: {
flexDirection: "row",
alignItems: "center",
paddingVertical: 12,
paddingHorizontal: 10,
// backgroundColor: AccentColor.darkblue,
borderRadius: 8,
marginBottom: 5,
},
singleItemActive: {
backgroundColor: AccentColor.blue,
},
singleText: {
fontSize: 16,
fontWeight: "500",
marginLeft: 10,
color: MainColor.white,
},
icon: {
width: 24,
textAlign: "center",
paddingRight: 10,
},
submenu: {
overflow: "hidden",
marginLeft: 30,
marginTop: 5,
},
subItem: {
flexDirection: "row",
alignItems: "center",
paddingVertical: 8,
paddingHorizontal: 10,
borderRadius: 6,
marginBottom: 4,
},
subItemActive: {
backgroundColor: AccentColor.blue,
},
subText: {
color: MainColor.white,
fontSize: 16,
fontWeight: "500",
},
});

View File

@@ -0,0 +1,279 @@
import React, { useEffect, useRef, useState } from "react";
import {
Animated,
Dimensions,
StyleSheet,
Text,
TouchableOpacity,
View,
} from "react-native";
import { AccentColor, MainColor } from "@/constants/color-palet";
import { Ionicons } from "@expo/vector-icons";
import { router, usePathname } from "expo-router";
// Lebar sidebar
const SIDEBAR_WIDTH = Dimensions.get("window").width * 0.8;
interface SidebarItem {
label: string;
icon?: keyof typeof Ionicons.glyphMap;
color?: string;
link?: string;
links?: {
label: string;
link: string;
}[];
initiallyOpened?: boolean;
}
interface SidebarMenuProps {
items: SidebarItem[];
onClose?: () => void;
}
export default function SidebarMenu({ items, onClose }: SidebarMenuProps) {
const pathname = usePathname();
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]);
// Auto-buka dropdown jika submenu aktif
useEffect(() => {
const activeItem = items.find((item) =>
item.links?.some((sub) => sub.link === normalizedPathname)
);
if (activeItem && !openKeys.includes(activeItem.label)) {
setOpenKeys([activeItem.label]);
}
}, [normalizedPathname, items, openKeys]);
// Toggle dropdown
const toggleOpen = (label: string) => {
setOpenKeys((prev) =>
prev.includes(label) ? prev.filter((key) => key !== label) : [label]
);
};
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>
);
}
// Komponen Item Menu
function MenuItem({
item,
onClose,
activeLink,
setActiveLink,
isOpen,
toggleOpen,
}: {
item: SidebarItem;
onClose?: () => void;
activeLink: string | null;
setActiveLink: (link: string | null) => void;
isOpen: boolean;
toggleOpen: () => void;
}) {
const animatedHeight = useRef(new Animated.Value(0)).current;
// Animasi saat isOpen berubah
React.useEffect(() => {
Animated.timing(animatedHeight, {
toValue: isOpen ? (item.links ? item.links.length * 40 : 0) : 0,
duration: 200,
useNativeDriver: false,
}).start();
}, [isOpen, item.links]);
// Cek apakah menu ini aktif
const isActive = activeLink === item.link;
// Cek apakah ada submenu aktif
const hasActiveSubItem = item.links?.some((sub) => sub.link === activeLink);
// Jika ada submenu
if (item.links && item.links.length > 0) {
return (
<View>
{/* Parent Item */}
<TouchableOpacity style={styles.parentItem} onPress={toggleOpen}>
<Ionicons
name={item.icon}
size={20}
color={MainColor.white}
style={styles.icon}
/>
<Text style={styles.parentText}>{item.label}</Text>
<Ionicons
name={isOpen ? "chevron-up" : "chevron-down"}
size={16}
color={MainColor.white}
/>
</TouchableOpacity>
{/* Submenu (Animated) */}
<Animated.View
style={[
styles.submenu,
{
height: animatedHeight,
opacity: animatedHeight.interpolate({
inputRange: [0, item.links.length * 40],
outputRange: [0, 1],
extrapolate: "clamp",
}),
},
]}
>
{item.links.map((subItem, index) => {
const isSubActive = activeLink === subItem.link;
return (
<TouchableOpacity
key={index}
style={[styles.subItem, isSubActive && styles.subItemActive]}
onPress={() => {
setActiveLink(subItem.link);
onClose?.();
router.push(subItem.link as any);
}}
>
<Ionicons
name="caret-forward-sharp"
size={16}
color={isSubActive ? MainColor.yellow : MainColor.white}
style={styles.icon}
/>
<Text
style={[
styles.subText,
isSubActive && { color: MainColor.yellow },
]}
>
{subItem.label}
</Text>
</TouchableOpacity>
);
})}
</Animated.View>
</View>
);
}
// Menu tanpa submenu
return (
<TouchableOpacity
style={[styles.singleItem, isActive && styles.singleItemActive]}
onPress={() => {
setActiveLink(item.link || null);
onClose?.();
router.push(item.link as any);
}}
>
<Ionicons
name={item.icon}
size={20}
color={isActive ? MainColor.yellow : MainColor.white}
style={styles.icon}
/>
<Text
style={[
styles.singleText,
{ color: isActive ? MainColor.yellow : MainColor.white },
]}
>
{item.label}
</Text>
</TouchableOpacity>
);
}
// Styles
const styles = StyleSheet.create({
container: {
marginTop: 20,
},
parentItem: {
flexDirection: "row",
alignItems: "center",
paddingVertical: 12,
paddingHorizontal: 10,
backgroundColor: AccentColor.darkblue,
borderRadius: 8,
marginBottom: 5,
justifyContent: "space-between",
},
parentText: {
flex: 1,
fontSize: 16,
fontWeight: "500",
marginLeft: 10,
color: MainColor.white,
},
singleItem: {
flexDirection: "row",
alignItems: "center",
paddingVertical: 12,
paddingHorizontal: 10,
backgroundColor: AccentColor.darkblue,
borderRadius: 8,
marginBottom: 5,
},
singleItemActive: {
backgroundColor: AccentColor.blue,
},
singleText: {
fontSize: 16,
fontWeight: "500",
marginLeft: 10,
color: MainColor.white,
},
icon: {
width: 24,
textAlign: "center",
paddingRight: 10,
},
submenu: {
overflow: "hidden",
marginLeft: 30,
marginTop: 5,
},
subItem: {
flexDirection: "row",
alignItems: "center",
paddingVertical: 8,
paddingHorizontal: 10,
borderRadius: 6,
marginBottom: 4,
},
subItemActive: {
backgroundColor: AccentColor.blue,
},
subText: {
color: MainColor.white,
fontSize: 14,
},
});

View File

@@ -22,7 +22,7 @@ interface TextCustomProps {
style?: StyleProp<TextStyle>;
bold?: boolean;
semiBold?: boolean;
size?: "default" | "large" | "small" | "xlarge";
size?: "default" | "large" | "small" | "xlarge" | number
color?: "default" | "yellow" | "red" | "gray" | "green" | "black"
align?: TextAlign; // Prop untuk alignment
truncate?: boolean | number;
@@ -54,6 +54,7 @@ const TextCustom: React.FC<TextCustomProps> = ({
if (size === "large") selectedStyles.push(styles.large);
else if (size === "xlarge") selectedStyles.push(styles.xlarge);
else if (size === "small") selectedStyles.push(styles.small);
else if (typeof size === "number") selectedStyles.push({ fontSize: size });
// Color
if (color === "yellow") selectedStyles.push(styles.yellow);
@@ -105,7 +106,7 @@ export const styles = StyleSheet.create({
fontSize: TEXT_SIZE_MEDIUM,
color: MainColor.white,
fontFamily: "Poppins-Regular",
lineHeight: 20,
// lineHeight: 20,
},
bold: {
fontFamily: "Poppins-Bold",

View File

@@ -0,0 +1,46 @@
import BaseBox from "@/components/Box/BaseBox";
import CircleContainer from "@/components/Container/CircleContainer";
import Grid from "@/components/Grid/GridCustom";
import StackCustom from "@/components/Stack/StackCustom";
import TextCustom from "@/components/Text/TextCustom";
import { MainColor } from "@/constants/color-palet";
interface BoxDashboardProps {
item: {
label: string;
value: string | number;
icon: React.ReactNode;
};
}
export default function AdminComp_BoxDashboard({ item }: BoxDashboardProps) {
return (
<>
<BaseBox
backgroundColor={MainColor.soft_darkblue}
paddingTop={5}
paddingBottom={5}
>
<Grid containerStyle={{ marginBlock: 0 }}>
<Grid.Col
span={9}
style={{
paddingLeft: 10,
}}
>
<StackCustom gap={"xs"}>
<TextCustom bold>{item.label}</TextCustom>
<TextCustom size={50}>{item.value}</TextCustom>
</StackCustom>
</Grid.Col>
<Grid.Col
span={3}
style={{ alignItems: "flex-start", justifyContent: "center" }}
>
<CircleContainer icon={item.icon} />
</Grid.Col>
</Grid>
</BaseBox>
</>
);
}

View File

@@ -0,0 +1,16 @@
import BaseBox from "@/components/Box/BaseBox";
import TextCustom from "@/components/Text/TextCustom";
import { TEXT_SIZE_LARGE } from "@/constants/constans-value";
export default function AdminComp_BoxTitle({ title , rightComponent}: { title: string , rightComponent?: React.ReactNode}) {
return (
<>
<BaseBox style={{ flexDirection: "row", justifyContent: "space-between" }}>
<TextCustom style={{ alignSelf: "center" }} bold size={TEXT_SIZE_LARGE}>
{title}
</TextCustom>
{rightComponent}
</BaseBox>
</>
);
}

View File

@@ -5,14 +5,16 @@ import { StyleSheet } from "react-native";
import ClickableCustom from "../Clickable/ClickableCustom";
import { router } from "expo-router";
export default function DummyLandscapeImage() {
export default function DummyLandscapeImage({height, unClickPath}: {height?: number, unClickPath?: boolean}) {
return (
<ClickableCustom
onPress={() => {
router.push("/(application)/(image)/preview-image/1");
if (!unClickPath) {
router.push("/(application)/(image)/preview-image/1");
}
}}
>
<Image source={DUMMY_IMAGE.background} style={styles.backgroundImage} />
<Image source={DUMMY_IMAGE.background} style={[styles.backgroundImage, {height: height || 200}]} />
</ClickableCustom>
);
}
@@ -20,7 +22,6 @@ export default function DummyLandscapeImage() {
const styles = StyleSheet.create({
backgroundImage: {
width: "100%",
height: 200, // Tinggi background sesuai kebutuhan
justifyContent: "center",
alignItems: "center",
borderRadius: 6,

View File

@@ -0,0 +1,25 @@
import Grid from "../Grid/GridCustom";
export default function GridComponentView({
leftIcon,
children,
rightIcon,
}: {
leftIcon?: React.ReactNode;
children: React.ReactNode;
rightIcon?: React.ReactNode;
}) {
return (
<Grid containerStyle={{ marginBottom: 0 }}>
<Grid.Col span={1} style={{ justifyContent: "center" }}>
{leftIcon}
</Grid.Col>
<Grid.Col span={10} style={{ justifyContent: "center" }}>
{children}
</Grid.Col>
<Grid.Col span={1} style={{ justifyContent: "center" }}>
{rightIcon}
</Grid.Col>
</Grid>
);
}

View File

@@ -55,6 +55,7 @@ import TabBarBackground from "./_ShareComponent/TabBarBackground";
import ViewWrapper from "./_ShareComponent/ViewWrapper";
import SearchInput from "./_ShareComponent/SearchInput";
import DummyLandscapeImage from "./_ShareComponent/DummyLandscapeImage";
import GridComponentView from "./_ShareComponent/GridSectionView";
// Progress
import ProgressCustom from "./Progress/ProgressCustom";
@@ -107,6 +108,7 @@ export {
// ShareComponent
SearchInput,
DummyLandscapeImage,
GridComponentView,
Spacing,
// Stack
StackCustom,

View File

@@ -0,0 +1,18 @@
export const dummyDonasiDurasi = [
{
label: "1 Bulan",
value: "1_bulan",
},
{
label: "3 Bulan",
value: "3_bulan",
},
{
label: "6 Bulan",
value: "6_bulan",
},
{
label: "1 Tahun",
value: "1_tahun",
},
];

View File

@@ -0,0 +1,22 @@
export const dummyDonasiKategori = [
{
label: "Medis",
value: "medis",
},
{
label: "Pendidikan",
value: "pendidikan",
},
{
label: "Kesehatan",
value: "kesehatan",
},
{
label: "Bantuan Sosial",
value: "bantuan_sosial",
},
{
label: "Lainnya",
value: "lainnya",
},
];

View File

@@ -0,0 +1,9 @@
import AdminComp_BoxTitle from "@/components/_ShareComponent/Admin/BoxTitlePage";
export default function AdminAppInformation_BusinessFieldSection() {
return (
<>
<AdminComp_BoxTitle title="Bidang Bisnis" />
</>
);
}

View File

@@ -0,0 +1,95 @@
import {
BaseBox,
ButtonCustom,
Divider,
Grid,
TextCustom
} from "@/components";
import AdminComp_BoxTitle from "@/components/_ShareComponent/Admin/BoxTitlePage";
import { MainColor } from "@/constants/color-palet";
import { ICON_SIZE_SMALL } from "@/constants/constans-value";
import { dummyMasterBank } from "@/lib/dummy-data/_master/bank";
import { FontAwesome5, Ionicons } from "@expo/vector-icons";
import { useState } from "react";
import { TouchableOpacity, View } from "react-native";
import { Switch } from "react-native-paper";
export default function AdminAppInformation_Bank() {
const [value, setValue] = useState(false);
return (
<>
<AdminComp_BoxTitle
title="Bank"
rightComponent={
<TouchableOpacity
activeOpacity={0.7}
style={{
backgroundColor: MainColor.yellow,
padding: 5,
borderRadius: 50,
}}
onPress={() => {}}
>
<Ionicons name="add" size={16} color="black" />
</TouchableOpacity>
}
/>
<BaseBox>
<Grid>
<Grid.Col span={4} style={{ alignItems: "center" }}>
<TextCustom bold>Aksi</TextCustom>
</Grid.Col>
<Grid.Col span={4} style={{ alignItems: "center" }}>
<TextCustom bold>Status</TextCustom>
</Grid.Col>
<Grid.Col span={4}>
<TextCustom bold>Nama Bank</TextCustom>
</Grid.Col>
</Grid>
<Divider />
{dummyMasterBank.map((e, i) => (
<View key={i}>
<Grid>
<Grid.Col span={4}>
<ButtonCustom
iconLeft={
<FontAwesome5
name="edit"
size={ICON_SIZE_SMALL}
color="black"
/>
}
onPress={() => {}}
>
Edit
</ButtonCustom>
</Grid.Col>
<Grid.Col
span={4}
style={{ alignItems: "center", justifyContent: "center" }}
>
<Switch
value={value}
onValueChange={() => {
setValue(!value);
}}
theme={{
colors: {
primary: MainColor.yellow,
},
}}
/>
</Grid.Col>
<Grid.Col span={4} style={{ justifyContent: "center" }}>
<TextCustom>{e.code}</TextCustom>
</Grid.Col>
</Grid>
<Divider />
</View>
))}
</BaseBox>
</>
);
}

View File

@@ -0,0 +1,9 @@
import AdminComp_BoxTitle from "@/components/_ShareComponent/Admin/BoxTitlePage";
export default function AdminAppInformation_StickerSection() {
return (
<>
<AdminComp_BoxTitle title="Sticker" />
</>
);
}

View File

@@ -0,0 +1,96 @@
import { NavbarItem } from "@/components/Drawer/NavbarMenu";
export { adminListMenu }
const adminListMenu: 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/app-information",
},
{
label: "User Access",
icon: "people",
link: "/admin/user-access",
},
];

View File

@@ -38,7 +38,9 @@ export default function LoginView() {
// router.navigate(`/(application)/(image)/preview-image/${id}`);
// router.replace("/(application)/(user)/event/(tabs)");
// router.replace("/(application)/coba");
router.navigate("/investment/(tabs)")
// router.navigate("/investment/(tabs)")1
// router.navigate("/crowdfunding")
router.navigate("/admin/dashboard")
}
return (

View File

@@ -0,0 +1,41 @@
import {
BaseBox,
Grid,
DummyLandscapeImage,
StackCustom,
TextCustom,
ProgressCustom,
} from "@/components";
import { View } from "react-native";
export default function Donation_BoxPublish({ id }: { id: string }) {
return (
<>
<BaseBox paddingTop={7} paddingBottom={7} href={`/donation/${id}`}>
<Grid>
<Grid.Col span={5}>
<DummyLandscapeImage unClickPath height={100} />
</Grid.Col>
<Grid.Col span={1}>
<View />
</Grid.Col>
<Grid.Col span={6}>
<StackCustom>
<View>
<TextCustom truncate>
Judul Donasi: Lorem ipsum dolor sit amet consectetur
adipisicing elit.
</TextCustom>
<TextCustom size="small">Sisa hari: 0</TextCustom>
</View>
<ProgressCustom value={(Number(id) % 5) * 20} size="lg" />
{/* <TextCustom>
Terkumpul : Rp 300.000
</TextCustom> */}
</StackCustom>
</Grid.Col>
</Grid>
</BaseBox>
</>
);
}

View File

@@ -0,0 +1,50 @@
import {
BaseBox,
Grid,
DummyLandscapeImage,
StackCustom,
TextCustom,
} from "@/components";
import { View } from "react-native";
export default function Donasi_BoxStatus({
id,
status,
}: {
id: string;
status: string;
}) {
return (
<>
<BaseBox
paddingTop={7}
paddingBottom={7}
href={`/donation/${id}/${status}/detail`}
>
<Grid>
<Grid.Col span={5}>
<DummyLandscapeImage unClickPath height={100} />
</Grid.Col>
<Grid.Col span={1}>
<View />
</Grid.Col>
<Grid.Col span={6}>
<StackCustom>
<TextCustom truncate>
Judul Donasi: {status} Lorem ipsum dolor sit amet consectetur
adipisicing elit.
</TextCustom>
<View>
<TextCustom>Target Dana</TextCustom>
<TextCustom bold color="yellow">
Rp. 7.500.000
</TextCustom>
</View>
</StackCustom>
</Grid.Col>
</Grid>
</BaseBox>
</>
);
}

View File

@@ -0,0 +1,121 @@
import { AlertDefaultSystem, ButtonCustom, Grid } from "@/components";
import { router } from "expo-router";
export default function Donation_ButtonStatusSection({
status,
}: {
status: string;
}) {
const handleBatalkanReview = () => {
AlertDefaultSystem({
title: "Batalkan Review",
message: "Apakah Anda yakin ingin batalkan review ini?",
textLeft: "Batal",
textRight: "Ya",
onPressRight: () => {
console.log("Hapus");
router.back();
},
});
};
const handleAjukanReview = () => {
AlertDefaultSystem({
title: "Ajukan Review",
message: "Apakah Anda yakin ingin ajukan review ini?",
textLeft: "Batal",
textRight: "Ya",
onPressRight: () => {
console.log("Hapus");
router.back();
},
});
};
const handleEditKembali = () => {
AlertDefaultSystem({
title: "Edit Kembali",
message: "Apakah Anda yakin ingin edit kembali ini?",
textLeft: "Batal",
textRight: "Ya",
onPressRight: () => {
console.log("Hapus");
router.back();
},
});
};
const handleOpenDeleteAlert = () => {
AlertDefaultSystem({
title: "Hapus",
message: "Apakah Anda yakin ingin menghapus data ini?",
textLeft: "Batal",
textRight: "Hapus",
onPressRight: () => {
console.log("Hapus");
router.back();
},
});
};
const DeleteButton = () => {
return (
<>
<ButtonCustom
backgroundColor="red"
textColor="white"
onPress={handleOpenDeleteAlert}
>
Hapus
</ButtonCustom>
</>
);
};
switch (status) {
case "publish":
return <></>;
case "review":
return (
<ButtonCustom onPress={handleBatalkanReview}>
Batalkan Review
</ButtonCustom>
);
case "draft":
return (
<>
<Grid>
<Grid.Col span={6} style={{ paddingRight: 10 }}>
<ButtonCustom onPress={handleAjukanReview}>
Ajukan Review
</ButtonCustom>
</Grid.Col>
<Grid.Col span={6} style={{ paddingLeft: 10 }}>
{DeleteButton()}
</Grid.Col>
</Grid>
</>
);
case "reject":
return (
<>
<Grid>
<Grid.Col span={6} style={{ paddingRight: 10 }}>
<ButtonCustom onPress={handleEditKembali}>
Edit Kembali
</ButtonCustom>
</Grid.Col>
<Grid.Col span={6} style={{ paddingLeft: 10 }}>
{DeleteButton()}
</Grid.Col>
</Grid>
</>
);
default:
return <ButtonCustom disabled>Status Undifined</ButtonCustom>;
}
}

View File

@@ -0,0 +1,52 @@
import {
BaseBox,
StackCustom,
DummyLandscapeImage,
TextCustom,
Grid,
} from "@/components";
import React from "react";
import { View } from "react-native";
export default function Donation_ComponentBoxDetailData({
bottomSection,
}: {
bottomSection?: React.ReactNode;
}) {
return (
<>
<BaseBox>
<StackCustom>
<DummyLandscapeImage />
<View>
<TextCustom bold size="large">
Judul Donasi: Lorem, ipsum dolor sit amet consectetur adipisicing
elit.
</TextCustom>
<TextCustom size="small">Durasi: 30 hari</TextCustom>
</View>
<Grid>
<Grid.Col span={6}>
<View>
<TextCustom size="small">Target Dana</TextCustom>
<TextCustom truncate={2} size="large" bold color="yellow">
Rp. 7.500.000
</TextCustom>
</View>
</Grid.Col>
<Grid.Col span={6}>
<View>
<TextCustom size="small">Kategori</TextCustom>
<TextCustom size="large" bold color="yellow">
Kegiatan Sosial
</TextCustom>
</View>
</Grid.Col>
</Grid>
{bottomSection}
</StackCustom>
</BaseBox>
</>
);
}

View File

@@ -0,0 +1,48 @@
import {
AvatarUsernameAndOtherComponent,
BaseBox,
Grid,
InformationBox,
StackCustom,
TextCustom,
} from "@/components";
import { MainColor } from "@/constants/color-palet";
import { ICON_SIZE_SMALL } from "@/constants/constans-value";
import { Ionicons } from "@expo/vector-icons";
export default function Donation_ComponentInfoFundrising({
id,
}: {
id: string;
}) {
return (
<>
<BaseBox href={`/donation/${id}/infromation-fundrising`} style={{paddingBottom: 0}}>
<StackCustom gap={"xs"}>
<Grid>
<Grid.Col span={10}>
<TextCustom bold size="large">
Informasi Penggalang Dana
</TextCustom>
</Grid.Col>
<Grid.Col span={2}>
<Ionicons
name="chevron-forward-circle-outline"
size={ICON_SIZE_SMALL}
color={MainColor.yellow}
style={{
alignSelf: "flex-end",
}}
/>
</Grid.Col>
</Grid>
<AvatarUsernameAndOtherComponent />
<InformationBox
text="Semua dana yang terkumpul akan disalurkan ke penggalang dana, kabar penyaluran dapat dilihat di halaman kabar terbaru."
/>
</StackCustom>
</BaseBox>
</>
);
}

View File

@@ -0,0 +1,42 @@
import { BaseBox, StackCustom, Grid, TextCustom } from "@/components";
import { MainColor } from "@/constants/color-palet";
import { ICON_SIZE_SMALL } from "@/constants/constans-value";
import { Ionicons } from "@expo/vector-icons";
export default function Donation_ComponentStoryFunrising({
id,
}: {
id: string;
}) {
return (
<>
<BaseBox href={`/donation/${id}/detail-story`}>
<StackCustom gap={"xs"}>
<Grid>
<Grid.Col span={10}>
<TextCustom bold size="large">
Cerita Penggalang Dana
</TextCustom>
</Grid.Col>
<Grid.Col span={2}>
<Ionicons
name="chevron-forward-circle-outline"
size={ICON_SIZE_SMALL}
color={MainColor.yellow}
style={{
alignSelf: "flex-end",
}}
/>
</Grid.Col>
</Grid>
<TextCustom truncate={3}>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Totam,
iusto porro quae optio accusantium amet minima deleniti temporibus
cum voluptatem vel veniam doloribus blanditiis sapiente deserunt
distinctio eaque aliquid laboriosam?
</TextCustom>
</StackCustom>
</BaseBox>
</>
);
}

View File

@@ -0,0 +1,70 @@
import {
ClickableCustom,
Grid,
ProgressCustom,
Spacing,
TextCustom,
} from "@/components";
import { MainColor } from "@/constants/color-palet";
import { ICON_SIZE_MEDIUM } from "@/constants/constans-value";
import { Ionicons, MaterialIcons } from "@expo/vector-icons";
import { router } from "expo-router";
import { View } from "react-native";
export default function Donation_ProgressSection({ id }: { id: string }) {
return (
<>
<View>
<ProgressCustom size="lg" />
<Spacing />
<Grid>
<Grid.Col span={4}>
<ClickableCustom
onPress={() => router.push(`/donation/${id}/list-of-donatur`)}
>
<View style={{ alignItems: "center" }}>
<Ionicons
name="flower-sharp"
size={ICON_SIZE_MEDIUM}
color={MainColor.yellow}
/>
<Spacing height={10} />
<TextCustom size="small">Donatur</TextCustom>
</View>
</ClickableCustom>
</Grid.Col>
<Grid.Col span={4}>
<ClickableCustom
onPress={() => router.push(`/donation/${id}/(news)/list-of-news`)}
>
<View style={{ alignItems: "center" }}>
<Ionicons
name="chatbox"
size={ICON_SIZE_MEDIUM}
color={MainColor.yellow}
/>
<Spacing height={10} />
<TextCustom size="small">Kabar Terbaru</TextCustom>
</View>
</ClickableCustom>
</Grid.Col>
<Grid.Col span={4}>
<ClickableCustom
onPress={() => router.push(`/donation/${id}/fund-disbursement`)}
>
<View style={{ alignItems: "center" }}>
<MaterialIcons
name="transfer-within-a-station"
size={ICON_SIZE_MEDIUM}
color={MainColor.yellow}
/>
<Spacing height={10} />
<TextCustom size="small">Pencairan Dana</TextCustom>
</View>
</ClickableCustom>
</Grid.Col>
</Grid>
</View>
</>
);
}

View File

@@ -52,11 +52,17 @@ export const drawerItemsProfile = ({
label: "Tambah portofolio",
path: `/(application)/portofolio/${id}/create`,
},
// {
// icon: "settings",
// label: "Dashboard Admin",
// path: `/(application)/profile/dashboard-admin`,
// },
{
icon: (
<Ionicons
name="settings"
size={ICON_SIZE_MEDIUM}
color={AccentColor.white}
/>
),
label: "Dashboard Admin",
path: `/(application)/admin/dashboard`,
},
{
icon: (
<Ionicons

View File

@@ -26,9 +26,14 @@ export default function Profile_MenuDrawerSection({
<>
{/* Menu Items */}
<MenuDrawerDynamicGrid
data={drawerItems}
data={drawerItems.map((item) => ({
icon: item.icon,
label: item.label,
path: item.path as any,
color: item.color,
}))}
columns={4} // Ubah ke 2 jika ingin 2 kolom per baris
onPressItem={handlePress}
onPressItem={(item) => handlePress(item as any)}
/>
</>
);