Merge pull request #582 from sharetribe/change-usercard-layout

Change UserCard layout
This commit is contained in:
Kimmo Puputti 2017-12-01 16:22:40 +02:00 committed by GitHub
commit ce469aae8f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 115 additions and 35 deletions

View file

@ -1,11 +1,15 @@
@import '../../marketplace.css';
.root {
}
.content {
display: flex;
flex-direction: row;
}
.avatar {
flex-shrink: 0;
margin-right: 36px;
}
@ -22,7 +26,12 @@
}
}
.bio {
.link {
white-space: nowrap;
}
.mobileBio,
.desktopBio {
/* Preserve newlines, but collapse other whitespace */
white-space: pre-line;
@ -35,6 +44,20 @@
}
}
.mobileBio {
@media (--viewportMedium) {
display: none;
}
}
.desktopBio {
display: none;
@media (--viewportMedium) {
display: block;
}
}
.showMore {
margin-left: 5px;
}
@ -51,4 +74,5 @@
.linkSeparator {
margin: 0 10px;
color: var(--marketplaceColor);
}

View file

@ -5,24 +5,28 @@ import UserCard from './UserCard';
const { UUID } = types;
export const EmptyUser = {
component: UserCard,
props: {},
group: 'users',
};
export const WithUser = {
component: UserCard,
props: {
user: createUser('test-card-user'),
onContactUser: user => console.log('concact user:', user),
},
group: 'users',
};
export const WithCurrentUser = {
export const WithoutBio = {
component: UserCard,
props: {
user: createUser('test-card-user'),
onContactUser: user => console.log('concact user:', user),
},
group: 'users',
};
export const WithoutBioCurrentUser = {
component: UserCard,
props: {
user: createUser('test-card-user'),
currentUser: createCurrentUser('test-card-user'),
onContactUser: user => console.log('concact user:', user),
},
group: 'users',
};
@ -63,7 +67,7 @@ export const WithProfileImageAndBio = {
},
},
},
currentUser: createCurrentUser('full-user'),
onContactUser: user => console.log('concact user:', user),
},
group: 'users',
};

View file

@ -1,5 +1,5 @@
import React, { Component } from 'react';
import { string } from 'prop-types';
import { string, func } from 'prop-types';
import { FormattedMessage } from 'react-intl';
import { truncate } from 'lodash';
import classNames from 'classnames';
@ -35,7 +35,7 @@ class ExpandableBio extends Component {
}
render() {
const { expand } = this.state;
const { bio } = this.props;
const { className, bio } = this.props;
const truncatedBio = truncated(bio);
const handleShowMoreClick = () => {
@ -47,7 +47,7 @@ class ExpandableBio extends Component {
</InlineTextButton>
);
return (
<p className={css.bio}>
<p className={className}>
{expand ? bio : truncatedBio}
{bio !== truncatedBio && !expand ? showMore : null}
</p>
@ -55,45 +55,60 @@ class ExpandableBio extends Component {
}
}
ExpandableBio.defaultProps = { className: null };
ExpandableBio.propTypes = {
className: string,
bio: string.isRequired,
};
const UserCard = props => {
const { rootClassName, className, user, currentUser } = props;
const { rootClassName, className, user, currentUser, onContactUser } = props;
const ensuredUser = ensureUser(user);
const ensuredCurrentUser = ensureCurrentUser(currentUser);
const isCurrentUser =
ensuredUser.id && ensuredCurrentUser.id && ensuredUser.id.uuid === ensuredCurrentUser.id.uuid;
const { displayName, bio } = ensuredUser.attributes.profile;
const handleContactUserClick = () => {
onContactUser(user);
};
const hasBio = !!bio;
const classes = classNames(rootClassName || css.root, className);
const linkClasses = classNames(css.links, {
[css.withBioMissingAbove]: !hasBio,
});
const separator = isCurrentUser ? null : <span className={css.linkSeparator}></span>;
const contact = isCurrentUser ? null : (
<InlineTextButton onClick={handleContactUserClick}>
<FormattedMessage id="UserCard.contactUser" />
</InlineTextButton>
);
const links = ensuredUser.id ? (
<p className={linkClasses}>
<NamedLink className={css.link} name="ProfilePage" params={{ id: ensuredUser.id.uuid }}>
<FormattedMessage id="UserCard.viewProfileLink" />
</NamedLink>
{separator}
{contact}
</p>
) : null;
return (
<div className={classes}>
<AvatarLarge className={css.avatar} user={user} />
<div className={css.info}>
<h3 className={css.heading}>
<FormattedMessage id="UserCard.heading" values={{ name: displayName }} />
</h3>
{hasBio ? <ExpandableBio bio={bio} /> : null}
<p className={linkClasses}>
{ensuredUser.id ? (
<NamedLink name="ProfilePage" params={{ id: ensuredUser.id.uuid }}>
<FormattedMessage id="UserCard.viewProfileLink" />
</NamedLink>
) : null}
{isCurrentUser ? <span className={css.linkSeparator}></span> : null}
{isCurrentUser ? (
<NamedLink name="ProfileSettingsPage">
<FormattedMessage id="UserCard.editProfileLink" />
</NamedLink>
) : null}
</p>
<div className={css.content}>
<AvatarLarge className={css.avatar} user={user} />
<div className={css.info}>
<h3 className={css.heading}>
<FormattedMessage id="UserCard.heading" values={{ name: displayName }} />
</h3>
{hasBio ? <ExpandableBio className={css.desktopBio} bio={bio} /> : null}
{links}
</div>
</div>
{hasBio ? <ExpandableBio className={css.mobileBio} bio={bio} /> : null}
</div>
);
};
@ -108,6 +123,7 @@ UserCard.propTypes = {
className: string,
user: propTypes.user,
currentUser: propTypes.currentUser,
onContactUser: func.isRequired,
};
export default UserCard;

View file

@ -186,6 +186,7 @@
.mainContent {
flex-basis: 100%;
margin-bottom: 23px;
@media (--viewportMedium) {
margin-top: 50px;
@ -382,6 +383,7 @@
}
.yourHostContainer {
position: relative;
padding: 0 24px;
margin-bottom: 5px;
@ -407,6 +409,24 @@
}
}
.editProfileLink {
@apply --marketplaceH4FontStyles;
position: absolute;
margin: 0;
/* Align to same baseline as the "Your host" heading */
top: 2px;
right: 24px;
@media (--viewportMedium) {
margin: 0;
/* Align to same baseline as the "Hello, ..." heading */
top: 74px;
right: 0;
}
}
.map {
/* Dimensions: Map takes all available space from viewport (excludes action button and section title) */
height: calc(100vh - 193px);

View file

@ -375,6 +375,11 @@ export class ListingPageComponent extends Component {
</NamedLink>
);
const handleContactUser = user => {
// TODO: this
console.log('contact user:', user);
};
return (
<Page
title={schemaTitle}
@ -474,7 +479,16 @@ export class ListingPageComponent extends Component {
<h2 className={css.yourHostHeading}>
<FormattedMessage id="ListingPage.yourHostHeading" />
</h2>
<UserCard user={currentListing.author} currentUser={currentUser} />
{isOwnListing ? (
<NamedLink className={css.editProfileLink} name="ProfileSettingsPage">
<FormattedMessage id="ListingPage.editProfileLink" />
</NamedLink>
) : null}
<UserCard
user={currentListing.author}
currentUser={currentUser}
onContactUser={handleContactUser}
/>
</div>
</div>

View file

@ -274,6 +274,7 @@ exports[`ListingPage matches snapshot 1`] = `
"type": "currentUser",
}
}
onContactUser={[Function]}
rootClassName={null}
user={
Object {

View file

@ -229,6 +229,7 @@
"ListingPage.ctaButtonMessage": "Request to book",
"ListingPage.descriptionTitle": "About this sauna",
"ListingPage.editListing": "Edit listing",
"ListingPage.editProfileLink": "Edit profile",
"ListingPage.errorLoadingListingMessage": "Could not load listing. Please try again.",
"ListingPage.errorLoadingListingTitle": "Error in loading listing",
"ListingPage.hostedBy": "Hosted by {name}",
@ -619,7 +620,7 @@
"TopbarMobileMenu.yourListingsLink": "Your listings",
"TopbarSearchForm.placeholder": "Search saunas…",
"TopbarSearchForm.searchHelp": "Tip: You can also search saunas by zip code, for example \"00500\" or city district \"Sörnäinen\".",
"UserCard.editProfileLink": "Edit profile",
"UserCard.contactUser": "Contact",
"UserCard.heading": "Hello, I'm {name}.",
"UserCard.showFullBioLink": "more",
"UserCard.viewProfileLink": "View profile"