diff --git a/ui/.editorconfig b/ui/.editorconfig new file mode 100644 index 0000000..9d08a1a --- /dev/null +++ b/ui/.editorconfig @@ -0,0 +1,9 @@ +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true diff --git a/ui/.eslintignore b/ui/.eslintignore new file mode 100644 index 0000000..9f81cf8 --- /dev/null +++ b/ui/.eslintignore @@ -0,0 +1,7 @@ +/dist +/src-capacitor +/src-cordova +/.quasar +/node_modules +.eslintrc.cjs +/quasar.config.*.temporary.compiled* diff --git a/ui/.eslintrc.cjs b/ui/.eslintrc.cjs new file mode 100644 index 0000000..b3d242c --- /dev/null +++ b/ui/.eslintrc.cjs @@ -0,0 +1,69 @@ +module.exports = { + // https://eslint.org/docs/user-guide/configuring#configuration-cascading-and-hierarchy + // This option interrupts the configuration hierarchy at this file + // Remove this if you have an higher level ESLint config file (it usually happens into a monorepos) + root: true, + + parserOptions: { + ecmaVersion: 2022, // Allows for the parsing of modern ECMAScript features + }, + + env: { + node: true, + browser: true + }, + + // Rules order is important, please avoid shuffling them + extends: [ + // Base ESLint recommended rules + // 'eslint:recommended', + + // Uncomment any of the lines below to choose desired strictness, + // but leave only one uncommented! + // See https://eslint.vuejs.org/rules/#available-rules + 'plugin:vue/vue3-essential', // Priority A: Essential (Error Prevention) + // 'plugin:vue/vue3-strongly-recommended', // Priority B: Strongly Recommended (Improving Readability) + // 'plugin:vue/vue3-recommended', // Priority C: Recommended (Minimizing Arbitrary Choices and Cognitive Overhead) + + // https://github.com/prettier/eslint-config-prettier#installation + // usage with Prettier, provided by 'eslint-config-prettier'. + 'prettier' + ], + + plugins: [ + // https://eslint.vuejs.org/user-guide/#why-doesn-t-it-work-on-vue-files + // required to lint *.vue files + 'vue', + + // https://github.com/typescript-eslint/typescript-eslint/issues/389#issuecomment-509292674 + // Prettier has not been included as plugin to avoid performance impact + // add it as an extension for your IDE + + ], + + globals: { + ga: 'readonly', // Google Analytics + cordova: 'readonly', + __statics: 'readonly', + __QUASAR_SSR__: 'readonly', + __QUASAR_SSR_SERVER__: 'readonly', + __QUASAR_SSR_CLIENT__: 'readonly', + __QUASAR_SSR_PWA__: 'readonly', + process: 'readonly', + Capacitor: 'readonly', + chrome: 'readonly' + }, + + // add your custom rules here + rules: { + + 'prefer-promise-reject-errors': 'off', + + // allow debugger during development only + 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off', + + // + 'vue/multi-word-component-names': 'off', + 'vue/no-dupe-keys': 'off' + } +} diff --git a/ui/.gitignore b/ui/.gitignore new file mode 100644 index 0000000..f1d913c --- /dev/null +++ b/ui/.gitignore @@ -0,0 +1,33 @@ +.DS_Store +.thumbs.db +node_modules + +# Quasar core related directories +.quasar +/dist +/quasar.config.*.temporary.compiled* + +# Cordova related directories and files +/src-cordova/node_modules +/src-cordova/platforms +/src-cordova/plugins +/src-cordova/www + +# Capacitor related directories and files +/src-capacitor/www +/src-capacitor/node_modules + +# Log files +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Editor directories and files +.idea +*.suo +*.ntvs* +*.njsproj +*.sln + +# local .env files +.env.local* diff --git a/ui/.npmrc b/ui/.npmrc new file mode 100644 index 0000000..eb19082 --- /dev/null +++ b/ui/.npmrc @@ -0,0 +1,5 @@ +# pnpm-related options +shamefully-hoist=true +strict-peer-dependencies=false +# to get the latest compatible packages when creating the project https://github.com/pnpm/pnpm/issues/6463 +resolution-mode=highest diff --git a/ui/.vscode/extensions.json b/ui/.vscode/extensions.json new file mode 100644 index 0000000..fe38802 --- /dev/null +++ b/ui/.vscode/extensions.json @@ -0,0 +1,15 @@ +{ + "recommendations": [ + "dbaeumer.vscode-eslint", + "esbenp.prettier-vscode", + "editorconfig.editorconfig", + "vue.volar", + "wayou.vscode-todo-highlight" + ], + "unwantedRecommendations": [ + "octref.vetur", + "hookyqr.beautify", + "dbaeumer.jshint", + "ms-vscode.vscode-typescript-tslint-plugin" + ] +} \ No newline at end of file diff --git a/ui/.vscode/settings.json b/ui/.vscode/settings.json new file mode 100644 index 0000000..b3bb1e4 --- /dev/null +++ b/ui/.vscode/settings.json @@ -0,0 +1,15 @@ +{ + "editor.bracketPairColorization.enabled": true, + "editor.guides.bracketPairs": true, + "editor.formatOnSave": true, + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.codeActionsOnSave": [ + "source.fixAll.eslint" + ], + "eslint.validate": [ + "javascript", + "javascriptreact", + "typescript", + "vue" + ] +} \ No newline at end of file diff --git a/ui/README.md b/ui/README.md new file mode 100644 index 0000000..f39cece --- /dev/null +++ b/ui/README.md @@ -0,0 +1,41 @@ +# Bordro Eşleme (tr.com.notitek.bordro-esleme) + +Bordro Eşleme + +## Install the dependencies +```bash +yarn +# or +npm install +``` + +### Start the app in development mode (hot-code reloading, error reporting, etc.) +```bash +quasar dev +``` + + +### Lint the files +```bash +yarn lint +# or +npm run lint +``` + + +### Format the files +```bash +yarn format +# or +npm run format +``` + + + +### Build the app for production +```bash +quasar build +``` + +### Customize the configuration +See [Configuring quasar.config.js](https://v2.quasar.dev/quasar-cli-vite/quasar-config-js). diff --git a/ui/index.html b/ui/index.html new file mode 100644 index 0000000..3c8c78f --- /dev/null +++ b/ui/index.html @@ -0,0 +1,21 @@ + + + + <%= productName %> + + + + + + + + + + + + + + + + + diff --git a/ui/jsconfig.json b/ui/jsconfig.json new file mode 100644 index 0000000..456944a --- /dev/null +++ b/ui/jsconfig.json @@ -0,0 +1,39 @@ +{ + "compilerOptions": { + "baseUrl": ".", + "paths": { + "src/*": [ + "src/*" + ], + "app/*": [ + "*" + ], + "components/*": [ + "src/components/*" + ], + "layouts/*": [ + "src/layouts/*" + ], + "pages/*": [ + "src/pages/*" + ], + "assets/*": [ + "src/assets/*" + ], + "boot/*": [ + "src/boot/*" + ], + "stores/*": [ + "src/stores/*" + ], + "vue$": [ + "node_modules/vue/dist/vue.runtime.esm-bundler.js" + ] + } + }, + "exclude": [ + "dist", + ".quasar", + "node_modules" + ] +} \ No newline at end of file diff --git a/ui/package.json b/ui/package.json new file mode 100644 index 0000000..f3b1094 --- /dev/null +++ b/ui/package.json @@ -0,0 +1,39 @@ +{ + "name": "tr.com.notitek.bordro-esleme", + "version": "0.0.1", + "description": "Bordro Eşleme", + "productName": "Bordro Eşleme", + "author": "dev@notitek.com.tr", + "private": true, + "scripts": { + "lint": "eslint --ext .js,.vue ./", + "format": "prettier --write \"**/*.{js,vue,scss,html,md,json}\" --ignore-path .gitignore", + "test": "echo \"No test specified\" && exit 0", + "dev": "quasar dev", + "build": "quasar build" + }, + "dependencies": { + "@quasar/extras": "^1.16.4", + "axios": "^1.2.1", + "jwt-decode": "^4.0.0", + "pinia": "^2.0.11", + "quasar": "^2.8.0", + "vue": "^3.4.18", + "vue-router": "^4.0.12" + }, + "devDependencies": { + "@quasar/app-vite": "^1.8.0", + "autoprefixer": "^10.4.2", + "eslint": "^8.11.0", + "eslint-config-prettier": "^8.1.0", + "eslint-plugin-vue": "^9.0.0", + "postcss": "^8.4.14", + "prettier": "^2.5.1", + "vite-plugin-checker": "^0.6.4" + }, + "engines": { + "node": "^20 || ^18 || ^16", + "npm": ">= 6.13.4", + "yarn": ">= 1.21.1" + } +} diff --git a/ui/postcss.config.cjs b/ui/postcss.config.cjs new file mode 100644 index 0000000..94b7b1c --- /dev/null +++ b/ui/postcss.config.cjs @@ -0,0 +1,27 @@ +/* eslint-disable */ +// https://github.com/michael-ciniawsky/postcss-load-config + +module.exports = { + plugins: [ + // https://github.com/postcss/autoprefixer + require('autoprefixer')({ + overrideBrowserslist: [ + 'last 4 Chrome versions', + 'last 4 Firefox versions', + 'last 4 Edge versions', + 'last 4 Safari versions', + 'last 4 Android versions', + 'last 4 ChromeAndroid versions', + 'last 4 FirefoxAndroid versions', + 'last 4 iOS versions' + ] + }) + + // https://github.com/elchininet/postcss-rtlcss + // If you want to support RTL css, then + // 1. yarn/npm install postcss-rtlcss + // 2. optionally set quasar.config.js > framework > lang to an RTL language + // 3. uncomment the following line: + // require('postcss-rtlcss') + ] +} diff --git a/ui/public/bres.png b/ui/public/bres.png new file mode 100644 index 0000000..d198839 Binary files /dev/null and b/ui/public/bres.png differ diff --git a/ui/public/favicon.ico b/ui/public/favicon.ico new file mode 100644 index 0000000..324249b Binary files /dev/null and b/ui/public/favicon.ico differ diff --git a/ui/public/icons/favicon-128x128.png b/ui/public/icons/favicon-128x128.png new file mode 100644 index 0000000..cd0ff81 Binary files /dev/null and b/ui/public/icons/favicon-128x128.png differ diff --git a/ui/public/icons/favicon-16x16.png b/ui/public/icons/favicon-16x16.png new file mode 100644 index 0000000..287e7fe Binary files /dev/null and b/ui/public/icons/favicon-16x16.png differ diff --git a/ui/public/icons/favicon-32x32.png b/ui/public/icons/favicon-32x32.png new file mode 100644 index 0000000..dc7b85d Binary files /dev/null and b/ui/public/icons/favicon-32x32.png differ diff --git a/ui/public/icons/favicon-96x96.png b/ui/public/icons/favicon-96x96.png new file mode 100644 index 0000000..9e8cfca Binary files /dev/null and b/ui/public/icons/favicon-96x96.png differ diff --git a/ui/public/notitek.png b/ui/public/notitek.png new file mode 100644 index 0000000..1f6be05 Binary files /dev/null and b/ui/public/notitek.png differ diff --git a/ui/quasar.config.js b/ui/quasar.config.js new file mode 100644 index 0000000..8a11ef6 --- /dev/null +++ b/ui/quasar.config.js @@ -0,0 +1,240 @@ +/* eslint-env node */ + +/* + * This file runs in a Node context (it's NOT transpiled by Babel), so use only + * the ES6 features that are supported by your Node version. https://node.green/ + */ + +// Configuration for your app +// https://v2.quasar.dev/quasar-cli-vite/quasar-config-js + + +const { configure } = require('quasar/wrappers'); + + +module.exports = configure(function (ctx) { + return { + // https://v2.quasar.dev/quasar-cli-vite/prefetch-feature + // preFetch: true, + + // app boot file (/src/boot) + // --> boot files are part of "main.js" + // https://v2.quasar.dev/quasar-cli-vite/boot-files + boot: [ + 'axios', + 'version', + 'pinia', + ], + + // https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#css + css: [ + 'app.scss' + ], + + // https://github.com/quasarframework/quasar/tree/dev/extras + extras: [ + // 'ionicons-v4', + 'mdi-v7', + // 'fontawesome-v6', + // 'eva-icons', + // 'themify', + // 'line-awesome', + 'roboto-font-latin-ext', // this or either 'roboto-font', NEVER both! + + //'roboto-font', // optional, you are not bound to it + 'material-icons', // optional, you are not bound to it + ], + + // Full list of options: https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#build + build: { + target: { + browser: [ 'es2019', 'edge88', 'firefox78', 'chrome87', 'safari13.1' ], + node: 'node20' + }, + + vueRouterMode: 'history', // available values: 'hash', 'history' + // vueRouterBase, + // vueDevtools, + // vueOptionsAPI: false, + + // rebuildCache: true, // rebuilds Vite/linter/etc cache on startup + + // publicPath: '/', + // analyze: true, + env: { + apiAddr: (() => { + if (process.env.CUSTOM_API) { + return process.env.CUSTOM_API + } else { + if (ctx.dev) { + return 'http://localhost:41000/api' + } else { + return '/api' + } + } + })(), + wsAddr: (() => { + if (process.env.CUSTOM_WS) { + return process.env.CUSTOM_WS + } else { + if (ctx.dev) { + return 'ws://127.0.0.1:41000/ws' + } else { + return 'wss://bres.notitek.com.tr/ws' + } + } + })(), + }, + // rawDefine: {} + // ignorePublicFolder: true, + // minify: false, + // polyfillModulePreload: true, + // distDir + + extendViteConf (viteConf) { + viteConf.resolve.preserveSymlinks = true + }, + + // viteVuePluginOptions: {}, + + vitePlugins: [ + ['vite-plugin-checker', { + eslint: { + lintCommand: 'eslint "./**/*.{js,mjs,cjs,vue}"' + } + }, { server: false }] + ] + }, + + // Full list of options: https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#devServer + devServer: { + // https: true + port:9400, + open: true // opens browser window automatically + }, + + // https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#framework + framework: { + config: {}, + + // iconSet: 'material-icons', // Quasar icon set + // lang: 'en-US', // Quasar language pack + + // For special cases outside of where the auto-import strategy can have an impact + // (like functional components as one of the examples), + // you can manually specify Quasar components/directives to be available everywhere: + // + // components: [], + // directives: [], + + // Quasar plugins + plugins: [ + 'Notify', + 'Loading', + 'Dialog', + 'Meta' + ] + }, + + // animations: 'all', // --- includes all animations + // https://v2.quasar.dev/options/animations + animations: [], + + // https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#property-sourcefiles + // sourceFiles: { + // rootComponent: 'src/App.vue', + // router: 'src/router/index', + // store: 'src/store/index', + // registerServiceWorker: 'src-pwa/register-service-worker', + // serviceWorker: 'src-pwa/custom-service-worker', + // pwaManifestFile: 'src-pwa/manifest.json', + // electronMain: 'src-electron/electron-main', + // electronPreload: 'src-electron/electron-preload' + // }, + + // https://v2.quasar.dev/quasar-cli-vite/developing-ssr/configuring-ssr + ssr: { + // ssrPwaHtmlFilename: 'offline.html', // do NOT use index.html as name! + // will mess up SSR + + // extendSSRWebserverConf (esbuildConf) {}, + // extendPackageJson (json) {}, + + pwa: false, + + // manualStoreHydration: true, + // manualPostHydrationTrigger: true, + + prodPort: 3000, // The default port that the production server should use + // (gets superseded if process.env.PORT is specified at runtime) + + middlewares: [ + 'render' // keep this as last one + ] + }, + + // https://v2.quasar.dev/quasar-cli-vite/developing-pwa/configuring-pwa + pwa: { + workboxMode: 'generateSW', // or 'injectManifest' + injectPwaMetaTags: true, + swFilename: 'sw.js', + manifestFilename: 'manifest.json', + useCredentialsForManifestTag: false, + // useFilenameHashes: true, + // extendGenerateSWOptions (cfg) {} + // extendInjectManifestOptions (cfg) {}, + // extendManifestJson (json) {} + // extendPWACustomSWConf (esbuildConf) {} + }, + + // Full list of options: https://v2.quasar.dev/quasar-cli-vite/developing-cordova-apps/configuring-cordova + cordova: { + // noIosLegacyBuildFlag: true, // uncomment only if you know what you are doing + }, + + // Full list of options: https://v2.quasar.dev/quasar-cli-vite/developing-capacitor-apps/configuring-capacitor + capacitor: { + hideSplashscreen: true + }, + + // Full list of options: https://v2.quasar.dev/quasar-cli-vite/developing-electron-apps/configuring-electron + electron: { + // extendElectronMainConf (esbuildConf) + // extendElectronPreloadConf (esbuildConf) + + // specify the debugging port to use for the Electron app when running in development mode + inspectPort: 5858, + + bundler: 'packager', // 'packager' or 'builder' + + packager: { + // https://github.com/electron-userland/electron-packager/blob/master/docs/api.md#options + + // OS X / Mac App Store + // appBundleId: '', + // appCategoryType: '', + // osxSign: '', + // protocol: 'myapp://path', + + // Windows only + // win32metadata: { ... } + }, + + builder: { + // https://www.electron.build/configuration/configuration + + appId: 'tr.com.notitek.bres' + } + }, + + // Full list of options: https://v2.quasar.dev/quasar-cli-vite/developing-browser-extensions/configuring-bex + bex: { + contentScripts: [ + 'my-content-script' + ], + + // extendBexScriptsConf (esbuildConf) {} + // extendBexManifestJson (json) {} + } + } +}); diff --git a/ui/src/App.vue b/ui/src/App.vue new file mode 100644 index 0000000..79d5cce --- /dev/null +++ b/ui/src/App.vue @@ -0,0 +1,9 @@ + + + diff --git a/ui/src/assets/quasar-logo-vertical.svg b/ui/src/assets/quasar-logo-vertical.svg new file mode 100644 index 0000000..8210831 --- /dev/null +++ b/ui/src/assets/quasar-logo-vertical.svg @@ -0,0 +1,15 @@ + + + + + + + + + \ No newline at end of file diff --git a/ui/src/boot/.gitkeep b/ui/src/boot/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/ui/src/boot/axios.js b/ui/src/boot/axios.js new file mode 100644 index 0000000..9dbc942 --- /dev/null +++ b/ui/src/boot/axios.js @@ -0,0 +1,24 @@ +import { boot } from 'quasar/wrappers' +import axios from 'axios' + +// Be careful when using SSR for cross-request state pollution +// due to creating a Singleton instance here; +// If any client changes this (global) instance, it might be a +// good idea to move this instance creation inside of the +// "export default () => {}" function below (which runs individually +// for each client) +const api = axios.create({ baseURL: 'https://api.example.com' }) + +export default boot(({ app }) => { + // for use inside Vue files (Options API) through this.$axios and this.$api + + app.config.globalProperties.$axios = axios + // ^ ^ ^ this will allow you to use this.$axios (for Vue Options API form) + // so you won't necessarily have to import axios in each vue file + + app.config.globalProperties.$api = api + // ^ ^ ^ this will allow you to use this.$api (for Vue Options API form) + // so you can easily perform requests against your app's API +}) + +export { api } diff --git a/ui/src/boot/pinia.js b/ui/src/boot/pinia.js new file mode 100644 index 0000000..0f05547 --- /dev/null +++ b/ui/src/boot/pinia.js @@ -0,0 +1,4 @@ +import { useLoginStore } from 'stores/login' + +const store = useLoginStore() +store.load() diff --git a/ui/src/boot/version.js b/ui/src/boot/version.js new file mode 100644 index 0000000..247117a --- /dev/null +++ b/ui/src/boot/version.js @@ -0,0 +1,5 @@ +import vdata from '../../version' + +const $VERSION = vdata +export { $VERSION } + diff --git a/ui/src/components/EssentialLink.vue b/ui/src/components/EssentialLink.vue new file mode 100644 index 0000000..3a29f8f --- /dev/null +++ b/ui/src/components/EssentialLink.vue @@ -0,0 +1,48 @@ + + + diff --git a/ui/src/css/app.scss b/ui/src/css/app.scss new file mode 100644 index 0000000..3038c18 --- /dev/null +++ b/ui/src/css/app.scss @@ -0,0 +1,12 @@ +// app global css in SCSS form +@import "panel"; + +@import url('https://fonts.googleapis.com/css2?family=Nunito:ital,wght@0,200;0,300;0,400;0,500;0,600;0,700;1,200;1,300;1,400;1,500;1,600;1,700&display=swap'); +@import url('https://fonts.googleapis.com/css2?family=Merriweather:ital,wght@0,300;0,400;0,700;0,900;1,300;1,400;1,700;1,900&display=swap'); +@import url('https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,300;0,400;0,700;0,900;1,300;1,400;1,700;1,900&display=swap'); + +body { + font-family: 'Nunito', sans-serif; + font-size: 16px; + color: #334155; +} diff --git a/ui/src/css/panel.scss b/ui/src/css/panel.scss new file mode 100644 index 0000000..01a8491 --- /dev/null +++ b/ui/src/css/panel.scss @@ -0,0 +1,44 @@ +:root { + --pcolor1: #c84b41; + --pcolor2: #020f40; + --pcolor3: #64748b; +} + +.text-pcolor1 { + color: var(--pcolor1) !important; +} + +.bg-pcolor1 { + background-color: var(--pcolor1) !important; +} + +.text-pcolor2 { + color: var(--pcolor2) !important; +} + +.bg-pcolor2 { + background-color: var(--pcolor2) !important; +} + +.text-pcolor3 { + color: var(--pcolor3) !important; +} + +.bg-pcolor3 { + background-color: var(--pcolor3) !important; +} + + +.border-bottom { + border-bottom: #cccccc 1px solid; +} + + +a.pcolor1link { + color: var(--pcolor1); + text-decoration: none; + &:hover { + color: var(--pcolor1); + text-decoration: underline; + } +} diff --git a/ui/src/css/quasar.variables.scss b/ui/src/css/quasar.variables.scss new file mode 100644 index 0000000..3996ce1 --- /dev/null +++ b/ui/src/css/quasar.variables.scss @@ -0,0 +1,25 @@ +// Quasar SCSS (& Sass) Variables +// -------------------------------------------------- +// To customize the look and feel of this app, you can override +// the Sass/SCSS variables found in Quasar's source Sass/SCSS files. + +// Check documentation for full list of Quasar variables + +// Your own variables (that are declared here) and Quasar's own +// ones will be available out of the box in your .vue/.scss/.sass files + +// It's highly recommended to change the default colors +// to match your app's branding. +// Tip: Use the "Theme Builder" on Quasar's documentation website. + +$primary : #1976D2; +$secondary : #26A69A; +$accent : #9C27B0; + +$dark : #1D1D1D; +$dark-page : #121212; + +$positive : #21BA45; +$negative : #C10015; +$info : #31CCEC; +$warning : #F2C037; diff --git a/ui/src/layouts/MainLayout.vue b/ui/src/layouts/MainLayout.vue new file mode 100644 index 0000000..e4a792e --- /dev/null +++ b/ui/src/layouts/MainLayout.vue @@ -0,0 +1,106 @@ + + + diff --git a/ui/src/layouts/landingLayout.vue b/ui/src/layouts/landingLayout.vue new file mode 100644 index 0000000..7f9dd8b --- /dev/null +++ b/ui/src/layouts/landingLayout.vue @@ -0,0 +1,46 @@ + + + diff --git a/ui/src/layouts/panelLayout.vue b/ui/src/layouts/panelLayout.vue new file mode 100644 index 0000000..eba898c --- /dev/null +++ b/ui/src/layouts/panelLayout.vue @@ -0,0 +1,64 @@ + + + + diff --git a/ui/src/pages/ErrorNotFound.vue b/ui/src/pages/ErrorNotFound.vue new file mode 100644 index 0000000..23041c4 --- /dev/null +++ b/ui/src/pages/ErrorNotFound.vue @@ -0,0 +1,29 @@ + + + diff --git a/ui/src/pages/IndexPage.vue b/ui/src/pages/IndexPage.vue new file mode 100644 index 0000000..a595c2d --- /dev/null +++ b/ui/src/pages/IndexPage.vue @@ -0,0 +1,15 @@ + + + diff --git a/ui/src/pages/login.vue b/ui/src/pages/login.vue new file mode 100644 index 0000000..7f314a0 --- /dev/null +++ b/ui/src/pages/login.vue @@ -0,0 +1,54 @@ + + + diff --git a/ui/src/router/index.js b/ui/src/router/index.js new file mode 100644 index 0000000..e28c96f --- /dev/null +++ b/ui/src/router/index.js @@ -0,0 +1,66 @@ +import { + createMemoryHistory, + createRouter, + createWebHashHistory, + createWebHistory, +} from 'vue-router' +import routes from './routes' +import useLoginStore from 'stores/login' + +/* + * 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. + */ + +const createHistory = process.env.SERVER + ? createMemoryHistory + : (process.env.VUE_ROUTER_MODE === 'history' + ? createWebHistory + : createWebHashHistory) + +const Router = createRouter({ + scrollBehavior: () => ({ left: 0, top: 0 }), + routes, + + // Leave this as is and make changes in quasar.conf.js instead! + // quasar.conf.js -> build -> vueRouterMode + // quasar.conf.js -> build -> publicPath + history: createHistory(process.env.VUE_ROUTER_BASE), +}) + +Router.beforeEach( + (to, from) => { + const loginStore = useLoginStore() + + const isLoggedIn = loginStore.IsLoggedIn() + + // instead of having to check every route record with + // to.matched.some(record => record.meta.requiresAuth) + + if (to.meta.requiresAuth && !isLoggedIn && + ((to.path !== '/') || (to.path !== 'login'))) { + // this route requires auth, check if logged in + // if not, redirect to login page. + + return { + path: '/login', + // save the location we were at to come back later + //query: { redirect: to.fullPath }, + } + } + + if ((isLoggedIn) && ((to.path === '/') || (to.path === 'login'))) { + return { + path: '/panel', + query: '', + } + } + }, +) + +export default Router + diff --git a/ui/src/router/routes.js b/ui/src/router/routes.js new file mode 100644 index 0000000..695c004 --- /dev/null +++ b/ui/src/router/routes.js @@ -0,0 +1,33 @@ + +const routes = [ + { + path: '/', + component: () => import('layouts/panelLayout.vue'), + meta: { + requiresAuth: true + }, + children: [ + { path: '', component: () => import('pages/IndexPage.vue') }, + ] + }, + + { + path: '/login', + component: () => import('layouts/landingLayout.vue'), + children: [ + { path: '', component: () => import('pages/login.vue') } + ], + meta: { + requiresAuth: false + }, + }, + + // Always leave this as last one, + // but you can also remove it + { + path: '/:catchAll(.*)*', + component: () => import('pages/ErrorNotFound.vue') + } +] + +export default routes diff --git a/ui/src/stores/index.js b/ui/src/stores/index.js new file mode 100644 index 0000000..ca5bee5 --- /dev/null +++ b/ui/src/stores/index.js @@ -0,0 +1,20 @@ +import { store } from 'quasar/wrappers' +import { createPinia } from 'pinia' + +/* + * If not building with SSR mode, you can + * directly export the Store instantiation; + * + * The function below can be async too; either use + * async/await or return a Promise which resolves + * with the Store instance. + */ + +export default store((/* { ssrContext } */) => { + const pinia = createPinia() + + // You can add Pinia plugins here + // pinia.use(SomePiniaPlugin) + + return pinia +}) diff --git a/ui/src/stores/login.js b/ui/src/stores/login.js new file mode 100644 index 0000000..69f7954 --- /dev/null +++ b/ui/src/stores/login.js @@ -0,0 +1,79 @@ +import { defineStore } from 'pinia' +import { LocalStorage } from 'quasar' +import { api } from 'boot/axios' +import { jwtDecode } from "jwt-decode" +import Router from 'src/router/index' + +export const sessionName = 'bresSession' + +const defaultState = { + LoggedIn: false, + Token: '', + UsrKSUID: '', + ClientKSUID: '', + Email: '', + Fullname: '', +} + +export const useLoginStore = defineStore('login', { + state: () => { + return JSON.parse(JSON.stringify(defaultState)) + }, + getters: {}, + actions: { + + login (payload) { + // kaldıysa önceki session'ı uçuralım + LocalStorage.remove(sessionName) + const ds = JSON.parse(JSON.stringify(defaultState)) + Object.assign(this, ds) + + payload['LoggedIn'] = true + const pl = JSON.parse(JSON.stringify(payload)) + Object.assign(this, pl) + api.defaults.headers.common['Authorization'] = `Bearer ${payload.Token}` + LocalStorage.set(sessionName, payload) + }, + + logout () { + // todo: burada güvenlik zafiyeti var ! backend'de token invalidate edilmeli + // bunun için memlist'e ek bir claim tutulabilir + // ve jwtAuth verify koduna yazılıabilinir. + // örnek : https://dev.to/stevensunflash/a-working-solution-to-jwt-creation-and-invalidation-in-golang-4oe4 + const ds = JSON.parse(JSON.stringify(defaultState)) + Object.assign(this, ds) + + api.defaults.headers.common['Authorization'] = '' + LocalStorage.remove(sessionName) + + if (Router) { + Router.push('/login') + //router.push({ path: '/login', replace: true }) + } + }, + + updateState (payload) { + Object.assign(this, payload) + api.defaults.headers.common['Authorization'] = `Bearer ${payload.Token}` + }, + + load() { + const authInfo = LocalStorage.getItem(sessionName) + if (authInfo) { + const decoded = jwtDecode(authInfo.Token) + const now = Date.now() / 1000 + if (decoded.exp < now) { + this.logout() + } else { + this.updateState(authInfo) + } + } + }, + + IsLoggedIn () { + return this.LoggedIn + } + } +}) + +export default useLoginStore diff --git a/ui/src/stores/store-flag.d.ts b/ui/src/stores/store-flag.d.ts new file mode 100644 index 0000000..7677175 --- /dev/null +++ b/ui/src/stores/store-flag.d.ts @@ -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 { + store: true; + } +}