Skip to content

Commit

Permalink
Fix loading labels, results, no result on later pages
Browse files Browse the repository at this point in the history
  • Loading branch information
obulat committed Jan 10, 2025
1 parent aa359a0 commit fe145ad
Show file tree
Hide file tree
Showing 13 changed files with 159 additions and 92 deletions.
1 change: 1 addition & 0 deletions frontend/nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export default defineNuxtConfig({
port: 8443,
host: "0.0.0.0",
},
devtools: { enabled: true },
imports: {
autoImport: false,
},
Expand Down
22 changes: 3 additions & 19 deletions frontend/src/components/VContentLink/VContentLink.vue
Original file line number Diff line number Diff line change
@@ -1,43 +1,27 @@
<script setup lang="ts">
import { useNuxtApp } from "#imports"
import { computed } from "vue"
import type { SupportedMediaType } from "#shared/constants/media"
import useSearchType from "~/composables/use-search-type"
import { useHydrating } from "~/composables/use-hydrating"
import { useI18nResultsCount } from "~/composables/use-i18n-utilities"
import VButton from "~/components/VButton.vue"
import VIcon from "~/components/VIcon/VIcon.vue"
const props = defineProps<{
mediaType: SupportedMediaType
/**
* Current search term for aria-label.
*/
searchTerm: string
/**
* The number of results that the search returned. The link
* will be disabled if this value is zero.
*/
resultsCount: number
/**
* The route target of the link.
*/
to?: string
to: string | undefined
resultsAriaLabel: string
resultsCountLabel: string
}>()
defineEmits<{
"shift-tab": [KeyboardEvent]
}>()
const { getI18nCount, getI18nContentLinkLabel } = useI18nResultsCount()
const resultsCountLabel = computed(() => getI18nCount(props.resultsCount))
const resultsAriaLabel = computed(() =>
getI18nContentLinkLabel(props.resultsCount, props.searchTerm, props.mediaType)
)
const { activeType } = useSearchType({ component: "VContentLink" })
const { $sendCustomEvent } = useNuxtApp()
Expand Down
10 changes: 3 additions & 7 deletions frontend/src/components/VLoadMore.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,9 @@ import { useSearchStore } from "~/stores/search"
import VButton from "~/components/VButton.vue"
const props = defineProps<
defineProps<
SingleResultProps & {
searchType: SupportedSearchType
isFetching: boolean
}
>()
Expand Down Expand Up @@ -46,6 +45,7 @@ const eventPayload = computed(() => {
* more results to fetch, we show the button.
*/
const canLoadMore = computed(() => mediaStore.canLoadMore)
const isFetching = computed(() => mediaStore.isFetching)
const reachResultEndEventSent = ref(false)
/**
Expand All @@ -56,10 +56,6 @@ const reachResultEndEventSent = ref(false)
*
*/
const onLoadMore = async () => {
if (props.isFetching) {
return
}
reachResultEndEventSent.value = false
$sendCustomEvent("LOAD_MORE_RESULTS", eventPayload.value)
Expand All @@ -76,7 +72,7 @@ const sendReachResultEnd = () => {
}
const buttonLabel = computed(() =>
props.isFetching ? t("browsePage.loading") : t("browsePage.load")
isFetching.value ? t("browsePage.loading") : t("browsePage.load")
)
const mainPageElement = ref<HTMLElement | null>(null)
onMounted(() => {
Expand Down
18 changes: 15 additions & 3 deletions frontend/src/components/VSearchResultsGrid/VSearchResults.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script setup lang="ts">
import { useI18n } from "#imports"
import { useI18n, useI18nResultsCount } from "#imports"
import { computed } from "vue"
import type { SupportedMediaType } from "#shared/constants/media"
Expand Down Expand Up @@ -33,6 +33,18 @@ const collectionLabel = computed(() => {
const contentLinkPath = (mediaType: SupportedMediaType) =>
searchStore.getSearchPath({ type: mediaType })
const showLoading = computed(() => mediaStore.showLoading)
const { getI18nCount, getI18nContentLinkLabel } =
useI18nResultsCount(showLoading)
const resultsCountLabel = (count: number) => getI18nCount(count)
const resultsAriaLabel = (
count: number,
searchTerm: string,
mediaType: SupportedMediaType
) => getI18nContentLinkLabel(count, searchTerm, mediaType)
const resultCounts = computed(() => mediaStore.resultCountsPerMediaType)
</script>

Expand Down Expand Up @@ -62,9 +74,9 @@ const resultCounts = computed(() => mediaStore.resultCountsPerMediaType)
<VContentLink
v-for="[mediaType, count] in resultCounts"
:key="mediaType"
:results-aria-label="resultsAriaLabel(count, searchTerm, mediaType)"
:results-count-label="resultsCountLabel(count)"
:media-type="mediaType"
:search-term="searchTerm"
:results-count="count"
:to="contentLinkPath(mediaType)"
/>
</div>
Expand Down
13 changes: 11 additions & 2 deletions frontend/src/components/meta/CustomButtonComponents.stories.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { h } from "vue"

import { AUDIO, IMAGE } from "#shared/constants/media"
import { useMediaStore } from "~/stores/media"

import VLoadMore from "~/components/VLoadMore.vue"
Expand All @@ -11,8 +12,16 @@ const Template: Story = {
components: { VLoadMore },
setup() {
const mediaStore = useMediaStore()
mediaStore.results.image.page = 1
mediaStore.results.image.pageCount = 12
mediaStore.results[AUDIO] = {
...mediaStore.results[AUDIO],
page: 1,
pageCount: 12,
}
mediaStore.results[IMAGE] = {
...mediaStore.results[IMAGE],
page: 1,
pageCount: 12,
}
return () =>
h("div", { class: "flex p-4", id: "wrapper" }, [
h(VLoadMore, {
Expand Down
5 changes: 2 additions & 3 deletions frontend/src/composables/use-collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,8 @@ export const useCollection = <T extends SupportedMediaType>({
shouldPersistMedia: false,
}
) => {
media.value = (await mediaStore.fetchMedia({
shouldPersistMedia,
})) as ResultType[]
const results = await mediaStore.fetchMedia({ shouldPersistMedia })
media.value = results.items as ResultType[]
creatorUrl.value =
media.value.length > 0 ? media.value[0].creator_url : undefined
return media.value
Expand Down
15 changes: 14 additions & 1 deletion frontend/src/composables/use-i18n-utilities.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useNuxtApp } from "#imports"
import type { ComputedRef } from "vue"

import { ALL_MEDIA, AUDIO, IMAGE } from "#shared/constants/media"
import type {
Expand Down Expand Up @@ -88,7 +89,7 @@ export function getCountKey(resultsCount: number): keyof KeyCollection {
/**
* Returns the localized text for the number of search results.
*/
export function useI18nResultsCount() {
export function useI18nResultsCount(showLoading?: ComputedRef<boolean>) {
const { t } = useNuxtApp().$i18n
const getLocaleFormattedNumber = useGetLocaleFormattedNumber()

Expand All @@ -98,6 +99,9 @@ export function useI18nResultsCount() {
resultsCount: number,
searchType: SupportedSearchType
) => {
if (showLoading?.value) {
return "header.loading"
}
const countKey = getCountKey(resultsCount)
return searchResultKeys[searchType][countKey]
}
Expand All @@ -111,6 +115,9 @@ export function useI18nResultsCount() {
query: string,
mediaType: SupportedMediaType
) => {
if (showLoading?.value) {
return getLoading()
}
return t(getI18nKey(resultsCount, mediaType), {
count: resultsCount,
localeCount: getLocaleFormattedNumber(resultsCount),
Expand All @@ -124,6 +131,9 @@ export function useI18nResultsCount() {
collectionType: Collection,
params: Record<string, string> | undefined = undefined
) => {
if (showLoading?.value) {
return getLoading()
}
const key =
collectionKeys[collectionType][mediaType][getCountKey(resultCount)]
return t(key, {
Expand All @@ -139,6 +149,9 @@ export function useI18nResultsCount() {
* E.g. "No results", "132 results", "Top 240 results".
*/
const getI18nCount = (resultsCount: number) => {
if (showLoading?.value) {
return getLoading()
}
return t(getI18nKey(resultsCount, ALL_MEDIA), {
count: resultsCount,
localeCount: getLocaleFormattedNumber(resultsCount),
Expand Down
7 changes: 2 additions & 5 deletions frontend/src/composables/use-search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,10 @@ export const useSearch = (
return navigateTo(searchPath)
}

const isFetching = computed(() => mediaStore.isFetching)
const resultsCount = computed(() => mediaStore.resultCount)
const showLoading = computed(() => mediaStore.showLoading)

const { getI18nCount, getLoading } = useI18nResultsCount()
const { getI18nCount } = useI18nResultsCount(showLoading)
/**
* Additional text at the end of the search bar.
* Shows the loading state or result count.
Expand All @@ -85,9 +85,6 @@ export const useSearch = (
if (searchStore.searchTerm === "") {
return ""
}
if (isFetching.value) {
return getLoading()
}
return getI18nCount(resultsCount.value)
})

Expand Down
6 changes: 5 additions & 1 deletion frontend/src/middleware/search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,11 @@ export const searchMiddleware = defineNuxtRouteMiddleware(async (to) => {
const results = await mediaStore.fetchMedia()

const fetchingError = mediaStore.fetchState.error
if (!results.length && fetchingError && !handledClientSide(fetchingError)) {
if (
!results.items.length &&
fetchingError &&
!handledClientSide(fetchingError)
) {
showError(createError(fetchingError))
}
}
Expand Down
31 changes: 15 additions & 16 deletions frontend/src/pages/search.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import { computed, ref, watch } from "vue"
import { watchDebounced } from "@vueuse/core"
import { storeToRefs } from "pinia"
import { ALL_MEDIA } from "#shared/constants/media"
import { skipToContentTargetId } from "#shared/constants/window"
import { areQueriesEqual } from "#shared/utils/search-query-transform"
import { handledClientSide, isRetriable } from "#shared/utils/errors"
Expand Down Expand Up @@ -62,15 +61,7 @@ useHead(() => ({
}))
const searchResults = ref<Results | null>(
isSearchTypeSupported(searchType.value)
? ({
type: searchType.value,
items:
searchType.value === ALL_MEDIA
? mediaStore.allMedia
: mediaStore.resultItems[searchType.value],
} as Results)
: null
isSearchTypeSupported(searchType.value) ? mediaStore.searchResults : null
)
const fetchMedia = async (payload: { shouldPersistMedia?: boolean } = {}) => {
Expand All @@ -82,7 +73,9 @@ const fetchMedia = async (payload: { shouldPersistMedia?: boolean } = {}) => {
* and there is an error status that will not change if retried, don't re-fetch.
*/
const shouldNotRefetch =
fetchingError.value !== null && !isRetriable(fetchingError.value)
mediaStore.fetchState.status !== "idle" &&
fetchingError.value !== null &&
!isRetriable(fetchingError.value)
if (shouldNotRefetch) {
return
}
Expand All @@ -91,9 +84,9 @@ const fetchMedia = async (payload: { shouldPersistMedia?: boolean } = {}) => {
}
const media = await mediaStore.fetchMedia(payload)
searchResults.value = { type: searchType.value, items: media } as Results
if (fetchingError.value === null || handledClientSide(fetchingError.value)) {
if (!fetchingError.value || handledClientSide(fetchingError.value)) {
searchResults.value = media
return media
}
return fetchingError.value
Expand Down Expand Up @@ -135,14 +128,20 @@ await useAsyncData(
*/
document.getElementById("main-page")?.scroll(0, 0)
const res = await fetchMedia()
if (!res || (res && "requestKind" in res)) {
return showError(res ?? createError("No results found"))
if (!res) {
return showError(
createError(
fetchingError.value ?? "Fetch media did not return anything"
)
)
}
if ("requestKind" in res) {
return showError(res)
}
return res
},
{
server: false,
lazy: true,
watch: [shouldFetchSensitiveResults, routeQuery, routePath],
}
)
Expand Down
Loading

0 comments on commit fe145ad

Please sign in to comment.