Skip to content

Commit

Permalink
Merge remote-tracking branch 'expensify/main' into upgrade-react-nati…
Browse files Browse the repository at this point in the history
…ve-web
  • Loading branch information
getusha committed Aug 24, 2023
1 parent 02aa981 commit d7a3667
Show file tree
Hide file tree
Showing 87 changed files with 974 additions and 204 deletions.
2 changes: 0 additions & 2 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,5 @@ EXPENSIFY_ACCOUNT_ID_QA=-1
EXPENSIFY_ACCOUNT_ID_QA_TRAVIS=-1
EXPENSIFY_ACCOUNT_ID_RECEIPTS=-1
EXPENSIFY_ACCOUNT_ID_REWARDS=-1
EXPENSIFY_ACCOUNT_ID_SAASTR=-1
EXPENSIFY_ACCOUNT_ID_SBE=-1
EXPENSIFY_ACCOUNT_ID_STUDENT_AMBASSADOR=-1
EXPENSIFY_ACCOUNT_ID_SVFG=-1
6 changes: 3 additions & 3 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ react {
// The list of variants to that are debuggable. For those we're going to
// skip the bundling of the JS bundle and the assets. By default is just 'debug'.
// If you add flavors like lite, prod, etc. you'll have to list your debuggableVariants.
// debuggableVariants = ["liteDebug", "prodDebug"]
debuggableVariants = ["developmentDebug"]

/* Bundling */
// A list containing the node command and its flags. Default is just 'node'.
Expand Down Expand Up @@ -90,8 +90,8 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
multiDexEnabled rootProject.ext.multiDexEnabled
versionCode 1001035619
versionName "1.3.56-19"
versionCode 1001035702
versionName "1.3.57-2"
}

flavorDimensions "default"
Expand Down
18 changes: 18 additions & 0 deletions assets/images/expensify-app-icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
37 changes: 34 additions & 3 deletions contributingGuides/TS_STYLE.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
- [1.16 Reusable Types](#reusable-types)
- [1.17 `.tsx`](#tsx)
- [1.18 No inline prop types](#no-inline-prop-types)
- [1.19 Satisfies operator](#satisfies-operator)
- [Exception to Rules](#exception-to-rules)
- [Communication Items](#communication-items)
- [Migration Guidelines](#migration-guidelines)
Expand Down Expand Up @@ -101,7 +102,7 @@ type Foo = {

<a name="d-ts-extension"></a><a name="1.2"></a>

- [1.2](#d-ts-extension) **`d.ts` Extension**: Do not use `d.ts` file extension even when a file contains only type declarations. Only exception is the `global.d.ts` file in which third party packages can be modified using module augmentation. Refer to the [Communication Items](#communication-items) section to learn more about module augmentation.
- [1.2](#d-ts-extension) **`d.ts` Extension**: Do not use `d.ts` file extension even when a file contains only type declarations. Only exceptions are `src/types/global.d.ts` and `src/types/modules/*.d.ts` files in which third party packages can be modified using module augmentation. Refer to the [Communication Items](#communication-items) section to learn more about module augmentation.
> Why? Type errors in `d.ts` files are not checked by TypeScript [^1].
Expand Down Expand Up @@ -358,7 +359,7 @@ type Foo = {

<a name="file-organization"></a><a name="1.15"></a>

- [1.15](#file-organization) **File organization**: In modules with platform-specific implementations, create `types.ts` to define shared types. Import and use shared types in each platform specific files.
- [1.15](#file-organization) **File organization**: In modules with platform-specific implementations, create `types.ts` to define shared types. Import and use shared types in each platform specific files. Do not use [`satisfies` operator](#satisfies-operator) for platform-specific implementations, always define shared types that complies with all variants.

> Why? To encourage consistent API across platform-specific implementations. If you're migrating module that doesn't have a default implement (i.e. `index.ts`, e.g. `getPlatform`), refer to [Migration Guidelines](#migration-guidelines) for further information.
Expand Down Expand Up @@ -458,6 +459,34 @@ type Foo = {
}
```

<a name="satisfies-operator"></a><a name="1.19"></a>

- [1.19](#satisfies-operator) **Satisfies Operator**: Use the `satisfies` operator when you need to validate that the structure of an expression matches a specific type, without affecting the resulting type of the expression.

> Why? TypeScript developers often want to ensure that an expression aligns with a certain type, but they also want to retain the most specific type possible for inference purposes. The `satisfies` operator assists in doing both.
```ts
// BAD
const sizingStyles = {
w50: {
width: '50%',
},
mw100: {
maxWidth: '100%',
},
} as const;

// GOOD
const sizingStyles = {
w50: {
width: '50%',
},
mw100: {
maxWidth: '100%',
},
} satisfies Record<string, ViewStyle>;
```

## Exception to Rules

Most of the rules are enforced in ESLint or checked by TypeScript. If you think your particular situation warrants an exception, post the context in the `#expensify-open-source` Slack channel with your message prefixed with `TS EXCEPTION:`. The internal engineer assigned to the PR should be the one that approves each exception, however all discussion regarding granting exceptions should happen in the public channel instead of the GitHub PR page so that the TS migration team can access them easily.
Expand All @@ -472,9 +501,11 @@ This rule will apply until the migration is done. After the migration, discussio
- I think types definitions in a third party library is incomplete or incorrect

When the library indeed contains incorrect or missing type definitions and it cannot be updated, use module augmentation to correct them. All module augmentation code should be contained in `/src/global.d.ts`.
When the library indeed contains incorrect or missing type definitions and it cannot be updated, use module augmentation to correct them. All module augmentation code should be contained in `/src/types/modules/*.d.ts`, each library as a separate file.

```ts
// external-library-name.d.ts

declare module "external-library-name" {
interface LibraryComponentProps {
// Add or modify typings
Expand Down
17 changes: 17 additions & 0 deletions docs/Card-Rev-Share-for-Approved-Partners.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
title: Expensify Card revenue share for ExpensifyApproved! partners
description: Earn money when your clients adopt the Expensify Card
---
<!-- The lines above are required by Jekyll to process the .md file -->

# About
Start making more with us! We're thrilled to announce a new incentive for our US-based ExpensifyApproved! partner accountants. You can now earn additional income for your firm every time your client uses their Expensify Card. We're offering 0.5% of the total Expensify Card spend of your clients in cashback returned to your firm. The more your clients spend, the more cashback your firm receives!<br>
<br>This program is currently only available to US-based ExpensifyApproved! partner accountants.

# How-to
To benefit from this program, all you need to do is ensure that you are listed as a domain admin on your client's Expensify account. If you're not currently a domain admin, your client can follow the instructions outlined in [our help article](https://community.expensify.com/discussion/5749/how-to-add-and-remove-domain-admins#:~:text=Domain%20Admins%20have%20total%20control,a%20member%20of%20the%20domain.) to assign you this role.
# FAQ
- What if my firm is not permitted to accept revenue share from our clients? <br>
<br>We understand that different firms may have different policies. If your firm is unable to accept this revenue share, you can pass the revenue share back to your client to give them an additional 0.5% of cash back using your own internal payment tools.<br><br>
- What if my firm does not wish to participate in the program? <br>
<br>Please reach out to your assigned partner manager at new.expensify.com to inform them you would not like to accept the revenue share nor do you want to pass the revenue share to your clients.
4 changes: 2 additions & 2 deletions ios/NewExpensify/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.3.56</string>
<string>1.3.57</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>
Expand All @@ -40,7 +40,7 @@
</dict>
</array>
<key>CFBundleVersion</key>
<string>1.3.56.19</string>
<string>1.3.57.2</string>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<key>LSApplicationQueriesSchemes</key>
Expand Down
4 changes: 2 additions & 2 deletions ios/NewExpensifyTests/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.3.56</string>
<string>1.3.57</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.3.56.19</string>
<string>1.3.57.2</string>
</dict>
</plist>
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "new.expensify",
"version": "1.3.56-19",
"version": "1.3.57-2",
"author": "Expensify, Inc.",
"homepage": "https://new.expensify.com",
"description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.",
Expand Down
18 changes: 18 additions & 0 deletions patches/react-native+0.72.3+004+ModalKeyboardFlashing.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
diff --git a/node_modules/react-native/React/Views/RCTModalHostViewManager.m b/node_modules/react-native/React/Views/RCTModalHostViewManager.m
index 4b9f9ad..b72984c 100644
--- a/node_modules/react-native/React/Views/RCTModalHostViewManager.m
+++ b/node_modules/react-native/React/Views/RCTModalHostViewManager.m
@@ -79,6 +79,13 @@ RCT_EXPORT_MODULE()
if (self->_presentationBlock) {
self->_presentationBlock([modalHostView reactViewController], viewController, animated, completionBlock);
} else {
+ // In our App, If an input is blurred and a modal is opened, the rootView will become the firstResponder, which
+ // will cause system to retain a wrong keyboard state, and then the keyboard to flicker when the modal is closed.
+ // We first resign the rootView to avoid this problem.
+ UIWindow *window = RCTKeyWindow();
+ if (window && window.rootViewController && [window.rootViewController.view isFirstResponder]) {
+ [window.rootViewController.view resignFirstResponder];
+ }
[[modalHostView reactViewController] presentViewController:viewController
animated:animated
completion:completionBlock];
11 changes: 3 additions & 8 deletions src/CONST.js
Original file line number Diff line number Diff line change
Expand Up @@ -663,6 +663,7 @@ const CONST = {
SYSTEM: 'system',
},
TRANSACTION: {
DEFAULT_MERCHANT: 'Request',
TYPE: {
CUSTOM_UNIT: 'customUnit',
},
Expand Down Expand Up @@ -899,8 +900,6 @@ const CONST = {
QA_TRAVIS: Number(lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_QA_TRAVIS', 8595733)),
RECEIPTS: Number(lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_RECEIPTS', -1)),
REWARDS: Number(lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_REWARDS', 11023767)), // rewards@expensify.com
SAASTR: Number(lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_SAASTR', 15252830)),
SBE: Number(lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_SBE', 15305309)),
STUDENT_AMBASSADOR: Number(lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_STUDENT_AMBASSADOR', 10476956)),
SVFG: Number(lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_SVFG', 2012843)),
},
Expand Down Expand Up @@ -1148,8 +1147,8 @@ const CONST = {
REGEX: {
SPECIAL_CHARS_WITHOUT_NEWLINE: /((?!\n)[()-\s\t])/g,
DIGITS_AND_PLUS: /^\+?[0-9]*$/,
ALPHABETIC_AND_LATIN_CHARS: /^[a-zA-ZÀ-ÿ ]*$/,
NON_ALPHABETIC_AND_NON_LATIN_CHARS: /[^a-zA-ZÀ-ÿ]/g,
ALPHABETIC_AND_LATIN_CHARS: /^[\p{Script=Latin} ]*$/u,
NON_ALPHABETIC_AND_NON_LATIN_CHARS: /[^\p{Script=Latin}]/gu,
POSITIVE_INTEGER: /^\d+$/,
PO_BOX: /\b[P|p]?(OST|ost)?\.?\s*[O|o|0]?(ffice|FFICE)?\.?\s*[B|b][O|o|0]?[X|x]?\.?\s+[#]?(\d+)\b/,
ANY_VALUE: /^.+$/,
Expand Down Expand Up @@ -1237,8 +1236,6 @@ const CONST = {
this.EMAIL.QA,
this.EMAIL.QA_TRAVIS,
this.EMAIL.RECEIPTS,
this.EMAIL.SAASTR,
this.EMAIL.SBE,
this.EMAIL.STUDENT_AMBASSADOR,
this.EMAIL.SVFG,
];
Expand All @@ -1259,8 +1256,6 @@ const CONST = {
this.ACCOUNT_ID.QA_TRAVIS,
this.ACCOUNT_ID.RECEIPTS,
this.ACCOUNT_ID.REWARDS,
this.ACCOUNT_ID.SAASTR,
this.ACCOUNT_ID.SBE,
this.ACCOUNT_ID.STUDENT_AMBASSADOR,
this.ACCOUNT_ID.SVFG,
];
Expand Down
2 changes: 2 additions & 0 deletions src/Expensify.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import AppleAuthWrapper from './components/SignInButtons/AppleAuthWrapper';
import EmojiPicker from './components/EmojiPicker/EmojiPicker';
import * as EmojiPickerAction from './libs/actions/EmojiPickerAction';
import * as DemoActions from './libs/actions/DemoActions';
import DownloadAppModal from './components/DownloadAppModal';
import DeeplinkWrapper from './components/DeeplinkWrapper';

// This lib needs to be imported, but it has nothing to export since all it contains is an Onyx connection
Expand Down Expand Up @@ -198,6 +199,7 @@ function Expensify(props) {
<KeyboardShortcutsModal />
<GrowlNotification ref={Growl.growlRef} />
<PopoverReportActionContextMenu ref={ReportActionContextMenu.contextMenuRef} />
<DownloadAppModal />
<EmojiPicker ref={EmojiPickerAction.emojiPickerRef} />
{/* We include the modal for showing a new update at the top level so the option is always present. */}
{props.updateAvailable ? <UpdateAppModal /> : null}
Expand Down
4 changes: 4 additions & 0 deletions src/ONYXKEYS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@ const ONYXKEYS = {
SESSION: 'session',
BETAS: 'betas',

/** Denotes if the Download App Banner has been dismissed */
SHOW_DOWNLOAD_APP_BANNER: 'showDownloadAppBanner',

/** NVP keys
* Contains the user's payPalMe data */
PAYPAL: 'paypal',
Expand Down Expand Up @@ -286,6 +289,7 @@ type OnyxValues = {
[ONYXKEYS.ACTIVE_CLIENTS]: string[];
[ONYXKEYS.DEVICE_ID]: string;
[ONYXKEYS.IS_SIDEBAR_LOADED]: boolean;
[ONYXKEYS.SHOW_DOWNLOAD_APP_BANNER]: boolean;
[ONYXKEYS.PERSISTED_REQUESTS]: OnyxTypes.Request[];
[ONYXKEYS.QUEUED_ONYX_UPDATES]: OnyxTypes.QueuedOnyxUpdates;
[ONYXKEYS.CURRENT_DATE]: string;
Expand Down
7 changes: 6 additions & 1 deletion src/ROUTES.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ export default {
MONEY_REQUEST_DATE: ':iouType/new/date/:reportID?',
MONEY_REQUEST_CURRENCY: ':iouType/new/currency/:reportID?',
MONEY_REQUEST_DESCRIPTION: ':iouType/new/description/:reportID?',
MONEY_REQUEST_CATEGORY: ':iouType/new/category/:reportID?',
MONEY_REQUEST_MERCHANT: ':iouType/new/merchant/:reportID?',
MONEY_REQUEST_MANUAL_TAB: ':iouType/new/:reportID?/manual',
MONEY_REQUEST_SCAN_TAB: ':iouType/new/:reportID?/scan',
Expand All @@ -106,6 +107,7 @@ export default {
getMoneyRequestCreatedRoute: (iouType, reportID = '') => `${iouType}/new/date/${reportID}`,
getMoneyRequestCurrencyRoute: (iouType, reportID = '', currency, backTo) => `${iouType}/new/currency/${reportID}?currency=${currency}&backTo=${backTo}`,
getMoneyRequestDescriptionRoute: (iouType, reportID = '') => `${iouType}/new/description/${reportID}`,
getMoneyRequestCategoryRoute: (iouType, reportID = '') => `${iouType}/new/category/${reportID}`,
getMoneyRequestMerchantRoute: (iouType, reportID = '') => `${iouType}/new/merchant/${reportID}`,
getMoneyRequestDistanceTabRoute: (iouType, reportID = '') => `${iouType}/new/${reportID}/distance`,
getMoneyRequestWaypointRoute: (iouType, waypointIndex) => `${iouType}/new/waypoint/${waypointIndex}`,
Expand All @@ -130,7 +132,10 @@ export default {
DETAILS: 'details',
getDetailsRoute: (login) => `details?login=${encodeURIComponent(login)}`,
PROFILE: 'a/:accountID',
getProfileRoute: (accountID) => `a/${accountID}`,
getProfileRoute: (accountID, backTo = '') => {
const backToParam = backTo ? `?backTo=${encodeURIComponent(backTo)}` : '';
return `a/${accountID}${backToParam}`;
},
REPORT_PARTICIPANTS: 'r/:reportID/participants',
getReportParticipantsRoute: (reportID) => `r/${reportID}/participants`,
REPORT_WITH_ID_DETAILS: 'r/:reportID/details',
Expand Down
2 changes: 1 addition & 1 deletion src/SCREENS.js → src/SCREENS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ export default {
},
SIGN_IN_WITH_APPLE_DESKTOP: 'AppleSignInDesktop',
SIGN_IN_WITH_GOOGLE_DESKTOP: 'GoogleSignInDesktop',
};
} as const;
13 changes: 11 additions & 2 deletions src/components/AttachmentPicker/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ function getAcceptableFileTypes(type) {
function AttachmentPicker(props) {
const fileInput = useRef();
const onPicked = useRef();
const onCanceled = useRef(() => {});

return (
<>
<input
Expand All @@ -46,13 +48,20 @@ function AttachmentPicker(props) {
}}
// We are stopping the event propagation because triggering the `click()` on the hidden input
// causes the event to unexpectedly bubble up to anything wrapping this component e.g. Pressable
onClick={(e) => e.stopPropagation()}
onClick={(e) => {
e.stopPropagation();
if (!fileInput.current) {
return;
}
fileInput.current.addEventListener('cancel', () => onCanceled.current(), {once: true});
}}
accept={getAcceptableFileTypes(props.type)}
/>
{props.children({
openPicker: ({onPicked: newOnPicked}) => {
openPicker: ({onPicked: newOnPicked, onCanceled: newOnCanceled = () => {}}) => {
onPicked.current = newOnPicked;
fileInput.current.click();
onCanceled.current = newOnCanceled;
},
})}
</>
Expand Down
Loading

0 comments on commit d7a3667

Please sign in to comment.