Skip to content

Commit

Permalink
Fix search results fetching and error handling
Browse files Browse the repository at this point in the history
  • Loading branch information
obulat committed Jul 17, 2023
1 parent 94ace66 commit ced64dd
Show file tree
Hide file tree
Showing 19 changed files with 221 additions and 268 deletions.
21 changes: 12 additions & 9 deletions frontend/src/components/VSearchGrid.vue
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
<template>
<section
v-if="
!fetchState.hasStarted ||
fetchState.isFetching ||
(!fetchState.isFetching && resultsCount)
"
>
<section v-if="!showError">
<header v-if="query.q && supported" class="my-0 md:mb-8 md:mt-4">
<VSearchResultsTitle :size="isAllView ? 'large' : 'default'">
{{ searchTerm }}
Expand Down Expand Up @@ -40,9 +34,9 @@ import { computed, defineComponent, PropType } from "vue"
import {
ALL_MEDIA,
IMAGE,
SearchType,
isSupportedMediaType,
isAdditionalSearchType,
isSupportedMediaType,
SearchType,
} from "~/constants/media"
import { NO_RESULT } from "~/constants/errors"
import { defineEvent } from "~/types/emits"
Expand Down Expand Up @@ -129,13 +123,22 @@ export default defineComponent({
const searchTerm = computed(() => props.query.q || "")
const showError = computed(() => {
return (
props.fetchState.hasStarted &&
!props.fetchState.isFetching &&
props.resultsCount === 0
)
})
return {
hasNoResults,
externalSourcesType,
isAllView,
NO_RESULT,
externalSources,
searchTerm,
showError,
}
},
})
Expand Down
38 changes: 29 additions & 9 deletions frontend/src/middleware/search.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
import { useSearchStore } from "~/stores/search"

import { useMediaStore } from "~/stores/media"

import type { Middleware } from "@nuxt/types"

export const searchMiddleware: Middleware = ({ redirect, route, $pinia }) => {
export const searchMiddleware: Middleware = async ({
redirect,
route,
$pinia,
error: nuxtError,
}) => {
const {
query: { q },
query: { q: rawQ },
} = route
const q = Array.isArray(rawQ) ? rawQ[0] : rawQ

/**
* This middleware redirects any search without a query to the homepage.
* This is meant to block direct access to /search and all sub-routes.
Expand All @@ -19,13 +28,24 @@ export const searchMiddleware: Middleware = ({ redirect, route, $pinia }) => {
* Note that the search by creator is not displayed in the UI.
*/
if (!q) return redirect("/")
/**
* We need to make sure that query `q` exists before checking if it matches
* the store searchTerm.
*/

const searchStore = useSearchStore($pinia)
const querySearchTerm = Array.isArray(q) ? q[0] : q
if (querySearchTerm !== searchStore.searchTerm) {
searchStore.setSearchTerm(querySearchTerm)

await searchStore.initProviderFilters()

searchStore.setSearchStateFromUrl({
path: route.path,
urlQuery: route.query,
})

// Fetch results before rendering the page on the server.
if (process.server) {
const mediaStore = useMediaStore($pinia)
const results = await mediaStore.fetchMedia()

const fetchingError = mediaStore.fetchState.fetchingError
if (!results && fetchingError && fetchingError?.statusCode !== 404) {
nuxtError(fetchingError)
}
}
}
38 changes: 24 additions & 14 deletions frontend/src/pages/search.vue
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,12 @@
import { isShallowEqualObjects } from "@wordpress/is-shallow-equal"
import { computed, inject, watch } from "vue"
import { storeToRefs } from "pinia"
import { defineComponent, useMeta, useRoute } from "@nuxtjs/composition-api"
import {
defineComponent,
useContext,
useMeta,
useRoute,
} from "@nuxtjs/composition-api"
import { searchMiddleware } from "~/middleware/search"
import { useMediaStore } from "~/stores/media"
Expand All @@ -54,6 +59,7 @@ export default defineComponent({
},
layout: "search-layout",
middleware: searchMiddleware,
fetchOnServer: false,
setup() {
const showScrollButton = inject(ShowScrollButtonKey)
const isSidebarVisible = inject(IsSidebarVisibleKey)
Expand Down Expand Up @@ -89,10 +95,26 @@ export default defineComponent({
meta: [{ hid: "robots", name: "robots", content: "all" }],
})
const { error: nuxtError } = useContext()
const fetchMedia = async (
payload: { shouldPersistMedia?: boolean } = {}
) => {
return mediaStore.fetchMedia(payload)
/**
* If the fetch has already started in the middleware and there is an error,
* don't re-fetch.
*/
if (
mediaStore.fetchState.fetchingError?.statusCode &&
mediaStore.fetchState.hasStarted
)
return
const results = await mediaStore.fetchMedia(payload)
if (!results) {
const errorStatus = mediaStore.fetchState.fetchingError?.statusCode
if (errorStatus !== 404)
return nuxtError(mediaStore.fetchState.fetchingError)
}
}
watch(route, async (newRoute, oldRoute) => {
Expand Down Expand Up @@ -130,18 +152,6 @@ export default defineComponent({
fetchMedia,
}
},
/**
* asyncData blocks the rendering of the page, so we only
* update the state from the route here, and do not fetch media.
*/
async asyncData({ route, $pinia }) {
const searchStore = useSearchStore($pinia)
await searchStore.initProviderFilters()
searchStore.setSearchStateFromUrl({
path: route.path,
urlQuery: route.query,
})
},
/**
* Fetch media, if necessary, in a non-blocking way.
*/
Expand Down
Loading

0 comments on commit ced64dd

Please sign in to comment.