diff --git a/src/components/Avatar/Avatar.js b/src/components/Avatar/Avatar.js index 3aac1327..226cee24 100644 --- a/src/components/Avatar/Avatar.js +++ b/src/components/Avatar/Avatar.js @@ -1,18 +1,16 @@ import React, { PropTypes } from 'react'; import classNames from 'classnames'; +import * as propTypes from '../../util/propTypes'; import css from './Avatar.css'; const Avatar = props => { - const { className, firstName, lastName, rootClassName } = props; + const { rootClassName, className, user } = props; const classes = classNames(rootClassName || css.root, className); - - const authorName = lastName ? `${firstName} ${lastName}` : firstName; - const initials = lastName ? firstName.charAt(0) + lastName.charAt(0) : firstName.charAt(0); - + const { displayName, abbreviatedName } = user.profile; const placeHolderAvatar = ( -
- {initials} +
+ {abbreviatedName}
); @@ -23,14 +21,12 @@ const { string } = PropTypes; Avatar.defaultProps = { className: null, - lastName: null, rootClassName: null, }; Avatar.propTypes = { className: string, - firstName: string.isRequired, - lastName: string, + user: propTypes.user.isRequired, rootClassName: string, }; diff --git a/src/components/ListingCard/ListingCard.js b/src/components/ListingCard/ListingCard.js index 80d461db..8315b3d7 100644 --- a/src/components/ListingCard/ListingCard.js +++ b/src/components/ListingCard/ListingCard.js @@ -37,7 +37,7 @@ export const ListingCardComponent = props => { const { title = '', price } = currentListing.attributes; const slug = createSlug(title); const author = ensureUser(listing.author); - const authorName = `${author.attributes.profile.firstName} ${author.attributes.profile.lastName}`; + const authorName = author.attributes.profile.displayName; const firstImage = currentListing.images && currentListing.images.length > 0 ? currentListing.images[0] : null; diff --git a/src/components/OrderDetailsPanel/OrderDetailsPanel.js b/src/components/OrderDetailsPanel/OrderDetailsPanel.js index ff480c79..3b31c857 100644 --- a/src/components/OrderDetailsPanel/OrderDetailsPanel.js +++ b/src/components/OrderDetailsPanel/OrderDetailsPanel.js @@ -132,9 +132,8 @@ const OrderDetailsPanel = props => { const currentCustomer = ensureUser(currentTransaction.customer); const providerProfile = currentProvider.attributes.profile; - const authorFirstName = providerProfile.firstName; - const authorLastName = providerProfile.lastName; - const customerName = currentCustomer.attributes.profile.firstName; + const authorDisplayName = providerProfile.displayName; + const customerDisplayName = currentCustomer.attributes.profile.displayName; const transactionState = currentTransaction.attributes.state; const lastTransitionedAt = currentTransaction.attributes.lastTransitionedAt; const lastTransition = currentTransaction.attributes.lastTransitione; @@ -154,11 +153,11 @@ const OrderDetailsPanel = props => { const listingTitle = currentListing.attributes.title; const bookingInfo = breakdown(currentTransaction); - const title = orderTitle(transactionState, listingLink, customerName, lastTransition); + const title = orderTitle(transactionState, listingLink, customerDisplayName, lastTransition); const message = orderMessage( transactionState, listingLink, - authorFirstName, + authorDisplayName, lastTransitionedAt, lastTransition ); @@ -185,7 +184,7 @@ const OrderDetailsPanel = props => { />
- +

{title}

@@ -214,14 +213,14 @@ const OrderDetailsPanel = props => { />
- +

{listingTitle}

diff --git a/src/components/SaleDetailsPanel/SaleDetailsPanel.js b/src/components/SaleDetailsPanel/SaleDetailsPanel.js index 7c085fc4..b45ff001 100644 --- a/src/components/SaleDetailsPanel/SaleDetailsPanel.js +++ b/src/components/SaleDetailsPanel/SaleDetailsPanel.js @@ -125,8 +125,7 @@ const SaleDetailsPanel = props => { const currentListing = ensureListing(currentTransaction.listing); const currentCustomer = ensureUser(currentTransaction.customer); - const customerFirstName = currentCustomer.attributes.profile.firstName; - const customerLastName = currentCustomer.attributes.profile.lastName; + const customerDisplayName = currentCustomer.attributes.profile.displayName; const transactionState = currentTransaction.attributes.state; const lastTransitionedAt = currentTransaction.attributes.lastTransitionedAt; const lastTransition = currentTransaction.attributes.lastTransition; @@ -150,10 +149,10 @@ const SaleDetailsPanel = props => { const bookingInfo = breakdown(currentTransaction, totalMessage); - const title = saleTitle(transactionState, listingLink, customerFirstName, lastTransition); + const title = saleTitle(transactionState, listingLink, customerDisplayName, lastTransition); const message = saleMessage( transactionState, - customerFirstName, + customerDisplayName, lastTransitionedAt, lastTransition ); @@ -202,11 +201,11 @@ const SaleDetailsPanel = props => { />
- +
- +

{title}

{message}

diff --git a/src/components/Topbar/Topbar.js b/src/components/Topbar/Topbar.js index 94d21297..d3537210 100644 --- a/src/components/Topbar/Topbar.js +++ b/src/components/Topbar/Topbar.js @@ -7,7 +7,7 @@ import { Button, Modal, NamedLink, TopbarDesktop, TopbarMobileMenu } from '../.. import { TopbarSearchForm } from '../../containers'; import { withFlattenedRoutes, withViewport } from '../../util/contextHelpers'; import { parse, stringify } from '../../util/urlHelpers'; -import { ensureUser } from '../../util/data'; +import { ensureCurrentUser } from '../../util/data'; import { createResourceLocatorString, pathByRouteName } from '../../util/routes'; import * as propTypes from '../../util/propTypes'; @@ -96,8 +96,7 @@ class TopbarComponent extends Component { location, onManageDisableScrolling, } = this.props; - const me = ensureUser(currentUser); - const profile = me.attributes.profile; + const me = ensureCurrentUser(currentUser); const { mobilemenu, mobilesearch, address, origin, bounds, country } = parse(location.search, { latlng: ['origin'], @@ -114,8 +113,7 @@ class TopbarComponent extends Component { @@ -157,8 +155,7 @@ class TopbarComponent extends Component {
{ const { className, - firstName, - lastName, + user, rootClassName, currentUserHasListings, notificationCount, @@ -61,7 +61,7 @@ const TopbarDesktop = props => { const profileMenu = isAuthenticated ? - + @@ -111,8 +111,6 @@ const TopbarDesktop = props => { const { bool, func, object, number, string } = PropTypes; TopbarDesktop.defaultProps = { - firstName: '', - lastName: '', notificationCount: 0, className: null, rootClassName: null, @@ -124,8 +122,7 @@ TopbarDesktop.propTypes = { currentUserHasListings: bool.isRequired, isAuthenticated: bool.isRequired, onLogout: func.isRequired, - firstName: string, - lastName: string, + user: propTypes.currentUser.isRequired, notificationCount: number, rootClassName: string, onSearchSubmit: func.isRequired, diff --git a/src/components/TopbarMobileMenu/TopbarMobileMenu.js b/src/components/TopbarMobileMenu/TopbarMobileMenu.js index 0e42f7b9..faba82ac 100644 --- a/src/components/TopbarMobileMenu/TopbarMobileMenu.js +++ b/src/components/TopbarMobileMenu/TopbarMobileMenu.js @@ -4,6 +4,7 @@ */ import React, { PropTypes } from 'react'; import { FormattedMessage } from 'react-intl'; +import * as propTypes from '../../util/propTypes'; import { AvatarLarge, InlineTextButton, NamedLink, NotificationBadge } from '../../components'; import css from './TopbarMobileMenu.css'; @@ -12,8 +13,7 @@ const TopbarMobileMenu = props => { const { isAuthenticated, currentUserHasListings, - firstName, - lastName, + user, notificationCount, onLogout, } = props; @@ -69,12 +69,14 @@ const TopbarMobileMenu = props => { ); + const displayName = user.attributes.profile.displayName; + return (
- +
- + @@ -90,15 +92,14 @@ const TopbarMobileMenu = props => { ); }; -TopbarMobileMenu.defaultProps = { firstName: '', lastName: '', notificationCount: 0 }; +TopbarMobileMenu.defaultProps = { notificationCount: 0 }; -const { bool, func, number, string } = PropTypes; +const { bool, func, number } = PropTypes; TopbarMobileMenu.propTypes = { isAuthenticated: bool.isRequired, currentUserHasListings: bool.isRequired, - firstName: string, - lastName: string, + user: propTypes.currentUser.isRequired, notificationCount: number, onLogout: func.isRequired, }; diff --git a/src/containers/CheckoutPage/CheckoutPage.js b/src/containers/CheckoutPage/CheckoutPage.js index 72bfaf6e..8480f59d 100644 --- a/src/containers/CheckoutPage/CheckoutPage.js +++ b/src/containers/CheckoutPage/CheckoutPage.js @@ -124,9 +124,7 @@ export class CheckoutPageComponent extends Component { const { bookingStart, bookingEnd } = pageData.bookingDates || {}; const currentListing = ensureListing(pageData.listing); const currentAuthor = ensureUser(currentListing.author); - const authorProfile = currentAuthor.attributes.profile; - const authorFirstName = authorProfile.firstName; - const authorLastName = authorProfile.lastName; + const authorDisplayName = currentAuthor.attributes.profile.displayName; const isOwnListing = currentListing.id && currentUser && @@ -207,14 +205,17 @@ export class CheckoutPageComponent extends Component { />
- +

{title}

- +
@@ -257,12 +258,12 @@ export class CheckoutPageComponent extends Component { />
- +

{listingTitle}

- +

diff --git a/src/containers/InboxPage/InboxPage.js b/src/containers/InboxPage/InboxPage.js index 750fea50..8298f645 100644 --- a/src/containers/InboxPage/InboxPage.js +++ b/src/containers/InboxPage/InboxPage.js @@ -26,17 +26,6 @@ import css from './InboxPage.css'; const { arrayOf, bool, func, instanceOf, number, object, oneOf, shape, string } = PropTypes; -const formatUser = user => { - const profile = user && user.attributes && user.attributes.profile - ? user.attributes.profile - : null; - return { - name: `${profile.firstName} ${profile.lastName}`, - firstName: profile.firstName, - lastName: profile.lastName, - }; -}; - const formatDate = (intl, date) => { return { short: intl.formatDate(date, { @@ -103,7 +92,8 @@ export const InboxItem = props => { const { customer, provider, booking } = tx; const isOrder = type === 'order'; - const otherUser = formatUser(isOrder ? provider : customer); + const otherUser = isOrder ? provider : customer; + const otherUserDisplayName = otherUser.attributes.profile.displayName; const stateData = txState(intl, tx, isOrder); const isSaleNotification = !isOrder && tx.attributes.state === propTypes.TX_STATE_PREAUTHORIZED; @@ -121,14 +111,14 @@ export const InboxItem = props => { params={{ id: tx.id.uuid }} >
- +
{rowNotificationDot}
- {otherUser.name} + {otherUserDisplayName}
{bookingStart.short} - {bookingEnd.short} diff --git a/src/containers/ListingPage/ListingPage.js b/src/containers/ListingPage/ListingPage.js index 810d98bd..dbdedc4f 100644 --- a/src/containers/ListingPage/ListingPage.js +++ b/src/containers/ListingPage/ListingPage.js @@ -132,9 +132,8 @@ export class ListingPageComponent extends Component { currentListing.author.id.uuid === currentUser.id.uuid; const showBookButton = !isOwnListing; - const { firstName: authorFirstName, lastName: authorLastName } = authorAvailable - ? ensureUser(currentListing.author).attributes.profile - : { firstName: '', lastName: '' }; + const currentAuthor = ensureUser(authorAvailable ? currentListing.author : {}); + const currentAuthorDisplayName = currentAuthor.attributes.profile.displayName; // TODO location address is currently serialized inside address field (API will change later) // Content is something like { locationAddress: 'Street, Province, Country', building: 'A 42' }; @@ -219,11 +218,7 @@ export class ListingPageComponent extends Component {
- +
@@ -242,7 +237,7 @@ export class ListingPageComponent extends Component {
@@ -276,7 +271,7 @@ export class ListingPageComponent extends Component {
diff --git a/src/translations/en.json b/src/translations/en.json index 24eb4fbe..32918484 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -317,7 +317,7 @@ "TopbarDesktop.logo": "Logo", "TopbarDesktop.logout": "Log out", "TopbarDesktop.signup": "Sign up", - "TopbarMobileMenu.greeting": "Hello {firstName}", + "TopbarMobileMenu.greeting": "Hello {displayName}", "TopbarMobileMenu.inboxLink": "Inbox", "TopbarMobileMenu.loginLink": "Log in", "TopbarMobileMenu.logoutLink": "Log out", diff --git a/src/util/data.js b/src/util/data.js index ae9de3cc..58a942f6 100644 --- a/src/util/data.js +++ b/src/util/data.js @@ -153,3 +153,13 @@ export const ensureUser = user => { const empty = { id: null, type: 'user', attributes: { profile: {} } }; return { ...empty, ...user }; }; + +/** + * Create shell objects to ensure that attributes etc. exists. + * + * @param {Object} current user entity object, which is to be ensured agains null values + */ +export const ensureCurrentUser = user => { + const empty = { id: null, type: 'current-user', attributes: { profile: {} } }; + return { ...empty, ...user }; +}; diff --git a/src/util/propTypes.js b/src/util/propTypes.js index ff9ddf9f..a495891b 100644 --- a/src/util/propTypes.js +++ b/src/util/propTypes.js @@ -70,6 +70,8 @@ export const currentUser = shape({ profile: shape({ firstName: string.isRequired, lastName: string.isRequired, + displayName: string.isRequired, + abbreviatedName: string.isRequired, }).isRequired, stripeConnected: bool.isRequired, }), @@ -81,8 +83,8 @@ export const user = shape({ type: value('user').isRequired, attributes: shape({ profile: shape({ - firstName: string.isRequired, - lastName: string.isRequired, + displayName: string.isRequired, + abbreviatedName: string.isRequired, }).isRequired, }), }); diff --git a/src/util/test-data.js b/src/util/test-data.js index ff226da0..e73fc9e3 100644 --- a/src/util/test-data.js +++ b/src/util/test-data.js @@ -19,7 +19,10 @@ export const createUser = id => ({ id: new UUID(id), type: 'user', attributes: { - profile: { firstName: `${id} first name`, lastName: `${id} last name` }, + profile: { + displayName: `${id} display name`, + abbreviatedName: `${id} abbreviated name`, + }, }, }); @@ -29,7 +32,12 @@ export const createCurrentUser = id => ({ type: 'current-user', attributes: { email: `${id}@example.com`, - profile: { firstName: `${id} first name`, lastName: `${id} last name` }, + profile: { + firstName: `${id} first name`, + lastName: `${id} last name`, + displayName: `${id} display name`, + abbreviatedName: `${id} abbreviated name`, + }, stripeConnected: true, }, });