- risolto problema spazi vuoti in cima alla app

- risolto problema sulle card di telegram, immagini non alte uguali e non si vedono bene...
This commit is contained in:
Surya Paolo
2025-11-02 21:16:41 +01:00
parent d179581b23
commit 7e156ca820
79 changed files with 1437 additions and 3592997 deletions

4
.env
View File

@@ -1,6 +1,6 @@
VITE_APP_VERSION="1.2.75" VITE_APP_VERSION="1.2.76"
VITE_LANG_DEFAULT="it" VITE_LANG_DEFAULT="it"
VITE_PAO_APP_ID="KKPPAA5KJK435J3KSS9F9D8S9F8SD98F9SDF" VITE_PAO_APP_ID="KKPPAA5KJK435J3KSS9F9D8S9F8SD98F9SDF"
VITE_SERVICE_WORKER_FILE="sw-1.2.75.js" VITE_SERVICE_WORKER_FILE="sw-1.2.76.js"
VITE_PROJECT_ID_MAIN="5cc0a13fe5c9d156728f400a" VITE_PROJECT_ID_MAIN="5cc0a13fe5c9d156728f400a"
VITE_VUE_ROUTER_MODE="history" VITE_VUE_ROUTER_MODE="history"

View File

@@ -1,12 +1,14 @@
VITE_APP_ID="18" VITE_APP_ID="13"
VITE_APP_URL="https://localhost" VITE_APP_URL="https://localhost"
VITE_MONGODB_HOST="https://localhost:3000" VITE_MONGODB_HOST="https://localhost:3000"
VITE_LOGO_REG='gruppomacro-logo-full.png' DEBUG_VITE_APP_URL="https://192.168.8.182"
DEBUG_VITE_MONGODB_HOST="https://192.168.8.182:3000"
VITE_LOGO_REG='riso-logo-full.png'
VITE_PUBLICKEY_PUSH='BDncvMiUZmjaCG2Kr1V9N0_33hOG-AuNSbHSvL24y2dzBiUjAxKm02emx5SeJvz2IGmtRf6YqCgopeQwCwUmZw8' VITE_PUBLICKEY_PUSH='BDncvMiUZmjaCG2Kr1V9N0_33hOG-AuNSbHSvL24y2dzBiUjAxKm02emx5SeJvz2IGmtRf6YqCgopeQwCwUmZw8'
VITE_DEBUG="1" VITE_DEBUG="1"
VITE_VUE_APP_ISTEST=0 VITE_VUE_APP_ISTEST=0
VITE_VUE_APP_INLOCALE=1 VITE_VUE_APP_INLOCALE=1
DIRECTORY_LOCAL="newfreeplanet" DIRECTORY_LOCAL="myprojplanet_vite"
DIRECTORY_SERVER="freeplanet_serverside" DIRECTORY_SERVER="freeplanet_serverside"
SERVERDIR_WEBSITE="" SERVERDIR_WEBSITE=""
SERVERPW_WEBSITE="" SERVERPW_WEBSITE=""

View File

@@ -1,13 +1,11 @@
VITE_APP_ID="18" VITE_APP_ID="13"
VITE_APP_URL="https://gruppomacro.app" VITE_APP_URL="https://test.riso.app"
VITE_MONGODB_HOST="https://api.gruppomacro.app" VITE_MONGODB_HOST="https://testapi.riso.app"
VITE_LOGO_REG='gruppomacro-logo-full.png' VITE_LOGO_REG="riso-logo-full.png"
VITE_PUBLICKEY_PUSH="BJgo8XR_upbnbMLWgCAUELo6DK7dRXffYAnFOxbaMMz5favBgcQBKT-eISqouO-jRad4Sw8l5nd2wCF6KorGiTc" VITE_PUBLICKEY_PUSH="BGXRf1TgcqocqD6J7qnRgCG7AvM2lxAoW7peb7UEzB4SxBb6DxGRdJ0UvD9ewnrB9KrSrh0-aDCODXBm7sZ1DDs"
VITE_DEBUG="0" VITE_DEBUG="1"
VITE_VUE_APP_ISTEST="0" VITE_VUE_APP_ISTEST="1"
DIRECTORY_LOCAL="myprojplanet_vite" DIRECTORY_LOCAL="myprojplanet_vite"
DIRECTORY_SERVER="/var/www/nodejs_piuchebuono_server" DIRECTORY_SERVER="/var/www/nodejs_test.riso_server"
SERVERDIR_WEBSITE="/var/www/gruppomacro.app" SERVERDIR_WEBSITE="/var/www/test.riso.app"
SERVERPW_WEBSITE="pwdadmin@1AOK" SERVERPW_WEBSITE="pwdadmin@1AOK"
PORT_SPA="8089"
PORT_PWA="8099"

View File

@@ -10,7 +10,7 @@
<meta name="description" content="<%= productDescription %>"> <meta name="description" content="<%= productDescription %>">
<meta name="format-detection" content="telephone=no"> <meta name="format-detection" content="telephone=no">
<meta name="msapplication-tap-highlight" content="no"> <meta name="msapplication-tap-highlight" content="no">
<meta name="version" content="1.2.75"> <meta name="version" content="1.2.76">
<meta name="viewport" <meta name="viewport"
content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width<% if (ctx.mode.cordova || ctx.mode.capacitor) { %>, viewport-fit=cover<% } %>"> content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width<% if (ctx.mode.cordova || ctx.mode.capacitor) { %>, viewport-fit=cover<% } %>">

View File

@@ -1,28 +1,28 @@
{ {
"name": "gruppomacro", "name": "riso",
"version": "1.2.75", "version": "1.2.76",
"productName": "Gruppo Macro", "productName": "Riso 💚 - Rete Italiana Scambi Orizzontali",
"description": "Il Gruppo Editoriale Macro, attivo dal 1987, è leader europeo nella pubblicazione di libri per il benessere e la consapevolezza. Con oltre 1.500 titoli, promuove una visione armonica del mondo, offrendo opere di autori internazionali e italiani come Gregg Braden, Bruce Lipton, Joe Dispenza, Louise Hay, Eckhart Tolle e molti altri. Scopri un'editoria che abbraccia il corpo, la mente, lo spirito e l'ecologia.", "description": "Progetto RISO (Rete Italiana Scambi Orizzontali) promuove una rete di comunità locali che favoriscono scambi di beni, servizi e ospitalità. Con l'App RISO, sviluppata per facilitare il baratto, il dono e l'uso di monete alternative come i RIS, il progetto crea legami autentici basati sulla fiducia e sostenibilità. Partecipa agli scambi e costruisci una comunità più consapevole e autosufficiente.",
"author": "Surya", "author": "Surya",
"private": true, "private": true,
"keywords": [], "keywords": [],
"license": "MIT", "license": "MIT",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "PORT=8089 APP_VERSION='1.2.75' quasar dev", "dev": "APP_VERSION='1.2.76' PORT=8084 quasar dev",
"dev_noCheck": "SKIP_TSC=true quasar dev", "dev_noCheck": "SKIP_TSC=true quasar dev",
"build": "quasar build", "build": "quasar build",
"buildpwa": "NODE_ENV=production APP_VERSION='1.2.75' quasar build -m pwa", "buildpwa": "NODE_ENV=production APP_VERSION='1.2.76' quasar build -m pwa",
"buildpwatest": "NODE_ENV=production APP_VERSION='1.2.75' quasar build -m pwa", "buildpwatest": "NODE_ENV=production APP_VERSION='1.2.76' quasar build -m pwa",
"type-check": "vue-tsc --noEmit", "type-check": "vue-tsc --noEmit",
"type-check:watch": "vue-tsc --noEmit --watch", "type-check:watch": "vue-tsc --noEmit --watch",
"buildspa": "APP_VERSION='1.2.75' quasar build -m spa", "buildspa": "quasar build -m spa",
"lint": "eslint -c ./eslint.config.js \"./src*/**/*.{ts,js,cjs,mjs,vue}\"", "lint": "eslint -c ./eslint.config.js \"./src*/**/*.{ts,js,cjs,mjs,vue}\"",
"lintfile": "eslint --ext .js,.ts,.vue --ignore-path .gitignore ./ > file.out.txt", "lintfile": "eslint --ext .js,.ts,.vue --ignore-path .gitignore ./ > file.out.txt",
"lintfileNoJS": "eslint --ext .ts,.vue --ignore-path .gitignore ./ > file.out.txt", "lintfileNoJS": "eslint --ext .ts,.vue --ignore-path .gitignore ./ > file.out.txt",
"fix": "eslint -c ./eslint.config.js \"./src*/**/*.{ts,js,cjs,mjs,vue}\" --ignore-pattern .gitignore ./ --fix > file.out.txt", "fix": "eslint -c ./eslint.config.js \"./src*/**/*.{ts,js,cjs,mjs,vue}\" --ignore-pattern .gitignore ./ --fix > file.out.txt",
"pwa": "NODE_ENV=development PORT=8099 APP_VERSION='1.2.75' quasar dev -m pwa", "pwa": "NODE_ENV=development PORT=8094 APP_VERSION='1.2.76' quasar dev -m pwa",
"spa": "NODE_ENV=development PORT=8089 APP_VERSION='1.2.75' quasar dev", "spa": "NODE_ENV=development PORT=8084 APP_VERSION='1.2.76' quasar dev",
"debug": "quasar dev --mode debug", "debug": "quasar dev --mode debug",
"test": "echo \"No test specified\" && exit 0", "test": "echo \"No test specified\" && exit 0",
"generate-sw": "workbox generateSW workbox-config.js", "generate-sw": "workbox generateSW workbox-config.js",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 158 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 81 KiB

BIN
public/images/layers-2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
public/images/layers.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 696 B

BIN
public/images/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 424 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 185 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 424 KiB

BIN
public/images/riso_home.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 279 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 258 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

View File

@@ -1,2 +0,0 @@
!function(){'use strict';try{self['workbox:sw:6.1.0']&&_()}catch(t){}const t={backgroundSync:'background-sync',broadcastUpdate:'broadcast-update',cacheableResponse:'cacheable-response',core:'core',expiration:'expiration',googleAnalytics:'offline-ga',navigationPreload:'navigation-preload',precaching:'precaching',rangeRequests:'range-requests',routing:'routing',strategies:'strategies',streams:'streams',recipes:'recipes'};self.workbox=new class{constructor(){return this.v={},this.Pt={debug:'localhost'===self.location.hostname,modulePathPrefix:null,modulePathCb:null},this.$t=this.Pt.debug?'dev':'prod',this.jt=!1,new Proxy(this,{get(e,s){if(e[s])return e[s];const o=t[s];return o&&e.loadModule('workbox-'+o),e[s]}})}setConfig(t={}){if(this.jt)throw new Error('Config must be set before accessing workbox.* modules');Object.assign(this.Pt,t),this.$t=this.Pt.debug?'dev':'prod'}loadModule(t){const e=this.St(t);try{importScripts(e),this.jt=!0}catch(s){throw console.error(`Unable to import module '${t}' from '${e}'.`),s}}St(t){if(this.Pt.modulePathCb)return this.Pt.modulePathCb(t,this.Pt.debug);let e=['https://storage.googleapis.com/workbox-cdn/releases/6.1.0'];const s=`${t}.${this.$t}.js`,o=this.Pt.modulePathPrefix;return o&&(e=o.split('/'),''===e[e.length-1]&&e.splice(e.length-1,1)),e.push(s),e.join('/')}}}();
//# sourceMappingURL=workbox-sw.js.map

View File

@@ -1,2 +0,0 @@
!function(){"use strict";try{self["workbox:sw:5.1.4"]&&_()}catch(t){}const t={backgroundSync:"background-sync",broadcastUpdate:"broadcast-update",cacheableResponse:"cacheable-response",core:"core",expiration:"expiration",googleAnalytics:"offline-ga",navigationPreload:"navigation-preload",precaching:"precaching",rangeRequests:"range-requests",routing:"routing",strategies:"strategies",streams:"streams"};self.workbox=new class{constructor(){return this.v={},this.t={debug:"localhost"===self.location.hostname,modulePathPrefix:null,modulePathCb:null},this.s=this.t.debug?"dev":"prod",this.o=!1,new Proxy(this,{get(e,s){if(e[s])return e[s];const o=t[s];return o&&e.loadModule("workbox-"+o),e[s]}})}setConfig(t={}){if(this.o)throw new Error("Config must be set before accessing workbox.* modules");Object.assign(this.t,t),this.s=this.t.debug?"dev":"prod"}loadModule(t){const e=this.i(t);try{importScripts(e),this.o=!0}catch(s){throw console.error(`Unable to import module '${t}' from '${e}'.`),s}}i(t){if(this.t.modulePathCb)return this.t.modulePathCb(t,this.t.debug);let e=["https://storage.googleapis.com/workbox-cdn/releases/5.1.4"];const s=`${t}.${this.s}.js`,o=this.t.modulePathPrefix;return o&&(e=o.split("/"),""===e[e.length-1]&&e.splice(e.length-1,1)),e.push(s),e.join("/")}}}();
//# sourceMappingURL=workbox-sw.js.map

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -1,2 +1,2 @@
!function(){"use strict";try{self["workbox:sw:5.1.4"]&&_()}catch(t){}const t={backgroundSync:"background-sync",broadcastUpdate:"broadcast-update",cacheableResponse:"cacheable-response",core:"core",expiration:"expiration",googleAnalytics:"offline-ga",navigationPreload:"navigation-preload",precaching:"precaching",rangeRequests:"range-requests",routing:"routing",strategies:"strategies",streams:"streams"};self.workbox=new class{constructor(){return this.v={},this.t={debug:"localhost"===self.location.hostname,modulePathPrefix:null,modulePathCb:null},this.s=this.t.debug?"dev":"prod",this.o=!1,new Proxy(this,{get(e,s){if(e[s])return e[s];const o=t[s];return o&&e.loadModule("workbox-"+o),e[s]}})}setConfig(t={}){if(this.o)throw new Error("Config must be set before accessing workbox.* modules");Object.assign(this.t,t),this.s=this.t.debug?"dev":"prod"}loadModule(t){const e=this.i(t);try{importScripts(e),this.o=!0}catch(s){throw console.error(`Unable to import module '${t}' from '${e}'.`),s}}i(t){if(this.t.modulePathCb)return this.t.modulePathCb(t,this.t.debug);let e=["https://storage.googleapis.com/workbox-cdn/releases/5.1.4"];const s=`${t}.${this.s}.js`,o=this.t.modulePathPrefix;return o&&(e=o.split("/"),""===e[e.length-1]&&e.splice(e.length-1,1)),e.push(s),e.join("/")}}}(); !function(){"use strict";try{self["workbox:sw:7.3.0"]&&_()}catch(t){}const t={backgroundSync:"background-sync",broadcastUpdate:"broadcast-update",cacheableResponse:"cacheable-response",core:"core",expiration:"expiration",googleAnalytics:"offline-ga",navigationPreload:"navigation-preload",precaching:"precaching",rangeRequests:"range-requests",routing:"routing",strategies:"strategies",streams:"streams",recipes:"recipes"};self.workbox=new class{constructor(){return this.v={},this.Pt={debug:"localhost"===self.location.hostname,modulePathPrefix:null,modulePathCb:null},this.$t=this.Pt.debug?"dev":"prod",this.jt=!1,new Proxy(this,{get(e,s){if(e[s])return e[s];const o=t[s];return o&&e.loadModule(`workbox-${o}`),e[s]}})}setConfig(t={}){if(this.jt)throw new Error("Config must be set before accessing workbox.* modules");Object.assign(this.Pt,t),this.$t=this.Pt.debug?"dev":"prod"}loadModule(t){const e=this.St(t);try{importScripts(e),this.jt=!0}catch(s){throw console.error(`Unable to import module '${t}' from '${e}'.`),s}}St(t){if(this.Pt.modulePathCb)return this.Pt.modulePathCb(t,this.Pt.debug);let e=["https://storage.googleapis.com/workbox-cdn/releases/7.3.0"];const s=`${t}.${this.$t}.js`,o=this.Pt.modulePathPrefix;return o&&(e=o.split("/"),""===e[e.length-1]&&e.splice(e.length-1,1)),e.push(s),e.join("/")}}}();
//# sourceMappingURL=workbox-sw.js.map //# sourceMappingURL=workbox-sw.js.map

View File

@@ -1,6 +1,6 @@
{ {
"name": "cnm", "name": "cnm",
"version": "1.2.75", "version": "1.2.76",
"description": "Comunita Nuovo Mondo", "description": "Comunita Nuovo Mondo",
"productName": "ComunitaNuovoMondo", "productName": "ComunitaNuovoMondo",
"author": "Surya", "author": "Surya",
@@ -9,7 +9,7 @@
"license": "MIT", "license": "MIT",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "PORT=8083 APP_VERSION='1.2.75' quasar dev", "dev": "PORT=8083 APP_VERSION='1.2.76' quasar dev",
"dev_noCheck": "SKIP_TSC=true quasar dev", "dev_noCheck": "SKIP_TSC=true quasar dev",
"build": "quasar build", "build": "quasar build",
"buildpwa": "NODE_ENV=production quasar build -m pwa", "buildpwa": "NODE_ENV=production quasar build -m pwa",
@@ -21,8 +21,8 @@
"lintfile": "eslint --ext .js,.ts,.vue --ignore-path .gitignore ./ > file.out.txt", "lintfile": "eslint --ext .js,.ts,.vue --ignore-path .gitignore ./ > file.out.txt",
"lintfileNoJS": "eslint --ext .ts,.vue --ignore-path .gitignore ./ > file.out.txt", "lintfileNoJS": "eslint --ext .ts,.vue --ignore-path .gitignore ./ > file.out.txt",
"fix": "eslint -c ./eslint.config.js \"./src*/**/*.{ts,js,cjs,mjs,vue}\" --ignore-pattern .gitignore ./ --fix > file.out.txt", "fix": "eslint -c ./eslint.config.js \"./src*/**/*.{ts,js,cjs,mjs,vue}\" --ignore-pattern .gitignore ./ --fix > file.out.txt",
"pwa": "NODE_ENV=development PORT=8093 APP_VERSION='1.2.75' quasar dev -m pwa", "pwa": "NODE_ENV=development PORT=8093 APP_VERSION='1.2.76' quasar dev -m pwa",
"spa": "NODE_ENV=development PORT=8083 APP_VERSION='1.2.75' quasar dev", "spa": "NODE_ENV=development PORT=8083 APP_VERSION='1.2.76' quasar dev",
"debug": "quasar dev --mode debug", "debug": "quasar dev --mode debug",
"test": "echo \"No test specified\" && exit 0", "test": "echo \"No test specified\" && exit 0",
"generate-sw": "workbox generateSW workbox-config.js", "generate-sw": "workbox generateSW workbox-config.js",

View File

@@ -1,6 +1,6 @@
{ {
"name": "freeplanet", "name": "freeplanet",
"version": "1.2.75", "version": "1.2.76",
"description": "freeplanet", "description": "freeplanet",
"productName": "freeplanet", "productName": "freeplanet",
"author": "Surya", "author": "Surya",
@@ -9,11 +9,11 @@
"license": "MIT", "license": "MIT",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "PORT=8087 APP_VERSION='1.2.75' quasar dev", "dev": "PORT=8087 APP_VERSION='1.2.76' quasar dev",
"dev_noCheck": "SKIP_TSC=true quasar dev", "dev_noCheck": "SKIP_TSC=true quasar dev",
"build": "quasar build", "build": "quasar build",
"buildpwa": "NODE_ENV=production APP_VERSION='1.2.75' quasar build -m pwa", "buildpwa": "NODE_ENV=production APP_VERSION='1.2.76' quasar build -m pwa",
"buildpwatest": "NODE_ENV=production APP_VERSION='1.2.75' quasar build -m pwa", "buildpwatest": "NODE_ENV=production APP_VERSION='1.2.76' quasar build -m pwa",
"type-check": "vue-tsc --noEmit", "type-check": "vue-tsc --noEmit",
"type-check:watch": "vue-tsc --noEmit --watch", "type-check:watch": "vue-tsc --noEmit --watch",
"buildspa": "quasar build -m spa", "buildspa": "quasar build -m spa",
@@ -21,8 +21,8 @@
"lintfile": "eslint --ext .js,.ts,.vue --ignore-path .gitignore ./ > file.out.txt", "lintfile": "eslint --ext .js,.ts,.vue --ignore-path .gitignore ./ > file.out.txt",
"lintfileNoJS": "eslint --ext .ts,.vue --ignore-path .gitignore ./ > file.out.txt", "lintfileNoJS": "eslint --ext .ts,.vue --ignore-path .gitignore ./ > file.out.txt",
"fix": "eslint -c ./eslint.config.js \"./src*/**/*.{ts,js,cjs,mjs,vue}\" --ignore-pattern .gitignore ./ --fix > file.out.txt", "fix": "eslint -c ./eslint.config.js \"./src*/**/*.{ts,js,cjs,mjs,vue}\" --ignore-pattern .gitignore ./ --fix > file.out.txt",
"pwa": "NODE_ENV=development PORT=8097 APP_VERSION='1.2.75' quasar dev -m pwa", "pwa": "NODE_ENV=development PORT=8097 APP_VERSION='1.2.76' quasar dev -m pwa",
"spa": "NODE_ENV=development PORT=8087 APP_VERSION='1.2.75' quasar dev", "spa": "NODE_ENV=development PORT=8087 APP_VERSION='1.2.76' quasar dev",
"debug": "quasar dev --mode debug", "debug": "quasar dev --mode debug",
"test": "echo \"No test specified\" && exit 0", "test": "echo \"No test specified\" && exit 0",
"generate-sw": "workbox generateSW workbox-config.js", "generate-sw": "workbox generateSW workbox-config.js",

View File

@@ -1,6 +1,6 @@
{ {
"name": "gruppomacro", "name": "gruppomacro",
"version": "1.2.75", "version": "1.2.76",
"productName": "Gruppo Macro", "productName": "Gruppo Macro",
"description": "Il Gruppo Editoriale Macro, attivo dal 1987, è leader europeo nella pubblicazione di libri per il benessere e la consapevolezza. Con oltre 1.500 titoli, promuove una visione armonica del mondo, offrendo opere di autori internazionali e italiani come Gregg Braden, Bruce Lipton, Joe Dispenza, Louise Hay, Eckhart Tolle e molti altri. Scopri un'editoria che abbraccia il corpo, la mente, lo spirito e l'ecologia.", "description": "Il Gruppo Editoriale Macro, attivo dal 1987, è leader europeo nella pubblicazione di libri per il benessere e la consapevolezza. Con oltre 1.500 titoli, promuove una visione armonica del mondo, offrendo opere di autori internazionali e italiani come Gregg Braden, Bruce Lipton, Joe Dispenza, Louise Hay, Eckhart Tolle e molti altri. Scopri un'editoria che abbraccia il corpo, la mente, lo spirito e l'ecologia.",
"author": "Surya", "author": "Surya",
@@ -9,20 +9,20 @@
"license": "MIT", "license": "MIT",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "PORT=8089 APP_VERSION='1.2.75' quasar dev", "dev": "PORT=8089 APP_VERSION='1.2.76' quasar dev",
"dev_noCheck": "SKIP_TSC=true quasar dev", "dev_noCheck": "SKIP_TSC=true quasar dev",
"build": "quasar build", "build": "quasar build",
"buildpwa": "NODE_ENV=production APP_VERSION='1.2.75' quasar build -m pwa", "buildpwa": "NODE_ENV=production APP_VERSION='1.2.76' quasar build -m pwa",
"buildpwatest": "NODE_ENV=production APP_VERSION='1.2.75' quasar build -m pwa", "buildpwatest": "NODE_ENV=production APP_VERSION='1.2.76' quasar build -m pwa",
"type-check": "vue-tsc --noEmit", "type-check": "vue-tsc --noEmit",
"type-check:watch": "vue-tsc --noEmit --watch", "type-check:watch": "vue-tsc --noEmit --watch",
"buildspa": "APP_VERSION='1.2.75' quasar build -m spa", "buildspa": "APP_VERSION='1.2.76' quasar build -m spa",
"lint": "eslint -c ./eslint.config.js \"./src*/**/*.{ts,js,cjs,mjs,vue}\"", "lint": "eslint -c ./eslint.config.js \"./src*/**/*.{ts,js,cjs,mjs,vue}\"",
"lintfile": "eslint --ext .js,.ts,.vue --ignore-path .gitignore ./ > file.out.txt", "lintfile": "eslint --ext .js,.ts,.vue --ignore-path .gitignore ./ > file.out.txt",
"lintfileNoJS": "eslint --ext .ts,.vue --ignore-path .gitignore ./ > file.out.txt", "lintfileNoJS": "eslint --ext .ts,.vue --ignore-path .gitignore ./ > file.out.txt",
"fix": "eslint -c ./eslint.config.js \"./src*/**/*.{ts,js,cjs,mjs,vue}\" --ignore-pattern .gitignore ./ --fix > file.out.txt", "fix": "eslint -c ./eslint.config.js \"./src*/**/*.{ts,js,cjs,mjs,vue}\" --ignore-pattern .gitignore ./ --fix > file.out.txt",
"pwa": "NODE_ENV=development PORT=8099 APP_VERSION='1.2.75' quasar dev -m pwa", "pwa": "NODE_ENV=development PORT=8099 APP_VERSION='1.2.76' quasar dev -m pwa",
"spa": "NODE_ENV=development PORT=8089 APP_VERSION='1.2.75' quasar dev", "spa": "NODE_ENV=development PORT=8089 APP_VERSION='1.2.76' quasar dev",
"debug": "quasar dev --mode debug", "debug": "quasar dev --mode debug",
"test": "echo \"No test specified\" && exit 0", "test": "echo \"No test specified\" && exit 0",
"generate-sw": "workbox generateSW workbox-config.js", "generate-sw": "workbox generateSW workbox-config.js",

View File

@@ -1,6 +1,6 @@
{ {
"name": "nuovomondo", "name": "nuovomondo",
"version": "1.2.75", "version": "1.2.76",
"description": "Nuovo Mondo", "description": "Nuovo Mondo",
"productName": "Nuovo Mondo", "productName": "Nuovo Mondo",
"author": "Surya", "author": "Surya",
@@ -9,11 +9,11 @@
"license": "MIT", "license": "MIT",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "APP_VERSION='1.2.75' PORT=8083 quasar dev", "dev": "APP_VERSION='1.2.76' PORT=8083 quasar dev",
"dev_noCheck": "SKIP_TSC=true quasar dev", "dev_noCheck": "SKIP_TSC=true quasar dev",
"build": "quasar build", "build": "quasar build",
"buildpwa": "NODE_ENV=production APP_VERSION='1.2.75' quasar build -m pwa", "buildpwa": "NODE_ENV=production APP_VERSION='1.2.76' quasar build -m pwa",
"buildpwatest": "NODE_ENV=production APP_VERSION='1.2.75' quasar build -m pwa", "buildpwatest": "NODE_ENV=production APP_VERSION='1.2.76' quasar build -m pwa",
"type-check": "vue-tsc --noEmit", "type-check": "vue-tsc --noEmit",
"type-check:watch": "vue-tsc --noEmit --watch", "type-check:watch": "vue-tsc --noEmit --watch",
"buildspa": "quasar build -m spa", "buildspa": "quasar build -m spa",
@@ -21,8 +21,8 @@
"lintfile": "eslint --ext .js,.ts,.vue --ignore-path .gitignore ./ > file.out.txt", "lintfile": "eslint --ext .js,.ts,.vue --ignore-path .gitignore ./ > file.out.txt",
"lintfileNoJS": "eslint --ext .ts,.vue --ignore-path .gitignore ./ > file.out.txt", "lintfileNoJS": "eslint --ext .ts,.vue --ignore-path .gitignore ./ > file.out.txt",
"fix": "eslint -c ./eslint.config.js \"./src*/**/*.{ts,js,cjs,mjs,vue}\" --ignore-pattern .gitignore ./ --fix > file.out.txt", "fix": "eslint -c ./eslint.config.js \"./src*/**/*.{ts,js,cjs,mjs,vue}\" --ignore-pattern .gitignore ./ --fix > file.out.txt",
"pwa": "NODE_ENV=development PORT=8094 APP_VERSION='1.2.75' quasar dev -m pwa", "pwa": "NODE_ENV=development PORT=8094 APP_VERSION='1.2.76' quasar dev -m pwa",
"spa": "NODE_ENV=development PORT=8083 APP_VERSION='1.2.75' quasar dev", "spa": "NODE_ENV=development PORT=8083 APP_VERSION='1.2.76' quasar dev",
"debug": "quasar dev --mode debug", "debug": "quasar dev --mode debug",
"test": "echo \"No test specified\" && exit 0", "test": "echo \"No test specified\" && exit 0",
"generate-sw": "workbox generateSW workbox-config.js", "generate-sw": "workbox generateSW workbox-config.js",

View File

@@ -1,6 +1,6 @@
{ {
"name": "nutriben", "name": "nutriben",
"version": "1.2.75", "version": "1.2.76",
"description": "Nutriben", "description": "Nutriben",
"productName": "Nutriben", "productName": "Nutriben",
"author": "Surya", "author": "Surya",
@@ -9,20 +9,20 @@
"license": "MIT", "license": "MIT",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "PORT=8093 APP_VERSION='1.2.75' quasar dev", "dev": "PORT=8093 APP_VERSION='1.2.76' quasar dev",
"dev_noCheck": "SKIP_TSC=true quasar dev", "dev_noCheck": "SKIP_TSC=true quasar dev",
"build": "quasar build", "build": "quasar build",
"buildpwa": "NODE_ENV=production APP_VERSION='1.2.75' quasar build -m pwa", "buildpwa": "NODE_ENV=production APP_VERSION='1.2.76' quasar build -m pwa",
"buildpwatest": "NODE_ENV=production APP_VERSION='1.2.75' quasar build -m pwa", "buildpwatest": "NODE_ENV=production APP_VERSION='1.2.76' quasar build -m pwa",
"type-check": "vue-tsc --noEmit", "type-check": "vue-tsc --noEmit",
"type-check:watch": "vue-tsc --noEmit --watch", "type-check:watch": "vue-tsc --noEmit --watch",
"buildspa": "APP_VERSION='1.2.75' quasar build -m spa", "buildspa": "APP_VERSION='1.2.76' quasar build -m spa",
"lint": "eslint -c ./eslint.config.js \"./src*/**/*.{ts,js,cjs,mjs,vue}\"", "lint": "eslint -c ./eslint.config.js \"./src*/**/*.{ts,js,cjs,mjs,vue}\"",
"lintfile": "eslint --ext .js,.ts,.vue --ignore-path .gitignore ./ > file.out.txt", "lintfile": "eslint --ext .js,.ts,.vue --ignore-path .gitignore ./ > file.out.txt",
"lintfileNoJS": "eslint --ext .ts,.vue --ignore-path .gitignore ./ > file.out.txt", "lintfileNoJS": "eslint --ext .ts,.vue --ignore-path .gitignore ./ > file.out.txt",
"fix": "eslint -c ./eslint.config.js \"./src*/**/*.{ts,js,cjs,mjs,vue}\" --ignore-pattern .gitignore ./ --fix > file.out.txt", "fix": "eslint -c ./eslint.config.js \"./src*/**/*.{ts,js,cjs,mjs,vue}\" --ignore-pattern .gitignore ./ --fix > file.out.txt",
"pwa": "NODE_ENV=development PORT=8099 APP_VERSION='1.2.75' quasar dev -m pwa", "pwa": "NODE_ENV=development PORT=8099 APP_VERSION='1.2.76' quasar dev -m pwa",
"spa": "NODE_ENV=development PORT=8093 APP_VERSION='1.2.75' quasar dev", "spa": "NODE_ENV=development PORT=8093 APP_VERSION='1.2.76' quasar dev",
"debug": "quasar dev --mode debug", "debug": "quasar dev --mode debug",
"test": "echo \"No test specified\" && exit 0", "test": "echo \"No test specified\" && exit 0",
"generate-sw": "workbox generateSW workbox-config.js", "generate-sw": "workbox generateSW workbox-config.js",

View File

@@ -1,6 +1,6 @@
{ {
"name": "piuchebuono", "name": "piuchebuono",
"version": "1.2.75", "version": "1.2.76",
"description": "PiuCheBuono", "description": "PiuCheBuono",
"productName": "PiuCheBuono", "productName": "PiuCheBuono",
"author": "Surya", "author": "Surya",
@@ -9,11 +9,11 @@
"license": "MIT", "license": "MIT",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "PORT=8085 APP_VERSION='1.2.75' quasar dev", "dev": "PORT=8085 APP_VERSION='1.2.76' quasar dev",
"dev_noCheck": "SKIP_TSC=true quasar dev", "dev_noCheck": "SKIP_TSC=true quasar dev",
"build": "quasar build", "build": "quasar build",
"buildpwa": "NODE_ENV=production APP_VERSION='1.2.75' quasar build -m pwa", "buildpwa": "NODE_ENV=production APP_VERSION='1.2.76' quasar build -m pwa",
"buildpwatest": "NODE_ENV=production APP_VERSION='1.2.75' quasar build -m pwa", "buildpwatest": "NODE_ENV=production APP_VERSION='1.2.76' quasar build -m pwa",
"type-check": "vue-tsc --noEmit", "type-check": "vue-tsc --noEmit",
"type-check:watch": "vue-tsc --noEmit --watch", "type-check:watch": "vue-tsc --noEmit --watch",
"buildspa": "quasar build -m spa", "buildspa": "quasar build -m spa",
@@ -21,8 +21,8 @@
"lintfile": "eslint --ext .js,.ts,.vue --ignore-path .gitignore ./ > file.out.txt", "lintfile": "eslint --ext .js,.ts,.vue --ignore-path .gitignore ./ > file.out.txt",
"lintfileNoJS": "eslint --ext .ts,.vue --ignore-path .gitignore ./ > file.out.txt", "lintfileNoJS": "eslint --ext .ts,.vue --ignore-path .gitignore ./ > file.out.txt",
"fix": "eslint -c ./eslint.config.js \"./src*/**/*.{ts,js,cjs,mjs,vue}\" --ignore-pattern .gitignore ./ --fix > file.out.txt", "fix": "eslint -c ./eslint.config.js \"./src*/**/*.{ts,js,cjs,mjs,vue}\" --ignore-pattern .gitignore ./ --fix > file.out.txt",
"pwa": "NODE_ENV=development PORT=8085 APP_VERSION='1.2.75' quasar dev -m pwa", "pwa": "NODE_ENV=development PORT=8085 APP_VERSION='1.2.76' quasar dev -m pwa",
"spa": "NODE_ENV=development PORT=8085 APP_VERSION='1.2.75' quasar dev", "spa": "NODE_ENV=development PORT=8085 APP_VERSION='1.2.76' quasar dev",
"debug": "quasar dev --mode debug", "debug": "quasar dev --mode debug",
"test": "echo \"No test specified\" && exit 0", "test": "echo \"No test specified\" && exit 0",
"generate-sw": "workbox generateSW workbox-config.js", "generate-sw": "workbox generateSW workbox-config.js",

View File

@@ -1,6 +1,6 @@
{ {
"name": "riso", "name": "riso",
"version": "1.2.75", "version": "1.2.76",
"productName": "Riso 💚 - Rete Italiana Scambi Orizzontali", "productName": "Riso 💚 - Rete Italiana Scambi Orizzontali",
"description": "Progetto RISO (Rete Italiana Scambi Orizzontali) promuove una rete di comunità locali che favoriscono scambi di beni, servizi e ospitalità. Con l'App RISO, sviluppata per facilitare il baratto, il dono e l'uso di monete alternative come i RIS, il progetto crea legami autentici basati sulla fiducia e sostenibilità. Partecipa agli scambi e costruisci una comunità più consapevole e autosufficiente.", "description": "Progetto RISO (Rete Italiana Scambi Orizzontali) promuove una rete di comunità locali che favoriscono scambi di beni, servizi e ospitalità. Con l'App RISO, sviluppata per facilitare il baratto, il dono e l'uso di monete alternative come i RIS, il progetto crea legami autentici basati sulla fiducia e sostenibilità. Partecipa agli scambi e costruisci una comunità più consapevole e autosufficiente.",
"author": "Surya", "author": "Surya",
@@ -9,11 +9,11 @@
"license": "MIT", "license": "MIT",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "APP_VERSION='1.2.75' PORT=8084 quasar dev", "dev": "APP_VERSION='1.2.76' PORT=8084 quasar dev",
"dev_noCheck": "SKIP_TSC=true quasar dev", "dev_noCheck": "SKIP_TSC=true quasar dev",
"build": "quasar build", "build": "quasar build",
"buildpwa": "NODE_ENV=production APP_VERSION='1.2.75' quasar build -m pwa", "buildpwa": "NODE_ENV=production APP_VERSION='1.2.76' quasar build -m pwa",
"buildpwatest": "NODE_ENV=production APP_VERSION='1.2.75' quasar build -m pwa", "buildpwatest": "NODE_ENV=production APP_VERSION='1.2.76' quasar build -m pwa",
"type-check": "vue-tsc --noEmit", "type-check": "vue-tsc --noEmit",
"type-check:watch": "vue-tsc --noEmit --watch", "type-check:watch": "vue-tsc --noEmit --watch",
"buildspa": "quasar build -m spa", "buildspa": "quasar build -m spa",
@@ -21,8 +21,8 @@
"lintfile": "eslint --ext .js,.ts,.vue --ignore-path .gitignore ./ > file.out.txt", "lintfile": "eslint --ext .js,.ts,.vue --ignore-path .gitignore ./ > file.out.txt",
"lintfileNoJS": "eslint --ext .ts,.vue --ignore-path .gitignore ./ > file.out.txt", "lintfileNoJS": "eslint --ext .ts,.vue --ignore-path .gitignore ./ > file.out.txt",
"fix": "eslint -c ./eslint.config.js \"./src*/**/*.{ts,js,cjs,mjs,vue}\" --ignore-pattern .gitignore ./ --fix > file.out.txt", "fix": "eslint -c ./eslint.config.js \"./src*/**/*.{ts,js,cjs,mjs,vue}\" --ignore-pattern .gitignore ./ --fix > file.out.txt",
"pwa": "NODE_ENV=development PORT=8094 APP_VERSION='1.2.75' quasar dev -m pwa", "pwa": "NODE_ENV=development PORT=8094 APP_VERSION='1.2.76' quasar dev -m pwa",
"spa": "NODE_ENV=development PORT=8084 APP_VERSION='1.2.75' quasar dev", "spa": "NODE_ENV=development PORT=8084 APP_VERSION='1.2.76' quasar dev",
"debug": "quasar dev --mode debug", "debug": "quasar dev --mode debug",
"test": "echo \"No test specified\" && exit 0", "test": "echo \"No test specified\" && exit 0",
"generate-sw": "workbox generateSW workbox-config.js", "generate-sw": "workbox generateSW workbox-config.js",

View File

@@ -1 +1 @@
TERMINA DI LAVORARE SU riso.app: (Sovrascrivo!) TERMINA DI LAVORARE SU gruppomacro.app: (Sovrascrivo!)

View File

@@ -3,7 +3,7 @@
/* global workbox */ /* global workbox */
/* global cfgenv */ /* global cfgenv */
const VITE_APP_VERSION = '1.2.75'; const VITE_APP_VERSION = '1.2.76';
// Costanti di configurazione // Costanti di configurazione
const DYNAMIC_CACHE = 'dynamic-cache-v2'; const DYNAMIC_CACHE = 'dynamic-cache-v2';

View File

@@ -1,7 +1,7 @@
{ {
"name": "Gruppo Macro", "name": "Riso",
"short_name": "GruppoMacro", "short_name": "Riso",
"description": "", "description": "Siamo la Rete Italiana di Scambio Orizzontale, abbiamo creato questa piattaforma per metterla al servizio di chi vuole riscoprire il valore della condivisione e della cooperazione. Valori semplici e profondi che ci aiutano a ritrovare il Senso della Vita, perduto in questa società consumista, e riporti quei Sani Pricìpi Naturali ed Umani di Fratellanza che intere popolazioni antiche conoscevano bene.",
"display": "standalone", "display": "standalone",
"orientation": "portrait", "orientation": "portrait",
"background_color": "#fff", "background_color": "#fff",
@@ -11,17 +11,47 @@
"start_url": "/?homescreen=1", "start_url": "/?homescreen=1",
"icons": [ "icons": [
{ {
"src": "/images/gm-android-icon-512x512.png", "src": "/images/riso-android-icon-512x512.png",
"sizes": "512x512", "sizes": "512x512",
"type": "image/png" "type": "image/png"
}, },
{ {
"src": "/images/gm-android-icon-192x192.png", "src": "/images/riso-android-icon-384x384.png",
"sizes": "384x384",
"type": "image/png"
},
{
"src": "/images/riso-android-icon-192x192.png",
"sizes": "192x192", "sizes": "192x192",
"type": "image/png" "type": "image/png"
}, },
{ {
"src": "/images/gm-apple-touch-icon.png", "src": "/images/riso-android-icon-144x144.png",
"sizes": "144x144",
"type": "image/png"
},
{
"src": "/images/riso-android-icon-96x96.png",
"sizes": "96x96",
"type": "image/png"
},
{
"src": "/images/riso-apple-icon-120x120.png",
"sizes": "120x120",
"type": "image/png"
},
{
"src": "/images/riso-apple-icon-144x144.png",
"sizes": "144x144",
"type": "image/png"
},
{
"src": "/images/riso-apple-icon-152x152.png",
"sizes": "152x152",
"type": "image/png"
},
{
"src": "/images/riso-apple-icon-180x180.png",
"sizes": "180x180", "sizes": "180x180",
"type": "image/png" "type": "image/png"
} }

View File

@@ -18,7 +18,7 @@
<!-- 🔥 Aggiungi qui il componente PWA Updater --> <!-- 🔥 Aggiungi qui il componente PWA Updater -->
<CCheckUpdatesPWA <CCheckUpdatesPWA
:showManualCheckButton="tools.isDebug()" :showManualCheckButton="false"
:autoCheckInterval="60" :autoCheckInterval="60"
:showSuccessNotification="true" :showSuccessNotification="true"
/> />

View File

@@ -0,0 +1,65 @@
.elemEdit {
position: absolute;
top: 10px;
left: 10px;
background: rgba(0, 0, 0, 0.5);
color: white;
padding: 5px 10px;
border-radius: 4px;
z-index: 100;
font-size: 12px;
}
.card-group-scrollable {
overflow-x: auto;
overflow-y: hidden;
scrollbar-width: thin;
}
.card-group-scrollable::-webkit-scrollbar {
height: 8px;
}
.card-group-scrollable::-webkit-scrollbar-track {
background: rgba(0, 0, 0, 0.1);
border-radius: 4px;
}
.card-group-scrollable::-webkit-scrollbar-thumb {
background: rgba(0, 0, 0, 0.3);
border-radius: 4px;
}
.flex-card {
display: flex;
flex-direction: column;
transition: transform 0.3s ease;
margin: 0 0.25rem !important;
}
.titolo_card {
cursor: pointer;
}
.titolo_card:hover {
transform: scale(1.05);
}
.img-container {
display: flex;
align-items: center;
justify-content: center;
background: rgba(0, 0, 0, 0.02);
}
.q-card-section-small {
padding: px !important; // o il valore che preferisci
flex: 1;
}
.clEdit {
border: 2px dashed #ff9800;
background: rgba(255, 152, 0, 0.1);
cursor: pointer;
}

View File

@@ -0,0 +1,148 @@
import { ref, computed, defineComponent, onMounted } from 'vue';
import { useQuasar } from 'quasar';
import { tools } from '@tools';
import { IMyCard, IMyPage, IOperators } from '@src/model';
import objectId from '@src/js/objectId';
export default defineComponent({
name: 'ElementComponent',
props: {
myel: {
type: Object,
required: true,
},
editOn: {
type: Boolean,
default: false,
},
path: {
type: String,
default: '',
},
cardColumnClass: {
type: String,
default: 'col-12 col-sm-6 col-md-4',
},
cardWidth: {
type: String,
default: '300px',
},
cardHeight: {
type: String,
required: true,
},
cardImg: {
type: String,
required: true,
},
},
setup(props) {
const $q = useQuasar();
const carousel = ref(null);
const cardScroller = ref(<any>null);
const slide = ref(0);
const animarecard = ref(0);
// Computed per l'altezza del contenitore immagine (70% dell'altezza card)
const imageContainerHeight = computed(() => {
const heightValue = parseInt(props.cardHeight.replace('px', ''));
return `${heightValue * 0.7}px`;
});
const currentCardsPerSlide = computed(() => {
return props.myel.num2 ? props.myel.num2 : 2; // cardsPerSlide
});
// Costanti per i tipi di elemento
const ELEMTYPE = {
CARD: 'card',
MARGINI: 'margini',
};
const cardGroups = computed(() => {
const cards = props.myel.listcards || [];
const groups = [];
for (let i = 0; i < cards.length; i += currentCardsPerSlide.value) {
groups.push(cards.slice(i, i + currentCardsPerSlide.value));
}
if (!groups.length) {
groups.push([
{
_id: objectId(),
imagefile: '',
alt: '',
description: '',
vers_img: 0,
},
]);
}
return groups;
});
// Metodi
const canScrollLeft = ref(false);
const canScrollRight = ref(false);
// Funzione per aggiornare lo stato degli scroll
function updateScrollButtons() {
const scroller = Array.isArray(cardScroller.value)
? cardScroller.value[slide.value]
: cardScroller.value;
if (scroller) {
canScrollLeft.value = scroller.scrollLeft > 5; // 5px di tolleranza
canScrollRight.value = scroller.scrollLeft < (scroller.scrollWidth - scroller.clientWidth - 5);
}
}
// Modifica scrollCards per aggiornare i bottoni dopo lo scroll
function scrollCards(delta: number) {
const scroller = Array.isArray(cardScroller.value)
? cardScroller.value[slide.value]
: cardScroller.value;
if (scroller) {
scroller.scrollBy({
left: delta,
behavior: 'smooth',
});
// Aggiorna i bottoni dopo un piccolo delay per lo smooth scroll
setTimeout(updateScrollButtons, 300);
}
}
const clickOnElem = () => {
// Logica per il click sull'elemento
console.log('Element clicked', props.myel);
};
const getClass = () => {
// Restituisce classi aggiuntive basate sulla configurazione
return props.myel.extraClass || '';
};
onMounted(() => {
updateScrollButtons();
});
return {
carousel,
cardScroller,
slide,
animarecard,
ELEMTYPE,
cardGroups,
scrollCards,
clickOnElem,
getClass,
tools,
imageContainerHeight,
canScrollLeft,
canScrollRight,
updateScrollButtons,
};
},
});

View File

@@ -0,0 +1,158 @@
<template>
<div>
<!-- Card Carousel -->
<div class="card-carousel-container">
<div
v-if="editOn"
class="elemEdit"
>
Card
</div>
<q-carousel
swipeable
animated
:autoplay="animarecard"
v-model="slide"
navigation
control-text-color="white"
ref="carousel"
transition-next="slide-left"
transition-prev="slide-right"
:height="tools.getNumberByPixel(cardHeight) + 20 + 'px'"
width="100%"
control-type="flat"
class="shadow-2 rounded-borders"
:style="`background-color: ${myel.color || '#ffffff'} !important`"
@mouseenter="animarecard = 0"
@mouseleave="animarecard = 1000"
>
<template v-slot:control>
<q-carousel-control
position="top-left"
:offset="[10, -10]"
class="q-gutter-xs"
style="opacity: 0.7"
>
<q-btn
v-if="canScrollLeft"
push
round
:color="$q.dark.isActive ? 'black' : 'white'"
:text-color="$q.dark.isActive ? 'white' : 'black'"
icon="keyboard_arrow_left"
@click="scrollCards(-300)"
@scroll="updateScrollButtons"
/>
</q-carousel-control>
<q-carousel-control
position="top-right"
class="q-gutter-xs"
:offset="[10, -10]"
style="opacity: 0.7"
>
<q-btn
v-if="canScrollRight"
push
round
:color="$q.dark.isActive ? 'black' : 'white'"
:text-color="$q.dark.isActive ? 'white' : 'black'"
icon="keyboard_arrow_right"
@click="scrollCards(300)"
@scroll="updateScrollButtons"
/>
</q-carousel-control>
</template>
<!-- Slides con gruppi di card -->
<q-carousel-slide
v-for="(group, groupIndex) in cardGroups"
:key="groupIndex"
:name="groupIndex"
>
<div
ref="cardScroller"
@scroll="updateScrollButtons"
:style="{
'max-height': tools.getNumberByPixel(cardHeight) + 20 + 'px',
'max-width': $q.screen.width + 'px',
'overflow-x': 'auto',
'overflow-y': 'hidden',
'padding-bottom': '10px',
}"
>
<div class="row no-wrap items-center">
<div
v-for="(rec, cardIndex) in group"
:key="cardIndex"
:class="cardColumnClass"
class="flex flex-center"
>
<q-card
:class="
'flex-card bordered ' +
(myel.class3 || '') +
(rec.link ? ' titolo_card' : '')
"
:style="`
${rec.style || ''};
height: ${tools.getNumberByPixel(cardHeight) - 0 + 'px'};
width: ${rec.width || cardWidth};
flex: 0 0 auto;
display: flex;
flex-direction: column;
`"
@click="rec.link ? tools.openUrl(rec.link) : undefined"
>
<div
class="img-container"
:style="`
height: ${cardImg};
min-height: ${cardImg};
max-height: ${cardImg};
overflow: hidden;
flex-shrink: 0;
`"
>
<q-img
:class="
(tools.getClassAnim(myel.anim2) || '') + ' ' + (myel.class4 || '')
"
:src="tools.getImgFileByElem(myel, rec, path)"
fit="contain"
:style="`height: ${cardImg};`"
/>
</div>
<q-card-section class="q-card-section-small">
<div
:class="rec.size || 'text-subtitle1'"
:style="`color: ${rec.color || 'inherit'}`"
>
{{ tools.getText(rec.alt) }}
</div>
<div
:class="'q-mt-xs q-mb-xs ' + (tools.getClassAnim(myel.anim) || '')"
v-html="rec.content"
/>
<div
v-if="rec.description"
class="text-caption"
:style="`color: ${rec.colorsub || 'grey'}`"
>
{{ rec.description }}
</div>
</q-card-section>
</q-card>
</div>
</div>
</div>
</q-carousel-slide>
</q-carousel>
</div>
</div>
</template>
<script lang="ts" src="./CCardCarouselComp.ts"></script>
<style lang="scss" scoped>
@import './CCardCarouselComp.scss';
</style>

View File

@@ -0,0 +1 @@
export {default as CCardCarouselComp} from './CCardCarouselComp.vue'

View File

@@ -10,7 +10,7 @@
<div <div
v-if="finishLoading" v-if="finishLoading"
class="row justify-center q-gutter-md" class="row justify-center"
> >
<!-- 🚫 Se sei in un WebView non compatibile (es. Telegram) --> <!-- 🚫 Se sei in un WebView non compatibile (es. Telegram) -->

View File

@@ -1,9 +1,9 @@
<template> <template>
<div class="q-ma-xs"> <div class="q-ma-none">
<div <div
v-if="tools.visualizzaHomeApp()" v-if="tools.visualizzaHomeApp()"
class="row q-my-xs shadow" class="row q-mx-xs shadow-1"
style="border-radius: 4px; border: 1px solid rgba(0, 0, 0, 0.12)" style="border-radius: 2px; border: 1px solid rgba(0, 0, 0, 0.12)"
> >
<!--<div class="col-md-3 col-lg-3 col-sm-12 col-xs-12 box_4" style="border-left: 1px solid #efefef;" <!--<div class="col-md-3 col-lg-3 col-sm-12 col-xs-12 box_4" style="border-left: 1px solid #efefef;"
v-bind:class="{'border-top': $q.platform.is.mobile}"> v-bind:class="{'border-top': $q.platform.is.mobile}">

View File

@@ -243,6 +243,7 @@
<div class="row"> <div class="row">
<CMySlider <CMySlider
v-if=" v-if="
myel.type === shared_consts.ELEMTYPE.CARD ||
myel.type === shared_consts.ELEMTYPE.CATALOGLIST || myel.type === shared_consts.ELEMTYPE.CATALOGLIST ||
myel.type === shared_consts.ELEMTYPE.RACCOLTE_CATALOGHI myel.type === shared_consts.ELEMTYPE.RACCOLTE_CATALOGHI
" "
@@ -470,6 +471,15 @@
/> />
</q-expansion-item> </q-expansion-item>
<div class="row"> <div class="row">
<q-input
dense
label="Classe per Card:"
@update:model-value="modifElem"
v-model="myel.class2"
filled
v-on:keyup.enter="saveElem"
>
</q-input>
<q-input <q-input
dense dense
label="Classe Schede:" label="Classe Schede:"

View File

@@ -467,4 +467,7 @@ h1 {
.elemEdit:hover { .elemEdit:hover {
border: #11f609 solid 2px; border: #11f609 solid 2px;
cursor: pointer; cursor: pointer;
}
.myElemBase{
margin-bottom: 16px;
} }

View File

@@ -34,6 +34,7 @@ import { CMyVideoYoutube } from '@src/components/CMyVideoYoutube';
import { CStatMacro } from '@src/components/CStatMacro'; import { CStatMacro } from '@src/components/CStatMacro';
import { CSearchProduct } from '@src/components/CSearchProduct'; import { CSearchProduct } from '@src/components/CSearchProduct';
import { CPageViewStats } from '@src/components/CPageViewStats'; import { CPageViewStats } from '@src/components/CPageViewStats';
import { CCardCarouselComp } from 'app/src/components/CCardCarouselComp';
import { CQRCode } from '@src/components/CQRCode'; import { CQRCode } from '@src/components/CQRCode';
import { CAITools } from '@src/components/CAITools'; import { CAITools } from '@src/components/CAITools';
import { CCatalogo } from '@src/components/CCatalogo'; import { CCatalogo } from '@src/components/CCatalogo';
@@ -105,6 +106,7 @@ export default defineComponent({
CMainView, CMainView,
CNotifAtTop, CNotifAtTop,
CPresentazione, CPresentazione,
CCardCarouselComp,
CMyActivities, CMyActivities,
CMyProfileTutorial, CMyProfileTutorial,
CSendRISTo, CSendRISTo,
@@ -196,6 +198,8 @@ export default defineComponent({
const tabcatalogo = ref('griglia'); const tabcatalogo = ref('griglia');
const enablePwa = computed(() => globalStore.site.confpages?.enablePwa);
const social = ref(<ISocial>{}); const social = ref(<ISocial>{});
const neworder = ref(<number | undefined>0); const neworder = ref(<number | undefined>0);
@@ -244,7 +248,6 @@ export default defineComponent({
const speedSafe = computed(() => (myel.value as any).speed ?? 0); const speedSafe = computed(() => (myel.value as any).speed ?? 0);
const carouselRef = ref(<any>null); const carouselRef = ref(<any>null);
const cardScroller = ref(<any>null);
const isAtStart = ref(true); const isAtStart = ref(true);
const isAtEnd = ref(false); const isAtEnd = ref(false);
const activeIndex = ref(0); const activeIndex = ref(0);
@@ -399,16 +402,6 @@ export default defineComponent({
} }
} }
function scrollCards(delta: number) {
const scroller = cardScroller.value?.[0] || cardScroller.value;
if (scroller) {
scroller.scrollBy({
left: delta,
behavior: 'smooth',
});
}
}
const updateApp = async () => { const updateApp = async () => {
// Invia il messaggio al Service Worker per saltare l'attesa // Invia il messaggio al Service Worker per saltare l'attesa
const registration = await navigator.serviceWorker.getRegistration(); const registration = await navigator.serviceWorker.getRegistration();
@@ -472,9 +465,8 @@ export default defineComponent({
speedSafe, speedSafe,
t, t,
cardGroupMaxWidth, cardGroupMaxWidth,
cardScroller,
scrollCards,
isNewVersionAvailable, isNewVersionAvailable,
enablePwa,
}; };
}, },
}); });

View File

@@ -1,5 +1,6 @@
<template> <template>
<div> <div>
<!-- CMyElem -->
<div <div
v-if="myel" v-if="myel"
:class=" :class="
@@ -40,139 +41,17 @@
</div> </div>
</transition> </transition>
</div> </div>
<div <CCardCarouselComp
v-if="myel.type === shared_consts.ELEMTYPE.CARD" v-else-if="myel.type === shared_consts.ELEMTYPE.CARD"
class="card-carousel-container" :myel="myel"
> :edit-on="editOn"
<div :path="path"
v-if="editOn" :card-column-class="cardColumnClass()"
class="elemEdit" :card-width="myel.widthcard"
> :card-height="myel.heightcarousel"
Card :card-img="myel.heightimg"
</div>
<q-carousel
swipeable
animated
:autoplay="animarecard"
v-model="slide"
navigation
control-text-color="white"
ref="carousel"
transition-next="slide-left"
transition-prev="slide-right"
:height="myel.heightcarousel"
width="100%"
control-type="flat"
class="shadow-2 rounded-borders"
:style="`background-color: ${myel.color} !important`"
@mouseenter="animarecard = 0"
@mouseleave="animarecard = 1000"
>
<template v-slot:control>
<q-carousel-control
position="top-left"
:offset="[-10, -10]"
class="q-gutter-xs"
style="opacity: 0.7"
>
<q-btn
push
round
:color="$q.dark.isActive ? `black` : `white`"
:text-color="$q.dark.isActive ? `white` : `black`"
icon="keyboard_arrow_left"
@click="scrollCards(-300)"
></q-btn>
</q-carousel-control>
<q-carousel-control
position="top-right"
class="q-gutter-xs"
:offset="[-10, -10]"
style="opacity: 0.7"
>
<q-btn
push
round
:color="$q.dark.isActive ? `black` : `white`"
:text-color="$q.dark.isActive ? `white` : `black`"
icon="keyboard_arrow_right"
@click="scrollCards(300)"
></q-btn>
</q-carousel-control>
</template>
<!-- Iteriamo sui gruppi di card invece che sulle singole card -->
<q-carousel-slide
v-for="(group, groupIndex) in cardGroups"
:key="groupIndex"
:name="groupIndex"
>
<!-- Contenitore scrollabile orizzontalmente -->
<div
ref="cardScroller"
class="card-group-scrollable"
:style="{ 'max-height': myel.heightcarousel, 'max-width': ($q.screen.width - 45) + 'px' }"
>
<div class="row no-wrap items-center">
<template
v-for="(rec, cardIndex) in group"
:key="cardIndex"
>
<div
:class="cardColumnClass"
class="flex flex-center"
>
<q-card
:class="
`flex-card bordered ` +
myel.class3 +
(rec.link ? ' titolo_card' : '')
"
:style="`
${rec.style};
height: ${myel.heightimg || '300px'};
width: ${myel.widthimg || '300px'};
flex: 0 0 auto;
`"
@click="rec.link ? tools.openUrl(rec.link) : undefined"
>
<div
class="img-container"
:style="`height: ${parseInt(myel?.heightimg?.replace('px', '')) * 0.7}px; overflow: hidden;`"
>
<q-img
:class="tools.getClassAnim(myel.anim2) + ' ' + myel.class4"
:src="tools.getImgFileByElem(myel, rec, path)"
fit="contain"
/>
</div>
<q-card-section class="q-card-section-small">
<div
:class="rec.size"
:style="`color: ${rec.color}`"
>
{{ tools.getText(rec.alt) }}
</div>
<div
:class="`q-mt-xs q-mb-xs ` + tools.getClassAnim(myel.anim)"
v-html="rec.content"
></div>
<div
v-if="rec.description"
class="text-caption"
:style="`color: ${rec.colorsub}`"
>
{{ rec.description }}
</div>
</q-card-section>
</q-card>
</div>
</template>
</div>
</div>
</q-carousel-slide>
</q-carousel>
</div>
/>
<div v-if="myel.type === shared_consts.ELEMTYPE.MARGINI"> <div v-if="myel.type === shared_consts.ELEMTYPE.MARGINI">
<div <div
:class="myel.class + (editOn ? ` clEdit` : ``) + getClass()" :class="myel.class + (editOn ? ` clEdit` : ``) + getClass()"
@@ -182,7 +61,10 @@
&nbsp; &nbsp;
</div> </div>
</div> </div>
<div v-else-if="myel.type === shared_consts.ELEMTYPE.TITLE"> <div
v-else-if="myel.type === shared_consts.ELEMTYPE.TITLE"
class="myElemBase"
>
<div> <div>
<div <div
:class=" :class="
@@ -204,7 +86,10 @@
</div> </div>
</div> </div>
</div> </div>
<div v-else-if="myel.type === shared_consts.ELEMTYPE.IMGTITLE"> <div
v-else-if="myel.type === shared_consts.ELEMTYPE.IMGTITLE"
class="myElemBase"
>
<div> <div>
<div <div
:class=" :class="
@@ -226,7 +111,10 @@
</div> </div>
</div> </div>
</div> </div>
<div v-else-if="myel.type === shared_consts.ELEMTYPE.IMGPOSTER"> <div
v-else-if="myel.type === shared_consts.ELEMTYPE.IMGPOSTER"
class="myElemBase"
>
<div <div
:class="myel.class + (editOn ? ` clEdit` : ``) + getClass()" :class="myel.class + (editOn ? ` clEdit` : ``) + getClass()"
@click="clickOnElem" @click="clickOnElem"
@@ -248,7 +136,10 @@
</CImgPoster> </CImgPoster>
</div> </div>
</div> </div>
<div v-else-if="myel.type === shared_consts.ELEMTYPE.HTML"> <div
v-else-if="myel.type === shared_consts.ELEMTYPE.HTML"
class="myElemBase"
>
<div> <div>
<div <div
:class=" :class="
@@ -263,7 +154,10 @@
></div> ></div>
</div> </div>
</div> </div>
<div v-else-if="myel.type === shared_consts.ELEMTYPE.QRCODE"> <div
v-else-if="myel.type === shared_consts.ELEMTYPE.QRCODE"
class="myElemBase"
>
<div <div
v-if="editOn" v-if="editOn"
class="elemEdit" class="elemEdit"
@@ -277,7 +171,10 @@
:imglogo="tools.getImgFileByElem(myel, undefined, path)" :imglogo="tools.getImgFileByElem(myel, undefined, path)"
></CQRCode> ></CQRCode>
</div> </div>
<div v-else-if="myel.type === shared_consts.ELEMTYPE.IMAGE"> <div
v-else-if="myel.type === shared_consts.ELEMTYPE.IMAGE"
class="myElemBase"
>
<div class="text-center"> <div class="text-center">
<div <div
:class=" :class="
@@ -300,7 +197,10 @@
</div> </div>
</div> </div>
<div v-else-if="myel.type === shared_consts.ELEMTYPE.IMAGEUPLOAD"> <div
v-else-if="myel.type === shared_consts.ELEMTYPE.IMAGEUPLOAD"
class="myElemBase"
>
<div class="text-center"> <div class="text-center">
<div <div
:class=" :class="
@@ -331,7 +231,10 @@
</div> </div>
</div> </div>
</div> </div>
<div v-else-if="myel.type === shared_consts.ELEMTYPE.VIDEO"> <div
v-else-if="myel.type === shared_consts.ELEMTYPE.VIDEO"
class="myElemBase"
>
<div <div
:class="myel.class + (editOn ? ` clEdit` : ``) + getClass()" :class="myel.class + (editOn ? ` clEdit` : ``) + getClass()"
@click="clickOnElem" @click="clickOnElem"
@@ -344,7 +247,10 @@
</q-video> </q-video>
</div> </div>
</div> </div>
<div v-else-if="myel.type === shared_consts.ELEMTYPE.VIDEO_YOUTUBE"> <div
v-else-if="myel.type === shared_consts.ELEMTYPE.VIDEO_YOUTUBE"
class="myElemBase"
>
<CMyVideoYoutube <CMyVideoYoutube
:url="myelem.container" :url="myelem.container"
:title="myelem.container2 || ''" :title="myelem.container2 || ''"
@@ -364,7 +270,10 @@
:ccLoad="myelem.ccLoad ?? false" :ccLoad="myelem.ccLoad ?? false"
/> />
</div> </div>
<div v-else-if="myel.type === shared_consts.ELEMTYPE.IMAGE_GALLERY"> <div
v-else-if="myel.type === shared_consts.ELEMTYPE.IMAGE_GALLERY"
class="myElemBase"
>
<CMyImageGallery> </CMyImageGallery> <CMyImageGallery> </CMyImageGallery>
</div> </div>
<div v-else-if="myel.type === shared_consts.ELEMTYPE.HEADING"> <div v-else-if="myel.type === shared_consts.ELEMTYPE.HEADING">
@@ -396,9 +305,6 @@
Pagina: {{ myel.container }} Pagina: {{ myel.container }}
</div> </div>
</div> </div>
<!--
<CMyPageElem v-if="myel.container" title="" :mypath="myel.container"> </CMyPageElem>
-->
</div> </div>
<div v-else-if="myel.type === shared_consts.ELEMTYPE.PAGEINTRO"> <div v-else-if="myel.type === shared_consts.ELEMTYPE.PAGEINTRO">
<div <div
@@ -574,7 +480,10 @@
> >
</CEventsCalendar> </CEventsCalendar>
</div> </div>
<div v-else-if="myel.type === shared_consts.ELEMTYPE.MAINVIEW"> <div
v-else-if="myel.type === shared_consts.ELEMTYPE.MAINVIEW"
class="myElemBase"
>
<div <div
v-if="editOn" v-if="editOn"
class="elemEdit" class="elemEdit"
@@ -592,16 +501,10 @@
</div> </div>
<CMyProfileTutorial /> <CMyProfileTutorial />
</div> </div>
<div v-else-if="myel.type === shared_consts.ELEMTYPE.CHECKAPPRUNNING"> <div
<div v-else-if="myel.type === shared_consts.ELEMTYPE.REGISTRATION"
v-if="editOn" class="myElemBase"
class="elemEdit" >
>
CheckAppRunning
</div>
<CCheckAppRunning />
</div>
<div v-else-if="myel.type === shared_consts.ELEMTYPE.REGISTRATION">
<div <div
v-if="editOn" v-if="editOn"
class="elemEdit" class="elemEdit"
@@ -638,7 +541,10 @@
</q-btn> </q-btn>
</div> </div>
</div> </div>
<div v-else-if="myel.type === shared_consts.ELEMTYPE.DASHBOARD"> <div
v-else-if="myel.type === shared_consts.ELEMTYPE.DASHBOARD"
class="myElemBase"
>
<div <div
v-if="editOn" v-if="editOn"
class="elemEdit" class="elemEdit"
@@ -647,7 +553,10 @@
</div> </div>
<CDashboard></CDashboard> <CDashboard></CDashboard>
</div> </div>
<div v-else-if="myel.type === shared_consts.ELEMTYPE.DASHGROUP"> <div
v-else-if="myel.type === shared_consts.ELEMTYPE.DASHGROUP"
class="myElemBase"
>
<div <div
v-if="editOn" v-if="editOn"
class="elemEdit" class="elemEdit"
@@ -656,7 +565,10 @@
</div> </div>
<CDashGroup></CDashGroup> <CDashGroup></CDashGroup>
</div> </div>
<div v-else-if="myel.type === shared_consts.ELEMTYPE.MOVEMENTS"> <div
v-else-if="myel.type === shared_consts.ELEMTYPE.MOVEMENTS"
class="myElemBase"
>
<div <div
v-if="editOn" v-if="editOn"
class="elemEdit" class="elemEdit"
@@ -665,7 +577,10 @@
</div> </div>
<CMovements :showbuttolastmov="true"></CMovements> <CMovements :showbuttolastmov="true"></CMovements>
</div> </div>
<div v-else-if="myel.type === shared_consts.ELEMTYPE.CSENDRISTO"> <div
v-else-if="myel.type === shared_consts.ELEMTYPE.CSENDRISTO"
class="myElemBase"
>
<div <div
v-if="editOn" v-if="editOn"
class="elemEdit" class="elemEdit"
@@ -674,7 +589,10 @@
</div> </div>
<CSendRISTo></CSendRISTo> <CSendRISTo></CSendRISTo>
</div> </div>
<div v-else-if="myel.type === shared_consts.ELEMTYPE.GRID_ORIZ"> <div
v-else-if="myel.type === shared_consts.ELEMTYPE.GRID_ORIZ"
class="myElemBase"
>
<div <div
v-if="editOn" v-if="editOn"
class="elemEdit" class="elemEdit"
@@ -691,14 +609,20 @@
:prop_modif="myel.parambool4" :prop_modif="myel.parambool4"
></CGridOriz> ></CGridOriz>
</div> </div>
<div v-else-if="myel.type === shared_consts.ELEMTYPE.SEARCHPRODUCT"> <div
v-else-if="myel.type === shared_consts.ELEMTYPE.SEARCHPRODUCT"
class="myElemBase"
>
<CSearchProduct <CSearchProduct
v-model="myel.catalogo" v-model="myel.catalogo"
table="products" table="products"
> >
</CSearchProduct> </CSearchProduct>
</div> </div>
<div v-else-if="myel.type === shared_consts.ELEMTYPE.CATALOGLIST"> <div
v-else-if="myel.type === shared_consts.ELEMTYPE.CATALOGLIST"
class="myElemBase"
>
<div <div
v-if="editOn" v-if="editOn"
class="elemEdit" class="elemEdit"
@@ -779,10 +703,16 @@
</q-tab-panel> </q-tab-panel>
</q-tab-panels> </q-tab-panels>
</div> </div>
<div v-else-if="myel.type === shared_consts.ELEMTYPE.STAT_PAGES"> <div
v-else-if="myel.type === shared_consts.ELEMTYPE.STAT_PAGES"
class="myElemBase"
>
<CPageViewStats></CPageViewStats> <CPageViewStats></CPageViewStats>
</div> </div>
<div v-else-if="myel.type === shared_consts.ELEMTYPE.RACCOLTE_CATALOGHI"> <div
v-else-if="myel.type === shared_consts.ELEMTYPE.RACCOLTE_CATALOGHI"
class="myElemBase"
>
<div <div
v-if="editOn" v-if="editOn"
class="elemEdit" class="elemEdit"
@@ -841,7 +771,10 @@
</q-tab-panel> </q-tab-panel>
</q-tab-panels> </q-tab-panels>
</div> </div>
<div v-else-if="myel.type === shared_consts.ELEMTYPE.STATUSREG"> <div
v-else-if="myel.type === shared_consts.ELEMTYPE.STATUSREG"
class="myElemBase"
>
<div <div
v-if="editOn" v-if="editOn"
class="elemEdit" class="elemEdit"
@@ -850,7 +783,10 @@
</div> </div>
<CStatusReg> </CStatusReg> <CStatusReg> </CStatusReg>
</div> </div>
<div v-else-if="myel.type === shared_consts.ELEMTYPE.CHECKIFISLOGGED"> <div
v-else-if="myel.type === shared_consts.ELEMTYPE.CHECKIFISLOGGED"
class="myElemBase"
>
<div <div
v-if="editOn" v-if="editOn"
class="elemEdit" class="elemEdit"
@@ -859,7 +795,10 @@
</div> </div>
<CCheckIfIsLogged :showalways="myel.container"></CCheckIfIsLogged> <CCheckIfIsLogged :showalways="myel.container"></CCheckIfIsLogged>
</div> </div>
<div v-else-if="myel.type === shared_consts.ELEMTYPE.VISUVIDEOPROMOANDPDF"> <div
v-else-if="myel.type === shared_consts.ELEMTYPE.VISUVIDEOPROMOANDPDF"
class="myElemBase"
>
<div <div
v-if="editOn" v-if="editOn"
class="elemEdit" class="elemEdit"
@@ -868,10 +807,16 @@
</div> </div>
<CVisuVideoPromoAndPDF :showalways="myel.container"></CVisuVideoPromoAndPDF> <CVisuVideoPromoAndPDF :showalways="myel.container"></CVisuVideoPromoAndPDF>
</div> </div>
<div v-else-if="myel.type === shared_consts.ELEMTYPE.INFO_VERSION"> <div
v-else-if="myel.type === shared_consts.ELEMTYPE.INFO_VERSION"
class="myElemBase"
>
<div>Versione: {{ tools.getvers() }}</div> <div>Versione: {{ tools.getvers() }}</div>
</div> </div>
<div v-else-if="myel.type === shared_consts.ELEMTYPE.BOTT_CONDIVIDI"> <div
v-else-if="myel.type === shared_consts.ELEMTYPE.BOTT_CONDIVIDI"
class="myElemBase"
>
<div class="row justify-evenly items-center q-pa-sm q-ma-sm"> <div class="row justify-evenly items-center q-pa-sm q-ma-sm">
<q-btn <q-btn
icon="fas fa-share" icon="fas fa-share"
@@ -893,7 +838,10 @@
</q-btn> </q-btn>
</div> </div>
</div> </div>
<div v-else-if="myel.type === shared_consts.ELEMTYPE.BOTT_CHAT_TERRITORIALE"> <div
v-else-if="myel.type === shared_consts.ELEMTYPE.BOTT_CHAT_TERRITORIALE"
class="myElemBase"
>
<div <div
v-if="editOn" v-if="editOn"
class="elemEdit" class="elemEdit"
@@ -944,7 +892,10 @@
</div> </div>
<CPresentazione></CPresentazione> <CPresentazione></CPresentazione>
</div> </div>
<div v-else-if="myel.type === shared_consts.ELEMTYPE.MYACTIVITIES"> <div
v-else-if="myel.type === shared_consts.ELEMTYPE.MYACTIVITIES"
class="myElemBase"
>
<div <div
v-if="editOn" v-if="editOn"
class="elemEdit" class="elemEdit"
@@ -953,7 +904,10 @@
</div> </div>
<CMyActivities></CMyActivities> <CMyActivities></CMyActivities>
</div> </div>
<div v-else-if="myel.type === shared_consts.ELEMTYPE.ECOMMERCE"> <div
v-else-if="myel.type === shared_consts.ELEMTYPE.ECOMMERCE"
class="myElemBase"
>
<div <div
v-if="editOn" v-if="editOn"
class="elemEdit" class="elemEdit"
@@ -962,21 +916,30 @@
</div> </div>
<CECommerce></CECommerce> <CECommerce></CECommerce>
</div> </div>
<div v-else-if="myel.type === shared_consts.ELEMTYPE.CATALOGO"> <div
v-else-if="myel.type === shared_consts.ELEMTYPE.CATALOGO"
class="myElemBase"
>
<CCatalogo <CCatalogo
v-model="myel.catalogo" v-model="myel.catalogo"
:idPage="idPage" :idPage="idPage"
@updateCatalogo="updateCatalogoEmit(myel.catalogo)" @updateCatalogo="updateCatalogoEmit(myel.catalogo)"
/> />
</div> </div>
<div v-else-if="myel.type === shared_consts.ELEMTYPE.RACCOLTA"> <div
v-else-if="myel.type === shared_consts.ELEMTYPE.RACCOLTA"
class="myElemBase"
>
<CRaccolta <CRaccolta
v-model="myel.catalogo" v-model="myel.catalogo"
:idPage="idPage" :idPage="idPage"
@updateCatalogo="updateCatalogoEmit(myel.catalogo)" @updateCatalogo="updateCatalogoEmit(myel.catalogo)"
/> />
</div> </div>
<div v-else-if="myel.type === shared_consts.ELEMTYPE.MAPPA"> <div
v-else-if="myel.type === shared_consts.ELEMTYPE.MAPPA"
class="myElemBase"
>
<div <div
v-if="editOn" v-if="editOn"
class="elemEdit" class="elemEdit"
@@ -987,7 +950,10 @@
></CMapMarker>--> ></CMapMarker>-->
</div> </div>
<div v-else-if="myel.type === shared_consts.ELEMTYPE.MAPPAUTENTI"> <div
v-else-if="myel.type === shared_consts.ELEMTYPE.MAPPAUTENTI"
class="myElemBase"
>
<div <div
v-if="editOn" v-if="editOn"
class="elemEdit" class="elemEdit"
@@ -996,7 +962,10 @@
</div> </div>
<CMapUsers></CMapUsers> <CMapUsers></CMapUsers>
</div> </div>
<div v-else-if="myel.type === shared_consts.ELEMTYPE.MAPPAGETCOORDINATE"> <div
v-else-if="myel.type === shared_consts.ELEMTYPE.MAPPAGETCOORDINATE"
class="myElemBase"
>
<div <div
v-if="editOn" v-if="editOn"
class="elemEdit" class="elemEdit"
@@ -1005,7 +974,10 @@
</div> </div>
<CMapGetCoordinates></CMapGetCoordinates> <CMapGetCoordinates></CMapGetCoordinates>
</div> </div>
<div v-else-if="myel.type === shared_consts.ELEMTYPE.EDITADDRESSBYCOORD"> <div
v-else-if="myel.type === shared_consts.ELEMTYPE.EDITADDRESSBYCOORD"
class="myElemBase"
>
<div <div
v-if="editOn" v-if="editOn"
class="elemEdit" class="elemEdit"
@@ -1017,7 +989,10 @@
v-model:model-value="coordaddr" v-model:model-value="coordaddr"
></CMapEditAddressByCoord> ></CMapEditAddressByCoord>
</div> </div>
<div v-else-if="myel.type === shared_consts.ELEMTYPE.MAPPACOMUNI"> <div
v-else-if="myel.type === shared_consts.ELEMTYPE.MAPPACOMUNI"
class="myElemBase"
>
<div <div
v-if="editOn" v-if="editOn"
class="elemEdit" class="elemEdit"
@@ -1026,7 +1001,10 @@
</div> </div>
<CMapComuni></CMapComuni> <CMapComuni></CMapComuni>
</div> </div>
<div v-else-if="myel.type === shared_consts.ELEMTYPE.TOOLSAI"> <div
v-else-if="myel.type === shared_consts.ELEMTYPE.TOOLSAI"
class="myElemBase"
>
<div <div
v-if="editOn" v-if="editOn"
class="elemEdit" class="elemEdit"
@@ -1035,7 +1013,10 @@
</div> </div>
<CAITools></CAITools> <CAITools></CAITools>
</div> </div>
<div v-else-if="myel.type === shared_consts.ELEMTYPE.CHATBOT"> <div
v-else-if="myel.type === shared_consts.ELEMTYPE.CHATBOT"
class="myElemBase"
>
<div <div
v-if="editOn" v-if="editOn"
class="elemEdit" class="elemEdit"
@@ -1044,6 +1025,15 @@
</div> </div>
<ChatBot></ChatBot> <ChatBot></ChatBot>
</div> </div>
<div v-else-if="myel.type === shared_consts.ELEMTYPE.CHECKAPPRUNNING">
<div
v-if="editOn"
class="elemEdit"
>
CheckAppRunning
</div>
<CCheckAppRunning v-if="enablePwa" />
</div>
<div v-else-if="myel.type === shared_consts.ELEMTYPE.NOTIFATTOP"> <div v-else-if="myel.type === shared_consts.ELEMTYPE.NOTIFATTOP">
<div <div
v-if="editOn" v-if="editOn"
@@ -1107,8 +1097,8 @@
</div> </div>
<div v-else> <div v-else>
<span class="mybanner" <span class="mybanner"
>* Aggiornamento APP in corso ... Se dopo 1 minuto non dovesse scomparire >Aggiornamento APP in corso ... Se dopo 1 minuto non dovesse scomparire il
questo messaggio, chiudere e riaprire la pagina.</span messaggio, chiudere e riaprire la pagina.</span
> >
</div> </div>
</q-banner> </q-banner>

View File

@@ -65,7 +65,7 @@
<!-- Contenuto pagina --> <!-- Contenuto pagina -->
<div <div
:class="[{ 'q-gutter-xs': !hideHeader, 'q-mx-auto': !hideHeader, 'q-pb-lg': !hideHeader}]" :class="[{ 'q-ma-xs': !hideHeader, 'q-mx-auto': !hideHeader }]"
:style="hideHeader ? [{ 'margin-left': 0, 'margin-right': 0 }] : containerStyle" :style="hideHeader ? [{ 'margin-left': 0, 'margin-right': 0 }] : containerStyle"
> >
<div v-if="globalStore.showHeader"> <div v-if="globalStore.showHeader">
@@ -116,6 +116,7 @@
appear appear
:duration="300" :duration="300"
enter-active-class="animated fadeInUp" enter-active-class="animated fadeInUp"
class="q-ma-none"
> >
<div> <div>
<CTitleBanner <CTitleBanner
@@ -135,8 +136,8 @@
order: {{ myelem.order }} order: {{ myelem.order }}
</div> </div>
<!-- Sezione -->
<div v-if="myelem.type === shared_consts.ELEMTYPE.SECTION"> <div v-if="myelem.type === shared_consts.ELEMTYPE.SECTION">
<!-- Sezione -->
<div <div
v-if="editOn" v-if="editOn"
class="text-center text-caption q-mb-sm" class="text-center text-caption q-mb-sm"
@@ -360,8 +361,8 @@
</CMyElem> </CMyElem>
</div> </div>
<!-- Elementi fuori sezione (retrocompatibilità) -->
<div v-else> <div v-else>
<!-- Elementi fuori sezione (retrocompatibilità) -->
<CMyElem <CMyElem
v-if="myelem.active || editOn" v-if="myelem.active || editOn"
:myelem="myelem" :myelem="myelem"
@@ -377,8 +378,8 @@
</transition> </transition>
</div> </div>
<!-- Stato vuoto -->
<div v-if="myelems.length === 0 && editOn"> <div v-if="myelems.length === 0 && editOn">
<!-- Stato vuoto -->
<CMyElem <CMyElem
:myelem="myelemVoid" :myelem="myelemVoid"
:editOn="editOn" :editOn="editOn"
@@ -390,11 +391,11 @@
/> />
</div> </div>
<!-- Aggiungi elemento al fondo lista -->
<div <div
v-if="editOn" v-if="editOn"
class="text-center q-mt-sm" class="text-center q-mt-sm"
> >
<!-- Aggiungi elemento al fondo lista -->
<q-btn <q-btn
dense dense
rounded rounded

View File

@@ -1,6 +1,6 @@
<template> <template>
<div v-if="contact"> <div v-if="contact">
<div class="row items-center"> <div class="row items-center q-mt-0 q-mb-0">
<div <div
v-if="progressStep !== 1" v-if="progressStep !== 1"
:class="indstep >= numindstep ? 'col-10' : 'col-12'" :class="indstep >= numindstep ? 'col-10' : 'col-12'"

View File

@@ -1,5 +1,5 @@
<template> <template>
<div v-if="!hide && num_notifs > 0" class="q-ma-sm text-center"> <div v-if="!hide && num_notifs > 0" class="text-center">
<q-btn <q-btn
:label=" :label="
num_notifs > 1 num_notifs > 1

View File

@@ -1,34 +1,70 @@
.drag-handle { .drag-handle {
cursor: grab; /* Mostra la manina */ cursor: grab;
} /* Mostra la manina */
}
.drag-handle:active {
cursor: grabbing; /* Cambia la manina quando l'utente sta trascinando */
}
.etichetta{ .drag-handle:active {
margin-top: 5px; cursor: grabbing;
margin-bottom: 5px; /* Cambia la manina quando l'utente sta trascinando */
padding-top: 5px; }
padding-bottom: 5px;
font-weight: bold; .etichetta {
font-size: 1.15rem; margin-top: 5px;
margin-bottom: 5px;
padding-top: 5px;
padding-bottom: 5px;
font-weight: bold;
font-size: 1.15rem;
}
.boxtitleval {
padding: 10px;
vertical-align: middle;
}
.custom-flat-button {
border: 1px solid #0078D4;
/* Colore del bordo */
background-color: transparent;
/* Rendi il background trasparente */
color: #0078D4;
/* Colore dell'icona e del testo */
}
.custom-flat-button:hover {
background-color: rgba(0, 120, 212, 0.1);
/* Aggiungi un colore di hover, se desideri */
border-color: #005A8C;
/* Colore del bordo al passaggio del mouse */
}
/* Stili per la vista responsiva */
.table-container {
overflow-x: auto;
-webkit-overflow-scrolling: touch;
}
.responsive-table {
min-width: 800px;
/* Imposta una larghezza minima per la tabella */
width: 100%;
}
.product-card {
border-left: 4px solid $primary;
}
/* Breakpoint personalizzati se necessario */
@media (max-width: 599px) {
.table-container {
display: none;
} }
}
.boxtitleval{
padding: 10px; @media (min-width: 600px) {
vertical-align: middle; .lt-md {
display: none;
} }
}
.custom-flat-button {
border: 1px solid #0078D4; /* Colore del bordo */
background-color: transparent; /* Rendi il background trasparente */
color: #0078D4; /* Colore dell'icona e del testo */
}
.custom-flat-button:hover {
background-color: rgba(0, 120, 212, 0.1); /* Aggiungi un colore di hover, se desideri */
border-color: #005A8C; /* Colore del bordo al passaggio del mouse */
}

View File

@@ -24,7 +24,7 @@
Lista filtrata con il termine "{{ searchText }}" Lista filtrata con il termine "{{ searchText }}"
</div> </div>
</div> </div>
<div class="q-mb-md text-right"> <div class="q-mb-md text-right full-width">
<q-select <q-select
v-model="selectedColumns" v-model="selectedColumns"
:options="allColumnsComputed" :options="allColumnsComputed"
@@ -147,225 +147,393 @@
</div> </div>
</div> </div>
<!-- Tabella Prodotti --> <!-- Vista Mobile: Cards -->
<table> <div class="lt-md q-pa-md">
<!-- Intestazioni (Thead) -->
<thead>
<tr>
<template v-for="col in allColumnsComputed">
<th
v-if="isColumnVisible(col.name)"
:key="col.name"
@click="isSortable(col.name) ? sortTable(col.name) : ''"
:style="{
'background-color': sortAttribute === col.name ? 'yellow' : '',
}"
>
<span>{{ col.label }}</span>
<span v-if="isSortable(col.name)">
<q-icon
v-if="sortAttribute === col.name && optcatalogo.showListaArgomenti"
:name="sortDirection === 1 ? 'expand_less' : 'expand_more'"
size="36px"
class="q-ml-xs"
/>
<q-icon
v-else-if="optcatalogo.showListaArgomenti"
:name="sortDirection === 1 ? 'expand_less' : 'expand_more'"
size="24px"
class="q-ml-xs"
/>
</span>
</th>
</template>
</tr>
</thead>
<!-- Corpo della Tabella (Tbody) -->
<draggable <draggable
v-if="!loading" v-if="!loading"
:model-value="internalProducts" :model-value="internalProducts"
tag="tbody" tag="div"
handle=".drag-handle" handle=".drag-handle"
item-key="_id" item-key="_id"
@end="onDragEnd" @end="onDragEnd"
@update:modelValue="handleUpdate" @update:modelValue="handleUpdate"
> >
<template #item="{ element }"> <template #item="{ element, index }">
<tr <q-card
:key="element._id" :key="element._id"
:class="{ class="q-mb-md product-card"
'bg-grey-3': internalProducts.indexOf(element) % 2 === 1, flat
}" bordered
> >
<template <q-card-section class="row items-center q-pa-sm bg-grey-2">
v-for="field in allColumnsComputed" <div class="col">
:key="field.name" <div class="text-weight-bold">
> #{{ index + 1 }} - {{ getFieldValue(element, { name: 'title' }) || 'Prodotto' }}
<!-- Icona Drag Handle -->
<td v-if="field.name === 'pos' && isColumnVisible('pos')">
<div class="row justify-center">
<span class="q-ma-sm"
>{{
// put index in the first column
internalProducts.indexOf(element) + 1
}}
</span>
</div> </div>
</td> </div>
<td <div class="col-auto">
v-else-if="field.name === 'drag' && isColumnVisible('drag')"
class="drag-handle"
>
<q-icon <q-icon
v-if="isColumnVisible('drag')"
name="drag_handle" name="drag_handle"
size="32px" size="24px"
color="primary" color="primary"
class="drag-handle cursor-pointer"
/> />
</td> </div>
<td v-else-if="field.name === 'edit' && isColumnVisible('edit')"> </q-card-section>
<span
v-if="!tools.isUtente()" <q-separator />
class="justify-center"
<q-card-section class="q-pa-md">
<div class="row q-col-gutter-md">
<!-- Immagine -->
<div
v-if="isColumnVisible('image')"
class="col-12 col-sm-4 text-center"
> >
<q-btn <q-img
flat :src="
rounded getImageByElement(element)
outline ? tools.getFullFileNameByImageFile(
size="sm" table,
icon="edit" getImageByElement(element),
@click="modifyProduct(element)" element._id
)
: element.productInfo?.image_link
"
style="max-width: 150px; max-height: 150px"
class="rounded-borders cursor-pointer q-mx-auto"
@click="showProduct(element)"
/>
</div>
<!-- Dati Prodotto -->
<div class="col-12 col-sm-8">
<template v-for="field in allColumnsComputed" :key="field.name">
<div
v-if="
isColumnVisible(field.name) &&
!['pos', 'drag', 'image', 'edit', 'actions', 'addtocart', 'addtolist'].includes(field.name)
"
class="q-mb-sm"
>
<div class="text-caption text-grey-7">{{ field.label }}</div>
<div
:class="getFieldClass(element, field)"
@click="getFieldClick(element, field)?.()"
v-html="getFieldValue(element, field)"
></div>
</div>
</template>
</div>
</div>
</q-card-section>
<q-separator />
<!-- Azioni Card -->
<q-card-actions class="q-pa-sm">
<q-btn
v-if="!tools.isUtente() && isColumnVisible('edit')"
flat
dense
icon="edit"
label="Modifica"
@click="modifyProduct(element)"
color="primary"
/>
<q-space />
<q-btn
v-if="isColumnVisible('addtocart')"
dense
icon-right="fas fa-cart-plus"
color="positive"
:label="
t('products.addcart', {
qta: ProductStore.qtaNextAdd(element.myorder, element),
})
"
@click="addtoCart(element, true)"
/>
<q-btn
v-if="isColumnVisible('addtocart') && ProductStore.enableSubQty(element.myorder)"
dense
icon-right="fas fa-cart-arrow-down"
color="negative"
:label="
t('products.subcart', {
qta: ProductStore.qtaNextSub(element.myorder, element),
})
"
@click="addtoCart(element, false)"
/>
<q-btn
v-if="isColumnVisible('addtolist') && isElementVisible('addtolist', element)"
dense
icon="fas fa-plus"
color="primary"
@click="addtolist(element)"
/>
<q-btn-dropdown
v-if="isColumnVisible('actions', true)"
dense
flat
icon="more_vert"
color="primary"
>
<q-list>
<q-item
v-if="isVisibleEditBtn"
clickable
v-close-popup v-close-popup
class="custom-flat-button" @click="modifyProduct(element)"
>
<q-item-section>
<q-item-label>
<q-icon name="edit" size="20px" class="q-mr-xs" />
Scheda
</q-item-label>
</q-item-section>
</q-item>
<q-item
clickable
v-close-popup
@click="removeProduct(element)"
>
<q-item-section>
<q-item-label>
<q-icon name="delete" size="20px" class="q-mr-xs" />
Elimina
</q-item-label>
</q-item-section>
</q-item>
</q-list>
</q-btn-dropdown>
</q-card-actions>
</q-card>
</template>
</draggable>
</div>
<!-- Vista Desktop/Tablet: Tabella con Scroll Orizzontale -->
<div class="gt-sm table-container">
<table class="responsive-table">
<!-- Intestazioni (Thead) -->
<thead>
<tr>
<template v-for="col in allColumnsComputed">
<th
v-if="isColumnVisible(col.name)"
:key="col.name"
@click="isSortable(col.name) ? sortTable(col.name) : ''"
:style="{
'background-color': sortAttribute === col.name ? 'yellow' : '',
}"
>
<span>{{ col.label }}</span>
<span v-if="isSortable(col.name)">
<q-icon
v-if="sortAttribute === col.name && optcatalogo.showListaArgomenti"
:name="sortDirection === 1 ? 'expand_less' : 'expand_more'"
size="36px"
class="q-ml-xs"
/>
<q-icon
v-else-if="optcatalogo.showListaArgomenti"
:name="sortDirection === 1 ? 'expand_less' : 'expand_more'"
size="24px"
class="q-ml-xs"
/> />
</span> </span>
</td> </th>
<td v-else-if="field.name === 'addtocart' && isColumnVisible('addtocart')">
<q-btn
icon-right="fas fa-cart-plus"
color="positive"
rounded
dense
size="sm"
:label="
t('products.addcart', {
qta: ProductStore.qtaNextAdd(element.myorder, element),
})
"
@click="addtoCart(element, true)"
>
</q-btn>
<q-btn
v-if="ProductStore.enableSubQty(element.myorder)"
icon-right="fas fa-cart-arrow-down"
color="negative"
rounded
dense
size="sm"
:label="
t('products.subcart', {
qta: ProductStore.qtaNextSub(element.myorder, element),
})
"
@click="addtoCart(element, false)"
>
</q-btn>
</td>
<td
v-else-if="
field.name === 'addtolist' &&
isColumnVisible('addtolist') &&
isElementVisible('addtolist', element)
"
>
<q-btn
icon="fas fa-plus"
color="primary"
rounded
dense
size="sm"
@click="addtolist(element)"
>
</q-btn>
</td>
<!-- Immagine Piccola -->
<td v-else-if="field.name === 'image' && isColumnVisible('image')">
<q-img
:src="
getImageByElement(element)
? tools.getFullFileNameByImageFile(
table,
getImageByElement(element),
element._id
)
: element.productInfo?.image_link
"
style="width: 50px; height: 50px"
class="rounded-borders cursor-pointer"
@click="showProduct(element)"
/>
</td>
<td
v-else-if="isColumnVisible(field.name)"
:class="getFieldClass(element, field)"
:style="getFieldStyle(element, field)"
@click="getFieldClick(element, field)?.()"
>
<span v-html="getFieldValue(element, field)"></span>
</td>
<!-- Azioni -->
<td
v-else-if="field.name === 'actions' && isColumnVisible('actions', true)"
>
<q-btn-dropdown
label="Azioni"
color="primary"
flat
>
<q-list>
<q-item
v-if="isVisibleEditBtn"
clickable
v-close-popup
@click="modifyProduct(element)"
>
<q-item-section>
<q-item-label>
<q-icon
name="edit"
size="20px"
class="q-mr-xs"
/>
Scheda
</q-item-label>
</q-item-section>
</q-item>
<q-item
clickable
v-close-popup
@click="removeProduct(element)"
>
<q-item-section>
<q-item-label>
<q-icon
name="delete"
size="20px"
class="q-mr-xs"
/>
Elimina
</q-item-label>
</q-item-section>
</q-item>
</q-list>
</q-btn-dropdown>
</td>
</template> </template>
</tr></template </tr>
</thead>
<!-- Corpo della Tabella (Tbody) -->
<draggable
v-if="!loading"
:model-value="internalProducts"
tag="tbody"
handle=".drag-handle"
item-key="_id"
@end="onDragEnd"
@update:modelValue="handleUpdate"
> >
> <template #item="{ element }">
</draggable> <tr
</table> :key="element._id"
:class="{
'bg-grey-3': internalProducts.indexOf(element) % 2 === 1,
}"
>
<template
v-for="field in allColumnsComputed"
:key="field.name"
>
<!-- Icona Drag Handle -->
<td v-if="field.name === 'pos' && isColumnVisible('pos')">
<div class="row justify-center">
<span class="q-ma-sm"
>{{
internalProducts.indexOf(element) + 1
}}
</span>
</div>
</td>
<td
v-else-if="field.name === 'drag' && isColumnVisible('drag')"
class="drag-handle"
>
<q-icon
name="drag_handle"
size="32px"
color="primary"
/>
</td>
<td v-else-if="field.name === 'edit' && isColumnVisible('edit')">
<span
v-if="!tools.isUtente()"
class="justify-center"
>
<q-btn
flat
rounded
outline
size="sm"
icon="edit"
@click="modifyProduct(element)"
v-close-popup
class="custom-flat-button"
/>
</span>
</td>
<td v-else-if="field.name === 'addtocart' && isColumnVisible('addtocart')">
<q-btn
icon-right="fas fa-cart-plus"
color="positive"
rounded
dense
size="sm"
:label="
t('products.addcart', {
qta: ProductStore.qtaNextAdd(element.myorder, element),
})
"
@click="addtoCart(element, true)"
>
</q-btn>
<q-btn
v-if="ProductStore.enableSubQty(element.myorder)"
icon-right="fas fa-cart-arrow-down"
color="negative"
rounded
dense
size="sm"
:label="
t('products.subcart', {
qta: ProductStore.qtaNextSub(element.myorder, element),
})
"
@click="addtoCart(element, false)"
>
</q-btn>
</td>
<td
v-else-if="
field.name === 'addtolist' &&
isColumnVisible('addtolist') &&
isElementVisible('addtolist', element)
"
>
<q-btn
icon="fas fa-plus"
color="primary"
rounded
dense
size="sm"
@click="addtolist(element)"
>
</q-btn>
</td>
<!-- Immagine Piccola -->
<td v-else-if="field.name === 'image' && isColumnVisible('image')">
<q-img
:src="
getImageByElement(element)
? tools.getFullFileNameByImageFile(
table,
getImageByElement(element),
element._id
)
: element.productInfo?.image_link
"
style="width: 50px; height: 50px"
class="rounded-borders cursor-pointer"
@click="showProduct(element)"
/>
</td>
<td
v-else-if="isColumnVisible(field.name)"
:class="getFieldClass(element, field)"
:style="getFieldStyle(element, field)"
@click="getFieldClick(element, field)?.()"
>
<span v-html="getFieldValue(element, field)"></span>
</td>
<!-- Azioni -->
<td
v-else-if="field.name === 'actions' && isColumnVisible('actions', true)"
>
<q-btn-dropdown
label="Azioni"
color="primary"
flat
>
<q-list>
<q-item
v-if="isVisibleEditBtn"
clickable
v-close-popup
@click="modifyProduct(element)"
>
<q-item-section>
<q-item-label>
<q-icon
name="edit"
size="20px"
class="q-mr-xs"
/>
Scheda
</q-item-label>
</q-item-section>
</q-item>
<q-item
clickable
v-close-popup
@click="removeProduct(element)"
>
<q-item-section>
<q-item-label>
<q-icon
name="delete"
size="20px"
class="q-mr-xs"
/>
Elimina
</q-item-label>
</q-item-section>
</q-item>
</q-list>
</q-btn-dropdown>
</td>
</template>
</tr>
</template>
</draggable>
</table>
</div>
</div> </div>
<CMyDialog <CMyDialog
v-model="showProd" v-model="showProd"

View File

@@ -2258,7 +2258,7 @@ $coloreprincipale: lightblue;
} }
.card-carousel-container { .card-carousel-container {
max-width: 100%; width: 100%;
overflow: hidden; overflow: hidden;
position: relative; position: relative;
} }
@@ -2852,7 +2852,6 @@ body.body--dark {
.card-group-scrollable { .card-group-scrollable {
width: 100%; width: 100%;
overflow-x: auto; overflow-x: auto;
overflow-y: hidden;
-webkit-overflow-scrolling: touch; // smooth scroll su iOS -webkit-overflow-scrolling: touch; // smooth scroll su iOS
scrollbar-width: none; // nasconde scrollbar su Firefox scrollbar-width: none; // nasconde scrollbar su Firefox
-ms-overflow-style: none; // nasconde scrollbar su IE/Edge -ms-overflow-style: none; // nasconde scrollbar su IE/Edge

View File

@@ -1,9 +1,9 @@
const msg_website_it = { const msg_website_it = {
ws: { ws: {
sitename: 'Gruppo Macro', sitename: 'RISO',
siteshortname: 'Gruppo Macro', siteshortname: 'RISO',
description: '', description: 'Siamo la Rete Italiana di Scambio Orizzontale, abbiamo creato questa piattaforma per metterla al servizio di chi vuole riscoprire il valore della condivisione e della cooperazione. Valori semplici e profondi che ci aiutano a ritrovare il Senso della Vita, perduto in questa società consumista, e riporti quei Sani Pricìpi Naturali ed Umani di Fratellanza che intere popolazioni antiche conoscevano bene.',
keywords: '', keywords: 'riso, piattaforma di scambio, rete italiana scambio orizzontale, riso app, riso piattaforma, scambio e baratto, momenta RIS',
}, },
hours: { hours: {
descr: 'Descrizione', descr: 'Descrizione',
@@ -16,20 +16,29 @@ const msg_website_it = {
pages: { pages: {
home: 'Home', home: 'Home',
profile: 'Profilo', profile: 'Profilo',
install_site: 'Installa Sito',
profile2: 'ProfiloU', profile2: 'ProfiloU',
mypage2: 'mypage2', mypage2: 'mypage2',
myservice2: 'myservice2', myservice2: 'myservice2',
myhosps2: 'myhosps2', myhosps2: 'myhosps2',
mygood2: 'mygood2', mygood2: 'mygood2',
catalogo: 'Catalogo',
fundraising: 'Sostieni il Progetto', fundraising: 'Sostieni il Progetto',
notifs: 'Configura le Notifiche', notifs: 'Configura le Notifiche',
unsubscribe: 'Disiscriviti', unsubscribe: 'Disiscriviti',
unsubscribe_user: 'Disiscriviti User',
test: 'Test', test: 'Test',
projects: 'Progetti', projects: 'Progetti',
report: 'Report Ore', report: 'Report Ore',
producer: 'Produttore',
orderinfo: 'Ordini Effettuati',
products: 'Prodotti',
productslist: 'Lista Prodotti',
collabora: 'Collabora',
storehouses: 'Magazzino',
departments: 'Uffici',
orders: 'Ordini Ricevuti',
orders2: 'Ordini Ricevuti',
sharewithus: 'Condividi con Noi',
checkout: 'Carrello',
payment: 'Pagamenti',
regok: 'Registrazione Confermata', regok: 'Registrazione Confermata',
presentazione: 'Presentazione', presentazione: 'Presentazione',
presentazione2: 'Presentazione', presentazione2: 'Presentazione',
@@ -75,12 +84,14 @@ const msg_website_it = {
eventodef: 'Evento:', eventodef: 'Evento:',
prova: 'prova', prova: 'prova',
dbop: 'Operazioni', dbop: 'Operazioni',
dbopmacro: 'Operazioni Macro',
projall: 'Comunitari', projall: 'Comunitari',
groups: 'Lista Gruppi', groups: 'Lista Gruppi',
projectsShared: 'Condivisi da me', projectsShared: 'Condivisi da me',
myprojects: 'Privati', myprojects: 'Privati',
favproj: 'Favoriti', favproj: 'Favoriti',
admin_ecommerce: 'ECommerce',
ecommerce: 'Prodotti',
ecommerce_menu: 'ECommerce1',
hours: 'Ore', hours: 'Ore',
department: 'Uffici', department: 'Uffici',
title: 'Titolo', title: 'Titolo',
@@ -109,11 +120,16 @@ const msg_website_it = {
onlyif_logged: 'Solo se Loggati', onlyif_logged: 'Solo se Loggati',
only_residenti: 'Solo Residenti', only_residenti: 'Solo Residenti',
only_consiglio: 'Solo Consiglieri', only_consiglio: 'Solo Consiglieri',
only_collab: 'Solo Collaboratori',
color: 'Colore', color: 'Colore',
mainMenu: 'Menu Principale',
subtitle: 'Sottotitolo',
lang: 'Lingua',
keywords: 'Parole Chiave',
desctiption: 'Descrizione',
heightimg: 'Altezza Immagine',
}, },
msg: { msg: {
myAppName: 'Più che Buono', myAppName: 'Riso',
myAppDescription: 'Il primo Vero Social Libero, Equo e Solidale, dove Vive Consapevolezza e Aiuto Comunitario. Gratuito', myAppDescription: 'Il primo Vero Social Libero, Equo e Solidale, dove Vive Consapevolezza e Aiuto Comunitario. Gratuito',
underconstruction: 'App in costruzione...', underconstruction: 'App in costruzione...',
myDescriz: '', myDescriz: '',
@@ -172,18 +188,7 @@ const msg_website_it = {
descr: '<ul class="mylist" style="padding-left: 20px;">' descr: '<ul class="mylist" style="padding-left: 20px;">'
+ '<li>📱<strong>Condividendo la APP</strong> a tutti coloro che vogliono far parte insieme della crescita e sviluppo di una Nuova Era</li>' + '<li>📱<strong>Condividendo la APP</strong> a tutti coloro che vogliono far parte insieme della crescita e sviluppo di una Nuova Era</li>'
+ '<li>👥 Aiutando a creare Gruppi Territoriali nella vostra città, impegnandosi a realizzare progetti per il Bene Comune, in onore ai principi Amorevoli e di condivisione.</li>' + '<li>👥 Aiutando a creare Gruppi Territoriali nella vostra città, impegnandosi a realizzare progetti per il Bene Comune, in onore ai principi Amorevoli e di condivisione.</li>'
+ '<li>🌱 Sostenendo le persone attorno a voi, e rispettando la nostra vera Casa: Madre Natura e Tutti gli Esseri Viventi. ❤️</li>' + '<li>🌱 Sostenendo le persone attorno a voi, e rispettando la nostra vera Casa: Madre Natura e Tutti gli Esseri Viventi. ❤️</li>' +
+ '<li>👨🏻‍💻 Con una <strong>piccola donazione</strong> per le spese dei Server, manutenzione e per i continui sviluppi e miglioramenti</li></ul>' +
'1) Tramite <strong><a href="https://paypal.me/paoloarena" target="_blank">Paypal</a></strong>:<br>' +
'<br>2) Tramite <strong>Satispay</strong>: <a href="https://www.satispay.com/app/match/link/money-box/S6Y-SVN--62712D42-35B0-4BB9-8511-410C2AB8CD45" target="_blank">Clicca qui</a><br>' +
'<div style="font-size: 1rem; background-color: white; color: blue; border: solid 2px #f00; margin: 5px; padding: 5px; border-radius: 10px; " ' +
'class="row justify-around">' +
'Se ancora non hai Satispay <a href="https://www.satispay.com/promo/PAOLOARENA4">Richiedila cliccando qui</a></br>' +
'</div>' +
'<br>3) Tramite <strong>Bonifico Bancario</strong>:<br>' +
'(Scrivi a Surya (<a href="https://t.me/surya1977">@surya1977</a>) per le coordinate</br>' +
'' +
'4) In alternativa scegli tu una forma di Dono <br />' +
'Grazie Mille per l\'Aiuto ed il Supporto' + 'Grazie Mille per l\'Aiuto ed il Supporto' +
'<br>', '<br>',
}, },

View File

@@ -1,6 +1,6 @@
/* GRUPPOMACRO APP /* RISO APP
*/ */
import { import type {
IListRoutes, IListRoutes,
ILang, ILang,
IPreloadImages, IPreloadImages,
@@ -44,7 +44,6 @@ const firstPage = {
infooter: true, infooter: true,
} }
function getDynamicPages(site: ISites): IListRoutes[] { function getDynamicPages(site: ISites): IListRoutes[] {
const baseroutes: IListRoutes[] = [ const baseroutes: IListRoutes[] = [
@@ -71,11 +70,34 @@ function getDynamicPages(site: ISites): IListRoutes[] {
}, },
{ {
active: true, active: true,
order: 400, order: 12,
path: '/test-lungo', path: '/goods',
materialIcon: 'fas fa-test', materialIcon: 'fas fa-tshirt',
name: 'mypages.test_lungo', name: 'mypages.goods',
component: () => import('@src/views/testLungo/testLungo.vue'), component: () => import('@src/root/goods/goods.vue'),
meta: { requiresAuth: true },
inmenu: true,
infooter: true,
},
{
active: true,
order: 15,
path: '/services',
materialIcon: 'fas fa-house-user',
name: 'mypages.services',
component: () => import('@src/root/services/services.vue'),
meta: { requiresAuth: true },
inmenu: true,
infooter: true,
},
{
active: true,
order: 15,
path: '/activities',
materialIcon: 'fas fa-house-user',
name: 'mypages.activities',
component: () => import('@src/root/activities/activities.vue'),
meta: { requiresAuth: true },
inmenu: false, inmenu: false,
infooter: false, infooter: false,
}, },
@@ -90,6 +112,17 @@ function getDynamicPages(site: ISites): IListRoutes[] {
inmenu: false, inmenu: false,
infooter: false, infooter: false,
}, },
{
active: true,
order: 15,
path: '/hosps',
materialIcon: 'fas fa-bed',
name: 'mypages.hosp',
component: () => import('@src/root/hosp/hosp.vue'),
meta: { requiresAuth: true },
inmenu: true,
infooter: true,
},
{ {
active: site.confpages && site.confpages.enableCircuits, active: site.confpages && site.confpages.enableCircuits,
order: 16, order: 16,
@@ -102,7 +135,7 @@ function getDynamicPages(site: ISites): IListRoutes[] {
infooter: true, infooter: true,
}, },
{ {
active: site.confpages && site.confpages.enableEvents, active: true,
order: 20, order: 20,
path: '/events', path: '/events',
materialIcon: 'fas fa-bullhorn', materialIcon: 'fas fa-bullhorn',
@@ -124,7 +157,7 @@ function getDynamicPages(site: ISites): IListRoutes[] {
infooter: false, infooter: false,
}, },
{ {
active: site.confpages && site.confpages.showProfile, active: true,
order: 120, order: 120,
path: '/myprofile', path: '/myprofile',
materialIcon: 'fas fa-user', materialIcon: 'fas fa-user',
@@ -135,7 +168,7 @@ function getDynamicPages(site: ISites): IListRoutes[] {
infooter: true, infooter: true,
}, },
{ {
active: site.confpages && site.confpages.showProfile, active: true,
order: 120, order: 120,
path: '/editprofile', path: '/editprofile',
materialIcon: 'fas fa-user', materialIcon: 'fas fa-user',
@@ -146,7 +179,7 @@ function getDynamicPages(site: ISites): IListRoutes[] {
infooter: false, infooter: false,
}, },
{ {
active: site.confpages && site.confpages.showiscrittiMenu, active: true,
order: 130, order: 130,
path: '/friends', path: '/friends',
materialIcon: 'fas fa-user-friends', materialIcon: 'fas fa-user-friends',
@@ -241,6 +274,16 @@ function getDynamicPages(site: ISites): IListRoutes[] {
inmenu: false, inmenu: false,
infooter: false, infooter: false,
}, },
{
active: true,
order: 150,
path: '/sostieniilprogetto',
materialIcon: 'fas fa-hand-holding-heart',
name: 'pages.fundraising',
component: () => import('@src/root/fundraising/fundraising.vue'),
inmenu: false,
infooter: false,
},
{ {
active: true, active: true,
order: 80, order: 80,
@@ -259,7 +302,7 @@ function getDynamicPages(site: ISites): IListRoutes[] {
export function firstimagehome() { export function firstimagehome() {
let img = 'statics/images/background.jpg' const img = 'statics/images/background.jpg'
return img return img
} }

View File

@@ -1,33 +1,38 @@
import { useGlobalStore } from '@store/globalStore' import { useGlobalStore } from '@store/globalStore';
import { useUserStore } from '@store/UserStore' import { useUserStore } from '@store/UserStore';
export * from './ApiTypes' export * from './ApiTypes';
import axios from 'axios' import axios from 'axios';
export { addAuthHeaders, API_URL } from './Instance' export { addAuthHeaders, API_URL } from './Instance';
// import {AlgoliaSearch} from './AlgoliaController' // import {AlgoliaSearch} from './AlgoliaController'
import Paths from '@paths' import Paths from '@paths';
import { tools } from '@src/store/Modules/tools' import { tools } from '@src/store/Modules/tools';
import { toolsext } from '@src/store/Modules/toolsext' import { toolsext } from '@src/store/Modules/toolsext';
import { serv_constants } from '@src/store/Modules/serv_constants' import { serv_constants } from '@src/store/Modules/serv_constants';
import type * as Types from '@src/store/Api/ApiTypes' import type * as Types from '@src/store/Api/ApiTypes';
import { costanti } from '@src/store/Modules/costanti' import { costanti } from '@src/store/Modules/costanti';
import * as ApiTables from '@src/store/Modules/ApiTables' import * as ApiTables from '@src/store/Modules/ApiTables';
import sendRequest from './Inst-Pao' import sendRequest from './Inst-Pao';
import Request from './Instance' import Request from './Instance';
import globalroutines from '../../globalroutines/index' import globalroutines from '../../globalroutines/index';
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router';
function ReceiveResponsefromServer(tablesync: string, nametab: string, method: string, risdata: any) { function ReceiveResponsefromServer(
tablesync: string,
nametab: string,
method: string,
risdata: any
) {
// console.log('ReceiveResponsefromServer', nametab, method, risdata) // console.log('ReceiveResponsefromServer', nametab, method, risdata)
if (risdata) { if (risdata) {
// Updated somw data after Server arrived data. // Updated somw data after Server arrived data.
if (method === 'PATCH') { if (method === 'PATCH') {
if (nametab === 'projects') { if (nametab === 'projects') {
if (risdata.projectris) { if (risdata.projectris) {
const copyrec = tools.jsonCopy(risdata.projectris) const copyrec = tools.jsonCopy(risdata.projectris);
// +*Todo conv: Projects.updateProject({ objproj: copyrec }) // +*Todo conv: Projects.updateProject({ objproj: copyrec })
} }
} }
@@ -38,52 +43,56 @@ function ReceiveResponsefromServer(tablesync: string, nametab: string, method: s
// const algoliaApi = new AlgoliaSearch() // const algoliaApi = new AlgoliaSearch()
export const Api = { export const Api = {
async post(path: string, payload?: any, responsedata?: any, options?: any) { async post(path: string, payload?: any, responsedata?: any, options?: any) {
const globalStore = useGlobalStore() const globalStore = useGlobalStore();
globalStore.connData.downloading_server = 1 globalStore.connData.downloading_server = 1;
globalStore.connData.uploading_server = 1 globalStore.connData.uploading_server = 1;
return await Request('post', path, payload, responsedata, options) return await Request('post', path, payload, responsedata, options);
}, },
async postFormData(path: string, payload?: any, responsedata?: any) { async postFormData(path: string, payload?: any, responsedata?: any) {
const globalStore = useGlobalStore() const globalStore = useGlobalStore();
globalStore.connData.uploading_server = 1 globalStore.connData.uploading_server = 1;
globalStore.connData.downloading_server = 1 globalStore.connData.downloading_server = 1;
return await Request('postFormData', path, payload, responsedata) return await Request('postFormData', path, payload, responsedata);
}, },
async get(path: string, payload?: any, responsedata?: any) { async get(path: string, payload?: any, responsedata?: any) {
const globalStore = useGlobalStore() const globalStore = useGlobalStore();
globalStore.connData.downloading_server = 1 globalStore.connData.downloading_server = 1;
globalStore.connData.uploading_server = 0 globalStore.connData.uploading_server = 0;
return await Request('get', path, payload, responsedata) return await Request('get', path, payload, responsedata);
}, },
async put(path: string, payload?: any, responsedata?: any) { async put(path: string, payload?: any, responsedata?: any) {
const globalStore = useGlobalStore() const globalStore = useGlobalStore();
globalStore.connData.uploading_server = 1 globalStore.connData.uploading_server = 1;
return await Request('put', path, payload, responsedata) return await Request('put', path, payload, responsedata);
}, },
async patch(path: string, payload?: any, responsedata?: any) { async patch(path: string, payload?: any, responsedata?: any) {
const globalStore = useGlobalStore() const globalStore = useGlobalStore();
globalStore.connData.uploading_server = 1 globalStore.connData.uploading_server = 1;
return await Request('patch', path, payload, responsedata) return await Request('patch', path, payload, responsedata);
}, },
async Delete(path: string, payload: any, responsedata?: any) { async Delete(path: string, payload: any, responsedata?: any) {
const globalStore = useGlobalStore() const globalStore = useGlobalStore();
globalStore.connData.uploading_server = 1 globalStore.connData.uploading_server = 1;
return await Request('delete', path, payload, responsedata) return await Request('delete', path, payload, responsedata);
}, },
async checkSession({ token, refresh_token }: any) { async checkSession({ token, refresh_token }: any) {
return await axios.post(import.meta.env.VITE_API_URL + Paths.TOKEN_REFRESH, { return await axios.post(
refresh_token, import.meta.env.VITE_API_URL + Paths.TOKEN_REFRESH,
}, { {
headers: { refresh_token,
Authorization: `Bearer ${token}`,
}, },
}) {
headers: {
Authorization: `Bearer ${token}`,
},
}
);
}, },
async refreshToken() { async refreshToken() {
@@ -96,7 +105,9 @@ export const Api = {
return false; return false;
} }
const response = await sendRequest('/users/newtok', 'POST', { refreshToken: refrTok }); const response = await sendRequest('/users/newtok', 'POST', {
refreshToken: refrTok,
});
if (response && response.data) { if (response && response.data) {
// Salva il nuovo access token // Salva il nuovo access token
@@ -105,7 +116,10 @@ export const Api = {
// Aggiorna il refresh token se fornito dal server // Aggiorna il refresh token se fornito dal server
if (response.data.refreshToken) { if (response.data.refreshToken) {
userStore.setRefreshToken(response.data.refreshToken); userStore.setRefreshToken(response.data.refreshToken);
localStorage.setItem(toolsext.localStorage.refreshToken, response.data.refreshToken); localStorage.setItem(
toolsext.localStorage.refreshToken,
response.data.refreshToken
);
} }
return response.data.token; return response.data.token;
@@ -122,10 +136,21 @@ export const Api = {
} }
}, },
async checkTokenScaduto(status: number, evitaloop: boolean, url: string, method: string, mydata: any, setAuthToken: boolean = false, statuscode2: number = 0) { async checkTokenScaduto(
status: number,
evitaloop: boolean,
url: string,
method: string,
mydata: any,
setAuthToken: boolean = false,
statuscode2: number = 0
) {
const userStore = useUserStore(); const userStore = useUserStore();
if (status === serv_constants.RIS_CODE__HTTP_FORBIDDEN_TOKEN_EXPIRED || statuscode2 === serv_constants.RIS_CODE__HTTP_FORBIDDEN_TOKEN_EXPIRED) { if (
status === serv_constants.RIS_CODE__HTTP_FORBIDDEN_TOKEN_EXPIRED ||
statuscode2 === serv_constants.RIS_CODE__HTTP_FORBIDDEN_TOKEN_EXPIRED
) {
try { try {
console.log('Token scaduto. Tentativo di refresh...'); console.log('Token scaduto. Tentativo di refresh...');
const newAccessToken = await this.refreshToken(); const newAccessToken = await this.refreshToken();
@@ -140,26 +165,34 @@ export const Api = {
} else { } else {
// Se il refresh token fallisce, logout dell'utente // Se il refresh token fallisce, logout dell'utente
// userStore.setAuth('', ''); // userStore.setAuth('', '');
const $router = useRouter() const $router = useRouter();
throw { code: toolsext.ERR_RETRY_LOGIN }; throw { code: toolsext.ERR_RETRY_LOGIN };
} }
} catch (err2) { } catch (err2) {
console.error('Errore durante il refresh token:', err2); console.error('Errore durante il refresh token:', err2);
let mystatus = err2?.code || err2?.status let mystatus = err2?.code || err2?.status;
if (mystatus === serv_constants.RIS_CODE__HTTP_FORBIDDEN_INVALID_TOKEN || mystatus === toolsext.ERR_RETRY_LOGIN) { if (
mystatus === serv_constants.RIS_CODE__HTTP_FORBIDDEN_INVALID_TOKEN ||
mystatus === serv_constants.RIS_CODE__HTTP_FORBIDDEN_PERMESSI ||
mystatus === toolsext.ERR_RETRY_LOGIN
) {
userStore.setServerCode(toolsext.ERR_AUTHENTICATION); userStore.setServerCode(toolsext.ERR_AUTHENTICATION);
userStore.setAuth('', ''); userStore.setAuth('', '');
throw { status: toolsext.ERR_RETRY_LOGIN }; throw { status: toolsext.ERR_RETRY_LOGIN };
} }
// Gestione di altri errori critici // Gestione di altri errori critici
throw err2 || {status: serv_constants.RIS_CODE__HTTP_FORBIDDEN_INVALID_TOKEN} ; throw err2 || { status: serv_constants.RIS_CODE__HTTP_FORBIDDEN_INVALID_TOKEN };
} }
} else if (status === serv_constants.RIS_CODE__HTTP_FORBIDDEN_INVALID_TOKEN || statuscode2 === serv_constants.RIS_CODE__HTTP_FORBIDDEN_INVALID_TOKEN) { } else if (
status === serv_constants.RIS_CODE__HTTP_FORBIDDEN_INVALID_TOKEN ||
status === serv_constants.RIS_CODE__HTTP_FORBIDDEN_PERMESSI ||
statuscode2 === serv_constants.RIS_CODE__HTTP_FORBIDDEN_INVALID_TOKEN
) {
userStore.setAuth('', ''); userStore.setAuth('', '');
const $router = useRouter() const $router = useRouter();
throw { status: toolsext.ERR_RETRY_LOGIN }; throw { status: toolsext.ERR_RETRY_LOGIN };
} }
@@ -167,7 +200,16 @@ export const Api = {
}, },
// Base per la chiamata con gestione degli errori e retry // Base per la chiamata con gestione degli errori e retry
async SendReqBase(url: string, method: string, mydata: any, setAuthToken = false, evitaloop = false, myformdata: any, responsedata: any, options: any) { async SendReqBase(
url: string,
method: string,
mydata: any,
setAuthToken = false,
evitaloop = false,
myformdata: any,
responsedata: any,
options: any
) {
const mydataout = { const mydataout = {
...mydata, ...mydata,
keyappid: import.meta.env.VITE_PAO_APP_ID, keyappid: import.meta.env.VITE_PAO_APP_ID,
@@ -180,7 +222,14 @@ export const Api = {
userStore.setResStatus(0); userStore.setResStatus(0);
try { try {
const res = await sendRequest(url, method, mydataout, myformdata, responsedata, options); const res = await sendRequest(
url,
method,
mydataout,
myformdata,
responsedata,
options
);
// Aggiornamento dello stato della connessione dopo 1 secondo // Aggiornamento dello stato della connessione dopo 1 secondo
setTimeout(() => { setTimeout(() => {
@@ -199,7 +248,15 @@ export const Api = {
} }
// Verifica sul token (funzione custom) // Verifica sul token (funzione custom)
const ret: any = await this.checkTokenScaduto(res.status, evitaloop, url, method, mydata, setAuthToken, res.data!.statuscode2!); const ret: any = await this.checkTokenScaduto(
res.status,
evitaloop,
url,
method,
mydata,
setAuthToken,
res.data!.statuscode2!
);
if (ret) return ret; if (ret) return ret;
if (tools.isDebug()) console.log(' ----> ', res); if (tools.isDebug()) console.log(' ----> ', res);
@@ -214,7 +271,14 @@ export const Api = {
} }
}, 1000); }, 1000);
const ret: any = await this.checkTokenScaduto(error.status, evitaloop, url, method, mydataout, setAuthToken); const ret: any = await this.checkTokenScaduto(
error.status,
evitaloop,
url,
method,
mydataout,
setAuthToken
);
if (ret) return ret; if (ret) return ret;
console.error('Errore nella richiesta:', error); console.error('Errore nella richiesta:', error);
@@ -223,125 +287,172 @@ export const Api = {
}, },
/** /**
* Creates a Promise that resolves after a specified number of milliseconds. * Creates a Promise that resolves after a specified number of milliseconds.
* Useful for creating delayed operations or pause in async functions. * Useful for creating delayed operations or pause in async functions.
* *
* @param ms - The number of milliseconds to delay * @param ms - The number of milliseconds to delay
* @returns A Promise that resolves after the specified delay * @returns A Promise that resolves after the specified delay
* *
* @example * @example
* // Basic usage * // Basic usage
* await delay(1000); // waits for 1 second * await delay(1000); // waits for 1 second
* *
* @example * @example
* // Usage in an async function * // Usage in an async function
* async function example() { * async function example() {
* console.log('Start'); * console.log('Start');
* await delay(2000); * await delay(2000);
* console.log('2 seconds later'); * console.log('2 seconds later');
* } * }
* *
* @example * @example
* // Usage with Promise chaining * // Usage with Promise chaining
* delay(1000).then(() => console.log('1 second passed')); * delay(1000).then(() => console.log('1 second passed'));
*/ */
async delay(ms: number): Promise<void> { async delay(ms: number): Promise<void> {
// Input validation // Input validation
if (ms < 0) { if (ms < 0) {
throw new Error('Delay time cannot be negative'); throw new Error('Delay time cannot be negative');
} }
return new Promise(resolve => setTimeout(resolve, ms)); return new Promise((resolve) => setTimeout(resolve, ms));
}, },
// Funzione che gestisce la chiamata con retry // Funzione che gestisce la chiamata con retry
async SendReq(url: string, method: string, mydata: any, setAuthToken = false, evitaloop = false, retryCount = 1, retryDelay = 5000, myformdata: any = null, responsedata: any = null, options: any = null) { async SendReq(
url: string,
method: string,
mydata: any,
setAuthToken = false,
evitaloop = false,
retryCount = 1,
retryDelay = 5000,
myformdata: any = null,
responsedata: any = null,
options: any = null
) {
try { try {
return await this.SendReqBase(url, method, mydata, setAuthToken, evitaloop, myformdata, responsedata, options); return await this.SendReqBase(
url,
method,
mydata,
setAuthToken,
evitaloop,
myformdata,
responsedata,
options
);
} catch (error) { } catch (error) {
// Se lo status non è 403 e sono rimasti tentativi, eseguo il retry // Se lo status non è 403 e sono rimasti tentativi, eseguo il retry
const riprova = error && error.status !== 403 && error.status !== toolsext.ERR_RETRY_LOGIN; const riprova =
error && error.status !== 403 && error.status !== toolsext.ERR_RETRY_LOGIN;
if (retryCount > 0 && riprova) { if (retryCount > 0 && riprova) {
console.log(`❌❌❌ Retrying request. Attempts remaining: ${retryCount}`); console.log(`❌❌❌ Retrying request. Attempts remaining: ${retryCount}`);
await this.delay(retryDelay); await this.delay(retryDelay);
return this.SendReq(url, method, mydata, setAuthToken, evitaloop, retryCount - 1, retryDelay, myformdata, responsedata); return this.SendReq(
url,
method,
mydata,
setAuthToken,
evitaloop,
retryCount - 1,
retryDelay,
myformdata,
responsedata
);
} }
throw error; throw error;
} }
}, },
async syncAlternative(mystrparam: string) { async syncAlternative(mystrparam: string) {
console.log('[ALTERNATIVE Background syncing', mystrparam) console.log('[ALTERNATIVE Background syncing', mystrparam);
const multiparams = mystrparam.split('|') const multiparams = mystrparam.split('|');
if (multiparams) { if (multiparams) {
if (multiparams.length > 3) { if (multiparams.length > 3) {
const cmd = multiparams[0] const cmd = multiparams[0];
const tablesync = multiparams[1] const tablesync = multiparams[1];
const nametab = multiparams[2] const nametab = multiparams[2];
const method = multiparams[3] const method = multiparams[3];
// const token = multiparams[3] // const token = multiparams[3]
if (cmd === ApiTables.DB.CMD_SYNC) { if (cmd === ApiTables.DB.CMD_SYNC) {
let errorfromserver = false let errorfromserver = false;
let lettoqualcosa = false let lettoqualcosa = false;
// console.log('A1) INIZIO.............................................................') // console.log('A1) INIZIO.............................................................')
return globalroutines('readall', tablesync, null) return globalroutines('readall', tablesync, null)
.then((alldata) => { .then((alldata) => {
if (alldata === undefined) { if (alldata === undefined) {
console.log('alldata NON DEFINITA') console.log('alldata NON DEFINITA');
return true return true;
} }
const myrecs = [...alldata] const myrecs = [...alldata];
const promises = myrecs.map((rec) => { const promises = myrecs.map((rec) => {
let link = `/${ApiTables.getLinkByTableName(nametab)}` let link = `/${ApiTables.getLinkByTableName(nametab)}`;
if (method !== 'POST') { if (method !== 'POST') {
link += `/${rec._id}` link += `/${rec._id}`;
} }
console.log('----------------------- LEGGO QUALCOSA ', link) console.log('----------------------- LEGGO QUALCOSA ', link);
// Insert/Delete/Update table to the server // Insert/Delete/Update table to the server
return this.SendReq(link, method, rec) return this.SendReq(link, method, rec)
.then((ris) => { .then((ris) => {
ReceiveResponsefromServer(tablesync, nametab, method, ris.data) ReceiveResponsefromServer(tablesync, nametab, method, ris.data);
lettoqualcosa = true lettoqualcosa = true;
return globalroutines('delete', tablesync, null, rec._id) return globalroutines('delete', tablesync, null, rec._id);
}) })
.then(() => { .then(() => {
return globalroutines('delete', 'swmsg', null, mystrparam) return globalroutines('delete', 'swmsg', null, mystrparam);
}).catch((err) => { })
.catch((err) => {
if (err.msgerr) { if (err.msgerr) {
if (err.msgerr.message.includes('Failed to fetch') || err.msgerr.message.includes('Network Error')) { if (
errorfromserver = true err.msgerr.message.includes('Failed to fetch') ||
err.msgerr.message.includes('Network Error')
) {
errorfromserver = true;
} }
} }
console.log(' [Alternative] !!!!!!!!!!!!!!! Error while sending data', err, errorfromserver, 'lettoqualcosa', lettoqualcosa) console.log(
' [Alternative] !!!!!!!!!!!!!!! Error while sending data',
err,
errorfromserver,
'lettoqualcosa',
lettoqualcosa
);
if (!errorfromserver) { if (!errorfromserver) {
return globalroutines('delete', 'swmsg', null, mystrparam) return globalroutines('delete', 'swmsg', null, mystrparam);
} }
}) });
}) });
// CALL ALL THE PROMISES // CALL ALL THE PROMISES
return Promise.all(promises).then(() => (errorfromserver && !lettoqualcosa)).catch((err) => (errorfromserver && !lettoqualcosa)) return Promise.all(promises)
}).catch((error) => { .then(() => errorfromserver && !lettoqualcosa)
console.log('¨¨¨¨¨¨¨¨¨¨¨¨¨¨ errorfromserver:', errorfromserver, error) .catch((err) => errorfromserver && !lettoqualcosa);
return (errorfromserver && !lettoqualcosa) })
.catch((error) => {
console.log('¨¨¨¨¨¨¨¨¨¨¨¨¨¨ errorfromserver:', errorfromserver, error);
return errorfromserver && !lettoqualcosa;
}) })
.then((error) => { .then((error) => {
const mystate = (error || errorfromserver) ? 'offline' : 'online' const mystate = error || errorfromserver ? 'offline' : 'online';
const globalStore = useGlobalStore() const globalStore = useGlobalStore();
globalStore.setStateConnection(mystate) globalStore.setStateConnection(mystate);
globalStore.saveConfig({ _id: costanti.CONFIG_ID_STATE_CONN, value: mystate }) globalStore.saveConfig({
}) _id: costanti.CONFIG_ID_STATE_CONN,
value: mystate,
});
});
} }
} }
} }
return null return null;
}, },
} };

View File

@@ -3074,7 +3074,7 @@ export const useGlobalStore = defineStore('GlobalStore', {
newrec.container2 = '8'; newrec.container2 = '8';
newrec.height = 600; newrec.height = 600;
} else if (newrec.type === shared_consts.ELEMTYPE.CARD) { } else if (newrec.type === shared_consts.ELEMTYPE.CARD) {
newrec.class2 = 'row justify-center'; newrec.class2 = 'justify-center';
} else if (newrec.type === shared_consts.ELEMTYPE.SEARCHPRODUCT) { } else if (newrec.type === shared_consts.ELEMTYPE.SEARCHPRODUCT) {
newrec.catalogo = this.createCatalogoVuoto(); newrec.catalogo = this.createCatalogoVuoto();
} else if (newrec.type === shared_consts.ELEMTYPE.CATALOGO) { } else if (newrec.type === shared_consts.ELEMTYPE.CATALOGO) {