upd: caching data

Deskripsi:
- update caching pada fitur utama -yg fitur divisi belom
This commit is contained in:
2026-04-20 14:23:14 +08:00
parent 772551a917
commit ccf8ee1caf
27 changed files with 767 additions and 766 deletions

View File

@@ -1,3 +1,4 @@
import styles from "@/components/AppHeader"
import AppHeader from "@/components/AppHeader"
import HeaderRightBannerList from "@/components/banner/headerBannerList"
import BorderBottomItem from "@/components/borderBottomItem"
@@ -5,6 +6,7 @@ import DrawerBottom from "@/components/drawerBottom"
import MenuItemRow from "@/components/menuItemRow"
import ModalConfirmation from "@/components/ModalConfirmation"
import ModalLoading from "@/components/modalLoading"
import Skeleton from "@/components/skeleton"
import Text from "@/components/Text"
import { ConstEnv } from "@/constants/ConstEnv"
import Styles from "@/constants/Styles"
@@ -13,11 +15,12 @@ import { setEntities } from "@/lib/bannerSlice"
import { useAuthSession } from "@/providers/AuthProvider"
import { useTheme } from "@/providers/ThemeProvider"
import { Ionicons, MaterialCommunityIcons } from "@expo/vector-icons"
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"
import * as FileSystem from 'expo-file-system'
import { startActivityAsync } from 'expo-intent-launcher'
import { router, Stack } from "expo-router"
import * as Sharing from 'expo-sharing'
import { useState } from "react"
import { useEffect, useState } from "react"
import { Alert, Image, Platform, RefreshControl, SafeAreaView, ScrollView, View } from "react-native"
import ImageViewing from 'react-native-image-viewing'
import * as mime from 'react-native-mime-types'
@@ -43,36 +46,51 @@ export default function BannerList() {
const [loadingOpen, setLoadingOpen] = useState(false)
const [viewImg, setViewImg] = useState(false)
const [showDeleteModal, setShowDeleteModal] = useState(false)
const queryClient = useQueryClient()
const handleDeleteEntity = async () => {
try {
const hasil = await decryptToken(String(token?.current));
const deletedEntity = await apiDeleteBanner({ user: hasil }, dataId);
if (deletedEntity.success) {
Toast.show({ type: 'small', text1: 'Berhasil menghapus data', })
apiGetBanner({ user: hasil }).then((data) =>
dispatch(setEntities(data.data))
);
} else {
Toast.show({ type: 'small', text1: 'Gagal menghapus data', })
}
} catch (error: any) {
console.error(error);
const message = error?.response?.data?.message || "Gagal menghapus data"
// 1. Fetching logic with useQuery
const { data: bannersRes, isLoading } = useQuery({
queryKey: ['banners'],
queryFn: async () => {
const hasil = await decryptToken(String(token?.current))
const response = await apiGetBanner({ user: hasil })
return response.data || []
},
enabled: !!token?.current,
staleTime: 0,
})
Toast.show({ type: 'small', text1: message })
} finally {
setModal(false)
// Sync results with Redux
useEffect(() => {
if (bannersRes) {
dispatch(setEntities(bannersRes))
}
}, [bannersRes, dispatch])
// 2. Deletion logic with useMutation
const deleteMutation = useMutation({
mutationFn: async (id: string) => {
const hasil = await decryptToken(String(token?.current))
return await apiDeleteBanner({ user: hasil }, id)
},
onSuccess: () => {
Toast.show({ type: 'small', text1: 'Berhasil menghapus data' })
queryClient.invalidateQueries({ queryKey: ['banners'] })
},
onError: (error: any) => {
const message = error?.response?.data?.message || "Gagal menghapus data"
Toast.show({ type: 'small', text1: message })
}
})
const handleDeleteEntity = () => {
deleteMutation.mutate(dataId)
setModal(false)
};
const handleRefresh = async () => {
setRefreshing(true)
const hasil = await decryptToken(String(token?.current));
apiGetBanner({ user: hasil }).then((data) =>
dispatch(setEntities(data.data))
);
await new Promise(resolve => setTimeout(resolve, 2000));
await queryClient.invalidateQueries({ queryKey: ['banners'] })
setRefreshing(false)
};
@@ -140,36 +158,40 @@ export default function BannerList() {
}
style={[Styles.h100, { backgroundColor: colors.background }]}
>
{
entities.length > 0
?
<View style={[Styles.p15, Styles.mb100]}>
{entities.map((index: any, key: number) => (
<BorderBottomItem
key={key}
onPress={() => {
setDataId(index.id)
setSelectFile(index)
setModal(true)
}}
borderType="all"
icon={
<Image
source={{ uri: `${ConstEnv.url_storage}/files/${index.image}` }}
style={[Styles.imgListBanner]}
/>
}
title={index.title}
/>
))}
</View>
:
<View style={[Styles.p15, Styles.mb100]}>
<Text style={[Styles.textDefault, Styles.textCenter]}>Tidak ada data</Text>
</View>
}
<View style={[Styles.p15, Styles.mb100]}>
{
isLoading ? (
<>
<Skeleton width={100} height={150} borderRadius={10} widthType="percent" />
<Skeleton width={100} height={150} borderRadius={10} widthType="percent" />
<Skeleton width={100} height={150} borderRadius={10} widthType="percent" />
</>
) :
entities.length > 0 ?
entities.map((index: any, key: number) => (
<BorderBottomItem
key={key}
onPress={() => {
setDataId(index.id)
setSelectFile(index)
setModal(true)
}}
borderType="all"
icon={
<Image
source={{ uri: `${ConstEnv.url_storage}/files/${index.image}` }}
style={[Styles.imgListBanner]}
/>
}
title={index.title}
/>
))
:
<View style={[Styles.p15, Styles.mb100]}>
<Text style={[Styles.textDefault, Styles.textCenter]}>Tidak ada data</Text>
</View>
}
</View>
</ScrollView>
<DrawerBottom animation="slide" isVisible={isModal} setVisible={() => setModal(false)} title="Menu">