diff --git a/Dockerfile b/Dockerfile
index d854ec1..31de7a2 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -2,26 +2,28 @@
FROM node:20-alpine as develop-stage
WORKDIR /app
-COPY package*.json ./
-RUN yarn global add @quasar/cli && yarn --production=false
+RUN yarn global add @quasar/cli
+
+COPY package.json yarn.lock ./
+RUN yarn --production=false
+RUN npx update-browserslist-db@latest
COPY . .
# build stage
FROM develop-stage as build-stage
-
-#ARG API_URL
-#ENV VUE_API_URL $API_URL
-
-RUN yarn --production=false
RUN quasar build -m ssr
-# production stage
-#FROM nginx:1.25-alpine as production-stage
-#COPY conf/nginx.conf /etc/nginx/nginx.conf
-#COPY --from=build-stage /app/dist/spa /app/html
-#EXPOSE 80
-#
-#CMD ["nginx", "-g", "daemon off;"]
+FROM node:20-alpine as production-stage
-FROM keymetrics/pm2:latest-alpine as production-stage
+ENV NODE_ENV production
+EXPOSE 3000
+WORKDIR /app
+
+COPY process.yml /app
+COPY --from=build-stage /app/dict/ssr/package.json /app
+RUN yarn global add pm2 && yarn && yarn cache clean
+
+COPY --from=build-stage /app/dist/ssr /app
+
+CMD ["pm2-runtime", "/app/process.yml"]
diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml
index 5070edc..e3ee00f 100644
--- a/docker-compose.prod.yml
+++ b/docker-compose.prod.yml
@@ -1,7 +1,12 @@
-version: "3.3"
+version: "3.4"
services:
poletani-app:
image: "docker.kvacek.cz/poletani/app:latest"
+# build:
+# context: .
+# dockerfile: Dockerfile
+# target: "production-stage"
restart: always
ports:
- - 9000:80
+# - 9000:80
+ - 9000:3000
diff --git a/docker-compose.yml b/docker-compose.yml
index da7a96a..f0651c7 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -24,6 +24,7 @@ services:
## command: ls -l /app
app:
+ network_mode: host
build:
context: .
target: "develop-stage"
diff --git a/index.html b/index.html
index 3c8c78f..e581fa7 100644
--- a/index.html
+++ b/index.html
@@ -1,10 +1,7 @@
- <%= productName %>
-
-
diff --git a/process.yml b/process.yml
new file mode 100644
index 0000000..4fcd19f
--- /dev/null
+++ b/process.yml
@@ -0,0 +1,5 @@
+apps:
+ - name: poletani
+ script: /app/index.js
+ exec_mode: cluster
+ instances: 3
diff --git a/quasar.config.js b/quasar.config.js
index fb36068..de24d6e 100644
--- a/quasar.config.js
+++ b/quasar.config.js
@@ -23,7 +23,7 @@ module.exports = configure(function (ctx) {
},
// https://v2.quasar.dev/quasar-cli/prefetch-feature
- // preFetch: true,
+ preFetch: true,
// app boot file (/poletani/boot)
// --> boot files are part of "main.js"
@@ -56,7 +56,7 @@ module.exports = configure(function (ctx) {
build: {
target: {
browser: ['es2019', 'edge88', 'firefox78', 'chrome87', 'safari13.1'],
- node: 'node18'
+ node: 'node20'
},
env: {
@@ -76,7 +76,7 @@ module.exports = configure(function (ctx) {
// env: {},
// rawDefine: {}
// ignorePublicFolder: true,
- // minify: false,
+ minify: true,
// polyfillModulePreload: true,
// distDir
diff --git a/src/App.vue b/src/App.vue
index 7e98841..17dfbe1 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -7,7 +7,6 @@ import {useAppStore} from "stores/App";
const route = useRoute();
-
const layoutComponent = computed(() => {
if (!route.meta) return null;
return route.meta.layout;
diff --git a/src/boot/apollo.js b/src/boot/apollo.js
index add596f..dfd699a 100644
--- a/src/boot/apollo.js
+++ b/src/boot/apollo.js
@@ -1,4 +1,3 @@
-// import {boot} from "quasar/wrappers";
import {ApolloClient, ApolloLink, fromPromise, InMemoryCache} from '@apollo/client/core'
import {createUploadLink} from 'apollo-upload-client';
import {onError} from "@apollo/client/link/error";
@@ -8,89 +7,86 @@ import {Notify} from "quasar";
import {errorObject, warningObject} from "src/composables/dialog";
const handleRefreshToken = (store, forward, operation) => {
- return fromPromise(useUserStore(store).refreshAccessToken()
- .catch((error) => {
- Notify.create(warningObject("Tvoje přihlášení vypřešlo. Přihlaš se prosím znovu."));
- window.location = "/login";
- }))
- .filter((value) => Boolean(value))
- .flatMap((accessToken) => {
- const oldHeaders = operation.getContext().headers;
- operation.setContext({
- headers: {
- ...oldHeaders, authorization: `Bearer ${accessToken}`,
- },
- });
+ if (!operation._refreshUnauthorizedUser) return;
- // retry the request, returning the new observable
- return forward(operation);
- });
+ return fromPromise(useUserStore(store).refreshAccessToken()
+ .catch((error) => {
+ Notify.create(warningObject("Tvoje přihlášení vypřešlo. Přihlaš se prosím znovu."));
+ window.location = "/login";
+ }))
+ .filter((value) => Boolean(value))
+ .flatMap((accessToken) => {
+ const oldHeaders = operation.getContext().headers;
+ operation.setContext({
+ headers: {
+ ...oldHeaders,
+ authorization: `Bearer ${accessToken}`,
+ },
+ });
+
+ // retry the request, returning the new observable
+ return forward(operation);
+ });
}
-
-
export const apolloWrapper = {};
export default (({store}) => {
- const uploadLink = createUploadLink({
- uri: process.env.API_URL + '/graphql',
+ const uploadLink = createUploadLink({
+ uri: process.env.API_URL + '/graphql',
+ })
+
+ const authLink = new ApolloLink((operation, forward) => {
+ const accessToken = useUserStore(store).getAccessToken();
+
+ if (accessToken) {
+ operation.setContext({
+ headers: {"Authorization": `Bearer ${accessToken}`},
+ });
+ }
+ return forward(operation);
+ });
+
+ const errorLink = onError(({graphQLErrors, networkError, operation, forward}) => {
+ if (networkError?.statusCode === 401) {
+ return handleRefreshToken(store, forward, operation);
+ }
+
+ if (graphQLErrors) {
+ for (const error of graphQLErrors) {
+ if (error.message === "Not found") {
+ useAppStore(store).appStatus = 404;
+ } else if (error.message.includes("401") || error.message.includes("Not authorized")) {
+ return handleRefreshToken(store, forward, operation);
+ } else {
+ Notify.create(errorObject("API error: " + error.message));
+ }
+ }
+ }
+ });
+
+ const apolloClient = new ApolloClient({
+ link: ApolloLink.from([authLink, errorLink, uploadLink]), cache: new InMemoryCache(), connectToDevTools: true,
+ });
+
+ apolloWrapper.query = (query, variables = {}) => {
+ return apolloClient.query({
+ query: query, fetchPolicy: 'no-cache', variables: variables
})
-
- const authLink = new ApolloLink((operation, forward) => {
- const accessToken = useUserStore(store).getAccessToken();
-
- if (accessToken) {
- operation.setContext({
- headers: {"Authorization": `Bearer ${accessToken}`},
- });
- }
- return forward(operation);
- });
-
- const errorLink = onError(({graphQLErrors, networkError, operation, forward}) => {
- if (networkError?.statusCode === 401) {
- return handleRefreshToken(store, forward, operation);
- }
-
- if (graphQLErrors) {
- for (const error of graphQLErrors) {
- if (error.message === "Not found") {
- useAppStore(store).appStatus = 404;
- } else if (error.message.includes("401") || error.message.includes("Not authorized")) {
- return handleRefreshToken(store, forward, operation);
- } else {
- Notify.create(errorObject("API error: " + error.message));
- }
- }
- }
- });
-
-
- const apolloClient = new ApolloClient({
- link: ApolloLink.from([authLink, errorLink, uploadLink]), cache: new InMemoryCache(), connectToDevTools: true,
- });
- // const apolloProvider = createApolloProvider({
- // defaultClient: apolloClient,
- // });
-
-
- apolloWrapper.query = (query, variables = {}) => {
- return apolloClient.query({
- query: query, fetchPolicy: 'no-cache', variables: variables
- })
- .then((response) => response)
- .catch(err => {
- console.error("Error during query: ", err)
- return err;
- })
- };
- apolloWrapper.mutate = (mutation, variables) => {
- return apolloClient
- .mutate({
- mutation: mutation, fetchPolicy: 'no-cache', variables: variables,
- })
- .then((response) => response)
- .catch(err => {
- console.error("Error during mutation: ", err);
- })
- };
+ .then((response) => response)
+ .catch(err => {
+ if (!err.toString().includes("401") && !err.toString().includes("Not authorized"))
+ console.error("Error during query: ", err)
+ return err;
+ })
+ };
+ apolloWrapper.mutate = (mutation, variables) => {
+ return apolloClient
+ .mutate({
+ mutation: mutation, fetchPolicy: 'no-cache', variables: variables,
+ })
+ .then((response) => response)
+ .catch(err => {
+ console.error("Error during mutation: ", err);
+ })
+ };
});
diff --git a/src/composables/meta.js b/src/composables/meta.js
new file mode 100644
index 0000000..a41887b
--- /dev/null
+++ b/src/composables/meta.js
@@ -0,0 +1,22 @@
+export const metaData = ({title, description, keywords, image}) => {
+ return {
+ title: title || "",
+ titleTemplate(title) {
+ return title !== '' ? `${title} - Polétání.cz` : 'Polétání.cz'
+ },
+ meta: {
+ description: {name: "description", content: description || ""},
+ keywords: {name: "keywords", content: (keywords || []).join(", ")},
+ ogImage: image ? {property: "og:image", content: image} : undefined,
+ ogTitle: {
+ property: "og:title",
+ content: title,
+ template(ogTitle) {
+ return (!ogTitle || ogTitle === '') ? "Polétání.cz" : `${ogTitle} - Polétání.cz`
+ }
+ }
+ }
+ }
+}
+
+export const commonKeywords = ["zápisník", "létání", "ultralight", "letectví", "fotogalerie", "výlet", "vyhlídkový let", "navigační let"];
diff --git a/src/composables/photos/editor/crop.js b/src/composables/photos/editor/crop.js
index 095166d..42f0bf2 100644
--- a/src/composables/photos/editor/crop.js
+++ b/src/composables/photos/editor/crop.js
@@ -13,7 +13,6 @@ export const croppedArea = ref(null);
export const selectedAspectRatio = ref(null);
watch(() => selectedAspectRatio.value, (newVal) => {
- console.log(newVal);
cropper.setAspectRatio(newVal);
})
diff --git a/src/composables/photos/editor/splitter.js b/src/composables/photos/editor/splitter.js
index 2ce6a75..b733c97 100644
--- a/src/composables/photos/editor/splitter.js
+++ b/src/composables/photos/editor/splitter.js
@@ -2,7 +2,7 @@ import {ref} from "vue";
export const compare = ref(false);
-export const splitterWidth = ref(750); // TODO: doresit onresize a zmenu velikosti
+export const splitterWidth = ref(750);
export const splitter = ref(50);
export const onResize = (info) => {
splitterWidth.value = info.width < 750 ? info.width : 750;
diff --git a/src/layouts/ProfileLayout.vue b/src/layouts/ProfileLayout.vue
index 9dff330..c99d30e 100644
--- a/src/layouts/ProfileLayout.vue
+++ b/src/layouts/ProfileLayout.vue
@@ -25,9 +25,8 @@
show-if-above
bordered
>
-
-
-
+
+
@@ -44,14 +43,12 @@
diff --git a/src/pages/public/IndexPage.vue b/src/pages/public/IndexPage.vue
index 42470c6..a35ef91 100644
--- a/src/pages/public/IndexPage.vue
+++ b/src/pages/public/IndexPage.vue
@@ -1,8 +1,15 @@
+import {useMeta} from "quasar";
+import {commonKeywords, metaData} from "src/composables/meta";
+useMeta(() => metaData({
+ title: "",
+ description: "Polétání.cz je aplikace na ukládání a sdílení fotografií a tras z vyhlídkových letů.",
+ keywords: [...commonKeywords]
+}));
+
-
+
@@ -24,7 +31,7 @@
-
Pochlub se polétáním
+
Fotogalerie ze vzduchu
@@ -60,7 +67,7 @@
- Založit profil
+ Založit účet
diff --git a/src/pages/public/PilotProfilePage.vue b/src/pages/public/PilotProfilePage.vue
index dd0767d..a4a5669 100644
--- a/src/pages/public/PilotProfilePage.vue
+++ b/src/pages/public/PilotProfilePage.vue
@@ -1,28 +1,28 @@
-
+
+
diff --git a/src/pages/public/TestPage.vue b/src/pages/public/TestPage.vue
deleted file mode 100644
index 22005a6..0000000
--- a/src/pages/public/TestPage.vue
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
- letadlo: {{ aircrafts }}
-
diff --git a/src/pages/public/pilotProfile/CopilotDetailPage.vue b/src/pages/public/pilotProfile/CopilotDetailPage.vue
index bad7457..e385dac 100644
--- a/src/pages/public/pilotProfile/CopilotDetailPage.vue
+++ b/src/pages/public/pilotProfile/CopilotDetailPage.vue
@@ -1,55 +1,45 @@
+
+
-
+
Společné lety
diff --git a/src/pages/public/pilotProfile/EventDetailPage.vue b/src/pages/public/pilotProfile/EventDetailPage.vue
index d29f953..d26dc65 100644
--- a/src/pages/public/pilotProfile/EventDetailPage.vue
+++ b/src/pages/public/pilotProfile/EventDetailPage.vue
@@ -1,19 +1,23 @@
+
+
diff --git a/src/pages/public/pilotProfile/EventsListPage.vue b/src/pages/public/pilotProfile/EventsListPage.vue
index 171f82b..709127f 100644
--- a/src/pages/public/pilotProfile/EventsListPage.vue
+++ b/src/pages/public/pilotProfile/EventsListPage.vue
@@ -1,43 +1,39 @@
-
+
@@ -48,7 +44,7 @@ const {isQueryRunning, events} = storeToRefs(useEventsStore());
diff --git a/src/pages/public/pilotProfile/FlightDetailPage.vue b/src/pages/public/pilotProfile/FlightDetailPage.vue
index e5befc5..32fe9fa 100644
--- a/src/pages/public/pilotProfile/FlightDetailPage.vue
+++ b/src/pages/public/pilotProfile/FlightDetailPage.vue
@@ -1,29 +1,45 @@
+
@@ -38,14 +54,14 @@ const {isQueryRunning, flight} = storeToRefs(useFlightsStore());
-
{{ flightName(flight) }}
+
{{ flightName(flight) }}
@@ -55,8 +71,6 @@ const {isQueryRunning, flight} = storeToRefs(useFlightsStore());
-
-
diff --git a/src/pages/public/pilotProfile/FlightsListPage.vue b/src/pages/public/pilotProfile/FlightsListPage.vue
index 36ea222..19c9574 100644
--- a/src/pages/public/pilotProfile/FlightsListPage.vue
+++ b/src/pages/public/pilotProfile/FlightsListPage.vue
@@ -2,42 +2,40 @@
import FlightsListSkeleton from "components/flights/FlightsListSkeleton.vue";
import FlightsList from "components/flights/FlightsList.vue";
import PublicFlightEventSwitcher from "components/navigation/PublicFlightEventSwitcher.vue";
-import {onMounted} from "vue";
import {useAppStore} from "stores/App";
-import {useUserStore} from "stores/User";
import {useFlightsStore} from "stores/Flights";
import {storeToRefs} from "pinia";
+import {commonKeywords, metaData} from "src/composables/meta";
+import {useMeta} from "quasar";
+import {useUserStore} from "stores/User";
const props = defineProps({
- loggedUser: {
+ pilot: {
type: Object,
- required: false
- },
-
- username: {
- type: String,
- required: true
+ required: true,
}
});
-onMounted(() => {
- useUserStore().fetchPublicUserDetail(props.username).then(user => {
- useAppStore().setPageTitle(user.publicUsername);
- useAppStore().setBreadcrumbs([
- {to: {name: 'homepage'}, label: "Polétání.cz"},
- {label: `@${user.publicUsername}`},
- ])
- })
+useMeta(() => metaData({
+ title: `${props.pilot.publicUsername} - Lety`,
+ keywords: [...commonKeywords, "pilot", props.pilot.publicUsername, props.pilot.name],
+ description: `Výlety publikované pilotem ${props.pilot.name}. ${props.pilot.publicUsername}: ${props.pilot.description}`,
+ image: props.pilot.titleImageUrl
+}));
- useFlightsStore().fetch(props.username);
-});
+useAppStore().setPageTitle(props.pilot.publicUsername);
+useAppStore().setBreadcrumbs([
+ {to: {name: 'homepage'}, label: "Polétání.cz"},
+ {label: `@${props.pilot.publicUsername}`},
+])
+useFlightsStore().fetch(props.pilot.publicUsername);
const {flights, isQueryRunning: areFlightsLoading} = storeToRefs(useFlightsStore());
-const {publicUser: pilot} = storeToRefs(useUserStore());
+const loggedUser = storeToRefs(useUserStore()).user;
-
+
@@ -48,8 +46,8 @@ const {publicUser: pilot} = storeToRefs(useUserStore());
diff --git a/src/router/routes.js b/src/router/routes.js
index d979a9b..0156520 100644
--- a/src/router/routes.js
+++ b/src/router/routes.js
@@ -1,7 +1,6 @@
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}},
diff --git a/src/stores/App.js b/src/stores/App.js
index 82b7193..411fdb4 100644
--- a/src/stores/App.js
+++ b/src/stores/App.js
@@ -7,9 +7,9 @@ export const useAppStore = defineStore('App', () => {
const appStatus = ref(200); // TODO: toto nejspis nebude potreba!
const resetAfterRouteChange = () => {
- setPageTitle("");
- setBreadcrumbs([]);
+ pageTitle.value = null;
appStatus.value = 200;
+ breadcrumbs.value = []
};
const setPageTitle = (value) => {
@@ -22,6 +22,7 @@ export const useAppStore = defineStore('App', () => {
}
return {
- pageTitle, breadcrumbs, appStatus, resetAfterRouteChange, setPageTitle, setBreadcrumbs
+ pageTitle, breadcrumbs, appStatus,
+ resetAfterRouteChange, setPageTitle, setBreadcrumbs
}
})
diff --git a/src/stores/Events.js b/src/stores/Events.js
index 2acc2ad..0279e05 100644
--- a/src/stores/Events.js
+++ b/src/stores/Events.js
@@ -10,11 +10,11 @@ export const useEventsStore = defineStore('Events', () => {
const isMutationRunning = ref(false);
const isQueryRunning = ref(false);
- const fetchDetail = (id) => {
+ const fetchDetail = (id, username) => {
return query({
isQueryRunning,
query: EVENT_DETAIL,
- variables: {id},
+ variables: {id, username},
}).then(item => event.value = item);
};
diff --git a/src/stores/Flights.js b/src/stores/Flights.js
index 27bef2a..c606d14 100644
--- a/src/stores/Flights.js
+++ b/src/stores/Flights.js
@@ -3,7 +3,6 @@ import {FLIGHT_DETAIL, FLIGHTS_LIST} from "src/graphql/queries/flights";
import {EDIT_FLIGHT, CREATE_FLIGHT, DELETE_FLIGHT} from "src/graphql/mutations/flight";
import {deleteFromItems, mutate, query, updateInItems} from "stores/helpers";
import {ref} from "vue";
-import {DELETE_AIRCRAFT} from "src/graphql/mutations/aircrafts";
export const useFlightsStore = defineStore('Flights', () => {
const flight = ref(null);
@@ -58,57 +57,7 @@ export const useFlightsStore = defineStore('Flights', () => {
}).then(item => deleteFromItems(flights.value, 'id', item))
}
-
return {
flight, flights, isMutationRunning, isQueryRunning, fetchDetail, fetch, create, update, destroy
}
- //
- // actions: {
- // create(formData) {
- // delete formData['id'];
- // return apolloWrapper.mutate(CREATE_FLIGHT, {input: formData}).then(({data}) => {
- // const flightId = data.createFlight.id;
- //
- // // pitomy ohack kvuli tomu, ze se mi nedari dostat z API rovnou informace o nove vytvorenem letadle
- // this.fetchDetail(flightId).then(flight => {
- // this.items.push(flight);
- // })
- //
- // return data.createFlight;
- // })
- // },
- // update(id, formData) {
- // this.isMutationRunning = true;
- // return apolloWrapper.mutate(EDIT_FLIGHT, {id: id, input: formData}).then(({data}) => {
- // const flight = data.editFlight;
- // updateInItems(this.items, "id", flight);
- //
- // return flight;
- // }).finally(() => this.isMutationRunning = false);
- // },
- // fetchDetail(id, username = null) {
- // if (typeof id !== "number") {
- // id = parseInt(id);
- // }
- // return apolloWrapper.query(FLIGHT_DETAIL, {id, username}).then(result => result.data.flight);
- // },
- // fetch(username = null) {
- // return apolloWrapper
- // .query(FLIGHTS_LIST, {username})
- // .then((resp) => {
- // const data = resp.data;
- // this.items = data.flights;
- // return data.flights;
- // }).catch(err => console.log(err));
- // },
- // delete(id) {
- // return apolloWrapper.mutate(DELETE_FLIGHT, {id}).then(({data}) => {
- //
- // const idx = this.items.indexOf(this.items.find(f => f.id === id));
- // this.items.splice(idx, 1);
- //
- // return data.deleteFlight;
- // })
- // },
- // },
});
diff --git a/src/stores/User.js b/src/stores/User.js
index 6103e08..23b9a78 100644
--- a/src/stores/User.js
+++ b/src/stores/User.js
@@ -6,89 +6,92 @@ import {ref} from "vue";
import {mutate, query} from "stores/helpers";
export const useUserStore = defineStore('LoggedUser', () => {
- const user = ref(null);
- const publicUser = ref(null);
- const isQueryRunning = ref(false);
- const isMutationRunning = ref(false);
- const isRefreshing = ref(false);
+ const user = ref(null);
+ const publicUser = ref(null);
+ const isQueryRunning = ref(false);
+ const isMutationRunning = ref(false);
+ const isRefreshing = ref(false);
- const fetchLoggedUserDetail = () => query({
- isQueryRunning,
- query: LOGGED_USER_DETAIL
- }).then(item => {
- user.value = item;
- return item;
+ const fetchLoggedUserDetail = ({refresh}) => query({
+ isQueryRunning,
+ query: LOGGED_USER_DETAIL,
+ refreshUnauthorized: refresh || false,
+ }).then(item => {
+ user.value = item;
+ return item;
+ });
+
+ const fetchPublicUserDetail = (username) => query({
+ isQueryRunning,
+ query: USER_DETAIL,
+ variables: {username}
+ }).then(item => {
+ publicUser.value = item;
+ return item;
+ });
+
+ const update = (input) => mutate({
+ isMutationRunning,
+ mutation: EDIT_USER,
+ variables: {input}
+ }).then(item => {
+ user.value = item;
+ return item;
+ });
+
+ const register = async (formData) => {
+ return api.post('/registration', formData).then(response => {
+ const registeredUser = response.data;
+ const isSuccess = response.status === 201
+ })
+ };
+
+ const login = async (formData) => {
+ return api.post("/login", formData).then(({data}) => {
+ setTokens(data);
+ user.value = data.user;
+ })
+ };
+
+ const logout = () => {
+ return api.post("/logout").then(response => {
+ localStorage.removeItem("accessToken");
+ localStorage.removeItem("accessTokenValidity");
+ user.value = null;
});
+ };
- const fetchPublicUserDetail = (username) => query({
- isQueryRunning,
- query: USER_DETAIL,
- variables: {username}
- }).then(item => {
- publicUser.value = item;
- return item;
- });
+ const setTokens = ({access_token, access_token_validity}) => {
+ const now = new Date().getTime() / 1000;
+ localStorage.setItem("accessToken", access_token);
+ localStorage.setItem("accessTokenValidity", now + access_token_validity);
+ };
- const update = (input) => mutate({
- isMutationRunning,
- mutation: EDIT_USER,
- variables: {input}
- }).then(item => {
- user.value = item;
- return item;
- });
+ const getAccessToken = () => {
+ if (typeof localStorage === 'undefined') return null;
- const register = async (formData) => {
- return api.post('/registration', formData).then(response => {
- const registeredUser = response.data;
- const isSuccess = response.status === 201
- })
- };
+ const tokenValidity = localStorage.getItem("accessTokenValidity");
+ const now = new Date().getTime() / 1000;
- const login = async (formData) => {
- return api.post("/login", formData).then(({data}) => {
- setTokens(data);
- user.value = data.user;
- })
- };
-
- const logout = () => {
- return api.post("/logout").then(response => {
- localStorage.removeItem("accessToken");
- localStorage.removeItem("accessTokenValidity");
- user.value = null;
- });
- };
-
- const setTokens = ({access_token, access_token_validity}) => {
- const now = new Date().getTime() / 1000;
- localStorage.setItem("accessToken", access_token);
- localStorage.setItem("accessTokenValidity", now + access_token_validity);
- };
-
- const getAccessToken = () => {
- const tokenValidity = localStorage.getItem("accessTokenValidity");
- const now = new Date().getTime() / 1000;
-
- if (tokenValidity < now) {
- localStorage.removeItem("accessToken");
- localStorage.removeItem("accessTokenValidity");
- }
-
- return localStorage.getItem(`accessToken`);
- };
-
- const hasAccessToken = () => !!localStorage.getItem("accessToken");
-
- const refreshAccessToken = async () => api.post("/refresh")
- .then(({data}) => {
- setTokens(data);
- return data.access_token;
- });
-
- return {
- isQueryRunning, isMutationRunning, user, publicUser, fetchLoggedUserDetail, fetchPublicUserDetail, update,
- register, login, logout,
- getAccessToken, hasAccessToken, refreshAccessToken, isRefreshing
+ if (tokenValidity < now) {
+ localStorage.removeItem("accessToken");
+ localStorage.removeItem("accessTokenValidity");
}
+
+ return localStorage.getItem(`accessToken`);
+ };
+
+ const hasAccessToken = () => !!localStorage.getItem("accessToken");
+
+ const refreshAccessToken = async () => api.post("/refresh")
+ .then(({data}) => {
+ setTokens(data);
+ return data.access_token;
+ });
+
+ return {
+ isQueryRunning, isMutationRunning, user, publicUser, fetchLoggedUserDetail, fetchPublicUserDetail, update,
+ register, login, logout,
+ getAccessToken, hasAccessToken, refreshAccessToken, isRefreshing
+ }
});
diff --git a/src/stores/helpers.js b/src/stores/helpers.js
index 20cbd79..3ebbe37 100644
--- a/src/stores/helpers.js
+++ b/src/stores/helpers.js
@@ -17,15 +17,22 @@ export const deleteFromItems = (items, key, value) => {
items.splice(idx, 1);
}
-export const query = ({isQueryRunning, query, variables}) => {
+export const query = ({isQueryRunning, query, variables, refreshUnauthorized}) => {
if (variables && variables.id) {
variables.id = parseInt(variables.id);
}
+ query._refreshUnauthorizedUser = refreshUnauthorized;
+
isQueryRunning.value = true;
const queryName = query.definitions[0].selectionSet.selections[0].name.value;
return apolloWrapper.query(query, variables)
- .then((result) => result.data[queryName])
+ .then((result) => {
+ if (!result || result.error || !result.data) {
+ return null;
+ }
+ return result.data[queryName]
+ })
.finally(() => isQueryRunning.value = false);
}