mirror of
https://github.com/kingomarnajjar/flex-template-web.git
synced 2026-07-28 20:53:24 +10:00
Merge pull request #408 from sharetribe/handle-deleted-listing
Handle deleted listing
This commit is contained in:
commit
18e2d79109
10 changed files with 133 additions and 72 deletions
|
|
@ -39,7 +39,7 @@ describe('Application', () => {
|
|||
'/s/listings': 'Search page: listings',
|
||||
'/s/filters': 'Search page: filters',
|
||||
'/s/map': 'Search page: map',
|
||||
'/l/listing-title-slug/1234': 'Loading listing data',
|
||||
'/l/listing-title-slug/1234': 'Loading listing…',
|
||||
'/u/1234': 'Profile page with display name: 1234',
|
||||
'/login': 'Login',
|
||||
'/signup': 'Sign up',
|
||||
|
|
|
|||
|
|
@ -8,6 +8,15 @@
|
|||
}
|
||||
}
|
||||
|
||||
.loadingText {
|
||||
margin: 24px;
|
||||
}
|
||||
|
||||
.errorText {
|
||||
color: var(--failColor);
|
||||
margin: 24px;
|
||||
}
|
||||
|
||||
.threeToTwoWrapper {
|
||||
/* Layout */
|
||||
display: block;
|
||||
|
|
|
|||
|
|
@ -52,6 +52,5 @@ export const showListing = listingId =>
|
|||
})
|
||||
.catch(e => {
|
||||
dispatch(showListingError(e));
|
||||
throw e;
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import {
|
|||
ResponsiveImage,
|
||||
Topbar,
|
||||
NamedLink,
|
||||
NamedRedirect,
|
||||
Modal,
|
||||
ImageCarousel,
|
||||
} from '../../components';
|
||||
|
|
@ -175,12 +176,57 @@ export class ListingPageComponent extends Component {
|
|||
title = '',
|
||||
} = currentListing.attributes;
|
||||
|
||||
if (!currentListing.id && showListingError) {
|
||||
const noDataMsg = { id: 'ListingPage.noListingData' };
|
||||
return <PageLayout title={intl.formatMessage(noDataMsg)} />;
|
||||
const topbar = (
|
||||
<Topbar
|
||||
isAuthenticated={isAuthenticated}
|
||||
authInProgress={authInProgress}
|
||||
currentUser={currentUser}
|
||||
currentUserHasListings={currentUserHasListings}
|
||||
currentUserHasOrders={currentUserHasOrders}
|
||||
notificationCount={notificationCount}
|
||||
history={history}
|
||||
location={location}
|
||||
onLogout={onLogout}
|
||||
onManageDisableScrolling={onManageDisableScrolling}
|
||||
onResendVerificationEmail={onResendVerificationEmail}
|
||||
sendVerificationEmailInProgress={sendVerificationEmailInProgress}
|
||||
sendVerificationEmailError={sendVerificationEmailError}
|
||||
/>
|
||||
);
|
||||
|
||||
const loadingTitle = intl.formatMessage({
|
||||
id: 'ListingPage.loadingListingTitle',
|
||||
});
|
||||
const errorTitle = intl.formatMessage({
|
||||
id: 'ListingPage.errorLoadingListingTitle',
|
||||
});
|
||||
|
||||
if (showListingError && showListingError.status === 404) {
|
||||
// 404 listing not found
|
||||
|
||||
return <NamedRedirect name="NotFoundPage" />;
|
||||
} else if (showListingError) {
|
||||
// Other error in fetching listing
|
||||
|
||||
return (
|
||||
<PageLayout title={errorTitle}>
|
||||
{topbar}
|
||||
<p className={css.errorText}>
|
||||
<FormattedMessage id="ListingPage.errorLoadingListingMessage" />
|
||||
</p>
|
||||
</PageLayout>
|
||||
);
|
||||
} else if (!currentListing.id) {
|
||||
const loadingPageMsg = { id: 'ListingPage.loadingListingData' };
|
||||
return <PageLayout title={intl.formatMessage(loadingPageMsg)} />;
|
||||
// Still loading the listing
|
||||
|
||||
return (
|
||||
<PageLayout title={loadingTitle}>
|
||||
{topbar}
|
||||
<p className={css.loadingText}>
|
||||
<FormattedMessage id="ListingPage.loadingListingMessage" />
|
||||
</p>
|
||||
</PageLayout>
|
||||
);
|
||||
}
|
||||
|
||||
const hasImages = currentListing.images && currentListing.images.length > 0;
|
||||
|
|
@ -291,21 +337,7 @@ export class ListingPageComponent extends Component {
|
|||
title={`${title} ${formattedPrice}`}
|
||||
scrollingDisabled={scrollingDisabled}
|
||||
>
|
||||
<Topbar
|
||||
isAuthenticated={isAuthenticated}
|
||||
authInProgress={authInProgress}
|
||||
currentUser={currentUser}
|
||||
currentUserHasListings={currentUserHasListings}
|
||||
currentUserHasOrders={currentUserHasOrders}
|
||||
notificationCount={notificationCount}
|
||||
history={history}
|
||||
location={location}
|
||||
onLogout={onLogout}
|
||||
onManageDisableScrolling={onManageDisableScrolling}
|
||||
onResendVerificationEmail={onResendVerificationEmail}
|
||||
sendVerificationEmailInProgress={sendVerificationEmailInProgress}
|
||||
sendVerificationEmailError={sendVerificationEmailError}
|
||||
/>
|
||||
{topbar}
|
||||
<div className={listingClasses}>
|
||||
<div className={css.threeToTwoWrapper}>
|
||||
<div className={css.aspectWrapper} onClick={handleViewPhotosClick}>
|
||||
|
|
|
|||
|
|
@ -72,22 +72,16 @@ describe('ListingPage', () => {
|
|||
|
||||
// Calling sdk.listings.show is expected to fail now
|
||||
|
||||
return showListing(id)(dispatch, null, sdk).then(
|
||||
() => {
|
||||
throw new Error('sdk.listings.show was supposed to fail!');
|
||||
},
|
||||
e => {
|
||||
expect(e).toEqual(error);
|
||||
expect(show.mock.calls).toEqual([
|
||||
[{ id, include: ['author', 'author.profileImage', 'images'] }],
|
||||
]);
|
||||
expect(dispatch.mock.calls).toEqual([
|
||||
[showListingRequest(id)],
|
||||
[expect.anything()], // fetchCurrentUser() call
|
||||
[showListingError(e)],
|
||||
]);
|
||||
}
|
||||
);
|
||||
return showListing(id)(dispatch, null, sdk).then(data => {
|
||||
expect(show.mock.calls).toEqual([
|
||||
[{ id, include: ['author', 'author.profileImage', 'images'] }],
|
||||
]);
|
||||
expect(dispatch.mock.calls).toEqual([
|
||||
[showListingRequest(id)],
|
||||
[expect.anything()], // fetchCurrentUser() call
|
||||
[showListingError(error)],
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
3
src/containers/NotFoundPage/NotFoundPage.css
Normal file
3
src/containers/NotFoundPage/NotFoundPage.css
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
.root {
|
||||
padding: 0 24px;
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
import React, { Component, PropTypes } from 'react';
|
||||
import { injectIntl, intlShape, FormattedMessage } from 'react-intl';
|
||||
import { compose } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
import { withRouter } from 'react-router-dom';
|
||||
|
|
@ -6,7 +7,9 @@ import * as propTypes from '../../util/propTypes';
|
|||
import { sendVerificationEmail } from '../../ducks/user.duck';
|
||||
import { logout, authenticationInProgress } from '../../ducks/Auth.duck';
|
||||
import { manageDisableScrolling, isScrollingDisabled } from '../../ducks/UI.duck';
|
||||
import { NamedLink, PageLayout, Topbar } from '../../components';
|
||||
import { PageLayout, Topbar } from '../../components';
|
||||
|
||||
import css from './NotFoundPage.css';
|
||||
|
||||
export class NotFoundPageComponent extends Component {
|
||||
componentWillMount() {
|
||||
|
|
@ -34,10 +37,15 @@ export class NotFoundPageComponent extends Component {
|
|||
sendVerificationEmailInProgress,
|
||||
sendVerificationEmailError,
|
||||
onResendVerificationEmail,
|
||||
intl,
|
||||
} = this.props;
|
||||
|
||||
const title = intl.formatMessage({
|
||||
id: 'NotFoundPage.title',
|
||||
});
|
||||
|
||||
return (
|
||||
<PageLayout authInfoError={authInfoError} logoutError={logoutError} title="Page not found">
|
||||
<PageLayout authInfoError={authInfoError} logoutError={logoutError} title={title}>
|
||||
<Topbar
|
||||
authInProgress={authInProgress}
|
||||
currentUser={currentUser}
|
||||
|
|
@ -53,7 +61,11 @@ export class NotFoundPageComponent extends Component {
|
|||
sendVerificationEmailInProgress={sendVerificationEmailInProgress}
|
||||
sendVerificationEmailError={sendVerificationEmailError}
|
||||
/>
|
||||
<NamedLink name="LandingPage">Home</NamedLink>
|
||||
<div className={css.root}>
|
||||
<h1>
|
||||
<FormattedMessage id="NotFoundPage.heading" />
|
||||
</h1>
|
||||
</div>
|
||||
</PageLayout>
|
||||
);
|
||||
}
|
||||
|
|
@ -89,6 +101,9 @@ NotFoundPageComponent.propTypes = {
|
|||
// context object from StaticRouter, injected by the withRouter wrapper
|
||||
staticContext: object,
|
||||
|
||||
// from injectIntl
|
||||
intl: intlShape.isRequired,
|
||||
|
||||
// from withRouter
|
||||
history: shape({
|
||||
push: func.isRequired,
|
||||
|
|
@ -130,7 +145,7 @@ const mapDispatchToProps = dispatch => ({
|
|||
onResendVerificationEmail: () => dispatch(sendVerificationEmail()),
|
||||
});
|
||||
|
||||
const NotFoundPage = compose(connect(mapStateToProps, mapDispatchToProps), withRouter)(
|
||||
const NotFoundPage = compose(connect(mapStateToProps, mapDispatchToProps), withRouter, injectIntl)(
|
||||
NotFoundPageComponent
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import React from 'react';
|
||||
import { renderShallow } from '../../util/test-helpers';
|
||||
import { fakeIntl } from '../../util/test-data';
|
||||
import { NotFoundPageComponent } from './NotFoundPage';
|
||||
|
||||
const noop = () => null;
|
||||
|
|
@ -19,6 +20,7 @@ describe('NotFoundPageComponent', () => {
|
|||
onManageDisableScrolling={noop}
|
||||
sendVerificationEmailInProgress={false}
|
||||
onResendVerificationEmail={noop}
|
||||
intl={fakeIntl}
|
||||
/>
|
||||
);
|
||||
expect(tree).toMatchSnapshot();
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ exports[`NotFoundPageComponent matches snapshot 1`] = `
|
|||
<withRouter(PageLayout)
|
||||
authInfoError={null}
|
||||
logoutError={null}
|
||||
title="Page not found">
|
||||
title="NotFoundPage.title">
|
||||
<Topbar
|
||||
authInProgress={false}
|
||||
currentUser={null}
|
||||
|
|
@ -25,9 +25,12 @@ exports[`NotFoundPageComponent matches snapshot 1`] = `
|
|||
onResendVerificationEmail={[Function]}
|
||||
sendVerificationEmailError={null}
|
||||
sendVerificationEmailInProgress={false} />
|
||||
<withFlattenedRoutes(withRouter(NamedLink))
|
||||
name="LandingPage">
|
||||
Home
|
||||
</withFlattenedRoutes(withRouter(NamedLink))>
|
||||
<div>
|
||||
<h1>
|
||||
<FormattedMessage
|
||||
id="NotFoundPage.heading"
|
||||
values={Object {}} />
|
||||
</h1>
|
||||
</div>
|
||||
</withRouter(PageLayout)>
|
||||
`;
|
||||
|
|
|
|||
|
|
@ -157,10 +157,12 @@
|
|||
"ListingPage.ctaButtonMessage": "Request to book",
|
||||
"ListingPage.descriptionTitle": "About this sauna",
|
||||
"ListingPage.editListing": "Edit listing",
|
||||
"ListingPage.errorLoadingListingMessage": "Could not load listing. Please try again.",
|
||||
"ListingPage.errorLoadingListingTitle": "Error in loading listing",
|
||||
"ListingPage.hostedBy": "Hosted by {name}",
|
||||
"ListingPage.loadingListingData": "Loading listing data",
|
||||
"ListingPage.loadingListingMessage": "Loading listing…",
|
||||
"ListingPage.loadingListingTitle": "Loading listing…",
|
||||
"ListingPage.locationTitle": "Location",
|
||||
"ListingPage.noListingData": "Could not find listing data",
|
||||
"ListingPage.ownClosedListing": "Your listing has been closed and can't be booked.",
|
||||
"ListingPage.ownListing": "This is your own listing.",
|
||||
"ListingPage.perNight": "per night",
|
||||
|
|
@ -169,8 +171,8 @@
|
|||
"LoginForm.emailPlaceholder": "john.doe@example.com",
|
||||
"LoginForm.emailRequired": "This field is required",
|
||||
"LoginForm.forgotPassword": "Forgot your password?",
|
||||
"LoginForm.logIn": "Log in",
|
||||
"LoginForm.forgotPasswordHelp": "No problem.",
|
||||
"LoginForm.logIn": "Log in",
|
||||
"LoginForm.passwordLabel": "Password",
|
||||
"LoginForm.passwordPlaceholder": "Enter your password…",
|
||||
"LoginForm.passwordRequired": "This field is required",
|
||||
|
|
@ -193,6 +195,8 @@
|
|||
"MapPriceMarker.unsupportedPrice": "({currency})",
|
||||
"Modal.close": "CLOSE",
|
||||
"Modal.closeModal": "Close modal",
|
||||
"NotFoundPage.heading": "Oops, could not find the page you were looking for.",
|
||||
"NotFoundPage.title": "Page not found",
|
||||
"OrderDetailsPanel.bannedUserDisplayName": "Banned user",
|
||||
"OrderDetailsPanel.bookingBreakdownTitle": "Booking breakdown",
|
||||
"OrderDetailsPanel.deletedListingOrderTitle": "a listing",
|
||||
|
|
@ -219,6 +223,28 @@
|
|||
"PaginationLinks.next": "Next page",
|
||||
"PaginationLinks.previous": "Previous page",
|
||||
"PaginationLinks.toPage": "Go to page {page}",
|
||||
"PasswordRecoveryForm.emailLabel": "Email",
|
||||
"PasswordRecoveryForm.emailNotFound": "Hmm. We didn't find an account with that email. Please double-check your email and try again.",
|
||||
"PasswordRecoveryForm.emailPlaceholder": "john.doe@example.com",
|
||||
"PasswordRecoveryForm.emailRequired": "This field is required",
|
||||
"PasswordRecoveryForm.loginLinkInfo": "Suddenly remembered your password? {loginLink}",
|
||||
"PasswordRecoveryForm.loginLinkText": "Go log in.",
|
||||
"PasswordRecoveryForm.sendInstructions": "Send instructions",
|
||||
"PasswordRecoveryPage.actionFailedMessage": "Something went wrong. Please refresh the page and try again.",
|
||||
"PasswordRecoveryPage.actionFailedTitle": "Whoops!",
|
||||
"PasswordRecoveryPage.emailNotVerifiedContactAdmin": "To resolve the issue, please contact Saunatime administrators.",
|
||||
"PasswordRecoveryPage.emailNotVerifiedMessage": "Unfortunately, we cannot recover your password, because your email {initialEmailText} hasn't been verified.",
|
||||
"PasswordRecoveryPage.emailNotVerifiedTitle": "We have bad news",
|
||||
"PasswordRecoveryPage.emailSubmittedMessage": "We have sent the instructions for resetting your password to {submittedEmailText}.",
|
||||
"PasswordRecoveryPage.emailSubmittedTitle": "Check your inbox",
|
||||
"PasswordRecoveryPage.fixEmailInfo": "Whoops, typo in your email? {fixEmailLink}",
|
||||
"PasswordRecoveryPage.fixEmailLinkText": "Fix it.",
|
||||
"PasswordRecoveryPage.forgotPasswordMessage": "No worries! Please enter the email address you used when signing up and we'll send you instructions on how to set a new password.",
|
||||
"PasswordRecoveryPage.forgotPasswordTitle": "Forgot your password?",
|
||||
"PasswordRecoveryPage.resendEmailInfo": "Didn't get the email? {resendEmailLink}",
|
||||
"PasswordRecoveryPage.resendEmailLinkText": "Send another email.",
|
||||
"PasswordRecoveryPage.resendingEmailInfo": "Resending instructions...",
|
||||
"PasswordRecoveryPage.title": "Request a new password",
|
||||
"PasswordResetForm.passwordLabel": "Your new password",
|
||||
"PasswordResetForm.passwordPlaceholder": "Enter your new password...",
|
||||
"PasswordResetForm.passwordRequired": "This field is required",
|
||||
|
|
@ -231,28 +257,6 @@
|
|||
"PasswordResetPage.passwordChangedHelpText": "Your password has been changed successfully.",
|
||||
"PasswordResetPage.resetFailed": "Reset failed. Please try again.",
|
||||
"PasswordResetPage.title": "Reset password",
|
||||
"PasswordRecoveryForm.emailLabel": "Email",
|
||||
"PasswordRecoveryForm.emailNotFound": "Hmm. We didn't find an account with that email. Please double-check your email and try again.",
|
||||
"PasswordRecoveryForm.emailPlaceholder": "john.doe@example.com",
|
||||
"PasswordRecoveryForm.emailRequired": "This field is required",
|
||||
"PasswordRecoveryForm.loginLinkText": "Go log in.",
|
||||
"PasswordRecoveryForm.loginLinkInfo": "Suddenly remembered your password? {loginLink}",
|
||||
"PasswordRecoveryForm.sendInstructions": "Send instructions",
|
||||
"PasswordRecoveryPage.actionFailedTitle": "Whoops!",
|
||||
"PasswordRecoveryPage.actionFailedMessage": "Something went wrong. Please refresh the page and try again.",
|
||||
"PasswordRecoveryPage.emailNotVerifiedTitle": "We have bad news",
|
||||
"PasswordRecoveryPage.emailNotVerifiedMessage": "Unfortunately, we cannot recover your password, because your email {initialEmailText} hasn't been verified.",
|
||||
"PasswordRecoveryPage.emailNotVerifiedContactAdmin": "To resolve the issue, please contact Saunatime administrators.",
|
||||
"PasswordRecoveryPage.emailSubmittedTitle": "Check your inbox",
|
||||
"PasswordRecoveryPage.emailSubmittedMessage": "We have sent the instructions for resetting your password to {submittedEmailText}.",
|
||||
"PasswordRecoveryPage.fixEmailLinkText": "Fix it.",
|
||||
"PasswordRecoveryPage.fixEmailInfo": "Whoops, typo in your email? {fixEmailLink}",
|
||||
"PasswordRecoveryPage.forgotPasswordTitle": "Forgot your password?",
|
||||
"PasswordRecoveryPage.forgotPasswordMessage": "No worries! Please enter the email address you used when signing up and we'll send you instructions on how to set a new password.",
|
||||
"PasswordRecoveryPage.resendEmailLinkText": "Send another email.",
|
||||
"PasswordRecoveryPage.resendEmailInfo": "Didn't get the email? {resendEmailLink}",
|
||||
"PasswordRecoveryPage.resendingEmailInfo": "Resending instructions...",
|
||||
"PasswordRecoveryPage.title": "Request a new password",
|
||||
"PayoutDetailsForm.addressTitle": "Address",
|
||||
"PayoutDetailsForm.bankDetails": "Bank details",
|
||||
"PayoutDetailsForm.birthdayDatePlaceholder": "dd",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue