generated from Flycro/laravel-nuxt
feat: BR Overview + Modal for New Recommendations
This commit is contained in:
@@ -19,6 +19,10 @@ const columns = [
|
||||
key: 'author',
|
||||
label: 'Autor',
|
||||
},
|
||||
{
|
||||
key: 'published_at',
|
||||
label: 'Erstveröffentlichung',
|
||||
},
|
||||
{
|
||||
key: 'description',
|
||||
label: 'Beschreibung',
|
||||
@@ -42,27 +46,46 @@ const columns = [
|
||||
{
|
||||
key: 'votes',
|
||||
label: 'Votes',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
key: 'actions',
|
||||
label: '',
|
||||
},
|
||||
]
|
||||
const sort = ref({
|
||||
column: 'votes',
|
||||
direction: 'desc',
|
||||
})
|
||||
|
||||
function resolveStatus(status: string) {
|
||||
return bookRecommendationStore.statusOptions.find(option => option.value === status)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<NewBookRecommendation />
|
||||
<UTable :loading="bookRecommendationStore.fetchRecommendationsStatus === 'pending'" :columns="columns" :rows="bookRecommendationStore.recommendations">
|
||||
<UTable :sort="sort" :loading="bookRecommendationStore.fetchRecommendationsStatus === 'pending'" :columns="columns" :rows="bookRecommendationStore.recommendations">
|
||||
<template #created_at-data="{ row }">
|
||||
<div>{{ dayjs(row.created_at).format('DD.MM.YYYY') }}</div>
|
||||
</template>
|
||||
<template #published_at-data="{ row }">
|
||||
<div>{{ dayjs(row.published_at).format('DD.MM.YYYY') }}</div>
|
||||
</template>
|
||||
<template #description-data="{ row }">
|
||||
{{ `${row.description.substring(0, 50)}...` }}
|
||||
<div v-if="row.description">
|
||||
{{ `${row.description.substring(0, 50)}...` }}
|
||||
</div>
|
||||
</template>
|
||||
<template #votes-data="{ row }">
|
||||
{{ row.votes.length }}
|
||||
</template>
|
||||
<template #status-data="{ row }">
|
||||
<UBadge :color="resolveStatus(row.status)?.color">
|
||||
{{ resolveStatus(row.status)?.name }}
|
||||
</UBadge>
|
||||
</template>
|
||||
<template #actions-data="{ row }">
|
||||
<div class="flex space-x-2">
|
||||
<CastVote :row="row" />
|
||||
|
||||
@@ -2,50 +2,95 @@
|
||||
import { useBookRecommendationStore } from '~/stores/book-recommendations'
|
||||
|
||||
const isOpen = ref(false)
|
||||
const loading = ref(false)
|
||||
|
||||
const dayjs = useDayjs()
|
||||
|
||||
const form = ref()
|
||||
|
||||
const state = reactive({
|
||||
book_name: null,
|
||||
author: null,
|
||||
description: null,
|
||||
isbn: null,
|
||||
pages: null,
|
||||
cover_image: null,
|
||||
status: null,
|
||||
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()
|
||||
|
||||
const { refresh: onSubmit, status } = useFetch<any>(`book-recommendations`, {
|
||||
method: 'POST',
|
||||
body: state,
|
||||
immediate: false,
|
||||
watch: false,
|
||||
async onResponse({ response }) {
|
||||
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 aktualisiert.',
|
||||
color: 'emerald',
|
||||
})
|
||||
await bookRecommendationStore.fetchRecommendations()
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
state.book_name = null
|
||||
state.author = null
|
||||
state.description = null
|
||||
state.isbn = null
|
||||
state.pages = null
|
||||
state.cover_image = null
|
||||
state.status = null
|
||||
|
||||
isOpen.value = false
|
||||
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
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -72,9 +117,15 @@ const { refresh: onSubmit, status } = useFetch<any>(`book-recommendations`, {
|
||||
<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>
|
||||
<UFormGroup label="Cover" name="cover_image">
|
||||
<UInput type="file" @change="handleCoverImageInput" />
|
||||
</UFormGroup>
|
||||
<UFormGroup label="ISBN" name="isbn">
|
||||
<UInput v-model="state.isbn" />
|
||||
</UFormGroup>
|
||||
|
||||
Reference in New Issue
Block a user