diff --git a/package.json b/package.json index 7a732c93..c7792b18 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "redux-thunk": "^2.2.0", "sanitize.css": "^5.0.0", "sharetribe-scripts": "1.0.14", - "sharetribe-sdk": "git+ssh://git@github.com/sharetribe/sharetribe-sdk-js#9c4e102cb304bc5d8a2d70b58ef6e161945ed100", + "sharetribe-sdk": "git+ssh://git@github.com/sharetribe/sharetribe-sdk-js#ff76ef91e1e3b1e26b035a04d643d328ea3d1d61", "smoothscroll-polyfill": "^0.4.0", "source-map-support": "^0.5.0", "url": "^0.11.0" diff --git a/src/containers/ListingPage/ListingPage.duck.js b/src/containers/ListingPage/ListingPage.duck.js index e55f9322..add65e7a 100644 --- a/src/containers/ListingPage/ListingPage.duck.js +++ b/src/containers/ListingPage/ListingPage.duck.js @@ -1,5 +1,7 @@ +import { types } from '../../util/sdkLoader'; import { storableError } from '../../util/errors'; import { addMarketplaceEntities } from '../../ducks/marketplaceData.duck'; +import { updatedEntities, denormalisedEntities } from '../../util/data'; import { fetchCurrentUser } from '../../ducks/user.duck'; // ================ Action types ================ // @@ -7,11 +9,17 @@ import { fetchCurrentUser } from '../../ducks/user.duck'; export const SHOW_LISTING_REQUEST = 'app/ListingPage/SHOW_LISTING_REQUEST'; export const SHOW_LISTING_ERROR = 'app/ListingPage/SHOW_LISTING_ERROR'; +export const FETCH_REVIEWS_REQUEST = 'app/ListingPage/FETCH_REVIEWS_REQUEST'; +export const FETCH_REVIEWS_SUCCESS = 'app/ListingPage/FETCH_REVIEWS_SUCCESS'; +export const FETCH_REVIEWS_ERROR = 'app/ListingPage/FETCH_REVIEWS_ERROR'; + // ================ Reducer ================ // const initialState = { id: null, showListingError: null, + reviews: [], + fetchReviewsError: null, }; const listingPageReducer = (state = initialState, action = {}) => { @@ -21,6 +29,12 @@ const listingPageReducer = (state = initialState, action = {}) => { return { ...state, id: payload.id, showListingError: null }; case SHOW_LISTING_ERROR: return { ...state, showListingError: payload }; + case FETCH_REVIEWS_REQUEST: + return { ...state, fetchReviewsError: null }; + case FETCH_REVIEWS_SUCCESS: + return { ...state, reviews: payload }; + case FETCH_REVIEWS_ERROR: + return { ...state, fetchReviewsError: payload }; default: return state; } @@ -41,6 +55,12 @@ export const showListingError = e => ({ payload: e, }); +export const fetchReviewsRequest = () => ({ type: FETCH_REVIEWS_REQUEST }); +export const fetchReviewsSuccess = reviews => ({ type: FETCH_REVIEWS_SUCCESS, payload: reviews }); +export const fetchReviewsError = error => ({ type: FETCH_REVIEWS_ERROR, payload: error }); + +// ================ Thunks ================ // + export const showListing = listingId => (dispatch, getState, sdk) => { dispatch(showListingRequest(listingId)); dispatch(fetchCurrentUser()); @@ -54,3 +74,23 @@ export const showListing = listingId => (dispatch, getState, sdk) => { dispatch(showListingError(storableError(e))); }); }; + +export const fetchReviews = listingId => (dispatch, getState, sdk) => { + return sdk.reviews + .query({ listing_id: listingId, include: ['author', 'author.profileImage'] }) + .then(response => { + const entities = updatedEntities({}, response.data); + const reviewIds = response.data.data.map(d => d.id); + const denormalized = denormalisedEntities(entities, 'review', reviewIds); + dispatch(fetchReviewsSuccess(denormalized)); + }) + .catch(e => { + dispatch(fetchReviewsError(e)); + }); +}; + +export const loadData = params => dispatch => { + const listingId = new types.UUID(params.id); + + return Promise.all([dispatch(showListing(listingId)), dispatch(fetchReviews(listingId))]); +}; diff --git a/src/containers/ListingPage/ListingPage.js b/src/containers/ListingPage/ListingPage.js index 80d4ebf7..66fbfbff 100644 --- a/src/containers/ListingPage/ListingPage.js +++ b/src/containers/ListingPage/ListingPage.js @@ -36,7 +36,7 @@ import { } from '../../components'; import { BookingDatesForm, TopbarContainer } from '../../containers'; -import { showListing } from './ListingPage.duck'; +import { loadData } from './ListingPage.duck'; import EditIcon from './EditIcon'; import css from './ListingPage.css'; @@ -616,9 +616,6 @@ const ListingPage = compose(withRouter, connect(mapStateToProps, mapDispatchToPr ListingPageComponent ); -ListingPage.loadData = params => { - const id = new UUID(params.id); - return showListing(id); -}; +ListingPage.loadData = loadData; export default ListingPage; diff --git a/yarn.lock b/yarn.lock index 6ee8c63a..106b2e0a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7214,9 +7214,9 @@ sharetribe-scripts@1.0.14: optionalDependencies: fsevents "1.1.2" -"sharetribe-sdk@git+ssh://git@github.com/sharetribe/sharetribe-sdk-js#9c4e102cb304bc5d8a2d70b58ef6e161945ed100": +"sharetribe-sdk@git+ssh://git@github.com/sharetribe/sharetribe-sdk-js#ff76ef91e1e3b1e26b035a04d643d328ea3d1d61": version "0.0.1" - resolved "git+ssh://git@github.com/sharetribe/sharetribe-sdk-js#9c4e102cb304bc5d8a2d70b58ef6e161945ed100" + resolved "git+ssh://git@github.com/sharetribe/sharetribe-sdk-js#ff76ef91e1e3b1e26b035a04d643d328ea3d1d61" dependencies: axios "^0.15.3" js-cookie "^2.1.3"