(ui) WIP trying to get all cache scenarios working smoothly, fix assets

This commit is contained in:
Mary Hipp 2023-08-11 16:14:47 -04:00 committed by psychedelicious
parent 0a71d6baa1
commit 767a612746
4 changed files with 67 additions and 47 deletions

View File

@ -36,7 +36,7 @@ import {
import { ImageDTO } from 'services/api/types'; import { ImageDTO } from 'services/api/types';
import { useDebounce } from 'use-debounce'; import { useDebounce } from 'use-debounce';
import { sentImageToCanvas, sentImageToImg2Img } from '../../store/actions'; import { sentImageToCanvas, sentImageToImg2Img } from '../../store/actions';
import { BsPinAngle, BsPinAngleFill } from 'react-icons/bs'; import { BsBookmarkStar, BsFillBookmarkStarFill } from 'react-icons/bs';
type SingleSelectionMenuItemsProps = { type SingleSelectionMenuItemsProps = {
imageDTO: ImageDTO; imageDTO: ImageDTO;
@ -211,11 +211,14 @@ const SingleSelectionMenuItems = (props: SingleSelectionMenuItemsProps) => {
Change Board Change Board
</MenuItem> </MenuItem>
{imageDTO.pinned ? ( {imageDTO.pinned ? (
<MenuItem icon={<BsPinAngle />} onClickCapture={handleUnpinImage}> <MenuItem icon={<BsBookmarkStar />} onClickCapture={handleUnpinImage}>
Unpin Image Unpin Image
</MenuItem> </MenuItem>
) : ( ) : (
<MenuItem icon={<BsPinAngleFill />} onClickCapture={handlePinImage}> <MenuItem
icon={<BsFillBookmarkStarFill />}
onClickCapture={handlePinImage}
>
Pin Image Pin Image
</MenuItem> </MenuItem>
)} )}

View File

@ -2,16 +2,19 @@ import { Box, Flex } from '@chakra-ui/react';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import IAIDndImage from 'common/components/IAIDndImage'; import IAIDndImage from 'common/components/IAIDndImage';
import IAIFillSkeleton from 'common/components/IAIFillSkeleton'; import IAIFillSkeleton from 'common/components/IAIFillSkeleton';
import { useMultiselect } from 'features/gallery/hooks/useMultiselect.ts';
import { imagesToDeleteSelected } from 'features/deleteImageModal/store/slice'; import { imagesToDeleteSelected } from 'features/deleteImageModal/store/slice';
import { MouseEvent, memo, useCallback, useMemo } from 'react';
import { FaTrash } from 'react-icons/fa';
import { useGetImageDTOQuery } from 'services/api/endpoints/images';
import { import {
ImageDTOsDraggableData, ImageDTOsDraggableData,
ImageDraggableData, ImageDraggableData,
TypesafeDraggableData, TypesafeDraggableData,
} from 'features/dnd/types'; } from 'features/dnd/types';
import { useMultiselect } from 'features/gallery/hooks/useMultiselect.ts';
import { MouseEvent, memo, useCallback, useMemo } from 'react';
import { BsBookmarkStar, BsFillBookmarkStarFill } from 'react-icons/bs';
import {
useChangeImagePinnedMutation,
useGetImageDTOQuery,
} from 'services/api/endpoints/images';
interface HoverableImageProps { interface HoverableImageProps {
imageName: string; imageName: string;
@ -59,6 +62,14 @@ const GalleryImage = (props: HoverableImageProps) => {
} }
}, [imageDTO, selection, selectionCount]); }, [imageDTO, selection, selectionCount]);
const [togglePin] = useChangeImagePinnedMutation();
const togglePinnedState = useCallback(() => {
if (imageDTO) {
togglePin({ imageDTO, pinned: !imageDTO.pinned });
}
}, [togglePin, imageDTO]);
if (!imageDTO) { if (!imageDTO) {
return <IAIFillSkeleton />; return <IAIFillSkeleton />;
} }
@ -80,15 +91,17 @@ const GalleryImage = (props: HoverableImageProps) => {
draggableData={draggableData} draggableData={draggableData}
isSelected={isSelected} isSelected={isSelected}
minSize={0} minSize={0}
onClickReset={handleDelete} onClickReset={togglePinnedState}
imageSx={{ w: 'full', h: 'full' }} imageSx={{ w: 'full', h: 'full' }}
isDropDisabled={true} isDropDisabled={true}
isUploadDisabled={true} isUploadDisabled={true}
thumbnail={true} thumbnail={true}
withHoverOverlay withHoverOverlay
resetIcon={<FaTrash />} resetIcon={
resetTooltip="Delete image" imageDTO.pinned ? <BsFillBookmarkStarFill /> : <BsBookmarkStar />
withResetIcon={shouldShowDeleteButton} // removed bc it's too easy to accidentally delete images }
resetTooltip="Pin image"
withResetIcon={true}
/> />
</Flex> </Flex>
</Box> </Box>

View File

@ -399,15 +399,18 @@ export const imagesApi = api.injectEndpoints({
method: 'PATCH', method: 'PATCH',
body: { pinned }, body: { pinned },
}), }),
invalidatesTags: (result, error, { imageDTO }) => [ invalidatesTags: (result, error, { imageDTO }) => {
const categories = getCategories(imageDTO);
return [
{ {
type: 'ImageList', type: 'ImageList',
id: getListImagesUrl({ id: getListImagesUrl({
board_id: imageDTO.board_id, board_id: imageDTO.board_id,
categories: IMAGE_CATEGORIES, categories,
}), }),
}, },
], ]
},
async onQueryStarted( async onQueryStarted(
{ imageDTO, pinned }, { imageDTO, pinned },
{ dispatch, queryFulfilled, getState } { dispatch, queryFulfilled, getState }
@ -465,27 +468,14 @@ export const imagesApi = api.injectEndpoints({
const isCacheFullyPopulated = const isCacheFullyPopulated =
currentCache.data && currentCache.data.ids.length >= (total ?? 0); currentCache.data && currentCache.data.ids.length >= (total ?? 0);
const isInDateRangeForPinnedState = getIsImageInDateRange( const isInDateRange = getIsImageInDateRange(
currentCache.data, currentCache.data,
updatedImage updatedImage
); );
if (!isInDateRangeForPinnedState) { // should we remove images from cache if _not_ in date range? ie you are showing 100 of 101 pinned images and you unpin one. technically it should disappear from list.
// if newly pinned or unpinned image is not in date range for its new state, remove from cache
patches.push(
dispatch(
imagesApi.util.updateQueryData(
'listImages',
queryArgs,
(draft) => {
imagesAdapter.removeOne(draft, updatedImage.image_name);
}
)
)
);
}
if (isCacheFullyPopulated || isInDateRangeForPinnedState) { if (isCacheFullyPopulated || isInDateRange) {
// *upsert* to $cache // *upsert* to $cache
patches.push( patches.push(
dispatch( dispatch(

View File

@ -21,21 +21,35 @@ export const getIsImageInDateRange = (
return true; return true;
} }
const cacheImageDTOSForPinnedState = totalCachedImageDtos.filter((image) => image.pinned === imageDTO.pinned); const cachedPinnedImages = [];
const cachedUnpinnedImages = [];
if (cacheImageDTOSForPinnedState.length > 1) { for (let index = 0; index < totalCachedImageDtos.length; index++) {
// Images are sorted by `pinned` DESC and then `created_at` DESC const image = totalCachedImageDtos[index];
// check if the image is newer than the oldest image in the cache for either the pinned group or unpinned group if (image?.pinned) cachedPinnedImages.push(image)
const createdDate = new Date(imageDTO.created_at); if (!image?.pinned) cachedUnpinnedImages.push(image)
const oldestImage = cacheImageDTOSForPinnedState[cacheImageDTOSForPinnedState.length - 1]; }
if (!oldestImage) {
const lastPinnedImage = cachedPinnedImages[cachedPinnedImages.length - 1];
const lastUnpinnedImage = cachedUnpinnedImages[cachedUnpinnedImages.length - 1];
if (!lastPinnedImage || !lastUnpinnedImage) {
// satisfy TS gods, we already confirmed the array has more than one image // satisfy TS gods, we already confirmed the array has more than one image
return false; return false;
} }
const oldestDate = new Date(oldestImage.created_at);
if (imageDTO.pinned) {
// if pinning or already pinned, want to look in list of pinned images
const createdDate = new Date(imageDTO.created_at);
const oldestDate = new Date(lastPinnedImage.created_at);
return createdDate >= oldestDate;
} else {
// if unpinning or already unpinned, want to look in list of unpinned images
const createdDate = new Date(imageDTO.created_at);
const oldestDate = new Date(lastUnpinnedImage.created_at);
return createdDate >= oldestDate; return createdDate >= oldestDate;
} }
return false;
}; };
export const getCategories = (imageDTO: ImageDTO) => { export const getCategories = (imageDTO: ImageDTO) => {