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