From 61b04929f03b12ecbcb09158be89d08eb22a3183 Mon Sep 17 00:00:00 2001
From: Audric Ackermann <audric@loki.network>
Date: Tue, 1 Jun 2021 16:01:59 +1000
Subject: [PATCH] show a spinner while default rooms are loading

---
 .../session/SessionJoinableDefaultRooms.tsx   | 43 +++++++++++--------
 ts/opengroup/opengroupV2/ApiUtil.ts           |  5 ++-
 ts/state/ducks/defaultRooms.tsx               | 30 ++++++++++---
 3 files changed, 52 insertions(+), 26 deletions(-)

diff --git a/ts/components/session/SessionJoinableDefaultRooms.tsx b/ts/components/session/SessionJoinableDefaultRooms.tsx
index 250b8aaf9..a5fe30f71 100644
--- a/ts/components/session/SessionJoinableDefaultRooms.tsx
+++ b/ts/components/session/SessionJoinableDefaultRooms.tsx
@@ -1,4 +1,4 @@
-import React, { useContext, useEffect, useReducer, useState } from 'react';
+import React, { useEffect } from 'react';
 import { useSelector } from 'react-redux';
 import {
   joinOpenGroupV2WithUIEvents,
@@ -11,6 +11,7 @@ import { Avatar, AvatarSize } from '../Avatar';
 import { Flex } from '../basic/Flex';
 import { PillContainer } from '../basic/PillContainer';
 import { H3 } from '../basic/Text';
+import { SessionSpinner } from './SessionSpinner';
 // tslint:disable: no-void-expression
 
 export type JoinableRoomProps = {
@@ -83,29 +84,35 @@ const SessionJoinableRoomRow = (props: JoinableRoomProps) => {
 export const SessionJoinableRooms = () => {
   const joinableRooms = useSelector((state: StateType) => state.defaultRooms);
 
-  if (!joinableRooms?.length) {
-    window?.log?.info('no default joinable rooms yet');
+  if (!joinableRooms.inProgress && !joinableRooms.rooms?.length) {
+    window?.log?.info('no default joinable rooms yet and not in progress');
     return <></>;
   }
 
+  const componentToRender = joinableRooms.inProgress ? (
+    <SessionSpinner loading={true} />
+  ) : (
+    joinableRooms.rooms.map(r => {
+      return (
+        <SessionJoinableRoomRow
+          key={r.id}
+          completeUrl={r.completeUrl}
+          name={r.name}
+          roomId={r.id}
+          base64Data={r.base64Data}
+          onClick={completeUrl => {
+            void joinOpenGroupV2WithUIEvents(completeUrl, true, false);
+          }}
+        />
+      );
+    })
+  );
+
   return (
     <Flex container={true} flexGrow={1} flexDirection="column" width="93%">
       <H3 text={window.i18n('orJoinOneOfThese')} />
-      <Flex container={true} flexGrow={1} flexWrap="wrap">
-        {joinableRooms.map(r => {
-          return (
-            <SessionJoinableRoomRow
-              key={r.id}
-              completeUrl={r.completeUrl}
-              name={r.name}
-              roomId={r.id}
-              base64Data={r.base64Data}
-              onClick={completeUrl => {
-                void joinOpenGroupV2WithUIEvents(completeUrl, true, false);
-              }}
-            />
-          );
-        })}
+      <Flex container={true} flexGrow={1} flexWrap="wrap" justifyContent="center">
+        {componentToRender}
       </Flex>
     </Flex>
   );
diff --git a/ts/opengroup/opengroupV2/ApiUtil.ts b/ts/opengroup/opengroupV2/ApiUtil.ts
index c1c63be42..7f9f5f20c 100644
--- a/ts/opengroup/opengroupV2/ApiUtil.ts
+++ b/ts/opengroup/opengroupV2/ApiUtil.ts
@@ -3,7 +3,7 @@ import { FileServerV2Request } from '../../fileserver/FileServerApiV2';
 import { PubKey } from '../../session/types';
 import { allowOnlyOneAtATime } from '../../session/utils/Promise';
 import { fromBase64ToArrayBuffer, fromHex } from '../../session/utils/String';
-import { updateDefaultRooms } from '../../state/ducks/defaultRooms';
+import { updateDefaultRooms, updateDefaultRoomsInProgress } from '../../state/ducks/defaultRooms';
 import { getCompleteUrlFromRoom } from '../utils/OpenGroupUtils';
 import { parseOpenGroupV2 } from './JoinOpenGroupV2';
 import { getAllRoomInfos } from './OpenGroupAPIV2';
@@ -120,7 +120,10 @@ const loadDefaultRoomsSingle = () =>
  * This call will only run once at a time.
  */
 export const loadDefaultRooms = async () => {
+  window.inboxStore?.dispatch(updateDefaultRoomsInProgress(true));
   const allRooms: Array<OpenGroupV2InfoJoinable> = await loadDefaultRoomsSingle();
+  window.inboxStore?.dispatch(updateDefaultRoomsInProgress(false));
+
   if (allRooms !== undefined) {
     window.inboxStore?.dispatch(updateDefaultRooms(allRooms));
   }
diff --git a/ts/state/ducks/defaultRooms.tsx b/ts/state/ducks/defaultRooms.tsx
index a6c74aecb..6803f6dc9 100644
--- a/ts/state/ducks/defaultRooms.tsx
+++ b/ts/state/ducks/defaultRooms.tsx
@@ -1,9 +1,15 @@
 import { createSlice, PayloadAction } from '@reduxjs/toolkit';
 import { OpenGroupV2InfoJoinable } from '../../opengroup/opengroupV2/ApiUtil';
 
-export type DefaultRoomsState = Array<OpenGroupV2InfoJoinable>;
+export type DefaultRoomsState = {
+  rooms: Array<OpenGroupV2InfoJoinable>;
+  inProgress: boolean;
+};
 
-const initialState: DefaultRoomsState = [];
+const initialState: DefaultRoomsState = {
+  rooms: [],
+  inProgress: false,
+};
 
 /**
  * Payload to dispatch to update the base64 data of a default room
@@ -21,12 +27,18 @@ const defaultRoomsSlice = createSlice({
   initialState,
   reducers: {
     updateDefaultRooms(state, action) {
-      window?.log?.warn('updating default rooms', action.payload);
-      return action.payload as DefaultRoomsState;
+      window?.log?.info('updating default rooms', action.payload);
+      const rooms = action.payload as Array<OpenGroupV2InfoJoinable>;
+      return { ...state, rooms: rooms };
+    },
+    updateDefaultRoomsInProgress(state, action) {
+      const inProgress = action.payload as boolean;
+      window?.log?.info('fetching default rooms inProgress?', action.payload);
+      return { ...state, inProgress };
     },
     updateDefaultBase64RoomData(state, action: PayloadAction<Base64Update>) {
       const payload = action.payload;
-      const newState = state.map(room => {
+      const newRoomsState = state.rooms.map(room => {
         if (room.id === payload.roomId) {
           return {
             ...room,
@@ -35,11 +47,15 @@ const defaultRoomsSlice = createSlice({
         }
         return room;
       });
-      return newState;
+      return { ...state, rooms: newRoomsState };
     },
   },
 });
 
 const { actions, reducer } = defaultRoomsSlice;
-export const { updateDefaultRooms, updateDefaultBase64RoomData } = actions;
+export const {
+  updateDefaultRooms,
+  updateDefaultBase64RoomData,
+  updateDefaultRoomsInProgress,
+} = actions;
 export const defaultRoomReducer = reducer;