Skip to content

Commit

Permalink
Merge branch 'main' into fix/40495
Browse files Browse the repository at this point in the history
  • Loading branch information
nkdengineer committed Apr 25, 2024
2 parents c079b78 + 9a727de commit 533a8af
Show file tree
Hide file tree
Showing 158 changed files with 1,017 additions and 1,722 deletions.
14 changes: 3 additions & 11 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,12 @@ apply plugin: "com.android.application"
apply plugin: "org.jetbrains.kotlin.android"
apply plugin: "com.facebook.react"
apply plugin: "com.google.firebase.firebase-perf"
apply plugin: "fullstory"
apply from: project(':react-native-config').projectDir.getPath() + "/dotenv.gradle"

/**
* This is the configuration block to customize your React Native Android app.
* By default you don't need to apply any configuration, just uncomment the lines you need.
*/

/* Fullstory settings */
fullstory {
org 'o-1WN56P-na1'
enabledVariants 'all'
}

react {
/* Folders */
// The root of your project, i.e. where "package.json" lives. Default is '..'
Expand Down Expand Up @@ -106,8 +98,8 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
multiDexEnabled rootProject.ext.multiDexEnabled
versionCode 1001046500
versionName "1.4.65-0"
versionCode 1001046505
versionName "1.4.65-5"
// Supported language variants must be declared here to avoid from being removed during the compilation.
// This also helps us to not include unnecessary language variants in the APK.
resConfigs "en", "es"
Expand Down Expand Up @@ -170,7 +162,7 @@ android {
signingConfig null
// buildTypes take precedence over productFlavors when it comes to the signing configuration,
// thus we need to manually set the signing config, so that the e2e uses the debug config again.
// In other words, the signingConfig setting above will be ignored when we build the flavor in release mode.
// In other words, the signingConfig setting above will be ignored when we build the flavor in release mode.
productFlavors.all { flavor ->
// All release builds should be signed with the release config ...
flavor.signingConfig signingConfigs.release
Expand Down
6 changes: 1 addition & 5 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,13 @@ buildscript {
repositories {
google()
mavenCentral()
maven {url "https://maven.fullstory.com"}
}
dependencies {
classpath("com.android.tools.build:gradle")
classpath("com.facebook.react:react-native-gradle-plugin")
classpath("com.google.gms:google-services:4.3.4")
classpath("com.google.firebase:firebase-crashlytics-gradle:2.7.1")
classpath("com.google.firebase:perf-plugin:1.4.1")
// Fullstory integration
classpath ("com.fullstory:gradle-plugin-local:1.45.1")

// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion")
Expand Down Expand Up @@ -74,7 +70,7 @@ allprojects {
// 'mapbox' is the fixed username for Mapbox's Maven repository.
username = 'mapbox'

// The value for password is read from the 'MAPBOX_DOWNLOADS_TOKEN' gradle property.
// The value for password is read from the 'MAPBOX_DOWNLOADS_TOKEN' gradle property.
// Run "npm run setup-mapbox-sdk" to set this property in «USER_HOME»/.gradle/gradle.properties

// Example gradle.properties entry:
Expand Down
1 change: 1 addition & 0 deletions assets/images/all.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 0 additions & 17 deletions babel.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,6 @@ const defaultPlugins = [
// source code transformation as we do not use class property assignment.
'transform-class-properties',

/* Fullstory */
[
'@fullstory/react-native',
{
version: '1.4.0',
org: 'o-1WN56P-na1',
enabledVariants: 'all',
},
],
[
'@fullstory/babel-plugin-annotate-react',
{
native: true,
setFSTagName: true,
},
],

// Keep it last
'react-native-reanimated/plugin',
];
Expand Down
2 changes: 1 addition & 1 deletion config/webpack/webpack.common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ const getCommonConfiguration = ({file = '.env', platform = 'web'}: Environment):
{from: 'web/apple-touch-icon.png'},
{from: 'assets/images/expensify-app-icon.svg'},
{from: 'web/manifest.json'},
{from: 'web/thirdPartyScripts.js'},
{from: 'web/gtm.js'},
{from: 'assets/css', to: 'css'},
{from: 'assets/fonts/web', to: 'fonts'},
{from: 'assets/sounds', to: 'sounds'},
Expand Down
4 changes: 2 additions & 2 deletions contributingGuides/ACCESSIBILITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ When implementing pressable components, it's essential to create accessible flow

- ensure that after performing press focus is set on the correct next element - this is especially important for keyboard users who rely on focus to navigate the app. All Pressable components have a `nextFocusRef` prop that can be used to set the next focusable element after the pressable component. This prop accepts a ref to the next focusable element. For example, if you have a button that opens a modal, you can set the next focus to the first focusable element in the modal. This way, when the user presses the button, focus will be set on the first focusable element in the modal, and the user can continue navigating the modal using the keyboard.

- size of any pressable component should be at least 44x44dp. This is the minimum size recommended by Apple and Google for touch targets. If the pressable component is smaller than `44x44dp`, it will be difficult for users with motor disabilities to interact with it. Pressable components have a `autoHitSlop` prop that can be used to automatically increase the size of the pressable component to `44x44dp`. This prop accepts a boolean value. If set to true, the pressable component will automatically increase its touchable size to 44x44dp. If set to false, the pressable component will not increase its size. By default, this prop is set to false.
- size of any pressable component should be at least 44x44dp. This is the minimum size recommended by Apple and Google for touch targets. If the pressable component is smaller than `44x44dp`, it will be difficult for users with motor disabilities to interact with it. Pressable components have a `autoHitSlop` prop that can be used to automatically increase the size of the pressable component to `44x44dp`. This prop accepts a boolean value. If set to true, the pressable component will automatically increase its touchable size to `44x44dp`. If set to false, the pressable component will not increase its size. By default, this prop is set to false.

- ensure that the pressable component has a label and hint. This is especially important for users with visual disabilities who rely on screen readers to navigate the app. All Pressable components have a `accessibilitylabel` prop that can be used to set the label of the pressable component. This prop accepts a string value. All Pressable components also have a `accessibilityHint` prop that can be used to set the hint of the pressable component. This prop accepts a string value. The accessibilityHint prop is optional. If not set, the pressable component will fallback to the accessibilityLabel prop. For example, if you have a button that opens a modal, you can set the accessibilityLabel to "Open modal" and the accessibilityHint to "Opens a modal with more information". This way, when the user focuses on the button, the screen reader will read "Open modal. Opens a modal with more information". This will help the user understand what the button does and what to expect after pressing it.
- ensure that the pressable component has a label and hint. This is especially important for users with visual disabilities who rely on screen readers to navigate the app. All Pressable components have a `accessibilitylabel` prop that can be used to set the label of the pressable component. This prop accepts a string value. All Pressable components also have a `accessibilityHint` prop that can be used to set the hint of the pressable component. This prop accepts a string value. The `accessibilityHint` prop is optional. If not set, the pressable component will fallback to the `accessibilityLabel` prop. For example, if you have a button that opens a modal, you can set the `accessibilityLabel` to "Open modal" and the `accessibilityHint` to "Opens a modal with more information". This way, when the user focuses on the button, the screen reader will read "Open modal. Opens a modal with more information". This will help the user understand what the button does and what to expect after pressing it.

- the `enableInScreenReaderStates` prop proves invaluable when aiming to enhance the accessibility of clickable elements, particularly when desiring to enlarge the clickable area of a component, such as an entire row. This can be especially useful, for instance, when dealing with tables where only a small portion of a row, like a checkbox, might traditionally trigger an action. By employing this prop, developers can ensure that the entirety of a designated component, in this case a row, is made accessible to users employing screen readers. This creates a more inclusive user experience, allowing individuals relying on screen readers to interact with the component effortlessly. For instance, in a table, using this prop on a row component enables users to click anywhere within the row to trigger an action, significantly improving accessibility and user-friendliness.

Expand Down
13 changes: 10 additions & 3 deletions contributingGuides/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,43 +8,50 @@ These are best practices related to the current API used for App.
- Data is pushed to the client and put straight into Onyx by low-level libraries.
- Clients should be kept up-to-date with many small incremental changes to data.
- Creating data needs to be optimistic on every connection (offline, slow 3G, etc), eg. `RequestMoney` or `SplitBill` should work without waiting for a server response.
- For new objects created from the client (reports, reportActions, policies) we're going to generate a random string ID immediately on the client, rather than needing to wait for the server to give us an ID for the created object.
- For new objects created from the client (reports, reportActions, policies), we're going to generate a random string ID immediately on the client, rather than needing to wait for the server to give us an ID for the created object.
- This client-generated ID will become the primary key for that record in the database. This will provide more offline functionality than was previously possible.

## Response Handling
When the web server responds to an API call the response is sent to the server in one of two ways.
When the web server responds to an API call, the response is sent to the server in one of two ways.
1. **HTTPS Response** - Data that is returned with the HTTPS response is only sent to the client that initiated the request.

The network library will look for any `onyxData` in the response and send it straight to `Onyx.update(response.onyxData)`.

1. **Pusher Event** (web socket) - Data returned with a Pusher event is sent to all currently connected clients for the user that made the request, as well as any other necessary participants (eg. like other people in the chat)

Pusher listens for an `onyxApiUpdate` event and sends the data straight to `Onyx.update(pushJSON)`.

### READ Responses
This is a response that returns data from the database.

A READ response is very specific to the client making the request, so it's data is returned with the **HTTPS Response**. This prevents a lot of unnecessary data from being sent to other clients that will never use it.
A READ response is very specific to the client making the request, so its data is returned with the **HTTPS Response**. This prevents a lot of unnecessary data from being sent to other clients that will never use it.

In PHP, the response is added like this:

```php
$response['onyxData'][] = blahblahblah;
```

The data will be returned with the HTTPS response.

### WRITE Responses
This response happens when new data is created in the database.

New data (`jsonCode===200`) should be sent to all connected clients so a **Pusher Event** is used to update another currently connected clients with the new data that was created.

In PHP, the response is added like this:

```php
$onyxUpdate[] = blahblahblah;
```

The data will automatically be sent to the user via Pusher.

#### WRITE Response Errors
When there is an error on a WRITE response (`jsonCode!==200`), the error must come back to the client on the HTTPS response. The error is only relevant to the client that made the request and it wouldn't make sense to send it out to all connected clients.

Error messages should be returned and stored as an object under the `errors` property, keyed by an integer [microtime](https://github.com/Expensify/Web-Expensify/blob/25d056c9c531ea7f12c9bf3283ec554dd5d1d316/lib/Onyx.php#L148-L154). It's also common to store errors keyed by microtime under `errorFields.fieldName`. Use this format when error messages should be saved on a general object but are only relevant to a specific field / key on the object. If absolutely needed, additional error properties can be stored under other, more specific fields that sit at the same level as `errors`:

```php
[
'onyxMethod' => Onyx::METHOD_MERGE,
Expand Down
26 changes: 13 additions & 13 deletions contributingGuides/APPLE_GOOGLE_SIGNIN.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ The redirect URI must match a URI in the Google or Apple client ID configuration

Pop-up mode opens a pop-up window to show the third-party sign-in form. But it also changes how tokens are given to the client app. Instead of an HTTPS request, they are returned by the JS libraries in memory, either via a callback (Google) or a promise (Apple).

Apple and Google both check that the client app is running on an allowed domain. The sign-in process will fail otherwise. Google allows localhost, but Apple does not, and so testing Apple in development environments requires hosting the client app on a domain that the Apple client ID (or "service ID", in Apple's case) has been configured with.
Apple and Google both check that the client app is running on an allowed domain. The sign-in process will fail otherwise. Google allows `localhost`, but Apple does not, and so testing Apple in development environments requires hosting the client app on a domain that the Apple client ID (or "service ID", in Apple's case) has been configured with.

In the case of Apple, sometimes it will silently fail at the very end of the sign-in process, where the only sign that something is wrong is that the pop-up fails to close. In this case, it's very likely that configuration mismatch is the issue.

Expand Down Expand Up @@ -125,24 +125,24 @@ If you need to check that you received the correct data, check it on [jwt.io](ht

Hardcode this token into `Session.beginAppleSignIn`, and but also verify a valid token was passed into the function, for example:

```
```js
function beginAppleSignIn(idToken) {
+ // Show that a token was passed in, without logging the token, for privacy
+ window.alert(`ORIGINAL ID TOKEN LENGTH: ${idToken.length}`);
+ const hardcodedToken = '...';
// Show that a token was passed in, without logging the token, for privacy
window.alert(`ORIGINAL ID TOKEN LENGTH: ${idToken.length}`);
const hardcodedToken = '...';
const {optimisticData, successData, failureData} = signInAttemptState();
+ API.write('SignInWithApple', {idToken: hardcodedToken}, {optimisticData, successData, failureData});
- API.write('SignInWithApple', {idToken}, {optimisticData, successData, failureData});
API.write('SignInWithApple', {idToken: hardcodedToken}, {optimisticData, successData, failureData});
API.write('SignInWithApple', {idToken}, {optimisticData, successData, failureData});
}
```

#### Configure the SSH tunneling

You can use any SSH tunneling service that allows you to configure custom subdomains so that we have a consistent address to use. We'll use ngrok in these examples, but ngrok requires a paid account for this. If you need a free option, try serveo.net.
You can use any SSH tunneling service that allows you to configure custom subdomains so that we have a consistent address to use. We'll use ngrok in these examples, but ngrok requires a paid account for this. If you need a free option, try [serveo.net](https://serveo.net).

After you've set ngrok up to be able to run on your machine (requires configuring a key with the command line tool, instructions provided by the ngrok website after you create an account), test hosting the web app on a custom subdomain. This example assumes the development web app is running at `dev.new.expensify.com:8082`:

```
```shell
ngrok http 8082 --host-header="dev.new.expensify.com:8082" --subdomain=mysubdomain
```

Expand Down Expand Up @@ -183,7 +183,7 @@ Desktop will require the same configuration, with these additional steps:

#### Configure web app URL in .env

Add `NEW_EXPENSIFY_URL` to .env, and set it to the HTTPS URL where the web app can be found, for example:
Add `NEW_EXPENSIFY_URL` to `.env`, and set it to the HTTPS URL where the web app can be found, for example:

```
NEW_EXPENSIFY_URL=https://subdomain.ngrok-free.app
Expand All @@ -195,23 +195,23 @@ Note that changing this value to a domain that isn't configured for use with Exp

#### Set Environment to something other than "Development"

The DeepLinkWrapper component will not handle deep links in the development environment. To be able to test deep linking, you must set the environment to something other than "Development".
The `DeepLinkWrapper` component will not handle deep links in the development environment. To be able to test deep linking, you must set the environment to something other than "Development".

Within the `.env` file, set `envName` to something other than "Development", for example:

```
envName=Staging
```

Alternatively, within the `DeepLinkWrapper/index.website.js` file you can set the `CONFIG.ENVIRONMENT` to something other than "Development".
Alternatively, within the `DeepLinkWrapper/index.website.js` file, you can set the `CONFIG.ENVIRONMENT` to something other than "Development".

#### Handle deep links in dev on MacOS

If developing on MacOS, the development desktop app can't handle deeplinks correctly. To be able to test deeplinking back to the app, follow these steps:

1. Create a "real" build of the desktop app, which can handle deep links, open the build folder, and install the dmg there:

```
```shell
npm run desktop-build
open desktop-build
# Then double-click "NewExpensify.dmg" in Finder window
Expand Down
Loading

0 comments on commit 533a8af

Please sign in to comment.