Skip to content

Commit

Permalink
Add collection page
Browse files Browse the repository at this point in the history
Signed-off-by: Olga Bulat <obulat@gmail.com>
  • Loading branch information
obulat committed Nov 13, 2023
1 parent eb3266f commit 30236b6
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 4 deletions.
90 changes: 90 additions & 0 deletions frontend/src/pages/_mediaType/_collection/_.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
<template>
<div class="px-6 lg:px-10"></div>
</template>

<script lang="ts">
import { defineComponent } from "@nuxtjs/composition-api"
import { useProviderStore } from "~/stores/provider"
import { useSearchStore } from "~/stores/search"
import { isSupportedMediaType, SupportedMediaType } from "~/constants/media"
import type { Collection, CollectionParams } from "~/types/search"
import { useFeatureFlagStore } from "~/stores/feature-flag"
import { warn } from "~/utils/console"
export default defineComponent({
name: "VCollectionPage",
layout: "content-layout",
/**
* Validate the dynamic path parameters.
*
* Shows an error page if `validate` returns `false`.
*
* @param params - the path parameters: `mediaType`, `collection` and `pathMatch` for the rest.
* @param $pinia - passed to update the store with the validated data.
*/
validate({ params, $pinia }): Promise<boolean> | boolean {
// This page is shown only when the feature flag is `on`.
if (!useFeatureFlagStore($pinia).isOn("additional_search_views")) {
return false
}
// Validate media type
if (!isSupportedMediaType(params.mediaType)) {
return false
}
const mediaType = params.mediaType as SupportedMediaType
// Validate collection
// `source` is the second path parameter for both source and creator views.
if (!["tag", "source"].includes(params.collection)) {
return false
}
// Build collection params.
// pathMatch is the part of the path after the collection name:
// `/tagName` or `/sourceName` or `/sourceName/creator/creatorName`.
const pathMatchParts = params.pathMatch
.split("/")
.map((part) => part.trim())
.filter((part) => part !== "")
// The path parts must be either ["tagName"], ["sourceName"] or ["sourceName", "creator", "creatorName"].
let collection: Collection
let collectionParams: CollectionParams
if (pathMatchParts.length === 1 && params.collection === "source") {
collection = "source"
collectionParams = { collection, source: pathMatchParts[0] }
} else if (pathMatchParts.length === 1 && params.collection === "tag") {
collection = "tag"
collectionParams = { collection, tag: pathMatchParts[0] }
} else if (pathMatchParts.length === 3 && params.collection === "source") {
collection = "creator"
const [source, , creator] = pathMatchParts
collectionParams = { collection, creator, source }
} else {
return false
}
// Validate source param
if (collectionParams.collection !== "tag") {
if (
!useProviderStore($pinia).isSourceNameValid(
mediaType,
collectionParams.source
)
) {
warn(
`Attempting to get a ${collectionParams.collection} collection for an invalid source name: ${collectionParams.source}`
)
return false
}
}
// Update the search store
const searchStore = useSearchStore($pinia)
searchStore.setStrategy(collection, collectionParams)
searchStore.setSearchType(mediaType)
return true
},
})
</script>
19 changes: 19 additions & 0 deletions frontend/src/stores/provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ export interface ProviderState {
audio: FetchState
image: FetchState
}
sourceNames: {
audio: string[]
image: string[]
}
}

/**
Expand Down Expand Up @@ -56,6 +60,10 @@ export const useProviderStore = defineStore("provider", {
[AUDIO]: { isFetching: false, hasStarted: false, fetchingError: null },
[IMAGE]: { isFetching: false, hasStarted: false, fetchingError: null },
},
sourceNames: {
[AUDIO]: [],
[IMAGE]: [],
},
}),

actions: {
Expand Down Expand Up @@ -153,8 +161,19 @@ export const useProviderStore = defineStore("provider", {
this.$nuxt.$sentry.captureException(error, { extra: { errorData } })
} finally {
this.providers[mediaType] = sortedProviders
this.sourceNames[mediaType] = sortedProviders.map((p) => p.source_name)
}
},

/**
* Returns true if the given source name exists in the given media type sources list.
*/
isSourceNameValid(
mediaType: SupportedMediaType,
sourceName: string
): boolean {
return this.sourceNames[mediaType].includes(sourceName)
},
},

getters: {
Expand Down
8 changes: 4 additions & 4 deletions frontend/src/stores/search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,13 +109,13 @@ export function computeQueryParams(
export function collectionToPath(collectionParams: CollectionParams) {
switch (collectionParams.collection) {
case "tag": {
return `tag/${collectionParams.tag}`
return `tag/${collectionParams.tag}/`
}
case "creator": {
return `source/${collectionParams.source}/creator/${collectionParams.creator}`
return `source/${collectionParams.source}/creator/${collectionParams.creator}/`
}
case "source": {
return `source/${collectionParams.source}`
return `source/${collectionParams.source}/`
}
}
}
Expand Down Expand Up @@ -276,7 +276,7 @@ export const useSearchStore = defineStore("search", {
type: SupportedMediaType
collectionParams: CollectionParams
}) {
const path = `/${type}/${collectionToPath(collectionParams)}/`
const path = `/${type}/${collectionToPath(collectionParams)}`
return this.$nuxt.localePath(path)
},

Expand Down

0 comments on commit 30236b6

Please sign in to comment.