Compare commits

...

9 Commits

Author SHA1 Message Date
aa4ea9fb0c deskripsi:
Fix: ProfileSection & /dummy-user ( image )
Event: box publisj

# No Issue"
2025-07-23 10:25:40 +08:00
81d86885f4 Deskripsi
Event:
Add  app/(application)/(user)/event/[id]/history

# No Issue"
2025-07-22 15:20:53 +08:00
814f261881 Deskripsi:
Event:
Add history detail
Fix : - nama variabel pada [id]/

Component
Fix:
- Spacing : tipe data num | str
- ScrollView : tambah background

# No Issue "
2025-07-22 14:56:29 +08:00
7889d25a44 Deskripsi:
Event:
Add  app/(application)/(user)/event/(tabs)/contribution.tsx
     app/(application)/(user)/event/(tabs)/history.tsx

Fix modified:   app/(application)/(user)/event/(tabs)/_layout.tsx
        deleted:    app/(application)/(user)/event/(tabs)/kontribusi.tsx
        deleted:    app/(application)/(user)/event/(tabs)/riwayat.tsx
    modified:   app/(application)/(user)/event/[id]/publish.tsx

# No Issue
2025-07-22 12:14:08 +08:00
ce0e82e627 Deskripsi:
Event:
Add file:
- contibution with id
- list of participan
- publish
- BoxDetailPublishSection
- BoxPublishSection
- menuDrawerPublish

Fix:
Event:
- layout dan index\

# No Issue
2025-07-22 12:06:54 +08:00
08dfd62bfd Deskripsi:
Event:
Add menu drawer draft
Fix event layoutk, index (beranda) , kontribusi

Comp
Add share avatar-username

# No Issue
2025-07-22 10:35:47 +08:00
c8cc0f0232 deskripsi
Fix: page event/id/deteil menjadi event/id/status
Feature:
Add  screens/Event/AlertButtonStatusSection
Add app/(application)/(user)/event/[id]/[status]/

# No Issue"
2025-07-21 17:39:37 +08:00
b844a8151d deskripsi:
Fix event: layout dan event deatil
Feature: Button dot, edit screen

# No Issue
2025-07-21 15:23:18 +08:00
f9e96aa077 Deskripsi:
Fix: event beranda dan status > tampilan
Feature: create event dan halaman detail status
Fix: Basebox: Hide safearea kalau ada tabs
Fix: TextCustom: Tambah size xlarge
Fix: ScrollCustom penambhan props value

# No Issue
2025-07-18 16:30:56 +08:00
39 changed files with 1169 additions and 148 deletions

View File

@@ -92,6 +92,22 @@ export default function UserLayout() {
}}
/>
<Stack.Screen
name="event/[id]/edit"
options={{
title: "Edit Event",
headerLeft: () => <BackButton />,
}}
/>
<Stack.Screen
name="event/[id]/list-of-participants"
options={{
title: "Daftar peserta",
headerLeft: () => <BackButton />,
}}
/>
{/* ========== Forum Section ========= */}
<Stack.Screen
name="forum/create"

View File

@@ -4,7 +4,7 @@ import { FontAwesome5, Ionicons } from "@expo/vector-icons";
import { Tabs } from "expo-router";
import { Platform, View } from "react-native";
export default function EventLayout() {
export default function EventTabsLayout() {
return (
<Tabs
screenOptions={{
@@ -30,7 +30,7 @@ export default function EventLayout() {
<Tabs.Screen
name="index"
options={{
title: "Home",
title: "Beranda",
tabBarIcon: ({ color }) => (
<Ionicons size={20} name="home" color={color} />
),
@@ -46,7 +46,7 @@ export default function EventLayout() {
}}
/>
<Tabs.Screen
name="kontribusi"
name="contribution"
options={{
title: "Kontribusi",
tabBarIcon: ({ color }) => (
@@ -55,7 +55,7 @@ export default function EventLayout() {
}}
/>
<Tabs.Screen
name="riwayat"
name="history"
options={{
title: "Riwayat",
tabBarIcon: ({ color }) => (

View File

@@ -0,0 +1,43 @@
import {
AvatarCustom,
AvatarUsernameAndOtherComponent,
BoxWithHeaderSection,
Grid,
StackCustom,
TextCustom,
ViewWrapper
} from "@/components";
import React from "react";
export default function EventContribution() {
return (
<ViewWrapper hideFooter>
{Array.from({ length: 10 }).map((_, index) => (
<BoxWithHeaderSection key={index} href={`/event/${index}/contribution`}>
<StackCustom>
<AvatarUsernameAndOtherComponent
avatarHref={`/profile/${index}`}
rightComponent={
<TextCustom truncate>
{new Date().toLocaleDateString()}
</TextCustom>
}
/>
<TextCustom bold align="center" size="xlarge">
Judul Event Disini
</TextCustom>
<Grid>
{Array.from({ length: 4 }).map((_, index2) => (
<Grid.Col span={3} key={index2}>
<AvatarCustom size="sm" href={`/profile/${index2}`} />
</Grid.Col>
))}
</Grid>
</StackCustom>
</BoxWithHeaderSection>
))}
</ViewWrapper>
);
}

View File

@@ -0,0 +1,68 @@
import { ButtonCustom, Spacing, TextCustom } from "@/components";
import ViewWrapper from "@/components/_ShareComponent/ViewWrapper";
import { AccentColor, MainColor } from "@/constants/color-palet";
import Event_BoxPublishSection from "@/screens/Event/BoxPublishSection";
import { useState } from "react";
import { View } from "react-native";
export default function EventHistory() {
const [activeCategory, setActiveCategory] = useState<string | null>("all");
const handlePress = (item: any) => {
setActiveCategory(item);
// tambahkan logika lain seperti filter dsb.
};
const headerComponent = (
<View
style={{
flexDirection: "row",
alignItems: "center",
padding: 5,
backgroundColor: MainColor.soft_darkblue,
borderRadius: 50,
width: "100%",
}}
>
<ButtonCustom
backgroundColor={
activeCategory === "all" ? MainColor.yellow : AccentColor.blue
}
textColor={activeCategory === "all" ? MainColor.black : MainColor.white}
style={{ width: "49%" }}
onPress={() => handlePress("all")}
>
Semua Riwayat
</ButtonCustom>
<Spacing width={"2%"} />
<ButtonCustom
backgroundColor={
activeCategory === "main" ? MainColor.yellow : AccentColor.blue
}
textColor={
activeCategory === "main" ? MainColor.black : MainColor.white
}
style={{ width: "49%" }}
onPress={() => handlePress("main")}
>
Riwayat Saya
</ButtonCustom>
</View>
);
return (
<ViewWrapper headerComponent={headerComponent} hideFooter>
{Array.from({ length: 10 }).map((_, index) => (
<Event_BoxPublishSection
key={index.toString()}
id={index.toString()}
username={`Riwayat ${activeCategory === "main" ? "Saya" : "Semua"}`}
rightComponentAvatar={
<TextCustom>{new Date().toLocaleDateString()}</TextCustom>
}
href={`/event/${index}/history`}
/>
))}
</ViewWrapper>
);
}

View File

@@ -1,30 +1,23 @@
import ViewWrapper from "@/components/_ShareComponent/ViewWrapper";
import FloatingButton from "@/components/Button/FloatingButton";
import { AccentColor, MainColor } from "@/constants/color-palet";
import { GStyles } from "@/styles/global-styles";
import Event_BoxPublishSection from "@/screens/Event/BoxPublishSection";
import { router } from "expo-router";
import { Text, TouchableHighlight, View } from "react-native";
export default function Event() {
export default function EventBeranda() {
return (
<ViewWrapper
hideFooter
floatingButton={
<FloatingButton onPress={() => router.push("/event/create")} />
}
>
<TouchableHighlight onPress={() => router.push("/event/detail/1")}>
<View
style={{
padding: 20,
backgroundColor: MainColor.darkblue,
borderRadius: 10,
borderColor: AccentColor.blue,
borderWidth: 1,
}}
>
<Text style={GStyles.textLabel}>Event</Text>
</View>
</TouchableHighlight>
{Array.from({ length: 10 }).map((_, index) => (
<Event_BoxPublishSection
key={index}
id={index.toString()}
href={`/event/${index}/publish`}
/>
))}
</ViewWrapper>
);
}

View File

@@ -1,11 +0,0 @@
import ViewWrapper from "@/components/_ShareComponent/ViewWrapper";
import { GStyles } from "@/styles/global-styles";
import { Text } from "react-native";
export default function Kontribusi() {
return (
<ViewWrapper>
<Text style={GStyles.textLabel}>Kontribusi</Text>
</ViewWrapper>
);
}

View File

@@ -1,11 +0,0 @@
import ViewWrapper from "@/components/_ShareComponent/ViewWrapper";
import { GStyles } from "@/styles/global-styles";
import { Text } from "react-native";
export default function Riwayat() {
return (
<ViewWrapper>
<Text style={GStyles.textLabel}>Riwayat</Text>
</ViewWrapper>
);
}

View File

@@ -1,11 +1,63 @@
import {
BoxWithHeaderSection,
Grid,
ScrollableCustom,
StackCustom,
TextCustom
} from "@/components";
import ViewWrapper from "@/components/_ShareComponent/ViewWrapper";
import { GStyles } from "@/styles/global-styles";
import { Text } from "react-native";
import { masterStatus } from "@/lib/dummy-data/_master/status";
import { useState } from "react";
export default function EventStatus() {
const id = "test-id-event";
const [activeCategory, setActiveCategory] = useState<string | null>(
"publish"
);
const handlePress = (item: any) => {
setActiveCategory(item.value);
// tambahkan logika lain seperti filter dsb.
};
const scrollComponent = (
<ScrollableCustom
data={masterStatus.map((e, i) => ({
id: i,
label: e.label,
value: e.value,
}))}
onButtonPress={handlePress}
activeId={activeCategory as any}
/>
);
export default function Status() {
return (
<ViewWrapper>
<Text style={GStyles.textLabel}>Status</Text>
<ViewWrapper headerComponent={scrollComponent}>
<BoxWithHeaderSection href={`/event/${id}/${activeCategory}/detail-event`}>
<StackCustom gap={"xs"}>
<Grid>
<Grid.Col span={8}>
<TextCustom truncate bold>
Lorem ipsum,{" "}
<TextCustom color="green">{activeCategory}</TextCustom> dolor
sit amet consectetur adipisicing elit.
</TextCustom>
</Grid.Col>
<Grid.Col span={4} style={{ alignItems: "flex-end" }}>
<TextCustom>{new Date().toLocaleDateString()}</TextCustom>
</Grid.Col>
</Grid>
<TextCustom truncate={2}>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Consectetur
eveniet ab eum ducimus tempore a quia deserunt quisquam. Tempora,
atque. Aperiam minima asperiores dicta perferendis quis adipisci,
dolore optio porro!
</TextCustom>
</StackCustom>
</BoxWithHeaderSection>
</ViewWrapper>
);
}

View File

@@ -0,0 +1,117 @@
import {
BaseBox,
DotButton,
DrawerCustom,
Grid,
MenuDrawerDynamicGrid,
Spacing,
StackCustom,
TextCustom,
ViewWrapper,
} from "@/components";
import { IMenuDrawerItem } from "@/components/_Interface/types";
import LeftButtonCustom from "@/components/Button/BackButton";
import Event_AlertButtonStatusSection from "@/screens/Event/AlertButtonStatusSection";
import Event_ButtonStatusSection from "@/screens/Event/ButtonStatusSection";
import { menuDrawerDraftEvent } from "@/screens/Event/menuDrawerDraft";
import { router, Stack, useLocalSearchParams } from "expo-router";
import { useState } from "react";
export default function EventDetailStatus() {
const { id, status } = useLocalSearchParams();
const [openDrawer, setOpenDrawer] = useState(false);
const [openAlert, setOpenAlert] = useState(false);
const [openDeleteAlert, setOpenDeleteAlert] = 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 ${status === "publish" ? "" : status}`,
headerLeft: () => <LeftButtonCustom />,
headerRight: () =>
status === "draft" ? (
<DotButton onPress={() => setOpenDrawer(true)} />
) : null,
}}
/>
<ViewWrapper>
<BaseBox>
<StackCustom>
<TextCustom bold align="center" size="xlarge">
Judul event {status}
</TextCustom>
{listData.map((item, index) => (
<Grid key={index}>
<Grid.Col span={4}>
<TextCustom bold>{item.title}</TextCustom>
</Grid.Col>
<Grid.Col span={8}>
<TextCustom>{item.value}</TextCustom>
</Grid.Col>
</Grid>
))}
</StackCustom>
</BaseBox>
<Event_ButtonStatusSection
status={status as string}
onOpenAlert={setOpenAlert}
onOpenDeleteAlert={setOpenDeleteAlert}
/>
<Spacing />
</ViewWrapper>
<DrawerCustom
isVisible={openDrawer}
closeDrawer={() => setOpenDrawer(false)}
height={250}
>
<MenuDrawerDynamicGrid
data={menuDrawerDraftEvent({ id: id as string })}
columns={4}
onPressItem={handlePress}
/>
</DrawerCustom>
<Event_AlertButtonStatusSection
id={id as string}
status={status as string}
openAlert={openAlert}
setOpenAlert={setOpenAlert}
openDeleteAlert={openDeleteAlert}
setOpenDeleteAlert={setOpenDeleteAlert}
/>
</>
);
}
const listData = [
{
title: "Lokasi",
value:
"Lorem ipsum dolor sit amet consectetur adipisicing elit. Consectetur eveniet ab eum ducimus tempore a quia deserunt quisquam. Tempora, atque. Aperiam minima asperiores dicta perferendis quis adipisci, dolore optio porro!",
},
{
title: "Tipe Acara",
value: "Workshop",
},
{
title: "Tanggal Mulai",
value: "Senin, 18 Juli 2025, 10:00 WIB",
},
{
title: "Tanggal Berakhir",
value: "Selasa, 19 Juli 2025, 12:00 WIB",
},
{
title: "Deskripsi",
value:
"Lorem ipsum dolor sit amet consectetur adipisicing elit. Consectetur eveniet ab eum ducimus tempore a quia deserunt quisquam. Tempora, atque. Aperiam minima asperiores dicta perferendis quis adipisci, dolore optio porro!",
},
];

View File

@@ -0,0 +1,51 @@
import {
DotButton,
DrawerCustom,
MenuDrawerDynamicGrid,
ViewWrapper,
Spacing,
} from "@/components";
import { IMenuDrawerItem } from "@/components/_Interface/types";
import LeftButtonCustom from "@/components/Button/BackButton";
import Event_BoxDetailPublishSection from "@/screens/Event/BoxDetailPublishSection";
import { menuDrawerPublishEvent } from "@/screens/Event/menuDrawerPublish";
import { router, Stack, useLocalSearchParams } from "expo-router";
import { useState } from "react";
export default function EventDetailContribution() {
const { id } = useLocalSearchParams();
const [openDrawer, setOpenDrawer] = 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 kontribusi`,
headerLeft: () => <LeftButtonCustom />,
headerRight: () => <DotButton onPress={() => setOpenDrawer(true)} />,
}}
/>
<ViewWrapper>
<Event_BoxDetailPublishSection />
<Spacing />
</ViewWrapper>
<DrawerCustom
isVisible={openDrawer}
closeDrawer={() => setOpenDrawer(false)}
height={250}
>
<MenuDrawerDynamicGrid
data={menuDrawerPublishEvent({ id: id as string })}
columns={4}
onPressItem={handlePress}
/>
</DrawerCustom>
</>
);
}

View File

@@ -0,0 +1,107 @@
import {
ButtonCustom,
SelectCustom,
StackCustom,
TextAreaCustom,
TextInputCustom,
ViewWrapper,
} from "@/components";
import DateTimePickerCustom from "@/components/DateInput/DateTimePickerCustom";
import { masterTypeEvent } from "@/lib/dummy-data/event/master-type-event";
import { DateTimePickerEvent } from "@react-native-community/datetimepicker";
import { router } from "expo-router";
import React, { useState } from "react";
import { Platform } from "react-native";
export default function EventEdit() {
const [selectedDate, setSelectedDate] = useState<
Date | DateTimePickerEvent | null
>(null);
const [selectedEndDate, setSelectedEndDate] = useState<
Date | DateTimePickerEvent | null
>(null);
const handlerSubmit = () => {
try {
if (selectedDate) {
console.log("Tanggal yang dipilih:", selectedDate);
console.log(`ISO Format ${Platform.OS}:`, selectedDate.toString());
// Kirim ke API atau proses lanjutan
} else {
console.log("Tanggal belum dipilih");
}
if (selectedEndDate) {
console.log("Tanggal yang dipilih:", selectedEndDate);
console.log(`ISO Format ${Platform.OS}:`, selectedEndDate.toString());
// Kirim ke API atau proses lanjutan
} else {
console.log("Tanggal berakhir belum dipilih");
}
console.log("Data berhasil terupdate");
router.back()
} catch (error) {
console.log(error);
}
};
const buttonSubmit = (
<ButtonCustom title="Update" onPress={handlerSubmit} />
);
return (
<>
<ViewWrapper>
<StackCustom gap={"xs"}>
<TextInputCustom
placeholder="Masukkan nama event"
label="Nama Event"
required
/>
<SelectCustom
label="Tipe Event"
placeholder="Pilih tipe event"
data={masterTypeEvent}
onChange={(value) => console.log(value)}
/>
<TextInputCustom
label="Lokasi"
placeholder="Masukkan lokasi event"
required
/>
<DateTimePickerCustom
label="Tanggal & Waktu Mulai"
required
onChange={(date: Date) => {
setSelectedDate(date as any);
}}
value={selectedDate as any}
minimumDate={new Date(Date.now())}
/>
<DateTimePickerCustom
label="Tanggal & Waktu Berakhir"
required
onChange={(date: Date) => {
setSelectedEndDate(date as any);
}}
value={selectedEndDate as any}
/>
<TextAreaCustom
label="Deskripsi"
placeholder="Masukkan deskripsi event"
required
showCount
maxLength={100}
/>
{buttonSubmit}
</StackCustom>
</ViewWrapper>
</>
);
}

View File

@@ -0,0 +1,51 @@
import {
DotButton,
DrawerCustom,
MenuDrawerDynamicGrid,
ViewWrapper,
Spacing,
} from "@/components";
import { IMenuDrawerItem } from "@/components/_Interface/types";
import LeftButtonCustom from "@/components/Button/BackButton";
import Event_BoxDetailPublishSection from "@/screens/Event/BoxDetailPublishSection";
import { menuDrawerPublishEvent } from "@/screens/Event/menuDrawerPublish";
import { router, Stack, useLocalSearchParams } from "expo-router";
import { useState } from "react";
export default function EventDetailHistory() {
const { id } = useLocalSearchParams();
const [openDrawer, setOpenDrawer] = 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 riwayat`,
headerLeft: () => <LeftButtonCustom />,
headerRight: () => <DotButton onPress={() => setOpenDrawer(true)} />,
}}
/>
<ViewWrapper>
<Event_BoxDetailPublishSection />
<Spacing />
</ViewWrapper>
<DrawerCustom
isVisible={openDrawer}
closeDrawer={() => setOpenDrawer(false)}
height={250}
>
<MenuDrawerDynamicGrid
data={menuDrawerPublishEvent({ id: id as string })}
columns={4}
onPressItem={handlePress}
/>
</DrawerCustom>
</>
);
}

View File

@@ -0,0 +1,17 @@
import {
AvatarUsernameAndOtherComponent,
BaseBox,
ViewWrapper,
} from "@/components";
export default function EventListOfParticipants() {
return (
<ViewWrapper>
{Array.from({ length: 10 }).map((_, index) => (
<BaseBox key={index} paddingBlock={0}>
<AvatarUsernameAndOtherComponent avatarHref={`/profile/${index}`} />
</BaseBox>
))}
</ViewWrapper>
);
}

View File

@@ -0,0 +1,64 @@
import {
ButtonCustom,
DotButton,
DrawerCustom,
MenuDrawerDynamicGrid,
Spacing,
ViewWrapper
} from "@/components";
import { IMenuDrawerItem } from "@/components/_Interface/types";
import LeftButtonCustom from "@/components/Button/BackButton";
import Event_BoxDetailPublishSection from "@/screens/Event/BoxDetailPublishSection";
import { menuDrawerPublishEvent } from "@/screens/Event/menuDrawerPublish";
import { router, Stack, useLocalSearchParams } from "expo-router";
import { useState } from "react";
import { Alert } from "react-native";
export default function EventDetailPublish() {
const { id } = useLocalSearchParams();
const [openDrawer, setOpenDrawer] = useState(false);
const handlePress = (item: IMenuDrawerItem) => {
console.log("PATH ", item.path);
router.navigate(item.path as any);
setOpenDrawer(false);
};
const footerButton = (
<ButtonCustom
backgroundColor="green"
textColor="white"
onPress={() => Alert.alert("Anda berhasil join event ini")}
>
Join
</ButtonCustom>
);
return (
<>
<Stack.Screen
options={{
title: `Event publish`,
headerLeft: () => <LeftButtonCustom />,
headerRight: () => <DotButton onPress={() => setOpenDrawer(true)} />,
}}
/>
<ViewWrapper>
<Event_BoxDetailPublishSection footerButton={footerButton} />
<Spacing />
</ViewWrapper>
<DrawerCustom
isVisible={openDrawer}
closeDrawer={() => setOpenDrawer(false)}
height={250}
>
<MenuDrawerDynamicGrid
data={menuDrawerPublishEvent({ id: id as string })}
columns={4}
onPressItem={handlePress}
/>
</DrawerCustom>
</>
);
}

View File

@@ -1,15 +1,15 @@
import {
BoxButtonOnFooter,
ButtonCustom,
SelectCustom,
StackCustom,
TextAreaCustom,
TextInputCustom,
ViewWrapper,
ButtonCustom,
SelectCustom,
StackCustom,
TextAreaCustom,
TextInputCustom,
ViewWrapper,
} from "@/components";
import DateTimePickerCustom from "@/components/DateInput/DateTimePickerCustom";
import { masterTypeEvent } from "@/lib/dummy-data/event/master-type-event";
import { DateTimePickerEvent } from "@react-native-community/datetimepicker";
import { router } from "expo-router";
import React, { useState } from "react";
import { Platform } from "react-native";
@@ -23,32 +23,39 @@ export default function EventCreate() {
>(null);
const handlerSubmit = () => {
if (selectedDate) {
console.log("Tanggal yang dipilih:", selectedDate);
console.log(`ISO Format ${Platform.OS}:`, selectedDate.toString());
// Kirim ke API atau proses lanjutan
} else {
console.warn("Tanggal belum dipilih");
}
try {
if (selectedDate) {
console.log("Tanggal yang dipilih:", selectedDate);
console.log(`ISO Format ${Platform.OS}:`, selectedDate.toString());
// Kirim ke API atau proses lanjutan
} else {
console.log("Tanggal belum dipilih");
}
if (selectedEndDate) {
console.log("Tanggal yang dipilih:", selectedEndDate);
console.log(`ISO Format ${Platform.OS}:`, selectedEndDate.toString());
// Kirim ke API atau proses lanjutan
} else {
console.warn("Tanggal belum dipilih");
if (selectedEndDate) {
console.log("Tanggal yang dipilih:", selectedEndDate);
console.log(`ISO Format ${Platform.OS}:`, selectedEndDate.toString());
// Kirim ke API atau proses lanjutan
} else {
console.log("Tanggal berakhir belum dipilih");
}
console.log("Data berhasil disimpan");
router.navigate("/event/status");
} catch (error) {
console.log(error);
}
};
const buttonSubmit = (
<BoxButtonOnFooter>
<ButtonCustom title="Simpan" onPress={handlerSubmit} />
</BoxButtonOnFooter>
<ButtonCustom title="Simpan" onPress={handlerSubmit} />
// <BoxButtonOnFooter>
// </BoxButtonOnFooter>
);
return (
<>
<ViewWrapper footerComponent={buttonSubmit}>
<ViewWrapper>
<StackCustom gap={"xs"}>
<TextInputCustom
placeholder="Masukkan nama event"
@@ -93,6 +100,8 @@ export default function EventCreate() {
showCount
maxLength={100}
/>
{buttonSubmit}
</StackCustom>
</ViewWrapper>
</>

View File

@@ -11,18 +11,18 @@ import { useState } from "react";
import { View } from "react-native";
const categories = [
{ id: 1, label: "Semua" },
{ id: 2, label: "Event" },
{ id: 3, label: "Job" },
{ id: 4, label: "Voting" },
{ id: 5, label: "Donasi" },
{ id: 6, label: "Investasi" },
{ id: 7, label: "Forum" },
{ id: 8, label: "Collaboration" },
{ value: "all", label: "Semua" },
{ value: "event", label: "Event" },
{ value: "job", label: "Job" },
{ value: "voting", label: "Voting" },
{ value: "donasi", label: "Donasi" },
{ value: "investasi", label: "Investasi" },
{ value: "forum", label: "Forum" },
{ value: "collaboration", label: "Collaboration" },
];
const selectedCategory = (id: number) => {
const category = categories.find((c) => c.id === id);
const selectedCategory = (value: string) => {
const category = categories.find((c) => c.value === value);
return category?.label;
};
@@ -31,7 +31,7 @@ const BoxNotification = ({
activeCategory,
}: {
index: number;
activeCategory: number | null;
activeCategory: string | null;
}) => {
return (
<>
@@ -39,13 +39,13 @@ const BoxNotification = ({
onPress={() =>
console.log(
"Notification >",
selectedCategory(activeCategory as number)
selectedCategory(activeCategory as string)
)
}
>
<StackCustom>
<TextCustom bold>
# {selectedCategory(activeCategory as number)}
# {selectedCategory(activeCategory as string)}
</TextCustom>
<View
@@ -81,38 +81,31 @@ const BoxNotification = ({
};
export default function Notifications() {
const [activeCategory, setActiveCategory] = useState<number | null>(1);
const [activeCategory, setActiveCategory] = useState<string | null>("all");
const handlePress = (item: any) => {
setActiveCategory(item.id);
setActiveCategory(item.value);
// tambahkan logika lain seperti filter dsb.
};
return (
<ViewWrapper
headerComponent={
<ScrollableCustom
data={categories}
data={categories.map((e, i) => ({
id: i,
label: e.label,
value: e.value,
}))}
onButtonPress={handlePress}
activeId={activeCategory as any}
activeId={activeCategory as string}
/>
}
>
{Array.from({ length: 20 }).map((e, i) => (
<View key={i}>
<BoxNotification index={i} activeCategory={activeCategory} />
<BoxNotification index={i} activeCategory={activeCategory as any} />
</View>
))}
{/* Konten utama di sini */}
{/* <View style={{ flex: 1 }}>
<Text style={{ color: "white" }}>
{activeCategory
? `Kategori Aktif: ${
categories.find((c) => c.id === activeCategory)?.label
}`
: "Pilih kategori"}
</Text>
</View> */}
</ViewWrapper>
);
}

View File

@@ -4,8 +4,8 @@ import LeftButtonCustom from "@/components/Button/BackButton";
import DrawerCustom from "@/components/Drawer/DrawerCustom";
import { MainColor } from "@/constants/color-palet";
import { drawerItemsProfile } from "@/screens/Profile/ListPage";
import Profile_MenuDrawerSection from "@/screens/Profile/MenuDrawerSection";
import ProfilSection from "@/screens/Profile/ProfilSection";
import Profile_MenuDrawerSection from "@/screens/Profile/menuDrawerSection";
import ProfileSection from "@/screens/Profile/ProfileSection";
import { GStyles } from "@/styles/global-styles";
import { Ionicons } from "@expo/vector-icons";
import { router, Stack, useLocalSearchParams } from "expo-router";
@@ -52,7 +52,7 @@ export default function Profile() {
headerTitleStyle: GStyles.headerTitleStyle,
}}
/>
<ProfilSection />
<ProfileSection />
</ViewWrapper>
{/* Drawer Komponen Eksternal */}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 395 KiB

View File

@@ -1,13 +1,25 @@
import { AccentColor } from "@/constants/color-palet";
import { PADDING_EXTRA_SMALL, PADDING_MEDIUM, PADDING_SMALL } from "@/constants/constans-value";
import { StyleProp, TouchableHighlight, View, ViewStyle } from "react-native";
import {
PADDING_MEDIUM,
PADDING_SMALL
} from "@/constants/constans-value";
import { Href, router } from "expo-router";
import {
StyleProp,
TouchableOpacity,
View,
ViewStyle
} from "react-native";
interface BaseBoxProps {
children: React.ReactNode;
style?: StyleProp<ViewStyle>;
href?: Href;
onPress?: () => void;
marginBottom?: number;
padding?: number;
paddingTop?: number;
paddingBottom?: number;
paddingInline?: number;
paddingBlock?: number;
}
@@ -15,16 +27,21 @@ interface BaseBoxProps {
export default function BaseBox({
children,
style,
href,
onPress,
marginBottom = PADDING_MEDIUM,
paddingBlock = PADDING_EXTRA_SMALL,
paddingBlock = PADDING_MEDIUM,
paddingInline = PADDING_SMALL,
paddingTop = PADDING_MEDIUM,
paddingBottom = PADDING_MEDIUM,
}: BaseBoxProps) {
return (
<>
{onPress ? (
<TouchableHighlight
onPress={onPress}
{onPress || href ? (
<TouchableOpacity
activeOpacity={0.7}
onPress={href ? () => router.navigate(href) : onPress}
style={[
{
backgroundColor: AccentColor.darkblue,
@@ -34,13 +51,14 @@ export default function BaseBox({
marginBottom,
paddingBlock,
paddingInline,
paddingTop,
paddingBottom,
},
style,
]}
// activeOpacity={0.7}
>
<View>{children}</View>
</TouchableHighlight>
</TouchableOpacity>
) : (
<View
style={[

View File

@@ -0,0 +1,20 @@
import { Href } from "expo-router";
import BaseBox from "./BaseBox";
export default function BoxWithHeaderSection({
children,
href,
onPress,
}: {
children: React.ReactNode;
href?: Href;
onPress?: () => void;
}) {
return (
<>
<BaseBox href={href} onPress={onPress} paddingTop={5}>
{children}
</BaseBox>
</>
);
}

View File

@@ -0,0 +1,13 @@
import { Ionicons } from "@expo/vector-icons";
import { MainColor } from "@/constants/color-palet";
export default function DotButton({ onPress }: { onPress: () => void }) {
return (
<Ionicons
onPress={onPress}
name="ellipsis-vertical"
size={20}
color={MainColor.yellow}
/>
);
}

View File

@@ -6,6 +6,7 @@ import ButtonCustom from "../Button/ButtonCustom";
interface ButtonData {
id: string | number;
label: string;
value: string;
}
interface ScrollableCustomProps {
@@ -27,7 +28,7 @@ const ScrollableCustom = ({
style={styles.scrollView}
>
{data.map((item) => {
const isActive = activeId === item.id;
const isActive = activeId === item.value;
return (
<ButtonCustom
@@ -48,6 +49,9 @@ export default ScrollableCustom;
const styles = StyleSheet.create({
scrollView: {
backgroundColor: MainColor.soft_darkblue,
borderRadius: 50,
padding: 5,
// maxHeight: 50,
},
buttonContainer: {

View File

@@ -3,6 +3,7 @@ import {
TEXT_SIZE_LARGE,
TEXT_SIZE_MEDIUM,
TEXT_SIZE_SMALL,
TEXT_SIZE_XLARGE,
} from "@/constants/constans-value";
import React from "react";
import {
@@ -21,7 +22,7 @@ interface TextCustomProps {
style?: StyleProp<TextStyle>;
bold?: boolean;
semiBold?: boolean;
size?: "default" | "large" | "small";
size?: "default" | "large" | "small" | "xlarge";
color?: "default" | "yellow" | "red" | "gray" | "green" | "black"
align?: TextAlign; // Prop untuk alignment
truncate?: boolean | number;
@@ -51,6 +52,7 @@ const TextCustom: React.FC<TextCustomProps> = ({
// Size
if (size === "large") selectedStyles.push(styles.large);
else if (size === "xlarge") selectedStyles.push(styles.xlarge);
else if (size === "small") selectedStyles.push(styles.small);
// Color
@@ -113,11 +115,14 @@ export const styles = StyleSheet.create({
fontFamily: "Poppins-SemiBold",
fontWeight: "500",
},
small: {
fontSize: TEXT_SIZE_SMALL,
},
large: {
fontSize: TEXT_SIZE_LARGE,
},
small: {
fontSize: TEXT_SIZE_SMALL,
xlarge: {
fontSize: TEXT_SIZE_XLARGE,
},
yellow: {
color: MainColor.yellow,

View File

@@ -0,0 +1,46 @@
import { ImageSourcePropType, View } from "react-native";
import Grid from "../Grid/GridCustom";
import AvatarCustom from "../Image/AvatarCustom";
import TextCustom from "../Text/TextCustom";
const AvatarUsernameAndOtherComponent = ({
avatarHref,
avatar,
name,
rightComponent,
}: {
avatarHref?: string;
avatar?: ImageSourcePropType;
name?: string;
rightComponent?: React.ReactNode;
}) => {
return (
<>
<View>
<Grid containerStyle={{ zIndex: 10 }}>
<Grid.Col span={2}>
<AvatarCustom source={avatar} href={avatarHref as any} />
</Grid.Col>
<Grid.Col
span={rightComponent ? 6 : 10}
style={{ justifyContent: "center" }}
>
<TextCustom truncate bold>
{name || "Username"}
</TextCustom>
</Grid.Col>
{rightComponent && (
<Grid.Col
span={4}
style={{ alignItems: "flex-end", justifyContent: "center" }}
>
{rightComponent}
</Grid.Col>
)}
</Grid>
</View>
</>
);
};
export default AvatarUsernameAndOtherComponent;

View File

@@ -3,12 +3,12 @@ import React from "react";
import { View } from "react-native";
interface SpacingProps {
width?: number;
height?: number;
width?: number | string;
height?: number | string;
}
const Spacing: React.FC<SpacingProps> = ({ width = 20, height = 20 }) => {
return <View style={{ height, width }} />;
return <View style={{ height: height as any, width: width as any }} />;
};
export default Spacing;

View File

@@ -20,15 +20,23 @@ interface ViewWrapperProps {
headerComponent?: React.ReactNode;
footerComponent?: React.ReactNode;
floatingButton?: React.ReactNode;
hideFooter?: boolean;
style?: StyleProp<ViewStyle>;
}
/**
*
* @param hideFooter
* @returns meneyembunyikan footer ketika menggunakan tabs (misal: bottom tab)
*/
const ViewWrapper = ({
children,
withBackground = false,
headerComponent,
footerComponent,
floatingButton,
hideFooter = false,
style,
}: ViewWrapperProps) => {
const assetBackground = require("../../assets/images/main-background.png");
@@ -78,10 +86,12 @@ const ViewWrapper = ({
{footerComponent}
</SafeAreaView>
) : (
<SafeAreaView
edges={["bottom"]}
style={{ backgroundColor: MainColor.darkblue }}
/>
hideFooter ? null : (
<SafeAreaView
edges={["bottom"]}
style={{ backgroundColor: MainColor.darkblue }}
/>
)
)}
{/* Floating Component (misal: FAB) */}

View File

@@ -4,12 +4,10 @@ import AlertCustom from "./Alert/AlertCustom";
import LeftButtonCustom from "./Button/BackButton";
import ButtonCenteredOnly from "./Button/ButtonCenteredOnly";
import ButtonCustom from "./Button/ButtonCustom";
import DotButton from "./Button/DotButton";
// Drawer
import DrawerCustom from "./Drawer/DrawerCustom";
import MenuDrawerDynamicGrid from "./Drawer/MenuDrawerDynamicGird";
// ShareComponent
import Spacing from "./_ShareComponent/Spacing";
import ViewWrapper from "./_ShareComponent/ViewWrapper";
// Text
import TextCustom from "./Text/TextCustom";
// TextInput
@@ -21,6 +19,7 @@ import Grid from "./Grid/GridCustom";
// Box
import BaseBox from "./Box/BaseBox";
import BoxButtonOnFooter from "./Box/BoxButtonOnFooter";
import BoxWithHeaderSection from "./Box/BoxWithHeaderInformation";
import InformationBox from "./Box/InformationBox";
// Stack
import StackCustom from "./Stack/StackCustom";
@@ -39,27 +38,36 @@ import CenterCustom from "./Center/CenterCustom";
import ClickableCustom from "./Clickable/ClickableCustom";
// Scroll
import ScrollableCustom from "./Scroll/ScrollCustom";
// ShareComponent
import AvatarUsernameAndOtherComponent from "./_ShareComponent/AvataraAndOtherHeaderComponent";
import Spacing from "./_ShareComponent/Spacing";
import ViewWrapper from "./_ShareComponent/ViewWrapper";
export {
AlertCustom,
// Image
AvatarCustom,
LandscapeFrameUploaded,
// ShareComponent
AvatarUsernameAndOtherComponent, LeftButtonCustom as BackButton,
// Box
BaseBox,
BoxButtonOnFooter,
ButtonCenteredOnly,
InformationBox,
LeftButtonCustom as BackButton,
BoxButtonOnFooter, BoxWithHeaderSection,
// Button
ButtonCenteredOnly,
ButtonCustom,
// Center
CenterCustom,
// Clickable
ClickableCustom,
// Divider
DividerCustom, DotButton,
// Drawer
DrawerCustom,
MenuDrawerDynamicGrid,
// Grid
Grid,
Grid, InformationBox, LandscapeFrameUploaded,
// Map
MapCustom,
MapCustom, MenuDrawerDynamicGrid,
// Scroll
ScrollableCustom,
// Select
SelectCustom,
// ShareComponent
@@ -73,13 +81,6 @@ export {
// TextInput
TextInputCustom,
// ViewWrapper
ViewWrapper,
// Divider
DividerCustom,
// Center
CenterCustom,
// Clickable
ClickableCustom,
// Scroll
ScrollableCustom,
ViewWrapper
};

View File

@@ -7,6 +7,7 @@ export {
TEXT_SIZE_SMALL,
TEXT_SIZE_MEDIUM,
TEXT_SIZE_LARGE,
TEXT_SIZE_XLARGE,
ICON_SIZE_SMALL,
ICON_SIZE_MEDIUM,
DRAWER_HEIGHT,
@@ -27,6 +28,7 @@ const OS_HEIGHT = Platform.OS === "ios" ? OS_IOS_HEIGHT : OS_ANDROID_HEIGHT
const TEXT_SIZE_SMALL = 12;
const TEXT_SIZE_MEDIUM = 14;
const TEXT_SIZE_LARGE = 16;
const TEXT_SIZE_XLARGE = 18;
// Icon Size
const ICON_SIZE_BUTTON = 18

View File

@@ -1,5 +1,5 @@
const DUMMY_IMAGE = {
avatar: require("@/assets/images/dummy/dummy-avatar.png"),
avatar: require("@/assets/images/dummy/dummy-user.png"),
background: require("@/assets/images/dummy/dummy-image-background.jpg"),
};

View File

@@ -0,0 +1,6 @@
export const masterStatus = [
{ value: "publish", label: "Publish" },
{ value: "review", label: "Review" },
{ value: "draft", label: "Draft" },
{ value: "reject", label: "Reject" },
];

View File

@@ -30,13 +30,13 @@ export default function LoginView() {
const id = randomAlfabet + randomNumber + fixNumber;
console.log("login user id :", id);
// router.navigate("/verification");
router.navigate("/verification");
// router.navigate(`/(application)/(user)/profile/${id}`);
// router.navigate("/(application)/(user)/home");
// router.navigate(`/(application)/profile/${id}/edit`);
// router.navigate(`/(application)/(user)/portofolio/${id}`)
// router.navigate(`/(application)/(image)/preview-image/${id}`);
router.replace("/(application)/(user)/event/(tabs)");
// router.replace("/(application)/(user)/event/(tabs)");
}
return (

View File

@@ -0,0 +1,115 @@
import AlertCustom from "@/components/Alert/AlertCustom";
import { router } from "expo-router";
export default function Event_AlertButtonStatusSection({
id,
status,
openAlert,
setOpenAlert,
openDeleteAlert,
setOpenDeleteAlert,
}: {
id: string;
status: string;
openAlert: boolean;
setOpenAlert: (value: boolean) => void;
openDeleteAlert: boolean;
setOpenDeleteAlert: (value: boolean) => void;
}) {
// --- Alert untuk aksi berdasarkan status ---
const renderStatusAlert = () => {
switch (status) {
case "publish":
return <></>;
case "review":
return (
<AlertCustom
isVisible={openAlert}
title="Batalkan Review"
message="Apakah Anda yakin ingin membatalkan review?"
textLeft="Batal"
textRight="Ya"
colorRight="green"
onLeftPress={() => {
setOpenAlert(false);
}}
onRightPress={() => {
setOpenAlert(false);
router.back();
}}
/>
);
case "draft":
return (
<AlertCustom
isVisible={openAlert}
title="Ajukan Review ?"
message="Apakah Anda yakin ingin mengajukan review kembali?"
textLeft="Batal"
textRight="Ya"
colorRight="green"
onLeftPress={() => {
setOpenAlert(false);
router.back();
}}
onRightPress={() => {
setOpenAlert(false);
router.back();
}}
/>
);
case "reject":
return (
<AlertCustom
isVisible={openAlert}
title="Edit Kembali"
message="Apakah Anda yakin ingin mengedit kembali event ini?"
textLeft="Batal"
textRight="Ya"
colorRight="green"
onLeftPress={() => {
setOpenAlert(false);
router.back();
}}
onRightPress={() => {
setOpenAlert(false);
router.back();
}}
/>
);
default:
return null;
}
};
return (
<>
{/* Alert berdasarkan status */}
{renderStatusAlert()}
{/* Alert untuk hapus - selalu muncul jika openDeleteAlert true */}
<AlertCustom
isVisible={openDeleteAlert}
title="Hapus Event"
message="Apakah Anda yakin ingin menghapus event ini?"
textLeft="Batal"
textRight="Ya, Hapus"
colorRight="red"
onLeftPress={() => {
setOpenDeleteAlert(false);
router.back();
}}
onRightPress={() => {
// Aksi hapus event
console.log("Menghapus event dengan ID:", id);
setOpenDeleteAlert(false);
router.back();
}}
/>
</>
);
}

View File

@@ -0,0 +1,61 @@
import {
BaseBox,
Grid,
StackCustom,
TextCustom
} from "@/components";
export default function Event_BoxDetailPublishSection({
footerButton,
}: {
footerButton?: React.ReactNode;
}) {
return (
<>
<BaseBox>
<StackCustom>
<TextCustom bold align="center" size="xlarge">
Judul event publish
</TextCustom>
{listData.map((item, index) => (
<Grid key={index}>
<Grid.Col span={4}>
<TextCustom bold>{item.title}</TextCustom>
</Grid.Col>
<Grid.Col span={8}>
<TextCustom>{item.value}</TextCustom>
</Grid.Col>
</Grid>
))}
</StackCustom>
</BaseBox>
{footerButton}
</>
);
}
const listData = [
{
title: "Lokasi",
value:
"Lorem ipsum dolor sit amet consectetur adipisicing elit. Consectetur eveniet ab eum ducimus tempore a quia deserunt quisquam. Tempora, atque. Aperiam minima asperiores dicta perferendis quis adipisci, dolore optio porro!",
},
{
title: "Tipe Acara",
value: "Workshop",
},
{
title: "Tanggal Mulai",
value: "Senin, 18 Juli 2025, 10:00 WIB",
},
{
title: "Tanggal Berakhir",
value: "Selasa, 19 Juli 2025, 12:00 WIB",
},
{
title: "Deskripsi",
value:
"Lorem ipsum dolor sit amet consectetur adipisicing elit. Consectetur eveniet ab eum ducimus tempore a quia deserunt quisquam. Tempora, atque. Aperiam minima asperiores dicta perferendis quis adipisci, dolore optio porro!",
},
];

View File

@@ -0,0 +1,51 @@
import {
AvatarUsernameAndOtherComponent,
BoxWithHeaderSection,
StackCustom,
TextCustom,
} from "@/components";
import { Href } from "expo-router";
export default function Event_BoxPublishSection({
id,
title,
username,
description,
href,
// Avatar
sourceAvatar,
rightComponentAvatar,
}: {
id: string;
title?: string;
username?: string;
description?: string;
href: Href;
// Avatar
sourceAvatar?: string;
rightComponentAvatar?: React.ReactNode;
}) {
return (
<>
<BoxWithHeaderSection href={href}>
<StackCustom gap={"xs"}>
<AvatarUsernameAndOtherComponent
avatarHref={`/profile/${id}`}
name={username || "Lorem ipsum dolor sit"}
rightComponent={rightComponentAvatar}
avatar={sourceAvatar as any}
/>
<TextCustom truncate bold>
{title || "Lorem ipsum dolor sit"}
</TextCustom>
<TextCustom truncate={2}>
{description ||
"Lorem ipsum dolor sit amet consectetur adipisicing elit. Porro sed doloremque tempora soluta. Dolorem ex quidem ipsum tempora, ipsa, obcaecati quia suscipit numquam, voluptates commodi porro impedit natus quos doloremque!"}
</TextCustom>
</StackCustom>
</BoxWithHeaderSection>
</>
);
}

View File

@@ -0,0 +1,76 @@
import { ButtonCustom, Grid } from "@/components";
import { View } from "react-native";
export default function Event_ButtonStatusSection({
status,
onOpenAlert,
onOpenDeleteAlert,
}: {
status: string;
onOpenAlert: (value: boolean) => void;
onOpenDeleteAlert: (value: boolean) => void;
}) {
const handleOpenAlert = () => {
onOpenAlert(true);
};
const handleOpenDeleteAlert = () => {
onOpenDeleteAlert(true);
};
const DeleteButton = () => {
return (
<>
<ButtonCustom backgroundColor="red" textColor="white" onPress={handleOpenDeleteAlert}>
Hapus
</ButtonCustom>
</>
);
};
switch (status) {
case "publish":
return <></>;
case "review":
return (
<ButtonCustom onPress={handleOpenAlert}>
Batalkan Review
</ButtonCustom>
);
case "draft":
return (
<>
<Grid>
<Grid.Col span={5}>
<ButtonCustom onPress={handleOpenAlert}>Ajukan Review</ButtonCustom>
</Grid.Col>
<Grid.Col span={2}>
<View />
</Grid.Col>
<Grid.Col span={5}>{DeleteButton()}</Grid.Col>
</Grid>
</>
);
case "reject":
return (
<>
<Grid>
<Grid.Col span={5}>
<ButtonCustom onPress={handleOpenAlert}>Edit Kembali</ButtonCustom>
</Grid.Col>
<Grid.Col span={2}>
<View />
</Grid.Col>
<Grid.Col span={5}>{DeleteButton()}</Grid.Col>
</Grid>
</>
);
default:
return <ButtonCustom disabled>Status Undifined</ButtonCustom>;
}
}

View File

@@ -0,0 +1,17 @@
import { AccentColor } from "@/constants/color-palet";
import { ICON_SIZE_MEDIUM } from "@/constants/constans-value";
import { Ionicons } from "@expo/vector-icons";
export const menuDrawerDraftEvent = ({ id }: { id: string }) => [
{
icon: (
<Ionicons
name="create"
size={ICON_SIZE_MEDIUM}
color={AccentColor.white}
/>
),
label: "Edit event",
path: `/(application)/(user)/event/${id}/edit`,
},
];

View File

@@ -0,0 +1,17 @@
import { AccentColor } from "@/constants/color-palet";
import { ICON_SIZE_MEDIUM } from "@/constants/constans-value";
import { FontAwesome } from "@expo/vector-icons";
export const menuDrawerPublishEvent = ({ id }: { id: string }) => [
{
icon: (
<FontAwesome
name="users"
size={ICON_SIZE_MEDIUM}
color={AccentColor.white}
/>
),
label: "Daftar peserta",
path: `/(application)/(user)/event/${id}/list-of-participants`,
},
];

View File

@@ -6,7 +6,7 @@ import { router, useLocalSearchParams } from "expo-router";
import { View } from "react-native";
import AvatarAndBackground from "./AvatarAndBackground";
export default function ProfilSection() {
export default function ProfileSection() {
const { id } = useLocalSearchParams();
const listData = [