feat: Report posts (#2184)
This commit is contained in:
parent
5ea09d323f
commit
34aca66fef
8 changed files with 462 additions and 70 deletions
266
components/report/ReportModal.vue
Normal file
266
components/report/ReportModal.vue
Normal file
|
@ -0,0 +1,266 @@
|
|||
<script setup lang="ts">
|
||||
import type { mastodon } from 'masto'
|
||||
import { toggleBlockAccount, toggleFollowAccount, toggleMuteAccount, useRelationship } from '~~/composables/masto/relationship'
|
||||
|
||||
const { account, status } = defineProps<{
|
||||
account: mastodon.v1.Account
|
||||
status?: mastodon.v1.Status
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(event: 'close'): void
|
||||
}>()
|
||||
|
||||
const { client } = useMasto()
|
||||
|
||||
const step = ref('selectCategory')
|
||||
const serverRules = ref((await client.value.v2.instance.fetch()).rules || [])
|
||||
const reportReason = ref('')
|
||||
const selectedRuleIds = ref([])
|
||||
const availableStatuses = ref(status ? [status] : [])
|
||||
const selectedStatusIds = ref(status ? [status.id] : [])
|
||||
const additionalComments = ref('')
|
||||
const forwardReport = ref(false)
|
||||
|
||||
const dismissButton = ref<HTMLDivElement>()
|
||||
|
||||
loadStatuses() // Load statuses asynchronously ahead of time
|
||||
|
||||
function categoryChosen() {
|
||||
step.value = reportReason.value === 'dontlike' ? 'furtherActions' : 'selectStatuses'
|
||||
resetModal()
|
||||
}
|
||||
|
||||
async function loadStatuses() {
|
||||
if (status) {
|
||||
// Load the 5 statuses before and after the reported status
|
||||
const prevStatuses = await client.value.v1.accounts.listStatuses(account.id, {
|
||||
maxId: status.id,
|
||||
limit: 5,
|
||||
})
|
||||
const nextStatuses = await client.value.v1.accounts.listStatuses(account.id, {
|
||||
minId: status.id,
|
||||
limit: 5,
|
||||
})
|
||||
availableStatuses.value = availableStatuses.value.concat(prevStatuses)
|
||||
availableStatuses.value = availableStatuses.value.concat(nextStatuses)
|
||||
}
|
||||
else {
|
||||
// Reporting an account directly
|
||||
// Load the 10 most recent statuses
|
||||
const mostRecentStatuses = await client.value.v1.accounts.listStatuses(account.id, {
|
||||
limit: 10,
|
||||
})
|
||||
availableStatuses.value = mostRecentStatuses
|
||||
}
|
||||
availableStatuses.value.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime())
|
||||
}
|
||||
|
||||
async function submitReport() {
|
||||
await client.value.v1.reports.create({
|
||||
accountId: account.id,
|
||||
statusIds: selectedStatusIds.value,
|
||||
comment: additionalComments.value,
|
||||
forward: forwardReport.value,
|
||||
category: reportReason.value === 'spam' ? 'spam' : reportReason.value === 'violation' ? 'violation' : 'other',
|
||||
ruleIds: reportReason.value === 'violation' ? selectedRuleIds.value : null,
|
||||
})
|
||||
step.value = 'furtherActions'
|
||||
resetModal()
|
||||
}
|
||||
|
||||
function unfollow() {
|
||||
emit('close')
|
||||
toggleFollowAccount(useRelationship(account).value!, account)
|
||||
}
|
||||
|
||||
function mute() {
|
||||
emit('close')
|
||||
toggleMuteAccount(useRelationship(account).value!, account)
|
||||
}
|
||||
|
||||
function block() {
|
||||
emit('close')
|
||||
toggleBlockAccount(useRelationship(account).value!, account)
|
||||
}
|
||||
|
||||
function resetModal() {
|
||||
// TODO: extract this scroll/reset logic into ModalDialog element
|
||||
dismissButton.value?.scrollIntoView() // scroll to top
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div my-8 px-3 sm:px-8 flex="~ col gap-4" relative>
|
||||
<h2 mxa text-xl>
|
||||
<i18n-t :keypath="reportReason === 'dontlike' ? 'report.limiting' : 'report.reporting'">
|
||||
<b text-primary>@{{ account.acct }}</b>
|
||||
</i18n-t>
|
||||
</h2>
|
||||
<button ref="dismissButton" btn-action-icon absolute top--8 right-0 m1 aria-label="Close" @click="emit('close')">
|
||||
<div i-ri:close-line />
|
||||
</button>
|
||||
|
||||
<template v-if="step === 'selectCategory'">
|
||||
<h1 mxa text-4xl mb4>
|
||||
{{ status ? $t('report.whats_wrong_post') : $t('report.whats_wrong_account') }}
|
||||
</h1>
|
||||
<p text-xl>
|
||||
{{ $t('report.select_one') }}
|
||||
</p>
|
||||
|
||||
<div>
|
||||
<input id="dontlike" v-model="reportReason" type="radio" value="dontlike">
|
||||
<label pl-2 for="dontlike" font-bold>{{ $t('report.dontlike') }}</label>
|
||||
<p pl-6>
|
||||
{{ $t('report.dontlike_desc') }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<input id="spam" v-model="reportReason" type="radio" value="spam">
|
||||
<label pl-2 for="spam" font-bold>{{ $t('report.spam') }}</label>
|
||||
<p pl-6>
|
||||
{{ $t('report.spam_desc') }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div v-if="serverRules.length > 0">
|
||||
<input id="violation" v-model="reportReason" type="radio" value="violation">
|
||||
<label pl-2 for="violation" font-bold>{{ $t('report.violation') }}</label>
|
||||
<p v-if="reportReason === 'violation'" pl-6 pt-2 text-primary font-bold>
|
||||
{{ $t('report.select_many') }}
|
||||
</p>
|
||||
<ul pl-6>
|
||||
<li v-for="rule in serverRules" :key="rule.id" pt-2>
|
||||
<input
|
||||
:id="rule.id"
|
||||
v-model="selectedRuleIds"
|
||||
type="checkbox"
|
||||
:value="rule.id"
|
||||
:disabled="reportReason !== 'violation'"
|
||||
>
|
||||
<label pl-2 :for="rule.id">{{ rule.text }}</label>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<input id="other" v-model="reportReason" type="radio" value="other">
|
||||
<label pl-2 for="other" font-bold>{{ $t('report.other') }}</label>
|
||||
<p pl-6>
|
||||
{{ $t('report.other_desc') }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div v-if="reportReason && reportReason !== 'dontlike'">
|
||||
<h3 mt-8 mb-4 font-bold>
|
||||
{{ $t('report.anything_else') }}
|
||||
</h3>
|
||||
<textarea v-model="additionalComments" w-full h-20 p-3 border :placeholder="$t('report.additional_comments')" />
|
||||
<div v-if="getServerName(account) && getServerName(account) !== currentServer">
|
||||
<h3 mt-8 mb-2 font-bold>
|
||||
{{ $t('report.another_server') }}
|
||||
</h3>
|
||||
<p pb-1>
|
||||
{{ $t('report.forward_question') }}
|
||||
</p>
|
||||
<input id="forward" v-model="forwardReport" type="checkbox" value="rule.id">
|
||||
<label pl-2 for="forward"><b>{{ $t('report.forward', [getServerName(account)]) }}</b></label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
btn-solid mxa mt-10
|
||||
:disabled="!reportReason || (reportReason === 'violation' && selectedRuleIds.length < 1)"
|
||||
@click="categoryChosen()"
|
||||
>
|
||||
{{ $t('action.next') }}
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<template v-else-if="step === 'selectStatuses'">
|
||||
<h1 mxa text-4xl mb4>
|
||||
{{ status ? $t('report.select_posts_other') : $t('report.select_posts') }}
|
||||
</h1>
|
||||
<p text-primary font-bold>
|
||||
{{ $t('report.select_many') }}
|
||||
</p>
|
||||
<table>
|
||||
<tr v-for="availableStatus in availableStatuses" :key="availableStatus.id">
|
||||
<td>
|
||||
<input
|
||||
:id="availableStatus.id"
|
||||
v-model="selectedStatusIds"
|
||||
type="checkbox"
|
||||
:value="availableStatus.id"
|
||||
>
|
||||
</td>
|
||||
<td>
|
||||
<label :for="availableStatus.id">
|
||||
<StatusCard :status="availableStatus" :actions="false" pointer-events-none />
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<button
|
||||
btn-solid mxa mt-5
|
||||
@click="submitReport()"
|
||||
>
|
||||
{{ $t('report.submit') }}
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<template v-else-if="step === 'furtherActions'">
|
||||
<h1 mxa text-4xl mb4>
|
||||
{{ reportReason === 'dontlike' ? $t('report.further_actions.limit.title') : $t('report.further_actions.report.title') }}
|
||||
</h1>
|
||||
<p text-xl>
|
||||
{{ reportReason === 'dontlike' ? $t('report.further_actions.limit.description') : $t('report.further_actions.report.description') }}
|
||||
</p>
|
||||
|
||||
<div v-if="useRelationship(account).value?.following">
|
||||
<button btn-outline mxa mt-4 mb-2 @click="unfollow()">
|
||||
<i18n-t keypath="menu.unfollow_account">
|
||||
<b>@{{ account.acct }}</b>
|
||||
</i18n-t>
|
||||
</button><br>
|
||||
{{ $t('report.unfollow_desc') }}
|
||||
</div>
|
||||
<div v-if="!useRelationship(account).value?.muting">
|
||||
<button btn-outline mxa mt-4 mb-2 @click="mute()">
|
||||
<i18n-t keypath="menu.mute_account">
|
||||
<b>@{{ account.acct }}</b>
|
||||
</i18n-t>
|
||||
</button><br>
|
||||
{{ $t('report.mute_desc') }}
|
||||
</div>
|
||||
<div v-if="!useRelationship(account).value?.blocking">
|
||||
<button btn-outline mxa mt-4 mb-2 @click="block()">
|
||||
<i18n-t keypath="menu.block_account">
|
||||
<b>@{{ account.acct }}</b>
|
||||
</i18n-t>
|
||||
</button><br>
|
||||
{{ $t('report.block_desc') }}
|
||||
</div>
|
||||
<button btn-solid mxa mt-10 @click="emit('close')">
|
||||
{{ $t('action.done') }}
|
||||
</button>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
tr {
|
||||
border-bottom-width: 1px;
|
||||
}
|
||||
|
||||
tr:last-child {
|
||||
border: none;
|
||||
}
|
||||
|
||||
td {
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
</style>
|
Loading…
Add table
Add a link
Reference in a new issue