Compare commits

...

1 Commits

Author SHA1 Message Date
5d4328a139 Integrasi API: Donation Admin
Add:
-  screens/Admin/Donation/funDonationUpdateStatus.ts
-  utils/countDownAndCondition.ts

Fix:
- app/(application)/(user)/donation/[id]/index.tsx
- app/(application)/admin/donation/[id]/[status]/index.tsx
- app/(application)/admin/donation/[id]/list-of-donatur.tsx
- app/(application)/admin/donation/[id]/reject-input.tsx
- app/(application)/admin/donation/index.tsx
- app/(application)/admin/event/[id]/[status]/index.tsx
- app/(application)/admin/voting/[id]/[status]/index.tsx
- screens/Admin/Donation/BoxOfDonationStory.tsx
- screens/Donation/BoxPublish.tsx
- screens/Donation/ComponentBoxDetailData.tsx
- service/api-admin/api-admin-donation.ts
- service/api-client/api-master.ts
- utils/colorBadge.ts
git add . && git commit -m
2025-10-28 10:19:47 +08:00
15 changed files with 487 additions and 132 deletions

View File

@@ -16,20 +16,19 @@ import Donation_ComponentInfoFundrising from "@/screens/Donation/ComponentInfoFu
import Donation_ComponentStoryFunrising from "@/screens/Donation/ComponentStoryFunrising"; import Donation_ComponentStoryFunrising from "@/screens/Donation/ComponentStoryFunrising";
import Donation_ProgressSection from "@/screens/Donation/ProgressSection"; import Donation_ProgressSection from "@/screens/Donation/ProgressSection";
import { apiDonationGetOne } from "@/service/api-client/api-donation"; import { apiDonationGetOne } from "@/service/api-client/api-donation";
import { countDownAndCondition } from "@/utils/countDownAndCondition";
import { import {
router, router,
Stack, Stack,
useFocusEffect, useFocusEffect,
useLocalSearchParams, useLocalSearchParams,
} from "expo-router"; } from "expo-router";
import { useCallback, useState } from "react"; import { useCallback, useEffect, useState } from "react";
export default function DonasiDetailBeranda() { export default function DonasiDetailBeranda() {
const { user } = useAuth(); const { user } = useAuth();
const { id } = useLocalSearchParams(); const { id } = useLocalSearchParams();
console.log("ID ", id);
const [openDrawer, setOpenDrawer] = useState(false); const [openDrawer, setOpenDrawer] = useState(false);
const [data, setData] = useState<any>(); const [data, setData] = useState<any>();
useFocusEffect( useFocusEffect(
@@ -45,21 +44,41 @@ export default function DonasiDetailBeranda() {
category: "permanent", category: "permanent",
}); });
console.log("[RES GET ONE]", JSON.stringify(response.data, null, 2));
setData(response.data); setData(response.data);
} catch (error) { } catch (error) {
console.log("[ERROR]", error); console.log("[ERROR]", error);
} }
}; };
const [value, setValue] = useState({
sisa: 0,
reminder: false,
});
useEffect(() => {
updateCountDown();
}, [data]);
const updateCountDown = () => {
const countDown = countDownAndCondition({
duration: data?.DonasiMaster_Durasi?.name,
publishTime: data?.publishTime,
});
setValue({
sisa: countDown.durationDay,
reminder: countDown.reminder,
});
};
const buttonSection = ( const buttonSection = (
<> <>
<BoxButtonOnFooter> <BoxButtonOnFooter>
<ButtonCustom <ButtonCustom
disabled={value?.reminder}
onPress={() => router.navigate(`/donation/${id}/(transaction-flow)`)} onPress={() => router.navigate(`/donation/${id}/(transaction-flow)`)}
> >
Donasi {value?.reminder ? "Waktu berakhir" : "Donasi"}
</ButtonCustom> </ButtonCustom>
</BoxButtonOnFooter> </BoxButtonOnFooter>
</> </>
@@ -80,6 +99,8 @@ export default function DonasiDetailBeranda() {
<ViewWrapper footerComponent={buttonSection}> <ViewWrapper footerComponent={buttonSection}>
<StackCustom> <StackCustom>
<Donation_ComponentBoxDetailData <Donation_ComponentBoxDetailData
sisaHari={value.sisa}
reminder={value.reminder}
data={data} data={data}
bottomSection={<Donation_ProgressSection id={id as string} />} bottomSection={<Donation_ProgressSection id={id as string} />}
/> />

View File

@@ -1,3 +1,4 @@
/* eslint-disable react-hooks/exhaustive-deps */
import { import {
ActionIcon, ActionIcon,
AlertDefaultSystem, AlertDefaultSystem,
@@ -18,97 +19,147 @@ import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButt
import AdminButtonReject from "@/components/_ShareComponent/Admin/ButtonReject"; import AdminButtonReject from "@/components/_ShareComponent/Admin/ButtonReject";
import AdminButtonReview from "@/components/_ShareComponent/Admin/ButtonReview"; import AdminButtonReview from "@/components/_ShareComponent/Admin/ButtonReview";
import { GridDetail_4_8 } from "@/components/_ShareComponent/GridDetail_4_8"; import { GridDetail_4_8 } from "@/components/_ShareComponent/GridDetail_4_8";
import { MainColor } from "@/constants/color-palet"; import ReportBox from "@/components/Box/ReportBox";
import { ICON_SIZE_BUTTON, TEXT_SIZE_LARGE } from "@/constants/constans-value"; import { ICON_SIZE_BUTTON, TEXT_SIZE_LARGE } from "@/constants/constans-value";
import AdminDonation_BoxOfDonationStory from "@/screens/Admin/Donation/BoxOfDonationStory"; import AdminDonation_BoxOfDonationStory from "@/screens/Admin/Donation/BoxOfDonationStory";
import { funUpdateStatusDonation } from "@/screens/Admin/Donation/funDonationUpdateStatus";
import { apiAdminDonationDetailById } from "@/service/api-admin/api-admin-donation";
import { colorBadgeStatus } from "@/utils/colorBadge";
import { formatCurrencyDisplay } from "@/utils/formatCurrencyDisplay";
import { Ionicons } from "@expo/vector-icons"; import { Ionicons } from "@expo/vector-icons";
import { router, useLocalSearchParams } from "expo-router"; import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
import _ from "lodash"; import _ from "lodash";
import React from "react"; import React from "react";
import { View } from "react-native"; import { View } from "react-native";
import Toast from "react-native-toast-message";
export default function AdminDonationDetail() { export default function AdminDonationDetail() {
const { id, status } = useLocalSearchParams(); const { id, status } = useLocalSearchParams();
const [openDrawer, setOpenDrawer] = React.useState(false); const [openDrawer, setOpenDrawer] = React.useState(false);
const colorBadge = () => { const [data, setData] = React.useState<any | null>(null);
if (status === "publish") { const [isLoading, setIsLoading] = React.useState(false);
return MainColor.green;
} else if (status === "review") { useFocusEffect(
return MainColor.orange; React.useCallback(() => {
} else if (status === "reject") { onLoadData();
return MainColor.red; }, [id])
} else { );
return MainColor.placeholder;
const onLoadData = async () => {
try {
const response = await apiAdminDonationDetailById({
id: id as string,
});
console.log("[RES GET BY ID]", JSON.stringify(response, null, 2));
if (response.success) {
setData(response.data);
}
} catch (error) {
console.log("[ERROR]", error);
setData(null);
} }
}; };
const listData = [ const listData = [
{ {
label: "Penggalang Dana", label: "Penggalang Dana",
value: `Bagas Banuna ${id}`, value: (data && data?.Author?.username) || "-",
}, },
{ {
label: "Judul", label: "Judul",
value: `Donasi Lorem ipsum dolor sit amet, consectetur adipisicing elit.`, value: (data && data?.title) || "-",
}, },
{ {
label: "Status", label: "Status",
value: ( value:
<BadgeCustom color={colorBadge()}> data && data?.DonasiMaster_Status?.name ? (
{_.startCase(status as string)} <BadgeCustom
</BadgeCustom> color={colorBadgeStatus({ status: data?.DonasiMaster_Status?.name })}
), >
{_.startCase(data?.DonasiMaster_Status?.name)}
</BadgeCustom>
) : (
"-"
),
}, },
{ {
label: "Durasi", label: "Durasi",
value: "30 Hari", value: (data && data?.DonasiMaster_Durasi?.name) + " hari" || "-",
}, },
{ {
label: "Target Dana", label: "Target Dana",
value: "Rp 10.000.000", value:
data && data?.target
? `Rp. ${formatCurrencyDisplay(data?.target)}`
: "-",
}, },
{ {
label: "Kategori", label: "Kategori",
value: "Kategori Donasi", value: (data && data?.DonasiMaster_Ketegori?.name) || "-",
}, },
// {
// label: "Total Donatur",
// value: "-",
// },
// {
// label: "Progress",
// value: "0 %",
// },
// {
// label: "Dana Terkumpul",
// value: "Rp 0",
// },
]; ];
const listPencarianDana = [ const listPencarianDana = [
{ {
label: "Total Dana Dicairkan", label: "Total Dana Dicairkan",
value: "Rp 0", value: `Rp ${(data && data?.totalPencairan) || 0}`,
}, },
{ {
label: "Sisa Dana", label: "Sisa Dana",
value: "Rp 0", value: `Rp ${(data && data?.terkumpul - data?.totalPencairan) || 0}`,
}, },
{ {
label: "Akumulasi Pencairan", label: "Akumulasi Pencairan",
value: "0 kali", value: `${(data && data?.totalPencairan) || 0} kali`,
}, },
{ {
label: "Bank Tujuan", label: "Bank Tujuan",
value: "BNI", value: (data && data?.namaBank) || "-",
}, },
{ {
label: "Nomor Rekening", label: "Nomor Rekening",
value: "123456789", value: (data && data?.rekening) || "-",
}, },
]; ];
const handleReport = async ({
changeStatus,
}: {
changeStatus: "publish" | "review" | "reject";
}) => {
try {
setIsLoading(true);
const response = await funUpdateStatusDonation({
id: id as string,
changeStatus,
data: data,
});
if (!response.success) {
Toast.show({
type: "error",
text1: "Update status gagal",
});
return;
}
Toast.show({
type: "success",
text1: "Update status berhasil",
});
router.back();
} catch (error) {
console.log("[ERROR]", error);
} finally {
setIsLoading(false);
}
};
const rightComponent = ( const rightComponent = (
<ActionIcon <ActionIcon
icon={<IconDot size={ICON_SIZE_BUTTON} />} icon={<IconDot size={ICON_SIZE_BUTTON} />}
@@ -118,8 +169,6 @@ export default function AdminDonationDetail() {
/> />
); );
return ( return (
<> <>
<ViewWrapper <ViewWrapper
@@ -147,6 +196,7 @@ export default function AdminDonationDetail() {
/> />
))} ))}
</StackCustom> </StackCustom>
<ButtonCustom <ButtonCustom
iconLeft={ iconLeft={
<Ionicons name="cash-outline" size={ICON_SIZE_BUTTON} /> <Ionicons name="cash-outline" size={ICON_SIZE_BUTTON} />
@@ -179,7 +229,7 @@ export default function AdminDonationDetail() {
<BaseBox> <BaseBox>
<StackCustom> <StackCustom>
<DummyLandscapeImage /> <DummyLandscapeImage imageId={data?.imageId || ""} />
{listData.map((item, i) => ( {listData.map((item, i) => (
<GridDetail_4_8 <GridDetail_4_8
key={i} key={i}
@@ -190,27 +240,33 @@ export default function AdminDonationDetail() {
</StackCustom> </StackCustom>
</BaseBox> </BaseBox>
<AdminDonation_BoxOfDonationStory data={data?.CeritaDonasi as any} />
{data &&
data?.catatan &&
(status === "review" || status === "reject") && (
<ReportBox text={data?.catatan} />
)}
{status === "review" && ( {status === "review" && (
<StackCustom> <StackCustom>
<AdminDonation_BoxOfDonationStory />
<AdminButtonReview <AdminButtonReview
isLoading={isLoading}
onPublish={() => { onPublish={() => {
AlertDefaultSystem({ AlertDefaultSystem({
title: "Publish", title: "Publish",
message: "Apakah anda yakin ingin mempublikasikan data ini?", message: "Apakah anda yakin ingin mempublikasikan data ini?",
textLeft: "Batal", textLeft: "Batal",
textRight: "Ya", textRight: "Ya",
onPressLeft: () => {
router.back();
},
onPressRight: () => { onPressRight: () => {
router.back(); handleReport({ changeStatus: "publish" });
}, },
}); });
}} }}
onReject={() => { onReject={() => {
router.push(`/admin/donation/${id}/reject-input`); router.push(
`/admin/donation/${id}/reject-input?status=${status}`
);
}} }}
/> />
</StackCustom> </StackCustom>
@@ -218,12 +274,12 @@ export default function AdminDonationDetail() {
{status === "reject" && ( {status === "reject" && (
<StackCustom> <StackCustom>
<AdminDonation_BoxOfDonationStory />
<AdminButtonReject <AdminButtonReject
title="Tambah Catatan" title="Tambah Catatan"
onReject={() => { onReject={() => {
router.push(`/admin/donation/${id}/reject-input`); router.push(
`/admin/donation/${id}/reject-input?status=${status}`
);
}} }}
/> />
</StackCustom> </StackCustom>

View File

@@ -1,3 +1,4 @@
/* eslint-disable react-hooks/exhaustive-deps */
import { import {
ActionIcon, ActionIcon,
BadgeCustom, BadgeCustom,
@@ -10,22 +11,86 @@ import {
import { IconView } from "@/components/_Icon/IconComponent"; import { IconView } from "@/components/_Icon/IconComponent";
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle"; import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
import { GridViewCustomSpan } from "@/components/_ShareComponent/GridViewCustomSpan"; import { GridViewCustomSpan } from "@/components/_ShareComponent/GridViewCustomSpan";
import { MainColor } from "@/constants/color-palet";
import { ICON_SIZE_BUTTON } from "@/constants/constans-value"; import { ICON_SIZE_BUTTON } from "@/constants/constans-value";
import { dummyMasterStatusTransaction } from "@/lib/dummy-data/_master/status-transaction"; import { apiAdminDonationListOfDonatur } from "@/service/api-admin/api-admin-donation";
import { router, useLocalSearchParams } from "expo-router"; import { apiMasterTransaction } from "@/service/api-client/api-master";
import React from "react"; import { colorBadgeTransaction } from "@/utils/colorBadge";
import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
import _ from "lodash";
import React, { useEffect } from "react";
import { View } from "react-native"; import { View } from "react-native";
import { Divider } from "react-native-paper"; import { Divider } from "react-native-paper";
export default function AdminDonasiListOfDonatur() { export default function AdminDonasiListOfDonatur() {
const { id } = useLocalSearchParams(); const { id } = useLocalSearchParams();
console.log("[ID >>]", id);
const [listData, setListData] = React.useState<any[] | null>(null);
const [master, setMaster] = React.useState<any[]>([]);
const [selectStatus, setSelectStatus] = React.useState<
"berhasil" | "gagal" | "proses" | "menunggu" | ""
>("");
useFocusEffect(
React.useCallback(() => {
onLoadData();
}, [id, selectStatus])
);
const onLoadData = async () => {
try {
const response = await apiAdminDonationListOfDonatur({
id: id as string,
status: "" as any,
});
console.log(
"[LIST OF DONATUR]",
JSON.stringify(response, null, 2)
);
if (response.success) {
setListData(response.data);
}
} catch (error) {
console.log("[ERROR]", error);
setListData([]);
}
};
useEffect(() => {
onLoadMaster();
}, []);
const onLoadMaster = async () => {
try {
const response = await apiMasterTransaction();
if (response.success) {
setMaster(response.data);
}
} catch (error) {
console.log("[ERROR]", error);
setMaster([]);
}
};
const searchComponent = ( const searchComponent = (
<View style={{ flexDirection: "row", gap: 5 }}> <View style={{ flexDirection: "row", gap: 5 }}>
<SelectCustom <SelectCustom
placeholder="Pilih status transaksi" placeholder="Pilih status transaksi"
data={dummyMasterStatusTransaction} data={
onChange={(value) => console.log(value)} _.isEmpty(master)
? []
: master?.map((item: any) => ({
label: item.name,
value: item.name
}))
}
onChange={(value: any) => {
console.log("[SELECT STATUS]", value);
const statusChooses = _.lowerCase(value);
setSelectStatus(statusChooses as any);
}}
styleContainer={{ width: "100%", marginBottom: 0 }} styleContainer={{ width: "100%", marginBottom: 0 }}
/> />
</View> </View>
@@ -59,7 +124,7 @@ export default function AdminDonasiListOfDonatur() {
/> />
<Divider /> <Divider />
<StackCustom> <StackCustom>
{Array.from({ length: 10 }).map((_, index) => ( {listData?.map((item: any, index: number) => (
<View key={index}> <View key={index}>
<GridViewCustomSpan <GridViewCustomSpan
span1={3} span1={3}
@@ -79,15 +144,15 @@ export default function AdminDonasiListOfDonatur() {
} }
component2={ component2={
<TextCustom bold align="center" truncate> <TextCustom bold align="center" truncate>
Bagas Banuna {item?.Author?.username || "-"}
</TextCustom> </TextCustom>
} }
component3={ component3={
<BadgeCustom <BadgeCustom
style={{ alignSelf: "center" }} style={{ alignSelf: "center" }}
color={MainColor.green} color={colorBadgeTransaction({status: item?.DonasiMaster_StatusInvoice?.name})}
> >
Berhasil {item?.DonasiMaster_StatusInvoice?.name}
</BadgeCustom> </BadgeCustom>
} }
/> />

View File

@@ -1,3 +1,4 @@
/* eslint-disable react-hooks/exhaustive-deps */
import { import {
AlertDefaultSystem, AlertDefaultSystem,
BoxButtonOnFooter, BoxButtonOnFooter,
@@ -6,15 +7,84 @@ import {
} from "@/components"; } from "@/components";
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle"; import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
import AdminButtonReject from "@/components/_ShareComponent/Admin/ButtonReject"; import AdminButtonReject from "@/components/_ShareComponent/Admin/ButtonReject";
import { router, useLocalSearchParams } from "expo-router"; import { funUpdateStatusDonation } from "@/screens/Admin/Donation/funDonationUpdateStatus";
import { useState } from "react"; import {
apiAdminDonationDetailById
} from "@/service/api-admin/api-admin-donation";
import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
import React from "react";
import Toast from "react-native-toast-message";
export default function AdminDonationRejectInput() { export default function AdminDonationRejectInput() {
const { id } = useLocalSearchParams(); const { id, status } = useLocalSearchParams();
const [value, setValue] = useState(id as string);
const [data, setData] = React.useState<any | null>(null);
const [isLoading, setIsLoading] = React.useState(false);
useFocusEffect(
React.useCallback(() => {
onLoadData();
}, [id])
);
const onLoadData = async () => {
try {
const response = await apiAdminDonationDetailById({
id: id as string,
});
if (response.success) {
setData(response.data.catatan);
}
} catch (error) {
console.log("[ERROR]", error);
setData(null);
}
};
const handleReport = async ({
changeStatus,
}: {
changeStatus: "publish" | "review" | "reject";
}) => {
try {
setIsLoading(true);
const response = await funUpdateStatusDonation({
id: id as string,
changeStatus,
data: data,
});
if (!response.success) {
Toast.show({
type: "error",
text1: "Report gagal",
});
return
}
Toast.show({
type: "success",
text1: "Report berhasil",
});
if (status === "review") {
router.replace(`/admin/donation/reject/status`);
} else if (status === "reject") {
router.back();
}
} catch (error) {
console.log("[ERROR]", error);
} finally {
setIsLoading(false);
}
};
const buttonSubmit = ( const buttonSubmit = (
<BoxButtonOnFooter> <BoxButtonOnFooter>
<AdminButtonReject <AdminButtonReject
isLoading={isLoading}
title="Reject" title="Reject"
onReject={() => onReject={() =>
AlertDefaultSystem({ AlertDefaultSystem({
@@ -22,12 +92,9 @@ export default function AdminDonationRejectInput() {
message: "Apakah anda yakin ingin menolak data ini?", message: "Apakah anda yakin ingin menolak data ini?",
textLeft: "Batal", textLeft: "Batal",
textRight: "Ya", textRight: "Ya",
onPressLeft: () => {
router.back();
},
onPressRight: () => { onPressRight: () => {
console.log("value:", value); handleReport({ changeStatus: "reject" });
router.replace(`/admin/donation/reject/status`);
}, },
}) })
} }
@@ -42,8 +109,8 @@ export default function AdminDonationRejectInput() {
headerComponent={<AdminBackButtonAntTitle title="Penolakan Donasi" />} headerComponent={<AdminBackButtonAntTitle title="Penolakan Donasi" />}
> >
<TextAreaCustom <TextAreaCustom
value={value} value={data}
onChangeText={setValue} onChangeText={setData}
placeholder="Masukan alasan" placeholder="Masukan alasan"
required required
showCount showCount

View File

@@ -14,7 +14,6 @@ import { useState, useCallback } from "react";
export default function AdminDonation() { export default function AdminDonation() {
const [data, setData] = useState<any | null>(null); const [data, setData] = useState<any | null>(null);
const [loadData, setLoadData] = useState<boolean>(false);
useFocusEffect( useFocusEffect(
useCallback(() => { useCallback(() => {
@@ -24,7 +23,7 @@ export default function AdminDonation() {
const onLoadData = async () => { const onLoadData = async () => {
try { try {
setLoadData(true);
const response = await apiAdminDonation({ const response = await apiAdminDonation({
category: "dashboard", category: "dashboard",
}); });
@@ -37,9 +36,7 @@ export default function AdminDonation() {
} catch (error) { } catch (error) {
console.log("[ERROR]", error); console.log("[ERROR]", error);
setData([]); setData([]);
} finally { }
setLoadData(false);
}
}; };
const listData = [ const listData = [

View File

@@ -1,16 +1,16 @@
/* eslint-disable react-hooks/exhaustive-deps */ /* eslint-disable react-hooks/exhaustive-deps */
import { import {
ActionIcon, ActionIcon,
AlertDefaultSystem, AlertDefaultSystem,
BadgeCustom, BadgeCustom,
BaseBox, BaseBox,
DrawerCustom, DrawerCustom,
LoaderCustom, LoaderCustom,
MenuDrawerDynamicGrid, MenuDrawerDynamicGrid,
Spacing, Spacing,
StackCustom, StackCustom,
TextCustom, TextCustom,
ViewWrapper, ViewWrapper,
} from "@/components"; } from "@/components";
import { IconDot, IconList } from "@/components/_Icon/IconComponent"; import { IconDot, IconList } from "@/components/_Icon/IconComponent";
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle"; import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
@@ -23,7 +23,7 @@ import { useAuth } from "@/hooks/use-auth";
import { funUpdateStatusEvent } from "@/screens/Admin/Event/funUpdateStatus"; import { funUpdateStatusEvent } from "@/screens/Admin/Event/funUpdateStatus";
import { apiAdminEventById } from "@/service/api-admin/api-admin-event"; import { apiAdminEventById } from "@/service/api-admin/api-admin-event";
import { DEEP_LINK_URL } from "@/service/api-config"; import { DEEP_LINK_URL } from "@/service/api-config";
import { colorBadge } from "@/utils/colorBadge"; import { colorBadgeStatus } from "@/utils/colorBadge";
import { dateTimeView } from "@/utils/dateTimeView"; import { dateTimeView } from "@/utils/dateTimeView";
import { router, useFocusEffect, useLocalSearchParams } from "expo-router"; import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
import _ from "lodash"; import _ from "lodash";
@@ -74,7 +74,7 @@ export default function AdminEventDetail() {
label: "Status", label: "Status",
value: value:
(data && ( (data && (
<BadgeCustom color={colorBadge({ status: status as string })}> <BadgeCustom color={colorBadgeStatus({ status: status as string })}>
{_.startCase(status as string)} {_.startCase(status as string)}
</BadgeCustom> </BadgeCustom>
)) || )) ||

View File

@@ -1,14 +1,14 @@
/* eslint-disable react-hooks/exhaustive-deps */ /* eslint-disable react-hooks/exhaustive-deps */
import { import {
AlertDefaultSystem, AlertDefaultSystem,
BadgeCustom, BadgeCustom,
BaseBox, BaseBox,
CircleContainer, CircleContainer,
Grid, Grid,
Spacing, Spacing,
StackCustom, StackCustom,
TextCustom, TextCustom,
ViewWrapper, ViewWrapper,
} from "@/components"; } from "@/components";
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle"; import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
import AdminButtonReject from "@/components/_ShareComponent/Admin/ButtonReject"; import AdminButtonReject from "@/components/_ShareComponent/Admin/ButtonReject";
@@ -18,7 +18,7 @@ import ReportBox from "@/components/Box/ReportBox";
import { MainColor } from "@/constants/color-palet"; import { MainColor } from "@/constants/color-palet";
import funUpdateStatusVoting from "@/screens/Admin/Voting/funUpdateStatus"; import funUpdateStatusVoting from "@/screens/Admin/Voting/funUpdateStatus";
import { apiAdminVotingById } from "@/service/api-admin/api-admin-voting"; import { apiAdminVotingById } from "@/service/api-admin/api-admin-voting";
import { colorBadge } from "@/utils/colorBadge"; import { colorBadgeStatus } from "@/utils/colorBadge";
import { dateTimeView } from "@/utils/dateTimeView"; import { dateTimeView } from "@/utils/dateTimeView";
import { Entypo } from "@expo/vector-icons"; import { Entypo } from "@expo/vector-icons";
import dayjs from "dayjs"; import dayjs from "dayjs";
@@ -68,7 +68,7 @@ export default function AdminVotingDetail() {
label: "Status", label: "Status",
value: value:
data && data?.Voting_Status?.name ? ( data && data?.Voting_Status?.name ? (
<BadgeCustom color={colorBadge({ status: status as string })}> <BadgeCustom color={colorBadgeStatus({ status: status as string })}>
{status === "history" ? "Riwayat" : _.startCase(status as string)} {status === "history" ? "Riwayat" : _.startCase(status as string)}
</BadgeCustom> </BadgeCustom>
) : ( ) : (

View File

@@ -6,7 +6,11 @@ import {
DummyLandscapeImage, DummyLandscapeImage,
} from "@/components"; } from "@/components";
export default function AdminDonation_BoxOfDonationStory() { export default function AdminDonation_BoxOfDonationStory({
data,
}: {
data: any;
}) {
return ( return (
<> <>
<BaseBox> <BaseBox>
@@ -14,19 +18,9 @@ export default function AdminDonation_BoxOfDonationStory() {
<Spacing /> <Spacing />
<StackCustom> <StackCustom>
<TextCustom> <TextCustom>{(data && data?.pembukaan) || "-"}</TextCustom>
Lorem ipsum dolor sit, amet consectetur adipisicing elit. Rem magni <DummyLandscapeImage imageId={data?.imageId || "-"} />
perspiciatis eius ipsam provident, impedit, fugiat aliquid nobis <TextCustom>{(data && data?.cerita) || "-"}</TextCustom>
pariatur asperiores fuga quidem temporibus labore, molestias
perferendis optio ipsum. Praesentium, tempore?
</TextCustom>
<DummyLandscapeImage />
<TextCustom>
Lorem ipsum dolor sit, amet consectetur adipisicing elit. Rem magni
perspiciatis eius ipsam provident, impedit, fugiat aliquid nobis
pariatur asperiores fuga quidem temporibus labore, molestias
perferendis optio ipsum. Praesentium, tempore?
</TextCustom>
</StackCustom> </StackCustom>
</BaseBox> </BaseBox>
</> </>

View File

@@ -0,0 +1,23 @@
import { apiAdminDonationUpdateStatus } from "@/service/api-admin/api-admin-donation";
export const funUpdateStatusDonation = async ({
id,
changeStatus,
data,
}: {
id: string;
changeStatus: "publish" | "review" | "reject";
data?: string;
}) => {
try {
const response = await apiAdminDonationUpdateStatus({
id: id,
changeStatus: changeStatus as any,
data: data,
});
return response;
} catch (error) {
console.log("[ERROR]", error);
throw error;
}
};

View File

@@ -1,11 +1,14 @@
/* eslint-disable react-hooks/exhaustive-deps */
import { import {
BaseBox, BaseBox,
Grid,
DummyLandscapeImage, DummyLandscapeImage,
Grid,
ProgressCustom,
StackCustom, StackCustom,
TextCustom, TextCustom,
ProgressCustom,
} from "@/components"; } from "@/components";
import { countDownAndCondition } from "@/utils/countDownAndCondition";
import { useEffect, useState } from "react";
import { View } from "react-native"; import { View } from "react-native";
export default function Donation_BoxPublish({ export default function Donation_BoxPublish({
@@ -15,6 +18,27 @@ export default function Donation_BoxPublish({
id: string; id: string;
data: any; data: any;
}) { }) {
const [value, setValue] = useState({
sisa: 0,
reminder: false,
});
useEffect(() => {
updateCountDown();
}, [data]);
const updateCountDown = () => {
const countDown = countDownAndCondition({
duration: data?.durasiDonasi,
publishTime: data?.publishTime,
});
setValue({
sisa: countDown.durationDay,
reminder: countDown.reminder,
});
};
return ( return (
<> <>
<BaseBox paddingTop={7} paddingBottom={7} href={`/donation/${id}`}> <BaseBox paddingTop={7} paddingBottom={7} href={`/donation/${id}`}>
@@ -36,7 +60,13 @@ export default function Donation_BoxPublish({
{data?.title || "-"} {data?.title || "-"}
</TextCustom> </TextCustom>
<TextCustom size="small"> <TextCustom size="small">
Sisa hari: {data?.durasiDonasi || 0} {value.reminder ? (
<TextCustom bold color="red">
Waktu berakhir
</TextCustom>
) : (
<TextCustom>Sisa hari: {value.sisa}</TextCustom>
)}
</TextCustom> </TextCustom>
</View> </View>
<ProgressCustom <ProgressCustom

View File

@@ -1,9 +1,9 @@
import { import {
BaseBox, BaseBox,
StackCustom,
DummyLandscapeImage, DummyLandscapeImage,
TextCustom,
Grid, Grid,
StackCustom,
TextCustom,
} from "@/components"; } from "@/components";
import { formatCurrencyDisplay } from "@/utils/formatCurrencyDisplay"; import { formatCurrencyDisplay } from "@/utils/formatCurrencyDisplay";
import React from "react"; import React from "react";
@@ -12,10 +12,15 @@ import { View } from "react-native";
export default function Donation_ComponentBoxDetailData({ export default function Donation_ComponentBoxDetailData({
bottomSection, bottomSection,
data, data,
sisaHari,
reminder,
}: { }: {
bottomSection?: React.ReactNode; bottomSection?: React.ReactNode;
data: any; data: any;
sisaHari: number;
reminder: boolean;
}) { }) {
return ( return (
<> <>
<BaseBox> <BaseBox>
@@ -25,9 +30,13 @@ export default function Donation_ComponentBoxDetailData({
<TextCustom bold size="large"> <TextCustom bold size="large">
{data?.title || "-"} {data?.title || "-"}
</TextCustom> </TextCustom>
<TextCustom size="small"> {reminder ? (
Durasi: {data?.DonasiMaster_Durasi?.name || "-"} <TextCustom bold color="red">
</TextCustom> Waktu berakhir
</TextCustom>
) : (
<TextCustom>Sisa hari: {sisaHari}</TextCustom>
)}
</View> </View>
<Grid> <Grid>

View File

@@ -4,7 +4,7 @@ export async function apiAdminDonation({
category, category,
search, search,
}: { }: {
category: "dashboard" | "publish" | "review" | "reject" ; category: "dashboard" | "publish" | "review" | "reject";
search?: string; search?: string;
}) { }) {
try { try {
@@ -16,3 +16,51 @@ export async function apiAdminDonation({
throw error; throw error;
} }
} }
export async function apiAdminDonationDetailById({ id }: { id: string }) {
try {
const response = await apiConfig.get(`/mobile/admin/donation/${id}`);
return response.data;
} catch (error) {
throw error;
}
}
export async function apiAdminDonationUpdateStatus({
id,
changeStatus,
data,
}: {
id: string;
changeStatus: "publish" | "review" | "reject";
data?: string;
}) {
try {
const response = await apiConfig.put(
`/mobile/admin/donation/${id}?status=${changeStatus}`,
{
data: data,
}
);
return response.data;
} catch (error) {
throw error;
}
}
export async function apiAdminDonationListOfDonatur({
id,
status,
}: {
id: string;
status: "berhasil" | "gagal" | "proses" | "menunggu" | "";
}) {
try {
const response = await apiConfig.get(
`/mobile/admin/donation/${id}/donatur?status=${status}`
);
return response.data;
} catch (error) {
throw error;
}
}

View File

@@ -157,3 +157,14 @@ export async function apiMasterDonation({
throw error; throw error;
} }
} }
// ================== END MASTER DONATION ================== //
export async function apiMasterTransaction() {
try {
const response = await apiConfig.get(`/mobile/master/transaction-status`);
return response.data;
} catch (error) {
throw error;
}
}

View File

@@ -1,6 +1,6 @@
import { MainColor } from "@/constants/color-palet"; import { AccentColor, MainColor } from "@/constants/color-palet";
export const colorBadge = ({ status }: { status: string }) => { export const colorBadgeStatus = ({ status }: { status: string }) => {
const statusLowerCase = status.toLowerCase(); const statusLowerCase = status.toLowerCase();
if (statusLowerCase === "publish") { if (statusLowerCase === "publish") {
return MainColor.green; return MainColor.green;
@@ -12,3 +12,16 @@ export const colorBadge = ({ status }: { status: string }) => {
return MainColor.placeholder; return MainColor.placeholder;
} }
}; };
export const colorBadgeTransaction = ({ status }: { status: string }) => {
const statusLowerCase = status.toLowerCase();
if (statusLowerCase === "berhasil") {
return MainColor.green;
} else if (statusLowerCase === "menunggu") {
return MainColor.orange;
} else if (statusLowerCase === "gagal") {
return MainColor.red;
} else {
return AccentColor.blue;
}
};

View File

@@ -0,0 +1,21 @@
import dayjs from "dayjs";
export function countDownAndCondition({
publishTime,
duration,
}: {
publishTime: Date;
duration: number | string;
}) {
const now = dayjs();
const publish = dayjs(publishTime);
const diffTime = publish.diff(now, "day");
const durasi = Number(duration);
const sisaHari = durasi + diffTime;
return {
durationDay: sisaHari,
reminder: sisaHari <= 0,
};
}