diff --git a/assets/images/simple-illustrations/simple-illustration__hotdogstand.svg b/assets/images/simple-illustrations/simple-illustration__hotdogstand.svg
new file mode 100644
index 000000000000..732c16a75a2b
--- /dev/null
+++ b/assets/images/simple-illustrations/simple-illustration__hotdogstand.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/components/DatePicker/CalendarPicker/index.js b/src/components/DatePicker/CalendarPicker/index.js
index a404c4746397..bbdeda6ef84f 100644
--- a/src/components/DatePicker/CalendarPicker/index.js
+++ b/src/components/DatePicker/CalendarPicker/index.js
@@ -236,7 +236,7 @@ class CalendarPicker extends React.PureComponent {
diff --git a/src/components/Icon/Illustrations.ts b/src/components/Icon/Illustrations.ts
index 440350895826..c8a14c7aba03 100644
--- a/src/components/Icon/Illustrations.ts
+++ b/src/components/Icon/Illustrations.ts
@@ -35,6 +35,7 @@ import ConciergeNew from '@assets/images/simple-illustrations/simple-illustratio
import CreditCardsNew from '@assets/images/simple-illustrations/simple-illustration__credit-cards.svg';
import EmailAddress from '@assets/images/simple-illustrations/simple-illustration__email-address.svg';
import HandEarth from '@assets/images/simple-illustrations/simple-illustration__handearth.svg';
+import HotDogStand from '@assets/images/simple-illustrations/simple-illustration__hotdogstand.svg';
import InvoiceBlue from '@assets/images/simple-illustrations/simple-illustration__invoice.svg';
import LockOpen from '@assets/images/simple-illustrations/simple-illustration__lockopen.svg';
import Luggage from '@assets/images/simple-illustrations/simple-illustration__luggage.svg';
@@ -60,6 +61,7 @@ export {
ConciergeExclamation,
CreditCardsBlue,
EmailAddress,
+ HotDogStand,
InvoiceOrange,
JewelBoxBlue,
JewelBoxGreen,
diff --git a/src/components/MenuItem.tsx b/src/components/MenuItem.tsx
index a5e02dccddd3..db150d55f0d2 100644
--- a/src/components/MenuItem.tsx
+++ b/src/components/MenuItem.tsx
@@ -547,7 +547,7 @@ function MenuItem(
{badgeText && (
)}
{/* Since subtitle can be of type number, we should allow 0 to be shown */}
diff --git a/src/components/Section/IconSection.js b/src/components/Section/IconSection.js
new file mode 100644
index 000000000000..307331aa36d6
--- /dev/null
+++ b/src/components/Section/IconSection.js
@@ -0,0 +1,41 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import {View} from 'react-native';
+import Icon from '@components/Icon';
+import sourcePropTypes from '@components/Image/sourcePropTypes';
+import useThemeStyles from '@hooks/useThemeStyles';
+
+const iconSectionPropTypes = {
+ icon: sourcePropTypes,
+ IconComponent: PropTypes.IconComponent,
+ iconContainerStyles: PropTypes.iconContainerStyles,
+};
+
+const defaultIconSectionPropTypes = {
+ icon: null,
+ IconComponent: null,
+ iconContainerStyles: [],
+};
+
+function IconSection({icon, IconComponent, iconContainerStyles}) {
+ const styles = useThemeStyles();
+
+ return (
+
+ {Boolean(icon) && (
+
+ )}
+ {Boolean(IconComponent) && }
+
+ );
+}
+
+IconSection.displayName = 'IconSection';
+IconSection.propTypes = iconSectionPropTypes;
+IconSection.defaultProps = defaultIconSectionPropTypes;
+
+export default IconSection;
diff --git a/src/components/Section.js b/src/components/Section/index.js
similarity index 60%
rename from src/components/Section.js
rename to src/components/Section/index.js
index c204632e2a25..50576abef025 100644
--- a/src/components/Section.js
+++ b/src/components/Section/index.js
@@ -1,12 +1,17 @@
import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
+import sourcePropTypes from '@components/Image/sourcePropTypes';
+import MenuItemList from '@components/MenuItemList';
+import menuItemPropTypes from '@components/menuItemPropTypes';
+import Text from '@components/Text';
import useThemeStyles from '@hooks/useThemeStyles';
-import Icon from './Icon';
-import sourcePropTypes from './Image/sourcePropTypes';
-import MenuItemList from './MenuItemList';
-import menuItemPropTypes from './menuItemPropTypes';
-import Text from './Text';
+import IconSection from './IconSection';
+
+const CARD_LAYOUT = {
+ ICON_ON_TOP: 'iconOnTop',
+ ICON_ON_RIGHT: 'iconOnRight',
+};
const propTypes = {
/** An array of props that are pass to individual MenuItem components */
@@ -24,6 +29,10 @@ const propTypes = {
/** Icon component */
IconComponent: PropTypes.func,
+ /** Card layout that affects icon positioning, margins, sizes. */
+ // eslint-disable-next-line rulesdir/prefer-underscore-method
+ cardLayout: PropTypes.oneOf(Object.values(CARD_LAYOUT)),
+
/** Contents to display inside the section */
children: PropTypes.node,
@@ -39,6 +48,9 @@ const propTypes = {
// eslint-disable-next-line react/forbid-prop-types
subtitleStyles: PropTypes.arrayOf(PropTypes.object),
+ /** Whether the subtitle should have a muted style */
+ subtitleMuted: PropTypes.bool,
+
/** Customize the Section container */
// eslint-disable-next-line react/forbid-prop-types
childrenStyles: PropTypes.arrayOf(PropTypes.object),
@@ -53,38 +65,45 @@ const defaultProps = {
children: null,
icon: null,
IconComponent: null,
+ cardLayout: CARD_LAYOUT.ICON_ON_RIGHT,
containerStyles: [],
iconContainerStyles: [],
titleStyles: [],
subtitleStyles: [],
+ subtitleMuted: false,
childrenStyles: [],
subtitle: null,
};
-function Section({children, childrenStyles, containerStyles, icon, IconComponent, iconContainerStyles, menuItems, subtitle, subtitleStyles, title, titleStyles}) {
+function Section({children, childrenStyles, containerStyles, icon, IconComponent, cardLayout, iconContainerStyles, menuItems, subtitle, subtitleStyles, subtitleMuted, title, titleStyles}) {
const styles = useThemeStyles();
+
return (
<>
-
+ {cardLayout === CARD_LAYOUT.ICON_ON_TOP && (
+
+ )}
+
{title}
-
- {Boolean(icon) && (
-
- )}
- {Boolean(IconComponent) && }
-
+ {cardLayout === CARD_LAYOUT.ICON_ON_RIGHT && (
+
+ )}
{Boolean(subtitle) && (
-
- {subtitle}
+
+ {subtitle}
)}
@@ -95,9 +114,9 @@ function Section({children, childrenStyles, containerStyles, icon, IconComponent
>
);
}
-
Section.displayName = 'Section';
Section.propTypes = propTypes;
Section.defaultProps = defaultProps;
+export {CARD_LAYOUT};
export default Section;
diff --git a/src/languages/en.ts b/src/languages/en.ts
index fec747ae253b..71d27e341cac 100755
--- a/src/languages/en.ts
+++ b/src/languages/en.ts
@@ -1489,8 +1489,9 @@ export default {
mustBeOnlineToViewMembers: 'You must be online in order to view members of this workspace.',
},
emptyWorkspace: {
- title: 'Create a new workspace',
- subtitle: "Workspaces are where you'll chat with your team, reimburse expenses, issue cards, send invoices, pay bills, and more — all in one place.",
+ title: 'Create a workspace',
+ subtitle: 'Manage business expenses, issue cards, send invoices, and more.',
+ createAWorkspaceCTA: 'Get Started',
features: {
trackAndCollect: 'Track and collect receipts',
companyCards: 'Company credit cards',
diff --git a/src/languages/es.ts b/src/languages/es.ts
index 73ee616d57bb..85223c559f81 100644
--- a/src/languages/es.ts
+++ b/src/languages/es.ts
@@ -1512,8 +1512,9 @@ export default {
mustBeOnlineToViewMembers: 'Debes estar en línea para poder ver los miembros de este espacio de trabajo.',
},
emptyWorkspace: {
- title: 'Crear un nuevo espacio de trabajo',
- subtitle: 'En los espacios de trabajo es donde puedes chatear con tu equipo, reembolsar gastos, emitir tarjetas, enviar y pagar facturas y mas — todo en un mismo lugar',
+ title: 'Crea un espacio de trabajo',
+ subtitle: 'Administra gastos de empresa, emite tarjetas, envía facturas y mucho más.',
+ createAWorkspaceCTA: 'Comenzar',
features: {
trackAndCollect: 'Organiza recibos',
companyCards: 'Tarjetas de crédito corporativas',
diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts
index 9a3099ba6c02..4847eee2c8c6 100644
--- a/src/libs/ReportActionsUtils.ts
+++ b/src/libs/ReportActionsUtils.ts
@@ -735,7 +735,7 @@ function getMemberChangeMessageFragment(reportAction: OnyxEntry):
.map((messageElement) => {
switch (messageElement.kind) {
case 'userMention':
- return ``;
+ return `${messageElement.content}`;
case 'roomReference':
return `${messageElement.roomName}`;
default:
diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts
index 135e616f7691..0ea325cacf00 100644
--- a/src/libs/actions/Report.ts
+++ b/src/libs/actions/Report.ts
@@ -24,6 +24,7 @@ import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils';
import * as Pusher from '@libs/Pusher/pusher';
import * as ReportActionsUtils from '@libs/ReportActionsUtils';
import * as ReportUtils from '@libs/ReportUtils';
+import shouldSkipDeepLinkNavigation from '@libs/shouldSkipDeepLinkNavigation';
import * as UserUtils from '@libs/UserUtils';
import Visibility from '@libs/Visibility';
import CONFIG from '@src/CONFIG';
@@ -2032,6 +2033,10 @@ function openReportFromDeepLink(url: string, isAuthenticated: boolean) {
return;
}
+ if (shouldSkipDeepLinkNavigation(route)) {
+ return;
+ }
+
Navigation.navigate(route as Route, CONST.NAVIGATION.ACTION_TYPE.PUSH);
});
});
diff --git a/src/libs/shouldSkipDeepLinkNavigation/index.desktop.ts b/src/libs/shouldSkipDeepLinkNavigation/index.desktop.ts
new file mode 100644
index 000000000000..0a2d7f533e74
--- /dev/null
+++ b/src/libs/shouldSkipDeepLinkNavigation/index.desktop.ts
@@ -0,0 +1,12 @@
+import ROUTES from '@src/ROUTES';
+
+export default function shouldSkipDeepLinkNavigation(route: string) {
+ // When deep-linking to desktop app with `transition` route we don't want to call navigate
+ // on the route because it will display an infinite loading indicator.
+ // See issue: https://github.com/Expensify/App/issues/33149
+ if (route.includes(ROUTES.TRANSITION_BETWEEN_APPS)) {
+ return true;
+ }
+
+ return false;
+}
diff --git a/src/libs/shouldSkipDeepLinkNavigation/index.ts b/src/libs/shouldSkipDeepLinkNavigation/index.ts
new file mode 100644
index 000000000000..8a2d8035507f
--- /dev/null
+++ b/src/libs/shouldSkipDeepLinkNavigation/index.ts
@@ -0,0 +1,5 @@
+// eslint-disable-next-line @typescript-eslint/no-unused-vars
+export default function shouldSkipDeepLinkNavigation(route: string) {
+ // no-op for all other platforms
+ return false;
+}
diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.js b/src/pages/home/report/ContextMenu/ContextMenuActions.js
index a5e946e6a78a..3682ef602a2b 100644
--- a/src/pages/home/report/ContextMenu/ContextMenuActions.js
+++ b/src/pages/home/report/ContextMenu/ContextMenuActions.js
@@ -35,6 +35,20 @@ function getActionText(reportAction) {
return lodashGet(message, 'html', '');
}
+/**
+ * Sets the HTML string to Clipboard.
+ * @param {String} content
+ */
+function setClipboardMessage(content) {
+ const parser = new ExpensiMark();
+ if (!Clipboard.canSetHtml()) {
+ Clipboard.setString(parser.htmlToMarkdown(content));
+ } else {
+ const plainText = parser.htmlToText(content);
+ Clipboard.setHtml(content, plainText);
+ }
+}
+
const CONTEXT_MENU_TYPES = {
LINK: 'LINK',
REPORT_ACTION: 'REPORT_ACTION',
@@ -291,19 +305,13 @@ export default [
const taskPreviewMessage = TaskUtils.getTaskCreatedMessage(reportAction);
Clipboard.setString(taskPreviewMessage);
} else if (ReportActionsUtils.isMemberChangeAction(reportAction)) {
- const logMessage = ReportActionsUtils.getMemberChangeMessagePlainText(reportAction);
- Clipboard.setString(logMessage);
+ const logMessage = ReportActionsUtils.getMemberChangeMessageFragment(reportAction).html;
+ setClipboardMessage(logMessage);
} else if (ReportActionsUtils.isSubmittedExpenseAction(reportAction)) {
const submittedMessage = _.reduce(reportAction.message, (acc, curr) => `${acc}${curr.text}`, '');
Clipboard.setString(submittedMessage);
} else if (content) {
- const parser = new ExpensiMark();
- if (!Clipboard.canSetHtml()) {
- Clipboard.setString(parser.htmlToMarkdown(content));
- } else {
- const plainText = parser.htmlToText(content);
- Clipboard.setHtml(content, plainText);
- }
+ setClipboardMessage(content);
}
}
diff --git a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
index 8dda0ea0025d..84ca74c2842f 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
@@ -166,6 +166,7 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
key={`${index}+${item.value}`}
onSelectRow={() => updateMode(item)}
showTooltip={false}
+ isFocused={item.isSelected}
/>
)),
[statusType, updateMode],
diff --git a/src/pages/workspace/card/WorkspaceCardCreateAWorkspace.tsx b/src/pages/workspace/card/WorkspaceCardCreateAWorkspace.tsx
new file mode 100644
index 000000000000..9e45bd143e7e
--- /dev/null
+++ b/src/pages/workspace/card/WorkspaceCardCreateAWorkspace.tsx
@@ -0,0 +1,33 @@
+import React from 'react';
+import Button from '@components/Button';
+import * as Illustrations from '@components/Icon/Illustrations';
+import Section, {CARD_LAYOUT} from '@components/Section';
+import useLocalize from '@hooks/useLocalize';
+import useThemeStyles from '@hooks/useThemeStyles';
+
+function WorkspaceCardCreateAWorkspace() {
+ const styles = useThemeStyles();
+ const {translate} = useLocalize();
+
+ return (
+
+ );
+}
+
+WorkspaceCardCreateAWorkspace.displayName = 'WorkspaceCardNoVBAView';
+
+export default WorkspaceCardCreateAWorkspace;
diff --git a/src/styles/index.ts b/src/styles/index.ts
index aececf93beb9..074e70622dac 100644
--- a/src/styles/index.ts
+++ b/src/styles/index.ts
@@ -938,10 +938,14 @@ const styles = (theme: ThemeColors) =>
overflow: 'hidden',
},
- calendarDayContainerSelected: {
+ buttonDefaultBG: {
backgroundColor: theme.buttonDefaultBG,
},
+ buttonHoveredBG: {
+ backgroundColor: theme.buttonHoveredBG,
+ },
+
autoGrowHeightInputContainer: (textInputHeight: number, minHeight: number, maxHeight: number) =>
({
height: lodashClamp(textInputHeight, minHeight, maxHeight),
@@ -1952,10 +1956,6 @@ const styles = (theme: ThemeColors) =>
alignSelf: 'flex-end',
},
- hoveredButton: {
- backgroundColor: theme.buttonHoveredBG,
- },
-
composerSizeButton: {
alignSelf: 'center',
height: 32,