From 277f2bfa6ee8068d0746485c3bb9aabe116766da Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Tue, 13 Aug 2024 20:54:58 +0300 Subject: [PATCH 01/88] add lang --- src/languages/en.ts | 5 +++++ src/languages/es.ts | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/src/languages/en.ts b/src/languages/en.ts index 41d8ffe6148b..6ac3351e914f 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -4371,5 +4371,10 @@ export default { }, delegate: { switchAccount: 'Switch accounts:', + copilotDelegatedAccess: 'Copilot: Delegated access', + copilotDelegatedAccessDescription: 'Allow other members to access your account.', + addCopilot: 'Add Copilot', + membersCanAccessYourAccount: 'These members can access your account:', + youCanAccessTheseAccounts: 'You can access these accounts via the account switcher:', }, } satisfies TranslationBase; diff --git a/src/languages/es.ts b/src/languages/es.ts index 55a1e2222075..f30f3357e4e9 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -4891,5 +4891,10 @@ export default { }, delegate: { switchAccount: 'Cambiar cuentas:', + copilotDelegatedAccess: 'Copilot: Acceso delegado', + copilotDelegatedAccessDescription: 'Permitir que otros miembros accedan a tu cuenta.', + addCopilot: 'Agregar Copiloto', + membersCanAccessYourAccount: 'Estos miembros pueden acceder a tu cuenta:', + youCanAccessTheseAccounts: 'Puedes acceder a estas cuentas a través del conmutador de cuentas:', }, } satisfies EnglishTranslation; From 4178a212a8832575d5c8aaf05eac32d3edc9db30 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Tue, 13 Aug 2024 20:55:08 +0300 Subject: [PATCH 02/88] add copilot section --- .../settings/Security/SecuritySettingsPage.tsx | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/pages/settings/Security/SecuritySettingsPage.tsx b/src/pages/settings/Security/SecuritySettingsPage.tsx index 3420e352e056..afd7684747be 100644 --- a/src/pages/settings/Security/SecuritySettingsPage.tsx +++ b/src/pages/settings/Security/SecuritySettingsPage.tsx @@ -4,6 +4,7 @@ import HeaderWithBackButton from '@components/HeaderWithBackButton'; import * as Expensicons from '@components/Icon/Expensicons'; import * as Illustrations from '@components/Icon/Illustrations'; import LottieAnimations from '@components/LottieAnimations'; +import MenuItem from '@components/MenuItem'; import MenuItemList from '@components/MenuItemList'; import ScreenWrapper from '@components/ScreenWrapper'; import ScrollView from '@components/ScrollView'; @@ -76,6 +77,23 @@ function SecuritySettingsPage() { shouldUseSingleExecution /> +
+ {/* add copilot menu item with add member icon */} + {}} + shouldShowRightIcon + wrapperStyle={[styles.sectionMenuItemTopDescription]} + /> +
From b4c6799a5b7f94dac6beb054a7057a5c8c7ec8e1 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Tue, 13 Aug 2024 21:08:35 +0300 Subject: [PATCH 03/88] add icon --- assets/images/user-plus.svg | 5 +++++ src/components/Icon/Expensicons.ts | 2 ++ src/pages/settings/Security/SecuritySettingsPage.tsx | 6 +++++- 3 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 assets/images/user-plus.svg diff --git a/assets/images/user-plus.svg b/assets/images/user-plus.svg new file mode 100644 index 000000000000..9ccc1d40cfa5 --- /dev/null +++ b/assets/images/user-plus.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/components/Icon/Expensicons.ts b/src/components/Icon/Expensicons.ts index 728740e8182a..dc88c10f3e63 100644 --- a/src/components/Icon/Expensicons.ts +++ b/src/components/Icon/Expensicons.ts @@ -182,6 +182,7 @@ import Unlock from '@assets/images/unlock.svg'; import UploadAlt from '@assets/images/upload-alt.svg'; import Upload from '@assets/images/upload.svg'; import UserCheck from '@assets/images/user-check.svg'; +import UserPlus from '@assets/images/user-plus.svg'; import User from '@assets/images/user.svg'; import Users from '@assets/images/users.svg'; import VolumeHigh from '@assets/images/volume-high.svg'; @@ -388,4 +389,5 @@ export { CalendarSolid, Filter, CaretUpDown, + UserPlus, }; diff --git a/src/pages/settings/Security/SecuritySettingsPage.tsx b/src/pages/settings/Security/SecuritySettingsPage.tsx index afd7684747be..613f34cbec6d 100644 --- a/src/pages/settings/Security/SecuritySettingsPage.tsx +++ b/src/pages/settings/Security/SecuritySettingsPage.tsx @@ -11,6 +11,7 @@ import ScrollView from '@components/ScrollView'; import Section from '@components/Section'; import useLocalize from '@hooks/useLocalize'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; +import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import useWaitForNavigation from '@hooks/useWaitForNavigation'; import Navigation from '@libs/Navigation/Navigation'; @@ -22,6 +23,7 @@ function SecuritySettingsPage() { const {translate} = useLocalize(); const waitForNavigate = useWaitForNavigation(); const {shouldUseNarrowLayout} = useResponsiveLayout(); + const theme = useTheme(); const menuItems = useMemo(() => { const baseMenuItems = [ @@ -88,7 +90,9 @@ function SecuritySettingsPage() { {/* add copilot menu item with add member icon */} {}} shouldShowRightIcon wrapperStyle={[styles.sectionMenuItemTopDescription]} From b87ac4d4d95ff1e1646519d5ebecdefa505bdc86 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Tue, 13 Aug 2024 21:34:51 +0300 Subject: [PATCH 04/88] display copilots --- .../Security/SecuritySettingsPage.tsx | 36 +++++++++++++++++-- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/src/pages/settings/Security/SecuritySettingsPage.tsx b/src/pages/settings/Security/SecuritySettingsPage.tsx index 613f34cbec6d..cd44a29f2437 100644 --- a/src/pages/settings/Security/SecuritySettingsPage.tsx +++ b/src/pages/settings/Security/SecuritySettingsPage.tsx @@ -1,21 +1,28 @@ +import {Str} from 'expensify-common'; import React, {useMemo} from 'react'; import {View} from 'react-native'; +import {useOnyx} from 'react-native-onyx'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import * as Expensicons from '@components/Icon/Expensicons'; import * as Illustrations from '@components/Icon/Illustrations'; import LottieAnimations from '@components/LottieAnimations'; import MenuItem from '@components/MenuItem'; +import type {MenuItemProps} from '@components/MenuItem'; import MenuItemList from '@components/MenuItemList'; import ScreenWrapper from '@components/ScreenWrapper'; import ScrollView from '@components/ScrollView'; import Section from '@components/Section'; +import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import useWaitForNavigation from '@hooks/useWaitForNavigation'; import Navigation from '@libs/Navigation/Navigation'; +import {getPersonalDetailByEmail} from '@libs/PersonalDetailsUtils'; +import CONST from '@src/CONST'; import type {TranslationPaths} from '@src/languages/types'; +import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; function SecuritySettingsPage() { @@ -25,7 +32,11 @@ function SecuritySettingsPage() { const {shouldUseNarrowLayout} = useResponsiveLayout(); const theme = useTheme(); - const menuItems = useMemo(() => { + const [account] = useOnyx(ONYXKEYS.ACCOUNT); + const delegates = account?.delegatedAccess?.delegates ?? []; + const delegators = account?.delegatedAccess?.delegators ?? []; + + const securityMenuItems = useMemo(() => { const baseMenuItems = [ { translationKey: 'twoFactorAuth.headerTitle', @@ -50,6 +61,24 @@ function SecuritySettingsPage() { })); }, [translate, waitForNavigate, styles]); + const delegateMenuItems: MenuItemProps[] = delegates.map(({email, role}) => { + const personalDetail = getPersonalDetailByEmail(email); + + return { + title: personalDetail?.displayName ?? email, + description: personalDetail?.displayName ? email : '', + // TODO: replace with Full or Limited + badgeText: Str.recapitalize(role), + avatarID: personalDetail?.accountID ?? -1, + icon: personalDetail?.avatar ?? '', + iconType: CONST.ICON_TYPE_AVATAR, + numberOfLinesDescription: 1, + wrapperStyle: [styles.sectionMenuItemTopDescription], + iconRight: Expensicons.ThreeDots, + shouldShowRightIcon: true, + }; + }); + return ( @@ -87,7 +116,8 @@ function SecuritySettingsPage() { titleStyles={styles.accountSettingsSectionTitle} childrenStyles={styles.pt5} > - {/* add copilot menu item with add member icon */} + {translate('delegate.membersCanAccessYourAccount')} + Date: Tue, 13 Aug 2024 21:41:29 +0300 Subject: [PATCH 05/88] display delegators --- .../Security/SecuritySettingsPage.tsx | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/pages/settings/Security/SecuritySettingsPage.tsx b/src/pages/settings/Security/SecuritySettingsPage.tsx index cd44a29f2437..3c7db4692551 100644 --- a/src/pages/settings/Security/SecuritySettingsPage.tsx +++ b/src/pages/settings/Security/SecuritySettingsPage.tsx @@ -79,6 +79,22 @@ function SecuritySettingsPage() { }; }); + const delegatorsMenuItems: MenuItemProps[] = delegators.map(({email, role}) => { + const personalDetail = getPersonalDetailByEmail(email); + + return { + title: personalDetail?.displayName ?? email, + description: personalDetail?.displayName ? email : '', + badgeText: Str.recapitalize(role), + avatarID: personalDetail?.accountID ?? -1, + icon: personalDetail?.avatar ?? '', + iconType: CONST.ICON_TYPE_AVATAR, + numberOfLinesDescription: 1, + wrapperStyle: [styles.sectionMenuItemTopDescription], + interactive: false, + }; + }); + return ( {}} shouldShowRightIcon - wrapperStyle={[styles.sectionMenuItemTopDescription]} + wrapperStyle={[styles.sectionMenuItemTopDescription, styles.mb6]} /> + {translate('delegate.youCanAccessTheseAccounts')} + From 46562f79bfe3f3d88f8eeddae1c3a5125689cb08 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Tue, 13 Aug 2024 21:43:23 +0300 Subject: [PATCH 06/88] hide behind beta --- .../Security/SecuritySettingsPage.tsx | 48 ++++++++++--------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/src/pages/settings/Security/SecuritySettingsPage.tsx b/src/pages/settings/Security/SecuritySettingsPage.tsx index 3c7db4692551..3f674624675d 100644 --- a/src/pages/settings/Security/SecuritySettingsPage.tsx +++ b/src/pages/settings/Security/SecuritySettingsPage.tsx @@ -14,6 +14,7 @@ import ScrollView from '@components/ScrollView'; import Section from '@components/Section'; import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; +import usePermissions from '@hooks/usePermissions'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -31,6 +32,7 @@ function SecuritySettingsPage() { const waitForNavigate = useWaitForNavigation(); const {shouldUseNarrowLayout} = useResponsiveLayout(); const theme = useTheme(); + const {canUseNewDotCopilot} = usePermissions(); const [account] = useOnyx(ONYXKEYS.ACCOUNT); const delegates = account?.delegatedAccess?.delegates ?? []; @@ -124,28 +126,30 @@ function SecuritySettingsPage() { shouldUseSingleExecution /> -
- {translate('delegate.membersCanAccessYourAccount')} - - {}} - shouldShowRightIcon - wrapperStyle={[styles.sectionMenuItemTopDescription, styles.mb6]} - /> - {translate('delegate.youCanAccessTheseAccounts')} - -
+ {canUseNewDotCopilot && ( +
+ {translate('delegate.membersCanAccessYourAccount')} + + {}} + shouldShowRightIcon + wrapperStyle={[styles.sectionMenuItemTopDescription, styles.mb6]} + /> + {translate('delegate.youCanAccessTheseAccounts')} + +
+ )}
From 3d0c4b210d6fa58b1a3dc7bc287b366e1f29a813 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Wed, 14 Aug 2024 11:08:15 +0300 Subject: [PATCH 07/88] add user plus icon --- assets/images/user-plus.svg | 16 +++++++++++----- .../settings/Security/SecuritySettingsPage.tsx | 3 +-- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/assets/images/user-plus.svg b/assets/images/user-plus.svg index 9ccc1d40cfa5..bd49633bf738 100644 --- a/assets/images/user-plus.svg +++ b/assets/images/user-plus.svg @@ -1,5 +1,11 @@ - - - - - + + + + + + + + + + + \ No newline at end of file diff --git a/src/pages/settings/Security/SecuritySettingsPage.tsx b/src/pages/settings/Security/SecuritySettingsPage.tsx index 3f674624675d..56a446ac486f 100644 --- a/src/pages/settings/Security/SecuritySettingsPage.tsx +++ b/src/pages/settings/Security/SecuritySettingsPage.tsx @@ -139,8 +139,7 @@ function SecuritySettingsPage() { {}} shouldShowRightIcon From 7dbcd0e2e22c7d300f95d2fdecf5c3f28d1441da Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Wed, 14 Aug 2024 12:17:37 +0300 Subject: [PATCH 08/88] switch delegates and delegators --- src/pages/settings/Security/SecuritySettingsPage.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pages/settings/Security/SecuritySettingsPage.tsx b/src/pages/settings/Security/SecuritySettingsPage.tsx index 56a446ac486f..f7c6a773cb31 100644 --- a/src/pages/settings/Security/SecuritySettingsPage.tsx +++ b/src/pages/settings/Security/SecuritySettingsPage.tsx @@ -35,8 +35,8 @@ function SecuritySettingsPage() { const {canUseNewDotCopilot} = usePermissions(); const [account] = useOnyx(ONYXKEYS.ACCOUNT); - const delegates = account?.delegatedAccess?.delegates ?? []; const delegators = account?.delegatedAccess?.delegators ?? []; + const delegates = account?.delegatedAccess?.delegates ?? []; const securityMenuItems = useMemo(() => { const baseMenuItems = [ @@ -63,7 +63,7 @@ function SecuritySettingsPage() { })); }, [translate, waitForNavigate, styles]); - const delegateMenuItems: MenuItemProps[] = delegates.map(({email, role}) => { + const delegatorMenuItems: MenuItemProps[] = delegators.map(({email, role}) => { const personalDetail = getPersonalDetailByEmail(email); return { @@ -81,7 +81,7 @@ function SecuritySettingsPage() { }; }); - const delegatorsMenuItems: MenuItemProps[] = delegators.map(({email, role}) => { + const delegateMenuItems: MenuItemProps[] = delegates.map(({email, role}) => { const personalDetail = getPersonalDetailByEmail(email); return { @@ -146,7 +146,7 @@ function SecuritySettingsPage() { wrapperStyle={[styles.sectionMenuItemTopDescription, styles.mb6]} /> {translate('delegate.youCanAccessTheseAccounts')} - + )} From d0f721770c0dae34923630831c693664d003992c Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Wed, 14 Aug 2024 12:42:32 +0300 Subject: [PATCH 09/88] fix interactivity --- src/pages/settings/Security/SecuritySettingsPage.tsx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/pages/settings/Security/SecuritySettingsPage.tsx b/src/pages/settings/Security/SecuritySettingsPage.tsx index 44dc2974a90f..e597e38bc360 100644 --- a/src/pages/settings/Security/SecuritySettingsPage.tsx +++ b/src/pages/settings/Security/SecuritySettingsPage.tsx @@ -34,8 +34,8 @@ function SecuritySettingsPage() { const {canUseNewDotCopilot} = usePermissions(); const [account] = useOnyx(ONYXKEYS.ACCOUNT); - const delegators = account?.delegatedAccess?.delegators ?? []; const delegates = account?.delegatedAccess?.delegates ?? []; + const delegators = account?.delegatedAccess?.delegators ?? []; const securityMenuItems = useMemo(() => { const baseMenuItems = [ @@ -62,13 +62,12 @@ function SecuritySettingsPage() { })); }, [translate, waitForNavigate, styles]); - const delegatorMenuItems: MenuItemProps[] = delegators.map(({email, role}) => { + const delegateMenuItems: MenuItemProps[] = delegates.map(({email, role}) => { const personalDetail = getPersonalDetailByEmail(email); return { title: personalDetail?.displayName ?? email, description: personalDetail?.displayName ? email : '', - // TODO: replace with Full or Limited badgeText: translate('delegate.role', role), avatarID: personalDetail?.accountID ?? -1, icon: personalDetail?.avatar ?? '', @@ -80,7 +79,7 @@ function SecuritySettingsPage() { }; }); - const delegateMenuItems: MenuItemProps[] = delegates.map(({email, role}) => { + const delegatorMenuItems: MenuItemProps[] = delegators.map(({email, role}) => { const personalDetail = getPersonalDetailByEmail(email); return { From 9921cc6c97ac9b671b3bc5a8747b64c410231ee0 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Wed, 14 Aug 2024 13:53:14 +0300 Subject: [PATCH 10/88] hide delegates if they dont exist --- .../Security/SecuritySettingsPage.tsx | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/pages/settings/Security/SecuritySettingsPage.tsx b/src/pages/settings/Security/SecuritySettingsPage.tsx index e597e38bc360..d08f84cca859 100644 --- a/src/pages/settings/Security/SecuritySettingsPage.tsx +++ b/src/pages/settings/Security/SecuritySettingsPage.tsx @@ -32,11 +32,14 @@ function SecuritySettingsPage() { const {shouldUseNarrowLayout} = useResponsiveLayout(); const theme = useTheme(); const {canUseNewDotCopilot} = usePermissions(); - const [account] = useOnyx(ONYXKEYS.ACCOUNT); + const delegates = account?.delegatedAccess?.delegates ?? []; const delegators = account?.delegatedAccess?.delegators ?? []; + const hasDelegates = delegates.length > 0; + const hasDelegators = delegators.length > 0; + const securityMenuItems = useMemo(() => { const baseMenuItems = [ { @@ -133,8 +136,12 @@ function SecuritySettingsPage() { titleStyles={styles.accountSettingsSectionTitle} childrenStyles={styles.pt5} > - {translate('delegate.membersCanAccessYourAccount')} - + {hasDelegates && ( + <> + {translate('delegate.membersCanAccessYourAccount')} + + + )} - {translate('delegate.youCanAccessTheseAccounts')} - + {hasDelegators && ( + <> + {translate('delegate.youCanAccessTheseAccounts')} + + + )} )} From 0b07897b6f5fbeeb319a194c78ed8e855fd1b75f Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Thu, 15 Aug 2024 03:15:50 +0300 Subject: [PATCH 11/88] create add copilot page --- src/languages/en.ts | 2 +- src/languages/es.ts | 2 +- src/libs/Permissions.ts | 1 + .../Security/AddDelegate/AddDelegatePage.tsx | 80 +++++++++++++++++++ .../AddDelegate/ConfirmDelegatePage.tsx | 0 .../AddDelegate/SelectDelegateRolePage.tsx | 0 6 files changed, 83 insertions(+), 2 deletions(-) create mode 100644 src/pages/settings/Security/AddDelegate/AddDelegatePage.tsx create mode 100644 src/pages/settings/Security/AddDelegate/ConfirmDelegatePage.tsx create mode 100644 src/pages/settings/Security/AddDelegate/SelectDelegateRolePage.tsx diff --git a/src/languages/en.ts b/src/languages/en.ts index 5e926c1e1f02..665c6ee4c164 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -4374,7 +4374,7 @@ export default { switchAccount: 'Switch accounts:', copilotDelegatedAccess: 'Copilot: Delegated access', copilotDelegatedAccessDescription: 'Allow other members to access your account.', - addCopilot: 'Add Copilot', + addCopilot: 'Add copilot', membersCanAccessYourAccount: 'These members can access your account:', youCanAccessTheseAccounts: 'You can access these accounts via the account switcher:', role: (role: DelegateRole): string => { diff --git a/src/languages/es.ts b/src/languages/es.ts index 118d9fadfb91..6c4f1bdf56a5 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -4894,7 +4894,7 @@ export default { switchAccount: 'Cambiar cuentas:', copilotDelegatedAccess: 'Copilot: Acceso delegado', copilotDelegatedAccessDescription: 'Permitir que otros miembros accedan a tu cuenta.', - addCopilot: 'Agregar Copiloto', + addCopilot: 'Agregar copiloto', membersCanAccessYourAccount: 'Estos miembros pueden acceder a tu cuenta:', youCanAccessTheseAccounts: 'Puedes acceder a estas cuentas a través del conmutador de cuentas:', role: (role: DelegateRole): string => { diff --git a/src/libs/Permissions.ts b/src/libs/Permissions.ts index 0581fd41853e..ebee5d3ab45f 100644 --- a/src/libs/Permissions.ts +++ b/src/libs/Permissions.ts @@ -41,6 +41,7 @@ function canUseNetSuiteUSATax(betas: OnyxEntry): boolean { } function canUseNewDotCopilot(betas: OnyxEntry): boolean { + return true; return !!betas?.includes(CONST.BETAS.NEW_DOT_COPILOT) || canUseAllBetas(betas); } diff --git a/src/pages/settings/Security/AddDelegate/AddDelegatePage.tsx b/src/pages/settings/Security/AddDelegate/AddDelegatePage.tsx new file mode 100644 index 000000000000..474eb5b54bbf --- /dev/null +++ b/src/pages/settings/Security/AddDelegate/AddDelegatePage.tsx @@ -0,0 +1,80 @@ +import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import ScreenWrapper from '@components/ScreenWrapper'; +import SelectionList from '@components/SelectionList'; +import useLocalize from '@hooks/useLocalize'; +import Navigation from '@libs/Navigation/Navigation'; + +function AddDelegatePage() { + const {translate} = useLocalize(); + + + const sections = useMemo(() => { + const sectionsList = []; + + sectionsList.push({ + title: translate('common.recents'), + data: recentReports, + shouldShow: recentReports?.length > 0, + }); + + sectionsList.push({ + title: translate('common.contacts'), + data: personalDetails, + shouldShow: personalDetails?.length > 0, + }); + + + return sectionsList.map((section) => ({ + ...section, + data: section.data.map((option) => ({ + ...option, + text: option.text ?? '', + alternateText: option.alternateText ?? undefined, + keyForList: option.keyForList ?? '', + isDisabled: option.isDisabled ?? undefined, + login: option.login ?? undefined, + shouldShowSubscript: option.shouldShowSubscript ?? undefined, + })), + })); + }, [currentUserOption, personalDetails, recentReports, translate]); + + return ( + + { + Navigation.goBack(); + }} + /> + { + SearchInputManager.searchInput = value; + setSearchTerm(value); + }} + headerMessage={headerMessage} + onSelectRow={toggleOption} + onConfirm={inviteUser} + showScrollIndicator + showLoadingPlaceholder={!areOptionsInitialized || !didScreenTransitionEnd} + shouldPreventDefaultFocusOnSelectRow={!DeviceCapabilities.canUseTouchScreen()} + footerContent={footerContent} + isLoadingNewOptions={!!isSearchingForReports} + /> + + ); +} + +AddDelegatePage.displayName = 'AddDelegatePage'; + +export default AddDelegatePage; diff --git a/src/pages/settings/Security/AddDelegate/ConfirmDelegatePage.tsx b/src/pages/settings/Security/AddDelegate/ConfirmDelegatePage.tsx new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/src/pages/settings/Security/AddDelegate/SelectDelegateRolePage.tsx b/src/pages/settings/Security/AddDelegate/SelectDelegateRolePage.tsx new file mode 100644 index 000000000000..e69de29bb2d1 From 79b90ff034b500312633f839027aba7229591767 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Thu, 15 Aug 2024 14:39:37 +0300 Subject: [PATCH 12/88] create add delegate command --- src/libs/API/parameters/AddDelegateParams.ts | 8 +++ src/libs/API/parameters/index.ts | 1 + src/libs/API/types.ts | 2 + src/libs/actions/Delegate.ts | 57 ++++++++++++++++++-- src/types/onyx/Account.ts | 4 +- 5 files changed, 67 insertions(+), 5 deletions(-) create mode 100644 src/libs/API/parameters/AddDelegateParams.ts diff --git a/src/libs/API/parameters/AddDelegateParams.ts b/src/libs/API/parameters/AddDelegateParams.ts new file mode 100644 index 000000000000..f97af795c56d --- /dev/null +++ b/src/libs/API/parameters/AddDelegateParams.ts @@ -0,0 +1,8 @@ +import type {DelegateRole} from '@src/types/onyx/Account'; + +type AddDelegateParams = { + email: string; + role: DelegateRole; +}; + +export default AddDelegateParams; diff --git a/src/libs/API/parameters/index.ts b/src/libs/API/parameters/index.ts index 2de6a5b2d6a5..561fd698d0c4 100644 --- a/src/libs/API/parameters/index.ts +++ b/src/libs/API/parameters/index.ts @@ -276,3 +276,4 @@ export type {default as ConnectAsDelegateParams} from './ConnectAsDelegateParams export type {default as ConfigureExpensifyCardsForPolicyParams} from './ConfigureExpensifyCardsForPolicyParams'; export type {default as CreateExpensifyCardParams} from './CreateExpensifyCardParams'; export type {default as UpdateExpensifyCardTitleParams} from './UpdateExpensifyCardTitleParams'; +export type {default as AddDelegateParams} from './AddDelegateParams'; diff --git a/src/libs/API/types.ts b/src/libs/API/types.ts index 26393aed8f40..453cdbaf7a08 100644 --- a/src/libs/API/types.ts +++ b/src/libs/API/types.ts @@ -332,6 +332,7 @@ const WRITE_COMMANDS = { CONFIGURE_EXPENSIFY_CARDS_FOR_POLICY: 'ConfigureExpensifyCardsForPolicy', CREATE_EXPENSIFY_CARD: 'CreateExpensifyCard', CREATE_ADMIN_ISSUED_VIRTUAL_CARD: 'CreateAdminIssuedVirtualCard', + ADD_DELEGATE: 'AddDelegate', } as const; type WriteCommand = ValueOf; @@ -669,6 +670,7 @@ type WriteCommandParameters = { [WRITE_COMMANDS.CONFIGURE_EXPENSIFY_CARDS_FOR_POLICY]: Parameters.ConfigureExpensifyCardsForPolicyParams; [WRITE_COMMANDS.CREATE_EXPENSIFY_CARD]: Parameters.CreateExpensifyCardParams; [WRITE_COMMANDS.CREATE_ADMIN_ISSUED_VIRTUAL_CARD]: Omit; + [WRITE_COMMANDS.ADD_DELEGATE]: Parameters.AddDelegateParams; }; const READ_COMMANDS = { diff --git a/src/libs/actions/Delegate.ts b/src/libs/actions/Delegate.ts index 7eaaee798be5..e5dde9984e8e 100644 --- a/src/libs/actions/Delegate.ts +++ b/src/libs/actions/Delegate.ts @@ -1,12 +1,14 @@ import Onyx from 'react-native-onyx'; import type {OnyxUpdate} from 'react-native-onyx'; import * as API from '@libs/API'; -import {SIDE_EFFECT_REQUEST_COMMANDS} from '@libs/API/types'; +import {AddDelegateParams} from '@libs/API/parameters'; +import {SIDE_EFFECT_REQUEST_COMMANDS, WRITE_COMMANDS} from '@libs/API/types'; import Log from '@libs/Log'; import * as NetworkStore from '@libs/Network/NetworkStore'; import * as SequentialQueue from '@libs/Network/SequentialQueue'; +import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import type {DelegatedAccess} from '@src/types/onyx/Account'; +import type {DelegatedAccess, DelegateRole} from '@src/types/onyx/Account'; import {openApp} from './App'; import updateSessionAuthTokens from './Session/updateSessionAuthTokens'; @@ -92,5 +94,54 @@ function clearDelegatorErrors() { Onyx.merge(ONYXKEYS.ACCOUNT, {delegatedAccess: {delegators: delegatedAccess.delegators.map((delegator) => ({...delegator, error: undefined}))}}); } +function addDelegate(email: string, role: DelegateRole) { + if (!delegatedAccess?.delegates) { + return; + } + + const optimisticData: OnyxUpdate[] = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.ACCOUNT, + value: { + delegatedAccess: { + delegates: [ + ...delegatedAccess.delegates, + {email, role, pendingAction: 'add', pendingFields: {email: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, role: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD}}, + ], + }, + }, + }, + ]; + + const successData: OnyxUpdate[] = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.ACCOUNT, + value: { + delegatedAccess: { + delegates: [...delegatedAccess.delegates, {email, role, error: undefined, pendingAction: null, pendingFields: {email: null, role: null}}], + }, + }, + }, + ]; + + const failureData: OnyxUpdate[] = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.ACCOUNT, + value: { + delegatedAccess: { + delegates: delegatedAccess.delegates.map((delegate) => (delegate.email !== email ? delegate : {...delegate, error: 'delegate.genericError'})), + }, + }, + }, + ]; + + const parameters: AddDelegateParams = {email, role}; + + API.write(WRITE_COMMANDS.ADD_DELEGATE, parameters, {optimisticData, successData, failureData}); +} + // eslint-disable-next-line import/prefer-default-export -export {connect, clearDelegatorErrors}; +export {connect, clearDelegatorErrors, addDelegate}; diff --git a/src/types/onyx/Account.ts b/src/types/onyx/Account.ts index e1356e7e6135..00d1f70b227c 100644 --- a/src/types/onyx/Account.ts +++ b/src/types/onyx/Account.ts @@ -11,7 +11,7 @@ type TwoFactorAuthStep = ValueOf | ''; type DelegateRole = ValueOf; /** Model of delegate */ -type Delegate = { +type Delegate = OnyxCommon.OnyxValueWithOfflineFeedback<{ /** The email of the delegate */ email: string; @@ -20,7 +20,7 @@ type Delegate = { /** Authentication failure errors */ error?: TranslationPaths; -}; +}>; /** Model of delegated access data */ type DelegatedAccess = { From 234f6ac749be976934f4fa1b7a67d22936856c54 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Thu, 15 Aug 2024 14:40:27 +0300 Subject: [PATCH 13/88] cleanup --- src/libs/actions/Delegate.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/Delegate.ts b/src/libs/actions/Delegate.ts index e5dde9984e8e..d94b286f3b81 100644 --- a/src/libs/actions/Delegate.ts +++ b/src/libs/actions/Delegate.ts @@ -1,7 +1,7 @@ import Onyx from 'react-native-onyx'; import type {OnyxUpdate} from 'react-native-onyx'; import * as API from '@libs/API'; -import {AddDelegateParams} from '@libs/API/parameters'; +import type {AddDelegateParams} from '@libs/API/parameters'; import {SIDE_EFFECT_REQUEST_COMMANDS, WRITE_COMMANDS} from '@libs/API/types'; import Log from '@libs/Log'; import * as NetworkStore from '@libs/Network/NetworkStore'; From b05c19eee8be46972f562194b882f8191c923a44 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Thu, 15 Aug 2024 14:52:48 +0300 Subject: [PATCH 14/88] handle undefined --- src/libs/actions/Delegate.ts | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/libs/actions/Delegate.ts b/src/libs/actions/Delegate.ts index f2317eb35380..2c05dd01a066 100644 --- a/src/libs/actions/Delegate.ts +++ b/src/libs/actions/Delegate.ts @@ -95,10 +95,6 @@ function clearDelegatorErrors() { } function addDelegate(email: string, role: DelegateRole) { - if (!delegatedAccess?.delegates) { - return; - } - const optimisticData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, @@ -106,7 +102,7 @@ function addDelegate(email: string, role: DelegateRole) { value: { delegatedAccess: { delegates: [ - ...delegatedAccess.delegates, + ...(delegatedAccess.delegates ?? []), {email, role, pendingAction: 'add', pendingFields: {email: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, role: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD}}, ], }, @@ -120,7 +116,7 @@ function addDelegate(email: string, role: DelegateRole) { key: ONYXKEYS.ACCOUNT, value: { delegatedAccess: { - delegates: [...delegatedAccess.delegates, {email, role, error: undefined, pendingAction: null, pendingFields: {email: null, role: null}}], + delegates: [...(delegatedAccess.delegates ?? []), {email, role, error: undefined, pendingAction: null, pendingFields: {email: null, role: null}}], }, }, }, @@ -132,7 +128,7 @@ function addDelegate(email: string, role: DelegateRole) { key: ONYXKEYS.ACCOUNT, value: { delegatedAccess: { - delegates: delegatedAccess.delegates.map((delegate) => (delegate.email !== email ? delegate : {...delegate, error: 'delegate.genericError'})), + delegates: delegatedAccess.delegates?.map((delegate) => (delegate.email !== email ? delegate : {...delegate, error: 'delegate.genericError'})), }, }, }, From d3315a69f7ac2a123dc59f11dd1435c09c44d6b2 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Thu, 15 Aug 2024 16:32:51 +0300 Subject: [PATCH 15/88] add navigation for add delegate page --- src/ROUTES.ts | 3 + src/SCREENS.ts | 5 + .../ModalStackNavigators/index.tsx | 1 + src/libs/Navigation/linkingConfig/config.ts | 4 + src/libs/Navigation/types.ts | 3 + .../Security/AddDelegate/AddDelegatePage.tsx | 129 ++++++++++++++---- .../Security/SecuritySettingsPage.tsx | 2 +- 7 files changed, 116 insertions(+), 31 deletions(-) diff --git a/src/ROUTES.ts b/src/ROUTES.ts index de495568daa3..6a0fb9dce03b 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -126,6 +126,9 @@ const ROUTES = { SETTINGS_WORKSPACES: 'settings/workspaces', SETTINGS_SECURITY: 'settings/security', SETTINGS_CLOSE: 'settings/security/closeAccount', + SETTINGS_ADD_DELEGATE: 'settings/security/delegate/add', + SETTINGS_DELEGATE_ROLE: 'settings/security/delegate/role', + SETTINGS_DELEGATE_CONFIRM: 'settings/security/delegate/confirm', SETTINGS_ABOUT: 'settings/about', SETTINGS_APP_DOWNLOAD_LINKS: 'settings/about/app-download-links', SETTINGS_WALLET: 'settings/wallet', diff --git a/src/SCREENS.ts b/src/SCREENS.ts index 30adc5f89d08..1a95c983749b 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -125,6 +125,11 @@ const SCREENS = { CHANGE_PAYMENT_CURRENCY: 'Settings_Subscription_Change_Payment_Currency', REQUEST_EARLY_CANCELLATION: 'Settings_Subscription_RequestEarlyCancellation', }, + DELEGATE: { + ADD_DELEGATE: 'Settings_Delegate_Add', + DELEGATE_ROLE: 'Settings_Delegate_Role', + DELEGATE_CONFIRM: 'Settings_Delegate_Confirm', + }, }, SAVE_THE_WORLD: { ROOT: 'SaveTheWorld_Root', diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx index f105de52a5ac..b2237fc84373 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx @@ -453,6 +453,7 @@ const SettingsModalStackNavigator = createModalStackNavigator('../../../../pages/workspace/accounting/intacct/import/SageIntacctAddUserDimensionPage').default, [SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_EDIT_USER_DIMENSION]: () => require('../../../../pages/workspace/accounting/intacct/import/SageIntacctEditUserDimensionsPage').default, + [SCREENS.SETTINGS.DELEGATE.ADD_DELEGATE]: () => require('../../../../pages/settings/Security/AddDelegate/AddDelegatePage').default, }); const EnablePaymentsStackNavigator = createModalStackNavigator({ diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index 236b56882dde..5e9f6556dfc8 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -279,6 +279,10 @@ const config: LinkingOptions['config'] = { path: ROUTES.SETTINGS_2FA.route, exact: true, }, + [SCREENS.SETTINGS.DELEGATE.ADD_DELEGATE]: { + path: ROUTES.SETTINGS_ADD_DELEGATE, + exact: true, + }, [SCREENS.SETTINGS.PROFILE.STATUS]: { path: ROUTES.SETTINGS_STATUS, exact: true, diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index 8bd1c44568c4..d4feba9113a4 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -633,6 +633,9 @@ type SettingsNavigatorParamList = { backTo?: Routes; forwardTo?: string; }; + [SCREENS.SETTINGS.DELEGATE.ADD_DELEGATE]: { + backTo?: Routes; + }; [SCREENS.SETTINGS.REPORT_CARD_LOST_OR_DAMAGED]: { /** cardID of selected card */ cardID: string; diff --git a/src/pages/settings/Security/AddDelegate/AddDelegatePage.tsx b/src/pages/settings/Security/AddDelegate/AddDelegatePage.tsx index 474eb5b54bbf..6ccb151f2a4d 100644 --- a/src/pages/settings/Security/AddDelegate/AddDelegatePage.tsx +++ b/src/pages/settings/Security/AddDelegate/AddDelegatePage.tsx @@ -1,13 +1,89 @@ +import React, {useEffect, useMemo, useState} from 'react'; +import {View} from 'react-native'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import {useBetas} from '@components/OnyxProvider'; +import {useOptionsList} from '@components/OptionListContextProvider'; import ScreenWrapper from '@components/ScreenWrapper'; import SelectionList from '@components/SelectionList'; +import UserListItem from '@components/SelectionList/UserListItem'; +import useDebouncedState from '@hooks/useDebouncedState'; import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; +import * as ReportActions from '@libs/actions/Report'; import Navigation from '@libs/Navigation/Navigation'; +import * as OptionsListUtils from '@libs/OptionsListUtils'; +import CONST from '@src/CONST'; +function useOptions() { + const betas = useBetas(); + const [isLoading, setIsLoading] = useState(true); + const [searchValue, debouncedSearchValue, setSearchValue] = useDebouncedState(''); + const {options: optionsList, areOptionsInitialized} = useOptionsList(); + + const defaultOptions = useMemo(() => { + const {recentReports, personalDetails, userToInvite, currentUserOption} = OptionsListUtils.getFilteredOptions( + optionsList.reports, + optionsList.personalDetails, + betas, + '', + [], + CONST.EXPENSIFY_EMAILS, + false, + true, + false, + {}, + [], + false, + {}, + [], + true, + false, + false, + 0, + ); + + const headerMessage = OptionsListUtils.getHeaderMessage((recentReports?.length || 0) + (personalDetails?.length || 0) !== 0 || !!currentUserOption, !!userToInvite, ''); + + if (isLoading) { + setIsLoading(false); + } + + return { + userToInvite, + recentReports, + personalDetails, + currentUserOption, + headerMessage, + categoryOptions: [], + tagOptions: [], + taxRatesOptions: [], + }; + }, [optionsList.reports, optionsList.personalDetails, betas, isLoading]); + + const options = useMemo(() => { + const filteredOptions = OptionsListUtils.filterOptions(defaultOptions, debouncedSearchValue.trim(), { + excludeLogins: CONST.EXPENSIFY_EMAILS, + maxRecentReportsToShow: CONST.IOU.MAX_RECENT_REPORTS_TO_SHOW, + }); + const headerMessage = OptionsListUtils.getHeaderMessage( + (filteredOptions.recentReports?.length || 0) + (filteredOptions.personalDetails?.length || 0) !== 0 || !!filteredOptions.currentUserOption, + !!filteredOptions.userToInvite, + debouncedSearchValue, + ); + + return { + ...filteredOptions, + headerMessage, + }; + }, [debouncedSearchValue, defaultOptions]); + + return {...options, searchValue, debouncedSearchValue, setSearchValue, areOptionsInitialized}; +} function AddDelegatePage() { const {translate} = useLocalize(); + const styles = useThemeStyles(); + const {userToInvite, recentReports, personalDetails, searchValue, debouncedSearchValue, setSearchValue, headerMessage, areOptionsInitialized} = useOptions(); - const sections = useMemo(() => { const sectionsList = []; @@ -23,7 +99,6 @@ function AddDelegatePage() { shouldShow: personalDetails?.length > 0, }); - return sectionsList.map((section) => ({ ...section, data: section.data.map((option) => ({ @@ -36,41 +111,35 @@ function AddDelegatePage() { shouldShowSubscript: option.shouldShowSubscript ?? undefined, })), })); - }, [currentUserOption, personalDetails, recentReports, translate]); + }, [personalDetails, recentReports, translate]); + + useEffect(() => { + ReportActions.searchInServer(debouncedSearchValue); + }, [debouncedSearchValue]); return ( { - Navigation.goBack(); - }} - /> - { - SearchInputManager.searchInput = value; - setSearchTerm(value); - }} - headerMessage={headerMessage} - onSelectRow={toggleOption} - onConfirm={inviteUser} - showScrollIndicator - showLoadingPlaceholder={!areOptionsInitialized || !didScreenTransitionEnd} - shouldPreventDefaultFocusOnSelectRow={!DeviceCapabilities.canUseTouchScreen()} - footerContent={footerContent} - isLoadingNewOptions={!!isSearchingForReports} + title={translate('delegate.addCopilot')} + onBackButtonPress={() => Navigation.goBack()} /> + + {}} + shouldSingleExecuteRowSelect + onChangeText={setSearchValue} + textInputValue={searchValue} + headerMessage={headerMessage} + textInputLabel={translate('selectionList.nameEmailOrPhoneNumber')} + showLoadingPlaceholder={!areOptionsInitialized} + // isLoadingNewOptions={!!isSearchingForReports} + /> + ); } diff --git a/src/pages/settings/Security/SecuritySettingsPage.tsx b/src/pages/settings/Security/SecuritySettingsPage.tsx index d08f84cca859..b91af4f29c80 100644 --- a/src/pages/settings/Security/SecuritySettingsPage.tsx +++ b/src/pages/settings/Security/SecuritySettingsPage.tsx @@ -146,7 +146,7 @@ function SecuritySettingsPage() { title={translate('delegate.addCopilot')} icon={Expensicons.UserPlus} iconFill={theme.iconSuccessFill} - onPress={() => {}} + onPress={() => Navigation.navigate(ROUTES.SETTINGS_ADD_DELEGATE)} shouldShowRightIcon wrapperStyle={[styles.sectionMenuItemTopDescription, styles.mb6]} /> From 7cc14d5586da6aa42d118cf679ad4d2e078f5bdd Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Mon, 26 Aug 2024 02:47:11 +0300 Subject: [PATCH 16/88] update routes for role select page --- src/ROUTES.ts | 12 ++++++--- src/languages/en.ts | 6 ++++- src/languages/es.ts | 4 +++ .../ModalStackNavigators/index.tsx | 2 ++ src/libs/Navigation/linkingConfig/config.ts | 8 ++++++ src/libs/Navigation/types.ts | 10 +++++-- src/libs/actions/Delegate.ts | 22 +++++++++++++++- .../Security/AddDelegate/AddDelegatePage.tsx | 19 +++++++++++--- .../AddDelegate/SelectDelegateRolePage.tsx | 26 +++++++++++++++++++ src/types/onyx/Account.ts | 4 +-- 10 files changed, 100 insertions(+), 13 deletions(-) diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 9aaff262f46b..50afaddd3596 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -127,9 +127,15 @@ const ROUTES = { SETTINGS_WORKSPACES: 'settings/workspaces', SETTINGS_SECURITY: 'settings/security', SETTINGS_CLOSE: 'settings/security/closeAccount', - SETTINGS_ADD_DELEGATE: 'settings/security/delegate/add', - SETTINGS_DELEGATE_ROLE: 'settings/security/delegate/role', - SETTINGS_DELEGATE_CONFIRM: 'settings/security/delegate/confirm', + SETTINGS_ADD_DELEGATE: 'settings/security/delegate', + SETTINGS_DELEGATE_ROLE: { + route: 'settings/security/delegate/:accountID/role/:role', + getRoute: (accountID: string, role?: ValueOf) => `settings/security/delegate/${accountID}/role/${role}` as const, + }, + SETTINGS_DELEGATE_CONFIRM: { + route: 'settings/security/delegate/:accountID/role/:role/confirm', + getRoute: (accountID: string, role: ValueOf) => `settings/security/delegate/${accountID}/role/${role}/confirm` as const, + }, SETTINGS_ABOUT: 'settings/about', SETTINGS_APP_DOWNLOAD_LINKS: 'settings/about/app-download-links', SETTINGS_WALLET: 'settings/wallet', diff --git a/src/languages/en.ts b/src/languages/en.ts index 715b39edec58..1d2c5c37480d 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -4473,7 +4473,7 @@ export default { addCopilot: 'Add copilot', membersCanAccessYourAccount: 'These members can access your account:', youCanAccessTheseAccounts: 'You can access these accounts via the account switcher:', - role: (role: DelegateRole): string => { + role: (role?: DelegateRole): string => { switch (role) { case CONST.DELEGATE_ROLE.ALL: return 'Full'; @@ -4484,5 +4484,9 @@ export default { } }, genericError: 'Oops, something went wrong. Please try again.', + accessLevel: 'Access level', + accessLevelDescription: 'Choose an access level below. Both Full and Limited access allow copilots to view all conversations and expenses.', + fullAccessDescription: 'Allow another member to take all actions in your account, on your behalf. Includes chat, submissions, approvals, payments, settings updates, and more.', + limitedAccessDescription: 'Allow another member to take most actions in your account, on your behalf. Excludes approvals, payments, rejections, and holds.', }, } satisfies TranslationBase; diff --git a/src/languages/es.ts b/src/languages/es.ts index 1a2ce22eb55b..5947585f7923 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -5000,5 +5000,9 @@ export default { } }, genericError: '¡Ups! Ha ocurrido un error. Por favor, inténtalo de nuevo.', + accessLevel: 'Access level', + accessLevelDescription: 'Choose an access level below. Both Full and Limited access allow copilots to view all conversations and expenses.', + fullAccessDescription: 'Allow another member to take all actions in your account, on your behalf. Includes chat, submissions, approvals, payments, settings updates, and more.', + limitedAccessDescription: 'Allow another member to take most actions in your account, on your behalf. Excludes approvals, payments, rejections, and holds.', }, } satisfies EnglishTranslation; diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx index 0d9deea845cd..9ef4b3898511 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx @@ -454,6 +454,8 @@ const SettingsModalStackNavigator = createModalStackNavigator require('../../../../pages/workspace/accounting/intacct/import/SageIntacctEditUserDimensionsPage').default, [SCREENS.SETTINGS.DELEGATE.ADD_DELEGATE]: () => require('../../../../pages/settings/Security/AddDelegate/AddDelegatePage').default, + [SCREENS.SETTINGS.DELEGATE.DELEGATE_ROLE]: () => require('../../../../pages/settings/Security/AddDelegate/SelectDelegateRolePage').default, + [SCREENS.SETTINGS.DELEGATE.DELEGATE_CONFIRM]: () => require('../../../../pages/settings/Security/AddDelegate/ConfirmDelegatePage').default, }); const EnablePaymentsStackNavigator = createModalStackNavigator({ diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index a49e1ca2aa5e..84cfb8505f8f 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -283,6 +283,14 @@ const config: LinkingOptions['config'] = { path: ROUTES.SETTINGS_ADD_DELEGATE, exact: true, }, + [SCREENS.SETTINGS.DELEGATE.DELEGATE_ROLE]: { + path: ROUTES.SETTINGS_DELEGATE_ROLE, + exact: true, + }, + [SCREENS.SETTINGS.DELEGATE.DELEGATE_CONFIRM]: { + path: ROUTES.SETTINGS_DELEGATE_CONFIRM, + exact: true, + }, [SCREENS.SETTINGS.PROFILE.STATUS]: { path: ROUTES.SETTINGS_STATUS, exact: true, diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index c47b3f1d7818..12bdab5cdaf1 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -633,8 +633,14 @@ type SettingsNavigatorParamList = { backTo?: Routes; forwardTo?: string; }; - [SCREENS.SETTINGS.DELEGATE.ADD_DELEGATE]: { - backTo?: Routes; + [SCREENS.SETTINGS.DELEGATE.ADD_DELEGATE]: undefined; + [SCREENS.SETTINGS.DELEGATE.DELEGATE_ROLE]: { + accountID: string; + role?: string; + }; + [SCREENS.SETTINGS.DELEGATE.DELEGATE_CONFIRM]: { + accountID: string; + role: string; }; [SCREENS.SETTINGS.REPORT_CARD_LOST_OR_DAMAGED]: { /** cardID of selected card */ diff --git a/src/libs/actions/Delegate.ts b/src/libs/actions/Delegate.ts index 8187b99675ea..88725b659ba5 100644 --- a/src/libs/actions/Delegate.ts +++ b/src/libs/actions/Delegate.ts @@ -156,6 +156,26 @@ function clearDelegatorErrors() { Onyx.merge(ONYXKEYS.ACCOUNT, {delegatedAccess: {delegators: delegatedAccess.delegators.map((delegator) => ({...delegator, error: undefined}))}}); } +function setDelegateEmail(email: string) { + if (!email) { + return; + } + + Onyx.merge(ONYXKEYS.ACCOUNT, { + delegatedAccess: { + delegates: [...(delegatedAccess.delegates ?? []), {email}], + }, + }); +} + +function setDelegateRole(email: string, role: DelegateRole) { + Onyx.merge(ONYXKEYS.ACCOUNT, { + delegatedAccess: { + delegates: [...(delegatedAccess.delegates ?? []), {email, role}], + }, + }); +} + function addDelegate(email: string, role: DelegateRole) { const optimisticData: OnyxUpdate[] = [ { @@ -201,4 +221,4 @@ function addDelegate(email: string, role: DelegateRole) { API.write(WRITE_COMMANDS.ADD_DELEGATE, parameters, {optimisticData, successData, failureData}); } -export {connect, disconnect, clearDelegatorErrors, addDelegate}; +export {connect, disconnect, clearDelegatorErrors, addDelegate, setDelegateEmail, setDelegateRole}; diff --git a/src/pages/settings/Security/AddDelegate/AddDelegatePage.tsx b/src/pages/settings/Security/AddDelegate/AddDelegatePage.tsx index 6ccb151f2a4d..9f7465d5d96a 100644 --- a/src/pages/settings/Security/AddDelegate/AddDelegatePage.tsx +++ b/src/pages/settings/Security/AddDelegate/AddDelegatePage.tsx @@ -1,5 +1,6 @@ -import React, {useEffect, useMemo, useState} from 'react'; +import React, {useCallback, useEffect, useMemo, useState} from 'react'; import {View} from 'react-native'; +import {useOnyx} from 'react-native-onyx'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import {useBetas} from '@components/OnyxProvider'; import {useOptionsList} from '@components/OptionListContextProvider'; @@ -9,10 +10,14 @@ import UserListItem from '@components/SelectionList/UserListItem'; import useDebouncedState from '@hooks/useDebouncedState'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; +import {setDelegateEmail} from '@libs/actions/Delegate'; import * as ReportActions from '@libs/actions/Report'; import Navigation from '@libs/Navigation/Navigation'; import * as OptionsListUtils from '@libs/OptionsListUtils'; import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; +import ROUTES from '@src/ROUTES'; +import type {Participant} from '@src/types/onyx/IOU'; function useOptions() { const betas = useBetas(); @@ -82,7 +87,8 @@ function useOptions() { function AddDelegatePage() { const {translate} = useLocalize(); const styles = useThemeStyles(); - const {userToInvite, recentReports, personalDetails, searchValue, debouncedSearchValue, setSearchValue, headerMessage, areOptionsInitialized} = useOptions(); + const [isSearchingForReports] = useOnyx(ONYXKEYS.IS_SEARCHING_FOR_REPORTS, {initWithStoredValues: false}); + const {recentReports, personalDetails, searchValue, debouncedSearchValue, setSearchValue, headerMessage, areOptionsInitialized} = useOptions(); const sections = useMemo(() => { const sectionsList = []; @@ -113,6 +119,11 @@ function AddDelegatePage() { })); }, [personalDetails, recentReports, translate]); + const onSelectRow = useCallback((option: Participant) => { + // setDelegateEmail(option.login ?? ''); + Navigation.navigate(ROUTES.SETTINGS_DELEGATE_ROLE); + }, []); + useEffect(() => { ReportActions.searchInServer(debouncedSearchValue); }, [debouncedSearchValue]); @@ -130,14 +141,14 @@ function AddDelegatePage() { {}} + onSelectRow={onSelectRow} shouldSingleExecuteRowSelect onChangeText={setSearchValue} textInputValue={searchValue} headerMessage={headerMessage} textInputLabel={translate('selectionList.nameEmailOrPhoneNumber')} showLoadingPlaceholder={!areOptionsInitialized} - // isLoadingNewOptions={!!isSearchingForReports} + isLoadingNewOptions={!!isSearchingForReports} />
diff --git a/src/pages/settings/Security/AddDelegate/SelectDelegateRolePage.tsx b/src/pages/settings/Security/AddDelegate/SelectDelegateRolePage.tsx index e69de29bb2d1..6c0601d0a476 100644 --- a/src/pages/settings/Security/AddDelegate/SelectDelegateRolePage.tsx +++ b/src/pages/settings/Security/AddDelegate/SelectDelegateRolePage.tsx @@ -0,0 +1,26 @@ +import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import ScreenWrapper from '@components/ScreenWrapper'; +import SelectionList from '@components/SelectionList'; +import useLocalize from '@hooks/useLocalize'; +import Navigation from '@libs/Navigation/Navigation'; + +function SelectDelegateRolePage() { + const {translate} = useLocalize(); + + return ( + + Navigation.goBack()} + /> + + ); +} + +SelectDelegateRolePage.displayName = 'SelectDelegateRolePage'; + +export default SelectDelegateRolePage; diff --git a/src/types/onyx/Account.ts b/src/types/onyx/Account.ts index 80c77ec0b3a9..e9dae72e68bc 100644 --- a/src/types/onyx/Account.ts +++ b/src/types/onyx/Account.ts @@ -16,7 +16,7 @@ type Delegate = OnyxCommon.OnyxValueWithOfflineFeedback<{ email: string; /** The role of the delegate */ - role: DelegateRole; + role?: DelegateRole; /** Authentication failure errors */ error?: TranslationPaths; @@ -125,4 +125,4 @@ type Account = { }; export default Account; -export type {TwoFactorAuthStep, DelegateRole, DelegatedAccess}; +export type {TwoFactorAuthStep, DelegateRole, DelegatedAccess, Delegate}; From 71a3533fd0f3cd58fb0b12defad8d8d9a8982bc9 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Mon, 26 Aug 2024 03:37:47 +0300 Subject: [PATCH 17/88] add role select page options --- src/CONST.ts | 2 +- src/ROUTES.ts | 4 +-- src/libs/Navigation/linkingConfig/config.ts | 4 +-- .../Security/AddDelegate/AddDelegatePage.tsx | 2 +- .../AddDelegate/SelectDelegateRolePage.tsx | 28 +++++++++++++++++-- 5 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index 3baa2075f67c..3e21c75b7e90 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -3926,8 +3926,8 @@ const CONST = { DISABLED: 'DISABLED', }, DELEGATE_ROLE: { - SUBMITTER: 'submitter', ALL: 'all', + SUBMITTER: 'submitter', }, STRIPE_GBP_AUTH_STATUSES: { SUCCEEDED: 'succeeded', diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 50afaddd3596..bf47a32956b6 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -130,11 +130,11 @@ const ROUTES = { SETTINGS_ADD_DELEGATE: 'settings/security/delegate', SETTINGS_DELEGATE_ROLE: { route: 'settings/security/delegate/:accountID/role/:role', - getRoute: (accountID: string, role?: ValueOf) => `settings/security/delegate/${accountID}/role/${role}` as const, + getRoute: (accountID: number, role?: ValueOf) => `settings/security/delegate/${accountID}/role/${role}` as const, }, SETTINGS_DELEGATE_CONFIRM: { route: 'settings/security/delegate/:accountID/role/:role/confirm', - getRoute: (accountID: string, role: ValueOf) => `settings/security/delegate/${accountID}/role/${role}/confirm` as const, + getRoute: (accountID: number, role: ValueOf) => `settings/security/delegate/${accountID}/role/${role}/confirm` as const, }, SETTINGS_ABOUT: 'settings/about', SETTINGS_APP_DOWNLOAD_LINKS: 'settings/about/app-download-links', diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index 84cfb8505f8f..c91aa45ad543 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -284,11 +284,11 @@ const config: LinkingOptions['config'] = { exact: true, }, [SCREENS.SETTINGS.DELEGATE.DELEGATE_ROLE]: { - path: ROUTES.SETTINGS_DELEGATE_ROLE, + path: ROUTES.SETTINGS_DELEGATE_ROLE.route, exact: true, }, [SCREENS.SETTINGS.DELEGATE.DELEGATE_CONFIRM]: { - path: ROUTES.SETTINGS_DELEGATE_CONFIRM, + path: ROUTES.SETTINGS_DELEGATE_CONFIRM.route, exact: true, }, [SCREENS.SETTINGS.PROFILE.STATUS]: { diff --git a/src/pages/settings/Security/AddDelegate/AddDelegatePage.tsx b/src/pages/settings/Security/AddDelegate/AddDelegatePage.tsx index 9f7465d5d96a..b6fa3b8a688c 100644 --- a/src/pages/settings/Security/AddDelegate/AddDelegatePage.tsx +++ b/src/pages/settings/Security/AddDelegate/AddDelegatePage.tsx @@ -121,7 +121,7 @@ function AddDelegatePage() { const onSelectRow = useCallback((option: Participant) => { // setDelegateEmail(option.login ?? ''); - Navigation.navigate(ROUTES.SETTINGS_DELEGATE_ROLE); + Navigation.navigate(ROUTES.SETTINGS_DELEGATE_ROLE.getRoute(option.accountID ?? -1)); }, []); useEffect(() => { diff --git a/src/pages/settings/Security/AddDelegate/SelectDelegateRolePage.tsx b/src/pages/settings/Security/AddDelegate/SelectDelegateRolePage.tsx index 6c0601d0a476..a5f30ed8a474 100644 --- a/src/pages/settings/Security/AddDelegate/SelectDelegateRolePage.tsx +++ b/src/pages/settings/Security/AddDelegate/SelectDelegateRolePage.tsx @@ -1,11 +1,30 @@ +import type {StackScreenProps} from '@react-navigation/stack'; +import React, {useState} from 'react'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import ScreenWrapper from '@components/ScreenWrapper'; import SelectionList from '@components/SelectionList'; +import RadioListItem from '@components/SelectionList/RadioListItem'; +import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; import Navigation from '@libs/Navigation/Navigation'; +import type {SettingsNavigatorParamList} from '@libs/Navigation/types'; +import CONST from '@src/CONST'; +import type SCREENS from '@src/SCREENS'; -function SelectDelegateRolePage() { +type SelectDelegateRolePageProps = StackScreenProps; + +function SelectDelegateRolePage({route}: SelectDelegateRolePageProps) { const {translate} = useLocalize(); + const [selectedRole, setSelectedRole] = useState(route.params.role); + + const styles = useThemeStyles(); + const roleOptions = Object.values(CONST.DELEGATE_ROLE).map((role) => ({ + value: role, + text: translate('delegate.role', role), + keyForList: role, + isSelected: role === selectedRole, + })); return ( Navigation.goBack()} /> + {translate('delegate.accessLevelDescription')}} + onSelectRow={() => {}} + sections={[{data: roleOptions}]} + ListItem={RadioListItem} + /> ); } From 62cbae8ae77763c91178308fcba7a4d9e938747e Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Mon, 26 Aug 2024 04:46:52 +0300 Subject: [PATCH 18/88] fix route types --- src/ROUTES.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ROUTES.ts b/src/ROUTES.ts index bf47a32956b6..cf6d94044431 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -5,6 +5,7 @@ import type {IOUAction, IOUType} from './CONST'; import type {IOURequestType} from './libs/actions/IOU'; import type {ConnectionName, SageIntacctMappingName} from './types/onyx/Policy'; import type AssertTypesNotEqual from './types/utils/AssertTypesNotEqual'; +import { DelegateRole } from './types/onyx/Account'; // This is a file containing constants for all the routes we want to be able to go to @@ -130,11 +131,11 @@ const ROUTES = { SETTINGS_ADD_DELEGATE: 'settings/security/delegate', SETTINGS_DELEGATE_ROLE: { route: 'settings/security/delegate/:accountID/role/:role', - getRoute: (accountID: number, role?: ValueOf) => `settings/security/delegate/${accountID}/role/${role}` as const, + getRoute: (accountID: number, role?: string) => `settings/security/delegate/${accountID}/role/${role}` as const, }, SETTINGS_DELEGATE_CONFIRM: { route: 'settings/security/delegate/:accountID/role/:role/confirm', - getRoute: (accountID: number, role: ValueOf) => `settings/security/delegate/${accountID}/role/${role}/confirm` as const, + getRoute: (accountID: number, role: string) => `settings/security/delegate/${accountID}/role/${role}/confirm` as const, }, SETTINGS_ABOUT: 'settings/about', SETTINGS_APP_DOWNLOAD_LINKS: 'settings/about/app-download-links', From f5fe9881d12f6024388221c987383e7e29ffa05e Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Mon, 26 Aug 2024 04:47:02 +0300 Subject: [PATCH 19/88] add lang --- src/languages/en.ts | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/languages/en.ts b/src/languages/en.ts index 1d2c5c37480d..b63518d6e0a7 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -4473,7 +4473,7 @@ export default { addCopilot: 'Add copilot', membersCanAccessYourAccount: 'These members can access your account:', youCanAccessTheseAccounts: 'You can access these accounts via the account switcher:', - role: (role?: DelegateRole): string => { + role: (role?: string): string => { switch (role) { case CONST.DELEGATE_ROLE.ALL: return 'Full'; @@ -4485,8 +4485,17 @@ export default { }, genericError: 'Oops, something went wrong. Please try again.', accessLevel: 'Access level', + confirmCopilot: 'Confirm your copilot below.', accessLevelDescription: 'Choose an access level below. Both Full and Limited access allow copilots to view all conversations and expenses.', - fullAccessDescription: 'Allow another member to take all actions in your account, on your behalf. Includes chat, submissions, approvals, payments, settings updates, and more.', - limitedAccessDescription: 'Allow another member to take most actions in your account, on your behalf. Excludes approvals, payments, rejections, and holds.', + roleDescription: (role?: string): string => { + switch (role) { + case CONST.DELEGATE_ROLE.ALL: + return 'Allow another member to take all actions in your account, on your behalf. Includes chat, submissions, approvals, payments, settings updates, and more.'; + case CONST.DELEGATE_ROLE.SUBMITTER: + return 'Allow another member to take most actions in your account, on your behalf. Excludes approvals, payments, rejections, and holds.'; + default: + return ''; + } + }, }, } satisfies TranslationBase; From c6e42421820ea9d2d0bbfd8d4b2a431c46e8210a Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Mon, 26 Aug 2024 04:47:07 +0300 Subject: [PATCH 20/88] add lang --- src/languages/es.ts | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/languages/es.ts b/src/languages/es.ts index 5947585f7923..6813c2e720b4 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -5001,8 +5001,17 @@ export default { }, genericError: '¡Ups! Ha ocurrido un error. Por favor, inténtalo de nuevo.', accessLevel: 'Access level', + confirmCopilot: 'Confirm your copilot below.', accessLevelDescription: 'Choose an access level below. Both Full and Limited access allow copilots to view all conversations and expenses.', - fullAccessDescription: 'Allow another member to take all actions in your account, on your behalf. Includes chat, submissions, approvals, payments, settings updates, and more.', - limitedAccessDescription: 'Allow another member to take most actions in your account, on your behalf. Excludes approvals, payments, rejections, and holds.', + roleDescription: (role?: DelegateRole): string => { + switch (role) { + case CONST.DELEGATE_ROLE.ALL: + return 'Allow another member to take all actions in your account, on your behalf. Includes chat, submissions, approvals, payments, settings updates, and more.'; + case CONST.DELEGATE_ROLE.SUBMITTER: + return 'Allow another member to take most actions in your account, on your behalf. Excludes approvals, payments, rejections, and holds.'; + default: + return ''; + } + }, }, } satisfies EnglishTranslation; From db4d5be98e8f43f088b8a91ca7ca9b309d950c8f Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Mon, 26 Aug 2024 04:47:18 +0300 Subject: [PATCH 21/88] add confirm delegate page --- .../AddDelegate/ConfirmDelegatePage.tsx | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/src/pages/settings/Security/AddDelegate/ConfirmDelegatePage.tsx b/src/pages/settings/Security/AddDelegate/ConfirmDelegatePage.tsx index e69de29bb2d1..fb1bdd309328 100644 --- a/src/pages/settings/Security/AddDelegate/ConfirmDelegatePage.tsx +++ b/src/pages/settings/Security/AddDelegate/ConfirmDelegatePage.tsx @@ -0,0 +1,61 @@ +import type {StackScreenProps} from '@react-navigation/stack'; +import React from 'react'; +import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import MenuItem from '@components/MenuItem'; +import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; +import ScreenWrapper from '@components/ScreenWrapper'; +import SelectionList from '@components/SelectionList'; +import RadioListItem from '@components/SelectionList/RadioListItem'; +import Text from '@components/Text'; +import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; +import Navigation from '@libs/Navigation/Navigation'; +import type {SettingsNavigatorParamList} from '@libs/Navigation/types'; +import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; +import CONST from '@src/CONST'; +import ROUTES from '@src/ROUTES'; +import type SCREENS from '@src/SCREENS'; + +type ConfirmDelegatePageProps = StackScreenProps; + +function ConfirmDelegatePage({route}: ConfirmDelegatePageProps) { + const {translate} = useLocalize(); + + const styles = useThemeStyles(); + const accountID = Number(route.params.accountID); + + const personalDetails = PersonalDetailsUtils.getPersonalDetailsByIDs([accountID], -1)[0]; + + return ( + + Navigation.goBack()} + /> + {translate('delegate.confirmCopilot')} + + Navigation.navigate(ROUTES.SETTINGS_DELEGATE_ROLE.getRoute(accountID, route.params.role))} + shouldShowRightIcon + /> + + ); +} + +ConfirmDelegatePage.displayName = 'ConfirmDelegatePage'; + +export default ConfirmDelegatePage; From 0d4af2519e99e519ce87eb51b9e8482bda5293a3 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Mon, 26 Aug 2024 04:47:27 +0300 Subject: [PATCH 22/88] navigate to confirm delegate page --- .../Security/AddDelegate/SelectDelegateRolePage.tsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/pages/settings/Security/AddDelegate/SelectDelegateRolePage.tsx b/src/pages/settings/Security/AddDelegate/SelectDelegateRolePage.tsx index a5f30ed8a474..19ac9a5f3a61 100644 --- a/src/pages/settings/Security/AddDelegate/SelectDelegateRolePage.tsx +++ b/src/pages/settings/Security/AddDelegate/SelectDelegateRolePage.tsx @@ -10,20 +10,20 @@ import useThemeStyles from '@hooks/useThemeStyles'; import Navigation from '@libs/Navigation/Navigation'; import type {SettingsNavigatorParamList} from '@libs/Navigation/types'; import CONST from '@src/CONST'; +import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; type SelectDelegateRolePageProps = StackScreenProps; function SelectDelegateRolePage({route}: SelectDelegateRolePageProps) { const {translate} = useLocalize(); - const [selectedRole, setSelectedRole] = useState(route.params.role); const styles = useThemeStyles(); const roleOptions = Object.values(CONST.DELEGATE_ROLE).map((role) => ({ value: role, text: translate('delegate.role', role), keyForList: role, - isSelected: role === selectedRole, + isSelected: role === route.params.role, })); return ( @@ -37,7 +37,9 @@ function SelectDelegateRolePage({route}: SelectDelegateRolePageProps) { /> {translate('delegate.accessLevelDescription')}} - onSelectRow={() => {}} + onSelectRow={(option) => { + Navigation.navigate(ROUTES.SETTINGS_DELEGATE_CONFIRM.getRoute(Number(route.params.accountID), option.value)); + }} sections={[{data: roleOptions}]} ListItem={RadioListItem} /> From 6cb8bf62e552001db2669fe0ee1e9f3266fac612 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Mon, 26 Aug 2024 04:47:35 +0300 Subject: [PATCH 23/88] add mv6 --- src/styles/utils/spacing.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/styles/utils/spacing.ts b/src/styles/utils/spacing.ts index 92edd6e7fa18..bb0beab695bf 100644 --- a/src/styles/utils/spacing.ts +++ b/src/styles/utils/spacing.ts @@ -83,6 +83,10 @@ export default { marginVertical: 20, }, + mv6: { + marginVertical: 24, + }, + mhv5: { marginVertical: -20, }, From 6cd3d8c7e51037d5059fd7a184d90978ff364af3 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Mon, 26 Aug 2024 04:59:51 +0300 Subject: [PATCH 24/88] add submit button --- .../AddDelegate/ConfirmDelegatePage.tsx | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/pages/settings/Security/AddDelegate/ConfirmDelegatePage.tsx b/src/pages/settings/Security/AddDelegate/ConfirmDelegatePage.tsx index fb1bdd309328..fb570066f5c9 100644 --- a/src/pages/settings/Security/AddDelegate/ConfirmDelegatePage.tsx +++ b/src/pages/settings/Security/AddDelegate/ConfirmDelegatePage.tsx @@ -1,14 +1,15 @@ import type {StackScreenProps} from '@react-navigation/stack'; import React from 'react'; +import Button from '@components/Button'; +import FixedFooter from '@components/FixedFooter'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import MenuItem from '@components/MenuItem'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; import ScreenWrapper from '@components/ScreenWrapper'; -import SelectionList from '@components/SelectionList'; -import RadioListItem from '@components/SelectionList/RadioListItem'; import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; +import {addDelegate} from '@libs/actions/Delegate'; import Navigation from '@libs/Navigation/Navigation'; import type {SettingsNavigatorParamList} from '@libs/Navigation/types'; import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; @@ -52,6 +53,19 @@ function ConfirmDelegatePage({route}: ConfirmDelegatePageProps) { onPress={() => Navigation.navigate(ROUTES.SETTINGS_DELEGATE_ROLE.getRoute(accountID, route.params.role))} shouldShowRightIcon /> + +