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

Commit

Permalink
Await fetching related media in the single result store (#1349)
Browse files Browse the repository at this point in the history
* Await fetching related media in the single result store

* Fix fetching related media both on the server and on the client

* Simplify typing hacks

* Stop showing 'Load more' button in the related images
  • Loading branch information
obulat authored May 4, 2022
1 parent 5e72fd4 commit 9b43fcc
Show file tree
Hide file tree
Showing 7 changed files with 182 additions and 128 deletions.
2 changes: 1 addition & 1 deletion src/components/VImageDetails/VRelatedImages.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
</h3>
<VImageGrid
:images="media"
:can-load-more="false"
:show-load-more="false"
:fetch-state="fetchState"
/>
</aside>
Expand Down
12 changes: 6 additions & 6 deletions src/components/VImageGrid/VImageGrid.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<h5 v-if="isError && !fetchState.isFinished" class="py-4">
{{ fetchState.fetchingError }}
</h5>
<footer class="pt-4">
<footer v-if="showLoadMore" class="pt-4">
<VLoadMore />
</footer>
</section>
Expand All @@ -34,7 +34,11 @@ export default {
images: {
default: () => [],
},
canLoadMore: {
/**
* Whether to show the 'Load More' button.
* Is false for related images
*/
showLoadMore: {
type: Boolean,
default: true,
},
Expand All @@ -47,10 +51,6 @@ export default {
isError() {
return !!this.fetchState.fetchingError
},
fetchingErrorHeading() {
const type = this.$t('browse-page.search-form.image')
return this.$t('browse-page.fetching-error', { type })
},
},
methods: {
onLoadMore() {
Expand Down
7 changes: 3 additions & 4 deletions src/locales/po-files/openverse.pot
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Openverse \n"
"Report-Msgid-Bugs-To: https://github.com/wordpress/openverse/issues \n"
"POT-Creation-Date: 2022-05-03T05:46:51+00:00\n"
"POT-Creation-Date: 2022-05-03T16:18:32+00:00\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
Expand Down Expand Up @@ -797,7 +797,6 @@ msgctxt "browse-page.search-form.placeholder"
msgid "Search all ###type###"
msgstr ""

#: src/components/VImageGrid/VImageGrid.vue:51
msgctxt "browse-page.search-form.image"
msgid "images"
msgstr ""
Expand Down Expand Up @@ -1120,13 +1119,13 @@ msgid "An error occurred"
msgstr ""

#. Do not translate words between ### ###.
#: src/pages/image/_id.vue:142
#: src/pages/image/_id.vue:195
msgctxt "error.image-not-found"
msgid "Couldn't find image with id ###id###"
msgstr ""

#. Do not translate words between ### ###.
#: src/pages/audio/_id.vue:71
#: src/pages/audio/_id.vue:84
msgctxt "error.media-not-found"
msgid "Couldn't find ###mediaType### with id ###id###"
msgstr ""
Expand Down
60 changes: 33 additions & 27 deletions src/pages/audio/_id.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@
</main>
</template>

<script>
import { computed } from '@nuxtjs/composition-api'
<script lang="ts">
import { computed, defineComponent } from '@nuxtjs/composition-api'
import { AUDIO } from '~/constants/media'
import type { AudioDetail } from '~/models/media'
import { useRelatedMediaStore } from '~/stores/media/related-media'
import { useSingleResultStore } from '~/stores/media/single-result'
Expand All @@ -32,7 +32,9 @@ import VBackToSearchResultsLink from '~/components/VBackToSearchResultsLink.vue'
import VRelatedAudio from '~/components/VAudioDetails/VRelatedAudio.vue'
import VMediaReuse from '~/components/VMediaInfo/VMediaReuse.vue'
const AudioDetailPage = {
import type { NuxtApp } from '@nuxt/types/app'
export default defineComponent({
name: 'AudioDetailPage',
components: {
VAudioDetails,
Expand All @@ -41,30 +43,41 @@ const AudioDetailPage = {
VMediaReuse,
VRelatedAudio,
},
data() {
return {
backToSearchPath: '',
}
beforeRouteEnter(to, from, nextPage) {
nextPage((_this) => {
// `_this` is the component instance that also has nuxt app properties injected
const localeRoute = (_this as NuxtApp).localeRoute
if (
from.name === localeRoute({ path: '/search/' }).name ||
from.name === localeRoute({ path: '/search/audio' }).name
) {
// I don't know how to type `_this` here
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
_this.backToSearchPath = from.fullPath
}
})
},
setup() {
const singleResultStore = useSingleResultStore()
const relatedMediaStore = useRelatedMediaStore()
const audio = computed(() =>
singleResultStore.mediaType === AUDIO
? (singleResultStore.mediaItem as AudioDetail)
: null
)
const relatedMedia = computed(() => relatedMediaStore.media)
const relatedFetchState = computed(() => relatedMediaStore.fetchState)
return { relatedMedia, relatedFetchState }
return { audio, relatedMedia, relatedFetchState }
},
async asyncData({ route, error, app, $pinia }) {
const audioId = route.params.id
const singleResultStore = useSingleResultStore($pinia)
try {
await singleResultStore.fetchMediaItem(AUDIO, audioId)
const audio = singleResultStore.mediaItem
return {
audio,
}
await singleResultStore.fetch(AUDIO, audioId)
} catch (err) {
error({
statusCode: 404,
Expand All @@ -75,15 +88,10 @@ const AudioDetailPage = {
})
}
},
beforeRouteEnter(to, from, nextPage) {
nextPage((_this) => {
if (
from.name === _this.localeRoute({ path: '/search/' }).name ||
from.name === _this.localeRoute({ path: '/search/audio' }).name
) {
_this.backToSearchPath = from.fullPath
}
})
data() {
return {
backToSearchPath: '',
}
},
head() {
const title = this.audio.title
Expand All @@ -98,9 +106,7 @@ const AudioDetailPage = {
],
}
},
}
export default AudioDetailPage
})
</script>
<style>
.audio-page {
Expand Down
149 changes: 86 additions & 63 deletions src/pages/image/_id.vue
Original file line number Diff line number Diff line change
Expand Up @@ -73,14 +73,15 @@
</div>
</template>

<script>
<script lang="ts">
import axios from 'axios'
import { computed } from '@nuxtjs/composition-api'
import { computed, defineComponent, ref } from '@nuxtjs/composition-api'
import { IMAGE } from '~/constants/media'
import { useSingleResultStore } from '~/stores/media/single-result'
import { useRelatedMediaStore } from '~/stores/media/related-media'
import type { ImageDetail } from '~/models/media'
import VButton from '~/components/VButton.vue'
import VLink from '~/components/VLink.vue'
Expand All @@ -90,7 +91,9 @@ import VRelatedImages from '~/components/VImageDetails/VRelatedImages.vue'
import SketchFabViewer from '~/components/SketchFabViewer.vue'
import VBackToSearchResultsLink from '~/components/VBackToSearchResultsLink.vue'
const VImageDetailsPage = {
import type { NuxtApp } from '@nuxt/types/app'
export default defineComponent({
name: 'VImageDetailsPage',
components: {
VButton,
Expand All @@ -101,85 +104,107 @@ const VImageDetailsPage = {
SketchFabViewer,
VBackToSearchResultsLink,
},
data() {
return {
imageWidth: 0,
imageHeight: 0,
imageType: 'Unknown',
isLoadingFullImage: true,
backToSearchPath: '',
sketchFabfailure: false,
}
beforeRouteEnter(_to, from, nextPage) {
nextPage((_this) => {
// `_this` is the component instance that also has nuxt app properties injected
const localeRoute = (_this as NuxtApp).localeRoute
if (
from.name === localeRoute({ path: '/search/' })?.name ||
from.name === localeRoute({ path: '/search/image' })?.name
) {
// I don't know how to type `this` here
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
_this.backToSearchPath = from.fullPath
}
})
},
setup() {
const singleResultStore = useSingleResultStore()
const relatedMediaStore = useRelatedMediaStore()
const image = computed(() =>
singleResultStore.mediaType === IMAGE
? (singleResultStore.mediaItem as ImageDetail)
: null
)
const relatedMedia = computed(() => relatedMediaStore.media)
const relatedFetchState = computed(() => relatedMediaStore.fetchState)
return { relatedMedia, relatedFetchState }
},
computed: {
sketchFabUid() {
if (this.image?.source !== 'sketchfab' || this.sketchFabfailure) {
const imageWidth = ref(0)
const imageHeight = ref(0)
const imageType = ref('Unknown')
const isLoadingFullImage = ref(true)
const sketchFabfailure = ref(false)
const sketchFabUid = computed(() => {
if (image.value?.source !== 'sketchfab' || sketchFabfailure.value) {
return null
}
return this.image.url
return image.value.url
.split('https://media.sketchfab.com/models/')[1]
.split('/')[0]
},
})
const onImageLoaded = (event: Event) => {
if (!(event.target instanceof HTMLImageElement)) {
return
}
imageWidth.value = image.value?.width || event.target.naturalWidth
imageHeight.value = image.value?.height || event.target.naturalHeight
if (image.value?.filetype) {
imageType.value = image.value.filetype
} else {
if (event.target) {
axios
.head(event.target.src)
.then((res) => {
imageType.value = res.headers['content-type']
})
.catch(() => {
/**
* Do nothing. This avoid the console warning "Uncaught (in promise) Error:
* Network Error" in Firefox in development mode.
*/
})
}
}
isLoadingFullImage.value = false
}
return {
image,
relatedMedia,
relatedFetchState,
imageWidth,
imageHeight,
imageType,
isLoadingFullImage,
sketchFabfailure,
sketchFabUid,
onImageLoaded,
}
},
async asyncData({ app, error, route, $pinia }) {
const imageId = route.params.id
const singleResultStore = useSingleResultStore($pinia)
try {
await singleResultStore.fetchMediaItem(IMAGE, imageId)
const image = singleResultStore.mediaItem
return {
image,
}
await singleResultStore.fetch(IMAGE, imageId)
} catch (err) {
const errorMessage = app.i18n.t('error.image-not-found', {
id: imageId,
})
error({
const errorMessage = app.i18n
.t('error.image-not-found', {
id: imageId,
})
.toString()
return error({
statusCode: 404,
message: errorMessage,
})
}
},
beforeRouteEnter(to, from, nextPage) {
nextPage((_this) => {
if (
from.name === _this.localeRoute({ path: '/search/' }).name ||
from.name === _this.localeRoute({ path: '/search/image' }).name
) {
_this.backToSearchPath = from.fullPath
}
})
},
methods: {
onImageLoaded(event) {
this.imageWidth = this.image.width || event.target.naturalWidth
this.imageHeight = this.image.height || event.target.naturalHeight
if (this.image.filetype) {
this.imageType = this.image.filetype
} else {
axios
.head(event.target.src)
.then((res) => {
this.imageType = res.headers['content-type']
})
.catch(() => {
/**
* Do nothing. This avoids the console warning "Uncaught (in promise) Error:
* Network Error" in Firefox in development mode.
*/
})
}
this.isLoadingFullImage = false
},
},
data: () => ({
backToSearchPath: '',
}),
head() {
const title = `${this.image.title} | Openverse`
Expand All @@ -204,9 +229,7 @@ const VImageDetailsPage = {
],
}
},
}
export default VImageDetailsPage
})
</script>

<style scoped>
Expand Down
Loading

0 comments on commit 9b43fcc

Please sign in to comment.