2022-05-28 15:54:04 -05:00
|
|
|
<template>
|
|
|
|
|
<div>
|
2022-11-07 18:27:17 -06:00
|
|
|
<ui-multi-select-query-input v-model="seriesItems" text-key="displayName" :label="$strings.LabelSeries" :disabled="disabled" readonly show-edit @edit="editSeriesItem" @add="addNewSeries" />
|
2022-05-28 15:54:04 -05:00
|
|
|
|
2025-05-19 17:37:11 -05:00
|
|
|
<modals-edit-series-input-inner-modal v-model="showSeriesForm" :selected-series="selectedSeries" :existing-series-names="existingSeriesNames" :original-series-sequence="originalSeriesSequence" @submit="submitSeriesForm" />
|
2022-05-28 15:54:04 -05:00
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
export default {
|
|
|
|
|
props: {
|
|
|
|
|
value: {
|
|
|
|
|
type: Array,
|
|
|
|
|
default: () => []
|
2022-10-01 17:15:21 -05:00
|
|
|
},
|
|
|
|
|
disabled: Boolean
|
2022-05-28 15:54:04 -05:00
|
|
|
},
|
|
|
|
|
data() {
|
|
|
|
|
return {
|
|
|
|
|
selectedSeries: null,
|
2025-05-19 17:37:11 -05:00
|
|
|
originalSeriesSequence: null,
|
2022-05-28 15:54:04 -05:00
|
|
|
showSeriesForm: false
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
computed: {
|
|
|
|
|
seriesItems: {
|
|
|
|
|
get() {
|
|
|
|
|
return (this.value || []).map((se) => {
|
|
|
|
|
return {
|
|
|
|
|
displayName: se.sequence ? `${se.name} #${se.sequence}` : se.name,
|
|
|
|
|
...se
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
set(val) {
|
|
|
|
|
this.$emit('input', val)
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
series() {
|
|
|
|
|
return this.filterData.series || []
|
|
|
|
|
},
|
|
|
|
|
filterData() {
|
|
|
|
|
return this.$store.state.libraries.filterData || {}
|
|
|
|
|
},
|
|
|
|
|
existingSeriesNames() {
|
|
|
|
|
// Only show series names not already selected
|
|
|
|
|
var alreadySelectedSeriesIds = (this.value || []).map((se) => se.id)
|
|
|
|
|
return this.series.filter((se) => !alreadySelectedSeriesIds.includes(se.id)).map((se) => se.name)
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
methods: {
|
|
|
|
|
cancelSeriesForm() {
|
|
|
|
|
this.showSeriesForm = false
|
|
|
|
|
},
|
|
|
|
|
editSeriesItem(series) {
|
|
|
|
|
var _series = this.seriesItems.find((se) => se.id === series.id)
|
|
|
|
|
if (!_series) return
|
|
|
|
|
|
2026-01-03 10:34:05 -06:00
|
|
|
// If this is an existing series (not new), fetch the full series data to get ASIN
|
|
|
|
|
if (!_series.id.startsWith('new-')) {
|
|
|
|
|
this.fetchSeriesData(_series.id).then((fullSeries) => {
|
|
|
|
|
this.selectedSeries = {
|
|
|
|
|
..._series,
|
|
|
|
|
audibleSeriesAsin: fullSeries?.audibleSeriesAsin || ''
|
|
|
|
|
}
|
|
|
|
|
this.originalSeriesSequence = _series.sequence
|
|
|
|
|
this.showSeriesForm = true
|
|
|
|
|
})
|
|
|
|
|
} else {
|
|
|
|
|
this.selectedSeries = {
|
|
|
|
|
..._series,
|
|
|
|
|
// Map 'asin' from match data to 'audibleSeriesAsin' for the edit form
|
|
|
|
|
audibleSeriesAsin: _series.asin || _series.audibleSeriesAsin || ''
|
|
|
|
|
}
|
|
|
|
|
this.originalSeriesSequence = _series.sequence
|
|
|
|
|
this.showSeriesForm = true
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
async fetchSeriesData(seriesId) {
|
|
|
|
|
try {
|
|
|
|
|
const libraryId = this.$store.state.libraries.currentLibraryId
|
|
|
|
|
const series = await this.$axios.$get(`/api/libraries/${libraryId}/series/${seriesId}`)
|
|
|
|
|
return series
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('Failed to fetch series data:', error)
|
|
|
|
|
return null
|
2022-05-28 15:54:04 -05:00
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
addNewSeries() {
|
|
|
|
|
this.selectedSeries = {
|
|
|
|
|
id: `new-${Date.now()}`,
|
|
|
|
|
name: '',
|
|
|
|
|
sequence: ''
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-19 17:37:11 -05:00
|
|
|
this.originalSeriesSequence = null
|
2022-05-28 15:54:04 -05:00
|
|
|
this.showSeriesForm = true
|
|
|
|
|
},
|
2026-01-03 10:34:05 -06:00
|
|
|
submitSeriesForm(formData) {
|
2022-05-28 15:54:04 -05:00
|
|
|
if (!this.selectedSeries.name) {
|
|
|
|
|
this.$toast.error('Must enter a series')
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var existingSeriesIndex = this.seriesItems.findIndex((se) => se.id === this.selectedSeries.id)
|
|
|
|
|
|
|
|
|
|
var existingSeriesSameName = this.seriesItems.findIndex((se) => se.name.toLowerCase() === this.selectedSeries.name.toLowerCase())
|
|
|
|
|
if (existingSeriesSameName >= 0 && existingSeriesIndex < 0) {
|
|
|
|
|
console.error('Attempt to add duplicate series')
|
2025-03-23 18:09:59 -05:00
|
|
|
this.$toast.error(this.$strings.ToastSeriesSubmitFailedSameName)
|
2022-05-28 15:54:04 -05:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var seriesSameName = this.series.find((se) => se.name.toLowerCase() === this.selectedSeries.name.toLowerCase())
|
|
|
|
|
if (existingSeriesIndex < 0 && seriesSameName) {
|
|
|
|
|
this.selectedSeries.id = seriesSameName.id
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var selectedSeriesCopy = { ...this.selectedSeries }
|
|
|
|
|
selectedSeriesCopy.displayName = selectedSeriesCopy.sequence ? `${selectedSeriesCopy.name} #${selectedSeriesCopy.sequence}` : selectedSeriesCopy.name
|
|
|
|
|
|
2026-01-03 10:34:05 -06:00
|
|
|
// Store ASIN for later update (after book is saved and series exists)
|
|
|
|
|
if (formData?.audibleSeriesAsin !== undefined) {
|
|
|
|
|
selectedSeriesCopy.audibleSeriesAsin = formData.audibleSeriesAsin
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-28 15:54:04 -05:00
|
|
|
var seriesCopy = this.seriesItems.map((v) => ({ ...v }))
|
|
|
|
|
if (existingSeriesIndex >= 0) {
|
|
|
|
|
seriesCopy.splice(existingSeriesIndex, 1, selectedSeriesCopy)
|
|
|
|
|
this.seriesItems = seriesCopy
|
|
|
|
|
} else {
|
|
|
|
|
seriesCopy.push(selectedSeriesCopy)
|
|
|
|
|
this.seriesItems = seriesCopy
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-03 10:34:05 -06:00
|
|
|
// If this is an existing series (not new), update the ASIN immediately
|
|
|
|
|
if (!this.selectedSeries.id.startsWith('new-') && formData?.audibleSeriesAsin !== undefined) {
|
|
|
|
|
this.updateSeriesAsin(this.selectedSeries.id, formData.audibleSeriesAsin)
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-28 15:54:04 -05:00
|
|
|
this.showSeriesForm = false
|
2026-01-03 10:34:05 -06:00
|
|
|
},
|
|
|
|
|
async updateSeriesAsin(seriesId, asin) {
|
|
|
|
|
// Skip API call if ASIN is empty - backend safeguard prevents clearing anyway,
|
|
|
|
|
// but this avoids unnecessary network requests
|
|
|
|
|
if (!asin) {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
try {
|
|
|
|
|
await this.$axios.$patch(`/api/series/${seriesId}`, {
|
|
|
|
|
audibleSeriesAsin: asin
|
|
|
|
|
})
|
|
|
|
|
this.$toast.success(this.$strings.ToastSeriesUpdateSuccess)
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('Failed to update series ASIN:', error)
|
|
|
|
|
this.$toast.error(this.$strings.ToastSeriesUpdateFailed)
|
|
|
|
|
}
|
2022-05-28 15:54:04 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-06-02 19:34:25 +02:00
|
|
|
</script>
|