Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Empty State Design #13647

Merged
merged 36 commits into from
Jan 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
17f4d94
initial text formatting
dangrous Dec 8, 2022
a739303
Merge branch 'main' into dangrous-emptystatedesign
dangrous Dec 13, 2022
7fb162d
add svg
dangrous Dec 15, 2022
3d31260
allow for review
dangrous Dec 15, 2022
e16af81
add background image to empty state
dangrous Dec 19, 2022
882a866
make text styling work
dangrous Dec 19, 2022
2137936
clean code, fix unrelated spelling error
dangrous Dec 19, 2022
1ce6051
revert Podfile
dangrous Dec 19, 2022
cc8a117
address review and lint
dangrous Dec 20, 2022
284b025
fix padding
dangrous Dec 20, 2022
61cb1d5
update spanish translations
dangrous Dec 21, 2022
86095e1
update english
dangrous Dec 21, 2022
0383b99
merge main
dangrous Dec 21, 2022
17e6fa0
update image sizing
dangrous Dec 21, 2022
d3eee04
add trailing comma
dangrous Dec 21, 2022
57f1bc8
remove unnecessary view
dangrous Dec 22, 2022
514d4b9
update spacing to be uniform across chat types
dangrous Dec 22, 2022
55a42ee
address comments
dangrous Dec 28, 2022
b9577b8
Merge branch 'main' into dangrous-emptystatedesign
dangrous Dec 29, 2022
95f5cf0
update clickability
dangrous Dec 29, 2022
5e0dcc4
update background image
dangrous Jan 3, 2023
7e961e9
address comments
dangrous Jan 3, 2023
8e36b3f
Merge branch 'main' into dangrous-emptystatedesign
dangrous Jan 3, 2023
0482070
merge main, fix conflicts
dangrous Jan 3, 2023
8329746
remove unnecessary propType
dangrous Jan 3, 2023
1feae14
add window proptypes
dangrous Jan 3, 2023
c8d2492
Merge branch 'main' into dangrous-emptystatedesign
dangrous Jan 9, 2023
70b2302
update header font
dangrous Jan 9, 2023
44b28f2
update image, change to imagebackground
dangrous Jan 11, 2023
f378578
merge conflicts
dangrous Jan 11, 2023
c192797
update error message style
dangrous Jan 12, 2023
a33d6c8
add minheight to see full image when text in chat
dangrous Jan 13, 2023
51a9688
fix scrolling issue
dangrous Jan 17, 2023
fa6ea43
merge and add docs
dangrous Jan 23, 2023
87d197a
merge conflicts
dangrous Jan 25, 2023
752ea0f
move pointerEvent none
dangrous Jan 30, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added assets/images/empty-state_background-fade.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 14 additions & 0 deletions src/CONST.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,20 @@ const CONST = {
AVATAR_MAX_WIDTH_PX: 4096,
AVATAR_MAX_HEIGHT_PX: 4096,

// Sizes needed for report empty state background image handling
EMPTY_STATE_BACKGROUND: {
SMALL_SCREEN: {
IMAGE_HEIGHT: 300,
CONTAINER_MINHEIGHT: 200,
VIEW_HEIGHT: 185,
},
WIDE_SCREEN: {
IMAGE_HEIGHT: 450,
CONTAINER_MINHEIGHT: 500,
VIEW_HEIGHT: 275,
},
},

NEW_EXPENSIFY_URL: ACTIVE_EXPENSIFY_URL,
APP_DOWNLOAD_LINKS: {
ANDROID: `https://play.google.com/store/apps/details?id=${ANDROID_PACKAGE_NAME}`,
Expand Down
125 changes: 67 additions & 58 deletions src/components/ReportWelcomeText.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import lodashGet from 'lodash/get';
import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
import styles from '../styles/styles';
Expand Down Expand Up @@ -62,66 +63,74 @@ const ReportWelcomeText = (props) => {
);
const roomWelcomeMessage = ReportUtils.getRoomWelcomeMessage(props.report, props.policies);
return (
<Text style={[styles.mt3, styles.mw100, styles.textAlignCenter]}>
{isPolicyExpenseChat && (
<>
{/* Add align center style individually because of limited style inheritance in React Native https://reactnative.dev/docs/text#limited-style-inheritance */}
<Text style={styles.textAlignCenter}>
Comment on lines -68 to -69
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it okay to remove this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep! Removing that style shifts the text over to the left, to match the mocks. Not needed anymore.

{props.translate('reportActionsView.beginningOfChatHistoryPolicyExpenseChatPartOne')}
</Text>
<Text style={[styles.textStrong]}>
{/* Use the policyExpenseChat owner's first name or their email if it's undefined or an empty string */}
{lodashGet(props.personalDetails, [props.report.ownerEmail, 'firstName']) || props.report.ownerEmail}
</Text>
<Text>
{props.translate('reportActionsView.beginningOfChatHistoryPolicyExpenseChatPartTwo')}
</Text>
<Text style={[styles.textStrong]}>
{ReportUtils.getPolicyName(props.report, props.policies)}
</Text>
<Text>
{props.translate('reportActionsView.beginningOfChatHistoryPolicyExpenseChatPartThree')}
</Text>
</>
)}
{isChatRoom && (
<>
{/* Add align center style individually because of limited style inheritance in React Native https://reactnative.dev/docs/text#limited-style-inheritance */}
<Text style={styles.textAlignCenter}>
{roomWelcomeMessage.phrase1}
</Text>
<Text style={[styles.textStrong]} onPress={() => Navigation.navigate(ROUTES.getReportDetailsRoute(props.report.reportID))}>
{ReportUtils.getReportName(props.report, props.policies)}
</Text>
<>
<View>
<Text style={[styles.textHero]}>
{props.translate('reportActionsView.sayHello')}
</Text>
</View>
<Text style={[styles.mt3, styles.mw100]}>
{isPolicyExpenseChat && (
<>
<Text>
{props.translate('reportActionsView.beginningOfChatHistoryPolicyExpenseChatPartOne')}
</Text>
<Text style={[styles.textStrong]}>
{/* Use the policyExpenseChat owner's first name or their email if it's undefined or an empty string */}
{lodashGet(props.personalDetails, [props.report.ownerEmail, 'firstName']) || props.report.ownerEmail}
</Text>
<Text>
{props.translate('reportActionsView.beginningOfChatHistoryPolicyExpenseChatPartTwo')}
</Text>
<Text style={[styles.textStrong]}>
{ReportUtils.getPolicyName(props.report, props.policies)}
</Text>
<Text>
{props.translate('reportActionsView.beginningOfChatHistoryPolicyExpenseChatPartThree')}
</Text>
</>
)}
{isChatRoom && (
<>
<Text>
{roomWelcomeMessage.phrase1}
</Text>
<Text style={[styles.textStrong]} onPress={() => Navigation.navigate(ROUTES.getReportDetailsRoute(props.report.reportID))}>
{ReportUtils.getReportName(props.report, props.policies)}
</Text>
<Text>
{roomWelcomeMessage.phrase2}
</Text>
</>
)}
{isDefault && (
<Text>
{roomWelcomeMessage.phrase2}
</Text>
</>
)}
{isDefault && (
<>
{/* Add align center style individually because of limited style inheritance in React Native https://reactnative.dev/docs/text#limited-style-inheritance */}
<Text style={styles.textAlignCenter}>
{props.translate('reportActionsView.beginningOfChatHistory')}
</Text>
{_.map(displayNamesWithTooltips, ({
displayName, pronouns, tooltip,
}, index) => (
<Text key={`${displayName}${pronouns}${index}`}>
<Tooltip text={tooltip} containerStyles={[styles.dInline]}>
<Text style={[styles.textStrong]} onPress={() => Navigation.navigate(ROUTES.getDetailsRoute(participants[index]))}>
{displayName}
</Text>
</Tooltip>
{!_.isEmpty(pronouns) && <Text>{` (${pronouns})`}</Text>}
{(index === displayNamesWithTooltips.length - 1) && <Text>.</Text>}
{(index === displayNamesWithTooltips.length - 2) && <Text>{` ${props.translate('common.and')} `}</Text>}
{(index < displayNamesWithTooltips.length - 2) && <Text>, </Text>}
<Text>
{props.translate('reportActionsView.beginningOfChatHistory')}
</Text>
))}
</>
)}
</Text>
{_.map(displayNamesWithTooltips, ({
displayName, pronouns, tooltip,
}, index) => (
<Text key={`${displayName}${pronouns}${index}`}>
<Tooltip text={tooltip} containerStyles={[styles.dInline]}>
<Text style={[styles.textStrong]} onPress={() => Navigation.navigate(ROUTES.getDetailsRoute(participants[index]))}>
{displayName}
</Text>
</Tooltip>
{!_.isEmpty(pronouns) && <Text>{` (${pronouns})`}</Text>}
{(index === displayNamesWithTooltips.length - 1) && <Text>.</Text>}
{(index === displayNamesWithTooltips.length - 2) && <Text>{` ${props.translate('common.and')} `}</Text>}
{(index < displayNamesWithTooltips.length - 2) && <Text>, </Text>}
</Text>
))}
<Text>
{/* Need to confirm copy for the below with marketing, and then add to translations. */}
{props.translate('reportActionsView.usePlusButton')}
</Text>
</Text>
)}
</Text>
</>
);
};

Expand Down
6 changes: 4 additions & 2 deletions src/languages/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -206,8 +206,8 @@ export default {
deleteConfirmation: 'Are you sure you want to delete this comment?',
},
reportActionsView: {
begginningOfArchivedRoomPartOne: 'You missed the party in ',
begginningOfArchivedRoomPartTwo: ', there\'s nothing to see here.',
beginningOfArchivedRoomPartOne: 'You missed the party in ',
beginningOfArchivedRoomPartTwo: ', there\'s nothing to see here.',
beginningOfChatHistoryDomainRoomPartOne: ({domainRoom}) => `Collaboration with everyone at ${domainRoom} starts here! 🎉\nUse `,
beginningOfChatHistoryDomainRoomPartTwo: ' to chat with colleagues, share tips, and ask questions.',
beginningOfChatHistoryAdminRoomPartOne: ({workspaceName}) => `Collaboration among ${workspaceName} admins starts here! 🎉\nUse `,
Expand All @@ -221,6 +221,8 @@ export default {
beginningOfChatHistoryPolicyExpenseChatPartTwo: ' and ',
beginningOfChatHistoryPolicyExpenseChatPartThree: ' starts here! 🎉 This is the place to chat, request money and settle up.',
chatWithAccountManager: 'Chat with your account manager here',
sayHello: 'Say hello!',
usePlusButton: '\n\nYou can also use the + button below to send or request money!',
},
newMessages: 'New messages',
reportTypingIndicator: {
Expand Down
6 changes: 4 additions & 2 deletions src/languages/es.js
Original file line number Diff line number Diff line change
Expand Up @@ -206,8 +206,8 @@ export default {
deleteConfirmation: '¿Estás seguro de que quieres eliminar este comentario?',
},
reportActionsView: {
begginningOfArchivedRoomPartOne: 'Te perdiste la fiesta en ',
begginningOfArchivedRoomPartTwo: ', no hay nada que ver aquí.',
beginningOfArchivedRoomPartOne: 'Te perdiste la fiesta en ',
beginningOfArchivedRoomPartTwo: ', no hay nada que ver aquí.',
beginningOfChatHistoryDomainRoomPartOne: ({domainRoom}) => `Colabora aquí con todos los participantes de ${domainRoom}! 🎉\nUtiliza `,
beginningOfChatHistoryDomainRoomPartTwo: ' para chatear con compañeros, compartir consejos o hacer una pregunta.',
beginningOfChatHistoryAdminRoomPartOne: ({workspaceName}) => `Este es el lugar para que los administradores de ${workspaceName} colaboren! 🎉\nUsa `,
Expand All @@ -221,6 +221,8 @@ export default {
beginningOfChatHistoryPolicyExpenseChatPartTwo: ' y ',
beginningOfChatHistoryPolicyExpenseChatPartThree: ' empieza aquí! 🎉 Este es el lugar donde chatear, pedir dinero y pagar.',
chatWithAccountManager: 'Chatea con tu gestor de cuenta aquí',
sayHello: '¡Saluda!',
usePlusButton: '\n\n¡También puedes usar el botón + de abajo para enviar o pedir dinero!',
},
newMessages: 'Mensajes nuevos',
reportTypingIndicator: {
Expand Down
4 changes: 2 additions & 2 deletions src/libs/ReportUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -328,8 +328,8 @@ function getRoomWelcomeMessage(report, policiesMap) {
const workspaceName = getPolicyName(report, policiesMap);

if (isArchivedRoom(report)) {
welcomeMessage.phrase1 = Localize.translateLocal('reportActionsView.begginningOfArchivedRoomPartOne');
welcomeMessage.phrase2 = Localize.translateLocal('reportActionsView.begginningOfArchivedRoomPartTwo');
welcomeMessage.phrase1 = Localize.translateLocal('reportActionsView.beginningOfArchivedRoomPartOne');
welcomeMessage.phrase2 = Localize.translateLocal('reportActionsView.beginningOfArchivedRoomPartTwo');
} else if (isDomainRoom(report)) {
welcomeMessage.phrase1 = Localize.translateLocal('reportActionsView.beginningOfChatHistoryDomainRoomPartOne', {domainRoom: report.reportName});
welcomeMessage.phrase2 = Localize.translateLocal('reportActionsView.beginningOfChatHistoryDomainRoomPartTwo');
Expand Down
65 changes: 41 additions & 24 deletions src/pages/home/report/ReportActionItemCreated.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import {Pressable, View} from 'react-native';
import {Pressable, ImageBackground, View} from 'react-native';
import lodashGet from 'lodash/get';
import {withOnyx} from 'react-native-onyx';
import PropTypes from 'prop-types';
Expand All @@ -12,6 +12,10 @@ import styles from '../../../styles/styles';
import OfflineWithFeedback from '../../../components/OfflineWithFeedback';
import * as Report from '../../../libs/actions/Report';
import reportPropTypes from '../../reportPropTypes';
import EmptyStateBackgroundImage from '../../../../assets/images/empty-state_background-fade.png';
import * as StyleUtils from '../../../styles/StyleUtils';
import withWindowDimensions, {windowDimensionsPropTypes} from '../../../components/withWindowDimensions';
import compose from '../../../libs/compose';

const propTypes = {
/** The id of the report */
Expand All @@ -28,6 +32,8 @@ const propTypes = {
/** Name of the policy */
name: PropTypes.string,
}),

...windowDimensionsPropTypes,
};
const defaultProps = {
report: {},
Expand All @@ -37,28 +43,36 @@ const defaultProps = {

const ReportActionItemCreated = (props) => {
const icons = ReportUtils.getIcons(props.report, props.personalDetails, props.policies);

return (
<OfflineWithFeedback
pendingAction={lodashGet(props.report, 'pendingFields.addWorkspaceRoom') || lodashGet(props.report, 'pendingFields.createChat')}
errors={lodashGet(props.report, 'errorFields.addWorkspaceRoom') || lodashGet(props.report, 'errorFields.createChat')}
errorRowStyles={styles.addWorkspaceRoomErrorRow}
errorRowStyles={[styles.ml10, styles.mr2]}
onClose={() => Report.navigateToConciergeChatAndDeleteReport(props.report.reportID)}
>
<View
accessibilityLabel="Chat welcome message"
style={[
styles.chatContent,
styles.pb8,
styles.p5,
]}
>
<View style={[styles.justifyContentCenter, styles.alignItemsCenter, styles.flex1]}>
<Pressable onPress={() => ReportUtils.navigateToDetailsPage(props.report)}>
<View style={StyleUtils.getReportWelcomeContainerStyle(props.isSmallScreenWidth)}>
<View pointerEvents="none" style={StyleUtils.getReportWelcomeBackgroundImageViewStyle(props.isSmallScreenWidth)}>
<ImageBackground
source={EmptyStateBackgroundImage}
style={StyleUtils.getReportWelcomeBackgroundImageStyle(props.isSmallScreenWidth)}
/>
</View>
<View
accessibilityLabel="Chat welcome message"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we be using non-translated strings for accessibilityLabel? Another thing is no string should be used directly on the code, it should be coming as CONST or translation key.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's translate this as well.

Copy link
Contributor Author

@dangrous dangrous Jan 30, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my comments in Slack - I agree that this should be changed BUT I think we need to handle that separately (for context, this was already here, I just moved it). It is being used for testing here and this is the pattern across the app. Again, I don't like this either but I think we can do another issue for this at this time.

style={styles.p5}
>
<Pressable
onPress={() => ReportUtils.navigateToDetailsPage(props.report)}
style={[styles.ph5, styles.pb3, styles.alignSelfStart]}
>
<RoomHeaderAvatars
icons={icons}
/>
</Pressable>
<ReportWelcomeText report={props.report} />
<View style={[styles.ph5]}>
<ReportWelcomeText report={props.report} />
</View>
</View>
</View>
</OfflineWithFeedback>
Expand All @@ -69,14 +83,17 @@ ReportActionItemCreated.defaultProps = defaultProps;
ReportActionItemCreated.propTypes = propTypes;
ReportActionItemCreated.displayName = 'ReportActionItemCreated';

export default withOnyx({
report: {
key: ({reportID}) => `${ONYXKEYS.COLLECTION.REPORT}${reportID}`,
},
personalDetails: {
key: ONYXKEYS.PERSONAL_DETAILS,
},
policies: {
key: ONYXKEYS.COLLECTION.POLICY,
},
})(ReportActionItemCreated);
export default compose(
withWindowDimensions,
withOnyx({
report: {
key: ({reportID}) => `${ONYXKEYS.COLLECTION.REPORT}${reportID}`,
},
personalDetails: {
key: ONYXKEYS.PERSONAL_DETAILS,
},
policies: {
key: ONYXKEYS.COLLECTION.POLICY,
},
}),
)(ReportActionItemCreated);
63 changes: 63 additions & 0 deletions src/styles/StyleUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -662,6 +662,66 @@ function getErrorPageContainerStyle(safeAreaPaddingBottom = 0) {
};
}

/**
* Gets the correct size for the empty state background image based on screen dimensions
*
* @param {Boolean} isSmallScreenWidth
* @returns {Object}
*/
function getReportWelcomeBackgroundImageStyle(isSmallScreenWidth) {
if (isSmallScreenWidth) {
return {
height: CONST.EMPTY_STATE_BACKGROUND.SMALL_SCREEN.IMAGE_HEIGHT,
width: '100%',
};
}

return {
height: CONST.EMPTY_STATE_BACKGROUND.WIDE_SCREEN.IMAGE_HEIGHT,
width: '100%',
};
}

/**
* Gets the correct size for the empty state background image view based on screen dimensions
*
* @param {Boolean} isSmallScreenWidth
* @returns {Object}
*/
function getReportWelcomeBackgroundImageViewStyle(isSmallScreenWidth) {
if (isSmallScreenWidth) {
return {
height: CONST.EMPTY_STATE_BACKGROUND.SMALL_SCREEN.VIEW_HEIGHT,
};
}

return {
height: CONST.EMPTY_STATE_BACKGROUND.WIDE_SCREEN.VIEW_HEIGHT,
};
}

/**
* Gets the correct size for the empty state container based on screen dimensions
*
* @param {Boolean} isSmallScreenWidth
* @returns {Object}
*/
function getReportWelcomeContainerStyle(isSmallScreenWidth) {
if (isSmallScreenWidth) {
return {
minHeight: CONST.EMPTY_STATE_BACKGROUND.SMALL_SCREEN.CONTAINER_MINHEIGHT,
display: 'flex',
justifyContent: 'space-between',
};
}

return {
minHeight: CONST.EMPTY_STATE_BACKGROUND.WIDE_SCREEN.CONTAINER_MINHEIGHT,
display: 'flex',
justifyContent: 'space-between',
};
}

export {
getAvatarSize,
getAvatarStyle,
Expand Down Expand Up @@ -698,4 +758,7 @@ export {
getHeight,
fade,
getHorizontalStackedAvatarBorderStyle,
getReportWelcomeBackgroundImageStyle,
getReportWelcomeBackgroundImageViewStyle,
getReportWelcomeContainerStyle,
};
Loading