From 6fd874777d5f3a347408ab97cf4579e960dd2922 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Gonz=C3=A1lez=20Mu=C3=B1oz?= Date: Thu, 16 Nov 2023 13:46:38 +0100 Subject: [PATCH] delays cache invalidation of wdpas --- app/hooks/wdpa/index.ts | 9 +- .../project/inventory-panel/wdpas/index.tsx | 1 - .../wdpas/modals/upload/index.tsx | 99 +++++++++---------- app/layout/projects/show/map/index.tsx | 2 +- .../projects/show/map/legend/hooks/index.ts | 6 +- .../scenarios/edit/map/legend/hooks/index.ts | 4 +- 6 files changed, 63 insertions(+), 58 deletions(-) diff --git a/app/hooks/wdpa/index.ts b/app/hooks/wdpa/index.ts index b29977ed7f..6e6697d6c4 100644 --- a/app/hooks/wdpa/index.ts +++ b/app/hooks/wdpa/index.ts @@ -2,6 +2,7 @@ import { useMutation, useQuery, QueryObserverOptions, useQueryClient } from 'rea import { AxiosRequestConfig } from 'axios'; import { useSession } from 'next-auth/react'; +import { useDebouncedCallback } from 'use-debounce'; import { Project } from 'types/api/project'; import { Scenario } from 'types/api/scenario'; @@ -148,6 +149,10 @@ export function useUploadWDPAsShapefile({ const queryClient = useQueryClient(); const { data: session } = useSession(); + const delayedInvalidateQueryCache = useDebouncedCallback(async (id: Project['id']) => { + await queryClient.invalidateQueries(['wdpas', id]); + }, 550); + const uploadWDPAShapefile = ({ id, data }: { id: Project['id']; data: FormData }) => { return UPLOADS.request<{ success: true }>({ url: `/projects/${id}/protected-areas/shapefile`, @@ -163,7 +168,9 @@ export function useUploadWDPAsShapefile({ return useMutation(uploadWDPAShapefile, { onSuccess: async (data, variables) => { const { id: projectId } = variables; - await queryClient.invalidateQueries(['wdpas', projectId]); + // ? It takes the API a little bit to get the final list of WDPAs updated + // ? after uploading a shapefile, so we need to delay the cache invalidation a few milliseconds + await delayedInvalidateQueryCache(projectId); }, }); } diff --git a/app/layout/project/sidebar/project/inventory-panel/wdpas/index.tsx b/app/layout/project/sidebar/project/inventory-panel/wdpas/index.tsx index 1d9ed566ec..59d0e152e2 100644 --- a/app/layout/project/sidebar/project/inventory-panel/wdpas/index.tsx +++ b/app/layout/project/sidebar/project/inventory-panel/wdpas/index.tsx @@ -49,7 +49,6 @@ const InventoryPanelProtectedAreas = ({ search, }, { - keepPreviousData: true, placeholderData: [], } ); diff --git a/app/layout/project/sidebar/project/inventory-panel/wdpas/modals/upload/index.tsx b/app/layout/project/sidebar/project/inventory-panel/wdpas/modals/upload/index.tsx index 8641979341..560dc68e2c 100644 --- a/app/layout/project/sidebar/project/inventory-panel/wdpas/modals/upload/index.tsx +++ b/app/layout/project/sidebar/project/inventory-panel/wdpas/modals/upload/index.tsx @@ -2,7 +2,6 @@ import React, { useCallback, useEffect, useRef, useState } from 'react'; import { useDropzone, DropzoneProps } from 'react-dropzone'; import { Form as FormRFF, Field as FieldRFF, FormProps } from 'react-final-form'; -import { useQueryClient } from 'react-query'; import { useRouter } from 'next/router'; @@ -50,7 +49,6 @@ export const WDPAUploadModal = ({ const { pid } = query as { pid: string }; const { addToast } = useToasts(); - const queryClient = useQueryClient(); const uploadWDPAsShapefileMutation = useUploadWDPAsShapefile({}); @@ -114,57 +112,58 @@ export const WDPAUploadModal = ({ data.append('file', file); data.append('name', name); - const mutationResponse = { - onSuccess: () => { - setSuccessFile({ ...successFile }); - onClose(); - addToast( - 'success-upload-wdpa-file', - <> -

Success!

-

File uploaded

- , - { - level: 'success', + uploadWDPAsShapefileMutation.mutate( + { data, id: pid }, + { + onSuccess: () => { + setSuccessFile({ ...successFile }); + + addToast( + 'success-upload-wdpa-file', + <> +

Success!

+

File uploaded

+ , + { + level: 'success', + } + ); + onClose(); + }, + onError: (error: AxiosError | Error) => { + let errors: { status: number; title: string }[] = []; + + if (isAxiosError(error)) { + errors = [...error.response.data.errors]; + } else { + // ? in case of unknown error (not request error), display generic error message + errors = [{ status: 500, title: 'Something went wrong' }]; } - ); - queryClient.invalidateQueries(['wdpas', pid]); - }, - onError: (error: AxiosError | Error) => { - let errors: { status: number; title: string }[] = []; - - if (isAxiosError(error)) { - errors = [...error.response.data.errors]; - } else { - // ? in case of unknown error (not request error), display generic error message - errors = [{ status: 500, title: 'Something went wrong' }]; - } - - setSuccessFile(null); - - addToast( - 'error-upload-wdpa-csv', - <> -

Error

- - , - { - level: 'error', - } - ); - }, - onSettled: () => { - setLoading(false); - }, - }; - uploadWDPAsShapefileMutation.mutate({ data, id: `${pid}` }, mutationResponse); + setSuccessFile(null); + + addToast( + 'error-upload-wdpa-csv', + <> +

Error

+ + , + { + level: 'error', + } + ); + }, + onSettled: () => { + setLoading(false); + }, + } + ); }, - [pid, addToast, onClose, uploadWDPAsShapefileMutation, successFile, queryClient] + [pid, addToast, onClose, uploadWDPAsShapefileMutation, successFile] ); const { getRootProps, getInputProps, isDragActive, isDragAccept, isDragReject } = useDropzone({ diff --git a/app/layout/projects/show/map/index.tsx b/app/layout/projects/show/map/index.tsx index 34fe58edb5..dd8c05d961 100644 --- a/app/layout/projects/show/map/index.tsx +++ b/app/layout/projects/show/map/index.tsx @@ -108,7 +108,7 @@ export const ProjectMap = (): JSX.Element => { const protectedAreaQuery = useProjectWDPAs( pid, - {}, + { sort: 'name' }, { select: (data) => data.map(({ id }) => id), } diff --git a/app/layout/projects/show/map/legend/hooks/index.ts b/app/layout/projects/show/map/legend/hooks/index.ts index 10afdc239c..6f6cfeb6ef 100644 --- a/app/layout/projects/show/map/legend/hooks/index.ts +++ b/app/layout/projects/show/map/legend/hooks/index.ts @@ -86,7 +86,7 @@ export const useConservationAreasLegend = () => { const protectedAreaQuery = useProjectWDPAs( pid, - {}, + { sort: 'name' }, { select: (data) => data.map(({ id, name }) => ({ id, name })), } @@ -140,14 +140,14 @@ export const useFeaturesLegend = () => { [] ).map((feature) => ({ ...feature, - color: featureColorQueryState.data?.find(({ id }) => id === feature.id)?.color, + color: featureColorQueryState?.data?.find(({ id }) => id === feature.id)?.color, })), continuousFeatures: ( data?.filter(({ amountRange }) => amountRange.min !== null && amountRange.max !== null) || [] ).map((feature) => ({ ...feature, - color: featureColorQueryState.data?.find(({ id }) => id === feature.id)?.color, + color: featureColorQueryState?.data?.find(({ id }) => id === feature.id)?.color, })), }), enabled: featureColorQueryState?.status === 'success', diff --git a/app/layout/scenarios/edit/map/legend/hooks/index.ts b/app/layout/scenarios/edit/map/legend/hooks/index.ts index 0a966ed733..0f5fee0d59 100644 --- a/app/layout/scenarios/edit/map/legend/hooks/index.ts +++ b/app/layout/scenarios/edit/map/legend/hooks/index.ts @@ -148,14 +148,14 @@ export const useFeaturesLegend = () => { [] ).map((feature) => ({ ...feature, - color: featureColorQueryState.data?.find(({ id }) => id === feature.id)?.color, + color: featureColorQueryState?.data?.find(({ id }) => id === feature.id)?.color, })), continuousFeatures: ( data?.filter(({ amountRange }) => amountRange.min !== null && amountRange.max !== null) || [] ).map((feature) => ({ ...feature, - color: featureColorQueryState.data?.find(({ id }) => id === feature.id)?.color, + color: featureColorQueryState?.data?.find(({ id }) => id === feature.id)?.color, })), }), enabled: featureColorQueryState?.status === 'success',