Add:
- BoxDetailContribution
- app/(application)/(user)/voting/[id]/contribution.tsx

Fix:
- app/(application)/(user)/voting/(tabs)/contribution.tsx
- app/(application)/(user)/voting/[id]/[status]/detail.tsx
- app/(application)/(user)/voting/[id]/list-of-contributor.tsx
- app/(application)/(user)/voting/[id]/index.tsx

# No Issue
This commit is contained in:
2025-07-28 17:29:52 +08:00
parent 4bcfcb5f5a
commit c9a1ac1db5
9 changed files with 246 additions and 81 deletions

View File

@@ -165,13 +165,6 @@ export default function UserLayout() {
headerLeft: () => <BackButton path="/home" />, headerLeft: () => <BackButton path="/home" />,
}} }}
/> />
<Stack.Screen
name="voting/[id]/index"
options={{
title: "Detail Voting",
headerLeft: () => <BackButton />,
}}
/>
<Stack.Screen <Stack.Screen
name="voting/[id]/edit" name="voting/[id]/edit"
options={{ options={{

View File

@@ -1,25 +1,15 @@
import { import {
BadgeCustom, ViewWrapper
StackCustom,
TextCustom,
ViewWrapper,
} from "@/components"; } from "@/components";
import Voting_BoxPublishSection from "@/screens/Voting/BoxPublishSection"; import Voting_BoxPublishSection from "@/screens/Voting/BoxPublishSection";
import { GStyles } from "@/styles/global-styles";
export default function VotingContribution() { export default function VotingContribution() {
const bottomComponent = (
<StackCustom>
<TextCustom align="center">Pilihan Anda:</TextCustom>
<BadgeCustom style={[GStyles.alignSelfCenter]}>Pilihan 1</BadgeCustom>
</StackCustom>
);
return ( return (
<ViewWrapper hideFooter> <ViewWrapper hideFooter>
{Array.from({ length: 5 }).map((_, index) => ( {Array.from({ length: 5 }).map((_, index) => (
<Voting_BoxPublishSection <Voting_BoxPublishSection
key={index} key={index}
bottomComponent={bottomComponent} href={`/voting/${index}/contribution`}
/> />
))} ))}
</ViewWrapper> </ViewWrapper>

View File

@@ -1,19 +1,16 @@
import { import {
AlertDefaultSystem, AlertDefaultSystem,
BackButton, BackButton,
DotButton, DotButton,
DrawerCustom, DrawerCustom,
MenuDrawerDynamicGrid, MenuDrawerDynamicGrid,
Spacing, Spacing,
ViewWrapper, ViewWrapper,
} from "@/components"; } from "@/components";
import { IconArchive, IconEdit } from "@/components/_Icon"; import { IconArchive, IconContribution, IconEdit } from "@/components/_Icon";
import { IMenuDrawerItem } from "@/components/_Interface/types"; import { IMenuDrawerItem } from "@/components/_Interface/types";
import { MainColor } from "@/constants/color-palet";
import { ICON_SIZE_SMALL } from "@/constants/constans-value";
import { Voting_BoxDetailSection } from "@/screens/Voting/BoxDetailSection"; import { Voting_BoxDetailSection } from "@/screens/Voting/BoxDetailSection";
import Voting_ButtonStatusSection from "@/screens/Voting/ButtonStatusSection"; import Voting_ButtonStatusSection from "@/screens/Voting/ButtonStatusSection";
import { Ionicons } from "@expo/vector-icons";
import { router, Stack, useLocalSearchParams } from "expo-router"; import { router, Stack, useLocalSearchParams } from "expo-router";
import { useState } from "react"; import { useState } from "react";
@@ -45,7 +42,6 @@ export default function VotingDetailStatus() {
setOpenDrawerPublish(false); setOpenDrawerPublish(false);
}; };
return ( return (
<> <>
<Stack.Screen <Stack.Screen
@@ -66,6 +62,7 @@ export default function VotingDetailStatus() {
<Spacing /> <Spacing />
</ViewWrapper> </ViewWrapper>
{/* ========= Draft Drawer ========= */}
<DrawerCustom <DrawerCustom
isVisible={openDrawerDraft} isVisible={openDrawerDraft}
closeDrawer={() => setOpenDrawerDraft(false)} closeDrawer={() => setOpenDrawerDraft(false)}
@@ -84,6 +81,7 @@ export default function VotingDetailStatus() {
/> />
</DrawerCustom> </DrawerCustom>
{/* ========= Publish Drawer ========= */}
<DrawerCustom <DrawerCustom
isVisible={openDrawerPublish} isVisible={openDrawerPublish}
closeDrawer={() => setOpenDrawerPublish(false)} closeDrawer={() => setOpenDrawerPublish(false)}
@@ -92,13 +90,7 @@ export default function VotingDetailStatus() {
<MenuDrawerDynamicGrid <MenuDrawerDynamicGrid
data={[ data={[
{ {
icon: ( icon: <IconContribution />,
<Ionicons
name="people"
size={ICON_SIZE_SMALL}
color={MainColor.white}
/>
),
label: "Daftar Kontributor", label: "Daftar Kontributor",
path: `/voting/${id}/list-of-contributor`, path: `/voting/${id}/list-of-contributor`,
}, },

View 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>
</>
);
}

View File

@@ -1,25 +1,87 @@
import { import {
AvatarUsernameAndOtherComponent, AlertDefaultSystem,
InformationBox, AvatarUsernameAndOtherComponent,
StackCustom, BackButton,
ViewWrapper DotButton,
DrawerCustom,
InformationBox,
MenuDrawerDynamicGrid,
StackCustom,
ViewWrapper,
} from "@/components"; } from "@/components";
import { IconArchive, IconContribution } from "@/components/_Icon";
import { IMenuDrawerItem } from "@/components/_Interface/types";
import Voting_BoxDetailHasilVotingSection from "@/screens/Voting/BoxDetailHasilVotingSection"; import Voting_BoxDetailHasilVotingSection from "@/screens/Voting/BoxDetailHasilVotingSection";
import { Voting_BoxDetailPublishSection } from "@/screens/Voting/BoxDetailPublishSection"; import { Voting_BoxDetailPublishSection } from "@/screens/Voting/BoxDetailPublishSection";
import React from "react"; import { router, Stack, useLocalSearchParams } from "expo-router";
import React, { useState } from "react";
export default function VotingDetail() { 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 ( return (
<ViewWrapper> <>
<StackCustom> <Stack.Screen
<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." /> options={{
title: `Detail Voting`,
headerLeft: () => <BackButton />,
headerRight: () => (
<DotButton onPress={() => setOpenDrawerPublish(true)} />
),
}}
/>
<Voting_BoxDetailPublishSection <ViewWrapper>
headerAvatar={<AvatarUsernameAndOtherComponent />} <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>
<Voting_BoxDetailHasilVotingSection /> </>
</StackCustom>
</ViewWrapper>
); );
} }

View File

@@ -1,15 +1,24 @@
import { import {
AvatarUsernameAndOtherComponent, AvatarUsernameAndOtherComponent,
BaseBox, BadgeCustom,
ViewWrapper BaseBox,
ViewWrapper,
} from "@/components"; } from "@/components";
export default function Voting_ListOfContributor() { export default function Voting_ListOfContributor() {
return ( return (
<ViewWrapper> <ViewWrapper>
{Array.from({ length: 10 }).map((_, index) => ( {Array.from({ length: 10 }).map((_, index) => (
<BaseBox key={index.toString()}> <BaseBox paddingTop={5} paddingBottom={5} key={index.toString()}>
<AvatarUsernameAndOtherComponent /> <AvatarUsernameAndOtherComponent
rightComponent={
<BadgeCustom
style={{alignSelf: "flex-end" }}
>
Pilihan {index + 1}
</BadgeCustom>
}
/>
</BaseBox> </BaseBox>
))} ))}
</ViewWrapper> </ViewWrapper>

View File

@@ -6,7 +6,7 @@ export default function IconContribution({ color }: { color?: string }) {
<> <>
<Ionicons <Ionicons
size={ICON_SIZE_SMALL} size={ICON_SIZE_SMALL}
name="extension-puzzle" name="people"
color={color || "white"} color={color || "white"}
/> />
</> </>

View File

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

View File

@@ -0,0 +1,56 @@
import {
BadgeCustom,
BoxWithHeaderSection,
Spacing,
StackCustom,
TextCustom,
} from "@/components";
import { GStyles } from "@/styles/global-styles";
import dayjs from "dayjs";
import { View } from "react-native";
export function Voting_BoxDetailContributionSection({
headerAvatar,
}: {
headerAvatar?: React.ReactNode;
}) {
return (
<>
<BoxWithHeaderSection>
{headerAvatar ? headerAvatar : <Spacing />}
<StackCustom gap={"lg"}>
<TextCustom align="center" bold size="large">
Title of Voting Here
</TextCustom>
<TextCustom>
Lorem ipsum dolor sit amet consectetur adipisicing elit.
Perspiciatis corporis blanditiis est provident corrupti facilis iste
cum voluptate. Natus eum aut quos consequatur doloribus fugiat sit
ullam minima non enim?
</TextCustom>
<View>
<TextCustom bold size="small" align="center">
Batas Voting
</TextCustom>
<BadgeCustom
style={[GStyles.alignSelfCenter, { width: "70%" }]}
variant="light"
>
{dayjs().format("DD/MM/YYYY")} -{" "}
{dayjs().add(1, "day").format("DD/MM/YYYY")}
</BadgeCustom>
</View>
<StackCustom gap={"xs"}>
<TextCustom bold size="small" align="center">
Pilihan Anda
</TextCustom>
<BadgeCustom style={[GStyles.alignSelfCenter]}>
Pilihan 1
</BadgeCustom>
</StackCustom>
</StackCustom>
</BoxWithHeaderSection>
</>
);
}