Collection: new widget to add book to collection
This commit is contained in:
95
front/src/AddBookToCollection.vue
Normal file
95
front/src/AddBookToCollection.vue
Normal file
@@ -0,0 +1,95 @@
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue'
|
||||
import { getSearchBooks, postCollectionAddBook, extractFormErrorFromField } from './api.js'
|
||||
|
||||
const props = defineProps({
|
||||
collectionId: Number,
|
||||
})
|
||||
|
||||
const emit = defineEmits(['created'])
|
||||
|
||||
const book = ref({
|
||||
id: 0,
|
||||
title: '',
|
||||
})
|
||||
const addingBook = ref(false)
|
||||
const data = ref(null)
|
||||
const error = ref(null)
|
||||
const titleError = computed(() => {
|
||||
return extractFormErrorFromField('Title', error.value)
|
||||
})
|
||||
const vFocus = {
|
||||
mounted: (el) => el.focus(),
|
||||
}
|
||||
|
||||
const limit = 5
|
||||
|
||||
function fetchBooks() {
|
||||
if (!book || book.value.title.length < 3) {
|
||||
return
|
||||
}
|
||||
const lang = navigator.language.substring(0, 2)
|
||||
getSearchBooks(data, error, book.value.title, lang, 0, limit, 0)
|
||||
}
|
||||
|
||||
function addBook(bookId) {
|
||||
postCollectionAddBook(props.collectionId, bookId).then((res) => {
|
||||
if (res.ok) {
|
||||
addingBook.value = false
|
||||
book.value.id = 0
|
||||
book.value.title = ''
|
||||
data.value = null
|
||||
error.value = null
|
||||
emit('created')
|
||||
} else {
|
||||
res.json().then((json) => {
|
||||
console.log(json)
|
||||
error.value = json
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="field has-addons">
|
||||
<div v-if="addingBook" class="control">
|
||||
<input
|
||||
:class="'input is-large ' + (titleError ? 'is-danger' : '')"
|
||||
v-focus
|
||||
@keyup="fetchBooks()"
|
||||
type="text"
|
||||
maxlength="300"
|
||||
v-model="book.title"
|
||||
:placeholder="$t('addbook.title')"
|
||||
/>
|
||||
<p v-if="titleError" class="help is-danger">{{ titleError }}</p>
|
||||
<ul v-if="data" class="popupresults has-background-dark">
|
||||
<li v-for="book in data.books" @click="addBook(book.id)" class="bookresult p-2">
|
||||
{{ book.title }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div v-if="!addingBook" class="control">
|
||||
<button @click="addingBook = true" class="button is-large mb-2">
|
||||
<span class="icon" :title="$t('collections.add')">
|
||||
<b-icon-plus />
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.popupresults {
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
.bookresult {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.bookresult:hover {
|
||||
background-color: var(--bulma-text-40);
|
||||
}
|
||||
</style>
|
||||
@@ -2,6 +2,7 @@
|
||||
import { computed, ref } from 'vue'
|
||||
import { getCollection } from './api.js'
|
||||
import CollectionFormBookItem from './CollectionFormBookItem.vue'
|
||||
import AddBookToCollection from './AddBookToCollection.vue'
|
||||
import Pagination from './Pagination.vue'
|
||||
|
||||
const props = defineProps({
|
||||
@@ -27,14 +28,20 @@ getCollection(data, error, props.id, limit, offset.value)
|
||||
function pageChange(newPageNumber) {
|
||||
pageNumber.value = newPageNumber
|
||||
data.value = null
|
||||
error.value = null
|
||||
getCollection(data, error, props.id, limit, offset.value)
|
||||
}
|
||||
|
||||
function fetchCollection() {
|
||||
pageChange(1)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="error">{{ $t('bookform.error', { error: error.message }) }}</div>
|
||||
<div v-if="data">
|
||||
<h2 class="title">{{ data.name }}</h2>
|
||||
<AddBookToCollection :collection-id="props.id" @created="fetchCollection" />
|
||||
<div>
|
||||
<CollectionFormBookItem v-for="book in data.books" :key="book.id" v-bind="book" />
|
||||
</div>
|
||||
|
||||
@@ -36,7 +36,15 @@ function fetchData(searchTerm, authorId) {
|
||||
error.value = null
|
||||
if (searchTerm != null) {
|
||||
const lang = navigator.language.substring(0, 2)
|
||||
getSearchBooks(data, error, searchTerm, lang, forceSearchInventaire.value, limit, offset.value)
|
||||
getSearchBooks(
|
||||
data,
|
||||
error,
|
||||
searchTerm,
|
||||
lang,
|
||||
forceSearchInventaire.value ? 2 : 1,
|
||||
limit,
|
||||
offset.value,
|
||||
)
|
||||
} else if (authorId != null) {
|
||||
getAuthorBooks(data, error, authorId, limit, offset.value)
|
||||
}
|
||||
|
||||
@@ -130,6 +130,14 @@ export function postCollection(collection) {
|
||||
return genericPayloadCall('/ws/collection', collection, 'POST')
|
||||
}
|
||||
|
||||
export function postCollectionAddBook(collectionId, bookId) {
|
||||
return genericPayloadCall(
|
||||
'/ws/collection/' + collectionId + '/addbook',
|
||||
{ bookId: bookId },
|
||||
'POST',
|
||||
)
|
||||
}
|
||||
|
||||
export function putBook(id, book) {
|
||||
return genericPayloadCall('/ws/book/edit/' + id, book.value, 'PUT')
|
||||
}
|
||||
@@ -219,10 +227,9 @@ export function genericPayloadCall(apiRoute, object, method) {
|
||||
}
|
||||
|
||||
export function extractFormErrorFromField(fieldName, errors) {
|
||||
if (errors == null) {
|
||||
if (errors == null || typeof errors == 'undefined' || !Array.isArray(errors)) {
|
||||
return ''
|
||||
}
|
||||
console.log(errors.value)
|
||||
const titleErr = errors.find((e) => e['field'] === fieldName)
|
||||
if (typeof titleErr !== 'undefined') {
|
||||
return titleErr.error
|
||||
|
||||
Reference in New Issue
Block a user