Skip to content

Commit

Permalink
Refactor ReportAbuseButton to use DismissibleTextForm (#7382)
Browse files Browse the repository at this point in the history
  • Loading branch information
mirefly authored and willdurand committed Jan 18, 2019
1 parent 2e2ae93 commit 8319dad
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 434 deletions.
75 changes: 15 additions & 60 deletions src/amo/components/ReportAbuseButton/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,21 @@ import makeClassName from 'classnames';
import { oneLine } from 'common-tags';
import * as React from 'react';
import { connect } from 'react-redux';
import Textarea from 'react-textarea-autosize';
import { compose } from 'redux';

import { withErrorHandler } from 'core/errorHandler';
import type { ErrorHandlerType } from 'core/errorHandler';
import translate from 'core/i18n/translate';
import log from 'core/logger';
import {
disableAbuseButtonUI,
enableAbuseButtonUI,
hideAddonAbuseReportUI,
sendAddonAbuseReport,
showAddonAbuseReportUI,
} from 'core/reducers/abuse';
import { sanitizeHTML } from 'core/utils';
import { normalizeFileNameId, sanitizeHTML } from 'core/utils';
import Button from 'ui/components/Button';
import DismissibleTextForm from 'ui/components/DismissibleTextForm';
import type { OnSubmitParams } from 'ui/components/DismissibleTextForm';
import type { AppState } from 'amo/store';
import type { AddonAbuseState } from 'core/reducers/abuse';
import type { DispatchFunc } from 'core/types/redux';
Expand All @@ -41,11 +40,7 @@ type InternalProps = {|
|};

export class ReportAbuseButtonBase extends React.Component<InternalProps> {
textarea: React.ElementRef<typeof Textarea>;

dismissReportUI = (event: SyntheticEvent<any>) => {
event.preventDefault();

dismissReportUI = () => {
const { addon, dispatch, loading } = this.props;

if (loading) {
Expand All @@ -58,12 +53,10 @@ export class ReportAbuseButtonBase extends React.Component<InternalProps> {
dispatch(hideAddonAbuseReportUI({ addon }));
};

sendReport = (event: SyntheticEvent<any>) => {
event.preventDefault();

sendReport = ({ text }: OnSubmitParams) => {
// The button isn't clickable if there is no content, but just in case:
// we verify there's a message to send.
if (!this.textarea.value.length) {
if (!text.trim().length) {
log.debug(oneLine`User managed to click submit button while textarea
was empty. Ignoring this onClick/sendReport event.`);
return;
Expand All @@ -75,7 +68,7 @@ export class ReportAbuseButtonBase extends React.Component<InternalProps> {
sendAddonAbuseReport({
addonSlug: addon.slug,
errorHandlerId: errorHandler.id,
message: this.textarea.value,
message: text,
}),
);
};
Expand All @@ -86,20 +79,6 @@ export class ReportAbuseButtonBase extends React.Component<InternalProps> {
const { addon, dispatch } = this.props;

dispatch(showAddonAbuseReportUI({ addon }));
this.textarea.focus();
};

textareaChange = () => {
const { abuseReport, addon, dispatch } = this.props;

// Don't dispatch the UI update if the button is already visible.
// We also test for `value.trim()` so the user can't submit an
// empty report full of spaces.
if (this.textarea.value.trim().length && !abuseReport.buttonEnabled) {
dispatch(enableAbuseButtonUI({ addon }));
} else if (!this.textarea.value.trim().length) {
dispatch(disableAbuseButtonUI({ addon }));
}
};

render() {
Expand Down Expand Up @@ -133,8 +112,6 @@ export class ReportAbuseButtonBase extends React.Component<InternalProps> {
);
}

const sendButtonIsDisabled = loading || !abuseReport.buttonEnabled;

const prefaceText = i18n.sprintf(
i18n.gettext(
`If you think this add-on violates
Expand Down Expand Up @@ -190,40 +167,18 @@ export class ReportAbuseButtonBase extends React.Component<InternalProps> {

{errorHandler.renderErrorIfPresent()}

<Textarea
className="ReportAbuseButton-textarea"
disabled={loading}
inputRef={(ref) => {
this.textarea = ref;
}}
onChange={this.textareaChange}
<DismissibleTextForm
id={normalizeFileNameId(__filename)}
isSubmitting={loading}
onSubmit={this.sendReport}
submitButtonText={i18n.gettext('Send abuse report')}
submitButtonInProgressText={i18n.gettext('Sending abuse report')}
onDismiss={this.dismissReportUI}
dismissButtonText={i18n.gettext('Dismiss')}
placeholder={i18n.gettext(
'Explain how this add-on is violating our policies.',
)}
/>

<div className="ReportAbuseButton-buttons">
<a
className={makeClassName('ReportAbuseButton-dismiss-report', {
'ReportAbuseButton-dismiss-report--disabled': loading,
})}
href="#cancel"
onClick={this.dismissReportUI}
>
{i18n.gettext('Dismiss')}
</a>
<Button
buttonType="alert"
className="ReportAbuseButton-send-report"
disabled={sendButtonIsDisabled}
onClick={this.sendReport}
micro
>
{loading
? i18n.gettext('Sending abuse report')
: i18n.gettext('Send abuse report')}
</Button>
</div>
</div>
</div>
);
Expand Down
29 changes: 0 additions & 29 deletions src/amo/components/ReportAbuseButton/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -32,32 +32,3 @@
.ReportAbuseButton-show-more {
width: 100%;
}

.ReportAbuseButton-textarea {
font-size: $font-size-m-smaller;
line-height: 1.4;
margin: 5px auto;
// This is the height of two lines of text. Often the placeholder text
// will span two lines–because this element will grow/shrink based on
// the contents of the text inside it, we set a minimum height so it
// won't shrink when the two-line placeholder is replaced with a single
// character when the user starts typing.
min-height: 51px;
padding: 5px;
resize: none;
width: 100%;
}

.ReportAbuseButton-buttons {
display: flex;
justify-content: space-between;
}

.ReportAbuseButton-dismiss-report {
align-self: center;
}

.ReportAbuseButton-dismiss-report--disabled:link {
color: $neutral-base-color;
cursor: not-allowed;
}
64 changes: 0 additions & 64 deletions src/core/reducers/abuse.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,6 @@ import invariant from 'invariant';
import type { AddonType } from 'core/types/addons';
import type { AbuseReporter } from 'core/api/abuse';

export const DISABLE_ADDON_ABUSE_BUTTON_UI: 'DISABLE_ADDON_ABUSE_BUTTON_UI' =
'DISABLE_ADDON_ABUSE_BUTTON_UI';
export const ENABLE_ADDON_ABUSE_BUTTON_UI: 'ENABLE_ADDON_ABUSE_BUTTON_UI' =
'ENABLE_ADDON_ABUSE_BUTTON_UI';
export const HIDE_ADDON_ABUSE_REPORT_UI: 'HIDE_ADDON_ABUSE_REPORT_UI' =
'HIDE_ADDON_ABUSE_REPORT_UI';
export const LOAD_ADDON_ABUSE_REPORT: 'LOAD_ADDON_ABUSE_REPORT' =
Expand Down Expand Up @@ -36,42 +32,6 @@ export const initialState: AbuseState = {
loading: false,
};

type DisableAbuseButtonUIParams = {| addon: AddonType |};

type DisableAbuseButtonUIAction = {|
type: typeof DISABLE_ADDON_ABUSE_BUTTON_UI,
payload: DisableAbuseButtonUIParams,
|};

export function disableAbuseButtonUI({
addon,
}: DisableAbuseButtonUIParams): DisableAbuseButtonUIAction {
invariant(addon, 'addon is required');

return {
type: DISABLE_ADDON_ABUSE_BUTTON_UI,
payload: { addon },
};
}

type EnableAbuseButtonUIParams = {| addon: AddonType |};

type EnableAbuseButtonUIAction = {|
type: typeof ENABLE_ADDON_ABUSE_BUTTON_UI,
payload: EnableAbuseButtonUIParams,
|};

export function enableAbuseButtonUI({
addon,
}: EnableAbuseButtonUIParams): EnableAbuseButtonUIAction {
invariant(addon, 'addon is required');

return {
type: ENABLE_ADDON_ABUSE_BUTTON_UI,
payload: { addon },
};
}

type HideAddonAbuseReportUIParams = {| addon: AddonType |};

type HideAddonAbuseReportUIAction = {|
Expand Down Expand Up @@ -165,8 +125,6 @@ export function showAddonAbuseReportUI({
}

type Action =
| DisableAbuseButtonUIAction
| EnableAbuseButtonUIAction
| HideAddonAbuseReportUIAction
| LoadAddonAbuseReportAction
| SendAddonAbuseReportAction
Expand All @@ -177,28 +135,6 @@ export default function abuseReducer(
action: Action,
) {
switch (action.type) {
case DISABLE_ADDON_ABUSE_BUTTON_UI: {
const { addon } = action.payload;

return {
...state,
bySlug: {
...state.bySlug,
[addon.slug]: { ...state.bySlug[addon.slug], buttonEnabled: false },
},
};
}
case ENABLE_ADDON_ABUSE_BUTTON_UI: {
const { addon } = action.payload;

return {
...state,
bySlug: {
...state.bySlug,
[addon.slug]: { ...state.bySlug[addon.slug], buttonEnabled: true },
},
};
}
case HIDE_ADDON_ABUSE_REPORT_UI: {
const { addon } = action.payload;

Expand Down
Loading

0 comments on commit 8319dad

Please sign in to comment.