Compare commits
1 Commits
api/17-sep
...
api-voting
| Author | SHA1 | Date | |
|---|---|---|---|
| 391430de46 |
@@ -1,23 +1,63 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import {
|
||||
FloatingButton,
|
||||
LoaderCustom,
|
||||
SearchInput,
|
||||
ViewWrapper
|
||||
TextCustom,
|
||||
ViewWrapper,
|
||||
} from "@/components";
|
||||
import Voting_BoxPublishSection from "@/screens/Voting/BoxPublishSection";
|
||||
import { apiVotingGetAll } from "@/service/api-client/api-voting";
|
||||
import { router } from "expo-router";
|
||||
import _ from "lodash";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
export default function VotingBeranda() {
|
||||
const [listData, setListData] = useState<any>([]);
|
||||
const [loadingGetData, setLoadingGetData] = useState(false);
|
||||
const [search, setSearch] = useState("");
|
||||
|
||||
useEffect(() => {
|
||||
onLoadData();
|
||||
}, [search]);
|
||||
|
||||
const onLoadData = async () => {
|
||||
try {
|
||||
setLoadingGetData(true);
|
||||
const response = await apiVotingGetAll({ search });
|
||||
if (response.success) {
|
||||
setListData(response.data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
} finally {
|
||||
setLoadingGetData(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<ViewWrapper
|
||||
hideFooter
|
||||
floatingButton={
|
||||
<FloatingButton onPress={() => router.push("/voting/create")} />
|
||||
}
|
||||
headerComponent={<SearchInput placeholder="Cari voting" />}
|
||||
headerComponent={
|
||||
<SearchInput placeholder="Cari voting" onChangeText={setSearch} />
|
||||
}
|
||||
>
|
||||
{Array.from({ length: 5 }).map((_, index) => (
|
||||
<Voting_BoxPublishSection key={index} href={`/voting/${index}`} />
|
||||
))}
|
||||
{loadingGetData ? (
|
||||
<LoaderCustom />
|
||||
) : _.isEmpty(listData) ? (
|
||||
<TextCustom align="center">Tidak ada data</TextCustom>
|
||||
) : (
|
||||
listData.map((item: any, index: number) => (
|
||||
<Voting_BoxPublishSection
|
||||
data={item}
|
||||
key={index}
|
||||
href={`/voting/${item.id}`}
|
||||
/>
|
||||
))
|
||||
)}
|
||||
</ViewWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@ import { useAuth } from "@/hooks/use-auth";
|
||||
import { dummyMasterStatus } from "@/lib/dummy-data/_master/status";
|
||||
import { apiVotingGetByStatus } from "@/service/api-client/api-voting";
|
||||
import { dateTimeView } from "@/utils/dateTimeView";
|
||||
import dayjs from "dayjs";
|
||||
import { useFocusEffect } from "expo-router";
|
||||
import _ from "lodash";
|
||||
import { useCallback, useState } from "react";
|
||||
@@ -20,7 +19,6 @@ import { useCallback, useState } from "react";
|
||||
export default function VotingStatus() {
|
||||
const { user } = useAuth();
|
||||
const id = user?.id || "";
|
||||
console.log("ID >> ", id);
|
||||
const [activeCategory, setActiveCategory] = useState<string | null>(
|
||||
"publish"
|
||||
);
|
||||
@@ -41,7 +39,6 @@ export default function VotingStatus() {
|
||||
id: id as string,
|
||||
status: activeCategory!,
|
||||
});
|
||||
console.log("[RES LIST STATUS]", JSON.stringify(response.data, null, 2));
|
||||
setListData(response.data);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
|
||||
@@ -20,15 +20,12 @@ import {
|
||||
useLocalSearchParams,
|
||||
} from "expo-router";
|
||||
import { useCallback, useState } from "react";
|
||||
import { useAuth } from "@/hooks/use-auth";
|
||||
|
||||
export default function VotingDetailStatus() {
|
||||
const {user} = useAuth()
|
||||
const { id, status } = useLocalSearchParams();
|
||||
console.log("ID >> ", id);
|
||||
console.log("STATUS >> ", status);
|
||||
const [openDrawerDraft, setOpenDrawerDraft] = useState(false);
|
||||
const [openDrawerPublish, setOpenDrawerPublish] = useState(false);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
const [data, setData] = useState<any>(null);
|
||||
|
||||
@@ -41,10 +38,11 @@ export default function VotingDetailStatus() {
|
||||
const onLoadData = async () => {
|
||||
try {
|
||||
const response = await apiVotingGetOne({ id: id as string });
|
||||
console.log("Response", JSON.stringify(response.data, null, 2));
|
||||
setData(response.data);
|
||||
if(response.success){
|
||||
setData(response.data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
console.log("[ERROR]", error);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -62,7 +60,7 @@ export default function VotingDetailStatus() {
|
||||
textLeft: "Batal",
|
||||
textRight: "Ya",
|
||||
onPressRight: () => {
|
||||
console.log("Hapus");
|
||||
console.log("Arsip voting");
|
||||
router.back();
|
||||
},
|
||||
});
|
||||
@@ -86,8 +84,13 @@ export default function VotingDetailStatus() {
|
||||
}}
|
||||
/>
|
||||
<ViewWrapper>
|
||||
<Voting_BoxDetailSection data={data as any}/>
|
||||
<Voting_ButtonStatusSection id={id as string} status={status as string} />
|
||||
<Voting_BoxDetailSection data={data as any} />
|
||||
<Voting_ButtonStatusSection
|
||||
isLoading={isLoading}
|
||||
onSetLoading={setIsLoading}
|
||||
id={id as string}
|
||||
status={status as string}
|
||||
/>
|
||||
<Spacing />
|
||||
</ViewWrapper>
|
||||
|
||||
|
||||
@@ -1,29 +1,183 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import {
|
||||
ActionIcon,
|
||||
BoxButtonOnFooter,
|
||||
ButtonCenteredOnly,
|
||||
ButtonCustom,
|
||||
Grid,
|
||||
CenterCustom,
|
||||
LoaderCustom,
|
||||
Spacing,
|
||||
StackCustom,
|
||||
TextAreaCustom,
|
||||
TextCustom,
|
||||
TextInputCustom,
|
||||
ViewWrapper,
|
||||
} from "@/components";
|
||||
import DateTimePickerCustom from "@/components/DateInput/DateTimePickerCustom";
|
||||
import { MainColor } from "@/constants/color-palet";
|
||||
import { ICON_SIZE_XLARGE } from "@/constants/constans-value";
|
||||
import {
|
||||
apiVotingGetOne,
|
||||
apiVotingUpdateData,
|
||||
} from "@/service/api-client/api-voting";
|
||||
import { Ionicons } from "@expo/vector-icons";
|
||||
import { router } from "expo-router";
|
||||
import { TouchableOpacity } from "react-native";
|
||||
import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
|
||||
import _ from "lodash";
|
||||
import { useCallback, useState } from "react";
|
||||
import { View } from "react-native";
|
||||
import Toast from "react-native-toast-message";
|
||||
|
||||
interface IEditData {
|
||||
title?: string;
|
||||
deskripsi?: string;
|
||||
awalVote?: string;
|
||||
akhirVote?: string;
|
||||
Voting_DaftarNamaVote?: [
|
||||
{
|
||||
value?: string;
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
export default function VotingEdit() {
|
||||
const { id } = useLocalSearchParams();
|
||||
const [loadingGetData, setLoadingGetData] = useState(false);
|
||||
const [data, setData] = useState<IEditData>();
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
onLoadData();
|
||||
}, [id])
|
||||
);
|
||||
|
||||
const onLoadData = async () => {
|
||||
try {
|
||||
setLoadingGetData(true);
|
||||
const response = await apiVotingGetOne({ id: id as string });
|
||||
|
||||
if (response.success) {
|
||||
const data = response.data;
|
||||
setData({
|
||||
title: data.title,
|
||||
deskripsi: data.deskripsi,
|
||||
awalVote: data.awalVote,
|
||||
akhirVote: data.akhirVote,
|
||||
Voting_DaftarNamaVote: data.Voting_DaftarNamaVote,
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
} finally {
|
||||
setLoadingGetData(false);
|
||||
}
|
||||
};
|
||||
|
||||
const validateDateRange = ({
|
||||
selectedStratDate,
|
||||
selectedEndDate,
|
||||
}: {
|
||||
selectedStratDate: string | Date;
|
||||
selectedEndDate: string | Date;
|
||||
}): { isValid: boolean; error?: string } => {
|
||||
const startDate = new Date(selectedStratDate);
|
||||
const endDate = new Date(selectedEndDate);
|
||||
|
||||
// Cek apakah tanggal valid
|
||||
if (isNaN(startDate.getTime()) || isNaN(endDate.getTime())) {
|
||||
return {
|
||||
isValid: false,
|
||||
error: "Invalid date provided",
|
||||
};
|
||||
}
|
||||
|
||||
if (startDate >= endDate) {
|
||||
return {
|
||||
isValid: false,
|
||||
error: "Ubah tanggal berakhirnya event",
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
isValid: true,
|
||||
error: undefined,
|
||||
};
|
||||
};
|
||||
|
||||
const validateForm = async () => {
|
||||
if (!data?.title || !data?.deskripsi) {
|
||||
Toast.show({
|
||||
type: "info",
|
||||
text1: "Lengkapi semua data",
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
if (data?.Voting_DaftarNamaVote?.some((item: any) => item.value === "")) {
|
||||
Toast.show({
|
||||
type: "info",
|
||||
text1: "Isi semua data pilihan",
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
const startDate = new Date(data?.awalVote as any);
|
||||
const endDate = new Date(data?.akhirVote as any);
|
||||
|
||||
if (startDate >= endDate) {
|
||||
Toast.show({
|
||||
type: "info",
|
||||
text1: "Ubah tanggal berakhirnya event",
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
const handlerUpdateSubmit = async () => {
|
||||
const isValid = await validateForm();
|
||||
if (!isValid) return;
|
||||
|
||||
try {
|
||||
setIsLoading(true);
|
||||
const newData = {
|
||||
...data,
|
||||
awalVote: new Date(data?.awalVote as any).toISOString(),
|
||||
akhirVote: new Date(data?.akhirVote as any).toISOString(),
|
||||
listVote: data?.Voting_DaftarNamaVote?.map((item: any) => item.value),
|
||||
};
|
||||
|
||||
const response = await apiVotingUpdateData({
|
||||
id: id as string,
|
||||
data: newData,
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
Toast.show({
|
||||
type: "success",
|
||||
text1: response.message,
|
||||
});
|
||||
return router.back();
|
||||
} else {
|
||||
Toast.show({
|
||||
type: "error",
|
||||
text1: response.message,
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const buttonSubmit = () => {
|
||||
return (
|
||||
<>
|
||||
<BoxButtonOnFooter>
|
||||
<ButtonCustom
|
||||
onPress={() =>
|
||||
router.back()
|
||||
}
|
||||
isLoading={isLoading}
|
||||
onPress={() => handlerUpdateSubmit()}
|
||||
>
|
||||
Update
|
||||
</ButtonCustom>
|
||||
@@ -34,45 +188,144 @@ export default function VotingEdit() {
|
||||
|
||||
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 />
|
||||
{loadingGetData ? (
|
||||
<LoaderCustom />
|
||||
) : (
|
||||
<StackCustom gap={"xs"}>
|
||||
<TextInputCustom
|
||||
label="Judul Voting"
|
||||
placeholder="MasukanJudul Voting"
|
||||
required
|
||||
value={data?.title}
|
||||
onChangeText={(text) => setData({ ...data, title: text })}
|
||||
/>
|
||||
<TextAreaCustom
|
||||
label="Deskripsi"
|
||||
placeholder="Masukan Deskripsi"
|
||||
required
|
||||
showCount
|
||||
maxLength={1000}
|
||||
value={data?.deskripsi}
|
||||
onChangeText={(text) => setData({ ...data, deskripsi: text })}
|
||||
/>
|
||||
|
||||
<Grid>
|
||||
<Grid.Col span={10}>
|
||||
<Spacing />
|
||||
|
||||
<DateTimePickerCustom
|
||||
minimumDate={new Date(Date.now())}
|
||||
label="Mulai Voting"
|
||||
required
|
||||
value={new Date(data?.awalVote as any)}
|
||||
onChange={(date: any) => {
|
||||
setData({ ...data, awalVote: date });
|
||||
}}
|
||||
/>
|
||||
|
||||
<StackCustom gap={0}>
|
||||
<DateTimePickerCustom
|
||||
minimumDate={new Date(data?.awalVote as any)}
|
||||
label="Voting Berakhir"
|
||||
required
|
||||
value={new Date(data?.akhirVote as any)}
|
||||
onChange={(date: any) => {
|
||||
setData({ ...data, akhirVote: date });
|
||||
}}
|
||||
/>
|
||||
|
||||
{validateDateRange({
|
||||
selectedStratDate: data?.awalVote as any,
|
||||
selectedEndDate: data?.akhirVote as any,
|
||||
}).isValid ? (
|
||||
<TextCustom style={{ color: "green" }}>
|
||||
{
|
||||
validateDateRange({
|
||||
selectedStratDate: data?.awalVote as any,
|
||||
selectedEndDate: data?.akhirVote as any,
|
||||
}).error
|
||||
}
|
||||
</TextCustom>
|
||||
) : (
|
||||
<TextCustom style={{ color: "red" }}>
|
||||
{
|
||||
validateDateRange({
|
||||
selectedStratDate: data?.awalVote as any,
|
||||
selectedEndDate: data?.akhirVote as any,
|
||||
}).error
|
||||
}
|
||||
</TextCustom>
|
||||
)}
|
||||
<Spacing />
|
||||
</StackCustom>
|
||||
|
||||
{data?.Voting_DaftarNamaVote?.map((item: any, index: number) => (
|
||||
<TextInputCustom
|
||||
key={index}
|
||||
label="Pilihan"
|
||||
placeholder="Masukan Pilihan"
|
||||
required
|
||||
value={item.value}
|
||||
onChangeText={(value: any) =>
|
||||
setData({
|
||||
...(data as any),
|
||||
Voting_DaftarNamaVote: data?.Voting_DaftarNamaVote?.map(
|
||||
(item: any, i: any) =>
|
||||
i === index ? { ...item, value } : item
|
||||
),
|
||||
})
|
||||
}
|
||||
/>
|
||||
</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>
|
||||
<CenterCustom>
|
||||
<View
|
||||
style={{ flexDirection: "row", alignItems: "center", gap: 10 }}
|
||||
>
|
||||
<ActionIcon
|
||||
disabled={(data as any)?.Voting_DaftarNamaVote?.length >= 4}
|
||||
onPress={() => {
|
||||
setData({
|
||||
...(data as any),
|
||||
Voting_DaftarNamaVote: [
|
||||
...(data as any)?.Voting_DaftarNamaVote,
|
||||
{ value: "" },
|
||||
],
|
||||
});
|
||||
}}
|
||||
icon={
|
||||
<Ionicons
|
||||
name="add-circle-outline"
|
||||
size={ICON_SIZE_XLARGE}
|
||||
color={MainColor.black}
|
||||
/>
|
||||
}
|
||||
size="xl"
|
||||
/>
|
||||
<ActionIcon
|
||||
disabled={
|
||||
((data as any)?.Voting_DaftarNamaVote?.length as any) <= 2
|
||||
}
|
||||
onPress={() => {
|
||||
const list = _.clone((data as any)?.Voting_DaftarNamaVote);
|
||||
list.pop();
|
||||
setData({
|
||||
...(data as any),
|
||||
Voting_DaftarNamaVote: list,
|
||||
});
|
||||
}}
|
||||
icon={
|
||||
<Ionicons
|
||||
name="remove-circle-outline"
|
||||
size={ICON_SIZE_XLARGE}
|
||||
color={MainColor.black}
|
||||
/>
|
||||
}
|
||||
size="xl"
|
||||
/>
|
||||
</View>
|
||||
</CenterCustom>
|
||||
<Spacing />
|
||||
</StackCustom>
|
||||
)}
|
||||
</ViewWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import {
|
||||
AlertDefaultSystem,
|
||||
AvatarUsernameAndOtherComponent,
|
||||
@@ -5,20 +6,90 @@ import {
|
||||
DotButton,
|
||||
DrawerCustom,
|
||||
InformationBox,
|
||||
LoaderCustom,
|
||||
MenuDrawerDynamicGrid,
|
||||
StackCustom,
|
||||
TextCustom,
|
||||
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";
|
||||
import {
|
||||
apiVotingCheckContribution,
|
||||
apiVotingGetOne,
|
||||
} from "@/service/api-client/api-voting";
|
||||
import {
|
||||
router,
|
||||
Stack,
|
||||
useFocusEffect,
|
||||
useLocalSearchParams,
|
||||
} from "expo-router";
|
||||
import React, { useCallback, useState } from "react";
|
||||
import { useAuth } from "@/hooks/use-auth";
|
||||
|
||||
export default function VotingDetail() {
|
||||
const { id } = useLocalSearchParams();
|
||||
const { user } = useAuth();
|
||||
console.log("[ID]", id);
|
||||
const dateNow = new Date();
|
||||
console.log("[DATE NOW]", dateNow);
|
||||
|
||||
const [openDrawerPublish, setOpenDrawerPublish] = useState(false);
|
||||
const [data, setData] = useState<any>(null);
|
||||
const [loadingGetData, setLoadingGetData] = useState(false);
|
||||
const [isContribution, setIsContribution] = useState(false);
|
||||
const [nameChoice, setNameChoice] = useState("");
|
||||
|
||||
console.log("[DATA AWAL]", data?.awalVote);
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
handlerLoadData();
|
||||
}, [id, user?.id])
|
||||
);
|
||||
|
||||
async function handlerLoadData() {
|
||||
try {
|
||||
setLoadingGetData(true);
|
||||
await onLoadData();
|
||||
await onLoadCheckContribution();
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
} finally {
|
||||
setLoadingGetData(false);
|
||||
}
|
||||
}
|
||||
|
||||
const onLoadData = async () => {
|
||||
try {
|
||||
const response = await apiVotingGetOne({ id: id as string });
|
||||
// console.log("[DATA]", JSON.stringify(response.data, null, 2));
|
||||
if (response.success) {
|
||||
setData(response.data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
}
|
||||
};
|
||||
|
||||
const onLoadCheckContribution = async () => {
|
||||
try {
|
||||
const response = await apiVotingCheckContribution({
|
||||
id: id as string,
|
||||
authorId: user?.id as string,
|
||||
});
|
||||
console.log("[DATA CONTRIBUION]", response.data);
|
||||
if (response.success) {
|
||||
setIsContribution(response.data.isContribution);
|
||||
setNameChoice(response.data.nameChoice);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
}
|
||||
};
|
||||
|
||||
const handlePressPublish = (item: IMenuDrawerItem) => {
|
||||
if (item.path === "") {
|
||||
AlertDefaultSystem({
|
||||
@@ -49,15 +120,32 @@ export default function VotingDetail() {
|
||||
/>
|
||||
|
||||
<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." />
|
||||
{loadingGetData ? (
|
||||
<LoaderCustom />
|
||||
) : (
|
||||
<StackCustom gap={"xs"}>
|
||||
{dateNow < new Date(data?.awalVote) && (
|
||||
<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
|
||||
data={data}
|
||||
userId={user?.id as string}
|
||||
isContribution={isContribution}
|
||||
nameChoice={nameChoice}
|
||||
headerAvatar={
|
||||
<AvatarUsernameAndOtherComponent
|
||||
avatar={data?.Author?.Profile?.imageId || ""}
|
||||
name={data?.Author?.username || "Username"}
|
||||
avatarHref={`/profile/${data?.Author?.Profile?.id}`}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<Voting_BoxDetailPublishSection
|
||||
headerAvatar={<AvatarUsernameAndOtherComponent />}
|
||||
/>
|
||||
|
||||
<Voting_BoxDetailHasilVotingSection />
|
||||
</StackCustom>
|
||||
<Voting_BoxDetailHasilVotingSection
|
||||
listData={data?.Voting_DaftarNamaVote}
|
||||
/>
|
||||
</StackCustom>
|
||||
)}
|
||||
</ViewWrapper>
|
||||
|
||||
{/* ========= Publish Drawer ========= */}
|
||||
|
||||
@@ -142,26 +142,6 @@ export default function VotingCreate() {
|
||||
}
|
||||
/>
|
||||
|
||||
{/* <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> */}
|
||||
|
||||
{listVote.map((item, index) => (
|
||||
<TextInputCustom
|
||||
|
||||
@@ -6,7 +6,11 @@ import {
|
||||
CircleContainer,
|
||||
} from "@/components";
|
||||
|
||||
export default function Voting_BoxDetailHasilVotingSection() {
|
||||
export default function Voting_BoxDetailHasilVotingSection({
|
||||
listData,
|
||||
}: {
|
||||
listData?: any[];
|
||||
}) {
|
||||
return (
|
||||
<>
|
||||
<BaseBox>
|
||||
@@ -16,10 +20,12 @@ export default function Voting_BoxDetailHasilVotingSection() {
|
||||
</TextCustom>
|
||||
|
||||
<Grid>
|
||||
{Array.from({ length: 4 }).map((_, i) => (
|
||||
<Grid.Col span={3} style={{ alignItems: "center" }} key={i}>
|
||||
<CircleContainer value={9 % (i + 4)} />
|
||||
<TextCustom size="small">Pilihan {i + 1}</TextCustom>
|
||||
{listData?.map((item: any, i: number) => (
|
||||
<Grid.Col span={12 / listData?.length} style={{ alignItems: "center" }} key={i}>
|
||||
<StackCustom>
|
||||
<CircleContainer value={item?.jumlah} />
|
||||
<TextCustom align="center" size="small">{item?.value}</TextCustom>
|
||||
</StackCustom>
|
||||
</Grid.Col>
|
||||
))}
|
||||
</Grid>
|
||||
|
||||
@@ -1,45 +1,95 @@
|
||||
import {
|
||||
BadgeCustom,
|
||||
BoxWithHeaderSection,
|
||||
ButtonCustom,
|
||||
CenterCustom,
|
||||
Spacing,
|
||||
StackCustom,
|
||||
TextCustom
|
||||
TextCustom,
|
||||
} from "@/components";
|
||||
import { RadioCustom, RadioGroup } from "@/components/Radio/RadioCustom";
|
||||
import { useState } from "react";
|
||||
import { View } from "react-native";
|
||||
import { Voting_ComponentDetailDataSection } from "./ComponentDetailDataSection";
|
||||
import { apiVotingVote } from "@/service/api-client/api-voting";
|
||||
import { useAuth } from "@/hooks/use-auth";
|
||||
|
||||
export function Voting_BoxDetailPublishSection({
|
||||
headerAvatar,
|
||||
data,
|
||||
userId,
|
||||
isContribution,
|
||||
nameChoice,
|
||||
}: {
|
||||
headerAvatar?: React.ReactNode;
|
||||
data?: any;
|
||||
userId: string;
|
||||
isContribution?: boolean;
|
||||
nameChoice?: string;
|
||||
}) {
|
||||
const [value, setValue] = useState<any | number>("");
|
||||
|
||||
const handlerSubmitVote = async () => {
|
||||
const newData = {
|
||||
chooseId: value,
|
||||
userId: userId,
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await apiVotingVote({
|
||||
id: data?.id,
|
||||
data: newData,
|
||||
});
|
||||
console.log("[RES VOTE]", response);
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<BoxWithHeaderSection>
|
||||
{headerAvatar ? headerAvatar : <Spacing />}
|
||||
{headerAvatar && (
|
||||
<>
|
||||
{headerAvatar}
|
||||
<Spacing />
|
||||
</>
|
||||
)}
|
||||
|
||||
<StackCustom gap={"lg"}>
|
||||
<Voting_ComponentDetailDataSection />
|
||||
<Voting_ComponentDetailDataSection data={data} />
|
||||
|
||||
<View>
|
||||
<TextCustom bold size="small">
|
||||
Pilihan :
|
||||
</TextCustom>
|
||||
<RadioGroup value={value} onChange={setValue}>
|
||||
{Array.from({ length: 4 }).map((_, i) => (
|
||||
<View key={i}>
|
||||
<RadioCustom
|
||||
label={`Pilihan ${i + 1}`}
|
||||
value={`Pilihan ${i + 1}`}
|
||||
/>
|
||||
</View>
|
||||
))}
|
||||
</RadioGroup>
|
||||
</View>
|
||||
{isContribution ? (
|
||||
<StackCustom gap={"sm"}>
|
||||
<TextCustom align="center" size="small" bold>
|
||||
Pilihan Anda :
|
||||
</TextCustom>
|
||||
<View style={{ alignSelf: "center" }}>
|
||||
<BadgeCustom variant="light" size="lg">
|
||||
{nameChoice || "-"}
|
||||
</BadgeCustom>
|
||||
</View>
|
||||
</StackCustom>
|
||||
) : (
|
||||
<>
|
||||
<StackCustom>
|
||||
<TextCustom bold size="small">
|
||||
Pilihan :
|
||||
</TextCustom>
|
||||
<RadioGroup value={value} onChange={setValue}>
|
||||
{data?.Voting_DaftarNamaVote?.map((item: any, i: number) => (
|
||||
<View key={i}>
|
||||
<RadioCustom label={item?.value} value={item?.id} />
|
||||
</View>
|
||||
))}
|
||||
</RadioGroup>
|
||||
</StackCustom>
|
||||
|
||||
<ButtonCustom onPress={() => console.log("vote")}>Vote</ButtonCustom>
|
||||
<ButtonCustom disabled={value === ""} onPress={handlerSubmitVote}>
|
||||
Vote
|
||||
</ButtonCustom>
|
||||
</>
|
||||
)}
|
||||
</StackCustom>
|
||||
</BoxWithHeaderSection>
|
||||
</>
|
||||
|
||||
@@ -15,37 +15,43 @@ export default function Voting_BoxPublishSection({
|
||||
href,
|
||||
id,
|
||||
bottomComponent,
|
||||
data,
|
||||
}: {
|
||||
href?: Href
|
||||
id?: string
|
||||
href?: Href;
|
||||
id?: string;
|
||||
bottomComponent?: React.ReactNode;
|
||||
data?: any;
|
||||
}) {
|
||||
return (
|
||||
<>
|
||||
<BoxWithHeaderSection href={href}>
|
||||
<AvatarUsernameAndOtherComponent avatarHref="/profile/1" />
|
||||
<Spacing />
|
||||
<StackCustom>
|
||||
<AvatarUsernameAndOtherComponent
|
||||
avatar={data?.Author?.Profile?.imageId || ""}
|
||||
name={data?.Author?.username || "Username"}
|
||||
avatarHref="/profile/1"
|
||||
/>
|
||||
<Spacing height={0} />
|
||||
<StackCustom gap={"lg"}>
|
||||
<TextCustom align="center" bold truncate size="large">
|
||||
Voting Title {id}
|
||||
{data?.title || "-"}
|
||||
</TextCustom>
|
||||
|
||||
<BadgeCustom
|
||||
style={{ width: "70%", alignSelf: "center" }}
|
||||
variant="light"
|
||||
>
|
||||
{dayjs().format("DD/MM/YYYY")} -{" "}
|
||||
{dayjs().add(1, "day").format("DD/MM/YYYY")}
|
||||
{dayjs(data?.awalVote).format("DD/MM/YYYY")} -{" "}
|
||||
{dayjs(data?.akhirVote).format("DD/MM/YYYY")}
|
||||
</BadgeCustom>
|
||||
|
||||
<Grid>
|
||||
{/* <Grid>
|
||||
{Array.from({ length: 4 }).map((_, i) => (
|
||||
<Grid.Col span={3} style={{ alignItems: "center" }} key={i}>
|
||||
<CircleContainer value={9 % (i + 4)} />
|
||||
<TextCustom size="small">Pilihan {i + 1}</TextCustom>
|
||||
</Grid.Col>
|
||||
))}
|
||||
</Grid>
|
||||
</Grid> */}
|
||||
{bottomComponent}
|
||||
</StackCustom>
|
||||
</BoxWithHeaderSection>
|
||||
|
||||
@@ -1,14 +1,21 @@
|
||||
import { AlertDefaultSystem, ButtonCustom, Grid } from "@/components";
|
||||
import { apiVotingUpdateStatus } from "@/service/api-client/api-voting";
|
||||
import {
|
||||
apiVotingDelete,
|
||||
apiVotingUpdateStatus,
|
||||
} from "@/service/api-client/api-voting";
|
||||
import { router } from "expo-router";
|
||||
import { View } from "react-native";
|
||||
import Toast from "react-native-toast-message";
|
||||
|
||||
export default function Voting_ButtonStatusSection({
|
||||
id,
|
||||
status,
|
||||
isLoading,
|
||||
onSetLoading,
|
||||
}: {
|
||||
id: string;
|
||||
status: string;
|
||||
isLoading: boolean;
|
||||
onSetLoading: (value: boolean) => void;
|
||||
}) {
|
||||
const handleBatalkanReview = () => {
|
||||
AlertDefaultSystem({
|
||||
@@ -16,15 +23,33 @@ export default function Voting_ButtonStatusSection({
|
||||
message: "Apakah Anda yakin ingin batalkan review ini?",
|
||||
textLeft: "Batal",
|
||||
textRight: "Ya",
|
||||
onPressRight: async() => {
|
||||
// console.log("Hapus");
|
||||
// router.back();
|
||||
const response = await apiVotingUpdateStatus({
|
||||
id: id as string,
|
||||
status: "draft",
|
||||
})
|
||||
console.log("[RES BATALKAN REVIEW]", JSON.stringify(response, null, 2));
|
||||
// router.back();
|
||||
onPressRight: async () => {
|
||||
try {
|
||||
onSetLoading(true);
|
||||
const response = await apiVotingUpdateStatus({
|
||||
id: id as string,
|
||||
status: "draft",
|
||||
});
|
||||
|
||||
if (response?.success) {
|
||||
Toast.show({
|
||||
type: "success",
|
||||
text1: response.message,
|
||||
});
|
||||
router.back();
|
||||
} else {
|
||||
Toast.show({
|
||||
type: "info",
|
||||
text1: "Info",
|
||||
text2: response.message,
|
||||
});
|
||||
router.back();
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
} finally {
|
||||
onSetLoading(false);
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -35,9 +60,33 @@ export default function Voting_ButtonStatusSection({
|
||||
message: "Apakah Anda yakin ingin ajukan review ini?",
|
||||
textLeft: "Batal",
|
||||
textRight: "Ya",
|
||||
onPressRight: () => {
|
||||
console.log("Hapus");
|
||||
router.back();
|
||||
onPressRight: async () => {
|
||||
try {
|
||||
onSetLoading(true);
|
||||
const response = await apiVotingUpdateStatus({
|
||||
id: id as string,
|
||||
status: "review",
|
||||
});
|
||||
|
||||
if (response?.success) {
|
||||
Toast.show({
|
||||
type: "success",
|
||||
text1: response.message,
|
||||
});
|
||||
router.back();
|
||||
} else {
|
||||
Toast.show({
|
||||
type: "info",
|
||||
text1: "Info",
|
||||
text2: response.message,
|
||||
});
|
||||
router.back();
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
} finally {
|
||||
onSetLoading(false);
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -48,9 +97,33 @@ export default function Voting_ButtonStatusSection({
|
||||
message: "Apakah Anda yakin ingin edit kembali ini?",
|
||||
textLeft: "Batal",
|
||||
textRight: "Ya",
|
||||
onPressRight: () => {
|
||||
console.log("Hapus");
|
||||
router.back();
|
||||
onPressRight: async () => {
|
||||
try {
|
||||
onSetLoading(true);
|
||||
const response = await apiVotingUpdateStatus({
|
||||
id: id as string,
|
||||
status: "draft",
|
||||
});
|
||||
|
||||
if (response?.success) {
|
||||
Toast.show({
|
||||
type: "success",
|
||||
text1: response.message,
|
||||
});
|
||||
router.back();
|
||||
} else {
|
||||
Toast.show({
|
||||
type: "info",
|
||||
text1: "Info",
|
||||
text2: response.message,
|
||||
});
|
||||
router.back();
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
} finally {
|
||||
onSetLoading(false);
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -61,9 +134,32 @@ export default function Voting_ButtonStatusSection({
|
||||
message: "Apakah Anda yakin ingin menghapus data ini?",
|
||||
textLeft: "Batal",
|
||||
textRight: "Hapus",
|
||||
onPressRight: () => {
|
||||
console.log("Hapus");
|
||||
router.back();
|
||||
onPressRight: async () => {
|
||||
try {
|
||||
onSetLoading(true);
|
||||
const response = await apiVotingDelete({
|
||||
id: id as string,
|
||||
});
|
||||
|
||||
if (response?.success) {
|
||||
Toast.show({
|
||||
type: "success",
|
||||
text1: response.message,
|
||||
});
|
||||
router.back();
|
||||
} else {
|
||||
Toast.show({
|
||||
type: "info",
|
||||
text1: "Info",
|
||||
text2: response.message,
|
||||
});
|
||||
router.back();
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
} finally {
|
||||
onSetLoading(false);
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -72,6 +168,7 @@ export default function Voting_ButtonStatusSection({
|
||||
return (
|
||||
<>
|
||||
<ButtonCustom
|
||||
isLoading={isLoading}
|
||||
backgroundColor="red"
|
||||
textColor="white"
|
||||
onPress={handleOpenDeleteAlert}
|
||||
@@ -88,7 +185,7 @@ export default function Voting_ButtonStatusSection({
|
||||
|
||||
case "review":
|
||||
return (
|
||||
<ButtonCustom onPress={handleBatalkanReview}>
|
||||
<ButtonCustom isLoading={isLoading} onPress={handleBatalkanReview}>
|
||||
Batalkan Review
|
||||
</ButtonCustom>
|
||||
);
|
||||
@@ -97,15 +194,14 @@ export default function Voting_ButtonStatusSection({
|
||||
return (
|
||||
<>
|
||||
<Grid>
|
||||
<Grid.Col span={5}>
|
||||
<ButtonCustom onPress={handleAjukanReview}>
|
||||
<Grid.Col span={6} style={{ paddingRight: 10 }}>
|
||||
<ButtonCustom isLoading={isLoading} onPress={handleAjukanReview}>
|
||||
Ajukan Review
|
||||
</ButtonCustom>
|
||||
</Grid.Col>
|
||||
<Grid.Col span={2}>
|
||||
<View />
|
||||
<Grid.Col span={6} style={{ paddingRight: 10 }}>
|
||||
{DeleteButton()}
|
||||
</Grid.Col>
|
||||
<Grid.Col span={5}>{DeleteButton()}</Grid.Col>
|
||||
</Grid>
|
||||
</>
|
||||
);
|
||||
@@ -114,15 +210,14 @@ export default function Voting_ButtonStatusSection({
|
||||
return (
|
||||
<>
|
||||
<Grid>
|
||||
<Grid.Col span={5}>
|
||||
<ButtonCustom onPress={handleEditKembali}>
|
||||
<Grid.Col span={6} style={{ paddingRight: 10 }}>
|
||||
<ButtonCustom isLoading={isLoading} onPress={handleEditKembali}>
|
||||
Edit Kembali
|
||||
</ButtonCustom>
|
||||
</Grid.Col>
|
||||
<Grid.Col span={2}>
|
||||
<View />
|
||||
<Grid.Col span={6} style={{ paddingLeft: 10 }}>
|
||||
{DeleteButton()}
|
||||
</Grid.Col>
|
||||
<Grid.Col span={5}>{DeleteButton()}</Grid.Col>
|
||||
</Grid>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import { BadgeCustom, StackCustom, TextCustom } from "@/components";
|
||||
import { GStyles } from "@/styles/global-styles";
|
||||
import { dateTimeView } from "@/utils/dateTimeView";
|
||||
import dayjs from "dayjs";
|
||||
import { View } from "react-native";
|
||||
|
||||
export function Voting_ComponentDetailDataSection({ data }: { data?: any }) {
|
||||
return (
|
||||
|
||||
@@ -35,7 +35,6 @@ export async function apiVotingGetOne({ id }: { id: string }) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export async function apiVotingUpdateStatus({
|
||||
id,
|
||||
status,
|
||||
@@ -50,3 +49,68 @@ export async function apiVotingUpdateStatus({
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
export async function apiVotingDelete({ id }: { id: string }) {
|
||||
try {
|
||||
const response = await apiConfig.delete(`/mobile/voting/${id}`);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
export async function apiVotingUpdateData({
|
||||
id,
|
||||
data,
|
||||
}: {
|
||||
id: string;
|
||||
data: any;
|
||||
}) {
|
||||
try {
|
||||
const response = await apiConfig.put(`/mobile/voting/${id}`, {
|
||||
data: data,
|
||||
});
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
export async function apiVotingGetAll({ search }: { search: string }) {
|
||||
try {
|
||||
const searchQuery = search ? `?search=${search}` : "";
|
||||
const response = await apiConfig.get(`/mobile/voting${searchQuery}`);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
export async function apiVotingVote({ id, data }: { id: string; data: any }) {
|
||||
try {
|
||||
const response = await apiConfig.post(`/mobile/voting/${id}`, {
|
||||
data: data,
|
||||
});
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
export async function apiVotingCheckContribution({
|
||||
id,
|
||||
authorId,
|
||||
}: {
|
||||
id: string;
|
||||
authorId: string;
|
||||
}) {
|
||||
try {
|
||||
const response = await apiConfig.get(
|
||||
`/mobile/voting/${id}/contribution?authorId=${authorId}`
|
||||
);
|
||||
console.log("[DATA CONTRIBUION]", response.data);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user