mirror of
https://github.com/kingomarnajjar/flex-template-web.git
synced 2026-07-26 06:47:17 +10:00
Merge pull request #582 from sharetribe/change-usercard-layout
Change UserCard layout
This commit is contained in:
commit
ce469aae8f
7 changed files with 115 additions and 35 deletions
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
||||
|
|
|
|||
|
|
@ -274,6 +274,7 @@ exports[`ListingPage matches snapshot 1`] = `
|
|||
"type": "currentUser",
|
||||
}
|
||||
}
|
||||
onContactUser={[Function]}
|
||||
rootClassName={null}
|
||||
user={
|
||||
Object {
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue