From 68c6a745ef27967a4f1a37d7f4b7f94ef1565526 Mon Sep 17 00:00:00 2001 From: amel Date: Wed, 4 Jun 2025 17:38:36 +0800 Subject: [PATCH] upd: skeleton Deskripsi: - divisi - detail divisi - informasi divisi - calender list - calender detail - history - diskusi list - detail diskusi - list task divisi NO Issuese --- .../calendar/[detail]/add-member.tsx | 1 + .../calendar/[detail]/index.tsx | 68 ++++++-- .../(fitur-division)/calendar/history.tsx | 18 +- .../[id]/(fitur-division)/calendar/index.tsx | 59 ++++--- .../discussion/[detail]/index.tsx | 138 +++++++++------ .../(fitur-division)/discussion/index.tsx | 85 +++++---- .../[id]/(fitur-division)/task/index.tsx | 164 ++++++++++-------- app/(application)/division/[id]/info.tsx | 64 +++++-- app/(application)/division/index.tsx | 103 ++++++----- components/calendar/headerCalendarDetail.tsx | 7 +- .../division/discussionDivisionDetail.tsx | 52 ++++-- components/division/fileDivisionDetail.tsx | 84 +++++---- components/division/taskDivisionDetail.tsx | 57 +++--- 13 files changed, 560 insertions(+), 340 deletions(-) diff --git a/app/(application)/division/[id]/(fitur-division)/calendar/[detail]/add-member.tsx b/app/(application)/division/[id]/(fitur-division)/calendar/[detail]/add-member.tsx index ea70a85..1b3d528 100644 --- a/app/(application)/division/[id]/(fitur-division)/calendar/[detail]/add-member.tsx +++ b/app/(application)/division/[id]/(fitur-division)/calendar/[detail]/add-member.tsx @@ -144,6 +144,7 @@ export default function AddMemberCalendarEvent() { style={[Styles.itemSelectModal]} onPress={() => { !found && onChoose(item.idUser, item.name, item.img) + onChoose(item.idUser, item.name, item.img) }} > diff --git a/app/(application)/division/[id]/(fitur-division)/calendar/[detail]/index.tsx b/app/(application)/division/[id]/(fitur-division)/calendar/[detail]/index.tsx index 7143084..1745e9b 100644 --- a/app/(application)/division/[id]/(fitur-division)/calendar/[detail]/index.tsx +++ b/app/(application)/division/[id]/(fitur-division)/calendar/[detail]/index.tsx @@ -5,6 +5,7 @@ import HeaderRightCalendarDetail from "@/components/calendar/headerCalendarDetai import DrawerBottom from "@/components/drawerBottom" import ImageUser from "@/components/imageNew" import MenuItemRow from "@/components/menuItemRow" +import Skeleton from "@/components/skeleton" import Styles from "@/constants/Styles" import { apiDeleteCalendarMember, apiGetCalendarOne, apiGetDivisionOneFeature } from "@/lib/api" import { setUpdateCalendar } from "@/lib/calendarUpdate" @@ -49,6 +50,8 @@ export default function DetailEventCalendar() { const dispatch = useDispatch() const entityUser = useSelector((state: any) => state.user); const [isMemberDivision, setIsMemberDivision] = useState(false); + const [loading, setLoading] = useState(true) + const arrSkeleton = Array.from({ length: 5 }) async function handleCheckMember() { try { @@ -67,6 +70,7 @@ export default function DetailEventCalendar() { async function handleLoad() { try { + setLoading(true) const hasil = await decryptToken(String(token?.current)); const response = await apiGetCalendarOne({ user: hasil, @@ -76,6 +80,8 @@ export default function DetailEventCalendar() { setData(response.data); } catch (error) { console.error(error); + } finally { + setLoading(false) } } @@ -131,7 +137,7 @@ export default function DetailEventCalendar() { headerLeft: () => { router.back() }} />, headerTitle: 'Detail Acara', headerTitleAlign: 'center', - headerRight: () => (entityUser.role == "user" || entityUser.role == "coadmin") && !isMemberDivision ? <> : + headerRight: () => (entityUser.role == "user" || entityUser.role == "coadmin") && !isMemberDivision ? <> : }} /> @@ -139,36 +145,66 @@ export default function DetailEventCalendar() { - {data?.title} + { + loading ? + + : {data?.title} + } + - {data?.dateStart} + { + loading ? + + : + {data?.dateStart} + } - {data?.timeStart} | {data?.timeEnd} + { + loading ? + + : + {data?.timeStart} | {data?.timeEnd} + } - - { - data?.repeatEventTyper.toString() === 'once' ? 'Acara 1 Kali' : - data?.repeatEventTyper.toString() === 'daily' ? 'Setiap Hari' : - data?.repeatEventTyper.toString() === 'weekly' ? 'Mingguan' : - data?.repeatEventTyper.toString() === 'monthly' ? 'Bulanan' : - data?.repeatEventTyper.toString() === 'yearly' ? 'Tahunan' : - '' - } - + { + loading ? + + : + + { + data?.repeatEventTyper.toString() === 'once' ? 'Acara 1 Kali' : + data?.repeatEventTyper.toString() === 'daily' ? 'Setiap Hari' : + data?.repeatEventTyper.toString() === 'weekly' ? 'Mingguan' : + data?.repeatEventTyper.toString() === 'monthly' ? 'Bulanan' : + data?.repeatEventTyper.toString() === 'yearly' ? 'Tahunan' : + '' + } + + } - {data?.linkMeet ? data.linkMeet : '-'} + { + loading ? + + : + {data?.linkMeet ? data.linkMeet : '-'} + } - {data?.desc} + { + loading ? + + : + {data?.desc} + } diff --git a/app/(application)/division/[id]/(fitur-division)/calendar/history.tsx b/app/(application)/division/[id]/(fitur-division)/calendar/history.tsx index 11ce5b4..39215c9 100644 --- a/app/(application)/division/[id]/(fitur-division)/calendar/history.tsx +++ b/app/(application)/division/[id]/(fitur-division)/calendar/history.tsx @@ -1,6 +1,7 @@ import ButtonBackHeader from "@/components/buttonBackHeader"; import ItemHistoryEvent from "@/components/calendar/itemHistoryEvent"; import InputSearch from "@/components/inputSearch"; +import Skeleton from "@/components/skeleton"; import Styles from "@/constants/Styles"; import { apiGetCalendarHistory } from "@/lib/api"; import { useAuthSession } from "@/providers/AuthProvider"; @@ -10,7 +11,7 @@ import { SafeAreaView, ScrollView, View } from "react-native"; type Props = { dateStart: Date - year:string + year: string data: [] } export default function CalendarHistory() { @@ -18,14 +19,19 @@ export default function CalendarHistory() { const { token, decryptToken } = useAuthSession(); const [data, setData] = useState([]) const [search, setSearch] = useState('') + const [loading, setLoading] = useState(true) + const arrSkeleton = Array.from({ length: 5 }) async function handleLoad() { try { + setLoading(true) const hasil = await decryptToken(String(token?.current)); const response = await apiGetCalendarHistory({ user: hasil, search: search, division: id }); setData(response.data); } catch (error) { console.error(error); + } finally { + setLoading(false) } } @@ -45,7 +51,15 @@ export default function CalendarHistory() { setSearch(val)} /> - + { + loading ? + arrSkeleton.map((item, index) => ( + + )) + : + + } + diff --git a/app/(application)/division/[id]/(fitur-division)/calendar/index.tsx b/app/(application)/division/[id]/(fitur-division)/calendar/index.tsx index ffbe2a2..376c928 100644 --- a/app/(application)/division/[id]/(fitur-division)/calendar/index.tsx +++ b/app/(application)/division/[id]/(fitur-division)/calendar/index.tsx @@ -2,6 +2,7 @@ import ButtonBackHeader from "@/components/buttonBackHeader"; import HeaderRightCalendarList from "@/components/calendar/headerCalendarList"; import ItemDateCalendar from "@/components/calendar/itemDateCalendar"; import EventItem from "@/components/eventItem"; +import Skeleton from "@/components/skeleton"; import Styles from "@/constants/Styles"; import { apiGetCalendarByDateDivision, apiGetIndicatorCalendar } from "@/lib/api"; import { useAuthSession } from "@/providers/AuthProvider"; @@ -15,7 +16,7 @@ import Datepicker, { CalendarComponents, CalendarDay } from "react-native-ui-datepicker"; -import { useDispatch, useSelector } from "react-redux"; +import { useSelector } from "react-redux"; type Props = { id: string; @@ -38,10 +39,12 @@ export default function CalendarDivision() { const [dataIndicator, setDataIndicator] = useState([]); const [month, setMonth] = useState(new Date().getMonth()); const update = useSelector((state: any) => state.calendarUpdate) + const [loading, setLoading] = useState(true) - async function handleLoad() { + async function handleLoad(loading: boolean) { try { + setLoading(loading) const hasil = await decryptToken(String(token?.current)); const response = await apiGetCalendarByDateDivision({ user: hasil, @@ -51,6 +54,8 @@ export default function CalendarDivision() { setData(response.data); } catch (error) { console.error(error); + } finally { + setLoading(false) } } @@ -70,8 +75,12 @@ export default function CalendarDivision() { } useEffect(() => { - handleLoad(); - }, [selected, update.data]); + handleLoad(true) + }, [selected]) + + useEffect(() => { + handleLoad(false); + }, [update.data]); useEffect(() => { handleLoadIndicator(); @@ -133,23 +142,31 @@ export default function CalendarDivision() { Acara - {data.length > 0 ? ( - data.map((item, index) => ( - { - router.push(`./calendar/${item.id}`); - }} - /> - )) - ) : ( - Tidak ada acara - )} + { + loading ? + <> + + + + : + data.length > 0 ? ( + data.map((item, index) => ( + { + router.push(`./calendar/${item.id}`); + }} + /> + )) + ) : ( + Tidak ada acara + ) + } diff --git a/app/(application)/division/[id]/(fitur-division)/discussion/[detail]/index.tsx b/app/(application)/division/[id]/(fitur-division)/discussion/[detail]/index.tsx index a3920e0..4ded1be 100644 --- a/app/(application)/division/[id]/(fitur-division)/discussion/[detail]/index.tsx +++ b/app/(application)/division/[id]/(fitur-division)/discussion/[detail]/index.tsx @@ -4,6 +4,8 @@ import HeaderRightDiscussionDetail from "@/components/discussion/headerDiscussio import ImageUser from "@/components/imageNew"; import { InputForm } from "@/components/inputForm"; import LabelStatus from "@/components/labelStatus"; +import Skeleton from "@/components/skeleton"; +import SkeletonContent from "@/components/skeletonContent"; import Styles from "@/constants/Styles"; import { apiGetDiscussionOne, @@ -50,9 +52,13 @@ export default function DiscussionDetail() { const [isMemberDivision, setIsMemberDivision] = useState(false); const [isAdminDivision, setIsAdminDivision] = useState(false); const [isCreator, setIsCreator] = useState(false); + const [loading, setLoading] = useState(true) + const [loadingKomentar, setLoadingKomentar] = useState(true) + const arrSkeleton = Array.from({ length: 3 }) - async function handleLoad() { + async function handleLoad(loading: boolean) { try { + setLoading(loading) const hasil = await decryptToken(String(token?.current)); const response = await apiGetDiscussionOne({ id: detail, @@ -63,11 +69,14 @@ export default function DiscussionDetail() { setIsCreator(response.data.createdBy == hasil); } catch (error) { console.error(error); + } finally { + setLoading(false) } } - async function handleLoadComment() { + async function handleLoadComment(loading: boolean) { try { + setLoadingKomentar(loading) const hasil = await decryptToken(String(token?.current)); const response = await apiGetDiscussionOne({ id: detail, @@ -77,6 +86,8 @@ export default function DiscussionDetail() { setDataComment(response.data); } catch (error) { console.error(error); + } finally { + setLoadingKomentar(false) } } @@ -102,11 +113,12 @@ export default function DiscussionDetail() { } useEffect(() => { - handleLoad(); + handleLoad(false); }, [update.data]); useEffect(() => { - handleLoadComment(); + handleLoad(true) + handleLoadComment(true); handleCheckMember(); }, []); @@ -120,7 +132,7 @@ export default function DiscussionDetail() { }); if (response.success) { setKomentar(""); - handleLoadComment(); + handleLoadComment(false); } } catch (error) { console.error(error); @@ -155,64 +167,78 @@ export default function DiscussionDetail() { - - } - title={data?.username} - subtitle={ - data?.isActive ? ( - data?.status == 1 ? ( - - ) : ( - - ) - ) : ( - - ) - } - rightTopInfo={data?.createdAt} - desc={data?.desc} - leftBottomInfo={ - - - - {dataComment.length} Komentar - - - } - /> - - {dataComment.map((item, index) => ( + { + loading ? + + : } - title={item.username} - rightTopInfo={item.createdAt} - desc={item.comment} - descEllipsize={false} + title={data?.username} + subtitle={ + data?.isActive ? ( + data?.status == 1 ? ( + + ) : ( + + ) + ) : ( + + ) + } + rightTopInfo={data?.createdAt} + desc={data?.desc} + leftBottomInfo={ + + + + {dataComment.length} Komentar + + + } /> - ))} + } + + + { + loadingKomentar ? + arrSkeleton.map((item, index) => ( + + )) + : + dataComment.map((item, index) => ( + + } + title={item.username} + rightTopInfo={item.createdAt} + desc={item.comment} + descEllipsize={false} + /> + )) + } + diff --git a/app/(application)/division/[id]/(fitur-division)/discussion/index.tsx b/app/(application)/division/[id]/(fitur-division)/discussion/index.tsx index a2a19f2..e4daa41 100644 --- a/app/(application)/division/[id]/(fitur-division)/discussion/index.tsx +++ b/app/(application)/division/[id]/(fitur-division)/discussion/index.tsx @@ -3,8 +3,9 @@ import ButtonTab from "@/components/buttonTab"; import ImageUser from "@/components/imageNew"; import InputSearch from "@/components/inputSearch"; import LabelStatus from "@/components/labelStatus"; +import SkeletonContent from "@/components/skeletonContent"; import Styles from "@/constants/Styles"; -import { apiGetDiscussion, apiGetDivisionOneFeature } from "@/lib/api"; +import { apiGetDiscussion } from "@/lib/api"; import { useAuthSession } from "@/providers/AuthProvider"; import { AntDesign, Feather, Ionicons } from "@expo/vector-icons"; import { router, useLocalSearchParams } from "expo-router"; @@ -32,21 +33,30 @@ export default function DiscussionDivision() { const { token, decryptToken } = useAuthSession() const [search, setSearch] = useState('') const update = useSelector((state: any) => state.discussionUpdate); + const [loading, setLoading] = useState(true) + const arrSkeleton = Array.from({ length: 5 }) - async function handleLoad() { + async function handleLoad(loading: boolean) { try { + setLoading(loading) const hasil = await decryptToken(String(token?.current)) const response = await apiGetDiscussion({ user: hasil, search, division: id, active }) setData(response.data) } catch (error) { console.error(error) + } finally { + setLoading(false) } } + useEffect(() => { + handleLoad(false) + }, [update.data]) + useEffect(() => { - handleLoad() - }, [active, search, update.data]) + handleLoad(true) + }, [active, search]) return ( @@ -70,35 +80,44 @@ export default function DiscussionDivision() { - {data.length > 0 ? - data.map((item, index) => ( - { router.push(`./discussion/${item.id}`) }} - borderType="bottom" - icon={ - - } - title={item.user_name} - subtitle={ - active == "true" ? item.status == 1 ? : : <> - } - rightTopInfo={item.createdAt} - desc={item.desc} - leftBottomInfo={ - - - Diskusikan - - } - rightBottomInfo={item.total_komentar + ' Komentar'} - /> - )) - : - ( - Tidak ada diskusi - )} + { + loading ? + arrSkeleton.map((item: any, i: number) => { + return ( + + ) + }) + : + data.length > 0 ? + data.map((item, index) => ( + { router.push(`./discussion/${item.id}`) }} + borderType="bottom" + icon={ + + } + title={item.user_name} + subtitle={ + active == "true" ? item.status == 1 ? : : <> + } + rightTopInfo={item.createdAt} + desc={item.desc} + leftBottomInfo={ + + + Diskusikan + + } + rightBottomInfo={item.total_komentar + ' Komentar'} + /> + )) + : + ( + Tidak ada diskusi + ) + } diff --git a/app/(application)/division/[id]/(fitur-division)/task/index.tsx b/app/(application)/division/[id]/(fitur-division)/task/index.tsx index e53bb81..220c380 100644 --- a/app/(application)/division/[id]/(fitur-division)/task/index.tsx +++ b/app/(application)/division/[id]/(fitur-division)/task/index.tsx @@ -4,6 +4,8 @@ import InputSearch from "@/components/inputSearch"; import LabelStatus from "@/components/labelStatus"; import PaperGridContent from "@/components/paperGridContent"; import ProgressBar from "@/components/progressBar"; +import Skeleton from "@/components/skeleton"; +import SkeletonTwoItem from "@/components/skeletonTwoItem"; import { ColorsStatus } from "@/constants/ColorsStatus"; import Styles from "@/constants/Styles"; import { apiGetTask } from "@/lib/api"; @@ -34,9 +36,12 @@ export default function ListTask() { const [data, setData] = useState([]); const [search, setSearch] = useState(""); const update = useSelector((state: any) => state.taskUpdate) + const [loading, setLoading] = useState(true) + const arrSkeleton = Array.from({ length: 3 }) - async function handleLoad() { + async function handleLoad(loading: boolean) { try { + setLoading(loading) const hasil = await decryptToken(String(token?.current)); const response = await apiGetTask({ user: hasil, @@ -47,12 +52,18 @@ export default function ListTask() { setData(response.data); } catch (error) { console.error(error); + } finally { + setLoading(false) } } useEffect(() => { - handleLoad(); - }, [status, search, update.data]); + handleLoad(false) + }, [update.data]) + + useEffect(() => { + handleLoad(true); + }, [status, search]); return ( @@ -138,74 +149,87 @@ export default function ListTask() { /> - {data.length > 0 ? ( - <> - ) : ( - - Tidak ada data - - )} - {isList ? ( - - {data.map((item, index) => ( - { - router.push(`./task/${item.id}`); - }} - borderType="bottom" - icon={ - - - - } - title={item.title} - /> - ))} - - ) : ( - - {data.map((item, index) => ( - { - router.push(`./task/${item.id}`); - }} - content="page" - title={item.title} - headerColor="primary" - > - - - - + { + + loading ? + isList ? + arrSkeleton.map((item, index) => ( + + )) + : + arrSkeleton.map((item, index) => ( + + )) + : + data.length > 0 ? ( + isList ? ( + + {data.map((item, index) => ( + { + router.push(`./task/${item.id}`); + }} + borderType="bottom" + icon={ + + + + } + title={item.title} + /> + ))} - - ))} - - )} + ) : ( + + {data.map((item, index) => ( + { + router.push(`./task/${item.id}`); + }} + content="page" + title={item.title} + headerColor="primary" + > + + + + + + + ))} + + ) + ) : ( + + Tidak ada data + + ) + + } diff --git a/app/(application)/division/[id]/info.tsx b/app/(application)/division/[id]/info.tsx index 571a013..ed2386a 100644 --- a/app/(application)/division/[id]/info.tsx +++ b/app/(application)/division/[id]/info.tsx @@ -5,6 +5,8 @@ import HeaderRightDivisionInfo from "@/components/division/headerDivisionInfo" import DrawerBottom from "@/components/drawerBottom" import ImageUser from "@/components/imageNew" import SectionCancel from "@/components/sectionCancel" +import Skeleton from "@/components/skeleton" +import SkeletonTwoItem from "@/components/skeletonTwoItem" import { ColorsStatus } from "@/constants/ColorsStatus" import Styles from "@/constants/Styles" import { apiDeleteMemberDivision, apiGetDivisionOneDetail, apiUpdateStatusAdminDivision } from "@/lib/api" @@ -41,6 +43,8 @@ export default function InformationDivision() { const [dataMember, setDataMember] = useState([]) const [refresh, setRefresh] = useState(false) const update = useSelector((state: any) => state.divisionUpdate) + const arrSkeleton = Array.from({ length: 5 }, (_, index) => index) + const [loading, setLoading] = useState(true) const [dataMemberChoose, setDataMemberChoose] = useState({ id: '', name: '', @@ -91,21 +95,28 @@ export default function InformationDivision() { } } - async function handleLoad() { + async function handleLoad(loading: boolean) { try { + setLoading(loading) const hasil = await decryptToken(String(token?.current)) const response = await apiGetDivisionOneDetail({ user: hasil, id }) setDataDetail(response.data.division) setDataMember(response.data.member) } catch (error) { console.error(error) + } finally { + setLoading(false) } } useEffect(() => { - handleLoad() + handleLoad(false) }, [refresh, update]) + useEffect(() => { + handleLoad(true) + }, []) + function handleChooseMember(item: PropsMember) { setDataMemberChoose(item) setModal(true) @@ -118,7 +129,7 @@ export default function InformationDivision() { headerLeft: () => { router.back() }} />, headerTitle: 'Informasi Divisi', headerTitleAlign: 'center', - headerRight: () => , + headerRight: () => , }} /> @@ -131,7 +142,15 @@ export default function InformationDivision() { Deskripsi Divisi - {dataDetail?.desc} + {loading ? + arrSkeleton.map((item, index) => { + return ( + + ) + }) + : + {dataDetail?.desc} + } @@ -153,21 +172,28 @@ export default function InformationDivision() { } { - dataMember.map((item, index) => { - return ( - { dataDetail?.isActive && handleChooseMember(item) }} - icon={ - - } - title={item.name} - rightTopInfo={item.isAdmin ? "Admin" : "Anggota"} - /> - ) - }) + loading ? + arrSkeleton.map((item, index) => { + return ( + + ) + }) + : + dataMember.map((item, index) => { + return ( + { dataDetail?.isActive && handleChooseMember(item) }} + icon={ + + } + title={item.name} + rightTopInfo={item.isAdmin ? "Admin" : "Anggota"} + /> + ) + }) } diff --git a/app/(application)/division/index.tsx b/app/(application)/division/index.tsx index 6492101..fa83515 100644 --- a/app/(application)/division/index.tsx +++ b/app/(application)/division/index.tsx @@ -2,6 +2,8 @@ import BorderBottomItem from "@/components/borderBottomItem"; import ButtonTab from "@/components/buttonTab"; import InputSearch from "@/components/inputSearch"; import PaperGridContent from "@/components/paperGridContent"; +import Skeleton from "@/components/skeleton"; +import SkeletonTwoItem from "@/components/skeletonTwoItem"; import { ColorsStatus } from "@/constants/ColorsStatus"; import Styles from "@/constants/Styles"; import { apiGetDivision } from "@/lib/api"; @@ -38,9 +40,12 @@ export default function ListDivision() { const [nameGroup, setNameGroup] = useState(""); const [data, setData] = useState([]); const update = useSelector((state: any) => state.divisionUpdate) + const arrSkeleton = Array.from({ length: 3 }, (_, index) => index) + const [loading, setLoading] = useState(false) - async function handleLoad() { + async function handleLoad(loading: boolean) { try { + setLoading(loading) const hasil = await decryptToken(String(token?.current)); const response = await apiGetDivision({ user: hasil, @@ -56,12 +61,18 @@ export default function ListDivision() { } } catch (error) { console.error(error); + } finally { + setLoading(false) } } useEffect(() => { - handleLoad(); - }, [active, search, group, cat, update]); + handleLoad(false); + }, [update]); + + useEffect(() => { + handleLoad(true); + }, [active, search, group, cat]); return ( @@ -162,47 +173,57 @@ export default function ListDivision() { )} { - data.length == 0 ? ( - - Tidak ada data - - ) : ( - isList ? ( - - {data.map((item, index) => ( - { }} - borderType="bottom" - icon={ - - - - } - title={item.name} - titleWeight="normal" - /> - ))} + loading ? + isList ? + arrSkeleton.map((item, index) => ( + + )) + : + arrSkeleton.map((item, index) => ( + + )) + : + data.length == 0 ? ( + + Tidak ada data ) : ( - - {data.map((item, index) => ( - { - router.push(`/division/${item.id}`); - }} - content="page" - title={item.name} - headerColor="primary" - contentPosition="top" - > - {item.desc} - - ))} - + isList ? ( + + {data.map((item, index) => ( + { }} + borderType="bottom" + icon={ + + + + } + title={item.name} + titleWeight="normal" + /> + ))} + + ) : ( + + {data.map((item, index) => ( + { + router.push(`/division/${item.id}`); + }} + content="page" + title={item.name} + headerColor="primary" + contentPosition="top" + > + {item.desc} + + ))} + + ) ) - ) } diff --git a/components/calendar/headerCalendarDetail.tsx b/components/calendar/headerCalendarDetail.tsx index c9142c8..88ee69e 100644 --- a/components/calendar/headerCalendarDetail.tsx +++ b/components/calendar/headerCalendarDetail.tsx @@ -13,10 +13,11 @@ import DrawerBottom from "../drawerBottom" import MenuItemRow from "../menuItemRow" type Props = { - id: string | string[] + id: string | string[], + idReminder?: string } -export default function HeaderRightCalendarDetail({ id }: Props) { +export default function HeaderRightCalendarDetail({ id, idReminder }: Props) { const [isVisible, setVisible] = useState(false) const { token, decryptToken } = useAuthSession() const update = useSelector((state: any) => state.calendarUpdate) @@ -51,7 +52,7 @@ export default function HeaderRightCalendarDetail({ id }: Props) { title="Tambah Anggota" onPress={() => { setVisible(false) - router.push(`./${id}/add-member`) + router.push(`./${idReminder}/add-member`) }} /> (); const [data, setData] = useState([]); + const [loading, setLoading] = useState(true) async function handleLoad() { try { + setLoading(true) const hasil = await decryptToken(String(token?.current)); const response = await apiGetDivisionOneFeature({ user: hasil, @@ -30,6 +33,8 @@ export default function DiscussionDivisionDetail() { setData(response.data); } catch (error) { console.error(error); + } finally { + setLoading(false) } } @@ -40,25 +45,34 @@ export default function DiscussionDivisionDetail() { Diskusi - {data.length > 0 ? ( - data.map((item, index) => ( - { - router.push(`/division/${id}/discussion/${item.id}`); - }} - /> - )) - ) : ( - - Tidak ada diskusi - - )} + + { + loading ? + <> + + + + : + data.length > 0 ? ( + data.map((item, index) => ( + { + router.push(`/division/${id}/discussion/${item.id}`); + }} + /> + )) + ) : ( + + Tidak ada diskusi + + ) + } ); diff --git a/components/division/fileDivisionDetail.tsx b/components/division/fileDivisionDetail.tsx index 4ca3e03..e9c94f1 100644 --- a/components/division/fileDivisionDetail.tsx +++ b/components/division/fileDivisionDetail.tsx @@ -1,11 +1,12 @@ import Styles from "@/constants/Styles"; +import { apiGetDivisionOneFeature } from "@/lib/api"; +import { useAuthSession } from "@/providers/AuthProvider"; import { Feather } from "@expo/vector-icons"; +import { useLocalSearchParams } from "expo-router"; import React, { useEffect, useState } from "react"; import { Dimensions, Text, View } from "react-native"; import Carousel, { ICarouselInstance } from "react-native-reanimated-carousel"; -import { useAuthSession } from "@/providers/AuthProvider"; -import { useLocalSearchParams } from "expo-router"; -import { apiGetDivisionOneFeature } from "@/lib/api"; +import Skeleton from "../skeleton"; type Props = { id: string @@ -21,14 +22,18 @@ export default function FileDivisionDetail() { const [data, setData] = useState([]) const { token, decryptToken } = useAuthSession() const { id } = useLocalSearchParams<{ id: string }>() + const [loading, setLoading] = useState(true) async function handleLoad() { try { + setLoading(true) const hasil = await decryptToken(String(token?.current)) const response = await apiGetDivisionOneFeature({ user: hasil, id, cat: 'new-file' }) setData(response.data) } catch (error) { console.error(error) + } finally { + setLoading(false) } } @@ -40,40 +45,47 @@ export default function FileDivisionDetail() { Dokumen Terkini { - data.length > 0 ? - ( - - - - - - - {data[index].name}.{data[index].extension} - - - )} - /> + loading ? + + + + + : - Tidak ada file + data.length > 0 ? + ( + + + + + + + {data[index].name}.{data[index].extension} + + + )} + /> + : + Tidak ada file } ) diff --git a/components/division/taskDivisionDetail.tsx b/components/division/taskDivisionDetail.tsx index 0773bb0..4f49bba 100644 --- a/components/division/taskDivisionDetail.tsx +++ b/components/division/taskDivisionDetail.tsx @@ -6,6 +6,7 @@ import { useLocalSearchParams } from "expo-router"; import React, { useEffect, useState } from "react"; import { Dimensions, Text, View } from "react-native"; import Carousel, { ICarouselInstance } from "react-native-reanimated-carousel"; +import Skeleton from "../skeleton"; type Props = { id: string @@ -22,14 +23,18 @@ export default function TaskDivisionDetail() { const [data, setData] = useState([]) const ref = React.useRef(null); const width = Dimensions.get("window").width; + const [loading, setLoading] = useState(true) async function handleLoad() { try { + setLoading(true) const hasil = await decryptToken(String(token?.current)) const response = await apiGetDivisionOneFeature({ user: hasil, id, cat: 'today-task' }) setData(response.data) } catch (error) { console.error(error) + } finally { + setLoading(false) } } @@ -40,32 +45,36 @@ export default function TaskDivisionDetail() { return ( Tugas Hari Ini + { - data.length > 0 ? - ( - - {data[index].title} - {data[index].projectTitle} - - - {data[index].dateStart} - {data[index].dateEnd} - - - )} - /> + loading ? + : - Tidak ada tugas + data.length > 0 ? + ( + + {data[index].title} - {data[index].projectTitle} + + + {data[index].dateStart} - {data[index].dateEnd} + + + )} + /> + : + Tidak ada tugas } )