Zaklad ssr

This commit is contained in:
Michal Kváček
2023-11-14 16:20:01 +01:00
parent e65491e00b
commit 331ebbc4e4
19 changed files with 298 additions and 84 deletions
+27 -25
View File
@@ -2,6 +2,7 @@ import {boot} from 'quasar/wrappers'
import axios from 'axios'
import {useUserStore} from "stores/User";
const api = axios.create({
baseURL: process.env.API_URL,
withCredentials: true,
@@ -12,37 +13,38 @@ const api = axios.create({
},
})
api.interceptors.request.use((config) => {
const token = useUserStore().getAccessToken();
if (token) {
config.headers['Authorization'] = `Bearer ${token}`
}
export default boot(({app, store}) => {
if (['/refresh', '/login'].includes(config.url)) {
delete config.headers['Authorization'];
}
api.interceptors.request.use((config) => {
const token = useUserStore(store).getAccessToken();
if (token) {
config.headers['Authorization'] = `Bearer ${token}`
}
return config;
})
if (['/refresh', '/login'].includes(config.url)) {
delete config.headers['Authorization'];
}
return config;
})
// Response interceptor for API calls
api.interceptors.response.use((response) => {
return response
}, async function (error) {
const originalRequest = error.config;
if (error.response.status === 401 && !['/refresh', '/login'].includes(originalRequest.url)) {
const newToken = await useUserStore().refreshAccessToken().catch(err => {
console.error(err);
return Promise.reject("Logged out");
})
api.defaults.headers.common['Authorization'] = 'Bearer ' + newToken;
return api(originalRequest);
}
return Promise.reject(error);
});
api.interceptors.response.use((response) => {
return response
}, async function (error) {
const originalRequest = error.config;
if (error.response.status === 401 && !['/refresh', '/login'].includes(originalRequest.url)) {
const newToken = await useUserStore(store).refreshAccessToken().catch(err => {
console.error(err);
return Promise.reject("Logged out");
})
api.defaults.headers.common['Authorization'] = 'Bearer ' + newToken;
return api(originalRequest);
}
return Promise.reject(error);
});
export default boot(({app}) => {
// for use inside Vue files (Options API) through this.$axios and this.$api
// app.config.globalProperties.$axios = axios
@@ -13,7 +13,7 @@ import BasicTextSkeleton from "components/basicSkeletons/BasicTextSkeleton.vue";
</q-card-section>
<q-card-section class="q-my-md">
<BasicTextSkeleton :paragraphs="1" :lines="randomInt(1, 3)"/>
<BasicTextSkeleton :paragraphs="1" :lines="2"/>
</q-card-section>
</q-card>
@@ -1,5 +1,6 @@
<script setup>
import {randomInt} from "src/composables/random";
import {onBeforeMount, onMounted, ref} from "vue";
const props = defineProps({
itemsCountMin: {
@@ -12,13 +13,18 @@ const props = defineProps({
required:false,
default: 5
}
});
const items = ref(0);
onMounted(() => {
items.value = randomInt(props.itemsCountMin, props.itemsCountMax);
})
</script>
<template>
<q-list bordered separator>
<q-item v-ripple v-for="i in randomInt(itemsCountMin, itemsCountMax)" :key="i">
<q-item v-ripple v-for="i in items" :key="i">
<q-item-section avatar>
<q-skeleton type="QAvatar" />
</q-item-section>
@@ -26,7 +26,7 @@ import BasicTextSkeleton from "components/basicSkeletons/BasicTextSkeleton.vue";
</q-list>
<article class="q-my-lg">
<BasicTextSkeleton :lines="randomInt(2, 5)" :paragraphs="randomInt(1, 2)" />
<BasicTextSkeleton :lines="7" :paragraphs="2" />
</article>
<q-skeleton height="400px" square class="q-mt-lg"/>
@@ -4,7 +4,7 @@ import {randomInt} from "src/composables/random";
<template>
<q-list bordered separator class="q-mx-md q-my-md">
<q-item v-for="i in randomInt(5, 10)" :key="i" ripple>
<q-item v-for="i in 10" :key="i" ripple>
<q-item-section avatar>
<q-avatar size="100px">
<q-skeleton type="QAvatar" size="100px"></q-skeleton>
@@ -12,7 +12,6 @@ import {randomInt} from "src/composables/random";
</q-item-section>
<q-item-section>
<q-skeleton :width="randomInt(30,50)+'%'"/>
<q-skeleton type="text" :width="randomInt(10,15)+'%'"/>
<q-skeleton type="text" :width="randomInt(5,10)+'%'"/>
<q-skeleton type="text" width="8%"/>
+3 -8
View File
@@ -1,14 +1,10 @@
<script setup>
import {onMounted, onUnmounted, ref} from "vue";
import PhotoSwipeLightbox from "photoswipe/lightbox";
import {onMounted, onUnmounted} from "vue";
import 'photoswipe/style.css';
import "photoswipe-dynamic-caption-plugin/photoswipe-dynamic-caption-plugin.css";
import PhotoSwipeDynamicCaption from "photoswipe-dynamic-caption-plugin";
import MapWithMarkers from "components/map/MapWithMarkers.vue";
import {formatDatetime} from "src/composables/datetimeUtils";
import EmbeddedMap from "components/map/EmbeddedMap.vue";
import {roundWithPrecision} from "../../composables/utils";
import PhotoSwipeDynamicCaption from "../../../node_modules/photoswipe-dynamic-caption-plugin/photoswipe-dynamic-caption-plugin.esm";
import PhotoCaption from "components/photos/PhotoCaption.vue";
import PhotoSwipeLightbox from "../../../node_modules/photoswipe/dist/photoswipe-lightbox.esm"
const props = defineProps({
@@ -25,7 +21,6 @@ const props = defineProps({
let $lightbox = null;
onMounted(() => {
if (!$lightbox) {
$lightbox = new PhotoSwipeLightbox({
+2 -2
View File
@@ -6,12 +6,12 @@ import BasicTextSkeleton from "components/basicSkeletons/BasicTextSkeleton.vue";
<template>
<div>
<BasicTextSkeleton :lines="randomInt(4, 8)" />
<BasicTextSkeleton :lines="4" />
<q-skeleton type="rect" width="100%" class="q-my-lg" height="400px"/>
<div class="row">
<div class="col-12 col-sm-4 col-md-4 col-lg-3" v-for="i in randomInt(3, 10)" :key="i">
<div class="col-12 col-sm-4 col-md-4 col-lg-3" v-for="i in 6" :key="i">
<q-card class="q-my-sm q-mx-sm">
<q-skeleton type="rect" width="100%" height="200px"/>
</q-card>
@@ -15,7 +15,7 @@ import {randomInt} from "src/composables/random";
<q-skeleton class="inline-block" type="text" height="40px" :width="`${randomInt(60, 90)}%`"/>
</div>
<div class="q-mt-lg">
<BasicTextSkeleton :lines="randomInt(1, 5)" :paragraphs="1"/>
<BasicTextSkeleton :lines="3" :paragraphs="1"/>
</div>
</q-card-section>
</q-card>
+17 -17
View File
@@ -3,23 +3,23 @@
</template>
<script setup>
import {storeToRefs} from "pinia";
import {useUserStore} from "stores/User";
import {onMounted} from "vue";
import {useAppStore} from "stores/App";
import {useMeta} from "quasar";
// import {storeToRefs} from "pinia";
// import {useUserStore} from "stores/User";
// import {onMounted} from "vue";
// import {useAppStore} from "stores/App";
// import {useMeta} from "quasar";
const {pageTitle} = storeToRefs(useAppStore());
const loggedUser = storeToRefs(useUserStore()).user;
useMeta(() => ({
title: pageTitle.value !== '' ? `${pageTitle.value} - Polétání.cz` : 'Polétání.cz'
}));
onMounted(() => {
if (useUserStore().getAccessToken()) {
useUserStore().fetchLoggedUserDetail();
}
})
// const {pageTitle} = storeToRefs(useAppStore());
const loggedUser = null;//storeToRefs(useUserStore()).user;
//
// useMeta(() => ({
// title: pageTitle.value !== '' ? `${pageTitle.value} - Polétání.cz` : 'Polétání.cz'
// }));
//
// onMounted(() => {
// if (useUserStore().getAccessToken()) {
// useUserStore().fetchLoggedUserDetail();
// }
// })
</script>
+1 -1
View File
@@ -43,7 +43,7 @@ watch(() => [adjustment.value, croppedAreaForPreview.value], debounce(() => {
const savePhotoAdjustment = (photoId) => {
const adjustmentInput = {...adjustment.value};
if (croppedArea.value.left !== null) {
if (croppedArea.value && croppedArea.value.left !== null) {
adjustmentInput.crop = {...croppedArea.value}
}
+15
View File
@@ -0,0 +1,15 @@
<script setup>
import {useAircraftsStore} from "stores/Aircrafts";
import {onMounted} from "vue";
import {storeToRefs} from "pinia";
const {aircraft, isQueryRunning, aircrafts} = storeToRefs(useAircraftsStore());
onMounted(() => {
useAircraftsStore().fetch();
});
</script>
<template>
<q-spinner v-if="isQueryRunning" />
letadlo: {{ aircrafts }}
</template>
+2 -11
View File
@@ -3,16 +3,7 @@ import {createRouter, createMemoryHistory, createWebHistory, createWebHashHistor
import routes from './routes'
import {useAppStore} from "stores/App";
/*
* If not building with SSR mode, you can
* directly export the Router instantiation;
*
* The function below can be async too; either use
* async/await or return a Promise which resolves
* with the Router instance.
*/
export default route(function (/* { store, ssrContext } */) {
export default route(function ({ store }) {
const createHistory = process.env.SERVER
? createMemoryHistory
: (process.env.VUE_ROUTER_MODE === 'history' ? createWebHistory : createWebHashHistory)
@@ -29,7 +20,7 @@ export default route(function (/* { store, ssrContext } */) {
Router.afterEach(async (to, from) => {
if (from.name !== to.name) {
useAppStore().resetAfterRouteChange();
useAppStore(store).resetAfterRouteChange();
}
});
+5 -4
View File
@@ -1,6 +1,7 @@
import PlainLayout from "layouts/PlainLayout.vue";
const routes = [
{path: '/test', name: "test", component: () => import('pages/public/TestPage.vue'), meta: {layout: PlainLayout}},
{path: '/login', name: "login", component: () => import('pages/public/LoginPage.vue'), meta: {layout: PlainLayout}},
{path: '/registrace', name: "registration", component: () => import('pages/public/RegisterPage.vue'), meta: {layout: PlainLayout}},
{path: '/zapomenute-heslo', name: "forgottenPassword", component: () => import('pages/public/RegisterPage.vue'), meta: {layout: PlainLayout}},
@@ -68,10 +69,10 @@ const routes = [
// Always leave this as last one,
// but you can also remove it
{
path: '/:catchAll(.*)*',
component: () => import('pages/ErrorNotFound.vue')
}
// {
// path: '/:catchAll(.*)*',
// component: () => import('pages/ErrorNotFound.vue')
// }
]
export default routes