From dccf787f13ade970a833954dd2a8dfbe756ac4fd Mon Sep 17 00:00:00 2001 From: Hannu Lyytikainen Date: Thu, 23 Nov 2017 15:21:45 +0200 Subject: [PATCH] Add reviews to the ActivityFeed component --- src/components/ActivityFeed/ActivityFeed.css | 26 ++ .../ActivityFeed/ActivityFeed.example.js | 68 ++++- src/components/ActivityFeed/ActivityFeed.js | 232 ++++++++++++++---- .../OrderDetailsPanel.test.js.snap | 18 ++ .../SaleDetailsPanel.test.js.snap | 18 ++ .../__snapshots__/InboxPage.test.js.snap | 4 + .../__snapshots__/OrderPage.test.js.snap | 1 + .../__snapshots__/SalePage.test.js.snap | 1 + src/translations/en.json | 6 +- src/util/propTypes.js | 1 + src/util/test-data.js | 18 ++ 11 files changed, 346 insertions(+), 47 deletions(-) diff --git a/src/components/ActivityFeed/ActivityFeed.css b/src/components/ActivityFeed/ActivityFeed.css index 6b8a9405..f0ddc930 100644 --- a/src/components/ActivityFeed/ActivityFeed.css +++ b/src/components/ActivityFeed/ActivityFeed.css @@ -137,6 +137,32 @@ margin-right: 6px; } +.reviewContent { + @apply --marketplaceH4FontStyles; + font-style: italic; + white-space: pre-line; + margin: 8px 0 0 0; + + @media (--viewportMedium) { + max-width: 500px; + margin: 7px 0 0 0; + } +} + +.reviewStars { + margin-top: 4px; + + @media (--viewportMedium) { + margin-top: 2px; + } +} + +.reviewStar { + width: 12px; + height: 12px; + font-styles: initial; +} + .showOlderWrapper { text-align: center; margin-bottom: 1px; diff --git a/src/components/ActivityFeed/ActivityFeed.example.js b/src/components/ActivityFeed/ActivityFeed.example.js index bd99f626..8740b28d 100644 --- a/src/components/ActivityFeed/ActivityFeed.example.js +++ b/src/components/ActivityFeed/ActivityFeed.example.js @@ -6,6 +6,7 @@ import { createTransaction, createListing, createTxTransition, + createReview, } from '../../util/test-data'; import * as propTypes from '../../util/propTypes'; import ActivityFeed from './ActivityFeed'; @@ -84,7 +85,7 @@ export const WithTransitions = { group: 'messages', }; -export const WithMessagesAndTransitions = { +export const WithMessagesTransitionsAndReviews = { component: ActivityFeed, props: { currentUser: createCurrentUser('user2'), @@ -92,6 +93,7 @@ export const WithMessagesAndTransitions = { customer: createUser('user1'), provider: createUser('user2'), listing: createListing('Listing'), + lastTransition: propTypes.TX_TRANSITION_REVIEW_BY_CUSTOMER_SECOND, transitions: [ createTxTransition({ at: new Date(Date.UTC(2017, 10, 9, 8, 10)), @@ -113,6 +115,28 @@ export const WithMessagesAndTransitions = { by: propTypes.TX_TRANSITION_ACTOR_PROVIDER, transition: propTypes.TX_TRANSITION_MARK_DELIVERED, }), + createTxTransition({ + at: new Date(Date.UTC(2017, 10, 9, 11, 34)), + by: propTypes.TX_TRANSITION_ACTOR_PROVIDER, + transition: propTypes.TX_TRANSITION_REVIEW_BY_PROVIDER_FIRST, + }), + createTxTransition({ + at: new Date(Date.UTC(2017, 10, 9, 12, 34)), + by: propTypes.TX_TRANSITION_ACTOR_CUSTOMER, + transition: propTypes.TX_TRANSITION_REVIEW_BY_CUSTOMER_SECOND, + }), + ], + reviews: [ + createReview( + 'review1', + { at: new Date(Date.UTC(2017, 10, 9, 11, 34)), rating: 3, type: 'ofCustomer' }, + { author: createUser('user2'), subject: createUser('user1') } + ), + createReview( + 'review2', + { at: new Date(Date.UTC(2017, 10, 9, 12, 34)), rating: 5, type: 'ofProvider' }, + { author: createUser('user1'), subject: createUser('user2') } + ), ], }), messages: [ @@ -144,6 +168,48 @@ export const WithMessagesAndTransitions = { group: 'messages', }; +export const WithAReviewFromBothUsers = { + component: ActivityFeed, + props: { + currentUser: createCurrentUser('user1'), + transaction: createTransaction({ + customer: createUser('user1'), + provider: createUser('user2'), + listing: createListing('Listing'), + reviews: [ + createReview( + 'review1', + { at: new Date(Date.UTC(2017, 10, 9, 8, 10)), rating: 3, type: 'ofProvider' }, + { author: createUser('user1'), subject: createUser('user2') } + ), + createReview( + 'review2', + { at: new Date(Date.UTC(2017, 10, 10, 8, 10)), rating: 5, type: 'ofCustomer' }, + { author: createUser('user2'), subject: createUser('user1') } + ), + ], + lastTransition: propTypes.TX_TRANSITION_REVIEW_BY_PROVIDER_SECOND, + transitions: [ + createTxTransition({ + at: new Date(Date.UTC(2017, 10, 9, 8, 10)), + by: propTypes.TX_TRANSITION_ACTOR_CUSTOMER, + transition: propTypes.TX_TRANSITION_REVIEW_BY_CUSTOMER_FIRST, + }), + createTxTransition({ + at: new Date(Date.UTC(2017, 10, 10, 8, 10)), + by: propTypes.TX_TRANSITION_ACTOR_PROVIDER, + transition: propTypes.TX_TRANSITION_REVIEW_BY_PROVIDER_SECOND, + }), + ], + }), + messages: [], + hasOlderMessages: false, + onShowOlderMessages: noop, + fetchMessagesInProgress: false, + }, + group: 'messages', +}; + class PagedFeed extends Component { constructor(props) { super(props); diff --git a/src/components/ActivityFeed/ActivityFeed.js b/src/components/ActivityFeed/ActivityFeed.js index 80780078..f45e3fb5 100644 --- a/src/components/ActivityFeed/ActivityFeed.js +++ b/src/components/ActivityFeed/ActivityFeed.js @@ -1,9 +1,9 @@ import React from 'react'; -import { string, arrayOf, bool, func } from 'prop-types'; +import { string, arrayOf, bool, func, number } from 'prop-types'; import { injectIntl, intlShape, FormattedMessage } from 'react-intl'; import { dropWhile } from 'lodash'; import classNames from 'classnames'; -import { Avatar, InlineTextButton } from '../../components'; +import { Avatar, InlineTextButton, NamedLink, ReviewRating } from '../../components'; import { formatDate } from '../../util/dates'; import { ensureTransaction, ensureUser, ensureListing } from '../../util/data'; import * as propTypes from '../../util/propTypes'; @@ -47,43 +47,156 @@ OwnMessage.propTypes = { intl: intlShape.isRequired, }; +const Review = props => { + const { content, rating } = props; + return ( +
+

{content}

+ +
+ ); +}; + +Review.propTypes = { + content: string.isRequired, + rating: number.isRequired, +}; + +const areReviewsCompleted = transition => { + return [ + propTypes.TX_TRANSITION_REVIEW_BY_PROVIDER_SECOND, + propTypes.TX_TRANSITION_REVIEW_BY_CUSTOMER_SECOND, + propTypes.TX_TRANSITION_MARK_REVIEWED_BY_CUSTOMER, + propTypes.TX_TRANSITION_MARK_REVIEWED_BY_PROVIDER, + propTypes.TX_TRANSITION_AUTO_COMPLETE_WITHOUT_REVIEWS, + ].includes(transition); +}; + +const isReviewTransition = transition => { + return [ + propTypes.TX_TRANSITION_REVIEW_BY_PROVIDER_FIRST, + propTypes.TX_TRANSITION_REVIEW_BY_CUSTOMER_FIRST, + propTypes.TX_TRANSITION_REVIEW_BY_PROVIDER_SECOND, + propTypes.TX_TRANSITION_REVIEW_BY_CUSTOMER_SECOND, + ].includes(transition); +}; + +const hasUserLeftAReviewFirst = (userRole, lastTransition) => { + return ( + (lastTransition === propTypes.TX_TRANSITION_REVIEW_BY_CUSTOMER_FIRST && + userRole === propTypes.TX_TRANSITION_ACTOR_CUSTOMER) || + (lastTransition === propTypes.TX_TRANSITION_REVIEW_BY_PROVIDER_FIRST && + userRole === propTypes.TX_TRANSITION_ACTOR_PROVIDER) || + areReviewsCompleted(lastTransition) + ); +}; + +const resolveTransitionMessage = ( + transition, + lastTransition, + listingTitle, + ownRole, + otherUsersName, + intl +) => { + const isOwnTransition = transition.by === ownRole; + const currentTransition = transition.transition; + const displayName = otherUsersName; + const deliveredState = lastTransition === propTypes.TX_TRANSITION_MARK_DELIVERED; + + switch (currentTransition) { + case propTypes.TX_TRANSITION_PREAUTHORIZE: + return isOwnTransition ? ( + + ) : ( + + ); + case propTypes.TX_TRANSITION_ACCEPT: + return isOwnTransition ? ( + + ) : ( + + ); + case propTypes.TX_TRANSITION_DECLINE: + return isOwnTransition ? ( + + ) : ( + + ); + case propTypes.TX_TRANSITION_AUTO_DECLINE: + return ownRole === propTypes.TX_TRANSITION_ACTOR_PROVIDER ? ( + + ) : ( + + ); + case propTypes.TX_TRANSITION_CANCEL: + return ; + case propTypes.TX_TRANSITION_MARK_DELIVERED: + // Show the leave a review link if the state is delivered or + // if current user is not the first to leave a review + const reviewLink = + deliveredState || !hasUserLeftAReviewFirst(ownRole, lastTransition) ? ( + + + + ) : null; + + return ; + case propTypes.TX_TRANSITION_REVIEW_BY_PROVIDER_FIRST: + case propTypes.TX_TRANSITION_REVIEW_BY_CUSTOMER_FIRST: + if (isOwnTransition) { + return ; + } else { + // show the leave a review link if current user is not the first + // one to leave a review + const reviewLink = !hasUserLeftAReviewFirst(ownRole, lastTransition) ? ( + + + + ) : null; + return ( + + ); + } + case propTypes.TX_TRANSITION_REVIEW_BY_PROVIDER_SECOND: + case propTypes.TX_TRANSITION_REVIEW_BY_CUSTOMER_SECOND: + if (isOwnTransition) { + return ; + } else { + return ( + + ); + } + + default: + return ''; + } +}; + +const reviewByAuthorId = (transaction, userId) => { + return transaction.reviews.filter(r => r.author.id.uuid === userId.uuid)[0]; +}; + const Transition = props => { - const { transition, currentUser, customer, provider, listingTitle, intl } = props; + const { transition, transaction, currentUser, intl } = props; - const resolveTransitionMessage = (transition, ownRole, otherUsersName, intl) => { - const isOwnTransition = transition.by === ownRole; - const transitionType = transition.transition; - const displayName = otherUsersName; - - switch (transitionType) { - case propTypes.TX_TRANSITION_PREAUTHORIZE: - return isOwnTransition - ? intl.formatMessage({ id: 'ActivityFeed.ownTransitionRequest' }, { listingTitle }) - : intl.formatMessage( - { id: 'ActivityFeed.transitionRequest' }, - { displayName, listingTitle } - ); - case propTypes.TX_TRANSITION_ACCEPT: - return isOwnTransition - ? intl.formatMessage({ id: 'ActivityFeed.ownTransitionAccept' }) - : intl.formatMessage({ id: 'ActivityFeed.transitionAccept' }, { displayName }); - case propTypes.TX_TRANSITION_DECLINE: - return isOwnTransition - ? intl.formatMessage({ id: 'ActivityFeed.ownTransitionDecline' }) - : intl.formatMessage({ id: 'ActivityFeed.transitionDecline' }, { displayName }); - case propTypes.TX_TRANSITION_AUTO_DECLINE: - return ownRole === propTypes.TX_TRANSITION_ACTOR_PROVIDER - ? intl.formatMessage({ id: 'ActivityFeed.ownTransitionAutoDecline' }) - : intl.formatMessage({ id: 'ActivityFeed.transitionAutoDecline' }, { displayName }); - case propTypes.TX_TRANSITION_MARK_DELIVERED: - return intl.formatMessage({ id: 'ActivityFeed.transitionComplete' }); - case propTypes.TX_TRANSITION_CANCEL: - return intl.formatMessage({ id: 'ActivityFeed.transitionCancel' }); - - default: - return ''; - } - }; + const customer = transaction.customer; + const provider = transaction.provider; + const listingTitle = transaction.listing.attributes.title; + const lastTransition = transaction.attributes.lastTransition; const ownRole = currentUser.id.uuid === customer.id.uuid @@ -95,7 +208,38 @@ const Transition = props => { ? provider.attributes.profile.displayName : customer.attributes.profile.displayName; - const transitionMessage = resolveTransitionMessage(transition, ownRole, otherUsersName, intl); + const transitionMessage = resolveTransitionMessage( + transition, + lastTransition, + listingTitle, + ownRole, + otherUsersName, + intl + ); + const currentTransition = transition.transition; + + let reviewComponent = null; + + if (isReviewTransition(currentTransition) && areReviewsCompleted(lastTransition)) { + const customerReview = + currentTransition === propTypes.TX_TRANSITION_REVIEW_BY_CUSTOMER_FIRST || + currentTransition === propTypes.TX_TRANSITION_REVIEW_BY_CUSTOMER_SECOND; + const providerReview = + currentTransition === propTypes.TX_TRANSITION_REVIEW_BY_PROVIDER_FIRST || + currentTransition === propTypes.TX_TRANSITION_REVIEW_BY_PROVIDER_SECOND; + if (customerReview) { + const review = reviewByAuthorId(transaction, customer.id); + reviewComponent = ( + + ); + } else if (providerReview) { + const review = reviewByAuthorId(transaction, provider.id); + reviewComponent = ( + + ); + } + } + const todayString = intl.formatMessage({ id: 'ActivityFeed.today' }); return ( @@ -106,6 +250,7 @@ const Transition = props => {

{transitionMessage}

{formatDate(intl, todayString, transition.at)}

+ {reviewComponent}
); @@ -113,10 +258,8 @@ const Transition = props => { Transition.propTypes = { transition: propTypes.txTransition.isRequired, + transaction: propTypes.transaction.isRequired, currentUser: propTypes.currentUser.isRequired, - customer: propTypes.user.isRequired, - provider: propTypes.user.isRequired, - listingTitle: string.isRequired, intl: intlShape.isRequired, }; @@ -180,7 +323,8 @@ export const ActivityFeedComponent = props => { currentUser && currentUser.id && currentCustomer.id && - currentProvider.id + currentProvider.id && + currentListing.id ); // combine messages and transaction transitions @@ -191,10 +335,8 @@ export const ActivityFeedComponent = props => { return ( ); diff --git a/src/components/OrderDetailsPanel/__snapshots__/OrderDetailsPanel.test.js.snap b/src/components/OrderDetailsPanel/__snapshots__/OrderDetailsPanel.test.js.snap index 03cf25a8..71cf60de 100644 --- a/src/components/OrderDetailsPanel/__snapshots__/OrderDetailsPanel.test.js.snap +++ b/src/components/OrderDetailsPanel/__snapshots__/OrderDetailsPanel.test.js.snap @@ -217,6 +217,7 @@ exports[`OrderDetailsPanel accepted matches snapshot 1`] = ` }, "type": "user", }, + "reviews": Array [], "type": "transaction", } } @@ -424,6 +425,7 @@ exports[`OrderDetailsPanel accepted matches snapshot 1`] = ` }, "type": "user", }, + "reviews": Array [], "type": "transaction", } } @@ -633,6 +635,7 @@ exports[`OrderDetailsPanel accepted matches snapshot 1`] = ` }, "type": "user", }, + "reviews": Array [], "type": "transaction", } } @@ -849,6 +852,7 @@ exports[`OrderDetailsPanel autodeclined matches snapshot 1`] = ` }, "type": "user", }, + "reviews": Array [], "type": "transaction", } } @@ -1056,6 +1060,7 @@ exports[`OrderDetailsPanel autodeclined matches snapshot 1`] = ` }, "type": "user", }, + "reviews": Array [], "type": "transaction", } } @@ -1265,6 +1270,7 @@ exports[`OrderDetailsPanel autodeclined matches snapshot 1`] = ` }, "type": "user", }, + "reviews": Array [], "type": "transaction", } } @@ -1493,6 +1499,7 @@ exports[`OrderDetailsPanel canceled matches snapshot 1`] = ` }, "type": "user", }, + "reviews": Array [], "type": "transaction", } } @@ -1700,6 +1707,7 @@ exports[`OrderDetailsPanel canceled matches snapshot 1`] = ` }, "type": "user", }, + "reviews": Array [], "type": "transaction", } } @@ -1909,6 +1917,7 @@ exports[`OrderDetailsPanel canceled matches snapshot 1`] = ` }, "type": "user", }, + "reviews": Array [], "type": "transaction", } } @@ -2125,6 +2134,7 @@ exports[`OrderDetailsPanel declined matches snapshot 1`] = ` }, "type": "user", }, + "reviews": Array [], "type": "transaction", } } @@ -2332,6 +2342,7 @@ exports[`OrderDetailsPanel declined matches snapshot 1`] = ` }, "type": "user", }, + "reviews": Array [], "type": "transaction", } } @@ -2541,6 +2552,7 @@ exports[`OrderDetailsPanel declined matches snapshot 1`] = ` }, "type": "user", }, + "reviews": Array [], "type": "transaction", } } @@ -2757,6 +2769,7 @@ exports[`OrderDetailsPanel delivered matches snapshot 1`] = ` }, "type": "user", }, + "reviews": Array [], "type": "transaction", } } @@ -2964,6 +2977,7 @@ exports[`OrderDetailsPanel delivered matches snapshot 1`] = ` }, "type": "user", }, + "reviews": Array [], "type": "transaction", } } @@ -3173,6 +3187,7 @@ exports[`OrderDetailsPanel delivered matches snapshot 1`] = ` }, "type": "user", }, + "reviews": Array [], "type": "transaction", } } @@ -3412,6 +3427,7 @@ exports[`OrderDetailsPanel preauthorized matches snapshot 1`] = ` }, "type": "user", }, + "reviews": Array [], "type": "transaction", } } @@ -3619,6 +3635,7 @@ exports[`OrderDetailsPanel preauthorized matches snapshot 1`] = ` }, "type": "user", }, + "reviews": Array [], "type": "transaction", } } @@ -3828,6 +3845,7 @@ exports[`OrderDetailsPanel preauthorized matches snapshot 1`] = ` }, "type": "user", }, + "reviews": Array [], "type": "transaction", } } diff --git a/src/components/SaleDetailsPanel/__snapshots__/SaleDetailsPanel.test.js.snap b/src/components/SaleDetailsPanel/__snapshots__/SaleDetailsPanel.test.js.snap index 260d3344..020ddbac 100644 --- a/src/components/SaleDetailsPanel/__snapshots__/SaleDetailsPanel.test.js.snap +++ b/src/components/SaleDetailsPanel/__snapshots__/SaleDetailsPanel.test.js.snap @@ -211,6 +211,7 @@ exports[`SaleDetailsPanel accepted matches snapshot 1`] = ` "type": "listing", }, "provider": null, + "reviews": Array [], "type": "transaction", } } @@ -406,6 +407,7 @@ exports[`SaleDetailsPanel accepted matches snapshot 1`] = ` "type": "listing", }, "provider": null, + "reviews": Array [], "type": "transaction", } } @@ -571,6 +573,7 @@ exports[`SaleDetailsPanel accepted matches snapshot 1`] = ` "type": "listing", }, "provider": null, + "reviews": Array [], "type": "transaction", } } @@ -795,6 +798,7 @@ exports[`SaleDetailsPanel autodeclined matches snapshot 1`] = ` "type": "listing", }, "provider": null, + "reviews": Array [], "type": "transaction", } } @@ -990,6 +994,7 @@ exports[`SaleDetailsPanel autodeclined matches snapshot 1`] = ` "type": "listing", }, "provider": null, + "reviews": Array [], "type": "transaction", } } @@ -1155,6 +1160,7 @@ exports[`SaleDetailsPanel autodeclined matches snapshot 1`] = ` "type": "listing", }, "provider": null, + "reviews": Array [], "type": "transaction", } } @@ -1379,6 +1385,7 @@ exports[`SaleDetailsPanel canceled matches snapshot 1`] = ` "type": "listing", }, "provider": null, + "reviews": Array [], "type": "transaction", } } @@ -1574,6 +1581,7 @@ exports[`SaleDetailsPanel canceled matches snapshot 1`] = ` "type": "listing", }, "provider": null, + "reviews": Array [], "type": "transaction", } } @@ -1739,6 +1747,7 @@ exports[`SaleDetailsPanel canceled matches snapshot 1`] = ` "type": "listing", }, "provider": null, + "reviews": Array [], "type": "transaction", } } @@ -1963,6 +1972,7 @@ exports[`SaleDetailsPanel declined matches snapshot 1`] = ` "type": "listing", }, "provider": null, + "reviews": Array [], "type": "transaction", } } @@ -2158,6 +2168,7 @@ exports[`SaleDetailsPanel declined matches snapshot 1`] = ` "type": "listing", }, "provider": null, + "reviews": Array [], "type": "transaction", } } @@ -2323,6 +2334,7 @@ exports[`SaleDetailsPanel declined matches snapshot 1`] = ` "type": "listing", }, "provider": null, + "reviews": Array [], "type": "transaction", } } @@ -2547,6 +2559,7 @@ exports[`SaleDetailsPanel delivered matches snapshot 1`] = ` "type": "listing", }, "provider": null, + "reviews": Array [], "type": "transaction", } } @@ -2742,6 +2755,7 @@ exports[`SaleDetailsPanel delivered matches snapshot 1`] = ` "type": "listing", }, "provider": null, + "reviews": Array [], "type": "transaction", } } @@ -2907,6 +2921,7 @@ exports[`SaleDetailsPanel delivered matches snapshot 1`] = ` "type": "listing", }, "provider": null, + "reviews": Array [], "type": "transaction", } } @@ -3141,6 +3156,7 @@ exports[`SaleDetailsPanel preauthorized matches snapshot 1`] = ` "type": "listing", }, "provider": null, + "reviews": Array [], "type": "transaction", } } @@ -3336,6 +3352,7 @@ exports[`SaleDetailsPanel preauthorized matches snapshot 1`] = ` "type": "listing", }, "provider": null, + "reviews": Array [], "type": "transaction", } } @@ -3529,6 +3546,7 @@ exports[`SaleDetailsPanel preauthorized matches snapshot 1`] = ` "type": "listing", }, "provider": null, + "reviews": Array [], "type": "transaction", } } diff --git a/src/containers/InboxPage/__snapshots__/InboxPage.test.js.snap b/src/containers/InboxPage/__snapshots__/InboxPage.test.js.snap index 18ebeb1c..7131cc9e 100644 --- a/src/containers/InboxPage/__snapshots__/InboxPage.test.js.snap +++ b/src/containers/InboxPage/__snapshots__/InboxPage.test.js.snap @@ -183,6 +183,7 @@ exports[`InboxPage matches snapshot 1`] = ` }, "type": "user", }, + "reviews": Array [], "type": "transaction", } } @@ -297,6 +298,7 @@ exports[`InboxPage matches snapshot 1`] = ` }, "type": "user", }, + "reviews": Array [], "type": "transaction", } } @@ -569,6 +571,7 @@ exports[`InboxPage matches snapshot 3`] = ` }, "type": "user", }, + "reviews": Array [], "type": "transaction", } } @@ -683,6 +686,7 @@ exports[`InboxPage matches snapshot 3`] = ` }, "type": "user", }, + "reviews": Array [], "type": "transaction", } } diff --git a/src/containers/OrderPage/__snapshots__/OrderPage.test.js.snap b/src/containers/OrderPage/__snapshots__/OrderPage.test.js.snap index fc91023a..981a359a 100644 --- a/src/containers/OrderPage/__snapshots__/OrderPage.test.js.snap +++ b/src/containers/OrderPage/__snapshots__/OrderPage.test.js.snap @@ -165,6 +165,7 @@ exports[`OrderPage matches snapshot 1`] = ` }, "type": "user", }, + "reviews": Array [], "type": "transaction", } } diff --git a/src/containers/SalePage/__snapshots__/SalePage.test.js.snap b/src/containers/SalePage/__snapshots__/SalePage.test.js.snap index b2183007..b9280c89 100644 --- a/src/containers/SalePage/__snapshots__/SalePage.test.js.snap +++ b/src/containers/SalePage/__snapshots__/SalePage.test.js.snap @@ -170,6 +170,7 @@ exports[`SalePage matches snapshot 1`] = ` }, "type": "user", }, + "reviews": Array [], "type": "transaction", } } diff --git a/src/translations/en.json b/src/translations/en.json index 35ef6050..6d166f6e 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -1,16 +1,20 @@ { + "ActivityFeed.leaveAReview": "Leave a review for { displayName }.", + "ActivityFeed.leaveAReviewSecond": "Leave a review for { displayName } to see their review.", "ActivityFeed.ownTransitionAccept": "You accepted the booking request.", "ActivityFeed.ownTransitionAutoDecline": "Booking request expired. You did not reply on time.", "ActivityFeed.ownTransitionDecline": "You declined the booking request.", "ActivityFeed.ownTransitionRequest": "You requested to book { listingTitle }.", + "ActivityFeed.ownTransitionReview": "You left a review for { displayName }.", "ActivityFeed.showOlderMessages": "Show older", "ActivityFeed.today": "Today", "ActivityFeed.transitionAccept": "{ displayName } accepted the booking request.", "ActivityFeed.transitionAutoDecline": "Booking request expired. { displayName } did not reply on time.", "ActivityFeed.transitionCancel": "The booking was cancelled.", - "ActivityFeed.transitionComplete": "The booking was completed.", + "ActivityFeed.transitionComplete": "The booking was completed. { reviewLink }", "ActivityFeed.transitionDecline": "{ displayName } declined the booking request.", "ActivityFeed.transitionRequest": "{ displayName } requested to book { listingTitle }.", + "ActivityFeed.transitionReview": "{ displayName } left a review for you. { reviewLink }", "AuthenticationPage.emailAlreadyInUse": "An account with this email address already exists. Try logging in instead.", "AuthenticationPage.fixEmail": "Whoops, typo in your email? {fixEmailLink}.", "AuthenticationPage.fixEmailLinkText": "Fix it", diff --git a/src/util/propTypes.js b/src/util/propTypes.js index 233161db..bad686e0 100644 --- a/src/util/propTypes.js +++ b/src/util/propTypes.js @@ -263,6 +263,7 @@ export const transaction = shape({ listing, customer: user, provider: user, + reviews: arrayOf(review), }); // Denormalised transaction message diff --git a/src/util/test-data.js b/src/util/test-data.js index d6767095..d191f3e3 100644 --- a/src/util/test-data.js +++ b/src/util/test-data.js @@ -105,6 +105,7 @@ export const createTransaction = options => { listing = null, customer = null, provider = null, + reviews = [], lastTransitionedAt = new Date(Date.UTC(2017, 5, 1)), transitions = [ createTxTransition({ @@ -150,6 +151,7 @@ export const createTransaction = options => { listing, customer, provider, + reviews, }; }; @@ -166,6 +168,22 @@ export const createMessage = (id, attributes = {}, includes = {}) => { }; }; +export const createReview = (id, attributes = {}, includes = {}) => { + return { + id: new UUID(id), + attributes: { + at: new Date(), + content: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', + rating: 3, + state: 'public', + type: 'ofProvider', + ...attributes, + }, + ...includes, + }; +}; + // Default config for currency formatting in tests and examples. export const currencyConfig = { style: 'currency',