feat(ui): update right arrow gallery load more

- add hotkey support
- add loading state
- only show if there are more images to load
This commit is contained in:
psychedelicious
2023-07-09 00:26:49 +10:00
committed by Kent Keirsey
parent 2c956806d7
commit 3001e4c947
2 changed files with 70 additions and 24 deletions

View File

@ -57,6 +57,7 @@ const selector = createSelector(
images, images,
allImagesTotal, allImagesTotal,
isLoading, isLoading,
isFetching,
categories, categories,
selectedBoardId, selectedBoardId,
}; };
@ -82,8 +83,14 @@ const ImageGalleryGrid = () => {
}, },
}); });
const { images, isLoading, allImagesTotal, categories, selectedBoardId } = const {
useAppSelector(selector); images,
isLoading,
isFetching,
allImagesTotal,
categories,
selectedBoardId,
} = useAppSelector(selector);
const { selectedBoard } = useListAllBoardsQuery(undefined, { const { selectedBoard } = useListAllBoardsQuery(undefined, {
selectFromResult: ({ data }) => ({ selectFromResult: ({ data }) => ({
@ -176,7 +183,7 @@ const ImageGalleryGrid = () => {
<IAIButton <IAIButton
onClick={handleLoadMoreImages} onClick={handleLoadMoreImages}
isDisabled={!areMoreAvailable} isDisabled={!areMoreAvailable}
isLoading={isLoading} isLoading={isFetching}
loadingText="Loading" loadingText="Loading"
flexShrink={0} flexShrink={0}
> >

View File

@ -1,17 +1,17 @@
import { ChakraProps, Flex, Grid, IconButton } from '@chakra-ui/react'; import { ChakraProps, Flex, Grid, IconButton, Spinner } from '@chakra-ui/react';
import { createSelector } from '@reduxjs/toolkit'; import { createSelector } from '@reduxjs/toolkit';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { clamp, isEqual } from 'lodash-es';
import { useCallback, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { FaAngleLeft, FaAngleRight, FaRedo } from 'react-icons/fa';
import { stateSelector } from 'app/store/store'; import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { import {
imageSelected, imageSelected,
selectFilteredImages,
selectImagesById, selectImagesById,
} from 'features/gallery/store/gallerySlice'; } from 'features/gallery/store/gallerySlice';
import { clamp, isEqual } from 'lodash-es';
import { useCallback, useState } from 'react';
import { useHotkeys } from 'react-hotkeys-hook'; import { useHotkeys } from 'react-hotkeys-hook';
import { selectFilteredImages } from 'features/gallery/store/gallerySlice'; import { useTranslation } from 'react-i18next';
import { FaAngleDoubleRight, FaAngleLeft, FaAngleRight } from 'react-icons/fa';
import { receivedPageOfImages } from 'services/api/thunks/image'; import { receivedPageOfImages } from 'services/api/thunks/image';
const nextPrevButtonTriggerAreaStyles: ChakraProps['sx'] = { const nextPrevButtonTriggerAreaStyles: ChakraProps['sx'] = {
@ -27,6 +27,7 @@ const nextPrevButtonStyles: ChakraProps['sx'] = {
export const nextPrevImageButtonsSelector = createSelector( export const nextPrevImageButtonsSelector = createSelector(
[stateSelector, selectFilteredImages], [stateSelector, selectFilteredImages],
(state, filteredImages) => { (state, filteredImages) => {
const { total, isFetching } = state.gallery;
const lastSelectedImage = const lastSelectedImage =
state.gallery.selection[state.gallery.selection.length - 1]; state.gallery.selection[state.gallery.selection.length - 1];
@ -64,6 +65,8 @@ export const nextPrevImageButtonsSelector = createSelector(
isOnFirstImage: currentImageIndex === 0, isOnFirstImage: currentImageIndex === 0,
isOnLastImage: isOnLastImage:
!isNaN(currentImageIndex) && currentImageIndex === imagesLength - 1, !isNaN(currentImageIndex) && currentImageIndex === imagesLength - 1,
areMoreImagesAvailable: total > imagesLength,
isFetching,
nextImage, nextImage,
prevImage, prevImage,
nextImageId, nextImageId,
@ -81,8 +84,14 @@ const NextPrevImageButtons = () => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const { t } = useTranslation(); const { t } = useTranslation();
const { isOnFirstImage, isOnLastImage, nextImageId, prevImageId } = const {
useAppSelector(nextPrevImageButtonsSelector); isOnFirstImage,
isOnLastImage,
nextImageId,
prevImageId,
areMoreImagesAvailable,
isFetching,
} = useAppSelector(nextPrevImageButtonsSelector);
const [shouldShowNextPrevButtons, setShouldShowNextPrevButtons] = const [shouldShowNextPrevButtons, setShouldShowNextPrevButtons] =
useState<boolean>(false); useState<boolean>(false);
@ -122,9 +131,21 @@ const NextPrevImageButtons = () => {
useHotkeys( useHotkeys(
'right', 'right',
() => { () => {
handleNextImage(); if (isOnLastImage && areMoreImagesAvailable && !isFetching) {
handleLoadMoreImages();
return;
}
if (!isOnLastImage) {
handleNextImage();
}
}, },
[nextImageId] [
nextImageId,
isOnLastImage,
areMoreImagesAvailable,
handleLoadMoreImages,
isFetching,
]
); );
return ( return (
@ -173,16 +194,34 @@ const NextPrevImageButtons = () => {
sx={nextPrevButtonStyles} sx={nextPrevButtonStyles}
/> />
)} )}
{shouldShowNextPrevButtons && isOnLastImage && ( {shouldShowNextPrevButtons &&
<IconButton isOnLastImage &&
aria-label={t('accessibility.loadMore')} areMoreImagesAvailable &&
icon={<FaRedo size={42} />} !isFetching && (
variant="unstyled" <IconButton
onClick={handleLoadMoreImages} aria-label={t('accessibility.loadMore')}
boxSize={16} icon={<FaAngleDoubleRight size={64} />}
sx={nextPrevButtonStyles} variant="unstyled"
/> onClick={handleLoadMoreImages}
)} boxSize={16}
sx={nextPrevButtonStyles}
/>
)}
{shouldShowNextPrevButtons &&
isOnLastImage &&
areMoreImagesAvailable &&
isFetching && (
<Flex
sx={{
w: 16,
h: 16,
alignItems: 'center',
justifyContent: 'center',
}}
>
<Spinner opacity={0.5} size="xl" />
</Flex>
)}
</Grid> </Grid>
</Flex> </Flex>
); );