mirror of
https://github.com/kingomarnajjar/flex-template-web.git
synced 2026-07-28 12:43:11 +10:00
commit
e4d5051ffa
4 changed files with 76 additions and 55 deletions
|
|
@ -3,6 +3,7 @@ import { connect } from 'react-redux';
|
|||
import { Switch, Route } from 'react-router-dom';
|
||||
import { NotFoundPage } from './containers';
|
||||
import { NamedRedirect } from './components';
|
||||
import * as propTypes from './util/propTypes';
|
||||
|
||||
const Routes = props => {
|
||||
const { isAuthenticated, routes } = props;
|
||||
|
|
@ -33,20 +34,11 @@ const Routes = props => {
|
|||
);
|
||||
};
|
||||
|
||||
const { bool, arrayOf, shape, string, func } = PropTypes;
|
||||
const { bool, arrayOf } = PropTypes;
|
||||
|
||||
Routes.propTypes = {
|
||||
isAuthenticated: bool.isRequired,
|
||||
routes: arrayOf(
|
||||
shape({
|
||||
name: string.isRequired,
|
||||
pattern: string.isRequired,
|
||||
exactly: bool,
|
||||
strict: bool,
|
||||
component: func.isRequired,
|
||||
loadData: func,
|
||||
}),
|
||||
).isRequired,
|
||||
routes: arrayOf(propTypes.route).isRequired,
|
||||
};
|
||||
|
||||
const mapStateToProps = state => ({ isAuthenticated: state.Auth.isAuthenticated });
|
||||
|
|
|
|||
|
|
@ -10,32 +10,25 @@ const createSubmitHandler = onLocationChanged => formData => {
|
|||
};
|
||||
|
||||
export const LandingPageComponent = props => {
|
||||
const handleSubmit = createSubmitHandler(props.onLocationChanged);
|
||||
const componentOrRedirect = props.LocationFilter && props.LocationFilter.length > 0
|
||||
? <NamedRedirect name="SearchPage" query={{ location: props.LocationFilter }} />
|
||||
const { onLocationChanged, filter } = props;
|
||||
const handleSubmit = createSubmitHandler(onLocationChanged);
|
||||
|
||||
return filter.length > 0
|
||||
? <NamedRedirect name="SearchPage" search={`location=${filter}`} />
|
||||
: <PageLayout title="Landing page">
|
||||
<HeroSection>
|
||||
<HeroSearchForm className={css.form} onSubmit={handleSubmit} />
|
||||
</HeroSection>
|
||||
</PageLayout>;
|
||||
|
||||
return componentOrRedirect;
|
||||
};
|
||||
|
||||
const { func, string } = PropTypes;
|
||||
|
||||
LandingPageComponent.defaultProps = { LocationFilter: '' };
|
||||
LandingPageComponent.defaultProps = { filter: '' };
|
||||
|
||||
LandingPageComponent.propTypes = { onLocationChanged: func.isRequired, LocationFilter: string };
|
||||
LandingPageComponent.propTypes = { onLocationChanged: func.isRequired, filter: string };
|
||||
|
||||
/**
|
||||
* Container functions.
|
||||
* Since we add this to global store state with combineReducers, this will only get partial state
|
||||
* which is page specific.
|
||||
*/
|
||||
const mapStateToProps = function mapStateToProps(state) {
|
||||
return state;
|
||||
};
|
||||
const mapStateToProps = state => ({ filter: state.LocationFilter });
|
||||
|
||||
const mapDispatchToProps = function mapDispatchToProps(dispatch) {
|
||||
return { onLocationChanged: v => dispatch(changeLocationFilter(v)) };
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import React, { Component, PropTypes } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { connect } from 'react-redux';
|
||||
import { includes } from 'lodash';
|
||||
import { addFlashNotification } from '../../ducks/FlashNotification.ducks';
|
||||
import { addFilter, callFetchListings, loadListings } from './SearchPage.ducks';
|
||||
import css from './SearchPage.css';
|
||||
|
|
@ -17,21 +16,18 @@ import {
|
|||
export class SearchPageComponent extends Component {
|
||||
componentDidMount() {
|
||||
// TODO: This should be moved to Router
|
||||
const { SearchPage } = this.props;
|
||||
if (!SearchPage.initialListingsLoaded) {
|
||||
const { initialListingsLoaded } = this.props;
|
||||
if (!initialListingsLoaded) {
|
||||
this.props.onLoadListings();
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { tab, SearchPage } = this.props;
|
||||
const { listings } = SearchPage;
|
||||
const fakeListings = listings || [];
|
||||
const selectedTab = includes(['filters', 'listings', 'map'], tab) ? tab : 'listings';
|
||||
const { tab, listings } = this.props;
|
||||
|
||||
const filtersClassName = classNames(css.filters, { [css.open]: selectedTab === 'filters' });
|
||||
const listingsClassName = classNames(css.listings, { [css.open]: selectedTab === 'listings' });
|
||||
const mapClassName = classNames(css.map, { [css.open]: selectedTab === 'map' });
|
||||
const filtersClassName = classNames(css.filters, { [css.open]: tab === 'filters' });
|
||||
const listingsClassName = classNames(css.listings, { [css.open]: tab === 'listings' });
|
||||
const mapClassName = classNames(css.map, { [css.open]: tab === 'map' });
|
||||
|
||||
return (
|
||||
<PageLayout title="Search page">
|
||||
|
|
@ -41,12 +37,12 @@ export class SearchPageComponent extends Component {
|
|||
</div>
|
||||
<div className={listingsClassName}>
|
||||
<SearchResultsPanel>
|
||||
{fakeListings.map(l => <ListingCard key={l.id} {...l} />)}
|
||||
{listings.map(l => <ListingCard key={l.id} {...l} />)}
|
||||
</SearchResultsPanel>
|
||||
</div>
|
||||
<div className={mapClassName}>
|
||||
<MapPanel>
|
||||
{fakeListings.map(l => <ListingCardSmall key={l.id} {...l} />)}
|
||||
{listings.map(l => <ListingCardSmall key={l.id} {...l} />)}
|
||||
</MapPanel>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -57,29 +53,21 @@ export class SearchPageComponent extends Component {
|
|||
|
||||
SearchPageComponent.loadData = callFetchListings;
|
||||
|
||||
SearchPageComponent.defaultProps = { SearchPage: {}, tab: 'listings' };
|
||||
SearchPageComponent.defaultProps = { initialListingsLoaded: false, listings: [], tab: 'listings' };
|
||||
|
||||
const { array, bool, func, shape, string } = PropTypes;
|
||||
const { array, bool, func, oneOf } = PropTypes;
|
||||
|
||||
SearchPageComponent.propTypes = {
|
||||
onLoadListings: func.isRequired,
|
||||
SearchPage: shape({
|
||||
filters: array,
|
||||
initialListingsLoaded: bool,
|
||||
listings: array,
|
||||
loadingListings: bool,
|
||||
}),
|
||||
tab: string,
|
||||
initialListingsLoaded: bool,
|
||||
listings: array,
|
||||
tab: oneOf(['filters', 'listings', 'map']).isRequired,
|
||||
};
|
||||
|
||||
/**
|
||||
* Container functions.
|
||||
* Since we add this to global store state with combineReducers, this will only get partial state
|
||||
* which is page specific.
|
||||
*/
|
||||
const mapStateToProps = function mapStateToProps(state) {
|
||||
return state;
|
||||
};
|
||||
const mapStateToProps = state => ({
|
||||
initialListingsLoaded: state.SearchPage.initialListingsLoaded,
|
||||
listings: state.SearchPage.listings,
|
||||
});
|
||||
|
||||
const mapDispatchToProps = function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
|
|
|
|||
48
src/util/propTypes.js
Normal file
48
src/util/propTypes.js
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
/**
|
||||
* This module defines custom PropTypes shared within the application.
|
||||
*
|
||||
* To learn about validating React component props with PropTypes, see:
|
||||
*
|
||||
* https://facebook.github.io/react/docs/typechecking-with-proptypes.html
|
||||
*
|
||||
* For component specific PropTypes, it's perfectly ok to inline them
|
||||
* to the component itself. If the type is shared or external (SDK or
|
||||
* API), however, it should be in this file for sharing with other
|
||||
* components.
|
||||
*
|
||||
* PropTypes should usually be validated only at the lowest level
|
||||
* where the props are used, not along the way in parents that pass
|
||||
* along the props to their children. Those parents should usually
|
||||
* just validate the presense of the prop key and that the value is
|
||||
* defined. This way we get the validation errors only in the most
|
||||
* specific place and avoid duplicate errros.
|
||||
*/
|
||||
import { PropTypes } from 'react';
|
||||
import { types as sdkTypes } from 'sharetribe-sdk';
|
||||
|
||||
const { UUID, LatLng, LatLngBounds } = sdkTypes;
|
||||
const { oneOf, string, bool, func, shape, instanceOf } = PropTypes;
|
||||
|
||||
// Fixed value
|
||||
export const value = val => oneOf([val]);
|
||||
|
||||
// SDK type instances
|
||||
export const uuid = instanceOf(UUID);
|
||||
export const latlng = instanceOf(LatLng);
|
||||
export const latlngBounds = instanceOf(LatLngBounds);
|
||||
|
||||
// Configuration for a single route
|
||||
export const route = shape({
|
||||
name: string.isRequired,
|
||||
pattern: string.isRequired,
|
||||
exactly: bool,
|
||||
strict: bool,
|
||||
component: func.isRequired,
|
||||
loadData: func,
|
||||
});
|
||||
|
||||
// User object from the API
|
||||
export const user = shape({ id: uuid.isRequired, type: value('user').isRequired });
|
||||
|
||||
// Listing object from the API
|
||||
export const listing = shape({ id: uuid.isRequired, type: value('listing').isRequired });
|
||||
Loading…
Add table
Reference in a new issue