added rating books

This commit is contained in:
2025-10-29 22:38:38 +01:00
parent b4df375e4c
commit 26df6417b1
14 changed files with 353 additions and 153 deletions

View File

@@ -12,10 +12,12 @@
"pinia": "^3.0.3",
"vue": "^3.5.18",
"vue-i18n": "^11.1.12",
"vue-router": "^4.5.1"
"vue-router": "^4.5.1",
"vuetify": "^3.10.8"
},
"devDependencies": {
"@eslint/js": "^9.31.0",
"@mdi/font": "^7.4.47",
"@vitejs/plugin-vue": "^6.0.1",
"@vue/eslint-config-prettier": "^10.2.0",
"eslint": "^9.31.0",
@@ -1256,6 +1258,13 @@
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
"node_modules/@mdi/font": {
"version": "7.4.47",
"resolved": "https://registry.npmjs.org/@mdi/font/-/font-7.4.47.tgz",
"integrity": "sha512-43MtGpd585SNzHZPcYowu/84Vz2a2g31TvPMTm9uTiCSWzaheQySUcSyUH/46fPnuPQWof2yd0pGBtzee/IQWw==",
"dev": true,
"license": "Apache-2.0"
},
"node_modules/@pkgr/core": {
"version": "0.2.9",
"resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz",
@@ -3916,6 +3925,33 @@
"vue": "^3.2.0"
}
},
"node_modules/vuetify": {
"version": "3.10.8",
"resolved": "https://registry.npmjs.org/vuetify/-/vuetify-3.10.8.tgz",
"integrity": "sha512-TV1bx8mUjOPbhmEsamm38/CBcVe5DHYepOZGE6aQJ2uxvg96B4k+QHgIJcD5uKVfKmxKkJRtHdEXyq6JP9wBtg==",
"license": "MIT",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/johnleider"
},
"peerDependencies": {
"typescript": ">=4.7",
"vite-plugin-vuetify": ">=2.1.0",
"vue": "^3.5.0",
"webpack-plugin-vuetify": ">=3.1.0"
},
"peerDependenciesMeta": {
"typescript": {
"optional": true
},
"vite-plugin-vuetify": {
"optional": true
},
"webpack-plugin-vuetify": {
"optional": true
}
}
},
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",

View File

@@ -18,10 +18,12 @@
"pinia": "^3.0.3",
"vue": "^3.5.18",
"vue-i18n": "^11.1.12",
"vue-router": "^4.5.1"
"vue-router": "^4.5.1",
"vuetify": "^3.10.8"
},
"devDependencies": {
"@eslint/js": "^9.31.0",
"@mdi/font": "^7.4.47",
"@vitejs/plugin-vue": "^6.0.1",
"@vue/eslint-config-prettier": "^10.2.0",
"eslint": "^9.31.0",

View File

@@ -2,6 +2,7 @@
import { computed } from 'vue'
import { useRouter } from 'vue-router'
import { getImagePathOrDefault } from './api.js'
import { VRating } from 'vuetify/components/VRating';
const props = defineProps({
id: Number,
@@ -31,7 +32,15 @@ function openBook() {
<div class="media-content">
<div class="is-size-4">{{title}}</div>
<div class="is-size-5 is-italic">{{author}}</div>
<p>{{rating}}/10</p>
<VRating
half-increments
readonly
:length="5"
size="medium"
:model-value="rating/2"
active-color="bulma-body-color"
/>
</div>
<nav v-if="read" class="level">
<div class="level-left">

View File

@@ -1,7 +1,8 @@
<script setup>
import { computed } from 'vue'
import { getBook, getImagePathOrDefault } from './api.js'
import { getBook, getImagePathOrDefault, putBookUpdate } from './api.js'
import { onBeforeRouteUpdate } from 'vue-router'
import { VRating } from 'vuetify/components/VRating';
const props = defineProps({
id: String
@@ -15,6 +16,11 @@
error = res.error;
})
function onRatingUpdate(rating) {
data.value.rating = rating * 2
putBookUpdate(props.id, {rating: data.value.rating})
}
</script>
<template>
@@ -22,9 +28,21 @@
<div v-if="data">
<h3 class="title">{{data.title}}</h3>
<h3 class="subtitle">{{data.author}}</h3>
<figure class="image">
<img v-bind:src="imagePathOrDefault" v-bind:alt="data.title">
</figure>
<div class="imagewithrating">
<figure class="image">
<img v-bind:src="imagePathOrDefault" v-bind:alt="data.title">
</figure>
<VRating
half-increments
hover
:length="5"
size="x-large"
density="compact"
:model-value="data.rating/2"
@update:modelValue="onRatingUpdate"
active-color="bulma-body-color"
/>
</div>
</div>
</template>
@@ -35,4 +53,10 @@ img {
height:auto;
width:auto;
}
.imagewithrating {
vertical-align: top;
display: inline-block;
text-align: center;
}
</style>

View File

@@ -1,6 +1,6 @@
<script setup>
import { ref, computed } from 'vue'
import { postReadBook, getImagePathOrDefault } from './api.js'
import { putReadBook, getImagePathOrDefault } from './api.js'
import { useRouter } from 'vue-router'
const router = useRouter();
@@ -16,7 +16,7 @@
const error = ref(null)
async function onUserBookRead() {
const res = await postReadBook({bookId: props.id});
const res = await putReadBook(props.id);
if (res.ok) {
router.push('/books')
} else {

View File

@@ -42,11 +42,15 @@ export function getBook(id) {
}
export function postBook(book) {
return genericPostCall('/book', book.value)
return genericPayloadCall('/book', book.value, 'POST')
}
export async function postReadBook(userbook) {
return genericPostCall('/book/read', userbook)
export async function putReadBook(bookId) {
return putBookUpdate(bookId, {read: true})
}
export async function putBookUpdate(bookId, payload) {
return genericPayloadCall('/book/' + bookId, payload, 'PUT')
}
export function postLogin(user) {
@@ -84,12 +88,12 @@ export function genericPostCallNoAuth(apiRoute, object) {
})
}
export function genericPostCall(apiRoute, object) {
export function genericPayloadCall(apiRoute, object, method) {
const { user } = useAuthStore();
if (user != null) {
return fetch(baseUrl + apiRoute, {
method: 'POST',
method: method,
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + user.token

View File

@@ -2,7 +2,10 @@ import { createApp } from 'vue'
import { createI18n } from "vue-i18n";
import { createPinia } from 'pinia'
import { BootstrapIconsPlugin } from "bootstrap-icons-vue";
import { router } from './router.js'
import { router } from './router.js';
import { createVuetify } from 'vuetify'
import { aliases, mdi } from 'vuetify/iconsets/mdi-svg'
import { VRating } from 'vuetify/components/VRating';
import App from './App.vue'
import fr from './locales/fr.json';
@@ -17,6 +20,18 @@ const i18n = createI18n({
});
const vuetify = createVuetify({
VRating,
icons: {
defaultSet: 'mdi',
aliases,
sets: {
mdi,
},
},
})
const pinia = createPinia()
createApp(App).use(i18n).use(pinia).use(BootstrapIconsPlugin).use(router).mount('#app')
createApp(App).use(i18n).use(vuetify).use(pinia).use(BootstrapIconsPlugin).use(router).mount('#app')