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

Update RequestStepCategory to add Empty and Loading states for category list #41344

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 25 additions & 4 deletions src/ROUTES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,27 @@ const ROUTES = {
getRoute: (action: IOUAction, iouType: IOUType, transactionID: string, reportID: string, backTo = '', reportActionID?: string) =>
getUrlWithBackToParam(`${action as string}/${iouType as string}/category/${transactionID}/${reportID}${reportActionID ? `/${reportActionID}` : ''}`, backTo),
},
SETTINGS_CATEGORIES_ROOT: {
route: 'settings/:policyID/categories',
getRoute: (policyID: string, backTo = '') => getUrlWithBackToParam(`settings/${policyID}/categories`, backTo),
},
SETTINGS_CATEGORY_SETTINGS: {
route: 'settings/:policyID/categories/:categoryName',
getRoute: (policyID: string, categoryName: string, backTo = '') => getUrlWithBackToParam(`settings/${policyID}/categories/${encodeURIComponent(categoryName)}`, backTo),
},
SETTINGS_CATEGORIES_SETTINGS: {
route: 'settings/:policyID/categories/settings',
getRoute: (policyID: string, backTo = '') => getUrlWithBackToParam(`settings/${policyID}/categories/settings`, backTo),
},
SETTINGS_CATEGORY_CREATE: {
route: 'settings/:policyID/categories/new',
getRoute: (policyID: string, backTo = '') => getUrlWithBackToParam(`settings/${policyID}/categories/new`, backTo),
},
SETTINGS_CATEGORY_EDIT: {
route: 'settings/:policyID/categories/:categoryName/edit',
getRoute: (policyID: string, categoryName: string, backTo = '') =>
getUrlWithBackToParam(`settings/workspaces/${policyID}/categories/${encodeURIComponent(categoryName)}/edit`, backTo),
},
Beamanator marked this conversation as resolved.
Show resolved Hide resolved
MONEY_REQUEST_STEP_CURRENCY: {
route: ':action/:iouType/currency/:transactionID/:reportID/:pageIndex?',
getRoute: (action: IOUAction, iouType: IOUType, transactionID: string, reportID: string, pageIndex = '', currency = '', backTo = '') =>
Expand Down Expand Up @@ -657,10 +678,6 @@ const ROUTES = {
route: 'settings/workspaces/:policyID/categories/settings',
getRoute: (policyID: string) => `settings/workspaces/${policyID}/categories/settings` as const,
},
WORKSPACE_MORE_FEATURES: {
route: 'settings/workspaces/:policyID/more-features',
getRoute: (policyID: string) => `settings/workspaces/${policyID}/more-features` as const,
},
WORKSPACE_CATEGORY_CREATE: {
route: 'settings/workspaces/:policyID/categories/new',
getRoute: (policyID: string) => `settings/workspaces/${policyID}/categories/new` as const,
Expand All @@ -669,6 +686,10 @@ const ROUTES = {
route: 'settings/workspaces/:policyID/categories/:categoryName/edit',
getRoute: (policyID: string, categoryName: string) => `settings/workspaces/${policyID}/categories/${encodeURIComponent(categoryName)}/edit` as const,
},
WORKSPACE_MORE_FEATURES: {
route: 'settings/workspaces/:policyID/more-features',
getRoute: (policyID: string) => `settings/workspaces/${policyID}/more-features` as const,
},
WORKSPACE_TAGS: {
route: 'settings/workspaces/:policyID/tags',
getRoute: (policyID: string) => `settings/workspaces/${policyID}/tags` as const,
Expand Down
9 changes: 9 additions & 0 deletions src/SCREENS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ const SCREENS = {
PROCESS_MONEY_REQUEST_HOLD: 'ProcessMoneyRequestHold',
TRAVEL: 'Travel',
SEARCH_REPORT: 'SearchReport',
SETTINGS_CATEGORIES: 'SettingsCategories',
},
ONBOARDING_MODAL: {
ONBOARDING: 'Onboarding',
Expand Down Expand Up @@ -186,6 +187,14 @@ const SCREENS = {
ENABLE_PAYMENTS: 'IOU_Send_Enable_Payments',
},

SETTINGS_CATEGORIES: {
SETTINGS_CATEGORY_SETTINGS: 'Settings_Category_Settings',
SETTINGS_CATEGORIES_SETTINGS: 'Settings_Categories_Settings',
SETTINGS_CATEGORY_CREATE: 'Settings_Category_Create',
SETTINGS_CATEGORY_EDIT: 'Settings_Category_Edit',
SETTINGS_CATEGORIES_ROOT: 'Settings_Categories',
},

REPORT_SETTINGS: {
ROOT: 'Report_Settings_Root',
NAME: 'Report_Settings_Name',
Expand Down
6 changes: 6 additions & 0 deletions src/components/BlockingViews/BlockingView.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type {ImageContentFit} from 'expo-image';
import React, {useMemo} from 'react';
import type {ImageSourcePropType, StyleProp, ViewStyle, WebStyle} from 'react-native';
import {View} from 'react-native';
Expand Down Expand Up @@ -37,6 +38,9 @@ type BaseBlockingViewProps = {
/** Render custom subtitle */
CustomSubtitle?: React.ReactElement;

/** Determines how the image should be resized to fit its container */
contentFitImage?: ImageContentFit;

/** Additional styles to apply to the container */
containerStyle?: StyleProp<ViewStyle>;
};
Expand Down Expand Up @@ -84,6 +88,7 @@ function BlockingView({
animationStyles = [],
animationWebStyle = {},
CustomSubtitle,
contentFitImage,
containerStyle,
}: BlockingViewProps) {
const styles = useThemeStyles();
Expand Down Expand Up @@ -137,6 +142,7 @@ function BlockingView({
fill={iconColor}
width={iconWidth}
height={iconHeight}
contentFit={contentFitImage}
/>
)}
<View>
Expand Down
1 change: 1 addition & 0 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2149,6 +2149,7 @@ export default {
createFailureMessage: 'An error occurred while creating the category, please try again.',
addCategory: 'Add category',
editCategory: 'Edit category',
editCategories: 'Edit categories',
categoryRequiredError: 'Category name is required.',
existingCategoryError: 'A category with this name already exists.',
invalidCategoryName: 'Invalid category name.',
Expand Down
1 change: 1 addition & 0 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2187,6 +2187,7 @@ export default {
createFailureMessage: 'Se ha producido un error al intentar crear la categoría. Por favor, inténtalo más tarde.',
addCategory: 'Añadir categoría',
editCategory: 'Editar categoría',
editCategories: 'Editar categorías',
categoryRequiredError: 'Lo nombre de la categoría es obligatorio.',
existingCategoryError: 'Ya existe una categoría con este nombre.',
invalidCategoryName: 'Lo nombre de la categoría es invalido.',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ const MoneyRequestModalStackNavigator = createModalStackNavigator<MoneyRequestNa
[SCREENS.MONEY_REQUEST.STEP_DISTANCE_RATE]: () => require('@pages/iou/request/step/IOURequestStepDistanceRate').default as React.ComponentType,
[SCREENS.MONEY_REQUEST.STEP_MERCHANT]: () => require('../../../../pages/iou/request/step/IOURequestStepMerchant').default as React.ComponentType,
[SCREENS.MONEY_REQUEST.STEP_PARTICIPANTS]: () => require('../../../../pages/iou/request/step/IOURequestStepParticipants').default as React.ComponentType,
[SCREENS.SETTINGS_CATEGORIES.SETTINGS_CATEGORIES_ROOT]: () => require('../../../../pages/workspace/categories/WorkspaceCategoriesPage').default as React.ComponentType,
[SCREENS.MONEY_REQUEST.STEP_SCAN]: () => require('../../../../pages/iou/request/step/IOURequestStepScan').default as React.ComponentType,
[SCREENS.MONEY_REQUEST.STEP_TAG]: () => require('../../../../pages/iou/request/step/IOURequestStepTag').default as React.ComponentType,
[SCREENS.MONEY_REQUEST.STEP_WAYPOINT]: () => require('../../../../pages/iou/request/step/IOURequestStepWaypoint').default as React.ComponentType,
Expand Down Expand Up @@ -133,6 +134,13 @@ const ReportDescriptionModalStackNavigator = createModalStackNavigator<ReportDes
[SCREENS.REPORT_DESCRIPTION_ROOT]: () => require('../../../../pages/ReportDescriptionPage').default as React.ComponentType,
});

const CategoriesModalStackNavigator = createModalStackNavigator({
[SCREENS.SETTINGS_CATEGORIES.SETTINGS_CATEGORIES_SETTINGS]: () => require('../../../../pages/workspace/categories/WorkspaceCategoriesSettingsPage').default as React.ComponentType,
[SCREENS.SETTINGS_CATEGORIES.SETTINGS_CATEGORY_CREATE]: () => require('../../../../pages/workspace/categories/CreateCategoryPage').default as React.ComponentType,
[SCREENS.SETTINGS_CATEGORIES.SETTINGS_CATEGORY_EDIT]: () => require('../../../../pages/workspace/categories/EditCategoryPage').default as React.ComponentType,
[SCREENS.SETTINGS_CATEGORIES.SETTINGS_CATEGORY_SETTINGS]: () => require('../../../../pages/workspace/categories/CategorySettingsPage').default as React.ComponentType,
});

const ReportParticipantsModalStackNavigator = createModalStackNavigator<ParticipantsNavigatorParamList>({
[SCREENS.REPORT_PARTICIPANTS.ROOT]: () => require('../../../../pages/ReportParticipantsPage').default as React.ComponentType,
[SCREENS.REPORT_PARTICIPANTS.INVITE]: () => require('../../../../pages/InviteReportParticipantsPage').default as React.ComponentType,
Expand Down Expand Up @@ -392,6 +400,7 @@ export {
RoomMembersModalStackNavigator,
SettingsModalStackNavigator,
SignInModalStackNavigator,
CategoriesModalStackNavigator,
SplitDetailsModalStackNavigator,
TaskModalStackNavigator,
WalletStatementStackNavigator,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ function RightModalNavigator({navigation}: RightModalNavigatorProps) {
name={SCREENS.RIGHT_MODAL.REPORT_DESCRIPTION}
component={ModalStackNavigators.ReportDescriptionModalStackNavigator}
/>
<Stack.Screen
name={SCREENS.RIGHT_MODAL.SETTINGS_CATEGORIES}
component={ModalStackNavigators.CategoriesModalStackNavigator}
/>
<Stack.Screen
name={SCREENS.RIGHT_MODAL.PARTICIPANTS}
component={ModalStackNavigators.ReportParticipantsModalStackNavigator}
Expand Down
23 changes: 23 additions & 0 deletions src/libs/Navigation/linkingConfig/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,28 @@ const config: LinkingOptions<RootStackParamList>['config'] = {
},
},
},
[SCREENS.RIGHT_MODAL.SETTINGS_CATEGORIES]: {
screens: {
[SCREENS.SETTINGS_CATEGORIES.SETTINGS_CATEGORY_SETTINGS]: {
path: ROUTES.SETTINGS_CATEGORY_SETTINGS.route,
parse: {
categoryName: (categoryName: string) => decodeURIComponent(categoryName),
},
},
[SCREENS.SETTINGS_CATEGORIES.SETTINGS_CATEGORIES_SETTINGS]: {
path: ROUTES.SETTINGS_CATEGORIES_SETTINGS.route,
},
[SCREENS.SETTINGS_CATEGORIES.SETTINGS_CATEGORY_CREATE]: {
path: ROUTES.SETTINGS_CATEGORY_CREATE.route,
},
[SCREENS.SETTINGS_CATEGORIES.SETTINGS_CATEGORY_EDIT]: {
path: ROUTES.SETTINGS_CATEGORY_EDIT.route,
parse: {
categoryName: (categoryName: string) => decodeURIComponent(categoryName),
},
},
},
},
[SCREENS.RIGHT_MODAL.REPORT_DESCRIPTION]: {
screens: {
[SCREENS.REPORT_DESCRIPTION_ROOT]: ROUTES.REPORT_DESCRIPTION.route,
Expand Down Expand Up @@ -631,6 +653,7 @@ const config: LinkingOptions<RootStackParamList>['config'] = {
},
},
},
[SCREENS.SETTINGS_CATEGORIES.SETTINGS_CATEGORIES_ROOT]: ROUTES.SETTINGS_CATEGORIES_ROOT.route,
[SCREENS.MONEY_REQUEST.STEP_SEND_FROM]: ROUTES.MONEY_REQUEST_STEP_SEND_FROM.route,
[SCREENS.MONEY_REQUEST.STEP_AMOUNT]: ROUTES.MONEY_REQUEST_STEP_AMOUNT.route,
[SCREENS.MONEY_REQUEST.STEP_CATEGORY]: ROUTES.MONEY_REQUEST_STEP_CATEGORY.route,
Expand Down
6 changes: 6 additions & 0 deletions src/libs/Navigation/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,17 +193,21 @@ type SettingsNavigatorParamList = {
};
[SCREENS.WORKSPACE.CATEGORY_CREATE]: {
policyID: string;
backTo?: Routes;
};
[SCREENS.WORKSPACE.CATEGORY_EDIT]: {
policyID: string;
categoryName: string;
backTo?: Routes;
};
[SCREENS.WORKSPACE.CATEGORY_SETTINGS]: {
policyID: string;
categoryName: string;
backTo?: Routes;
};
[SCREENS.WORKSPACE.CATEGORIES_SETTINGS]: {
policyID: string;
backTo?: Routes;
};
[SCREENS.WORKSPACE.TAG_CREATE]: {
policyID: string;
Expand Down Expand Up @@ -730,6 +734,7 @@ type RightModalNavigatorParamList = {
[SCREENS.SETTINGS.SHARE_CODE]: undefined;
[SCREENS.RIGHT_MODAL.REPORT_DETAILS]: NavigatorScreenParams<ReportDetailsNavigatorParamList>;
[SCREENS.RIGHT_MODAL.REPORT_SETTINGS]: NavigatorScreenParams<ReportSettingsNavigatorParamList>;
[SCREENS.RIGHT_MODAL.SETTINGS_CATEGORIES]: NavigatorScreenParams<SettingsNavigatorParamList>;
[SCREENS.RIGHT_MODAL.REPORT_DESCRIPTION]: NavigatorScreenParams<ReportDescriptionNavigatorParamList>;
[SCREENS.RIGHT_MODAL.PARTICIPANTS]: NavigatorScreenParams<ParticipantsNavigatorParamList>;
[SCREENS.RIGHT_MODAL.ROOM_MEMBERS]: NavigatorScreenParams<RoomMembersNavigatorParamList>;
Expand Down Expand Up @@ -796,6 +801,7 @@ type FullScreenNavigatorParamList = {
};
[SCREENS.WORKSPACE.CATEGORIES]: {
policyID: string;
backTo?: Routes;
};
[SCREENS.WORKSPACE.MORE_FEATURES]: {
policyID: string;
Expand Down
68 changes: 58 additions & 10 deletions src/pages/iou/request/step/IOURequestStepCategory.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
import lodashIsEmpty from 'lodash/isEmpty';
import React, {useEffect} from 'react';
import {ActivityIndicator, View} from 'react-native';
import type {OnyxEntry} from 'react-native-onyx';
import {withOnyx} from 'react-native-onyx';
import BlockingView from '@components/BlockingViews/BlockingView';
import Button from '@components/Button';
import CategoryPicker from '@components/CategoryPicker';
import FixedFooter from '@components/FixedFooter';
import * as Illustrations from '@components/Icon/Illustrations';
import type {ListItem} from '@components/SelectionList/types';
import Text from '@components/Text';
import useLocalize from '@hooks/useLocalize';
import useNetwork from '@hooks/useNetwork';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import Navigation from '@libs/Navigation/Navigation';
import * as OptionsListUtils from '@libs/OptionsListUtils';
import * as ReportUtils from '@libs/ReportUtils';
import * as TransactionUtils from '@libs/TransactionUtils';
import variables from '@styles/variables';
import * as IOU from '@userActions/IOU';
import * as PolicyActions from '@userActions/Policy/Policy';
import CONST from '@src/CONST';
Expand Down Expand Up @@ -75,6 +82,7 @@ function IOURequestStepCategory({
const policy = policyReal ?? policyDraft;
const policyCategories = policyCategoriesReal ?? policyCategoriesDraft;
const styles = useThemeStyles();
const theme = useTheme();
const {translate} = useLocalize();
const isEditing = action === CONST.IOU.ACTION.EDIT;
const isEditingSplitBill = isEditing && iouType === CONST.IOU.TYPE.SPLIT;
Expand All @@ -92,7 +100,7 @@ function IOURequestStepCategory({
const isSplitBill = iouType === CONST.IOU.TYPE.SPLIT;
const canEditSplitBill = isSplitBill && reportAction && session?.accountID === reportAction.actorAccountID && TransactionUtils.areRequiredFieldsEmpty(transaction);
// eslint-disable-next-line rulesdir/no-negated-variables
Beamanator marked this conversation as resolved.
Show resolved Hide resolved
const shouldShowNotFoundPage = !shouldShowCategory || (isEditing && (isSplitBill ? !canEditSplitBill : !ReportUtils.canEditMoneyRequest(reportAction)));
const shouldShowNotFoundPage = isEditing && (isSplitBill ? !canEditSplitBill : !ReportUtils.canEditMoneyRequest(reportAction));

const fetchData = () => {
if (policy && policyCategories) {
Expand All @@ -101,8 +109,9 @@ function IOURequestStepCategory({

PolicyActions.openDraftWorkspaceRequest(report?.policyID ?? '');
};

useNetwork({onReconnect: fetchData});
const {isOffline} = useNetwork({onReconnect: fetchData});
const isLoading = !isOffline && policyCategories === undefined;
const shouldShowEmptyState = !isLoading && !shouldShowCategory;

useEffect(() => {
fetchData();
Expand Down Expand Up @@ -150,14 +159,53 @@ function IOURequestStepCategory({
shouldShowWrapper
shouldShowNotFoundPage={shouldShowNotFoundPage}
testID={IOURequestStepCategory.displayName}
includeSafeAreaPaddingBottom={false}
>
<Text style={[styles.ph5, styles.pv3]}>{translate('iou.categorySelection')}</Text>
<CategoryPicker
selectedCategory={transactionCategory}
policyID={report?.policyID ?? policy?.id ?? ''}
onSubmit={updateCategory}
/>
{isLoading && (
<ActivityIndicator
size={CONST.ACTIVITY_INDICATOR_SIZE.LARGE}
style={[styles.flex1]}
color={theme.spinner}
/>
)}
{shouldShowEmptyState && (
<View style={[styles.flex1]}>
<BlockingView
icon={Illustrations.EmptyStateExpenses}
iconWidth={variables.modalTopIconWidth}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Coming from #43064. This caused a regression where the empty folder icon was not centred. This is because the width and height values used here are incorrect for the icon used.

iconHeight={variables.modalTopIconHeight}
title={translate('workspace.categories.emptyCategories.title')}
subtitle={translate('workspace.categories.emptyCategories.subtitle')}
contentFitImage="contain"
/>
<FixedFooter style={[styles.mtAuto, styles.pt5]}>
<Button
large
success
style={[styles.w100]}
onPress={() =>
Navigation.navigate(
ROUTES.SETTINGS_CATEGORIES_ROOT.getRoute(
policy?.id ?? '',
ROUTES.MONEY_REQUEST_STEP_CATEGORY.getRoute(action, iouType, transactionID, report?.reportID ?? '', backTo, reportActionID),
),
)
}
text={translate('workspace.categories.editCategories')}
pressOnEnter
/>
</FixedFooter>
</View>
)}
{!shouldShowEmptyState && !isLoading && (
<>
<Text style={[styles.ph5, styles.pv3]}>{translate('iou.categorySelection')}</Text>
<CategoryPicker
selectedCategory={transactionCategory}
policyID={report?.policyID ?? policy?.id ?? ''}
onSubmit={updateCategory}
/>
</>
)}
</StepScreenWrapper>
);
}
Expand Down
4 changes: 1 addition & 3 deletions src/pages/workspace/categories/CategoryForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import useAutoFocusInput from '@hooks/useAutoFocusInput';
import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import * as ErrorUtils from '@libs/ErrorUtils';
import Navigation from '@libs/Navigation/Navigation';
import * as ValidationUtils from '@libs/ValidationUtils';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
Expand Down Expand Up @@ -58,9 +57,8 @@ function CategoryForm({onSubmit, policyCategories, categoryName, validateEdit}:

const submit = useCallback(
(values: FormOnyxValues<typeof ONYXKEYS.FORMS.WORKSPACE_CATEGORY_FORM>) => {
onSubmit(values);
Keyboard.dismiss();
Navigation.goBack();
onSubmit(values);
},
[onSubmit],
);
Expand Down
Loading
Loading