Library/frontend/src/components/BooksAddEdit.vue

351 lines
11 KiB
Vue

<template>
<div>
<form class="ui form" :class="{ loading: loading }" @submit.prevent="insertNewBook">
<div class="field">
<label v-lang.books.gridColumns.title></label>
<input name="title" :placeholder="langBooks.gridColumns.title" type="text" v-model="book.title" required v-focus>
</div>
<div class="field">
<label v-lang.books.description></label>
<textarea name="description" :placeholder="langBooks.description" rows="3" v-model="book.description"></textarea>
</div>
<div class="three fields">
<div class="field">
<label v-lang.books.gridColumns.isbn></label>
<input name="isbn" :placeholder="langBooks.gridColumns.isbn" type="text" v-model="book.isbn">
</div>
<div class="field">
<label v-lang.books.gridColumns.price></label>
<div class="ui right labeled input ">
<input name="price" :placeholder="langBooks.gridColumns.price" type="number" step="0.01" min="0" v-model.number="book.price">
<label class="ui label">€</label>
</div>
</div>
<div class="field">
<label v-lang.books.gridColumns.year></label>
<input name="year" :placeholder="langBooks.gridColumns.year" type="number" step="1" min="1800" v-model.number="book.year">
</div>
<div class="field">
<label v-lang.books.gridColumns.quantity></label>
<input :placeholder="langBooks.gridColumns.quantity" type="number" min="0" step="1" v-model.number="book.quantity">
</div>
</div>
<div class="field" v-if="!addPublisherForm">
<label v-lang.books.gridColumns.publisher></label>
<a class="ui green icon button add-publisher-btn" @click="toggleAddPublisher()"><i class="plus icon"></i></a>
<multiselect
v-model="book.publisher"
track-by="id"
label="name"
:placeholder="langGeneral.selectOne"
:options="publishers"
:searchable="true"
:allow-empty="false"
class="add-btn-input">
</multiselect>
</div>
<div class="field" v-if="addPublisherForm">
<label v-lang.publishers.newPublisher></label>
<a class="ui green icon button add-publisher-btn" @click="toggleAddPublisher()"><i class="list icon"></i></a>
<input name="name" :placeholder="langPublishers.newPublisher" type="text" v-model="book.publisher.name" class="add-publisher">
</div>
<div class="field">
<label v-lang.books.gridColumns.authors></label>
<multiselect
v-model="book.authors"
track-by="id"
label="name"
:placeholder="langGeneral.selectOneOrMore"
:options="authors"
:searchable="true"
:multiple="true"
:allow-empty="false">
</multiselect>
</div>
<template v-for="(inputModel, index) in addAuthorForm">
<div class="field" v-if="addAuthorForm">
<label v-lang.authors.newAuthor></label>
<a class="ui red icon button add-publisher-btn" @click="removeAuthor(index)"><i class="cancel icon"></i></a>
<input name="name" :placeholder="langBooks.gridColumns.authors" v-model="newAuthors[inputModel.modelName]" type="text" class="add-publisher">
</div>
</template>
<div class="field">
<a class="ui green icon button" @click="addAddAuthor()"><i class="plus icon"></i> <span v-lang.authors.newAuthor></span></a>
</div>
<div class="inline fields">
<label v-lang.books.gridColumns.status></label>
<div class="field" v-for="status in allStatus">
<div class="ui radio checkbox">
<input name="status" :id="status.id" :value="status.id" class="hidden" type="radio" v-model="book.status"/>
<label :for="status.id">{{ status.Name }}</label>
</div>
</div>
</div>
<button class="ui blue button" type="submit" v-lang.general.submit></button>
</form>
</div>
</template>
<script>
import {HTTP} from '../http-common'
import router from '../router'
export default {
name: 'BooksAddEdit',
data () {
return {
loading: false,
bookID: this.$route.params.id,
edit: false,
book: {
authors: [],
title: '',
description: '',
isbn: '',
year: (new Date()).getFullYear(),
price: 0,
status: 0,
quantity: 0,
publisher: {
id: 0,
name: ''
}
},
publishers: [],
authors: [],
addPublisherForm: false,
addAuthorForm: [],
newAuthors: {},
newestAuthor: 0,
allStatus: []
}
},
computed: {
langBooks () {
return this.translate('books')
},
langPublishers () {
return this.translate('publishers')
},
langGeneral () {
return this.translate('general')
}
},
created () {
this.loading = true
this.loadPublishers()
this.loadAuthors()
this.loadStatus()
// Look if we're in edit mode and get the book infos if nessesary
if (this.bookID) {
HTTP.get('books/' + this.bookID)
.then(response => {
this.book = response.data
this.edit = true
// Loop through all authors and reverse them
let as = this.book.authors
for (const i in as) {
this.book.authors[i] = {
id: as[i].id,
name: as[i].forename + ' ' + as[i].lastname
}
}
// Workaround when the book don't has any authors
if (this.book.authors === null) {
this.book.authors = []
}
})
.catch(e => {
this.errorNotification(e)
})
}
// Set the title
document.title = this.translate('books').add
if (this.bookID) {
document.title = this.translate('general').edit + ' | ' + this.translate('nav').books
}
this.loading = false
},
methods: {
errorNotification (e) {
// Build the notification text from error response
let err = e.message
if (e.response.data.message) {
err += '<br/>' + e.response.data.message
}
// Fire a notification
this.$notify({
type: 'error',
title: this.langGeneral.error,
text: err
})
},
loadPublishers: function () {
HTTP.get('publishers')
.then(response => {
this.publishers = response.data
})
.catch(e => {
this.errorNotification(e)
})
},
loadAuthors: function () {
HTTP.get('authors')
.then(response => {
let as = response.data
for (const i in as) {
this.authors[i] = {
id: as[i].id,
name: as[i].forename + ' ' + as[i].lastname
}
}
})
.catch(e => {
this.errorNotification(e)
})
},
loadStatus: function () {
HTTP.get('status')
.then(response => {
this.allStatus = response.data
})
.catch(e => {
this.errorNotification(e)
})
},
toggleAddPublisher: function () {
this.addPublisherForm = !this.addPublisherForm
this.book.publisher = {id: 0, name: ''}
},
addAddAuthor: function () {
this.addAuthorForm.push({
modelName: 'newAuthor' + this.newestAuthor
})
this.newestAuthor++
},
removeAuthor: function (i) {
delete this.newAuthors[this.addAuthorForm[i].modelName]
this.addAuthorForm.splice(i, 1)
},
insertNewBook: function () {
if (this.book.title === '') {
// Fire a notification
this.$notify({
type: 'warn',
text: this.translate('books').errorNoTitle
})
} else {
this.loading = true
// Add all newly created authors to it
let as = this.newAuthors
for (const i in as) {
this.book.authors.push({
id: 0,
name: as[i]
})
}
// Beautify all Authors aka split the names in forename and lastname
for (const i in this.book.authors) {
let author = this.book.authors[i].name
let firstname = ''
let lastname = ''
// Check if the name contains a space, if so split it up
if ((new RegExp(' ')).test(author)) {
let split = author.indexOf(' ')
let splits = [author.slice(0, split), author.slice(split + 1)]
firstname = splits[0]
lastname = splits[1]
} else {
lastname = author
}
// Put it all together
this.book.authors[i] = {
id: this.book.authors[i].id,
forename: firstname,
lastname: lastname
}
}
// Finally Send it
// If we want to newly insert it, make a different request
if (this.edit) {
HTTP.post('books/' + this.book.id, {book: this.book})
.then(response => {
this.loading = false
// Fire a notification
this.$notify({
type: 'success',
title: this.translate('general').success,
text: this.translate('books').updatedSuccess
})
// Redirect to books list
router.push({ name: 'books' })
})
.catch(e => {
this.loading = false
this.errorNotification(e)
})
} else { // insert a new book
HTTP.put('books', {book: this.book})
.then(response => {
this.loading = false
// Fire a notification
this.$notify({
type: 'success',
title: this.translate('general').success,
text: this.translate('books').insertedSuccess
})
// Redirect to books list
router.push({ name: 'books' })
})
.catch(e => {
this.loading = false
this.errorNotification(e)
})
}
}
}
}
}
</script>
<style src="vue-multiselect/dist/vue-multiselect.min.css"></style>
<style>
.multiselect__input {
border: none !important;
margin-top: -0.5rem !important;
margin-left: -0.5rem !important;
}
.add-publisher-btn{
float: right;
margin-top: 2px;
}
.add-btn-input, .field input.add-publisher {
width: 97% !important;
}
</style>