From 2480fb7a9e129857934913344fa38711d1e39d2b Mon Sep 17 00:00:00 2001 From: mateusz-winiarczyk <mateusz.winiarczyk@appunite.com> Date: Fri, 12 Jan 2024 13:56:56 +0100 Subject: [PATCH] feat(overlays): add loading indicators for overlays --- src/assets/vectors/icons/spinner.svg | 3 +++ .../OverlayListItem.component.test.tsx | 14 +++++++++++++ .../OverlayListItem.component.tsx | 21 ++++++++++++++++--- .../OverlayListItem/hooks/useOverlay.ts | 9 ++++++-- .../overlayBioEntity.selector.ts | 6 ++++++ 5 files changed, 48 insertions(+), 5 deletions(-) create mode 100644 src/assets/vectors/icons/spinner.svg diff --git a/src/assets/vectors/icons/spinner.svg b/src/assets/vectors/icons/spinner.svg new file mode 100644 index 00000000..c977723f --- /dev/null +++ b/src/assets/vectors/icons/spinner.svg @@ -0,0 +1,3 @@ +<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg"> + <path d="M10.2427 1.75736L9.2998 2.70017C8.45533 1.85567 7.28867 1.33333 6 1.33333C3.42267 1.33333 1.33333 3.42267 1.33333 6C1.33333 8.57733 3.42267 10.6667 6 10.6667C8.57733 10.6667 10.6667 8.57733 10.6667 6H12C12 9.31373 9.31373 12 6 12C2.68629 12 0 9.31373 0 6C0 2.68629 2.68629 0 6 0C7.65687 0 9.15687 0.671574 10.2427 1.75736Z" fill="black"/> +</svg> diff --git a/src/components/Map/Drawer/OverlaysDrawer/GeneralOverlays/OverlayListItem/OverlayListItem.component.test.tsx b/src/components/Map/Drawer/OverlaysDrawer/GeneralOverlays/OverlayListItem/OverlayListItem.component.test.tsx index 1c2e5658..37ede689 100644 --- a/src/components/Map/Drawer/OverlaysDrawer/GeneralOverlays/OverlayListItem/OverlayListItem.component.test.tsx +++ b/src/components/Map/Drawer/OverlaysDrawer/GeneralOverlays/OverlayListItem/OverlayListItem.component.test.tsx @@ -95,6 +95,20 @@ describe('OverlayListItem - component', () => { expect(store.getState().overlayBioEntity.data).toEqual([]); expect(store.getState().overlayBioEntity.overlaysId).toEqual([]); }); + it('should display spinner icon if overlay is loading', () => { + const OVERLAY_ID = 21; + renderComponent({ + overlayBioEntity: { + data: { + [OVERLAY_ID]: {}, + }, + overlaysId: [OVERLAY_ID], + }, + }); + + expect(screen.getByAltText('spinner icon')).toBeVisible(); + expect(screen.getByText('Disable')).toBeVisible(); + }); }); // TODO implement when connecting logic to component diff --git a/src/components/Map/Drawer/OverlaysDrawer/GeneralOverlays/OverlayListItem/OverlayListItem.component.tsx b/src/components/Map/Drawer/OverlaysDrawer/GeneralOverlays/OverlayListItem/OverlayListItem.component.tsx index ab40e7cf..21eefae1 100644 --- a/src/components/Map/Drawer/OverlaysDrawer/GeneralOverlays/OverlayListItem/OverlayListItem.component.tsx +++ b/src/components/Map/Drawer/OverlaysDrawer/GeneralOverlays/OverlayListItem/OverlayListItem.component.tsx @@ -1,4 +1,6 @@ import { Button } from '@/shared/Button'; +import Image from 'next/image'; +import spinnerIcon from '@/assets/vectors/icons/spinner.svg'; import { useOverlay } from './hooks/useOverlay'; interface OverlayListItemProps { @@ -8,14 +10,27 @@ interface OverlayListItemProps { export const OverlayListItem = ({ name, overlayId }: OverlayListItemProps): JSX.Element => { const onDownloadOverlay = (): void => {}; - const { toggleOverlay, isOverlayActive } = useOverlay(overlayId); + const { toggleOverlay, isOverlayActive, isOverlayLoading } = useOverlay(overlayId); return ( <li className="flex flex-row flex-nowrap justify-between pl-5 [&:not(:last-of-type)]:mb-4"> <span>{name}</span> <div className="flex flex-row flex-nowrap"> - <Button variantStyles="ghost" className="mr-4 max-h-8" onClick={toggleOverlay}> - {isOverlayActive ? 'Disable' : 'View'} + <Button + variantStyles="ghost" + className="mr-4 max-h-8 flex-none gap-1.5" + onClick={toggleOverlay} + > + {isOverlayLoading && ( + <Image + src={spinnerIcon} + alt="spinner icon" + height={12} + width={12} + className="animate-spin" + /> + )} + {isOverlayActive || isOverlayActive ? 'Disable' : 'View'} </Button> <Button className="max-h-8" variantStyles="ghost" onClick={onDownloadOverlay}> Download diff --git a/src/components/Map/Drawer/OverlaysDrawer/GeneralOverlays/OverlayListItem/hooks/useOverlay.ts b/src/components/Map/Drawer/OverlaysDrawer/GeneralOverlays/OverlayListItem/hooks/useOverlay.ts index 89f65ee8..d69c8df3 100644 --- a/src/components/Map/Drawer/OverlaysDrawer/GeneralOverlays/OverlayListItem/hooks/useOverlay.ts +++ b/src/components/Map/Drawer/OverlaysDrawer/GeneralOverlays/OverlayListItem/hooks/useOverlay.ts @@ -1,6 +1,9 @@ import { useAppDispatch } from '@/redux/hooks/useAppDispatch'; import { useAppSelector } from '@/redux/hooks/useAppSelector'; -import { isOverlayActiveSelector } from '@/redux/overlayBioEntity/overlayBioEntity.selector'; +import { + isOverlayActiveSelector, + isOverlayLoadingSelector, +} from '@/redux/overlayBioEntity/overlayBioEntity.selector'; import { removeOverlayBioEntityForGivenOverlay } from '@/redux/overlayBioEntity/overlayBioEntity.slice'; import { getOverlayBioEntityForAllModels } from '@/redux/overlayBioEntity/overlayBioEntity.thunk'; import { useEmptyBackground } from './useEmptyBackground'; @@ -8,11 +11,13 @@ import { useEmptyBackground } from './useEmptyBackground'; type UseOverlay = { toggleOverlay: () => void; isOverlayActive: boolean; + isOverlayLoading: boolean; }; export const useOverlay = (overlayId: number): UseOverlay => { const dispatch = useAppDispatch(); const isOverlayActive = useAppSelector(state => isOverlayActiveSelector(state, overlayId)); + const isOverlayLoading = useAppSelector(state => isOverlayLoadingSelector(state, overlayId)); const { setBackgroundtoEmptyIfAvailable } = useEmptyBackground(); const toggleOverlay = (): void => { @@ -24,5 +29,5 @@ export const useOverlay = (overlayId: number): UseOverlay => { } }; - return { toggleOverlay, isOverlayActive }; + return { toggleOverlay, isOverlayActive, isOverlayLoading }; }; diff --git a/src/redux/overlayBioEntity/overlayBioEntity.selector.ts b/src/redux/overlayBioEntity/overlayBioEntity.selector.ts index 0e87f44e..94f18b3a 100644 --- a/src/redux/overlayBioEntity/overlayBioEntity.selector.ts +++ b/src/redux/overlayBioEntity/overlayBioEntity.selector.ts @@ -42,6 +42,12 @@ export const isOverlayActiveSelector = createSelector( (overlaysId, overlayId) => overlaysId.includes(overlayId), ); +export const isOverlayLoadingSelector = createSelector( + [overlayBioEntitySelector, (_, overlayId: number): number => overlayId], + ({ overlaysId, data }, overlayId) => + overlaysId.includes(overlayId) && data[overlayId] && !Object.keys(data[overlayId]).length, +); + export const activeOverlaysSelector = createSelector( rootSelector, overlaysDataSelector, -- GitLab