Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Include Add-on name and Add-on Icon in each review under "My reviews" on User Profile #12426

Open
wants to merge 17 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions src/amo/actions/reviews.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import type {
ExternalReviewType,
} from 'amo/api/reviews';
import type { UserId } from 'amo/reducers/users';
import { selectLocalizedContent } from 'amo/reducers/utils';

export const CREATE_ADDON_REVIEW: 'CREATE_ADDON_REVIEW' = 'CREATE_ADDON_REVIEW';
export const SHOW_EDIT_REVIEW_FORM: 'SHOW_EDIT_REVIEW_FORM' =
Expand Down Expand Up @@ -77,12 +78,13 @@ export type UserReviewType = {|

export function createInternalReview(
review: ExternalReviewType | ExternalReviewReplyType,
lang: string = '',
): UserReviewType {
return {
reviewAddon: {
iconUrl: review.addon.icon_url,
id: review.addon.id,
name: review.addon.name,
name: selectLocalizedContent(review.addon.name, lang),
slug: review.addon.slug,
},
body: review.body,
Expand All @@ -92,7 +94,7 @@ export function createInternalReview(
isDeveloperReply: review.is_developer_reply,
isLatest: review.is_latest,
score: review.score || null,
reply: review.reply ? createInternalReview(review.reply) : null,
reply: review.reply ? createInternalReview(review.reply, lang) : null,
userId: review.user.id,
userName: review.user.name,
userUrl: review.user.url,
Expand Down
4 changes: 2 additions & 2 deletions src/amo/api/reviews.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ import { callApi } from 'amo/api';
import type { FlagReviewReasonType } from 'amo/constants';
import type { ApiState } from 'amo/reducers/api';
import type { ErrorHandlerType } from 'amo/types/errorHandler';
import type { PaginatedApiResponse } from 'amo/types/api';
import type { PaginatedApiResponse, LocalizedString } from 'amo/types/api';

type ExternalReviewTypeBase = {|
addon: {|
icon_url: string,
id: number,
name: string,
name: LocalizedString,
slug: string,
|},
body: string,
Expand Down
26 changes: 26 additions & 0 deletions src/amo/components/AddonReviewCard/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ type Props = {|
isReplyToReviewId?: number,
review?: UserReviewType | null,
siteUserCanReply: ?boolean,
isUserProfile?: boolean,
|};

type PropsFromState = {|
Expand Down Expand Up @@ -358,6 +359,8 @@ export class AddonReviewCardBase extends React.Component<InternalProps> {
} = this.props;

let byLine;
const addonIconURL = review?.reviewAddon?.iconUrl || null;
const addonName = review?.reviewAddon?.name || null;
const noAuthor = shortByLine || this.isReply();
const showUserProfileLink = !noAuthor && hasUsersEditPermission;

Expand Down Expand Up @@ -545,6 +548,29 @@ export class AddonReviewCardBase extends React.Component<InternalProps> {
>
<div className="AddonReviewCard-container">
{errorHandler.renderErrorIfPresent()}
{/* Div to display Addon's name and icon */}
{this.props.isUserProfile &&
addonName &&
addonIconURL &&
!this.isReply() && (
<div className="AddonReviewCard-addonInfo">
<img
src={addonIconURL}
alt={i18n.sprintf(i18n.gettext('Icon for %1$s'), {
'%1$s': addonName,
})}
/>
<span>
<span className="AddonReviewCard-addonReviewLabel">
{i18n.sprintf(i18n.gettext('Review of %1$s'), {
'%1$s': addonName,
})}
</span>
<span className="AddonReviewCard-addonName">{addonName}</span>
</span>
</div>
)}

{review && review.isDeleted && (
<Notice type="error" className="AddonReviewCard-non-public-notice">
{i18n.gettext(
Expand Down
22 changes: 22 additions & 0 deletions src/amo/components/AddonReviewCard/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
.AddonReviewCard {
.Rating {
height: $font-size-l;
margin-top: auto;
padding: auto;
}

&:not(.AddonReviewCard-slim) .UserReview-body {
Expand All @@ -23,6 +25,26 @@
}
}

.AddonReviewCard-addonReviewLabel {
font-weight: normal;
margin-left: 3px;
}

.AddonReviewCard-addonName {
font-weight: bold;
}

.AddonReviewCard-addonInfo {
display: flex;
align-items: center;
padding: auto;
}

.AddonReviewCard-addonInfo img {
max-width: 20px;
max-height: 20px;
}

.AddonReviewCard-authorByLine {
overflow: hidden;
text-overflow: ellipsis;
Expand Down
1 change: 1 addition & 0 deletions src/amo/pages/UserProfile/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ export class UserProfileBase extends React.Component<InternalProps> {
review={review}
shortByLine
siteUserCanReply={false}
isUserProfile
/>
</li>
);
Expand Down
16 changes: 12 additions & 4 deletions src/amo/reducers/reviews.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { oneLine } from 'common-tags';
import invariant from 'invariant';
import { LOCATION_CHANGE } from 'redux-first-history';

import { SET_LANG } from 'amo/reducers/api';
import {
BEGIN_DELETE_ADDON_REVIEW,
CANCEL_DELETE_ADDON_REVIEW,
Expand Down Expand Up @@ -160,6 +161,7 @@ export type ReviewsState = {|
loadingForSlug: {
[slug: string]: boolean,
},
lang: string,
|};

export const initialState: ReviewsState = {
Expand All @@ -172,6 +174,7 @@ export const initialState: ReviewsState = {
view: {},
flashMessage: undefined,
loadingForSlug: {},
lang: '',
};

export function selectReviews({
Expand Down Expand Up @@ -517,7 +520,7 @@ export default function reviewsReducer(
}
case SET_REVIEW: {
const { payload } = action;
const review = createInternalReview(payload);
const review = createInternalReview(payload, state.lang);

const newState = _addReviewToState({ state, review });
return changeViewState({
Expand All @@ -544,7 +547,7 @@ export default function reviewsReducer(
...state.byId,
[review.id]: {
...review,
reply: createInternalReview(action.payload.reply),
reply: createInternalReview(action.payload.reply, state.lang),
},
},
};
Expand Down Expand Up @@ -592,7 +595,7 @@ export default function reviewsReducer(
case SET_ADDON_REVIEWS: {
const { payload } = action;
const reviews = payload.reviews.map((review) =>
createInternalReview(review),
createInternalReview(review, state.lang),
);

return {
Expand All @@ -619,7 +622,7 @@ export default function reviewsReducer(
case SET_USER_REVIEWS: {
const { payload } = action;
const reviews = payload.reviews.map((review) =>
createInternalReview(review),
createInternalReview(review, state.lang),
);

return {
Expand Down Expand Up @@ -721,6 +724,11 @@ export default function reviewsReducer(
},
};
}
case SET_LANG:
return {
...state,
lang: action.payload.lang,
};
default:
return state;
}
Expand Down
44 changes: 44 additions & 0 deletions tests/unit/amo/components/TestAddonReviewCard.js
Original file line number Diff line number Diff line change
Expand Up @@ -1334,6 +1334,50 @@ describe(__filename, () => {
});
});

describe('Tests for AddonReviewCard-addonInfo', () => {
it('displays addon icon and name when isUserProfile is true and isReply is false', () => {
const review = _setReview({
reviewAddon: {
...fakeReview.reviewAddon,
IconUrl: 'http://sample.url/icon.png',
name: 'Sample Addon',
},
});

render({ review, isUserProfile: true, isReply: false });
expect(
screen.getByClassName('AddonReviewCard-addonInfo'),
).toBeInTheDocument();
expect(
screen.getByClassName('AddonReviewCard-addonReviewLabel'),
).toBeInTheDocument();
expect(
screen.getByClassName('AddonReviewCard-addonName'),
).toBeInTheDocument();
});

it('does not display addon icon and name when isUserProfile is false and isReply is false', () => {
const review = _setReview({
reviewAddon: {
...fakeReview.reviewAddon,
IconUrl: 'http://sample.url/icon.png',
name: 'Sample Addon',
},
});

render({ review, isUserProfile: false, isReply: false });
expect(
screen.queryByClassName('AddonReviewCard-addonInfo'),
).not.toBeInTheDocument();
expect(
screen.queryByClassName('AddonReviewCard-addonReviewLabel'),
).not.toBeInTheDocument();
expect(
screen.queryByClassName('AddonReviewCard-addonName'),
).not.toBeInTheDocument();
});
});

shribyte marked this conversation as resolved.
Show resolved Hide resolved
describe('Tests for UserRating', () => {
it('renders a Rating', () => {
render({ review: _setReview({ score: 2 }) });
Expand Down
Loading