Compare commits
27 Commits
resourcing
...
voting/28-
| Author | SHA1 | Date | |
|---|---|---|---|
| c9a1ac1db5 | |||
| 4bcfcb5f5a | |||
| f21ff744d3 | |||
| b18044f53f | |||
| 20258d1fe5 | |||
| 51d696128e | |||
| 1b1732c7d8 | |||
| 7528c449eb | |||
| ed87d4a3f3 | |||
| 603003865b | |||
| e02ae8e35d | |||
| 4f8ae2d7e0 | |||
| 360ac5807c | |||
| 8cb0054580 | |||
| 64d5a4308c | |||
| 30d61c84aa | |||
| 70e324e76e | |||
| 4474b46ff3 | |||
| aa4ea9fb0c | |||
| 81d86885f4 | |||
| 814f261881 | |||
| 7889d25a44 | |||
| ce0e82e627 | |||
| 08dfd62bfd | |||
| c8cc0f0232 | |||
| b844a8151d | |||
| f9e96aa077 |
@@ -92,6 +92,128 @@ 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 />,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{/* ========== End Event Section ========= */}
|
||||||
|
|
||||||
|
{/* ========== Collaboration Section ========= */}
|
||||||
|
<Stack.Screen
|
||||||
|
name="collaboration/(tabs)"
|
||||||
|
options={{
|
||||||
|
title: "Collaboration",
|
||||||
|
headerLeft: () => <BackButton path="/home" />,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Stack.Screen
|
||||||
|
name="collaboration/create"
|
||||||
|
options={{
|
||||||
|
title: "Tambah Proyek",
|
||||||
|
headerLeft: () => <BackButton />,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Stack.Screen
|
||||||
|
name="collaboration/[id]/list-of-participants"
|
||||||
|
options={{
|
||||||
|
title: "Daftar Partisipan",
|
||||||
|
headerLeft: () => <BackButton />,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Stack.Screen
|
||||||
|
name="collaboration/[id]/detail-participant"
|
||||||
|
options={{
|
||||||
|
title: "Partisipasi Proyek",
|
||||||
|
headerLeft: () => <BackButton />,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Stack.Screen
|
||||||
|
name="collaboration/[id]/edit"
|
||||||
|
options={{
|
||||||
|
title: "Edit Proyek",
|
||||||
|
headerLeft: () => <BackButton />,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
|
||||||
|
{/* ========== End Collaboration Section ========= */}
|
||||||
|
|
||||||
|
{/* ========== Voting Section ========= */}
|
||||||
|
<Stack.Screen
|
||||||
|
name="voting/create"
|
||||||
|
options={{
|
||||||
|
title: "Tambah Voting",
|
||||||
|
headerLeft: () => <BackButton />,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Stack.Screen
|
||||||
|
name="voting/(tabs)"
|
||||||
|
options={{
|
||||||
|
title: "Voting",
|
||||||
|
headerLeft: () => <BackButton path="/home" />,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Stack.Screen
|
||||||
|
name="voting/[id]/edit"
|
||||||
|
options={{
|
||||||
|
title: "Edit Voting",
|
||||||
|
headerLeft: () => <BackButton />,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Stack.Screen
|
||||||
|
name="voting/[id]/list-of-contributor"
|
||||||
|
options={{
|
||||||
|
title: "Daftar Kontributor",
|
||||||
|
headerLeft: () => <BackButton />,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* ========== End Voting Section ========= */}
|
||||||
|
|
||||||
|
{/* ========== Job Section ========= */}
|
||||||
|
<Stack.Screen
|
||||||
|
name="job/create"
|
||||||
|
options={{
|
||||||
|
title: "Tambah Job",
|
||||||
|
headerLeft: () => <BackButton />,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Stack.Screen
|
||||||
|
name="job/(tabs)"
|
||||||
|
options={{
|
||||||
|
title: "Job Vacancy",
|
||||||
|
headerLeft: () => <BackButton path="/home" />,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Stack.Screen
|
||||||
|
name="job/[id]/index"
|
||||||
|
options={{
|
||||||
|
title: "Detail Job",
|
||||||
|
headerLeft: () => <BackButton />,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Stack.Screen
|
||||||
|
name="job/[id]/edit"
|
||||||
|
options={{
|
||||||
|
title: "Edit Job",
|
||||||
|
headerLeft: () => <BackButton />,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* ========== End Job Section ========= */}
|
||||||
|
|
||||||
{/* ========== Forum Section ========= */}
|
{/* ========== Forum Section ========= */}
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
name="forum/create"
|
name="forum/create"
|
||||||
@@ -111,7 +233,7 @@ export default function UserLayout() {
|
|||||||
name="forum/[id]/forumku"
|
name="forum/[id]/forumku"
|
||||||
options={{
|
options={{
|
||||||
title: "Forumku",
|
title: "Forumku",
|
||||||
headerLeft: () => <BackButton icon={'close'} />,
|
headerLeft: () => <BackButton icon={"close"} />,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
|
|||||||
36
app/(application)/(user)/collaboration/(tabs)/_layout.tsx
Normal file
36
app/(application)/(user)/collaboration/(tabs)/_layout.tsx
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import { IconHome } from "@/components/_Icon";
|
||||||
|
import { TabsStyles } from "@/styles/tabs-styles";
|
||||||
|
import { Ionicons } from "@expo/vector-icons";
|
||||||
|
import { Tabs } from "expo-router";
|
||||||
|
|
||||||
|
export default function CollaborationTabsLayout() {
|
||||||
|
return (
|
||||||
|
<Tabs screenOptions={TabsStyles}>
|
||||||
|
<Tabs.Screen
|
||||||
|
name="index"
|
||||||
|
options={{
|
||||||
|
title: "Beranda",
|
||||||
|
tabBarIcon: ({ color }) => <IconHome color={color} />,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Tabs.Screen
|
||||||
|
name="participant"
|
||||||
|
options={{
|
||||||
|
title: "Partisipan",
|
||||||
|
tabBarIcon: ({ color }) => (
|
||||||
|
<Ionicons size={20} name="people" color={color} />
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Tabs.Screen
|
||||||
|
name="group"
|
||||||
|
options={{
|
||||||
|
title: "Grup",
|
||||||
|
tabBarIcon: ({ color }) => (
|
||||||
|
<Ionicons size={20} name="chatbox-ellipses" color={color} />
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Tabs>
|
||||||
|
);
|
||||||
|
}
|
||||||
68
app/(application)/(user)/collaboration/(tabs)/group.tsx
Normal file
68
app/(application)/(user)/collaboration/(tabs)/group.tsx
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
import { BaseBox, Grid, TextCustom } from "@/components";
|
||||||
|
import ViewWrapper from "@/components/_ShareComponent/ViewWrapper";
|
||||||
|
import { MainColor } from "@/constants/color-palet";
|
||||||
|
import { Feather } from "@expo/vector-icons";
|
||||||
|
|
||||||
|
export default function CollaborationGroup() {
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ViewWrapper hideFooter>
|
||||||
|
{Array.from({ length: 10 }).map((_, index) => (
|
||||||
|
<BaseBox
|
||||||
|
key={index}
|
||||||
|
paddingBlock={5}
|
||||||
|
href={`/collaboration/${index}/${generateProjectName()}/room-chat`}
|
||||||
|
>
|
||||||
|
<Grid>
|
||||||
|
<Grid.Col span={10}>
|
||||||
|
<TextCustom bold>{generateProjectName()}</TextCustom>
|
||||||
|
<TextCustom size="small">2 Anggota</TextCustom>
|
||||||
|
</Grid.Col>
|
||||||
|
<Grid.Col
|
||||||
|
span={2}
|
||||||
|
style={{ alignItems: "flex-end", justifyContent: "center" }}
|
||||||
|
>
|
||||||
|
<Feather name="chevron-right" size={20} color={MainColor.white} />
|
||||||
|
</Grid.Col>
|
||||||
|
</Grid>
|
||||||
|
</BaseBox>
|
||||||
|
))}
|
||||||
|
</ViewWrapper>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function generateProjectName() {
|
||||||
|
const adjectives = [
|
||||||
|
"Blue",
|
||||||
|
"Dark",
|
||||||
|
"Bright",
|
||||||
|
"Quantum",
|
||||||
|
"Silent",
|
||||||
|
"Cyber",
|
||||||
|
"Epic",
|
||||||
|
"Golden",
|
||||||
|
"Shadow",
|
||||||
|
"Rapid",
|
||||||
|
];
|
||||||
|
|
||||||
|
const nouns = [
|
||||||
|
"Spark",
|
||||||
|
"Core",
|
||||||
|
"Orbit",
|
||||||
|
"Nest",
|
||||||
|
"Drive",
|
||||||
|
"Nova",
|
||||||
|
"Cloud",
|
||||||
|
"Blade",
|
||||||
|
"Matrix",
|
||||||
|
"Link",
|
||||||
|
];
|
||||||
|
|
||||||
|
const randomAdjective =
|
||||||
|
adjectives[Math.floor(Math.random() * adjectives.length)];
|
||||||
|
const randomNoun = nouns[Math.floor(Math.random() * nouns.length)];
|
||||||
|
|
||||||
|
return randomAdjective + randomNoun;
|
||||||
|
}
|
||||||
28
app/(application)/(user)/collaboration/(tabs)/index.tsx
Normal file
28
app/(application)/(user)/collaboration/(tabs)/index.tsx
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import { FloatingButton, ViewWrapper } from "@/components";
|
||||||
|
import Collaboration_BoxPublishSection from "@/screens/Collaboration/BoxPublishSection";
|
||||||
|
import { router } from "expo-router";
|
||||||
|
|
||||||
|
export default function CollaborationBeranda() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<ViewWrapper
|
||||||
|
hideFooter
|
||||||
|
floatingButton={
|
||||||
|
<FloatingButton
|
||||||
|
onPress={() => {
|
||||||
|
router.push("/collaboration/create");
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{Array.from({ length: 10 }).map((_, index) => (
|
||||||
|
<Collaboration_BoxPublishSection
|
||||||
|
key={index}
|
||||||
|
id={index.toString()}
|
||||||
|
href={`/collaboration/${index}`}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</ViewWrapper>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
import { ButtonCustom, Spacing } from "@/components";
|
||||||
|
import ViewWrapper from "@/components/_ShareComponent/ViewWrapper";
|
||||||
|
import { AccentColor, MainColor } from "@/constants/color-palet";
|
||||||
|
import Collaboration_BoxPublishSection from "@/screens/Collaboration/BoxPublishSection";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { View } from "react-native";
|
||||||
|
|
||||||
|
export default function CollaborationParticipans() {
|
||||||
|
const [activeCategory, setActiveCategory] = useState<string | null>(
|
||||||
|
"participant"
|
||||||
|
);
|
||||||
|
|
||||||
|
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 === "participant" ? MainColor.yellow : AccentColor.blue
|
||||||
|
}
|
||||||
|
textColor={
|
||||||
|
activeCategory === "participant" ? MainColor.black : MainColor.white
|
||||||
|
}
|
||||||
|
style={{ width: "49%" }}
|
||||||
|
onPress={() => handlePress("participant")}
|
||||||
|
>
|
||||||
|
Partisipasi Proyek
|
||||||
|
</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")}
|
||||||
|
>
|
||||||
|
Proyek Saya
|
||||||
|
</ButtonCustom>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ViewWrapper hideFooter headerComponent={headerComponent}>
|
||||||
|
{Array.from({ length: 10 }).map((_, index) => (
|
||||||
|
<Collaboration_BoxPublishSection
|
||||||
|
key={index.toString()}
|
||||||
|
id={index.toString()}
|
||||||
|
username={` ${
|
||||||
|
activeCategory === "participant"
|
||||||
|
? "Partisipasi Proyek"
|
||||||
|
: "Proyek Saya"
|
||||||
|
}`}
|
||||||
|
href={
|
||||||
|
activeCategory === "participant"
|
||||||
|
? `/collaboration/${index}/detail-participant`
|
||||||
|
: `/collaboration/${index}/detail-project-main`
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</ViewWrapper>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||||
|
import {
|
||||||
|
AvatarUsernameAndOtherComponent,
|
||||||
|
BackButton,
|
||||||
|
BoxWithHeaderSection,
|
||||||
|
Grid,
|
||||||
|
StackCustom,
|
||||||
|
TextCustom,
|
||||||
|
ViewWrapper,
|
||||||
|
} from "@/components";
|
||||||
|
import { Stack, useLocalSearchParams } from "expo-router";
|
||||||
|
|
||||||
|
export default function CollaborationRoomInfo() {
|
||||||
|
const { id, detail } = useLocalSearchParams();
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Stack.Screen
|
||||||
|
options={{
|
||||||
|
title: `Info`,
|
||||||
|
headerLeft: () => <BackButton />,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ViewWrapper>
|
||||||
|
<BoxWithHeaderSection>
|
||||||
|
<StackCustom>
|
||||||
|
{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>
|
||||||
|
</BoxWithHeaderSection>
|
||||||
|
|
||||||
|
<BoxWithHeaderSection>
|
||||||
|
{Array.from({ length: 10 }).map((_, index) => (
|
||||||
|
<AvatarUsernameAndOtherComponent key={index} avatarHref={`/profile/${index}`} />
|
||||||
|
))}
|
||||||
|
</BoxWithHeaderSection>
|
||||||
|
</ViewWrapper>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const listData = [
|
||||||
|
{
|
||||||
|
title: "Judul Proyek",
|
||||||
|
value: "Judul Proyek",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Industri",
|
||||||
|
value: "Pilihan Industri",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Deskripsi",
|
||||||
|
value: "Deskripsi Proyek",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Tujuan Proyek",
|
||||||
|
value:
|
||||||
|
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Keuntungan Proyek",
|
||||||
|
value:
|
||||||
|
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
|
||||||
|
},
|
||||||
|
];
|
||||||
@@ -0,0 +1,192 @@
|
|||||||
|
import {
|
||||||
|
BackButton,
|
||||||
|
BoxButtonOnFooter,
|
||||||
|
Grid,
|
||||||
|
TextCustom,
|
||||||
|
TextInputCustom,
|
||||||
|
ViewWrapper,
|
||||||
|
} from "@/components";
|
||||||
|
import { AccentColor, MainColor } from "@/constants/color-palet";
|
||||||
|
import { ICON_SIZE_SMALL } from "@/constants/constans-value";
|
||||||
|
import { Feather } from "@expo/vector-icons";
|
||||||
|
import { router, Stack, useLocalSearchParams } from "expo-router";
|
||||||
|
import { StyleSheet, TouchableOpacity, View } from "react-native";
|
||||||
|
|
||||||
|
export default function CollaborationRoomChat() {
|
||||||
|
const { id, detail } = useLocalSearchParams();
|
||||||
|
|
||||||
|
const inputChat = () => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<BoxButtonOnFooter>
|
||||||
|
{/* <View style={{flexDirection: 'row', alignItems: 'center'}}>
|
||||||
|
<TextInputCustom placeholder="Ketik pesan..." />
|
||||||
|
<TouchableOpacity
|
||||||
|
activeOpacity={0.5}
|
||||||
|
onPress={() => console.log("Send")}
|
||||||
|
style={{
|
||||||
|
backgroundColor: AccentColor.blue,
|
||||||
|
padding: 10,
|
||||||
|
borderRadius: 50,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Feather name="send" size={30} color={MainColor.white} />
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View> */}
|
||||||
|
<Grid>
|
||||||
|
<Grid.Col span={9}>
|
||||||
|
<TextInputCustom placeholder="Ketik pesan..." />
|
||||||
|
</Grid.Col>
|
||||||
|
<Grid.Col span={1}>
|
||||||
|
<View />
|
||||||
|
</Grid.Col>
|
||||||
|
<Grid.Col span={2} style={{ alignItems: "center" }}>
|
||||||
|
<TouchableOpacity
|
||||||
|
activeOpacity={0.5}
|
||||||
|
onPress={() => console.log("Send")}
|
||||||
|
style={{
|
||||||
|
backgroundColor: AccentColor.blue,
|
||||||
|
padding: 10,
|
||||||
|
borderRadius: 50,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Feather
|
||||||
|
name="send"
|
||||||
|
size={30}
|
||||||
|
color={MainColor.white}
|
||||||
|
/>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</Grid.Col>
|
||||||
|
</Grid>
|
||||||
|
</BoxButtonOnFooter>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Stack.Screen
|
||||||
|
options={{
|
||||||
|
title: `Proyek ${detail}`,
|
||||||
|
headerLeft: () => <BackButton />,
|
||||||
|
headerRight: () => (
|
||||||
|
<Feather
|
||||||
|
name="info"
|
||||||
|
size={ICON_SIZE_SMALL}
|
||||||
|
color={MainColor.yellow}
|
||||||
|
onPress={() => router.push(`/collaboration/${id}/${detail}/info`)}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<ViewWrapper footerComponent={inputChat()}>
|
||||||
|
{dummyData.map((item, index) => (
|
||||||
|
<View
|
||||||
|
key={index}
|
||||||
|
style={[
|
||||||
|
styles.messageRow,
|
||||||
|
item.role === 1 ? styles.rightAlign : styles.leftAlign,
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<View
|
||||||
|
style={[
|
||||||
|
styles.bubble,
|
||||||
|
item.role === 1 ? styles.bubbleRight : styles.bubbleLeft,
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<TextCustom style={styles.sender}>{item.nama}</TextCustom>
|
||||||
|
<TextCustom style={styles.message}>{item.chat}</TextCustom>
|
||||||
|
<TextCustom style={styles.time}>
|
||||||
|
{new Date(item.time).toLocaleTimeString([], {
|
||||||
|
hour: "2-digit",
|
||||||
|
minute: "2-digit",
|
||||||
|
})}
|
||||||
|
</TextCustom>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
))}
|
||||||
|
{/* <TextInputCustom placeholder="Ketik pesan..." />
|
||||||
|
<Spacing/> */}
|
||||||
|
</ViewWrapper>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const dummyData = [
|
||||||
|
{
|
||||||
|
nama: "Dina",
|
||||||
|
role: 1,
|
||||||
|
chat: "Hai! Kamu udah lihat dokumen proyek yang baru?",
|
||||||
|
time: "2025-07-24T09:01:15Z",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
nama: "Rafi",
|
||||||
|
role: 2,
|
||||||
|
chat: "Halo! Iya, aku baru aja baca. Kayaknya kita harus revisi bagian akhir deh.",
|
||||||
|
time: "2025-07-24T09:02:03Z",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
nama: "Dina",
|
||||||
|
role: 1,
|
||||||
|
chat: "Setuju. Aku juga kurang sreg sama penutupnya.",
|
||||||
|
time: "2025-07-24T09:02:45Z",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
nama: "Rafi",
|
||||||
|
role: 2,
|
||||||
|
chat: "Oke, aku coba edit malam ini ya. Nanti aku share ulang versinya.",
|
||||||
|
time: "2025-07-24T09:03:10Z",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
nama: "Dina",
|
||||||
|
role: 1,
|
||||||
|
chat: "Siap, makasih ya. Jangan begadang!",
|
||||||
|
time: "2025-07-24T09:03:30Z",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
paddingVertical: 10,
|
||||||
|
paddingHorizontal: 12,
|
||||||
|
},
|
||||||
|
messageRow: {
|
||||||
|
flexDirection: "row",
|
||||||
|
marginBottom: 12,
|
||||||
|
},
|
||||||
|
rightAlign: {
|
||||||
|
justifyContent: "flex-end",
|
||||||
|
},
|
||||||
|
leftAlign: {
|
||||||
|
justifyContent: "flex-start",
|
||||||
|
},
|
||||||
|
bubble: {
|
||||||
|
maxWidth: "75%",
|
||||||
|
padding: 10,
|
||||||
|
borderRadius: 12,
|
||||||
|
},
|
||||||
|
bubbleRight: {
|
||||||
|
backgroundColor: "#DCF8C6", // hijau muda
|
||||||
|
borderTopRightRadius: 0,
|
||||||
|
},
|
||||||
|
bubbleLeft: {
|
||||||
|
backgroundColor: "#F0F0F0", // abu-abu terang
|
||||||
|
borderTopLeftRadius: 0,
|
||||||
|
},
|
||||||
|
sender: {
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: "bold",
|
||||||
|
marginBottom: 2,
|
||||||
|
color: "#555",
|
||||||
|
},
|
||||||
|
message: {
|
||||||
|
fontSize: 15,
|
||||||
|
color: "#000",
|
||||||
|
},
|
||||||
|
time: {
|
||||||
|
fontSize: 10,
|
||||||
|
color: "#888",
|
||||||
|
textAlign: "right",
|
||||||
|
marginTop: 4,
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
import {
|
||||||
|
AvatarUsernameAndOtherComponent,
|
||||||
|
BaseBox,
|
||||||
|
DrawerCustom,
|
||||||
|
StackCustom,
|
||||||
|
TextCustom,
|
||||||
|
ViewWrapper,
|
||||||
|
} from "@/components";
|
||||||
|
import { ICON_SIZE_SMALL } from "@/constants/constans-value";
|
||||||
|
import Collaboration_BoxDetailSection from "@/screens/Collaboration/BoxDetailSection";
|
||||||
|
import { MaterialIcons } from "@expo/vector-icons";
|
||||||
|
import { useLocalSearchParams } from "expo-router";
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
export default function CollaborationDetailParticipant() {
|
||||||
|
const { id } = useLocalSearchParams();
|
||||||
|
const [openDrawerParticipant, setOpenDrawerParticipant] = useState(false);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<ViewWrapper>
|
||||||
|
<Collaboration_BoxDetailSection id={id as string} />
|
||||||
|
<BaseBox style={{ height: 500 }}>
|
||||||
|
<TextCustom align="center" bold size="large">
|
||||||
|
Partisipan
|
||||||
|
</TextCustom>
|
||||||
|
|
||||||
|
{Array.from({ length: 5 }).map((_, index) => (
|
||||||
|
<AvatarUsernameAndOtherComponent
|
||||||
|
key={index}
|
||||||
|
avatarHref={`/profile/${index}`}
|
||||||
|
rightComponent={
|
||||||
|
<MaterialIcons
|
||||||
|
name="notes"
|
||||||
|
size={ICON_SIZE_SMALL}
|
||||||
|
color="white"
|
||||||
|
onPress={() => setOpenDrawerParticipant(true)}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</BaseBox>
|
||||||
|
</ViewWrapper>
|
||||||
|
|
||||||
|
<DrawerCustom
|
||||||
|
isVisible={openDrawerParticipant}
|
||||||
|
closeDrawer={() => setOpenDrawerParticipant(false)}
|
||||||
|
height={"auto"}
|
||||||
|
>
|
||||||
|
<StackCustom>
|
||||||
|
<TextCustom bold>Deskripsi Diri</TextCustom>
|
||||||
|
<TextCustom>
|
||||||
|
Lorem ipsum dolor sit, amet consectetur adipisicing elit. Commodi,
|
||||||
|
itaque adipisci. Voluptas, sed quod! Ad facere labore voluptates,
|
||||||
|
neque quidem aut reprehenderit ducimus mollitia quisquam temporibus!
|
||||||
|
Temporibus iusto soluta necessitatibus.
|
||||||
|
</TextCustom>
|
||||||
|
</StackCustom>
|
||||||
|
</DrawerCustom>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
import {
|
||||||
|
AlertDefaultSystem,
|
||||||
|
BackButton,
|
||||||
|
ButtonCustom,
|
||||||
|
DotButton,
|
||||||
|
DrawerCustom,
|
||||||
|
MenuDrawerDynamicGrid,
|
||||||
|
Spacing,
|
||||||
|
StackCustom,
|
||||||
|
TextCustom,
|
||||||
|
ViewWrapper
|
||||||
|
} from "@/components";
|
||||||
|
import { IconEdit } from "@/components/_Icon";
|
||||||
|
import Collaboration_BoxDetailSection from "@/screens/Collaboration/BoxDetailSection";
|
||||||
|
import Collaboration_MainParticipanSelectedSection from "@/screens/Collaboration/ProjectMainSelectedSection";
|
||||||
|
import { router, Stack, useLocalSearchParams } from "expo-router";
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
export default function CollaborationDetailProjectMain() {
|
||||||
|
const { id } = useLocalSearchParams();
|
||||||
|
const [openDrawer, setOpenDrawer] = useState(false);
|
||||||
|
const [openDrawerParticipant, setOpenDrawerParticipant] = useState(false);
|
||||||
|
const [selected, setSelected] = useState<(string | number)[]>([]);
|
||||||
|
|
||||||
|
const handleEdit = () => {
|
||||||
|
console.log("Edit collaboration");
|
||||||
|
router.push("/(application)/(user)/collaboration/(id)/edit");
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Stack.Screen
|
||||||
|
options={{
|
||||||
|
title: "Proyek Saya",
|
||||||
|
headerLeft: () => <BackButton />,
|
||||||
|
headerRight: () => <DotButton onPress={() => setOpenDrawer(true)} />,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<ViewWrapper>
|
||||||
|
<Collaboration_BoxDetailSection id={id as string} />
|
||||||
|
<Collaboration_MainParticipanSelectedSection
|
||||||
|
selected={selected}
|
||||||
|
setSelected={setSelected}
|
||||||
|
setOpenDrawerParticipant={setOpenDrawerParticipant}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ButtonCustom
|
||||||
|
onPress={() => {
|
||||||
|
AlertDefaultSystem({
|
||||||
|
title: "Buat Grup",
|
||||||
|
message:
|
||||||
|
"Apakah anda yakin ingin membuat grup untuk proyek ini ?",
|
||||||
|
textLeft: "Tidak",
|
||||||
|
textRight: "Ya",
|
||||||
|
onPressLeft: () => {},
|
||||||
|
onPressRight: () => {
|
||||||
|
router.navigate(
|
||||||
|
"/(application)/(user)/collaboration/(tabs)/group"
|
||||||
|
);
|
||||||
|
console.log("selected :", selected);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Buat Grup
|
||||||
|
</ButtonCustom>
|
||||||
|
<Spacing />
|
||||||
|
</ViewWrapper>
|
||||||
|
|
||||||
|
<DrawerCustom
|
||||||
|
isVisible={openDrawer}
|
||||||
|
closeDrawer={() => setOpenDrawer(false)}
|
||||||
|
height={"auto"}
|
||||||
|
>
|
||||||
|
<MenuDrawerDynamicGrid
|
||||||
|
data={[
|
||||||
|
{
|
||||||
|
label: "Edit",
|
||||||
|
path: "/(application)/(user)/collaboration/(tabs)/group",
|
||||||
|
icon: <IconEdit />,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
onPressItem={(item) => {
|
||||||
|
handleEdit();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</DrawerCustom>
|
||||||
|
|
||||||
|
<DrawerCustom
|
||||||
|
isVisible={openDrawerParticipant}
|
||||||
|
closeDrawer={() => setOpenDrawerParticipant(false)}
|
||||||
|
height={"auto"}
|
||||||
|
>
|
||||||
|
<StackCustom>
|
||||||
|
<TextCustom bold>Deskripsi Diri</TextCustom>
|
||||||
|
<TextCustom>
|
||||||
|
Lorem ipsum dolor sit, amet consectetur adipisicing elit. Commodi,
|
||||||
|
itaque adipisci. Voluptas, sed quod! Ad facere labore voluptates,
|
||||||
|
neque quidem aut reprehenderit ducimus mollitia quisquam temporibus!
|
||||||
|
Temporibus iusto soluta necessitatibus.
|
||||||
|
</TextCustom>
|
||||||
|
</StackCustom>
|
||||||
|
</DrawerCustom>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
53
app/(application)/(user)/collaboration/[id]/edit.tsx
Normal file
53
app/(application)/(user)/collaboration/[id]/edit.tsx
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
import {
|
||||||
|
ButtonCustom,
|
||||||
|
SelectCustom,
|
||||||
|
StackCustom,
|
||||||
|
TextAreaCustom,
|
||||||
|
TextInputCustom,
|
||||||
|
ViewWrapper,
|
||||||
|
} from "@/components";
|
||||||
|
import { router } from "expo-router";
|
||||||
|
|
||||||
|
export default function CollaborationEdit() {
|
||||||
|
return (
|
||||||
|
<ViewWrapper>
|
||||||
|
<StackCustom gap={"xs"}>
|
||||||
|
<TextInputCustom label="Judul" placeholder="Masukan judul" required />
|
||||||
|
<TextInputCustom label="Lokasi" placeholder="Masukan lokasi" required />
|
||||||
|
<SelectCustom
|
||||||
|
label="Pilih Industri"
|
||||||
|
data={[
|
||||||
|
{ label: "Industri 1", value: "industri-1" },
|
||||||
|
{ label: "Industri 2", value: "industri-2" },
|
||||||
|
{ label: "Industri 3", value: "industri-3" },
|
||||||
|
]}
|
||||||
|
onChange={(value) => console.log(value)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextAreaCustom
|
||||||
|
required
|
||||||
|
label="Tujuan Proyek"
|
||||||
|
placeholder="Masukan tujuan proyek"
|
||||||
|
showCount
|
||||||
|
maxLength={1000}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextAreaCustom
|
||||||
|
required
|
||||||
|
label="Keuntungan Proyek"
|
||||||
|
placeholder="Masukan keuntungan proyek"
|
||||||
|
showCount
|
||||||
|
maxLength={1000}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ButtonCustom
|
||||||
|
title="Update"
|
||||||
|
onPress={() => {
|
||||||
|
console.log("Update proyek");
|
||||||
|
router.back();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</StackCustom>
|
||||||
|
</ViewWrapper>
|
||||||
|
);
|
||||||
|
}
|
||||||
91
app/(application)/(user)/collaboration/[id]/index.tsx
Normal file
91
app/(application)/(user)/collaboration/[id]/index.tsx
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
import {
|
||||||
|
AlertDefaultSystem,
|
||||||
|
BackButton,
|
||||||
|
ButtonCustom,
|
||||||
|
DotButton,
|
||||||
|
DrawerCustom,
|
||||||
|
MenuDrawerDynamicGrid,
|
||||||
|
TextAreaCustom,
|
||||||
|
ViewWrapper,
|
||||||
|
} from "@/components";
|
||||||
|
import Collaboration_BoxDetailSection from "@/screens/Collaboration/BoxDetailSection";
|
||||||
|
import { Ionicons } from "@expo/vector-icons";
|
||||||
|
import { router, Stack, useLocalSearchParams } from "expo-router";
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
export default function CollaborationDetail() {
|
||||||
|
const { id } = useLocalSearchParams();
|
||||||
|
const [openDrawerPartisipasi, setOpenDrawerPartisipasi] = useState(false);
|
||||||
|
const [openDrawerMenu, setOpenDrawerMenu] = useState(false);
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Stack.Screen
|
||||||
|
options={{
|
||||||
|
title: "Detail Proyek",
|
||||||
|
headerLeft: () => <BackButton />,
|
||||||
|
headerRight: () => (
|
||||||
|
<DotButton onPress={() => setOpenDrawerMenu(true)} />
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<ViewWrapper>
|
||||||
|
<Collaboration_BoxDetailSection id={id as string} />
|
||||||
|
|
||||||
|
<ButtonCustom onPress={() => setOpenDrawerPartisipasi(true)}>
|
||||||
|
Partisipasi
|
||||||
|
</ButtonCustom>
|
||||||
|
</ViewWrapper>
|
||||||
|
|
||||||
|
{/* Drawer Partisipasi */}
|
||||||
|
<DrawerCustom
|
||||||
|
isVisible={openDrawerPartisipasi}
|
||||||
|
closeDrawer={() => setOpenDrawerPartisipasi(false)}
|
||||||
|
height={300}
|
||||||
|
>
|
||||||
|
<TextAreaCustom
|
||||||
|
label="Dekripsi diri"
|
||||||
|
placeholder="Masukan dekripsi diri"
|
||||||
|
required
|
||||||
|
showCount
|
||||||
|
maxLength={500}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ButtonCustom
|
||||||
|
style={{ alignSelf: "flex-end" }}
|
||||||
|
onPress={() => {
|
||||||
|
AlertDefaultSystem({
|
||||||
|
title: "Simpan data deskripsi",
|
||||||
|
message: "Apakah anda sudah yakin ingin menyimpan data ini ?",
|
||||||
|
textLeft: "Batal",
|
||||||
|
textRight: "Simpan",
|
||||||
|
onPressRight: () => router.replace(`/collaboration/(tabs)/group`),
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Simpan
|
||||||
|
</ButtonCustom>
|
||||||
|
</DrawerCustom>
|
||||||
|
|
||||||
|
{/* Drawer Menu */}
|
||||||
|
<DrawerCustom
|
||||||
|
isVisible={openDrawerMenu}
|
||||||
|
closeDrawer={() => setOpenDrawerMenu(false)}
|
||||||
|
height={250}
|
||||||
|
>
|
||||||
|
<MenuDrawerDynamicGrid
|
||||||
|
data={[
|
||||||
|
{
|
||||||
|
icon: <Ionicons name="people" size={24} color="white" />,
|
||||||
|
label: "Daftar Partisipan",
|
||||||
|
path: `/collaboration/${id}/list-of-participants`,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
onPressItem={(item) => {
|
||||||
|
router.push(item.path as any);
|
||||||
|
setOpenDrawerMenu(false);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</DrawerCustom>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
import {
|
||||||
|
AvatarUsernameAndOtherComponent,
|
||||||
|
BaseBox,
|
||||||
|
DrawerCustom,
|
||||||
|
Spacing,
|
||||||
|
StackCustom,
|
||||||
|
TextCustom,
|
||||||
|
ViewWrapper
|
||||||
|
} from "@/components";
|
||||||
|
import { Feather } from "@expo/vector-icons";
|
||||||
|
import { useLocalSearchParams } from "expo-router";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { ScrollView } from "react-native";
|
||||||
|
|
||||||
|
export default function CollaborationListOfParticipants() {
|
||||||
|
const { id } = useLocalSearchParams();
|
||||||
|
const [openDrawer, setOpenDrawer] = useState(false);
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<ViewWrapper>
|
||||||
|
{Array.from({ length: 10 }).map((_, index) => (
|
||||||
|
<BaseBox key={index} paddingBlock={5}>
|
||||||
|
<AvatarUsernameAndOtherComponent
|
||||||
|
avatarHref={`/profile/${id}`}
|
||||||
|
rightComponent={
|
||||||
|
<Feather
|
||||||
|
name="chevron-right"
|
||||||
|
size={24}
|
||||||
|
color="white"
|
||||||
|
onPress={() => setOpenDrawer(true)}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</BaseBox>
|
||||||
|
))}
|
||||||
|
</ViewWrapper>
|
||||||
|
|
||||||
|
{/* Drawer */}
|
||||||
|
<DrawerCustom
|
||||||
|
isVisible={openDrawer}
|
||||||
|
closeDrawer={() => setOpenDrawer(false)}
|
||||||
|
>
|
||||||
|
<StackCustom>
|
||||||
|
<TextCustom bold>Deskripsi diri</TextCustom>
|
||||||
|
<BaseBox>
|
||||||
|
<ScrollView style={{ height: "80%" }}>
|
||||||
|
<TextCustom>
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
|
||||||
|
eiusmod tempor incididunt ut labore et dolore magna aliqua.
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
|
||||||
|
eiusmod tempor incididunt ut labore et dolore magna aliqua.Lorem
|
||||||
|
ipsum dolor sit amet, consectetur adipiscing elit, sed do
|
||||||
|
eiusmod tempor incididunt ut labore et dolore magna aliqua.Lorem
|
||||||
|
ipsum dolor sit amet, consectetur adipiscing elit, sed do
|
||||||
|
eiusmod tempor incididunt ut labore et dolore magna aliqua.Lorem
|
||||||
|
ipsum dolor sit amet, consectetur adipiscing elit, sed do
|
||||||
|
eiusmod tempor incididunt ut iqua.Lorem ipsum dolor sit amet,
|
||||||
|
consectetur adipiscing elit, sed do eiusmod tempor incididunt ut
|
||||||
|
labore et dolore magna aliqua.Lorem ipsum dolor sit amet,
|
||||||
|
consectetur adipiscing elit, sed do eiusmod tempor incididunt ut
|
||||||
|
labore et dolore magna aliqua.Lorem ipsum dolor sit amet,
|
||||||
|
consectetur adipiscing elit, sed do eiusmod tempor incididunt ut
|
||||||
|
labore et dolore magna aliqua.Lorem ipsum dolor sit amet,
|
||||||
|
consectetur adipiscing elit, sed do eiusmod tempor incididunt ut
|
||||||
|
labore et dolore magna aliqua.Lorem ipsum dolor sit amet,
|
||||||
|
consectetur adipiscing elit, sed do eiusmod tempor incididunt ut
|
||||||
|
labore et dolore magna aliqua.Lorem ipsum dolor sit amet,
|
||||||
|
consectetur adipiscing elit, sed do eiusmod tempor incididunt ut
|
||||||
|
labore et dolore magna aliqua.Lorem ipsum dolor sit amet,
|
||||||
|
consectetur adipiscing elit, sed do eiusmod tempor incididunt ut
|
||||||
|
labore et dolore magna aliqua.Lorem ipsum dolor sit amet,
|
||||||
|
consectetur adipiscing elit, sed do eiusmod tempor incididunt ut
|
||||||
|
labore et dolore magna aliqua.
|
||||||
|
</TextCustom>
|
||||||
|
</ScrollView>
|
||||||
|
</BaseBox>
|
||||||
|
<Spacing />
|
||||||
|
</StackCustom>
|
||||||
|
</DrawerCustom>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
53
app/(application)/(user)/collaboration/create.tsx
Normal file
53
app/(application)/(user)/collaboration/create.tsx
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
import {
|
||||||
|
ButtonCustom,
|
||||||
|
SelectCustom,
|
||||||
|
StackCustom,
|
||||||
|
TextAreaCustom,
|
||||||
|
TextInputCustom,
|
||||||
|
ViewWrapper
|
||||||
|
} from "@/components";
|
||||||
|
import { router } from "expo-router";
|
||||||
|
|
||||||
|
export default function CollaborationCreate() {
|
||||||
|
return (
|
||||||
|
<ViewWrapper>
|
||||||
|
<StackCustom gap={"xs"}>
|
||||||
|
<TextInputCustom label="Judul" placeholder="Masukan judul" required />
|
||||||
|
<TextInputCustom label="Lokasi" placeholder="Masukan lokasi" required />
|
||||||
|
<SelectCustom
|
||||||
|
label="Pilih Industri"
|
||||||
|
data={[
|
||||||
|
{ label: "Industri 1", value: "industri-1" },
|
||||||
|
{ label: "Industri 2", value: "industri-2" },
|
||||||
|
{ label: "Industri 3", value: "industri-3" },
|
||||||
|
]}
|
||||||
|
onChange={(value) => console.log(value)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextAreaCustom
|
||||||
|
required
|
||||||
|
label="Tujuan Proyek"
|
||||||
|
placeholder="Masukan tujuan proyek"
|
||||||
|
showCount
|
||||||
|
maxLength={1000}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextAreaCustom
|
||||||
|
required
|
||||||
|
label="Keuntungan Proyek"
|
||||||
|
placeholder="Masukan keuntungan proyek"
|
||||||
|
showCount
|
||||||
|
maxLength={1000}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ButtonCustom
|
||||||
|
title="Simpan"
|
||||||
|
onPress={() => {
|
||||||
|
console.log("Simpan proyek");
|
||||||
|
router.back();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</StackCustom>
|
||||||
|
</ViewWrapper>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,81 +1,43 @@
|
|||||||
import { AccentColor, MainColor } from "@/constants/color-palet";
|
import {
|
||||||
import { OS_IOS_HEIGHT, OS_ANDROID_HEIGHT } from "@/constants/constans-value";
|
IconContribution,
|
||||||
import { FontAwesome5, Ionicons } from "@expo/vector-icons";
|
IconHistory,
|
||||||
|
IconHome,
|
||||||
|
IconStatus,
|
||||||
|
} from "@/components/_Icon";
|
||||||
|
import { TabsStyles } from "@/styles/tabs-styles";
|
||||||
import { Tabs } from "expo-router";
|
import { Tabs } from "expo-router";
|
||||||
import { Platform, View } from "react-native";
|
|
||||||
|
|
||||||
export default function EventLayout() {
|
export default function EventTabsLayout() {
|
||||||
return (
|
return (
|
||||||
<Tabs
|
<Tabs screenOptions={TabsStyles}>
|
||||||
screenOptions={{
|
|
||||||
headerShown: false,
|
|
||||||
tabBarActiveTintColor: MainColor.yellow,
|
|
||||||
tabBarInactiveTintColor: MainColor.white_gray,
|
|
||||||
tabBarBackground: CustomTabBarBackground,
|
|
||||||
tabBarStyle: Platform.select({
|
|
||||||
ios: {
|
|
||||||
borderTopWidth: 0,
|
|
||||||
paddingTop: 5,
|
|
||||||
height: OS_IOS_HEIGHT,
|
|
||||||
},
|
|
||||||
android: {
|
|
||||||
borderTopWidth: 0,
|
|
||||||
paddingTop: 5,
|
|
||||||
height: OS_ANDROID_HEIGHT,
|
|
||||||
},
|
|
||||||
default: {},
|
|
||||||
}),
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Tabs.Screen
|
<Tabs.Screen
|
||||||
name="index"
|
name="index"
|
||||||
options={{
|
options={{
|
||||||
title: "Home",
|
title: "Beranda",
|
||||||
tabBarIcon: ({ color }) => (
|
tabBarIcon: ({ color }) => <IconHome color={color} />,
|
||||||
<Ionicons size={20} name="home" color={color} />
|
|
||||||
),
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Tabs.Screen
|
<Tabs.Screen
|
||||||
name="status"
|
name="status"
|
||||||
options={{
|
options={{
|
||||||
title: "Status",
|
title: "Status",
|
||||||
tabBarIcon: ({ color }) => (
|
tabBarIcon: ({ color }) => <IconStatus color={color} />,
|
||||||
<Ionicons size={20} name="list" color={color} />
|
|
||||||
),
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Tabs.Screen
|
<Tabs.Screen
|
||||||
name="kontribusi"
|
name="contribution"
|
||||||
options={{
|
options={{
|
||||||
title: "Kontribusi",
|
title: "Kontribusi",
|
||||||
tabBarIcon: ({ color }) => (
|
tabBarIcon: ({ color }) => <IconContribution color={color} />,
|
||||||
<Ionicons size={20} name="extension-puzzle" color={color} />
|
|
||||||
),
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Tabs.Screen
|
<Tabs.Screen
|
||||||
name="riwayat"
|
name="history"
|
||||||
options={{
|
options={{
|
||||||
title: "Riwayat",
|
title: "Riwayat",
|
||||||
tabBarIcon: ({ color }) => (
|
tabBarIcon: ({ color }) => <IconHistory color={color} />,
|
||||||
<FontAwesome5 size={20} name="history" color={color} />
|
|
||||||
),
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function CustomTabBarBackground() {
|
|
||||||
return (
|
|
||||||
<View
|
|
||||||
style={{
|
|
||||||
flex: 1,
|
|
||||||
backgroundColor: MainColor.darkblue,
|
|
||||||
borderTopWidth: 1,
|
|
||||||
borderTopColor: AccentColor.blue,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|||||||
43
app/(application)/(user)/event/(tabs)/contribution.tsx
Normal file
43
app/(application)/(user)/event/(tabs)/contribution.tsx
Normal 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>
|
||||||
|
);
|
||||||
|
}
|
||||||
68
app/(application)/(user)/event/(tabs)/history.tsx
Normal file
68
app/(application)/(user)/event/(tabs)/history.tsx
Normal 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>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,30 +1,23 @@
|
|||||||
import ViewWrapper from "@/components/_ShareComponent/ViewWrapper";
|
import ViewWrapper from "@/components/_ShareComponent/ViewWrapper";
|
||||||
import FloatingButton from "@/components/Button/FloatingButton";
|
import FloatingButton from "@/components/Button/FloatingButton";
|
||||||
import { AccentColor, MainColor } from "@/constants/color-palet";
|
import Event_BoxPublishSection from "@/screens/Event/BoxPublishSection";
|
||||||
import { GStyles } from "@/styles/global-styles";
|
|
||||||
import { router } from "expo-router";
|
import { router } from "expo-router";
|
||||||
import { Text, TouchableHighlight, View } from "react-native";
|
|
||||||
|
|
||||||
export default function Event() {
|
export default function EventBeranda() {
|
||||||
return (
|
return (
|
||||||
<ViewWrapper
|
<ViewWrapper
|
||||||
|
hideFooter
|
||||||
floatingButton={
|
floatingButton={
|
||||||
<FloatingButton onPress={() => router.push("/event/create")} />
|
<FloatingButton onPress={() => router.push("/event/create")} />
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<TouchableHighlight onPress={() => router.push("/event/detail/1")}>
|
{Array.from({ length: 10 }).map((_, index) => (
|
||||||
<View
|
<Event_BoxPublishSection
|
||||||
style={{
|
key={index}
|
||||||
padding: 20,
|
id={index.toString()}
|
||||||
backgroundColor: MainColor.darkblue,
|
href={`/event/${index}/publish`}
|
||||||
borderRadius: 10,
|
/>
|
||||||
borderColor: AccentColor.blue,
|
))}
|
||||||
borderWidth: 1,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Text style={GStyles.textLabel}>Event</Text>
|
|
||||||
</View>
|
|
||||||
</TouchableHighlight>
|
|
||||||
</ViewWrapper>
|
</ViewWrapper>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -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>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,11 +1,63 @@
|
|||||||
|
import {
|
||||||
|
BoxWithHeaderSection,
|
||||||
|
Grid,
|
||||||
|
ScrollableCustom,
|
||||||
|
StackCustom,
|
||||||
|
TextCustom
|
||||||
|
} from "@/components";
|
||||||
import ViewWrapper from "@/components/_ShareComponent/ViewWrapper";
|
import ViewWrapper from "@/components/_ShareComponent/ViewWrapper";
|
||||||
import { GStyles } from "@/styles/global-styles";
|
import { masterStatus } from "@/lib/dummy-data/_master/status";
|
||||||
import { Text } from "react-native";
|
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 (
|
return (
|
||||||
<ViewWrapper>
|
<ViewWrapper headerComponent={scrollComponent}>
|
||||||
<Text style={GStyles.textLabel}>Status</Text>
|
<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>
|
</ViewWrapper>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
117
app/(application)/(user)/event/[id]/[status]/detail-event.tsx
Normal file
117
app/(application)/(user)/event/[id]/[status]/detail-event.tsx
Normal 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 }) as any}
|
||||||
|
columns={4}
|
||||||
|
onPressItem={handlePress as any}
|
||||||
|
/>
|
||||||
|
</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!",
|
||||||
|
},
|
||||||
|
];
|
||||||
51
app/(application)/(user)/event/[id]/contribution.tsx
Normal file
51
app/(application)/(user)/event/[id]/contribution.tsx
Normal 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>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
107
app/(application)/(user)/event/[id]/edit.tsx
Normal file
107
app/(application)/(user)/event/[id]/edit.tsx
Normal 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>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
51
app/(application)/(user)/event/[id]/history.tsx
Normal file
51
app/(application)/(user)/event/[id]/history.tsx
Normal 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>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
17
app/(application)/(user)/event/[id]/list-of-participants.tsx
Normal file
17
app/(application)/(user)/event/[id]/list-of-participants.tsx
Normal 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>
|
||||||
|
);
|
||||||
|
}
|
||||||
64
app/(application)/(user)/event/[id]/publish.tsx
Normal file
64
app/(application)/(user)/event/[id]/publish.tsx
Normal 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>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,15 +1,15 @@
|
|||||||
import {
|
import {
|
||||||
BoxButtonOnFooter,
|
ButtonCustom,
|
||||||
ButtonCustom,
|
SelectCustom,
|
||||||
SelectCustom,
|
StackCustom,
|
||||||
StackCustom,
|
TextAreaCustom,
|
||||||
TextAreaCustom,
|
TextInputCustom,
|
||||||
TextInputCustom,
|
ViewWrapper,
|
||||||
ViewWrapper,
|
|
||||||
} from "@/components";
|
} from "@/components";
|
||||||
import DateTimePickerCustom from "@/components/DateInput/DateTimePickerCustom";
|
import DateTimePickerCustom from "@/components/DateInput/DateTimePickerCustom";
|
||||||
import { masterTypeEvent } from "@/lib/dummy-data/event/master-type-event";
|
import { masterTypeEvent } from "@/lib/dummy-data/event/master-type-event";
|
||||||
import { DateTimePickerEvent } from "@react-native-community/datetimepicker";
|
import { DateTimePickerEvent } from "@react-native-community/datetimepicker";
|
||||||
|
import { router } from "expo-router";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { Platform } from "react-native";
|
import { Platform } from "react-native";
|
||||||
|
|
||||||
@@ -23,32 +23,39 @@ export default function EventCreate() {
|
|||||||
>(null);
|
>(null);
|
||||||
|
|
||||||
const handlerSubmit = () => {
|
const handlerSubmit = () => {
|
||||||
if (selectedDate) {
|
try {
|
||||||
console.log("Tanggal yang dipilih:", selectedDate);
|
if (selectedDate) {
|
||||||
console.log(`ISO Format ${Platform.OS}:`, selectedDate.toString());
|
console.log("Tanggal yang dipilih:", selectedDate);
|
||||||
// Kirim ke API atau proses lanjutan
|
console.log(`ISO Format ${Platform.OS}:`, selectedDate.toString());
|
||||||
} else {
|
// Kirim ke API atau proses lanjutan
|
||||||
console.warn("Tanggal belum dipilih");
|
} else {
|
||||||
}
|
console.log("Tanggal belum dipilih");
|
||||||
|
}
|
||||||
|
|
||||||
if (selectedEndDate) {
|
if (selectedEndDate) {
|
||||||
console.log("Tanggal yang dipilih:", selectedEndDate);
|
console.log("Tanggal yang dipilih:", selectedEndDate);
|
||||||
console.log(`ISO Format ${Platform.OS}:`, selectedEndDate.toString());
|
console.log(`ISO Format ${Platform.OS}:`, selectedEndDate.toString());
|
||||||
// Kirim ke API atau proses lanjutan
|
// Kirim ke API atau proses lanjutan
|
||||||
} else {
|
} else {
|
||||||
console.warn("Tanggal belum dipilih");
|
console.log("Tanggal berakhir belum dipilih");
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("Data berhasil disimpan");
|
||||||
|
router.navigate("/event/status");
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const buttonSubmit = (
|
const buttonSubmit = (
|
||||||
<BoxButtonOnFooter>
|
<ButtonCustom title="Simpan" onPress={handlerSubmit} />
|
||||||
<ButtonCustom title="Simpan" onPress={handlerSubmit} />
|
// <BoxButtonOnFooter>
|
||||||
</BoxButtonOnFooter>
|
// </BoxButtonOnFooter>
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ViewWrapper footerComponent={buttonSubmit}>
|
<ViewWrapper>
|
||||||
<StackCustom gap={"xs"}>
|
<StackCustom gap={"xs"}>
|
||||||
<TextInputCustom
|
<TextInputCustom
|
||||||
placeholder="Masukkan nama event"
|
placeholder="Masukkan nama event"
|
||||||
@@ -93,6 +100,8 @@ export default function EventCreate() {
|
|||||||
showCount
|
showCount
|
||||||
maxLength={100}
|
maxLength={100}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{buttonSubmit}
|
||||||
</StackCustom>
|
</StackCustom>
|
||||||
</ViewWrapper>
|
</ViewWrapper>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -3,16 +3,14 @@ import {
|
|||||||
AvatarCustom,
|
AvatarCustom,
|
||||||
BackButton,
|
BackButton,
|
||||||
DrawerCustom,
|
DrawerCustom,
|
||||||
TextInputCustom,
|
SearchInput,
|
||||||
ViewWrapper,
|
ViewWrapper,
|
||||||
} from "@/components";
|
} from "@/components";
|
||||||
import FloatingButton from "@/components/Button/FloatingButton";
|
import FloatingButton from "@/components/Button/FloatingButton";
|
||||||
import { MainColor } from "@/constants/color-palet";
|
import { MainColor } from "@/constants/color-palet";
|
||||||
import { ICON_SIZE_SMALL } from "@/constants/constans-value";
|
|
||||||
import Forum_BoxDetailSection from "@/screens/Forum/DiscussionBoxSection";
|
import Forum_BoxDetailSection from "@/screens/Forum/DiscussionBoxSection";
|
||||||
import { listDummyDiscussionForum } from "@/screens/Forum/list-data-dummy";
|
import { listDummyDiscussionForum } from "@/screens/Forum/list-data-dummy";
|
||||||
import Forum_MenuDrawerBerandaSection from "@/screens/Forum/MenuDrawerSection.tsx/MenuBeranda";
|
import Forum_MenuDrawerBerandaSection from "@/screens/Forum/MenuDrawerSection.tsx/MenuBeranda";
|
||||||
import { Ionicons } from "@expo/vector-icons";
|
|
||||||
import { router, Stack } from "expo-router";
|
import { router, Stack } from "expo-router";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
|
||||||
@@ -34,20 +32,7 @@ export default function Forum() {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<ViewWrapper
|
<ViewWrapper
|
||||||
headerComponent={
|
headerComponent={<SearchInput placeholder="Cari topik diskusi" />}
|
||||||
<TextInputCustom
|
|
||||||
iconLeft={
|
|
||||||
<Ionicons
|
|
||||||
name="search-outline"
|
|
||||||
size={ICON_SIZE_SMALL}
|
|
||||||
color={MainColor.placeholder}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
placeholder="Cari topik forum..."
|
|
||||||
borderRadius={50}
|
|
||||||
containerStyle={{ marginBottom: 0 }}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
floatingButton={
|
floatingButton={
|
||||||
<FloatingButton
|
<FloatingButton
|
||||||
onPress={() =>
|
onPress={() =>
|
||||||
|
|||||||
34
app/(application)/(user)/job/(tabs)/_layout.tsx
Normal file
34
app/(application)/(user)/job/(tabs)/_layout.tsx
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import { IconHome, IconStatus } from "@/components/_Icon";
|
||||||
|
import { TabsStyles } from "@/styles/tabs-styles";
|
||||||
|
import { Ionicons } from "@expo/vector-icons";
|
||||||
|
import { Tabs } from "expo-router";
|
||||||
|
|
||||||
|
export default function JobTabsLayout() {
|
||||||
|
return (
|
||||||
|
<Tabs screenOptions={TabsStyles}>
|
||||||
|
<Tabs.Screen
|
||||||
|
name="index"
|
||||||
|
options={{
|
||||||
|
title: "Beranda",
|
||||||
|
tabBarIcon: ({ color }) => <IconHome color={color} />,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Tabs.Screen
|
||||||
|
name="status"
|
||||||
|
options={{
|
||||||
|
title: "Status",
|
||||||
|
tabBarIcon: ({ color }) => <IconStatus color={color} />,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Tabs.Screen
|
||||||
|
name="archive"
|
||||||
|
options={{
|
||||||
|
title: "Arsip",
|
||||||
|
tabBarIcon: ({ color }) => (
|
||||||
|
<Ionicons size={20} name="archive" color={color} />
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Tabs>
|
||||||
|
);
|
||||||
|
}
|
||||||
16
app/(application)/(user)/job/(tabs)/archive.tsx
Normal file
16
app/(application)/(user)/job/(tabs)/archive.tsx
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { BaseBox, TextCustom, ViewWrapper } from "@/components";
|
||||||
|
import { jobDataDummy } from "@/screens/Job/listDataDummy";
|
||||||
|
|
||||||
|
export default function JobArchive() {
|
||||||
|
return (
|
||||||
|
<ViewWrapper hideFooter>
|
||||||
|
{jobDataDummy.map((e, i) => (
|
||||||
|
<BaseBox key={i} paddingTop={20} paddingBottom={20}>
|
||||||
|
<TextCustom align="center" bold truncate size="large">
|
||||||
|
{e.posisi}
|
||||||
|
</TextCustom>
|
||||||
|
</BaseBox>
|
||||||
|
))}
|
||||||
|
</ViewWrapper>
|
||||||
|
);
|
||||||
|
}
|
||||||
34
app/(application)/(user)/job/(tabs)/index.tsx
Normal file
34
app/(application)/(user)/job/(tabs)/index.tsx
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import {
|
||||||
|
AvatarUsernameAndOtherComponent,
|
||||||
|
BoxWithHeaderSection,
|
||||||
|
FloatingButton,
|
||||||
|
SearchInput,
|
||||||
|
Spacing,
|
||||||
|
TextCustom,
|
||||||
|
ViewWrapper
|
||||||
|
} from "@/components";
|
||||||
|
import { jobDataDummy } from "@/screens/Job/listDataDummy";
|
||||||
|
import { router } from "expo-router";
|
||||||
|
|
||||||
|
export default function JobBeranda() {
|
||||||
|
return (
|
||||||
|
<ViewWrapper
|
||||||
|
hideFooter
|
||||||
|
floatingButton={
|
||||||
|
<FloatingButton onPress={() => router.push("/job/create")} />
|
||||||
|
}
|
||||||
|
headerComponent={<SearchInput placeholder="Cari pekerjaan" />}
|
||||||
|
>
|
||||||
|
{jobDataDummy.map((item, index) => (
|
||||||
|
<BoxWithHeaderSection key={index} onPress={() => router.push(`/job/${item.id}`)}>
|
||||||
|
<AvatarUsernameAndOtherComponent avatarHref={`/profile/${item.id}`} />
|
||||||
|
<Spacing />
|
||||||
|
<TextCustom truncate={2} align="center" bold size="large">
|
||||||
|
{item.posisi}
|
||||||
|
</TextCustom>
|
||||||
|
<Spacing />
|
||||||
|
</BoxWithHeaderSection>
|
||||||
|
))}
|
||||||
|
</ViewWrapper>
|
||||||
|
);
|
||||||
|
}
|
||||||
50
app/(application)/(user)/job/(tabs)/status.tsx
Normal file
50
app/(application)/(user)/job/(tabs)/status.tsx
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
import {
|
||||||
|
BaseBox,
|
||||||
|
ScrollableCustom,
|
||||||
|
TextCustom,
|
||||||
|
ViewWrapper,
|
||||||
|
} from "@/components";
|
||||||
|
import { masterStatus } from "@/lib/dummy-data/_master/status";
|
||||||
|
import { jobDataDummy } from "@/screens/Job/listDataDummy";
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
export default function JobStatus() {
|
||||||
|
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}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ViewWrapper headerComponent={scrollComponent} hideFooter>
|
||||||
|
{jobDataDummy.map((e, i) => (
|
||||||
|
<BaseBox
|
||||||
|
key={i}
|
||||||
|
paddingTop={20}
|
||||||
|
paddingBottom={20}
|
||||||
|
href={`/job/${e.id}/${activeCategory}/detail`}
|
||||||
|
// onPress={() => console.log("pressed")}
|
||||||
|
>
|
||||||
|
<TextCustom align="center" bold truncate size="large">
|
||||||
|
{e.posisi} {activeCategory?.toUpperCase()}
|
||||||
|
</TextCustom>
|
||||||
|
</BaseBox>
|
||||||
|
))}
|
||||||
|
</ViewWrapper>
|
||||||
|
);
|
||||||
|
}
|
||||||
65
app/(application)/(user)/job/[id]/[status]/detail.tsx
Normal file
65
app/(application)/(user)/job/[id]/[status]/detail.tsx
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
import {
|
||||||
|
BackButton,
|
||||||
|
DotButton,
|
||||||
|
DrawerCustom,
|
||||||
|
MenuDrawerDynamicGrid,
|
||||||
|
Spacing,
|
||||||
|
ViewWrapper,
|
||||||
|
} from "@/components";
|
||||||
|
import { IconEdit } from "@/components/_Icon";
|
||||||
|
import { IMenuDrawerItem } from "@/components/_Interface/types";
|
||||||
|
import Job_BoxDetailSection from "@/screens/Job/BoxDetailSection";
|
||||||
|
import Job_ButtonStatusSection from "@/screens/Job/ButtonStatusSection";
|
||||||
|
import { jobDataDummy } from "@/screens/Job/listDataDummy";
|
||||||
|
import { router, Stack, useLocalSearchParams } from "expo-router";
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
export default function JobDetailStatus() {
|
||||||
|
const { id, status } = useLocalSearchParams();
|
||||||
|
const [openDrawer, setOpenDrawer] = useState(false);
|
||||||
|
const jobDetail = jobDataDummy.find((e) => e.id === Number(id));
|
||||||
|
|
||||||
|
const handlePress = (item: IMenuDrawerItem) => {
|
||||||
|
console.log("PATH >> ", item.path);
|
||||||
|
router.navigate(item.path as any);
|
||||||
|
setOpenDrawer(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Stack.Screen
|
||||||
|
options={{
|
||||||
|
title: `Detail`,
|
||||||
|
headerLeft: () => <BackButton />,
|
||||||
|
headerRight: () =>
|
||||||
|
status === "draft" ? (
|
||||||
|
<DotButton onPress={() => setOpenDrawer(true)} />
|
||||||
|
) : null,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<ViewWrapper>
|
||||||
|
<Job_BoxDetailSection data={jobDetail} />
|
||||||
|
<Job_ButtonStatusSection status={status as string} />
|
||||||
|
<Spacing />
|
||||||
|
</ViewWrapper>
|
||||||
|
|
||||||
|
<DrawerCustom
|
||||||
|
isVisible={openDrawer}
|
||||||
|
closeDrawer={() => setOpenDrawer(false)}
|
||||||
|
height={"auto"}
|
||||||
|
>
|
||||||
|
<MenuDrawerDynamicGrid
|
||||||
|
data={[
|
||||||
|
{
|
||||||
|
icon: <IconEdit />,
|
||||||
|
label: "Edit",
|
||||||
|
path: `/job/${id}/edit`,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
columns={4}
|
||||||
|
onPressItem={handlePress as any}
|
||||||
|
/>
|
||||||
|
</DrawerCustom>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
67
app/(application)/(user)/job/[id]/edit.tsx
Normal file
67
app/(application)/(user)/job/[id]/edit.tsx
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
import {
|
||||||
|
ButtonCenteredOnly,
|
||||||
|
ButtonCustom,
|
||||||
|
InformationBox,
|
||||||
|
LandscapeFrameUploaded,
|
||||||
|
Spacing,
|
||||||
|
StackCustom,
|
||||||
|
TextAreaCustom,
|
||||||
|
TextInputCustom,
|
||||||
|
ViewWrapper,
|
||||||
|
} from "@/components";
|
||||||
|
import { router } from "expo-router";
|
||||||
|
|
||||||
|
export default function JobEdit() {
|
||||||
|
const buttonSubmit = () => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<ButtonCustom onPress={() => router.back()}>Update</ButtonCustom>
|
||||||
|
<Spacing />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ViewWrapper>
|
||||||
|
<StackCustom gap={"xs"}>
|
||||||
|
<InformationBox text="Poster atau gambar lowongan kerja bersifat opsional, tidak wajib untuk dimasukkan dan upload lah gambar yang sesuai dengan deskripsi lowongan kerja." />
|
||||||
|
|
||||||
|
<LandscapeFrameUploaded />
|
||||||
|
<ButtonCenteredOnly
|
||||||
|
onPress={() => {
|
||||||
|
router.push("/(application)/(image)/take-picture/123");
|
||||||
|
}}
|
||||||
|
icon="upload"
|
||||||
|
>
|
||||||
|
Upload
|
||||||
|
</ButtonCenteredOnly>
|
||||||
|
|
||||||
|
<Spacing />
|
||||||
|
|
||||||
|
<TextInputCustom
|
||||||
|
label="Judul Lowongan"
|
||||||
|
placeholder="Masukan Judul Lowongan Kerja"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextAreaCustom
|
||||||
|
label="Syarat & Kualifikasi"
|
||||||
|
placeholder="Masukan Syarat & Kualifikasi Lowongan Kerja"
|
||||||
|
required
|
||||||
|
showCount
|
||||||
|
maxLength={1000}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextAreaCustom
|
||||||
|
label="Deskripsi Lowongan"
|
||||||
|
placeholder="Masukan Deskripsi Lowongan Kerja"
|
||||||
|
required
|
||||||
|
showCount
|
||||||
|
maxLength={1000}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{buttonSubmit()}
|
||||||
|
</StackCustom>
|
||||||
|
</ViewWrapper>
|
||||||
|
);
|
||||||
|
}
|
||||||
79
app/(application)/(user)/job/[id]/index.tsx
Normal file
79
app/(application)/(user)/job/[id]/index.tsx
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
import {
|
||||||
|
ButtonCustom,
|
||||||
|
Spacing,
|
||||||
|
ViewWrapper
|
||||||
|
} from "@/components";
|
||||||
|
import { MainColor } from "@/constants/color-palet";
|
||||||
|
import { ICON_SIZE_SMALL } from "@/constants/constans-value";
|
||||||
|
import Job_BoxDetailSection from "@/screens/Job/BoxDetailSection";
|
||||||
|
import { jobDataDummy } from "@/screens/Job/listDataDummy";
|
||||||
|
import { Ionicons } from "@expo/vector-icons";
|
||||||
|
import * as Clipboard from "expo-clipboard";
|
||||||
|
import { useLocalSearchParams } from "expo-router";
|
||||||
|
import { Alert, Linking } from "react-native";
|
||||||
|
|
||||||
|
export default function JobDetail() {
|
||||||
|
const { id } = useLocalSearchParams();
|
||||||
|
|
||||||
|
const jobDetail = jobDataDummy.find((e) => e.id === Number(id));
|
||||||
|
|
||||||
|
const OpenLinkButton = () => {
|
||||||
|
const jobUrl =
|
||||||
|
"https://stg-hipmi.wibudev.com/job-vacancy/cm6ijt9w8005zucv4twsct657";
|
||||||
|
|
||||||
|
const openInBrowser = async () => {
|
||||||
|
const supported = await Linking.canOpenURL(jobUrl);
|
||||||
|
if (supported) {
|
||||||
|
await Linking.openURL(jobUrl);
|
||||||
|
} else {
|
||||||
|
Alert.alert("Gagal membuka link", "Browser tidak tersedia.");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ButtonCustom
|
||||||
|
iconLeft={
|
||||||
|
<Ionicons name="globe" size={ICON_SIZE_SMALL} color="white" />
|
||||||
|
}
|
||||||
|
onPress={openInBrowser}
|
||||||
|
backgroundColor="green"
|
||||||
|
textColor="white"
|
||||||
|
>
|
||||||
|
Buka Lowongan di Browser
|
||||||
|
</ButtonCustom>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const CopyLinkButton = () => {
|
||||||
|
const jobUrl =
|
||||||
|
"https://stg-hipmi.wibudev.com/job-vacancy/cm6ijt9w8005zucv4twsct657";
|
||||||
|
|
||||||
|
const copyToClipboard = async () => {
|
||||||
|
await Clipboard.setStringAsync(jobUrl);
|
||||||
|
Alert.alert(
|
||||||
|
"Link disalin",
|
||||||
|
"Tautan lowongan telah disalin ke clipboard."
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ButtonCustom
|
||||||
|
iconLeft={<Ionicons name="copy" size={ICON_SIZE_SMALL} color="white" />}
|
||||||
|
onPress={copyToClipboard}
|
||||||
|
backgroundColor={MainColor.orange}
|
||||||
|
textColor="white"
|
||||||
|
>
|
||||||
|
Salin Link
|
||||||
|
</ButtonCustom>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ViewWrapper>
|
||||||
|
<Job_BoxDetailSection data={jobDetail}/>
|
||||||
|
<OpenLinkButton />
|
||||||
|
<Spacing />
|
||||||
|
<CopyLinkButton />
|
||||||
|
</ViewWrapper>
|
||||||
|
);
|
||||||
|
}
|
||||||
73
app/(application)/(user)/job/create.tsx
Normal file
73
app/(application)/(user)/job/create.tsx
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
import {
|
||||||
|
ButtonCenteredOnly,
|
||||||
|
ButtonCustom,
|
||||||
|
InformationBox,
|
||||||
|
LandscapeFrameUploaded,
|
||||||
|
Spacing,
|
||||||
|
StackCustom,
|
||||||
|
TextAreaCustom,
|
||||||
|
TextInputCustom,
|
||||||
|
ViewWrapper,
|
||||||
|
} from "@/components";
|
||||||
|
import { router } from "expo-router";
|
||||||
|
|
||||||
|
export default function JobCreate() {
|
||||||
|
const buttonSubmit = () => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<ButtonCustom
|
||||||
|
onPress={() =>
|
||||||
|
router.replace("/(application)/(user)/job/(tabs)/status")
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Simpan
|
||||||
|
</ButtonCustom>
|
||||||
|
<Spacing />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ViewWrapper>
|
||||||
|
<StackCustom gap={"xs"}>
|
||||||
|
<InformationBox text="Poster atau gambar lowongan kerja bersifat opsional, tidak wajib untuk dimasukkan dan upload lah gambar yang sesuai dengan deskripsi lowongan kerja." />
|
||||||
|
|
||||||
|
<LandscapeFrameUploaded />
|
||||||
|
<ButtonCenteredOnly
|
||||||
|
onPress={() => {
|
||||||
|
router.push("/(application)/(image)/take-picture/123");
|
||||||
|
}}
|
||||||
|
icon="upload"
|
||||||
|
>
|
||||||
|
Upload
|
||||||
|
</ButtonCenteredOnly>
|
||||||
|
|
||||||
|
<Spacing />
|
||||||
|
|
||||||
|
<TextInputCustom
|
||||||
|
label="Judul Lowongan"
|
||||||
|
placeholder="Masukan Judul Lowongan Kerja"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextAreaCustom
|
||||||
|
label="Syarat & Kualifikasi"
|
||||||
|
placeholder="Masukan Syarat & Kualifikasi Lowongan Kerja"
|
||||||
|
required
|
||||||
|
showCount
|
||||||
|
maxLength={1000}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextAreaCustom
|
||||||
|
label="Deskripsi Lowongan"
|
||||||
|
placeholder="Masukan Deskripsi Lowongan Kerja"
|
||||||
|
required
|
||||||
|
showCount
|
||||||
|
maxLength={1000}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{buttonSubmit()}
|
||||||
|
</StackCustom>
|
||||||
|
</ViewWrapper>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -11,18 +11,18 @@ import { useState } from "react";
|
|||||||
import { View } from "react-native";
|
import { View } from "react-native";
|
||||||
|
|
||||||
const categories = [
|
const categories = [
|
||||||
{ id: 1, label: "Semua" },
|
{ value: "all", label: "Semua" },
|
||||||
{ id: 2, label: "Event" },
|
{ value: "event", label: "Event" },
|
||||||
{ id: 3, label: "Job" },
|
{ value: "job", label: "Job" },
|
||||||
{ id: 4, label: "Voting" },
|
{ value: "voting", label: "Voting" },
|
||||||
{ id: 5, label: "Donasi" },
|
{ value: "donasi", label: "Donasi" },
|
||||||
{ id: 6, label: "Investasi" },
|
{ value: "investasi", label: "Investasi" },
|
||||||
{ id: 7, label: "Forum" },
|
{ value: "forum", label: "Forum" },
|
||||||
{ id: 8, label: "Collaboration" },
|
{ value: "collaboration", label: "Collaboration" },
|
||||||
];
|
];
|
||||||
|
|
||||||
const selectedCategory = (id: number) => {
|
const selectedCategory = (value: string) => {
|
||||||
const category = categories.find((c) => c.id === id);
|
const category = categories.find((c) => c.value === value);
|
||||||
return category?.label;
|
return category?.label;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ const BoxNotification = ({
|
|||||||
activeCategory,
|
activeCategory,
|
||||||
}: {
|
}: {
|
||||||
index: number;
|
index: number;
|
||||||
activeCategory: number | null;
|
activeCategory: string | null;
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -39,13 +39,13 @@ const BoxNotification = ({
|
|||||||
onPress={() =>
|
onPress={() =>
|
||||||
console.log(
|
console.log(
|
||||||
"Notification >",
|
"Notification >",
|
||||||
selectedCategory(activeCategory as number)
|
selectedCategory(activeCategory as string)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<StackCustom>
|
<StackCustom>
|
||||||
<TextCustom bold>
|
<TextCustom bold>
|
||||||
# {selectedCategory(activeCategory as number)}
|
# {selectedCategory(activeCategory as string)}
|
||||||
</TextCustom>
|
</TextCustom>
|
||||||
|
|
||||||
<View
|
<View
|
||||||
@@ -81,38 +81,31 @@ const BoxNotification = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default function Notifications() {
|
export default function Notifications() {
|
||||||
const [activeCategory, setActiveCategory] = useState<number | null>(1);
|
const [activeCategory, setActiveCategory] = useState<string | null>("all");
|
||||||
|
|
||||||
const handlePress = (item: any) => {
|
const handlePress = (item: any) => {
|
||||||
setActiveCategory(item.id);
|
setActiveCategory(item.value);
|
||||||
// tambahkan logika lain seperti filter dsb.
|
// tambahkan logika lain seperti filter dsb.
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<ViewWrapper
|
<ViewWrapper
|
||||||
headerComponent={
|
headerComponent={
|
||||||
<ScrollableCustom
|
<ScrollableCustom
|
||||||
data={categories}
|
data={categories.map((e, i) => ({
|
||||||
|
id: i,
|
||||||
|
label: e.label,
|
||||||
|
value: e.value,
|
||||||
|
}))}
|
||||||
onButtonPress={handlePress}
|
onButtonPress={handlePress}
|
||||||
activeId={activeCategory as any}
|
activeId={activeCategory as string}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{Array.from({ length: 20 }).map((e, i) => (
|
{Array.from({ length: 20 }).map((e, i) => (
|
||||||
<View key={i}>
|
<View key={i}>
|
||||||
<BoxNotification index={i} activeCategory={activeCategory} />
|
<BoxNotification index={i} activeCategory={activeCategory as any} />
|
||||||
</View>
|
</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>
|
</ViewWrapper>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import LeftButtonCustom from "@/components/Button/BackButton";
|
|||||||
import DrawerCustom from "@/components/Drawer/DrawerCustom";
|
import DrawerCustom from "@/components/Drawer/DrawerCustom";
|
||||||
import { MainColor } from "@/constants/color-palet";
|
import { MainColor } from "@/constants/color-palet";
|
||||||
import { drawerItemsProfile } from "@/screens/Profile/ListPage";
|
import { drawerItemsProfile } from "@/screens/Profile/ListPage";
|
||||||
import Profile_MenuDrawerSection from "@/screens/Profile/MenuDrawerSection";
|
import Profile_MenuDrawerSection from "@/screens/Profile/menuDrawerSection";
|
||||||
import ProfilSection from "@/screens/Profile/ProfilSection";
|
import ProfileSection from "@/screens/Profile/ProfileSection";
|
||||||
import { GStyles } from "@/styles/global-styles";
|
import { GStyles } from "@/styles/global-styles";
|
||||||
import { Ionicons } from "@expo/vector-icons";
|
import { Ionicons } from "@expo/vector-icons";
|
||||||
import { router, Stack, useLocalSearchParams } from "expo-router";
|
import { router, Stack, useLocalSearchParams } from "expo-router";
|
||||||
@@ -52,7 +52,7 @@ export default function Profile() {
|
|||||||
headerTitleStyle: GStyles.headerTitleStyle,
|
headerTitleStyle: GStyles.headerTitleStyle,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<ProfilSection />
|
<ProfileSection />
|
||||||
</ViewWrapper>
|
</ViewWrapper>
|
||||||
|
|
||||||
{/* Drawer Komponen Eksternal */}
|
{/* Drawer Komponen Eksternal */}
|
||||||
|
|||||||
43
app/(application)/(user)/voting/(tabs)/_layout.tsx
Normal file
43
app/(application)/(user)/voting/(tabs)/_layout.tsx
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
import {
|
||||||
|
IconContribution,
|
||||||
|
IconHistory,
|
||||||
|
IconHome,
|
||||||
|
IconStatus,
|
||||||
|
} from "@/components/_Icon";
|
||||||
|
import { TabsStyles } from "@/styles/tabs-styles";
|
||||||
|
import { Tabs } from "expo-router";
|
||||||
|
|
||||||
|
export default function VotingTabsLayout() {
|
||||||
|
return (
|
||||||
|
<Tabs screenOptions={TabsStyles}>
|
||||||
|
<Tabs.Screen
|
||||||
|
name="index"
|
||||||
|
options={{
|
||||||
|
title: "Beranda",
|
||||||
|
tabBarIcon: ({ color }) => <IconHome color={color} />,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Tabs.Screen
|
||||||
|
name="status"
|
||||||
|
options={{
|
||||||
|
title: "Status",
|
||||||
|
tabBarIcon: ({ color }) => <IconStatus color={color} />,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Tabs.Screen
|
||||||
|
name="contribution"
|
||||||
|
options={{
|
||||||
|
title: "Kontribusi",
|
||||||
|
tabBarIcon: ({ color }) => <IconContribution color={color} />,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Tabs.Screen
|
||||||
|
name="history"
|
||||||
|
options={{
|
||||||
|
title: "Riwayat",
|
||||||
|
tabBarIcon: ({ color }) => <IconHistory color={color} />,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Tabs>
|
||||||
|
);
|
||||||
|
}
|
||||||
17
app/(application)/(user)/voting/(tabs)/contribution.tsx
Normal file
17
app/(application)/(user)/voting/(tabs)/contribution.tsx
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import {
|
||||||
|
ViewWrapper
|
||||||
|
} from "@/components";
|
||||||
|
import Voting_BoxPublishSection from "@/screens/Voting/BoxPublishSection";
|
||||||
|
|
||||||
|
export default function VotingContribution() {
|
||||||
|
return (
|
||||||
|
<ViewWrapper hideFooter>
|
||||||
|
{Array.from({ length: 5 }).map((_, index) => (
|
||||||
|
<Voting_BoxPublishSection
|
||||||
|
key={index}
|
||||||
|
href={`/voting/${index}/contribution`}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</ViewWrapper>
|
||||||
|
);
|
||||||
|
}
|
||||||
33
app/(application)/(user)/voting/(tabs)/history.tsx
Normal file
33
app/(application)/(user)/voting/(tabs)/history.tsx
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import { ViewWrapper } from "@/components";
|
||||||
|
import TabsTwoHeaderCustom from "@/components/_ShareComponent/TabsTwoHeaderCustom";
|
||||||
|
import Voting_BoxPublishSection from "@/screens/Voting/BoxPublishSection";
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
export default function VotingHistory() {
|
||||||
|
const [activeCategory, setActiveCategory] = useState<string | null>("all");
|
||||||
|
|
||||||
|
const handlePress = (item: any) => {
|
||||||
|
setActiveCategory(item);
|
||||||
|
// tambahkan logika lain seperti filter dsb.
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ViewWrapper
|
||||||
|
hideFooter
|
||||||
|
headerComponent={
|
||||||
|
<TabsTwoHeaderCustom
|
||||||
|
leftValue="all"
|
||||||
|
rightValue="main"
|
||||||
|
leftText="Semua Riwayat"
|
||||||
|
rightText="Riwayat Saya"
|
||||||
|
activeCategory={activeCategory}
|
||||||
|
handlePress={handlePress}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{Array.from({ length: 10 }).map((_, index) => (
|
||||||
|
<Voting_BoxPublishSection key={index} id={activeCategory as any} />
|
||||||
|
))}
|
||||||
|
</ViewWrapper>
|
||||||
|
);
|
||||||
|
}
|
||||||
23
app/(application)/(user)/voting/(tabs)/index.tsx
Normal file
23
app/(application)/(user)/voting/(tabs)/index.tsx
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import {
|
||||||
|
FloatingButton,
|
||||||
|
SearchInput,
|
||||||
|
ViewWrapper
|
||||||
|
} from "@/components";
|
||||||
|
import Voting_BoxPublishSection from "@/screens/Voting/BoxPublishSection";
|
||||||
|
import { router } from "expo-router";
|
||||||
|
|
||||||
|
export default function VotingBeranda() {
|
||||||
|
return (
|
||||||
|
<ViewWrapper
|
||||||
|
hideFooter
|
||||||
|
floatingButton={
|
||||||
|
<FloatingButton onPress={() => router.push("/voting/create")} />
|
||||||
|
}
|
||||||
|
headerComponent={<SearchInput placeholder="Cari voting" />}
|
||||||
|
>
|
||||||
|
{Array.from({ length: 5 }).map((_, index) => (
|
||||||
|
<Voting_BoxPublishSection key={index} href={`/voting/${index}`} />
|
||||||
|
))}
|
||||||
|
</ViewWrapper>
|
||||||
|
);
|
||||||
|
}
|
||||||
60
app/(application)/(user)/voting/(tabs)/status.tsx
Normal file
60
app/(application)/(user)/voting/(tabs)/status.tsx
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
import {
|
||||||
|
BadgeCustom,
|
||||||
|
BaseBox,
|
||||||
|
ScrollableCustom,
|
||||||
|
StackCustom,
|
||||||
|
TextCustom,
|
||||||
|
ViewWrapper,
|
||||||
|
} from "@/components";
|
||||||
|
import { masterStatus } from "@/lib/dummy-data/_master/status";
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
export default function VotingStatus() {
|
||||||
|
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}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ViewWrapper headerComponent={scrollComponent} hideFooter>
|
||||||
|
{Array.from({ length: 10 }).map((_, i) => (
|
||||||
|
<BaseBox
|
||||||
|
key={i}
|
||||||
|
paddingTop={20}
|
||||||
|
paddingBottom={20}
|
||||||
|
href={`/voting/${i}/${activeCategory}/detail`}
|
||||||
|
>
|
||||||
|
<StackCustom>
|
||||||
|
<TextCustom align="center" bold truncate size="large">
|
||||||
|
Lorem ipsum dolor sit {activeCategory}
|
||||||
|
</TextCustom>
|
||||||
|
<BadgeCustom
|
||||||
|
style={{ width: "70%", alignSelf: "center" }}
|
||||||
|
variant="light"
|
||||||
|
>
|
||||||
|
{dayjs().format("DD/MM/YYYY")} -{" "}
|
||||||
|
{dayjs().add(1, "day").format("DD/MM/YYYY")}
|
||||||
|
</BadgeCustom>
|
||||||
|
</StackCustom>
|
||||||
|
</BaseBox>
|
||||||
|
))}
|
||||||
|
</ViewWrapper>
|
||||||
|
);
|
||||||
|
}
|
||||||
108
app/(application)/(user)/voting/[id]/[status]/detail.tsx
Normal file
108
app/(application)/(user)/voting/[id]/[status]/detail.tsx
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
import {
|
||||||
|
AlertDefaultSystem,
|
||||||
|
BackButton,
|
||||||
|
DotButton,
|
||||||
|
DrawerCustom,
|
||||||
|
MenuDrawerDynamicGrid,
|
||||||
|
Spacing,
|
||||||
|
ViewWrapper,
|
||||||
|
} from "@/components";
|
||||||
|
import { IconArchive, IconContribution, IconEdit } from "@/components/_Icon";
|
||||||
|
import { IMenuDrawerItem } from "@/components/_Interface/types";
|
||||||
|
import { Voting_BoxDetailSection } from "@/screens/Voting/BoxDetailSection";
|
||||||
|
import Voting_ButtonStatusSection from "@/screens/Voting/ButtonStatusSection";
|
||||||
|
import { router, Stack, useLocalSearchParams } from "expo-router";
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
export default function VotingDetailStatus() {
|
||||||
|
const { id, status } = useLocalSearchParams();
|
||||||
|
const [openDrawerDraft, setOpenDrawerDraft] = useState(false);
|
||||||
|
const [openDrawerPublish, setOpenDrawerPublish] = useState(false);
|
||||||
|
|
||||||
|
const handlePressDraft = (item: IMenuDrawerItem) => {
|
||||||
|
console.log("PATH >> ", item.path);
|
||||||
|
router.navigate(item.path as any);
|
||||||
|
setOpenDrawerDraft(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handlePressPublish = (item: IMenuDrawerItem) => {
|
||||||
|
if (item.path === "") {
|
||||||
|
AlertDefaultSystem({
|
||||||
|
title: "Update Arsip",
|
||||||
|
message: "Apakah Anda yakin ingin mengarsipkan voting ini?",
|
||||||
|
textLeft: "Batal",
|
||||||
|
textRight: "Ya",
|
||||||
|
onPressRight: () => {
|
||||||
|
console.log("Hapus");
|
||||||
|
router.back();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
router.navigate(item.path as any);
|
||||||
|
setOpenDrawerPublish(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Stack.Screen
|
||||||
|
options={{
|
||||||
|
title: `Detail ${status}`,
|
||||||
|
headerLeft: () => <BackButton />,
|
||||||
|
headerRight: () =>
|
||||||
|
status === "draft" ? (
|
||||||
|
<DotButton onPress={() => setOpenDrawerDraft(true)} />
|
||||||
|
) : status === "publish" ? (
|
||||||
|
<DotButton onPress={() => setOpenDrawerPublish(true)} />
|
||||||
|
) : null,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<ViewWrapper>
|
||||||
|
<Voting_BoxDetailSection />
|
||||||
|
<Voting_ButtonStatusSection status={status as string} />
|
||||||
|
<Spacing />
|
||||||
|
</ViewWrapper>
|
||||||
|
|
||||||
|
{/* ========= Draft Drawer ========= */}
|
||||||
|
<DrawerCustom
|
||||||
|
isVisible={openDrawerDraft}
|
||||||
|
closeDrawer={() => setOpenDrawerDraft(false)}
|
||||||
|
height={"auto"}
|
||||||
|
>
|
||||||
|
<MenuDrawerDynamicGrid
|
||||||
|
data={[
|
||||||
|
{
|
||||||
|
icon: <IconEdit />,
|
||||||
|
label: "Edit",
|
||||||
|
path: `/voting/${id}/edit`,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
columns={4}
|
||||||
|
onPressItem={handlePressDraft as any}
|
||||||
|
/>
|
||||||
|
</DrawerCustom>
|
||||||
|
|
||||||
|
{/* ========= Publish Drawer ========= */}
|
||||||
|
<DrawerCustom
|
||||||
|
isVisible={openDrawerPublish}
|
||||||
|
closeDrawer={() => setOpenDrawerPublish(false)}
|
||||||
|
height={"auto"}
|
||||||
|
>
|
||||||
|
<MenuDrawerDynamicGrid
|
||||||
|
data={[
|
||||||
|
{
|
||||||
|
icon: <IconContribution />,
|
||||||
|
label: "Daftar Kontributor",
|
||||||
|
path: `/voting/${id}/list-of-contributor`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: <IconArchive />,
|
||||||
|
label: "Update Arsip",
|
||||||
|
path: "" as any,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
onPressItem={handlePressPublish as any}
|
||||||
|
/>
|
||||||
|
</DrawerCustom>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
65
app/(application)/(user)/voting/[id]/contribution.tsx
Normal file
65
app/(application)/(user)/voting/[id]/contribution.tsx
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
import {
|
||||||
|
AvatarUsernameAndOtherComponent,
|
||||||
|
BackButton,
|
||||||
|
DotButton,
|
||||||
|
DrawerCustom,
|
||||||
|
MenuDrawerDynamicGrid,
|
||||||
|
Spacing,
|
||||||
|
ViewWrapper,
|
||||||
|
} from "@/components";
|
||||||
|
import { IconContribution } from "@/components/_Icon";
|
||||||
|
import { IMenuDrawerItem } from "@/components/_Interface/types";
|
||||||
|
import { Voting_BoxDetailContributionSection } from "@/screens/Voting/BoxDetailContribution";
|
||||||
|
import Voting_BoxDetailHasilVotingSection from "@/screens/Voting/BoxDetailHasilVotingSection";
|
||||||
|
import { router, Stack, useLocalSearchParams } from "expo-router";
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
export default function VotingDetailContribution() {
|
||||||
|
const { id } = useLocalSearchParams();
|
||||||
|
const [openDrawerPublish, setOpenDrawerPublish] = useState(false);
|
||||||
|
|
||||||
|
const handlePressPublish = (item: IMenuDrawerItem) => {
|
||||||
|
router.navigate(item.path as any);
|
||||||
|
setOpenDrawerPublish(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Stack.Screen
|
||||||
|
options={{
|
||||||
|
title: "Detail Kontribusi",
|
||||||
|
headerLeft: () => <BackButton />,
|
||||||
|
headerRight: () => (
|
||||||
|
<DotButton onPress={() => setOpenDrawerPublish(true)} />
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ViewWrapper>
|
||||||
|
<Voting_BoxDetailContributionSection
|
||||||
|
headerAvatar={<AvatarUsernameAndOtherComponent />}
|
||||||
|
/>
|
||||||
|
<Voting_BoxDetailHasilVotingSection />
|
||||||
|
<Spacing />
|
||||||
|
</ViewWrapper>
|
||||||
|
|
||||||
|
{/* ========= Publish Drawer ========= */}
|
||||||
|
<DrawerCustom
|
||||||
|
isVisible={openDrawerPublish}
|
||||||
|
closeDrawer={() => setOpenDrawerPublish(false)}
|
||||||
|
height={"auto"}
|
||||||
|
>
|
||||||
|
<MenuDrawerDynamicGrid
|
||||||
|
data={[
|
||||||
|
{
|
||||||
|
icon: <IconContribution />,
|
||||||
|
label: "Daftar Kontributor",
|
||||||
|
path: `/voting/${id}/list-of-contributor`,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
onPressItem={handlePressPublish as any}
|
||||||
|
/>
|
||||||
|
</DrawerCustom>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
78
app/(application)/(user)/voting/[id]/edit.tsx
Normal file
78
app/(application)/(user)/voting/[id]/edit.tsx
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
import {
|
||||||
|
BoxButtonOnFooter,
|
||||||
|
ButtonCenteredOnly,
|
||||||
|
ButtonCustom,
|
||||||
|
Grid,
|
||||||
|
Spacing,
|
||||||
|
StackCustom,
|
||||||
|
TextAreaCustom,
|
||||||
|
TextInputCustom,
|
||||||
|
ViewWrapper,
|
||||||
|
} from "@/components";
|
||||||
|
import DateTimePickerCustom from "@/components/DateInput/DateTimePickerCustom";
|
||||||
|
import { MainColor } from "@/constants/color-palet";
|
||||||
|
import { Ionicons } from "@expo/vector-icons";
|
||||||
|
import { router } from "expo-router";
|
||||||
|
import { TouchableOpacity } from "react-native";
|
||||||
|
|
||||||
|
export default function VotingEdit() {
|
||||||
|
const buttonSubmit = () => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<BoxButtonOnFooter>
|
||||||
|
<ButtonCustom
|
||||||
|
onPress={() =>
|
||||||
|
router.back()
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Update
|
||||||
|
</ButtonCustom>
|
||||||
|
</BoxButtonOnFooter>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ViewWrapper footerComponent={buttonSubmit()}>
|
||||||
|
<StackCustom gap={"xs"}>
|
||||||
|
<TextInputCustom
|
||||||
|
label="Judul Voting"
|
||||||
|
placeholder="MasukanJudul Voting"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
<TextAreaCustom
|
||||||
|
label="Deskripsi"
|
||||||
|
placeholder="Masukan Deskripsi"
|
||||||
|
required
|
||||||
|
showCount
|
||||||
|
maxLength={1000}
|
||||||
|
/>
|
||||||
|
<DateTimePickerCustom label="Mulai Voting" required />
|
||||||
|
<DateTimePickerCustom label="Voting Berakhir" required />
|
||||||
|
|
||||||
|
<Grid>
|
||||||
|
<Grid.Col span={10}>
|
||||||
|
<TextInputCustom
|
||||||
|
label="Pilihan"
|
||||||
|
placeholder="Masukan Pilihan"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</Grid.Col>
|
||||||
|
<Grid.Col
|
||||||
|
span={2}
|
||||||
|
style={{ alignItems: "center", justifyContent: "center" }}
|
||||||
|
>
|
||||||
|
<TouchableOpacity onPress={() => console.log("delete")}>
|
||||||
|
<Ionicons name="trash" size={24} color={MainColor.red} />
|
||||||
|
</TouchableOpacity>
|
||||||
|
</Grid.Col>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<ButtonCenteredOnly onPress={() => console.log("add")}>
|
||||||
|
Tambah Pilihan
|
||||||
|
</ButtonCenteredOnly>
|
||||||
|
<Spacing />
|
||||||
|
</StackCustom>
|
||||||
|
</ViewWrapper>
|
||||||
|
);
|
||||||
|
}
|
||||||
87
app/(application)/(user)/voting/[id]/index.tsx
Normal file
87
app/(application)/(user)/voting/[id]/index.tsx
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
import {
|
||||||
|
AlertDefaultSystem,
|
||||||
|
AvatarUsernameAndOtherComponent,
|
||||||
|
BackButton,
|
||||||
|
DotButton,
|
||||||
|
DrawerCustom,
|
||||||
|
InformationBox,
|
||||||
|
MenuDrawerDynamicGrid,
|
||||||
|
StackCustom,
|
||||||
|
ViewWrapper,
|
||||||
|
} from "@/components";
|
||||||
|
import { IconArchive, IconContribution } from "@/components/_Icon";
|
||||||
|
import { IMenuDrawerItem } from "@/components/_Interface/types";
|
||||||
|
import Voting_BoxDetailHasilVotingSection from "@/screens/Voting/BoxDetailHasilVotingSection";
|
||||||
|
import { Voting_BoxDetailPublishSection } from "@/screens/Voting/BoxDetailPublishSection";
|
||||||
|
import { router, Stack, useLocalSearchParams } from "expo-router";
|
||||||
|
import React, { useState } from "react";
|
||||||
|
|
||||||
|
export default function VotingDetail() {
|
||||||
|
const { id } = useLocalSearchParams();
|
||||||
|
const [openDrawerPublish, setOpenDrawerPublish] = useState(false);
|
||||||
|
const handlePressPublish = (item: IMenuDrawerItem) => {
|
||||||
|
if (item.path === "") {
|
||||||
|
AlertDefaultSystem({
|
||||||
|
title: "Update Arsip",
|
||||||
|
message: "Apakah Anda yakin ingin mengarsipkan voting ini?",
|
||||||
|
textLeft: "Batal",
|
||||||
|
textRight: "Ya",
|
||||||
|
onPressRight: () => {
|
||||||
|
console.log("Hapus");
|
||||||
|
router.back();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
router.navigate(item.path as any);
|
||||||
|
setOpenDrawerPublish(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Stack.Screen
|
||||||
|
options={{
|
||||||
|
title: `Detail Voting`,
|
||||||
|
headerLeft: () => <BackButton />,
|
||||||
|
headerRight: () => (
|
||||||
|
<DotButton onPress={() => setOpenDrawerPublish(true)} />
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ViewWrapper>
|
||||||
|
<StackCustom>
|
||||||
|
<InformationBox text="Untuk sementara voting ini belum di buka. Voting akan dimulai sesuai dengan tanggal awal pemilihan, dan akan ditutup sesuai dengan tanggal akhir pemilihan." />
|
||||||
|
|
||||||
|
<Voting_BoxDetailPublishSection
|
||||||
|
headerAvatar={<AvatarUsernameAndOtherComponent />}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Voting_BoxDetailHasilVotingSection />
|
||||||
|
</StackCustom>
|
||||||
|
</ViewWrapper>
|
||||||
|
|
||||||
|
{/* ========= Publish Drawer ========= */}
|
||||||
|
<DrawerCustom
|
||||||
|
isVisible={openDrawerPublish}
|
||||||
|
closeDrawer={() => setOpenDrawerPublish(false)}
|
||||||
|
height={"auto"}
|
||||||
|
>
|
||||||
|
<MenuDrawerDynamicGrid
|
||||||
|
data={[
|
||||||
|
{
|
||||||
|
icon: <IconContribution />,
|
||||||
|
label: "Daftar Kontributor",
|
||||||
|
path: `/voting/${id}/list-of-contributor`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: <IconArchive />,
|
||||||
|
label: "Update Arsip",
|
||||||
|
path: "" as any,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
onPressItem={handlePressPublish as any}
|
||||||
|
/>
|
||||||
|
</DrawerCustom>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
26
app/(application)/(user)/voting/[id]/list-of-contributor.tsx
Normal file
26
app/(application)/(user)/voting/[id]/list-of-contributor.tsx
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import {
|
||||||
|
AvatarUsernameAndOtherComponent,
|
||||||
|
BadgeCustom,
|
||||||
|
BaseBox,
|
||||||
|
ViewWrapper,
|
||||||
|
} from "@/components";
|
||||||
|
|
||||||
|
export default function Voting_ListOfContributor() {
|
||||||
|
return (
|
||||||
|
<ViewWrapper>
|
||||||
|
{Array.from({ length: 10 }).map((_, index) => (
|
||||||
|
<BaseBox paddingTop={5} paddingBottom={5} key={index.toString()}>
|
||||||
|
<AvatarUsernameAndOtherComponent
|
||||||
|
rightComponent={
|
||||||
|
<BadgeCustom
|
||||||
|
style={{alignSelf: "flex-end" }}
|
||||||
|
>
|
||||||
|
Pilihan {index + 1}
|
||||||
|
</BadgeCustom>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</BaseBox>
|
||||||
|
))}
|
||||||
|
</ViewWrapper>
|
||||||
|
);
|
||||||
|
}
|
||||||
78
app/(application)/(user)/voting/create.tsx
Normal file
78
app/(application)/(user)/voting/create.tsx
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
import {
|
||||||
|
BoxButtonOnFooter,
|
||||||
|
ButtonCenteredOnly,
|
||||||
|
ButtonCustom,
|
||||||
|
Grid,
|
||||||
|
Spacing,
|
||||||
|
StackCustom,
|
||||||
|
TextAreaCustom,
|
||||||
|
TextInputCustom,
|
||||||
|
ViewWrapper,
|
||||||
|
} from "@/components";
|
||||||
|
import DateTimePickerCustom from "@/components/DateInput/DateTimePickerCustom";
|
||||||
|
import { MainColor } from "@/constants/color-palet";
|
||||||
|
import { Ionicons } from "@expo/vector-icons";
|
||||||
|
import { router } from "expo-router";
|
||||||
|
import { TouchableOpacity } from "react-native";
|
||||||
|
|
||||||
|
export default function VotingCreate() {
|
||||||
|
const buttonSubmit = () => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<BoxButtonOnFooter>
|
||||||
|
<ButtonCustom
|
||||||
|
onPress={() =>
|
||||||
|
router.replace("/(application)/(user)/voting/(tabs)/status")
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Simpan
|
||||||
|
</ButtonCustom>
|
||||||
|
</BoxButtonOnFooter>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ViewWrapper footerComponent={buttonSubmit()}>
|
||||||
|
<StackCustom gap={"xs"}>
|
||||||
|
<TextInputCustom
|
||||||
|
label="Judul Voting"
|
||||||
|
placeholder="MasukanJudul Voting"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
<TextAreaCustom
|
||||||
|
label="Deskripsi"
|
||||||
|
placeholder="Masukan Deskripsi"
|
||||||
|
required
|
||||||
|
showCount
|
||||||
|
maxLength={1000}
|
||||||
|
/>
|
||||||
|
<DateTimePickerCustom label="Mulai Voting" required />
|
||||||
|
<DateTimePickerCustom label="Voting Berakhir" required />
|
||||||
|
|
||||||
|
<Grid>
|
||||||
|
<Grid.Col span={10}>
|
||||||
|
<TextInputCustom
|
||||||
|
label="Pilihan"
|
||||||
|
placeholder="Masukan Pilihan"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</Grid.Col>
|
||||||
|
<Grid.Col
|
||||||
|
span={2}
|
||||||
|
style={{ alignItems: "center", justifyContent: "center" }}
|
||||||
|
>
|
||||||
|
<TouchableOpacity onPress={() => console.log("delete")}>
|
||||||
|
<Ionicons name="trash" size={24} color={MainColor.red} />
|
||||||
|
</TouchableOpacity>
|
||||||
|
</Grid.Col>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<ButtonCenteredOnly onPress={() => console.log("add")}>
|
||||||
|
Tambah Pilihan
|
||||||
|
</ButtonCenteredOnly>
|
||||||
|
<Spacing />
|
||||||
|
</StackCustom>
|
||||||
|
</ViewWrapper>
|
||||||
|
);
|
||||||
|
}
|
||||||
258
app/(application)/coba/double-scroll.tsx
Normal file
258
app/(application)/coba/double-scroll.tsx
Normal file
@@ -0,0 +1,258 @@
|
|||||||
|
// File: src/screens/EventDetailScreen.tsx
|
||||||
|
|
||||||
|
import LeftButtonCustom from "@/components/Button/BackButton";
|
||||||
|
import { MainColor } from "@/constants/color-palet";
|
||||||
|
import React, { useState, useEffect } from "react";
|
||||||
|
import {
|
||||||
|
FlatList,
|
||||||
|
View,
|
||||||
|
Text,
|
||||||
|
Image,
|
||||||
|
StyleSheet,
|
||||||
|
ActivityIndicator,
|
||||||
|
} from "react-native";
|
||||||
|
import { SafeAreaView } from "react-native-safe-area-context";
|
||||||
|
|
||||||
|
// === TYPES ===
|
||||||
|
type Participant = {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
avatar: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type EventDetail = {
|
||||||
|
id: number;
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
date: string;
|
||||||
|
location: string;
|
||||||
|
organizer: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
// === KOMPONEN UTAMA ===
|
||||||
|
const EventDetailScreen: React.FC = () => {
|
||||||
|
const [participants, setParticipants] = useState<Participant[]>([]);
|
||||||
|
const [loading, setLoading] = useState<boolean>(true);
|
||||||
|
const [loadingMore, setLoadingMore] = useState<boolean>(false);
|
||||||
|
|
||||||
|
// Data event
|
||||||
|
const event: EventDetail = {
|
||||||
|
id: 1,
|
||||||
|
title: "Workshop React Native & Expo",
|
||||||
|
description:
|
||||||
|
"Pelatihan intensif pengembangan aplikasi mobile menggunakan React Native, Expo, dan TypeScript. Cocok untuk developer tingkat menengah.",
|
||||||
|
date: "Sabtu, 5 April 2025 | 09:00 - 16:00",
|
||||||
|
location: "Gedung Teknologi, Jakarta Selatan",
|
||||||
|
organizer: "DevCommunity Indonesia",
|
||||||
|
};
|
||||||
|
|
||||||
|
// Simulasi API: generate data dummy
|
||||||
|
const generateParticipants = (
|
||||||
|
startId: number,
|
||||||
|
count: number
|
||||||
|
): Participant[] => {
|
||||||
|
return Array.from({ length: count }, (_, i) => {
|
||||||
|
const id = startId + i;
|
||||||
|
return {
|
||||||
|
id,
|
||||||
|
name: `Peserta ${id}`,
|
||||||
|
avatar: `https://i.pravatar.cc/150?img=${(id % 70) + 1}`, // 70 gambar unik
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Load data awal
|
||||||
|
useEffect(() => {
|
||||||
|
const loadInitial = () => {
|
||||||
|
setTimeout(() => {
|
||||||
|
const initialData = generateParticipants(1, 20); // 20 peserta pertama
|
||||||
|
setParticipants(initialData);
|
||||||
|
setLoading(false);
|
||||||
|
}, 800);
|
||||||
|
};
|
||||||
|
|
||||||
|
loadInitial();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// Load lebih banyak peserta saat scroll ke bawah
|
||||||
|
const loadMore = () => {
|
||||||
|
if (loadingMore || participants.length >= 200) return; // Batas 200 peserta
|
||||||
|
|
||||||
|
setLoadingMore(true);
|
||||||
|
setTimeout(() => {
|
||||||
|
const nextId = participants.length + 1;
|
||||||
|
const newData = generateParticipants(nextId, 10); // Tambah 10 peserta
|
||||||
|
setParticipants((prev) => [...prev, ...newData]);
|
||||||
|
setLoadingMore(false);
|
||||||
|
}, 1000);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Render footer: loading indicator
|
||||||
|
const renderFooter = () => {
|
||||||
|
if (!loadingMore) return null;
|
||||||
|
return (
|
||||||
|
<View style={styles.footer}>
|
||||||
|
<ActivityIndicator size="small" color="#007AFF" />
|
||||||
|
<Text style={styles.loadingText}> Memuat peserta berikutnya...</Text>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Render header: detail event + info jumlah peserta
|
||||||
|
const renderHeader = () => (
|
||||||
|
<>
|
||||||
|
<View style={styles.headerContainer}>
|
||||||
|
<LeftButtonCustom path={"/"} />
|
||||||
|
<Text style={styles.title}>{event.title}</Text>
|
||||||
|
<Text style={styles.info}>📅 {event.date}</Text>
|
||||||
|
<Text style={styles.info}>📍 {event.location}</Text>
|
||||||
|
<Text style={styles.info}>👤 {event.organizer}</Text>
|
||||||
|
<Text style={styles.description}>{event.description}</Text>
|
||||||
|
|
||||||
|
<View style={styles.divider} />
|
||||||
|
|
||||||
|
<Text style={styles.sectionTitle}>
|
||||||
|
Daftar Peserta ({participants.length})
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* Sub-header tambahan jika perlu */}
|
||||||
|
{participants.length === 0 ? (
|
||||||
|
<Text style={styles.empty}>Belum ada peserta yang terdaftar.</Text>
|
||||||
|
) : null}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
|
||||||
|
// Loading awal
|
||||||
|
if (loading) {
|
||||||
|
return (
|
||||||
|
<SafeAreaView style={styles.container}>
|
||||||
|
<ActivityIndicator size="large" color="#007AFF" style={styles.loader} />
|
||||||
|
</SafeAreaView>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<FlatList
|
||||||
|
data={participants}
|
||||||
|
keyExtractor={(item) => item.id.toString()}
|
||||||
|
ListHeaderComponent={renderHeader}
|
||||||
|
ListFooterComponent={renderFooter}
|
||||||
|
onEndReached={loadMore}
|
||||||
|
onEndReachedThreshold={0.5}
|
||||||
|
renderItem={({ item }) => (
|
||||||
|
<View style={styles.participantItem}>
|
||||||
|
<Image source={{ uri: item.avatar }} style={styles.avatar} />
|
||||||
|
<Text style={styles.participantName}>{item.name}</Text>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
initialNumToRender={10}
|
||||||
|
maxToRenderPerBatch={5}
|
||||||
|
windowSize={7}
|
||||||
|
showsVerticalScrollIndicator={false}
|
||||||
|
ListEmptyComponent={
|
||||||
|
<Text style={styles.empty}>Tidak ada peserta.</Text>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<SafeAreaView
|
||||||
|
edges={["bottom"]}
|
||||||
|
style={{ backgroundColor: MainColor.darkblue }}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default EventDetailScreen;
|
||||||
|
|
||||||
|
// === STYLES ===
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
flex: 1,
|
||||||
|
backgroundColor: "#f8f9fa",
|
||||||
|
},
|
||||||
|
loader: {
|
||||||
|
marginTop: 20,
|
||||||
|
},
|
||||||
|
headerContainer: {
|
||||||
|
padding: 16,
|
||||||
|
backgroundColor: "#ffffff",
|
||||||
|
borderBottomWidth: 1,
|
||||||
|
borderBottomColor: "#e0e0e0",
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
fontSize: 24,
|
||||||
|
fontWeight: "bold",
|
||||||
|
color: "#1d1d1d",
|
||||||
|
marginBottom: 8,
|
||||||
|
},
|
||||||
|
info: {
|
||||||
|
fontSize: 16,
|
||||||
|
color: "#444",
|
||||||
|
marginBottom: 4,
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
fontSize: 14,
|
||||||
|
color: "#666",
|
||||||
|
lineHeight: 20,
|
||||||
|
marginTop: 12,
|
||||||
|
},
|
||||||
|
divider: {
|
||||||
|
height: 1,
|
||||||
|
backgroundColor: "#e0e0e0",
|
||||||
|
marginVertical: 16,
|
||||||
|
},
|
||||||
|
sectionTitle: {
|
||||||
|
fontSize: 18,
|
||||||
|
fontWeight: "600",
|
||||||
|
color: "#1d1d1d",
|
||||||
|
marginBottom: 12,
|
||||||
|
},
|
||||||
|
participantItem: {
|
||||||
|
flexDirection: "row",
|
||||||
|
alignItems: "center",
|
||||||
|
paddingHorizontal: 16,
|
||||||
|
paddingVertical: 12,
|
||||||
|
backgroundColor: "#fff",
|
||||||
|
borderBottomWidth: 1,
|
||||||
|
borderBottomColor: "#f0f0f0",
|
||||||
|
},
|
||||||
|
avatar: {
|
||||||
|
width: 40,
|
||||||
|
height: 40,
|
||||||
|
borderRadius: 20,
|
||||||
|
marginRight: 12,
|
||||||
|
},
|
||||||
|
participantName: {
|
||||||
|
fontSize: 16,
|
||||||
|
color: "#333",
|
||||||
|
},
|
||||||
|
footer: {
|
||||||
|
flexDirection: "row",
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center",
|
||||||
|
padding: 16,
|
||||||
|
backgroundColor: "#f8f9fa",
|
||||||
|
},
|
||||||
|
loadingText: {
|
||||||
|
color: "#555",
|
||||||
|
fontSize: 14,
|
||||||
|
},
|
||||||
|
empty: {
|
||||||
|
textAlign: "center",
|
||||||
|
color: "#999",
|
||||||
|
fontStyle: "italic",
|
||||||
|
padding: 16,
|
||||||
|
backgroundColor: "#fff",
|
||||||
|
fontSize: 14,
|
||||||
|
},
|
||||||
|
subHeader: {
|
||||||
|
paddingHorizontal: 16,
|
||||||
|
paddingVertical: 8,
|
||||||
|
backgroundColor: "#f1f1f1",
|
||||||
|
fontSize: 14,
|
||||||
|
color: "#666",
|
||||||
|
fontStyle: "italic",
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -8,7 +8,9 @@ import {
|
|||||||
ScrollView,
|
ScrollView,
|
||||||
} from "react-native";
|
} from "react-native";
|
||||||
import { Ionicons } from "@expo/vector-icons";
|
import { Ionicons } from "@expo/vector-icons";
|
||||||
import { router } from "expo-router";
|
import { router, Stack } from "expo-router";
|
||||||
|
import EventDetailScreen from "./double-scroll";
|
||||||
|
import LeftButtonCustom from "@/components/Button/BackButton";
|
||||||
|
|
||||||
const { width } = Dimensions.get("window");
|
const { width } = Dimensions.get("window");
|
||||||
|
|
||||||
@@ -16,7 +18,9 @@ const { width } = Dimensions.get("window");
|
|||||||
const HomeScreen = () => (
|
const HomeScreen = () => (
|
||||||
<View style={styles.screen}>
|
<View style={styles.screen}>
|
||||||
<Text style={styles.screenTitle}>Selamat Datang!</Text>
|
<Text style={styles.screenTitle}>Selamat Datang!</Text>
|
||||||
<Text style={styles.screenText}>Ini adalah halaman utama aplikasi Anda</Text>
|
<Text style={styles.screenText}>
|
||||||
|
Ini adalah halaman utama aplikasi Anda
|
||||||
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
const SearchScreen = () => (
|
const SearchScreen = () => (
|
||||||
@@ -65,9 +69,7 @@ const CustomTab = ({ icon, label, isActive, onPress }: any) => (
|
|||||||
|
|
||||||
// Main Custom Tab Navigator
|
// Main Custom Tab Navigator
|
||||||
const CustomTabNavigator = () => {
|
const CustomTabNavigator = () => {
|
||||||
const [activeTab, setActiveTab] = React.useState(
|
const [activeTab, setActiveTab] = React.useState("home");
|
||||||
'home'
|
|
||||||
);
|
|
||||||
const [showHome, setShowHome] = React.useState(true);
|
const [showHome, setShowHome] = React.useState(true);
|
||||||
|
|
||||||
const tabs = [
|
const tabs = [
|
||||||
@@ -97,13 +99,12 @@ const CustomTabNavigator = () => {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
// Function untuk handle tab press
|
// Function untuk handle tab press
|
||||||
const handleTabPress = (tabId: string) => {
|
const handleTabPress = (tabId: string) => {
|
||||||
setActiveTab(tabId);
|
setActiveTab(tabId);
|
||||||
setShowHome(false); // Hide home when any tab is pressed
|
setShowHome(false); // Hide home when any tab is pressed
|
||||||
};
|
};
|
||||||
|
|
||||||
// Determine which component to show
|
// Determine which component to show
|
||||||
const getActiveComponent = () => {
|
const getActiveComponent = () => {
|
||||||
if (showHome || activeTab === "home") {
|
if (showHome || activeTab === "home") {
|
||||||
@@ -111,38 +112,46 @@ const CustomTabNavigator = () => {
|
|||||||
}
|
}
|
||||||
// const selectedTab = tabs.find((tab) => tab.id === activeTab);
|
// const selectedTab = tabs.find((tab) => tab.id === activeTab);
|
||||||
// return selectedTab ? selectedTab.component : HomeScreen;
|
// return selectedTab ? selectedTab.component : HomeScreen;
|
||||||
return HomeScreen
|
return HomeScreen;
|
||||||
};
|
};
|
||||||
|
|
||||||
const ActiveComponent = getActiveComponent();
|
const ActiveComponent = getActiveComponent();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.container}>
|
<>
|
||||||
{/* Content Area */}
|
<Stack.Screen
|
||||||
<ScrollView>
|
options={{
|
||||||
<View style={styles.content}>
|
title: "Custom Tab Navigator",
|
||||||
<ActiveComponent />
|
}}
|
||||||
</View>
|
/>
|
||||||
</ScrollView>
|
<EventDetailScreen />
|
||||||
|
</>
|
||||||
|
// <View style={styles.container}>
|
||||||
|
// {/* Content Area */}
|
||||||
|
// <ScrollView>
|
||||||
|
// <View style={styles.content}>
|
||||||
|
// <ActiveComponent />
|
||||||
|
// </View>
|
||||||
|
// </ScrollView>
|
||||||
|
|
||||||
{/* Custom Tab Bar */}
|
// {/* Custom Tab Bar */}
|
||||||
<View style={styles.tabBar}>
|
// <View style={styles.tabBar}>
|
||||||
<View style={styles.tabContainer}>
|
// <View style={styles.tabContainer}>
|
||||||
{tabs.map((e) => (
|
// {tabs.map((e) => (
|
||||||
<CustomTab
|
// <CustomTab
|
||||||
key={e.id}
|
// key={e.id}
|
||||||
icon={activeTab === e.id ? e.activeIcon : e.icon}
|
// icon={activeTab === e.id ? e.activeIcon : e.icon}
|
||||||
label={e.label}
|
// label={e.label}
|
||||||
isActive={activeTab === e.id && !showHome}
|
// isActive={activeTab === e.id && !showHome}
|
||||||
onPress={() => {
|
// onPress={() => {
|
||||||
handleTabPress(e.id);
|
// handleTabPress(e.id);
|
||||||
router.push(e.path as any);
|
// router.push(e.path as any);
|
||||||
}}
|
// }}
|
||||||
/>
|
// />
|
||||||
))}
|
// ))}
|
||||||
</View>
|
// </View>
|
||||||
</View>
|
// </View>
|
||||||
</View>
|
// </View>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 40 KiB |
BIN
assets/images/dummy/dummy-user.png
Normal file
BIN
assets/images/dummy/dummy-user.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 395 KiB |
6
bun.lock
6
bun.lock
@@ -16,6 +16,7 @@
|
|||||||
"expo": "53.0.17",
|
"expo": "53.0.17",
|
||||||
"expo-blur": "~14.1.5",
|
"expo-blur": "~14.1.5",
|
||||||
"expo-camera": "~16.1.10",
|
"expo-camera": "~16.1.10",
|
||||||
|
"expo-clipboard": "~7.1.5",
|
||||||
"expo-constants": "~17.1.7",
|
"expo-constants": "~17.1.7",
|
||||||
"expo-font": "~13.3.2",
|
"expo-font": "~13.3.2",
|
||||||
"expo-haptics": "~14.1.4",
|
"expo-haptics": "~14.1.4",
|
||||||
@@ -35,6 +36,7 @@
|
|||||||
"react-native-international-phone-number": "^0.9.3",
|
"react-native-international-phone-number": "^0.9.3",
|
||||||
"react-native-maps": "1.20.1",
|
"react-native-maps": "1.20.1",
|
||||||
"react-native-otp-entry": "^1.8.5",
|
"react-native-otp-entry": "^1.8.5",
|
||||||
|
"react-native-pager-view": "6.7.1",
|
||||||
"react-native-paper": "^5.14.5",
|
"react-native-paper": "^5.14.5",
|
||||||
"react-native-reanimated": "~3.17.4",
|
"react-native-reanimated": "~3.17.4",
|
||||||
"react-native-safe-area-context": "5.4.0",
|
"react-native-safe-area-context": "5.4.0",
|
||||||
@@ -827,6 +829,8 @@
|
|||||||
|
|
||||||
"expo-camera": ["expo-camera@16.1.10", "", { "dependencies": { "invariant": "^2.2.4" }, "peerDependencies": { "expo": "*", "react": "*", "react-native": "*", "react-native-web": "*" }, "optionalPeers": ["react-native-web"] }, "sha512-qoRJeSwPmMbuu0VfnQTC+q79Kt2SqTWColEImgithL9u0qUQcC55U89IfhZk55Hpt6f1DgKuDzUOG5oY+snSWg=="],
|
"expo-camera": ["expo-camera@16.1.10", "", { "dependencies": { "invariant": "^2.2.4" }, "peerDependencies": { "expo": "*", "react": "*", "react-native": "*", "react-native-web": "*" }, "optionalPeers": ["react-native-web"] }, "sha512-qoRJeSwPmMbuu0VfnQTC+q79Kt2SqTWColEImgithL9u0qUQcC55U89IfhZk55Hpt6f1DgKuDzUOG5oY+snSWg=="],
|
||||||
|
|
||||||
|
"expo-clipboard": ["expo-clipboard@7.1.5", "", { "peerDependencies": { "expo": "*", "react": "*", "react-native": "*" } }, "sha512-TCANUGOxouoJXxKBW5ASJl2WlmQLGpuZGemDCL2fO5ZMl57DGTypUmagb0CVUFxDl0yAtFIcESd78UsF9o64aw=="],
|
||||||
|
|
||||||
"expo-constants": ["expo-constants@17.1.7", "", { "dependencies": { "@expo/config": "~11.0.12", "@expo/env": "~1.0.7" }, "peerDependencies": { "expo": "*", "react-native": "*" } }, "sha512-byBjGsJ6T6FrLlhOBxw4EaiMXrZEn/MlUYIj/JAd+FS7ll5X/S4qVRbIimSJtdW47hXMq0zxPfJX6njtA56hHA=="],
|
"expo-constants": ["expo-constants@17.1.7", "", { "dependencies": { "@expo/config": "~11.0.12", "@expo/env": "~1.0.7" }, "peerDependencies": { "expo": "*", "react-native": "*" } }, "sha512-byBjGsJ6T6FrLlhOBxw4EaiMXrZEn/MlUYIj/JAd+FS7ll5X/S4qVRbIimSJtdW47hXMq0zxPfJX6njtA56hHA=="],
|
||||||
|
|
||||||
"expo-file-system": ["expo-file-system@18.1.11", "", { "peerDependencies": { "expo": "*", "react-native": "*" } }, "sha512-HJw/m0nVOKeqeRjPjGdvm+zBi5/NxcdPf8M8P3G2JFvH5Z8vBWqVDic2O58jnT1OFEy0XXzoH9UqFu7cHg9DTQ=="],
|
"expo-file-system": ["expo-file-system@18.1.11", "", { "peerDependencies": { "expo": "*", "react-native": "*" } }, "sha512-HJw/m0nVOKeqeRjPjGdvm+zBi5/NxcdPf8M8P3G2JFvH5Z8vBWqVDic2O58jnT1OFEy0XXzoH9UqFu7cHg9DTQ=="],
|
||||||
@@ -1389,6 +1393,8 @@
|
|||||||
|
|
||||||
"react-native-otp-entry": ["react-native-otp-entry@1.8.5", "", { "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-TZNkIuUzZKAAWrC8X/A22ZHJdycLysxUNysrGf0yTmDLRUyf4zLXwVFcDYUcRNe763Hjaf5qvtKGILb6lDGzoA=="],
|
"react-native-otp-entry": ["react-native-otp-entry@1.8.5", "", { "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-TZNkIuUzZKAAWrC8X/A22ZHJdycLysxUNysrGf0yTmDLRUyf4zLXwVFcDYUcRNe763Hjaf5qvtKGILb6lDGzoA=="],
|
||||||
|
|
||||||
|
"react-native-pager-view": ["react-native-pager-view@6.7.1", "", { "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-cBSr6xw4g5N7Kd3VGWcf+kmaH7iBWb0DXAf2bVo3bXkzBcBbTOmYSvc0LVLHhUPW8nEq5WjT9LCIYAzgF++EXw=="],
|
||||||
|
|
||||||
"react-native-paper": ["react-native-paper@5.14.5", "", { "dependencies": { "@callstack/react-theme-provider": "^3.0.9", "color": "^3.1.2", "use-latest-callback": "^0.2.3" }, "peerDependencies": { "react": "*", "react-native": "*", "react-native-safe-area-context": "*" } }, "sha512-eaIH5bUQjJ/mYm4AkI6caaiyc7BcHDwX6CqNDi6RIxfxfWxROsHpll1oBuwn/cFvknvA8uEAkqLk/vzVihI3AQ=="],
|
"react-native-paper": ["react-native-paper@5.14.5", "", { "dependencies": { "@callstack/react-theme-provider": "^3.0.9", "color": "^3.1.2", "use-latest-callback": "^0.2.3" }, "peerDependencies": { "react": "*", "react-native": "*", "react-native-safe-area-context": "*" } }, "sha512-eaIH5bUQjJ/mYm4AkI6caaiyc7BcHDwX6CqNDi6RIxfxfWxROsHpll1oBuwn/cFvknvA8uEAkqLk/vzVihI3AQ=="],
|
||||||
|
|
||||||
"react-native-reanimated": ["react-native-reanimated@3.17.5", "", { "dependencies": { "@babel/plugin-transform-arrow-functions": "^7.0.0-0", "@babel/plugin-transform-class-properties": "^7.0.0-0", "@babel/plugin-transform-classes": "^7.0.0-0", "@babel/plugin-transform-nullish-coalescing-operator": "^7.0.0-0", "@babel/plugin-transform-optional-chaining": "^7.0.0-0", "@babel/plugin-transform-shorthand-properties": "^7.0.0-0", "@babel/plugin-transform-template-literals": "^7.0.0-0", "@babel/plugin-transform-unicode-regex": "^7.0.0-0", "@babel/preset-typescript": "^7.16.7", "convert-source-map": "^2.0.0", "invariant": "^2.2.4", "react-native-is-edge-to-edge": "1.1.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0", "react": "*", "react-native": "*" } }, "sha512-SxBK7wQfJ4UoWoJqQnmIC7ZjuNgVb9rcY5Xc67upXAFKftWg0rnkknTw6vgwnjRcvYThrjzUVti66XoZdDJGtw=="],
|
"react-native-reanimated": ["react-native-reanimated@3.17.5", "", { "dependencies": { "@babel/plugin-transform-arrow-functions": "^7.0.0-0", "@babel/plugin-transform-class-properties": "^7.0.0-0", "@babel/plugin-transform-classes": "^7.0.0-0", "@babel/plugin-transform-nullish-coalescing-operator": "^7.0.0-0", "@babel/plugin-transform-optional-chaining": "^7.0.0-0", "@babel/plugin-transform-shorthand-properties": "^7.0.0-0", "@babel/plugin-transform-template-literals": "^7.0.0-0", "@babel/plugin-transform-unicode-regex": "^7.0.0-0", "@babel/preset-typescript": "^7.16.7", "convert-source-map": "^2.0.0", "invariant": "^2.2.4", "react-native-is-edge-to-edge": "1.1.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0", "react": "*", "react-native": "*" } }, "sha512-SxBK7wQfJ4UoWoJqQnmIC7ZjuNgVb9rcY5Xc67upXAFKftWg0rnkknTw6vgwnjRcvYThrjzUVti66XoZdDJGtw=="],
|
||||||
|
|||||||
31
components/Alert/AlertDefaultSystem.ts
Normal file
31
components/Alert/AlertDefaultSystem.ts
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import { Alert } from "react-native";
|
||||||
|
|
||||||
|
export default function AlertDefaultSystem({
|
||||||
|
title,
|
||||||
|
message,
|
||||||
|
textLeft,
|
||||||
|
textRight,
|
||||||
|
onPressLeft,
|
||||||
|
onPressRight,
|
||||||
|
}: {
|
||||||
|
title: string;
|
||||||
|
message: string;
|
||||||
|
textLeft: string;
|
||||||
|
textRight: string;
|
||||||
|
onPressLeft?: () => void;
|
||||||
|
onPressRight?: () => void;
|
||||||
|
}) {
|
||||||
|
return Alert.alert(title, message, [
|
||||||
|
{
|
||||||
|
style: "cancel",
|
||||||
|
text: textLeft,
|
||||||
|
onPress: () => onPressLeft?.(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
style: "default",
|
||||||
|
text: textRight,
|
||||||
|
isPreferred: true,
|
||||||
|
onPress: () => onPressRight?.(),
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
}
|
||||||
189
components/Badge/BadgeCustom.tsx
Normal file
189
components/Badge/BadgeCustom.tsx
Normal file
@@ -0,0 +1,189 @@
|
|||||||
|
import React from "react";
|
||||||
|
import {
|
||||||
|
StyleSheet,
|
||||||
|
Text,
|
||||||
|
TextStyle,
|
||||||
|
View,
|
||||||
|
ViewProps,
|
||||||
|
ViewStyle,
|
||||||
|
} from "react-native";
|
||||||
|
|
||||||
|
type BadgeVariant = "filled" | "light" | "outline" | "dot";
|
||||||
|
type BadgeColor =
|
||||||
|
| "primary"
|
||||||
|
| "success"
|
||||||
|
| "warning"
|
||||||
|
| "danger"
|
||||||
|
| "gray"
|
||||||
|
| "dark";
|
||||||
|
type BadgeSize = "xs" | "sm" | "md" | "lg";
|
||||||
|
|
||||||
|
interface BadgeProps extends ViewProps {
|
||||||
|
children: React.ReactNode;
|
||||||
|
variant?: BadgeVariant;
|
||||||
|
color?: BadgeColor;
|
||||||
|
size?: BadgeSize;
|
||||||
|
leftIcon?: React.ReactNode;
|
||||||
|
rightIcon?: React.ReactNode;
|
||||||
|
radius?: number;
|
||||||
|
fullWidth?: boolean;
|
||||||
|
textColor?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const BadgeCustom: React.FC<BadgeProps> = ({
|
||||||
|
children,
|
||||||
|
variant = "filled",
|
||||||
|
color = "primary",
|
||||||
|
size = "md",
|
||||||
|
leftIcon,
|
||||||
|
rightIcon,
|
||||||
|
radius = 50,
|
||||||
|
fullWidth = false,
|
||||||
|
textColor = "#fff",
|
||||||
|
style,
|
||||||
|
...props
|
||||||
|
}) => {
|
||||||
|
const colors = {
|
||||||
|
primary: "#339AF0",
|
||||||
|
success: "#40C057",
|
||||||
|
warning: "#FAB005",
|
||||||
|
danger: "#FA5252",
|
||||||
|
gray: "#868E96",
|
||||||
|
dark: "#212529",
|
||||||
|
};
|
||||||
|
|
||||||
|
const themeColor = colors[color];
|
||||||
|
|
||||||
|
// Ganti bagian sizeStyles dan styles.container
|
||||||
|
const sizeStyles = {
|
||||||
|
xs: {
|
||||||
|
fontSize: 10,
|
||||||
|
paddingHorizontal: 6,
|
||||||
|
paddingVertical: 2,
|
||||||
|
height: 18, // Dinaikkan dari 16 → 18 agar teks tidak terpotong
|
||||||
|
lineHeight: 10, // 👈 Penting: match fontSize agar kontrol vertikal lebih baik
|
||||||
|
},
|
||||||
|
sm: {
|
||||||
|
fontSize: 11,
|
||||||
|
paddingHorizontal: 8,
|
||||||
|
paddingVertical: 3,
|
||||||
|
height: 20,
|
||||||
|
lineHeight: 11,
|
||||||
|
},
|
||||||
|
md: {
|
||||||
|
fontSize: 12,
|
||||||
|
paddingHorizontal: 10,
|
||||||
|
paddingVertical: 4,
|
||||||
|
height: 24,
|
||||||
|
lineHeight: 12,
|
||||||
|
},
|
||||||
|
lg: {
|
||||||
|
fontSize: 14,
|
||||||
|
paddingHorizontal: 12,
|
||||||
|
paddingVertical: 6,
|
||||||
|
height: 30,
|
||||||
|
lineHeight: 14,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const currentSize = sizeStyles[size];
|
||||||
|
|
||||||
|
let variantStyles: ViewStyle & { text: TextStyle } = {
|
||||||
|
backgroundColor: themeColor,
|
||||||
|
borderColor: themeColor,
|
||||||
|
borderWidth: 1,
|
||||||
|
borderRadius: radius,
|
||||||
|
flexDirection: "row",
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "center",
|
||||||
|
text: { color: textColor, fontWeight: "600" },
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (variant) {
|
||||||
|
case "light":
|
||||||
|
variantStyles.backgroundColor = `${themeColor}20`;
|
||||||
|
variantStyles.text.color = themeColor;
|
||||||
|
break;
|
||||||
|
case "outline":
|
||||||
|
variantStyles.backgroundColor = "transparent";
|
||||||
|
variantStyles.text.color = themeColor;
|
||||||
|
break;
|
||||||
|
case "dot":
|
||||||
|
variantStyles.backgroundColor = themeColor;
|
||||||
|
variantStyles.paddingHorizontal = 0;
|
||||||
|
variantStyles.paddingVertical = 0;
|
||||||
|
variantStyles.height = currentSize.fontSize * 2;
|
||||||
|
variantStyles.width = currentSize.fontSize * 2;
|
||||||
|
variantStyles.borderRadius = currentSize.fontSize;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (variant === "dot") {
|
||||||
|
return (
|
||||||
|
<View
|
||||||
|
style={[variantStyles, fullWidth && styles.fullWidth, style]}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View
|
||||||
|
style={[
|
||||||
|
styles.container,
|
||||||
|
variantStyles,
|
||||||
|
currentSize,
|
||||||
|
{ borderRadius: radius },
|
||||||
|
fullWidth && styles.fullWidth,
|
||||||
|
style,
|
||||||
|
]}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{leftIcon && <View style={styles.iconContainer}>{leftIcon}</View>}
|
||||||
|
<Text
|
||||||
|
style={[
|
||||||
|
styles.text,
|
||||||
|
variantStyles.text,
|
||||||
|
{ fontSize: currentSize.fontSize },
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</Text>
|
||||||
|
{rightIcon && <View style={styles.iconContainer}>{rightIcon}</View>}
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
alignSelf: "flex-start",
|
||||||
|
flexDirection: "row",
|
||||||
|
alignItems: "center", // Vertikal center anak-anak (termasuk teks)
|
||||||
|
justifyContent: "center", // Horizontal center
|
||||||
|
paddingHorizontal: 10,
|
||||||
|
paddingVertical: 4,
|
||||||
|
minWidth: 20,
|
||||||
|
borderRadius: 6,
|
||||||
|
// ❌ Jangan gunakan `height` fix di sini — kita override per size
|
||||||
|
},
|
||||||
|
text: {
|
||||||
|
fontWeight: "600",
|
||||||
|
textAlign: "center",
|
||||||
|
// ❌ Hapus marginHorizontal jika mengganggu alignment
|
||||||
|
// marginHorizontal: 2, // Opsional, bisa dihapus atau dikurangi
|
||||||
|
includeFontPadding: false, // 👈 Ini penting untuk Android!
|
||||||
|
padding: 0, // Bersihkan padding tambahan dari font
|
||||||
|
},
|
||||||
|
iconContainer: {
|
||||||
|
marginHorizontal: 2, // Lebih kecil dari sebelumnya agar tidak ganggu ukuran kecil
|
||||||
|
},
|
||||||
|
fullWidth: {
|
||||||
|
width: "100%",
|
||||||
|
alignSelf: "stretch",
|
||||||
|
justifyContent: "center",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default BadgeCustom;
|
||||||
@@ -1,57 +1,79 @@
|
|||||||
import { AccentColor } from "@/constants/color-palet";
|
import { AccentColor } from "@/constants/color-palet";
|
||||||
import { PADDING_EXTRA_SMALL, PADDING_MEDIUM, PADDING_SMALL } from "@/constants/constans-value";
|
import {
|
||||||
import { StyleProp, TouchableHighlight, View, ViewStyle } from "react-native";
|
PADDING_MEDIUM,
|
||||||
|
PADDING_SMALL
|
||||||
|
} from "@/constants/constans-value";
|
||||||
|
import { Href, router } from "expo-router";
|
||||||
|
import {
|
||||||
|
StyleProp,
|
||||||
|
TouchableOpacity,
|
||||||
|
View,
|
||||||
|
ViewStyle
|
||||||
|
} from "react-native";
|
||||||
|
|
||||||
interface BaseBoxProps {
|
interface BaseBoxProps {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
style?: StyleProp<ViewStyle>;
|
style?: StyleProp<ViewStyle>;
|
||||||
|
href?: Href;
|
||||||
onPress?: () => void;
|
onPress?: () => void;
|
||||||
marginBottom?: number;
|
marginBottom?: number;
|
||||||
padding?: number;
|
padding?: number;
|
||||||
|
paddingTop?: number;
|
||||||
|
paddingBottom?: number;
|
||||||
paddingInline?: number;
|
paddingInline?: number;
|
||||||
paddingBlock?: number;
|
paddingBlock?: number;
|
||||||
|
backgroundColor?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function BaseBox({
|
export default function BaseBox({
|
||||||
children,
|
children,
|
||||||
style,
|
style,
|
||||||
|
href,
|
||||||
onPress,
|
onPress,
|
||||||
marginBottom = PADDING_MEDIUM,
|
marginBottom = PADDING_MEDIUM,
|
||||||
paddingBlock = PADDING_EXTRA_SMALL,
|
paddingBlock = PADDING_MEDIUM,
|
||||||
paddingInline = PADDING_SMALL,
|
paddingInline = PADDING_SMALL,
|
||||||
|
paddingTop = PADDING_MEDIUM,
|
||||||
|
paddingBottom = PADDING_MEDIUM,
|
||||||
|
backgroundColor = AccentColor.darkblue,
|
||||||
}: BaseBoxProps) {
|
}: BaseBoxProps) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{onPress ? (
|
{onPress || href ? (
|
||||||
<TouchableHighlight
|
<TouchableOpacity
|
||||||
onPress={onPress}
|
activeOpacity={0.7}
|
||||||
|
onPress={href ? () => router.navigate(href) : onPress}
|
||||||
style={[
|
style={[
|
||||||
{
|
{
|
||||||
backgroundColor: AccentColor.darkblue,
|
backgroundColor,
|
||||||
borderColor: AccentColor.blue,
|
borderColor: AccentColor.blue,
|
||||||
borderWidth: 1,
|
borderWidth: 1,
|
||||||
borderRadius: 10,
|
borderRadius: 10,
|
||||||
marginBottom,
|
marginBottom,
|
||||||
paddingBlock,
|
paddingBlock,
|
||||||
paddingInline,
|
paddingInline,
|
||||||
|
paddingTop,
|
||||||
|
paddingBottom,
|
||||||
},
|
},
|
||||||
style,
|
style,
|
||||||
]}
|
]}
|
||||||
// activeOpacity={0.7}
|
|
||||||
>
|
>
|
||||||
<View>{children}</View>
|
<View>{children}</View>
|
||||||
</TouchableHighlight>
|
</TouchableOpacity>
|
||||||
) : (
|
) : (
|
||||||
<View
|
<View
|
||||||
style={[
|
style={[
|
||||||
{
|
{
|
||||||
backgroundColor: AccentColor.darkblue,
|
backgroundColor,
|
||||||
borderColor: AccentColor.blue,
|
borderColor: AccentColor.blue,
|
||||||
borderWidth: 1,
|
borderWidth: 1,
|
||||||
borderRadius: 10,
|
borderRadius: 10,
|
||||||
marginBottom,
|
marginBottom,
|
||||||
paddingBlock,
|
paddingBlock,
|
||||||
paddingInline,
|
paddingInline,
|
||||||
|
paddingTop,
|
||||||
|
paddingBottom,
|
||||||
},
|
},
|
||||||
style,
|
style,
|
||||||
]}
|
]}
|
||||||
|
|||||||
20
components/Box/BoxWithHeaderInformation.tsx
Normal file
20
components/Box/BoxWithHeaderInformation.tsx
Normal 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} style={{ paddingTop: 5 }}>
|
||||||
|
{children}
|
||||||
|
</BaseBox>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
components/Button/DotButton.tsx
Normal file
13
components/Button/DotButton.tsx
Normal 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}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
133
components/Checkbox/CheckboxCustom.tsx
Normal file
133
components/Checkbox/CheckboxCustom.tsx
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
import { AccentColor } from "@/constants/color-palet";
|
||||||
|
import { MaterialIcons } from "@expo/vector-icons"; // Bisa diganti dengan ikon lain
|
||||||
|
import React, { useContext } from "react";
|
||||||
|
import { Animated, Text, TouchableOpacity, View } from "react-native";
|
||||||
|
import { checkboxStyles } from "./checkbox-styles";
|
||||||
|
|
||||||
|
// Context untuk Group
|
||||||
|
interface CheckboxGroupContextType {
|
||||||
|
value: (string | number)[];
|
||||||
|
onChange: (value: (string | number)[]) => void;
|
||||||
|
disabled?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CheckboxGroupContext =
|
||||||
|
React.createContext<CheckboxGroupContextType | null>(null);
|
||||||
|
|
||||||
|
// Tipe props
|
||||||
|
// Tambahkan prop baru: groupValueKey
|
||||||
|
interface CheckboxProps {
|
||||||
|
label?: string;
|
||||||
|
description?: string;
|
||||||
|
error?: string;
|
||||||
|
value?: boolean; // controlled value (untuk standalone)
|
||||||
|
onChange?: (checked: boolean) => void;
|
||||||
|
disabled?: boolean;
|
||||||
|
size?: number;
|
||||||
|
color?: string;
|
||||||
|
style?: object;
|
||||||
|
component?: React.ReactNode;
|
||||||
|
// Prop tambahan untuk Group
|
||||||
|
valueKey?: string | number; // nilai unik untuk identifikasi di group
|
||||||
|
}
|
||||||
|
|
||||||
|
const CheckboxCustom: React.FC<CheckboxProps> = ({
|
||||||
|
label,
|
||||||
|
description,
|
||||||
|
error,
|
||||||
|
value: controlledValue,
|
||||||
|
onChange,
|
||||||
|
disabled: propDisabled,
|
||||||
|
size = 20,
|
||||||
|
color = AccentColor.softblue,
|
||||||
|
style,
|
||||||
|
component,
|
||||||
|
valueKey,
|
||||||
|
}) => {
|
||||||
|
// const [uncontrolledChecked, setUncontrolledChecked] = useState(false);
|
||||||
|
// const isChecked = controlledValue ?? uncontrolledChecked;
|
||||||
|
// const scaleValue = new Animated.Value(isChecked ? 1 : 0);
|
||||||
|
|
||||||
|
const group = useContext(CheckboxGroupContext);
|
||||||
|
const isInsideGroup = !!group && valueKey !== undefined;
|
||||||
|
|
||||||
|
// Jika di dalam group, gunakan logika group
|
||||||
|
const isChecked = isInsideGroup
|
||||||
|
? group.value.includes(valueKey!)
|
||||||
|
: controlledValue ?? false;
|
||||||
|
|
||||||
|
const disabled = propDisabled || (isInsideGroup && group.disabled);
|
||||||
|
|
||||||
|
const scaleValue = new Animated.Value(isChecked ? 1 : 0);
|
||||||
|
|
||||||
|
const toggle = () => {
|
||||||
|
if (disabled) return;
|
||||||
|
|
||||||
|
if (isInsideGroup) {
|
||||||
|
const newValue = isChecked
|
||||||
|
? group.value.filter((v) => v !== valueKey)
|
||||||
|
: [...group.value, valueKey!];
|
||||||
|
group.onChange(newValue);
|
||||||
|
} else if (onChange) {
|
||||||
|
onChange(!controlledValue);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const styles = checkboxStyles({
|
||||||
|
size,
|
||||||
|
color,
|
||||||
|
disabled: disabled as boolean,
|
||||||
|
error: !!error,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TouchableOpacity
|
||||||
|
activeOpacity={disabled ? 1 : 0.7}
|
||||||
|
onPress={toggle}
|
||||||
|
style={[styles.container, style]}
|
||||||
|
disabled={disabled}
|
||||||
|
>
|
||||||
|
<View style={styles.innerContainer}>
|
||||||
|
<View style={[styles.box, isChecked && !disabled && styles.checked]}>
|
||||||
|
{isChecked && (
|
||||||
|
<Animated.View
|
||||||
|
style={{
|
||||||
|
transform: [
|
||||||
|
{
|
||||||
|
scale: scaleValue.interpolate({
|
||||||
|
inputRange: [0, 1],
|
||||||
|
outputRange: [0, 1],
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<MaterialIcons name="check" size={size * 0.6} color="#fff" />
|
||||||
|
</Animated.View>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
{component}
|
||||||
|
{(label || description) && (
|
||||||
|
<View style={styles.labelWrapper}>
|
||||||
|
{label ? (
|
||||||
|
<Text style={styles.label} numberOfLines={1}>
|
||||||
|
{label}
|
||||||
|
</Text>
|
||||||
|
) : null}
|
||||||
|
{description ? (
|
||||||
|
<Text style={styles.description} numberOfLines={2}>
|
||||||
|
{description}
|
||||||
|
</Text>
|
||||||
|
) : null}
|
||||||
|
{error ? <Text style={styles.errorText}>{error}</Text> : null}
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
</TouchableOpacity>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CheckboxCustom;
|
||||||
|
|
||||||
|
// Export context agar bisa digunakan
|
||||||
|
export { CheckboxGroupContext };
|
||||||
75
components/Checkbox/CheckboxGroup.tsx
Normal file
75
components/Checkbox/CheckboxGroup.tsx
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
import React, { useState, useMemo } from "react";
|
||||||
|
import { View, Text, StyleSheet } from "react-native";
|
||||||
|
import { CheckboxGroupContext } from "./CheckboxCustom";
|
||||||
|
|
||||||
|
interface CheckboxGroupProps {
|
||||||
|
value?: (string | number)[];
|
||||||
|
onChange?: (values: (string | number)[]) => void;
|
||||||
|
defaultValue?: (string | number)[];
|
||||||
|
label?: string;
|
||||||
|
description?: string;
|
||||||
|
error?: string;
|
||||||
|
disabled?: boolean;
|
||||||
|
children: React.ReactNode;
|
||||||
|
style?: object;
|
||||||
|
}
|
||||||
|
const CheckboxGroup: React.FC<CheckboxGroupProps> = ({
|
||||||
|
value: controlledValue,
|
||||||
|
onChange,
|
||||||
|
defaultValue = [],
|
||||||
|
label,
|
||||||
|
description,
|
||||||
|
error,
|
||||||
|
disabled = false,
|
||||||
|
children,
|
||||||
|
style,
|
||||||
|
}) => {
|
||||||
|
const [uncontrolledValue, setUncontrolledValue] =
|
||||||
|
useState<(string | number)[]>(defaultValue);
|
||||||
|
|
||||||
|
const value = controlledValue ?? uncontrolledValue;
|
||||||
|
const handleChange = onChange ?? setUncontrolledValue;
|
||||||
|
|
||||||
|
const contextValue = useMemo(
|
||||||
|
() => ({ value, onChange: handleChange, disabled }),
|
||||||
|
[value, handleChange, disabled]
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<CheckboxGroupContext.Provider value={contextValue}>
|
||||||
|
<View style={[styles.container, style]}>
|
||||||
|
{label ? <Text style={styles.label}>{label}</Text> : null}
|
||||||
|
{description ? (
|
||||||
|
<Text style={styles.description}>{description}</Text>
|
||||||
|
) : null}
|
||||||
|
{children}
|
||||||
|
{error ? <Text style={styles.errorText}>{error}</Text> : null}
|
||||||
|
</View>
|
||||||
|
</CheckboxGroupContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
gap: 8,
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: "600",
|
||||||
|
color: "#f8f9fa",
|
||||||
|
marginBottom: 4,
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
fontSize: 14,
|
||||||
|
color: "#ced4da",
|
||||||
|
marginBottom: 8,
|
||||||
|
},
|
||||||
|
errorText: {
|
||||||
|
color: "#e03131",
|
||||||
|
fontSize: 14,
|
||||||
|
marginTop: 4,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default CheckboxGroup;
|
||||||
|
|
||||||
61
components/Checkbox/checkbox-styles.tsx
Normal file
61
components/Checkbox/checkbox-styles.tsx
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
import { MainColor } from "@/constants/color-palet";
|
||||||
|
import { StyleSheet } from "react-native";
|
||||||
|
|
||||||
|
export const checkboxStyles = (props: {
|
||||||
|
size: number;
|
||||||
|
color: string;
|
||||||
|
disabled: boolean;
|
||||||
|
error: boolean;
|
||||||
|
}) =>
|
||||||
|
StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
flexDirection: "row",
|
||||||
|
alignItems: "flex-start",
|
||||||
|
// marginBottom: 12,
|
||||||
|
},
|
||||||
|
innerContainer: {
|
||||||
|
flexDirection: "row",
|
||||||
|
alignItems: "center",
|
||||||
|
},
|
||||||
|
box: {
|
||||||
|
width: props.size,
|
||||||
|
height: props.size,
|
||||||
|
borderRadius: 6,
|
||||||
|
borderWidth: 2,
|
||||||
|
borderColor: props.error
|
||||||
|
? "#fff"
|
||||||
|
: props.disabled
|
||||||
|
? "#ced4da"
|
||||||
|
: props.color,
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center",
|
||||||
|
marginRight: 10,
|
||||||
|
},
|
||||||
|
checked: {
|
||||||
|
backgroundColor: props.color,
|
||||||
|
borderColor: props.color,
|
||||||
|
},
|
||||||
|
checkIcon: {
|
||||||
|
color: MainColor.white,
|
||||||
|
fontWeight: "bold",
|
||||||
|
fontSize: props.size * 0.6,
|
||||||
|
},
|
||||||
|
labelWrapper: {
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
fontSize: props.size * 0.6,
|
||||||
|
color: props.disabled ? MainColor.disabled : MainColor.white,
|
||||||
|
fontWeight: "500",
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
fontSize: props.size * 0.5,
|
||||||
|
color: props.disabled ? MainColor.disabled : MainColor.white,
|
||||||
|
marginTop: 2,
|
||||||
|
},
|
||||||
|
errorText: {
|
||||||
|
color: MainColor.red,
|
||||||
|
fontSize: props.size * 0.5,
|
||||||
|
marginTop: 2,
|
||||||
|
},
|
||||||
|
});
|
||||||
44
components/Container/CircleContainer.tsx
Normal file
44
components/Container/CircleContainer.tsx
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import { MainColor } from "@/constants/color-palet";
|
||||||
|
import React from "react";
|
||||||
|
import { StyleSheet, TextInput, View } from "react-native";
|
||||||
|
|
||||||
|
interface CircularInputProps {
|
||||||
|
value: string | number;
|
||||||
|
onChange?: (value: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CircularInput: React.FC<CircularInputProps> = ({ value, onChange }) => {
|
||||||
|
return (
|
||||||
|
<View style={styles.circleContainer}>
|
||||||
|
<TextInput
|
||||||
|
value={String(value)}
|
||||||
|
onChangeText={onChange}
|
||||||
|
style={styles.input}
|
||||||
|
keyboardType="numeric"
|
||||||
|
maxLength={2} // Batasan maksimal karakter
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
circleContainer: {
|
||||||
|
width: 60,
|
||||||
|
height: 60,
|
||||||
|
borderRadius: 40, // Setiap setengah dari lebar/tinggi
|
||||||
|
borderWidth: 2,
|
||||||
|
borderColor: MainColor.yellow, // Warna kuning
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center",
|
||||||
|
},
|
||||||
|
input: {
|
||||||
|
color: MainColor.yellow, // Warna kuning
|
||||||
|
fontSize: 24,
|
||||||
|
fontWeight: "bold",
|
||||||
|
textAlign: "center",
|
||||||
|
padding: 0,
|
||||||
|
backgroundColor: "transparent",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default CircularInput;
|
||||||
25
components/Divider/Divider.tsx
Normal file
25
components/Divider/Divider.tsx
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import { AccentColor } from "@/constants/color-palet";
|
||||||
|
import { View } from "react-native";
|
||||||
|
|
||||||
|
export default function Divider({
|
||||||
|
color = AccentColor.blue,
|
||||||
|
size = 1,
|
||||||
|
marginTop= 12,
|
||||||
|
marginBottom= 12,
|
||||||
|
}: {
|
||||||
|
color?: string;
|
||||||
|
size?: number;
|
||||||
|
marginTop?: number;
|
||||||
|
marginBottom?: number;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<View
|
||||||
|
style={{
|
||||||
|
borderTopColor: color,
|
||||||
|
borderTopWidth: size,
|
||||||
|
marginTop,
|
||||||
|
marginBottom,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -9,20 +9,20 @@ import {
|
|||||||
|
|
||||||
import { AccentColor, MainColor } from "@/constants/color-palet";
|
import { AccentColor, MainColor } from "@/constants/color-palet";
|
||||||
import { DRAWER_HEIGHT } from "@/constants/constans-value";
|
import { DRAWER_HEIGHT } from "@/constants/constans-value";
|
||||||
|
import { SafeAreaView } from "react-native-safe-area-context";
|
||||||
|
|
||||||
interface DrawerCustomProps {
|
interface DrawerCustomProps {
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
height?: number;
|
height?: number | "auto";
|
||||||
isVisible: boolean;
|
isVisible: boolean;
|
||||||
drawerAnim?: Animated.Value;
|
drawerAnim?: Animated.Value;
|
||||||
closeDrawer: () => void;
|
closeDrawer: () => void;
|
||||||
// openLogoutAlert: () => void;
|
// openLogoutAlert: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param drawerAnim
|
* @param drawerAnim
|
||||||
* @example const drawerAnim = useRef(new Animated.Value(DRAWER_HEIGHT)).current; // mulai di luar bawah layar
|
* @example const drawerAnim = useRef(new Animated.Value(DRAWER_HEIGHT)).current; // mulai di luar bawah layar
|
||||||
*/
|
*/
|
||||||
export default function DrawerCustom({
|
export default function DrawerCustom({
|
||||||
@@ -34,7 +34,9 @@ export default function DrawerCustom({
|
|||||||
}: // openLogoutAlert,
|
}: // openLogoutAlert,
|
||||||
DrawerCustomProps) {
|
DrawerCustomProps) {
|
||||||
const drawerAnima = useRef(
|
const drawerAnima = useRef(
|
||||||
new Animated.Value(height || DRAWER_HEIGHT)
|
new Animated.Value(
|
||||||
|
height === "auto" ? DRAWER_HEIGHT : height || DRAWER_HEIGHT
|
||||||
|
)
|
||||||
).current;
|
).current;
|
||||||
// Efek untuk handle open/close drawer
|
// Efek untuk handle open/close drawer
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -46,7 +48,7 @@ DrawerCustomProps) {
|
|||||||
}).start();
|
}).start();
|
||||||
} else {
|
} else {
|
||||||
Animated.timing(drawerAnima, {
|
Animated.timing(drawerAnima, {
|
||||||
toValue: height || DRAWER_HEIGHT,
|
toValue: height === "auto" ? DRAWER_HEIGHT : height || DRAWER_HEIGHT,
|
||||||
duration: 300,
|
duration: 300,
|
||||||
useNativeDriver: true,
|
useNativeDriver: true,
|
||||||
}).start();
|
}).start();
|
||||||
@@ -99,7 +101,7 @@ DrawerCustomProps) {
|
|||||||
style={[
|
style={[
|
||||||
styles.drawer,
|
styles.drawer,
|
||||||
{
|
{
|
||||||
height: height || DRAWER_HEIGHT,
|
height: height === "auto" ? "auto" : height || DRAWER_HEIGHT,
|
||||||
transform: [{ translateY: drawerAnima }],
|
transform: [{ translateY: drawerAnima }],
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
@@ -110,34 +112,7 @@ DrawerCustomProps) {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
{children}
|
{children}
|
||||||
|
{height === "auto" && <SafeAreaView edges={["bottom"]} />}
|
||||||
{/* <TouchableOpacity
|
|
||||||
style={styles.menuItem}
|
|
||||||
onPress={() => {
|
|
||||||
alert("Pilihan 1 diklik");
|
|
||||||
closeDrawer();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Text>Menu Item 1</Text>
|
|
||||||
</TouchableOpacity>
|
|
||||||
|
|
||||||
<TouchableOpacity
|
|
||||||
style={styles.menuItem}
|
|
||||||
onPress={() => {
|
|
||||||
alert("Pilihan 2 diklik");
|
|
||||||
closeDrawer();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Text>Menu Item 2</Text>
|
|
||||||
</TouchableOpacity>
|
|
||||||
|
|
||||||
|
|
||||||
<TouchableOpacity
|
|
||||||
style={styles.menuItem}
|
|
||||||
onPress={() => alert("Logout via Alert bawaan")}
|
|
||||||
>
|
|
||||||
<Text style={{ color: "red" }}>Keluar</Text>
|
|
||||||
</TouchableOpacity> */}
|
|
||||||
</Animated.View>
|
</Animated.View>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -2,13 +2,26 @@ import { AccentColor, MainColor } from "@/constants/color-palet";
|
|||||||
import { TEXT_SIZE_SMALL } from "@/constants/constans-value";
|
import { TEXT_SIZE_SMALL } from "@/constants/constans-value";
|
||||||
import { StyleSheet, Text, TouchableOpacity, View } from "react-native";
|
import { StyleSheet, Text, TouchableOpacity, View } from "react-native";
|
||||||
import { IMenuDrawerItem } from "../_Interface/types";
|
import { IMenuDrawerItem } from "../_Interface/types";
|
||||||
|
import { Href } from "expo-router";
|
||||||
|
|
||||||
const MenuDrawerDynamicGrid = ({ data, columns = 3, onPressItem }: any) => {
|
type IMenuDrawerItemProps = {
|
||||||
|
icon: React.ReactNode;
|
||||||
|
label: string;
|
||||||
|
path?: Href;
|
||||||
|
color?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface MenuDrawerDynamicGridProps {
|
||||||
|
data: IMenuDrawerItemProps[];
|
||||||
|
columns?: number;
|
||||||
|
onPressItem?: (item: IMenuDrawerItemProps) => void;
|
||||||
|
}
|
||||||
|
const MenuDrawerDynamicGrid = ({ data, columns = 4, onPressItem }: MenuDrawerDynamicGridProps) => {
|
||||||
const numColumns = columns;
|
const numColumns = columns;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
{data.map((item: IMenuDrawerItem, index: any) => (
|
{data.map((item: IMenuDrawerItemProps, index: any) => (
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
key={index}
|
key={index}
|
||||||
style={[styles.itemContainer, { flexBasis: `${100 / numColumns}%` }]}
|
style={[styles.itemContainer, { flexBasis: `${100 / numColumns}%` }]}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import ButtonCustom from "../Button/ButtonCustom";
|
|||||||
interface ButtonData {
|
interface ButtonData {
|
||||||
id: string | number;
|
id: string | number;
|
||||||
label: string;
|
label: string;
|
||||||
|
value: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ScrollableCustomProps {
|
interface ScrollableCustomProps {
|
||||||
@@ -27,7 +28,7 @@ const ScrollableCustom = ({
|
|||||||
style={styles.scrollView}
|
style={styles.scrollView}
|
||||||
>
|
>
|
||||||
{data.map((item) => {
|
{data.map((item) => {
|
||||||
const isActive = activeId === item.id;
|
const isActive = activeId === item.value;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ButtonCustom
|
<ButtonCustom
|
||||||
@@ -48,6 +49,9 @@ export default ScrollableCustom;
|
|||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
scrollView: {
|
scrollView: {
|
||||||
|
backgroundColor: MainColor.soft_darkblue,
|
||||||
|
borderRadius: 50,
|
||||||
|
padding: 5,
|
||||||
// maxHeight: 50,
|
// maxHeight: 50,
|
||||||
},
|
},
|
||||||
buttonContainer: {
|
buttonContainer: {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import {
|
|||||||
TEXT_SIZE_LARGE,
|
TEXT_SIZE_LARGE,
|
||||||
TEXT_SIZE_MEDIUM,
|
TEXT_SIZE_MEDIUM,
|
||||||
TEXT_SIZE_SMALL,
|
TEXT_SIZE_SMALL,
|
||||||
|
TEXT_SIZE_XLARGE,
|
||||||
} from "@/constants/constans-value";
|
} from "@/constants/constans-value";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import {
|
import {
|
||||||
@@ -21,7 +22,7 @@ interface TextCustomProps {
|
|||||||
style?: StyleProp<TextStyle>;
|
style?: StyleProp<TextStyle>;
|
||||||
bold?: boolean;
|
bold?: boolean;
|
||||||
semiBold?: boolean;
|
semiBold?: boolean;
|
||||||
size?: "default" | "large" | "small";
|
size?: "default" | "large" | "small" | "xlarge";
|
||||||
color?: "default" | "yellow" | "red" | "gray" | "green" | "black"
|
color?: "default" | "yellow" | "red" | "gray" | "green" | "black"
|
||||||
align?: TextAlign; // Prop untuk alignment
|
align?: TextAlign; // Prop untuk alignment
|
||||||
truncate?: boolean | number;
|
truncate?: boolean | number;
|
||||||
@@ -51,6 +52,7 @@ const TextCustom: React.FC<TextCustomProps> = ({
|
|||||||
|
|
||||||
// Size
|
// Size
|
||||||
if (size === "large") selectedStyles.push(styles.large);
|
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 (size === "small") selectedStyles.push(styles.small);
|
||||||
|
|
||||||
// Color
|
// Color
|
||||||
@@ -113,11 +115,14 @@ export const styles = StyleSheet.create({
|
|||||||
fontFamily: "Poppins-SemiBold",
|
fontFamily: "Poppins-SemiBold",
|
||||||
fontWeight: "500",
|
fontWeight: "500",
|
||||||
},
|
},
|
||||||
|
small: {
|
||||||
|
fontSize: TEXT_SIZE_SMALL,
|
||||||
|
},
|
||||||
large: {
|
large: {
|
||||||
fontSize: TEXT_SIZE_LARGE,
|
fontSize: TEXT_SIZE_LARGE,
|
||||||
},
|
},
|
||||||
small: {
|
xlarge: {
|
||||||
fontSize: TEXT_SIZE_SMALL,
|
fontSize: TEXT_SIZE_XLARGE,
|
||||||
},
|
},
|
||||||
yellow: {
|
yellow: {
|
||||||
color: MainColor.yellow,
|
color: MainColor.yellow,
|
||||||
|
|||||||
13
components/_Icon/IconArchive.tsx
Normal file
13
components/_Icon/IconArchive.tsx
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import { MainColor } from "@/constants/color-palet";
|
||||||
|
import { ICON_SIZE_SMALL } from "@/constants/constans-value";
|
||||||
|
import { Ionicons } from "@expo/vector-icons";
|
||||||
|
|
||||||
|
export default function IconArchive({ color }: { color?: string }) {
|
||||||
|
return (
|
||||||
|
<Ionicons
|
||||||
|
name="archive"
|
||||||
|
size={ICON_SIZE_SMALL}
|
||||||
|
color={color || MainColor.white}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
14
components/_Icon/IconContribution.tsx
Normal file
14
components/_Icon/IconContribution.tsx
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import { ICON_SIZE_SMALL } from "@/constants/constans-value";
|
||||||
|
import { Ionicons } from "@expo/vector-icons";
|
||||||
|
|
||||||
|
export default function IconContribution({ color }: { color?: string }) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Ionicons
|
||||||
|
size={ICON_SIZE_SMALL}
|
||||||
|
name="people"
|
||||||
|
color={color || "white"}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
10
components/_Icon/IconEdit.tsx
Normal file
10
components/_Icon/IconEdit.tsx
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import { ICON_SIZE_SMALL } from "@/constants/constans-value";
|
||||||
|
import { FontAwesome5 } from "@expo/vector-icons";
|
||||||
|
|
||||||
|
export default function IconEdit() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<FontAwesome5 name="edit" size={ICON_SIZE_SMALL} color="white" />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
9
components/_Icon/IconHistory.tsx
Normal file
9
components/_Icon/IconHistory.tsx
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import { FontAwesome5 } from "@expo/vector-icons";
|
||||||
|
|
||||||
|
export default function IconHistory({ color }: { color?: string }) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<FontAwesome5 size={20} name="history" color={color} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
10
components/_Icon/IconHome.tsx
Normal file
10
components/_Icon/IconHome.tsx
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import { ICON_SIZE_SMALL } from "@/constants/constans-value";
|
||||||
|
import { Ionicons } from "@expo/vector-icons";
|
||||||
|
|
||||||
|
export default function IconHome({ color }: { color?: string }) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Ionicons name="home" size={ICON_SIZE_SMALL} color={color || "white"} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
12
components/_Icon/IconStatus.tsx
Normal file
12
components/_Icon/IconStatus.tsx
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { ICON_SIZE_SMALL } from "@/constants/constans-value";
|
||||||
|
import { MaterialIcons } from "@expo/vector-icons";
|
||||||
|
|
||||||
|
export default function IconStatus({ color }: { color?: string }) {
|
||||||
|
return (
|
||||||
|
<MaterialIcons
|
||||||
|
size={ICON_SIZE_SMALL}
|
||||||
|
name="checklist-rtl"
|
||||||
|
color={color || "white"}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
15
components/_Icon/index.ts
Normal file
15
components/_Icon/index.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import IconContribution from "./IconContribution";
|
||||||
|
import IconEdit from "./IconEdit";
|
||||||
|
import IconHistory from "./IconHistory";
|
||||||
|
import IconHome from "./IconHome";
|
||||||
|
import IconStatus from "./IconStatus";
|
||||||
|
import IconArchive from "./IconArchive";
|
||||||
|
|
||||||
|
export {
|
||||||
|
IconContribution,
|
||||||
|
IconEdit,
|
||||||
|
IconHistory,
|
||||||
|
IconHome,
|
||||||
|
IconStatus,
|
||||||
|
IconArchive,
|
||||||
|
};
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
import { ImageSourcePropType } from "react-native";
|
||||||
|
import Divider from "../Divider/Divider";
|
||||||
|
import Grid from "../Grid/GridCustom";
|
||||||
|
import AvatarCustom from "../Image/AvatarCustom";
|
||||||
|
import TextCustom from "../Text/TextCustom";
|
||||||
|
|
||||||
|
const AvatarUsernameAndOtherComponent = ({
|
||||||
|
avatarHref,
|
||||||
|
avatar,
|
||||||
|
name,
|
||||||
|
rightComponent,
|
||||||
|
withBottomLine = false,
|
||||||
|
}: {
|
||||||
|
avatarHref?: string;
|
||||||
|
avatar?: ImageSourcePropType;
|
||||||
|
name?: string;
|
||||||
|
rightComponent?: React.ReactNode;
|
||||||
|
withBottomLine?: boolean;
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<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>
|
||||||
|
{withBottomLine && <Divider marginTop={0} />}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AvatarUsernameAndOtherComponent;
|
||||||
32
components/_ShareComponent/DummyLandscapeImage.tsx
Normal file
32
components/_ShareComponent/DummyLandscapeImage.tsx
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import { AccentColor } from "@/constants/color-palet";
|
||||||
|
import DUMMY_IMAGE from "@/constants/dummy-image-value";
|
||||||
|
import { Image } from "expo-image";
|
||||||
|
import { StyleSheet } from "react-native";
|
||||||
|
import ClickableCustom from "../Clickable/ClickableCustom";
|
||||||
|
import { router } from "expo-router";
|
||||||
|
|
||||||
|
export default function DummyLandscapeImage() {
|
||||||
|
return (
|
||||||
|
<ClickableCustom
|
||||||
|
onPress={() => {
|
||||||
|
router.push("/(application)/(image)/preview-image/1");
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Image source={DUMMY_IMAGE.background} style={styles.backgroundImage} />
|
||||||
|
</ClickableCustom>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
backgroundImage: {
|
||||||
|
width: "100%",
|
||||||
|
height: 200, // Tinggi background sesuai kebutuhan
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center",
|
||||||
|
borderRadius: 6,
|
||||||
|
overflow: "hidden",
|
||||||
|
borderWidth: 1,
|
||||||
|
borderColor: AccentColor.blue,
|
||||||
|
backgroundColor: "white",
|
||||||
|
},
|
||||||
|
});
|
||||||
39
components/_ShareComponent/SearchInput.tsx
Normal file
39
components/_ShareComponent/SearchInput.tsx
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import { MainColor } from "@/constants/color-palet";
|
||||||
|
import { ICON_SIZE_SMALL } from "@/constants/constans-value";
|
||||||
|
import TextInputCustom from "../TextInput/TextInputCustom";
|
||||||
|
import { Ionicons } from "@expo/vector-icons";
|
||||||
|
import { StyleProp, ViewStyle, TextStyle } from "react-native";
|
||||||
|
|
||||||
|
interface SearchInputProps {
|
||||||
|
placeholder?: string;
|
||||||
|
onPress?: () => void;
|
||||||
|
iconLeft?: React.ReactNode;
|
||||||
|
iconRight?: React.ReactNode;
|
||||||
|
containerStyle?: StyleProp<ViewStyle>;
|
||||||
|
style?: StyleProp<TextStyle>;
|
||||||
|
}
|
||||||
|
export default function SearchInput({
|
||||||
|
placeholder,
|
||||||
|
onPress,
|
||||||
|
iconLeft,
|
||||||
|
iconRight,
|
||||||
|
containerStyle = { marginBottom: 0 },
|
||||||
|
style,
|
||||||
|
...props
|
||||||
|
}: SearchInputProps) {
|
||||||
|
return (
|
||||||
|
<TextInputCustom
|
||||||
|
iconLeft={
|
||||||
|
<Ionicons
|
||||||
|
name="search-outline"
|
||||||
|
size={ICON_SIZE_SMALL}
|
||||||
|
color={MainColor.placeholder}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
placeholder={placeholder}
|
||||||
|
borderRadius={50}
|
||||||
|
containerStyle={containerStyle}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -3,12 +3,12 @@ import React from "react";
|
|||||||
import { View } from "react-native";
|
import { View } from "react-native";
|
||||||
|
|
||||||
interface SpacingProps {
|
interface SpacingProps {
|
||||||
width?: number;
|
width?: number | string;
|
||||||
height?: number;
|
height?: number | string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Spacing: React.FC<SpacingProps> = ({ width = 20, height = 20 }) => {
|
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;
|
export default Spacing;
|
||||||
|
|||||||
15
components/_ShareComponent/TabBarBackground.tsx
Normal file
15
components/_ShareComponent/TabBarBackground.tsx
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import { AccentColor, MainColor } from "@/constants/color-palet";
|
||||||
|
import { View } from "react-native";
|
||||||
|
|
||||||
|
export default function TabBarBackground() {
|
||||||
|
return (
|
||||||
|
<View
|
||||||
|
style={{
|
||||||
|
flex: 1,
|
||||||
|
backgroundColor: MainColor.darkblue,
|
||||||
|
borderTopWidth: 1,
|
||||||
|
borderTopColor: AccentColor.blue,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
61
components/_ShareComponent/TabsTwoHeaderCustom.tsx
Normal file
61
components/_ShareComponent/TabsTwoHeaderCustom.tsx
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
import { MainColor, AccentColor } from "@/constants/color-palet";
|
||||||
|
import { View } from "react-native";
|
||||||
|
import ButtonCustom from "../Button/ButtonCustom";
|
||||||
|
import Spacing from "./Spacing";
|
||||||
|
|
||||||
|
export default function TabsTwoHeaderCustom ({
|
||||||
|
leftValue,
|
||||||
|
rightValue,
|
||||||
|
leftText,
|
||||||
|
rightText,
|
||||||
|
activeCategory,
|
||||||
|
handlePress,
|
||||||
|
}: {
|
||||||
|
leftValue: string;
|
||||||
|
rightValue: string;
|
||||||
|
leftText: string;
|
||||||
|
rightText: string;
|
||||||
|
activeCategory: string | null;
|
||||||
|
handlePress: (item: string) => void;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<View
|
||||||
|
style={{
|
||||||
|
flexDirection: "row",
|
||||||
|
alignItems: "center",
|
||||||
|
padding: 5,
|
||||||
|
backgroundColor: MainColor.soft_darkblue,
|
||||||
|
borderRadius: 50,
|
||||||
|
width: "100%",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ButtonCustom
|
||||||
|
backgroundColor={
|
||||||
|
activeCategory === leftValue ? MainColor.yellow : AccentColor.blue
|
||||||
|
}
|
||||||
|
textColor={
|
||||||
|
activeCategory === leftValue ? MainColor.black : MainColor.white
|
||||||
|
}
|
||||||
|
style={{ width: "49%" }}
|
||||||
|
onPress={() => handlePress(leftValue)}
|
||||||
|
>
|
||||||
|
{leftText}
|
||||||
|
</ButtonCustom>
|
||||||
|
<Spacing width={"2%"} />
|
||||||
|
<ButtonCustom
|
||||||
|
backgroundColor={
|
||||||
|
activeCategory === rightValue ? MainColor.yellow : AccentColor.blue
|
||||||
|
}
|
||||||
|
textColor={
|
||||||
|
activeCategory === rightValue ? MainColor.black : MainColor.white
|
||||||
|
}
|
||||||
|
style={{ width: "49%" }}
|
||||||
|
onPress={() => handlePress(rightValue)}
|
||||||
|
>
|
||||||
|
{rightText}
|
||||||
|
</ButtonCustom>
|
||||||
|
</View>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -20,15 +20,23 @@ interface ViewWrapperProps {
|
|||||||
headerComponent?: React.ReactNode;
|
headerComponent?: React.ReactNode;
|
||||||
footerComponent?: React.ReactNode;
|
footerComponent?: React.ReactNode;
|
||||||
floatingButton?: React.ReactNode;
|
floatingButton?: React.ReactNode;
|
||||||
|
hideFooter?: boolean;
|
||||||
style?: StyleProp<ViewStyle>;
|
style?: StyleProp<ViewStyle>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param hideFooter
|
||||||
|
* @returns meneyembunyikan footer ketika menggunakan tabs (misal: bottom tab)
|
||||||
|
*/
|
||||||
|
|
||||||
const ViewWrapper = ({
|
const ViewWrapper = ({
|
||||||
children,
|
children,
|
||||||
withBackground = false,
|
withBackground = false,
|
||||||
headerComponent,
|
headerComponent,
|
||||||
footerComponent,
|
footerComponent,
|
||||||
floatingButton,
|
floatingButton,
|
||||||
|
hideFooter = false,
|
||||||
style,
|
style,
|
||||||
}: ViewWrapperProps) => {
|
}: ViewWrapperProps) => {
|
||||||
const assetBackground = require("../../assets/images/main-background.png");
|
const assetBackground = require("../../assets/images/main-background.png");
|
||||||
@@ -78,10 +86,12 @@ const ViewWrapper = ({
|
|||||||
{footerComponent}
|
{footerComponent}
|
||||||
</SafeAreaView>
|
</SafeAreaView>
|
||||||
) : (
|
) : (
|
||||||
<SafeAreaView
|
hideFooter ? null : (
|
||||||
edges={["bottom"]}
|
<SafeAreaView
|
||||||
style={{ backgroundColor: MainColor.darkblue }}
|
edges={["bottom"]}
|
||||||
/>
|
style={{ backgroundColor: MainColor.darkblue }}
|
||||||
|
/>
|
||||||
|
)
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Floating Component (misal: FAB) */}
|
{/* Floating Component (misal: FAB) */}
|
||||||
|
|||||||
@@ -1,15 +1,22 @@
|
|||||||
// Alert
|
// Alert
|
||||||
import AlertCustom from "./Alert/AlertCustom";
|
import AlertCustom from "./Alert/AlertCustom";
|
||||||
|
import AlertDefaultSystem from "./Alert/AlertDefaultSystem";
|
||||||
// Button
|
// Button
|
||||||
import LeftButtonCustom from "./Button/BackButton";
|
import LeftButtonCustom from "./Button/BackButton";
|
||||||
import ButtonCenteredOnly from "./Button/ButtonCenteredOnly";
|
import ButtonCenteredOnly from "./Button/ButtonCenteredOnly";
|
||||||
import ButtonCustom from "./Button/ButtonCustom";
|
import ButtonCustom from "./Button/ButtonCustom";
|
||||||
|
import DotButton from "./Button/DotButton";
|
||||||
|
import FloatingButton from "./Button/FloatingButton";
|
||||||
|
// Badge
|
||||||
|
import BadgeCustom from "./Badge/BadgeCustom";
|
||||||
|
// Container
|
||||||
|
import CircleContainer from "./Container/CircleContainer";
|
||||||
|
// Checkbox
|
||||||
|
import CheckboxCustom from "./Checkbox/CheckboxCustom";
|
||||||
|
import CheckboxGroup from "./Checkbox/CheckboxGroup";
|
||||||
// Drawer
|
// Drawer
|
||||||
import DrawerCustom from "./Drawer/DrawerCustom";
|
import DrawerCustom from "./Drawer/DrawerCustom";
|
||||||
import MenuDrawerDynamicGrid from "./Drawer/MenuDrawerDynamicGird";
|
import MenuDrawerDynamicGrid from "./Drawer/MenuDrawerDynamicGird";
|
||||||
// ShareComponent
|
|
||||||
import Spacing from "./_ShareComponent/Spacing";
|
|
||||||
import ViewWrapper from "./_ShareComponent/ViewWrapper";
|
|
||||||
// Text
|
// Text
|
||||||
import TextCustom from "./Text/TextCustom";
|
import TextCustom from "./Text/TextCustom";
|
||||||
// TextInput
|
// TextInput
|
||||||
@@ -21,6 +28,7 @@ import Grid from "./Grid/GridCustom";
|
|||||||
// Box
|
// Box
|
||||||
import BaseBox from "./Box/BaseBox";
|
import BaseBox from "./Box/BaseBox";
|
||||||
import BoxButtonOnFooter from "./Box/BoxButtonOnFooter";
|
import BoxButtonOnFooter from "./Box/BoxButtonOnFooter";
|
||||||
|
import BoxWithHeaderSection from "./Box/BoxWithHeaderInformation";
|
||||||
import InformationBox from "./Box/InformationBox";
|
import InformationBox from "./Box/InformationBox";
|
||||||
// Stack
|
// Stack
|
||||||
import StackCustom from "./Stack/StackCustom";
|
import StackCustom from "./Stack/StackCustom";
|
||||||
@@ -30,6 +38,7 @@ import SelectCustom from "./Select/SelectCustom";
|
|||||||
import AvatarCustom from "./Image/AvatarCustom";
|
import AvatarCustom from "./Image/AvatarCustom";
|
||||||
import LandscapeFrameUploaded from "./Image/LandscapeFrameUploaded";
|
import LandscapeFrameUploaded from "./Image/LandscapeFrameUploaded";
|
||||||
// Divider
|
// Divider
|
||||||
|
import Divider from "./Divider/Divider";
|
||||||
import DividerCustom from "./Divider/DividerCustom";
|
import DividerCustom from "./Divider/DividerCustom";
|
||||||
// Map
|
// Map
|
||||||
import MapCustom from "./Map/MapCustom";
|
import MapCustom from "./Map/MapCustom";
|
||||||
@@ -39,33 +48,65 @@ import CenterCustom from "./Center/CenterCustom";
|
|||||||
import ClickableCustom from "./Clickable/ClickableCustom";
|
import ClickableCustom from "./Clickable/ClickableCustom";
|
||||||
// Scroll
|
// Scroll
|
||||||
import ScrollableCustom from "./Scroll/ScrollCustom";
|
import ScrollableCustom from "./Scroll/ScrollCustom";
|
||||||
|
// ShareComponent
|
||||||
|
import AvatarUsernameAndOtherComponent from "./_ShareComponent/AvataraAndOtherHeaderComponent";
|
||||||
|
import Spacing from "./_ShareComponent/Spacing";
|
||||||
|
import TabBarBackground from "./_ShareComponent/TabBarBackground";
|
||||||
|
import ViewWrapper from "./_ShareComponent/ViewWrapper";
|
||||||
|
import SearchInput from "./_ShareComponent/SearchInput";
|
||||||
|
import DummyLandscapeImage from "./_ShareComponent/DummyLandscapeImage";
|
||||||
|
|
||||||
export {
|
export {
|
||||||
AlertCustom,
|
AlertCustom,
|
||||||
|
AlertDefaultSystem,
|
||||||
// Image
|
// Image
|
||||||
AvatarCustom,
|
AvatarCustom,
|
||||||
LandscapeFrameUploaded,
|
// ShareComponent
|
||||||
|
AvatarUsernameAndOtherComponent,
|
||||||
|
// Button
|
||||||
|
LeftButtonCustom as BackButton,
|
||||||
// Box
|
// Box
|
||||||
BaseBox,
|
BaseBox,
|
||||||
BoxButtonOnFooter,
|
BoxButtonOnFooter,
|
||||||
|
BoxWithHeaderSection,
|
||||||
ButtonCenteredOnly,
|
ButtonCenteredOnly,
|
||||||
InformationBox,
|
|
||||||
LeftButtonCustom as BackButton,
|
|
||||||
// Button
|
|
||||||
ButtonCustom,
|
ButtonCustom,
|
||||||
|
DotButton,
|
||||||
|
// Badge
|
||||||
|
BadgeCustom,
|
||||||
|
// Center
|
||||||
|
CenterCustom,
|
||||||
|
// Checkbox
|
||||||
|
CheckboxCustom,
|
||||||
|
CheckboxGroup,
|
||||||
|
// Clickable
|
||||||
|
ClickableCustom,
|
||||||
|
// Container
|
||||||
|
CircleContainer,
|
||||||
|
// Divider
|
||||||
|
Divider,
|
||||||
|
DividerCustom,
|
||||||
// Drawer
|
// Drawer
|
||||||
DrawerCustom,
|
DrawerCustom,
|
||||||
MenuDrawerDynamicGrid,
|
FloatingButton,
|
||||||
// Grid
|
// Grid
|
||||||
Grid,
|
Grid,
|
||||||
|
InformationBox,
|
||||||
|
LandscapeFrameUploaded,
|
||||||
// Map
|
// Map
|
||||||
MapCustom,
|
MapCustom,
|
||||||
|
MenuDrawerDynamicGrid,
|
||||||
|
// Scroll
|
||||||
|
ScrollableCustom,
|
||||||
// Select
|
// Select
|
||||||
SelectCustom,
|
SelectCustom,
|
||||||
// ShareComponent
|
// ShareComponent
|
||||||
|
SearchInput,
|
||||||
|
DummyLandscapeImage,
|
||||||
Spacing,
|
Spacing,
|
||||||
// Stack
|
// Stack
|
||||||
StackCustom,
|
StackCustom,
|
||||||
|
TabBarBackground,
|
||||||
// TextArea
|
// TextArea
|
||||||
TextAreaCustom,
|
TextAreaCustom,
|
||||||
// Text
|
// Text
|
||||||
@@ -74,12 +115,4 @@ export {
|
|||||||
TextInputCustom,
|
TextInputCustom,
|
||||||
// ViewWrapper
|
// ViewWrapper
|
||||||
ViewWrapper,
|
ViewWrapper,
|
||||||
// Divider
|
|
||||||
DividerCustom,
|
|
||||||
// Center
|
|
||||||
CenterCustom,
|
|
||||||
// Clickable
|
|
||||||
ClickableCustom,
|
|
||||||
// Scroll
|
|
||||||
ScrollableCustom,
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ export {
|
|||||||
TEXT_SIZE_SMALL,
|
TEXT_SIZE_SMALL,
|
||||||
TEXT_SIZE_MEDIUM,
|
TEXT_SIZE_MEDIUM,
|
||||||
TEXT_SIZE_LARGE,
|
TEXT_SIZE_LARGE,
|
||||||
|
TEXT_SIZE_XLARGE,
|
||||||
ICON_SIZE_SMALL,
|
ICON_SIZE_SMALL,
|
||||||
ICON_SIZE_MEDIUM,
|
ICON_SIZE_MEDIUM,
|
||||||
DRAWER_HEIGHT,
|
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_SMALL = 12;
|
||||||
const TEXT_SIZE_MEDIUM = 14;
|
const TEXT_SIZE_MEDIUM = 14;
|
||||||
const TEXT_SIZE_LARGE = 16;
|
const TEXT_SIZE_LARGE = 16;
|
||||||
|
const TEXT_SIZE_XLARGE = 18;
|
||||||
|
|
||||||
// Icon Size
|
// Icon Size
|
||||||
const ICON_SIZE_BUTTON = 18
|
const ICON_SIZE_BUTTON = 18
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
const DUMMY_IMAGE = {
|
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"),
|
background: require("@/assets/images/dummy/dummy-image-background.jpg"),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
6
lib/dummy-data/_master/status.tsx
Normal file
6
lib/dummy-data/_master/status.tsx
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export const masterStatus = [
|
||||||
|
{ value: "publish", label: "Publish" },
|
||||||
|
{ value: "review", label: "Review" },
|
||||||
|
{ value: "draft", label: "Draft" },
|
||||||
|
{ value: "reject", label: "Reject" },
|
||||||
|
];
|
||||||
@@ -23,6 +23,7 @@
|
|||||||
"expo": "53.0.17",
|
"expo": "53.0.17",
|
||||||
"expo-blur": "~14.1.5",
|
"expo-blur": "~14.1.5",
|
||||||
"expo-camera": "~16.1.10",
|
"expo-camera": "~16.1.10",
|
||||||
|
"expo-clipboard": "~7.1.5",
|
||||||
"expo-constants": "~17.1.7",
|
"expo-constants": "~17.1.7",
|
||||||
"expo-font": "~13.3.2",
|
"expo-font": "~13.3.2",
|
||||||
"expo-haptics": "~14.1.4",
|
"expo-haptics": "~14.1.4",
|
||||||
@@ -42,6 +43,7 @@
|
|||||||
"react-native-international-phone-number": "^0.9.3",
|
"react-native-international-phone-number": "^0.9.3",
|
||||||
"react-native-maps": "1.20.1",
|
"react-native-maps": "1.20.1",
|
||||||
"react-native-otp-entry": "^1.8.5",
|
"react-native-otp-entry": "^1.8.5",
|
||||||
|
"react-native-pager-view": "6.7.1",
|
||||||
"react-native-paper": "^5.14.5",
|
"react-native-paper": "^5.14.5",
|
||||||
"react-native-reanimated": "~3.17.4",
|
"react-native-reanimated": "~3.17.4",
|
||||||
"react-native-safe-area-context": "5.4.0",
|
"react-native-safe-area-context": "5.4.0",
|
||||||
|
|||||||
@@ -32,11 +32,12 @@ export default function LoginView() {
|
|||||||
|
|
||||||
// router.navigate("/verification");
|
// router.navigate("/verification");
|
||||||
// router.navigate(`/(application)/(user)/profile/${id}`);
|
// router.navigate(`/(application)/(user)/profile/${id}`);
|
||||||
// router.navigate("/(application)/(user)/home");
|
router.navigate("/(application)/(user)/home");
|
||||||
// router.navigate(`/(application)/profile/${id}/edit`);
|
// router.navigate(`/(application)/profile/${id}/edit`);
|
||||||
// router.navigate(`/(application)/(user)/portofolio/${id}`)
|
// router.navigate(`/(application)/(user)/portofolio/${id}`)
|
||||||
// router.navigate(`/(application)/(image)/preview-image/${id}`);
|
// router.navigate(`/(application)/(image)/preview-image/${id}`);
|
||||||
router.replace("/(application)/(user)/event/(tabs)");
|
// router.replace("/(application)/(user)/event/(tabs)");
|
||||||
|
// router.replace("/(application)/coba");
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
54
screens/Collaboration/BoxDetailSection.tsx
Normal file
54
screens/Collaboration/BoxDetailSection.tsx
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
import {
|
||||||
|
AvatarUsernameAndOtherComponent,
|
||||||
|
BoxWithHeaderSection,
|
||||||
|
Grid,
|
||||||
|
StackCustom,
|
||||||
|
TextCustom
|
||||||
|
} from "@/components";
|
||||||
|
|
||||||
|
export default function Collaboration_BoxDetailSection({ id }: { id: string }) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<BoxWithHeaderSection>
|
||||||
|
<StackCustom>
|
||||||
|
<AvatarUsernameAndOtherComponent />
|
||||||
|
<TextCustom align="center" bold size="large">
|
||||||
|
Judul Proyek {id}
|
||||||
|
</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>
|
||||||
|
</BoxWithHeaderSection>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const listData = [
|
||||||
|
{
|
||||||
|
title: "Industri",
|
||||||
|
value: "Pilihan Industri",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Deskripsi",
|
||||||
|
value: "Deskripsi Proyek",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Tujuan Proyek",
|
||||||
|
value:
|
||||||
|
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Keuntungan Proyek",
|
||||||
|
value:
|
||||||
|
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
|
||||||
|
},
|
||||||
|
];
|
||||||
60
screens/Collaboration/BoxPublishSection.tsx
Normal file
60
screens/Collaboration/BoxPublishSection.tsx
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
import {
|
||||||
|
AvatarUsernameAndOtherComponent,
|
||||||
|
BoxWithHeaderSection,
|
||||||
|
StackCustom,
|
||||||
|
TextCustom
|
||||||
|
} from "@/components";
|
||||||
|
import { Href } from "expo-router";
|
||||||
|
|
||||||
|
function Collaboration_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={0}>
|
||||||
|
<AvatarUsernameAndOtherComponent
|
||||||
|
avatarHref={`/profile/${id}`}
|
||||||
|
name={username || "Username"}
|
||||||
|
rightComponent={rightComponentAvatar}
|
||||||
|
avatar={sourceAvatar as any}
|
||||||
|
withBottomLine
|
||||||
|
/>
|
||||||
|
|
||||||
|
<StackCustom>
|
||||||
|
<TextCustom truncate={2} size="large" bold align="center">
|
||||||
|
{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>
|
||||||
|
{/* <TextCustom bold size="small" >
|
||||||
|
2 Partisipan
|
||||||
|
</TextCustom> */}
|
||||||
|
</StackCustom>
|
||||||
|
</StackCustom>
|
||||||
|
</BoxWithHeaderSection>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Collaboration_BoxPublishSection;
|
||||||
69
screens/Collaboration/ProjectMainSelectedSection.tsx
Normal file
69
screens/Collaboration/ProjectMainSelectedSection.tsx
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
import {
|
||||||
|
AvatarCustom,
|
||||||
|
BaseBox,
|
||||||
|
CheckboxCustom,
|
||||||
|
CheckboxGroup,
|
||||||
|
Grid,
|
||||||
|
StackCustom,
|
||||||
|
TextCustom
|
||||||
|
} from "@/components";
|
||||||
|
import { ICON_SIZE_SMALL } from "@/constants/constans-value";
|
||||||
|
import { MaterialIcons } from "@expo/vector-icons";
|
||||||
|
import { View } from "react-native";
|
||||||
|
|
||||||
|
export default function Collaboration_ProjectMainSelectedSection({
|
||||||
|
selected,
|
||||||
|
setSelected,
|
||||||
|
setOpenDrawerParticipant,
|
||||||
|
}: {
|
||||||
|
selected: (string | number)[];
|
||||||
|
setSelected: (value: (string | number)[]) => void;
|
||||||
|
setOpenDrawerParticipant: (value: boolean) => void;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<BaseBox style={{ height: 500 }}>
|
||||||
|
<StackCustom>
|
||||||
|
<TextCustom size="default" color="red" bold>
|
||||||
|
*{" "}
|
||||||
|
<TextCustom size="small" semiBold>
|
||||||
|
Pilih user yang akan menjadi tim proyek anda
|
||||||
|
</TextCustom>
|
||||||
|
</TextCustom>
|
||||||
|
|
||||||
|
<CheckboxGroup value={selected} onChange={setSelected}>
|
||||||
|
{Array.from({ length: 5 }).map((_, index) => (
|
||||||
|
<View key={index}>
|
||||||
|
<Grid key={index}>
|
||||||
|
<Grid.Col
|
||||||
|
span={2}
|
||||||
|
style={{ alignItems: "center", justifyContent: "center" }}
|
||||||
|
>
|
||||||
|
<CheckboxCustom valueKey={`user-${index}`} />
|
||||||
|
</Grid.Col>
|
||||||
|
<Grid.Col span={2} style={{ alignItems: "center" }}>
|
||||||
|
<AvatarCustom />
|
||||||
|
</Grid.Col>
|
||||||
|
<Grid.Col span={6} style={{ justifyContent: "center" }}>
|
||||||
|
<TextCustom bold truncate>
|
||||||
|
Username
|
||||||
|
</TextCustom>
|
||||||
|
</Grid.Col>
|
||||||
|
<Grid.Col
|
||||||
|
span={2}
|
||||||
|
style={{ alignItems: "center", justifyContent: "center" }}
|
||||||
|
>
|
||||||
|
<MaterialIcons
|
||||||
|
name="notes"
|
||||||
|
size={ICON_SIZE_SMALL}
|
||||||
|
color="white"
|
||||||
|
onPress={() => setOpenDrawerParticipant(true)}
|
||||||
|
/>
|
||||||
|
</Grid.Col>
|
||||||
|
</Grid>
|
||||||
|
</View>
|
||||||
|
))}
|
||||||
|
</CheckboxGroup>
|
||||||
|
</StackCustom>
|
||||||
|
</BaseBox>
|
||||||
|
);
|
||||||
|
}
|
||||||
115
screens/Event/AlertButtonStatusSection.tsx
Normal file
115
screens/Event/AlertButtonStatusSection.tsx
Normal 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();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
61
screens/Event/BoxDetailPublishSection.tsx
Normal file
61
screens/Event/BoxDetailPublishSection.tsx
Normal 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!",
|
||||||
|
},
|
||||||
|
];
|
||||||
51
screens/Event/BoxPublishSection.tsx
Normal file
51
screens/Event/BoxPublishSection.tsx
Normal 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>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
76
screens/Event/ButtonStatusSection.tsx
Normal file
76
screens/Event/ButtonStatusSection.tsx
Normal 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>;
|
||||||
|
}
|
||||||
|
}
|
||||||
17
screens/Event/menuDrawerDraft.tsx
Normal file
17
screens/Event/menuDrawerDraft.tsx
Normal 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`,
|
||||||
|
},
|
||||||
|
];
|
||||||
17
screens/Event/menuDrawerPublish.tsx
Normal file
17
screens/Event/menuDrawerPublish.tsx
Normal 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`,
|
||||||
|
},
|
||||||
|
];
|
||||||
@@ -1,8 +1,6 @@
|
|||||||
import { BaseBox, ButtonCustom, StackCustom, TextCustom } from "@/components";
|
import { BaseBox, StackCustom, TextCustom } from "@/components";
|
||||||
import { RadioCustom, RadioGroup } from "@/components/Radio/RadioCustom";
|
import { RadioCustom, RadioGroup } from "@/components/Radio/RadioCustom";
|
||||||
import { MainColor } from "@/constants/color-palet";
|
|
||||||
import { listDummyReportForum } from "@/lib/dummy-data/forum/report-list";
|
import { listDummyReportForum } from "@/lib/dummy-data/forum/report-list";
|
||||||
import { router } from "expo-router";
|
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { View } from "react-native";
|
import { View } from "react-native";
|
||||||
|
|
||||||
|
|||||||
@@ -1,52 +1,55 @@
|
|||||||
import { TextCustom } from "@/components";
|
import { ClickableCustom, TextCustom } from "@/components";
|
||||||
import Spacing from "@/components/_ShareComponent/Spacing";
|
import Spacing from "@/components/_ShareComponent/Spacing";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { View } from "react-native";
|
import { View } from "react-native";
|
||||||
import Icon from "react-native-vector-icons/FontAwesome";
|
import Icon from "react-native-vector-icons/FontAwesome";
|
||||||
import { stylesHome } from "./homeViewStyle";
|
import { stylesHome } from "./homeViewStyle";
|
||||||
|
import { router } from "expo-router";
|
||||||
|
|
||||||
export default function Home_BottomFeatureSection() {
|
export default function Home_BottomFeatureSection() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<View style={stylesHome.jobVacancyContainer}>
|
<ClickableCustom onPress={() => router.push("/job")}>
|
||||||
<View style={stylesHome.jobVacancyHeader}>
|
<View style={stylesHome.jobVacancyContainer}>
|
||||||
<Icon name="briefcase" size={24} color="white" />
|
<View style={stylesHome.jobVacancyHeader}>
|
||||||
<Spacing width={10}/>
|
<Icon name="briefcase" size={24} color="white" />
|
||||||
<TextCustom bold size="large">
|
<Spacing width={10} />
|
||||||
Job Vacancy
|
<TextCustom bold size="large">
|
||||||
</TextCustom>
|
Job Vacancy
|
||||||
</View>
|
</TextCustom>
|
||||||
|
|
||||||
<View style={stylesHome.vacancyList}>
|
|
||||||
{/* Vacancy Item 1 */}
|
|
||||||
<View style={stylesHome.vacancyItem}>
|
|
||||||
{/* <Icon name="user" size={20} color="#FFD700" /> */}
|
|
||||||
<View style={stylesHome.vacancyDetails}>
|
|
||||||
<TextCustom bold color="yellow" truncate size="large">
|
|
||||||
Bagas_banuna
|
|
||||||
</TextCustom>
|
|
||||||
<Spacing height={5} />
|
|
||||||
<TextCustom truncate={2}>
|
|
||||||
Dicari perawat kucing dan perawat anjing
|
|
||||||
</TextCustom>
|
|
||||||
</View>
|
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
{/* Vacancy Item 2 */}
|
<View style={stylesHome.vacancyList}>
|
||||||
<View style={stylesHome.vacancyItem}>
|
{/* Vacancy Item 1 */}
|
||||||
{/* <Icon name="user" size={20} color="#FFD700" /> */}
|
<View style={stylesHome.vacancyItem}>
|
||||||
<View style={stylesHome.vacancyDetails}>
|
{/* <Icon name="user" size={20} color="#FFD700" /> */}
|
||||||
<TextCustom bold color="yellow" truncate size="large">
|
<View style={stylesHome.vacancyDetails}>
|
||||||
fibramarcell
|
<TextCustom bold color="yellow" truncate size="large">
|
||||||
</TextCustom>
|
Bagas_banuna
|
||||||
<Spacing height={5} />
|
</TextCustom>
|
||||||
<TextCustom truncate={2}>
|
<Spacing height={5} />
|
||||||
Di Butuhkan Seorang Programer dan Designer
|
<TextCustom truncate={2}>
|
||||||
</TextCustom>
|
Dicari perawat kucing dan perawat anjing
|
||||||
|
</TextCustom>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* Vacancy Item 2 */}
|
||||||
|
<View style={stylesHome.vacancyItem}>
|
||||||
|
{/* <Icon name="user" size={20} color="#FFD700" /> */}
|
||||||
|
<View style={stylesHome.vacancyDetails}>
|
||||||
|
<TextCustom bold color="yellow" truncate size="large">
|
||||||
|
fibramarcell
|
||||||
|
</TextCustom>
|
||||||
|
<Spacing height={5} />
|
||||||
|
<TextCustom truncate={2}>
|
||||||
|
Di Butuhkan Seorang Programer dan Designer
|
||||||
|
</TextCustom>
|
||||||
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</ClickableCustom>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,11 +14,19 @@ export default function Home_FeatureSection() {
|
|||||||
<Ionicons name="analytics" size={48} color="white" />
|
<Ionicons name="analytics" size={48} color="white" />
|
||||||
<Text style={stylesHome.gridLabel}>Event</Text>
|
<Text style={stylesHome.gridLabel}>Event</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
<TouchableOpacity style={stylesHome.gridItem}>
|
<TouchableOpacity
|
||||||
|
style={stylesHome.gridItem}
|
||||||
|
onPress={() =>
|
||||||
|
router.push("/(application)/(user)/collaboration/(tabs)")
|
||||||
|
}
|
||||||
|
>
|
||||||
<Ionicons name="share" size={48} color="white" />
|
<Ionicons name="share" size={48} color="white" />
|
||||||
<Text style={stylesHome.gridLabel}>Collaboration</Text>
|
<Text style={stylesHome.gridLabel}>Collaboration</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
<TouchableOpacity style={stylesHome.gridItem}>
|
<TouchableOpacity
|
||||||
|
style={stylesHome.gridItem}
|
||||||
|
onPress={() => router.push("/(application)/(user)/voting/(tabs)")}
|
||||||
|
>
|
||||||
<Ionicons name="cube" size={48} color="white" />
|
<Ionicons name="cube" size={48} color="white" />
|
||||||
<Text style={stylesHome.gridLabel}>Voting</Text>
|
<Text style={stylesHome.gridLabel}>Voting</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user