Added song loading state
This commit is contained in:
1 parent
869ca7d728
commit
e908ae27ad
3 files changed
+51
-23
No files matched your search
@@ -47,6 +47,8 @@ interface ModalFormProps<T> {
|
||||
fields: Field<T>[]
|
||||
title?: string
|
||||
onSave: (value: any) => Promise<boolean>
|
||||
loading?: boolean
|
||||
loadingText?: string
|
||||
}
|
||||
|
||||
const props = defineProps<ModalFormProps<any>>()
|
||||
@@ -150,7 +152,10 @@ watch(
|
||||
/>
|
||||
</template>
|
||||
|
||||
<Button type="submit" full center-text>Save</Button>
|
||||
<Button type="submit" full center-text :disabled="props.loading">
|
||||
<span v-if="props.loading" class="spinner" aria-hidden="true" />
|
||||
{{ props.loading ? props.loadingText || "Saving…" : "Save" }}
|
||||
</Button>
|
||||
</form>
|
||||
</Modal>
|
||||
</template>
|
||||
@@ -169,4 +174,19 @@ watch(
|
||||
flex-direction: column;
|
||||
gap: 0.8rem;
|
||||
}
|
||||
|
||||
.spinner {
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
border: 2px solid currentColor;
|
||||
border-right-color: transparent;
|
||||
border-radius: 50%;
|
||||
animation: spin 0.7s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
+28
-22
@@ -106,6 +106,7 @@ const getOptionId = (option: string | Option) =>
|
||||
|
||||
const showModal = ref<boolean>(false)
|
||||
const item = ref<Track | undefined>(undefined)
|
||||
const addingSong = ref(false)
|
||||
|
||||
const save = async (value: any) => {
|
||||
if (value._id) {
|
||||
@@ -127,24 +128,31 @@ const save = async (value: any) => {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
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 && (!value.cover || !value.genre)) {
|
||||
toast.show(
|
||||
"A cover image and genre are required for a single",
|
||||
"error",
|
||||
)
|
||||
return false
|
||||
}
|
||||
|
||||
if (!value.createSingle && !value.album) {
|
||||
toast.show("Choose an album or create a single album", "error")
|
||||
return false
|
||||
}
|
||||
|
||||
addingSong.value = true
|
||||
await nextTick()
|
||||
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<{ _id: string }>("/admin/album", {
|
||||
method: "POST",
|
||||
data: {
|
||||
@@ -155,12 +163,6 @@ const save = async (value: any) => {
|
||||
},
|
||||
})
|
||||
value.album = albumResponse._id
|
||||
} else if (!value.album) {
|
||||
toast.show(
|
||||
"Choose an album or create a single album",
|
||||
"error",
|
||||
)
|
||||
return false
|
||||
}
|
||||
|
||||
await cfetch("/admin/track", {
|
||||
@@ -178,6 +180,8 @@ const save = async (value: any) => {
|
||||
toast.show("Failed to add song", "error")
|
||||
|
||||
return false
|
||||
} finally {
|
||||
addingSong.value = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -241,6 +245,8 @@ useHead({ title: "Admin - Songs" })
|
||||
:fields="modalFields"
|
||||
:item="item"
|
||||
:title="item ? 'Edit song' : 'Add new song'"
|
||||
:loading="addingSong"
|
||||
:loading-text="'Adding song…'"
|
||||
/>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ interface ButtonProps {
|
||||
full?: boolean
|
||||
iconName?: string
|
||||
centerText?: boolean
|
||||
disabled?: boolean
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<ButtonProps>(), {
|
||||
@@ -22,6 +23,7 @@ const props = withDefaults(defineProps<ButtonProps>(), {
|
||||
props.type == 'link' && props.to != undefined ? NuxtLink : 'button'
|
||||
"
|
||||
:to="props.to"
|
||||
:disabled="props.disabled"
|
||||
:class="[
|
||||
`button type-${props.variant}`,
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user