diff --git a/app/(application)/(user)/event/[id]/edit.tsx b/app/(application)/(user)/event/[id]/edit.tsx index b0c3a35..44cd774 100644 --- a/app/(application)/(user)/event/[id]/edit.tsx +++ b/app/(application)/(user)/event/[id]/edit.tsx @@ -58,7 +58,7 @@ export default function EventEdit() { try { setIsLoadData(true); const response = await apiEventGetOne({ id: id as string }); - console.log("[DATA BY ID]", JSON.stringify(response, null, 2)); + if (response.success) { setData(response.data); setSelectedDate(new Date(response.data.tanggal)); diff --git a/app/(application)/(user)/investment/[id]/edit.tsx b/app/(application)/(user)/investment/[id]/edit.tsx index c199030..af3b344 100644 --- a/app/(application)/(user)/investment/[id]/edit.tsx +++ b/app/(application)/(user)/investment/[id]/edit.tsx @@ -1,15 +1,16 @@ /* eslint-disable react-hooks/exhaustive-deps */ import { + BoxButtonOnFooter, ButtonCenteredOnly, ButtonCustom, InformationBox, LandscapeFrameUploaded, LoaderCustom, + NewWrapper, SelectCustom, Spacing, StackCustom, - TextInputCustom, - ViewWrapper, + TextInputCustom } from "@/components"; import API_STRORAGE from "@/constants/base-url-api-strorage"; import DIRECTORY_ID from "@/constants/directory-id"; @@ -198,7 +199,15 @@ export default function InvestmentEdit() { }; return ( - + + + Simpan + + + } + > - - Simpan - - - + ); } diff --git a/app/(application)/(user)/investment/create.tsx b/app/(application)/(user)/investment/create.tsx index 728b28c..14012ad 100644 --- a/app/(application)/(user)/investment/create.tsx +++ b/app/(application)/(user)/investment/create.tsx @@ -1,18 +1,19 @@ import { BaseBox, + BoxButtonOnFooter, ButtonCenteredOnly, ButtonCustom, CenterCustom, InformationBox, LandscapeFrameUploaded, - LoaderCustom, + NewWrapper, SelectCustom, Spacing, StackCustom, TextCustom, TextInputCustom, - ViewWrapper, } from "@/components"; +import CustomSkeleton from "@/components/_ShareComponent/SkeletonCustom"; import { MainColor } from "@/constants/color-palet"; import DIRECTORY_ID from "@/constants/directory-id"; import { useAuth } from "@/hooks/use-auth"; @@ -184,7 +185,19 @@ export default function InvestmentCreate() { // const [coba, setCoba] = useState(""); return ( - + + handleSubmit()} + > + Simpan + + + } + > @@ -264,7 +277,9 @@ export default function InvestmentCreate() { {loadingMaster ? ( - + ) : ( + ) : ( + ) : ( - handleSubmit()} - > - Simpan - - - + {/* */} + ); } diff --git a/app/(application)/(user)/notifications/index.tsx b/app/(application)/(user)/notifications/index.tsx index 2e2c57b..01bec9a 100644 --- a/app/(application)/(user)/notifications/index.tsx +++ b/app/(application)/(user)/notifications/index.tsx @@ -1,11 +1,11 @@ -import ScreenNotification from "@/screens/Notification/ScreenNotification_V2"; import ScreenNotification_V1 from "@/screens/Notification/ScreenNotification_V1"; +import ScreenNotification_V2 from "@/screens/Notification/ScreenNotification_V2"; export default function Notification() { return ( <> - - {/* */} + + {/* */} ); } diff --git a/app/(application)/(user)/voting/(tabs)/contribution.tsx b/app/(application)/(user)/voting/(tabs)/contribution.tsx index bb555ad..913aba0 100644 --- a/app/(application)/(user)/voting/(tabs)/contribution.tsx +++ b/app/(application)/(user)/voting/(tabs)/contribution.tsx @@ -1,59 +1,6 @@ /* eslint-disable react-hooks/exhaustive-deps */ -import { - LoaderCustom, - TextCustom, - ViewWrapper -} from "@/components"; -import { useAuth } from "@/hooks/use-auth"; -import Voting_BoxPublishSection from "@/screens/Voting/BoxPublishSection"; -import { apiVotingGetAll } from "@/service/api-client/api-voting"; -import { useFocusEffect } from "expo-router"; -import _ from "lodash"; -import { useState, useCallback } from "react"; +import Voting_ScreenContribution from "@/screens/Voting/ScreenContribution"; export default function VotingContribution() { - const { user } = useAuth(); - const [listData, setListData] = useState([]); - const [loadingGetData, setLoadingGetData] = useState(false); - - - useFocusEffect( - useCallback(() => { - onLoadData(); - }, []) - ); - - const onLoadData = async () => { - try { - setLoadingGetData(true); - const response = await apiVotingGetAll({ - category: "contribution", - authorId: user?.id as string, - }); - - if (response.success) { - setListData(response.data); - } - } catch (error) { - console.log("[ERROR]", error); - } finally { - setLoadingGetData(false); - } - }; - - return ( - - {loadingGetData ? ( - - ) : _.isEmpty(listData) ? ( - Tidak ada kontribusi - ) : listData.map((item: any, index: number) => ( - - ))} - - ); + return ; } diff --git a/app/(application)/(user)/voting/(tabs)/history.tsx b/app/(application)/(user)/voting/(tabs)/history.tsx index 38f3354..607aed8 100644 --- a/app/(application)/(user)/voting/(tabs)/history.tsx +++ b/app/(application)/(user)/voting/(tabs)/history.tsx @@ -1,77 +1,10 @@ /* eslint-disable react-hooks/exhaustive-deps */ -import { LoaderCustom, TextCustom, ViewWrapper } from "@/components"; -import TabsTwoButtonCustom from "@/components/_ShareComponent/TabsTwoHeaderCustom"; -import Voting_BoxPublishSection from "@/screens/Voting/BoxPublishSection"; -import { useAuth } from "@/hooks/use-auth"; -import { useCallback, useState } from "react"; -import { apiVotingGetAll } from "@/service/api-client/api-voting"; -import { useFocusEffect } from "expo-router"; -import _ from "lodash"; +import Voting_ScreenHistory from "@/screens/Voting/ScreenHistory"; export default function VotingHistory() { - const { user } = useAuth(); - const [activeCategory, setActiveCategory] = useState("all"); - - const [listData, setListData] = useState([]); - const [loadingGetData, setLoadingGetData] = useState(false); - - useFocusEffect( - useCallback(() => { - onLoadData(); - }, [activeCategory]) - ); - - const onLoadData = async () => { - try { - setLoadingGetData(true); - const response = await apiVotingGetAll({ - category: activeCategory === "all" ? "all-history" : "my-history", - authorId: user?.id as string, - }); - - if (response.success) { - setListData(response.data); - } - } catch (error) { - console.log("[ERROR]", error); - } finally { - setLoadingGetData(false); - } - }; - - const handlePress = (item: any) => { - setActiveCategory(item); - // tambahkan logika lain seperti filter dsb. - }; - return ( - - } - > - {loadingGetData ? ( - - ) : _.isEmpty(listData) ? ( - Tidak ada riwayat - ) : ( - listData.map((item: any, index: number) => ( - - )) - )} - + <> + + ); } diff --git a/app/(application)/(user)/voting/(tabs)/index.tsx b/app/(application)/(user)/voting/(tabs)/index.tsx index 0e42863..6ef1362 100644 --- a/app/(application)/(user)/voting/(tabs)/index.tsx +++ b/app/(application)/(user)/voting/(tabs)/index.tsx @@ -1,71 +1,10 @@ /* eslint-disable react-hooks/exhaustive-deps */ -import { - FloatingButton, - LoaderCustom, - SearchInput, - TextCustom, - ViewWrapper, -} from "@/components"; -import { useAuth } from "@/hooks/use-auth"; -import Voting_BoxPublishSection from "@/screens/Voting/BoxPublishSection"; -import { apiVotingGetAll } from "@/service/api-client/api-voting"; -import { router, useFocusEffect } from "expo-router"; -import _ from "lodash"; -import { useCallback, useState } from "react"; +import Voting_ScreenBeranda from "@/screens/Voting/ScreenBeranda"; export default function VotingBeranda() { - const { user } = useAuth(); - const [listData, setListData] = useState([]); - const [loadingGetData, setLoadingGetData] = useState(false); - const [search, setSearch] = useState(""); - - useFocusEffect( - useCallback(() => { - onLoadData(); - }, [search]) - ); - - const onLoadData = async () => { - try { - setLoadingGetData(true); - const response = await apiVotingGetAll({ - search, - category: "beranda", - userLoginId: user?.id, - }); - if (response.success) { - setListData(response.data); - } - } catch (error) { - console.log("[ERROR]", error); - } finally { - setLoadingGetData(false); - } - }; - return ( - router.push("/voting/create")} /> - } - headerComponent={ - - } - > - {loadingGetData ? ( - - ) : _.isEmpty(listData) ? ( - Tidak ada data - ) : ( - listData.map((item: any, index: number) => ( - - )) - )} - + <> + + ); } diff --git a/app/(application)/(user)/voting/[id]/[status]/detail.tsx b/app/(application)/(user)/voting/[id]/[status]/detail.tsx index 69c5f21..b638f39 100644 --- a/app/(application)/(user)/voting/[id]/[status]/detail.tsx +++ b/app/(application)/(user)/voting/[id]/[status]/detail.tsx @@ -51,8 +51,6 @@ export default function VotingDetailStatus() { setLoadingGetData(true); const response = await apiVotingGetOne({ id: id as string }); - console.log("[DATA BY ID]", JSON.stringify(response, null, 2)); - if (response.success) { setData(response.data); } diff --git a/app/(application)/(user)/voting/[id]/edit.tsx b/app/(application)/(user)/voting/[id]/edit.tsx index a224656..42d8988 100644 --- a/app/(application)/(user)/voting/[id]/edit.tsx +++ b/app/(application)/(user)/voting/[id]/edit.tsx @@ -5,13 +5,14 @@ import { ButtonCustom, CenterCustom, LoaderCustom, + NewWrapper, Spacing, StackCustom, TextAreaCustom, TextCustom, - TextInputCustom, - ViewWrapper, + TextInputCustom } from "@/components"; +import ListSkeletonComponent from "@/components/_ShareComponent/ListSkeletonComponent"; import DateTimePickerCustom from "@/components/DateInput/DateTimePickerCustom"; import { MainColor } from "@/constants/color-palet"; import { ICON_SIZE_XLARGE } from "@/constants/constans-value"; @@ -34,7 +35,7 @@ interface IEditData { Voting_DaftarNamaVote?: [ { value?: string; - } + }, ]; } @@ -47,7 +48,7 @@ export default function VotingEdit() { useFocusEffect( useCallback(() => { onLoadData(); - }, [id]) + }, [id]), ); const onLoadData = async () => { @@ -188,9 +189,9 @@ export default function VotingEdit() { }; return ( - + {loadingGetData ? ( - + ) : ( setData({ ...data, deskripsi: text })} /> - + )} - + {data?.Voting_DaftarNamaVote?.map((item: any, index: number) => ( @@ -270,7 +271,7 @@ export default function VotingEdit() { ...(data as any), Voting_DaftarNamaVote: data?.Voting_DaftarNamaVote?.map( (item: any, i: any) => - i === index ? { ...item, value } : item + i === index ? { ...item, value } : item, ), }) } @@ -327,6 +328,6 @@ export default function VotingEdit() { )} - + ); } diff --git a/app/(application)/(user)/voting/[id]/list-of-contributor.tsx b/app/(application)/(user)/voting/[id]/list-of-contributor.tsx index b7bb593..ab9be8d 100644 --- a/app/(application)/(user)/voting/[id]/list-of-contributor.tsx +++ b/app/(application)/(user)/voting/[id]/list-of-contributor.tsx @@ -1,69 +1,6 @@ /* eslint-disable react-hooks/exhaustive-deps */ -import { - AvatarUsernameAndOtherComponent, - BadgeCustom, - BaseBox, - LoaderCustom, - TextCustom, - ViewWrapper, -} from "@/components"; -import { apiVotingContribution } from "@/service/api-client/api-voting"; -import { useFocusEffect, useLocalSearchParams } from "expo-router"; -import _ from "lodash"; -import { useCallback, useState } from "react"; +import Voting_ScreenListOfContributor from "@/screens/Voting/ScreenListOfContributor"; -export default function Voting_ListOfContributor() { - const { id } = useLocalSearchParams(); - const [listData, setListData] = useState([]); - const [isLoadData, setIsLoadData] = useState(false); - - useFocusEffect( - useCallback(() => { - onLoadList(); - }, [id]) - ); - - const onLoadList = async () => { - try { - setIsLoadData(true); - const response = await apiVotingContribution({ - id: id as string, - authorId: "", - category: "list", - }); - - if (response.success) { - setListData(response.data); - } - } catch (error) { - console.log("[ERROR]", error); - } finally { - setIsLoadData(false); - } - }; - - return ( - - {isLoadData ? ( - - ) : _.isEmpty(listData) ? ( - Tidak ada kontributor - ) : ( - listData.map((item: any, index: number) => ( - - - {item?.Voting_DaftarNamaVote?.value} - - } - /> - - )) - )} - - ); +export default function VotingListOfContributor() { + return ; } diff --git a/app/(application)/(user)/voting/create.tsx b/app/(application)/(user)/voting/create.tsx index 1821425..42972bb 100644 --- a/app/(application)/(user)/voting/create.tsx +++ b/app/(application)/(user)/voting/create.tsx @@ -80,9 +80,7 @@ export default function VotingCreate() { type: "success", text1: "Data berhasil disimpan", }); - router.replace( - "/(application)/(user)/voting/(tabs)/status?status=review", - ); + router.replace("/voting/(tabs)/status?status=review"); } else { Toast.show({ type: "error", diff --git a/docs/prompt-for-qwen-code.md b/docs/prompt-for-qwen-code.md index 3949e34..952b35a 100644 --- a/docs/prompt-for-qwen-code.md +++ b/docs/prompt-for-qwen-code.md @@ -1,7 +1,7 @@ -File utama: screens/Voting/ScreenStatus.tsx -Function fecth: apiVotingGetByStatus +File utama: screens/Voting/ScreenListOfContributor.tsx +Function fecth: apiVotingContribution File function fetch: service/api-client/api-voting.ts File komponen wrapper: components/_ShareComponent/NewWrapper.tsx @@ -15,7 +15,8 @@ Jika tidak ada props page maka tambahkan props page dan default page: "1" Gunakan bahasa indonesia pada cli agar saya mudah membacanya. -File refrensi: screens/Event/ScreenStatus.tsx + +File refrensi: app/(application)/(user)/event/[id]/list-of-participants.tsx Anda bisa menggunakan refrensi dari "File refrensi" jika butuh pemahaman dengan tipe fitur yang sama @@ -23,4 +24,8 @@ Anda bisa menggunakan refrensi dari "File refrensi" jika butuh pemahaman dengan Terapkan NewWrapper pada file: screens/Forum/DetailForum.tsx Component yang digunakan: components/_ShareComponent/NewWrapper.tsx , karena ini adalah halaman detail saya ingin anda fokus pada props pada NewWrapper. Seperti - \ No newline at end of file + + +Bantu saya untuk memperbaiki logika path yang ada di dalam file "screens/Admin/Notification-Admin/ScreenNotificationAdmin2.tsx" , pada function fixPath +Saya ingin jika didalam deeplink ada "/admin/..." contoh "/admin/event/review/status" maka path yang akan di redirect adalah "/admin/event/review/status" +jika tidak maka terapkan sesuai dengan logika yang sudah ada diff --git a/screens/Admin/Notification-Admin/ScreenNotificationAdmin2.tsx b/screens/Admin/Notification-Admin/ScreenNotificationAdmin2.tsx index 26816b5..6ef400a 100644 --- a/screens/Admin/Notification-Admin/ScreenNotificationAdmin2.tsx +++ b/screens/Admin/Notification-Admin/ScreenNotificationAdmin2.tsx @@ -12,7 +12,7 @@ import { import { IconPlus } from "@/components/_Icon"; import { IconDot } from "@/components/_Icon/IconComponent"; import { AccentColor, MainColor } from "@/constants/color-palet"; -import { ICON_SIZE_SMALL } from "@/constants/constans-value"; +import { ICON_SIZE_SMALL, PAGINATION_DEFAULT_TAKE } from "@/constants/constans-value"; import { createPaginationComponents } from "@/helpers/paginationHelpers"; import { useAuth } from "@/hooks/use-auth"; import { useNotificationStore } from "@/hooks/use-notification-store"; @@ -26,8 +26,6 @@ import _ from "lodash"; import { useState } from "react"; import { RefreshControl, View } from "react-native"; -const PAGE_SIZE = 10; - const selectedCategory = (value: string) => { const category = listOfcategoriesAppNotification.find( (c) => c.value === value, @@ -35,6 +33,37 @@ const selectedCategory = (value: string) => { return category?.label; }; +const fixPath = ({ + deepLink, + categoryApp, +}: { + deepLink: string; + categoryApp: string; +}) => { + // Jika categoryApp adalah "OTHER", kembalikan deepLink tanpa perubahan + if (categoryApp === "OTHER") { + return deepLink; + } + + // Jika dalam deepLink terdapat "/admin/", kembalikan path tersebut tanpa modifikasi tambahan + if (deepLink.includes("/admin/")) { + return deepLink; + } + + console.log("Category App", categoryApp); + console.log("Deep Link", deepLink); + + const separator = deepLink.includes("?") ? "&" : "?"; + + const fixedPath = `${deepLink}${separator}from=notifications&category=${_.lowerCase( + categoryApp, + )}`; + + console.log("Fix Path", fixedPath); + + return fixedPath; +}; + const BoxNotification = ({ data, activeCategory, @@ -50,17 +79,22 @@ const BoxNotification = ({ { - console.log( - "Notification >", - selectedCategory(activeCategory as string), - ); - router.push(data.deepLink); - markAsRead(data.id); - setListData((prev: any) => - prev.map((item: any) => - item.id === data.id ? { ...item, isRead: true } : item, - ), - ); + const newPath = fixPath({ + deepLink: data.deepLink, + categoryApp: data.kategoriApp, + }); + + selectedCategory(activeCategory as string); + router.navigate(newPath as any); + + if (!data.isRead) { + markAsRead(data.id); + setListData((prev: any) => + prev.map((item: any) => + item.id === data.id ? { ...item, isRead: true } : item, + ), + ); + } }} > @@ -97,7 +131,7 @@ export default function Admin_ScreenNotification2() { page: String(page), }); }, - pageSize: PAGE_SIZE, + pageSize: PAGINATION_DEFAULT_TAKE, dependencies: [user?.id, activeCategory], onError: (error) => console.error("[ERROR] Fetch admin notifications:", error), @@ -110,7 +144,7 @@ export default function Admin_ScreenNotification2() { refreshing: pagination.refreshing, listData: pagination.listData, emptyMessage: "Belum ada notifikasi", - skeletonCount: 5, + skeletonCount: PAGINATION_DEFAULT_TAKE, skeletonHeight: 100, }); diff --git a/screens/Event/ScreenStatus.tsx b/screens/Event/ScreenStatus.tsx index 1971fb3..fd8ef62 100644 --- a/screens/Event/ScreenStatus.tsx +++ b/screens/Event/ScreenStatus.tsx @@ -13,8 +13,8 @@ import { useAuth } from "@/hooks/use-auth"; import { usePagination } from "@/hooks/use-pagination"; import { dummyMasterStatus } from "@/lib/dummy-data/_master/status"; import { apiEventGetByStatus } from "@/service/api-client/api-event"; -import { useLocalSearchParams } from "expo-router"; -import { useState } from "react"; +import { useFocusEffect, useLocalSearchParams } from "expo-router"; +import { useCallback, useState } from "react"; import { RefreshControl, View } from "react-native"; export default function Event_ScreenStatus() { @@ -84,6 +84,12 @@ export default function Event_ScreenStatus() { pagination.reset(); }; + useFocusEffect( + useCallback(() => { + pagination.onRefresh(); + }, [activeCategory]) + ); + const tabsComponent = ( ({ diff --git a/screens/Job/ButtonStatusSection.tsx b/screens/Job/ButtonStatusSection.tsx index a6c3e9b..848b801 100644 --- a/screens/Job/ButtonStatusSection.tsx +++ b/screens/Job/ButtonStatusSection.tsx @@ -20,6 +20,9 @@ export default function Job_ButtonStatusSection({ onSetLoading: (value: boolean) => void; isArchive?: boolean; }) { + const path : any =(status: string) => { + return `/job/(tabs)/status?status=${status}` + } const handleBatalkanReview = () => { AlertDefaultSystem({ title: "Batalkan Review", @@ -39,7 +42,7 @@ export default function Job_ButtonStatusSection({ type: "success", text1: response.message, }); - router.back(); + router.replace(path("draft")); } else { Toast.show({ type: "info", @@ -76,14 +79,14 @@ export default function Job_ButtonStatusSection({ type: "success", text1: response.message, }); - router.back(); + router.replace(path("review")); } else { Toast.show({ type: "info", text1: "Info", text2: response.message, }); - router.back(); + router.back() } } catch (error) { console.log("[ERROR]", error); @@ -113,14 +116,14 @@ export default function Job_ButtonStatusSection({ type: "success", text1: response.message, }); - router.back(); + router.replace(path("draft")); } else { Toast.show({ type: "info", text1: "Info", text2: response.message, }); - router.back(); + router. back(); } } catch (error) { console.log("[ERROR]", error); diff --git a/screens/Job/MainViewStatus2.tsx b/screens/Job/MainViewStatus2.tsx index c53724a..7e4c364 100644 --- a/screens/Job/MainViewStatus2.tsx +++ b/screens/Job/MainViewStatus2.tsx @@ -62,19 +62,17 @@ export default function Job_MainViewStatus2() { ); - // useFocusEffect( - // useCallback(() => { - // // Reset and load first page when category changes - // pagination.reset(); - // // pagination.onRefresh(); - // }, [activeCategory]), - // ); - const handlePress = (item: any) => { setActiveCategory(item.value); // Reset pagination saat kategori berubah pagination.reset(); }; + + useFocusEffect( + useCallback(() => { + pagination.onRefresh(); + }, [activeCategory]) + ); const scrollComponent = ( (); const [activeCategory, setActiveCategory] = useState( @@ -140,7 +143,7 @@ export default function ScreenNotification() { // useFocusEffect( // useCallback(() => { // // Reset and load first page when category changes - // pagination.reset(); + // pagination.onRefresh(); // }, [activeCategory]), // ); @@ -171,7 +174,7 @@ export default function ScreenNotification() { listData: pagination.listData, isInitialLoad: pagination.isInitialLoad, emptyMessage: "Belum ada notifikasi", - skeletonCount: 5, + skeletonCount: PAGINATION_DEFAULT_TAKE, skeletonHeight: 100, }); @@ -237,7 +240,6 @@ export default function ScreenNotification() { }, ]} onPressItem={(item: any) => { - // console.log("Item", item.value); if (item.value === "read-all") { AlertDefaultSystem({ title: "Tandai Semua Dibaca", diff --git a/screens/Voting/ButtonStatusSection.tsx b/screens/Voting/ButtonStatusSection.tsx index 9de27c6..c86dd4a 100644 --- a/screens/Voting/ButtonStatusSection.tsx +++ b/screens/Voting/ButtonStatusSection.tsx @@ -3,7 +3,7 @@ import { apiVotingDelete, apiVotingUpdateStatus, } from "@/service/api-client/api-voting"; -import { router } from "expo-router"; +import { RelativePathString, router } from "expo-router"; import Toast from "react-native-toast-message"; export default function Voting_ButtonStatusSection({ @@ -17,6 +17,10 @@ export default function Voting_ButtonStatusSection({ isLoading: boolean; onSetLoading: (value: boolean) => void; }) { + const path: any = (status: string) => { + return `/voting/(tabs)/status?status=${status}`; + }; + const handleBatalkanReview = () => { AlertDefaultSystem({ title: "Batalkan Review", @@ -34,9 +38,9 @@ export default function Voting_ButtonStatusSection({ if (response?.success) { Toast.show({ type: "success", - text1: response.message, + text1: "Berhasil batalkan review", }); - router.replace(`/voting/${id}/draft/detail`); + router.replace(path("draft")); } else { Toast.show({ type: "info", @@ -71,9 +75,9 @@ export default function Voting_ButtonStatusSection({ if (response?.success) { Toast.show({ type: "success", - text1: response.message, + text1: "Berhasil ajukan review", }); - router.replace(`/voting/${id}/review/detail`); + router.replace(path("review")); } else { Toast.show({ type: "info", @@ -108,9 +112,9 @@ export default function Voting_ButtonStatusSection({ if (response?.success) { Toast.show({ type: "success", - text1: response.message, + text1: "Berhasil edit kembali", }); - router.replace(`/voting/${id}/draft/detail`); + router.replace(path("draft")); } else { Toast.show({ type: "info", @@ -135,31 +139,31 @@ export default function Voting_ButtonStatusSection({ textLeft: "Batal", textRight: "Hapus", onPressRight: async () => { - try { - onSetLoading(true); - const response = await apiVotingDelete({ - id: id as string, - }); + 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); - } + if (response?.success) { + Toast.show({ + type: "success", + text1: "Berhasil hapus data", + }); + router.back(); + } else { + Toast.show({ + type: "info", + text1: "Info", + text2: response.message, + }); + router.back(); + } + } catch (error) { + console.log("[ERROR]", error); + } finally { + onSetLoading(false); + } }, }); }; diff --git a/screens/Voting/ScreenBeranda.tsx b/screens/Voting/ScreenBeranda.tsx new file mode 100644 index 0000000..d419897 --- /dev/null +++ b/screens/Voting/ScreenBeranda.tsx @@ -0,0 +1,82 @@ +/* eslint-disable react-hooks/exhaustive-deps */ +import { FloatingButton, SearchInput } from "@/components"; +import NewWrapper from "@/components/_ShareComponent/NewWrapper"; +import { createPaginationComponents } from "@/helpers/paginationHelpers"; +import { useAuth } from "@/hooks/use-auth"; +import { usePagination } from "@/hooks/use-pagination"; +import Voting_BoxPublishSection from "@/screens/Voting/BoxPublishSection"; +import { apiVotingGetAll } from "@/service/api-client/api-voting"; +import { router } from "expo-router"; +import { useMemo, useState } from "react"; +import { RefreshControl } from "react-native"; + +export default function Voting_ScreenBeranda() { + const { user } = useAuth(); + const [search, setSearch] = useState(""); + + const pagination = usePagination({ + fetchFunction: async (page, searchQuery) => { + return await apiVotingGetAll({ + search: searchQuery || "", + category: "beranda", + userLoginId: user?.id, + page: String(page), + }); + }, + pageSize: 5, + searchQuery: search, + dependencies: [user?.id], + onError: (error) => console.error("[ERROR] Fetch voting:", error), + }); + + // Gunakan helper untuk membuat komponen-komponen pagination + const { ListEmptyComponent, ListFooterComponent } = + createPaginationComponents({ + loading: pagination.loading, + refreshing: pagination.refreshing, + listData: pagination.listData, + searchQuery: search, + emptyMessage: "Tidak ada data", + emptySearchMessage: "Tidak ada hasil pencarian", + skeletonCount: 5, + skeletonHeight: 200, + isInitialLoad: pagination.isInitialLoad, + }); + + // Render item untuk FlatList + const renderItem = useMemo( + () => + ({ item }: { item: any }) => + ( + + ), + [], + ); + + return ( + + } + hideFooter + floatingButton={ + router.push("/voting/create")} /> + } + headerComponent={ + + } + /> + ); +} diff --git a/screens/Voting/ScreenContribution.tsx b/screens/Voting/ScreenContribution.tsx new file mode 100644 index 0000000..fa282a0 --- /dev/null +++ b/screens/Voting/ScreenContribution.tsx @@ -0,0 +1,70 @@ +/* eslint-disable react-hooks/exhaustive-deps */ +import NewWrapper from "@/components/_ShareComponent/NewWrapper"; +import { createPaginationComponents } from "@/helpers/paginationHelpers"; +import { useAuth } from "@/hooks/use-auth"; +import { usePagination } from "@/hooks/use-pagination"; +import Voting_BoxPublishSection from "@/screens/Voting/BoxPublishSection"; +import { apiVotingGetAll } from "@/service/api-client/api-voting"; +import { useMemo } from "react"; +import { RefreshControl } from "react-native"; + +export default function Voting_ScreenContribution() { + const { user } = useAuth(); + + const pagination = usePagination({ + fetchFunction: async (page) => { + return await apiVotingGetAll({ + category: "contribution", + authorId: user?.id as string, + page: String(page), + }); + }, + pageSize: 4, + dependencies: [user?.id], + onError: (error) => console.error("[ERROR] Fetch contribution:", error), + }); + + // Gunakan helper untuk membuat komponen-komponen pagination + const { ListEmptyComponent, ListFooterComponent } = + createPaginationComponents({ + loading: pagination.loading, + refreshing: pagination.refreshing, + listData: pagination.listData, + emptyMessage: "Tidak ada kontribusi", + emptySearchMessage: "Tidak ada hasil pencarian", + skeletonCount: 5, + skeletonHeight: 200, + isInitialLoad: pagination.isInitialLoad, + }); + + // Render item untuk FlatList + const renderItem = useMemo( + () => + ({ item }: { item: any }) => + ( + + ), + [], + ); + + return ( + + } + hideFooter + /> + ); +} diff --git a/screens/Voting/ScreenHistory.tsx b/screens/Voting/ScreenHistory.tsx new file mode 100644 index 0000000..1227446 --- /dev/null +++ b/screens/Voting/ScreenHistory.tsx @@ -0,0 +1,114 @@ +/* eslint-disable react-hooks/exhaustive-deps */ +import { ButtonCustom, Spacing, TextCustom } from "@/components"; +import NewWrapper from "@/components/_ShareComponent/NewWrapper"; +import { AccentColor, MainColor } from "@/constants/color-palet"; +import { PAGINATION_DEFAULT_TAKE } from "@/constants/constans-value"; +import { createPaginationComponents } from "@/helpers/paginationHelpers"; +import { useAuth } from "@/hooks/use-auth"; +import { usePagination } from "@/hooks/use-pagination"; +import Voting_BoxPublishSection from "@/screens/Voting/BoxPublishSection"; +import { apiVotingGetAll } from "@/service/api-client/api-voting"; +import { useState } from "react"; +import { RefreshControl, View } from "react-native"; + +export default function Voting_ScreenHistory() { + const [activeCategory, setActiveCategory] = useState("all"); + const { user } = useAuth(); + + // Setup pagination + const pagination = usePagination({ + fetchFunction: async (page) => { + return await apiVotingGetAll({ + category: activeCategory === "all" ? "all-history" : "my-history", + authorId: user?.id as string, + page: String(page), + }); + }, + pageSize: PAGINATION_DEFAULT_TAKE, + dependencies: [user?.id, activeCategory], + onError: (error) => console.error("[ERROR] Fetch voting history:", error), + }); + + // Generate komponen + const { ListEmptyComponent, ListFooterComponent } = + createPaginationComponents({ + loading: pagination.loading, + refreshing: pagination.refreshing, + listData: pagination.listData, + emptyMessage: "Belum ada riwayat", + skeletonCount: PAGINATION_DEFAULT_TAKE, + skeletonHeight: 100, + }); + + // Render item voting + const renderVotingItem = ({ item }: { item: any }) => ( + + ); + + const handlePress = (item: any) => { + setActiveCategory(item); + // Reset pagination saat kategori berubah + pagination.reset(); + }; + + const headerComponent = ( + + handlePress("all")} + > + Semua Riwayat + + + handlePress("main")} + > + Riwayat Saya + + + ); + + return ( + + } + onEndReached={pagination.loadMore} + ListEmptyComponent={ListEmptyComponent} + ListFooterComponent={ListFooterComponent} + hideFooter + /> + ); +} diff --git a/screens/Voting/ScreenListOfContributor.tsx b/screens/Voting/ScreenListOfContributor.tsx new file mode 100644 index 0000000..07f4682 --- /dev/null +++ b/screens/Voting/ScreenListOfContributor.tsx @@ -0,0 +1,80 @@ +/* eslint-disable react-hooks/exhaustive-deps */ +import { + AvatarUsernameAndOtherComponent, + BadgeCustom, + BaseBox, + Spacing, + TextCustom, +} from "@/components"; +import NewWrapper from "@/components/_ShareComponent/NewWrapper"; +import { PAGINATION_DEFAULT_TAKE } from "@/constants/constans-value"; +import { createPaginationComponents } from "@/helpers/paginationHelpers"; +import { usePagination } from "@/hooks/use-pagination"; +import { apiVotingContribution } from "@/service/api-client/api-voting"; +import { useLocalSearchParams } from "expo-router"; +import _ from "lodash"; +import { RefreshControl, View } from "react-native"; + +export default function Voting_ScreenListOfContributor() { + const { id } = useLocalSearchParams(); + + // Setup pagination + const pagination = usePagination({ + fetchFunction: async (page) => { + return await apiVotingContribution({ + id: id as string, + authorId: "", + category: "list", + page: String(page), + }); + }, + pageSize: PAGINATION_DEFAULT_TAKE, + dependencies: [id], + onError: (error) => + console.error("[ERROR] Fetch voting contributors:", error), + }); + + // Generate komponen + const { ListEmptyComponent, ListFooterComponent } = + createPaginationComponents({ + loading: pagination.loading, + refreshing: pagination.refreshing, + listData: pagination.listData, + emptyMessage: "Tidak ada kontributor", + skeletonCount: PAGINATION_DEFAULT_TAKE, + skeletonHeight: 100, + }); + + // Render item contributor + const renderContributorItem = ({ item }: { item: any }) => ( + + + {item?.Voting_DaftarNamaVote?.value} + + } + /> + + ); + + return ( + + } + onEndReached={pagination.loadMore} + ListEmptyComponent={ListEmptyComponent} + ListFooterComponent={ListFooterComponent} + /> + ); +} diff --git a/screens/Voting/ScreenStatus.tsx b/screens/Voting/ScreenStatus.tsx index 06c98e9..9401a52 100644 --- a/screens/Voting/ScreenStatus.tsx +++ b/screens/Voting/ScreenStatus.tsx @@ -8,17 +8,18 @@ import { } from "@/components"; import NewWrapper from "@/components/_ShareComponent/NewWrapper"; import { MainColor } from "@/constants/color-palet"; +import { PAGINATION_DEFAULT_TAKE } from "@/constants/constans-value"; import { createPaginationComponents } from "@/helpers/paginationHelpers"; import { useAuth } from "@/hooks/use-auth"; import { usePagination } from "@/hooks/use-pagination"; import { dummyMasterStatus } from "@/lib/dummy-data/_master/status"; import { apiVotingGetByStatus } from "@/service/api-client/api-voting"; import { dateTimeView } from "@/utils/dateTimeView"; -import { useLocalSearchParams } from "expo-router"; -import { useState } from "react"; +import { useFocusEffect, useLocalSearchParams } from "expo-router"; +import { useCallback, useState } from "react"; import { RefreshControl, View } from "react-native"; -const PAGE_SIZE = 10; +const PAGE_SIZE = 6 export default function Voting_ScreenStatus() { const { user } = useAuth(); @@ -40,7 +41,7 @@ export default function Voting_ScreenStatus() { page: String(page), }); }, - pageSize: PAGE_SIZE, + pageSize: PAGINATION_DEFAULT_TAKE, dependencies: [id, activeCategory], onError: (error) => console.error("[ERROR] Fetch voting by status:", error), }); @@ -91,6 +92,12 @@ export default function Voting_ScreenStatus() { pagination.reset(); }; + useFocusEffect( + useCallback(() => { + pagination.onRefresh(); + }, [activeCategory]) + ); + const scrollComponent = ( ({ diff --git a/service/api-client/api-voting.ts b/service/api-client/api-voting.ts index 4cbe63e..187fd44 100644 --- a/service/api-client/api-voting.ts +++ b/service/api-client/api-voting.ts @@ -81,14 +81,15 @@ export async function apiVotingUpdateData({ } } -export async function apiVotingGetAll({ search, category, authorId, userLoginId }: { search?: string, category: "beranda" | "contribution" | "all-history" | "my-history", authorId?: string, userLoginId?: string }) { +export async function apiVotingGetAll({ search, category, authorId, userLoginId, page = "1" }: { search?: string, category: "beranda" | "contribution" | "all-history" | "my-history", authorId?: string, userLoginId?: string, page?: string }) { try { console.log("userLoginId", userLoginId); const categoryQuery = category ? `?category=${category}` : ""; const searchQuery = search ? `&search=${search}` : ""; const authorIdQuery = authorId ? `&authorId=${authorId}` : ""; const userLoginIdQuery = userLoginId ? `&userLoginId=${userLoginId}` : ""; - const response = await apiConfig.get(`/mobile/voting${categoryQuery}${searchQuery}${authorIdQuery}${userLoginIdQuery}`); + const pageQuery = `&page=${page}`; + const response = await apiConfig.get(`/mobile/voting${categoryQuery}${searchQuery}${authorIdQuery}${userLoginIdQuery}${pageQuery}`); return response.data; } catch (error) { throw error; @@ -110,15 +111,17 @@ export async function apiVotingContribution({ id, authorId, category, + page = "1", }: { id: string; authorId: string; category: "list" | "checked"; + page?: string; }) { const query = category === "list" - ? "?category=list" - : `?category=checked&authorId=${authorId}`; + ? `?category=list&page=${page}` + : `?category=checked&authorId=${authorId}&page=${page}`; try { const response = await apiConfig.get( `/mobile/voting/${id}/contribution${query}` diff --git a/service/api-notifications.ts b/service/api-notifications.ts index 212e335..68b0bd9 100644 --- a/service/api-notifications.ts +++ b/service/api-notifications.ts @@ -47,9 +47,8 @@ export async function apiGetNotificationsById({ category: TypeNotificationCategoryApp; page?: string; }) { - console.log("ID", id); + console.log("Category", category); - console.log("Page", page); try { const response = await apiConfig.get(