diff --git a/app/(application)/announcement/[id].tsx b/app/(application)/announcement/[id].tsx index aec3f1a..f59bae2 100644 --- a/app/(application)/announcement/[id].tsx +++ b/app/(application)/announcement/[id].tsx @@ -1,9 +1,10 @@ import HeaderRightAnnouncementDetail from "@/components/announcement/headerAnnouncementDetail"; import ButtonBackHeader from "@/components/buttonBackHeader"; +import Skeleton from "@/components/skeleton"; import Styles from "@/constants/Styles"; import { apiGetAnnouncementOne } from "@/lib/api"; import { useAuthSession } from "@/providers/AuthProvider"; -import { AntDesign, Entypo, MaterialIcons } from "@expo/vector-icons"; +import { Entypo, MaterialIcons } from "@expo/vector-icons"; import { router, Stack, useLocalSearchParams } from "expo-router"; import { useEffect, useState } from "react"; import { Dimensions, SafeAreaView, ScrollView, Text, View } from "react-native"; @@ -24,22 +25,31 @@ export default function DetailAnnouncement() { const update = useSelector((state: any) => state.announcementUpdate) const entityUser = useSelector((state: any) => state.user) const contentWidth = Dimensions.get('window').width + const [loading, setLoading] = useState(true) + const arrSkeleton = Array.from({ length: 2 }, (_, index) => index) - async function handleLoad() { + async function handleLoad(loading: boolean) { try { + setLoading(loading) const hasil = await decryptToken(String(token?.current)) const response = await apiGetAnnouncementOne({ id: id, user: hasil }) setData(response.data) setDataMember(response.member) } catch (error) { console.error(error) + } finally { + setLoading(false) } } useEffect(() => { - handleLoad() + handleLoad(false) }, [update]) + useEffect(() => { + handleLoad(true) + }, []) + return ( - - - {data?.title} - - - - + { + loading ? + + + + + + + + + + + + : + <> + + + {data?.title} + + + + + + } + { - Object.keys(dataMember).map((v: any, i: any) => { - return ( - - {dataMember[v]?.[0].group} - { - dataMember[v].map((item: any, x: any) => { - return ( - - - {item.division} - - ) - }) - } + loading ? + arrSkeleton.map((item, index) => { + return ( + + + + + + ) + }) + : + Object.keys(dataMember).map((v: any, i: any) => { + return ( + + {dataMember[v]?.[0].group} + { + dataMember[v].map((item: any, x: any) => { + return ( + + + {item.division} + + ) + }) + } - - ) - }) + + ) + }) } diff --git a/app/(application)/announcement/index.tsx b/app/(application)/announcement/index.tsx index 65119e5..2ce1d3a 100644 --- a/app/(application)/announcement/index.tsx +++ b/app/(application)/announcement/index.tsx @@ -2,6 +2,7 @@ import HeaderRightAnnouncementList from "@/components/announcement/headerAnnounc import BorderBottomItem from "@/components/borderBottomItem"; import ButtonBackHeader from "@/components/buttonBackHeader"; import InputSearch from "@/components/inputSearch"; +import SkeletonContent from "@/components/skeletonContent"; import { ColorsStatus } from "@/constants/ColorsStatus"; import Styles from "@/constants/Styles"; import { apiGetAnnouncement } from "@/lib/api"; @@ -26,20 +27,29 @@ export default function Announcement() { const [search, setSearch] = useState('') const entityUser = useSelector((state: any) => state.user) const update = useSelector((state: any) => state.announcementUpdate) + const [loading, setLoading] = useState(true) + const arrSkeleton = Array.from({ length: 5 }, (_, index) => index) - async function handleLoad() { + async function handleLoad(loading: boolean) { try { + setLoading(loading) const hasil = await decryptToken(String(token?.current)) const response = await apiGetAnnouncement({ user: hasil, search: search }) setData(response.data) } catch (error) { console.error(error) + } finally { + setLoading(false) } } useEffect(() => { - handleLoad() - }, [search, update]) + handleLoad(false) + }, [update]) + + useEffect(() => { + handleLoad(true) + }, [search]) return ( @@ -56,27 +66,34 @@ export default function Announcement() { { - data.length > 0 - ? - data.map((item, index) => { + loading ? + arrSkeleton.map((item, index) => { return ( - { router.push(`/announcement/${item.id}`) }} - borderType="bottom" - icon={ - - - - } - title={item.title} - desc={item.desc.replace(/<[^>]*>?/gm, '')} - rightTopInfo={item.createdAt} - /> + ) }) : - Tidak ada pengumuman + data.length > 0 + ? + data.map((item, index) => { + return ( + { router.push(`/announcement/${item.id}`) }} + borderType="bottom" + icon={ + + + + } + title={item.title} + desc={item.desc.replace(/<[^>]*>?/gm, '')} + rightTopInfo={item.createdAt} + /> + ) + }) + : + Tidak ada pengumuman } diff --git a/app/(application)/discussion/[id].tsx b/app/(application)/discussion/[id].tsx index c6e1c8a..2442b0a 100644 --- a/app/(application)/discussion/[id].tsx +++ b/app/(application)/discussion/[id].tsx @@ -4,6 +4,8 @@ import HeaderRightDiscussionGeneralDetail from "@/components/discussion_general/ 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 { ColorsStatus } from "@/constants/ColorsStatus"; import Styles from "@/constants/Styles"; import { apiGetDiscussionGeneralOne, apiSendDiscussionGeneralCommentar } from "@/lib/api"; @@ -41,12 +43,22 @@ export default function DetailDiscussionGeneral() { const [memberDiscussion, setMemberDiscussion] = useState(false) const [komentar, setKomentar] = useState('') const update = useSelector((state: any) => state.discussionGeneralDetailUpdate) + const [loading, setLoading] = useState(true) + const [loadingKomentar, setLoadingKomentar] = useState(true) + const arrSkeleton = Array.from({ length: 3 }, (_, index) => index) - async function handleLoad(cat: 'detail' | 'komentar' | 'cek-anggota') { + async function handleLoad(cat: 'detail' | 'komentar' | 'cek-anggota', loading: boolean) { try { + if (cat == "detail") { + setLoading(loading) + } else if (cat == "komentar") { + setLoadingKomentar(loading) + } + const hasil = await decryptToken(String(token?.current)) const response = await apiGetDiscussionGeneralOne({ id: id, user: hasil, cat }) + if (cat == 'detail') { setData(response.data) } else if (cat == 'komentar') { @@ -54,17 +66,27 @@ export default function DetailDiscussionGeneral() { } else if (cat == 'cek-anggota') { setMemberDiscussion(response.data) } + } catch (error) { console.error(error) + } finally { + setLoading(false) + setLoadingKomentar(false) } } useEffect(() => { - handleLoad('detail') - handleLoad('komentar') - handleLoad('cek-anggota') + handleLoad('detail', false) + handleLoad('komentar', false) + handleLoad('cek-anggota', false) }, [update]); + useEffect(() => { + handleLoad('detail', true) + handleLoad('komentar', true) + handleLoad('cek-anggota', true) + }, []); + async function handleKomentar() { try { if (komentar != '') { @@ -72,7 +94,7 @@ export default function DetailDiscussionGeneral() { const response = await apiSendDiscussionGeneralCommentar({ id: id, data: { desc: komentar, user: hasil } }) if (response.success) { setKomentar('') - handleLoad('komentar') + handleLoad('komentar', false) } } } catch (error) { @@ -93,45 +115,57 @@ export default function DetailDiscussionGeneral() { - - - - } - title={data?.title} - subtitle={ - !data?.isActive ? - - : - - } - rightTopInfo={data?.createdAt} - desc={data?.desc} - leftBottomInfo={ - - - {dataKomentar.length} Komentar - - } - /> + { + loading ? + + : + + + + } + title={data?.title} + subtitle={ + !data?.isActive ? + + : + + } + rightTopInfo={data?.createdAt} + desc={data?.desc} + leftBottomInfo={ + + + {dataKomentar.length} Komentar + + } + /> + } { - dataKomentar.map((item, i) => { - return ( - - } - title={item.username} - rightTopInfo={item.createdAt} - desc={item.comment} - /> - ) - }) + loadingKomentar ? + arrSkeleton.map((item: any, i: number) => { + return ( + + ) + }) + : + dataKomentar.map((item, i) => { + return ( + + } + title={item.username} + rightTopInfo={item.createdAt} + desc={item.comment} + /> + ) + }) } diff --git a/app/(application)/discussion/index.tsx b/app/(application)/discussion/index.tsx index b811bed..64b7ebc 100644 --- a/app/(application)/discussion/index.tsx +++ b/app/(application)/discussion/index.tsx @@ -2,6 +2,7 @@ import BorderBottomItem from "@/components/borderBottomItem"; import ButtonTab from "@/components/buttonTab"; import InputSearch from "@/components/inputSearch"; import LabelStatus from "@/components/labelStatus"; +import SkeletonContent from "@/components/skeletonContent"; import { ColorsStatus } from "@/constants/ColorsStatus"; import Styles from "@/constants/Styles"; import { apiGetDiscussionGeneral } from "@/lib/api"; @@ -30,21 +31,30 @@ export default function Discussion() { const [nameGroup, setNameGroup] = useState('') const [data, setData] = useState([]) const update = useSelector((state: any) => state.discussionGeneralDetailUpdate) + const [loading, setLoading] = useState(true) + const arrSkeleton = Array.from({ length: 5 }, (_, index) => index) - async function handleLoad() { + async function handleLoad(loading: boolean) { try { + setLoading(loading) const hasil = await decryptToken(String(token?.current)) const response = await apiGetDiscussionGeneral({ user: hasil, active: String(active), search: search, group: String(group) }) setData(response.data) setNameGroup(response.filter.name) } catch (error) { console.error(error) + } finally { + setLoading(false) } } useEffect(() => { - handleLoad() - }, [active, search, group, update]) + handleLoad(true) + }, [active, search, group]) + + useEffect(() => { + handleLoad(false) + }, [update]) return ( @@ -75,37 +85,45 @@ export default function Discussion() { } { - data.length > 0 - ? - data.map((item: any, i: number) => { + loading ? + arrSkeleton.map((item: any, i: number) => { return ( - { router.push(`/discussion/${item.id}`) }} - borderType="bottom" - icon={ - - - - } - title={item.title} - subtitle={ - active != "false" && - } - rightTopInfo={item.createdAt} - desc={item.desc} - leftBottomInfo={ - - - Diskusikan - - } - rightBottomInfo={`${item.total_komentar} Komentar`} - /> + ) }) : - Tidak ada data + data.length > 0 + ? + data.map((item: any, i: number) => { + return ( + { router.push(`/discussion/${item.id}`) }} + borderType="bottom" + icon={ + + + + } + title={item.title} + subtitle={ + active != "false" && + } + rightTopInfo={item.createdAt} + desc={item.desc} + leftBottomInfo={ + + + Diskusikan + + } + rightBottomInfo={`${item.total_komentar} Komentar`} + + /> + ) + }) + : + Tidak ada data } diff --git a/app/(application)/discussion/member/[id].tsx b/app/(application)/discussion/member/[id].tsx index 52d5bca..948fe8b 100644 --- a/app/(application)/discussion/member/[id].tsx +++ b/app/(application)/discussion/member/[id].tsx @@ -4,6 +4,7 @@ import ButtonBackHeader from "@/components/buttonBackHeader"; import DrawerBottom from "@/components/drawerBottom"; import ImageUser from "@/components/imageNew"; import MenuItemRow from "@/components/menuItemRow"; +import SkeletonTwoItem from "@/components/skeletonTwoItem"; import { ColorsStatus } from "@/constants/ColorsStatus"; import Styles from "@/constants/Styles"; import { apiDeleteMemberDiscussionGeneral, apiGetDiscussionGeneralOne } from "@/lib/api"; @@ -28,28 +29,37 @@ export default function MemberDiscussionDetail() { const [isModal, setModal] = useState(false) const [chooseUser, setChooseUser] = useState({ idUser: '', name: '', img: '' }) const update = useSelector((state: any) => state.discussionGeneralDetailUpdate) + const [loading, setLoading] = useState(true) + const arrSkeleton = Array.from({ length: 5 }, (_, index) => index) - async function handleLoad() { + async function handleLoad(loading: boolean) { try { + setLoading(loading) const hasil = await decryptToken(String(token?.current)) const response = await apiGetDiscussionGeneralOne({ id: id, user: hasil, cat: 'anggota' }) setData(response.data) } catch (error) { console.error(error) + } finally { + setLoading(false) } } + useEffect(() => { + handleLoad(false) + }, [update]); + useEffect(() => { - handleLoad() - }, [update]); + handleLoad(true) + }, []); async function handleDeleteUser() { try { const hasil = await decryptToken(String(token?.current)) await apiDeleteMemberDiscussionGeneral({ user: hasil, idUser: chooseUser.idUser }, id) - ToastAndroid.show("Berhasil mengelluarkan anggota dari diskusi", ToastAndroid.SHORT) - handleLoad() + ToastAndroid.show("Berhasil mengeluarkan anggota dari diskusi", ToastAndroid.SHORT) + handleLoad(false) } catch (error) { console.error(error) } finally { @@ -84,22 +94,29 @@ export default function MemberDiscussionDetail() { /> } { - data.map((item, index) => { - return ( - - } - title={item.name} - onPress={() => { - setChooseUser(item) - setModal(true) - }} - /> - ) - }) + loading ? + arrSkeleton.map((item, index) => { + return ( + + ) + }) + : + data.map((item, index) => { + return ( + + } + title={item.name} + onPress={() => { + setChooseUser(item) + setModal(true) + }} + /> + ) + }) } diff --git a/app/(application)/group/index.tsx b/app/(application)/group/index.tsx index cda4c4c..fb94348 100644 --- a/app/(application)/group/index.tsx +++ b/app/(application)/group/index.tsx @@ -84,13 +84,15 @@ export default function Index() { } } + useEffect(() => { + handleLoad(false) + }, [update]) + useEffect(() => { handleLoad(true) }, [active, search]) - useEffect(() => { - handleLoad(false) - }, [update]) + return ( diff --git a/app/(application)/position/index.tsx b/app/(application)/position/index.tsx index 32c8d79..4af328f 100644 --- a/app/(application)/position/index.tsx +++ b/app/(application)/position/index.tsx @@ -59,15 +59,16 @@ export default function Index() { } } - useEffect(() => { - handleLoad(true) - }, [active, search, group]) - useEffect(() => { handleLoad(false) }, [update]) + useEffect(() => { + handleLoad(true) + }, [active, search, group]) + + function handleChooseData(id: string, name: string, active: boolean, group: string) { setChooseData({ id, name, active, idGroup: group }) setModal(true) diff --git a/app/(application)/project/[id]/index.tsx b/app/(application)/project/[id]/index.tsx index d26c05b..e1f0a8d 100644 --- a/app/(application)/project/[id]/index.tsx +++ b/app/(application)/project/[id]/index.tsx @@ -78,7 +78,7 @@ export default function DetailProject() { { router.back() }} />, - headerTitle: loading ? 'Loading...' : data?.title, + headerTitle: loading ? 'Loading... ' : data?.title, headerTitleAlign: 'center', headerRight: () => (entityUser.role == "user" || entityUser.role == "coadmin") && !isMember ? null : , }} diff --git a/app/(application)/project/index.tsx b/app/(application)/project/index.tsx index c8ac00d..3db4ed0 100644 --- a/app/(application)/project/index.tsx +++ b/app/(application)/project/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 { apiGetProject } from "@/lib/api"; @@ -41,9 +43,12 @@ export default function ListProject() { const [data, setData] = useState([]); const [isList, setList] = useState(false); const update = useSelector((state: any) => state.projectUpdate) + const [loading, setLoading] = useState(true) + const arrSkeleton = Array.from({ length: 3 }, (_, index) => index) - async function handleLoad() { + async function handleLoad(loading: boolean) { try { + setLoading(loading) const hasil = await decryptToken(String(token?.current)); const response = await apiGetProject({ user: hasil, @@ -59,12 +64,19 @@ export default function ListProject() { } } catch (error) { console.error(error); + } finally { + setLoading(false) } } useEffect(() => { - handleLoad(); - }, [status, search, group, cat, update.data]); + handleLoad(false); + }, [update.data]); + + + useEffect(() => { + handleLoad(true); + }, [status, search, group, cat]); return ( @@ -75,7 +87,7 @@ export default function ListProject() { active={String(status)} value="0" onPress={() => { - router.push( + router.replace( `/project?status=0&group=${group}&search=${search}&cat=${cat}` ); }} @@ -93,7 +105,7 @@ export default function ListProject() { active={String(status)} value="1" onPress={() => { - router.push( + router.replace( `/project?status=1&group=${group}&search=${search}&cat=${cat}` ); }} @@ -111,7 +123,7 @@ export default function ListProject() { active={String(status)} value="2" onPress={() => { - router.push( + router.replace( `/project?status=2&group=${group}&search=${search}&cat=${cat}` ); }} @@ -129,7 +141,7 @@ export default function ListProject() { active={String(status)} value="3" onPress={() => { - router.push( + router.replace( `/project?status=3&group=${group}&search=${search}&cat=${cat}` ); }} @@ -171,77 +183,87 @@ export default function ListProject() { { - data.length > 0 - ? - isList ? ( - - {data.map((item, index) => { - return ( - { router.push(`/project/${item.id}`); }} - borderType="bottom" - icon={ - - ( + + )) + : + arrSkeleton.map((item, index) => ( + + )) + : + data.length > 0 + ? + isList ? ( + + {data.map((item, index) => { + return ( + { router.push(`/project/${item.id}`); }} + borderType="bottom" + icon={ + + + + } + title={item.title} + /> + ); + })} + + ) : ( + + {data.map((item, index) => { + return ( + { + router.push(`/project/${item.id}`); + }} + content="page" + title={item.title} + headerColor="primary" + > + + + + {item.createdAt} + + - } - title={item.title} - /> - ); - })} + + ); + })} + + ) + : + + Tidak ada kegiatan - ) : ( - - {data.map((item, index) => { - return ( - { - router.push(`/project/${item.id}`); - }} - content="page" - title={item.title} - headerColor="primary" - > - - - - {item.createdAt} - - - - - ); - })} - - ) - : - - Tidak ada kegiatan - } diff --git a/components/borderBottomItem.tsx b/components/borderBottomItem.tsx index a71cf96..bac6dc2 100644 --- a/components/borderBottomItem.tsx +++ b/components/borderBottomItem.tsx @@ -27,8 +27,8 @@ export default function BorderBottomItem({ title, subtitle, icon, desc, onPress, {icon} - - + + {title} { subtitle && diff --git a/components/modalSelect.tsx b/components/modalSelect.tsx index 2c1ce96..148418c 100644 --- a/components/modalSelect.tsx +++ b/components/modalSelect.tsx @@ -133,7 +133,7 @@ export default function ModalSelect({ open, close, title, category, idParent, on onChoose(item.idUser, item.name, item.img)} /> )) diff --git a/components/modalSelectMultiple.tsx b/components/modalSelectMultiple.tsx index 82a14aa..e0c7044 100644 --- a/components/modalSelectMultiple.tsx +++ b/components/modalSelectMultiple.tsx @@ -145,7 +145,7 @@ export default function ModalSelectMultiple({ open, close, title, category, choo }; return ( - + { category == 'share-division' ? @@ -170,8 +170,8 @@ export default function ModalSelectMultiple({ open, close, title, category, choo : data.map((item: any, index: number) => { return ( - <> - { handleGroupCheck(item.id) }}> + + { handleGroupCheck(item.id) }}> {item.name} { checked[item.id] && checked[item.id].length === item.Division.length @@ -185,7 +185,7 @@ export default function ModalSelectMultiple({ open, close, title, category, choo item.Division.map((child: any, v: number) => { return ( { handleCheck(item.id, child.id) }}> - {child.name} + {child.name} { checked[item.id] && checked[item.id].includes(child.id) && } @@ -193,7 +193,7 @@ export default function ModalSelectMultiple({ open, close, title, category, choo ) }) } - + ) }) } diff --git a/components/project/sectionFile.tsx b/components/project/sectionFile.tsx index ce2348b..0eb6be0 100644 --- a/components/project/sectionFile.tsx +++ b/components/project/sectionFile.tsx @@ -14,6 +14,7 @@ import AlertKonfirmasi from "../alertKonfirmasi"; import BorderBottomItem from "../borderBottomItem"; import DrawerBottom from "../drawerBottom"; import MenuItemRow from "../menuItemRow"; +import Skeleton from "../skeleton"; type Props = { @@ -32,9 +33,12 @@ export default function SectionFile({ status, member }: { status: number | undef const update = useSelector((state: any) => state.projectUpdate) const [idSelect, setIdSelect] = useState('') const dispatch = useDispatch() + 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 apiGetProjectOne({ user: hasil, @@ -44,13 +48,20 @@ export default function SectionFile({ status, member }: { status: number | undef setData(response.data); } catch (error) { console.error(error); + } finally { + setLoading(false) } } useEffect(() => { - handleLoad(); + handleLoad(false); }, [update.file]); + + useEffect(() => { + handleLoad(true); + }, []); + async function handleDelete() { try { const hasil = await decryptToken(String(token?.current)); @@ -141,21 +152,28 @@ export default function SectionFile({ status, member }: { status: number | undef File { - data.length > 0 ? - data.map((item, index) => { + loading ? + arrSkeleton.map((item, index) => { return ( - } - title={item.name + '.' + item.extension} - titleWeight="normal" - onPress={() => { setIdSelect(item.id); setModal(true) }} - /> + ) }) : - Tidak ada file + data.length > 0 ? + data.map((item, index) => { + return ( + } + title={item.name + '.' + item.extension} + titleWeight="normal" + onPress={() => { setIdSelect(item.id); setModal(true) }} + /> + ) + }) + : + Tidak ada file } diff --git a/components/project/sectionMember.tsx b/components/project/sectionMember.tsx index d47b5ad..28e97cd 100644 --- a/components/project/sectionMember.tsx +++ b/components/project/sectionMember.tsx @@ -12,6 +12,7 @@ import BorderBottomItem from "../borderBottomItem"; import DrawerBottom from "../drawerBottom"; import ImageUser from "../imageNew"; import MenuItemRow from "../menuItemRow"; +import SkeletonTwoItem from "../skeletonTwoItem"; type Props = { id: string; @@ -30,14 +31,17 @@ export default function SectionMember({ status }: { status: number | undefined } const { token, decryptToken } = useAuthSession(); const { id } = useLocalSearchParams<{ id: string }>(); const [data, setData] = useState([]); + const [loading, setLoading] = useState(true) + const arrSkeleton = Array.from({ length: 3 }) const [memberChoose, setMemberChoose] = useState({ id: '', name: '', }) - async function handleLoad() { + async function handleLoad(loading: boolean) { try { + setLoading(loading) const hasil = await decryptToken(String(token?.current)); const response = await apiGetProjectOne({ user: hasil, @@ -47,13 +51,19 @@ export default function SectionMember({ status }: { status: number | undefined } setData(response.data); } catch (error) { console.error(error); + } finally { + setLoading(false) } } useEffect(() => { - handleLoad(); + handleLoad(false); }, [update.member]); + useEffect(() => { + handleLoad(true); + }, []); + async function handleDeleteMember() { try { const hasil = await decryptToken(String(token?.current)); @@ -81,28 +91,35 @@ export default function SectionMember({ status }: { status: number | undefined } { - data.length > 0 - ? - data.map((item, index) => { + loading ? + arrSkeleton.map((item, index) => { return ( - } - title={item.name} - onPress={() => { - if (status == 3) return - setMemberChoose({ - id: item.idUser, - name: item.name, - }) - setModal(true); - }} - /> - ); + + ) }) : - Tidak ada anggota + data.length > 0 + ? + data.map((item, index) => { + return ( + } + title={item.name} + onPress={() => { + if (status == 3) return + setMemberChoose({ + id: item.idUser, + name: item.name, + }) + setModal(true); + }} + /> + ); + }) + : + Tidak ada anggota } diff --git a/components/project/sectionTanggalTugas.tsx b/components/project/sectionTanggalTugas.tsx index 1f5409a..7a6109b 100644 --- a/components/project/sectionTanggalTugas.tsx +++ b/components/project/sectionTanggalTugas.tsx @@ -12,6 +12,7 @@ import DrawerBottom from "../drawerBottom"; import ItemSectionTanggalTugas from "../itemSectionTanggalTugas"; import MenuItemRow from "../menuItemRow"; import ModalSelect from "../modalSelect"; +import SkeletonTask from "../skeletonTask"; type Props = { id: string; @@ -32,13 +33,16 @@ export default function SectionTanggalTugasProject({ status, member }: { status: const { token, decryptToken } = useAuthSession(); const { id } = useLocalSearchParams<{ id: string }>(); const [data, setData] = useState([]); + const [loading, setLoading] = useState(true) + const arrSkeleton = Array.from({ length: 5 }); const [tugas, setTugas] = useState({ id: '', status: 0, }) - async function handleLoad() { + async function handleLoad(loading: boolean) { try { + setLoading(loading) const hasil = await decryptToken(String(token?.current)); const response = await apiGetProjectOne({ user: hasil, @@ -48,13 +52,18 @@ export default function SectionTanggalTugasProject({ status, member }: { status: setData(response.data); } catch (error) { console.error(error); + } finally { + setLoading(false) } } useEffect(() => { - handleLoad(); + handleLoad(false); }, [update.task]); + useEffect(() => { + handleLoad(true); + }, []); async function handleUpdate(status: number) { @@ -100,29 +109,36 @@ export default function SectionTanggalTugasProject({ status, member }: { status: { - data.length > 0 - ? - data.map((item, index) => { + loading ? + arrSkeleton.map((item, index) => { return ( - { - if (status == 3 || (!member && (entityUser.role == "user" || entityUser.role == "coadmin"))) return - setTugas({ - id: item.id, - status: item.status - }) - setModal(true) - }} - /> - ); + + ) }) : - Tidak ada tugas + data.length > 0 + ? + data.map((item, index) => { + return ( + { + if (status == 3 || (!member && (entityUser.role == "user" || entityUser.role == "coadmin"))) return + setTugas({ + id: item.id, + status: item.status + }) + setModal(true) + }} + /> + ); + }) + : + Tidak ada tugas } diff --git a/components/skeleton.tsx b/components/skeleton.tsx index 32514e2..fcdedd3 100644 --- a/components/skeleton.tsx +++ b/components/skeleton.tsx @@ -3,7 +3,7 @@ import React, { useEffect } from 'react'; import { StyleSheet } from 'react-native'; import Animated, { Easing, useAnimatedStyle, useSharedValue, withRepeat, withTiming } from 'react-native-reanimated'; -const Skeleton = ({ width, height, borderRadius = 0, widthType = 'number' }: { width: number, widthType?: 'number' | 'percent', height: number, borderRadius?: number }) => { +const Skeleton = ({ width, height, borderRadius = 0, widthType = 'number', style }: { width: number, widthType?: 'number' | 'percent', height: number, borderRadius?: number, style?: any }) => { const opacity = useSharedValue(0.3); useEffect(() => { @@ -25,7 +25,7 @@ const Skeleton = ({ width, height, borderRadius = 0, widthType = 'number' }: { w style={[ styles.skeleton, { width: widthType === 'percent' ? `${width}%` : width, height: height, borderRadius: borderRadius }, - animatedStyle, Styles.mv05 + animatedStyle, Styles.mv05, style ]} /> ); diff --git a/components/skeletonContent.tsx b/components/skeletonContent.tsx new file mode 100644 index 0000000..59354c5 --- /dev/null +++ b/components/skeletonContent.tsx @@ -0,0 +1,19 @@ +import Styles from "@/constants/Styles"; +import { View } from "react-native"; +import Skeleton from "./skeleton"; + +export default function SkeletonContent() { + return ( + + + + + + + + + + + + ) +} \ No newline at end of file diff --git a/components/skeletonTask.tsx b/components/skeletonTask.tsx new file mode 100644 index 0000000..02c2b5f --- /dev/null +++ b/components/skeletonTask.tsx @@ -0,0 +1,25 @@ +import Styles from "@/constants/Styles"; +import { View } from "react-native"; +import Skeleton from "./skeleton"; + +export default function SkeletonTask() { + return ( + + + + + + + + + + + + + + + + + + ) +} \ No newline at end of file diff --git a/components/skeletonTwoItem.tsx b/components/skeletonTwoItem.tsx index c4910e9..1215420 100644 --- a/components/skeletonTwoItem.tsx +++ b/components/skeletonTwoItem.tsx @@ -5,7 +5,7 @@ import Skeleton from "./skeleton"; export default function SkeletonTwoItem() { return ( - + diff --git a/constants/Styles.ts b/constants/Styles.ts index 858905c..4bb4a34 100644 --- a/constants/Styles.ts +++ b/constants/Styles.ts @@ -182,6 +182,9 @@ const Styles = StyleSheet.create({ w50: { width: '50%' }, + w45: { + width: '45%' + }, w40: { width: '40%' },