mirror of
https://github.com/Ocelot-Social-Community/Ocelot-Social.git
synced 2025-12-12 23:35:58 +00:00
Follow @roschaefer's PR review suggestions
- disable button if form.reasonCategory is falsy - extract valuesReasonCategoryOptions to global constant - extract reasonCategoryOptions to created lifecycle hook to keep data() clean and use map - extract formSchema to components/utils and test - remove validator from formSchema and validate based on "Deep Rules" https://github.com/yiminghe/async-validator#deep-rules - Use v-model to update reasonCategory and reasonDescription - default to error message in English from backend - Update template slot to use new syntax
This commit is contained in:
parent
37bf37f39b
commit
e8c6941142
@ -78,10 +78,7 @@ const validateReport = async (resolve, root, args, context, info) => {
|
||||
}
|
||||
})
|
||||
|
||||
if (existingReportedResource)
|
||||
throw new Error(
|
||||
`You have already reported the ${existingReportedResource.label}, please only report the same ${existingReportedResource.label} once`,
|
||||
)
|
||||
if (existingReportedResource) throw new Error(`${existingReportedResource.label}`)
|
||||
return resolve(root, args, context, info)
|
||||
}
|
||||
|
||||
|
||||
@ -8,9 +8,8 @@
|
||||
|
||||
<!-- eslint-disable-next-line vue/no-v-html -->
|
||||
<p v-html="message" />
|
||||
|
||||
<ds-radio
|
||||
:value="form.reasonCategory"
|
||||
v-model="form.reasonCategory"
|
||||
:schema="formSchema.reasonCategory"
|
||||
:label="$t('report.reason.category.label')"
|
||||
:options="form.reasonCategoryOptions"
|
||||
@ -18,7 +17,7 @@
|
||||
/>
|
||||
<ds-input
|
||||
class="reason-description"
|
||||
:value="form.reasonDescription"
|
||||
v-model="form.reasonDescription"
|
||||
:schema="formSchema.reasonDescription"
|
||||
:label="$t('report.reason.description.label')"
|
||||
:placeholder="$t('report.reason.description.placeholder')"
|
||||
@ -29,15 +28,16 @@
|
||||
{{ form.reasonDescription.length }}/{{ formSchema.reasonDescription.max }}
|
||||
</small>
|
||||
<ds-space />
|
||||
|
||||
<template slot="footer">
|
||||
<ds-button class="cancel" icon="close" @click="cancel">{{ $t('report.cancel') }}</ds-button>
|
||||
<template #footer>
|
||||
<ds-button class="cancel" icon="close" @click="cancel">
|
||||
{{ $t('report.cancel') }}
|
||||
</ds-button>
|
||||
|
||||
<ds-button
|
||||
danger
|
||||
class="confirm"
|
||||
icon="exclamation-circle"
|
||||
:disabled="failsValidations"
|
||||
:disabled="!form.reasonCategory"
|
||||
:loading="loading"
|
||||
@click="confirm"
|
||||
>
|
||||
@ -50,6 +50,8 @@
|
||||
<script>
|
||||
import { SweetalertIcon } from 'vue-sweetalert-icons'
|
||||
import { reportMutation } from '~/graphql/Moderation.js'
|
||||
import { valuesReasonCategoryOptions } from '~/constants/modals.js'
|
||||
import validReport from '~/components/utils/ReportModal'
|
||||
|
||||
export default {
|
||||
name: 'ReportModal',
|
||||
@ -62,58 +64,25 @@ export default {
|
||||
id: { type: String, required: true },
|
||||
},
|
||||
data() {
|
||||
// this list equals to enums in GraphQL schema file "backend/src/schema/types/type/REPORTED.gql"
|
||||
let valuesReasonCategoryOptions = [
|
||||
'discrimination_etc',
|
||||
'pornographic_content_links',
|
||||
'glorific_trivia_of_cruel_inhuman_acts',
|
||||
'doxing',
|
||||
'intentional_intimidation_stalking_persecution',
|
||||
'advert_products_services_commercial',
|
||||
'criminal_behavior_violation_german_law',
|
||||
'other',
|
||||
]
|
||||
|
||||
let reasonCategoryOptions = []
|
||||
valuesReasonCategoryOptions.forEach(reasonCategory => {
|
||||
reasonCategoryOptions.push({
|
||||
label: this.$t('report.reason.category.options.' + reasonCategory),
|
||||
value: reasonCategory,
|
||||
})
|
||||
})
|
||||
|
||||
return {
|
||||
isOpen: true,
|
||||
success: false,
|
||||
loading: false,
|
||||
failsValidations: true,
|
||||
form: {
|
||||
reasonCategory: null,
|
||||
reasonCategoryOptions,
|
||||
reasonCategoryOptions: [],
|
||||
reasonDescription: '',
|
||||
},
|
||||
formSchema: {
|
||||
reasonCategory: {
|
||||
type: 'enum',
|
||||
required: true,
|
||||
validator: (rule, value, callback, source, options) => {
|
||||
this.form.reasonCategory = value
|
||||
this.failsValidations = !this.form.reasonCategory
|
||||
callback()
|
||||
},
|
||||
},
|
||||
reasonDescription: {
|
||||
type: 'string',
|
||||
min: 0,
|
||||
max: 200,
|
||||
validator: (rule, value, callback, source, options) => {
|
||||
this.form.reasonDescription = value
|
||||
callback()
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.form.reasonCategoryOptions = valuesReasonCategoryOptions.map(reasonCategory => {
|
||||
return {
|
||||
label: this.$t('report.reason.category.options.' + reasonCategory),
|
||||
value: reasonCategory,
|
||||
}
|
||||
})
|
||||
},
|
||||
computed: {
|
||||
title() {
|
||||
return this.$t(`report.${this.type}.title`)
|
||||
@ -122,6 +91,12 @@ export default {
|
||||
const name = this.$filters.truncate(this.name, 30)
|
||||
return this.$t(`report.${this.type}.message`, { name })
|
||||
},
|
||||
formSchema() {
|
||||
const validReportSchema = validReport({ translate: this.$t })
|
||||
return {
|
||||
...validReportSchema.formSchema,
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async cancel() {
|
||||
@ -134,7 +109,6 @@ export default {
|
||||
},
|
||||
async confirm() {
|
||||
const { reasonCategory, reasonDescription } = this.form
|
||||
|
||||
this.loading = true
|
||||
// TODO: Use the "modalData" structure introduced in "ConfirmModal" and refactor this here. Be aware that all the Jest tests have to be refactored as well !!!
|
||||
// await this.modalData.buttons.confirm.callback()
|
||||
@ -172,6 +146,8 @@ export default {
|
||||
case 'GraphQL error: Comment':
|
||||
this.$toast.error(this.$t('report.comment.error'))
|
||||
break
|
||||
default:
|
||||
this.$toast.error(err.message)
|
||||
}
|
||||
this.loading = false
|
||||
})
|
||||
|
||||
25
webapp/components/utils/ReportModal.js
Normal file
25
webapp/components/utils/ReportModal.js
Normal file
@ -0,0 +1,25 @@
|
||||
import { valuesReasonCategoryOptions } from '~/constants/modals.js'
|
||||
|
||||
export default function validReport({ translate }) {
|
||||
return {
|
||||
formSchema: {
|
||||
reasonCategory: {
|
||||
type: 'object',
|
||||
required: true,
|
||||
fields: {
|
||||
value: {
|
||||
type: 'enum',
|
||||
enum: valuesReasonCategoryOptions,
|
||||
required: true,
|
||||
message: translate('report.reason.category.invalid'),
|
||||
},
|
||||
},
|
||||
},
|
||||
reasonDescription: {
|
||||
type: 'string',
|
||||
min: 0,
|
||||
max: 200,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
36
webapp/components/utils/ReportModal.spec.js
Normal file
36
webapp/components/utils/ReportModal.spec.js
Normal file
@ -0,0 +1,36 @@
|
||||
import validReport from './ReportModal'
|
||||
import Schema from 'async-validator'
|
||||
|
||||
let translate
|
||||
|
||||
beforeEach(() => {
|
||||
translate = jest.fn(() => 'Validation error')
|
||||
})
|
||||
|
||||
describe('validReport', () => {
|
||||
let validate = object => {
|
||||
const { formSchema } = validReport({ translate })
|
||||
const validator = new Schema(formSchema)
|
||||
return validator.validate(object, { suppressWarning: true }).catch(({ errors }) => {
|
||||
throw new Error(errors[0].message)
|
||||
})
|
||||
}
|
||||
|
||||
describe('reasonCategory', () => {
|
||||
describe('invalid enum', () => {
|
||||
it('rejects', async () => {
|
||||
await expect(validate({ reasonCategory: { value: 'invalid_enum' } })).rejects.toThrow(
|
||||
'Validation error',
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('valid enum', () => {
|
||||
it('resolves', async () => {
|
||||
await expect(
|
||||
validate({ reasonCategory: { value: 'discrimination_etc' } }),
|
||||
).resolves.toBeUndefined()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
11
webapp/constants/modals.js
Normal file
11
webapp/constants/modals.js
Normal file
@ -0,0 +1,11 @@
|
||||
// this list equals to enums in GraphQL schema file "backend/src/schema/types/type/REPORTED.gql"
|
||||
export const valuesReasonCategoryOptions = [
|
||||
'discrimination_etc',
|
||||
'pornographic_content_links',
|
||||
'glorific_trivia_of_cruel_inhuman_acts',
|
||||
'doxing',
|
||||
'intentional_intimidation_stalking_persecution',
|
||||
'advert_products_services_commercial',
|
||||
'criminal_behavior_violation_german_law',
|
||||
'other',
|
||||
]
|
||||
@ -507,7 +507,8 @@
|
||||
"advert_products_services_commercial": "Bewerben von Produkten und Dienstleistungen mit kommerzieller Absicht.",
|
||||
"criminal_behavior_violation_german_law": "Strafbares Verhalten bzw. Verstoß gegen deutsches Recht.",
|
||||
"other": "Andere …"
|
||||
}
|
||||
},
|
||||
"invalid": "Bitte wählen Sie eine gültige Kategorie aus"
|
||||
},
|
||||
"description": {
|
||||
"label": "Bitte erkläre: Warum möchtest du dies melden?",
|
||||
|
||||
@ -508,7 +508,8 @@
|
||||
"advert_products_services_commercial": "Advertising products and services with commercial intent.",
|
||||
"criminal_behavior_violation_german_law": "Criminal behavior or violation of German law.",
|
||||
"other": "Other …"
|
||||
}
|
||||
},
|
||||
"invalid": "Please select a valid category"
|
||||
},
|
||||
"description": {
|
||||
"label": "Please explain: Why you like to report this?",
|
||||
|
||||
@ -67,7 +67,7 @@
|
||||
<template slot="reasonCategory" slot-scope="scope">
|
||||
{{ $t('report.reason.category.options.' + scope.row.reasonCategory) }}
|
||||
</template>
|
||||
<!-- reasonCategory -->
|
||||
<!-- reasonDescription -->
|
||||
<template slot="reasonDescription" slot-scope="scope">
|
||||
{{ scope.row.reasonDescription }}
|
||||
</template>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user