From aed6ba5a688b88a13c2bba1e7cde746be3e8525e Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Wed, 7 Aug 2024 10:12:50 +0700 Subject: [PATCH 001/361] =?UTF-8?q?fix:=20button=20doesn=E2=80=99t=20work?= =?UTF-8?q?=20after=20using=203DS=20flow=20to=20add=20GBP=20payment=20card?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Subscription/CardAuthenticationModal/index.tsx | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/pages/settings/Subscription/CardAuthenticationModal/index.tsx b/src/pages/settings/Subscription/CardAuthenticationModal/index.tsx index 80cde4cb862c..c0bde6d9857f 100644 --- a/src/pages/settings/Subscription/CardAuthenticationModal/index.tsx +++ b/src/pages/settings/Subscription/CardAuthenticationModal/index.tsx @@ -6,11 +6,9 @@ import HeaderWithBackButton from '@components/HeaderWithBackButton'; import Modal from '@components/Modal'; import ScreenWrapper from '@components/ScreenWrapper'; import useThemeStyles from '@hooks/useThemeStyles'; -import Navigation from '@libs/Navigation/Navigation'; import * as PaymentMethods from '@userActions/PaymentMethods'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import ROUTES from '@src/ROUTES'; type CardAuthenticationModalProps = { /** Title shown in the header of the modal */ @@ -20,21 +18,12 @@ function CardAuthenticationModal({headerTitle}: CardAuthenticationModalProps) { const styles = useThemeStyles(); const [authenticationLink] = useOnyx(ONYXKEYS.VERIFY_3DS_SUBSCRIPTION); const [session] = useOnyx(ONYXKEYS.SESSION); - const [privateStripeCustomerID] = useOnyx(ONYXKEYS.NVP_PRIVATE_STRIPE_CUSTOMER_ID); const [isLoading, setIsLoading] = useState(true); const onModalClose = () => { PaymentMethods.clearPaymentCard3dsVerification(); }; - useEffect(() => { - if (privateStripeCustomerID?.status !== CONST.STRIPE_GBP_AUTH_STATUSES.SUCCEEDED) { - return; - } - PaymentMethods.clearPaymentCard3dsVerification(); - Navigation.navigate(ROUTES.SETTINGS_SUBSCRIPTION); - }, [privateStripeCustomerID]); - const handleGBPAuthentication = useCallback( (event: MessageEvent) => { const message = event.data; From a23976a681df6e600287bb73bb9bacf058a29eb2 Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Sat, 10 Aug 2024 14:42:18 +0800 Subject: [PATCH 002/361] optimistically remove hold when paying --- src/libs/actions/IOU.ts | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index ef5f6d6d61c0..c1d55a6afd1a 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -6705,6 +6705,29 @@ function getPayMoneyRequestParams( }); } + if (full) { + for (const transaction of TransactionUtils.getAllReportTransactions(iouReport.reportID)) { + optimisticData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transaction.transactionID}`, + value: { + comment: { + hold: null, + }, + }, + }); + failureData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transaction.transactionID}`, + value: { + comment: { + hold: transaction.comment?.hold, + }, + }, + }); + } + } + let optimisticHoldReportID; let optimisticHoldActionID; let optimisticHoldReportExpenseActionIDs; From a06431bdeb621625be28b74166b0d452caa0ff1b Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Mon, 12 Aug 2024 17:01:43 +0300 Subject: [PATCH 003/361] add delegate access type --- src/types/onyx/Account.ts | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/types/onyx/Account.ts b/src/types/onyx/Account.ts index e0f6fb79331f..d968204ca786 100644 --- a/src/types/onyx/Account.ts +++ b/src/types/onyx/Account.ts @@ -6,6 +6,24 @@ import type * as OnyxCommon from './OnyxCommon'; /** Two factor authentication steps */ type TwoFactorAuthStep = ValueOf | ''; +/** Model of delegate */ +type Delegate = { + /** The email of the delegate */ + email: string; + + /** The role of the delegate */ + role: 'submitter' | 'all'; +}; + +/** Model of delegated access data */ +type DelegatedAccess = { + /** The the users you can access as a delegate */ + delegates: Delegate[]; + + /** The users that can access your account as a delegate */ + delegators: Delegate[]; +}; + /** Model of user account */ type Account = { /** Whether SAML is enabled for the current account */ @@ -88,6 +106,9 @@ type Account = { /** Indicates whether the user has at least one previous purchase */ hasPurchases?: boolean; + + /** The users you can access as delegate and the users who can access your account as a delegate */ + delegatedAccess: DelegatedAccess; }; export default Account; From 567058b3036f29d9b0b09b39a76f2340357eae31 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Mon, 12 Aug 2024 17:02:03 +0300 Subject: [PATCH 004/361] add auth token for delegate access --- src/types/onyx/Response.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/types/onyx/Response.ts b/src/types/onyx/Response.ts index c26280652254..ef558896c55e 100644 --- a/src/types/onyx/Response.ts +++ b/src/types/onyx/Response.ts @@ -41,6 +41,9 @@ type Response = { /** Used to load resources like attachment videos and images */ encryptedAuthToken?: string; + /** User session auth token when connecting as a delegate */ + restrictedToken?: string; + /** Used to pass error messages for error handling purposes */ message?: string; From 40c55fb85ae212b921b9b962238f09e557c18cfa Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Mon, 12 Aug 2024 17:02:20 +0300 Subject: [PATCH 005/361] add connect as delegate action --- .../API/parameters/ConnectAsDelegateParams.ts | 5 ++++ src/libs/API/parameters/index.ts | 1 + src/libs/API/types.ts | 2 ++ src/libs/actions/Delegate.ts | 30 +++++++++++++++++++ 4 files changed, 38 insertions(+) create mode 100644 src/libs/API/parameters/ConnectAsDelegateParams.ts create mode 100644 src/libs/actions/Delegate.ts diff --git a/src/libs/API/parameters/ConnectAsDelegateParams.ts b/src/libs/API/parameters/ConnectAsDelegateParams.ts new file mode 100644 index 000000000000..6bd2c666e1b0 --- /dev/null +++ b/src/libs/API/parameters/ConnectAsDelegateParams.ts @@ -0,0 +1,5 @@ +type ConnectAsDelegateParams = { + to: string; +}; + +export default ConnectAsDelegateParams; diff --git a/src/libs/API/parameters/index.ts b/src/libs/API/parameters/index.ts index c89bf660fcd4..d979332ac80f 100644 --- a/src/libs/API/parameters/index.ts +++ b/src/libs/API/parameters/index.ts @@ -270,3 +270,4 @@ export type {default as ExportSearchItemsToCSVParams} from './ExportSearchItemsT export type {default as UpdateExpensifyCardLimitParams} from './UpdateExpensifyCardLimitParams'; export type {CreateWorkspaceApprovalParams, UpdateWorkspaceApprovalParams, RemoveWorkspaceApprovalParams} from './WorkspaceApprovalParams'; export type {default as StartIssueNewCardFlowParams} from './StartIssueNewCardFlowParams'; +export type {default as ConnectAsDelegateParams} from './ConnectAsDelegateParams'; diff --git a/src/libs/API/types.ts b/src/libs/API/types.ts index 57350bf6de13..dc05a9b2b51c 100644 --- a/src/libs/API/types.ts +++ b/src/libs/API/types.ts @@ -781,6 +781,7 @@ const SIDE_EFFECT_REQUEST_COMMANDS = { REVEAL_EXPENSIFY_CARD_DETAILS: 'RevealExpensifyCardDetails', SWITCH_TO_OLD_DOT: 'SwitchToOldDot', TWO_FACTOR_AUTH_VALIDATE: 'TwoFactorAuth_Validate', + CONNECT_AS_DELEGATE: 'ConnectAsDelegate', } as const; type SideEffectRequestCommand = ValueOf; @@ -797,6 +798,7 @@ type SideEffectRequestCommandParameters = { [SIDE_EFFECT_REQUEST_COMMANDS.ADD_PAYMENT_CARD_GBP]: Parameters.AddPaymentCardParams; [SIDE_EFFECT_REQUEST_COMMANDS.ACCEPT_SPOTNANA_TERMS]: null; [SIDE_EFFECT_REQUEST_COMMANDS.TWO_FACTOR_AUTH_VALIDATE]: Parameters.ValidateTwoFactorAuthParams; + [SIDE_EFFECT_REQUEST_COMMANDS.CONNECT_AS_DELEGATE]: Parameters.ConnectAsDelegateParams; }; type ApiRequestCommandParameters = WriteCommandParameters & ReadCommandParameters & SideEffectRequestCommandParameters; diff --git a/src/libs/actions/Delegate.ts b/src/libs/actions/Delegate.ts new file mode 100644 index 000000000000..3ed22552bec8 --- /dev/null +++ b/src/libs/actions/Delegate.ts @@ -0,0 +1,30 @@ +import Onyx from 'react-native-onyx'; +import * as API from '@libs/API'; +import {SIDE_EFFECT_REQUEST_COMMANDS} from '@libs/API/types'; +import * as NetworkStore from '@libs/Network/NetworkStore'; +import * as SequentialQueue from '@libs/Network/SequentialQueue'; +import {KEYS_TO_PRESERVE, openApp} from './App'; +import updateSessionAuthTokens from './Session/updateSessionAuthTokens'; + +function connect(email: string) { + // eslint-disable-next-line rulesdir/no-api-side-effects-method + API.makeRequestWithSideEffects(SIDE_EFFECT_REQUEST_COMMANDS.CONNECT_AS_DELEGATE, {to: email}, {}) + .then((response) => { + return SequentialQueue.waitForIdle() + .then(() => Onyx.clear(KEYS_TO_PRESERVE)) + .then(() => { + // Update authToken in Onyx and in our local variables so that API requests will use the new authToken + updateSessionAuthTokens(response?.restrictedToken, response?.encryptedAuthToken); + + NetworkStore.setAuthToken(response?.restrictedToken ?? null); + openApp(); + }); + }) + .catch((error) => { + // Handle any errors that occur during the process + console.error('Error during connect:', error); + }); +} + +// eslint-disable-next-line import/prefer-default-export +export {connect}; From 62ee90577fbabdd222b3274bc72bce30811e4c8f Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Mon, 12 Aug 2024 17:07:47 +0300 Subject: [PATCH 006/361] make delegated access optional --- src/types/onyx/Account.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/types/onyx/Account.ts b/src/types/onyx/Account.ts index d968204ca786..3f726f9884d9 100644 --- a/src/types/onyx/Account.ts +++ b/src/types/onyx/Account.ts @@ -108,7 +108,7 @@ type Account = { hasPurchases?: boolean; /** The users you can access as delegate and the users who can access your account as a delegate */ - delegatedAccess: DelegatedAccess; + delegatedAccess?: DelegatedAccess; }; export default Account; From 3d31f79d9b36057c8e6ea23cec3d5999a77af0f1 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Mon, 12 Aug 2024 17:55:53 +0300 Subject: [PATCH 007/361] rm display name and email --- src/libs/actions/Delegate.ts | 5 ++--- src/pages/settings/InitialSettingsPage.tsx | 14 -------------- 2 files changed, 2 insertions(+), 17 deletions(-) diff --git a/src/libs/actions/Delegate.ts b/src/libs/actions/Delegate.ts index 3ed22552bec8..b743b5c77e76 100644 --- a/src/libs/actions/Delegate.ts +++ b/src/libs/actions/Delegate.ts @@ -3,7 +3,7 @@ import * as API from '@libs/API'; import {SIDE_EFFECT_REQUEST_COMMANDS} from '@libs/API/types'; import * as NetworkStore from '@libs/Network/NetworkStore'; import * as SequentialQueue from '@libs/Network/SequentialQueue'; -import {KEYS_TO_PRESERVE, openApp} from './App'; +import {openApp} from './App'; import updateSessionAuthTokens from './Session/updateSessionAuthTokens'; function connect(email: string) { @@ -11,7 +11,7 @@ function connect(email: string) { API.makeRequestWithSideEffects(SIDE_EFFECT_REQUEST_COMMANDS.CONNECT_AS_DELEGATE, {to: email}, {}) .then((response) => { return SequentialQueue.waitForIdle() - .then(() => Onyx.clear(KEYS_TO_PRESERVE)) + .then(() => Onyx.clear()) .then(() => { // Update authToken in Onyx and in our local variables so that API requests will use the new authToken updateSessionAuthTokens(response?.restrictedToken, response?.encryptedAuthToken); @@ -21,7 +21,6 @@ function connect(email: string) { }); }) .catch((error) => { - // Handle any errors that occur during the process console.error('Error during connect:', error); }); } diff --git a/src/pages/settings/InitialSettingsPage.tsx b/src/pages/settings/InitialSettingsPage.tsx index bc98a9432630..ecd0b31cf881 100755 --- a/src/pages/settings/InitialSettingsPage.tsx +++ b/src/pages/settings/InitialSettingsPage.tsx @@ -435,20 +435,6 @@ function InitialSettingsPage({session, userWallet, bankAccountList, fundList, wa editIconStyle={styles.smallEditIconAccount} /> - - {currentUserPersonalDetails.displayName ? currentUserPersonalDetails.displayName : formatPhoneNumber(session?.email ?? '')} - - {!!currentUserPersonalDetails.displayName && ( - - {formatPhoneNumber(session?.email ?? '')} - - )} )} From 90a0bc996e6673312afed0c8c6044f71d4f9a290 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Mon, 12 Aug 2024 18:32:35 +0300 Subject: [PATCH 008/361] fix padding bottom style --- src/styles/utils/spacing.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/styles/utils/spacing.ts b/src/styles/utils/spacing.ts index 5b416f5a120e..f2f989efc6a7 100644 --- a/src/styles/utils/spacing.ts +++ b/src/styles/utils/spacing.ts @@ -377,7 +377,7 @@ export default { padding: 20, }, - pb6: { + p6: { padding: 24, }, @@ -613,6 +613,10 @@ export default { paddingBottom: 20, }, + pb6: { + paddingBottom: 24, + }, + pb8: { paddingBottom: 32, }, From 0a2b2f743cb4abafde736db2ce042d356910c989 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Mon, 12 Aug 2024 18:32:44 +0300 Subject: [PATCH 009/361] fix padding bottom style --- .../accounting/intacct/SageIntacctPrerequisitesPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/workspace/accounting/intacct/SageIntacctPrerequisitesPage.tsx b/src/pages/workspace/accounting/intacct/SageIntacctPrerequisitesPage.tsx index de0e0c6b3c90..4e5863d48317 100644 --- a/src/pages/workspace/accounting/intacct/SageIntacctPrerequisitesPage.tsx +++ b/src/pages/workspace/accounting/intacct/SageIntacctPrerequisitesPage.tsx @@ -79,7 +79,7 @@ function SageIntacctPrerequisitesPage({route}: SageIntacctPrerequisitesPageProps - {translate('workspace.intacct.prerequisitesTitle')} + {translate('workspace.intacct.prerequisitesTitle')} Date: Mon, 12 Aug 2024 18:33:00 +0300 Subject: [PATCH 010/361] move profile photo to profile page --- src/pages/settings/InitialSettingsPage.tsx | 21 ----------------- src/pages/settings/Profile/ProfilePage.tsx | 26 ++++++++++++++++++++++ 2 files changed, 26 insertions(+), 21 deletions(-) diff --git a/src/pages/settings/InitialSettingsPage.tsx b/src/pages/settings/InitialSettingsPage.tsx index ecd0b31cf881..2b2219fa9fb4 100755 --- a/src/pages/settings/InitialSettingsPage.tsx +++ b/src/pages/settings/InitialSettingsPage.tsx @@ -414,27 +414,6 @@ function InitialSettingsPage({session, userWallet, bankAccountList, fundList, wa - - Navigation.navigate(ROUTES.PROFILE_AVATAR.getRoute(String(accountID)))} - previewSource={UserUtils.getFullSizeAvatar(avatarURL, accountID)} - originalFileName={currentUserDetails.originalFileName} - headerTitle={translate('profilePage.profileAvatar')} - fallbackIcon={currentUserDetails?.fallbackIcon} - editIconStyle={styles.smallEditIconAccount} - /> - )} diff --git a/src/pages/settings/Profile/ProfilePage.tsx b/src/pages/settings/Profile/ProfilePage.tsx index 988b68ca5bfe..72944f36ce8b 100755 --- a/src/pages/settings/Profile/ProfilePage.tsx +++ b/src/pages/settings/Profile/ProfilePage.tsx @@ -2,6 +2,7 @@ import React from 'react'; import {View} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; import {withOnyx} from 'react-native-onyx'; +import AvatarWithImagePicker from '@components/AvatarWithImagePicker'; import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import * as Illustrations from '@components/Icon/Illustrations'; @@ -21,6 +22,7 @@ import * as LocalePhoneNumber from '@libs/LocalePhoneNumber'; import Navigation from '@libs/Navigation/Navigation'; import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; import * as UserUtils from '@libs/UserUtils'; +import * as PersonalDetails from '@userActions/PersonalDetails'; import CONST from '@src/CONST'; import type {TranslationPaths} from '@src/languages/types'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -68,6 +70,9 @@ function ProfilePage({ return pronounsKey ? translate(`pronouns.${pronounsKey}` as TranslationPaths) : translate('profilePage.selectYourPronouns'); }; + const avatarURL = currentUserPersonalDetails?.avatar ?? ''; + const accountID = currentUserPersonalDetails?.accountID ?? '-1'; + const contactMethodBrickRoadIndicator = UserUtils.getLoginListBrickRoadIndicator(loginList); const emojiCode = currentUserPersonalDetails?.status?.emojiCode ?? ''; const privateDetails = privatePersonalDetails ?? {}; @@ -143,6 +148,27 @@ function ProfilePage({ childrenStyles={styles.pt5} titleStyles={styles.accountSettingsSectionTitle} > + + Navigation.navigate(ROUTES.PROFILE_AVATAR.getRoute(String(accountID)))} + previewSource={UserUtils.getFullSizeAvatar(avatarURL, accountID)} + originalFileName={currentUserPersonalDetails.originalFileName} + headerTitle={translate('profilePage.profileAvatar')} + fallbackIcon={currentUserPersonalDetails?.fallbackIcon} + editIconStyle={styles.smallEditIconAccount} + /> + {publicOptions.map((detail, index) => ( Date: Mon, 12 Aug 2024 18:36:56 +0300 Subject: [PATCH 011/361] align left --- src/pages/settings/Profile/ProfilePage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/settings/Profile/ProfilePage.tsx b/src/pages/settings/Profile/ProfilePage.tsx index 72944f36ce8b..2e2f4c6acbaa 100755 --- a/src/pages/settings/Profile/ProfilePage.tsx +++ b/src/pages/settings/Profile/ProfilePage.tsx @@ -148,7 +148,7 @@ function ProfilePage({ childrenStyles={styles.pt5} titleStyles={styles.accountSettingsSectionTitle} > - + Date: Mon, 12 Aug 2024 18:40:11 +0300 Subject: [PATCH 012/361] cleanup --- src/pages/settings/InitialSettingsPage.tsx | 88 +++++++++------------- 1 file changed, 37 insertions(+), 51 deletions(-) diff --git a/src/pages/settings/InitialSettingsPage.tsx b/src/pages/settings/InitialSettingsPage.tsx index 2b2219fa9fb4..30deb190f7f3 100755 --- a/src/pages/settings/InitialSettingsPage.tsx +++ b/src/pages/settings/InitialSettingsPage.tsx @@ -6,7 +6,6 @@ import {NativeModules, View} from 'react-native'; import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; import {useOnyx, withOnyx} from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; -import AvatarWithImagePicker from '@components/AvatarWithImagePicker'; import ConfirmModal from '@components/ConfirmModal'; import CurrentUserPersonalDetailsSkeletonView from '@components/CurrentUserPersonalDetailsSkeletonView'; import Icon from '@components/Icon'; @@ -37,7 +36,6 @@ import * as ReportActionContextMenu from '@pages/home/report/ContextMenu/ReportA import variables from '@styles/variables'; import * as Link from '@userActions/Link'; import * as PaymentMethods from '@userActions/PaymentMethods'; -import * as PersonalDetails from '@userActions/PersonalDetails'; import * as Session from '@userActions/Session'; import * as Wallet from '@userActions/Wallet'; import CONST from '@src/CONST'; @@ -51,9 +49,6 @@ import {isEmptyObject} from '@src/types/utils/EmptyObject'; import type IconAsset from '@src/types/utils/IconAsset'; type InitialSettingsPageOnyxProps = { - /** The user's session */ - session: OnyxEntry; - /** The user's wallet account */ userWallet: OnyxEntry; @@ -97,14 +92,14 @@ type MenuData = { type Menu = {sectionStyle: StyleProp; sectionTranslationKey: TranslationPaths; items: MenuData[]}; -function InitialSettingsPage({session, userWallet, bankAccountList, fundList, walletTerms, loginList, currentUserPersonalDetails, policies}: InitialSettingsPageProps) { +function InitialSettingsPage({userWallet, bankAccountList, fundList, walletTerms, loginList, currentUserPersonalDetails, policies}: InitialSettingsPageProps) { const network = useNetwork(); const theme = useTheme(); const styles = useThemeStyles(); const {isExecuting, singleExecution} = useSingleExecution(); const waitForNavigate = useWaitForNavigation(); const popoverAnchor = useRef(null); - const {translate, formatPhoneNumber} = useLocalize(); + const {translate} = useLocalize(); const activeCentralPaneRoute = useActiveCentralPaneRoute(); const emojiCode = currentUserPersonalDetails?.status?.emojiCode ?? ''; @@ -364,57 +359,51 @@ function InitialSettingsPage({session, userWallet, bankAccountList, fundList, wa const generalMenuItems = useMemo(() => getMenuItemsSection(generalMenuItemsData), [generalMenuItemsData, getMenuItemsSection]); const workspaceMenuItems = useMemo(() => getMenuItemsSection(workspaceMenuItemsData), [workspaceMenuItemsData, getMenuItemsSection]); - const currentUserDetails = currentUserPersonalDetails; - const avatarURL = currentUserDetails?.avatar ?? ''; - const accountID = currentUserDetails?.accountID ?? '-1'; - const headerContent = ( {isEmptyObject(currentUserPersonalDetails) || currentUserPersonalDetails.displayName === undefined ? ( ) : ( - <> - - - Navigation.navigate(ROUTES.SETTINGS_SHARE_CODE)} - > - + + + Navigation.navigate(ROUTES.SETTINGS_SHARE_CODE)} + > + + + + + + + Navigation.navigate(ROUTES.SETTINGS_STATUS)} + > + + {emojiCode ? ( + {emojiCode} + ) : ( - - - - - Navigation.navigate(ROUTES.SETTINGS_STATUS)} - > - - {emojiCode ? ( - {emojiCode} - ) : ( - - )} - - - - - + )} + + + + )} ); @@ -494,9 +483,6 @@ export default withCurrentUserPersonalDetails( loginList: { key: ONYXKEYS.LOGIN_LIST, }, - session: { - key: ONYXKEYS.SESSION, - }, policies: { key: ONYXKEYS.COLLECTION.POLICY, }, From 1a5e6f76b0b6e89b88abc8d027a9c633a65843cf Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Mon, 12 Aug 2024 20:52:30 +0300 Subject: [PATCH 013/361] move share button to profile page --- src/pages/settings/InitialSettingsPage.tsx | 17 --------------- src/pages/settings/Profile/ProfilePage.tsx | 25 ++++++++++++++++++++++ 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/src/pages/settings/InitialSettingsPage.tsx b/src/pages/settings/InitialSettingsPage.tsx index 30deb190f7f3..77132619c9ba 100755 --- a/src/pages/settings/InitialSettingsPage.tsx +++ b/src/pages/settings/InitialSettingsPage.tsx @@ -365,23 +365,6 @@ function InitialSettingsPage({userWallet, bankAccountList, fundList, walletTerms ) : ( - - Navigation.navigate(ROUTES.SETTINGS_SHARE_CODE)} - > - - - - - ))} + + + Navigation.navigate(ROUTES.SETTINGS_SHARE_CODE)} + style={[styles.button, styles.flexRow, styles.gap1]} + > + + {translate('common.share')} + + +
Date: Mon, 12 Aug 2024 20:58:31 +0300 Subject: [PATCH 014/361] add padding to share btn --- src/pages/settings/Profile/ProfilePage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/settings/Profile/ProfilePage.tsx b/src/pages/settings/Profile/ProfilePage.tsx index a1c21dbf97cf..ef338d7ee0f9 100755 --- a/src/pages/settings/Profile/ProfilePage.tsx +++ b/src/pages/settings/Profile/ProfilePage.tsx @@ -194,7 +194,7 @@ function ProfilePage({ accessibilityRole="button" accessible onPress={() => Navigation.navigate(ROUTES.SETTINGS_SHARE_CODE)} - style={[styles.button, styles.flexRow, styles.gap1]} + style={[styles.button, styles.flexRow, styles.gap1, styles.ph4]} > Date: Mon, 12 Aug 2024 21:43:47 +0300 Subject: [PATCH 015/361] create account switcher component --- src/components/AccountSwitcher.tsx | 50 ++++++++++++++++++++++ src/pages/settings/InitialSettingsPage.tsx | 2 + 2 files changed, 52 insertions(+) create mode 100644 src/components/AccountSwitcher.tsx diff --git a/src/components/AccountSwitcher.tsx b/src/components/AccountSwitcher.tsx new file mode 100644 index 000000000000..feb98aadea4f --- /dev/null +++ b/src/components/AccountSwitcher.tsx @@ -0,0 +1,50 @@ +import React from 'react'; +import {View} from 'react-native'; +import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; +import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; +import CONST from '@src/CONST'; +import Avatar from './Avatar'; +import {PressableWithFeedback} from './Pressable'; +import Text from './Text'; + +function AccountSwitcher() { + const currentUserPersonalDetails = useCurrentUserPersonalDetails(); + const avatarUrl = currentUserPersonalDetails?.avatar ?? ''; + const accountID = currentUserPersonalDetails?.accountID ?? -1; + const styles = useThemeStyles(); + const {translate} = useLocalize(); + + return ( + + + + + + {currentUserPersonalDetails?.displayName} + + + {currentUserPersonalDetails?.login} + + + + + ); +} + +export default AccountSwitcher; diff --git a/src/pages/settings/InitialSettingsPage.tsx b/src/pages/settings/InitialSettingsPage.tsx index 77132619c9ba..aac9f2822a03 100755 --- a/src/pages/settings/InitialSettingsPage.tsx +++ b/src/pages/settings/InitialSettingsPage.tsx @@ -6,6 +6,7 @@ import {NativeModules, View} from 'react-native'; import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; import {useOnyx, withOnyx} from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; +import AccountSwitcher from '@components/AccountSwitcher'; import ConfirmModal from '@components/ConfirmModal'; import CurrentUserPersonalDetailsSkeletonView from '@components/CurrentUserPersonalDetailsSkeletonView'; import Icon from '@components/Icon'; @@ -365,6 +366,7 @@ function InitialSettingsPage({userWallet, bankAccountList, fundList, walletTerms ) : ( + Date: Tue, 13 Aug 2024 08:34:40 +0300 Subject: [PATCH 016/361] adjust styles to be responsive and text overflow --- src/components/AccountSwitcher.tsx | 31 +++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/src/components/AccountSwitcher.tsx b/src/components/AccountSwitcher.tsx index feb98aadea4f..f5181cd1fdd3 100644 --- a/src/components/AccountSwitcher.tsx +++ b/src/components/AccountSwitcher.tsx @@ -2,9 +2,13 @@ import React from 'react'; import {View} from 'react-native'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; import useLocalize from '@hooks/useLocalize'; +import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; +import variables from '@styles/variables'; import CONST from '@src/CONST'; import Avatar from './Avatar'; +import Icon from './Icon'; +import * as Expensicons from './Icon/Expensicons'; import {PressableWithFeedback} from './Pressable'; import Text from './Text'; @@ -14,11 +18,14 @@ function AccountSwitcher() { const accountID = currentUserPersonalDetails?.accountID ?? -1; const styles = useThemeStyles(); const {translate} = useLocalize(); + const theme = useTheme(); return ( {}} + wrapperStyle={[styles.flexGrow1, styles.accountSwitcherWrapper, styles.justifyContentCenter]} > - - - {currentUserPersonalDetails?.displayName} - + + + + {currentUserPersonalDetails?.displayName} + + + + + Date: Tue, 13 Aug 2024 08:34:55 +0300 Subject: [PATCH 017/361] add caret up down icon --- assets/images/caret-up-down.svg | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 assets/images/caret-up-down.svg diff --git a/assets/images/caret-up-down.svg b/assets/images/caret-up-down.svg new file mode 100644 index 000000000000..d08aa2a1ebbd --- /dev/null +++ b/assets/images/caret-up-down.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + \ No newline at end of file From d0cf30bd1784972600eb49de94f99b869ac4f6f4 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Tue, 13 Aug 2024 08:35:00 +0300 Subject: [PATCH 018/361] add caret up down icon --- src/components/Icon/Expensicons.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/components/Icon/Expensicons.ts b/src/components/Icon/Expensicons.ts index cb68f33face7..69131493c8aa 100644 --- a/src/components/Icon/Expensicons.ts +++ b/src/components/Icon/Expensicons.ts @@ -32,6 +32,7 @@ import Calendar from '@assets/images/calendar.svg'; import Camera from '@assets/images/camera.svg'; import CarWithKey from '@assets/images/car-with-key.svg'; import Car from '@assets/images/car.svg'; +import CaretUpDown from '@assets/images/caret-up-down.svg'; import Cash from '@assets/images/cash.svg'; import Chair from '@assets/images/chair.svg'; import ChatBubbleAdd from '@assets/images/chatbubble-add.svg'; @@ -384,4 +385,5 @@ export { Filters, CalendarSolid, Filter, + CaretUpDown, }; From 6112f607e4984b2a909d305821249376fc617d7a Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Tue, 13 Aug 2024 08:35:23 +0300 Subject: [PATCH 019/361] show account switcher --- src/pages/settings/InitialSettingsPage.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/settings/InitialSettingsPage.tsx b/src/pages/settings/InitialSettingsPage.tsx index aac9f2822a03..73e3c497894a 100755 --- a/src/pages/settings/InitialSettingsPage.tsx +++ b/src/pages/settings/InitialSettingsPage.tsx @@ -361,11 +361,11 @@ function InitialSettingsPage({userWallet, bankAccountList, fundList, walletTerms const workspaceMenuItems = useMemo(() => getMenuItemsSection(workspaceMenuItemsData), [workspaceMenuItemsData, getMenuItemsSection]); const headerContent = ( - + {isEmptyObject(currentUserPersonalDetails) || currentUserPersonalDetails.displayName === undefined ? ( ) : ( - + Date: Tue, 13 Aug 2024 08:36:58 +0300 Subject: [PATCH 020/361] add min width 0 style --- src/styles/index.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/styles/index.ts b/src/styles/index.ts index 59803541bfef..a1f1f17bfcc0 100644 --- a/src/styles/index.ts +++ b/src/styles/index.ts @@ -1,5 +1,6 @@ /* eslint-disable @typescript-eslint/naming-convention */ import type {LineLayerStyleProps} from '@rnmapbox/maps/src/utils/MapboxStyles'; +import {min} from 'lodash'; import lodashClamp from 'lodash/clamp'; import type {LineLayer} from 'react-map-gl'; import type {AnimatableNumericValue, Animated, ImageStyle, TextStyle, ViewStyle} from 'react-native'; @@ -5159,6 +5160,11 @@ const styles = (theme: ThemeColors) => marginLeft: 19, backgroundColor: theme.border, }, + + accountSwitcherWrapper: { + minWidth: 0, + flex: 1, + }, } satisfies Styles); type ThemeStyles = ReturnType; From cebf12924f49edf22c14eeaffea2bb7214d364c9 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Tue, 13 Aug 2024 08:39:32 +0300 Subject: [PATCH 021/361] add beta --- src/CONST.ts | 1 + src/libs/Permissions.ts | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/src/CONST.ts b/src/CONST.ts index 57c6da815eba..9ce618284ec2 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -381,6 +381,7 @@ const CONST = { REPORT_FIELDS_FEATURE: 'reportFieldsFeature', WORKSPACE_FEEDS: 'workspaceFeeds', NETSUITE_USA_TAX: 'netsuiteUsaTax', + NEW_DOT_COPILOT: 'newDotCopilot', }, BUTTON_STATES: { DEFAULT: 'default', diff --git a/src/libs/Permissions.ts b/src/libs/Permissions.ts index f652c2a423ec..0581fd41853e 100644 --- a/src/libs/Permissions.ts +++ b/src/libs/Permissions.ts @@ -40,6 +40,10 @@ function canUseNetSuiteUSATax(betas: OnyxEntry): boolean { return !!betas?.includes(CONST.BETAS.NETSUITE_USA_TAX) || canUseAllBetas(betas); } +function canUseNewDotCopilot(betas: OnyxEntry): boolean { + return !!betas?.includes(CONST.BETAS.NEW_DOT_COPILOT) || canUseAllBetas(betas); +} + /** * Link previews are temporarily disabled. */ @@ -57,4 +61,5 @@ export default { canUseReportFieldsFeature, canUseWorkspaceFeeds, canUseNetSuiteUSATax, + canUseNewDotCopilot, }; From 3655383bad5e01c695b5882ea8bd2cfa4f7ebb12 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Tue, 13 Aug 2024 08:42:00 +0300 Subject: [PATCH 022/361] rm unnecessary style --- src/components/AccountSwitcher.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/AccountSwitcher.tsx b/src/components/AccountSwitcher.tsx index f5181cd1fdd3..14ee4a60051c 100644 --- a/src/components/AccountSwitcher.tsx +++ b/src/components/AccountSwitcher.tsx @@ -39,7 +39,7 @@ function AccountSwitcher() { {currentUserPersonalDetails?.displayName} From 57dfbede700e6be22c702d542836f814375ca745 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Tue, 13 Aug 2024 09:24:51 +0300 Subject: [PATCH 023/361] add popover menu to show delegates --- src/components/AccountSwitcher.tsx | 117 ++++++++++++++++++++--------- src/styles/index.ts | 6 ++ 2 files changed, 88 insertions(+), 35 deletions(-) diff --git a/src/components/AccountSwitcher.tsx b/src/components/AccountSwitcher.tsx index 14ee4a60051c..6426a254903b 100644 --- a/src/components/AccountSwitcher.tsx +++ b/src/components/AccountSwitcher.tsx @@ -1,14 +1,20 @@ -import React from 'react'; +import {set} from 'lodash'; +import React, {useEffect, useRef, useState} from 'react'; import {View} from 'react-native'; +import Onyx, {useOnyx} from 'react-native-onyx'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; import useLocalize from '@hooks/useLocalize'; +import usePermissions from '@hooks/usePermissions'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import variables from '@styles/variables'; import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; import Avatar from './Avatar'; import Icon from './Icon'; import * as Expensicons from './Icon/Expensicons'; +import PopoverMenu from './PopoverMenu'; +import type {PopoverMenuItem} from './PopoverMenu/types'; import {PressableWithFeedback} from './Pressable'; import Text from './Text'; @@ -19,48 +25,89 @@ function AccountSwitcher() { const styles = useThemeStyles(); const {translate} = useLocalize(); const theme = useTheme(); + const {canUseNewDotCopilot} = usePermissions(); + const [account] = useOnyx(ONYXKEYS.ACCOUNT); + const [shouldShowDelegateMenu, setShouldShowDelegateMenu] = useState(false); + + const buttonRef = useRef(null); + + const delegates = account?.delegatedAccess?.delegates ?? []; + const shouldShowDelegates = delegates.length > 0 && canUseNewDotCopilot; + + const delegateMenuItems: PopoverMenuItem[] = delegates.map(({email, role}) => ({ + text: `${email} (${role})`, + onPress: () => {}, + })); + + useEffect(() => { + // eslint-disable-next-line rulesdir/prefer-actions-set-data + Onyx.merge(ONYXKEYS.ACCOUNT, { + delegatedAccess: { + delegates: [ + {email: 'delegate1@expensify.com', role: 'all'}, + {email: 'delegate2@expensify.com', role: 'submitter'}, + ], + }, + }); + }, []); return ( - {}} - wrapperStyle={[styles.flexGrow1, styles.accountSwitcherWrapper, styles.justifyContentCenter]} - > - - - - + <> + { + setShouldShowDelegateMenu(!shouldShowDelegateMenu); + }} + ref={buttonRef} + wrapperStyle={[styles.flexGrow1, styles.accountSwitcherWrapper, styles.justifyContentCenter]} + > + + + + + + {currentUserPersonalDetails?.displayName} + + {shouldShowDelegates && ( + + + + )} + - {currentUserPersonalDetails?.displayName} + {currentUserPersonalDetails?.login} - - - - - {currentUserPersonalDetails?.login} - - - + + setShouldShowDelegateMenu(false)} + onItemSelected={() => {}} + menuItems={delegateMenuItems} + anchorRef={buttonRef} + anchorPosition={styles.createAccountSwitcherPosition()} + /> + ); } diff --git a/src/styles/index.ts b/src/styles/index.ts index a1f1f17bfcc0..8c5e3e49905e 100644 --- a/src/styles/index.ts +++ b/src/styles/index.ts @@ -1711,6 +1711,12 @@ const styles = (theme: ThemeColors) => lineHeight: variables.fontSizeOnlyEmojisHeight, }, + createAccountSwitcherPosition: () => + ({ + horizontal: 12, + vertical: 285, + } satisfies AnchorPosition), + createMenuPositionSidebar: (windowHeight: number) => ({ horizontal: 18, From 190a319d96711314f33deef8c4c558f5df14061a Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Tue, 13 Aug 2024 11:04:52 +0300 Subject: [PATCH 024/361] cleanup --- src/components/AccountSwitcher.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/AccountSwitcher.tsx b/src/components/AccountSwitcher.tsx index 6426a254903b..35c9a85eb809 100644 --- a/src/components/AccountSwitcher.tsx +++ b/src/components/AccountSwitcher.tsx @@ -1,4 +1,3 @@ -import {set} from 'lodash'; import React, {useEffect, useRef, useState} from 'react'; import {View} from 'react-native'; import Onyx, {useOnyx} from 'react-native-onyx'; @@ -14,7 +13,7 @@ import Avatar from './Avatar'; import Icon from './Icon'; import * as Expensicons from './Icon/Expensicons'; import PopoverMenu from './PopoverMenu'; -import type {PopoverMenuItem} from './PopoverMenu/types'; +import type {PopoverMenuItem} from './PopoverMenu'; import {PressableWithFeedback} from './Pressable'; import Text from './Text'; From b43f7c04e6913ade3960877892e84eb44f781668 Mon Sep 17 00:00:00 2001 From: Wiktor Gut Date: Tue, 13 Aug 2024 12:58:22 +0200 Subject: [PATCH 025/361] pulling from, to filters --- src/pages/Search/AdvancedSearchFilters.tsx | 5 +++ src/pages/Search/SearchFiltersInPage.tsx | 42 +++++++++++++++++++++ src/types/form/SearchAdvancedFiltersForm.ts | 2 + 3 files changed, 49 insertions(+) create mode 100644 src/pages/Search/SearchFiltersInPage.tsx diff --git a/src/pages/Search/AdvancedSearchFilters.tsx b/src/pages/Search/AdvancedSearchFilters.tsx index 644ae64466f7..9a7688fdc268 100644 --- a/src/pages/Search/AdvancedSearchFilters.tsx +++ b/src/pages/Search/AdvancedSearchFilters.tsx @@ -190,6 +190,11 @@ function AdvancedSearchFilters() { description: 'common.to' as const, route: ROUTES.SEARCH_ADVANCED_FILTERS_TO, }, + { + title: getFilterParticipantDisplayTitle(searchAdvancedFilters.in ?? [], personalDetails), + description: 'common.to' as const, + route: ROUTES.SEARCH_ADVANCED_FILTERS_TO, + }, ], [searchAdvancedFilters, translate, cardList, taxRates, personalDetails], ); diff --git a/src/pages/Search/SearchFiltersInPage.tsx b/src/pages/Search/SearchFiltersInPage.tsx new file mode 100644 index 000000000000..1bcf1ea66248 --- /dev/null +++ b/src/pages/Search/SearchFiltersInPage.tsx @@ -0,0 +1,42 @@ +import React from 'react'; +import {View} from 'react-native'; +import {useOnyx} from 'react-native-onyx'; +import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import ScreenWrapper from '@components/ScreenWrapper'; +import SearchFiltersParticipantsSelector from '@components/Search/SearchFiltersParticipantsSelector'; +import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; +import * as SearchActions from '@userActions/Search'; +import ONYXKEYS from '@src/ONYXKEYS'; + +function SearchFiltersStatusPage() { + const styles = useThemeStyles(); + const {translate} = useLocalize(); + + const [searchAdvancedFiltersForm] = useOnyx(ONYXKEYS.FORMS.SEARCH_ADVANCED_FILTERS_FORM); + + return ( + + + + { + SearchActions.updateAdvancedFilters({ + from: selectedAccountIDs, + }); + }} + /> + + + ); +} + +SearchFiltersStatusPage.displayName = 'SearchFiltersStatusPage'; + +export default SearchFiltersStatusPage; diff --git a/src/types/form/SearchAdvancedFiltersForm.ts b/src/types/form/SearchAdvancedFiltersForm.ts index f2643c0c987d..2afc63b7a2d3 100644 --- a/src/types/form/SearchAdvancedFiltersForm.ts +++ b/src/types/form/SearchAdvancedFiltersForm.ts @@ -17,6 +17,7 @@ const FILTER_KEYS = { KEYWORD: 'keyword', FROM: 'from', TO: 'to', + IN: 'in', } as const; type InputID = ValueOf; @@ -39,6 +40,7 @@ type SearchAdvancedFiltersForm = Form< [FILTER_KEYS.TAG]: string[]; [FILTER_KEYS.FROM]: string[]; [FILTER_KEYS.TO]: string[]; + [FILTER_KEYS.IN]: string[]; } >; From 110af748c682b64da39732f52097a5f9d049f635 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Tue, 13 Aug 2024 16:22:01 +0300 Subject: [PATCH 026/361] add styling for menu item --- src/components/AccountSwitcher.tsx | 77 +++++++++++++++++++++++------- 1 file changed, 60 insertions(+), 17 deletions(-) diff --git a/src/components/AccountSwitcher.tsx b/src/components/AccountSwitcher.tsx index 35c9a85eb809..d8db6ae6f426 100644 --- a/src/components/AccountSwitcher.tsx +++ b/src/components/AccountSwitcher.tsx @@ -1,19 +1,22 @@ +import {Str} from 'expensify-common'; import React, {useEffect, useRef, useState} from 'react'; import {View} from 'react-native'; import Onyx, {useOnyx} from 'react-native-onyx'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; 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'; +import {getPersonalDetailByEmail} from '@libs/PersonalDetailsUtils'; import variables from '@styles/variables'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import Avatar from './Avatar'; import Icon from './Icon'; import * as Expensicons from './Icon/Expensicons'; -import PopoverMenu from './PopoverMenu'; -import type {PopoverMenuItem} from './PopoverMenu'; +import MenuItem from './MenuItem'; +import Popover from './Popover'; import {PressableWithFeedback} from './Pressable'; import Text from './Text'; @@ -32,19 +35,52 @@ function AccountSwitcher() { const delegates = account?.delegatedAccess?.delegates ?? []; const shouldShowDelegates = delegates.length > 0 && canUseNewDotCopilot; + const {isSmallScreenWidth} = useResponsiveLayout(); - const delegateMenuItems: PopoverMenuItem[] = delegates.map(({email, role}) => ({ - text: `${email} (${role})`, - onPress: () => {}, - })); + const delegateMenuItems = delegates.map(({email, role}) => { + const personalDetail = getPersonalDetailByEmail(email); + + return { + key: email, + title: personalDetail?.displayName ?? email, + description: personalDetail?.displayName ? email : '', + badgeText: Str.recapitalize(role), + onPress: () => {}, + avatarID: personalDetail?.accountID ?? -1, + icon: personalDetail?.avatar ?? '', + iconType: CONST.ICON_TYPE_AVATAR, + outerWrapperStyle: isSmallScreenWidth ? {} : styles.accountSwitcherPopover, + numberOfLinesDescription: 1, + }; + }); + + const delegateMenuItemsWithCurrentUser = [ + { + key: currentUserPersonalDetails?.login, + title: currentUserPersonalDetails?.displayName ?? currentUserPersonalDetails?.login, + description: currentUserPersonalDetails?.displayName ? currentUserPersonalDetails?.login : '', + onPress: () => {}, + iconRight: Expensicons.Checkmark, + shouldShowRightIcon: true, + success: true, + avatarID: currentUserPersonalDetails?.accountID ?? -1, + icon: avatarUrl, + iconType: CONST.ICON_TYPE_AVATAR, + outerWrapperStyle: isSmallScreenWidth ? {} : styles.accountSwitcherPopover, + numberOfLinesDescription: 1, + wrapperStyle: [styles.buttonDefaultBG], + focused: true, + }, + ...delegateMenuItems, + ]; useEffect(() => { // eslint-disable-next-line rulesdir/prefer-actions-set-data Onyx.merge(ONYXKEYS.ACCOUNT, { delegatedAccess: { delegates: [ - {email: 'delegate1@expensify.com', role: 'all'}, - {email: 'delegate2@expensify.com', role: 'submitter'}, + {email: 'rushatgabhane@gmail.com', role: 'all'}, + {email: 'expensifyopensource+10041232131212321@protonmail.com', role: 'submitter'}, ], }, }); @@ -97,15 +133,22 @@ function AccountSwitcher() { - setShouldShowDelegateMenu(false)} - onItemSelected={() => {}} - menuItems={delegateMenuItems} - anchorRef={buttonRef} - anchorPosition={styles.createAccountSwitcherPosition()} - /> + {shouldShowDelegates && ( + setShouldShowDelegateMenu(false)} + anchorRef={buttonRef} + anchorPosition={{top: 80, left: 12}} + > + + {translate('delegate.switchAccount')} + {delegateMenuItemsWithCurrentUser.map((item) => ( + // eslint-disable-next-line react/jsx-props-no-spreading + + ))} + + + )} ); } From 890b23e34f8189d58d0ddf708769e5452cf9e799 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Tue, 13 Aug 2024 16:22:18 +0300 Subject: [PATCH 027/361] add badge text --- src/components/PopoverMenu.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/PopoverMenu.tsx b/src/components/PopoverMenu.tsx index e9df68d43d06..135f0c9061e4 100644 --- a/src/components/PopoverMenu.tsx +++ b/src/components/PopoverMenu.tsx @@ -266,6 +266,7 @@ function PopoverMenu({ renderTooltipContent={item.renderTooltipContent} numberOfLinesTitle={item.numberOfLinesTitle} interactive={item.interactive} + badgeText={item.badgeText} /> ))} From d15ffabb559e84308362a8c4d5af6668486a649e Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Tue, 13 Aug 2024 16:22:27 +0300 Subject: [PATCH 028/361] add lang --- src/languages/en.ts | 3 +++ src/languages/es.ts | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/languages/en.ts b/src/languages/en.ts index bfe0eef70178..ed49cb449f10 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -4353,4 +4353,7 @@ export default { updateRoomDescription: 'set the room description to:', clearRoomDescription: 'cleared the room description', }, + delegate: { + switchAccount: 'Switch accounts:', + }, } satisfies TranslationBase; diff --git a/src/languages/es.ts b/src/languages/es.ts index 76d55a096808..1c79c828bc0f 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -4873,4 +4873,7 @@ export default { updateRoomDescription: 'establece la descripción de la sala a:', clearRoomDescription: 'la descripción de la habitación ha sido borrada', }, + delegate: { + switchAccount: 'Cambiar cuentas:', + }, } satisfies EnglishTranslation; From e0aaba50e06f86326072c3597b441dd9cc81310f Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Tue, 13 Aug 2024 16:23:22 +0300 Subject: [PATCH 029/361] add width for account switcher popover --- src/styles/index.ts | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/styles/index.ts b/src/styles/index.ts index 8c5e3e49905e..7c8882693fe1 100644 --- a/src/styles/index.ts +++ b/src/styles/index.ts @@ -1,6 +1,5 @@ /* eslint-disable @typescript-eslint/naming-convention */ import type {LineLayerStyleProps} from '@rnmapbox/maps/src/utils/MapboxStyles'; -import {min} from 'lodash'; import lodashClamp from 'lodash/clamp'; import type {LineLayer} from 'react-map-gl'; import type {AnimatableNumericValue, Animated, ImageStyle, TextStyle, ViewStyle} from 'react-native'; @@ -1711,12 +1710,6 @@ const styles = (theme: ThemeColors) => lineHeight: variables.fontSizeOnlyEmojisHeight, }, - createAccountSwitcherPosition: () => - ({ - horizontal: 12, - vertical: 285, - } satisfies AnchorPosition), - createMenuPositionSidebar: (windowHeight: number) => ({ horizontal: 18, @@ -5171,6 +5164,10 @@ const styles = (theme: ThemeColors) => minWidth: 0, flex: 1, }, + + accountSwitcherPopover: { + width: variables.sideBarWidth - 19, + }, } satisfies Styles); type ThemeStyles = ReturnType; From e05b5d9b9ef61611c96ea9c123f94466765e94e5 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Tue, 13 Aug 2024 16:24:11 +0300 Subject: [PATCH 030/361] cleanup --- src/components/AccountSwitcher.tsx | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/components/AccountSwitcher.tsx b/src/components/AccountSwitcher.tsx index d8db6ae6f426..33913baa496e 100644 --- a/src/components/AccountSwitcher.tsx +++ b/src/components/AccountSwitcher.tsx @@ -74,18 +74,6 @@ function AccountSwitcher() { ...delegateMenuItems, ]; - useEffect(() => { - // eslint-disable-next-line rulesdir/prefer-actions-set-data - Onyx.merge(ONYXKEYS.ACCOUNT, { - delegatedAccess: { - delegates: [ - {email: 'rushatgabhane@gmail.com', role: 'all'}, - {email: 'expensifyopensource+10041232131212321@protonmail.com', role: 'submitter'}, - ], - }, - }); - }, []); - return ( <> Date: Tue, 13 Aug 2024 16:24:45 +0300 Subject: [PATCH 031/361] cleanup --- src/components/AccountSwitcher.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/AccountSwitcher.tsx b/src/components/AccountSwitcher.tsx index 33913baa496e..fc254c1d01af 100644 --- a/src/components/AccountSwitcher.tsx +++ b/src/components/AccountSwitcher.tsx @@ -1,7 +1,7 @@ import {Str} from 'expensify-common'; -import React, {useEffect, useRef, useState} from 'react'; +import React, {useRef, useState} from 'react'; import {View} from 'react-native'; -import Onyx, {useOnyx} from 'react-native-onyx'; +import {useOnyx} from 'react-native-onyx'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; import useLocalize from '@hooks/useLocalize'; import usePermissions from '@hooks/usePermissions'; From cc3c7225e17ead425aef0e23a84fb20bb08f0e2c Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Tue, 13 Aug 2024 16:31:20 +0300 Subject: [PATCH 032/361] cleanup --- src/components/AccountSwitcher.tsx | 2 +- src/styles/index.ts | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/components/AccountSwitcher.tsx b/src/components/AccountSwitcher.tsx index fc254c1d01af..d9fa42a586dd 100644 --- a/src/components/AccountSwitcher.tsx +++ b/src/components/AccountSwitcher.tsx @@ -126,7 +126,7 @@ function AccountSwitcher() { isVisible={shouldShowDelegateMenu} onClose={() => setShouldShowDelegateMenu(false)} anchorRef={buttonRef} - anchorPosition={{top: 80, left: 12}} + anchorPosition={styles.accountSwitcherAnchorPosition} > {translate('delegate.switchAccount')} diff --git a/src/styles/index.ts b/src/styles/index.ts index 7c8882693fe1..102bfa93f337 100644 --- a/src/styles/index.ts +++ b/src/styles/index.ts @@ -5168,6 +5168,11 @@ const styles = (theme: ThemeColors) => accountSwitcherPopover: { width: variables.sideBarWidth - 19, }, + + accountSwitcherAnchorPosition: { + top: 80, + left: 12, + }, } satisfies Styles); type ThemeStyles = ReturnType; From b298b0b86ca58e4e1cf0fe55ccd7ae48bdde4aaf Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Tue, 13 Aug 2024 16:35:38 +0300 Subject: [PATCH 033/361] add menu item type --- src/components/AccountSwitcher.tsx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/components/AccountSwitcher.tsx b/src/components/AccountSwitcher.tsx index d9fa42a586dd..0b928ba92f48 100644 --- a/src/components/AccountSwitcher.tsx +++ b/src/components/AccountSwitcher.tsx @@ -16,6 +16,7 @@ import Avatar from './Avatar'; import Icon from './Icon'; import * as Expensicons from './Icon/Expensicons'; import MenuItem from './MenuItem'; +import type {MenuItemProps} from './MenuItem'; import Popover from './Popover'; import {PressableWithFeedback} from './Pressable'; import Text from './Text'; @@ -37,11 +38,10 @@ function AccountSwitcher() { const shouldShowDelegates = delegates.length > 0 && canUseNewDotCopilot; const {isSmallScreenWidth} = useResponsiveLayout(); - const delegateMenuItems = delegates.map(({email, role}) => { + const delegateMenuItems: MenuItemProps[] = delegates.map(({email, role}) => { const personalDetail = getPersonalDetailByEmail(email); return { - key: email, title: personalDetail?.displayName ?? email, description: personalDetail?.displayName ? email : '', badgeText: Str.recapitalize(role), @@ -54,9 +54,8 @@ function AccountSwitcher() { }; }); - const delegateMenuItemsWithCurrentUser = [ + const delegateMenuItemsWithCurrentUser: MenuItemProps[] = [ { - key: currentUserPersonalDetails?.login, title: currentUserPersonalDetails?.displayName ?? currentUserPersonalDetails?.login, description: currentUserPersonalDetails?.displayName ? currentUserPersonalDetails?.login : '', onPress: () => {}, From 30c56d1121f849ae855b3e465d82a9d643a6f554 Mon Sep 17 00:00:00 2001 From: daledah Date: Tue, 13 Aug 2024 20:29:12 +0700 Subject: [PATCH 034/361] fix: maintain tax assign when tax code changes --- src/libs/actions/TaxRate.ts | 60 +++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/src/libs/actions/TaxRate.ts b/src/libs/actions/TaxRate.ts index 0e7245a93f7b..869c14017607 100644 --- a/src/libs/actions/TaxRate.ts +++ b/src/libs/actions/TaxRate.ts @@ -21,6 +21,7 @@ import INPUT_IDS from '@src/types/form/WorkspaceNewTaxForm'; import {default as INPUT_IDS_TAX_CODE} from '@src/types/form/WorkspaceTaxCodeForm'; import type {Policy, TaxRate, TaxRates} from '@src/types/onyx'; import type * as OnyxCommon from '@src/types/onyx/OnyxCommon'; +import type {CustomUnit, Rate} from '@src/types/onyx/Policy'; import type {OnyxData} from '@src/types/onyx/Request'; let allPolicies: OnyxCollection; @@ -486,6 +487,63 @@ function renamePolicyTax(policyID: string, taxID: string, newName: string) { function setPolicyTaxCode(policyID: string, oldTaxCode: string, newTaxCode: string) { const policy = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${policyID}`]; const originalTaxRate = {...policy?.taxRates?.taxes[oldTaxCode]}; + const customUnits = Object.values(policy?.customUnits ?? {}); + const optimisticCustomUnit = { + customUnits: { + ...policy?.customUnits, + ...customUnits.reduce((units, customUnit) => { + // eslint-disable-next-line no-param-reassign + units[customUnit.customUnitID] = { + ...customUnit, + rates: { + ...customUnit.rates, + ...Object.keys(customUnit.rates).reduce((rates, rateID) => { + if (customUnit.rates[rateID].attributes?.taxRateExternalID === oldTaxCode) { + // eslint-disable-next-line no-param-reassign + rates[rateID] = { + ...customUnit.rates[rateID], + attributes: { + ...customUnit.rates[rateID].attributes, + taxRateExternalID: newTaxCode, + }, + }; + } + return rates; + }, {} as Record), + } as Record, + }; + return units; + }, {} as Record), + }, + }; + const failureCustomUnit = { + customUnits: { + ...policy?.customUnits, + ...customUnits.reduce((units, customUnit) => { + // eslint-disable-next-line no-param-reassign + units[customUnit.customUnitID] = { + ...customUnit, + rates: { + ...customUnit.rates, + ...Object.keys(customUnit.rates).reduce((rates, rateID) => { + if (customUnit.rates[rateID].attributes?.taxRateExternalID === oldTaxCode) { + // eslint-disable-next-line no-param-reassign + rates[rateID] = { + ...customUnit.rates[rateID], + attributes: { + ...customUnit.rates[rateID].attributes, + taxRateExternalID: oldTaxCode, + }, + }; + } + return rates; + }, {} as Record), + } as Record, + }; + return units; + }, {} as Record), + }, + }; const onyxData: OnyxData = { optimisticData: [ { @@ -504,6 +562,7 @@ function setPolicyTaxCode(policyID: string, oldTaxCode: string, newTaxCode: stri }, }, }, + ...(!!customUnits && optimisticCustomUnit), }, }, ], @@ -544,6 +603,7 @@ function setPolicyTaxCode(policyID: string, oldTaxCode: string, newTaxCode: stri }, }, }, + ...(!!customUnits && failureCustomUnit), }, }, ], From f426c002a93b98c3534e8095c3ec46d59af0b83d Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Tue, 13 Aug 2024 17:15:38 +0300 Subject: [PATCH 035/361] add todo for error handling --- src/components/AccountSwitcher.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/AccountSwitcher.tsx b/src/components/AccountSwitcher.tsx index 0b928ba92f48..262551c3647b 100644 --- a/src/components/AccountSwitcher.tsx +++ b/src/components/AccountSwitcher.tsx @@ -133,6 +133,7 @@ function AccountSwitcher() { // eslint-disable-next-line react/jsx-props-no-spreading ))} + {/* TODO error handling on API error Oops something went wrong. Please try again */} )} From 4f64b1d6c610b2caf9dc3b7d3e330d0ff7bbe4a1 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Tue, 13 Aug 2024 17:15:54 +0300 Subject: [PATCH 036/361] correct border color --- src/pages/settings/Profile/ProfilePage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/settings/Profile/ProfilePage.tsx b/src/pages/settings/Profile/ProfilePage.tsx index ef338d7ee0f9..b62342aa56f4 100755 --- a/src/pages/settings/Profile/ProfilePage.tsx +++ b/src/pages/settings/Profile/ProfilePage.tsx @@ -172,7 +172,7 @@ function ProfilePage({ originalFileName={currentUserPersonalDetails.originalFileName} headerTitle={translate('profilePage.profileAvatar')} fallbackIcon={currentUserPersonalDetails?.fallbackIcon} - editIconStyle={styles.smallEditIconAccount} + editIconStyle={styles.profilePageAvatar} /> {publicOptions.map((detail, index) => ( From 94811774cf837900781c1085446bad00aca62075 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Tue, 13 Aug 2024 17:16:02 +0300 Subject: [PATCH 037/361] correct border color --- src/styles/index.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/styles/index.ts b/src/styles/index.ts index 102bfa93f337..2eea5479bcfb 100644 --- a/src/styles/index.ts +++ b/src/styles/index.ts @@ -4515,6 +4515,10 @@ const styles = (theme: ThemeColors) => overflow: 'hidden', }, + profilePageAvatar: { + borderColor: theme.highlightBG, + }, + justSignedInModalAnimation: (is2FARequired: boolean) => ({ height: is2FARequired ? variables.modalTopIconHeight : variables.modalTopBigIconHeight, }), From d85b8afcab6056f1f9fb98de2998ffbf284f92d5 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Tue, 13 Aug 2024 17:48:29 +0300 Subject: [PATCH 038/361] add api call to connect --- src/components/AccountSwitcher.tsx | 6 ++++-- src/libs/actions/Delegate.ts | 6 ++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/components/AccountSwitcher.tsx b/src/components/AccountSwitcher.tsx index 262551c3647b..9a2c2b39591a 100644 --- a/src/components/AccountSwitcher.tsx +++ b/src/components/AccountSwitcher.tsx @@ -8,6 +8,7 @@ import usePermissions from '@hooks/usePermissions'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; +import {connect} from '@libs/actions/Delegate'; import {getPersonalDetailByEmail} from '@libs/PersonalDetailsUtils'; import variables from '@styles/variables'; import CONST from '@src/CONST'; @@ -45,7 +46,9 @@ function AccountSwitcher() { title: personalDetail?.displayName ?? email, description: personalDetail?.displayName ? email : '', badgeText: Str.recapitalize(role), - onPress: () => {}, + onPress: () => { + connect(email); + }, avatarID: personalDetail?.accountID ?? -1, icon: personalDetail?.avatar ?? '', iconType: CONST.ICON_TYPE_AVATAR, @@ -58,7 +61,6 @@ function AccountSwitcher() { { title: currentUserPersonalDetails?.displayName ?? currentUserPersonalDetails?.login, description: currentUserPersonalDetails?.displayName ? currentUserPersonalDetails?.login : '', - onPress: () => {}, iconRight: Expensicons.Checkmark, shouldShowRightIcon: true, success: true, diff --git a/src/libs/actions/Delegate.ts b/src/libs/actions/Delegate.ts index b743b5c77e76..2a3295a9dfd5 100644 --- a/src/libs/actions/Delegate.ts +++ b/src/libs/actions/Delegate.ts @@ -10,6 +10,11 @@ function connect(email: string) { // eslint-disable-next-line rulesdir/no-api-side-effects-method API.makeRequestWithSideEffects(SIDE_EFFECT_REQUEST_COMMANDS.CONNECT_AS_DELEGATE, {to: email}, {}) .then((response) => { + if (!response?.restrictedToken || !response?.encryptedAuthToken) { + // TODO: Show an error message to the user + console.error('Error during connect: No authToken returned'); + return; + } return SequentialQueue.waitForIdle() .then(() => Onyx.clear()) .then(() => { @@ -21,6 +26,7 @@ function connect(email: string) { }); }) .catch((error) => { + // TODO: Show an error message to the user console.error('Error during connect:', error); }); } From 9a2a35d143596fb9eea92c22cd4dcd8f288d34cd Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Tue, 13 Aug 2024 21:47:47 +0300 Subject: [PATCH 039/361] add gap --- src/components/AccountSwitcher.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/AccountSwitcher.tsx b/src/components/AccountSwitcher.tsx index 9a2c2b39591a..cf4c0491de36 100644 --- a/src/components/AccountSwitcher.tsx +++ b/src/components/AccountSwitcher.tsx @@ -94,7 +94,7 @@ function AccountSwitcher() { source={avatarUrl} fallbackIcon={currentUserPersonalDetails.fallbackIcon} /> - + Date: Wed, 14 Aug 2024 14:50:06 +0700 Subject: [PATCH 040/361] refactor: simplify optimistic and failture data --- src/libs/actions/TaxRate.ts | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/src/libs/actions/TaxRate.ts b/src/libs/actions/TaxRate.ts index 869c14017607..decb74c1a642 100644 --- a/src/libs/actions/TaxRate.ts +++ b/src/libs/actions/TaxRate.ts @@ -490,58 +490,48 @@ function setPolicyTaxCode(policyID: string, oldTaxCode: string, newTaxCode: stri const customUnits = Object.values(policy?.customUnits ?? {}); const optimisticCustomUnit = { customUnits: { - ...policy?.customUnits, ...customUnits.reduce((units, customUnit) => { // eslint-disable-next-line no-param-reassign units[customUnit.customUnitID] = { - ...customUnit, rates: { - ...customUnit.rates, ...Object.keys(customUnit.rates).reduce((rates, rateID) => { if (customUnit.rates[rateID].attributes?.taxRateExternalID === oldTaxCode) { // eslint-disable-next-line no-param-reassign rates[rateID] = { - ...customUnit.rates[rateID], attributes: { - ...customUnit.rates[rateID].attributes, taxRateExternalID: newTaxCode, }, }; } return rates; }, {} as Record), - } as Record, + }, }; return units; - }, {} as Record), + }, {} as Record>), }, }; const failureCustomUnit = { customUnits: { - ...policy?.customUnits, ...customUnits.reduce((units, customUnit) => { // eslint-disable-next-line no-param-reassign units[customUnit.customUnitID] = { - ...customUnit, rates: { - ...customUnit.rates, ...Object.keys(customUnit.rates).reduce((rates, rateID) => { if (customUnit.rates[rateID].attributes?.taxRateExternalID === oldTaxCode) { // eslint-disable-next-line no-param-reassign rates[rateID] = { - ...customUnit.rates[rateID], attributes: { - ...customUnit.rates[rateID].attributes, taxRateExternalID: oldTaxCode, }, }; } return rates; }, {} as Record), - } as Record, + }, }; return units; - }, {} as Record), + }, {} as Record>), }, }; const onyxData: OnyxData = { From c3e63638667ebdad1f8b8f5f8659081282fb39f6 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Wed, 14 Aug 2024 11:20:06 +0300 Subject: [PATCH 041/361] use menuitem list and delegators --- src/components/AccountSwitcher.tsx | 32 +++++++++++++----------------- 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/src/components/AccountSwitcher.tsx b/src/components/AccountSwitcher.tsx index cf4c0491de36..cd1fb9d894f8 100644 --- a/src/components/AccountSwitcher.tsx +++ b/src/components/AccountSwitcher.tsx @@ -16,8 +16,8 @@ import ONYXKEYS from '@src/ONYXKEYS'; import Avatar from './Avatar'; import Icon from './Icon'; import * as Expensicons from './Icon/Expensicons'; -import MenuItem from './MenuItem'; import type {MenuItemProps} from './MenuItem'; +import MenuItemList from './MenuItemList'; import Popover from './Popover'; import {PressableWithFeedback} from './Pressable'; import Text from './Text'; @@ -30,16 +30,15 @@ function AccountSwitcher() { const {translate} = useLocalize(); const theme = useTheme(); const {canUseNewDotCopilot} = usePermissions(); + const {isSmallScreenWidth} = useResponsiveLayout(); const [account] = useOnyx(ONYXKEYS.ACCOUNT); - const [shouldShowDelegateMenu, setShouldShowDelegateMenu] = useState(false); - const buttonRef = useRef(null); + const [shouldShowDelegatorMenu, setShouldShowDelegatorMenu] = useState(false); - const delegates = account?.delegatedAccess?.delegates ?? []; - const shouldShowDelegates = delegates.length > 0 && canUseNewDotCopilot; - const {isSmallScreenWidth} = useResponsiveLayout(); + const delegators = account?.delegatedAccess?.delegators ?? []; + const shouldShowDelegators = delegators.length > 0 && canUseNewDotCopilot; - const delegateMenuItems: MenuItemProps[] = delegates.map(({email, role}) => { + const delegatorMenuItems: MenuItemProps[] = delegators.map(({email, role}) => { const personalDetail = getPersonalDetailByEmail(email); return { @@ -57,7 +56,7 @@ function AccountSwitcher() { }; }); - const delegateMenuItemsWithCurrentUser: MenuItemProps[] = [ + const delegatorMenuItemsWithCurrentUser: MenuItemProps[] = [ { title: currentUserPersonalDetails?.displayName ?? currentUserPersonalDetails?.login, description: currentUserPersonalDetails?.displayName ? currentUserPersonalDetails?.login : '', @@ -72,7 +71,7 @@ function AccountSwitcher() { wrapperStyle: [styles.buttonDefaultBG], focused: true, }, - ...delegateMenuItems, + ...delegatorMenuItems, ]; return ( @@ -81,7 +80,7 @@ function AccountSwitcher() { accessible accessibilityLabel={translate('common.profile')} onPress={() => { - setShouldShowDelegateMenu(!shouldShowDelegateMenu); + setShouldShowDelegatorMenu(!shouldShowDelegatorMenu); }} ref={buttonRef} wrapperStyle={[styles.flexGrow1, styles.accountSwitcherWrapper, styles.justifyContentCenter]} @@ -102,7 +101,7 @@ function AccountSwitcher() { > {currentUserPersonalDetails?.displayName} - {shouldShowDelegates && ( + {shouldShowDelegators && ( - {shouldShowDelegates && ( + {shouldShowDelegators && ( setShouldShowDelegateMenu(false)} + isVisible={shouldShowDelegatorMenu} + onClose={() => setShouldShowDelegatorMenu(false)} anchorRef={buttonRef} anchorPosition={styles.accountSwitcherAnchorPosition} > {translate('delegate.switchAccount')} - {delegateMenuItemsWithCurrentUser.map((item) => ( - // eslint-disable-next-line react/jsx-props-no-spreading - - ))} + {/* TODO error handling on API error Oops something went wrong. Please try again */} From fb29be15d6bd7b467feeb960b8cb6e58aa153a26 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Wed, 14 Aug 2024 11:20:15 +0300 Subject: [PATCH 042/361] correct docs --- src/types/onyx/Account.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/types/onyx/Account.ts b/src/types/onyx/Account.ts index 3f726f9884d9..776e591de5c8 100644 --- a/src/types/onyx/Account.ts +++ b/src/types/onyx/Account.ts @@ -17,10 +17,10 @@ type Delegate = { /** Model of delegated access data */ type DelegatedAccess = { - /** The the users you can access as a delegate */ + /** The users that can access your account as a delegate */ delegates: Delegate[]; - /** The users that can access your account as a delegate */ + /** The the users you can access as a delegate */ delegators: Delegate[]; }; From 477ecb6d9e603898ec5ccca5de555756fb6fdcff Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Wed, 14 Aug 2024 11:27:34 +0300 Subject: [PATCH 043/361] single execution --- src/components/AccountSwitcher.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/components/AccountSwitcher.tsx b/src/components/AccountSwitcher.tsx index cd1fb9d894f8..4de85e9e23d8 100644 --- a/src/components/AccountSwitcher.tsx +++ b/src/components/AccountSwitcher.tsx @@ -130,7 +130,10 @@ function AccountSwitcher() { > {translate('delegate.switchAccount')} - + {/* TODO error handling on API error Oops something went wrong. Please try again */} From 46a62e40623c5ba0b30d0398f294daedf50e9eae Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Wed, 14 Aug 2024 11:28:53 +0300 Subject: [PATCH 044/361] import style --- src/components/AccountSwitcher.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/AccountSwitcher.tsx b/src/components/AccountSwitcher.tsx index 4de85e9e23d8..4de9b4c4e532 100644 --- a/src/components/AccountSwitcher.tsx +++ b/src/components/AccountSwitcher.tsx @@ -9,7 +9,7 @@ import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import {connect} from '@libs/actions/Delegate'; -import {getPersonalDetailByEmail} from '@libs/PersonalDetailsUtils'; +import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; import variables from '@styles/variables'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -39,7 +39,7 @@ function AccountSwitcher() { const shouldShowDelegators = delegators.length > 0 && canUseNewDotCopilot; const delegatorMenuItems: MenuItemProps[] = delegators.map(({email, role}) => { - const personalDetail = getPersonalDetailByEmail(email); + const personalDetail = PersonalDetailsUtils.getPersonalDetailByEmail(email); return { title: personalDetail?.displayName ?? email, From ebce5ec46b5710b47e4f12a41323e153da6fa6c1 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Wed, 14 Aug 2024 11:53:57 +0300 Subject: [PATCH 045/361] change skeleton to fit account switcher --- .../index.tsx | 25 ++++++++----------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/src/components/CurrentUserPersonalDetailsSkeletonView/index.tsx b/src/components/CurrentUserPersonalDetailsSkeletonView/index.tsx index 21e82c26f769..a41d63caeb77 100644 --- a/src/components/CurrentUserPersonalDetailsSkeletonView/index.tsx +++ b/src/components/CurrentUserPersonalDetailsSkeletonView/index.tsx @@ -23,34 +23,31 @@ function CurrentUserPersonalDetailsSkeletonView({shouldAnimate = true, avatarSiz const StyleUtils = useStyleUtils(); const avatarPlaceholderSize = StyleUtils.getAvatarSize(avatarSize); const avatarPlaceholderRadius = avatarPlaceholderSize / 2; - const spaceBetweenAvatarAndHeadline = styles.mb3.marginBottom + styles.mt1.marginTop + (variables.lineHeightXXLarge - variables.fontSizeXLarge) / 2; - const headlineSize = variables.fontSizeXLarge; - const spaceBetweenHeadlineAndLabel = styles.mt1.marginTop + (variables.lineHeightXXLarge - variables.fontSizeXLarge) / 2; - const labelSize = variables.fontSizeLabel; + return ( From 8f4b5b33f6c27394b089ca9ce347850f1dc168fc Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Wed, 14 Aug 2024 11:54:46 +0300 Subject: [PATCH 046/361] rm padding from avatar skeleton --- src/styles/index.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/styles/index.ts b/src/styles/index.ts index dd11f34e86ab..40a73f8c01dd 100644 --- a/src/styles/index.ts +++ b/src/styles/index.ts @@ -2808,8 +2808,6 @@ const styles = (theme: ThemeColors) => avatarSectionWrapperSkeleton: { width: '100%', - paddingHorizontal: 20, - paddingBottom: 20, }, avatarSectionWrapperSettings: { From 3d12f3f40842156d23c0b949023dbac11f4f00bc Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Wed, 14 Aug 2024 11:54:55 +0300 Subject: [PATCH 047/361] avatar size medium --- src/pages/settings/InitialSettingsPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/settings/InitialSettingsPage.tsx b/src/pages/settings/InitialSettingsPage.tsx index 73e3c497894a..e24491986231 100755 --- a/src/pages/settings/InitialSettingsPage.tsx +++ b/src/pages/settings/InitialSettingsPage.tsx @@ -363,7 +363,7 @@ function InitialSettingsPage({userWallet, bankAccountList, fundList, walletTerms const headerContent = ( {isEmptyObject(currentUserPersonalDetails) || currentUserPersonalDetails.displayName === undefined ? ( - + ) : ( From f0500f5e53dbb33c6e47fee943c645cab517f38a Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Wed, 14 Aug 2024 11:56:15 +0300 Subject: [PATCH 048/361] cleanup --- .../CurrentUserPersonalDetailsSkeletonView/index.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/CurrentUserPersonalDetailsSkeletonView/index.tsx b/src/components/CurrentUserPersonalDetailsSkeletonView/index.tsx index a41d63caeb77..e192a99d7b2a 100644 --- a/src/components/CurrentUserPersonalDetailsSkeletonView/index.tsx +++ b/src/components/CurrentUserPersonalDetailsSkeletonView/index.tsx @@ -6,7 +6,6 @@ import SkeletonViewContentLoader from '@components/SkeletonViewContentLoader'; import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; -import variables from '@styles/variables'; import CONST from '@src/CONST'; type CurrentUserPersonalDetailsSkeletonViewProps = { @@ -23,6 +22,7 @@ function CurrentUserPersonalDetailsSkeletonView({shouldAnimate = true, avatarSiz const StyleUtils = useStyleUtils(); const avatarPlaceholderSize = StyleUtils.getAvatarSize(avatarSize); const avatarPlaceholderRadius = avatarPlaceholderSize / 2; + const x = 30; return ( @@ -33,18 +33,18 @@ function CurrentUserPersonalDetailsSkeletonView({shouldAnimate = true, avatarSiz height={avatarPlaceholderSize + styles.pb5.paddingBottom} > Date: Wed, 14 Aug 2024 11:58:24 +0300 Subject: [PATCH 049/361] add type for delegate --- src/types/onyx/Account.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/types/onyx/Account.ts b/src/types/onyx/Account.ts index 776e591de5c8..114ea57abb81 100644 --- a/src/types/onyx/Account.ts +++ b/src/types/onyx/Account.ts @@ -22,6 +22,9 @@ type DelegatedAccess = { /** The the users you can access as a delegate */ delegators: Delegate[]; + + /** The email of original user when they are acting as a delegate for another account */ + delegate?: string; }; /** Model of user account */ From c0468bfb5cd1c659f63753844ba7e511fb0384d2 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Wed, 14 Aug 2024 12:29:31 +0300 Subject: [PATCH 050/361] add type delegate role --- src/types/onyx/Account.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/types/onyx/Account.ts b/src/types/onyx/Account.ts index 114ea57abb81..a545ed9fdfe1 100644 --- a/src/types/onyx/Account.ts +++ b/src/types/onyx/Account.ts @@ -6,13 +6,16 @@ import type * as OnyxCommon from './OnyxCommon'; /** Two factor authentication steps */ type TwoFactorAuthStep = ValueOf | ''; +/** The role of the delegate */ +type DelegateRole = ValueOf; + /** Model of delegate */ type Delegate = { /** The email of the delegate */ email: string; /** The role of the delegate */ - role: 'submitter' | 'all'; + role: DelegateRole; }; /** Model of delegated access data */ @@ -115,4 +118,4 @@ type Account = { }; export default Account; -export type {TwoFactorAuthStep}; +export type {TwoFactorAuthStep, DelegateRole}; From 41da8e80ff59a67aec1d1ec07dcebac1e2eebce5 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Wed, 14 Aug 2024 12:29:44 +0300 Subject: [PATCH 051/361] add mapping for delegate role --- src/languages/en.ts | 11 +++++++++++ src/languages/es.ts | 11 +++++++++++ 2 files changed, 22 insertions(+) diff --git a/src/languages/en.ts b/src/languages/en.ts index 41d8ffe6148b..237c58437297 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -2,6 +2,7 @@ import {CONST as COMMON_CONST, Str} from 'expensify-common'; import {startCase} from 'lodash'; import CONST from '@src/CONST'; import type {Country} from '@src/CONST'; +import type {DelegateRole} from '@src/types/onyx/Account'; import type {ConnectionName, PolicyConnectionSyncStage, SageIntacctMappingName} from '@src/types/onyx/Policy'; import type { AddressLineParams, @@ -4371,5 +4372,15 @@ export default { }, delegate: { switchAccount: 'Switch accounts:', + role: (role: DelegateRole): string => { + switch (role) { + case CONST.DELEGATE_ROLE.ALL: + return 'All'; + case CONST.DELEGATE_ROLE.SUBMITTER: + return 'Limited'; + default: + return ''; + } + }, }, } satisfies TranslationBase; diff --git a/src/languages/es.ts b/src/languages/es.ts index 55a1e2222075..941baff62cbd 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -1,5 +1,6 @@ import {Str} from 'expensify-common'; import CONST from '@src/CONST'; +import type {DelegateRole} from '@src/types/onyx/Account'; import type {ConnectionName, PolicyConnectionSyncStage, SageIntacctMappingName} from '@src/types/onyx/Policy'; import type { AddressLineParams, @@ -4891,5 +4892,15 @@ export default { }, delegate: { switchAccount: 'Cambiar cuentas:', + role: (role: DelegateRole): string => { + switch (role) { + case CONST.DELEGATE_ROLE.ALL: + return 'All'; + case CONST.DELEGATE_ROLE.SUBMITTER: + return 'Limited'; + default: + return ''; + } + }, }, } satisfies EnglishTranslation; From 4e4ff407c66d2499c909cbf8277e608730f89116 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Wed, 14 Aug 2024 12:30:00 +0300 Subject: [PATCH 052/361] move role to const --- src/CONST.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/CONST.ts b/src/CONST.ts index bad91f18dfe1..8a5dd6b50776 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -3905,6 +3905,10 @@ const CONST = { ENABLED: 'ENABLED', DISABLED: 'DISABLED', }, + DELEGATE_ROLE: { + SUBMITTER: 'submitter', + ALL: 'all', + }, STRIPE_GBP_AUTH_STATUSES: { SUCCEEDED: 'succeeded', }, From 22fb81dc8d6ec4fe2fb276076e5b9860c7a67bec Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Wed, 14 Aug 2024 12:31:47 +0300 Subject: [PATCH 053/361] show full or limited as role --- src/components/AccountSwitcher.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/AccountSwitcher.tsx b/src/components/AccountSwitcher.tsx index 4de9b4c4e532..da4160540a3a 100644 --- a/src/components/AccountSwitcher.tsx +++ b/src/components/AccountSwitcher.tsx @@ -1,4 +1,3 @@ -import {Str} from 'expensify-common'; import React, {useRef, useState} from 'react'; import {View} from 'react-native'; import {useOnyx} from 'react-native-onyx'; @@ -44,7 +43,7 @@ function AccountSwitcher() { return { title: personalDetail?.displayName ?? email, description: personalDetail?.displayName ? email : '', - badgeText: Str.recapitalize(role), + badgeText: translate('delegate.role', role), onPress: () => { connect(email); }, From 65df1c22706708c0e87303e7af0d14abcf8ee2b3 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Wed, 14 Aug 2024 12:35:23 +0300 Subject: [PATCH 054/361] show full or limited as role --- src/languages/en.ts | 2 +- src/languages/es.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/languages/en.ts b/src/languages/en.ts index 237c58437297..675e8635e77f 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -4375,7 +4375,7 @@ export default { role: (role: DelegateRole): string => { switch (role) { case CONST.DELEGATE_ROLE.ALL: - return 'All'; + return 'Full'; case CONST.DELEGATE_ROLE.SUBMITTER: return 'Limited'; default: diff --git a/src/languages/es.ts b/src/languages/es.ts index 941baff62cbd..536b73c9a806 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -4895,9 +4895,9 @@ export default { role: (role: DelegateRole): string => { switch (role) { case CONST.DELEGATE_ROLE.ALL: - return 'All'; + return 'Completo'; case CONST.DELEGATE_ROLE.SUBMITTER: - return 'Limited'; + return 'Limitado'; default: return ''; } From d43e7a87b6f821aee884eb307bcb4227448a7461 Mon Sep 17 00:00:00 2001 From: daledah Date: Wed, 14 Aug 2024 17:44:43 +0700 Subject: [PATCH 055/361] refactor: simplify failureCustomUnits --- src/libs/actions/TaxRate.ts | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/src/libs/actions/TaxRate.ts b/src/libs/actions/TaxRate.ts index decb74c1a642..29aa3c2fadff 100644 --- a/src/libs/actions/TaxRate.ts +++ b/src/libs/actions/TaxRate.ts @@ -512,27 +512,7 @@ function setPolicyTaxCode(policyID: string, oldTaxCode: string, newTaxCode: stri }, }; const failureCustomUnit = { - customUnits: { - ...customUnits.reduce((units, customUnit) => { - // eslint-disable-next-line no-param-reassign - units[customUnit.customUnitID] = { - rates: { - ...Object.keys(customUnit.rates).reduce((rates, rateID) => { - if (customUnit.rates[rateID].attributes?.taxRateExternalID === oldTaxCode) { - // eslint-disable-next-line no-param-reassign - rates[rateID] = { - attributes: { - taxRateExternalID: oldTaxCode, - }, - }; - } - return rates; - }, {} as Record), - }, - }; - return units; - }, {} as Record>), - }, + customUnits: policy?.customUnits, }; const onyxData: OnyxData = { optimisticData: [ From 4a30ea6af49f6415e4490055319815c8deb2cabf Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Wed, 14 Aug 2024 15:51:08 +0300 Subject: [PATCH 056/361] add error msg to translate --- src/languages/en.ts | 1 + src/languages/es.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/src/languages/en.ts b/src/languages/en.ts index 675e8635e77f..4ce7cf9fa814 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -4382,5 +4382,6 @@ export default { return ''; } }, + genericError: 'Oops something went wrong. Please try again.', }, } satisfies TranslationBase; diff --git a/src/languages/es.ts b/src/languages/es.ts index 536b73c9a806..6feee19b5235 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -4902,5 +4902,6 @@ export default { return ''; } }, + genericError: 'Oops algo salió mal. Por favor, inténtalo de nuevo.', }, } satisfies EnglishTranslation; From 19f2501212f758904eb0bcc91a671579af60c546 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Wed, 14 Aug 2024 15:51:37 +0300 Subject: [PATCH 057/361] show error message in account switcher --- src/components/AccountSwitcher.tsx | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/components/AccountSwitcher.tsx b/src/components/AccountSwitcher.tsx index da4160540a3a..02929c133f39 100644 --- a/src/components/AccountSwitcher.tsx +++ b/src/components/AccountSwitcher.tsx @@ -37,21 +37,23 @@ function AccountSwitcher() { const delegators = account?.delegatedAccess?.delegators ?? []; const shouldShowDelegators = delegators.length > 0 && canUseNewDotCopilot; - const delegatorMenuItems: MenuItemProps[] = delegators.map(({email, role}) => { + const delegatorMenuItems: MenuItemProps[] = delegators.map(({email, role, error}) => { const personalDetail = PersonalDetailsUtils.getPersonalDetailByEmail(email); - return { title: personalDetail?.displayName ?? email, description: personalDetail?.displayName ? email : '', badgeText: translate('delegate.role', role), onPress: () => { - connect(email); + connect(email, role); }, avatarID: personalDetail?.accountID ?? -1, icon: personalDetail?.avatar ?? '', iconType: CONST.ICON_TYPE_AVATAR, outerWrapperStyle: isSmallScreenWidth ? {} : styles.accountSwitcherPopover, numberOfLinesDescription: 1, + errorText: error ? translate(error) : '', + shouldShowRedDotIndicator: !!error, + errorTextStyle: styles.mt2, }; }); @@ -133,7 +135,6 @@ function AccountSwitcher() { menuItems={delegatorMenuItemsWithCurrentUser} shouldUseSingleExecution /> - {/* TODO error handling on API error Oops something went wrong. Please try again */} )} From 97e581d886b92a1a10bd970f124a3b1d2c078a22 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Wed, 14 Aug 2024 15:52:18 +0300 Subject: [PATCH 058/361] add onyx data to handle errors --- src/libs/actions/Delegate.ts | 64 ++++++++++++++++++++++++++++++++---- 1 file changed, 58 insertions(+), 6 deletions(-) diff --git a/src/libs/actions/Delegate.ts b/src/libs/actions/Delegate.ts index 2a3295a9dfd5..107ee41d5afe 100644 --- a/src/libs/actions/Delegate.ts +++ b/src/libs/actions/Delegate.ts @@ -1,18 +1,70 @@ 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 Log from '@libs/Log'; import * as NetworkStore from '@libs/Network/NetworkStore'; import * as SequentialQueue from '@libs/Network/SequentialQueue'; +import ONYXKEYS from '@src/ONYXKEYS'; +import type {DelegatedAccess, DelegateRole} from '@src/types/onyx/Account'; import {openApp} from './App'; import updateSessionAuthTokens from './Session/updateSessionAuthTokens'; -function connect(email: string) { +let delegatedAccess: DelegatedAccess; +Onyx.connect({ + key: ONYXKEYS.ACCOUNT, + callback: (val) => { + delegatedAccess = val?.delegatedAccess ?? {}; + }, +}); + +function connect(email: string, role: DelegateRole) { + if (!delegatedAccess?.delegators) { + return; + } + + const optimisticData: OnyxUpdate[] = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.ACCOUNT, + value: { + delegatedAccess: { + delegators: delegatedAccess.delegators.map((delegator) => (delegator.email === email ? {email, role, error: undefined} : delegator)), + }, + }, + }, + ]; + + const successData: OnyxUpdate[] = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.ACCOUNT, + value: { + delegatedAccess: { + delegators: delegatedAccess.delegators.map((delegator) => (delegator.email === email ? {email, role, error: undefined} : delegator)), + }, + }, + }, + ]; + + const failureData: OnyxUpdate[] = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.ACCOUNT, + value: { + delegatedAccess: { + delegators: delegatedAccess.delegators.map((delegator) => (delegator.email === email ? {email, role, error: 'delegate.genericError'} : delegator)), + }, + }, + }, + ]; + // eslint-disable-next-line rulesdir/no-api-side-effects-method - API.makeRequestWithSideEffects(SIDE_EFFECT_REQUEST_COMMANDS.CONNECT_AS_DELEGATE, {to: email}, {}) + API.makeRequestWithSideEffects(SIDE_EFFECT_REQUEST_COMMANDS.CONNECT_AS_DELEGATE, {to: email}, {optimisticData, successData, failureData}) .then((response) => { if (!response?.restrictedToken || !response?.encryptedAuthToken) { - // TODO: Show an error message to the user - console.error('Error during connect: No authToken returned'); + Log.alert('[Delegate] No auth token returned while connecting as a delegate'); + Onyx.update(failureData); return; } return SequentialQueue.waitForIdle() @@ -26,8 +78,8 @@ function connect(email: string) { }); }) .catch((error) => { - // TODO: Show an error message to the user - console.error('Error during connect:', error); + Log.alert('[Delegate] Error connecting as delegate', {error}); + Onyx.update(failureData); }); } From 313e8e9cd93efbec07a60beeef04faad45ee2a6e Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Wed, 14 Aug 2024 15:53:42 +0300 Subject: [PATCH 059/361] add error type --- src/types/onyx/Account.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/types/onyx/Account.ts b/src/types/onyx/Account.ts index a545ed9fdfe1..e1356e7e6135 100644 --- a/src/types/onyx/Account.ts +++ b/src/types/onyx/Account.ts @@ -1,5 +1,6 @@ import type {ValueOf} from 'type-fest'; import type CONST from '@src/CONST'; +import type {TranslationPaths} from '@src/languages/types'; import type DismissedReferralBanners from './DismissedReferralBanners'; import type * as OnyxCommon from './OnyxCommon'; @@ -16,15 +17,18 @@ type Delegate = { /** The role of the delegate */ role: DelegateRole; + + /** Authentication failure errors */ + error?: TranslationPaths; }; /** Model of delegated access data */ type DelegatedAccess = { /** The users that can access your account as a delegate */ - delegates: Delegate[]; + delegates?: Delegate[]; /** The the users you can access as a delegate */ - delegators: Delegate[]; + delegators?: Delegate[]; /** The email of original user when they are acting as a delegate for another account */ delegate?: string; @@ -118,4 +122,4 @@ type Account = { }; export default Account; -export type {TwoFactorAuthStep, DelegateRole}; +export type {TwoFactorAuthStep, DelegateRole, DelegatedAccess}; From 91f2ecf27844acb84c8091b379130ce0af97547e Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Wed, 14 Aug 2024 16:03:29 +0300 Subject: [PATCH 060/361] clear errors after closing popover --- src/components/AccountSwitcher.tsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/components/AccountSwitcher.tsx b/src/components/AccountSwitcher.tsx index 02929c133f39..b42e9a9a5826 100644 --- a/src/components/AccountSwitcher.tsx +++ b/src/components/AccountSwitcher.tsx @@ -7,7 +7,7 @@ import usePermissions from '@hooks/usePermissions'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; -import {connect} from '@libs/actions/Delegate'; +import {clearDelegatorErrors, connect} from '@libs/actions/Delegate'; import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; import variables from '@styles/variables'; import CONST from '@src/CONST'; @@ -44,7 +44,7 @@ function AccountSwitcher() { description: personalDetail?.displayName ? email : '', badgeText: translate('delegate.role', role), onPress: () => { - connect(email, role); + connect(email); }, avatarID: personalDetail?.accountID ?? -1, icon: personalDetail?.avatar ?? '', @@ -125,7 +125,10 @@ function AccountSwitcher() { {shouldShowDelegators && ( setShouldShowDelegatorMenu(false)} + onClose={() => { + setShouldShowDelegatorMenu(false); + clearDelegatorErrors(); + }} anchorRef={buttonRef} anchorPosition={styles.accountSwitcherAnchorPosition} > From ba51bba5cd046d60210ecdc37b3de925527bef97 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Wed, 14 Aug 2024 16:03:45 +0300 Subject: [PATCH 061/361] add func to clear errors --- src/libs/actions/Delegate.ts | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/libs/actions/Delegate.ts b/src/libs/actions/Delegate.ts index 107ee41d5afe..8f7654f4f1ca 100644 --- a/src/libs/actions/Delegate.ts +++ b/src/libs/actions/Delegate.ts @@ -18,7 +18,7 @@ Onyx.connect({ }, }); -function connect(email: string, role: DelegateRole) { +function connect(email: string) { if (!delegatedAccess?.delegators) { return; } @@ -29,7 +29,7 @@ function connect(email: string, role: DelegateRole) { key: ONYXKEYS.ACCOUNT, value: { delegatedAccess: { - delegators: delegatedAccess.delegators.map((delegator) => (delegator.email === email ? {email, role, error: undefined} : delegator)), + delegators: delegatedAccess.delegators.map((delegator) => (delegator.email === email ? {...delegator, error: undefined} : delegator)), }, }, }, @@ -41,7 +41,7 @@ function connect(email: string, role: DelegateRole) { key: ONYXKEYS.ACCOUNT, value: { delegatedAccess: { - delegators: delegatedAccess.delegators.map((delegator) => (delegator.email === email ? {email, role, error: undefined} : delegator)), + delegators: delegatedAccess.delegators.map((delegator) => (delegator.email === email ? {...delegator, error: undefined} : delegator)), }, }, }, @@ -53,7 +53,7 @@ function connect(email: string, role: DelegateRole) { key: ONYXKEYS.ACCOUNT, value: { delegatedAccess: { - delegators: delegatedAccess.delegators.map((delegator) => (delegator.email === email ? {email, role, error: 'delegate.genericError'} : delegator)), + delegators: delegatedAccess.delegators.map((delegator) => (delegator.email === email ? {...delegator, error: 'delegate.genericError'} : delegator)), }, }, }, @@ -83,5 +83,12 @@ function connect(email: string, role: DelegateRole) { }); } +function clearDelegatorErrors() { + if (!delegatedAccess?.delegators) { + return; + } + Onyx.merge(ONYXKEYS.ACCOUNT, {delegatedAccess: {delegators: delegatedAccess.delegators.map((delegator) => ({...delegator, error: undefined}))}}); +} + // eslint-disable-next-line import/prefer-default-export -export {connect}; +export {connect, clearDelegatorErrors}; From 0576180fb180fe0a9597ec6a61476281a42d2ec0 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Wed, 14 Aug 2024 16:06:09 +0300 Subject: [PATCH 062/361] 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 8f7654f4f1ca..8a66a537f27a 100644 --- a/src/libs/actions/Delegate.ts +++ b/src/libs/actions/Delegate.ts @@ -6,7 +6,7 @@ import Log from '@libs/Log'; import * as NetworkStore from '@libs/Network/NetworkStore'; import * as SequentialQueue from '@libs/Network/SequentialQueue'; import ONYXKEYS from '@src/ONYXKEYS'; -import type {DelegatedAccess, DelegateRole} from '@src/types/onyx/Account'; +import type {DelegatedAccess} from '@src/types/onyx/Account'; import {openApp} from './App'; import updateSessionAuthTokens from './Session/updateSessionAuthTokens'; From 0312b7cb797c298f227224c9adb450ea198c5b70 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Wed, 14 Aug 2024 16:24:08 +0300 Subject: [PATCH 063/361] add min width 0 --- src/styles/utils/sizing.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/styles/utils/sizing.ts b/src/styles/utils/sizing.ts index 8d75294564b8..f4be70391eb5 100644 --- a/src/styles/utils/sizing.ts +++ b/src/styles/utils/sizing.ts @@ -52,6 +52,10 @@ export default { minHeight: 0, }, + mnw0: { + minWidth: 0, + }, + mnw2: { minWidth: 8, }, From f2da059c9246090984307c6cfba599f03958e8f1 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Wed, 14 Aug 2024 16:24:18 +0300 Subject: [PATCH 064/361] cleanup --- src/components/AccountSwitcher.tsx | 2 +- src/styles/index.ts | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/components/AccountSwitcher.tsx b/src/components/AccountSwitcher.tsx index b42e9a9a5826..f4533f292acc 100644 --- a/src/components/AccountSwitcher.tsx +++ b/src/components/AccountSwitcher.tsx @@ -84,7 +84,7 @@ function AccountSwitcher() { setShouldShowDelegatorMenu(!shouldShowDelegatorMenu); }} ref={buttonRef} - wrapperStyle={[styles.flexGrow1, styles.accountSwitcherWrapper, styles.justifyContentCenter]} + wrapperStyle={[styles.flexGrow1, styles.flex1, styles.mnw0, styles.justifyContentCenter]} > backgroundColor: theme.border, }, - accountSwitcherWrapper: { - minWidth: 0, - flex: 1, - }, - accountSwitcherPopover: { width: variables.sideBarWidth - 19, }, From 964fdd536f1c6342b2b2b80cc182d3c7baa550bf Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Thu, 15 Aug 2024 05:34:23 +0300 Subject: [PATCH 065/361] preserve keys for copilot --- 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 8a66a537f27a..f33ea5d46630 100644 --- a/src/libs/actions/Delegate.ts +++ b/src/libs/actions/Delegate.ts @@ -68,7 +68,7 @@ function connect(email: string) { return; } return SequentialQueue.waitForIdle() - .then(() => Onyx.clear()) + .then(() => Onyx.clear([ONYXKEYS.NVP_TRY_FOCUS_MODE, ONYXKEYS.PREFERRED_THEME, ONYXKEYS.NVP_PREFERRED_LOCALE, ONYXKEYS.SESSION])) .then(() => { // Update authToken in Onyx and in our local variables so that API requests will use the new authToken updateSessionAuthTokens(response?.restrictedToken, response?.encryptedAuthToken); From c38d79882f0b32a49ed29ce4140152f0da082b8f Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Thu, 15 Aug 2024 05:36:21 +0300 Subject: [PATCH 066/361] move to const --- src/libs/actions/Delegate.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libs/actions/Delegate.ts b/src/libs/actions/Delegate.ts index f33ea5d46630..7eaaee798be5 100644 --- a/src/libs/actions/Delegate.ts +++ b/src/libs/actions/Delegate.ts @@ -18,6 +18,8 @@ Onyx.connect({ }, }); +const KEYS_TO_PRESERVE_DELEGATE_ACCESS = [ONYXKEYS.NVP_TRY_FOCUS_MODE, ONYXKEYS.PREFERRED_THEME, ONYXKEYS.NVP_PREFERRED_LOCALE, ONYXKEYS.SESSION]; + function connect(email: string) { if (!delegatedAccess?.delegators) { return; @@ -68,7 +70,7 @@ function connect(email: string) { return; } return SequentialQueue.waitForIdle() - .then(() => Onyx.clear([ONYXKEYS.NVP_TRY_FOCUS_MODE, ONYXKEYS.PREFERRED_THEME, ONYXKEYS.NVP_PREFERRED_LOCALE, ONYXKEYS.SESSION])) + .then(() => Onyx.clear(KEYS_TO_PRESERVE_DELEGATE_ACCESS)) .then(() => { // Update authToken in Onyx and in our local variables so that API requests will use the new authToken updateSessionAuthTokens(response?.restrictedToken, response?.encryptedAuthToken); From 907d57af3449d137ed13725c8d9841a7321eedc5 Mon Sep 17 00:00:00 2001 From: daledah Date: Thu, 15 Aug 2024 11:06:50 +0700 Subject: [PATCH 067/361] fix: remove settled transactions from duplicates --- .../MoneyRequestPreview/MoneyRequestPreviewContent.tsx | 10 ++++++---- src/libs/ReportUtils.ts | 5 +++++ src/libs/TransactionUtils/index.ts | 5 +++-- src/pages/TransactionDuplicate/Review.tsx | 4 ++++ 4 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx b/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx index 8597654576fc..df463acc12c9 100644 --- a/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx +++ b/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx @@ -125,9 +125,11 @@ function MoneyRequestPreviewContent({ // Get transaction violations for given transaction id from onyx, find duplicated transactions violations and get duplicates const duplicates = useMemo( () => - transactionViolations?.[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transaction?.transactionID}`]?.find( - (violation) => violation.name === CONST.VIOLATIONS.DUPLICATED_TRANSACTION, - )?.data?.duplicates ?? [], + ReportUtils.removeSettledTransactions( + transactionViolations?.[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transaction?.transactionID}`]?.find( + (violation) => violation.name === CONST.VIOLATIONS.DUPLICATED_TRANSACTION, + )?.data?.duplicates ?? [], + ), [transaction?.transactionID, transactionViolations], ); @@ -438,7 +440,7 @@ function MoneyRequestPreviewContent({ ]} > {childContainer} - {isReviewDuplicateTransactionPage && ( + {isReviewDuplicateTransactionPage && !isSettled && (