Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.

Commit 5cc64a0

Browse files
zackkridaobulat
andauthored
Image reporting view (#2090)
Co-authored-by: Olga Bulat <[email protected]>
1 parent 93f5785 commit 5cc64a0

File tree

7 files changed

+123
-2
lines changed

7 files changed

+123
-2
lines changed

src/components/VContentReport/VContentReportForm.vue

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<template>
2-
<div id="content-report-form" class="w-80 p-6">
2+
<div id="content-report-form">
33
<div v-if="status === SENT">
44
<p class="heading-6 mb-4">
55
{{ $t("media-details.content-report.success.title") }}
@@ -76,7 +76,11 @@
7676
</div>
7777

7878
<div class="flex flex-row items-center justify-end gap-4">
79-
<VButton variant="secondary-bordered" @click="handleCancel">
79+
<VButton
80+
v-if="allowCancel"
81+
variant="secondary-bordered"
82+
@click="handleCancel"
83+
>
8084
{{ $t("media-details.content-report.form.cancel") }}
8185
</VButton>
8286

@@ -146,6 +150,7 @@ export default defineComponent({
146150
providerName: { required: true },
147151
reportService: { required: false },
148152
closeFn: { required: true },
153+
allowCancel: { type: Boolean, default: true },
149154
},
150155
setup(props) {
151156
const service = props.reportService || ReportService

src/components/VContentReport/VContentReportPopover.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
@click="close"
1818
/>
1919
<VContentReportForm
20+
class="w-80 p-6"
2021
:close-fn="close"
2122
:media="media"
2223
:provider-name="media.providerName"

src/composables/use-match-routes.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,12 @@ export const useMatchSingleResultRoutes = () => {
6161
.filter((name) => name !== ALL_MEDIA)
6262
.map((name) => `${name}-id`),
6363
]
64+
// @TODO Switch to more generic implementation once
65+
// an Audio reporting page is designed.
66+
//
67+
// routes = routes.concat(routes.map((name) => `${name}-report`))
68+
routes.push("image-id-report")
69+
6470
return useMatchRoute(routes)
6571
}
6672

src/locales/scripts/en.json5

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -713,4 +713,7 @@
713713
none: "No recent searches to show.",
714714
disclaimer: "Openverse does not store your recent searches, this information is kept locally in your browser.",
715715
},
716+
report: {
717+
"image-details": "See image details",
718+
},
716719
}
File renamed without changes.
File renamed without changes.

src/pages/image/_id/report.vue

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
<template>
2+
<div
3+
class="mx-auto mt-8 mb-6 max-w-none gap-x-10 px-4 md:grid md:max-w-4xl md:grid-cols-2 md:px-6 lg:mb-30 lg:px-0 xl:max-w-4xl"
4+
>
5+
<figure class="mb-6 flex flex-col items-start gap-y-4">
6+
<img
7+
id="main-image"
8+
:src="imageSrc"
9+
:alt="image.title"
10+
class="mx-auto h-auto w-full rounded-sm"
11+
:width="imageWidth"
12+
:height="imageHeight"
13+
/>
14+
<!-- Disable reason: We control the attribution HTML generation so this is safe and will not lead to XSS attacks -->
15+
<!-- eslint-disable vue/no-v-html -->
16+
<caption
17+
class="block w-full text-left text-sr"
18+
v-html="getAttributionMarkup({ includeIcons: false })"
19+
/>
20+
<!-- eslint-enable vue/no-v-html -->
21+
<VButton
22+
variant="secondary-bordered"
23+
:href="`/image/${image.id}`"
24+
as="VLink"
25+
size="disabled"
26+
class="p-2 text-sr text-dark-charcoal"
27+
>
28+
{{ $t("report.image-details") }}
29+
</VButton>
30+
</figure>
31+
32+
<VContentReportForm
33+
:close-fn="() => {}"
34+
:media="image"
35+
:allow-cancel="false"
36+
:provider-name="image.providerName"
37+
/>
38+
</div>
39+
</template>
40+
41+
<script lang="ts">
42+
import { defineComponent, ref, computed } from "@nuxtjs/composition-api"
43+
44+
import { useI18n } from "~/composables/use-i18n"
45+
46+
import { IMAGE } from "~/constants/media"
47+
48+
import { useSingleResultStore } from "~/stores/media/single-result"
49+
import type { ImageDetail } from "~/types/media"
50+
import { AttributionOptions, getAttribution } from "~/utils/attribution-html"
51+
52+
import VButton from "~/components/VButton.vue"
53+
54+
export default defineComponent({
55+
name: "ReportImage",
56+
components: {
57+
VButton,
58+
},
59+
setup() {
60+
const i18n = useI18n()
61+
const singleResultStore = useSingleResultStore()
62+
const image = computed(() =>
63+
singleResultStore.mediaType === IMAGE
64+
? (singleResultStore.mediaItem as ImageDetail)
65+
: null
66+
)
67+
const imageWidth = ref(0)
68+
const imageHeight = ref(0)
69+
const imageType = ref("Unknown")
70+
/**
71+
* To make sure that image is loaded fast, we `src` to `image.thumbnail`,
72+
* and then replace it with the provider image once it is loaded.
73+
*/
74+
const imageSrc = ref(image.value.thumbnail)
75+
76+
const getAttributionMarkup = (options?: AttributionOptions) =>
77+
getAttribution(image.value, i18n, options)
78+
79+
return {
80+
image,
81+
imageWidth,
82+
imageHeight,
83+
imageType,
84+
imageSrc,
85+
getAttributionMarkup,
86+
}
87+
},
88+
async asyncData({ app, error, route, $pinia }) {
89+
const imageId = route.params.id
90+
const singleResultStore = useSingleResultStore($pinia)
91+
try {
92+
await singleResultStore.fetch(IMAGE, imageId)
93+
} catch (err) {
94+
const errorMessage = app.i18n
95+
.t("error.image-not-found", {
96+
id: imageId,
97+
})
98+
.toString()
99+
return error({
100+
statusCode: 404,
101+
message: errorMessage,
102+
})
103+
}
104+
},
105+
})
106+
</script>

0 commit comments

Comments
 (0)