Skip to content

Commit

Permalink
merge main
Browse files Browse the repository at this point in the history
  • Loading branch information
srikarparsi committed Dec 31, 2024
2 parents f257065 + c4b3297 commit 06eb9c7
Show file tree
Hide file tree
Showing 98 changed files with 2,156 additions and 470 deletions.
2 changes: 1 addition & 1 deletion Mobile-Expensify
4 changes: 2 additions & 2 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,8 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
multiDexEnabled rootProject.ext.multiDexEnabled
versionCode 1009007901
versionName "9.0.79-1"
versionCode 1009007905
versionName "9.0.79-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
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,16 @@ Expensify makes it easy to receive bills in three simple ways:
Share your Expensify billing email with vendors to receive bills automatically.

- Set a Primary Contact under **Settings > Domains > Domain Admins**.
- Ask vendors to email bills to your billing address: `[email protected]` (e.g., for *expensify.com*, use `expensify@expensify.cash`).
- Ask vendors to email bills to your billing address: `[email protected]` (e.g., for *expensicorp.com*, use `expensicorp@expensify.cash`).
- Once emailed, the bill is automatically created in Expensify, ready for payment.

![Setting the Primary Contact at Domain Admins > Primary Contact](https://help.expensify.com/assets/images/OldDot%20-%20Create%20%26%20Pay%20Bills%201.png){:width="100%"}

### 2. Forwarding Emails
Received a bill in your email? Forward it to Expensify.

- Ensure your Primary Contact is set under **Settings > Domains > Domain Admins**.
- Forward bills to `[email protected]`. Example: `[email protected]` (e.g., for *expensify.com*, use `expensify@expensify.cash`).
- Forward bills to `[email protected]`. Example: `[email protected]` (e.g., for *expensicorp.com*, use `expensicorp@expensify.cash`).
- Expensify will create a bill automatically, ready for payment.

### 3. Manual Upload
Expand All @@ -31,6 +33,7 @@ Got a paper bill? Create a bill manually in [Expensify](https://www.expensify.co
3. Enter the invoice details: sender’s email, merchant name, amount, and date.
4. Upload the invoice as a receipt.

![Manually Create a Bill](https://help.expensify.com/assets/images/OldDot%20-%20Create%20%26%20Pay%20Bills%202.png){:width="100%"}

# Paying Bills in Expensify

Expand All @@ -44,6 +47,8 @@ Expensify makes it easy to manage and pay vendor bills with a straightforward wo
4. **Approval Workflow**: Once reviewed, the bill follows your workspace’s approval process. The final approver handles the payment.
5. **Accounting Integration**: During approval, the bill is coded with the correct GL codes from your connected accounting software. Once approved, it can be exported back to your accounting system.

![Paying a Bill](https://help.expensify.com/assets/images/OldDot%20-%20Create%20%26%20Pay%20Bills%203.png){:width="100%"}

## Payment Methods

Expensify offers several ways to pay bills. Choose the method that works best for you:
Expand Down Expand Up @@ -92,20 +97,27 @@ If you prefer to pay outside Expensify, you can still track the payment within t
3. Select **Mark as Paid** to update its status.

**Fees:** None.

{% include faq-begin.md %}

## Who receives vendor bills in Expensify?
bills are sent to the Primary Contact listed under **Settings > Domains > [Domain Name] > Domain Admins**.

Bills are sent to the Primary Contact listed under **Settings > Domains > [Domain Name] > Domain Admins**.

## Who can view and pay a bill?

Only the primary domain contact can view and pay a bill.

## How can others access bills?

The primary contact can share bills or grant Copilot access for others to manage payments.

## Is bill Pay supported internationally?

Currently, payments are only supported in USD.

## What's the difference between a bill and an Invoice in Expensify?

A bill represents a payable amount owed to a vendor, while an Invoice is a receivable amount owed to you.

{% include faq-end.md %}
2 changes: 1 addition & 1 deletion ios/NewExpensify/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
</dict>
</array>
<key>CFBundleVersion</key>
<string>9.0.79.1</string>
<string>9.0.79.5</string>
<key>FullStory</key>
<dict>
<key>OrgId</key>
Expand Down
2 changes: 1 addition & 1 deletion ios/NewExpensifyTests/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>9.0.79.1</string>
<string>9.0.79.5</string>
</dict>
</plist>
2 changes: 1 addition & 1 deletion ios/NotificationServiceExtension/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<key>CFBundleShortVersionString</key>
<string>9.0.79</string>
<key>CFBundleVersion</key>
<string>9.0.79.1</string>
<string>9.0.79.5</string>
<key>NSExtension</key>
<dict>
<key>NSExtensionPointIdentifier</key>
Expand Down
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": "9.0.79-1",
"version": "9.0.79-5",
"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
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
diff --git a/node_modules/react-native-reanimated/src/mock.ts b/node_modules/react-native-reanimated/src/mock.ts
index 3d8e3f8..5eba613 100644
--- a/node_modules/react-native-reanimated/src/mock.ts
+++ b/node_modules/react-native-reanimated/src/mock.ts
@@ -87,7 +87,12 @@ const hook = {
useAnimatedReaction: NOOP,
useAnimatedRef: () => ({ current: null }),
useAnimatedScrollHandler: NOOP_FACTORY,
- useDerivedValue: <Value>(processor: () => Value) => ({ value: processor() }),
+ // https://github.com/software-mansion/react-native-reanimated/pull/6809
+ useDerivedValue: <Value>(processor: () => Value) => {
+ const result = processor();
+
+ return { value: result, get: () => result };
+ },
useAnimatedSensor: () => ({
sensor: {
value: {
2 changes: 2 additions & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {GestureHandlerRootView} from 'react-native-gesture-handler';
import {PickerStateProvider} from 'react-native-picker-select';
import {SafeAreaProvider} from 'react-native-safe-area-context';
import '../wdyr';
import * as ActionSheetAwareScrollView from './components/ActionSheetAwareScrollView';
import ActiveElementRoleProvider from './components/ActiveElementRoleProvider';
import ActiveWorkspaceContextProvider from './components/ActiveWorkspaceProvider';
import ColorSchemeWrapper from './components/ColorSchemeWrapper';
Expand Down Expand Up @@ -89,6 +90,7 @@ function App({url}: AppProps) {
CustomStatusBarAndBackgroundContextProvider,
ActiveElementRoleProvider,
ActiveWorkspaceContextProvider,
ActionSheetAwareScrollView.ActionSheetAwareScrollViewProvider,
ReportIDsContextProvider,
PlaybackContextProvider,
FullScreenContextProvider,
Expand Down
1 change: 1 addition & 0 deletions src/CONFIG.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,4 +104,5 @@ export default {
// to read more about StrictMode see: contributingGuides/STRICT_MODE.md
USE_REACT_STRICT_MODE_IN_DEV: false,
ELECTRON_DISABLE_SECURITY_WARNINGS: 'true',
IS_TEST_ENV: process.env.NODE_ENV === 'test',
} as const;
1 change: 1 addition & 0 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -665,6 +665,7 @@ const CONST = {
HANG_TIGHT: 4,
},
},
BANK_INFO_STEP_ACCOUNT_HOLDER_KEY_PREFIX: 'accountHolder',
},
INCORPORATION_TYPES: {
LLC: 'LLC',
Expand Down
4 changes: 4 additions & 0 deletions src/ONYXKEYS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,9 @@ const ONYXKEYS = {
/** The user's Concierge reportID */
CONCIERGE_REPORT_ID: 'conciergeReportID',

/* Corpay fieds to be used in the bank account creation setup */
CORPAY_FIELDS: 'corpayFields',

/** The user's session that will be preserved when using imported state */
PRESERVED_USER_SESSION: 'preservedUserSession',

Expand Down Expand Up @@ -1027,6 +1030,7 @@ type OnyxValuesMapping = {
[ONYXKEYS.IS_USING_IMPORTED_STATE]: boolean;
[ONYXKEYS.NVP_EXPENSIFY_COMPANY_CARDS_CUSTOM_NAMES]: Record<string, string>;
[ONYXKEYS.CONCIERGE_REPORT_ID]: string;
[ONYXKEYS.CORPAY_FIELDS]: OnyxTypes.CorpayFields;
[ONYXKEYS.PRESERVED_USER_SESSION]: OnyxTypes.Session;
[ONYXKEYS.NVP_DISMISSED_PRODUCT_TRAINING]: OnyxTypes.DismissedProductTraining;
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import noop from 'lodash/noop';
import PropTypes from 'prop-types';
import type {PropsWithChildren} from 'react';
import React, {createContext, useMemo} from 'react';
import type {SharedValue} from 'react-native-reanimated';
import type {ActionWithPayload, State} from '@hooks/useWorkletStateMachine';
import useWorkletStateMachine from '@hooks/useWorkletStateMachine';

type MeasuredElements = {
fy?: number;
popoverHeight?: number;
height?: number;
composerHeight?: number;
};

type Context = {
currentActionSheetState: SharedValue<State<MeasuredElements>>;
transitionActionSheetState: (action: ActionWithPayload) => void;
transitionActionSheetStateWorklet: (action: ActionWithPayload) => void;
resetStateMachine: () => void;
};

/** Holds all information that are needed to coordinate the state value for the action sheet state machine. */
const currentActionSheetStateValue = {
previous: {
state: 'idle',
payload: null,
},
current: {
state: 'idle',
payload: null,
},
};
const defaultValue: Context = {
currentActionSheetState: {
value: currentActionSheetStateValue,
addListener: noop,
removeListener: noop,
modify: noop,
get: () => currentActionSheetStateValue,
set: noop,
},
transitionActionSheetState: noop,
transitionActionSheetStateWorklet: noop,
resetStateMachine: noop,
};

const ActionSheetAwareScrollViewContext = createContext<Context>(defaultValue);

const Actions = {
OPEN_KEYBOARD: 'KEYBOARD_OPEN',
CLOSE_KEYBOARD: 'CLOSE_KEYBOARD',
OPEN_POPOVER: 'OPEN_POPOVER',
CLOSE_POPOVER: 'CLOSE_POPOVER',
MEASURE_POPOVER: 'MEASURE_POPOVER',
MEASURE_COMPOSER: 'MEASURE_COMPOSER',
POPOVER_ANY_ACTION: 'POPOVER_ANY_ACTION',
HIDE_WITHOUT_ANIMATION: 'HIDE_WITHOUT_ANIMATION',
END_TRANSITION: 'END_TRANSITION',
};

const States = {
IDLE: 'idle',
KEYBOARD_OPEN: 'keyboardOpen',
POPOVER_OPEN: 'popoverOpen',
POPOVER_CLOSED: 'popoverClosed',
KEYBOARD_POPOVER_CLOSED: 'keyboardPopoverClosed',
KEYBOARD_POPOVER_OPEN: 'keyboardPopoverOpen',
KEYBOARD_CLOSED_POPOVER: 'keyboardClosingPopover',
POPOVER_MEASURED: 'popoverMeasured',
MODAL_WITH_KEYBOARD_OPEN_DELETED: 'modalWithKeyboardOpenDeleted',
};

const STATE_MACHINE = {
[States.IDLE]: {
[Actions.OPEN_POPOVER]: States.POPOVER_OPEN,
[Actions.OPEN_KEYBOARD]: States.KEYBOARD_OPEN,
[Actions.MEASURE_POPOVER]: States.IDLE,
[Actions.MEASURE_COMPOSER]: States.IDLE,
},
[States.POPOVER_OPEN]: {
[Actions.CLOSE_POPOVER]: States.POPOVER_CLOSED,
[Actions.MEASURE_POPOVER]: States.POPOVER_OPEN,
[Actions.MEASURE_COMPOSER]: States.POPOVER_OPEN,
[Actions.POPOVER_ANY_ACTION]: States.POPOVER_CLOSED,
[Actions.HIDE_WITHOUT_ANIMATION]: States.IDLE,
},
[States.POPOVER_CLOSED]: {
[Actions.END_TRANSITION]: States.IDLE,
},
[States.KEYBOARD_OPEN]: {
[Actions.OPEN_KEYBOARD]: States.KEYBOARD_OPEN,
[Actions.OPEN_POPOVER]: States.KEYBOARD_POPOVER_OPEN,
[Actions.CLOSE_KEYBOARD]: States.IDLE,
[Actions.MEASURE_COMPOSER]: States.KEYBOARD_OPEN,
},
[States.KEYBOARD_POPOVER_OPEN]: {
[Actions.MEASURE_POPOVER]: States.KEYBOARD_POPOVER_OPEN,
[Actions.CLOSE_POPOVER]: States.KEYBOARD_CLOSED_POPOVER,
[Actions.OPEN_KEYBOARD]: States.KEYBOARD_OPEN,
},
[States.KEYBOARD_POPOVER_CLOSED]: {
[Actions.OPEN_KEYBOARD]: States.KEYBOARD_OPEN,
},
[States.KEYBOARD_CLOSED_POPOVER]: {
[Actions.OPEN_KEYBOARD]: States.KEYBOARD_OPEN,
[Actions.END_TRANSITION]: States.KEYBOARD_OPEN,
},
};

function ActionSheetAwareScrollViewProvider(props: PropsWithChildren<unknown>) {
const {currentState, transition, transitionWorklet, reset} = useWorkletStateMachine<MeasuredElements>(STATE_MACHINE, {
previous: {
state: 'idle',
payload: null,
},
current: {
state: 'idle',
payload: null,
},
});

const value = useMemo(
() => ({
currentActionSheetState: currentState,
transitionActionSheetState: transition,
transitionActionSheetStateWorklet: transitionWorklet,
resetStateMachine: reset,
}),
[currentState, reset, transition, transitionWorklet],
);

return <ActionSheetAwareScrollViewContext.Provider value={value}>{props.children}</ActionSheetAwareScrollViewContext.Provider>;
}

ActionSheetAwareScrollViewProvider.propTypes = {
children: PropTypes.node.isRequired,
};

export {ActionSheetAwareScrollViewContext, ActionSheetAwareScrollViewProvider, Actions, States};
Loading

0 comments on commit 06eb9c7

Please sign in to comment.