Add component to upload book cover images

This commit is contained in:
2025-10-27 22:51:28 +01:00
parent d407b41c9f
commit 8b8eee8210
11 changed files with 152 additions and 12 deletions

View File

@@ -2,6 +2,7 @@
import { ref, reactive, computed } from 'vue'
import { postBook, extractFormErrorFromField } from './api.js'
import { useRouter } from 'vue-router'
import CoverUpload from './CoverUpload.vue'
const router = useRouter();
@@ -28,6 +29,7 @@
}
})
}
</script>
<template>
@@ -48,6 +50,7 @@
</div>
<p v-if="authorError" class="help is-danger">{{authorError}}</p>
</div>
<CoverUpload name="cover"/>
<div class="field">
<div class="control">
<button class="button is-link">{{$t('addbook.submit')}}</button>

80
front/src/CoverUpload.vue Normal file
View File

@@ -0,0 +1,80 @@
<script setup>
import { ref, computed } from 'vue'
import { postImage } from './api.js'
const props = defineProps({
name: String
});
const imagePath = ref(null);
const error = ref(null);
function onFileChanged(e) {
postImage(e.target.files[0])
.then((res) => res.json())
.then((json) => (imagePath.value = json["filepath"]))
.catch((err) => (error.value = err["error"]));
}
function unsetImage() {
imagePath.value = null;
}
const imageSrc = computed(() => {
return "http://localhost:8080" + imagePath.value
})
</script>
<template>
<div v-if="imagePath">
<div class="relative">
<figure class="image mb-3">
<img v-bind:src="imageSrc" v-bind:alt="props.name">
</figure>
<span class="icon is-large" @click="unsetImage">
<b-icon-x-circle-fill/>
</span>
</div>
</div>
<div v-else class="file">
<label class="file-label">
<input class="file-input" @change="onFileChanged" type="file" :name="props.name" accept="image/*"/>
<span class="file-cta">
<span class="file-icon">
<b-icon-upload />
</span>
<span class="file-label">{{$t('addbook.coverupload')}}</span>
</span>
</label>
</div>
</template>
<style scoped>
img {
max-height:500px;
max-width:500px;
height:auto;
width:auto;
}
.relative {
position: relative;
}
.relative img {
display: block;
}
.relative .icon {
position: absolute;
bottom:5px;
left:5px;
background-color: rgba(0,0,0,0.7);
font-size: 24px;
border-radius: 5px;
}
.relative .icon:hover {
background-color: rgba(0,0,0,0.8);
cursor: pointer;
}
</style>

View File

@@ -52,6 +52,23 @@ export function postSignUp(user) {
return genericPostCallNoAuth('/auth/signup', user.value)
}
export function postImage(file) {
const { user } = useAuthStore();
const formData = new FormData();
formData.append('file', file);
if (user != null) {
return fetch(baseUrl + "/upload/cover", {
method: 'POST',
headers: {
'Authorization': 'Bearer ' + user.token
},
body: formData
})
} else {
return Promise.resolve();
}
}
export function genericPostCallNoAuth(apiRoute, object) {
return fetch(baseUrl + apiRoute, {
method: 'POST',

View File

@@ -13,7 +13,8 @@
"addbook": {
"title":"Title",
"author":"Author",
"submit":"Submit"
"submit":"Submit",
"coverupload":"Upload cover"
},
"signup": {
"username":"Username",

View File

@@ -13,7 +13,8 @@
"addbook": {
"title":"Titre",
"author":"Auteur",
"submit":"Confirmer"
"submit":"Confirmer",
"coverupload":"Téléverser la couverture"
},
"signup": {
"username":"Nom d'utilisateur",