feat(ui): more efficient board totals fetching

We only need to show the totals in the tooltip. Tooltips accpet a component for the tooltip label. The component isn't rendered until the tooltip is triggered.

Move the board total fetching into a tooltip component for the boards. Now we only fire these requests when the user mouses over the board
This commit is contained in:
psychedelicious 2024-06-21 18:50:50 +10:00
parent 689dc30f87
commit 719c066ac4
5 changed files with 31 additions and 49 deletions

View File

@ -37,7 +37,11 @@
"selectBoard": "Select a Board", "selectBoard": "Select a Board",
"topMessage": "This board contains images used in the following features:", "topMessage": "This board contains images used in the following features:",
"uncategorized": "Uncategorized", "uncategorized": "Uncategorized",
"downloadBoard": "Download Board" "downloadBoard": "Download Board",
"imagesWithCount_one": "{{count}} image",
"imagesWithCount_other": "{{count}} images",
"assetsWithCount_one": "{{count}} asset",
"assetsWithCount_other": "{{count}} assets"
}, },
"accordions": { "accordions": {
"generation": { "generation": {

View File

@ -0,0 +1,21 @@
import { useTranslation } from 'react-i18next';
import { useGetBoardImagesTotalQuery } from 'services/api/endpoints/boards';
type Props = {
board_id: string;
};
export const BoardTotalsTooltip = ({ board_id }: Props) => {
const { t } = useTranslation();
const { imagesTotal } = useGetBoardImagesTotalQuery(board_id, {
selectFromResult: ({ data }) => {
return { imagesTotal: data?.total ?? 0 };
},
});
const { assetsTotal } = useGetBoardImagesTotalQuery(board_id, {
selectFromResult: ({ data }) => {
return { assetsTotal: data?.total ?? 0 };
},
});
return `${t('boards.imagesWithCount', { count: imagesTotal })}, ${t('boards.assetsWithCount', { count: assetsTotal })}`;
};

View File

@ -8,15 +8,12 @@ import SelectionOverlay from 'common/components/SelectionOverlay';
import type { AddToBoardDropData } from 'features/dnd/types'; import type { AddToBoardDropData } from 'features/dnd/types';
import AutoAddIcon from 'features/gallery/components/Boards/AutoAddIcon'; import AutoAddIcon from 'features/gallery/components/Boards/AutoAddIcon';
import BoardContextMenu from 'features/gallery/components/Boards/BoardContextMenu'; import BoardContextMenu from 'features/gallery/components/Boards/BoardContextMenu';
import { BoardTotalsTooltip } from 'features/gallery/components/Boards/BoardsList/BoardTotalsTooltip';
import { autoAddBoardIdChanged, boardIdSelected, selectGallerySlice } from 'features/gallery/store/gallerySlice'; import { autoAddBoardIdChanged, boardIdSelected, selectGallerySlice } from 'features/gallery/store/gallerySlice';
import { memo, useCallback, useMemo, useState } from 'react'; import { memo, useCallback, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { PiImagesSquare } from 'react-icons/pi'; import { PiImagesSquare } from 'react-icons/pi';
import { import { useUpdateBoardMutation } from 'services/api/endpoints/boards';
useGetBoardAssetsTotalQuery,
useGetBoardImagesTotalQuery,
useUpdateBoardMutation,
} from 'services/api/endpoints/boards';
import { useGetImageDTOQuery } from 'services/api/endpoints/images'; import { useGetImageDTOQuery } from 'services/api/endpoints/images';
import type { BoardDTO } from 'services/api/types'; import type { BoardDTO } from 'services/api/types';
@ -51,17 +48,6 @@ const GalleryBoard = ({ board, isSelected, setBoardToDelete }: GalleryBoardProps
setIsHovered(false); setIsHovered(false);
}, []); }, []);
const { data: imagesTotal } = useGetBoardImagesTotalQuery(board.board_id);
const { data: assetsTotal } = useGetBoardAssetsTotalQuery(board.board_id);
const tooltip = useMemo(() => {
if (imagesTotal?.total === undefined || assetsTotal?.total === undefined) {
return undefined;
}
return `${imagesTotal.total} image${imagesTotal.total === 1 ? '' : 's'}, ${
assetsTotal.total
} asset${assetsTotal.total === 1 ? '' : 's'}`;
}, [assetsTotal, imagesTotal]);
const { currentData: coverImage } = useGetImageDTOQuery(board.cover_image_name ?? skipToken); const { currentData: coverImage } = useGetImageDTOQuery(board.cover_image_name ?? skipToken);
const { board_name, board_id } = board; const { board_name, board_id } = board;
@ -132,7 +118,7 @@ const GalleryBoard = ({ board, isSelected, setBoardToDelete }: GalleryBoardProps
> >
<BoardContextMenu board={board} board_id={board_id} setBoardToDelete={setBoardToDelete}> <BoardContextMenu board={board} board_id={board_id} setBoardToDelete={setBoardToDelete}>
{(ref) => ( {(ref) => (
<Tooltip label={tooltip} openDelay={1000}> <Tooltip label={<BoardTotalsTooltip board_id={board.board_id} />} openDelay={1000}>
<Flex <Flex
ref={ref} ref={ref}
onClick={handleSelectBoard} onClick={handleSelectBoard}

View File

@ -5,11 +5,11 @@ import SelectionOverlay from 'common/components/SelectionOverlay';
import type { RemoveFromBoardDropData } from 'features/dnd/types'; import type { RemoveFromBoardDropData } from 'features/dnd/types';
import AutoAddIcon from 'features/gallery/components/Boards/AutoAddIcon'; import AutoAddIcon from 'features/gallery/components/Boards/AutoAddIcon';
import BoardContextMenu from 'features/gallery/components/Boards/BoardContextMenu'; import BoardContextMenu from 'features/gallery/components/Boards/BoardContextMenu';
import { BoardTotalsTooltip } from 'features/gallery/components/Boards/BoardsList/BoardTotalsTooltip';
import { autoAddBoardIdChanged, boardIdSelected } from 'features/gallery/store/gallerySlice'; import { autoAddBoardIdChanged, boardIdSelected } from 'features/gallery/store/gallerySlice';
import InvokeLogoSVG from 'public/assets/images/invoke-symbol-wht-lrg.svg'; import InvokeLogoSVG from 'public/assets/images/invoke-symbol-wht-lrg.svg';
import { memo, useCallback, useMemo, useState } from 'react'; import { memo, useCallback, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useGetBoardAssetsTotalQuery, useGetBoardImagesTotalQuery } from 'services/api/endpoints/boards';
import { useBoardName } from 'services/api/hooks/useBoardName'; import { useBoardName } from 'services/api/hooks/useBoardName';
interface Props { interface Props {
@ -29,17 +29,6 @@ const NoBoardBoard = memo(({ isSelected }: Props) => {
}, [dispatch, autoAssignBoardOnClick]); }, [dispatch, autoAssignBoardOnClick]);
const [isHovered, setIsHovered] = useState(false); const [isHovered, setIsHovered] = useState(false);
const { data: imagesTotal } = useGetBoardImagesTotalQuery('none');
const { data: assetsTotal } = useGetBoardAssetsTotalQuery('none');
const tooltip = useMemo(() => {
if (imagesTotal?.total === undefined || assetsTotal?.total === undefined) {
return undefined;
}
return `${imagesTotal.total} image${imagesTotal.total === 1 ? '' : 's'}, ${
assetsTotal.total
} asset${assetsTotal.total === 1 ? '' : 's'}`;
}, [assetsTotal, imagesTotal]);
const handleMouseOver = useCallback(() => { const handleMouseOver = useCallback(() => {
setIsHovered(true); setIsHovered(true);
}, []); }, []);
@ -71,7 +60,7 @@ const NoBoardBoard = memo(({ isSelected }: Props) => {
> >
<BoardContextMenu board_id="none"> <BoardContextMenu board_id="none">
{(ref) => ( {(ref) => (
<Tooltip label={tooltip} openDelay={1000}> <Tooltip label={<BoardTotalsTooltip board_id="none" />} openDelay={1000}>
<Flex <Flex
ref={ref} ref={ref}
onClick={handleSelectBoard} onClick={handleSelectBoard}

View File

@ -1,18 +0,0 @@
import { useAppSelector } from 'app/store/storeHooks';
import type { BoardId } from 'features/gallery/store/types';
import { useMemo } from 'react';
import { useGetBoardAssetsTotalQuery, useGetBoardImagesTotalQuery } from 'services/api/endpoints/boards';
export const useBoardTotal = (board_id: BoardId) => {
const galleryView = useAppSelector((s) => s.gallery.galleryView);
const { data: totalImages } = useGetBoardImagesTotalQuery(board_id);
const { data: totalAssets } = useGetBoardAssetsTotalQuery(board_id);
const currentViewTotal = useMemo(
() => (galleryView === 'images' ? totalImages?.total : totalAssets?.total),
[galleryView, totalAssets, totalImages]
);
return { totalImages, totalAssets, currentViewTotal };
};