mirror of
https://github.com/scratchfoundation/scratch-www.git
synced 2024-11-27 09:35:56 -05:00
Merge pull request #2015 from benjiwheeler/report_project_endpoint
report project POSTs to scratchr2, displays modal reactively
This commit is contained in:
commit
0114d3ea2f
9 changed files with 260 additions and 119 deletions
|
@ -28,8 +28,8 @@ module.exports.validationHOCFactory = defaultValidationErrors => (Component => {
|
|||
<Component
|
||||
validationErrors={defaults(
|
||||
{},
|
||||
defaultValidationErrors,
|
||||
props.validationErrors
|
||||
props.validationErrors,
|
||||
defaultValidationErrors
|
||||
)}
|
||||
{...omit(props, ['validationErrors'])}
|
||||
/>
|
||||
|
|
|
@ -35,7 +35,6 @@
|
|||
.addToStudio-modal-content {
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
line-height: 1.5rem;
|
||||
font-size: .875rem;
|
||||
}
|
||||
|
||||
|
|
|
@ -64,11 +64,20 @@ $modal-close-size: 1rem;
|
|||
.action-buttons {
|
||||
display: flex;
|
||||
margin: 1.125rem .8275rem .9375rem .8275rem;
|
||||
line-height: 1.5rem;
|
||||
justify-content: flex-end !important;
|
||||
align-items: flex-start;
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
|
||||
/* setting overall modal to contain overflow looks good, but isn't
|
||||
compatible with elements (like validation popups) that need to bleed
|
||||
past modal boundary. This class can be used to force modal button
|
||||
row to appear to contain overflow. */
|
||||
.action-buttons-overflow-fix {
|
||||
margin-bottom: .9375rem;
|
||||
}
|
||||
|
||||
.action-button {
|
||||
margin: 0 0 0 .54625rem;
|
||||
border-radius: .25rem;
|
||||
|
@ -83,3 +92,19 @@ $modal-close-size: 1rem;
|
|||
.action-button-text {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.action-button.disabled {
|
||||
background-color: $active-dark-gray;
|
||||
}
|
||||
|
||||
.error-text
|
||||
{
|
||||
display: block;
|
||||
border: 1px solid $active-gray;
|
||||
border-radius: 5px;
|
||||
background-color: $ui-orange;
|
||||
padding: 1rem;
|
||||
min-height: 1rem;
|
||||
overflow: visible;
|
||||
color: $type-white;
|
||||
}
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
const bindAll = require('lodash.bindall');
|
||||
const PropTypes = require('prop-types');
|
||||
const React = require('react');
|
||||
const connect = require('react-redux').connect;
|
||||
const FormattedMessage = require('react-intl').FormattedMessage;
|
||||
const injectIntl = require('react-intl').injectIntl;
|
||||
const intlShape = require('react-intl').intlShape;
|
||||
const Modal = require('../base/modal.jsx');
|
||||
const classNames = require('classnames');
|
||||
|
||||
const Form = require('../../forms/form.jsx');
|
||||
const Button = require('../../forms/button.jsx');
|
||||
|
@ -12,6 +14,7 @@ const Select = require('../../forms/select.jsx');
|
|||
const Spinner = require('../../spinner/spinner.jsx');
|
||||
const TextArea = require('../../forms/textarea.jsx');
|
||||
const FlexRow = require('../../flex-row/flex-row.jsx');
|
||||
const previewActions = require('../../../redux/preview.js');
|
||||
|
||||
require('../../forms/button.scss');
|
||||
require('./modal.scss');
|
||||
|
@ -68,12 +71,24 @@ class ReportModal extends React.Component {
|
|||
constructor (props) {
|
||||
super(props);
|
||||
bindAll(this, [
|
||||
'handleReportCategorySelect'
|
||||
'handleCategorySelect',
|
||||
'handleValid',
|
||||
'handleInvalid'
|
||||
]);
|
||||
this.state = {reportCategory: this.props.report.category};
|
||||
this.state = {
|
||||
category: '',
|
||||
notes: '',
|
||||
valid: false
|
||||
};
|
||||
}
|
||||
handleReportCategorySelect (name, value) {
|
||||
this.setState({reportCategory: value});
|
||||
handleCategorySelect (name, value) {
|
||||
this.setState({category: value});
|
||||
}
|
||||
handleValid () {
|
||||
this.setState({valid: true});
|
||||
}
|
||||
handleInvalid () {
|
||||
this.setState({valid: false});
|
||||
}
|
||||
lookupPrompt (value) {
|
||||
const prompt = REPORT_OPTIONS.find(item => item.value === value).prompt;
|
||||
|
@ -82,17 +97,24 @@ class ReportModal extends React.Component {
|
|||
render () {
|
||||
const {
|
||||
intl,
|
||||
isConfirmed,
|
||||
isError,
|
||||
isOpen,
|
||||
isWaiting,
|
||||
onReport, // eslint-disable-line no-unused-vars
|
||||
report,
|
||||
onRequestClose,
|
||||
type,
|
||||
...modalProps
|
||||
} = this.props;
|
||||
const submitEnabled = this.state.valid && !isWaiting;
|
||||
const submitDisabledParam = submitEnabled ? {} : {disabled: 'disabled'};
|
||||
const contentLabel = intl.formatMessage({id: `report.${type}`});
|
||||
return (
|
||||
<Modal
|
||||
className="mod-report"
|
||||
contentLabel={contentLabel}
|
||||
isOpen={report.open}
|
||||
isOpen={isOpen}
|
||||
onRequestClose={onRequestClose}
|
||||
{...modalProps}
|
||||
>
|
||||
<div>
|
||||
|
@ -104,68 +126,115 @@ class ReportModal extends React.Component {
|
|||
|
||||
<Form
|
||||
className="report"
|
||||
onSubmit={onReport}
|
||||
onInvalid={this.handleInvalid}
|
||||
onValid={this.handleValid}
|
||||
onValidSubmit={onReport}
|
||||
>
|
||||
<div className="report-modal-content">
|
||||
<FormattedMessage
|
||||
id={`report.${type}Instructions`}
|
||||
values={{
|
||||
CommunityGuidelinesLink: (
|
||||
<a href="/community_guidelines">
|
||||
<FormattedMessage id="report.CommunityGuidelinesLinkText" />
|
||||
</a>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<Select
|
||||
required
|
||||
elementWrapperClassName="report-modal-field"
|
||||
label={null}
|
||||
name="report_category"
|
||||
options={REPORT_OPTIONS.map(option => ({
|
||||
value: option.value,
|
||||
label: this.props.intl.formatMessage(option.label)
|
||||
}))}
|
||||
value={this.state.reportCategory}
|
||||
onChange={this.handleReportCategorySelect}
|
||||
/>
|
||||
<TextArea
|
||||
required
|
||||
className="report-text"
|
||||
elementWrapperClassName="report-modal-field"
|
||||
label={null}
|
||||
name="notes"
|
||||
placeholder={this.lookupPrompt(this.state.reportCategory)}
|
||||
validationErrors={{
|
||||
maxLength: this.props.intl.formatMessage({id: 'report.tooLongError'}),
|
||||
minLength: this.props.intl.formatMessage({id: 'report.tooShortError'})
|
||||
}}
|
||||
validations={{
|
||||
maxLength: 500,
|
||||
minLength: 20
|
||||
}}
|
||||
value={report.notes}
|
||||
/>
|
||||
{isConfirmed ? (
|
||||
<div className="received">
|
||||
<div className="received-header">
|
||||
<FormattedMessage id="report.receivedHeader" />
|
||||
</div>
|
||||
<FormattedMessage id="report.receivedBody" />
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
<div className="instructions">
|
||||
<FormattedMessage
|
||||
id={`report.${type}Instructions`}
|
||||
key={`report.${type}Instructions`}
|
||||
values={{
|
||||
CommunityGuidelinesLink: (
|
||||
<a href="/community_guidelines">
|
||||
<FormattedMessage id="report.CommunityGuidelinesLinkText" />
|
||||
</a>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<Select
|
||||
required
|
||||
elementWrapperClassName="report-modal-field"
|
||||
label={null}
|
||||
name="report_category"
|
||||
options={REPORT_OPTIONS.map(option => ({
|
||||
value: option.value,
|
||||
label: this.props.intl.formatMessage(option.label),
|
||||
key: option.value
|
||||
}))}
|
||||
validationErrors={{
|
||||
isDefaultRequiredValue: this.props.intl.formatMessage({
|
||||
id: 'report.reasonMissing'
|
||||
})
|
||||
}}
|
||||
value={this.state.category}
|
||||
onChange={this.handleCategorySelect}
|
||||
/>
|
||||
<TextArea
|
||||
required
|
||||
className="report-text"
|
||||
elementWrapperClassName="report-modal-field"
|
||||
label={null}
|
||||
name="notes"
|
||||
placeholder={this.lookupPrompt(this.state.category)}
|
||||
validationErrors={{
|
||||
isDefaultRequiredValue: this.props.intl.formatMessage({
|
||||
id: 'report.textMissing'
|
||||
}),
|
||||
maxLength: this.props.intl.formatMessage({id: 'report.tooLongError'}),
|
||||
minLength: this.props.intl.formatMessage({id: 'report.tooShortError'})
|
||||
}}
|
||||
validations={{
|
||||
maxLength: 500,
|
||||
minLength: 20
|
||||
}}
|
||||
value={this.state.notes}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{isError && (
|
||||
<div className="error-text">
|
||||
<FormattedMessage id="report.error" />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<FlexRow className="action-buttons">
|
||||
{report.waiting ? [
|
||||
<Button
|
||||
className="submit-button"
|
||||
disabled="disabled"
|
||||
key="submitButton"
|
||||
type="submit"
|
||||
>
|
||||
<Spinner />
|
||||
</Button>
|
||||
] : [
|
||||
<Button
|
||||
className="submit-button"
|
||||
key="submitButton"
|
||||
type="submit"
|
||||
>
|
||||
<FormattedMessage id="report.send" />
|
||||
</Button>
|
||||
]}
|
||||
<div className="action-buttons-overflow-fix">
|
||||
{isConfirmed ? (
|
||||
<Button
|
||||
className="action-button submit-button"
|
||||
type="button"
|
||||
onClick={onRequestClose}
|
||||
>
|
||||
<div className="action-button-text">
|
||||
<FormattedMessage id="general.close" />
|
||||
</div>
|
||||
</Button>
|
||||
) : (
|
||||
<Button
|
||||
className={classNames(
|
||||
'action-button',
|
||||
'submit-button',
|
||||
{disabled: !submitEnabled}
|
||||
)}
|
||||
{...submitDisabledParam}
|
||||
key="submitButton"
|
||||
type="submit"
|
||||
>
|
||||
{isWaiting ? (
|
||||
<div className="action-button-text">
|
||||
<Spinner mode="smooth" />
|
||||
<FormattedMessage id="report.sending" />
|
||||
</div>
|
||||
) : (
|
||||
<div className="action-button-text">
|
||||
<FormattedMessage id="report.send" />
|
||||
</div>
|
||||
)}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</FlexRow>
|
||||
</Form>
|
||||
</div>
|
||||
|
@ -176,15 +245,26 @@ class ReportModal extends React.Component {
|
|||
|
||||
ReportModal.propTypes = {
|
||||
intl: intlShape,
|
||||
isConfirmed: PropTypes.bool,
|
||||
isError: PropTypes.bool,
|
||||
isOpen: PropTypes.bool,
|
||||
isWaiting: PropTypes.bool,
|
||||
onReport: PropTypes.func,
|
||||
onRequestClose: PropTypes.func,
|
||||
report: PropTypes.shape({
|
||||
category: PropTypes.string,
|
||||
notes: PropTypes.string,
|
||||
open: PropTypes.bool,
|
||||
waiting: PropTypes.bool
|
||||
}),
|
||||
type: PropTypes.string
|
||||
};
|
||||
|
||||
module.exports = injectIntl(ReportModal);
|
||||
const mapStateToProps = state => ({
|
||||
isConfirmed: state.preview.status.report === previewActions.Status.FETCHED,
|
||||
isError: state.preview.status.report === previewActions.Status.ERROR,
|
||||
isWaiting: state.preview.status.report === previewActions.Status.FETCHING
|
||||
});
|
||||
|
||||
const mapDispatchToProps = () => ({});
|
||||
|
||||
const ConnectedReportModal = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(ReportModal);
|
||||
|
||||
module.exports = injectIntl(ConnectedReportModal);
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
margin: 100px auto;
|
||||
outline: none;
|
||||
padding: 0;
|
||||
width: 30rem;
|
||||
width: 36.25rem; /* 580px; */
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
|
@ -34,26 +34,45 @@
|
|||
.report-modal-content {
|
||||
margin: 1rem auto;
|
||||
width: 80%;
|
||||
line-height: 1.5rem;
|
||||
font-size: .875rem;
|
||||
|
||||
.instructions {
|
||||
line-height: 1.5rem;
|
||||
}
|
||||
|
||||
.received {
|
||||
margin: 0 auto;
|
||||
width: 90%;
|
||||
text-align: center;
|
||||
line-height: 1.65rem;
|
||||
|
||||
.received-header {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.error-text {
|
||||
margin-top: .9375rem;
|
||||
}
|
||||
|
||||
.validation-message {
|
||||
$arrow-border-width: 1rem;
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
transform: translate(23.5rem, 0);
|
||||
left: 100%; /* position to the right of parent */
|
||||
margin-left: $arrow-border-width;
|
||||
border: 1px solid $active-gray;
|
||||
border-radius: 5px;
|
||||
background-color: $ui-orange;
|
||||
padding: 1rem;
|
||||
min-width: 12rem;
|
||||
max-width: 18.75rem;
|
||||
min-height: 1rem;
|
||||
overflow: visible;
|
||||
color: $type-white;
|
||||
|
||||
/* arrow on box that points to the left */
|
||||
&:before {
|
||||
display: block;
|
||||
position: absolute;
|
||||
|
@ -78,3 +97,13 @@
|
|||
.report-modal-field {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.form-group.has-error {
|
||||
.textarea, select {
|
||||
border: 1px solid $ui-orange;
|
||||
}
|
||||
}
|
||||
|
||||
.report-text .textarea {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
|
|
@ -172,6 +172,7 @@
|
|||
"registration.welcomeStepTitle": "Hurray! Welcome to Scratch!",
|
||||
|
||||
"thumbnail.by": "by",
|
||||
"report.error": "Something went wrong when trying to send your message. Please try again.",
|
||||
"report.project": "Report Project",
|
||||
"report.projectInstructions": "From the dropdown below, please select the reason why you feel this project is disrespectful or inappropriate or otherwise breaks the {CommunityGuidelinesLink}.",
|
||||
"report.CommunityGuidelinesLinkText": "Scratch Community Guidelines",
|
||||
|
@ -181,8 +182,11 @@
|
|||
"report.reasonScary": "Too Violent or Scary",
|
||||
"report.reasonLanguage": "Inappropriate Language",
|
||||
"report.reasonMusic": "Inappropriate Music",
|
||||
"report.reasonMissing": "Please select a reason",
|
||||
"report.reasonImage": "Inappropriate Images",
|
||||
"report.reasonPersonal": "Sharing Personal Contact Information",
|
||||
"report.receivedHeader": "We have received your report!",
|
||||
"report.receivedBody": "The Scratch Team will review the project based on the Scratch community guidelines.",
|
||||
"report.promptPlaceholder": "Select a reason why above.",
|
||||
"report.promptCopy": "Please provide a link to the original project",
|
||||
"report.promptUncredited": "Please provide links to the uncredited content",
|
||||
|
@ -194,5 +198,7 @@
|
|||
"report.promptImage": "Please say the name of the sprite or the backdrop with the inappropriate image",
|
||||
"report.tooLongError": "That's too long! Please find a way to shorten your text.",
|
||||
"report.tooShortError": "That's too short. Please describe in detail what's inappropriate or disrespectful about the project.",
|
||||
"report.send": "Send"
|
||||
"report.send": "Send",
|
||||
"report.sending": "Sending...",
|
||||
"report.textMissing": "Please tell us why you are reporting this project"
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
const defaults = require('lodash.defaults');
|
||||
const keyMirror = require('keymirror');
|
||||
const async = require('async');
|
||||
const merge = require('lodash.merge');
|
||||
|
@ -21,6 +22,7 @@ module.exports.getInitialState = () => ({
|
|||
original: module.exports.Status.NOT_FETCHED,
|
||||
parent: module.exports.Status.NOT_FETCHED,
|
||||
remixes: module.exports.Status.NOT_FETCHED,
|
||||
report: module.exports.Status.NOT_FETCHED,
|
||||
projectStudios: module.exports.Status.NOT_FETCHED,
|
||||
curatedStudios: module.exports.Status.NOT_FETCHED,
|
||||
studioRequests: {}
|
||||
|
@ -324,6 +326,7 @@ module.exports.getReplies = (projectId, commentIds) => (dispatch => {
|
|||
});
|
||||
|
||||
module.exports.setFavedStatus = (faved, id, username, token) => (dispatch => {
|
||||
dispatch(module.exports.setFetchStatus('faved', module.exports.Status.FETCHING));
|
||||
if (faved) {
|
||||
api({
|
||||
uri: `/projects/${id}/favorites/user/${username}`,
|
||||
|
@ -383,6 +386,7 @@ module.exports.getLovedStatus = (id, username, token) => (dispatch => {
|
|||
});
|
||||
|
||||
module.exports.setLovedStatus = (loved, id, username, token) => (dispatch => {
|
||||
dispatch(module.exports.setFetchStatus('loved', module.exports.Status.FETCHING));
|
||||
if (loved) {
|
||||
api({
|
||||
uri: `/projects/${id}/loves/user/${username}`,
|
||||
|
@ -531,6 +535,7 @@ module.exports.leaveStudio = (studioId, projectId, token) => (dispatch => {
|
|||
});
|
||||
|
||||
module.exports.updateProject = (id, jsonData, username, token) => (dispatch => {
|
||||
dispatch(module.exports.setFetchStatus('project', module.exports.Status.FETCHING));
|
||||
api({
|
||||
uri: `/projects/${id}`,
|
||||
authentication: token,
|
||||
|
@ -556,3 +561,27 @@ module.exports.updateProject = (id, jsonData, username, token) => (dispatch => {
|
|||
dispatch(module.exports.setProjectInfo(body));
|
||||
});
|
||||
});
|
||||
|
||||
module.exports.reportProject = (id, jsonData) => (dispatch => {
|
||||
dispatch(module.exports.setFetchStatus('report', module.exports.Status.FETCHING));
|
||||
// scratchr2 will fail if no thumbnail base64 string provided. We don't yet have
|
||||
// a way to get the actual project thumbnail in www/gui, so for now just submit
|
||||
// a minimal base64 png string.
|
||||
defaults(jsonData, {
|
||||
thumbnail: 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC' +
|
||||
'0lEQVR42mP8/x8AAwMCAO+ip1sAAAAASUVORK5CYII='
|
||||
});
|
||||
api({
|
||||
host: '',
|
||||
uri: `/site-api/projects/all/${id}/report/`,
|
||||
method: 'POST',
|
||||
json: jsonData,
|
||||
useCsrf: true
|
||||
}, (err, body, res) => {
|
||||
if (err || res.statusCode !== 200) {
|
||||
dispatch(module.exports.setFetchStatus('report', module.exports.Status.ERROR));
|
||||
return;
|
||||
}
|
||||
dispatch(module.exports.setFetchStatus('report', module.exports.Status.FETCHED));
|
||||
});
|
||||
});
|
||||
|
|
|
@ -43,7 +43,7 @@ const PreviewPresentation = ({
|
|||
projectId,
|
||||
projectInfo,
|
||||
remixes,
|
||||
report,
|
||||
reportOpen,
|
||||
replies,
|
||||
addToStudioOpen,
|
||||
projectStudios,
|
||||
|
@ -278,8 +278,8 @@ const PreviewPresentation = ({
|
|||
Report
|
||||
</Button>,
|
||||
<ReportModal
|
||||
isOpen={reportOpen}
|
||||
key="report-modal"
|
||||
report={report}
|
||||
type="project"
|
||||
onReport={onReportSubmit}
|
||||
onRequestClose={onReportClose}
|
||||
|
@ -377,12 +377,7 @@ PreviewPresentation.propTypes = {
|
|||
projectStudios: PropTypes.arrayOf(PropTypes.object),
|
||||
remixes: PropTypes.arrayOf(PropTypes.object),
|
||||
replies: PropTypes.objectOf(PropTypes.array),
|
||||
report: PropTypes.shape({
|
||||
category: PropTypes.string,
|
||||
notes: PropTypes.string,
|
||||
open: PropTypes.bool,
|
||||
waiting: PropTypes.bool
|
||||
}),
|
||||
reportOpen: PropTypes.bool,
|
||||
studios: PropTypes.arrayOf(PropTypes.object),
|
||||
userOwnsProject: PropTypes.bool
|
||||
};
|
||||
|
|
|
@ -57,12 +57,7 @@ class Preview extends React.Component {
|
|||
loveCount: 0,
|
||||
projectId: parts[1] === 'editor' ? 0 : parts[1],
|
||||
addToStudioOpen: false,
|
||||
report: {
|
||||
category: '',
|
||||
notes: '',
|
||||
open: false,
|
||||
waiting: false
|
||||
}
|
||||
reportOpen: false
|
||||
};
|
||||
this.getExtensions(this.state.projectId);
|
||||
this.addEventListeners();
|
||||
|
@ -87,7 +82,6 @@ class Preview extends React.Component {
|
|||
this.props.getRemixes(this.state.projectId);
|
||||
this.props.getProjectStudios(this.state.projectId);
|
||||
}
|
||||
|
||||
}
|
||||
if (this.props.projectInfo.id !== prevProps.projectInfo.id) {
|
||||
this.getExtensions(this.state.projectId);
|
||||
|
@ -118,7 +112,7 @@ class Preview extends React.Component {
|
|||
getExtensions (projectId) {
|
||||
storage
|
||||
.load(storage.AssetType.Project, projectId, storage.DataFormat.JSON)
|
||||
.then(projectAsset => {
|
||||
.then(projectAsset => { // NOTE: this is turning up null, breaking the line below.
|
||||
let input = projectAsset.data;
|
||||
if (typeof input === 'object' && !(input instanceof ArrayBuffer) &&
|
||||
!ArrayBuffer.isView(input)) { // taken from scratch-vm
|
||||
|
@ -148,10 +142,10 @@ class Preview extends React.Component {
|
|||
});
|
||||
}
|
||||
handleReportClick () {
|
||||
this.setState({report: {...this.state.report, open: true}});
|
||||
this.setState({reportOpen: true});
|
||||
}
|
||||
handleReportClose () {
|
||||
this.setState({report: {...this.state.report, open: false}});
|
||||
this.setState({reportOpen: false});
|
||||
}
|
||||
handleAddToStudioClick () {
|
||||
this.setState({addToStudioOpen: true});
|
||||
|
@ -159,27 +153,8 @@ class Preview extends React.Component {
|
|||
handleAddToStudioClose () {
|
||||
this.setState({addToStudioOpen: false});
|
||||
}
|
||||
// NOTE: this is a copy, change it
|
||||
handleReportSubmit (formData) {
|
||||
this.setState({report: {
|
||||
category: formData.report_category,
|
||||
notes: formData.notes,
|
||||
open: this.state.report.open,
|
||||
waiting: true}
|
||||
});
|
||||
|
||||
const data = {
|
||||
...formData,
|
||||
id: this.state.projectId,
|
||||
user: this.props.user.username
|
||||
};
|
||||
console.log('submit report data', data); // eslint-disable-line no-console
|
||||
this.setState({report: {
|
||||
category: '',
|
||||
notes: '',
|
||||
open: false,
|
||||
waiting: false}
|
||||
});
|
||||
this.props.reportProject(this.state.projectId, formData);
|
||||
}
|
||||
handlePopState () {
|
||||
const path = window.location.pathname.toLowerCase();
|
||||
|
@ -335,7 +310,7 @@ class Preview extends React.Component {
|
|||
projectStudios={this.props.projectStudios}
|
||||
remixes={this.props.remixes}
|
||||
replies={this.props.replies}
|
||||
report={this.state.report}
|
||||
reportOpen={this.state.reportOpen}
|
||||
studios={this.props.studios}
|
||||
user={this.props.user}
|
||||
userOwnsProject={this.userOwnsProject()}
|
||||
|
@ -383,6 +358,7 @@ Preview.propTypes = {
|
|||
projectStudios: PropTypes.arrayOf(PropTypes.object),
|
||||
remixes: PropTypes.arrayOf(PropTypes.object),
|
||||
replies: PropTypes.objectOf(PropTypes.array),
|
||||
reportProject: PropTypes.func,
|
||||
sessionStatus: PropTypes.string,
|
||||
setFavedStatus: PropTypes.func.isRequired,
|
||||
setFullScreen: PropTypes.func.isRequired,
|
||||
|
@ -461,7 +437,6 @@ const mapStateToProps = state => ({
|
|||
fullScreen: state.scratchGui.mode.isFullScreen
|
||||
});
|
||||
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
getOriginalInfo: id => {
|
||||
dispatch(previewActions.getOriginalInfo(id));
|
||||
|
@ -506,6 +481,9 @@ const mapDispatchToProps = dispatch => ({
|
|||
refreshSession: () => {
|
||||
dispatch(sessionActions.refreshSession());
|
||||
},
|
||||
reportProject: (id, formData) => {
|
||||
dispatch(previewActions.reportProject(id, formData));
|
||||
},
|
||||
setOriginalInfo: info => {
|
||||
dispatch(previewActions.setOriginalInfo(info));
|
||||
},
|
||||
|
|
Loading…
Reference in a new issue