Zaklad ssr
This commit is contained in:
+9
-6
@@ -13,12 +13,15 @@ FROM develop-stage as build-stage
|
|||||||
#ENV VUE_API_URL $API_URL
|
#ENV VUE_API_URL $API_URL
|
||||||
|
|
||||||
RUN yarn --production=false
|
RUN yarn --production=false
|
||||||
RUN quasar build
|
RUN quasar build -m ssr
|
||||||
|
|
||||||
# production stage
|
# production stage
|
||||||
FROM nginx:1.25-alpine as production-stage
|
#FROM nginx:1.25-alpine as production-stage
|
||||||
COPY conf/nginx.conf /etc/nginx/nginx.conf
|
#COPY conf/nginx.conf /etc/nginx/nginx.conf
|
||||||
COPY --from=build-stage /app/dist/spa /app/html
|
#COPY --from=build-stage /app/dist/spa /app/html
|
||||||
EXPOSE 80
|
#EXPOSE 80
|
||||||
|
#
|
||||||
|
#CMD ["nginx", "-g", "daemon off;"]
|
||||||
|
|
||||||
|
FROM keymetrics/pm2:latest-alpine as production-stage
|
||||||
|
|
||||||
CMD ["nginx", "-g", "daemon off;"]
|
|
||||||
|
|||||||
+2
-1
@@ -29,11 +29,12 @@ services:
|
|||||||
target: "develop-stage"
|
target: "develop-stage"
|
||||||
ports:
|
ports:
|
||||||
- "9000:9000"
|
- "9000:9000"
|
||||||
|
- "9001:9100"
|
||||||
volumes:
|
volumes:
|
||||||
- ./src:/app/src
|
- ./src:/app/src
|
||||||
- ./public:/app/public
|
- ./public:/app/public
|
||||||
- ./node_modules:/app/node_modules:delegated
|
- ./node_modules:/app/node_modules:delegated
|
||||||
command: quasar dev
|
command: quasar dev -m ssr
|
||||||
environment:
|
environment:
|
||||||
API_URL: "http://localhost:8000"
|
API_URL: "http://localhost:8000"
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -30,7 +30,7 @@ module.exports = configure(function (ctx) {
|
|||||||
// https://v2.quasar.dev/quasar-cli/boot-files
|
// https://v2.quasar.dev/quasar-cli/boot-files
|
||||||
boot: [
|
boot: [
|
||||||
"axios",
|
"axios",
|
||||||
"chartJs",
|
"chartJs"
|
||||||
],
|
],
|
||||||
|
|
||||||
// https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#css
|
// https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#css
|
||||||
@@ -135,10 +135,10 @@ module.exports = configure(function (ctx) {
|
|||||||
|
|
||||||
// https://v2.quasar.dev/quasar-cli/developing-ssr/configuring-ssr
|
// https://v2.quasar.dev/quasar-cli/developing-ssr/configuring-ssr
|
||||||
ssr: {
|
ssr: {
|
||||||
// ssrPwaHtmlFilename: 'offline.html', // do NOT use index.html as name!
|
ssrPwaHtmlFilename: 'offline.html', // do NOT use index.html as name!
|
||||||
// will mess up SSR
|
// will mess up SSR
|
||||||
|
|
||||||
// extendSSRWebserverConf (esbuildConf) {},
|
extendSSRWebserverConf (esbuildConf) {},
|
||||||
// extendPackageJson (json) {},
|
// extendPackageJson (json) {},
|
||||||
|
|
||||||
pwa: false,
|
pwa: false,
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
import { ssrMiddleware } from 'quasar/wrappers'
|
||||||
|
|
||||||
|
// This middleware should execute as last one
|
||||||
|
// since it captures everything and tries to
|
||||||
|
// render the page with Vue
|
||||||
|
|
||||||
|
export default ssrMiddleware(({ app, resolve, render, serve }) => {
|
||||||
|
// we capture any other Express route and hand it
|
||||||
|
// over to Vue and Vue Router to render our page
|
||||||
|
app.get(resolve.urlPath('*'), (req, res) => {
|
||||||
|
res.setHeader('Content-Type', 'text/html')
|
||||||
|
|
||||||
|
render(/* the ssrContext: */ { req, res })
|
||||||
|
.then(html => {
|
||||||
|
// now let's send the rendered html to the client
|
||||||
|
res.send(html)
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
// oops, we had an error while rendering the page
|
||||||
|
|
||||||
|
// we were told to redirect to another URL
|
||||||
|
if (err.url) {
|
||||||
|
if (err.code) {
|
||||||
|
res.redirect(err.code, err.url)
|
||||||
|
} else {
|
||||||
|
res.redirect(err.url)
|
||||||
|
}
|
||||||
|
} else if (err.code === 404) {
|
||||||
|
// hmm, Vue Router could not find the requested route
|
||||||
|
|
||||||
|
// Should reach here only if no "catch-all" route
|
||||||
|
// is defined in /src/routes
|
||||||
|
res.status(404).send('404 | Page Not Found')
|
||||||
|
} else if (process.env.DEV) {
|
||||||
|
// well, we treat any other code as error;
|
||||||
|
// if we're in dev mode, then we can use Quasar CLI
|
||||||
|
// to display a nice error page that contains the stack
|
||||||
|
// and other useful information
|
||||||
|
|
||||||
|
// serve.error is available on dev only
|
||||||
|
serve.error({ err, req, res })
|
||||||
|
} else {
|
||||||
|
// we're in production, so we should have another method
|
||||||
|
// to display something to the client when we encounter an error
|
||||||
|
// (for security reasons, it's not ok to display the same wealth
|
||||||
|
// of information as we do in development)
|
||||||
|
|
||||||
|
// Render Error Page on production or
|
||||||
|
// create a route (/src/routes) for an error page and redirect to it
|
||||||
|
res.status(500).send('500 | Internal Server Error')
|
||||||
|
// console.error(err.stack)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -0,0 +1,136 @@
|
|||||||
|
/**
|
||||||
|
* More info about this file:
|
||||||
|
* https://v2.quasar.dev/quasar-cli-vite/developing-ssr/ssr-webserver
|
||||||
|
*
|
||||||
|
* Runs in Node context.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make sure to yarn add / npm install (in your project root)
|
||||||
|
* anything you import here (except for express and compression).
|
||||||
|
*/
|
||||||
|
import express from 'express'
|
||||||
|
import compression from 'compression'
|
||||||
|
import {
|
||||||
|
ssrClose,
|
||||||
|
ssrCreate,
|
||||||
|
ssrListen,
|
||||||
|
ssrRenderPreloadTag,
|
||||||
|
ssrServeStaticContent
|
||||||
|
} from 'quasar/wrappers'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create your webserver and return its instance.
|
||||||
|
* If needed, prepare your webserver to receive
|
||||||
|
* connect-like middlewares.
|
||||||
|
*
|
||||||
|
* Should NOT be async!
|
||||||
|
*/
|
||||||
|
export const create = ssrCreate((/* { ... } */) => {
|
||||||
|
const app = express()
|
||||||
|
|
||||||
|
// attackers can use this header to detect apps running Express
|
||||||
|
// and then launch specifically-targeted attacks
|
||||||
|
app.disable('x-powered-by')
|
||||||
|
|
||||||
|
// place here any middlewares that
|
||||||
|
// absolutely need to run before anything else
|
||||||
|
if (process.env.PROD) {
|
||||||
|
app.use(compression())
|
||||||
|
}
|
||||||
|
|
||||||
|
return app
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* You need to make the server listen to the indicated port
|
||||||
|
* and return the listening instance or whatever you need to
|
||||||
|
* close the server with.
|
||||||
|
*
|
||||||
|
* The "listenResult" param for the "close()" definition below
|
||||||
|
* is what you return here.
|
||||||
|
*
|
||||||
|
* For production, you can instead export your
|
||||||
|
* handler for serverless use or whatever else fits your needs.
|
||||||
|
*/
|
||||||
|
export const listen = ssrListen(async ({ app, port, isReady }) => {
|
||||||
|
await isReady()
|
||||||
|
return app.listen(port, () => {
|
||||||
|
if (process.env.PROD) {
|
||||||
|
console.log('Server listening at port ' + port)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should close the server and free up any resources.
|
||||||
|
* Will be used on development only when the server needs
|
||||||
|
* to be rebooted.
|
||||||
|
*
|
||||||
|
* Should you need the result of the "listen()" call above,
|
||||||
|
* you can use the "listenResult" param.
|
||||||
|
*
|
||||||
|
* Can be async.
|
||||||
|
*/
|
||||||
|
export const close = ssrClose(({ listenResult }) => {
|
||||||
|
return listenResult.close()
|
||||||
|
})
|
||||||
|
|
||||||
|
const maxAge = process.env.DEV
|
||||||
|
? 0
|
||||||
|
: 1000 * 60 * 60 * 24 * 30
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should return middleware that serves the indicated path
|
||||||
|
* with static content.
|
||||||
|
*/
|
||||||
|
export const serveStaticContent = ssrServeStaticContent((path, opts) => {
|
||||||
|
return express.static(path, {
|
||||||
|
maxAge,
|
||||||
|
...opts
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
const jsRE = /\.js$/
|
||||||
|
const cssRE = /\.css$/
|
||||||
|
const woffRE = /\.woff$/
|
||||||
|
const woff2RE = /\.woff2$/
|
||||||
|
const gifRE = /\.gif$/
|
||||||
|
const jpgRE = /\.jpe?g$/
|
||||||
|
const pngRE = /\.png$/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should return a String with HTML output
|
||||||
|
* (if any) for preloading indicated file
|
||||||
|
*/
|
||||||
|
export const renderPreloadTag = ssrRenderPreloadTag((file) => {
|
||||||
|
if (jsRE.test(file) === true) {
|
||||||
|
return `<link rel="modulepreload" href="${file}" crossorigin>`
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cssRE.test(file) === true) {
|
||||||
|
return `<link rel="stylesheet" href="${file}">`
|
||||||
|
}
|
||||||
|
|
||||||
|
if (woffRE.test(file) === true) {
|
||||||
|
return `<link rel="preload" href="${file}" as="font" type="font/woff" crossorigin>`
|
||||||
|
}
|
||||||
|
|
||||||
|
if (woff2RE.test(file) === true) {
|
||||||
|
return `<link rel="preload" href="${file}" as="font" type="font/woff2" crossorigin>`
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gifRE.test(file) === true) {
|
||||||
|
return `<link rel="preload" href="${file}" as="image" type="image/gif">`
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jpgRE.test(file) === true) {
|
||||||
|
return `<link rel="preload" href="${file}" as="image" type="image/jpeg">`
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pngRE.test(file) === true) {
|
||||||
|
return `<link rel="preload" href="${file}" as="image" type="image/png">`
|
||||||
|
}
|
||||||
|
|
||||||
|
return ''
|
||||||
|
})
|
||||||
Vendored
+10
@@ -0,0 +1,10 @@
|
|||||||
|
/* eslint-disable */
|
||||||
|
// THIS FEATURE-FLAG FILE IS AUTOGENERATED,
|
||||||
|
// REMOVAL OR CHANGES WILL CAUSE RELATED TYPES TO STOP WORKING
|
||||||
|
import "quasar/dist/types/feature-flag";
|
||||||
|
|
||||||
|
declare module "quasar/dist/types/feature-flag" {
|
||||||
|
interface QuasarFeatureFlags {
|
||||||
|
ssr: true;
|
||||||
|
}
|
||||||
|
}
|
||||||
+10
-8
@@ -2,6 +2,7 @@ import {boot} from 'quasar/wrappers'
|
|||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import {useUserStore} from "stores/User";
|
import {useUserStore} from "stores/User";
|
||||||
|
|
||||||
|
|
||||||
const api = axios.create({
|
const api = axios.create({
|
||||||
baseURL: process.env.API_URL,
|
baseURL: process.env.API_URL,
|
||||||
withCredentials: true,
|
withCredentials: true,
|
||||||
@@ -12,8 +13,10 @@ const api = axios.create({
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
api.interceptors.request.use((config) => {
|
export default boot(({app, store}) => {
|
||||||
const token = useUserStore().getAccessToken();
|
|
||||||
|
api.interceptors.request.use((config) => {
|
||||||
|
const token = useUserStore(store).getAccessToken();
|
||||||
if (token) {
|
if (token) {
|
||||||
config.headers['Authorization'] = `Bearer ${token}`
|
config.headers['Authorization'] = `Bearer ${token}`
|
||||||
}
|
}
|
||||||
@@ -23,15 +26,15 @@ api.interceptors.request.use((config) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
})
|
})
|
||||||
|
|
||||||
// Response interceptor for API calls
|
// Response interceptor for API calls
|
||||||
api.interceptors.response.use((response) => {
|
api.interceptors.response.use((response) => {
|
||||||
return response
|
return response
|
||||||
}, async function (error) {
|
}, async function (error) {
|
||||||
const originalRequest = error.config;
|
const originalRequest = error.config;
|
||||||
if (error.response.status === 401 && !['/refresh', '/login'].includes(originalRequest.url)) {
|
if (error.response.status === 401 && !['/refresh', '/login'].includes(originalRequest.url)) {
|
||||||
const newToken = await useUserStore().refreshAccessToken().catch(err => {
|
const newToken = await useUserStore(store).refreshAccessToken().catch(err => {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
return Promise.reject("Logged out");
|
return Promise.reject("Logged out");
|
||||||
})
|
})
|
||||||
@@ -39,10 +42,9 @@ api.interceptors.response.use((response) => {
|
|||||||
return api(originalRequest);
|
return api(originalRequest);
|
||||||
}
|
}
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
export default boot(({app}) => {
|
|
||||||
// for use inside Vue files (Options API) through this.$axios and this.$api
|
// for use inside Vue files (Options API) through this.$axios and this.$api
|
||||||
|
|
||||||
// app.config.globalProperties.$axios = axios
|
// app.config.globalProperties.$axios = axios
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import BasicTextSkeleton from "components/basicSkeletons/BasicTextSkeleton.vue";
|
|||||||
</q-card-section>
|
</q-card-section>
|
||||||
|
|
||||||
<q-card-section class="q-my-md">
|
<q-card-section class="q-my-md">
|
||||||
<BasicTextSkeleton :paragraphs="1" :lines="randomInt(1, 3)"/>
|
<BasicTextSkeleton :paragraphs="1" :lines="2"/>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
</q-card>
|
</q-card>
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import {randomInt} from "src/composables/random";
|
import {randomInt} from "src/composables/random";
|
||||||
|
import {onBeforeMount, onMounted, ref} from "vue";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
itemsCountMin: {
|
itemsCountMin: {
|
||||||
@@ -12,13 +13,18 @@ const props = defineProps({
|
|||||||
required:false,
|
required:false,
|
||||||
default: 5
|
default: 5
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const items = ref(0);
|
||||||
|
onMounted(() => {
|
||||||
|
items.value = randomInt(props.itemsCountMin, props.itemsCountMax);
|
||||||
})
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<q-list bordered separator>
|
<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-item-section avatar>
|
||||||
<q-skeleton type="QAvatar" />
|
<q-skeleton type="QAvatar" />
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import BasicTextSkeleton from "components/basicSkeletons/BasicTextSkeleton.vue";
|
|||||||
</q-list>
|
</q-list>
|
||||||
|
|
||||||
<article class="q-my-lg">
|
<article class="q-my-lg">
|
||||||
<BasicTextSkeleton :lines="randomInt(2, 5)" :paragraphs="randomInt(1, 2)" />
|
<BasicTextSkeleton :lines="7" :paragraphs="2" />
|
||||||
</article>
|
</article>
|
||||||
|
|
||||||
<q-skeleton height="400px" square class="q-mt-lg"/>
|
<q-skeleton height="400px" square class="q-mt-lg"/>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import {randomInt} from "src/composables/random";
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<q-list bordered separator class="q-mx-md q-my-md">
|
<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-item-section avatar>
|
||||||
<q-avatar size="100px">
|
<q-avatar size="100px">
|
||||||
<q-skeleton type="QAvatar" size="100px"></q-skeleton>
|
<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-item-section>
|
<q-item-section>
|
||||||
<q-skeleton :width="randomInt(30,50)+'%'"/>
|
<q-skeleton :width="randomInt(30,50)+'%'"/>
|
||||||
|
|
||||||
<q-skeleton type="text" :width="randomInt(10,15)+'%'"/>
|
<q-skeleton type="text" :width="randomInt(10,15)+'%'"/>
|
||||||
<q-skeleton type="text" :width="randomInt(5,10)+'%'"/>
|
<q-skeleton type="text" :width="randomInt(5,10)+'%'"/>
|
||||||
<q-skeleton type="text" width="8%"/>
|
<q-skeleton type="text" width="8%"/>
|
||||||
|
|||||||
@@ -1,14 +1,10 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import {onMounted, onUnmounted, ref} from "vue";
|
import {onMounted, onUnmounted} from "vue";
|
||||||
import PhotoSwipeLightbox from "photoswipe/lightbox";
|
|
||||||
import 'photoswipe/style.css';
|
import 'photoswipe/style.css';
|
||||||
import "photoswipe-dynamic-caption-plugin/photoswipe-dynamic-caption-plugin.css";
|
import "photoswipe-dynamic-caption-plugin/photoswipe-dynamic-caption-plugin.css";
|
||||||
import PhotoSwipeDynamicCaption from "photoswipe-dynamic-caption-plugin";
|
import PhotoSwipeDynamicCaption from "../../../node_modules/photoswipe-dynamic-caption-plugin/photoswipe-dynamic-caption-plugin.esm";
|
||||||
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 PhotoCaption from "components/photos/PhotoCaption.vue";
|
import PhotoCaption from "components/photos/PhotoCaption.vue";
|
||||||
|
import PhotoSwipeLightbox from "../../../node_modules/photoswipe/dist/photoswipe-lightbox.esm"
|
||||||
|
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@@ -25,7 +21,6 @@ const props = defineProps({
|
|||||||
|
|
||||||
let $lightbox = null;
|
let $lightbox = null;
|
||||||
|
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if (!$lightbox) {
|
if (!$lightbox) {
|
||||||
$lightbox = new PhotoSwipeLightbox({
|
$lightbox = new PhotoSwipeLightbox({
|
||||||
|
|||||||
@@ -6,12 +6,12 @@ import BasicTextSkeleton from "components/basicSkeletons/BasicTextSkeleton.vue";
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
|
|
||||||
<BasicTextSkeleton :lines="randomInt(4, 8)" />
|
<BasicTextSkeleton :lines="4" />
|
||||||
|
|
||||||
<q-skeleton type="rect" width="100%" class="q-my-lg" height="400px"/>
|
<q-skeleton type="rect" width="100%" class="q-my-lg" height="400px"/>
|
||||||
|
|
||||||
<div class="row">
|
<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-card class="q-my-sm q-mx-sm">
|
||||||
<q-skeleton type="rect" width="100%" height="200px"/>
|
<q-skeleton type="rect" width="100%" height="200px"/>
|
||||||
</q-card>
|
</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)}%`"/>
|
<q-skeleton class="inline-block" type="text" height="40px" :width="`${randomInt(60, 90)}%`"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="q-mt-lg">
|
<div class="q-mt-lg">
|
||||||
<BasicTextSkeleton :lines="randomInt(1, 5)" :paragraphs="1"/>
|
<BasicTextSkeleton :lines="3" :paragraphs="1"/>
|
||||||
</div>
|
</div>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
</q-card>
|
</q-card>
|
||||||
|
|||||||
+17
-17
@@ -3,23 +3,23 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import {storeToRefs} from "pinia";
|
// import {storeToRefs} from "pinia";
|
||||||
import {useUserStore} from "stores/User";
|
// import {useUserStore} from "stores/User";
|
||||||
import {onMounted} from "vue";
|
// import {onMounted} from "vue";
|
||||||
import {useAppStore} from "stores/App";
|
// import {useAppStore} from "stores/App";
|
||||||
import {useMeta} from "quasar";
|
// import {useMeta} from "quasar";
|
||||||
|
|
||||||
const {pageTitle} = storeToRefs(useAppStore());
|
// const {pageTitle} = storeToRefs(useAppStore());
|
||||||
const loggedUser = storeToRefs(useUserStore()).user;
|
const loggedUser = null;//storeToRefs(useUserStore()).user;
|
||||||
|
//
|
||||||
useMeta(() => ({
|
// useMeta(() => ({
|
||||||
title: pageTitle.value !== '' ? `${pageTitle.value} - Polétání.cz` : 'Polétání.cz'
|
// title: pageTitle.value !== '' ? `${pageTitle.value} - Polétání.cz` : 'Polétání.cz'
|
||||||
}));
|
// }));
|
||||||
|
//
|
||||||
onMounted(() => {
|
// onMounted(() => {
|
||||||
if (useUserStore().getAccessToken()) {
|
// if (useUserStore().getAccessToken()) {
|
||||||
useUserStore().fetchLoggedUserDetail();
|
// useUserStore().fetchLoggedUserDetail();
|
||||||
}
|
// }
|
||||||
})
|
// })
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ watch(() => [adjustment.value, croppedAreaForPreview.value], debounce(() => {
|
|||||||
const savePhotoAdjustment = (photoId) => {
|
const savePhotoAdjustment = (photoId) => {
|
||||||
const adjustmentInput = {...adjustment.value};
|
const adjustmentInput = {...adjustment.value};
|
||||||
|
|
||||||
if (croppedArea.value.left !== null) {
|
if (croppedArea.value && croppedArea.value.left !== null) {
|
||||||
adjustmentInput.crop = {...croppedArea.value}
|
adjustmentInput.crop = {...croppedArea.value}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
@@ -3,16 +3,7 @@ import {createRouter, createMemoryHistory, createWebHistory, createWebHashHistor
|
|||||||
import routes from './routes'
|
import routes from './routes'
|
||||||
import {useAppStore} from "stores/App";
|
import {useAppStore} from "stores/App";
|
||||||
|
|
||||||
/*
|
export default route(function ({ store }) {
|
||||||
* 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 } */) {
|
|
||||||
const createHistory = process.env.SERVER
|
const createHistory = process.env.SERVER
|
||||||
? createMemoryHistory
|
? createMemoryHistory
|
||||||
: (process.env.VUE_ROUTER_MODE === 'history' ? createWebHistory : createWebHashHistory)
|
: (process.env.VUE_ROUTER_MODE === 'history' ? createWebHistory : createWebHashHistory)
|
||||||
@@ -29,7 +20,7 @@ export default route(function (/* { store, ssrContext } */) {
|
|||||||
|
|
||||||
Router.afterEach(async (to, from) => {
|
Router.afterEach(async (to, from) => {
|
||||||
if (from.name !== to.name) {
|
if (from.name !== to.name) {
|
||||||
useAppStore().resetAfterRouteChange();
|
useAppStore(store).resetAfterRouteChange();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import PlainLayout from "layouts/PlainLayout.vue";
|
import PlainLayout from "layouts/PlainLayout.vue";
|
||||||
|
|
||||||
const routes = [
|
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: '/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: '/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}},
|
{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,
|
// Always leave this as last one,
|
||||||
// but you can also remove it
|
// but you can also remove it
|
||||||
{
|
// {
|
||||||
path: '/:catchAll(.*)*',
|
// path: '/:catchAll(.*)*',
|
||||||
component: () => import('pages/ErrorNotFound.vue')
|
// component: () => import('pages/ErrorNotFound.vue')
|
||||||
}
|
// }
|
||||||
]
|
]
|
||||||
|
|
||||||
export default routes
|
export default routes
|
||||||
|
|||||||
Reference in New Issue
Block a user