diff --git a/android/app/build.gradle b/android/app/build.gradle
index 8a908f0ac306..ca023e4a5b9c 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -106,8 +106,8 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
multiDexEnabled rootProject.ext.multiDexEnabled
- versionCode 1001034802
- versionName "1.3.48-2"
+ versionCode 1001034803
+ versionName "1.3.48-3"
}
splits {
diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist
index 92b8b9877a60..54df358523e0 100644
--- a/ios/NewExpensify/Info.plist
+++ b/ios/NewExpensify/Info.plist
@@ -32,7 +32,7 @@
CFBundleVersion
- 1.3.48.2
+ 1.3.48.3
ITSAppUsesNonExemptEncryption
LSApplicationQueriesSchemes
diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist
index babb0945f07e..4a3502f97d0c 100644
--- a/ios/NewExpensifyTests/Info.plist
+++ b/ios/NewExpensifyTests/Info.plist
@@ -19,6 +19,6 @@
CFBundleSignature
????
CFBundleVersion
- 1.3.48.2
+ 1.3.48.3
diff --git a/package-lock.json b/package-lock.json
index 396840f8fd42..09472f396189 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "new.expensify",
- "version": "1.3.48-2",
+ "version": "1.3.48-3",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "new.expensify",
- "version": "1.3.48-2",
+ "version": "1.3.48-3",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
@@ -81,7 +81,6 @@
"react-native-localize": "^2.2.6",
"react-native-modal": "^13.0.0",
"react-native-onyx": "1.0.52",
- "react-native-pager-view": "^6.2.0",
"react-native-pdf": "^6.6.2",
"react-native-performance": "^4.0.0",
"react-native-permissions": "^3.0.1",
@@ -36620,6 +36619,7 @@
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/react-native-pager-view/-/react-native-pager-view-6.2.0.tgz",
"integrity": "sha512-pf9OnL/Tkr+5s4Gjmsn7xh91PtJLDa6qxYa/bmtUhd/+s4cQdWQ8DIFoOFghwZIHHHwVdWtoXkp6HtpjN+r20g==",
+ "peer": true,
"peerDependencies": {
"react": "*",
"react-native": "*"
@@ -68238,6 +68238,7 @@
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/react-native-pager-view/-/react-native-pager-view-6.2.0.tgz",
"integrity": "sha512-pf9OnL/Tkr+5s4Gjmsn7xh91PtJLDa6qxYa/bmtUhd/+s4cQdWQ8DIFoOFghwZIHHHwVdWtoXkp6HtpjN+r20g==",
+ "peer": true,
"requires": {}
},
"react-native-pdf": {
diff --git a/package.json b/package.json
index 2b5ad9513ae7..f7bb1fe289ec 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "new.expensify",
- "version": "1.3.48-2",
+ "version": "1.3.48-3",
"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.",
@@ -119,7 +119,6 @@
"react-native-localize": "^2.2.6",
"react-native-modal": "^13.0.0",
"react-native-onyx": "1.0.52",
- "react-native-pager-view": "^6.2.0",
"react-native-pdf": "^6.6.2",
"react-native-performance": "^4.0.0",
"react-native-permissions": "^3.0.1",
diff --git a/src/CONST.js b/src/CONST.js
index b214bc614f04..79c50cccac79 100755
--- a/src/CONST.js
+++ b/src/CONST.js
@@ -324,8 +324,8 @@ const CONST = {
},
type: KEYBOARD_SHORTCUT_NAVIGATION_TYPE,
},
- NEW_GROUP: {
- descriptionKey: 'newGroup',
+ NEW_CHAT: {
+ descriptionKey: 'newChat',
shortcutKey: 'K',
modifiers: ['CTRL', 'SHIFT'],
trigger: {
@@ -2550,6 +2550,8 @@ const CONST = {
RECEIPT_TAB_ID: 'ReceiptTab',
MANUAL: 'manual',
SCAN: 'scan',
+ NEW_CHAT: 'chat',
+ NEW_ROOM: 'room',
},
};
diff --git a/src/ROUTES.js b/src/ROUTES.js
index 65b335325e3d..0f78061c5155 100644
--- a/src/ROUTES.js
+++ b/src/ROUTES.js
@@ -58,8 +58,9 @@ export default {
SETTINGS_2FA_CODES: 'settings/security/two-factor-auth/codes',
SETTINGS_2FA_VERIFY: 'settings/security/two-factor-auth/verify',
SETTINGS_2FA_SUCCESS: 'settings/security/two-factor-auth/success',
- NEW_GROUP: 'new/group',
+ NEW: 'new/:tab',
NEW_CHAT: 'new/chat',
+ NEW_ROOM: 'new/room',
NEW_TASK,
REPORT,
REPORT_WITH_ID: 'r/:reportID?',
@@ -155,7 +156,6 @@ export default {
WORKSPACE_INVOICES: 'workspace/:policyID/invoices',
WORKSPACE_TRAVEL: 'workspace/:policyID/travel',
WORKSPACE_MEMBERS: 'workspace/:policyID/members',
- WORKSPACE_NEW_ROOM: 'workspace/new-room',
getWorkspaceInitialRoute: (policyID) => `workspace/${policyID}`,
getWorkspaceInviteRoute: (policyID) => `workspace/${policyID}/invite`,
getWorkspaceInviteMessageRoute: (policyID) => `workspace/${policyID}/invite-message`,
diff --git a/src/components/Button/index.js b/src/components/Button/index.js
index a850a43d2fb0..7f6fa06a845f 100644
--- a/src/components/Button/index.js
+++ b/src/components/Button/index.js
@@ -49,6 +49,9 @@ const propTypes = {
/** medium sized button */
medium: PropTypes.bool,
+ /** Center the text and the icon */
+ centered: PropTypes.bool,
+
/** Indicates whether the button should be disabled and in the loading state */
isLoading: PropTypes.bool,
@@ -96,6 +99,9 @@ const propTypes = {
/** Whether we should use the danger theme color */
danger: PropTypes.bool,
+ /** Whether the background of the button should be transparent */
+ transparent: PropTypes.bool,
+
/** Children to replace all inner contents of button */
children: PropTypes.node,
@@ -135,6 +141,7 @@ const defaultProps = {
small: false,
large: false,
medium: false,
+ centered: false,
onPress: () => {},
onLongPress: () => {},
onPressIn: () => {},
@@ -148,6 +155,7 @@ const defaultProps = {
shouldUseDefaultHover: false,
success: false,
danger: false,
+ transparent: false,
children: null,
shouldRemoveRightBorderRadius: false,
shouldRemoveLeftBorderRadius: false,
@@ -225,7 +233,7 @@ class Button extends Component {
if (this.props.icon || this.props.shouldShowRightIcon) {
return (
-
+
{this.props.icon && (
@@ -292,6 +300,7 @@ class Button extends Component {
this.props.large ? styles.buttonLarge : undefined,
this.props.success ? styles.buttonSuccess : undefined,
this.props.danger ? styles.buttonDanger : undefined,
+ this.props.transparent ? styles.buttonTransparent : undefined,
this.props.isDisabled && (this.props.success || this.props.danger) ? styles.buttonOpacityDisabled : undefined,
this.props.isDisabled && !this.props.danger && !this.props.success ? styles.buttonDisabled : undefined,
this.props.shouldRemoveRightBorderRadius ? styles.noRightBorderRadius : undefined,
diff --git a/src/components/OptionRow.js b/src/components/OptionRow.js
index adaa4457bbd9..9f194a31196c 100644
--- a/src/components/OptionRow.js
+++ b/src/components/OptionRow.js
@@ -6,6 +6,7 @@ import {View, StyleSheet, InteractionManager} from 'react-native';
import styles from '../styles/styles';
import * as StyleUtils from '../styles/StyleUtils';
import optionPropTypes from './optionPropTypes';
+import Button from './Button';
import Icon from './Icon';
import * as Expensicons from './Icon/Expensicons';
import MultipleAvatars from './MultipleAvatars';
@@ -39,6 +40,15 @@ const propTypes = {
/** Whether we should show the selected state */
showSelectedState: PropTypes.bool,
+ /** Whether to show a button pill instead of a tickbox */
+ shouldShowSelectedStateAsButton: PropTypes.bool,
+
+ /** Text for button pill */
+ selectedStateButtonText: PropTypes.string,
+
+ /** Callback to fire when the multiple selector (tickbox or button) is clicked */
+ onSelectedStatePressed: PropTypes.func,
+
/** Whether this item is selected */
isSelected: PropTypes.bool,
@@ -65,6 +75,9 @@ const propTypes = {
const defaultProps = {
hoverStyle: styles.sidebarLinkHover,
showSelectedState: false,
+ shouldShowSelectedStateAsButton: false,
+ selectedStateButtonText: 'Select',
+ onSelectedStatePressed: undefined,
isSelected: false,
boldStyle: false,
showTitleTooltip: false,
@@ -149,7 +162,6 @@ class OptionRow extends Component {
pendingAction={this.props.option.pendingAction}
errors={this.props.option.allReportErrors}
shouldShowErrorMessages={false}
- needsOffscreenAlphaCompositing
>
{(hovered) => (
@@ -248,7 +260,15 @@ class OptionRow extends Component {
/>
)}
- {this.props.showSelectedState && }
+ {this.props.showSelectedState && (this.props.shouldShowSelectedStateAsButton && !this.props.isSelected) ?
+
{Boolean(this.props.option.customIcon) && (
diff --git a/src/components/OptionsList/BaseOptionsList.js b/src/components/OptionsList/BaseOptionsList.js
index 9c5777e222c9..c8e441705f93 100644
--- a/src/components/OptionsList/BaseOptionsList.js
+++ b/src/components/OptionsList/BaseOptionsList.js
@@ -170,6 +170,9 @@ class BaseOptionsList extends Component {
onSelectRow={this.props.onSelectRow}
isSelected={Boolean(_.find(this.props.selectedOptions, (option) => option.accountID === item.accountID))}
showSelectedState={this.props.canSelectMultipleOptions}
+ shouldShowSelectedStateAsButton={this.props.shouldShowMultipleOptionSelectorAsButton}
+ selectedStateButtonText={this.props.multipleOptionSelectorButtonText}
+ onSelectedStatePressed={this.props.onAddToSelection}
boldStyle={this.props.boldStyle}
isDisabled={isDisabled}
shouldHaveOptionSeparator={index > 0 && this.props.shouldHaveOptionSeparator}
diff --git a/src/components/OptionsSelector/BaseOptionsSelector.js b/src/components/OptionsSelector/BaseOptionsSelector.js
index 0d05e8401cce..618e1817fc54 100755
--- a/src/components/OptionsSelector/BaseOptionsSelector.js
+++ b/src/components/OptionsSelector/BaseOptionsSelector.js
@@ -337,6 +337,9 @@ class BaseOptionsSelector extends Component {
focusedIndex={this.state.focusedIndex}
selectedOptions={this.props.selectedOptions}
canSelectMultipleOptions={this.props.canSelectMultipleOptions}
+ shouldShowMultipleOptionSelectorAsButton={this.props.shouldShowMultipleOptionSelectorAsButton}
+ multipleOptionSelectorButtonText={this.props.multipleOptionSelectorButtonText}
+ onAddToSelection={this.props.onAddToSelection}
hideSectionHeaders={this.props.hideSectionHeaders}
headerMessage={this.props.headerMessage}
boldStyle={this.props.boldStyle}
diff --git a/src/components/OptionsSelector/optionsSelectorPropTypes.js b/src/components/OptionsSelector/optionsSelectorPropTypes.js
index 02b807bf66c1..55bcda743855 100644
--- a/src/components/OptionsSelector/optionsSelectorPropTypes.js
+++ b/src/components/OptionsSelector/optionsSelectorPropTypes.js
@@ -53,6 +53,15 @@ const propTypes = {
/** Whether we can select multiple options */
canSelectMultipleOptions: PropTypes.bool,
+ /** Whether to show a button pill instead of a standard tickbox */
+ shouldShowMultipleOptionSelectorAsButton: PropTypes.bool,
+
+ /** Text for button pill */
+ multipleOptionSelectorButtonText: PropTypes.string,
+
+ /** Callback to fire when the multiple selector (tickbox or button) is clicked */
+ onAddToSelection: PropTypes.func,
+
/** Whether any section headers should be visible */
hideSectionHeaders: PropTypes.bool,
diff --git a/src/components/TabSelector/TabSelector.js b/src/components/TabSelector/TabSelector.js
index d34aa1e0a9fe..fccaaf4672a9 100644
--- a/src/components/TabSelector/TabSelector.js
+++ b/src/components/TabSelector/TabSelector.js
@@ -24,7 +24,20 @@ const defaultProps = {
onTabPress: () => {},
};
-const getIcon = (route) => (route === CONST.TAB.MANUAL ? Expensicons.Pencil : Expensicons.Receipt);
+const getIcon = (route) => {
+ switch (route) {
+ case CONST.TAB.MANUAL:
+ return Expensicons.Pencil;
+ case CONST.TAB.SCAN:
+ return Expensicons.Receipt;
+ case CONST.TAB.NEW_CHAT:
+ return Expensicons.User;
+ case CONST.TAB.NEW_ROOM:
+ return Expensicons.Hashtag;
+ default:
+ return Expensicons.DotIndicator
+ }
+}
function TabSelector({state, navigation, onTabPress}) {
const {translate} = useLocalize();
@@ -58,7 +71,7 @@ function TabSelector({state, navigation, onTabPress}) {
/>
);
})}
-
+
);
}
diff --git a/src/languages/en.js b/src/languages/en.js
index dd354115f512..9edfb9ab9431 100755
--- a/src/languages/en.js
+++ b/src/languages/en.js
@@ -331,13 +331,15 @@ export default {
},
},
sidebarScreen: {
- fabAction: 'New chat',
+ chat: 'Chat',
+ room: 'Room',
newChat: 'New chat',
newGroup: 'New group',
newRoom: 'New room',
+ fabNewChat: 'Send message',
+ fabNewChatExplained: 'Send message (Floating action)',
buttonSearch: 'Search',
buttonMySettings: 'My settings',
- fabNewChat: 'New chat (Floating action)',
chatPinned: 'Chat pinned',
draftedMessage: 'Drafted message',
listOfChatMessages: 'List of chat messages',
@@ -346,6 +348,8 @@ export default {
tabSelector: {
manual: 'Manual',
scan: 'Scan',
+ chat: 'Chat',
+ room: 'Room',
},
receipt: {
upload: 'Upload receipt',
@@ -383,6 +387,7 @@ export default {
payElsewhere: 'Pay elsewhere',
settlePaypalMe: ({formattedAmount}) => `Pay ${formattedAmount} with PayPal.me`,
requestAmount: ({amount}) => `request ${amount}`,
+ addToSplit: 'Add to split',
splitAmount: ({amount}) => `split ${amount}`,
amountEach: ({amount}) => `${amount} each`,
payerOwesAmount: ({payer, amount}) => `${payer} owes ${amount}`,
@@ -835,6 +840,8 @@ export default {
localTime: 'Local time',
},
newChatPage: {
+ addToGroup: 'Add to group',
+ createChat: 'Create chat',
createGroup: 'Create group',
},
yearPickerPage: {
@@ -1372,7 +1379,7 @@ export default {
openShortcutDialog: 'Opens the keyboard shortcuts dialog',
escape: 'Escape dialogs',
search: 'Open search dialog',
- newGroup: 'New group screen',
+ newChat: 'New chat screen',
copy: 'Copy comment',
},
},
diff --git a/src/languages/es.js b/src/languages/es.js
index b88d64692cc8..386b9587b948 100644
--- a/src/languages/es.js
+++ b/src/languages/es.js
@@ -330,13 +330,16 @@ export default {
},
},
sidebarScreen: {
- fabAction: 'Nuevo chat',
- newChat: 'Nuevo chat',
+ chat: 'Chat',
+ room: 'Sala',
+ fabAction: 'Enviar mensaje',
+ newChat: 'Enviar mensaje',
newGroup: 'Nuevo grupo',
newRoom: 'Nueva sala de chat',
+ fabNewChat: 'Enviar mensaje',
+ fabNewChatExplained: 'Enviar mensaje',
buttonSearch: 'Buscar',
buttonMySettings: 'Mi configuración',
- fabNewChat: 'Nuevo chat',
chatPinned: 'Chat fijado',
draftedMessage: 'Mensaje borrador',
listOfChatMessages: 'Lista de mensajes del chat',
@@ -345,6 +348,8 @@ export default {
tabSelector: {
manual: 'Manual',
scan: 'Escanear',
+ chat: 'Chat',
+ room: 'Sala',
},
receipt: {
upload: 'Subir recibo',
@@ -382,6 +387,7 @@ export default {
payElsewhere: 'Pagar de otra forma',
settlePaypalMe: ({formattedAmount}) => `Pagar ${formattedAmount} con PayPal.me`,
requestAmount: ({amount}) => `solicitar ${amount}`,
+ addToSplit: 'TODO: TRANSLATION NEEDED',
splitAmount: ({amount}) => `dividir ${amount}`,
amountEach: ({amount}) => `${amount} cada uno`,
payerOwesAmount: ({payer, amount}) => `${payer} debe ${amount}`,
@@ -839,6 +845,8 @@ export default {
localTime: 'Hora local',
},
newChatPage: {
+ addToGroup: 'Añadir al grupo',
+ createChat: 'Creat chat',
createGroup: 'Crear grupo',
},
yearPickerPage: {
@@ -1383,7 +1391,7 @@ export default {
openShortcutDialog: 'Abre el cuadro de diálogo de métodos abreviados de teclado',
escape: 'Diálogos de escape',
search: 'Abrir diálogo de búsqueda',
- newGroup: 'Nueva pantalla de grupo',
+ newGroup: 'Nueva pantalla de chat',
copy: 'Copiar comentario',
},
},
diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.js b/src/libs/Navigation/AppNavigator/AuthScreens.js
index 8fca9aea495c..c6c26895d712 100644
--- a/src/libs/Navigation/AppNavigator/AuthScreens.js
+++ b/src/libs/Navigation/AppNavigator/AuthScreens.js
@@ -147,7 +147,7 @@ class AuthScreens extends React.Component {
Timing.end(CONST.TIMING.HOMEPAGE_INITIAL_RENDER);
const searchShortcutConfig = CONST.KEYBOARD_SHORTCUTS.SEARCH;
- const groupShortcutConfig = CONST.KEYBOARD_SHORTCUTS.NEW_GROUP;
+ const chatShortcutConfig = CONST.KEYBOARD_SHORTCUTS.NEW_CHAT;
// Listen for the key K being pressed so that focus can be given to
// the chat switcher, or new group chat
@@ -167,17 +167,17 @@ class AuthScreens extends React.Component {
true,
);
this.unsubscribeGroupShortcut = KeyboardShortcut.subscribe(
- groupShortcutConfig.shortcutKey,
+ chatShortcutConfig.shortcutKey,
() => {
Modal.close(() => {
- if (Navigation.isActiveRoute(ROUTES.NEW_GROUP)) {
+ if (Navigation.isActiveRoute(ROUTES.NEW_CHAT)) {
return;
}
- Navigation.navigate(ROUTES.NEW_GROUP);
+ Navigation.navigate(ROUTES.NEW_CHAT);
});
},
- groupShortcutConfig.descriptionKey,
- groupShortcutConfig.modifiers,
+ chatShortcutConfig.descriptionKey,
+ chatShortcutConfig.modifiers,
true,
);
}
diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js
index 31d2057ddd5a..73034ea634c7 100644
--- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js
+++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js
@@ -231,21 +231,11 @@ const SearchModalStackNavigator = createModalStackNavigator([
},
]);
-const NewGroupModalStackNavigator = createModalStackNavigator([
- {
- getComponent: () => {
- const NewGroupPage = require('../../../pages/NewGroupPage').default;
- return NewGroupPage;
- },
- name: 'NewGroup_Root',
- },
-]);
-
const NewChatModalStackNavigator = createModalStackNavigator([
{
getComponent: () => {
- const NewChatPage = require('../../../pages/NewChatPage').default;
- return NewChatPage;
+ const NewChatSelectorPage = require('../../../pages/NewChatSelectorPage').default;
+ return NewChatSelectorPage;
},
name: 'NewChat_Root',
},
@@ -592,13 +582,6 @@ const SettingsModalStackNavigator = createModalStackNavigator([
},
name: 'Workspace_Invite_Message',
},
- {
- getComponent: () => {
- const WorkspaceNewRoomPage = require('../../../pages/workspace/WorkspaceNewRoomPage').default;
- return WorkspaceNewRoomPage;
- },
- name: 'Workspace_NewRoom',
- },
{
getComponent: () => {
const ReimbursementAccountPage = require('../../../pages/ReimbursementAccount/ReimbursementAccountPage').default;
@@ -722,7 +705,6 @@ export {
ReportWelcomeMessageModalStackNavigator,
ReportParticipantsModalStackNavigator,
SearchModalStackNavigator,
- NewGroupModalStackNavigator,
NewChatModalStackNavigator,
NewTaskModalStackNavigator,
SettingsModalStackNavigator,
diff --git a/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.js b/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.js
index 53e2120f4c21..1a540b17bf23 100644
--- a/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.js
+++ b/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.js
@@ -17,14 +17,6 @@ function RightModalNavigator() {
name="NewChat"
component={ModalStackNavigators.NewChatModalStackNavigator}
/>
-
{
- if (!props.isGroupChat) {
- return;
- }
const logins = _.pluck(selectedOptions, 'login');
if (logins.length < 1) {
return;
@@ -170,12 +160,11 @@ function NewChatPage(props) {
props.betas,
searchTerm,
[],
- props.isGroupChat ? excludedGroupEmails : [],
);
setFilteredRecentReports(recentReports);
setFilteredPersonalDetails(personalDetails);
setFilteredUserToInvite(userToInvite);
- // props.betas and props.isGroupChat are not added as dependencies since they don't change during the component lifecycle
+ // props.betas is not added as dependency since it doesn't change during the component lifecycle
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [props.reports, props.personalDetails, searchTerm]);
@@ -184,23 +173,25 @@ function NewChatPage(props) {
includeSafeAreaPaddingBottom={false}
shouldEnableMaxHeight
>
- {({didScreenTransitionEnd, safeAreaPaddingBottomStyle}) => (
+ {({safeAreaPaddingBottomStyle}) => (
<>
-
0 ? safeAreaPaddingBottomStyle : {}]}>
toggleOption(option)}
sections={sections}
selectedOptions={selectedOptions}
value={searchTerm}
- onSelectRow={(option) => (props.isGroupChat ? toggleOption(option) : createChat(option))}
+ onSelectRow={(option) => createChat(option)}
onChangeText={setSearchTerm}
headerMessage={headerMessage}
boldStyle
- shouldFocusOnSelectRow={props.isGroupChat && !Browser.isMobile()}
- shouldShowConfirmButton={props.isGroupChat}
- shouldShowOptions={didScreenTransitionEnd && isOptionsDataReady}
- confirmButtonText={props.translate('newChatPage.createGroup')}
+ shouldFocusOnSelectRow={!Browser.isMobile()}
+ shouldShowOptions={isOptionsDataReady}
+ shouldShowConfirmButton
+ confirmButtonText={selectedOptions.length > 1 ? props.translate('newChatPage.createGroup') : props.translate('newChatPage.createChat')}
onConfirmSelection={createGroup}
textInputLabel={props.translate('optionsSelector.nameEmailOrPhoneNumber')}
safeAreaPaddingBottomStyle={safeAreaPaddingBottomStyle}
diff --git a/src/pages/NewChatSelectorPage.js b/src/pages/NewChatSelectorPage.js
new file mode 100755
index 000000000000..d7b35552e0d0
--- /dev/null
+++ b/src/pages/NewChatSelectorPage.js
@@ -0,0 +1,70 @@
+import React from 'react';
+import {createMaterialTopTabNavigator} from '@react-navigation/material-top-tabs';
+import TabSelector from '../components/TabSelector/TabSelector';
+import Permissions from '../libs/Permissions';
+import NewChatPage from './NewChatPage';
+import WorkspaceNewRoomPage from './workspace/WorkspaceNewRoomPage';
+import CONST from '../CONST';
+import withWindowDimensions, {windowDimensionsPropTypes} from '../components/withWindowDimensions';
+import HeaderWithBackButton from '../components/HeaderWithBackButton';
+import ScreenWrapper from '../components/ScreenWrapper';
+import withLocalize, {withLocalizePropTypes} from '../components/withLocalize';
+import compose from '../libs/compose';
+
+const TopTab = createMaterialTopTabNavigator();
+
+const propTypes = {
+ ...windowDimensionsPropTypes,
+
+ ...withLocalizePropTypes,
+};
+
+const defaultProps = {
+ betas: [],
+ personalDetails: {},
+ reports: {},
+};
+
+function NewChatSelectorPage(props) {
+ return (
+
+ <>
+
+ (
+ <>
+ {Permissions.canUsePolicyRooms(props.betas) && (
+
+ )}
+ >
+ )}
+ >
+
+
+
+ >
+
+ );
+}
+
+NewChatSelectorPage.propTypes = propTypes;
+NewChatSelectorPage.defaultProps = defaultProps;
+NewChatSelectorPage.displayName = 'NewChatPage';
+
+export default compose(
+ withLocalize,
+ withWindowDimensions,
+)(NewChatSelectorPage);
diff --git a/src/pages/NewGroupPage.js b/src/pages/NewGroupPage.js
deleted file mode 100755
index 63f90016e63e..000000000000
--- a/src/pages/NewGroupPage.js
+++ /dev/null
@@ -1,16 +0,0 @@
-import React from 'react';
-import NewChatPage from './NewChatPage';
-
-function NewGroupPage(props) {
- return (
-
- );
-}
-
-NewGroupPage.displayName = 'NewGroupPage';
-
-export default NewGroupPage;
diff --git a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js
index 1ccdf9261b19..f77cbb6258bd 100644
--- a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js
+++ b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js
@@ -11,7 +11,6 @@ import NAVIGATORS from '../../../../NAVIGATORS';
import SCREENS from '../../../../SCREENS';
import Permissions from '../../../../libs/Permissions';
import * as Policy from '../../../../libs/actions/Policy';
-import * as PolicyUtils from '../../../../libs/PolicyUtils';
import PopoverMenu from '../../../../components/PopoverMenu';
import CONST from '../../../../CONST';
import FloatingActionButton from '../../../../components/FloatingActionButton';
@@ -173,8 +172,6 @@ function FloatingActionButtonAndPopover(props) {
},
}));
- const workspaces = PolicyUtils.getActivePolicies(props.allPolicies);
-
return (
interceptAnonymousUser(() => Navigation.navigate(ROUTES.NEW_CHAT)),
},
- {
- icon: Expensicons.Users,
- text: props.translate('sidebarScreen.newGroup'),
- onSelected: () => interceptAnonymousUser(() => Navigation.navigate(ROUTES.NEW_GROUP)),
- },
- ...(Permissions.canUsePolicyRooms(props.betas) && workspaces.length
- ? [
- {
- icon: Expensicons.Hashtag,
- text: props.translate('sidebarScreen.newRoom'),
- onSelected: () => interceptAnonymousUser(() => Navigation.navigate(ROUTES.WORKSPACE_NEW_ROOM)),
- },
- ]
- : []),
...(Permissions.canUseIOUSend(props.betas)
? [
{
@@ -217,11 +200,6 @@ function FloatingActionButtonAndPopover(props) {
text: props.translate('iou.requestMoney'),
onSelected: () => interceptAnonymousUser(() => IOU.startMoneyRequest(CONST.IOU.MONEY_REQUEST_TYPE.REQUEST)),
},
- {
- icon: Expensicons.Receipt,
- text: props.translate('iou.splitBill'),
- onSelected: () => interceptAnonymousUser(() => IOU.startMoneyRequest(CONST.IOU.MONEY_REQUEST_TYPE.SPLIT)),
- },
...(Permissions.canUseTasks(props.betas)
? [
{
@@ -246,7 +224,7 @@ function FloatingActionButtonAndPopover(props) {
]}
/>
{
- Navigation.navigate(ROUTES.getMoneyRequestConfirmationRoute(iouType.current, reportID.current));
+ const navigateToNextStep = (nextIoutype) => {
+ Navigation.navigate(ROUTES.getMoneyRequestConfirmationRoute(nextIoutype, reportID.current));
};
const navigateBack = (forceFallback = false) => {
@@ -59,9 +58,9 @@ function MoneyRequestParticipantsPage(props) {
useEffect(() => {
// ID in Onyx could change by initiating a new request in a separate browser tab or completing a request
- if (prevMoneyRequestId.current !== props.iou.id) {
+ if (prevMoneyRequestId.current !== iou.id) {
// The ID is cleared on completing a request. In that case, we will do nothing
- if (props.iou.id) {
+ if (iou.id) {
navigateBack(true);
}
return;
@@ -69,19 +68,19 @@ function MoneyRequestParticipantsPage(props) {
// Reset the money request Onyx if the ID in Onyx does not match the ID from params
const moneyRequestId = `${iouType.current}${reportID.current}`;
- const shouldReset = props.iou.id !== moneyRequestId;
+ const shouldReset = iou.id !== moneyRequestId;
if (shouldReset) {
IOU.resetMoneyRequestInfo(moneyRequestId, iouType.current);
}
- if ((props.iou.amount === 0 && !props.iou.receiptPath) || shouldReset) {
+ if (iou.amount === 0 || iou.receiptPath || shouldReset) {
navigateBack(true);
}
return () => {
- prevMoneyRequestId.current = props.iou.id;
+ prevMoneyRequestId.current = iou.id;
};
- }, [props.iou.amount, props.iou.id, props.iou.receiptPath]);
+ }, [iou.amount, iou.id, iou.receiptPath]);
return (
(
- {iouType.current === CONST.IOU.MONEY_REQUEST_TYPE.SPLIT ? (
navigateToNextStep(CONST.IOU.MONEY_REQUEST_TYPE.REQUEST)}
+ navigateToSplit={() => navigateToNextStep(CONST.IOU.MONEY_REQUEST_TYPE.SPLIT)}
/>
- ) : (
-
- )}
)}
diff --git a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSelector.js b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSelector.js
deleted file mode 100755
index a72e37c7b7f4..000000000000
--- a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSelector.js
+++ /dev/null
@@ -1,187 +0,0 @@
-import React, {Component} from 'react';
-import PropTypes from 'prop-types';
-import {withOnyx} from 'react-native-onyx';
-import _ from 'underscore';
-import * as OptionsListUtils from '../../../../libs/OptionsListUtils';
-import * as ReportUtils from '../../../../libs/ReportUtils';
-import OptionsSelector from '../../../../components/OptionsSelector';
-import ONYXKEYS from '../../../../ONYXKEYS';
-import withLocalize, {withLocalizePropTypes} from '../../../../components/withLocalize';
-import compose from '../../../../libs/compose';
-import CONST from '../../../../CONST';
-import personalDetailsPropType from '../../../personalDetailsPropType';
-import reportPropTypes from '../../../reportPropTypes';
-
-const propTypes = {
- /** Beta features list */
- betas: PropTypes.arrayOf(PropTypes.string),
-
- /** Callback to inform parent modal of success */
- onStepComplete: PropTypes.func.isRequired,
-
- /** Callback to add participants in MoneyRequestModal */
- onAddParticipants: PropTypes.func.isRequired,
-
- /** All of the personal details for everyone */
- personalDetails: PropTypes.objectOf(personalDetailsPropType),
-
- /** All reports shared with the user */
- reports: PropTypes.objectOf(reportPropTypes),
-
- /** padding bottom style of safe area */
- safeAreaPaddingBottomStyle: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.object), PropTypes.object]),
-
- /** The type of IOU report, i.e. bill, request, send */
- iouType: PropTypes.string.isRequired,
-
- ...withLocalizePropTypes,
-};
-
-const defaultProps = {
- safeAreaPaddingBottomStyle: {},
- personalDetails: {},
- reports: {},
- betas: [],
-};
-
-class MoneyRequestParticipantsSelector extends Component {
- constructor(props) {
- super(props);
-
- this.addSingleParticipant = this.addSingleParticipant.bind(this);
- this.updateOptionsWithSearchTerm = this.updateOptionsWithSearchTerm.bind(this);
-
- const {recentReports, personalDetails, userToInvite} = this.getRequestOptions();
-
- this.state = {
- recentReports,
- personalDetails,
- userToInvite,
- searchTerm: '',
- };
- }
-
- componentDidUpdate(prevProps) {
- if (_.isEqual(prevProps.reports, this.props.reports) && _.isEqual(prevProps.personalDetails, this.props.personalDetails)) {
- return;
- }
- this.updateOptionsWithSearchTerm(this.state.searchTerm);
- }
-
- /**
- * @param {string} searchTerm
- * @returns {Object}
- */
- getRequestOptions(searchTerm = '') {
- return OptionsListUtils.getNewChatOptions(
- this.props.reports,
- this.props.personalDetails,
- this.props.betas,
- searchTerm,
- [],
- CONST.EXPENSIFY_EMAILS,
-
- // If we are using this component in the "Request money" flow then we pass the includeOwnedWorkspaceChats argument so that the current user
- // sees the option to request money from their admin on their own Workspace Chat.
- this.props.iouType === CONST.IOU.MONEY_REQUEST_TYPE.REQUEST,
- );
- }
-
- /**
- * Returns the sections needed for the OptionsSelector
- *
- * @returns {Array}
- */
- getSections() {
- const sections = [];
- let indexOffset = 0;
-
- sections.push({
- title: this.props.translate('common.recents'),
- data: this.state.recentReports,
- shouldShow: !_.isEmpty(this.state.recentReports),
- indexOffset,
- });
- indexOffset += this.state.recentReports.length;
-
- sections.push({
- title: this.props.translate('common.contacts'),
- data: this.state.personalDetails,
- shouldShow: !_.isEmpty(this.state.personalDetails),
- indexOffset,
- });
- indexOffset += this.state.personalDetails.length;
-
- if (this.state.userToInvite && !OptionsListUtils.isCurrentUser(this.state.userToInvite)) {
- sections.push({
- undefined,
- data: [this.state.userToInvite],
- shouldShow: true,
- indexOffset,
- });
- }
-
- return sections;
- }
-
- updateOptionsWithSearchTerm(searchTerm = '') {
- const {recentReports, personalDetails, userToInvite} = this.getRequestOptions(searchTerm);
- this.setState({
- searchTerm,
- recentReports,
- userToInvite,
- personalDetails,
- });
- }
-
- /**
- * Adds a single participant to the request
- *
- * @param {Object} option
- */
- addSingleParticipant(option) {
- this.props.onAddParticipants([{accountID: option.accountID, login: option.login, isPolicyExpenseChat: option.isPolicyExpenseChat, reportID: option.reportID, selected: true}]);
- this.props.onStepComplete();
- }
-
- render() {
- const headerMessage = OptionsListUtils.getHeaderMessage(
- this.state.personalDetails.length + this.state.recentReports.length !== 0,
- Boolean(this.state.userToInvite),
- this.state.searchTerm,
- );
- const isOptionsDataReady = ReportUtils.isReportDataReady() && OptionsListUtils.isPersonalDetailsReady(this.props.personalDetails);
-
- return (
-
- );
- }
-}
-
-MoneyRequestParticipantsSelector.propTypes = propTypes;
-MoneyRequestParticipantsSelector.defaultProps = defaultProps;
-
-export default compose(
- withLocalize,
- withOnyx({
- personalDetails: {
- key: ONYXKEYS.PERSONAL_DETAILS_LIST,
- },
- reports: {
- key: ONYXKEYS.COLLECTION.REPORT,
- },
- betas: {
- key: ONYXKEYS.BETAS,
- },
- }),
-)(MoneyRequestParticipantsSelector);
diff --git a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSplitSelector.js b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSplitSelector.js
index 0c1376006271..c47d457be751 100755
--- a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSplitSelector.js
+++ b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSplitSelector.js
@@ -19,8 +19,11 @@ const propTypes = {
/** Beta features list */
betas: PropTypes.arrayOf(PropTypes.string),
- /** Callback to inform parent modal of success */
- onStepComplete: PropTypes.func.isRequired,
+ /** Callback to request parent modal to go to next step, which should be split */
+ navigateToRequest: PropTypes.func.isRequired,
+
+ /** Callback to request parent modal to go to next step, which should be split */
+ navigateToSplit: PropTypes.func.isRequired,
/** Callback to add participants in MoneyRequestModal */
onAddParticipants: PropTypes.func.isRequired,
@@ -56,7 +59,7 @@ const defaultProps = {
safeAreaPaddingBottomStyle: {},
};
-function MoneyRequestParticipantsSplitSelector({betas, participants, personalDetails, reports, translate, onAddParticipants, onStepComplete, safeAreaPaddingBottomStyle}) {
+function MoneyRequestParticipantsSplitSelector({betas, participants, personalDetails, reports, translate, navigateToRequest, navigateToSplit, onAddParticipants, safeAreaPaddingBottomStyle}) {
const [searchTerm, setSearchTerm] = useState('');
const [newChatOptions, setNewChatOptions] = useState({
recentReports: [],
@@ -166,16 +169,19 @@ function MoneyRequestParticipantsSplitSelector({betas, participants, personalDet
0 ? safeAreaPaddingBottomStyle : {}]}>
-
-
-
+
);
}
diff --git a/src/styles/styles.js b/src/styles/styles.js
index 259fc84bc9e8..366d7e3a6584 100644
--- a/src/styles/styles.js
+++ b/src/styles/styles.js
@@ -555,6 +555,10 @@ const styles = {
borderWidth: 0,
},
+ buttonTransparent: {
+ backgroundColor: 'transparent',
+ },
+
buttonDisabled: {
backgroundColor: themeColors.buttonDefaultBG,
borderWidth: 0,