Skip to content

Commit

Permalink
Convert the report content popover to a modal (#4701)
Browse files Browse the repository at this point in the history
* Convert the report popover to a modal

Signed-off-by: Olga Bulat <[email protected]>

* Fix the standalone report page heading

Signed-off-by: Olga Bulat <[email protected]>

* Update snapshots

Signed-off-by: Olga Bulat <[email protected]>

* Hover over the filter

Signed-off-by: Olga Bulat <[email protected]>

* Improve the UX for submitting reports

Signed-off-by: Olga Bulat <[email protected]>

* Update the e2e dmca report test

Signed-off-by: Olga Bulat <[email protected]>

* Address the change requests

Signed-off-by: Olga Bulat <[email protected]>

---------

Signed-off-by: Olga Bulat <[email protected]>
  • Loading branch information
obulat authored Aug 21, 2024
1 parent 1c7c2ff commit a200034
Show file tree
Hide file tree
Showing 22 changed files with 235 additions and 207 deletions.
137 changes: 63 additions & 74 deletions frontend/src/components/VContentReport/VContentReportForm.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script setup lang="ts">
import { useRuntimeConfig } from "#imports"
import { useNuxtApp, useRuntimeConfig } from "#imports"
import { computed, ref } from "vue"
Expand All @@ -11,13 +11,12 @@ import {
OTHER,
SENT,
FAILED,
WIP,
DMCA_FORM_URL,
type ReportReason,
type ReportStatus,
} from "~/constants/content-report"
import type { AudioDetail, ImageDetail } from "~/types/media"
import { useAnalytics } from "~/composables/use-analytics"
import { mediaSlug } from "~/utils/query-utils"
Expand All @@ -27,89 +26,86 @@ import VDmcaNotice from "~/components/VContentReport/VDmcaNotice.vue"
import VReportDescForm from "~/components/VContentReport/VReportDescForm.vue"
import VLink from "~/components/VLink.vue"
const props = withDefaults(
defineProps<{
media: AudioDetail | ImageDetail
providerName: string
closeFn: () => void
allowCancel?: boolean
}>(),
{
allowCancel: true,
}
)
const props = defineProps<{
media: AudioDetail | ImageDetail
status: ReportStatus
allowCancel: boolean
}>()
const emit = defineEmits<{
close: []
"update-status": [ReportStatus]
}>()
const selectedReason = ref<ReportReason>(DMCA)
const description = ref("")
const status = ref<string | null>(WIP)
const resetForm = () => {
selectedReason.value = DMCA
description.value = ""
}
const selectedReason = ref<ReportReason>(DMCA)
const reportUrl = computed(() => {
const apiUrl = useRuntimeConfig().public.apiUrl
return `${apiUrl}v1/${mediaSlug(props.media.frontendMediaType)}/${props.media.id}/report/`
})
const dmcaFormUrl = computed(
() =>
`${DMCA_FORM_URL}?entry.917669540=https://openverse.org/${props.media.frontendMediaType}/${props.media.id}`
)
/* Buttons */
const handleCancel = () => {
selectedReason.value = DMCA
description.value = ""
props.closeFn()
resetForm()
emit("close")
}
const isSubmitDisabled = computed(
() => selectedReason.value === OTHER && description.value.length < 20
)
const { sendCustomEvent } = useAnalytics()
const { $sendCustomEvent } = useNuxtApp()
const handleDmcaSubmit = () => {
sendCustomEvent("REPORT_MEDIA", {
id: props.media.id,
mediaType: props.media.frontendMediaType,
provider: props.media.provider,
reason: selectedReason.value,
})
status.value = SENT
updateStatus(SENT)
}
const handleSubmit = async (event: Event) => {
event.preventDefault()
// Submit report
try {
const mediaType = props.media.frontendMediaType
const reason = selectedReason.value
const {
public: { apiUrl },
} = useRuntimeConfig()
await ofetch(
`${apiUrl}v1/${mediaSlug(mediaType)}/${props.media.id}/report/`,
{
method: "POST",
body: {
mediaType,
reason,
identifier: props.media.id,
description: description.value,
},
}
)
sendCustomEvent("REPORT_MEDIA", {
mediaType,
reason,
await ofetch(reportUrl.value, {
method: "POST",
body: {
mediaType: props.media.frontendMediaType,
reason: selectedReason.value,
identifier: props.media.id,
description: description.value,
},
})
updateStatus(SENT)
} catch (error) {
updateStatus(FAILED)
}
}
const updateStatus = (newStatus: ReportStatus) => {
if (newStatus === SENT) {
$sendCustomEvent("REPORT_MEDIA", {
id: props.media.id,
mediaType: props.media.frontendMediaType,
provider: props.media.provider,
reason: selectedReason.value,
})
status.value = SENT
} catch (error) {
status.value = FAILED
}
emit("update-status", newStatus)
}
defineExpose({ resetForm })
</script>

<template>
<div id="content-report-form">
<div v-if="status === SENT">
<h2 class="heading-6 mb-4">
{{ $t("mediaDetails.contentReport.success.title") }}
</h2>
<i18n-t
scope="global"
keypath="mediaDetails.contentReport.success.note"
Expand All @@ -120,37 +116,30 @@ const handleSubmit = async (event: Event) => {
<VLink
:href="media.foreign_landing_url"
class="text-link hover:underline"
>{{ providerName }}</VLink
>{{ media.providerName }}</VLink
>
</template>
</i18n-t>
</div>

<div v-else-if="status === FAILED">
<h2 class="heading-6 mb-4">
{{ $t("mediaDetails.contentReport.failure.title") }}
</h2>
<p class="text-sm">
{{ $t("mediaDetails.contentReport.failure.note") }}
</p>
</div>

<!-- Main form -->
<div v-else>
<div class="heading-6 mb-4">
{{ $t("mediaDetails.contentReport.long") }}
</div>

<p class="mb-4 text-sm">
<p class="mb-4 text-sm leading-normal">
{{
$t("mediaDetails.contentReport.form.disclaimer", {
openverse: "Openverse",
})
}}
</p>

<form class="text-sm" @submit="handleSubmit">
<fieldset class="flex flex-col">
<form class="flex flex-col gap-y-4 text-sm" @submit="handleSubmit">
<fieldset class="flex flex-col gap-y-4">
<legend class="label-bold mb-4">
{{ $t("mediaDetails.contentReport.form.question") }}
</legend>
Expand All @@ -159,23 +148,22 @@ const handleSubmit = async (event: Event) => {
:id="reason"
:key="reason"
v-model="selectedReason"
class="mb-4"
name="reason"
:value="reason"
>
{{ $t(`mediaDetails.contentReport.form.${reason}.option`) }}
</VRadio>
</fieldset>

<div class="mb-4 min-h-[7rem]">
<div class="leading-normal">
<VDmcaNotice
v-if="media.foreign_landing_url && selectedReason === DMCA"
:provider="providerName"
v-if="selectedReason === DMCA"
:provider="media.providerName"
:foreign-landing-url="media.foreign_landing_url"
@click="handleDmcaSubmit"
/>
<VReportDescForm
v-if="selectedReason !== DMCA"
v-else
key="other"
v-model:content="description"
:reason="selectedReason"
Expand Down Expand Up @@ -204,8 +192,9 @@ const handleSubmit = async (event: Event) => {
has-icon-end
show-external-icon
:external-icon-size="6"
:href="DMCA_FORM_URL"
:href="dmcaFormUrl"
:send-external-link-click-event="false"
target="_blank"
@click="handleDmcaSubmit"
>
{{ $t("mediaDetails.contentReport.form.dmca.open") }}
Expand Down
64 changes: 64 additions & 0 deletions frontend/src/components/VContentReport/VContentReportModal.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<script setup lang="ts">
import { ref } from "vue"
import { WIP } from "~/constants/content-report"
import { useContentReport } from "~/composables/use-content-report"
import type { AudioDetail, ImageDetail } from "~/types/media"
import VContentReportButton from "~/components/VContentReport/VContentReportButton.vue"
import VContentReportForm from "~/components/VContentReport/VContentReportForm.vue"
import VModal from "~/components/VModal/VModal.vue"
defineProps<{
/**
* The media item to report. This can either be an audio track or an image.
*/
media: AudioDetail | ImageDetail
}>()
const modalRef = ref<InstanceType<typeof VModal> | null>(null)
const contentReportFormRef = ref<InstanceType<
typeof VContentReportForm
> | null>(null)
const { status, updateStatus, title } = useContentReport()
const resetForm = () => {
contentReportFormRef.value?.resetForm()
updateStatus(WIP)
}
const close = () => {
resetForm()
modalRef.value?.close()
}
</script>

<template>
<VModal
ref="modalRef"
:label="$t('mediaDetails.contentReport.long')"
:hide-on-click-outside="true"
variant="centered"
@close="resetForm"
>
<template #trigger="{ a11yProps }">
<VContentReportButton v-bind="a11yProps" />
</template>
<template #title>
<h2 class="heading-6" tabindex="-1">{{ title }}</h2>
</template>
<template #default>
<VContentReportForm
ref="contentReportFormRef"
class="p-7 pt-0 sm:p-9"
:media="media"
:status="status"
:allow-cancel="true"
@update-status="updateStatus"
@close="close"
>
</VContentReportForm>
</template>
</VModal>
</template>
60 changes: 0 additions & 60 deletions frontend/src/components/VContentReport/VContentReportPopover.vue

This file was deleted.

2 changes: 1 addition & 1 deletion frontend/src/components/VContentReport/VDmcaNotice.vue
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export default defineComponent({
<template>
<i18n-t
scope="global"
class="dmca-notice"
class="dmca-notice leading-normal"
keypath="mediaDetails.contentReport.form.dmca.note"
tag="p"
>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/VContentReport/VReportDescForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export default defineComponent({
</script>

<template>
<label class="other-form block" for="description">
<label class="other-form min-h-[7rem]" for="description">
<span class="flex flex-row items-center justify-between">
<span>{{ $t("mediaDetails.contentReport.form.other.note") }}</span>
<span>{{
Expand Down
Loading

0 comments on commit a200034

Please sign in to comment.