mirror of
https://github.com/kingomarnajjar/flex-template-web.git
synced 2026-07-29 05:00:43 +10:00
Merge pull request #149 from sharetribe/tabnav-component
TabNav component
This commit is contained in:
commit
3d1707d1f6
9 changed files with 174 additions and 95 deletions
19
src/components/TabNav/TabNav.css
Normal file
19
src/components/TabNav/TabNav.css
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
.tab {
|
||||
float: left;
|
||||
margin-left: 1rem;
|
||||
font-size: 20px;
|
||||
letter-spacing: -0.5px;
|
||||
|
||||
&:first-child {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.link {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.selected {
|
||||
font-weight: bold;
|
||||
text-decoration: underline;
|
||||
}
|
||||
16
src/components/TabNav/TabNav.example.js
Normal file
16
src/components/TabNav/TabNav.example.js
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
import TabNav from './TabNav';
|
||||
|
||||
const selfLinkProps = {
|
||||
name: 'StyleguideComponent',
|
||||
params: { component: 'TabNav' },
|
||||
};
|
||||
|
||||
export const Empty = {
|
||||
component: TabNav,
|
||||
props: {
|
||||
tabs: [
|
||||
{ text: 'Normal', linkProps: selfLinkProps },
|
||||
{ text: 'Selected', linkProps: selfLinkProps, selected: true },
|
||||
],
|
||||
},
|
||||
};
|
||||
45
src/components/TabNav/TabNav.js
Normal file
45
src/components/TabNav/TabNav.js
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
import React, { PropTypes } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { NamedLink } from '../../components';
|
||||
|
||||
import css from './TabNav.css';
|
||||
|
||||
const Tab = props => {
|
||||
const { text, selected, linkProps } = props;
|
||||
const classes = classNames(css.tab, {
|
||||
[css.selected]: selected,
|
||||
});
|
||||
return (
|
||||
<div className={classes}>
|
||||
<NamedLink className={css.link} {...linkProps}>{text}</NamedLink>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Tab.defaultProps = { selected: false };
|
||||
|
||||
const { arrayOf, object, string, bool } = PropTypes;
|
||||
|
||||
Tab.propTypes = {
|
||||
text: string.isRequired,
|
||||
selected: bool,
|
||||
linkProps: object.isRequired,
|
||||
};
|
||||
|
||||
const TabNav = props => {
|
||||
const { className, tabs } = props;
|
||||
return (
|
||||
<nav className={className}>
|
||||
{tabs.map(tab => <Tab key={tab.text} {...tab} />)}
|
||||
</nav>
|
||||
);
|
||||
};
|
||||
|
||||
TabNav.defaultProps = { className: '' };
|
||||
|
||||
TabNav.propTypes = {
|
||||
className: string,
|
||||
tabs: arrayOf(object).isRequired,
|
||||
};
|
||||
|
||||
export default TabNav;
|
||||
|
|
@ -32,6 +32,7 @@ import RoutesProvider from './RoutesProvider/RoutesProvider';
|
|||
import SaleDetailsPanel from './SaleDetailsPanel/SaleDetailsPanel';
|
||||
import SearchResultsPanel from './SearchResultsPanel/SearchResultsPanel';
|
||||
import StripeBankAccountToken from './StripeBankAccountToken/StripeBankAccountToken';
|
||||
import TabNav from './TabNav/TabNav';
|
||||
import ValidationError from './ValidationError/ValidationError';
|
||||
|
||||
export {
|
||||
|
|
@ -71,5 +72,6 @@ export {
|
|||
SaleDetailsPanel,
|
||||
SearchResultsPanel,
|
||||
StripeBankAccountToken,
|
||||
TabNav,
|
||||
ValidationError,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,17 +2,8 @@
|
|||
margin: 1rem;
|
||||
}
|
||||
|
||||
.tab {
|
||||
float: left;
|
||||
.tabs {
|
||||
margin-left: 1rem;
|
||||
font-size: 20px;
|
||||
letter-spacing: -0.5px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.activeTab {
|
||||
font-weight: bold;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.error {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,14 @@ import React, { PropTypes } from 'react';
|
|||
import { compose } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
import { FormattedMessage, injectIntl, intlShape } from 'react-intl';
|
||||
import { Avatar, NamedLink, NamedRedirect, PageLayout, PaginationLinks } from '../../components';
|
||||
import {
|
||||
Avatar,
|
||||
NamedLink,
|
||||
NamedRedirect,
|
||||
PageLayout,
|
||||
PaginationLinks,
|
||||
TabNav,
|
||||
} from '../../components';
|
||||
import * as propTypes from '../../util/propTypes';
|
||||
import { getMarketplaceEntities } from '../../ducks/marketplaceData.duck';
|
||||
import { loadData } from './InboxPage.duck';
|
||||
|
|
@ -86,8 +93,6 @@ export const InboxPageComponent = props => {
|
|||
fetchOrdersOrSalesError,
|
||||
pagination,
|
||||
transactions,
|
||||
currentUserHasListings,
|
||||
currentUserHasListingsError,
|
||||
intl,
|
||||
params,
|
||||
} = props;
|
||||
|
|
@ -112,7 +117,7 @@ export const InboxPageComponent = props => {
|
|||
);
|
||||
};
|
||||
|
||||
const error = fetchOrdersOrSalesError || currentUserHasListingsError
|
||||
const error = fetchOrdersOrSalesError
|
||||
? <p className={css.error}>
|
||||
<FormattedMessage id="InboxPage.fetchFailed" />
|
||||
</p>
|
||||
|
|
@ -133,31 +138,36 @@ export const InboxPageComponent = props => {
|
|||
/>
|
||||
: null;
|
||||
|
||||
const tabs = [
|
||||
{
|
||||
text: intl.formatMessage({
|
||||
id: 'InboxPage.ordersTabTitle',
|
||||
}),
|
||||
selected: isOrders,
|
||||
linkProps: {
|
||||
name: 'InboxPage',
|
||||
params: { tab: 'orders' },
|
||||
},
|
||||
},
|
||||
{
|
||||
text: intl.formatMessage({
|
||||
id: 'InboxPage.salesTabTitle',
|
||||
}),
|
||||
selected: !isOrders,
|
||||
linkProps: {
|
||||
name: 'InboxPage',
|
||||
params: { tab: 'sales' },
|
||||
},
|
||||
},
|
||||
];
|
||||
const nav = <TabNav className={css.tabs} tabs={tabs} />;
|
||||
|
||||
return (
|
||||
<PageLayout title={title}>
|
||||
<h1 className={css.title}>
|
||||
<FormattedMessage id="InboxPage.title" />
|
||||
</h1>
|
||||
{currentUserHasListings
|
||||
? <nav>
|
||||
<NamedLink
|
||||
className={css.tab}
|
||||
name="InboxPage"
|
||||
params={{ tab: 'orders' }}
|
||||
activeClassName={isOrders ? css.activeTab : null}
|
||||
>
|
||||
<FormattedMessage id="InboxPage.ordersTabTitle" />
|
||||
</NamedLink>
|
||||
<NamedLink
|
||||
className={css.tab}
|
||||
name="InboxPage"
|
||||
params={{ tab: 'sales' }}
|
||||
activeClassName={!isOrders ? css.activeTab : null}
|
||||
>
|
||||
<FormattedMessage id="InboxPage.salesTabTitle" />
|
||||
</NamedLink>
|
||||
</nav>
|
||||
: null}
|
||||
{nav}
|
||||
{error}
|
||||
<ul>
|
||||
{!fetchInProgress ? transactions.map(toTxItem) : null}
|
||||
|
|
@ -171,8 +181,6 @@ export const InboxPageComponent = props => {
|
|||
InboxPageComponent.defaultProps = {
|
||||
fetchOrdersOrSalesError: null,
|
||||
pagination: null,
|
||||
currentUserHasListings: false,
|
||||
currentUserHasListingsError: null,
|
||||
};
|
||||
|
||||
InboxPageComponent.propTypes = {
|
||||
|
|
@ -184,8 +192,6 @@ InboxPageComponent.propTypes = {
|
|||
fetchOrdersOrSalesError: instanceOf(Error),
|
||||
pagination: propTypes.pagination,
|
||||
transactions: arrayOf(propTypes.transaction).isRequired,
|
||||
currentUserHasListings: bool,
|
||||
currentUserHasListingsError: instanceOf(Error),
|
||||
|
||||
// from injectIntl
|
||||
intl: intlShape.isRequired,
|
||||
|
|
@ -197,16 +203,12 @@ const mapStateToProps = state => {
|
|||
fetchOrdersOrSalesError,
|
||||
pagination,
|
||||
transactionRefs,
|
||||
currentUserHasListings,
|
||||
currentUserHasListingsError,
|
||||
} = state.InboxPage;
|
||||
return {
|
||||
fetchInProgress,
|
||||
fetchOrdersOrSalesError,
|
||||
pagination,
|
||||
transactions: getMarketplaceEntities(state, transactionRefs),
|
||||
currentUserHasListings,
|
||||
currentUserHasListingsError,
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -6,31 +6,32 @@ exports[`InboxPage matches snapshot 1`] = `
|
|||
id="InboxPage.title"
|
||||
values={Object {}} />
|
||||
</h1>
|
||||
<nav>
|
||||
<withFlattenedRoutes(withRouter(NamedLink))
|
||||
name="InboxPage"
|
||||
params={
|
||||
<TabNav
|
||||
className=""
|
||||
tabs={
|
||||
Array [
|
||||
Object {
|
||||
"tab": "orders",
|
||||
}
|
||||
}>
|
||||
<FormattedMessage
|
||||
id="InboxPage.ordersTabTitle"
|
||||
values={Object {}} />
|
||||
</withFlattenedRoutes(withRouter(NamedLink))>
|
||||
<withFlattenedRoutes(withRouter(NamedLink))
|
||||
activeClassName={null}
|
||||
name="InboxPage"
|
||||
params={
|
||||
"linkProps": Object {
|
||||
"name": "InboxPage",
|
||||
"params": Object {
|
||||
"tab": "orders",
|
||||
},
|
||||
},
|
||||
"selected": true,
|
||||
"text": "InboxPage.ordersTabTitle",
|
||||
},
|
||||
Object {
|
||||
"tab": "sales",
|
||||
}
|
||||
}>
|
||||
<FormattedMessage
|
||||
id="InboxPage.salesTabTitle"
|
||||
values={Object {}} />
|
||||
</withFlattenedRoutes(withRouter(NamedLink))>
|
||||
</nav>
|
||||
"linkProps": Object {
|
||||
"name": "InboxPage",
|
||||
"params": Object {
|
||||
"tab": "sales",
|
||||
},
|
||||
},
|
||||
"selected": false,
|
||||
"text": "InboxPage.salesTabTitle",
|
||||
},
|
||||
]
|
||||
} />
|
||||
<ul>
|
||||
<li>
|
||||
<Component
|
||||
|
|
@ -182,31 +183,32 @@ exports[`InboxPage matches snapshot 3`] = `
|
|||
id="InboxPage.title"
|
||||
values={Object {}} />
|
||||
</h1>
|
||||
<nav>
|
||||
<withFlattenedRoutes(withRouter(NamedLink))
|
||||
activeClassName={null}
|
||||
name="InboxPage"
|
||||
params={
|
||||
<TabNav
|
||||
className=""
|
||||
tabs={
|
||||
Array [
|
||||
Object {
|
||||
"tab": "orders",
|
||||
}
|
||||
}>
|
||||
<FormattedMessage
|
||||
id="InboxPage.ordersTabTitle"
|
||||
values={Object {}} />
|
||||
</withFlattenedRoutes(withRouter(NamedLink))>
|
||||
<withFlattenedRoutes(withRouter(NamedLink))
|
||||
name="InboxPage"
|
||||
params={
|
||||
"linkProps": Object {
|
||||
"name": "InboxPage",
|
||||
"params": Object {
|
||||
"tab": "orders",
|
||||
},
|
||||
},
|
||||
"selected": false,
|
||||
"text": "InboxPage.ordersTabTitle",
|
||||
},
|
||||
Object {
|
||||
"tab": "sales",
|
||||
}
|
||||
}>
|
||||
<FormattedMessage
|
||||
id="InboxPage.salesTabTitle"
|
||||
values={Object {}} />
|
||||
</withFlattenedRoutes(withRouter(NamedLink))>
|
||||
</nav>
|
||||
"linkProps": Object {
|
||||
"name": "InboxPage",
|
||||
"params": Object {
|
||||
"tab": "sales",
|
||||
},
|
||||
},
|
||||
"selected": true,
|
||||
"text": "InboxPage.salesTabTitle",
|
||||
},
|
||||
]
|
||||
} />
|
||||
<ul>
|
||||
<li>
|
||||
<Component
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import * as LocationAutocompleteInput
|
|||
import * as PaginationLinks from './components/PaginationLinks/PaginationLinks.example';
|
||||
import * as StripeBankAccountToken
|
||||
from './components/StripeBankAccountToken/StripeBankAccountToken.example';
|
||||
import * as TabNav from './components/TabNav/TabNav.example';
|
||||
|
||||
// containers
|
||||
import * as BookingDatesForm from './containers/BookingDatesForm/BookingDatesForm.example';
|
||||
|
|
@ -36,7 +37,6 @@ export {
|
|||
CurrencyInput,
|
||||
DateInput,
|
||||
EditListingForm,
|
||||
SearchForm,
|
||||
ListingCard,
|
||||
LocationAutocompleteInput,
|
||||
LoginForm,
|
||||
|
|
@ -46,7 +46,9 @@ export {
|
|||
NamedLink,
|
||||
PaginationLinks,
|
||||
PasswordForgottenForm,
|
||||
SearchForm,
|
||||
SignupForm,
|
||||
StripeBankAccountToken,
|
||||
StripePaymentForm,
|
||||
TabNav,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -45,12 +45,12 @@
|
|||
"HeroSection.subTitle": "The largest online community to rent music studios",
|
||||
"HeroSection.title": "Book Studiotime anywhere",
|
||||
"InboxPage.fetchFailed": "Could not load all messages. Please try again.",
|
||||
"InboxPage.noOrdersFound": "No orders found.",
|
||||
"InboxPage.noSalesFound": "No sales found.",
|
||||
"InboxPage.ordersTabTitle": "Guest",
|
||||
"InboxPage.ordersTitle": "Inbox: Orders",
|
||||
"InboxPage.salesTabTitle": "Host",
|
||||
"InboxPage.salesTitle": "Inbox: Sales",
|
||||
"InboxPage.noOrdersFound": "You haven't made any bookings.",
|
||||
"InboxPage.noSalesFound": "Nobody has booked anything from you yet.",
|
||||
"InboxPage.ordersTabTitle": "Bathing",
|
||||
"InboxPage.ordersTitle": "Inbox: Bathing",
|
||||
"InboxPage.salesTabTitle": "Hosting",
|
||||
"InboxPage.salesTitle": "Inbox: Hosting",
|
||||
"InboxPage.stateAccepted": "Accepted",
|
||||
"InboxPage.statePending": "Pending",
|
||||
"InboxPage.stateRejected": "Rejected",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue