Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Add spinning loader until full list of policies is successfully download on the client #54238

Merged
merged 10 commits into from
Dec 30, 2024
44 changes: 26 additions & 18 deletions src/pages/WorkspaceSwitcherPage/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {useIsFocused} from '@react-navigation/native';
import React, {useCallback, useMemo} from 'react';
import {useOnyx} from 'react-native-onyx';
import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
import HeaderWithBackButton from '@components/HeaderWithBackButton';
import * as Expensicons from '@components/Icon/Expensicons';
import ScreenWrapper from '@components/ScreenWrapper';
Expand All @@ -11,6 +12,7 @@ import useActiveWorkspace from '@hooks/useActiveWorkspace';
import useDebouncedState from '@hooks/useDebouncedState';
import useLocalize from '@hooks/useLocalize';
import useNetwork from '@hooks/useNetwork';
import useThemeStyles from '@hooks/useThemeStyles';
import Navigation from '@libs/Navigation/Navigation';
import * as PolicyUtils from '@libs/PolicyUtils';
import {sortWorkspacesBySelected} from '@libs/PolicyUtils';
Expand All @@ -34,6 +36,7 @@ const WorkspaceCardCreateAWorkspaceInstance = <WorkspaceCardCreateAWorkspace />;

function WorkspaceSwitcherPage() {
const {isOffline} = useNetwork();
const styles = useThemeStyles();
const [searchTerm, debouncedSearchTerm, setSearchTerm] = useDebouncedState('');
const {translate} = useLocalize();
const {activeWorkspaceID, setActiveWorkspaceID} = useActiveWorkspace();
Expand All @@ -43,9 +46,10 @@ function WorkspaceSwitcherPage() {
const [reportActions] = useOnyx(ONYXKEYS.COLLECTION.REPORT_ACTIONS);
const [policies, fetchStatus] = useOnyx(ONYXKEYS.COLLECTION.POLICY);
const [currentUserLogin] = useOnyx(ONYXKEYS.SESSION, {selector: (session) => session?.email});

const [isLoadingApp] = useOnyx(ONYXKEYS.IS_LOADING_APP);
const brickRoadsForPolicies = useMemo(() => getWorkspacesBrickRoads(reports, policies, reportActions), [reports, policies, reportActions]);
const unreadStatusesForPolicies = useMemo(() => getWorkspacesUnreadStatuses(reports), [reports]);
const shouldShowLoadingIndicator = isLoadingApp && !isOffline;

const getIndicatorTypeForPolicy = useCallback(
(policyId?: string) => {
Expand Down Expand Up @@ -157,23 +161,27 @@ function WorkspaceSwitcherPage() {
title={translate('workspace.switcher.headerTitle')}
onBackButtonPress={Navigation.goBack}
/>
<SelectionList<WorkspaceListItem>
ListItem={UserListItem}
sections={sections}
onSelectRow={(option) => selectPolicy(option.policyID)}
textInputLabel={usersWorkspaces.length >= CONST.STANDARD_LIST_ITEM_LIMIT ? translate('common.search') : undefined}
textInputValue={searchTerm}
onChangeText={setSearchTerm}
headerMessage={headerMessage}
listEmptyContent={WorkspaceCardCreateAWorkspaceInstance}
shouldShowListEmptyContent={shouldShowCreateWorkspace}
initiallyFocusedOptionKey={activeWorkspaceID ?? CONST.WORKSPACE_SWITCHER.NAME}
showLoadingPlaceholder={fetchStatus.status === 'loading' || !didScreenTransitionEnd}
showConfirmButton={!!activeWorkspaceID}
shouldUseDefaultTheme
confirmButtonText={translate('workspace.common.clearFilter')}
onConfirm={() => selectPolicy(undefined)}
/>
{shouldShowLoadingIndicator ? (
<FullScreenLoadingIndicator style={[styles.flex1, styles.pRelative]} />
) : (
<SelectionList<WorkspaceListItem>
ListItem={UserListItem}
sections={sections}
onSelectRow={(option) => selectPolicy(option.policyID)}
textInputLabel={usersWorkspaces.length >= CONST.STANDARD_LIST_ITEM_LIMIT ? translate('common.search') : undefined}
textInputValue={searchTerm}
onChangeText={setSearchTerm}
headerMessage={headerMessage}
listEmptyContent={WorkspaceCardCreateAWorkspaceInstance}
shouldShowListEmptyContent={shouldShowCreateWorkspace}
initiallyFocusedOptionKey={activeWorkspaceID ?? CONST.WORKSPACE_SWITCHER.NAME}
showLoadingPlaceholder={fetchStatus.status === 'loading' || !didScreenTransitionEnd}
showConfirmButton={!!activeWorkspaceID}
shouldUseDefaultTheme
confirmButtonText={translate('workspace.common.clearFilter')}
onConfirm={() => selectPolicy(undefined)}
/>
)}
</>
)}
</ScreenWrapper>
Expand Down
39 changes: 23 additions & 16 deletions src/pages/workspace/WorkspacesListPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import Button from '@components/Button';
import ConfirmModal from '@components/ConfirmModal';
import FeatureList from '@components/FeatureList';
import type {FeatureListItem} from '@components/FeatureList';
import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
import HeaderWithBackButton from '@components/HeaderWithBackButton';
import * as Expensicons from '@components/Icon/Expensicons';
import * as Illustrations from '@components/Icon/Illustrations';
Expand Down Expand Up @@ -113,6 +114,8 @@ function WorkspacesListPage() {
const [reimbursementAccount] = useOnyx(ONYXKEYS.REIMBURSEMENT_ACCOUNT);
const [reports] = useOnyx(ONYXKEYS.COLLECTION.REPORT);
const [session] = useOnyx(ONYXKEYS.SESSION);
const [isLoadingApp] = useOnyx(ONYXKEYS.IS_LOADING_APP);
const shouldShowLoadingIndicator = isLoadingApp && !isOffline;

const {activeWorkspaceID, setActiveWorkspaceID} = useActiveWorkspace();

Expand Down Expand Up @@ -419,22 +422,26 @@ function WorkspacesListPage() {
icon={Illustrations.Buildings}
shouldUseHeadlineHeader
/>
<ScrollView contentContainerStyle={styles.pt3}>
<View style={[styles.flex1, isLessThanMediumScreen ? styles.workspaceSectionMobile : styles.workspaceSection]}>
<FeatureList
menuItems={workspaceFeatures}
title={translate('workspace.emptyWorkspace.title')}
subtitle={translate('workspace.emptyWorkspace.subtitle')}
ctaText={translate('workspace.new.newWorkspace')}
ctaAccessibilityLabel={translate('workspace.new.newWorkspace')}
onCtaPress={() => interceptAnonymousUser(() => App.createWorkspaceWithPolicyDraftAndNavigateToIt())}
illustration={LottieAnimations.WorkspacePlanet}
// We use this style to vertically center the illustration, as the original illustration is not centered
illustrationStyle={styles.emptyWorkspaceIllustrationStyle}
titleStyles={styles.textHeadlineH1}
/>
</View>
</ScrollView>
{shouldShowLoadingIndicator ? (
<FullScreenLoadingIndicator style={[styles.flex1, styles.pRelative]} />
) : (
<ScrollView contentContainerStyle={styles.pt3}>
<View style={[styles.flex1, isLessThanMediumScreen ? styles.workspaceSectionMobile : styles.workspaceSection]}>
<FeatureList
menuItems={workspaceFeatures}
title={translate('workspace.emptyWorkspace.title')}
subtitle={translate('workspace.emptyWorkspace.subtitle')}
ctaText={translate('workspace.new.newWorkspace')}
ctaAccessibilityLabel={translate('workspace.new.newWorkspace')}
onCtaPress={() => interceptAnonymousUser(() => App.createWorkspaceWithPolicyDraftAndNavigateToIt())}
illustration={LottieAnimations.WorkspacePlanet}
// We use this style to vertically center the illustration, as the original illustration is not centered
illustrationStyle={styles.emptyWorkspaceIllustrationStyle}
titleStyles={styles.textHeadlineH1}
/>
</View>
</ScrollView>
)}
</ScreenWrapper>
);
}
Expand Down
Loading