diff --git a/assets/images/turtle-in-shell.svg b/assets/images/turtle-in-shell.svg
new file mode 100644
index 000000000000..6c5a8e74bb31
--- /dev/null
+++ b/assets/images/turtle-in-shell.svg
@@ -0,0 +1,87 @@
+
+
\ No newline at end of file
diff --git a/src/components/Icon/Illustrations.ts b/src/components/Icon/Illustrations.ts
index e30fc8bce7b7..70cd0168aba8 100644
--- a/src/components/Icon/Illustrations.ts
+++ b/src/components/Icon/Illustrations.ts
@@ -113,6 +113,7 @@ import WalletAlt from '@assets/images/simple-illustrations/simple-illustration__
import Workflows from '@assets/images/simple-illustrations/simple-illustration__workflows.svg';
import ExpensifyApprovedLogoLight from '@assets/images/subscription-details__approvedlogo--light.svg';
import ExpensifyApprovedLogo from '@assets/images/subscription-details__approvedlogo.svg';
+import TurtleInShell from '@assets/images/turtle-in-shell.svg';
export {
Abracadabra,
@@ -230,4 +231,5 @@ export {
AmexCompanyCards,
MasterCardCompanyCards,
VisaCompanyCards,
+ TurtleInShell,
};
diff --git a/src/languages/en.ts b/src/languages/en.ts
index 48953757deca..3890bfe54b9f 100755
--- a/src/languages/en.ts
+++ b/src/languages/en.ts
@@ -1347,6 +1347,11 @@ export default {
approverInMultipleWorkflows: 'This member already belongs to another approval workflow. Any updates here will reflect there too.',
approverCircularReference: ({name1, name2}: ApprovalWorkflowErrorParams) =>
`${name1} already approves reports to ${name2}. Please choose a different approver to avoid a circular workflow.`,
+ emptyContent: {
+ title: 'No members to display',
+ expensesFromSubtitle: 'All workspace members already belong to an existing approval workflow.',
+ approverSubtitle: 'All approvers belong to an existing workflow.',
+ },
},
workflowsDelayedSubmissionPage: {
autoReportingErrorMessage: "Delayed submission couldn't be changed. Please try again or contact support.",
diff --git a/src/languages/es.ts b/src/languages/es.ts
index 2ab6deacda47..f1b1f4658865 100644
--- a/src/languages/es.ts
+++ b/src/languages/es.ts
@@ -1353,6 +1353,11 @@ export default {
approverInMultipleWorkflows: 'Este miembro ya pertenece a otro flujo de aprobación. Cualquier actualización aquí se reflejará allí también.',
approverCircularReference: ({name1, name2}: ApprovalWorkflowErrorParams) =>
`${name1} ya aprueba informes a ${name2}. Por favor, elige un aprobador diferente para evitar un flujo de trabajo circular.`,
+ emptyContent: {
+ title: 'No hay miembros para mostrar',
+ expensesFromSubtitle: 'Todos los miembros del espacio de trabajo ya pertenecen a un flujo de aprobación existente.',
+ approverSubtitle: 'Todos los aprobadores pertenecen a un flujo de trabajo existente.',
+ },
},
workflowsDelayedSubmissionPage: {
autoReportingErrorMessage: 'El parámetro de envío retrasado no pudo ser cambiado. Por favor, inténtelo de nuevo o contacte al soporte.',
diff --git a/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsApproverPage.tsx b/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsApproverPage.tsx
index 986456c9be0f..9daf6a6a41eb 100644
--- a/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsApproverPage.tsx
+++ b/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsApproverPage.tsx
@@ -4,10 +4,12 @@ import type {SectionListData} from 'react-native';
import type {OnyxEntry} from 'react-native-onyx';
import {useOnyx, withOnyx} from 'react-native-onyx';
import Badge from '@components/Badge';
+import BlockingView from '@components/BlockingViews/BlockingView';
import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView';
import FormAlertWithSubmitButton from '@components/FormAlertWithSubmitButton';
import HeaderWithBackButton from '@components/HeaderWithBackButton';
import {FallbackAvatar} from '@components/Icon/Expensicons';
+import * as Illustrations from '@components/Icon/Illustrations';
import ScreenWrapper from '@components/ScreenWrapper';
import SelectionList from '@components/SelectionList';
import InviteMemberListItem from '@components/SelectionList/InviteMemberListItem';
@@ -30,6 +32,7 @@ import * as PolicyUtils from '@libs/PolicyUtils';
import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper';
import withPolicyAndFullscreenLoading from '@pages/workspace/withPolicyAndFullscreenLoading';
import type {WithPolicyAndFullscreenLoadingProps} from '@pages/workspace/withPolicyAndFullscreenLoading';
+import variables from '@styles/variables';
import * as Policy from '@userActions/Policy/Policy';
import * as Workflow from '@userActions/Workflow';
import CONST from '@src/CONST';
@@ -74,9 +77,8 @@ function WorkspaceWorkflowsApprovalsApproverPageWrapper(props: WorkspaceWorkflow
function WorkspaceWorkflowsApprovalsApproverPageBeta({policy, personalDetails, isLoadingReportData = true, route}: WorkspaceWorkflowsApprovalsApproverPageProps) {
const styles = useThemeStyles();
const {translate} = useLocalize();
- const [didScreenTransitionEnd, setDidScreenTransitionEnd] = useState(false);
const [searchTerm, debouncedSearchTerm, setSearchTerm] = useDebouncedState('');
- const [approvalWorkflow, approvalWorkflowMetadata] = useOnyx(ONYXKEYS.APPROVAL_WORKFLOW);
+ const [approvalWorkflow] = useOnyx(ONYXKEYS.APPROVAL_WORKFLOW);
const [selectedApproverEmail, setSelectedApproverEmail] = useState(undefined);
// eslint-disable-next-line rulesdir/no-negated-variables
@@ -165,6 +167,8 @@ function WorkspaceWorkflowsApprovalsApproverPageBeta({policy, personalDetails, i
translate,
]);
+ const shouldShowListEmptyContent = !debouncedSearchTerm && approvalWorkflow && !sections[0].data.length;
+
const nextStep = useCallback(() => {
if (selectedApproverEmail) {
const policyMemberEmailsToAccountIDs = PolicyUtils.getMemberAccountIDsForWorkspace(policy?.employeeList);
@@ -191,18 +195,23 @@ function WorkspaceWorkflowsApprovalsApproverPageBeta({policy, personalDetails, i
}
}, [approvalWorkflow, approverIndex, personalDetails, policy?.employeeList, route.params.policyID, selectedApproverEmail]);
- const nextButton = useMemo(
- () => (
+ const button = useMemo(() => {
+ let buttonText = isInitialCreationFlow ? translate('common.next') : translate('common.save');
+
+ if (shouldShowListEmptyContent) {
+ buttonText = translate('common.buttonConfirm');
+ }
+
+ return (
- ),
- [isInitialCreationFlow, nextStep, selectedApproverEmail, styles.flexBasisAuto, styles.flexGrow0, styles.flexReset, styles.flexShrink0, translate],
- );
+ );
+ }, [isInitialCreationFlow, nextStep, selectedApproverEmail, shouldShowListEmptyContent, styles.flexBasisAuto, styles.flexGrow0, styles.flexReset, styles.flexShrink0, translate]);
const goBack = useCallback(() => {
if (isInitialCreationFlow) {
@@ -221,6 +230,21 @@ function WorkspaceWorkflowsApprovalsApproverPageBeta({policy, personalDetails, i
const headerMessage = useMemo(() => (searchTerm && !sections[0].data.length ? translate('common.noResultsFound') : ''), [searchTerm, sections, translate]);
+ const listEmptyContent = useMemo(
+ () => (
+
+ ),
+ [translate, styles.textSupporting, styles.pb10],
+ );
+
return (
setDidScreenTransitionEnd(true)}
>
- {approvalWorkflow?.action === CONST.APPROVAL_WORKFLOW.ACTION.CREATE && (
+ {approvalWorkflow?.action === CONST.APPROVAL_WORKFLOW.ACTION.CREATE && !shouldShowListEmptyContent && (
{translate('workflowsApproverPage.header')}
)}
diff --git a/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsExpensesFromPage.tsx b/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsExpensesFromPage.tsx
index f1a0f34dda01..e99164587da6 100644
--- a/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsExpensesFromPage.tsx
+++ b/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsExpensesFromPage.tsx
@@ -3,10 +3,12 @@ import React, {useCallback, useEffect, useMemo, useState} from 'react';
import type {SectionListData} from 'react-native';
import {useOnyx} from 'react-native-onyx';
import Badge from '@components/Badge';
+import BlockingView from '@components/BlockingViews/BlockingView';
import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView';
import FormAlertWithSubmitButton from '@components/FormAlertWithSubmitButton';
import HeaderWithBackButton from '@components/HeaderWithBackButton';
import {FallbackAvatar} from '@components/Icon/Expensicons';
+import * as Illustrations from '@components/Icon/Illustrations';
import ScreenWrapper from '@components/ScreenWrapper';
import SelectionList from '@components/SelectionList';
import InviteMemberListItem from '@components/SelectionList/InviteMemberListItem';
@@ -23,6 +25,7 @@ import * as PolicyUtils from '@libs/PolicyUtils';
import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper';
import withPolicyAndFullscreenLoading from '@pages/workspace/withPolicyAndFullscreenLoading';
import type {WithPolicyAndFullscreenLoadingProps} from '@pages/workspace/withPolicyAndFullscreenLoading';
+import variables from '@styles/variables';
import * as Workflow from '@userActions/Workflow';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
@@ -50,14 +53,14 @@ type WorkspaceWorkflowsApprovalsExpensesFromPageProps = WithPolicyAndFullscreenL
function WorkspaceWorkflowsApprovalsExpensesFromPage({policy, isLoadingReportData = true, route}: WorkspaceWorkflowsApprovalsExpensesFromPageProps) {
const styles = useThemeStyles();
const {translate} = useLocalize();
- const [didScreenTransitionEnd, setDidScreenTransitionEnd] = useState(false);
const [searchTerm, debouncedSearchTerm, setSearchTerm] = useDebouncedState('');
- const [approvalWorkflow, approvalWorkflowMetadata] = useOnyx(ONYXKEYS.APPROVAL_WORKFLOW);
+ const [approvalWorkflow] = useOnyx(ONYXKEYS.APPROVAL_WORKFLOW);
const [selectedMembers, setSelectedMembers] = useState([]);
// eslint-disable-next-line rulesdir/no-negated-variables
const shouldShowNotFoundView = (isEmptyObject(policy) && !isLoadingReportData) || !PolicyUtils.isPolicyAdmin(policy) || PolicyUtils.isPendingDeletePolicy(policy);
const isInitialCreationFlow = approvalWorkflow?.action === CONST.APPROVAL_WORKFLOW.ACTION.CREATE && !route.params.backTo;
+ const shouldShowListEmptyContent = approvalWorkflow && approvalWorkflow.availableMembers.length === 0;
useEffect(() => {
if (!approvalWorkflow?.members) {
@@ -150,18 +153,23 @@ function WorkspaceWorkflowsApprovalsExpensesFromPage({policy, isLoadingReportDat
Navigation.goBack();
}, [isInitialCreationFlow]);
- const nextButton = useMemo(
- () => (
+ const button = useMemo(() => {
+ let buttonText = isInitialCreationFlow ? translate('common.next') : translate('common.save');
+
+ if (shouldShowListEmptyContent) {
+ buttonText = translate('common.buttonConfirm');
+ }
+
+ return (
Navigation.goBack() : nextStep}
containerStyles={[styles.flexReset, styles.flexGrow0, styles.flexShrink0, styles.flexBasisAuto]}
enabledWhenOffline
/>
- ),
- [isInitialCreationFlow, nextStep, selectedMembers.length, styles.flexBasisAuto, styles.flexGrow0, styles.flexReset, styles.flexShrink0, translate],
- );
+ );
+ }, [isInitialCreationFlow, nextStep, selectedMembers.length, shouldShowListEmptyContent, styles.flexBasisAuto, styles.flexGrow0, styles.flexReset, styles.flexShrink0, translate]);
const toggleMember = (member: SelectionListMember) => {
const isAlreadySelected = selectedMembers.some((selectedOption) => selectedOption.login === member.login);
@@ -170,6 +178,21 @@ function WorkspaceWorkflowsApprovalsExpensesFromPage({policy, isLoadingReportDat
const headerMessage = useMemo(() => (searchTerm && !sections[0].data.length ? translate('common.noResultsFound') : ''), [searchTerm, sections, translate]);
+ const listEmptyContent = useMemo(
+ () => (
+
+ ),
+ [translate, styles.textSupporting, styles.pb10],
+ );
+
return (
setDidScreenTransitionEnd(true)}
>
- {approvalWorkflow?.action === CONST.APPROVAL_WORKFLOW.ACTION.CREATE && (
+
+ {approvalWorkflow?.action === CONST.APPROVAL_WORKFLOW.ACTION.CREATE && !shouldShowListEmptyContent && (
{translate('workflowsExpensesFromPage.header')}
)}