From 71e6a2fd7d2f3489d9531246718ffae07e6d14ab Mon Sep 17 00:00:00 2001 From: Jakub Butkiewicz Date: Mon, 25 Sep 2023 16:13:49 +0200 Subject: [PATCH 001/227] ref: move LocalNotification to TS --- ...tifications.js => BrowserNotifications.ts} | 44 ++++++------------- .../{index.desktop.js => index.desktop.ts} | 5 ++- .../LocalNotification/focusApp/index.ts | 6 +++ .../focusApp/index.website.js | 2 - .../LocalNotification/focusApp/types.ts | 3 ++ .../{index.desktop.js => index.desktop.ts} | 8 ++-- .../{index.native.js => index.native.ts} | 0 .../{index.website.js => index.ts} | 7 ++- .../Notification/LocalNotification/types.ts | 24 ++++++++++ 9 files changed, 61 insertions(+), 38 deletions(-) rename src/libs/Notification/LocalNotification/{BrowserNotifications.js => BrowserNotifications.ts} (77%) rename src/libs/Notification/LocalNotification/focusApp/{index.desktop.js => index.desktop.ts} (59%) create mode 100644 src/libs/Notification/LocalNotification/focusApp/index.ts delete mode 100644 src/libs/Notification/LocalNotification/focusApp/index.website.js create mode 100644 src/libs/Notification/LocalNotification/focusApp/types.ts rename src/libs/Notification/LocalNotification/{index.desktop.js => index.desktop.ts} (57%) rename src/libs/Notification/LocalNotification/{index.native.js => index.native.ts} (100%) rename src/libs/Notification/LocalNotification/{index.website.js => index.ts} (68%) create mode 100644 src/libs/Notification/LocalNotification/types.ts diff --git a/src/libs/Notification/LocalNotification/BrowserNotifications.js b/src/libs/Notification/LocalNotification/BrowserNotifications.ts similarity index 77% rename from src/libs/Notification/LocalNotification/BrowserNotifications.js rename to src/libs/Notification/LocalNotification/BrowserNotifications.ts index e55c0430fe17..fcf795c6769c 100644 --- a/src/libs/Notification/LocalNotification/BrowserNotifications.js +++ b/src/libs/Notification/LocalNotification/BrowserNotifications.ts @@ -1,18 +1,16 @@ // Web and desktop implementation only. Do not import for direct use. Use LocalNotification. -import _ from 'underscore'; -import focusApp from './focusApp'; import * as AppUpdate from '../../actions/AppUpdate'; import EXPENSIFY_ICON_URL from '../../../../assets/images/expensify-logo-round-clearspace.png'; import * as ReportUtils from '../../ReportUtils'; +import {PushParams, ReportCommentParams} from './types'; +import focusApp from './focusApp'; const DEFAULT_DELAY = 4000; /** * Checks if the user has granted permission to show browser notifications - * - * @return {Promise} */ -function canUseBrowserNotifications() { +function canUseBrowserNotifications(): Promise { return new Promise((resolve) => { // They have no browser notifications so we can't use this feature if (!window.Notification) { @@ -36,18 +34,9 @@ function canUseBrowserNotifications() { /** * Light abstraction around browser push notifications. * Checks for permission before determining whether to send. - * - * @param {Object} params - * @param {String} params.title - * @param {String} params.body - * @param {String} [params.icon] Path to icon - * @param {Number} [params.delay] - * @param {Function} [params.onClick] - * @param {String} [params.tag] - * - * @return {Promise} - resolves with Notification object or undefined + * @return resolves with Notification object or undefined */ -function push({title, body, delay = DEFAULT_DELAY, onClick = () => {}, tag = '', icon}) { +function push({title, body, delay = DEFAULT_DELAY, onClick = () => {}, tag = '', icon}: PushParams): Promise { return new Promise((resolve) => { if (!title || !body) { throw new Error('BrowserNotification must include title and body parameter.'); @@ -62,7 +51,7 @@ function push({title, body, delay = DEFAULT_DELAY, onClick = () => {}, tag = '', const notification = new Notification(title, { body, tag, - icon, + icon: String(icon), }); // If we pass in a delay param greater than 0 the notification @@ -91,27 +80,22 @@ function push({title, body, delay = DEFAULT_DELAY, onClick = () => {}, tag = '', export default { /** * Create a report comment notification - * - * @param {Object} params - * @param {Object} params.report - * @param {Object} params.reportAction - * @param {Function} params.onClick - * @param {Boolean} usesIcon true if notification uses right circular icon + * @param usesIcon true if notification uses right circular icon */ - pushReportCommentNotification({report, reportAction, onClick}, usesIcon = false) { - let title; - let body; + pushReportCommentNotification({report, reportAction, onClick}: ReportCommentParams, usesIcon = false) { + let title: string | undefined; + let body: string | undefined; const isChatRoom = ReportUtils.isChatRoom(report); const {person, message} = reportAction; - const plainTextPerson = _.map(person, (f) => f.text).join(); + const plainTextPerson = person?.map((f) => f.text).join(); // Specifically target the comment part of the message - const plainTextMessage = (_.find(message, (f) => f.type === 'COMMENT') || {}).text; + const plainTextMessage = message?.find((f) => f.type === 'COMMENT')?.text; if (isChatRoom) { - const roomName = _.get(report, 'displayName', ''); + const roomName = report.displayName ?? ''; title = roomName; body = `${plainTextPerson}: ${plainTextMessage}`; } else { @@ -120,7 +104,7 @@ export default { } push({ - title, + title: title ?? '', body, delay: 0, onClick, diff --git a/src/libs/Notification/LocalNotification/focusApp/index.desktop.js b/src/libs/Notification/LocalNotification/focusApp/index.desktop.ts similarity index 59% rename from src/libs/Notification/LocalNotification/focusApp/index.desktop.js rename to src/libs/Notification/LocalNotification/focusApp/index.desktop.ts index f00c72dc1af8..2b6f01457f44 100644 --- a/src/libs/Notification/LocalNotification/focusApp/index.desktop.js +++ b/src/libs/Notification/LocalNotification/focusApp/index.desktop.ts @@ -1,5 +1,8 @@ import ELECTRON_EVENTS from '../../../../../desktop/ELECTRON_EVENTS'; +import FocusApp from './types'; -export default () => { +const focusApp: FocusApp = () => { window.electron.send(ELECTRON_EVENTS.REQUEST_FOCUS_APP); }; + +export default focusApp; diff --git a/src/libs/Notification/LocalNotification/focusApp/index.ts b/src/libs/Notification/LocalNotification/focusApp/index.ts new file mode 100644 index 000000000000..8504fde1bcb2 --- /dev/null +++ b/src/libs/Notification/LocalNotification/focusApp/index.ts @@ -0,0 +1,6 @@ +import FocusApp from './types'; + +// On web this is up to the browser that shows the notifications +const focusApp: FocusApp = () => {}; + +export default focusApp; diff --git a/src/libs/Notification/LocalNotification/focusApp/index.website.js b/src/libs/Notification/LocalNotification/focusApp/index.website.js deleted file mode 100644 index ce7439d94cc3..000000000000 --- a/src/libs/Notification/LocalNotification/focusApp/index.website.js +++ /dev/null @@ -1,2 +0,0 @@ -// On web this is up to the browser that shows the notifications -export default () => {}; diff --git a/src/libs/Notification/LocalNotification/focusApp/types.ts b/src/libs/Notification/LocalNotification/focusApp/types.ts new file mode 100644 index 000000000000..534b7500fc71 --- /dev/null +++ b/src/libs/Notification/LocalNotification/focusApp/types.ts @@ -0,0 +1,3 @@ +type FocusApp = () => void; + +export default FocusApp; diff --git a/src/libs/Notification/LocalNotification/index.desktop.js b/src/libs/Notification/LocalNotification/index.desktop.ts similarity index 57% rename from src/libs/Notification/LocalNotification/index.desktop.js rename to src/libs/Notification/LocalNotification/index.desktop.ts index 2bef51cea0a6..acc3b8857c0f 100644 --- a/src/libs/Notification/LocalNotification/index.desktop.js +++ b/src/libs/Notification/LocalNotification/index.desktop.ts @@ -1,6 +1,7 @@ -import BrowserNotifications from './BrowserNotifications'; +import BrowserNotifications from './BrowserNotifications.js'; +import {LocalNotificationModule, ReportCommentParams} from './types.js'; -function showCommentNotification({report, reportAction, onClick}) { +function showCommentNotification({report, reportAction, onClick}: ReportCommentParams) { BrowserNotifications.pushReportCommentNotification({report, reportAction, onClick}); } @@ -8,7 +9,8 @@ function showUpdateAvailableNotification() { BrowserNotifications.pushUpdateAvailableNotification(); } -export default { +const LocalNotification: LocalNotificationModule = { showCommentNotification, showUpdateAvailableNotification, }; +export default LocalNotification; diff --git a/src/libs/Notification/LocalNotification/index.native.js b/src/libs/Notification/LocalNotification/index.native.ts similarity index 100% rename from src/libs/Notification/LocalNotification/index.native.js rename to src/libs/Notification/LocalNotification/index.native.ts diff --git a/src/libs/Notification/LocalNotification/index.website.js b/src/libs/Notification/LocalNotification/index.ts similarity index 68% rename from src/libs/Notification/LocalNotification/index.website.js rename to src/libs/Notification/LocalNotification/index.ts index 3410b3144caf..c0182d156d46 100644 --- a/src/libs/Notification/LocalNotification/index.website.js +++ b/src/libs/Notification/LocalNotification/index.ts @@ -1,6 +1,7 @@ import BrowserNotifications from './BrowserNotifications'; +import {LocalNotificationModule, ReportCommentParams} from './types'; -function showCommentNotification({report, reportAction, onClick}) { +function showCommentNotification({report, reportAction, onClick}: ReportCommentParams) { BrowserNotifications.pushReportCommentNotification({report, reportAction, onClick}, true); } @@ -8,7 +9,9 @@ function showUpdateAvailableNotification() { BrowserNotifications.pushUpdateAvailableNotification(); } -export default { +const LocalNotification: LocalNotificationModule = { showCommentNotification, showUpdateAvailableNotification, }; + +export default LocalNotification; diff --git a/src/libs/Notification/LocalNotification/types.ts b/src/libs/Notification/LocalNotification/types.ts new file mode 100644 index 000000000000..576297467155 --- /dev/null +++ b/src/libs/Notification/LocalNotification/types.ts @@ -0,0 +1,24 @@ +import {ImageSourcePropType} from 'react-native'; +import {ReportAction, Report} from '../../../types/onyx'; + +type PushParams = { + title: string; + body?: string; + icon?: string | ImageSourcePropType; + delay?: number; + onClick?: () => void; + tag?: string; +}; + +type ReportCommentParams = { + report: Report; + reportAction: ReportAction; + onClick: () => void; +}; + +type LocalNotificationModule = { + showCommentNotification: (reportCommentParams: ReportCommentParams) => void; + showUpdateAvailableNotification: () => void; +}; + +export type {PushParams, ReportCommentParams, LocalNotificationModule}; From 400156a0a29e04433fe830bab235a6c08f0e3fe7 Mon Sep 17 00:00:00 2001 From: Nikki Wines Date: Fri, 13 Oct 2023 11:57:50 +0900 Subject: [PATCH 002/227] add native view for SAML SignInPage --- .../signin/SAMLSignInPage/index.native.js | 44 +++++++++++++++++++ src/pages/signin/SignInPage.js | 12 ++--- 2 files changed, 47 insertions(+), 9 deletions(-) create mode 100644 src/pages/signin/SAMLSignInPage/index.native.js diff --git a/src/pages/signin/SAMLSignInPage/index.native.js b/src/pages/signin/SAMLSignInPage/index.native.js new file mode 100644 index 000000000000..c4b0ae78bc30 --- /dev/null +++ b/src/pages/signin/SAMLSignInPage/index.native.js @@ -0,0 +1,44 @@ +import React, {useEffect, useRef} from 'react'; +import {withOnyx} from 'react-native-onyx'; +import PropTypes from 'prop-types'; +import ONYXKEYS from '../../../ONYXKEYS'; +import CONFIG from '../../../CONFIG'; +import WebView from 'react-native-webview'; +import FullScreenLoadingIndicator from '../../../components/FullscreenLoadingIndicator'; + +const propTypes = { + /** The credentials of the logged in person */ + credentials: PropTypes.shape({ + /** The email/phone the user logged in with */ + login: PropTypes.string, + }), +}; + +const defaultProps = { + credentials: {}, +}; + +const renderLoading = () => ; + +function SAMLSignInPage({credentials}) { + const webViewRef = useRef(); + const samlLoginURL = `${CONFIG.EXPENSIFY.SAML_URL}?email=${credentials.login}&referer=${CONFIG.EXPENSIFY.EXPENSIFY_CASH_REFERER}`; + return ( + {console.log("meep meep navigation changed: " + JSON.stringify(ref))}} + /> + ); +} + +SAMLSignInPage.propTypes = propTypes; +SAMLSignInPage.defaultProps = defaultProps; + +export default withOnyx({ + credentials: {key: ONYXKEYS.CREDENTIALS}, +})(SAMLSignInPage); diff --git a/src/pages/signin/SignInPage.js b/src/pages/signin/SignInPage.js index 7da41e2ab474..81abbdb9d1ae 100644 --- a/src/pages/signin/SignInPage.js +++ b/src/pages/signin/SignInPage.js @@ -96,15 +96,9 @@ function getRenderOptions({hasLogin, hasValidateCode, account, isPrimaryLogin, i const isSAMLRequired = Boolean(account.isSAMLRequired); const hasEmailDeliveryFailure = Boolean(account.hasEmailDeliveryFailure); - // SAML is temporarily restricted to users on the beta or to users signing in on web and mweb - let shouldShowChooseSSOOrMagicCode = false; - let shouldInitiateSAMLLogin = false; - const platform = getPlatform(); - if (Permissions.canUseSAML() || platform === CONST.PLATFORM.WEB || platform === CONST.PLATFORM.DESKTOP) { - // True if the user has SAML required and we're not already loading their account - shouldInitiateSAMLLogin = hasAccount && hasLogin && isSAMLRequired && !hasInitiatedSAMLLogin && account.isLoading; - shouldShowChooseSSOOrMagicCode = hasAccount && hasLogin && isSAMLEnabled && !isSAMLRequired && !isUsingMagicCode; - } + // True if the user has SAML required and we're not already loading their account + const shouldInitiateSAMLLogin = hasAccount && hasLogin && isSAMLRequired && !hasInitiatedSAMLLogin && account.isLoading; + const shouldShowChooseSSOOrMagicCode = hasAccount && hasLogin && isSAMLEnabled && !isSAMLRequired && !isUsingMagicCode; // SAML required users may reload the login page after having already entered their login details, in which // case we want to clear their sign in data so they don't end up in an infinite loop redirecting back to their From 8991e7ef264595e150ed631c8e733291ec213be1 Mon Sep 17 00:00:00 2001 From: Nikki Wines Date: Fri, 13 Oct 2023 20:18:43 +0900 Subject: [PATCH 003/227] log in with shortlivedtoken when one is returned --- .../signin/SAMLSignInPage/index.native.js | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/pages/signin/SAMLSignInPage/index.native.js b/src/pages/signin/SAMLSignInPage/index.native.js index c4b0ae78bc30..3825cca0fa97 100644 --- a/src/pages/signin/SAMLSignInPage/index.native.js +++ b/src/pages/signin/SAMLSignInPage/index.native.js @@ -1,10 +1,11 @@ -import React, {useEffect, useRef} from 'react'; +import React, {useCallback, useRef} from 'react'; import {withOnyx} from 'react-native-onyx'; import PropTypes from 'prop-types'; import ONYXKEYS from '../../../ONYXKEYS'; import CONFIG from '../../../CONFIG'; import WebView from 'react-native-webview'; import FullScreenLoadingIndicator from '../../../components/FullscreenLoadingIndicator'; +import * as Session from '../../../libs/actions/Session'; const propTypes = { /** The credentials of the logged in person */ @@ -23,6 +24,24 @@ const renderLoading = () => ; function SAMLSignInPage({credentials}) { const webViewRef = useRef(); const samlLoginURL = `${CONFIG.EXPENSIFY.SAML_URL}?email=${credentials.login}&referer=${CONFIG.EXPENSIFY.EXPENSIFY_CASH_REFERER}`; + + /** + * Handles in-app navigation once we get a response back from Expensify + * + * @param {String} params.type + * @param {String} params.url + */ + const handleNavigationStateChange = useCallback( + ({type, url}) => { + const searchParams = new URLSearchParams(new URL(url).search); + if (searchParams.has('shortLivedAuthToken')) { + const shortLivedAuthToken = searchParams.get('shortLivedAuthToken'); + Session.signInWithShortLivedAuthToken(credentials.login, shortLivedAuthToken); + return; + } + }, + [webViewRef], + ); return ( {console.log("meep meep navigation changed: " + JSON.stringify(ref))}} + onNavigationStateChange={handleNavigationStateChange} /> ); } From 8386979f78ee4b0e3e3e6ebb6c315f1b3e871106 Mon Sep 17 00:00:00 2001 From: David Cardoza Date: Fri, 20 Oct 2023 13:42:47 +0800 Subject: [PATCH 004/227] Create Partner-Billing-Guide https://github.com/Expensify/Expensify/issues/318124 --- .../Partner-Billing-Guide | 89 +++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 docs/articles/expensify-classic/expensify-partner-program/Partner-Billing-Guide diff --git a/docs/articles/expensify-classic/expensify-partner-program/Partner-Billing-Guide b/docs/articles/expensify-classic/expensify-partner-program/Partner-Billing-Guide new file mode 100644 index 000000000000..f87cdc974cc7 --- /dev/null +++ b/docs/articles/expensify-classic/expensify-partner-program/Partner-Billing-Guide @@ -0,0 +1,89 @@ +--- +title: Partner Billing Guide +description: Understand how Expensify bills partners and their clients +--- + +# Overview + +The ExpensifyApproved! Partner Program offers exclusive billing rates and features tailored for accountants to ensure seamless client management. If you are an accountant or consultant who recommends spend management solutions to your clients, becoming an ExpensifyApproved! Accountant may be a great certification for you. This guide will walk you through the unique billing perks available to ExpensifyApproved! partners, emphasizing the importance of understanding and managing client billing effectively. To learn what perks partners receive, check out the ExpensifyApproved! program details here. + +# Get exclusive partner pricing + +All ExpensifyApproved! Partners are automatically eligible for a special rate of $9/seat monthly, without an annual commitment when they adopt the Expensify Card. This provides flexibility as active users can vary. Here are the specifics on pricing for our Approved! Partners’ clients: +- **Bundled pricing:** US Clients using the Expensify Card get up to a 50% discount, bringing their monthly bill to $9/seat. Reach out to your Partner Manager to discuss exclusive international pricing discount.s +- **Unbundled pricing (or pay-per-use pricing):** Clients not using the Expensify Card are billed at $18/seat monthly. +- **No annual commitment:** Partners pay only for what they use, with no annual subscriptions required. +- **Expensify Card revenue share:** All partners receive a 0.5% revenue share on Expensify Card transactions made by clients. This revenue share can be passed back to the client for an additional discount to offset their Expensify bill + +# Understanding the billing process + +Expensify bills the owner of the expense policy for the activity on that policy. If accountants retain ownership of client policies, they receive the bill and can then re-bill their clients based on individual agreements. + +Each month, Expensify will send a consolidated bill detailing: +- **Pay-per-use seats:** This is the number of active clients and their users for the month. +- **Expensify Card discount**: This amount reflects how much spend is put on your card, which then determines the discount for that month. +- **Total monthly price:** This amount is the overall price of Expensify when using the Expensify Card discount to offset the cost of the pay-per-use seats +- **Policy list:** This is an overview of all client policies with their respective active seats. + +## Consolidated Domain Billing + +If your firm wishes to consolidate all Expensify billing to a single account, the Consolidated Domain Billing feature is your go-to tool. It centralizes payment for all group policies owned by any domain member of your firm. + +### Activating Consolidated Domain Billing: + 1. Claim and verify your firm’s domain. + 2. Navigate to **Settings > Domains > [Domain Name] > Domain Admins** and set a **"Primary Domain Admin"** by using the drop down toggle to select an email address. + 3. Enable **Consolidated Domain Billing** in the same section. + +The Consolidated Domain Billing tool ensures that billing takes place under a single Expensify account associated with your firm. This eliminates the need to add multiple payment cards across various accounts to cover payments for multiple clients. + +## Maintaining a Console of all clients: + +If your firm wants to have a console view of all client policies and domains, you will want to create a single, centralized login to manage all client policies and domains, such as accounting@myfirm.com. + + 1. Create a dedicated email address that will act as the universal policy owner, for example, accounting@myfirm.com. + 2. Register this email with Expensify or your chosen platform and ensure it is verified and secured. + 3. Within each client policy settings, add your centralized email (e.g. accounting@myfirm.com) as a policy admin. + 4. Do the same with each client domain. + + +## Applying Client IDs to a bill + +Using client IDs for Optimized Billing in Expensify: A unique identifier feature for ExpensifyApproved! accountants. Streamline client Workspace recognition and make your billing process more efficient. + +# How to assign a client ID to a workspace + 1. Log in to your account: Ensure you’re using an Approved! accountant account. + 2. Navigate to the desired Workspace: Go to **Settings > Workspaces > [Workspace Name] > Overview**. + 3. Input the identifier: Here, you can input an alphanumeric unique identifier for each client workspace. +**Note:** If a client has multiple workspaces, ensure each workspace has a consistent client ID. + +# How to access and download billing receipts +Accessing Billing **Settings: Go to Settings > Your Account > Payments > Billing History.** +Download the Receipt: Click on **"Download Receipt CSV".** + + +# Deep Dive +Using client IDs for all Workspaces: It's beneficial to use client IDs for all Workspaces to ensure each one is easily recognizable. +Benefits of itemized billing receipts: Employing client IDs offers itemized billing by client, with each itemization detailing unique active users. + +# FAQ + +**Do I automatically get the special billing rate as an ExpensifyApproved! Partner?** +- Yes, when you join the ExpensifyApproved! program, you will automatically get the special billing rate. To join the ExpensifyApproved! Program, you need to enroll in ExpensifyApproved! University. + +**How can I check my billing details?** +- To check your billing details, be on the lookout for your detailed billing statement sent out at the end of each month. + +**Can I pass the bill to my clients?** +- Yes, you can pass the bill on to your clients. If you retain ownership of client policies in Expensify, you can re-bill your clients. If you’d like the client to own the billing of the Expensify, they can take over billing. + +**What if I don't want to use the Expensify Card?** +- If you prefer not to use the Expensify Card, your clients will be billed at $18/seat monthly. + +**Why use client IDs?** +- Client IDs provide a streamlined method to identify and manage policies, especially beneficial when a client has multiple policies. + +**Do I need a client ID for each Workspace?** +- Yes, if you want to ensure seamless identification and billing processes. + +** Where can I see the Billing Receipts?** +- All billing owners receive an emailed PDF of their monthly billing receipt, but a CSV version can also be downloaded from the platform. From 0168e72eb1427af2bcc9af8c3f36f208e9e70c4a Mon Sep 17 00:00:00 2001 From: Nikki Wines Date: Mon, 23 Oct 2023 11:58:50 -0700 Subject: [PATCH 005/227] include const --- src/pages/signin/SignInPage.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/signin/SignInPage.js b/src/pages/signin/SignInPage.js index dd43970d5412..3ccd2061d794 100644 --- a/src/pages/signin/SignInPage.js +++ b/src/pages/signin/SignInPage.js @@ -100,8 +100,8 @@ function getRenderOptions({hasLogin, hasValidateCode, account, isPrimaryLogin, i const hasEmailDeliveryFailure = Boolean(account.hasEmailDeliveryFailure); // True if the user has SAML required and we haven't already initiated SAML for their account - shouldInitiateSAMLLogin = hasAccount && hasLogin && isSAMLRequired && !hasInitiatedSAMLLogin && account.isLoading; - shouldShowChooseSSOOrMagicCode = hasAccount && hasLogin && isSAMLEnabled && !isSAMLRequired && !isUsingMagicCode; + const shouldInitiateSAMLLogin = hasAccount && hasLogin && isSAMLRequired && !hasInitiatedSAMLLogin && account.isLoading; + const shouldShowChooseSSOOrMagicCode = hasAccount && hasLogin && isSAMLEnabled && !isSAMLRequired && !isUsingMagicCode; // SAML required users may reload the login page after having already entered their login details, in which // case we want to clear their sign in data so they don't end up in an infinite loop redirecting back to their From 9e4b7ae1ba30fe91d62878d4168579b83061b4ea Mon Sep 17 00:00:00 2001 From: Nikki Wines Date: Mon, 23 Oct 2023 18:33:04 -0700 Subject: [PATCH 006/227] style and clean up --- src/pages/signin/SAMLSignInPage/index.native.js | 11 +++++------ src/pages/signin/SignInPage.js | 1 - 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/pages/signin/SAMLSignInPage/index.native.js b/src/pages/signin/SAMLSignInPage/index.native.js index 3825cca0fa97..4b4624b56cde 100644 --- a/src/pages/signin/SAMLSignInPage/index.native.js +++ b/src/pages/signin/SAMLSignInPage/index.native.js @@ -1,11 +1,12 @@ import React, {useCallback, useRef} from 'react'; import {withOnyx} from 'react-native-onyx'; import PropTypes from 'prop-types'; +import WebView from 'react-native-webview'; import ONYXKEYS from '../../../ONYXKEYS'; import CONFIG from '../../../CONFIG'; -import WebView from 'react-native-webview'; -import FullScreenLoadingIndicator from '../../../components/FullscreenLoadingIndicator'; import * as Session from '../../../libs/actions/Session'; +import SAMLLoadingIndicator from '../../../components/SAMLLoadingIndicator'; +import FullScreenLoadingIndicator from '../../../components/FullscreenLoadingIndicator'; const propTypes = { /** The credentials of the logged in person */ @@ -28,11 +29,10 @@ function SAMLSignInPage({credentials}) { /** * Handles in-app navigation once we get a response back from Expensify * - * @param {String} params.type * @param {String} params.url */ const handleNavigationStateChange = useCallback( - ({type, url}) => { + ({url}) => { const searchParams = new URLSearchParams(new URL(url).search); if (searchParams.has('shortLivedAuthToken')) { const shortLivedAuthToken = searchParams.get('shortLivedAuthToken'); @@ -40,11 +40,10 @@ function SAMLSignInPage({credentials}) { return; } }, - [webViewRef], + [credentials.login], ); return ( Date: Mon, 23 Oct 2023 18:33:21 -0700 Subject: [PATCH 007/227] add SAMLLOadingINdicator --- src/components/SAMLLoadingIndicator.js | 43 +++++++++++++++++++ src/pages/signin/SAMLSignInPage/index.js | 35 +-------------- .../signin/SAMLSignInPage/index.native.js | 4 +- 3 files changed, 46 insertions(+), 36 deletions(-) create mode 100644 src/components/SAMLLoadingIndicator.js diff --git a/src/components/SAMLLoadingIndicator.js b/src/components/SAMLLoadingIndicator.js new file mode 100644 index 000000000000..32438c5359c2 --- /dev/null +++ b/src/components/SAMLLoadingIndicator.js @@ -0,0 +1,43 @@ +import _ from 'underscore'; +import React from 'react'; +import {ActivityIndicator, View, StyleSheet} from 'react-native'; +import styles from '../styles/styles'; +import themeColors from '../styles/themes/default'; +import Icon from './Icon'; +import Text from './Text'; +import * as Expensicons from './Icon/Expensicons'; +import * as Illustrations from './Icon/Illustrations'; +import useLocalize from '../hooks/useLocalize'; + +function SAMLLoadingIndicator() { + const {translate} = useLocalize(); + return ( + + + + + + {translate('samlSignIn.launching')} + + {translate('samlSignIn.oneMoment')} + + + + + + + ); +} + +SAMLLoadingIndicator.displayName = 'SAMLLoadingIndicator'; + +export default SAMLLoadingIndicator; diff --git a/src/pages/signin/SAMLSignInPage/index.js b/src/pages/signin/SAMLSignInPage/index.js index 23ce9b93b8cc..f27a3a310597 100644 --- a/src/pages/signin/SAMLSignInPage/index.js +++ b/src/pages/signin/SAMLSignInPage/index.js @@ -1,16 +1,9 @@ import React, {useEffect} from 'react'; import {withOnyx} from 'react-native-onyx'; -import {View} from 'react-native'; import PropTypes from 'prop-types'; import ONYXKEYS from '../../../ONYXKEYS'; import CONFIG from '../../../CONFIG'; -import Icon from '../../../components/Icon'; -import Text from '../../../components/Text'; -import * as Expensicons from '../../../components/Icon/Expensicons'; -import * as Illustrations from '../../../components/Icon/Illustrations'; -import styles from '../../../styles/styles'; -import themeColors from '../../../styles/themes/default'; -import useLocalize from '../../../hooks/useLocalize'; +import SAMLLoadingIndicator from '../../../components/SAMLLoadingIndicator'; const propTypes = { /** The credentials of the logged in person */ @@ -25,36 +18,12 @@ const defaultProps = { }; function SAMLSignInPage({credentials}) { - const {translate} = useLocalize(); - useEffect(() => { window.open(`${CONFIG.EXPENSIFY.SAML_URL}?email=${credentials.login}&referer=${CONFIG.EXPENSIFY.EXPENSIFY_CASH_REFERER}`, '_self'); }, [credentials.login]); return ( - - - - - - {translate('samlSignIn.launching')} - - {translate('samlSignIn.oneMoment')} - - - - - - + ); } diff --git a/src/pages/signin/SAMLSignInPage/index.native.js b/src/pages/signin/SAMLSignInPage/index.native.js index 4b4624b56cde..25affdbf26fd 100644 --- a/src/pages/signin/SAMLSignInPage/index.native.js +++ b/src/pages/signin/SAMLSignInPage/index.native.js @@ -20,10 +20,8 @@ const defaultProps = { credentials: {}, }; -const renderLoading = () => ; function SAMLSignInPage({credentials}) { - const webViewRef = useRef(); const samlLoginURL = `${CONFIG.EXPENSIFY.SAML_URL}?email=${credentials.login}&referer=${CONFIG.EXPENSIFY.EXPENSIFY_CASH_REFERER}`; /** @@ -48,7 +46,7 @@ function SAMLSignInPage({credentials}) { source={{uri: samlLoginURL}} incognito // 'incognito' prop required for Android, issue here https://github.com/react-native-webview/react-native-webview/issues/1352 startInLoadingState - renderLoading={renderLoading} + renderLoading={() => } onNavigationStateChange={handleNavigationStateChange} /> ); From 89dc792ec697c1d12be8ab566c464318e9685eda Mon Sep 17 00:00:00 2001 From: Nikki Wines Date: Mon, 23 Oct 2023 18:51:18 -0700 Subject: [PATCH 008/227] style --- src/components/SAMLLoadingIndicator.js | 3 +-- src/pages/signin/SAMLSignInPage/index.native.js | 4 +--- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/components/SAMLLoadingIndicator.js b/src/components/SAMLLoadingIndicator.js index 32438c5359c2..1169436e79e5 100644 --- a/src/components/SAMLLoadingIndicator.js +++ b/src/components/SAMLLoadingIndicator.js @@ -1,6 +1,5 @@ -import _ from 'underscore'; import React from 'react'; -import {ActivityIndicator, View, StyleSheet} from 'react-native'; +import {View, StyleSheet} from 'react-native'; import styles from '../styles/styles'; import themeColors from '../styles/themes/default'; import Icon from './Icon'; diff --git a/src/pages/signin/SAMLSignInPage/index.native.js b/src/pages/signin/SAMLSignInPage/index.native.js index 25affdbf26fd..ea5621a22a65 100644 --- a/src/pages/signin/SAMLSignInPage/index.native.js +++ b/src/pages/signin/SAMLSignInPage/index.native.js @@ -1,4 +1,4 @@ -import React, {useCallback, useRef} from 'react'; +import React, {useCallback} from 'react'; import {withOnyx} from 'react-native-onyx'; import PropTypes from 'prop-types'; import WebView from 'react-native-webview'; @@ -6,7 +6,6 @@ import ONYXKEYS from '../../../ONYXKEYS'; import CONFIG from '../../../CONFIG'; import * as Session from '../../../libs/actions/Session'; import SAMLLoadingIndicator from '../../../components/SAMLLoadingIndicator'; -import FullScreenLoadingIndicator from '../../../components/FullscreenLoadingIndicator'; const propTypes = { /** The credentials of the logged in person */ @@ -35,7 +34,6 @@ function SAMLSignInPage({credentials}) { if (searchParams.has('shortLivedAuthToken')) { const shortLivedAuthToken = searchParams.get('shortLivedAuthToken'); Session.signInWithShortLivedAuthToken(credentials.login, shortLivedAuthToken); - return; } }, [credentials.login], From 526cf8f5f124d62d758491fc8e929a5b92d02b0c Mon Sep 17 00:00:00 2001 From: Nikki Wines Date: Mon, 23 Oct 2023 19:07:06 -0700 Subject: [PATCH 009/227] prettier --- src/pages/signin/SAMLSignInPage/index.js | 4 +--- src/pages/signin/SAMLSignInPage/index.native.js | 9 ++++----- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/pages/signin/SAMLSignInPage/index.js b/src/pages/signin/SAMLSignInPage/index.js index f27a3a310597..283a3113b61b 100644 --- a/src/pages/signin/SAMLSignInPage/index.js +++ b/src/pages/signin/SAMLSignInPage/index.js @@ -22,9 +22,7 @@ function SAMLSignInPage({credentials}) { window.open(`${CONFIG.EXPENSIFY.SAML_URL}?email=${credentials.login}&referer=${CONFIG.EXPENSIFY.EXPENSIFY_CASH_REFERER}`, '_self'); }, [credentials.login]); - return ( - - ); + return ; } SAMLSignInPage.propTypes = propTypes; diff --git a/src/pages/signin/SAMLSignInPage/index.native.js b/src/pages/signin/SAMLSignInPage/index.native.js index ea5621a22a65..afb1dd7d8b4b 100644 --- a/src/pages/signin/SAMLSignInPage/index.native.js +++ b/src/pages/signin/SAMLSignInPage/index.native.js @@ -19,15 +19,14 @@ const defaultProps = { credentials: {}, }; - function SAMLSignInPage({credentials}) { const samlLoginURL = `${CONFIG.EXPENSIFY.SAML_URL}?email=${credentials.login}&referer=${CONFIG.EXPENSIFY.EXPENSIFY_CASH_REFERER}`; /** - * Handles in-app navigation once we get a response back from Expensify - * - * @param {String} params.url - */ + * Handles in-app navigation once we get a response back from Expensify + * + * @param {String} params.url + */ const handleNavigationStateChange = useCallback( ({url}) => { const searchParams = new URLSearchParams(new URL(url).search); From c386ce4a67cdd50a36b3c7b2d8ba5d3730ddd06e Mon Sep 17 00:00:00 2001 From: Nikki Wines Date: Mon, 23 Oct 2023 19:24:27 -0700 Subject: [PATCH 010/227] include platform --- src/pages/signin/SAMLSignInPage/index.native.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pages/signin/SAMLSignInPage/index.native.js b/src/pages/signin/SAMLSignInPage/index.native.js index afb1dd7d8b4b..ad478c3c0dfd 100644 --- a/src/pages/signin/SAMLSignInPage/index.native.js +++ b/src/pages/signin/SAMLSignInPage/index.native.js @@ -6,6 +6,7 @@ import ONYXKEYS from '../../../ONYXKEYS'; import CONFIG from '../../../CONFIG'; import * as Session from '../../../libs/actions/Session'; import SAMLLoadingIndicator from '../../../components/SAMLLoadingIndicator'; +import getPlatform from '../../../libs/getPlatform'; const propTypes = { /** The credentials of the logged in person */ @@ -20,7 +21,7 @@ const defaultProps = { }; function SAMLSignInPage({credentials}) { - const samlLoginURL = `${CONFIG.EXPENSIFY.SAML_URL}?email=${credentials.login}&referer=${CONFIG.EXPENSIFY.EXPENSIFY_CASH_REFERER}`; + const samlLoginURL = `${CONFIG.EXPENSIFY.SAML_URL}?email=${credentials.login}&referer=${CONFIG.EXPENSIFY.EXPENSIFY_CASH_REFERER}&platform=${getPlatform()}`; /** * Handles in-app navigation once we get a response back from Expensify From b2c681abbb028739104d3380899938ea9da7f779 Mon Sep 17 00:00:00 2001 From: David Cardoza Date: Thu, 26 Oct 2023 00:46:28 +0800 Subject: [PATCH 011/227] Rename Partner-Billing-Guide to Partner-Billing-Guide.md --- .../{Partner-Billing-Guide => Partner-Billing-Guide.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename docs/articles/expensify-classic/expensify-partner-program/{Partner-Billing-Guide => Partner-Billing-Guide.md} (100%) diff --git a/docs/articles/expensify-classic/expensify-partner-program/Partner-Billing-Guide b/docs/articles/expensify-classic/expensify-partner-program/Partner-Billing-Guide.md similarity index 100% rename from docs/articles/expensify-classic/expensify-partner-program/Partner-Billing-Guide rename to docs/articles/expensify-classic/expensify-partner-program/Partner-Billing-Guide.md From 5172f95ffe48442ff49530cd2e277feb454119ed Mon Sep 17 00:00:00 2001 From: Nikki Wines Date: Wed, 25 Oct 2023 15:25:45 -0700 Subject: [PATCH 012/227] pull in changes from infinitered:cdanwards/saml-webview --- .../signin/SAMLSignInPage/index.native.js | 32 ++++++++++++++----- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/src/pages/signin/SAMLSignInPage/index.native.js b/src/pages/signin/SAMLSignInPage/index.native.js index ad478c3c0dfd..82d353680605 100644 --- a/src/pages/signin/SAMLSignInPage/index.native.js +++ b/src/pages/signin/SAMLSignInPage/index.native.js @@ -7,6 +7,9 @@ import CONFIG from '../../../CONFIG'; import * as Session from '../../../libs/actions/Session'; import SAMLLoadingIndicator from '../../../components/SAMLLoadingIndicator'; import getPlatform from '../../../libs/getPlatform'; +import FullPageOfflineBlockingView from '../../../components/BlockingViews/FullPageOfflineBlockingView'; +import HeaderWithBackButton from '../../../components/HeaderWithBackButton'; +import ScreenWrapper from '../../../components/ScreenWrapper'; const propTypes = { /** The credentials of the logged in person */ @@ -39,19 +42,32 @@ function SAMLSignInPage({credentials}) { [credentials.login], ); return ( - } - onNavigationStateChange={handleNavigationStateChange} - /> + + Navigation.navigate(ROUTES.HOME)} + /> + + } + onNavigationStateChange={handleNavigationStateChange} + /> + + ); } SAMLSignInPage.propTypes = propTypes; SAMLSignInPage.defaultProps = defaultProps; +SAMLSignInPage.displayName = "SAMLSignInPage" export default withOnyx({ credentials: {key: ONYXKEYS.CREDENTIALS}, From 544ff27b3c573c3031dc82558c9e442ea297ac2c Mon Sep 17 00:00:00 2001 From: Nikki Wines Date: Wed, 25 Oct 2023 18:35:58 -0700 Subject: [PATCH 013/227] fix imports --- src/pages/signin/SAMLSignInPage/index.native.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pages/signin/SAMLSignInPage/index.native.js b/src/pages/signin/SAMLSignInPage/index.native.js index 82d353680605..99384e5fe44a 100644 --- a/src/pages/signin/SAMLSignInPage/index.native.js +++ b/src/pages/signin/SAMLSignInPage/index.native.js @@ -10,6 +10,8 @@ import getPlatform from '../../../libs/getPlatform'; import FullPageOfflineBlockingView from '../../../components/BlockingViews/FullPageOfflineBlockingView'; import HeaderWithBackButton from '../../../components/HeaderWithBackButton'; import ScreenWrapper from '../../../components/ScreenWrapper'; +import Navigation from '../../../libs/Navigation/Navigation'; +import ROUTES from '../../../ROUTES'; const propTypes = { /** The credentials of the logged in person */ From 7073d9310f5ebbb87a17f9f6bae247e30877da40 Mon Sep 17 00:00:00 2001 From: Nikki Wines Date: Wed, 25 Oct 2023 18:36:53 -0700 Subject: [PATCH 014/227] fix redirect flickering when pressing go back after choosing magic code --- src/pages/signin/SignInPage.js | 7 ++++++- src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.js | 4 ---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/pages/signin/SignInPage.js b/src/pages/signin/SignInPage.js index 9f3bfbfece1c..6a568f059565 100644 --- a/src/pages/signin/SignInPage.js +++ b/src/pages/signin/SignInPage.js @@ -155,6 +155,12 @@ function SignInPage({credentials, account, isInModal, activeClients, preferredLo } App.setLocale(Localize.getDevicePreferredLocale()); }, [preferredLocale]); + useEffect(() => { + // If we don't have a login set, reset the user's login preference (SSO or magic code) + if (!credentials.login && isUsingMagicCode) { + setIsUsingMagicCode(false); + } + }, [credentials.login, isUsingMagicCode, setIsUsingMagicCode]) const { shouldShowLoginForm, @@ -249,7 +255,6 @@ function SignInPage({credentials, account, isInModal, activeClients, preferredLo )} {shouldShowUnlinkLoginForm && } diff --git a/src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.js b/src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.js index dc100fffe4f1..35853faa3c0b 100755 --- a/src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.js +++ b/src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.js @@ -70,9 +70,6 @@ const propTypes = { /** Function to change `isUsingRecoveryCode` state when user toggles between 2fa code and recovery code */ setIsUsingRecoveryCode: PropTypes.func.isRequired, - /** Function to change `isUsingMagicCode` state when the user goes back to the login page */ - setIsUsingMagicCode: PropTypes.func.isRequired, - ...withLocalizePropTypes, }; @@ -209,7 +206,6 @@ function BaseValidateCodeForm(props) { */ const clearSignInData = () => { // Reset the user's preference for signing in with SAML versus magic codes - props.setIsUsingMagicCode(false); clearLocalSignInData(); Session.clearSignInData(); }; From 4586feef26a31b7fb18d95eead7f20daf1a17268 Mon Sep 17 00:00:00 2001 From: Nikki Wines Date: Thu, 26 Oct 2023 10:57:15 -0700 Subject: [PATCH 015/227] reset sign in data if going back from SSO provider page --- src/pages/signin/SAMLSignInPage/index.native.js | 5 ++++- src/pages/signin/SignInPage.js | 12 +++++++++--- .../signin/ValidateCodeForm/BaseValidateCodeForm.js | 1 - 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/pages/signin/SAMLSignInPage/index.native.js b/src/pages/signin/SAMLSignInPage/index.native.js index 99384e5fe44a..60c41414174f 100644 --- a/src/pages/signin/SAMLSignInPage/index.native.js +++ b/src/pages/signin/SAMLSignInPage/index.native.js @@ -51,7 +51,10 @@ function SAMLSignInPage({credentials}) { > Navigation.navigate(ROUTES.HOME)} + onBackButtonPress={() => { + Session.clearSignInData(); + Navigation.navigate(ROUTES.HOME); + }} /> { - // If we don't have a login set, reset the user's login preference (SSO or magic code) - if (!credentials.login && isUsingMagicCode) { + // If we don't have a login set, reset the user's SAML login preferences + if (!credentials.login) { + if (isUsingMagicCode) { setIsUsingMagicCode(false); + } + if (hasInitiatedSAMLLogin) { + setHasInitiatedSAMLLogin(false); + } } - }, [credentials.login, isUsingMagicCode, setIsUsingMagicCode]) + + }, [credentials.login, isUsingMagicCode, setIsUsingMagicCode, hasInitiatedSAMLLogin, setHasInitiatedSAMLLogin]) const { shouldShowLoginForm, diff --git a/src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.js b/src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.js index 35853faa3c0b..0433a24db6e0 100755 --- a/src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.js +++ b/src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.js @@ -205,7 +205,6 @@ function BaseValidateCodeForm(props) { * Clears local and Onyx sign in states */ const clearSignInData = () => { - // Reset the user's preference for signing in with SAML versus magic codes clearLocalSignInData(); Session.clearSignInData(); }; From 4dd5f559ad7f9630b3081fc4216df05803fdc74f Mon Sep 17 00:00:00 2001 From: Nikki Wines Date: Thu, 26 Oct 2023 18:16:12 -0700 Subject: [PATCH 016/227] style --- src/pages/signin/SAMLSignInPage/index.native.js | 2 +- src/pages/signin/SignInPage.js | 17 +++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/pages/signin/SAMLSignInPage/index.native.js b/src/pages/signin/SAMLSignInPage/index.native.js index 60c41414174f..fa823ec9a01b 100644 --- a/src/pages/signin/SAMLSignInPage/index.native.js +++ b/src/pages/signin/SAMLSignInPage/index.native.js @@ -72,7 +72,7 @@ function SAMLSignInPage({credentials}) { SAMLSignInPage.propTypes = propTypes; SAMLSignInPage.defaultProps = defaultProps; -SAMLSignInPage.displayName = "SAMLSignInPage" +SAMLSignInPage.displayName = 'SAMLSignInPage'; export default withOnyx({ credentials: {key: ONYXKEYS.CREDENTIALS}, diff --git a/src/pages/signin/SignInPage.js b/src/pages/signin/SignInPage.js index e33e2df88563..81ada5a99790 100644 --- a/src/pages/signin/SignInPage.js +++ b/src/pages/signin/SignInPage.js @@ -156,17 +156,18 @@ function SignInPage({credentials, account, isInModal, activeClients, preferredLo App.setLocale(Localize.getDevicePreferredLocale()); }, [preferredLocale]); useEffect(() => { + if (credentials.login) { + return; + } + // If we don't have a login set, reset the user's SAML login preferences - if (!credentials.login) { - if (isUsingMagicCode) { + if (isUsingMagicCode) { setIsUsingMagicCode(false); - } - if (hasInitiatedSAMLLogin) { - setHasInitiatedSAMLLogin(false); - } } - - }, [credentials.login, isUsingMagicCode, setIsUsingMagicCode, hasInitiatedSAMLLogin, setHasInitiatedSAMLLogin]) + if (hasInitiatedSAMLLogin) { + setHasInitiatedSAMLLogin(false); + } + }, [credentials.login, isUsingMagicCode, setIsUsingMagicCode, hasInitiatedSAMLLogin, setHasInitiatedSAMLLogin]); const { shouldShowLoginForm, From 14818b737ba60d5cf3ca5b206d16174ef150dbd9 Mon Sep 17 00:00:00 2001 From: Nikki Wines Date: Mon, 30 Oct 2023 10:14:05 -0700 Subject: [PATCH 017/227] add in error handling from App/pull/30027 --- src/pages/signin/SAMLSignInPage/index.native.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/pages/signin/SAMLSignInPage/index.native.js b/src/pages/signin/SAMLSignInPage/index.native.js index fa823ec9a01b..e6ed33710b24 100644 --- a/src/pages/signin/SAMLSignInPage/index.native.js +++ b/src/pages/signin/SAMLSignInPage/index.native.js @@ -40,6 +40,12 @@ function SAMLSignInPage({credentials}) { const shortLivedAuthToken = searchParams.get('shortLivedAuthToken'); Session.signInWithShortLivedAuthToken(credentials.login, shortLivedAuthToken); } + + if (searchParams.has('error')) { + // Run the Onyx action to set an error state on the sign in page + // Currently this is what's going to trigger because the backend isn't redirecting SAML correctly + Navigation.navigate(ROUTES.HOME); + } }, [credentials.login], ); From ed660094b8a25e095eef055d40692dc98b5acdc1 Mon Sep 17 00:00:00 2001 From: Nikki Wines Date: Mon, 30 Oct 2023 10:44:14 -0700 Subject: [PATCH 018/227] update imports --- src/components/SAMLLoadingIndicator.js | 14 ++++++------- src/pages/signin/SAMLSignInPage/index.js | 2 +- .../signin/SAMLSignInPage/index.native.js | 20 +++++++++---------- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/components/SAMLLoadingIndicator.js b/src/components/SAMLLoadingIndicator.js index 1169436e79e5..e6171838e0ff 100644 --- a/src/components/SAMLLoadingIndicator.js +++ b/src/components/SAMLLoadingIndicator.js @@ -1,12 +1,12 @@ import React from 'react'; import {View, StyleSheet} from 'react-native'; -import styles from '../styles/styles'; -import themeColors from '../styles/themes/default'; -import Icon from './Icon'; -import Text from './Text'; -import * as Expensicons from './Icon/Expensicons'; -import * as Illustrations from './Icon/Illustrations'; -import useLocalize from '../hooks/useLocalize'; +import styles from '@styles/styles'; +import themeColors from '@styles/themes/default'; +import Icon from '@components/Icon'; +import Text from '@components/Text'; +import * as Expensicons from '@components/Icon/Expensicons'; +import * as Illustrations from '@components/Icon/Illustrations'; +import useLocalize from '@hooks/useLocalize'; function SAMLLoadingIndicator() { const {translate} = useLocalize(); diff --git a/src/pages/signin/SAMLSignInPage/index.js b/src/pages/signin/SAMLSignInPage/index.js index 6a4fdef80848..cfef9553f868 100644 --- a/src/pages/signin/SAMLSignInPage/index.js +++ b/src/pages/signin/SAMLSignInPage/index.js @@ -3,7 +3,7 @@ import {withOnyx} from 'react-native-onyx'; import PropTypes from 'prop-types'; import CONFIG from '@src/CONFIG'; import ONYXKEYS from '@src/ONYXKEYS'; -import SAMLLoadingIndicator from '../../../components/SAMLLoadingIndicator'; +import SAMLLoadingIndicator from '@components/SAMLLoadingIndicator'; const propTypes = { diff --git a/src/pages/signin/SAMLSignInPage/index.native.js b/src/pages/signin/SAMLSignInPage/index.native.js index e6ed33710b24..9a75508b10c5 100644 --- a/src/pages/signin/SAMLSignInPage/index.native.js +++ b/src/pages/signin/SAMLSignInPage/index.native.js @@ -2,16 +2,16 @@ import React, {useCallback} from 'react'; import {withOnyx} from 'react-native-onyx'; import PropTypes from 'prop-types'; import WebView from 'react-native-webview'; -import ONYXKEYS from '../../../ONYXKEYS'; -import CONFIG from '../../../CONFIG'; -import * as Session from '../../../libs/actions/Session'; -import SAMLLoadingIndicator from '../../../components/SAMLLoadingIndicator'; -import getPlatform from '../../../libs/getPlatform'; -import FullPageOfflineBlockingView from '../../../components/BlockingViews/FullPageOfflineBlockingView'; -import HeaderWithBackButton from '../../../components/HeaderWithBackButton'; -import ScreenWrapper from '../../../components/ScreenWrapper'; -import Navigation from '../../../libs/Navigation/Navigation'; -import ROUTES from '../../../ROUTES'; +import ONYXKEYS from '@src/ONYXKEYS'; +import CONFIG from '@src/CONFIG'; +import ROUTES from '@src/ROUTES'; +import * as Session from '@userActions/Session'; +import SAMLLoadingIndicator from '@components/SAMLLoadingIndicator'; +import FullPageOfflineBlockingView from '@components/BlockingViews/FullPageOfflineBlockingView'; +import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import ScreenWrapper from '@components/ScreenWrapper'; +import Navigation from '@libs/Navigation/Navigation'; +import getPlatform from '@libs/getPlatform'; const propTypes = { /** The credentials of the logged in person */ From b247558ef7889846c109cdbf3b0e698a39c640fa Mon Sep 17 00:00:00 2001 From: Nikki Wines Date: Mon, 30 Oct 2023 11:39:48 -0700 Subject: [PATCH 019/227] prettier --- src/components/SAMLLoadingIndicator.js | 12 ++++++------ src/pages/signin/SAMLSignInPage/index.js | 5 ++--- src/pages/signin/SAMLSignInPage/index.native.js | 14 +++++++------- 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/components/SAMLLoadingIndicator.js b/src/components/SAMLLoadingIndicator.js index e6171838e0ff..d00c5a032a72 100644 --- a/src/components/SAMLLoadingIndicator.js +++ b/src/components/SAMLLoadingIndicator.js @@ -1,12 +1,12 @@ import React from 'react'; -import {View, StyleSheet} from 'react-native'; +import {StyleSheet, View} from 'react-native'; +import useLocalize from '@hooks/useLocalize'; import styles from '@styles/styles'; import themeColors from '@styles/themes/default'; -import Icon from '@components/Icon'; -import Text from '@components/Text'; -import * as Expensicons from '@components/Icon/Expensicons'; -import * as Illustrations from '@components/Icon/Illustrations'; -import useLocalize from '@hooks/useLocalize'; +import Icon from './Icon'; +import * as Expensicons from './Icon/Expensicons'; +import * as Illustrations from './Icon/Illustrations'; +import Text from './Text'; function SAMLLoadingIndicator() { const {translate} = useLocalize(); diff --git a/src/pages/signin/SAMLSignInPage/index.js b/src/pages/signin/SAMLSignInPage/index.js index cfef9553f868..782ed4e0da27 100644 --- a/src/pages/signin/SAMLSignInPage/index.js +++ b/src/pages/signin/SAMLSignInPage/index.js @@ -1,10 +1,9 @@ +import PropTypes from 'prop-types'; import React, {useEffect} from 'react'; import {withOnyx} from 'react-native-onyx'; -import PropTypes from 'prop-types'; +import SAMLLoadingIndicator from '@components/SAMLLoadingIndicator'; import CONFIG from '@src/CONFIG'; import ONYXKEYS from '@src/ONYXKEYS'; -import SAMLLoadingIndicator from '@components/SAMLLoadingIndicator'; - const propTypes = { /** The credentials of the logged in person */ diff --git a/src/pages/signin/SAMLSignInPage/index.native.js b/src/pages/signin/SAMLSignInPage/index.native.js index 9a75508b10c5..9cf546d94313 100644 --- a/src/pages/signin/SAMLSignInPage/index.native.js +++ b/src/pages/signin/SAMLSignInPage/index.native.js @@ -1,17 +1,17 @@ +import PropTypes from 'prop-types'; import React, {useCallback} from 'react'; import {withOnyx} from 'react-native-onyx'; -import PropTypes from 'prop-types'; import WebView from 'react-native-webview'; -import ONYXKEYS from '@src/ONYXKEYS'; -import CONFIG from '@src/CONFIG'; -import ROUTES from '@src/ROUTES'; -import * as Session from '@userActions/Session'; -import SAMLLoadingIndicator from '@components/SAMLLoadingIndicator'; import FullPageOfflineBlockingView from '@components/BlockingViews/FullPageOfflineBlockingView'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import SAMLLoadingIndicator from '@components/SAMLLoadingIndicator'; import ScreenWrapper from '@components/ScreenWrapper'; -import Navigation from '@libs/Navigation/Navigation'; import getPlatform from '@libs/getPlatform'; +import Navigation from '@libs/Navigation/Navigation'; +import * as Session from '@userActions/Session'; +import CONFIG from '@src/CONFIG'; +import ONYXKEYS from '@src/ONYXKEYS'; +import ROUTES from '@src/ROUTES'; const propTypes = { /** The credentials of the logged in person */ From d4a1eea7d73e406ba05bf11c98c4f7f7fa4319ce Mon Sep 17 00:00:00 2001 From: Jasper Huang Date: Mon, 30 Oct 2023 15:43:42 -0700 Subject: [PATCH 020/227] don't restrict accessing members for non-public UCRs --- src/pages/ReportDetailsPage.js | 4 ++-- src/pages/RoomMembersPage.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pages/ReportDetailsPage.js b/src/pages/ReportDetailsPage.js index ef28102cc144..f5316468b274 100644 --- a/src/pages/ReportDetailsPage.js +++ b/src/pages/ReportDetailsPage.js @@ -95,7 +95,7 @@ function ReportDetailsPage(props) { return items; } - if ((!isUserCreatedPolicyRoom && participants.length) || (isUserCreatedPolicyRoom && isPolicyMember)) { + if ((!isUserCreatedPolicyRoom && participants.length) || (isUserCreatedPolicyRoom && (!ReportUtils.isPublicRoom(props.report) || isPolicyMember))) { items.push({ key: CONST.REPORT_DETAILS_MENU_ITEM.MEMBERS, translationKey: 'common.members', @@ -110,7 +110,7 @@ function ReportDetailsPage(props) { } }, }); - } else if ((!participants.length || !isPolicyMember) && isUserCreatedPolicyRoom && !props.report.parentReportID) { + } else if (isUserCreatedPolicyRoom && (!participants.length || !isPolicyMember) && !props.report.parentReportID) { items.push({ key: CONST.REPORT_DETAILS_MENU_ITEM.INVITE, translationKey: 'common.invite', diff --git a/src/pages/RoomMembersPage.js b/src/pages/RoomMembersPage.js index a2599b3382d7..5f4d60c354f0 100644 --- a/src/pages/RoomMembersPage.js +++ b/src/pages/RoomMembersPage.js @@ -93,7 +93,7 @@ function RoomMembersPage(props) { useEffect(() => { // Kick the user out if they tried to navigate to this via the URL - if (!PolicyUtils.isPolicyMember(props.report.policyID, props.policies) || !Permissions.canUsePolicyRooms(props.betas)) { + if ((ReportUtils.isPublicRoom(props.report) && !PolicyUtils.isPolicyMember(props.report.policyID, props.policies)) || !Permissions.canUsePolicyRooms(props.betas)) { Navigation.goBack(ROUTES.REPORT_WITH_ID_DETAILS.getRoute(props.report.reportID)); return; } From 380fa265b01e32290041e773f16a96f551e5149d Mon Sep 17 00:00:00 2001 From: Nikki Wines Date: Mon, 30 Oct 2023 16:54:27 -0700 Subject: [PATCH 021/227] remove navigation after callback --- src/pages/signin/SAMLSignInPage/index.native.js | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/pages/signin/SAMLSignInPage/index.native.js b/src/pages/signin/SAMLSignInPage/index.native.js index 9cf546d94313..58e3f53cd746 100644 --- a/src/pages/signin/SAMLSignInPage/index.native.js +++ b/src/pages/signin/SAMLSignInPage/index.native.js @@ -1,5 +1,5 @@ import PropTypes from 'prop-types'; -import React, {useCallback} from 'react'; +import React, {useCallback, useState} from 'react'; import {withOnyx} from 'react-native-onyx'; import WebView from 'react-native-webview'; import FullPageOfflineBlockingView from '@components/BlockingViews/FullPageOfflineBlockingView'; @@ -27,6 +27,7 @@ const defaultProps = { function SAMLSignInPage({credentials}) { const samlLoginURL = `${CONFIG.EXPENSIFY.SAML_URL}?email=${credentials.login}&referer=${CONFIG.EXPENSIFY.EXPENSIFY_CASH_REFERER}&platform=${getPlatform()}`; + const [showNavigation, shouldShowNavigation] = useState(true); /** * Handles in-app navigation once we get a response back from Expensify @@ -35,6 +36,11 @@ function SAMLSignInPage({credentials}) { */ const handleNavigationStateChange = useCallback( ({url}) => { + // If we've gotten a callback then remove the option to navigate back to the sign in page + if (url.includes('loginCallback')) { + shouldShowNavigation(false); + } + const searchParams = new URLSearchParams(new URL(url).search); if (searchParams.has('shortLivedAuthToken')) { const shortLivedAuthToken = searchParams.get('shortLivedAuthToken'); @@ -47,14 +53,16 @@ function SAMLSignInPage({credentials}) { Navigation.navigate(ROUTES.HOME); } }, - [credentials.login], + [credentials.login, shouldShowNavigation], ); + return ( + {showNavigation && ( { @@ -62,6 +70,7 @@ function SAMLSignInPage({credentials}) { Navigation.navigate(ROUTES.HOME); }} /> + )} Date: Thu, 2 Nov 2023 14:59:38 -0700 Subject: [PATCH 022/227] style --- .../signin/SAMLSignInPage/index.native.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/pages/signin/SAMLSignInPage/index.native.js b/src/pages/signin/SAMLSignInPage/index.native.js index 58e3f53cd746..8b765ecc1d32 100644 --- a/src/pages/signin/SAMLSignInPage/index.native.js +++ b/src/pages/signin/SAMLSignInPage/index.native.js @@ -62,15 +62,15 @@ function SAMLSignInPage({credentials}) { includeSafeAreaPaddingBottom={false} testID={SAMLSignInPage.displayName} > - {showNavigation && ( - { - Session.clearSignInData(); - Navigation.navigate(ROUTES.HOME); - }} - /> - )} + {showNavigation && ( + { + Session.clearSignInData(); + Navigation.navigate(ROUTES.HOME); + }} + /> + )} Date: Fri, 3 Nov 2023 12:49:03 -0700 Subject: [PATCH 023/227] remove beta checks from members screens --- src/pages/RoomInvitePage.js | 10 ---------- src/pages/RoomMembersPage.js | 5 ----- 2 files changed, 15 deletions(-) diff --git a/src/pages/RoomInvitePage.js b/src/pages/RoomInvitePage.js index 71585fefbcd3..dd1f4aa2267a 100644 --- a/src/pages/RoomInvitePage.js +++ b/src/pages/RoomInvitePage.js @@ -71,16 +71,6 @@ function RoomInvitePage(props) { // Any existing participants and Expensify emails should not be eligible for invitation const excludedUsers = useMemo(() => [...lodashGet(props.report, 'participants', []), ...CONST.EXPENSIFY_EMAILS], [props.report]); - useEffect(() => { - // Kick the user out if they tried to navigate to this via the URL - if (Permissions.canUsePolicyRooms(props.betas)) { - return; - } - Navigation.goBack(ROUTES.REPORT_WITH_ID_DETAILS.getRoute(props.report.reportID)); - - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - useEffect(() => { const inviteOptions = OptionsListUtils.getMemberInviteOptions(props.personalDetails, props.betas, searchTerm, excludedUsers); diff --git a/src/pages/RoomMembersPage.js b/src/pages/RoomMembersPage.js index 5f4d60c354f0..21eeae5f61fe 100644 --- a/src/pages/RoomMembersPage.js +++ b/src/pages/RoomMembersPage.js @@ -92,11 +92,6 @@ function RoomMembersPage(props) { }, [props.report.reportID]); useEffect(() => { - // Kick the user out if they tried to navigate to this via the URL - if ((ReportUtils.isPublicRoom(props.report) && !PolicyUtils.isPolicyMember(props.report.policyID, props.policies)) || !Permissions.canUsePolicyRooms(props.betas)) { - Navigation.goBack(ROUTES.REPORT_WITH_ID_DETAILS.getRoute(props.report.reportID)); - return; - } getRoomMembers(); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); From f2a73984d9ce5eb2cae09bf9e4be26cf3786cc14 Mon Sep 17 00:00:00 2001 From: Jasper Huang Date: Fri, 3 Nov 2023 12:50:33 -0700 Subject: [PATCH 024/227] remove unused --- src/pages/RoomMembersPage.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/pages/RoomMembersPage.js b/src/pages/RoomMembersPage.js index 21eeae5f61fe..8cfafc7e3dcb 100644 --- a/src/pages/RoomMembersPage.js +++ b/src/pages/RoomMembersPage.js @@ -92,6 +92,11 @@ function RoomMembersPage(props) { }, [props.report.reportID]); useEffect(() => { + // Kick the user out if they tried to navigate to this via the URL + if ((ReportUtils.isPublicRoom(props.report) && !PolicyUtils.isPolicyMember(props.report.policyID, props.policies))) { + Navigation.goBack(ROUTES.REPORT_WITH_ID_DETAILS.getRoute(props.report.reportID)); + return; + } getRoomMembers(); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); From 6329e16a37ee38b9e0b92248e6bf14d6d2f96883 Mon Sep 17 00:00:00 2001 From: Jasper Huang Date: Fri, 3 Nov 2023 12:59:16 -0700 Subject: [PATCH 025/227] remove unused --- src/pages/RoomInvitePage.js | 1 - src/pages/RoomMembersPage.js | 10 +--------- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/src/pages/RoomInvitePage.js b/src/pages/RoomInvitePage.js index dd1f4aa2267a..c4e24b3c4e22 100644 --- a/src/pages/RoomInvitePage.js +++ b/src/pages/RoomInvitePage.js @@ -14,7 +14,6 @@ import * as Browser from '@libs/Browser'; import compose from '@libs/compose'; import Navigation from '@libs/Navigation/Navigation'; import * as OptionsListUtils from '@libs/OptionsListUtils'; -import Permissions from '@libs/Permissions'; import * as PolicyUtils from '@libs/PolicyUtils'; import * as ReportUtils from '@libs/ReportUtils'; import styles from '@styles/styles'; diff --git a/src/pages/RoomMembersPage.js b/src/pages/RoomMembersPage.js index 8cfafc7e3dcb..ec5652d14767 100644 --- a/src/pages/RoomMembersPage.js +++ b/src/pages/RoomMembersPage.js @@ -17,7 +17,6 @@ import compose from '@libs/compose'; import Log from '@libs/Log'; import Navigation from '@libs/Navigation/Navigation'; import * as OptionsListUtils from '@libs/OptionsListUtils'; -import Permissions from '@libs/Permissions'; import * as PolicyUtils from '@libs/PolicyUtils'; import * as ReportUtils from '@libs/ReportUtils'; import * as UserUtils from '@libs/UserUtils'; @@ -34,9 +33,6 @@ const propTypes = { /** All personal details asssociated with user */ personalDetails: PropTypes.objectOf(personalDetailsPropType), - /** Beta features list */ - betas: PropTypes.arrayOf(PropTypes.string), - /** The report currently being looked at */ report: reportPropTypes.isRequired, @@ -73,7 +69,6 @@ const defaultProps = { }, report: {}, policies: {}, - betas: [], ...withCurrentUserPersonalDetailsDefaultProps, }; @@ -93,7 +88,7 @@ function RoomMembersPage(props) { useEffect(() => { // Kick the user out if they tried to navigate to this via the URL - if ((ReportUtils.isPublicRoom(props.report) && !PolicyUtils.isPolicyMember(props.report.policyID, props.policies))) { + if (ReportUtils.isPublicRoom(props.report) && !PolicyUtils.isPolicyMember(props.report.policyID, props.policies)) { Navigation.goBack(ROUTES.REPORT_WITH_ID_DETAILS.getRoute(props.report.reportID)); return; } @@ -327,9 +322,6 @@ export default compose( policies: { key: ONYXKEYS.COLLECTION.POLICY, }, - betas: { - key: ONYXKEYS.BETAS, - }, }), withCurrentUserPersonalDetails, )(RoomMembersPage); From 6a0bf33d425b09461198105984d4d1a5058cd514 Mon Sep 17 00:00:00 2001 From: Jasper Huang Date: Fri, 3 Nov 2023 13:27:39 -0700 Subject: [PATCH 026/227] fix display --- src/pages/RoomMembersPage.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/pages/RoomMembersPage.js b/src/pages/RoomMembersPage.js index ec5652d14767..25e1400eebea 100644 --- a/src/pages/RoomMembersPage.js +++ b/src/pages/RoomMembersPage.js @@ -87,11 +87,6 @@ function RoomMembersPage(props) { }, [props.report.reportID]); useEffect(() => { - // Kick the user out if they tried to navigate to this via the URL - if (ReportUtils.isPublicRoom(props.report) && !PolicyUtils.isPolicyMember(props.report.policyID, props.policies)) { - Navigation.goBack(ROUTES.REPORT_WITH_ID_DETAILS.getRoute(props.report.reportID)); - return; - } getRoomMembers(); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); @@ -244,7 +239,7 @@ function RoomMembersPage(props) { testID={RoomMembersPage.displayName} > Navigation.goBack(ROUTES.REPORT_WITH_ID_DETAILS.getRoute(props.report.reportID))} > From 211f2e59d49fb148cd4297fd6a39599c7918b88c Mon Sep 17 00:00:00 2001 From: Jasper Huang Date: Fri, 3 Nov 2023 13:49:09 -0700 Subject: [PATCH 027/227] remove 'remove' button for non workspace members --- src/pages/RoomMembersPage.js | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/pages/RoomMembersPage.js b/src/pages/RoomMembersPage.js index 25e1400eebea..a8de11fb12e9 100644 --- a/src/pages/RoomMembersPage.js +++ b/src/pages/RoomMembersPage.js @@ -269,14 +269,16 @@ function RoomMembersPage(props) { text={props.translate('common.invite')} onPress={inviteUser} /> -