From a842fa3ad7c756a0008d4b1adc71045ff37e05cb Mon Sep 17 00:00:00 2001 From: sajjad_talkhabi Date: Wed, 22 Sep 2021 17:23:24 +0330 Subject: [PATCH] fix --- package-lock.json | 171 ++++++++++--------- package.json | 1 + src/abstraction/repository/authRepository.js | 36 ++++ src/abstraction/resources/authResource.js | 9 + src/components/Global/Section/SideBar.vue | 40 +++++ src/main.js | 7 +- src/router/url.js | 7 + src/store/modules/auth/actions.js | 33 ++++ src/store/modules/auth/getters.js | 3 + src/store/modules/auth/mutations.js | 6 + src/store/modules/auth/state.js | 3 + src/utils/axios/api.js | 28 +++ src/utils/axios/errorHandler.js | 49 ++++++ src/utils/createFilterObject.js | 70 ++++++++ src/utils/objectToFormData.js | 89 ++++++++++ src/utils/setQueriesObject.js | 35 ++++ src/utils/storage.js | 47 +++++ src/utils/urlGenerator.js | 24 +++ src/views/Login.vue | 20 ++- vue.config.js | 11 +- 20 files changed, 602 insertions(+), 87 deletions(-) create mode 100644 src/abstraction/repository/authRepository.js create mode 100644 src/abstraction/resources/authResource.js create mode 100644 src/components/Global/Section/SideBar.vue create mode 100644 src/router/url.js create mode 100644 src/store/modules/auth/actions.js create mode 100644 src/store/modules/auth/getters.js create mode 100644 src/store/modules/auth/mutations.js create mode 100644 src/store/modules/auth/state.js create mode 100644 src/utils/axios/api.js create mode 100644 src/utils/axios/errorHandler.js create mode 100644 src/utils/createFilterObject.js create mode 100644 src/utils/objectToFormData.js create mode 100644 src/utils/setQueriesObject.js create mode 100644 src/utils/storage.js create mode 100644 src/utils/urlGenerator.js diff --git a/package-lock.json b/package-lock.json index d2a7c64..76ad679 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1753,63 +1753,6 @@ "integrity": "sha1-/q7SVZc9LndVW4PbwIhRpsY1IPo=", "dev": true }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "optional": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "optional": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "optional": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "optional": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "optional": true - }, - "loader-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", - "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", - "dev": true, - "optional": true, - "requires": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - } - }, "ssri": { "version": "8.0.1", "resolved": "https://registry.nlark.com/ssri/download/ssri-8.0.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fssri%2Fdownload%2Fssri-8.0.1.tgz", @@ -1818,28 +1761,6 @@ "requires": { "minipass": "^3.1.1" } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "optional": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "vue-loader-v16": { - "version": "npm:vue-loader@16.5.0", - "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-16.5.0.tgz", - "integrity": "sha512-WXh+7AgFxGTgb5QAkQtFeUcHNIEq3PGVQ8WskY5ZiFbWBkOwcCPRs4w/2tVyTbh2q6TVRlO3xfvIukUtjsu62A==", - "dev": true, - "optional": true, - "requires": { - "chalk": "^4.1.0", - "hash-sum": "^2.0.0", - "loader-utils": "^2.0.0" - } } } }, @@ -2432,6 +2353,14 @@ "integrity": "sha1-1h9G2DslGSUOJ4Ta9bCUeai0HFk=", "dev": true }, + "axios": { + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", + "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", + "requires": { + "follow-redirects": "^1.14.0" + } + }, "babel-eslint": { "version": "10.1.0", "resolved": "https://registry.npm.taobao.org/babel-eslint/download/babel-eslint-10.1.0.tgz", @@ -5537,8 +5466,7 @@ "follow-redirects": { "version": "1.14.3", "resolved": "https://registry.nlark.com/follow-redirects/download/follow-redirects-1.14.3.tgz", - "integrity": "sha1-atp4EY2NJMruWVWVrM3ArGq9Ai4=", - "dev": true + "integrity": "sha1-atp4EY2NJMruWVWVrM3ArGq9Ai4=" }, "for-in": { "version": "1.0.2", @@ -11411,6 +11339,87 @@ } } }, + "vue-loader-v16": { + "version": "npm:vue-loader@16.7.0", + "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-16.7.0.tgz", + "integrity": "sha512-43I0grWtwSCE8fiH/hAwFK+6sNlmvDuHhXScYH8HVSVAMS81IM66tgUOcxbPCeqhhz/1BE51YPxX59eZKGallQ==", + "dev": true, + "optional": true, + "requires": { + "chalk": "^4.1.0", + "hash-sum": "^2.0.0", + "loader-utils": "^2.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "optional": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "optional": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "optional": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "optional": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "optional": true + }, + "loader-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", + "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "dev": true, + "optional": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "optional": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "vue-meta": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/vue-meta/-/vue-meta-2.4.0.tgz", diff --git a/package.json b/package.json index aa05475..69fd989 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ "lint": "vue-cli-service lint" }, "dependencies": { + "axios": "^0.21.4", "bootstrap": "^4.6.0", "core-js": "^3.6.5", "jquery": "^3.6.0", diff --git a/src/abstraction/repository/authRepository.js b/src/abstraction/repository/authRepository.js new file mode 100644 index 0000000..b0f728e --- /dev/null +++ b/src/abstraction/repository/authRepository.js @@ -0,0 +1,36 @@ +import axios from "axios"; +import url from "@/router/url"; +import { setData } from "../resources/authResource"; + +export default class AuthRepository { + async login(data) { + let json = setData(data); + let response = await axios.post(url("login"), json); + if (response.status === 200) { + return response.data.data; + } + } + + async logout() { + let response = await axios.post(url("logout")); + if (response.status === 200) { + return true; + } + } + + async register(data) { + let json = setData(data); + let response = await axios.post(url("register"), json); + if (response.status === 200) { + return response.data.data; + } + } + + async resetPassword(data) { + let json = setData(data); + let response = await axios.post(url("resetPassword"), json); + if (response.status === 200) { + return response.data.data; + } + } +} diff --git a/src/abstraction/resources/authResource.js b/src/abstraction/resources/authResource.js new file mode 100644 index 0000000..860befe --- /dev/null +++ b/src/abstraction/resources/authResource.js @@ -0,0 +1,9 @@ +export const setData = (data) => ({ + first_name: data.first_name, + last_name: data.last_name, + email: data.email, + username: data.username, + password: data.password, + password_confirmation: data.password_confirmation, + }); + \ No newline at end of file diff --git a/src/components/Global/Section/SideBar.vue b/src/components/Global/Section/SideBar.vue new file mode 100644 index 0000000..f04df47 --- /dev/null +++ b/src/components/Global/Section/SideBar.vue @@ -0,0 +1,40 @@ + + \ No newline at end of file diff --git a/src/main.js b/src/main.js index 1e1db99..422662d 100644 --- a/src/main.js +++ b/src/main.js @@ -5,12 +5,15 @@ import vuetify from './plugins/vuetify'; import router from './router'; import './utils/GlobalComponents'; import "./styles/global.scss"; -import './mixins/Global.js' +import './mixins/Global.js'; +import ApiService from '@/utils/axios/api'; +ApiService.init('https://www.champya-dev.ir'); +import '@/utils/axios/errorHandler'; Vue.config.productionTip = false new Vue({ vuetify, - store, + store, router, render: h => h(App) }).$mount('#app') diff --git a/src/router/url.js b/src/router/url.js new file mode 100644 index 0000000..c6e05d8 --- /dev/null +++ b/src/router/url.js @@ -0,0 +1,7 @@ +import { urlGenerator } from "@/utils/urlGenerator"; + +const urls = { + login: "auth/login" +}; + +export default urlGenerator(urls); diff --git a/src/store/modules/auth/actions.js b/src/store/modules/auth/actions.js new file mode 100644 index 0000000..32e9980 --- /dev/null +++ b/src/store/modules/auth/actions.js @@ -0,0 +1,33 @@ +import AuthRepository from "../../../abstraction/repository/authRepository"; +import {TokenStorage, UserStorage} from "@/utils/storage"; +import ApiService from "@/utils/axios/api"; + +function setTokenHeader(commit, response) { + TokenStorage.saveToken(response.token); + UserStorage.save(response.user); + commit("SET_AUTH_USER", response.user); + ApiService.setAuthHeader(); +} + +export default { + async login({commit}, data) { + let repository = new AuthRepository(); + const response = await repository.login(data); + if (response) { + setTokenHeader(commit, response); + return response; + } + }, + async logout() { + let repository = new AuthRepository(); + await repository.logout(); + ApiService.removeAuthHeader(); + TokenStorage.removeToken(); + return true; + }, + async register({commit}, data) { + let repository = new AuthRepository(); + const response = await repository.register(data); + setTokenHeader(commit, response); + }, +}; diff --git a/src/store/modules/auth/getters.js b/src/store/modules/auth/getters.js new file mode 100644 index 0000000..a3e43a1 --- /dev/null +++ b/src/store/modules/auth/getters.js @@ -0,0 +1,3 @@ +export default { + getAuthUser: (state) => state.user, +}; diff --git a/src/store/modules/auth/mutations.js b/src/store/modules/auth/mutations.js new file mode 100644 index 0000000..cbcf3cb --- /dev/null +++ b/src/store/modules/auth/mutations.js @@ -0,0 +1,6 @@ +import Vue from "vue"; +export default { + SET_AUTH_USER(state, data) { + Vue.set(state, "user", data); + }, +}; diff --git a/src/store/modules/auth/state.js b/src/store/modules/auth/state.js new file mode 100644 index 0000000..27e1e40 --- /dev/null +++ b/src/store/modules/auth/state.js @@ -0,0 +1,3 @@ +export default { + user: {}, +}; diff --git a/src/utils/axios/api.js b/src/utils/axios/api.js new file mode 100644 index 0000000..9e7606d --- /dev/null +++ b/src/utils/axios/api.js @@ -0,0 +1,28 @@ +import axios from 'axios' +import {TokenStorage} from '../storage' + +const ApiService = { + + init(baseURL = null) { + if (baseURL) { + axios.defaults.baseURL = baseURL; + } else if (process.env.MIX_PUSHER_APP_API) { + axios.defaults.baseURL = process.env.MIX_PUSHER_APP_API; + } + + if (TokenStorage.getToken()) { + this.setAuthHeader(); + } + }, + + setAuthHeader() { + axios.defaults.headers.common["Authorization"] = `Bearer ${TokenStorage.getToken()}`; + }, + + removeAuthHeader() { + axios.defaults.headers.common["Authorization"] = null; + }, + +}; + +export default ApiService; diff --git a/src/utils/axios/errorHandler.js b/src/utils/axios/errorHandler.js new file mode 100644 index 0000000..f97ab89 --- /dev/null +++ b/src/utils/axios/errorHandler.js @@ -0,0 +1,49 @@ +import axios from "axios"; +import store from "@/store"; +// import toast from "../toast"; +import Vue from "vue"; +import { TokenStorage } from "../storage"; +import ApiService from "./api"; + +function errorResponseHandler(error) { + // check for errorHandle config + if ( + Object.prototype.hasOwnProperty.call(error.config, "errorHandle") && + error.config.errorHandle === false + ) { + return Promise.reject(error); + } + // if has response show the error + if (error.response) { + if (error.response.status === 401) { + TokenStorage.removeToken(); + ApiService.removeAuthHeader(); + store.commit('auth/logout', {}, { root: true }); + window.location.href = '/'; + // toast.error('Wrong username or password.', 'Error'); + } else if (error.response.status === 422) { + if (typeof error.response.data.errors !== 'undefined') { + for (const key in error.response.data.errors) { + if (Object.prototype.hasOwnProperty.call(error.response.data.errors, key)) { + // toast.error(error.response.data.errors[key], 'Error'); + } + } + } + } else if (error.response.status === 500) { + // toast.error('Server Error', 'Error'); + } + } + return Promise.reject(error); +} +function successHandler(response) { + if (response.status === 200 || response.status === 201) { + if (typeof response.data.message !== 'undefined' && typeof response.data.message.content !== 'undefined') { + // toast.success(response.data.message.content, response.data.message.title || 'Success'); + } + } + return response; +} + +// apply interceptor on response +axios.interceptors.response.use(successHandler, errorResponseHandler); +Vue.prototype.$axios = axios; diff --git a/src/utils/createFilterObject.js b/src/utils/createFilterObject.js new file mode 100644 index 0000000..133d21a --- /dev/null +++ b/src/utils/createFilterObject.js @@ -0,0 +1,70 @@ +const createFilterObject = filters => { + let filterObject = {}; + for (const key in filters) { + if (Object.hasOwnProperty.call(filters, key)) { + if (filters[key] && typeof filters[key]["type"] !== "undefined") { + let filterValue = window[filters[key]["type"]](filters[key]); + if (filterValue) { + filterObject[key] = filterValue; + } + } else if (typeof filters[key] !== 'object' ) { + filterObject[key] = filters[key]; + } + } + } + filters = {}; + for (var filter in filterObject) { + if (Object.hasOwnProperty.call(filterObject, filter)) { + filters[`filters[${filter}]`] = filterObject[filter]; + } + } + return filters; +}; +window["between"] = function(filter) { + var value = null; + if (filter.val1 && filter.val2) { + value = `<${filter.val1},${filter.val2}>`; + } else if (filter.val1) { + filter.val = filter.val1; + value = window["greater"](filter); + } else if (filter.val2) { + filter.val = filter.val2; + value = window["less"](filter); + } + return value; +}; +window["greater"] = function(filter) { + var value = null; + if (filter.val) { + value = `(ge)${filter.val}`; + } + return value; +}; +window["less"] = function(filter) { + var value = null; + if (filter.val) { + value = `(le)${filter.val}`; + } + return value; +}; + +window["like"] = function(filter) { + var value = null; + if (filter.val !== null) { + value = `%${filter.val}%`; + } + return value; +}; +window["in"] = function(filter) { + var value = null; + if (filter.val) { + if (Array.isArray(filter.val)) { + value = filter.val.join(","); + } else { + value = `${filter.val}`; + } + } + return value; +}; + +export default createFilterObject; diff --git a/src/utils/objectToFormData.js b/src/utils/objectToFormData.js new file mode 100644 index 0000000..388d08a --- /dev/null +++ b/src/utils/objectToFormData.js @@ -0,0 +1,89 @@ +const isUndefined = (value) => value === undefined; + +const isNull = (value) => value === null; + +const isBoolean = (value) => typeof value === "boolean"; + +const isObject = (value) => value === Object(value); + +const isArray = (value) => Array.isArray(value); + +const isDate = (value) => value instanceof Date; + +const isBlob = (value) => + value && + typeof value.size === "number" && + typeof value.type === "string" && + typeof value.slice === "function"; + +const isFile = (value) => + isBlob(value) && + typeof value.name === "string" && + (typeof value.lastModifiedDate === "object" || + typeof value.lastModified === "number"); + +const objectToFormData = (obj, cfg, fd, pre) => { + cfg = cfg || {}; + + cfg.indices = isUndefined(cfg.indices) ? true : cfg.indices; + + cfg.nullsAsUndefineds = isUndefined(cfg.nullsAsUndefineds) + ? false + : cfg.nullsAsUndefineds; + + cfg.booleansAsIntegers = isUndefined(cfg.booleansAsIntegers) + ? false + : cfg.booleansAsIntegers; + + cfg.allowEmptyArrays = isUndefined(cfg.allowEmptyArrays) + ? true + : cfg.allowEmptyArrays; + + fd = fd || new FormData(); + + if (isUndefined(obj)) { + return fd; + } else if (isNull(obj)) { + if (!cfg.nullsAsUndefineds) { + fd.append(pre, ""); + } + } else if (isBoolean(obj)) { + if (cfg.booleansAsIntegers) { + fd.append(pre, obj ? 1 : 0); + } else { + fd.append(pre, obj); + } + } else if (isArray(obj)) { + if (obj.length) { + obj.forEach((value, index) => { + const key = pre + "[" + (cfg.indices ? index : "") + "]"; + + objectToFormData(value, cfg, fd, key); + }); + } else if (cfg.allowEmptyArrays) { + fd.append(pre, []); + } + } else if (isDate(obj)) { + fd.append(pre, obj.toISOString()); + } else if (isObject(obj) && !isFile(obj) && !isBlob(obj)) { + Object.keys(obj).forEach((prop) => { + const value = obj[prop]; + + if (isArray(value)) { + while (prop.length > 2 && prop.lastIndexOf("[]") === prop.length - 2) { + prop = prop.substring(0, prop.length - 2); + } + } + + const key = pre ? pre + "[" + prop + "]" : prop; + + objectToFormData(value, cfg, fd, key); + }); + } else { + fd.append(pre, obj); + } + + return fd; +}; + +export { objectToFormData }; diff --git a/src/utils/setQueriesObject.js b/src/utils/setQueriesObject.js new file mode 100644 index 0000000..a4dc5bc --- /dev/null +++ b/src/utils/setQueriesObject.js @@ -0,0 +1,35 @@ +import createFilterObject from "./createFilterObject"; +export const SetQueriesObject = ({ filters, sorts, pagination }) => { + + let Query = {}; + + if (typeof filters === 'object') { + filters = createFilterObject(filters); + Query = {...Query, ...filters }; + } + + if (typeof sorts === 'string') { + sorts = sorts ? { 'sorts[]': sorts } : {}; + Query = {...Query, ...sorts }; + } + + if (typeof pagination === 'object') { + pagination = { + per_page: pagination.itemsPerPage, + page: pagination.page + }; + Query = {...Query, ...pagination }; + } + return Query; +}; + +export const SetPagination = (paginate) => { + return { + page: paginate.current_page, + pageStop: paginate.to, + pageStart: paginate.from, + pageCount: paginate.last_page, + itemsLength: paginate.total, + itemsPerPage: paginate.per_page, + } +}; diff --git a/src/utils/storage.js b/src/utils/storage.js new file mode 100644 index 0000000..f204d5d --- /dev/null +++ b/src/utils/storage.js @@ -0,0 +1,47 @@ +import qs from "qs"; + +const TOKEN_KEY = "access_token"; +const USER = "user"; +/** + * Manage the how Access Tokens are being stored and retreived from storage. + * + * Current implementation stores to localStorage. Local Storage should always be + * accessed through this instace. + **/ +const TokenStorage = { + getToken() { + return localStorage.getItem(TOKEN_KEY); + }, + + saveToken(accessToken = null) { + localStorage.setItem(TOKEN_KEY, accessToken); + }, + + removeToken() { + localStorage.removeItem(TOKEN_KEY); + }, + + hasToken() { + return localStorage.getItem(TOKEN_KEY) ? true : false; + }, +}; + +const UserStorage = { + get() { + if (localStorage.getItem(USER)) { + return qs.parse(localStorage.getItem(USER)); + } + return null; + }, + + save(user = null) { + user = qs.stringify(user); + localStorage.setItem(USER, user); + }, + + remove() { + localStorage.removeItem(USER); + }, +}; + +export { TokenStorage, UserStorage }; diff --git a/src/utils/urlGenerator.js b/src/utils/urlGenerator.js new file mode 100644 index 0000000..1c83ee8 --- /dev/null +++ b/src/utils/urlGenerator.js @@ -0,0 +1,24 @@ +const urlGenerator = (urls) => { + return function(routeAddress, parameters) { + let urlPath = urls[routeAddress].split("/"); + let newPath = []; + for (const iterator of urlPath) { + if (iterator.startsWith(":")) { + if (iterator.endsWith("?")) { + if (Object.prototype.hasOwnProperty.call(parameters, iterator.slice(1, -1))) { + newPath.push(parameters[iterator.slice(1, -1)]); + } + } else { + newPath.push(parameters[iterator.slice(1)]); + } + } else { + newPath.push(iterator); + } + } + return '/api/' + newPath.join("/"); + } +}; + +export { + urlGenerator +} diff --git a/src/views/Login.vue b/src/views/Login.vue index 5988111..6ebc911 100644 --- a/src/views/Login.vue +++ b/src/views/Login.vue @@ -20,7 +20,8 @@ placeholder="your email address" label="your email address" class="no-error-msg" - + v-model="form.email" + dark > @@ -33,7 +34,8 @@ :type="showPassword ? 'text' : 'password'" @click:append="showPassword = !showPassword" :append-icon="showPassword ? 'WMi-eye-off' : 'WMi-eye'" - + v-model="form.password" + dark > @@ -45,7 +47,8 @@ class="custom-btn w-100" height="25" :text-mode="true" - text="sign in as " + text="sign in" + @click.native="login" /> @@ -90,12 +93,23 @@ \ No newline at end of file diff --git a/vue.config.js b/vue.config.js index 2ae460b..061635e 100644 --- a/vue.config.js +++ b/vue.config.js @@ -1,5 +1,14 @@ module.exports = { transpileDependencies: [ 'vuetify' - ] + ], + configureWebpack: { + resolve: { + alias: { + '@Assets': path.resolve(__dirname, 'src/assets'), + '@Styles': path.resolve(__dirname, 'src/styles'), + '@': path.resolve(__dirname, 'src/') + }, + }, + } }