Add singles from admin

This commit is contained in:
lucast committed 2026-09-26 00:04:55 +02:00
1 parent 3255a97339
commit 3402178932
2 files changed
+72 -1

No files matched your search

+7 -1
View File
@@ -4,6 +4,7 @@ import { type Option } from "~/ui/SearchSelect.vue"
interface BaseField<T> {
key: keyof T
label?: string
visibleWhen?: (value: any) => boolean
}
interface TextField<T> extends BaseField<T> {
@@ -114,7 +115,12 @@ watch(
<p v-if="props.title" class="title">{{ props.title }}</p>
<form class="form" @submit.prevent="save">
<template v-for="field in props.fields">
<template
v-for="field in props.fields.filter(
(field) =>
!field.visibleWhen || field.visibleWhen(localItem),
)"
>
<SearchSelect
v-if="
field.type == 'search-select' ||
+65
View File
@@ -48,6 +48,14 @@ const albumFetchOptions = async (q?: string): Promise<Option[]> => {
}))
}
const { data: genreData } = useApiFetch<Genre[]>("/all/genres")
const genreFetchOptions = async (): Promise<Option[]> => {
return genreData.value.map<Option>((genre) => ({
label: genre.name,
value: genre._id,
}))
}
const modalFields: Field[] = [
{ key: "name", label: "Name" },
{ key: "file", label: "Audio file", type: "file" },
@@ -57,11 +65,31 @@ const modalFields: Field[] = [
type: "search-select-array",
fetchOptions: artistFetchOptions,
},
{
key: "createSingle",
label: "Create a single album automatically",
type: "checkbox",
visibleWhen: (value) => !value._id,
},
{
key: "album",
label: "Album",
type: "search-select",
fetchOptions: albumFetchOptions,
visibleWhen: (value) => !value.createSingle,
},
{
key: "cover",
label: "Single cover",
type: "file",
visibleWhen: (value) => !value._id && value.createSingle,
},
{
key: "genre",
label: "Genre",
type: "search-select",
fetchOptions: genreFetchOptions,
visibleWhen: (value) => !value._id && value.createSingle,
},
{ key: "lyrics.text", label: "Lyrics", type: "textarea", rows: 6 },
{ key: "lyrics.synced", label: "Synced lyrics", type: "checkbox" },
@@ -96,10 +124,47 @@ const save = async (value: any) => {
}
} else {
try {
if (!value.name || !value.file || !value.artists?.length) {
toast.show(
"Name, audio file, and at least one artist are required",
"error",
)
return false
}
if (value.createSingle) {
if (!value.cover || !value.genre) {
toast.show(
"A cover image and genre are required for a single",
"error",
)
return false
}
const albumResponse = await cfetch("/admin/album", {
method: "POST",
data: {
name: `${value.name} - Single`,
artists: value.artists.map((artist: Option) => artist.value),
genres: value.genre.value,
file: value.cover,
},
})
value.album = albumResponse.data._id
} else if (!value.album) {
toast.show(
"Choose an album or create a single album",
"error",
)
return false
}
await cfetch("/admin/track", {
method: "POST",
data: {
...value,
album: value.album?.value ?? value.album,
artists: value.artists.map((artist: Option) => artist.value),
lyrics: serializeLyrics(value.lyrics),
},
})