diff --git a/STORYBOOK.md b/STORYBOOK.md
index 1950e839e877..cb4cf290a77a 100644
--- a/STORYBOOK.md
+++ b/STORYBOOK.md
@@ -38,7 +38,7 @@ Here's an example story:
import React from 'react';
import Button from '../components/Button';
-export default {
+const story = {
// Title field will determine how the story displays in the sidebar
title: 'Components/Button',
component: Button,
@@ -48,11 +48,16 @@ export default {
const Template = args => ;
// Each story must be exported with a named export
-export const Default = Template.bind({});
+const Default = Template.bind({});
Default.args = {
text: 'Save & Continue',
success: true,
};
+
+export default story;
+export {
+ Default,
+};
```
That will give us an interactive playground to test out various component attributes with the defaults we passed.
diff --git a/STYLE.md b/STYLE.md
index b15901826e7e..def3507a8c3d 100644
--- a/STYLE.md
+++ b/STYLE.md
@@ -264,7 +264,23 @@ ES6 provides two ways to export a module from a file: `named export` and `defaul
- Files with multiple exports should always use named exports
- Files with a single method or variable export are OK to use named exports
- Mixing default and named exports in a single file is OK (e.g. in a self contained module), but should rarely be used
-- All exports should be declared at the bottom of the file
+- All exports (both default and named) should happen at the bottom of the file
+- Do **not** export individual features inline.
+
+```javascript
+// Bad
+export const something = 'nope';
+export const somethingElse = 'stop';
+
+// Good
+const something = 'yep';
+const somethingElse = 'go';
+
+export {
+ something,
+ somethingElse,
+};
+```
## Classes and constructors
diff --git a/__mocks__/react-native-permissions.js b/__mocks__/react-native-permissions.js
index e0355503f1e0..4c8b838466e2 100644
--- a/__mocks__/react-native-permissions.js
+++ b/__mocks__/react-native-permissions.js
@@ -3,12 +3,12 @@ const {RESULTS} = require('react-native-permissions/dist/commonjs/results');
export {PERMISSIONS, RESULTS};
-export const openLimitedPhotoLibraryPicker = jest.fn((() => {}));
-export const openSettings = jest.fn(() => {});
-export const check = jest.fn(() => RESULTS.GRANTED);
-export const request = jest.fn(() => RESULTS.GRANTED);
-export const checkLocationAccuracy = jest.fn(() => 'full');
-export const requestLocationAccuracy = jest.fn(() => 'full');
+const openLimitedPhotoLibraryPicker = jest.fn((() => {}));
+const openSettings = jest.fn(() => {});
+const check = jest.fn(() => RESULTS.GRANTED);
+const request = jest.fn(() => RESULTS.GRANTED);
+const checkLocationAccuracy = jest.fn(() => 'full');
+const requestLocationAccuracy = jest.fn(() => 'full');
const notificationOptions = ['alert', 'badge', 'sound', 'carPlay', 'criticalAlert', 'provisional'];
@@ -23,12 +23,12 @@ const notificationSettings = {
notificationCenter: true,
};
-export const checkNotifications = jest.fn(() => ({
+const checkNotifications = jest.fn(() => ({
status: RESULTS.GRANTED,
settings: notificationSettings,
}));
-export const requestNotifications = jest.fn(options => ({
+const requestNotifications = jest.fn(options => ({
status: RESULTS.GRANTED,
settings: options
.filter(option => notificationOptions.includes(option))
@@ -38,12 +38,12 @@ export const requestNotifications = jest.fn(options => ({
}),
}));
-export const checkMultiple = jest.fn(permissions => permissions.reduce((acc, permission) => ({
+const checkMultiple = jest.fn(permissions => permissions.reduce((acc, permission) => ({
...acc,
[permission]: RESULTS.GRANTED,
})));
-export const requestMultiple = jest.fn(permissions => permissions.reduce((acc, permission) => ({
+const requestMultiple = jest.fn(permissions => permissions.reduce((acc, permission) => ({
...acc,
[permission]: RESULTS.GRANTED,
})));
@@ -63,3 +63,16 @@ export default {
requestMultiple,
requestNotifications,
};
+
+export {
+ openLimitedPhotoLibraryPicker,
+ openSettings,
+ check,
+ request,
+ checkLocationAccuracy,
+ requestLocationAccuracy,
+ checkNotifications,
+ requestNotifications,
+ checkMultiple,
+ requestMultiple,
+};
diff --git a/__mocks__/urbanairship-react-native.js b/__mocks__/urbanairship-react-native.js
index 481cec4e40c9..c4e8a3939325 100644
--- a/__mocks__/urbanairship-react-native.js
+++ b/__mocks__/urbanairship-react-native.js
@@ -1,12 +1,12 @@
-export default {
- setUserNotificationsEnabled: jest.fn(),
-};
-
const EventType = {
NotificationResponse: 'notificationResponse',
PushReceived: 'pushReceived',
};
+export default {
+ setUserNotificationsEnabled: jest.fn(),
+};
+
export {
EventType,
};
diff --git a/android/app/build.gradle b/android/app/build.gradle
index 6d529beb3109..0582a73b82fb 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -150,8 +150,8 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
multiDexEnabled rootProject.ext.multiDexEnabled
- versionCode 1001010813
- versionName "1.1.8-13"
+ versionCode 1001010814
+ versionName "1.1.8-14"
}
splits {
abi {
diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist
index d5f02d84e105..a4ddf4908778 100644
--- a/ios/NewExpensify/Info.plist
+++ b/ios/NewExpensify/Info.plist
@@ -31,7 +31,7 @@
CFBundleVersion
- 1.1.8.13
+ 1.1.8.14
ITSAppUsesNonExemptEncryption
LSApplicationQueriesSchemes
diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist
index 7f72cf0a26f1..ac5b4fb27732 100644
--- a/ios/NewExpensifyTests/Info.plist
+++ b/ios/NewExpensifyTests/Info.plist
@@ -19,6 +19,6 @@
CFBundleSignature
????
CFBundleVersion
- 1.1.8.13
+ 1.1.8.14
diff --git a/package-lock.json b/package-lock.json
index 95eb97a70988..8a39dea6de97 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "new.expensify",
- "version": "1.1.8-13",
+ "version": "1.1.8-14",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/package.json b/package.json
index cb28c5324eae..bbb560739251 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "new.expensify",
- "version": "1.1.8-13",
+ "version": "1.1.8-14",
"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.",
diff --git a/src/components/withDrawerState.js b/src/components/withDrawerState.js
index 91083d8ea362..bd7a0247721e 100644
--- a/src/components/withDrawerState.js
+++ b/src/components/withDrawerState.js
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import {useDrawerStatus} from '@react-navigation/drawer';
import getComponentDisplayName from '../libs/getComponentDisplayName';
-export const withDrawerPropTypes = {
+const withDrawerPropTypes = {
isDrawerOpen: PropTypes.bool.isRequired,
};
@@ -36,3 +36,7 @@ export default function withDrawerState(WrappedComponent) {
));
}
+
+export {
+ withDrawerPropTypes,
+};
diff --git a/src/libs/Growl.js b/src/libs/Growl.js
index 15d46c3402ec..b4915c22bad4 100644
--- a/src/libs/Growl.js
+++ b/src/libs/Growl.js
@@ -1,7 +1,7 @@
import React from 'react';
import CONST from '../CONST';
-export const growlRef = React.createRef();
+const growlRef = React.createRef();
/**
* Show the growl notification
@@ -39,3 +39,7 @@ export default {
error,
success,
};
+
+export {
+ growlRef,
+};
diff --git a/src/libs/Navigation/Navigation.js b/src/libs/Navigation/Navigation.js
index c65d327c50dc..b2f98bba303e 100644
--- a/src/libs/Navigation/Navigation.js
+++ b/src/libs/Navigation/Navigation.js
@@ -21,7 +21,7 @@ Onyx.connect({
callback: val => isLoggedIn = Boolean(val && val.authToken),
});
-export const navigationRef = createNavigationContainerRef();
+const navigationRef = createNavigationContainerRef();
// This flag indicates that we're trying to deeplink to a report when react-navigation is not fully loaded yet.
// If true, this flag will cause the drawer to start in a closed state (which is not the default for small screens)
@@ -204,3 +204,7 @@ export default {
getDefaultDrawerState,
setDidTapNotification,
};
+
+export {
+ navigationRef,
+};
diff --git a/src/libs/canCaptureMetrics/index.js b/src/libs/canCaptureMetrics/index.js
index 420dd2898aee..1e006e0f298c 100644
--- a/src/libs/canCaptureMetrics/index.js
+++ b/src/libs/canCaptureMetrics/index.js
@@ -1,6 +1,11 @@
import CONFIG from '../../CONFIG';
// We don't capture performance metrics on web as there are enough tools available
-export const canCapturePerformanceMetrics = () => false;
+const canCapturePerformanceMetrics = () => false;
-export const canCaptureOnyxMetrics = () => Boolean(CONFIG.ONYX_METRICS);
+const canCaptureOnyxMetrics = () => Boolean(CONFIG.ONYX_METRICS);
+
+export {
+ canCapturePerformanceMetrics,
+ canCaptureOnyxMetrics,
+};
diff --git a/src/libs/canCaptureMetrics/index.native.js b/src/libs/canCaptureMetrics/index.native.js
index 32082a062adc..6be417d18eac 100644
--- a/src/libs/canCaptureMetrics/index.native.js
+++ b/src/libs/canCaptureMetrics/index.native.js
@@ -5,11 +5,16 @@ import CONFIG from '../../CONFIG';
*
* @returns {Boolean}
*/
-export const canCapturePerformanceMetrics = () => CONFIG.CAPTURE_METRICS;
+const canCapturePerformanceMetrics = () => CONFIG.CAPTURE_METRICS;
/**
* Is capturing Onyx stats enabled.
*
* @returns {Boolean}
*/
-export const canCaptureOnyxMetrics = () => CONFIG.ONYX_METRICS;
+const canCaptureOnyxMetrics = () => CONFIG.ONYX_METRICS;
+
+export {
+ canCapturePerformanceMetrics,
+ canCaptureOnyxMetrics,
+};
diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.js b/src/pages/home/report/ContextMenu/ContextMenuActions.js
index cee3d93d7cd1..688d27725f9d 100644
--- a/src/pages/home/report/ContextMenu/ContextMenuActions.js
+++ b/src/pages/home/report/ContextMenu/ContextMenuActions.js
@@ -22,7 +22,7 @@ function getActionText(reportAction) {
return lodashGet(message, 'html', '');
}
-export const CONTEXT_MENU_TYPES = {
+const CONTEXT_MENU_TYPES = {
LINK: 'LINK',
REPORT_ACTION: 'REPORT_ACTION',
};
@@ -132,3 +132,7 @@ export default [
},
},
];
+
+export {
+ CONTEXT_MENU_TYPES,
+};
diff --git a/src/stories/Button.stories.js b/src/stories/Button.stories.js
index a4c42c84c6b8..c951ba89c0bf 100644
--- a/src/stories/Button.stories.js
+++ b/src/stories/Button.stories.js
@@ -6,7 +6,7 @@ import Button from '../components/Button';
*
* https://storybook.js.org/docs/react/writing-stories/introduction#component-story-format
*/
-export default {
+const story = {
title: 'Components/Button',
component: Button,
};
@@ -16,8 +16,8 @@ const Template = args => ;
// Arguments can be passed to the component by binding
// See: https://storybook.js.org/docs/react/writing-stories/introduction#using-args
-export const Default = Template.bind({});
-export const Loading = Template.bind({});
+const Default = Template.bind({});
+const Loading = Template.bind({});
Default.args = {
text: 'Save & Continue',
success: true,
@@ -27,3 +27,9 @@ Loading.args = {
isLoading: true,
success: true,
};
+
+export default story;
+export {
+ Default,
+ Loading,
+};
diff --git a/src/stories/ButtonWithDropdown.stories.js b/src/stories/ButtonWithDropdown.stories.js
index d40ca9080ae8..5007649ed87f 100644
--- a/src/stories/ButtonWithDropdown.stories.js
+++ b/src/stories/ButtonWithDropdown.stories.js
@@ -6,7 +6,7 @@ import ButtonWithDropdown from '../components/ButtonWithDropdown';
*
* https://storybook.js.org/docs/react/writing-stories/introduction#component-story-format
*/
-export default {
+const story = {
title: 'Components/ButtonWithDropdown',
component: ButtonWithDropdown,
};
@@ -16,7 +16,12 @@ const Template = args => ;
// Arguments can be passed to the component by binding
// See: https://storybook.js.org/docs/react/writing-stories/introduction#using-args
-export const Default = Template.bind({});
+const Default = Template.bind({});
Default.args = {
buttonText: 'Pay with Venmo',
};
+
+export default story;
+export {
+ Default,
+};
diff --git a/src/stories/Checkbox.stories.js b/src/stories/Checkbox.stories.js
index 9f86cfc190ea..c5444626df94 100644
--- a/src/stories/Checkbox.stories.js
+++ b/src/stories/Checkbox.stories.js
@@ -16,8 +16,12 @@ const Template = args => ;
// Arguments can be passed to the component by binding
// See: https://storybook.js.org/docs/react/writing-stories/introduction#using-args
-export const Default = Template.bind({});
+const Default = Template.bind({});
Default.args = {
onPress: () => {},
isChecked: true,
};
+
+export {
+ Default,
+};
diff --git a/src/stories/CheckboxWithLabel.stories.js b/src/stories/CheckboxWithLabel.stories.js
index 7ba91dda9e6f..8b157a64d067 100644
--- a/src/stories/CheckboxWithLabel.stories.js
+++ b/src/stories/CheckboxWithLabel.stories.js
@@ -8,7 +8,7 @@ import styles from '../styles/styles';
*
* https://storybook.js.org/docs/react/writing-stories/introduction#component-story-format
*/
-export default {
+const story = {
title: 'Components/CheckboxWithLabel',
component: CheckboxWithLabel,
};
@@ -18,9 +18,9 @@ const Template = args => ;
// Arguments can be passed to the component by binding
// See: https://storybook.js.org/docs/react/writing-stories/introduction#using-args
-export const Default = Template.bind({});
-export const WithLabelComponent = Template.bind({});
-export const WithErrors = Template.bind({});
+const Default = Template.bind({});
+const WithLabelComponent = Template.bind({});
+const WithErrors = Template.bind({});
Default.args = {
isChecked: true,
label: 'Plain text label',
@@ -46,3 +46,10 @@ WithErrors.args = {
onPress: () => {},
label: 'I accept the Terms & Conditions',
};
+
+export default story;
+export {
+ Default,
+ WithLabelComponent,
+ WithErrors,
+};
diff --git a/src/stories/Datepicker.stories.js b/src/stories/Datepicker.stories.js
index c8dff1b0ee3c..0fb3cd31c2b6 100644
--- a/src/stories/Datepicker.stories.js
+++ b/src/stories/Datepicker.stories.js
@@ -26,8 +26,8 @@ const Template = args => ;
// Arguments can be passed to the component by binding
// See: https://storybook.js.org/docs/react/writing-stories/introduction#using-args
-export const Default = Template.bind({});
-export const PreFilled = Template.bind({});
+const Default = Template.bind({});
+const PreFilled = Template.bind({});
Default.args = {
label: 'Select Date',
};
@@ -36,3 +36,8 @@ PreFilled.args = {
label: 'Select Date',
value: new Date(2018, 7, 21),
};
+
+export {
+ Default,
+ PreFilled,
+};
diff --git a/src/stories/Header.stories.js b/src/stories/Header.stories.js
index 50c832264c0b..09c13b54d7d6 100644
--- a/src/stories/Header.stories.js
+++ b/src/stories/Header.stories.js
@@ -6,7 +6,7 @@ import Header from '../components/Header';
*
* https://storybook.js.org/docs/react/writing-stories/introduction#component-story-format
*/
-export default {
+const story = {
title: 'Components/Header',
component: Header,
};
@@ -16,8 +16,13 @@ const Template = args => ;
// Arguments can be passed to the component by binding
// See: https://storybook.js.org/docs/react/writing-stories/introduction#using-args
-export const Default = Template.bind({});
+const Default = Template.bind({});
Default.args = {
title: 'Chats',
shouldShowEnvironmentBadge: true,
};
+
+export default story;
+export {
+ Default,
+};
diff --git a/src/stories/HeaderWithCloseButton.stories.js b/src/stories/HeaderWithCloseButton.stories.js
index cbd1c9ce41db..c100ff60b8d0 100644
--- a/src/stories/HeaderWithCloseButton.stories.js
+++ b/src/stories/HeaderWithCloseButton.stories.js
@@ -6,7 +6,7 @@ import HeaderWithCloseButton from '../components/HeaderWithCloseButton';
*
* https://storybook.js.org/docs/react/writing-stories/introduction#component-story-format
*/
-export default {
+const story = {
title: 'Components/HeaderWithCloseButton',
component: HeaderWithCloseButton,
};
@@ -16,9 +16,9 @@ const Template = args => ;
// Arguments can be passed to the component by binding
// See: https://storybook.js.org/docs/react/writing-stories/introduction#using-args
-export const Default = Template.bind({});
-export const Attachment = Template.bind({});
-export const Profile = Template.bind({});
+const Default = Template.bind({});
+const Attachment = Template.bind({});
+const Profile = Template.bind({});
Default.args = {
title: 'Settings',
};
@@ -30,3 +30,10 @@ Profile.args = {
title: 'Profile',
shouldShowBackButton: true,
};
+
+export default story;
+export {
+ Default,
+ Attachment,
+ Profile,
+};