diff --git a/src/containers/CheckoutPage/CheckoutPage.duck.js b/src/containers/CheckoutPage/CheckoutPage.duck.js index 71d57d95..64871dca 100644 --- a/src/containers/CheckoutPage/CheckoutPage.duck.js +++ b/src/containers/CheckoutPage/CheckoutPage.duck.js @@ -1,5 +1,5 @@ import { pick } from 'lodash'; -import { updatedEntities, denormalisedEntities } from '../../util/data'; +import { denormalisedResponseEntities } from '../../util/data'; import { storableError } from '../../util/errors'; import { TRANSITION_REQUEST } from '../../util/types'; import * as log from '../../util/log'; @@ -176,10 +176,11 @@ export const speculateTransaction = (listingId, bookingStart, bookingEnd) => ( return sdk.transactions .initiateSpeculative(bodyParams, queryParams) .then(response => { - const transactionId = response.data.data.id; - const entities = updatedEntities({}, response.data); - const denormalised = denormalisedEntities(entities, 'transaction', [transactionId]); - const tx = denormalised[0]; + const entities = denormalisedResponseEntities(response); + if (entities.length !== 1) { + throw new Error('Expected a resource in the sdk.transactions.initiateSpeculative response'); + } + const tx = entities[0]; dispatch(speculateTransactionSuccess(tx)); }) .catch(e => { diff --git a/src/containers/ListingPage/ListingPage.duck.js b/src/containers/ListingPage/ListingPage.duck.js index 6c6b9d88..1e33acf7 100644 --- a/src/containers/ListingPage/ListingPage.duck.js +++ b/src/containers/ListingPage/ListingPage.duck.js @@ -2,7 +2,7 @@ import { pick } from 'lodash'; import { types as sdkTypes } from '../../util/sdkLoader'; import { storableError } from '../../util/errors'; import { addMarketplaceEntities } from '../../ducks/marketplaceData.duck'; -import { updatedEntities, denormalisedEntities } from '../../util/data'; +import { denormalisedResponseEntities } from '../../util/data'; import { TRANSITION_ENQUIRE } from '../../util/types'; import { fetchCurrentUser } from '../../ducks/user.duck'; @@ -117,10 +117,8 @@ export const fetchReviews = listingId => (dispatch, getState, sdk) => { return sdk.reviews .query({ listing_id: listingId, state: 'public', 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)); + const reviews = denormalisedResponseEntities(response); + dispatch(fetchReviewsSuccess(reviews)); }) .catch(e => { dispatch(fetchReviewsError(storableError(e))); diff --git a/src/containers/ProfilePage/ProfilePage.duck.js b/src/containers/ProfilePage/ProfilePage.duck.js index 58ac3b6d..1d34d324 100644 --- a/src/containers/ProfilePage/ProfilePage.duck.js +++ b/src/containers/ProfilePage/ProfilePage.duck.js @@ -1,6 +1,6 @@ import { addMarketplaceEntities } from '../../ducks/marketplaceData.duck'; import { fetchCurrentUser } from '../../ducks/user.duck'; -import { updatedEntities, denormalisedEntities } from '../../util/data'; +import { denormalisedResponseEntities } from '../../util/data'; import { storableError } from '../../util/errors'; // ================ Action types ================ // @@ -139,10 +139,8 @@ export const queryUserReviews = userId => (dispatch, getState, sdk) => { sdk.reviews .query({ subject_id: userId, state: 'public', include: ['author', 'author_profile_image'] }) .then(response => { - const entities = updatedEntities({}, response.data); - const reviewIds = response.data.data.map(d => d.id); - const denormalized = denormalisedEntities(entities, 'review', reviewIds); - dispatch(queryReviewsSuccess(denormalized)); + const reviews = denormalisedResponseEntities(response); + dispatch(queryReviewsSuccess(reviews)); }) .catch(e => dispatch(queryReviewsError(e))); }; diff --git a/src/containers/ProfileSettingsPage/ProfileSettingsPage.duck.js b/src/containers/ProfileSettingsPage/ProfileSettingsPage.duck.js index 1b808cc3..65328756 100644 --- a/src/containers/ProfileSettingsPage/ProfileSettingsPage.duck.js +++ b/src/containers/ProfileSettingsPage/ProfileSettingsPage.duck.js @@ -1,4 +1,4 @@ -import { updatedEntities, denormalisedEntities } from '../../util/data'; +import { denormalisedResponseEntities } from '../../util/data'; import { storableError } from '../../util/errors'; import { currentUserShowSuccess } from '../../ducks/user.duck'; @@ -134,11 +134,11 @@ export const updateProfile = actionPayload => { .then(response => { dispatch(updateProfileSuccess(response)); - // Include profile image to denormalized user entity - const currentUserId = response.data.data.id; - const entities = updatedEntities({}, response.data); - const denormalised = denormalisedEntities(entities, 'currentUser', [currentUserId]); - const currentUser = denormalised[0]; + const entities = denormalisedResponseEntities(response); + if (entities.length !== 1) { + throw new Error('Expected a resource in the sdk.currentUser.updateProfile response'); + } + const currentUser = entities[0]; // Update current user in state.user.currentUser through user.duck.js dispatch(currentUserShowSuccess(currentUser)); diff --git a/src/containers/TransactionPage/TransactionPage.duck.js b/src/containers/TransactionPage/TransactionPage.duck.js index ea007131..ad25d315 100644 --- a/src/containers/TransactionPage/TransactionPage.duck.js +++ b/src/containers/TransactionPage/TransactionPage.duck.js @@ -10,7 +10,11 @@ import { TRANSITION_REVIEW_2_BY_PROVIDER, } from '../../util/types'; import * as log from '../../util/log'; -import { updatedEntities, denormalisedEntities } from '../../util/data'; +import { + updatedEntities, + denormalisedEntities, + denormalisedResponseEntities, +} from '../../util/data'; import { addMarketplaceEntities } from '../../ducks/marketplaceData.duck'; import { fetchCurrentUserNotifications } from '../../ducks/user.duck'; @@ -302,15 +306,13 @@ const fetchMessages = (txId, page) => (dispatch, getState, sdk) => { return sdk.messages .query({ transaction_id: txId, include: ['sender', 'sender.profileImage'], ...paging }) .then(response => { - const entities = updatedEntities({}, response.data); - const messageIds = response.data.data.map(d => d.id); - const denormalizedMessages = denormalisedEntities(entities, 'message', messageIds); + const messages = denormalisedResponseEntities(response); const { totalItems, totalPages, page: fetchedPage } = response.data.meta; const pagination = { totalItems, totalPages, page: fetchedPage }; const totalMessages = getState().TransactionPage.totalMessages; // Original fetchMessages call succeeded - dispatch(fetchMessagesSuccess(denormalizedMessages, pagination)); + dispatch(fetchMessagesSuccess(messages, pagination)); // Check if totalItems has changed between fetched pagination pages // if totalItems has changed, fetch first page again to include new incoming messages. diff --git a/src/ducks/user.duck.js b/src/ducks/user.duck.js index 4e867608..45805c41 100644 --- a/src/ducks/user.duck.js +++ b/src/ducks/user.duck.js @@ -1,4 +1,4 @@ -import { updatedEntities, denormalisedEntities } from '../util/data'; +import { denormalisedResponseEntities } from '../util/data'; import { storableError } from '../util/errors'; import { TRANSITION_REQUEST, TRANSITION_REQUEST_AFTER_ENQUIRY } from '../util/types'; import * as log from '../util/log'; @@ -335,11 +335,12 @@ export const fetchCurrentUser = () => (dispatch, getState, sdk) => { return sdk.currentUser .show({ include: ['profileImage'] }) .then(response => { - // Include profile image to denormalized user entity - const currentUserId = response.data.data.id; - const entities = updatedEntities({}, response.data); - const denormalised = denormalisedEntities(entities, 'currentUser', [currentUserId]); - const currentUser = denormalised[0]; + const entities = denormalisedResponseEntities(response); + if (entities.length !== 1) { + throw new Error('Expected a resource in the sdk.currentUser.show response'); + } + const currentUser = entities[0]; + // set current user id to the logger log.setUserId(currentUser.id.uuid); dispatch(currentUserShowSuccess(currentUser)); diff --git a/src/util/data.js b/src/util/data.js index 70c5b13c..80969e45 100644 --- a/src/util/data.js +++ b/src/util/data.js @@ -104,6 +104,29 @@ export const denormalisedEntities = (entities, type, ids) => { }); }; +/** + * Denormalise the data from the given SDK response + * + * @param {Object} sdkResponse response object from an SDK call + * + * @return {Array} entities in the response with relationships + * denormalised from the included data + */ +export const denormalisedResponseEntities = sdkResponse => { + const apiResponse = sdkResponse.data; + const data = apiResponse.data; + const resources = Array.isArray(data) ? data : [data]; + + if (!data || resources.length === 0) { + return []; + } + + const entities = updatedEntities({}, apiResponse); + const type = resources[0].type; + const resourceIds = resources.map(r => r.id); + return denormalisedEntities(entities, type, resourceIds); +}; + /** * Create shell objects to ensure that attributes etc. exists. *