From fa7247a338cddfa3f6f3aae46f743be65ece54d2 Mon Sep 17 00:00:00 2001 From: Paolo Arena Date: Thu, 31 Jan 2019 13:52:52 +0100 Subject: [PATCH 01/18] - Activated Workbox precache PWA ! importScripts('https://storage.googleapis.com/workbox-cdn/releases/3.0.0/workbox-sw.js'); if (!workbox) { workbox = new self.WorkboxSW(); } if (workbox) { workbox.core.setCacheNameDetails({prefix: "freeplanet"}); /** * The workboxSW.precacheAndRoute() method efficiently caches and responds to * requests for URLs in the manifest. * See https://goo.gl/S9QRab */ self.__precacheManifest = [].concat(self.__precacheManifest || []); workbox.precaching.suppressWarnings(); workbox.precaching.precacheAndRoute(self.__precacheManifest, {}); workbox.routing.registerRoute(/^http/, workbox.strategies.networkFirst(), 'GET'); } --- .env.development | 2 +- package-lock.json | 22 ++++---- package.json | 13 +++-- quasar.conf.js | 12 ++++- src-pwa/custom-service-worker.js | 54 +++++++++++++------ src-pwa/register-service-worker.js | 7 ++- src/components/Header.vue | 2 +- src/components/todos/SingleTodo/SingleTodo.ts | 2 +- src/components/todos/todo/todo.ts | 28 ++++++---- src/index.template.html | 16 +++--- src/layouts/drawer/drawer.vue | 2 +- src/plugins/i18n.js | 2 +- src/root/home/home.ts | 4 +- src/{ => statics}/i18n.js | 6 ++- src/views/login/vreg/vreg.ts | 2 +- workbox-config.js | 13 +++++ 16 files changed, 128 insertions(+), 59 deletions(-) rename src/{ => statics}/i18n.js (96%) create mode 100644 workbox-config.js diff --git a/.env.development b/.env.development index fea6886..2c23d66 100644 --- a/.env.development +++ b/.env.development @@ -1,4 +1,4 @@ -SERVICE_WORKER_FILE='sw.js' +SERVICE_WORKER_FILE='service-worker.js' APP_ID='1' VUE_APP_URL='prova SVILUPPO!' PROVA_PAOLO='PROVA SVILUPPO' diff --git a/package-lock.json b/package-lock.json index 0c3bf32..0c848f1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "freeplanet", - "version": "0.0.1", + "version": "0.0.2", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -21098,7 +21098,7 @@ "dependencies": { "minimist": { "version": "1.2.0", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true } @@ -24014,7 +24014,7 @@ "graceful-fs": "4.1.15", "make-dir": "1.3.0", "unique-string": "1.0.0", - "write-file-atomic": "2.3.0", + "write-file-atomic": "2.4.2", "xdg-basedir": "3.0.0" } }, @@ -24028,9 +24028,9 @@ } }, "write-file-atomic": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.3.0.tgz", - "integrity": "sha512-xuPeK4OdjWqtfi59ylvVL0Yn35SF3zgcAcv7rBPFHVaEapaDr4GdGgm3j7ckTwH9wHL7fGmgfAnb0+THrHb8tA==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.2.tgz", + "integrity": "sha512-s0b6vB3xIVRLWywa6X9TOMA7k9zio0TMOsl9ZnDkliA/cfJlpHXAscj0gbHVJiTdIuAYpIyqS5GW91fqm6gG5g==", "dev": true, "requires": { "graceful-fs": "4.1.15", @@ -25489,9 +25489,9 @@ }, "dependencies": { "ansi-escapes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz", - "integrity": "sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", "dev": true }, "chardet": { @@ -25502,7 +25502,7 @@ }, "external-editor": { "version": "2.2.0", - "resolved": "http://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", "dev": true, "requires": { @@ -25537,7 +25537,7 @@ "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==", "dev": true, "requires": { - "ansi-escapes": "3.1.0", + "ansi-escapes": "3.2.0", "chalk": "2.4.1", "cli-cursor": "2.1.0", "cli-width": "2.2.0", diff --git a/package.json b/package.json index f48f25a..8c23234 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,13 @@ { "name": "freeplanet", - "version": "0.0.1", + "version": "0.0.2", "private": true, + "keywords": [ + "freeplanet", + "free social" + ], + "author": "Paolo Arena", + "license": "MIT", "scripts": { "lint": "tslint --project tsconfig.json", "lint:fix": "tslint --project tsconfig.json --fix", @@ -10,11 +16,12 @@ "pwa": "NODE_ENV=development NODE_OPTIONS=--max_old_space_size=4096 DEBUG=v8:* quasar dev -m pwa", "test:unit": "jest", "test:cover": "jest --coverage", - "build": "quasar build -m pwa && workbox generateSW workbox-config.js", + "build": "quasar build -m pwa", "build:clean": "quasar clean", "serve": "quasar serve ./dist/pwa-mat", "serve:coverage": "quasar serve test/coverage/lcov-report/ --cache 0 --port 8788", - "deploy": "deploy.sh" + "deploy": "deploy.sh", + "generate-sw": "workbox generateSW workbox-config.js" }, "dependencies": { "@types/vuelidate": "^0.7.0", diff --git a/quasar.conf.js b/quasar.conf.js index 3e42cce..6a82163 100644 --- a/quasar.conf.js +++ b/quasar.conf.js @@ -180,8 +180,18 @@ module.exports = function (ctx) { } }, pwa: { + // runtimeCaching: [ + // { + // urlPattern: '/statics', + // handler: 'networkFirst' + // } + // ], + + // workboxPluginMode: 'GenerateSW', workboxPluginMode: 'InjectManifest', - // workboxOptions: {}, + workboxOptions: { + // swSrc: 'src/sw.js', + }, manifest: { name: 'Free Planet', short_name: 'freeplanet', diff --git a/src-pwa/custom-service-worker.js b/src-pwa/custom-service-worker.js index 81b7637..587c207 100644 --- a/src-pwa/custom-service-worker.js +++ b/src-pwa/custom-service-worker.js @@ -4,21 +4,45 @@ * quasar.conf > pwa > workboxPluginMode is set to "InjectManifest" */ -self.addEventListener('install', function(event) { - console.log('[Service Worker] Installing Service Worker ...', event); -}); +// Questo è il swSrc -self.addEventListener('activate', function(event) { - console.log('[Service Worker] Activating Service Worker ...', event); - return self.clients.claim(); -}); +console.log('___________________________ PAO: this is my custom service worker'); -self.addEventListener('fetch', function(event) { - //console.log('[Service Worker] Fetching something ....', event); - if (event.request.cache === 'only-if-cached' && event.request.mode !== 'same-origin') { - console.log('SAME ORIGIN!', event); - return; - } - event.respondWith(fetch(event.request)); -}); +importScripts('https://storage.googleapis.com/workbox-cdn/releases/3.0.0/workbox-sw.js'); + +if (!workbox) { + workbox = new self.WorkboxSW(); +} + +if (workbox) { + workbox.core.setCacheNameDetails({prefix: "freeplanet"}); + + /** + * The workboxSW.precacheAndRoute() method efficiently caches and responds to + * requests for URLs in the manifest. + * See https://goo.gl/S9QRab + */ + self.__precacheManifest = [].concat(self.__precacheManifest || []); + workbox.precaching.suppressWarnings(); + workbox.precaching.precacheAndRoute(self.__precacheManifest, {}); + + workbox.routing.registerRoute(/^http/, workbox.strategies.networkFirst(), 'GET'); + +} + +if ('serviceWorker' in navigator) { + + console.log('***************** Entering in custom-service-worker.js:') + + self.addEventListener('fetch', function (event) { + console.log('[Service Worker] Fetching something ....', event); + console.log('event.request.cache=', event.request.cache) + if (event.request.cache === 'only-if-cached' && event.request.mode !== 'same-origin') { + console.log('SAME ORIGIN!', event); + return; + } + event.respondWith(fetch(event.request)); + }); + +} diff --git a/src-pwa/register-service-worker.js b/src-pwa/register-service-worker.js index b7df77d..5205056 100644 --- a/src-pwa/register-service-worker.js +++ b/src-pwa/register-service-worker.js @@ -8,9 +8,11 @@ import {register} from 'register-service-worker' register(process.env.SERVICE_WORKER_FILE, { ready() { console.log('READY::: App is being served from cache by a service worker.') + }, registered(registration) { // registration -> a ServiceWorkerRegistration instance - console.log('REGISTERED::: !!!') + console.log('REGISTERED::: !!!', process.env.SERVICE_WORKER_FILE) + }, cached(registration) { // registration -> a ServiceWorkerRegistration instance console.log('CACHED::: Content has been cached for offline use.') @@ -33,3 +35,6 @@ register(process.env.SERVICE_WORKER_FILE, { // ServiceWorkerRegistration: https://developer.mozilla.org/en-uk/docs/Web/API/ServiceWorkerRegistration + + +// "build": "quasar build -m pwa && workbox generateSW workbox-config.js", diff --git a/src/components/Header.vue b/src/components/Header.vue index db65f37..e859de8 100644 --- a/src/components/Header.vue +++ b/src/components/Header.vue @@ -106,7 +106,7 @@ // dynamic import, so loading on demand only import(`quasar-framework/i18n/${lang}`).then(lang => { this.$q.i18n.set(lang.default) - import(`src/i18n`).then(function () { + import(`src/statics/i18n`).then(function () { }) }) } diff --git a/src/components/todos/SingleTodo/SingleTodo.ts b/src/components/todos/SingleTodo/SingleTodo.ts index 436ac1c..895197e 100644 --- a/src/components/todos/SingleTodo/SingleTodo.ts +++ b/src/components/todos/SingleTodo/SingleTodo.ts @@ -284,7 +284,7 @@ export default class SingleTodo extends Vue { } updateicon() { - console.log('updateicon') + // console.log('updateicon') if (this.itemtodo.completed) this.iconCompleted = 'check_circle' else diff --git a/src/components/todos/todo/todo.ts b/src/components/todos/todo/todo.ts index 8389b06..ffcc80d 100644 --- a/src/components/todos/todo/todo.ts +++ b/src/components/todos/todo/todo.ts @@ -6,7 +6,7 @@ import { ITodo } from '@src/model' import { rescodes } from '../../../store/Modules/rescodes' -import { UserStore } from '@modules' +import { UserStore } from '@store' import _ from 'lodash' @@ -45,7 +45,7 @@ export default class Todo extends Vue { } @Watch('$route.params.category') changecat() { - console.log('changecat') + // console.log('changecat') this.load() } @@ -90,7 +90,7 @@ export default class Todo extends Vue { async updateLinkedList(init: boolean, arr: ITodo[] = this.todos_arr) { - console.log('updateLinkedList', this.todos_arr) + // console.log('updateLinkedList', this.todos_arr) let idprev = -1 let idnext = -1 @@ -123,7 +123,7 @@ export default class Todo extends Vue { pos++ - this.logelem('updateLinked', elem) + // this.logelem('updateLinked', elem) }) } @@ -240,7 +240,7 @@ export default class Todo extends Vue { arr.forEach(rec => { this.arrPrior.push(rec.value) }) - console.log('Array PRIOR:', this.arrPrior) + // console.log('Array PRIOR:', this.arrPrior) } @@ -251,15 +251,17 @@ export default class Todo extends Vue { for (let todosKey in rescodes.Todos) { this.listPriorityLabel.push(rescodes.Todos[todosKey]) } - console.log('Priority:' + this.listPriorityLabel) + // console.log('Priority:' + this.listPriorityLabel) this.setarrPriority() this.clearArr() await this.updatetable() +/* this.todos_arr.forEach((elem, index) => { this.logelem('LOAD ' + index, elem) }) +*/ } @@ -273,8 +275,8 @@ export default class Todo extends Vue { priority: rescodes.Todos.PRIORITY_NORMAL, completed: false, created_at: new Date(), - category: '', modify_at: new Date(), + category: '', expiring_at: mydateexp, enableExpiring: false, id_prev: 0, @@ -310,6 +312,12 @@ export default class Todo extends Vue { objtodo.pos = (lastelem !== null) ? lastelem.pos + 1 : 1 objtodo.modified = true + if (objtodo.userId === undefined) { + this.$q.notify(this.$t('todo.usernotdefined')) + return + } + + // Add to Indexdb await this.$db.todos.add(objtodo ).then((id) => { @@ -442,7 +450,7 @@ export default class Todo extends Vue { } async filtertodos(refresh: boolean = false) { - console.log('filtertodos') + // console.log('filtertodos') let arrtemp = [] @@ -515,7 +523,7 @@ export default class Todo extends Vue { // deselectAllRows(item, check, onlythis: boolean = false) { - console.log('deselectAllRows : ', item) + // console.log('deselectAllRows : ', item) for (let i = 0; i < this.$refs.single.length; i++) { @@ -574,7 +582,7 @@ export default class Todo extends Vue { if (miorec.modified) { miorec.modify_at = new Date() - this.logelem('modify', miorec) + // this.logelem('modify', miorec) await this.$db.todos.put(miorec) diff --git a/src/index.template.html b/src/index.template.html index 4e2e4de..5e4fb15 100644 --- a/src/index.template.html +++ b/src/index.template.html @@ -10,15 +10,15 @@ - - - - - - - + + + + + + + - + diff --git a/src/layouts/drawer/drawer.vue b/src/layouts/drawer/drawer.vue index fc56086..0452d8f 100644 --- a/src/layouts/drawer/drawer.vue +++ b/src/layouts/drawer/drawer.vue @@ -55,7 +55,7 @@ links created() { - console.log('Drawer created...') + // console.log('Drawer created...') let listatodo = [] diff --git a/src/plugins/i18n.js b/src/plugins/i18n.js index 1f812a8..fc70103 100644 --- a/src/plugins/i18n.js +++ b/src/plugins/i18n.js @@ -1,6 +1,6 @@ // src/plugins/i18n.js import VueI18n from 'vue-i18n'; -import messages from 'src/i18n'; +import messages from 'src/statics/i18n'; export default ({ app, store, Vue }) => { Vue.use(VueI18n); diff --git a/src/root/home/home.ts b/src/root/home/home.ts index c9b58c6..df3acf2 100644 --- a/src/root/home/home.ts +++ b/src/root/home/home.ts @@ -19,12 +19,12 @@ export default class Home extends Vue { constructor() { super() - console.log('Home constructor...') + // console.log('Home constructor...') this.initprompt() } created() { - console.log('Home created...') + // console.log('Home created...') } mystilecard() { diff --git a/src/i18n.js b/src/statics/i18n.js similarity index 96% rename from src/i18n.js rename to src/statics/i18n.js index 5687c04..c010462 100644 --- a/src/i18n.js +++ b/src/statics/i18n.js @@ -101,7 +101,8 @@ const messages = { titleprioritymenu: 'Priorità:', insert: 'Inserisci il Task', edit: 'Descrizione Task:', - completed: 'Completati' + completed: 'Completati', + usernotdefined: 'Attenzione, occorre essere Loggati per poter aggiungere un Todo' } }, enUk: { @@ -206,7 +207,8 @@ const messages = { titleprioritymenu: 'Priority:', insert: 'Insert Task', edit: 'Task Description:', - completed: 'Completed' + completed: 'Completed', + usernotdefined: 'Attention, you need to be Signed In to add a new Task' } }, }; diff --git a/src/views/login/vreg/vreg.ts b/src/views/login/vreg/vreg.ts index 83adbe6..6578ff1 100644 --- a/src/views/login/vreg/vreg.ts +++ b/src/views/login/vreg/vreg.ts @@ -39,7 +39,7 @@ export default class Vreg extends Vue { } load() { - console.log('load') + // console.log('load') let param: ILinkReg param = { idlink: this.$route.query.idlink.toString() } console.log('idlink = ', param) diff --git a/workbox-config.js b/workbox-config.js new file mode 100644 index 0000000..c10c1e4 --- /dev/null +++ b/workbox-config.js @@ -0,0 +1,13 @@ +module.exports = { + "globDirectory": "dist/pwa-mat/", + "globPatterns": [ + "**/*.{css,woff2,woff,svg,html,js,json,ico}" + // "src/images/*.{jpg,png}" + ], + // "swSrc": "dist/pwa-mat/src-sw.js", + "swDest": "dist/pwa-mat/service-worker.js", + "globIgnores": [ + "../workbox-config.js", + "help/**" + ], +}; From f52eb65284078d1aaff2c07ddee2ef5a55f7e2d9 Mon Sep 17 00:00:00 2001 From: Paolo Arena Date: Thu, 31 Jan 2019 17:08:10 +0100 Subject: [PATCH 02/18] - regular expression for precache new RegExp(/.*\/(?:css|font).*/), --- src-pwa/custom-service-worker.js | 112 ++++++++++++++++++++++++++++--- src/index.template.html | 2 +- 2 files changed, 102 insertions(+), 12 deletions(-) diff --git a/src-pwa/custom-service-worker.js b/src-pwa/custom-service-worker.js index 587c207..be847ef 100644 --- a/src-pwa/custom-service-worker.js +++ b/src-pwa/custom-service-worker.js @@ -15,7 +15,7 @@ if (!workbox) { } if (workbox) { - workbox.core.setCacheNameDetails({prefix: "freeplanet"}); + workbox.core.setCacheNameDetails({ prefix: "freeplanet" }); /** * The workboxSW.precacheAndRoute() method efficiently caches and responds to @@ -26,7 +26,97 @@ if (workbox) { workbox.precaching.suppressWarnings(); workbox.precaching.precacheAndRoute(self.__precacheManifest, {}); - workbox.routing.registerRoute(/^http/, workbox.strategies.networkFirst(), 'GET'); + // workbox.routing.registerRoute(/^http/, workbox.strategies.networkFirst(), 'GET'); + + workbox.routing.registerRoute( + new RegExp(/.*(?:googleapis|gstatic)\.com.*$/), + workbox.strategies.staleWhileRevalidate({ + cacheName: 'google-fonts', + plugins: [ + new workbox.expiration.Plugin({ + maxAgeSeconds: 30 * 24 * 60 * 60, + }), + ] + }) + ); + + workbox.routing.registerRoute( + new RegExp(/.*\/(?:statics\/icons).*$/), + workbox.strategies.cacheFirst({ + cacheName: 'image-cache', + plugins: [ + new workbox.expiration.Plugin({ + maxAgeSeconds: 30 * 24 * 60 * 60, + }), + ] + }) + ); + + workbox.routing.registerRoute( + new RegExp(/.*\/(?:css|font).*/), + workbox.strategies.cacheFirst({ + cacheName: 'css-fonts', + plugins: [ + new workbox.expiration.Plugin({ + maxAgeSeconds: 30 * 24 * 60 * 60, + }), + ] + }) + ); + + + workbox.routing.registerRoute( + new RegExp('https://cdnjs.coudflare.com/ajax/libs/material-design-lite/1.3.0/material.indigo-pink.min.css'), + workbox.strategies.staleWhileRevalidate({ + cacheName: 'material-css', + plugins: [ + new workbox.expiration.Plugin({ + maxAgeSeconds: 30 * 24 * 60 * 60, + }), + ] + }) + ); + +// Storage + workbox.routing.registerRoute( + new RegExp(/.*(?:storage\.freeplanet)\.app.*$/), + workbox.strategies.staleWhileRevalidate({ + cacheName: 'storage', + plugins: [ + new workbox.expiration.Plugin({ + maxAgeSeconds: 30 * 24 * 60 * 60, + // Only cache 10 requests. + maxEntries: 200, + }), + ] + }) + ); + + workbox.routing.registerRoute( + new RegExp(/.*\/(?:statics).*$/), + workbox.strategies.cacheFirst({ + cacheName: 'statics', + plugins: [ + new workbox.expiration.Plugin({ + maxAgeSeconds: 10 * 24 * 60 * 60, + // Only cache 10 requests. + }), + ] + }) + ); + + workbox.routing.registerRoute( + new RegExp(/^http/), + workbox.strategies.networkFirst({ + cacheName: 'all-stuff', + plugins: [ + new workbox.expiration.Plugin({ + maxAgeSeconds: 10 * 24 * 60 * 60, + // Only cache 10 requests. + }), + ] + }) + ); } @@ -34,15 +124,15 @@ if ('serviceWorker' in navigator) { console.log('***************** Entering in custom-service-worker.js:') - self.addEventListener('fetch', function (event) { - console.log('[Service Worker] Fetching something ....', event); - console.log('event.request.cache=', event.request.cache) - if (event.request.cache === 'only-if-cached' && event.request.mode !== 'same-origin') { - console.log('SAME ORIGIN!', event); - return; - } - event.respondWith(fetch(event.request)); - }); + // self.addEventListener('fetch', function (event) { + // console.log('[Service Worker] Fetching something ....', event); + // console.log('event.request.cache=', event.request.cache) + // if (event.request.cache === 'only-if-cached' && event.request.mode !== 'same-origin') { + // console.log('SAME ORIGIN!', event); + // return; + // } + // event.respondWith(fetch(event.request)); + // }); } diff --git a/src/index.template.html b/src/index.template.html index 5e4fb15..cb87612 100644 --- a/src/index.template.html +++ b/src/index.template.html @@ -10,7 +10,7 @@ - + From 484439efe0ce45649e300b321ac242b51ff8a67d Mon Sep 17 00:00:00 2001 From: Paolo Arena Date: Fri, 1 Feb 2019 04:10:31 +0100 Subject: [PATCH 03/18] - Service Worker: Save on IndexDb and Sync to send after to the DB. - Insert record on MongoDb, POST, GET. --- src-pwa/custom-service-worker.js | 130 +++++++++++++- .../categories/category/category.vue | 2 +- src/components/todos/SingleTodo/SingleTodo.ts | 4 +- .../todos/SingleTodo/SingleTodo.vue | 2 +- src/components/todos/todo/todo.ts | 162 +++++++++++------- src/components/todos/todo/todo.vue | 2 +- src/js/utility.js | 91 ++++++++++ src/model/Todos.ts | 5 +- src/plugins/vue-idb.js | 11 +- src/root/home/home.ts | 1 + src/store/Api/Inst-Pao.ts | 23 ++- src/store/Modules/Todos.ts | 138 ++++++++++++++- src/store/Modules/UserStore.ts | 22 ++- src/store/Modules/index.ts | 1 + 14 files changed, 494 insertions(+), 100 deletions(-) create mode 100644 src/js/utility.js diff --git a/src-pwa/custom-service-worker.js b/src-pwa/custom-service-worker.js index be847ef..c3a2d27 100644 --- a/src-pwa/custom-service-worker.js +++ b/src-pwa/custom-service-worker.js @@ -6,15 +6,24 @@ // Questo è il swSrc -console.log('___________________________ PAO: this is my custom service worker'); +console.log('05 ___________________________ PAO: this is my custom service worker'); + +importScripts('https://storage.googleapis.com/workbox-cdn/releases/3.0.0/workbox-sw.js'); //++Todo: Replace with local workbox.js +importScripts('js/idb.js'); +importScripts('js/utility.js'); -importScripts('https://storage.googleapis.com/workbox-cdn/releases/3.0.0/workbox-sw.js'); if (!workbox) { - workbox = new self.WorkboxSW(); + let workbox = new self.WorkboxSW(); + } if (workbox) { + // const url = new URL(location.href); + // const debug = url.searchParams.has('debug'); + const debug = false; + workbox.setConfig({ debug: debug }); + workbox.core.setCacheNameDetails({ prefix: "freeplanet" }); /** @@ -28,18 +37,49 @@ if (workbox) { // workbox.routing.registerRoute(/^http/, workbox.strategies.networkFirst(), 'GET'); + workbox.routing.registerRoute( + /\.(?:png|gif|jpg|jpeg|svg)$/, + workbox.strategies.staleWhileRevalidate({ + cacheName: 'images', + plugins: [ + new workbox.expiration.Plugin({ + maxEntries: 60, + maxAgeSeconds: 30 * 24 * 60 * 60, // 30 Days + }), + ], + }), + ); + workbox.routing.registerRoute( new RegExp(/.*(?:googleapis|gstatic)\.com.*$/), workbox.strategies.staleWhileRevalidate({ cacheName: 'google-fonts', plugins: [ new workbox.expiration.Plugin({ - maxAgeSeconds: 30 * 24 * 60 * 60, + maxEntries: 30, }), ] }) ); + workbox.routing.registerRoute('http://localhost:3000/todos', function (args) { + return fetch(args.event.request) + .then(function (res) { + var clonedRes = res.clone(); + clearAllData('todos') + .then(function () { + return clonedRes.json(); + }) + .then(function (data) { + for (let key in data) { + writeData('todos', data[key]) + } + }); + return res; + }); + }); + + workbox.routing.registerRoute( new RegExp(/.*\/(?:statics\/icons).*$/), workbox.strategies.cacheFirst({ @@ -118,12 +158,37 @@ if (workbox) { }) ); + // workbox.core.setLogLevel(workbox.core.LOG_LEVELS.debug); + + workbox.routing.registerRoute( + new RegExp('http://localhost:8080/todos'), + function (args) { + return fetch(args.event.request) + .then(function (res) { + console.log('******* fetch: ', args.event) + var clonedRes = res.clone(); + clearAllData('todos') + .then(function () { + return clonedRes.json(); + }) + .then(function (data) { + for (let key in data) { + writeData('todos', data[key]) + } + }); + return res + }) + } + ); + } if ('serviceWorker' in navigator) { console.log('***************** Entering in custom-service-worker.js:') +} + // self.addEventListener('fetch', function (event) { // console.log('[Service Worker] Fetching something ....', event); // console.log('event.request.cache=', event.request.cache) @@ -131,8 +196,61 @@ if ('serviceWorker' in navigator) { // console.log('SAME ORIGIN!', event); // return; // } - // event.respondWith(fetch(event.request)); + // event.respondWith(caches.match(event.request)); // }); -} + + self.addEventListener('sync', function (event) { + console.log('[Service Worker] Background syncing', event); + + if (event.tag === 'sync-new-todos') { + console.log('[Service Worker] Syncing new Todos'); + + let authHeader = [] + authHeader['content-type'] = 'application/json'; + authHeader['accept-language'] = 'en'; + // authHeader.append('x-auth', mytok) + + event.waitUntil( + readAllData('sync_todos') + .then(function (data) { + for (var dt of data) { + // var postData = new FormData(); + // postData.append('_id', dt._id); + // postData.append('title', dt.title); + // postData.append('location', dt.location); + // postData.append('rawLocationLat', dt.rawLocation.lat); + // postData.append('rawLocationLng', dt.rawLocation.lng); + // postData.append('file', dt.picture, dt._id + '.png'); + + console.log('Data to Send 6: ', JSON.stringify(dt)) + + // Update myTodo to the server + fetch('http://localhost:3000/todos', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json' + }, + // mode: 'no-cors', + mode: 'cors', + body: JSON.stringify(dt) + }) + .then(function (resData) { + console.log('Sent data Todo:', resData); + if (resData.ok) { + deleteItemFromData('sync_todos', dt.id); + } + }) + .catch(function (err) { + console.log('Error while sending data', err); + }); + } + + }) + ); + } + }); + +// } diff --git a/src/components/categories/category/category.vue b/src/components/categories/category/category.vue index 1d9eff6..6a9c70c 100644 --- a/src/components/categories/category/category.vue +++ b/src/components/categories/category/category.vue @@ -53,7 +53,7 @@ - + diff --git a/src/components/todos/SingleTodo/SingleTodo.ts b/src/components/todos/SingleTodo/SingleTodo.ts index 895197e..37c2c0f 100644 --- a/src/components/todos/SingleTodo/SingleTodo.ts +++ b/src/components/todos/SingleTodo/SingleTodo.ts @@ -130,7 +130,7 @@ export default class SingleTodo extends Vue { // this.classDescr += ' show' // } - // this.getinputdescr = 'inputdescr' + this.itemtodo.id + // this.getinputdescr = 'inputdescr' + this.itemtodo._id // console.log('classDescrEdit = ', this.classDescrEdit) // console.log('classDescr', this.classDescr) @@ -344,7 +344,7 @@ export default class SingleTodo extends Vue { .then(ris => { console.log('ris', ris) if (ris) - this.removeitem(this.itemtodo.id) + this.removeitem(this.itemtodo._id) }).catch(err => { }) diff --git a/src/components/todos/SingleTodo/SingleTodo.vue b/src/components/todos/SingleTodo/SingleTodo.vue index bbc070f..1c33fb7 100644 --- a/src/components/todos/SingleTodo/SingleTodo.vue +++ b/src/components/todos/SingleTodo/SingleTodo.vue @@ -59,7 +59,7 @@ - + diff --git a/src/components/todos/todo/todo.ts b/src/components/todos/todo/todo.ts index ffcc80d..0de8502 100644 --- a/src/components/todos/todo/todo.ts +++ b/src/components/todos/todo/todo.ts @@ -1,11 +1,12 @@ import Vue from 'vue' -import { Component, Prop, Watch } from 'vue-property-decorator' +import { Component, Watch } from 'vue-property-decorator' import { SingleTodo } from '../SingleTodo' import { ITodo } from '@src/model' import { rescodes } from '../../../store/Modules/rescodes' +import { Todos } from '@store' import { UserStore } from '@store' import _ from 'lodash' @@ -104,13 +105,13 @@ export default class Todo extends Vue { idprev = rescodes.LIST_START } else { const elemprev = this.getelem(index - 1, arr) - idprev = elemprev.id + idprev = elemprev._id } if (index === arr.length - 1) { idnext = rescodes.LIST_END } else { const elemnext = this.getelem(index + 1, arr) - idnext = elemnext.id + idnext = elemnext._id } elem.modified = ((elem.id_prev !== idprev) || (elem.id_next !== idnext) || (elem.pos !== pos)) ? true : elem.modified @@ -129,7 +130,7 @@ export default class Todo extends Vue { } logelem(mystr, elem) { - console.log(mystr, 'elem [', elem.id, '] ', elem.descr, ' Pr(', this.getPriorityByInd(elem.priority), ') [', elem.id_prev, '-', elem.id_next, '] modif=', elem.modified) + console.log(mystr, 'elem [', elem._id, '] ', elem.descr, ' Pr(', this.getPriorityByInd(elem.priority), ') [', elem.id_prev, '-', elem.id_next, '] modif=', elem.modified) } getPriorityToSet(ind1, ind2) { @@ -164,7 +165,7 @@ export default class Todo extends Vue { } - getTitlePriority (priority) { + getTitlePriority(priority) { let cl = '' if (priority === rescodes.Todos.PRIORITY_HIGH) @@ -245,6 +246,8 @@ export default class Todo extends Vue { async load() { + + // Set last category selected localStorage.setItem(rescodes.localStorage.categorySel, this.getCategory()) @@ -257,11 +260,11 @@ export default class Todo extends Vue { await this.updatetable() -/* - this.todos_arr.forEach((elem, index) => { - this.logelem('LOAD ' + index, elem) - }) -*/ + /* + this.todos_arr.forEach((elem, index) => { + this.logelem('LOAD ' + index, elem) + }) + */ } @@ -269,6 +272,8 @@ export default class Todo extends Vue { const mydateexp = new Date().setDate((new Date()).getDate() + 1) + console.log('User:' + UserStore.state.userId) + const objtodo: ITodo = { userId: UserStore.state.userId, descr: '', @@ -276,6 +281,7 @@ export default class Todo extends Vue { completed: false, created_at: new Date(), modify_at: new Date(), + completed_at: null, category: '', expiring_at: mydateexp, enableExpiring: false, @@ -298,16 +304,18 @@ export default class Todo extends Vue { return '' } - async insertTodo() { + insertTodo() { if (this.todo.trim() === '') return const objtodo = this.initcat() + console.log('autologin userId STATE ', UserStore.state.userId) + objtodo.descr = this.todo objtodo.category = this.getCategory() const lastelem = this.getLastList() - objtodo.id_prev = (lastelem !== null) ? lastelem.id : rescodes.LIST_START + objtodo.id_prev = (lastelem !== null) ? lastelem._id : rescodes.LIST_START objtodo.id_next = rescodes.LIST_END objtodo.pos = (lastelem !== null) ? lastelem.pos + 1 : 1 objtodo.modified = true @@ -317,29 +325,69 @@ export default class Todo extends Vue { return } + this.$db.todos.add(objtodo) // Add to Indexdb + .then((id) => { + console.log('*** IDNEW = ', id) - // Add to Indexdb - await this.$db.todos.add(objtodo - ).then((id) => { - console.log('*** IDNEW = ', id) - if (lastelem !== null) { - lastelem.id_next = id - lastelem.modified = true - this.modify(lastelem, false) - } - this.modify(objtodo, true) - }).catch(err => { - console.log('Errore: ' + err.message) - }) + // update also the last elem + if (lastelem !== null) { + lastelem.id_next = id + lastelem.modified = true + this.modify(lastelem, false) + } + + this.saveItemToSyncAndDb(objtodo) + + // this.modify(objtodo, true) + this.updatetable(false) + }).catch(err => { + console.log('Errore: ' + err.message) + }) + + console.log('ESCO.........') // empty the field this.todo = '' } + saveItemToSyncAndDb(item: ITodo) { + // Send to Server to Sync + const mythis = this + console.log('saveItemToSyncAndDb') + if ('serviceWorker' in navigator && 'SyncManager' in window) { + navigator.serviceWorker.ready + .then(function (sw) { + // _id: new Date().toISOString(), + console.log('---------------------- navigator.serviceWorker.ready') + + // check if exist _id, delete it + mythis.$db.sync_todos + .where('id').equals(item._id) + .delete() + + mythis.$db.sync_todos.add(item) + .then(function () { + return sw.sync.register('sync-new-todos') + }) + .then(function () { + let snackbarContainer = document.querySelector('#confirmation-toast') + let data = { message: 'Your Post was saved for syncing!' } + // snackbarContainer.MaterialSnackbar.showSnackbar(data) + }) + .catch(function (err) { + console.log(err) + }) + }) + } else { + Todos.actions.dbSaveTodo(item) + } + + } + getElemById(id, lista = this.todos_arr) { let myobj: ITodo for (myobj of lista) { - if (myobj.id === id) { + if (myobj._id === id) { return myobj } } @@ -436,7 +484,7 @@ export default class Todo extends Vue { current = this.getElemById(current.id_next, arrris) if (current === null) break - if (current.id === currentprec.id) + if (current._id === currentprec._id) break myarr.push(current) currentprec = current @@ -452,45 +500,21 @@ export default class Todo extends Vue { async filtertodos(refresh: boolean = false) { // console.log('filtertodos') - let arrtemp = [] + return await Todos.actions.getTodosByCategory(this.getCategory()) + .then(arrtemp => { - if (this.filter) { - // #Todo If need to filter the output database ... - await this.$db.todos - .where('userId').equals(UserStore.state.userId) - .and(todo => todo.category === this.getCategory()) - .toArray() - .then((response) => { - Promise.all(response.map(key => key)) - .then((ristodos) => { - arrtemp = ristodos - }) - }) - } else { - await this.$db.todos - .where('userId').equals(UserStore.state.userId) - .and(todo => todo.category === this.getCategory()) - .toArray().then(ristodos => { - arrtemp = ristodos - }) + arrtemp = _.orderBy(arrtemp, ['completed', 'priority', 'pos'], ['asc', 'desc', 'asc']) - arrtemp = _.orderBy(arrtemp, ['completed', 'priority', 'pos'], ['asc', 'desc', 'asc']) - } + this.updateLinkedList(true, arrtemp) - this.updateLinkedList(true, arrtemp) + this.todos_arr = [...arrtemp] // make copy + }) - // set array - // arrtemp = this.setArrayFinale(arrtemp) - - this.todos_arr = [...arrtemp] // make copy - - - return [] } sortarr(arr, field) { - return arr.slice().sort(function(a, b) { + return arr.slice().sort(function (a, b) { return a[field] - b[field] }) @@ -522,7 +546,7 @@ export default class Todo extends Vue { // } // - deselectAllRows(item, check, onlythis: boolean = false) { + deselectAllRows(item: ITodo, check, onlythis: boolean = false) { // console.log('deselectAllRows : ', item) for (let i = 0; i < this.$refs.single.length; i++) { @@ -530,13 +554,13 @@ export default class Todo extends Vue { let contr = this.$refs.single[i] // @ts-ignore - let id = contr.itemtodo.id + let id = contr.itemtodo._id // Don't deselect the actual clicked! let des = false if (onlythis) { - des = item.id === id - }else { - des = ((check && (item.id !== id)) || (!check)) + des = item._id === id + } else { + des = ((check && (item._id !== id)) || (!check)) } if (des) { // @ts-ignore @@ -549,7 +573,7 @@ export default class Todo extends Vue { // let index = -1 // // get index // this.$refs.single.forEach( (singletodo: SingleTodo) => { - // if (singletodo.itemtodo.id === rec.id) + // if (singletodo.itemtodo._id === rec._id) // index = -1 // }) // @@ -559,16 +583,20 @@ export default class Todo extends Vue { if (recOut[field] !== recIn[field]) { recOut.modified = true recOut[field] = recIn[field] + return true } + return false } async modify(myobj: ITodo, update: boolean) { await this.$db.transaction('rw', [this.$db.todos], async () => { - const miorec = await this.$db.todos.get(myobj.id) + const miorec = await this.$db.todos.get(myobj._id) this.modifyField(miorec, myobj, 'descr') - this.modifyField(miorec, myobj, 'completed') + if (this.modifyField(miorec, myobj, 'completed')) + miorec.completed_at = new Date() + this.modifyField(miorec, myobj, 'category') this.modifyField(miorec, myobj, 'expiring_at') this.modifyField(miorec, myobj, 'priority') @@ -586,6 +614,8 @@ export default class Todo extends Vue { await this.$db.todos.put(miorec) + this.saveItemToSyncAndDb(miorec) + if (update) await this.updatetable(false) } diff --git a/src/components/todos/todo/todo.vue b/src/components/todos/todo/todo.vue index a01f401..49d9656 100644 --- a/src/components/todos/todo/todo.vue +++ b/src/components/todos/todo/todo.vue @@ -13,7 +13,7 @@ -
+
diff --git a/src/js/utility.js b/src/js/utility.js new file mode 100644 index 0000000..ab782ba --- /dev/null +++ b/src/js/utility.js @@ -0,0 +1,91 @@ +console.log('utility.js') + +var dbPromise = idb.open('mydb', 10, function (db) { + console.log('OPEN MYDB') + if (!db.objectStoreNames.contains('sync_todos')) { + db.createObjectStore('sync_todos', { keyPath: 'id' }); + } + if (!db.objectStoreNames.contains('todos')) { + db.createObjectStore('todos', { keyPath: 'id' }); + } +}); + +function writeData(st, data) { + console.log('writeData', st, data); + return dbPromise + .then(function (db) { + var tx = db.transaction(st, 'readwrite'); + var store = tx.objectStore(st); + store.put(data); + return tx.complete; + }); +} + +function readAllData(st) { + console.log('readAllData', st); + return dbPromise + .then(function (db) { + var tx = db.transaction(st, 'readonly'); + var store = tx.objectStore(st); + return store.getAll(); + }); +} + +function clearAllData(st) { + console.log('clearAllData', st); + return dbPromise + .then(function (db) { + var tx = db.transaction(st, 'readwrite'); + var store = tx.objectStore(st); + store.clear(); + return tx.complete; + }); +} + +function deleteItemFromData(st, id) { + console.log('deleteItemFromData', st, 'ID:', id); + dbPromise + .then(function (db) { + + var tx = db.transaction(st, 'readwrite'); + var store = tx.objectStore(st); + + try { + store.delete(id); + return tx.complete; + } catch (e) { + return false; + } + }) + .then(function (res) { + if (res) + console.log('Item deleted!'); + }); +} + +function urlBase64ToUint8Array(base64String) { + var padding = '='.repeat((4 - base64String.length % 4) % 4); + var base64 = (base64String + padding) + .replace(/\-/g, '+') + .replace(/_/g, '/'); + + var rawData = window.atob(base64); + var outputArray = new Uint8Array(rawData.length); + + for (var i = 0; i < rawData.length; ++i) { + outputArray[i] = rawData.charCodeAt(i); + } + return outputArray; +} + +function dataURItoBlob(dataURI) { + var byteString = atob(dataURI.split(',')[1]); + var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0] + var ab = new ArrayBuffer(byteString.length); + var ia = new Uint8Array(ab); + for (var i = 0; i < byteString.length; i++) { + ia[i] = byteString.charCodeAt(i); + } + var blob = new Blob([ab], { type: mimeString }); + return blob; +} diff --git a/src/model/Todos.ts b/src/model/Todos.ts index 825e74d..e89ebc6 100644 --- a/src/model/Todos.ts +++ b/src/model/Todos.ts @@ -1,5 +1,5 @@ export interface ITodo { - id?: number, + _id?: number, userId: string category?: string descr?: string, @@ -7,6 +7,7 @@ export interface ITodo { completed: boolean, created_at: any, modify_at: any, + completed_at: any, expiring_at: any, enableExpiring?: boolean, id_prev?: number, @@ -18,4 +19,6 @@ export interface ITodo { export interface ITodosState { visuOnlyUncompleted: boolean + networkDataReceived: boolean + todos: ITodo[] } diff --git a/src/plugins/vue-idb.js b/src/plugins/vue-idb.js index af71717..192e9df 100644 --- a/src/plugins/vue-idb.js +++ b/src/plugins/vue-idb.js @@ -6,13 +6,16 @@ export default ({ Vue }) => { // Insert here the database for IndexDB new VueIdb({ - database: 'test', + database: 'mydb', + version: 1, schemas: [ - { categories: '++id, sub_categ_id, descr_it, campo2bool, campo3bool' }, - { todos: '++id, userId, category, pos, descr, priority, completed, created_at, modify_at, expiring_at, progress, enableExpiring' } + { categories: '++_id, sub_categ_id, descr_it, campo2bool, campo3bool' }, + { todos: '++_id, userId, category, pos, descr, priority, completed, created_at, modify_at, completed_at, expiring_at, progress, enableExpiring' }, + { sync_todos: '++_id, userId, category, pos, descr, priority, completed, created_at, modify_at, completed_at, expiring_at, progress, enableExpiring' } ], options: { todos: { type: 'list', primary: 'pos', label: 'label', updated_at: 'updated_at' }, + sync_todos: { type: 'list', primary: 'pos', label: 'label', updated_at: 'updated_at' }, } }) } @@ -25,7 +28,7 @@ export default new VueIdb({ version: 1, database: 'test', schemas: [ - { categories: '++id, sub_categ_id, descr_it' } + { categories: '++_id, sub_categ_id, descr_it' } ] }) */ diff --git a/src/root/home/home.ts b/src/root/home/home.ts index df3acf2..9666a70 100644 --- a/src/root/home/home.ts +++ b/src/root/home/home.ts @@ -54,6 +54,7 @@ export default class Home extends Vue { console.log('§§§§§§§§§§§§§§§§§§§§ IMPOSTA DEFERRED PROMPT !!!!!!!!!!!!!!!!! ') return false }) + } test_fetch() { diff --git a/src/store/Api/Inst-Pao.ts b/src/store/Api/Inst-Pao.ts index c155d03..5b7983d 100644 --- a/src/store/Api/Inst-Pao.ts +++ b/src/store/Api/Inst-Pao.ts @@ -5,14 +5,27 @@ async function sendRequest (url: string, lang: string, mytok: string, method: st // let mytok: string = this.getTok() const authHeader = new Headers() + console.log('sendRequest:', url) + authHeader.append('content-type', 'application/json') authHeader.append('x-auth', mytok) authHeader.append('accept-language', lang) - const configInit: RequestInit = { - method: method, - cache: 'no-cache', - body: JSON.stringify(mydata), - headers: authHeader + + let configInit: RequestInit + + if (method === 'GET') { + configInit = { + method: method, + cache: 'no-cache', + headers: authHeader + } + } else { + configInit = { + method: method, + cache: 'no-cache', + body: JSON.stringify(mydata), + headers: authHeader + } } const request: Promise = fetch(url, configInit) diff --git a/src/store/Modules/Todos.ts b/src/store/Modules/Todos.ts index cc4b656..a041576 100644 --- a/src/store/Modules/Todos.ts +++ b/src/store/Modules/Todos.ts @@ -1,12 +1,22 @@ -import { ITodosState } from 'model' +import VueIdb from 'vue-idb' +import { ISigninOptions, ITodo, ITodosState } from 'model' import { storeBuilder } from './Store/Store' +import Api from '@api' +import { serv_constants } from '../Modules/serv_constants' +import { rescodes } from './rescodes' +import { UserStore } from '@store' +import { IResult } from 'model/other' + const state: ITodosState = { - visuOnlyUncompleted: false + visuOnlyUncompleted: false, + networkDataReceived: false, + todos: [] } const b = storeBuilder.module('TodosModule', state) +const stateGetter = b.state() // Getters namespace Getters { @@ -27,8 +37,42 @@ namespace Mutations { // Cancella Item } + async function clearAllData(state: ITodosState) { + // Delete item + + VueIdb.$db.todos + .where('userId').equals(UserStore.state.userId) + .delete() + .then(() => { + console.log('Todo clearAllData !') + + // state + + }).catch((error) => { + console.log('err: ', error) + }) + } + + async function readdbTodoData(state: ITodosState) { + // Delete item + + VueIdb.$db.todos + .where('userId').equals(UserStore.state.userId) + // .and(todo => todo.category === this.getCategory()) + .toArray() + .then(ristodos => { + console.log('readdbTodoData OK !') + state.todos = ristodos + }).catch((error) => { + console.log('err: ', error) + }) + + } + export const mutations = { deleteItem: b.commit(deleteItem), + clearAllData: b.commit(clearAllData), + readdbTodoData: b.commit(readdbTodoData) } } @@ -38,13 +82,95 @@ namespace Actions { Mutations.mutations.deleteItem(num) } + function json2array(json){ + var result = [] + var keys = Object.keys(json); + keys.forEach(function(key){ + result.push(json[key]) + }); + return result; + } + + async function dbLoadTodo(context) { + + console.log('dbLoadTodo') + + const token = localStorage.getItem(rescodes.localStorage.token) + + let call = process.env.MONGODB_HOST + '/todos/' + UserStore.state.userId + + return await Api.SendReq(call, UserStore.state.lang, token, 'GET', null) + .then((res) => { + return res.json() + }).then((resData) => { + // console.log('res.todos:', res.todos) + + state.todos = [] + for(var i in resData.todos) + state.todos.push(resData.todos [i]) + + // state.todos = Object.keys(resData.todos).map((key) => { + // return resData.todos[key] + // }) + + console.log('state.todos', state.todos) + return rescodes.OK + }) + .catch((error) => { + if (process.env.DEV) { + console.log('ERROREEEEEEEEE') + console.log(error) + } + return rescodes.ERR_GENERICO + }) + } + + async function dbSaveTodo(context, itemtodo: ITodo) { + let call = process.env.MONGODB_HOST + '/todos/' + itemtodo._id + + const token = localStorage.getItem(rescodes.localStorage.token) + + let res = await Api.SendReq(call, UserStore.state.lang, token, 'PATCH', itemtodo) + .then(function (res) { + state.networkDataReceived = true + return rescodes.OK + }) + .catch((error) => { + if (process.env.DEV) { + console.log('ERROREEEEEEEEE') + console.log(error) + } + return rescodes.ERR_GENERICO + }) + + + if ('indexedDB' in window) { + await Mutations.mutations.readdbTodoData() + if (!state.networkDataReceived) { + console.log('From cache', state.todos) + } + } + + return res + } + + async function getTodosByCategory(context, category: string) { + let myarr = state.todos.filter((p) => { + return p.category === category + }) + + return myarr + } + export const actions = { - setConta: b.dispatch(deleteItem) + setConta: b.dispatch(deleteItem), + dbSaveTodo: b.dispatch(dbSaveTodo), + dbLoadTodo: b.dispatch(dbLoadTodo), + getTodosByCategory: b.dispatch(getTodosByCategory) } } -const stateGetter = b.state() // Module const TodosModule = { @@ -56,6 +182,4 @@ const TodosModule = { actions: Actions.actions } - -export default ITodosState - +export default TodosModule diff --git a/src/store/Modules/UserStore.ts b/src/store/Modules/UserStore.ts index d728707..78933c6 100644 --- a/src/store/Modules/UserStore.ts +++ b/src/store/Modules/UserStore.ts @@ -6,7 +6,7 @@ import router from '@router' import { serv_constants } from '../Modules/serv_constants' import { rescodes } from '../Modules/rescodes' -import { GlobalStore, UserStore } from '@store' +import { GlobalStore, UserStore, Todos } from '@store' const bcrypt = require('bcryptjs') @@ -156,7 +156,7 @@ namespace Actions { let x_auth_token: string = '' - return Api.SendReq(call, state.lang, Getters.getters.tok, 'POST', usertosend) + return await Api.SendReq(call, state.lang, Getters.getters.tok, 'POST', usertosend) .then((res) => { console.log(res) myres = res @@ -197,7 +197,7 @@ namespace Actions { let myres - return Api.SendReq(call, state.lang, Getters.getters.tok, 'POST', usertosend) + return await Api.SendReq(call, state.lang, Getters.getters.tok, 'POST', usertosend) .then((res) => { console.log(res) myres = res @@ -381,7 +381,7 @@ namespace Actions { let x_auth_token: string = '' - return Api.SendReq(call, state.lang, Getters.getters.tok, 'POST', usertosend) + return await Api.SendReq(call, state.lang, Getters.getters.tok, 'POST', usertosend) .then((res) => { myres = res x_auth_token = String(res.headers.get('x-auth')) @@ -433,6 +433,8 @@ namespace Actions { localStorage.setItem(rescodes.localStorage.isLogged, String(true)) localStorage.setItem(rescodes.localStorage.verifiedEmail, Number(verifiedEmail).toString()) + setGlobal() + // dispatch('storeUser', authData); // dispatch('setLogoutTimer', myres.data.expiresIn); return rescodes.OK @@ -469,7 +471,7 @@ namespace Actions { } console.log(usertosend) - Api.SendReq(call, state.lang, Getters.getters.tok, 'DELETE', usertosend) + return await Api.SendReq(call, state.lang, Getters.getters.tok, 'DELETE', usertosend) .then( (res) => { console.log(res) @@ -495,10 +497,13 @@ namespace Actions { function setGlobal() { GlobalStore.mutations.setleftDrawerOpen(localStorage.getItem(rescodes.localStorage.leftDrawerOpen) === 'true') GlobalStore.mutations.setCategorySel(localStorage.getItem(rescodes.localStorage.categorySel)) + + Todos.actions.dbLoadTodo() } async function autologin (context) { try { + console.log('*** Autologin ***') // INIT UserStore.mutations.setlang(process.env.LANG_DEFAULT) // ++Todo: Estrai la Lang dal Localstorage @@ -521,7 +526,7 @@ namespace Actions { const username = String(localStorage.getItem(rescodes.localStorage.username)) const verifiedEmail = localStorage.getItem(rescodes.localStorage.verifiedEmail) === '1' - setGlobal() + console.log('autologin userId', userId) Mutations.mutations.authUser({ userId: userId, @@ -529,6 +534,11 @@ namespace Actions { idToken: token, verifiedEmail: verifiedEmail }) + + setGlobal() + + console.log('autologin userId STATE ', state.userId) + return true } catch (e) { console.error('ERR autologin ', e.message) diff --git a/src/store/Modules/index.ts b/src/store/Modules/index.ts index 38b5fa1..f84bfb8 100644 --- a/src/store/Modules/index.ts +++ b/src/store/Modules/index.ts @@ -1,3 +1,4 @@ export {storeBuilder} from './Store/Store' export {default as GlobalStore} from './GlobalStore' export {default as UserStore} from './UserStore' +export {default as Todos} from './Todos' From 3c6b2c7bef1cbfc631bd3f30508a0d9eec0112ae Mon Sep 17 00:00:00 2001 From: Paolo Arena Date: Sat, 2 Feb 2019 20:13:06 +0100 Subject: [PATCH 04/18] - Service Worker - Indexdb --- .env.development | 2 +- package-lock.json | 14 + package.json | 1 + quasar.conf.js | 2 +- src-pwa/custom-service-worker.js | 246 ++++++++------ src-pwa/register-service-worker.js | 6 +- src/App.vue | 3 + .../categories/category/category.ts | 2 +- .../categories/tabledata/tabledata.ts | 2 +- .../todos/SingleTodo/SingleTodo.scss | 11 - src/components/todos/SubMenus/SubMenus.scss | 16 + src/components/todos/SubMenus/SubMenus.vue | 6 +- src/components/todos/todo/todo.ts | 171 ++++++---- src/globalroutines/index.js | 6 + src/globalroutines/indexdb.js | 63 ++++ src/index.template.html | 10 + src/js/fetch.js | 2 +- src/js/globalenv.js | 24 ++ src/js/idb.js | 311 ------------------ src/js/immortal-db.min.js | 8 + src/js/storage.js | 112 +++++++ src/js/utility.js | 106 +++--- src/model/Todos.ts | 6 +- src/model/index.ts | 2 +- src/model/payload/index.ts | 4 - src/model/payload/payload-mapper.ts | 80 ----- src/model/payload/payload-message.ts | 6 - src/model/payload/payload.ts | 8 - src/plugins/globalroutines.js | 8 + src/plugins/indexdb.js | 5 - src/plugins/vue-idb.js | 14 - src/statics/i18n.js | 4 +- src/statics/js/immortal-db.min.js | 8 + src/statics/js/storage.js | 91 +++++ src/store/Api/Inst-Pao.ts | 13 +- src/store/Modules/Todos.ts | 116 +++---- src/store/Modules/UserStore.ts | 2 - src/store/Modules/rescodes.ts | 13 +- src/typings/libs/globalroutines.d.ts | 8 + src/validation/registereduser.ts | 2 +- src/views/login/signin/signin.ts | 3 + 41 files changed, 762 insertions(+), 755 deletions(-) create mode 100644 src/globalroutines/index.js create mode 100644 src/globalroutines/indexdb.js create mode 100644 src/js/globalenv.js delete mode 100644 src/js/idb.js create mode 100644 src/js/immortal-db.min.js create mode 100644 src/js/storage.js delete mode 100644 src/model/payload/index.ts delete mode 100644 src/model/payload/payload-mapper.ts delete mode 100644 src/model/payload/payload-message.ts delete mode 100644 src/model/payload/payload.ts create mode 100644 src/plugins/globalroutines.js delete mode 100644 src/plugins/indexdb.js create mode 100644 src/statics/js/immortal-db.min.js create mode 100644 src/statics/js/storage.js create mode 100644 src/typings/libs/globalroutines.d.ts diff --git a/.env.development b/.env.development index 2c23d66..37baa9d 100644 --- a/.env.development +++ b/.env.development @@ -1,4 +1,4 @@ -SERVICE_WORKER_FILE='service-worker.js' +SERVICE_WORKER_FILE='service-worker.js${Math.random()}' APP_ID='1' VUE_APP_URL='prova SVILUPPO!' PROVA_PAOLO='PROVA SVILUPPO' diff --git a/package-lock.json b/package-lock.json index 0c848f1..2b2bcf6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11193,6 +11193,11 @@ } } }, + "idb-keyval": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-3.1.0.tgz", + "integrity": "sha512-iFwFN5n00KNNnVxlOOK280SJJfXWY7pbMUOQXdIXehvvc/mGCV/6T2Ae+Pk2KwAkkATDTwfMavOiDH5lrJKWXQ==" + }, "ieee754": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.12.tgz", @@ -11216,6 +11221,15 @@ "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=" }, + "immortal-db": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/immortal-db/-/immortal-db-1.0.2.tgz", + "integrity": "sha512-7EaVr6vUaaqsl9Jnp+CY4FzA1jIQD+o1tFEY2+O4ibYgmVB+FEWDoyUNN/naq9ZfiYKw4+uly1fpxk0xyE358w==", + "requires": { + "idb-keyval": "3.1.0", + "js-cookie": "2.2.0" + } + }, "import-cwd": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz", diff --git a/package.json b/package.json index 8c23234..32143ff 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,7 @@ "graphql": "^0.13.2", "graphql-tag": "^2.8.0", "gsap": "^2.0.2", + "immortal-db": "^1.0.2", "jquery": "^3.3.1", "js-cookie": "^2.2.0", "localforage": "^1.7.3", diff --git a/quasar.conf.js b/quasar.conf.js index 6a82163..b19d814 100644 --- a/quasar.conf.js +++ b/quasar.conf.js @@ -59,7 +59,7 @@ module.exports = function (ctx) { store: 'src/store/index.ts' }, // app plugins (/src/plugins) - plugins: ['i18n', 'axios', 'vee-validate', 'myconfig', 'local-storage', 'error-handler', 'indexdb', 'vue-idb'], + plugins: ['i18n', 'axios', 'vee-validate', 'myconfig', 'local-storage', 'error-handler', 'globalroutines', 'vue-idb'], css: [ 'app.styl' ], diff --git a/src-pwa/custom-service-worker.js b/src-pwa/custom-service-worker.js index c3a2d27..2f73450 100644 --- a/src-pwa/custom-service-worker.js +++ b/src-pwa/custom-service-worker.js @@ -9,13 +9,50 @@ console.log('05 ___________________________ PAO: this is my custom service worker'); importScripts('https://storage.googleapis.com/workbox-cdn/releases/3.0.0/workbox-sw.js'); //++Todo: Replace with local workbox.js -importScripts('js/idb.js'); -importScripts('js/utility.js'); +importScripts('../statics/js/idb.js'); +importScripts('js/globalenv.js'); +// importScripts('js/utility.js'); +importScripts('../statics/js/storage.js'); + +const cfgenv = { + website: 'http://localhost:8080', + serverweb: 'http://localhost:3000', + dbname: 'mydb3', + dbversion: 11, +} + +async function writeData(table, data) { + console.log('writeData', table, data); + await idbKeyval.setdata(table, data); +} + +async function readAllData(table) { + console.log('readAllData', table); + return await idbKeyval.getalldata(table); +} + +async function clearAllData(table) { + console.log('clearAllData', table); + await idbKeyval.clearalldata(table) +} + +async function deleteItemFromData(table, id) { + console.log('deleteItemFromData', table, 'ID:', id); + + await idbKeyval.deletedata(table, id) +} + + + +// self.addEventListener('activate', function(event) { +// event.waitUntil( +// // createDB() +// ); +// }); if (!workbox) { let workbox = new self.WorkboxSW(); - } if (workbox) { @@ -38,7 +75,7 @@ if (workbox) { // workbox.routing.registerRoute(/^http/, workbox.strategies.networkFirst(), 'GET'); workbox.routing.registerRoute( - /\.(?:png|gif|jpg|jpeg|svg)$/, + new RegExp(/\.(?:png|gif|jpg|jpeg|svg)$/), workbox.strategies.staleWhileRevalidate({ cacheName: 'images', plugins: [ @@ -62,22 +99,28 @@ if (workbox) { }) ); - workbox.routing.registerRoute('http://localhost:3000/todos', function (args) { - return fetch(args.event.request) - .then(function (res) { - var clonedRes = res.clone(); - clearAllData('todos') - .then(function () { - return clonedRes.json(); - }) - .then(function (data) { - for (let key in data) { - writeData('todos', data[key]) - } - }); - return res; - }); - }); + + workbox.routing.registerRoute( + new RegExp(cfgenv.serverweb + '/todos/'), + function (args) { + return fetch(args.event.request, args.event.headers) + .then(function (res) { + console.log('******* registerRoute fetch: (1) ', args.event) + var clonedRes = res.clone(); + clearAllData('todos') + .then(function () { + return clonedRes.json(); + }) + .then(function (data) { + console.log('2) data Received ', data.todos) + for (let key in data.todos) { + writeData('todos', data.todos[key]) + } + }); + return res + }) + } + ); workbox.routing.registerRoute( @@ -158,28 +201,6 @@ if (workbox) { }) ); - // workbox.core.setLogLevel(workbox.core.LOG_LEVELS.debug); - - workbox.routing.registerRoute( - new RegExp('http://localhost:8080/todos'), - function (args) { - return fetch(args.event.request) - .then(function (res) { - console.log('******* fetch: ', args.event) - var clonedRes = res.clone(); - clearAllData('todos') - .then(function () { - return clonedRes.json(); - }) - .then(function (data) { - for (let key in data) { - writeData('todos', data[key]) - } - }); - return res - }) - } - ); } @@ -189,68 +210,107 @@ if ('serviceWorker' in navigator) { } - // self.addEventListener('fetch', function (event) { - // console.log('[Service Worker] Fetching something ....', event); - // console.log('event.request.cache=', event.request.cache) - // if (event.request.cache === 'only-if-cached' && event.request.mode !== 'same-origin') { - // console.log('SAME ORIGIN!', event); - // return; - // } - // event.respondWith(caches.match(event.request)); - // }); +// self.addEventListener('fetch', function (event) { +// console.log('[Service Worker] Fetching something ....', event); +// console.log('event.request.cache=', event.request.cache) +// if (event.request.cache === 'only-if-cached' && event.request.mode !== 'same-origin') { +// console.log('SAME ORIGIN!', event); +// return; +// } +// event.respondWith(caches.match(event.request)); +// }); - self.addEventListener('sync', function (event) { - console.log('[Service Worker] Background syncing', event); +// const syncStore = {} +// self.addEventListener('message', event => { +// if (event.data.type === 'sync') { +// // get a unique id to save the data +// const id = uuid() +// syncStore[id] = event.data +// // register a sync and pass the id as tag for it to get the data +// self.registration.sync.register(id) +// } +// console.log(event.data) +// }) - if (event.tag === 'sync-new-todos') { - console.log('[Service Worker] Syncing new Todos'); +self.addEventListener('sync', function (event) { + console.log('[Service Worker V5] Background syncing', event); - let authHeader = [] - authHeader['content-type'] = 'application/json'; - authHeader['accept-language'] = 'en'; - // authHeader.append('x-auth', mytok) + let multiparams = event.tag.split('|') + if (multiparams && multiparams.length > 3) { + let cmd = multiparams[0] + let table = multiparams[1] + let method = multiparams[2] + let token = multiparams[3] + // let lang = multiparams[3] + + if ((cmd === 'sync-new-todos') || (cmd === 'sync-delete-todos')) { + console.log('[Service Worker] Syncing', cmd, table, method); + + const headers = new Headers() + headers.append('content-Type', 'application/json') + headers.append('Accept', 'application/json') + headers.append('x-auth', token) event.waitUntil( - readAllData('sync_todos') - .then(function (data) { - for (var dt of data) { - // var postData = new FormData(); - // postData.append('_id', dt._id); - // postData.append('title', dt.title); - // postData.append('location', dt.location); - // postData.append('rawLocationLat', dt.rawLocation.lat); - // postData.append('rawLocationLng', dt.rawLocation.lng); - // postData.append('file', dt.picture, dt._id + '.png'); + readAllData(table) + .then(function (alldata) { + console.log('data: ', alldata) + if (alldata) { + for (var rec of alldata) { + let link = cfgenv.serverweb + '/todos/' + rec._id + console.log('FETCH: ', method, link, 'data:', JSON.stringify(rec)) - console.log('Data to Send 6: ', JSON.stringify(dt)) - - // Update myTodo to the server - fetch('http://localhost:3000/todos', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'Accept': 'application/json' - }, - // mode: 'no-cors', - mode: 'cors', - body: JSON.stringify(dt) - }) - .then(function (resData) { - console.log('Sent data Todo:', resData); - if (resData.ok) { - deleteItemFromData('sync_todos', dt.id); - } + // Insert/Delete/Update table to the server + fetch(link, { + method: method, + headers: headers, + mode: 'cors', // 'no-cors', + body: JSON.stringify(rec) }) - .catch(function (err) { - console.log('Error while sending data', err); - }); + .then(function (resData) { + console.log('Result data Todo:', resData); + if (resData.ok) { + deleteItemFromData(table, rec._id); + } + }) + .catch(function (err) { + console.log('Error while sending data', err); + }); + } } - }) ); } - }); + } +}) +; -// } +/* + +// send message to serviceWorker +function sync (url, options) { + navigator.serviceWorker.controller.postMessage({type: 'sync', url, options}) +} + + +const syncStore = {} +self.addEventListener('message', event => { + if(event.data.type === 'sync') { + // get a unique id to save the data + const id = uuid() + syncStore[id] = event.data + // register a sync and pass the id as tag for it to get the data + self.registration.sync.register(id) + } + console.log(event.data) +}) + + +self.addEventListener('sync', event => { + // get the data by tag + const {url, options} = syncStore[event.tag] + event.waitUntil(fetch(url, options)) +}) +*/ diff --git a/src-pwa/register-service-worker.js b/src-pwa/register-service-worker.js index 5205056..b331a7e 100644 --- a/src-pwa/register-service-worker.js +++ b/src-pwa/register-service-worker.js @@ -14,13 +14,13 @@ register(process.env.SERVICE_WORKER_FILE, { console.log('REGISTERED::: !!!', process.env.SERVICE_WORKER_FILE) }, - cached(registration) { // registration -> a ServiceWorkerRegistration instance + cached(registration) { console.log('CACHED::: Content has been cached for offline use.') }, - updatefound(registration) { // registration -> a ServiceWorkerRegistration instance + updatefound(registration) { console.log('UPDATEFOUND::: New content is downloading.') }, - updated(registration) { // registration -> a ServiceWorkerRegistration instance + updated(registration) { console.log('New content is available; please refresh.') }, offline() { diff --git a/src/App.vue b/src/App.vue index 072e1c5..fd1fe53 100644 --- a/src/App.vue +++ b/src/App.vue @@ -26,6 +26,8 @@ import Header from './components/Header.vue' + import globalroutines from './globalroutines/index' + @Component({ components: { appHeader: Header, @@ -49,6 +51,7 @@ UserStore.actions.autologin() .then((loginEseguito) => { if (loginEseguito) { + globalroutines(this, 'loadapp', '') // this.$router.replace('/') } }) diff --git a/src/components/categories/category/category.ts b/src/components/categories/category/category.ts index 0cbfb38..eec08f6 100644 --- a/src/components/categories/category/category.ts +++ b/src/components/categories/category/category.ts @@ -80,7 +80,7 @@ export default class Category extends Vue { } async loadCat() { - await this.$db.categories.toArray().then(ris => this.categories_loc = ris) + // await this.$db.categories.toArray().then(ris => this.categories_loc = ris) this.updatetable() } diff --git a/src/components/categories/tabledata/tabledata.ts b/src/components/categories/tabledata/tabledata.ts index 7bb46c1..b27f197 100644 --- a/src/components/categories/tabledata/tabledata.ts +++ b/src/components/categories/tabledata/tabledata.ts @@ -100,7 +100,7 @@ export default class Tabledata extends Vue { objcat.descr_it = this.category // Add to Indexdb - await this.$db.categories.add(objcat + await this.$db.categories.put(objcat ).then(ris => { myid = ris }) diff --git a/src/components/todos/SingleTodo/SingleTodo.scss b/src/components/todos/SingleTodo/SingleTodo.scss index b8247e6..9ea75a7 100644 --- a/src/components/todos/SingleTodo/SingleTodo.scss +++ b/src/components/todos/SingleTodo/SingleTodo.scss @@ -57,15 +57,7 @@ $heightitem: 19px; font-size: 0.75rem; } -.todo-menu { - min-width: 202px; -} - -.item-menu{ - font-size: 1rem; - -} .titleLista-item { max-width: 92px; @@ -144,9 +136,6 @@ $heightitem: 19px; color: #888; } -.menuProgress { - -} .colProgress { } diff --git a/src/components/todos/SubMenus/SubMenus.scss b/src/components/todos/SubMenus/SubMenus.scss index e69de29..6cbbff6 100644 --- a/src/components/todos/SubMenus/SubMenus.scss +++ b/src/components/todos/SubMenus/SubMenus.scss @@ -0,0 +1,16 @@ +.todo-menu { + min-width: 202px; + +} + +.item-menu{ + font-size: 1rem; +} + +.item-menu:hover { + cursor: pointer; +} + +.menuProgress { + +} diff --git a/src/components/todos/SubMenus/SubMenus.vue b/src/components/todos/SubMenus/SubMenus.vue index f6fda08..73c166d 100644 --- a/src/components/todos/SubMenus/SubMenus.vue +++ b/src/components/todos/SubMenus/SubMenus.vue @@ -30,7 +30,7 @@ - {{field.label}} + {{field.label}} @@ -60,3 +60,7 @@ + + diff --git a/src/components/todos/todo/todo.ts b/src/components/todos/todo/todo.ts index 0de8502..7ddae5a 100644 --- a/src/components/todos/todo/todo.ts +++ b/src/components/todos/todo/todo.ts @@ -13,6 +13,10 @@ import _ from 'lodash' import draggable from 'vuedraggable' +import VueIdb from 'vue-idb' + +import globalroutines from '../../../globalroutines/index' + import $ from 'jquery' @Component({ @@ -93,8 +97,8 @@ export default class Todo extends Vue { // console.log('updateLinkedList', this.todos_arr) - let idprev = -1 - let idnext = -1 + let idprev = '' + let idnext = '' let pos = 1 if (arr.length > 0) { idprev = arr[0].id_prev @@ -221,6 +225,7 @@ export default class Todo extends Vue { let update = false await this.todos_arr.forEach((elem: ITodo) => { if (elem.modified) { + console.log('calling MODIFY 3') this.modify(elem, false) update = true } @@ -275,6 +280,7 @@ export default class Todo extends Vue { console.log('User:' + UserStore.state.userId) const objtodo: ITodo = { + _id: new Date().toISOString(), // Create NEW userId: UserStore.state.userId, descr: '', priority: rescodes.Todos.PRIORITY_NORMAL, @@ -285,8 +291,8 @@ export default class Todo extends Vue { category: '', expiring_at: mydateexp, enableExpiring: false, - id_prev: 0, - id_next: 0, + id_prev: '', + id_next: '', pos: 0, modified: true, progress: 0 @@ -304,7 +310,7 @@ export default class Todo extends Vue { return '' } - insertTodo() { + async insertTodo() { if (this.todo.trim() === '') return @@ -314,7 +320,7 @@ export default class Todo extends Vue { objtodo.descr = this.todo objtodo.category = this.getCategory() - const lastelem = this.getLastList() + const lastelem: ITodo = this.getLastList() objtodo.id_prev = (lastelem !== null) ? lastelem._id : rescodes.LIST_START objtodo.id_next = rescodes.LIST_END objtodo.pos = (lastelem !== null) ? lastelem.pos + 1 : 1 @@ -325,24 +331,31 @@ export default class Todo extends Vue { return } - this.$db.todos.add(objtodo) // Add to Indexdb + await globalroutines(this, 'write', 'todos', objtodo) .then((id) => { - console.log('*** IDNEW = ', id) + console.log('*** IDNEW (2) = ', id) // update also the last elem if (lastelem !== null) { lastelem.id_next = id lastelem.modified = true + console.log('calling MODIFY 4', lastelem) this.modify(lastelem, false) + .then(ris => { + console.log('END calling MODIFY 4') + + this.saveItemToSyncAndDb(rescodes.DB.TABLE_SYNC_TODOS, 'POST', objtodo) + this.updatetable(false) + + }) + } else { + this.saveItemToSyncAndDb(rescodes.DB.TABLE_SYNC_TODOS, 'POST', objtodo) + this.updatetable(false) } - this.saveItemToSyncAndDb(objtodo) - - // this.modify(objtodo, true) - this.updatetable(false) }).catch(err => { - console.log('Errore: ' + err.message) - }) + console.log('Errore: ' + err.message) + }) console.log('ESCO.........') @@ -350,40 +363,69 @@ export default class Todo extends Vue { this.todo = '' } - saveItemToSyncAndDb(item: ITodo) { + cmdToSyncAndDb(cmd, table, method, itemOrId, msg: String) { // Send to Server to Sync + + console.log('cmdToSyncAndDb', cmd, table, method, itemOrId, msg) + const mythis = this - console.log('saveItemToSyncAndDb') if ('serviceWorker' in navigator && 'SyncManager' in window) { navigator.serviceWorker.ready .then(function (sw) { // _id: new Date().toISOString(), console.log('---------------------- navigator.serviceWorker.ready') - // check if exist _id, delete it - mythis.$db.sync_todos - .where('id').equals(item._id) - .delete() + // mythis.sendMessageToSW(item, method) - mythis.$db.sync_todos.add(item) - .then(function () { - return sw.sync.register('sync-new-todos') + globalroutines(mythis, 'write', table, itemOrId) + .then(function (id) { + console.log('id', id) + const sep = '|' + + let multiparams = cmd + sep + table + sep + method + sep + UserStore.state.idToken + sep + UserStore.state.lang + return sw.sync.register(multiparams) }) .then(function () { let snackbarContainer = document.querySelector('#confirmation-toast') - let data = { message: 'Your Post was saved for syncing!' } + let data = { message: msg } // snackbarContainer.MaterialSnackbar.showSnackbar(data) }) .catch(function (err) { - console.log(err) + console.error('Errore in globalroutines', table, err) }) }) } else { - Todos.actions.dbSaveTodo(item) + if (cmd === rescodes.DB.CMD_SYNC_TODOS) + Todos.actions.dbSaveTodo(itemOrId) + else if (cmd === rescodes.DB.CMD_DELETE_TODOS) + Todos.actions.dbDeleteTodo(itemOrId) } - } + saveItemToSyncAndDb(table: String, method, item: ITodo) { + return this.cmdToSyncAndDb(rescodes.DB.CMD_SYNC_TODOS, table, method, item, 'Your Post was saved for syncing!') + } + + + deleteItemToSyncAndDb(table: String, id: String) { + return this.cmdToSyncAndDb(rescodes.DB.CMD_DELETE_TODOS, table, 'DELETE', id, 'Your Post was canceled for syncing!') + } + +/* + sendMessageToSW(recdata, method) { + + navigator.serviceWorker.controller.postMessage({ + type: 'sync', + recdata, + method, + cmd: 'sync-new-todos', + token: UserStore.state.idToken, + lang: UserStore.state.lang + }) + } +*/ + + getElemById(id, lista = this.todos_arr) { let myobj: ITodo for (myobj of lista) { @@ -407,27 +449,28 @@ export default class Todo extends Vue { if (myobjprev !== null) { myobjprev.id_next = myobjtrov.id_next myobjprev.modified = true + console.log('calling MODIFY 2') this.modify(myobjprev, false) } if (myobjnext !== null) { myobjnext.id_prev = myobjtrov.id_prev myobjnext.modified = true + console.log('calling MODIFY 1') this.modify(myobjnext, false) } - console.log('ENTRATO') + this.deleteItemToSyncAndDb(rescodes.DB.TABLE_DELETE_TODOS, id) + const mythis = this // Delete item - await this.$db.todos - .where('id').equals(id) - .delete() - .then(() => { - console.log('UpdateTable') + await globalroutines(this, 'delete', 'todos', id) + .then((ris) => { + console.log('UpdateTable', ris) mythis.updatetable() }).catch((error) => { - console.log('err: ', error) - }) + console.log('err: ', error) + }) } console.log('FINE deleteitem') @@ -498,7 +541,7 @@ export default class Todo extends Vue { } async filtertodos(refresh: boolean = false) { - // console.log('filtertodos') + console.log('filtertodos') return await Todos.actions.getTodosByCategory(this.getCategory()) .then(arrtemp => { @@ -583,45 +626,51 @@ export default class Todo extends Vue { if (recOut[field] !== recIn[field]) { recOut.modified = true recOut[field] = recIn[field] - return true + return recOut[field] } return false } async modify(myobj: ITodo, update: boolean) { - await this.$db.transaction('rw', [this.$db.todos], async () => { - const miorec = await this.$db.todos.get(myobj._id) + await globalroutines(this, 'read', 'todos', myobj._id) + .then(miorec => { + console.log('ArrTodos: ', myobj.descr, '[', myobj._id, ']') - this.modifyField(miorec, myobj, 'descr') - if (this.modifyField(miorec, myobj, 'completed')) - miorec.completed_at = new Date() + if (miorec === undefined) { + console.log('Record not Found !!!!!! id=', myobj._id) + return + } - this.modifyField(miorec, myobj, 'category') - this.modifyField(miorec, myobj, 'expiring_at') - this.modifyField(miorec, myobj, 'priority') - this.modifyField(miorec, myobj, 'id_prev') - this.modifyField(miorec, myobj, 'id_next') - this.modifyField(miorec, myobj, 'pos') - this.modifyField(miorec, myobj, 'enableExpiring') - this.modifyField(miorec, myobj, 'progress') + this.modifyField(miorec, myobj, 'descr') + if (this.modifyField(miorec, myobj, 'completed')) + miorec.completed_at = new Date() + + this.modifyField(miorec, myobj, 'category') + this.modifyField(miorec, myobj, 'expiring_at') + this.modifyField(miorec, myobj, 'priority') + this.modifyField(miorec, myobj, 'id_prev') + this.modifyField(miorec, myobj, 'id_next') + this.modifyField(miorec, myobj, 'pos') + this.modifyField(miorec, myobj, 'enableExpiring') + this.modifyField(miorec, myobj, 'progress') - if (miorec.modified) { - miorec.modify_at = new Date() + if (miorec.modified) { + miorec.modify_at = new Date() - // this.logelem('modify', miorec) + // this.logelem('modify', miorec) - await this.$db.todos.put(miorec) + globalroutines(this, 'write', 'todos', miorec) + .then(ris => { - this.saveItemToSyncAndDb(miorec) - - if (update) - await this.updatetable(false) - } - }) + this.saveItemToSyncAndDb(rescodes.DB.TABLE_SYNC_TODOS, 'PATCH', miorec) + if (update) + this.updatetable(false) + }) + } + }) } - } diff --git a/src/globalroutines/index.js b/src/globalroutines/index.js new file mode 100644 index 0000000..41568e9 --- /dev/null +++ b/src/globalroutines/index.js @@ -0,0 +1,6 @@ +import indexdb from './indexdb' + +export default async (context, cmd, table, data = null) => { + console.log('globalroutines', cmd, table, data) + return await indexdb(context, cmd, table, data) +} diff --git a/src/globalroutines/indexdb.js b/src/globalroutines/indexdb.js new file mode 100644 index 0000000..cbda898 --- /dev/null +++ b/src/globalroutines/indexdb.js @@ -0,0 +1,63 @@ +import store from '../store' +import _ from 'lodash' +import { UserStore } from '@modules' +import { i18n } from '../plugins/i18n' + +import {idbKeyval as storage} from '../js/storage.js'; + +function saveConfigIndexDb(context) { + + let data = [] + data['_id'] = 1 + data['lang'] = UserStore.state.lang + data['token'] = UserStore.state.idToken + data['userId'] = UserStore.state.userId + + writeConfigIndexDb('config', data) +} + +function writeConfigIndexDb(context, data) { + console.log('writeConfigIndexDb', data) + + storage.setdata('config', data) + .then(ris => { + return true + }) + +} + +async function readfromIndexDbToStateTodos(context) { + console.log('*** read from IndexDb to state.todos') + + return await storage.getalldata('todos') + .then(ristodos => { + console.log('&&&&&&& readfromIndexDbToStateTodos OK: Num RECORD: ', ristodos.length) + UserStore.state.todos = ristodos + }).catch((error) => { + console.log('err: ', error) + }) + +} + +export default async (context, cmd, table, datakey) => { + if (cmd === 'loadapp') { + // ****** LOAD APP AL CARICAMENTO ! ******* + return saveConfigIndexDb(context, datakey) + + + if ('indexedDB' in window) { + if (!UserStore.state.networkDataReceived) { + return await readfromIndexDbToStateTodos(context) + } + } + + } else if (cmd === 'write') { + return await storage.setdata(table, datakey) + } else if (cmd === 'readall') { + return await storage.getalldata(table) + } else if (cmd === 'read') { + return await storage.getdata(table, datakey) + } else if (cmd === 'delete') { + return await storage.deletedata(table, datakey) + } +} diff --git a/src/index.template.html b/src/index.template.html index cb87612..aa2c291 100644 --- a/src/index.template.html +++ b/src/index.template.html @@ -17,6 +17,16 @@ + + diff --git a/src/js/fetch.js b/src/js/fetch.js index 6bac6b3..30ea634 100644 --- a/src/js/fetch.js +++ b/src/js/fetch.js @@ -295,7 +295,7 @@ } // HTTP methods whose capitalization should be normalized - var methods = ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT'] + var methods = ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT', 'PATCH'] function normalizeMethod(method) { var upcased = method.toUpperCase() diff --git a/src/js/globalenv.js b/src/js/globalenv.js new file mode 100644 index 0000000..745dd1a --- /dev/null +++ b/src/js/globalenv.js @@ -0,0 +1,24 @@ + +// importScripts('/statics/js/immortal-db.min.js'); + +// const cfgenv = { +// website: 'http://localhost:8080', +// serverweb: 'http://localhost:3000', +// dbname: 'mydb3', +// dbversion: 10, +// } + +/* +async function clearAllDataImmortal(table) { + console.log('clearAllDataImmortal', table) + const db = ImmortalDB.ImmortalDB + await db.remove(table) +} + +async function writeDataImmortal(table, datavalue) { + console.log('writeDataImmortal', table, datavalue) + const db = ImmortalDB.ImmortalDB + await db.set(table, datavalue) +} + +*/ diff --git a/src/js/idb.js b/src/js/idb.js deleted file mode 100644 index 9835513..0000000 --- a/src/js/idb.js +++ /dev/null @@ -1,311 +0,0 @@ -'use strict'; - -(function() { - function toArray(arr) { - return Array.prototype.slice.call(arr); - } - - function promisifyRequest(request) { - return new Promise(function(resolve, reject) { - request.onsuccess = function() { - resolve(request.result); - }; - - request.onerror = function() { - reject(request.error); - }; - }); - } - - function promisifyRequestCall(obj, method, args) { - var request; - var p = new Promise(function(resolve, reject) { - request = obj[method].apply(obj, args); - promisifyRequest(request).then(resolve, reject); - }); - - p.request = request; - return p; - } - - function promisifyCursorRequestCall(obj, method, args) { - var p = promisifyRequestCall(obj, method, args); - return p.then(function(value) { - if (!value) return; - return new Cursor(value, p.request); - }); - } - - function proxyProperties(ProxyClass, targetProp, properties) { - properties.forEach(function(prop) { - Object.defineProperty(ProxyClass.prototype, prop, { - get: function() { - return this[targetProp][prop]; - }, - set: function(val) { - this[targetProp][prop] = val; - } - }); - }); - } - - function proxyRequestMethods(ProxyClass, targetProp, Constructor, properties) { - properties.forEach(function(prop) { - if (!(prop in Constructor.prototype)) return; - ProxyClass.prototype[prop] = function() { - return promisifyRequestCall(this[targetProp], prop, arguments); - }; - }); - } - - function proxyMethods(ProxyClass, targetProp, Constructor, properties) { - properties.forEach(function(prop) { - if (!(prop in Constructor.prototype)) return; - ProxyClass.prototype[prop] = function() { - return this[targetProp][prop].apply(this[targetProp], arguments); - }; - }); - } - - function proxyCursorRequestMethods(ProxyClass, targetProp, Constructor, properties) { - properties.forEach(function(prop) { - if (!(prop in Constructor.prototype)) return; - ProxyClass.prototype[prop] = function() { - return promisifyCursorRequestCall(this[targetProp], prop, arguments); - }; - }); - } - - function Index(index) { - this._index = index; - } - - proxyProperties(Index, '_index', [ - 'name', - 'keyPath', - 'multiEntry', - 'unique' - ]); - - proxyRequestMethods(Index, '_index', IDBIndex, [ - 'get', - 'getKey', - 'getAll', - 'getAllKeys', - 'count' - ]); - - proxyCursorRequestMethods(Index, '_index', IDBIndex, [ - 'openCursor', - 'openKeyCursor' - ]); - - function Cursor(cursor, request) { - this._cursor = cursor; - this._request = request; - } - - proxyProperties(Cursor, '_cursor', [ - 'direction', - 'key', - 'primaryKey', - 'value' - ]); - - proxyRequestMethods(Cursor, '_cursor', IDBCursor, [ - 'update', - 'delete' - ]); - - // proxy 'next' methods - ['advance', 'continue', 'continuePrimaryKey'].forEach(function(methodName) { - if (!(methodName in IDBCursor.prototype)) return; - Cursor.prototype[methodName] = function() { - var cursor = this; - var args = arguments; - return Promise.resolve().then(function() { - cursor._cursor[methodName].apply(cursor._cursor, args); - return promisifyRequest(cursor._request).then(function(value) { - if (!value) return; - return new Cursor(value, cursor._request); - }); - }); - }; - }); - - function ObjectStore(store) { - this._store = store; - } - - ObjectStore.prototype.createIndex = function() { - return new Index(this._store.createIndex.apply(this._store, arguments)); - }; - - ObjectStore.prototype.index = function() { - return new Index(this._store.index.apply(this._store, arguments)); - }; - - proxyProperties(ObjectStore, '_store', [ - 'name', - 'keyPath', - 'indexNames', - 'autoIncrement' - ]); - - proxyRequestMethods(ObjectStore, '_store', IDBObjectStore, [ - 'put', - 'add', - 'delete', - 'clear', - 'get', - 'getAll', - 'getKey', - 'getAllKeys', - 'count' - ]); - - proxyCursorRequestMethods(ObjectStore, '_store', IDBObjectStore, [ - 'openCursor', - 'openKeyCursor' - ]); - - proxyMethods(ObjectStore, '_store', IDBObjectStore, [ - 'deleteIndex' - ]); - - function Transaction(idbTransaction) { - this._tx = idbTransaction; - this.complete = new Promise(function(resolve, reject) { - idbTransaction.oncomplete = function() { - resolve(); - }; - idbTransaction.onerror = function() { - reject(idbTransaction.error); - }; - idbTransaction.onabort = function() { - reject(idbTransaction.error); - }; - }); - } - - Transaction.prototype.objectStore = function() { - return new ObjectStore(this._tx.objectStore.apply(this._tx, arguments)); - }; - - proxyProperties(Transaction, '_tx', [ - 'objectStoreNames', - 'mode' - ]); - - proxyMethods(Transaction, '_tx', IDBTransaction, [ - 'abort' - ]); - - function UpgradeDB(db, oldVersion, transaction) { - this._db = db; - this.oldVersion = oldVersion; - this.transaction = new Transaction(transaction); - } - - UpgradeDB.prototype.createObjectStore = function() { - return new ObjectStore(this._db.createObjectStore.apply(this._db, arguments)); - }; - - proxyProperties(UpgradeDB, '_db', [ - 'name', - 'version', - 'objectStoreNames' - ]); - - proxyMethods(UpgradeDB, '_db', IDBDatabase, [ - 'deleteObjectStore', - 'close' - ]); - - function DB(db) { - this._db = db; - } - - DB.prototype.transaction = function() { - return new Transaction(this._db.transaction.apply(this._db, arguments)); - }; - - proxyProperties(DB, '_db', [ - 'name', - 'version', - 'objectStoreNames' - ]); - - proxyMethods(DB, '_db', IDBDatabase, [ - 'close' - ]); - - // Add cursor iterators - // TODO: remove this once browsers do the right thing with promises - ['openCursor', 'openKeyCursor'].forEach(function(funcName) { - [ObjectStore, Index].forEach(function(Constructor) { - Constructor.prototype[funcName.replace('open', 'iterate')] = function() { - var args = toArray(arguments); - var callback = args[args.length - 1]; - var nativeObject = this._store || this._index; - var request = nativeObject[funcName].apply(nativeObject, args.slice(0, -1)); - request.onsuccess = function() { - callback(request.result); - }; - }; - }); - }); - - // polyfill getAll - [Index, ObjectStore].forEach(function(Constructor) { - if (Constructor.prototype.getAll) return; - Constructor.prototype.getAll = function(query, count) { - var instance = this; - var items = []; - - return new Promise(function(resolve) { - instance.iterateCursor(query, function(cursor) { - if (!cursor) { - resolve(items); - return; - } - items.push(cursor.value); - - if (count !== undefined && items.length == count) { - resolve(items); - return; - } - cursor.continue(); - }); - }); - }; - }); - - var exp = { - open: function(name, version, upgradeCallback) { - var p = promisifyRequestCall(indexedDB, 'open', [name, version]); - var request = p.request; - - request.onupgradeneeded = function(event) { - if (upgradeCallback) { - upgradeCallback(new UpgradeDB(request.result, event.oldVersion, request.transaction)); - } - }; - - return p.then(function(db) { - return new DB(db); - }); - }, - delete: function(name) { - return promisifyRequestCall(indexedDB, 'deleteDatabase', [name]); - } - }; - - if (typeof module !== 'undefined') { - module.exports = exp; - module.exports.default = module.exports; - } - else { - self.idb = exp; - } -}()); diff --git a/src/js/immortal-db.min.js b/src/js/immortal-db.min.js new file mode 100644 index 0000000..7735d36 --- /dev/null +++ b/src/js/immortal-db.min.js @@ -0,0 +1,8 @@ +var ImmortalDB=function(t){var r={};function n(e){if(r[e])return r[e].exports;var o=r[e]={i:e,l:!1,exports:{}};return t[e].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=t,n.c=r,n.d=function(t,r,e){n.o(t,r)||Object.defineProperty(t,r,{enumerable:!0,get:e})},n.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},n.t=function(t,r){if(1&r&&(t=n(t)),8&r)return t;if(4&r&&"object"==typeof t&&t&&t.__esModule)return t;var e=Object.create(null);if(n.r(e),Object.defineProperty(e,"default",{enumerable:!0,value:t}),2&r&&"string"!=typeof t)for(var o in t)n.d(e,o,function(r){return t[r]}.bind(null,o));return e},n.n=function(t){var r=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(r,"a",r),r},n.o=function(t,r){return Object.prototype.hasOwnProperty.call(t,r)},n.p="",n(n.s=68)}([function(t,r,n){var e=n(39)("wks"),o=n(19),i=n(1).Symbol,u="function"==typeof i;(t.exports=function(t){return e[t]||(e[t]=u&&i[t]||(u?i:o)("Symbol."+t))}).store=e},function(t,r){var n=t.exports="undefined"!=typeof window&&window.Math==Math?window:"undefined"!=typeof self&&self.Math==Math?self:Function("return this")();"number"==typeof __g&&(__g=n)},function(t,r){t.exports=function(t){return"object"==typeof t?null!==t:"function"==typeof t}},function(t,r,n){var e=n(1),o=n(13),i=n(10),u=n(12),c=n(7),a=function(t,r,n){var s,f,l,p,h=t&a.F,v=t&a.G,y=t&a.S,d=t&a.P,m=t&a.B,g=v?e:y?e[r]||(e[r]={}):(e[r]||{}).prototype,w=v?o:o[r]||(o[r]={}),x=w.prototype||(w.prototype={});for(s in v&&(n=r),n)l=((f=!h&&g&&void 0!==g[s])?g:n)[s],p=m&&f?c(l,e):d&&"function"==typeof l?c(Function.call,l):l,g&&u(g,s,l,t&a.U),w[s]!=l&&i(w,s,p),d&&x[s]!=l&&(x[s]=l)};e.core=o,a.F=1,a.G=2,a.S=4,a.P=8,a.B=16,a.W=32,a.U=64,a.R=128,t.exports=a},function(t,r,n){var e=n(6),o=n(67),i=n(43),u=Object.defineProperty;r.f=n(5)?Object.defineProperty:function(t,r,n){if(e(t),r=i(r,!0),e(n),o)try{return u(t,r,n)}catch(t){}if("get"in n||"set"in n)throw TypeError("Accessors not supported!");return"value"in n&&(t[r]=n.value),t}},function(t,r,n){t.exports=!n(9)(function(){return 7!=Object.defineProperty({},"a",{get:function(){return 7}}).a})},function(t,r,n){var e=n(2);t.exports=function(t){if(!e(t))throw TypeError(t+" is not an object!");return t}},function(t,r,n){var e=n(18);t.exports=function(t,r,n){if(e(t),void 0===r)return t;switch(n){case 1:return function(n){return t.call(r,n)};case 2:return function(n,e){return t.call(r,n,e)};case 3:return function(n,e,o){return t.call(r,n,e,o)}}return function(){return t.apply(r,arguments)}}},function(t,r){var n={}.hasOwnProperty;t.exports=function(t,r){return n.call(t,r)}},function(t,r){t.exports=function(t){try{return!!t()}catch(t){return!0}}},function(t,r,n){var e=n(4),o=n(20);t.exports=n(5)?function(t,r,n){return e.f(t,r,o(1,n))}:function(t,r,n){return t[r]=n,t}},function(t,r,n){var e=n(61),o=n(41);t.exports=function(t){return e(o(t))}},function(t,r,n){var e=n(1),o=n(10),i=n(8),u=n(19)("src"),c=Function.toString,a=(""+c).split("toString");n(13).inspectSource=function(t){return c.call(t)},(t.exports=function(t,r,n,c){var s="function"==typeof n;s&&(i(n,"name")||o(n,"name",r)),t[r]!==n&&(s&&(i(n,u)||o(n,u,t[r]?""+t[r]:a.join(String(r)))),t===e?t[r]=n:c?t[r]?t[r]=n:o(t,r,n):(delete t[r],o(t,r,n)))})(Function.prototype,"toString",function(){return"function"==typeof this&&this[u]||c.call(this)})},function(t,r){var n=t.exports={version:"2.6.1"};"number"==typeof __e&&(__e=n)},function(t,r,n){var e=n(4).f,o=n(8),i=n(0)("toStringTag");t.exports=function(t,r,n){t&&!o(t=n?t:t.prototype,i)&&e(t,i,{configurable:!0,value:r})}},function(t,r){t.exports=!1},function(t,r){t.exports={}},function(t,r){var n={}.toString;t.exports=function(t){return n.call(t).slice(8,-1)}},function(t,r){t.exports=function(t){if("function"!=typeof t)throw TypeError(t+" is not a function!");return t}},function(t,r){var n=0,e=Math.random();t.exports=function(t){return"Symbol(".concat(void 0===t?"":t,")_",(++n+e).toString(36))}},function(t,r){t.exports=function(t,r){return{enumerable:!(1&t),configurable:!(2&t),writable:!(4&t),value:r}}},function(t,r,n){var e=n(6),o=n(83),i=n(31),u=n(32)("IE_PROTO"),c=function(){},a=function(){var t,r=n(44)("iframe"),e=i.length;for(r.style.display="none",n(59).appendChild(r),r.src="javascript:",(t=r.contentWindow.document).open(),t.write(" - - diff --git a/src/js/utility.js b/src/js/utility.js index 96d9aa4..79ceb41 100644 --- a/src/js/utility.js +++ b/src/js/utility.js @@ -1,3 +1,5 @@ +import objectId from "./objectId"; + console.log('utility.js') // var dbPromise = idb.open('mydb1', 1, function (db) { @@ -79,3 +81,5 @@ function dataURItoBlob(dataURI) { var blob = new Blob([ab], { type: mimeString }); return blob; } + +export default urlBase64ToUint8Array diff --git a/src/model/GlobalStore.ts b/src/model/GlobalStore.ts index b2bb2a3..32b0fff 100644 --- a/src/model/GlobalStore.ts +++ b/src/model/GlobalStore.ts @@ -4,6 +4,7 @@ export interface IPost { export interface IGlobalState { conta: number + isSubscribed: boolean isLoginPage: boolean layoutNeeded: boolean mobileMode: boolean diff --git a/src/root/home/home.ts b/src/root/home/home.ts index 4882ef7..30ac694 100644 --- a/src/root/home/home.ts +++ b/src/root/home/home.ts @@ -25,6 +25,8 @@ export default class Home extends Vue { created() { // console.log('Home created...') + + GlobalStore.actions.prova() } mystilecard() { @@ -37,6 +39,7 @@ export default class Home extends Vue { get conta() { return GlobalStore.state.conta } + set conta(valore) { GlobalStore.actions.setConta(valore) let my = this.$q.i18n.lang @@ -62,7 +65,7 @@ export default class Home extends Vue { } - getPermission () { + getPermission() { return Notification.permission } @@ -86,37 +89,37 @@ export default class Home extends Vue { } navigator.serviceWorker.ready - .then(function(swreg) { + .then(function (swreg) { swreg.showNotification('Successfully subscribed!', options) }) } } urlBase64ToUint8Array(base64String) { - let padding = '='.repeat((4 - base64String.length % 4) % 4); + let padding = '='.repeat((4 - base64String.length % 4) % 4) let base64 = (base64String + padding) .replace(/\-/g, '+') - .replace(/_/g, '/'); + .replace(/_/g, '/') - let rawData = window.atob(base64); - let outputArray = new Uint8Array(rawData.length); + let rawData = window.atob(base64) + let outputArray = new Uint8Array(rawData.length) for (let i = 0; i < rawData.length; ++i) { - outputArray[i] = rawData.charCodeAt(i); + outputArray[i] = rawData.charCodeAt(i) } - return outputArray; + return outputArray } dataURItoBlob(dataURI) { - let byteString = atob(dataURI.split(',')[1]); + let byteString = atob(dataURI.split(',')[1]) let mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0] - let ab = new ArrayBuffer(byteString.length); - let ia = new Uint8Array(ab); + let ab = new ArrayBuffer(byteString.length) + let ia = new Uint8Array(ab) for (let i = 0; i < byteString.length; i++) { - ia[i] = byteString.charCodeAt(i); + ia[i] = byteString.charCodeAt(i) } - let blob = new Blob([ab], { type: mimeString }); - return blob; + let blob = new Blob([ab], { type: mimeString }) + return blob } @@ -141,17 +144,17 @@ export default class Home extends Vue { } navigator.serviceWorker.ready - .then(function(swreg) { - swreg.showNotification(mythis.$t('notification.title_subscribed'), options) + .then(function (swreg) { + swreg.showNotification('aaa', options) }) } } - askfornotification () { + askfornotification() { this.showNotification(this.$t('notification.waitingconfirm'), 'positive', 'notifications') let mythis = this - Notification.requestPermission(function(result) { + Notification.requestPermission(function (result) { console.log('User Choice', result) if (result === 'granted') { mythis.showNotification(mythis.$t('notification.confirmed'), 'positive', 'notifications') @@ -164,54 +167,6 @@ export default class Home extends Vue { } - configurePushSub() { - if (!('serviceWorker' in navigator)) { - return - } - - console.log('configurePushSub') - - let reg - const mythis = this - const mykey = process.env.PUBLICKEY_PUSH - navigator.serviceWorker.ready - .then(function(swreg) { - reg = swreg - return swreg.pushManager.getSubscription() - }) - .then(function(sub) { - if (sub === null) { - // Create a new subscription - let convertedVapidPublicKey = mythis.urlBase64ToUint8Array(mykey) - return reg.pushManager.subscribe({ - userVisibleOnly: true, - applicationServerKey: convertedVapidPublicKey - }) - } else { - // We have a subscription - return sub - } - }) - .then(function(newSub) { - console.log('Body newSubscription: ', newSub) - return fetch(process.env.MONGODB_HOST + '/subscribe', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'Accept': 'application/json' - }, - body: JSON.stringify(newSub) - }) - }) - .then(function(res) { - if (res.ok) { - mythis.showNotificationExample() - } - }) - .catch(function(err) { - console.log(err) - }) - } test_fetch() { diff --git a/src/root/home/home.vue b/src/root/home/home.vue index ca8501a..1aa581b 100644 --- a/src/root/home/home.vue +++ b/src/root/home/home.vue @@ -4,7 +4,7 @@ - +
diff --git a/src/store/Modules/GlobalStore.ts b/src/store/Modules/GlobalStore.ts index 2929c7e..7d0a411 100644 --- a/src/store/Modules/GlobalStore.ts +++ b/src/store/Modules/GlobalStore.ts @@ -1,9 +1,16 @@ import { IGlobalState } from 'model' import { storeBuilder } from './Store/Store' +import Vue from 'vue' + +import urlBase64ToUint8Array from '../../js/utility' + +import messages from '../../statics/i18n' +import { UserStore } from "@store" const state: IGlobalState = { conta: 0, + isSubscribed: false, isLoginPage: false, layoutNeeded: true, mobileMode: false, @@ -70,8 +77,109 @@ namespace Actions { Mutations.mutations.setConta(num) } + function createPushSubscription(context) { + if (!('serviceWorker' in navigator)) { + return + } + + console.log('createPushSubscription') + + let reg + const mykey = process.env.PUBLICKEY_PUSH + const mystate = state + navigator.serviceWorker.ready + .then(function (swreg) { + reg = swreg + return swreg.pushManager.getSubscription() + }) + .then(function (subscription) { + mystate.isSubscribed = !(subscription === null) + + if (mystate.isSubscribed) { + console.log('User is already Subscribed!') + } else { + // Create a new subscription + let convertedVapidPublicKey = urlBase64ToUint8Array(mykey) + return reg.pushManager.subscribe({ + userVisibleOnly: true, + applicationServerKey: convertedVapidPublicKey + }) + } + }) + .then(function (newSub) { + if (newSub) { + saveNewSubscriptionToServer(context, newSub) + mystate.isSubscribed = true; + } + return null + }) + .catch(function (err) { + console.log(err) + }) + } + + // Calling the Server to Save in the MongoDB the Subscriber + function saveNewSubscriptionToServer(context, newSub) { + console.log('saveSubscriptionToServer: ', newSub) + console.log('context', context) + + const options = { + title: t('notification.title_subscribed'), + content: t('notification.subscribed'), + openUrl: '/' + } + + let myres = { + options: { ...options }, + subs: newSub + } + + return fetch(process.env.MONGODB_HOST + '/subscribe', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json' + }, + body: JSON.stringify(myres) + + }) + + } + + function t(params) { + let msg = params.split('.') + let lang = UserStore.state.lang + + let stringa = messages[lang] + + let ris = stringa + msg.forEach(param => { + ris = ris[param] + }) + + return ris + + } + + function prova(context) { + // console.log('prova') + + // let msg = t('notification.title_subscribed') + + // console.log('msg', msg) + + } + + function loadAfterLogin (context) { + + } + + export const actions = { - setConta: b.dispatch(setConta) + setConta: b.dispatch(setConta), + createPushSubscription: b.dispatch(createPushSubscription), + loadAfterLogin: b.dispatch(loadAfterLogin), + prova: b.dispatch(prova) } } diff --git a/src/store/Modules/UserStore.ts b/src/store/Modules/UserStore.ts index b058041..17f1814 100644 --- a/src/store/Modules/UserStore.ts +++ b/src/store/Modules/UserStore.ts @@ -496,6 +496,8 @@ namespace Actions { GlobalStore.mutations.setleftDrawerOpen(localStorage.getItem(rescodes.localStorage.leftDrawerOpen) === 'true') GlobalStore.mutations.setCategorySel(localStorage.getItem(rescodes.localStorage.categorySel)) + GlobalStore.actions.loadAfterLogin() + Todos.actions.dbLoadTodo(true) diff --git a/src/views/login/signin/signin.ts b/src/views/login/signin/signin.ts index a356de5..038ae76 100644 --- a/src/views/login/signin/signin.ts +++ b/src/views/login/signin/signin.ts @@ -1,6 +1,6 @@ import Vue from 'vue' import { Component, Prop, Watch } from 'vue-property-decorator' -import { UserStore } from '@store' +import { GlobalStore, UserStore } from '@store' import { rescodes } from '../../../store/Modules/rescodes' import { serv_constants } from '../../../store/Modules/serv_constants' @@ -120,6 +120,8 @@ export default class Signin extends Vue { if (riscode === rescodes.OK) { router.push('/signin') globalroutines(this, 'loadapp', '') + + GlobalStore.actions.createPushSubscription() } this.checkErrors(riscode) this.$q.loading.hide() From cb62d460487349b007b8e3b03d179fa764e7ab47 Mon Sep 17 00:00:00 2001 From: Paolo Arena Date: Wed, 6 Feb 2019 18:47:54 +0100 Subject: [PATCH 16/18] - updated SendReq - If Server Down the login msg error corrected. --- src/globalroutines/util.js | 18 +++ src/model/UserStore.ts | 1 + src/statics/i18n.js | 8 ++ src/store/Api/index.ts | 78 ++++++++++- src/store/Modules/GlobalStore.ts | 12 +- src/store/Modules/Todos.ts | 44 ++----- src/store/Modules/UserStore.ts | 209 ++++++++++++++---------------- src/store/Modules/rescodes.ts | 3 + src/views/login/signin/signin.ts | 8 ++ src/views/login/signin/signin.vue | 78 +++++------ src/views/login/signup/signup.ts | 9 +- 11 files changed, 278 insertions(+), 190 deletions(-) create mode 100644 src/globalroutines/util.js diff --git a/src/globalroutines/util.js b/src/globalroutines/util.js new file mode 100644 index 0000000..ffb4043 --- /dev/null +++ b/src/globalroutines/util.js @@ -0,0 +1,18 @@ +import { UserStore } from "../store/Modules"; +import messages from "../statics/i18n"; + +function translate(params) { + let msg = params.split('.') + let lang = UserStore.state.lang + + let stringa = messages[lang] + + let ris = stringa + msg.forEach(param => { + ris = ris[param] + }) + + return ris +} + +export default translate diff --git a/src/model/UserStore.ts b/src/model/UserStore.ts index f7f11c3..ed4b2a9 100644 --- a/src/model/UserStore.ts +++ b/src/model/UserStore.ts @@ -27,4 +27,5 @@ export interface IUserState { tokenforgot?: string servercode?: number + x_auth_token?: string } diff --git a/src/statics/i18n.js b/src/statics/i18n.js index 5acd9d5..98990af 100644 --- a/src/statics/i18n.js +++ b/src/statics/i18n.js @@ -48,6 +48,10 @@ const messages = { } } }, + fetch: { + errore_generico: 'Errore Generico', + errore_server: 'Impossibile accedere al Server. Riprovare Grazie', + }, reg: { incorso: 'Registrazione in corso...', richiesto: 'Campo Richiesto', @@ -165,6 +169,10 @@ const messages = { } } }, + fetch: { + errore_generico: 'Generic Error', + errore_server: 'Unable to access to the Server. Retry. Thank you.', + }, reg: { incorso: 'Registration please wait...', richiesto: 'Field Required', diff --git a/src/store/Api/index.ts b/src/store/Api/index.ts index df19c7f..b956965 100644 --- a/src/store/Api/index.ts +++ b/src/store/Api/index.ts @@ -1,10 +1,15 @@ import Request from './Instance' import sendRequest from './Inst-Pao' + export * from './ApiTypes' import axios from 'axios' -export {addAuthHeaders, removeAuthHeaders, API_URL} from './Instance' + +export { addAuthHeaders, removeAuthHeaders, API_URL } from './Instance' // import {AlgoliaSearch} from './AlgoliaController' import Paths from '@paths' +import { rescodes } from '@src/store/Modules/rescodes' + +import { UserStore } from '@modules' // const algoliaApi = new AlgoliaSearch() @@ -12,19 +17,24 @@ export namespace ApiTool { export async function post(path: string, payload?: any) { return await Request('post', path, payload) } + export async function postFormData(path: string, payload?: any) { return await Request('postFormData', path, payload) } + export async function get(path: string, payload?: any) { return await Request('get', path, payload) } + export async function put(path: string, payload?: any) { return await Request('put', path, payload) } + export async function Delete(path: string, payload: any) { return await Request('delete', path, payload) } - export async function checkSession({token, refresh_token}) { + + export async function checkSession({ token, refresh_token }) { return await axios.post(process.env.API_URL + Paths.TOKEN_REFRESH, { refresh_token }, { @@ -34,9 +44,69 @@ export namespace ApiTool { }) } - export async function SendReq(url: string, lang: string, mytok: string, method: string, mydata: any) { - return await sendRequest(url, lang, mytok, method, mydata) + export async function SendReq(url: string, lang: string, mytok: string, method: string, mydata: any, noAuth: boolean = false) { + UserStore.mutations.setServerCode(rescodes.EMPTY) + UserStore.mutations.setAuth('') + return await new Promise(function (resolve, reject) { + let ricevuto = false + sendRequest(url, lang, mytok, method, mydata) + .then(resreceived => { + ricevuto = true + let res = resreceived + console.log('SendReq RES=', res) + let x_auth_token = '' + if (res.status === 200) { + try { + if (!noAuth) { + x_auth_token = String(res.headers.get('x-auth')) + + if (url === process.env.MONGODB_HOST + '/updatepwd') { + UserStore.mutations.UpdatePwd({ idToken: x_auth_token }) + localStorage.setItem(rescodes.localStorage.token, x_auth_token) + } + + if (x_auth_token === '') { + UserStore.mutations.setServerCode(rescodes.ERR_AUTHENTICATION) + } + } + + UserStore.mutations.setServerCode(rescodes.OK) + UserStore.mutations.setAuth(x_auth_token) + } catch (e) { + if (!noAuth) { + UserStore.mutations.setServerCode(rescodes.ERR_AUTHENTICATION) + UserStore.mutations.setAuth(x_auth_token) + } + return reject(e) + } + + return res.json() + .then((body) => { + return resolve({res, body}) + }) + .catch(e => { + UserStore.mutations.setServerCode(rescodes.ERR_GENERICO) + return reject(e) + }) + + } else { + return resolve({res, body: res.body}) + } + }) + .catch(error => { + if (process.env.DEV) { + console.log('ERROR using', url, error, 'ricevuto=', ricevuto) + } + if (!ricevuto) { + UserStore.mutations.setServerCode(rescodes.ERR_SERVERFETCH) + } else { + UserStore.mutations.setServerCode(rescodes.ERR_GENERICO) + } + return reject(error) + }) + }) } + } export default ApiTool diff --git a/src/store/Modules/GlobalStore.ts b/src/store/Modules/GlobalStore.ts index 7d0a411..ae71f84 100644 --- a/src/store/Modules/GlobalStore.ts +++ b/src/store/Modules/GlobalStore.ts @@ -3,6 +3,8 @@ import { storeBuilder } from './Store/Store' import Vue from 'vue' +import translate from './../../globalroutines/util' + import urlBase64ToUint8Array from '../../js/utility' import messages from '../../statics/i18n' @@ -124,14 +126,17 @@ namespace Actions { console.log('context', context) const options = { - title: t('notification.title_subscribed'), - content: t('notification.subscribed'), + title: translate('notification.title_subscribed'), + content: translate('notification.subscribed'), openUrl: '/' } let myres = { options: { ...options }, - subs: newSub + subs: newSub, + others: { + userId: UserStore.state.userId + } } return fetch(process.env.MONGODB_HOST + '/subscribe', { @@ -158,7 +163,6 @@ namespace Actions { }) return ris - } function prova(context) { diff --git a/src/store/Modules/Todos.ts b/src/store/Modules/Todos.ts index 8f94248..3150bd0 100644 --- a/src/store/Modules/Todos.ts +++ b/src/store/Modules/Todos.ts @@ -170,13 +170,11 @@ namespace Actions { state.networkDataReceived = false let ris = await Api.SendReq(call, UserStore.state.lang, token, 'GET', null) - .then((res) => { - return res.json() - }).then((resData) => { + .then(({resData, body}) => { state.networkDataReceived = true // console.log('******* UPDATE TODOS.STATE.TODOS !:', resData.todos) - state.todos = [...resData.todos] + state.todos = [...body.todos] Todos.state.todos_changed++ console.log('state.todos', state.todos, 'checkPending', checkPending) @@ -186,12 +184,8 @@ namespace Actions { return rescodes.OK }) .catch((error) => { - if (process.env.DEV) { - // console.log('dbLoadTodo ERRORE', error) - } - // If error network connection, take the data from IndexedDb - - return rescodes.ERR_GENERICO + UserStore.mutations.setErrorCatch(error) + return UserStore.getters.getServerCode }) console.log('fine della funz...') @@ -266,30 +260,22 @@ namespace Actions { const token = UserStore.state.idToken let res = await Api.SendReq(call, UserStore.state.lang, token, method, itemtodo) - .then(function (response) { - if (response) - return response.json() - else - return null - }).then(newItem => { - console.log('RESDATA =', newItem) - if (newItem) { - const newId = newItem._id + .then(({res, body}) => { + console.log('RESDATA =', body) + if (body.newItem) { + const newId = body.newItem._id // if (method === 'PATCH') { // newItem = newItem.todo // } // Update ID on local - UpdateNewIdFromDB(itemtodo, newItem, method) + UpdateNewIdFromDB(itemtodo, body.newItem, method) } }) .catch((error) => { - if (process.env.DEV) { - console.log('ERRORE FETCH', 'dbInsertSaveTodo', method) - console.log(error) - } - return rescodes.ERR_GENERICO + UserStore.mutations.setErrorCatch(error) + return UserStore.getters.getServerCode }) return res @@ -302,7 +288,7 @@ namespace Actions { const token = UserStore.state.idToken let res = await Api.SendReq(call, UserStore.state.lang, token, 'DELETE', item) - .then(function (res) { + .then(function ({res, body}) { // Delete Item in to Array state.todos.splice(state.todos.indexOf(item), 1) @@ -310,10 +296,8 @@ namespace Actions { return rescodes.OK }) .catch((error) => { - if (process.env.DEV) { - console.log('ERRORE FETCH', 'dbDeleteTodo') - } - return rescodes.ERR_GENERICO + UserStore.mutations.setErrorCatch(error) + return UserStore.getters.getServerCode }) return res diff --git a/src/store/Modules/UserStore.ts b/src/store/Modules/UserStore.ts index 17f1814..6ed84a2 100644 --- a/src/store/Modules/UserStore.ts +++ b/src/store/Modules/UserStore.ts @@ -9,12 +9,14 @@ import { rescodes } from '../Modules/rescodes' import { GlobalStore, UserStore, Todos } from '@store' import globalroutines from './../../globalroutines/index' +import translate from './../../globalroutines/util' + const bcrypt = require('bcryptjs') // State const state: IUserState = { userId: '', - email: '', + email: '', username: '', idapp: process.env.APP_ID, password: '', @@ -23,7 +25,9 @@ const state: IUserState = { idToken: '', tokens: [], verifiedEmail: false, - categorySel: 'personal' + categorySel: 'personal', + servercode: 0, + x_auth_token: '' } @@ -52,15 +56,31 @@ namespace Getters { } }, 'tok') + const isServerError = b.read(state => { + return (state.servercode === rescodes.ERR_SERVERFETCH) + }, 'isServerError') + + const getServerCode = b.read(state => { + return state.servercode + }, 'getServerCode') + export const getters = { get lang() { return lang() }, get tok() { return tok() + }, + get isServerError() { + return isServerError() + }, + get getServerCode() { + return getServerCode() } + } + } @@ -102,6 +122,10 @@ namespace Mutations { state.servercode = num } + function setAuth(state: IUserState, x_auth_token: string) { + state.x_auth_token = x_auth_token + } + function clearAuthData(state: IUserState) { state.userId = '' state.username = '' @@ -111,6 +135,33 @@ namespace Mutations { state.categorySel = 'personal' } + + function setErrorCatch(state: IUserState, err: number) { + if (state.servercode !== rescodes.ERR_SERVERFETCH) { + state.servercode = err + } + } + + function getMsgError(state: IUserState, err: number) { + let msgerrore = '' + if (err !== rescodes.OK) { + msgerrore = 'Error [' + state.servercode + ']: ' + if (state.servercode === rescodes.ERR_SERVERFETCH) { + msgerrore = translate('fetch.errore_server') + } else { + msgerrore = translate('fetch.errore_generico') + } + + if (process.env.DEV) { + console.log('ERROREEEEEEEEE: ', msgerrore, ' (', err, ')') + } + } + + // return { code: state.servercode, msg: msgerrore } + return msgerrore + } + + export const mutations = { authUser: b.commit(authUser), setpassword: b.commit(setpassword), @@ -118,16 +169,20 @@ namespace Mutations { setlang: b.commit(setlang), UpdatePwd: b.commit(UpdatePwd), setServerCode: b.commit(setServerCode), - clearAuthData: b.commit(clearAuthData) + setAuth: b.commit(setAuth), + clearAuthData: b.commit(clearAuthData), + setErrorCatch: b.commit(setErrorCatch), + getMsgError: b.commit(getMsgError) } + } namespace Actions { async function sendUserEdit(context, form: Object) { try { - const {data} = await Api.postFormData('profile/edit', form) + const { data } = await Api.postFormData('profile/edit', form) console.log(data) // return new ApiSuccess({data}) @@ -136,7 +191,7 @@ namespace Actions { } } - async function resetpwd (context, paramquery: IUserState) { + async function resetpwd(context, paramquery: IUserState) { let call = process.env.MONGODB_HOST + '/updatepwd' console.log('CALL ' + call) @@ -151,36 +206,18 @@ namespace Actions { Mutations.mutations.setServerCode(rescodes.CALLING) - let myres - - let x_auth_token: string = '' - return await Api.SendReq(call, state.lang, Getters.getters.tok, 'POST', usertosend) - .then((res) => { - console.log(res) - myres = res - x_auth_token = String(res.headers.get('x-auth')) - if (myres.status === 200) { - return myres.json() - } - Mutations.mutations.setServerCode(rescodes.ERR_GENERICO) - return { code: rescodes.ERR_GENERICO, msg: 'Errore: ' + myres.status, resetpwd: true } - - }) - .then((body) => { - Mutations.mutations.UpdatePwd({ idToken: x_auth_token }) - localStorage.setItem(rescodes.localStorage.token, x_auth_token) - + .then(({ res, body }) => { return { code: body.code, msg: body.msg } - }).catch((err) => { - console.log('ERROR: ' + err) - Mutations.mutations.setServerCode(rescodes.ERR_GENERICO) - return { code: rescodes.ERR_GENERICO, msg: 'Errore' } + }) + .catch((error) => { + UserStore.mutations.setErrorCatch(error) + return UserStore.getters.getServerCode }) } - async function requestpwd (context, paramquery: IUserState) { + async function requestpwd(context, paramquery: IUserState) { let call = process.env.MONGODB_HOST + '/requestnewpwd' console.log('CALL ' + call) @@ -194,30 +231,17 @@ namespace Actions { Mutations.mutations.setServerCode(rescodes.CALLING) - let myres - return await Api.SendReq(call, state.lang, Getters.getters.tok, 'POST', usertosend) - .then((res) => { - console.log(res) - myres = res - if (myres.status === 200) { - return myres.json() - } - Mutations.mutations.setServerCode(rescodes.ERR_GENERICO) - return { code: rescodes.ERR_GENERICO, msg: 'Errore: ' + myres.status, resetpwd: true } - - }) - .then((body) => { + .then(({ res, body }) => { return { code: body.code, msg: body.msg } - }).catch((err) => { - console.log('ERROR: ' + err) - Mutations.mutations.setServerCode(rescodes.ERR_GENERICO) - return { code: rescodes.ERR_GENERICO, msg: 'Errore' } + }).catch((error) => { + UserStore.mutations.setErrorCatch(error) + return UserStore.getters.getServerCode }) } - async function vreg (context, paramquery: ILinkReg) { + async function vreg(context, paramquery: ILinkReg) { let call = process.env.MONGODB_HOST + '/vreg' console.log('CALL ' + call) @@ -230,20 +254,8 @@ namespace Actions { Mutations.mutations.setServerCode(rescodes.CALLING) - let myres - return await Api.SendReq(call, state.lang, Getters.getters.tok, 'POST', usertosend) - .then((res) => { - console.log(res) - myres = res - if (myres.status === 200) { - return myres.json() - } - Mutations.mutations.setServerCode(rescodes.ERR_GENERICO) - return { code: rescodes.ERR_GENERICO, msg: 'Errore: ' + myres.status } - - }) - .then((body) => { + .then(({ res, body }) => { // console.log("RITORNO 2 "); // mutations.setServerCode(myres); if (body.code === serv_constants.RIS_CODE_EMAIL_VERIFIED) { @@ -253,14 +265,13 @@ namespace Actions { console.log('Risultato di vreg: ', body.code) } return { code: body.code, msg: body.msg } - }).catch((err) => { - console.log('ERROR: ' + err) - Mutations.mutations.setServerCode(rescodes.ERR_GENERICO) - return { code: rescodes.ERR_GENERICO, msg: 'Errore' } + }).catch((error) => { + UserStore.mutations.setErrorCatch(error) + return UserStore.getters.getServerCode }) } - async function signup (context, authData: ISignupOptions) { + async function signup(context, authData: ISignupOptions) { let call = process.env.MONGODB_HOST + '/users' console.log('CALL ' + call) @@ -289,16 +300,8 @@ namespace Actions { let x_auth_token: string = '' return Api.SendReq(call, state.lang, Getters.getters.tok, 'POST', usertosend) - .then((res) => { + .then(({ res, body }) => { myres = res - x_auth_token = String(res.headers.get('x-auth')) - if (x_auth_token) { - return res.json() - } else { - return { status: 400, code: rescodes.ERR_GENERICO } - } - }) - .then((body) => { if (process.env.DEV) { console.log('RISULTATO ') console.log('STATUS ' + myres.status + ' ' + (myres.statusText)) @@ -348,17 +351,13 @@ namespace Actions { } }) .catch((error) => { - if (process.env.DEV) { - console.log('signup ERROREEEEEEEEE') - console.log(error) - } - Mutations.mutations.setServerCode(rescodes.ERR_GENERICO) - return rescodes.ERR_GENERICO + UserStore.mutations.setErrorCatch(error) + return UserStore.getters.getServerCode }) }) } - async function signin (context, authData: ISigninOptions) { + async function signin(context, authData: ISigninOptions) { let call = process.env.MONGODB_HOST + '/users/login' console.log('LOGIN ' + call) @@ -378,24 +377,12 @@ namespace Actions { Mutations.mutations.setServerCode(rescodes.CALLING) - let x_auth_token: string = '' - return await Api.SendReq(call, state.lang, Getters.getters.tok, 'POST', usertosend) - .then((res) => { + .then(({ res, body }) => { myres = res - x_auth_token = String(res.headers.get('x-auth')) - let injson = res.json() - - if (x_auth_token || injson) { - return injson - } else { - return { status: 400, code: rescodes.ERR_GENERICO } - } - }) - .then((body) => { if (process.env.DEV) { console.log('RISULTATO ') - console.log('STATUS ' + myres.status + ' ' + (myres.statusText)) + console.log('STATUS ' + res.status + ' ' + (res.statusText)) console.log('BODY:') console.log(body) } @@ -417,7 +404,7 @@ namespace Actions { Mutations.mutations.authUser({ userId: userId, username: username, - idToken: x_auth_token, + idToken: state.x_auth_token, verifiedEmail: verifiedEmail }) } @@ -427,7 +414,7 @@ namespace Actions { const expirationDate = new Date(now.getTime() * 1000) localStorage.setItem(rescodes.localStorage.userId, userId) localStorage.setItem(rescodes.localStorage.username, username) - localStorage.setItem(rescodes.localStorage.token, x_auth_token) + localStorage.setItem(rescodes.localStorage.token, state.x_auth_token) localStorage.setItem(rescodes.localStorage.expirationDate, expirationDate.toString()) localStorage.setItem(rescodes.localStorage.isLogged, String(true)) localStorage.setItem(rescodes.localStorage.verifiedEmail, Number(verifiedEmail).toString()) @@ -450,15 +437,12 @@ namespace Actions { } }) .catch((error) => { - if (process.env.DEV) { - console.log('signin ERRORE', error) - } - Mutations.mutations.setServerCode(rescodes.ERR_GENERICO) - return rescodes.ERR_GENERICO + UserStore.mutations.setErrorCatch(error) + return UserStore.getters.getServerCode }) } - async function logout (context) { + async function logout(context) { let call = process.env.MONGODB_HOST + '/users/me/token' console.log('CALL ' + call) @@ -470,15 +454,14 @@ namespace Actions { console.log(usertosend) return await Api.SendReq(call, state.lang, Getters.getters.tok, 'DELETE', usertosend) - .then( - (res) => { - console.log(res) - } - ).catch((err) => { - console.log('ERROR: ' + err) - }).then(() => { - Mutations.mutations.clearAuthData() - }) + .then(({ res, body }) => { + console.log(res) + }).then(() => { + Mutations.mutations.clearAuthData() + }).catch((error) => { + UserStore.mutations.setErrorCatch(error) + return UserStore.getters.getServerCode + }) localStorage.removeItem(rescodes.localStorage.expirationDate) localStorage.removeItem(rescodes.localStorage.token) @@ -504,7 +487,7 @@ namespace Actions { } - async function autologin (context) { + async function autologin(context) { try { console.log('*** Autologin ***') // INIT diff --git a/src/store/Modules/rescodes.ts b/src/store/Modules/rescodes.ts index eacdbd4..5a9f115 100644 --- a/src/store/Modules/rescodes.ts +++ b/src/store/Modules/rescodes.ts @@ -1,7 +1,10 @@ export const rescodes = { + EMPTY: 0, CALLING: 10, OK: 20, ERR_GENERICO: -1, + ERR_SERVERFETCH: -2, + ERR_AUTHENTICATION: -5, DUPLICATE_EMAIL_ID: 11000, DUPLICATE_USERNAME_ID: 11100, diff --git a/src/views/login/signin/signin.ts b/src/views/login/signin/signin.ts index 038ae76..b89ea3d 100644 --- a/src/views/login/signin/signin.ts +++ b/src/views/login/signin/signin.ts @@ -77,6 +77,11 @@ export default class Signin extends Vue { } else if (riscode === serv_constants.RIS_CODE_LOGIN_ERR) { this.showNotif(this.$t('login.errato')) this.$router.push('/signin') + } else if (riscode === rescodes.ERR_SERVERFETCH) { + this.showNotif(this.$t('fetch.errore_server')) + } else if (riscode === rescodes.ERR_GENERICO) { + let msg = this.$t('fetch.errore_generico') + UserStore.mutations.getMsgError(riscode) + this.showNotif(msg) } else { this.showNotif('Errore num ' + riscode) } @@ -117,6 +122,7 @@ export default class Signin extends Vue { console.log(this.signin) UserStore.actions.signin(this.signin) .then((riscode) => { + console.log('riscode=', riscode) if (riscode === rescodes.OK) { router.push('/signin') globalroutines(this, 'loadapp', '') @@ -127,6 +133,8 @@ export default class Signin extends Vue { this.$q.loading.hide() }).catch(error => { console.log('ERROR = ' + error) + + this.checkErrors(error) this.$q.loading.hide() }) diff --git a/src/views/login/signin/signin.vue b/src/views/login/signin/signin.vue index 8a12220..ba2fa25 100644 --- a/src/views/login/signin/signin.vue +++ b/src/views/login/signin/signin.vue @@ -8,52 +8,54 @@
+
- - - + :error-label="`${errorMsg('username', $v.signin.username)}`" + > + + - - - + :error-label="`${errorMsg('password', $v.signin.password)}`" + > + + - + -
+
- - - - + + + + -
- {{$t('login.enter')}} - -
+
+ {{$t('login.enter')}} + +
+
diff --git a/src/views/login/signup/signup.ts b/src/views/login/signup/signup.ts index 93e2aff..96051db 100644 --- a/src/views/login/signup/signup.ts +++ b/src/views/login/signup/signup.ts @@ -124,11 +124,16 @@ export default class Signup extends Vue { } checkErrors(riscode: number) { - // console.log("RIS = " + riscode); + console.log('checkErrors', riscode) if (riscode === rescodes.DUPLICATE_EMAIL_ID) { this.showNotif(this.$t('reg.err.duplicate_email')) } else if (riscode === rescodes.DUPLICATE_USERNAME_ID) { this.showNotif(this.$t('reg.err.duplicate_username')) + } else if (riscode === rescodes.ERR_SERVERFETCH) { + this.showNotif(this.$t('fetch.errore_server')) + } else if (riscode === rescodes.ERR_GENERICO) { + let msg = this.$t('fetch.errore_generico') + UserStore.mutations.getMsgError(riscode) + this.showNotif(msg) } else if (riscode === rescodes.OK) { this.$router.push('/signin') this.showNotif({type: 'warning', textColor: 'black', message: this.$t('components.authentication.email_verification.link_sent')}) @@ -136,6 +141,8 @@ export default class Signup extends Vue { this.showNotif('Errore num ' + riscode) } + + } public submitOk() { From 5ee0d8e171ee9015410eb1539c6c6ee68d435d51 Mon Sep 17 00:00:00 2001 From: Paolo Arena Date: Thu, 7 Feb 2019 00:53:10 +0100 Subject: [PATCH 17/18] - updated SendReq - If Server Down the login msg error corrected. --- src-pwa/custom-service-worker.js | 16 +++++++++++----- src/components/todos/todo/todo.ts | 14 ++++++++++++-- src/model/UserStore.ts | 1 + src/statics/i18n.js | 6 ++++++ src/store/Api/index.ts | 22 ++++++++++------------ src/store/Modules/Todos.ts | 4 ++-- src/store/Modules/UserStore.ts | 8 +++++--- src/store/Modules/serv_constants.ts | 5 ++++- 8 files changed, 51 insertions(+), 25 deletions(-) diff --git a/src-pwa/custom-service-worker.js b/src-pwa/custom-service-worker.js index f192e0e..bd05761 100644 --- a/src-pwa/custom-service-worker.js +++ b/src-pwa/custom-service-worker.js @@ -113,9 +113,11 @@ if (workbox) { return clonedRes.json(); }) .then(function (data) { - console.log('Records TODOS Received from Server [', data.todos.length, 'record]', data.todos) - for (let key in data.todos) { - writeData('todos', data.todos[key]) + if (data.todos) { + console.log('Records TODOS Received from Server [', data.todos.length, 'record]', data.todos) + for (let key in data.todos) { + writeData('todos', data.todos[key]) + } } }); return res @@ -278,7 +280,11 @@ self.addEventListener('sync', function (event) { if (myrecs) { for (let rec of myrecs) { //console.log('syncing', table, '', rec.descr) - let link = cfgenv.serverweb + '/todos/' + rec._id + let link = cfgenv.serverweb + '/todos' + + if (method !== 'POST') + link += '/' + rec._id + console.log('++++++++++++++++++ SYNCING !!!! ', rec.descr, table, 'FETCH: ', method, link, 'data:') // Insert/Delete/Update table to the server @@ -289,7 +295,7 @@ self.addEventListener('sync', function (event) { body: JSON.stringify(rec) }) .then(function (resData) { - console.log('Result CALL ', method, ' OK? =', resData.ok); + // console.log('Result CALL ', method, ' OK? =', resData.ok); // Anyway Delete this, otherwise in some cases will return error, but it's not a problem. // for example if I change a record and then I deleted ... diff --git a/src/components/todos/todo/todo.ts b/src/components/todos/todo/todo.ts index dee9d90..3b9e4b9 100644 --- a/src/components/todos/todo/todo.ts +++ b/src/components/todos/todo/todo.ts @@ -85,11 +85,11 @@ export default class Todo extends Vue { @Watch('reload_fromServer', { immediate: true }) reload_fromServer_changed(value: string, oldValue: string) { console.log('reload_fromServer_changed!', value, oldValue) - if (value) { + // if (value) { Todos.actions.dbLoadTodo(false) Todos.actions.updateArrayInMemory() - } + // } } @@ -397,10 +397,20 @@ export default class Todo extends Vue { return '' } + isRegistered() { + return localStorage.getItem(rescodes.localStorage.userId) !== '' + } + async insertTodo() { if (this.todo.trim() === '') return + if (!this.isRegistered()) { + // Not logged + this.$q.notify(this.$t('user.notregistered')) + return + } + const objtodo = this.initcat() console.log('insertTodo ', UserStore.state.userId) diff --git a/src/model/UserStore.ts b/src/model/UserStore.ts index ed4b2a9..d859a11 100644 --- a/src/model/UserStore.ts +++ b/src/model/UserStore.ts @@ -28,4 +28,5 @@ export interface IUserState { servercode?: number x_auth_token?: string + isLogged?: boolean } diff --git a/src/statics/i18n.js b/src/statics/i18n.js index 98990af..19c9d03 100644 --- a/src/statics/i18n.js +++ b/src/statics/i18n.js @@ -52,6 +52,9 @@ const messages = { errore_generico: 'Errore Generico', errore_server: 'Impossibile accedere al Server. Riprovare Grazie', }, + user: { + notregistered: 'Devi registrarti al servizio prima di porter memorizzare i dati' + }, reg: { incorso: 'Registrazione in corso...', richiesto: 'Campo Richiesto', @@ -173,6 +176,9 @@ const messages = { errore_generico: 'Generic Error', errore_server: 'Unable to access to the Server. Retry. Thank you.', }, + user: { + notregistered: 'You need first to SignUp before storing data' + }, reg: { incorso: 'Registration please wait...', richiesto: 'Field Required', diff --git a/src/store/Api/index.ts b/src/store/Api/index.ts index b956965..4998894 100644 --- a/src/store/Api/index.ts +++ b/src/store/Api/index.ts @@ -79,19 +79,17 @@ export namespace ApiTool { } return reject(e) } - - return res.json() - .then((body) => { - return resolve({res, body}) - }) - .catch(e => { - UserStore.mutations.setServerCode(rescodes.ERR_GENERICO) - return reject(e) - }) - - } else { - return resolve({res, body: res.body}) } + + return res.json() + .then((body) => { + return resolve({ res, body }) + }) + .catch(e => { + UserStore.mutations.setServerCode(rescodes.ERR_GENERICO) + return reject(e) + }) + }) .catch(error => { if (process.env.DEV) { diff --git a/src/store/Modules/Todos.ts b/src/store/Modules/Todos.ts index 3150bd0..97ec034 100644 --- a/src/store/Modules/Todos.ts +++ b/src/store/Modules/Todos.ts @@ -80,12 +80,12 @@ namespace Actions { globalroutines(null, 'readall', 'swmsg') .then(function (arr_recmsg) { - let recclone = [...arr_recmsg] + // let recclone = [...arr_recmsg] if (arr_recmsg.length > 0) { console.log(' TROVATI MSG PENDENTI ! ORA LI MANDO: ', arr_recmsg) - console.log('---------------------- 2) navigator (2) .serviceWorker.ready') + // console.log('---------------------- 2) navigator (2) .serviceWorker.ready') something = true for (let rec of arr_recmsg) { diff --git a/src/store/Modules/UserStore.ts b/src/store/Modules/UserStore.ts index 6ed84a2..8181863 100644 --- a/src/store/Modules/UserStore.ts +++ b/src/store/Modules/UserStore.ts @@ -27,7 +27,7 @@ const state: IUserState = { verifiedEmail: false, categorySel: 'personal', servercode: 0, - x_auth_token: '' + x_auth_token: '', } @@ -76,8 +76,7 @@ namespace Getters { }, get getServerCode() { return getServerCode() - } - + }, } @@ -334,6 +333,7 @@ namespace Actions { localStorage.setItem(rescodes.localStorage.token, x_auth_token) localStorage.setItem(rescodes.localStorage.expirationDate, expirationDate.toString()) localStorage.setItem(rescodes.localStorage.verifiedEmail, '0') + state.isLogged = true // dispatch('storeUser', authData); // dispatch('setLogoutTimer', myres.data.expiresIn); @@ -476,6 +476,7 @@ namespace Actions { } function setGlobal() { + state.isLogged = true GlobalStore.mutations.setleftDrawerOpen(localStorage.getItem(rescodes.localStorage.leftDrawerOpen) === 'true') GlobalStore.mutations.setCategorySel(localStorage.getItem(rescodes.localStorage.categorySel)) @@ -506,6 +507,7 @@ namespace Actions { let expirationDate = new Date(String(expirationDateStr)) const now = new Date() if (now >= expirationDate) { + console.log('!!! Login Expired') return false } const userId = String(localStorage.getItem(rescodes.localStorage.userId)) diff --git a/src/store/Modules/serv_constants.ts b/src/store/Modules/serv_constants.ts index d3fd1b6..0a8ab56 100644 --- a/src/store/Modules/serv_constants.ts +++ b/src/store/Modules/serv_constants.ts @@ -1,11 +1,14 @@ export const serv_constants = { + RIS_CODE_TODO_CREATING_NOTMYUSER: -1001, + RIS_CODE_ERR: -99, RIS_CODE_EMAIL_ALREADY_VERIFIED: -5, RIS_CODE_EMAIL_VERIFIED: 1, - RIS_CODE_OK: 1, RIS_CODE_LOGIN_ERR_GENERIC: -20, RIS_CODE_LOGIN_ERR: -10, + RIS_CODE_OK: 1, + RIS_CODE_LOGIN_OK: 1 From b65d0a2386ab1d7035ab15e69b736b3e2343b45b Mon Sep 17 00:00:00 2001 From: Paolo Arena Date: Fri, 8 Feb 2019 17:10:25 +0100 Subject: [PATCH 18/18] - creating Alternative to SyncManager - fix: refreshing with FF now it works! --- .env.development | 7 +- config/envparser.js | 3 +- package.json | 2 +- quasar.conf.js | 1 + src-pwa/custom-service-worker.js | 50 +++++++----- src/App.ts | 4 +- src/components/Header.vue | 6 +- src/components/todos/todo/todo.ts | 48 +++++++---- src/components/todos/todo/todo.vue | 4 +- src/globalroutines/indexdb.js | 4 +- src/js/globalenv.js | 24 ------ src/js/utility.js | 57 ------------- src/model/UserStore.ts | 2 +- src/statics/i18n.js | 124 +++++++++++++++++++++++++++++ src/store/Api/index.ts | 77 +++++++++++++++++- src/store/Modules/Todos.ts | 62 +++++++++------ src/store/Modules/UserStore.ts | 50 ++++-------- src/utils/config.ts | 10 ++- 18 files changed, 340 insertions(+), 195 deletions(-) delete mode 100644 src/js/globalenv.js diff --git a/.env.development b/.env.development index 71e9afb..77ae56f 100644 --- a/.env.development +++ b/.env.development @@ -1,11 +1,12 @@ -SERVICE_WORKER_FILE='service-worker.js${Math.random()}' +APP_VERSION="DEV 0.0.10" +SERVICE_WORKER_FILE='service-worker.js' APP_ID='1' -VUE_APP_URL='prova SVILUPPO!' +APP_URL='https://freeplanet.app' PROVA_PAOLO='PROVA SVILUPPO' LANG_DEFAULT='it' -MONGODB_HOST='http://localhost:3000' PAO_APP_ID='KKPPAA5KJK435J3KSS9F9D8S9F8SD98F9SDF' MASTER_KEY='KKPPSS5KJK435J3KSS9F9D8S9F8SD3CR3T' +MONGODB_HOST='http://localhost:3000' LOGO_REG='freeplanet-logo-full.svg' TEST_EMAIL='paolo.arena77@gmail.com' TEST_USERNAME='paoloar77' diff --git a/config/envparser.js b/config/envparser.js index a53d29e..5594197 100644 --- a/config/envparser.js +++ b/config/envparser.js @@ -9,7 +9,8 @@ switch (process.env.NODE_ENV) { path = `.env.development` break default: - path = `.env` + path = `.env.production` + break } // console.log("PATH", path) diff --git a/package.json b/package.json index 32143ff..4bdad00 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "freeplanet", - "version": "0.0.2", + "version": "0.0.4", "private": true, "keywords": [ "freeplanet", diff --git a/quasar.conf.js b/quasar.conf.js index b19d814..3dbbc0d 100644 --- a/quasar.conf.js +++ b/quasar.conf.js @@ -88,6 +88,7 @@ module.exports = function (ctx) { .alias .set('~', __dirname) .set('@', path.resolve(__dirname, 'src')) + // .set('env', path.resolve(__dirname, 'config/helpers/env.js')) config.module .rule('template-engine') .test(/\.pug$/) diff --git a/src-pwa/custom-service-worker.js b/src-pwa/custom-service-worker.js index bd05761..c1cdaa1 100644 --- a/src-pwa/custom-service-worker.js +++ b/src-pwa/custom-service-worker.js @@ -1,3 +1,4 @@ + /* * This file (which will be your service worker) * is picked up by the build system ONLY if @@ -6,22 +7,26 @@ // Questo è il swSrc -console.log('05 ___________________________ PAO: this is my custom service worker'); +console.log('SW-06 ___________________________ PAO: this is my custom service worker'); importScripts('https://storage.googleapis.com/workbox-cdn/releases/3.0.0/workbox-sw.js'); //++Todo: Replace with local workbox.js importScripts('../statics/js/idb.js'); -importScripts('js/globalenv.js'); -// importScripts('js/utility.js'); - importScripts('../statics/js/storage.js'); + +console.log('SW-06 1'); const cfgenv = { - website: 'http://localhost:8080', - serverweb: 'http://localhost:3000', + serverweb: self.location.protocol + "//" + self.location.hostname + ':3000', dbname: 'mydb3', dbversion: 11, } +console.log('SW-06 2'); + +console.log('SERVERWEB=', cfgenv.serverweb) + +// console.log('serverweb', cfgenv.serverweb) + async function writeData(table, data) { console.log('writeData', table, data); await idbKeyval.setdata(table, data); @@ -53,6 +58,7 @@ async function deleteItemFromData(table, id) { if (!workbox) { let workbox = new self.WorkboxSW(); + console.log('SW-06 3'); } if (workbox) { @@ -103,24 +109,28 @@ if (workbox) { workbox.routing.registerRoute( new RegExp(cfgenv.serverweb + '/todos/'), function (args) { + console.log('registerRoute!') return fetch(args.event.request, args.event.headers) .then(function (res) { - // console.log('1° ******* registerRoute fetch: ', args.event) + console.log('1° ******* [[[ SERVICE-WORKER ]]] registerRoute fetch: ', args.event) // LOAD FROM SERVER , AND SAVE INTO INDEXEDDB - var clonedRes = res.clone(); - clearAllData('todos') - .then(function () { - return clonedRes.json(); - }) - .then(function (data) { - if (data.todos) { - console.log('Records TODOS Received from Server [', data.todos.length, 'record]', data.todos) - for (let key in data.todos) { - writeData('todos', data.todos[key]) + console.log('res.status', res.status) + if (res.status === 200) { + var clonedRes = res.clone(); + clearAllData('todos') + .then(function () { + return clonedRes.json(); + }) + .then(function (data) { + if (data.todos) { + console.log('Records TODOS Received from Server [', data.todos.length, 'record]', data.todos) + for (let key in data.todos) { + writeData('todos', data.todos[key]) + } } - } - }); - return res + }); + return res + } }) } ); diff --git a/src/App.ts b/src/App.ts index 3104915..3fa8cf6 100644 --- a/src/App.ts +++ b/src/App.ts @@ -9,7 +9,7 @@ import $ from 'jquery' import Header from './components/Header.vue' import globalroutines from './globalroutines/index' -import { GlobalStore } from "./store/Modules" +import { GlobalStore } from './store/Modules' @@ -34,7 +34,7 @@ export default class App extends Vue { } if (process.env.PROD) { console.info('SESSIONE IN PRODUZIONE!') - console.info(process.env) + // console.info(process.env) } UserStore.actions.autologin() diff --git a/src/components/Header.vue b/src/components/Header.vue index e859de8..7d2557b 100644 --- a/src/components/Header.vue +++ b/src/components/Header.vue @@ -29,7 +29,7 @@ {{$t('msg.myAppName')}} -
{{$t('msg.myDescriz')}}
+
{{$t('msg.myDescriz')}} {{ getAppVersion() }}
@@ -96,6 +96,10 @@ localStorage.setItem(rescodes.localStorage.leftDrawerOpen, value.toString()) } + getAppVersion() { + // return "AA" + return "[" + process.env.APP_VERSION + "]" + } get lang() { return this.$q.i18n.lang } diff --git a/src/components/todos/todo/todo.ts b/src/components/todos/todo/todo.ts index 3b9e4b9..cc35885 100644 --- a/src/components/todos/todo/todo.ts +++ b/src/components/todos/todo/todo.ts @@ -20,6 +20,7 @@ import VueIdb from 'vue-idb' import globalroutines from '../../../globalroutines/index' import $ from 'jquery' +import Api from "@api" @Component({ @@ -76,8 +77,11 @@ export default class Todo extends Vue { } - @Watch('todos_changed', { immediate: true }) + @Watch('todos_changed', { immediate: true, deep: true }) changetodos_changed(value: string, oldValue: string) { + + this.$q.notify('Changed...') + // console.log('Todos.state.todos_changed CHANGED!', value, oldValue) this.updatetable(true) } @@ -86,9 +90,9 @@ export default class Todo extends Vue { reload_fromServer_changed(value: string, oldValue: string) { console.log('reload_fromServer_changed!', value, oldValue) // if (value) { - Todos.actions.dbLoadTodo(false) + Todos.actions.dbLoadTodo(false) - Todos.actions.updateArrayInMemory() + Todos.actions.updateArrayInMemory() // } } @@ -343,7 +347,7 @@ export default class Todo extends Vue { checkUpdate_everytime() { this.polling = setInterval(() => { this.checkUpdate() - }, 10000) + }, 10000) } copy(o) { @@ -470,8 +474,13 @@ export default class Todo extends Vue { cmdSw = rescodes.DB.CMD_SYNC_TODOS } + if (process.env.DEV) { + console.log('serviceWorker ', ('serviceWorker' in navigator) ? 'PRESENT!' : 'DOESN\'T EXIST!') + console.log('SyncManager ', ('SyncManager' in window) ? 'PRESENT!' : 'DOESN\'T EXIST!') + } + const mythis = this - if (('serviceWorker' in navigator && 'SyncManager' in window)) { + if ('serviceWorker' in navigator) { await navigator.serviceWorker.ready .then(function (sw) { // _id: new Date().toISOString(), @@ -482,18 +491,24 @@ export default class Todo extends Vue { globalroutines(mythis, 'write', table, item, id) .then(function (id) { // console.log('id', id) - const sep = '|' - let multiparams = cmdSw + sep + table + sep + method + sep + UserStore.state.idToken + sep + UserStore.state.lang - console.log(' SENDING... sw.sync.register', multiparams) - let mymsgkey = { - _id: multiparams, - value: multiparams + }) + const sep = '|' + + let multiparams = cmdSw + sep + table + sep + method + sep + UserStore.state.idToken + sep + UserStore.state.lang + let mymsgkey = { + _id: multiparams, + value: multiparams + } + globalroutines(mythis, 'write', 'swmsg', mymsgkey, multiparams) + .then(ris => { + if ('SyncManager' in window) { + console.log(' SENDING... sw.sync.register', multiparams) + return sw.sync.register(multiparams) + } else { + // #Todo ++ Alternative 2 to SyncManager + Api.syncAlternative(multiparams) } - globalroutines(mythis, 'write', 'swmsg', mymsgkey, multiparams) - .then(ris => { - return sw.sync.register(multiparams) - }) }) .then(function () { @@ -822,6 +837,7 @@ export default class Todo extends Vue { objtodo.descr = 'PROVA' objtodo.category = this.getCategory() Todos.state.todos.push(objtodo) + Todos.mutations.setTodos_changed() console.log('Todos.state.todos', Todos.state.todos) } @@ -831,7 +847,7 @@ export default class Todo extends Vue { console.log('Todos.state.todos', Todos.state.todos) } - checkUpdate () { + checkUpdate() { Todos.actions.waitAndcheckPendingMsg() } diff --git a/src/components/todos/todo/todo.vue b/src/components/todos/todo/todo.vue index e82900c..eb221c3 100644 --- a/src/components/todos/todo/todo.vue +++ b/src/components/todos/todo/todo.vue @@ -35,8 +35,8 @@ :after="[{icon: 'arrow_forward', content: true, handler () {}}]" v-on:keyup.enter="insertTodo"/> - - + +
diff --git a/src/globalroutines/indexdb.js b/src/globalroutines/indexdb.js index d4b77a4..00e7d3b 100644 --- a/src/globalroutines/indexdb.js +++ b/src/globalroutines/indexdb.js @@ -34,7 +34,7 @@ async function readfromIndexDbToStateTodos(context, table) { // console.log('&&&&&&& readfromIndexDbToStateTodos OK: Num RECORD: ', records.length) if (table === 'todos') { Todos.state.todos = [...records] - Todos.state.todos_changed++ + Todos.mutations.setTodos_changed() // console.log('Todos.state.todos_changed:', Todos.state.todos_changed) // setTimeout(testfunc2, 3000) } @@ -52,7 +52,7 @@ function consolelogpao(str, str2 = '', str3 = '') { function testfunc2 () { consolelogpao('testfunc2') Todos.mutations.setTodos_changed() - Todos.mutations.setTestpao(Todos.state.todos_changed) + consolelogpao('testfunc2: Todos.state.todos_changed:', Todos.state.todos_changed) } diff --git a/src/js/globalenv.js b/src/js/globalenv.js deleted file mode 100644 index 745dd1a..0000000 --- a/src/js/globalenv.js +++ /dev/null @@ -1,24 +0,0 @@ - -// importScripts('/statics/js/immortal-db.min.js'); - -// const cfgenv = { -// website: 'http://localhost:8080', -// serverweb: 'http://localhost:3000', -// dbname: 'mydb3', -// dbversion: 10, -// } - -/* -async function clearAllDataImmortal(table) { - console.log('clearAllDataImmortal', table) - const db = ImmortalDB.ImmortalDB - await db.remove(table) -} - -async function writeDataImmortal(table, datavalue) { - console.log('writeDataImmortal', table, datavalue) - const db = ImmortalDB.ImmortalDB - await db.set(table, datavalue) -} - -*/ diff --git a/src/js/utility.js b/src/js/utility.js index 79ceb41..c629c4e 100644 --- a/src/js/utility.js +++ b/src/js/utility.js @@ -1,60 +1,3 @@ -import objectId from "./objectId"; - -console.log('utility.js') - -// var dbPromise = idb.open('mydb1', 1, function (db) { -// console.log('OPEN MYDB') -// if (!db.objectStoreNames.contains('todos')) { -// db.createObjectStore('todos', { keyPath: '_id' }); -// } -// if (!db.objectStoreNames.contains('config')) { -// db.createObjectStore('config', { keyPath: '_id' }); -// } -// }); - - -// function readAllData(st) { -// console.log('readAllData', st); -// return dbPromise -// .then(function (db) { -// var tx = db.transaction(st, 'readonly'); -// var store = tx.objectStore(st); -// return store.getAll(); -// }); -// } - -// function clearAllData(st) { -// console.log('clearAllData', st); -// return dbPromise -// .then(function (db) { -// var tx = db.transaction(st, 'readwrite'); -// var store = tx.objectStore(st); -// store.clear(); -// return tx.complete; -// }); -// } - -// function deleteItemFromData(st, id) { -// console.log('deleteItemFromData', st, 'ID:', id); -// dbPromise -// .then(function (db) { -// -// var tx = db.transaction(st, 'readwrite'); -// var store = tx.objectStore(st); -// -// try { -// store.delete(id); -// return tx.complete; -// } catch (e) { -// return false; -// } -// }) -// .then(function (res) { -// if (res) -// console.log('Item deleted!'); -// }); -// } - function urlBase64ToUint8Array(base64String) { var padding = '='.repeat((4 - base64String.length % 4) % 4); var base64 = (base64String + padding) diff --git a/src/model/UserStore.ts b/src/model/UserStore.ts index d859a11..94c7c12 100644 --- a/src/model/UserStore.ts +++ b/src/model/UserStore.ts @@ -21,7 +21,7 @@ export interface IUserState { tokens?: IToken[] - verifiedEmail?: boolean + verified_email?: boolean categorySel?: string tokenforgot?: string diff --git a/src/statics/i18n.js b/src/statics/i18n.js index 19c9d03..129ff64 100644 --- a/src/statics/i18n.js +++ b/src/statics/i18n.js @@ -123,6 +123,130 @@ const messages = { subscribed: 'Ora potrai ricevere i messaggi e le notifiche.' } }, + es: { + dialog: { + ok: 'Vale', + yes: 'Sí', + no: 'No', + delete: 'Borrar', + cancel: 'Cancelar', + msg: { + titledeleteTask: 'Borrar Tarea', + deleteTask: 'Quieres borrar este tarea?' + } + }, + comp:{ + Conta: "Conta", + }, + msg: { + hello: 'Buenos Días', + myAppName: 'FreePlanet', + myDescriz: 'La primera App Libera' + }, + pages: { + home: 'Principal', + SignUp: 'Registrarte', + SignIn: 'Login', + vreg: 'Verifica Reg', + Test: 'Test', + Category: 'Categorías', + Todo: 'Tareas', + personal: 'Personal', + work: 'Trabajo', + shopping: 'Compras', + }, + components: { + authentication:{ + login: { + facebook: 'Facebook' + }, + email_verification: { + title: 'Crea una cuenta', + introduce_email: 'ingrese su dirección de correo electrónico', + email: 'Email', + invalid_email: 'Tu correo electrónico no es válido', + verify_email: 'Revisa tu email', + go_login: 'Vuelve al Login', + incorrect_input: 'Entrada correcta.', + link_sent: 'Para confirmar el registro, lea su buzón y haga clic en "Verificar correo electrónico".\n' + 'Si no lo encuentras, busca en la carpeta Spam.' + } + } + }, + fetch: { + errore_generico: 'Error genérico', + errore_server: 'No se puede acceder al Servidor. Inténtalo de nuevo, Gracias', + }, + user: { + notregistered: 'Debe registrarse en el servicio antes de poder almacenar los datos' + }, + reg: { + incorso: 'Registro en curso...', + richiesto: 'Campo requerido', + email: 'Email', + username : 'Nombre usuario', + password: 'contraseña', + repeatPassword: 'Repetir contraseña', + terms: "Acepto los términos y condiciones", + submit: "Registrarse", + title_verif_reg: "Verifica registro", + verificato: "Verificado", + non_verificato: "No Verificado", + forgetpassword:"¿Olvidaste tu contraseña?", + err: { + required: 'se requiere', + email: 'Debe ser una email válida.', + errore_generico: 'Por favor, rellene los campos correctamente', + atleast: 'debe ser al menos largo', + complexity: 'debe contener al menos 1 minúscula, 1 mayúscula y 1 dígito', + notmore: 'no tiene que ser más largo que', + char: 'caracteres', + terms: 'Debes aceptar las condiciones, para continuar..', + duplicate_email: 'La email ya ha sido registrada', + duplicate_username: 'El nombre de usuario ya ha sido utilizado', + sameaspassword: 'Las contraseñas deben ser idénticas', + } + }, + login:{ + incorso: 'Login en curso', + enter: 'Login', + errato: "Nombre de usuario o contraseña incorrectos. inténtelo de nuevo", + completato: 'Login realizado!', + }, + reset: { + title_reset_pwd: "Restablece tu contraseña", + send_reset_pwd: 'Enviar restablecer contraseña', + incorso: 'Solicitar nueva Email...', + email_sent:'Email enviada', + check_email: 'Revise su correo electrónico, recibirá un mensaje con un enlace para restablecer su contraseña. Este enlace, por razones de seguridad, expirará después de 4 horas.', + title_update_pwd: 'Actualiza tu contraseña', + update_password: 'Actualizar contraseña', + }, + logout:{ + uscito: 'Estás desconectado', + }, + errors: { + graphql: { + undefined: 'no definido' + } + }, + todo: { + titleprioritymenu: 'Prioridad:', + insert: 'Ingrese una nueva Tarea', + edit: 'Descripción Tarea:', + completed: 'Completados', + usernotdefined: 'Atención, debes iniciar sesión para agregar una Tarea' + }, + notification : { + ask: 'Activar notificaciones', + waitingconfirm: 'Confirmar la solicitud de notificación.', + confirmed: 'Notificaciones activadas!', + denied: 'Notificaciones deshabilitadas! Ten cuidado, así no verás llegar los mensajes. Rehabilítalos para verlos.', + titlegranted: 'Notificaciones permitidas habilitadas!', + titledenied: 'Notificaciones permitidas deshabilitadas!', + title_subscribed: 'Suscripción a FreePlanet.app!', + subscribed: 'Ahora puedes recibir mensajes y notificaciones.' + } + }, enUk: { dialog: { ok: 'Ok', diff --git a/src/store/Api/index.ts b/src/store/Api/index.ts index 4998894..d8bec7f 100644 --- a/src/store/Api/index.ts +++ b/src/store/Api/index.ts @@ -10,6 +10,7 @@ import Paths from '@paths' import { rescodes } from '@src/store/Modules/rescodes' import { UserStore } from '@modules' +import globalroutines from './../../globalroutines/index' // const algoliaApi = new AlgoliaSearch() @@ -52,8 +53,11 @@ export namespace ApiTool { sendRequest(url, lang, mytok, method, mydata) .then(resreceived => { ricevuto = true - let res = resreceived - console.log('SendReq RES=', res) + let res = resreceived.clone() + if (process.env.DEV) { + console.log('SendReq RES [', res.status, ']', res) + } + let x_auth_token = '' if (res.status === 200) { try { @@ -105,6 +109,75 @@ export namespace ApiTool { }) } + export async function syncAlternative(mystrparam) { + console.log('[ALTERNATIVE Background syncing', mystrparam) + + let multiparams = mystrparam.split('|') + if (multiparams) { + if (multiparams.length > 3) { + let cmd = multiparams[0] + let table = multiparams[1] + let method = multiparams[2] + let token = multiparams[3] + // let lang = multiparams[3] + + if (cmd === 'sync-todos') { + console.log('[Alternative] Syncing', cmd, table, method) + + const headers = new Headers() + headers.append('content-Type', 'application/json') + headers.append('Accept', 'application/json') + headers.append('x-auth', token) + + console.log('A1) INIZIO.............................................................') + + await globalroutines(null, 'readall', table, null) + .then(function (alldata) { + const myrecs = [...alldata] + console.log('----------------------- LEGGO QUALCOSA ') + if (myrecs) { + for (let rec of myrecs) { + // console.log('syncing', table, '', rec.descr) + let link = process.env.MONGODB_HOST + '/todos' + + if (method !== 'POST') + link += '/' + rec._id + + console.log(' [Alternative] ++++++++++++++++++ SYNCING !!!! ', rec.descr, table, 'FETCH: ', method, link, 'data:') + + // Insert/Delete/Update table to the server + fetch(link, { + method: method, + headers: headers, + mode: 'cors', // 'no-cors', + body: JSON.stringify(rec) + }) + .then(function (resData) { + // console.log('Result CALL ', method, ' OK? =', resData.ok); + + // Anyway Delete this, otherwise in some cases will return error, but it's not a problem. + // for example if I change a record and then I deleted ... + // if (resData.ok) { + // deleteItemFromData(table, rec._id); + globalroutines(null, 'delete', table, null, rec._id) + + console.log('DELETE: ', mystrparam) + // deleteItemFromData('swmsg', mystrparam) + globalroutines(null, 'delete', 'swmsg', null, mystrparam) + + }) + .catch(function (err) { + console.log(' [Alternative] !!!!!!!!!!!!!!! Error while sending data', err) + }) + } + } + }) + console.log(' [Alternative] A2) ?????????????????????????? ESCO DAL LOOP !!!!!!!!! err=') + } + } + } + } + } export default ApiTool diff --git a/src/store/Modules/Todos.ts b/src/store/Modules/Todos.ts index 97ec034..55ac0ee 100644 --- a/src/store/Modules/Todos.ts +++ b/src/store/Modules/Todos.ts @@ -3,8 +3,9 @@ import { storeBuilder } from './Store/Store' import Api from '@api' import { rescodes } from './rescodes' -import { Todos, UserStore } from '@store' +import { GlobalStore, Todos, UserStore } from '@store' import globalroutines from './../../globalroutines/index' +import { Mutation } from "vuex-module-decorators" const state: ITodosState = { @@ -40,6 +41,8 @@ namespace Mutations { function setTodos_changed(state: ITodosState) { state.todos_changed++ + mutations.setTestpao('Cambiato : ' + String(state.todos_changed)) + console.log('******************************* state.todos_changed', state.todos_changed) } export const mutations = { @@ -67,14 +70,13 @@ namespace Actions { // If something in the call of Service Worker went wrong (Network or Server Down), then retry ! async function sendSwMsgIfAvailable() { - - console.log(' -------- sendSwMsgIfAvailable') - let something = false - let count = await checkPendingMsg(null) - if (count > 0) { - if (('serviceWorker' in navigator && 'SyncManager' in window)) { + if ('serviceWorker' in navigator) { + console.log(' -------- sendSwMsgIfAvailable') + + let count = await checkPendingMsg(null) + if (count > 0) { return navigator.serviceWorker.ready .then(function (sw) { @@ -90,14 +92,21 @@ namespace Actions { something = true for (let rec of arr_recmsg) { console.log(' .... sw.sync.register ( ', rec._id) - sw.sync.register(rec._id) + if ('SyncManager' in window) { + sw.sync.register(rec._id) + } else { + // #Todo ++ Alternative to SyncManager + Api.syncAlternative(rec._id) + } } + return something } - return something }) + }) } } + return something } @@ -170,12 +179,12 @@ namespace Actions { state.networkDataReceived = false let ris = await Api.SendReq(call, UserStore.state.lang, token, 'GET', null) - .then(({resData, body}) => { + .then(({ resData, body }) => { state.networkDataReceived = true // console.log('******* UPDATE TODOS.STATE.TODOS !:', resData.todos) state.todos = [...body.todos] - Todos.state.todos_changed++ + Todos.mutations.setTodos_changed() console.log('state.todos', state.todos, 'checkPending', checkPending) @@ -222,7 +231,7 @@ namespace Actions { async function testfunc() { while (true) { consolelogpao('testfunc') - Todos.state.todos_changed++ + Todos.mutations.setTodos_changed() // console.log('Todos.state.todos_changed:', Todos.state.todos_changed) await aspettansec(5000) } @@ -241,6 +250,7 @@ namespace Actions { console.log('ITEM', newItem) if (method === 'POST') { state.todos.push(newItem) + Todos.mutations.setTodos_changed() // } else if (method === 'PATCH') { // state.todos.map(item => { // if (item._id === newItem._id) { @@ -255,22 +265,20 @@ namespace Actions { async function dbInsertSaveTodo(context, itemtodo: ITodo, method) { console.log('dbInsertSaveTodo', itemtodo, method) - let call = process.env.MONGODB_HOST + '/todos/' + itemtodo._id + let call = process.env.MONGODB_HOST + '/todos' + + if (method !== 'POST') + call += '/' + itemtodo._id const token = UserStore.state.idToken let res = await Api.SendReq(call, UserStore.state.lang, token, method, itemtodo) - .then(({res, body}) => { - console.log('RESDATA =', body) - if (body.newItem) { - const newId = body.newItem._id - - // if (method === 'PATCH') { - // newItem = newItem.todo - // } + .then(({ res, newItem }) => { + console.log('dbInsertSaveTodo RIS =', newItem) + if (newItem) { // Update ID on local - UpdateNewIdFromDB(itemtodo, body.newItem, method) + UpdateNewIdFromDB(itemtodo, newItem, method) } }) .catch((error) => { @@ -288,10 +296,14 @@ namespace Actions { const token = UserStore.state.idToken let res = await Api.SendReq(call, UserStore.state.lang, token, 'DELETE', item) - .then(function ({res, body}) { + .then(function ({ res, itemris }) { - // Delete Item in to Array - state.todos.splice(state.todos.indexOf(item), 1) + if (res.status === 200) { + // Delete Item in to Array + state.todos.splice(state.todos.indexOf(item), 1) + + Todos.mutations.setTodos_changed() + } return rescodes.OK }) diff --git a/src/store/Modules/UserStore.ts b/src/store/Modules/UserStore.ts index 8181863..a9794c7 100644 --- a/src/store/Modules/UserStore.ts +++ b/src/store/Modules/UserStore.ts @@ -24,10 +24,10 @@ const state: IUserState = { repeatPassword: '', idToken: '', tokens: [], - verifiedEmail: false, + verified_email: false, categorySel: 'personal', servercode: 0, - x_auth_token: '', + x_auth_token: '' } @@ -76,7 +76,7 @@ namespace Getters { }, get getServerCode() { return getServerCode() - }, + } } @@ -88,7 +88,7 @@ namespace Mutations { state.userId = data.userId state.username = data.username state.idToken = data.idToken - state.verifiedEmail = data.verifiedEmail + state.verified_email = data.verified_email state.category = data.categorySel // @ts-ignore state.tokens = [ @@ -130,7 +130,7 @@ namespace Mutations { state.username = '' state.tokens = [] state.idToken = '' - state.verifiedEmail = false + state.verified_email = false state.categorySel = 'personal' } @@ -299,19 +299,13 @@ namespace Actions { let x_auth_token: string = '' return Api.SendReq(call, state.lang, Getters.getters.tok, 'POST', usertosend) - .then(({ res, body }) => { + .then(({ res, newuser }) => { myres = res - if (process.env.DEV) { - console.log('RISULTATO ') - console.log('STATUS ' + myres.status + ' ' + (myres.statusText)) - console.log('BODY:') - console.log(body) - } Mutations.mutations.setServerCode(myres.status) if (myres.status === 200) { - let userId = body.userId + let userId = newuser.userId let username = authData.username if (process.env.DEV) { console.log('USERNAME = ' + username) @@ -322,7 +316,7 @@ namespace Actions { userId: userId, username: username, idToken: x_auth_token, - verifiedEmail: false + verified_email: false }) const now = new Date() @@ -338,16 +332,8 @@ namespace Actions { // dispatch('setLogoutTimer', myres.data.expiresIn); return rescodes.OK - } else if (myres.status === 404) { - if (process.env.DEV) { - console.log('CODE = ' + body.code) - } - return body.code } else { - if (process.env.DEV) { - console.log('CODE = ' + body.code) - } - return body.code + return rescodes.ERR_GENERICO } }) .catch((error) => { @@ -380,14 +366,7 @@ namespace Actions { return await Api.SendReq(call, state.lang, Getters.getters.tok, 'POST', usertosend) .then(({ res, body }) => { myres = res - if (process.env.DEV) { - console.log('RISULTATO ') - console.log('STATUS ' + res.status + ' ' + (res.statusText)) - console.log('BODY:') - console.log(body) - } - - if (body.code === serv_constants.RIS_CODE_LOGIN_ERR) { + if (res.code === serv_constants.RIS_CODE_LOGIN_ERR) { Mutations.mutations.setServerCode(body.code) return body.code } @@ -395,9 +374,10 @@ namespace Actions { Mutations.mutations.setServerCode(myres.status) if (myres.status === 200) { - let userId = body.userId + let myuser: IUserState = body.usertosend + let userId = myuser.userId let username = authData.username - let verifiedEmail = body.verified_email === 'true' || body.verified_email === true + let verifiedEmail = myuser.verified_email === true if (process.env.DEV) { console.log('USERNAME = ' + username) console.log('IDUSER= ' + userId) @@ -405,7 +385,7 @@ namespace Actions { userId: userId, username: username, idToken: state.x_auth_token, - verifiedEmail: verifiedEmail + verified_email: verifiedEmail }) } @@ -520,7 +500,7 @@ namespace Actions { userId: userId, username: username, idToken: token, - verifiedEmail: verifiedEmail + verified_email: verifiedEmail }) setGlobal() diff --git a/src/utils/config.ts b/src/utils/config.ts index 6c669bc..ed2b339 100644 --- a/src/utils/config.ts +++ b/src/utils/config.ts @@ -6,13 +6,17 @@ switch (process.env.NODE_ENV) { case 'test': path = `${__dirname}/../../.env.test` break - case 'production': - path = `${__dirname}/../../.env.production` + case 'development': + path = `${__dirname}/../../.env.development` break default: - path = `${__dirname}/../../.env.development` + path = `${__dirname}/../../.env.production` } dotenv.config({ path }) +console.log('path', path) +console.log('process.env.APP_ID', process.env.APP_ID) + + export const APP_ID = process.env.APP_ID export const LOG_LEVEL = process.env.LOG_LEVEL