diff --git a/src/containers/ListingPage/ListingPage.js b/src/containers/ListingPage/ListingPage.js index cb9dd6e5..bb0d0370 100644 --- a/src/containers/ListingPage/ListingPage.js +++ b/src/containers/ListingPage/ListingPage.js @@ -97,14 +97,44 @@ ActionBar.propTypes = { ActionBar.displayName = 'ActionBar'; +const gotoBookTab = (history, listing) => { + if (!listing.id) { + // Listing not fully loaded yet + return; + } + const routes = routeConfiguration(); + history.push( + createResourceLocatorString( + 'ListingPageBook', + routes, + { id: listing.id.uuid, slug: createSlug(listing.attributes.title) }, + {} + ) + ); +}; + +const gotoListingTab = (history, listing) => { + if (!listing.id) { + // Listing not fully loaded yet + return; + } + const routes = routeConfiguration(); + history.push( + createResourceLocatorString( + 'ListingPage', + routes, + { id: listing.id.uuid, slug: createSlug(listing.attributes.title) }, + {} + ) + ); +}; + // TODO: price unit (per x), custom fields, contact, reviews // N.B. All the presentational content needs to be extracted to their own components export class ListingPageComponent extends Component { constructor(props) { super(props); - const tab = props.tab; this.state = { - isBookingModalOpenOnMobile: tab && tab === 'book', pageClassNames: [], imageCarouselOpen: false, }; @@ -117,8 +147,6 @@ export class ListingPageComponent extends Component { const listingId = new UUID(params.id); const listing = getListing(listingId); - this.setState({ isBookingModalOpenOnMobile: false }); - const { bookingDates } = values; const initialValues = { @@ -147,6 +175,7 @@ export class ListingPageComponent extends Component { render() { const { + tab, currentUser, getListing, intl, @@ -155,6 +184,7 @@ export class ListingPageComponent extends Component { params, scrollingDisabled, showListingError, + history, } = this.props; const listingId = new UUID(params.id); const currentListing = ensureListing(getListing(listingId)); @@ -281,6 +311,10 @@ export class ListingPageComponent extends Component { ); + const handleMobileBookModalClose = () => { + gotoListingTab(history, currentListing); + }; + const handleBookingSubmit = values => { const isClosed = currentListing.attributes.closed; if (isOwnListing || isClosed) { @@ -297,7 +331,7 @@ export class ListingPageComponent extends Component { if (isOwnListing || isClosed) { window.scrollTo(0, 0); } else { - this.setState({ isBookingModalOpenOnMobile: true }); + gotoBookTab(history, currentListing); } }; @@ -425,8 +459,8 @@ export class ListingPageComponent extends Component { className={css.modalInMobile} containerClassName={css.modalContainer} id="BookingDatesFormInModal" - isModalOpenOnMobile={this.state.isBookingModalOpenOnMobile} - onClose={() => this.setState({ isBookingModalOpenOnMobile: false })} + isModalOpenOnMobile={tab === 'book'} + onClose={handleMobileBookModalClose} showAsModalMaxWidth={MODAL_BREAKPOINT} onManageDisableScrolling={onManageDisableScrolling} > diff --git a/src/routeConfiguration.js b/src/routeConfiguration.js index 6480c90a..61ef3a40 100644 --- a/src/routeConfiguration.js +++ b/src/routeConfiguration.js @@ -87,7 +87,7 @@ const routeConfiguration = () => { }, { path: '/l/:slug/:id/book', - name: 'ListingPage', + name: 'ListingPageBook', component: props => , loadData: ListingPage.loadData, }, diff --git a/src/util/routes.js b/src/util/routes.js index 599a4c96..aa805672 100644 --- a/src/util/routes.js +++ b/src/util/routes.js @@ -103,16 +103,28 @@ export const canonicalRoutePath = (routes, location) => { const matches = matchPathname(pathname, routes); const isListingRoute = matches.length === 1 && matches[0].route.name === 'ListingPage'; + const isListingBookRoute = matches.length === 1 && matches[0].route.name === 'ListingPageBook'; if (isListingRoute) { // Remove the dynamic slug from the listing page canonical URL const parts = pathname.split('/'); + if (parts.length !== 4) { - throw new Error('Expecting ListingPage pathname to have 4 parts'); + throw new Error('Expected ListingPage route to have 4 parts'); } const canonicalListingPathname = `/${parts[1]}/${parts[3]}`; return `${canonicalListingPathname}${search}${hash}`; + } else if (isListingBookRoute) { + // Remove the dynamic slug from the listing book page canonical URL + + const parts = pathname.split('/'); + + if (parts.length !== 5) { + throw new Error('Expected ListingPageBook route to have 5 parts'); + } + const canonicalListingBookPathname = `/${parts[1]}/${parts[3]}/${parts[4]}`; + return `${canonicalListingBookPathname}${search}${hash}`; } return `${pathname}${search}${hash}`; diff --git a/src/util/routes.test.js b/src/util/routes.test.js index 9c5aae90..7e8da4ab 100644 --- a/src/util/routes.test.js +++ b/src/util/routes.test.js @@ -90,6 +90,17 @@ describe('util/routes.js', () => { '/l/00000000-0000-0000-0000-000000000000' ); }); + it('handles ListingPageBook', () => { + const routes = routeConfiguration(); + const location = { + pathname: '/l/some-slug-here/00000000-0000-0000-0000-000000000000/book', + search: '', + hash: '', + }; + expect(canonicalRoutePath(routes, location)).toEqual( + '/l/00000000-0000-0000-0000-000000000000/book' + ); + }); it('handles ListingBasePage', () => { const routes = routeConfiguration(); const location = {