generated from Flycro/laravel-nuxt
157 lines
4.7 KiB
Vue
157 lines
4.7 KiB
Vue
<script setup lang="ts">
|
|
import { useBookRecommendationStore } from '~/stores/book-recommendations'
|
|
|
|
const isOpen = ref(false)
|
|
const loading = ref(false)
|
|
|
|
const dayjs = useDayjs()
|
|
|
|
const form = ref()
|
|
|
|
interface State {
|
|
book_name: string
|
|
author: string
|
|
description: string
|
|
isbn: string
|
|
pages: number
|
|
cover_image?: File | string
|
|
status: string
|
|
published_at: string
|
|
// Index signature
|
|
[key: string]: string | number | File | undefined
|
|
}
|
|
|
|
const state: State = reactive({
|
|
book_name: '',
|
|
author: '',
|
|
description: '',
|
|
isbn: '',
|
|
pages: 0,
|
|
cover_image: '',
|
|
status: 'PENDING',
|
|
published_at: dayjs().format('YYYY-MM-DD'),
|
|
})
|
|
|
|
const bookRecommendationStore = useBookRecommendationStore()
|
|
|
|
function handleCoverImageInput(event: Event) {
|
|
const file = (event.target as HTMLInputElement).files?.[0]
|
|
if (file) {
|
|
// Update the state with the selected file
|
|
state.cover_image = file
|
|
}
|
|
}
|
|
|
|
async function onSubmit() {
|
|
loading.value = true
|
|
const formData = new FormData()
|
|
for (const key in state) {
|
|
const item = state[key]
|
|
if (item === undefined) {
|
|
continue
|
|
}
|
|
if (key === 'cover_image' && state[key] instanceof File) {
|
|
formData.append(key, item as Blob, (state[key] as File).name)
|
|
}
|
|
else {
|
|
if (key === 'cover_image') {
|
|
continue
|
|
}
|
|
const value = typeof item === 'string' ? item : String(item)
|
|
formData.append(key, value)
|
|
}
|
|
}
|
|
await $fetch<any>(`book-recommendations`, {
|
|
method: 'POST',
|
|
body: formData,
|
|
async onResponse({ response }) {
|
|
loading.value = false
|
|
if (response?.status === 422) {
|
|
form.value.setErrors(response._data?.errors)
|
|
}
|
|
else if (response.ok) {
|
|
useToast().add({
|
|
icon: 'i-heroicons-check-circle-20-solid',
|
|
title: 'Buchempfehlung wurde erfolgreich angelegt.',
|
|
color: 'emerald',
|
|
})
|
|
await bookRecommendationStore.fetchRecommendations()
|
|
|
|
state.book_name = ''
|
|
state.author = ''
|
|
state.description = ''
|
|
state.isbn = ''
|
|
state.pages = 0
|
|
state.cover_image = ''
|
|
state.status = 'PENDING'
|
|
state.published_at = dayjs().format('YYYY-MM-DD')
|
|
|
|
isOpen.value = false
|
|
}
|
|
},
|
|
})
|
|
}
|
|
function isFile(value: any): value is File {
|
|
return value instanceof File
|
|
}
|
|
|
|
function getFileUrl(file: File) {
|
|
return URL.createObjectURL(file)
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div>
|
|
<div class="flex justify-end">
|
|
<UButton icon="i-heroicons-plus" label="Neues Buch" size="sm" variant="solid" color="green" square @click="isOpen = true" />
|
|
</div>
|
|
|
|
<UModal v-model="isOpen">
|
|
<UCard :ui="{ ring: '', divide: 'divide-y divide-gray-100 dark:divide-gray-800' }">
|
|
<template #header>
|
|
<div class="flex items-center justify-between">
|
|
<h3 class="text-base font-semibold leading-6 text-gray-900 dark:text-white">
|
|
Neues Buch
|
|
</h3>
|
|
<UButton color="gray" variant="ghost" icon="i-heroicons-x-mark-20-solid" class="-my-1" @click="isOpen = false" />
|
|
</div>
|
|
</template>
|
|
|
|
<UForm ref="form" :state="state" class="space-y-4" @submit="onSubmit">
|
|
<UFormGroup label="Name" name="book_name">
|
|
<UInput v-model="state.book_name" />
|
|
</UFormGroup>
|
|
<UFormGroup label="Autor" name="author">
|
|
<UInput v-model="state.author" />
|
|
</UFormGroup>
|
|
<UFormGroup label="Erstveröffentlichung">
|
|
<UInput v-model="state.published_at" type="date" />
|
|
</UFormGroup>
|
|
<UFormGroup label="Beschreibung" name="description">
|
|
<UTextarea v-model="state.description" />
|
|
</UFormGroup>
|
|
<ClientOnly>
|
|
<img v-if="state.cover_image && isFile(state.cover_image)" :src="getFileUrl(state.cover_image)" alt="Cover" class="size-1/3 content-center rounded-lg">
|
|
</ClientOnly>
|
|
<UFormGroup label="Cover" name="cover_image">
|
|
<UInput type="file" @change="handleCoverImageInput" />
|
|
</UFormGroup>
|
|
<UFormGroup label="ISBN" name="isbn">
|
|
<UInput v-model="state.isbn" />
|
|
</UFormGroup>
|
|
<UFormGroup label="Seiten" name="pages">
|
|
<UInput v-model="state.pages" type="number" />
|
|
</UFormGroup>
|
|
<UFormGroup label="Status" name="status">
|
|
<USelect v-model="state.status" :options="bookRecommendationStore.statusOptions" option-attribute="name" />
|
|
</UFormGroup>
|
|
<UButton size="md" type="submit" :loading="status === 'pending'">
|
|
Erstellen
|
|
</UButton>
|
|
<UButton size="md" class="mx-4" color="white" label="Abbrechen" @click="isOpen = false" />
|
|
</UForm>
|
|
</UCard>
|
|
</UModal>
|
|
</div>
|
|
</template>
|