-
Notifications
You must be signed in to change notification settings - Fork 395
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
Allow users to edit their reviews #3220
Conversation
@@ -244,7 +244,7 @@ | |||
"intl": "^1.2.5", | |||
"intl-locales-supported": "^1.0.0", | |||
"jest": "^21.0.2", | |||
"jest-enzyme": "^3.2.0", | |||
"jest-enzyme": "^3.8.3", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This fixed a bug I was seeing in expect()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I definitely worked around these in #3202 so the tests aren't as good in there... thanks!
@@ -179,7 +200,7 @@ export class AddonReviewBase extends React.Component { | |||
<input | |||
className="AddonReview-submit" | |||
type="submit" | |||
value={i18n.gettext('Submit review')} | |||
value={i18n.gettext('Update review')} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's pretty much always an update whenever you're on this screen. Even the first time you see it, you are editing the review since you have already selected a star rating to get there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any (easy) way to check this though? Like maybe if the existing review text is zero-length? I get that technically they're updating a review after clicking a star, but we call that a rating and it doesn't feel like it. It would be a lot nicer UX to keep "Submit review" for the first time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's not an easy way. I would have to make the internal state of RatingManager
more complex and that test suite doesn't test the click-star-then-edit flow in its entirety (due to react-test-utils limitations).
I'll just revert it back to Submit review
for now since that makes sense in either case.
onEscapeReviewOverlay = () => { | ||
// Even though an escaped overlay will be hidden, we still have to | ||
// synchronize our show/hide state otherwise we won't be able to | ||
// show the overlay after it has been escaped. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a bit lame since we have a chain of callbacks now. I explained the issue in https://github.com/mozilla/addons-frontend/issues/3222 but I think using callbacks is a quicker fix for now.
store, | ||
...customProps, | ||
}; | ||
return shallowUntilTarget( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Believe it or not I didn't want to spend time converting this whole suite to shallow rendering. However, since I had to refactor the reviews
state and be sure I didn't break things along the way, it was really helpful to switch to shallow rendering first. It also turned out to be a nice validation of this shallowUntilTarget
pattern because you can see how this component's reliance on mapped state is fully tested now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I really like testing the entire component including the HOC. I'm happy with have that pattern.
Codecov Report
@@ Coverage Diff @@
## master mozilla/addons-frontend#3220 +/- ##
==========================================
+ Coverage 95.4% 95.41% +<.01%
==========================================
Files 159 160 +1
Lines 2984 3011 +27
Branches 588 593 +5
==========================================
+ Hits 2847 2873 +26
- Misses 118 119 +1
Partials 19 19
Continue to review full report at Codecov.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code looks good but I think the UX of this is a bit off. I think changing the button to more of a link style and giving it more context would be best.
Works well though, so once that's done I think it's set to merge!
@@ -244,7 +244,7 @@ | |||
"intl": "^1.2.5", | |||
"intl-locales-supported": "^1.0.0", | |||
"jest": "^21.0.2", | |||
"jest-enzyme": "^3.2.0", | |||
"jest-enzyme": "^3.8.3", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I definitely worked around these in #3202 so the tests aren't as good in there... thanks!
import type { SetReviewAction, UserReviewType } from 'amo/actions/reviews'; | ||
import type { SubmitReviewParams } from 'amo/api/index'; | ||
import type { ApiStateType } from 'core/reducers/api'; | ||
import type { ErrorHandler as ErrorHandlerType } from 'core/errorHandler'; | ||
import type { ElementEvent } from 'core/types/dom'; | ||
import type { DispatchFunc } from 'core/types/redux'; | ||
|
||
import 'amo/css/AddonReview.scss'; | ||
import './styles.scss'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for tidying this up 😄
@@ -179,7 +200,7 @@ export class AddonReviewBase extends React.Component { | |||
<input | |||
className="AddonReview-submit" | |||
type="submit" | |||
value={i18n.gettext('Submit review')} | |||
value={i18n.gettext('Update review')} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any (easy) way to check this though? Like maybe if the existing review text is zero-length? I get that technically they're updating a review after clicking a star, but we call that a rating and it doesn't feel like it. It would be a lot nicer UX to keep "Submit review" for the first time.
resize: vertical; | ||
|
||
@include respond-to("medium") { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You don't actually need the quotes here and we've tended not to use them. I only mention it because it'll make it easier to grep for if we're consistent. I'm happy to go all-quotes too, but right now we tend not to use them.
I get that's confusing though.
@@ -55,6 +52,8 @@ export class AddonReviewListBase extends React.Component { | |||
} | |||
|
|||
loadDataIfNeeded(nextProps?: AddonReviewListProps) { | |||
const lastAddon = this.props.addon; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No const { addon: lastAddon } = this.props;
? I think I'm finally used to that syntax! 😆
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It only seems necessary to me if you need to destruct multiple variables at once. Otherwise, what's the point?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair enough.
let store; | ||
|
||
beforeEach(() => { | ||
store = createStore().store; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, dispatchSignInActions()
might be better.
expect(rating).toHaveProp('readOnly', true); | ||
}); | ||
|
||
it('renders new lines in review bodies', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpick but I think it's "newlines", no?
.find(LoadingText)).toHaveLength(1); | ||
}); | ||
|
||
it('does not render controls when signed in without a review', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I found this spec a bit hard to parse. I got what it meant but I think it might be better rephrased:
it('does not render review controls unless the user left a review', () => {
expect(root.find('.AddonReviewListItem-controls')).toHaveLength(0); | ||
}); | ||
|
||
it('does not render controls for the wrong user', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe "does not render controls for another user's review"?
onClick={this.onClickToEditReview} | ||
className="AddonReviewListItem-edit-button Button--action Button--small" | ||
> | ||
{i18n.gettext('Edit')} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This button could definitely use some more context. I also don't really think it should be a button. I think stylistically looking like a link with a large tap-target would be better. Where there are multiple buttons it might look weird and things like "Report this review" will be link-styled, not button-styled. So I think this should be "Edit my review" and should be an <a>
tag instead with link styling.
Changing this to a <a>
tag should be fine, I think the only adjustment you'd need would be a preventDefault()
for the onClick
...
@tofumatt thanks, it should be ready for another review. I gave the Edit anchor tag |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is good but I just noticed some accessibility issues with the modal.
I'm of the opinion we should ditch modals but I wanted to bring them up:
-
When navigating with a keyboard, the modal gets activated but keyboard focus isn't changed to the
textarea
in the review modal. This means the user needs to manually tab over twenty times to get to the review modal. It might be nice to focus the textarea after "Edit my review" is activated. -
Esc does not close the modal, at least on my Mac in Nightly.
-
Clicking to the sides of the modal doesn't close the modal. I need to click above or below it. I'm clicking constantly in this GIF:
But I think only the first is worth fixing in the scope of this review.
In the future I'd love to ditch modals.
So r+wc if we fix 1. in the above list 😄
@@ -55,6 +52,8 @@ export class AddonReviewListBase extends React.Component { | |||
} | |||
|
|||
loadDataIfNeeded(nextProps?: AddonReviewListProps) { | |||
const lastAddon = this.props.addon; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair enough.
@@ -204,7 +173,11 @@ export class AddonReviewListBase extends React.Component { | |||
<CardList> | |||
<ul> | |||
{allReviews.map((review, index) => { | |||
return this.renderReview({ review, key: String(index) }); | |||
return ( | |||
<li className="AddonReviewList-li" key={String(index)}> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure we use this class anywhere anymore (based on its removal from the stylesheet below) and it's a bit awkwardly named anyway. I'd be fine just removing it if it isn't used anywhere.
.AddonReviewListItem { | ||
word-wrap: break-word; | ||
|
||
> h3 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know these are from a previous patch but if it'd be possible to label this with a className
and select them directly instead that'd be a bit less fragile. I've liked us not nesting selectors, especially direct selectors like this. I know it's way more verbose but it should help with HTML/CSS refactors.
If not though, it's okay.
I fixed the focus and looked into the other fixes but they weren't straight forward. I think on desktop we can do away with these modals. They were originally designed for mobile so clicking on the sides isn't really an issue (the gutter is pretty small). The modals might still be good UX for mobile screens. I'll land this and then look at replacing the modal for desktop edits as part of mozilla/addons#10582 The failing tests will be resolved on master soon by #3244 |
All sounds good 👍 Thanks! |
Fixes mozilla/addons#10789
I focused mainly on mobile styles only since we will do desktop styles in mozilla/addons#10472
Here is the new edit flow. A key difference is that the stars are now editable in the overlay.
(The blue line at the end is just a glitch in how I converted the movie.)