other components...

This commit is contained in:
Paolo Arena
2021-09-04 15:05:34 +02:00
parent 1c3df0fac1
commit fcc4f61f07
110 changed files with 4592 additions and 566 deletions

View File

@@ -0,0 +1,43 @@
import { defineComponent, PropType } from "vue"
import { useI18n } from '../src/boot/i18n'
import { useUserStore } from '../src/store/UserStore'
import { useGlobalStore } from '../src/store/globalStore'
import { useQuasar } from 'quasar'
export default defineComponent({
name: '',
props: {
mystr: {
type: String,
required: true,
default: '',
},
myval: {
type: Number,
required: true,
default: 0,
},
mybool: {
type: Boolean,
required: true,
default: false,
},
op: {
type: Object as PropType<IOperators>,
required: true,
},
},
components: {
},
setup() {
const $q = useQuasar()
const { t } = useI18n()
const userStore = useUserStore()
const globalStore = useGlobalStore()
return {
}
}
})

View File

@@ -20,18 +20,18 @@
"@quasar/extras": "^1.10.12",
"@types/googlemaps": "^3.43.3",
"@types/vuelidate": "^0.7.15",
"@vue/compat": "^3.2.7",
"@vue/compiler-sfc": "^3.2.7",
"@vue/compat": "^3.2.8",
"@vue/compiler-sfc": "^3.2.8",
"@vue/eslint-config-standard": "^6.1.0",
"acorn": "^8.4.1",
"autoprefixer": "^10.3.3",
"axios": "^0.21.1",
"autoprefixer": "^10.3.4",
"axios": "^0.21.2",
"bcrypt-nodejs": "0.0.3",
"bcryptjs": "^2.4.3",
"core-js": "^3.17.1",
"core-js": "^3.17.2",
"date-fns": "^2.23.0",
"dotenv": "^10.0.0",
"element-ui": "^2.15.5",
"element-ui": "^2.15.6",
"eslint-plugin-quasar": "^1.0.0",
"graphql": "^15.5.2",
"graphql-tag": "^2.12.5",
@@ -41,7 +41,7 @@
"localforage": "^1.10.0",
"lodash": "^4.17.21",
"normalize.css": "^8.0.1",
"npm": "^7.21.1",
"npm": "^7.22.0",
"nprogress": "^0.2.0",
"pinia": "^2.0.0-rc.6",
"prerender-spa-plugin": "^3.4.0",
@@ -67,7 +67,7 @@
"workbox": "0.0.0"
},
"devDependencies": {
"@babel/eslint-parser": "^7.15.0",
"@babel/eslint-parser": "^7.15.4",
"@quasar/app": "^3.1.0",
"@types/dotenv": "^8.2.0",
"@types/jest": "^27.0.1",
@@ -88,7 +88,7 @@
"jest": "^27.1.0",
"json-loader": "^0.5.7",
"node-sass": "^6.0.1",
"npm-check-updates": "^11.8.3",
"npm-check-updates": "^11.8.5",
"optimize-css-assets-webpack-plugin": "^6.0.1",
"postcss-loader": "^6.1.1",
"sass-loader": "^12.1.0",

View File

@@ -1,10 +0,0 @@
/* eslint-disable */
// THIS FEATURE-FLAG FILE IS AUTOGENERATED,
// REMOVAL OR CHANGES WILL CAUSE RELATED TYPES TO STOP WORKING
import "quasar/dist/types/feature-flag";
declare module "quasar/dist/types/feature-flag" {
interface QuasarFeatureFlags {
pwa: true;
}
}

View File

@@ -1,6 +1,5 @@
import { useQuasar } from 'quasar'
import {
defineComponent, onBeforeMount, onBeforeUnmount, onMounted, ref, toRefs, watch,
defineComponent, onMounted, ref,
} from 'vue'
import { useI18n } from '@src/boot/i18n'
@@ -17,7 +16,6 @@ export default defineComponent({
},
setup(props, context) {
const $q = useQuasar()
const { t } = useI18n();
const elementId = ref<string>('id');

66
src/components/CCard/CCard.scss Executable file
View File

@@ -0,0 +1,66 @@
$heightBtn: 100%;
$grayshadow: #555;
.text-subtitle-carica {
font-size: 1rem;
font-weight: 400;
line-height: 1.75rem;
letter-spacing: .00937em;
text-shadow: .1rem .1rem .1rem $grayshadow;
}
.text-subtitle-certificato {
font-size: 0.75rem;
line-height: 1rem;
}
@media (max-width: 718px) {
// PER VERSIONE MOBILE
.text-subtitle-carica {
font-size: 1rem;
}
}
.op {
text-align: center !important;
font-size: 1rem;
font-weight: 400;
line-height: 1.75rem;
letter-spacing: .00937em;
text-shadow: .1rem .1rem .1rem $grayshadow;
&__cell {
font-size: 1rem;
color: red;
}
&__email {
font-size: 1rem;
color: #3b5998;
}
&__email a {
text-decoration: none;
}
&__facebook a {
font-size: 1rem;
text-decoration: none;
}
&__storia {
margin-top: 1rem;
margin-bottom: 1rem;
text-align: justify;
}
}
.myimg {
border-radius: 300px !important;
}
.q-img {
&__image {
border-radius: 300px !important;
}
}

58
src/components/CCard/CCard.ts Executable file
View File

@@ -0,0 +1,58 @@
import { computed, defineComponent, PropType, ref } from 'vue'
import { IOperators } from '../../model'
import { tools } from '@store/Modules/tools'
export default defineComponent({
name: 'CCard',
props: {
tab: {
type: String,
required: true,
default: 'one',
},
op: {
type: Object as PropType<IOperators>,
required: true,
},
},
setup(props) {
const mytab = ref(props.tab)
function clicca() {
mytab.value = 'two'
}
const myop = computed(() => {
if (!!props.op) {
return props.op
} else {
return {
tab: '',
username: '',
name: '',
surname: '',
qualification: '',
usertelegram: '',
disciplines: '',
certifications: '',
img: '',
cell: '',
email: '',
paginaweb: '',
paginafb: '',
intro: '',
info: '',
}
}
})
return {
mytab,
myop,
tools,
clicca,
}
},
})

80
src/components/CCard/CCard.vue Executable file
View File

@@ -0,0 +1,80 @@
<template>
<div>
<q-card class="my-card text-center">
<q-img :src="`statics/images/` + myop.img" class="myimg">
<div class="absolute-bottom text-spacetrans text-shadow">
<div class="text-h6 text-trans">{{ myop.name }} {{ myop.surname }}</div>
<div class="text-subtitle-carica text-trans">{{ myop.qualification }}</div>
</div>
</q-img>
<q-tabs v-model="tab" class="text-teal">
<q-tab label="Info" name="one"></q-tab>
<q-tab v-if="myop.intro" label="Biografia" name="two"></q-tab>
</q-tabs>
<q-separator></q-separator>
<q-tab-panels v-model="tab" animated>
<q-tab-panel name="one">
<div class="text-subtitle-carica">{{ myop.disciplines }}</div>
<div v-if="myop.certifications" class="text-subtitle-certificato">{{ myop.certifications }}</div>
<div class="op__cell">
<q-icon class="flex-icon" name="mobile_friendly"></q-icon>
<span class="q-ma-sm">{{ myop.cell }}</span>
<div class="row justify-center margin_buttons q-gutter-lg">
<q-btn
v-if="myop.email" fab-mini icon="fas fa-envelope"
color="blue-grey-6" type="a"
size="sm"
:href="tools.getemailto(myop.email)" target="__blank">
</q-btn>
<q-btn
v-if="tools.getHttpForWhatsapp(myop.cell)"
fab-mini icon="fab fa-whatsapp"
color="green" type="a"
size="sm"
:href="tools.getHttpForWhatsapp(myop.cell)" target="__blank">
</q-btn>
<q-btn
v-if="tools.getHttpForTelegram(myop.usertelegram)" fab-mini icon="fab fa-telegram"
color="blue" type="a"
size="sm"
:href="tools.getHttpForTelegram(myop.usertelegram)" target="__blank">
</q-btn>
</div>
</div>
<div class="op__email">
<q-icon class="flex-icon" name="contact_mail"></q-icon>&nbsp;
<a :href="tools.getemailto(myop.email)" target="_blank">{{ myop.email }}
</a>
</div>
<div class="op__facebook" v-if="myop.paginafb">
<a :href="myop.paginafb" target="_blank">
<i aria-hidden="true" class="q-icon fab fa-facebook-f icon_contact links"></i> Pagina Facebook
</a>
</div>
<div class="op__storia" v-html="myop.intro"></div>
<q-btn v-if="myop.intro" rounded size="sm" color="secondary" @click="clicca()">Continua ...</q-btn>
</q-tab-panel>
<q-tab-panel name="two">
<div class="op__storia" v-html="myop.info"></div>
</q-tab-panel>
</q-tab-panels>
</q-card>
</div>
</template>
<script lang="ts" src="./CCard.ts">
</script>
<style lang="scss" scoped>
@import './CCard.scss';
</style>

1
src/components/CCard/index.ts Executable file
View File

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

View File

@@ -0,0 +1,12 @@
.landing__swirl-bg {
background-repeat: no-repeat !important;
background-position: top;
background-size: contain !important;
background-image: url(../../statics/images/landing_first_section.png) !important
}
.landing__features {
opacity: .9;
font-size: 1rem;
line-height: 1.5;
}

View File

@@ -0,0 +1,25 @@
import { defineComponent, ref } from 'vue'
import { CCardDiscipline } from '../CCardDiscipline'
import { useGlobalStore } from '@store/globalStore'
export default defineComponent({
name: 'CCardCarousel',
components: { CCardDiscipline },
props: {
myarr: {
type: Array,
required: true,
},
},
setup() {
const globalStore = useGlobalStore()
const slidedisc = ref(0)
return {
slidedisc,
globalStore,
}
},
})

View File

@@ -0,0 +1,96 @@
<template>
<div class="row items-center q-gutter-md ">
<div class="padding">
<div class="landing__features">
<q-list bordered class="q-ma-md">
<q-item>
<q-item-section>
<q-item-label overline class="text-subtitle3">Discipline Offerte:</q-item-label>
</q-item-section>
</q-item>
<div v-for="(disc, index) in myarr" :key="index">
<q-item
clickable v-ripple
:to="disc.linkpage">
<q-item-section avatar v-if="tools.getimgev(disc)">
<q-avatar>
<img :src="tools.getimgev(disc)" :alt="disc.label">
</q-avatar>
</q-item-section>
<q-item-section>{{disc.label}}</q-item-section>
</q-item>
<q-separator/>
</div>
</q-list>
</div>
</div>
<q-carousel
swipeable
animated
:autoplay="globalStore.autoplaydisc"
v-model="slidedisc"
thumbnails
infinite
ref="carousel"
transition-next="slide-left"
transition-prev="slide-right"
height="600px"
width="100%"
>
<template v-slot:control>
<q-carousel-control
position="top"
class="text-center"
style="padding: 4px 8px 4px 0; border-radius: 4px; font-weight: bold;"
>
<q-toggle
dark color="white" v-model="globalStore.autoplaydisc" label="Auto Play" class="shadow-8"
style="background-color: rgba(0,0,0, 0.2);"></q-toggle>
</q-carousel-control>
<q-carousel-control
position="top-left"
class="q-gutter-xs"
style="opacity: 0.7;"
>
<q-btn
push round color="white" text-color="black" icon="keyboard_arrow_left"
@click="$refs.carousel.previous()"></q-btn>
</q-carousel-control>
<q-carousel-control
position="top-right"
class="q-gutter-xs"
style="opacity: 0.7;"
>
<q-btn
push round color="white" text-color="black" icon="keyboard_arrow_right"
@click="$refs.carousel.next()"></q-btn>
</q-carousel-control>
</template>
<q-carousel-slide
v-for="(myrec, index) in myarr"
:key="index"
:img-src="`statics/`+myrec.img_small"
:alt="myrec.label"
:name="index">
<div class="row q-ma-xs">
<CCardDiscipline :discipline="myrec" mystyle="height: 500px" v-model:autoplay="globalStore.autoplaydisc">
</CCardDiscipline>
</div>
<div class="absolute-bottom sfondo-grigio">
<span class="text-h6 text-grey-1 shadow-max alignleft">{{index + 1}}. </span>
</div>
</q-carousel-slide>
</q-carousel>
</div>
</template>
<script lang="ts" src="./CCardCarousel.ts">
</script>
<style lang="scss" scoped>
@import './CCardCarousel.scss';
</style>

View File

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

View File

@@ -0,0 +1,91 @@
$heightBtn: 100%;
$grayshadow: #555;
.text-subtitle-carica {
font-size: 1rem;
font-weight: 400;
line-height: 1.75rem;
letter-spacing: .00937em;
text-shadow: .1rem .1rem .1rem $grayshadow;
}
.text-subtitle-certificato {
font-size: 0.75rem;
line-height: 1rem;
}
@media (max-width: 718px) {
// PER VERSIONE MOBILE
.text-subtitle-carica {
font-size: 1rem;
}
}
.my-card-discipline {
width: 100%;
max-width: 350px;
min-width: 300px;
padding: 0;
box-shadow: none;
border-radius: 30px;
}
.yes_shadow {
-webkit-box-shadow: 0 0 24px 0 rgba(0, 0, 0, 0.16);
box-shadow: 0 0 24px 0 rgba(0, 0, 0, 0.16);
}
.disc {
text-align: center !important;
font-size: 1rem;
font-weight: 400;
line-height: 1.75rem;
letter-spacing: .00937em;
text-shadow: .1rem .1rem .1rem $grayshadow;
&__title {
//color: white;
text-shadow: .125rem .125rem .125rem #2d2260;
}
&__cell {
font-size: 1rem;
color: red;
}
&__email {
font-size: 1rem;
color: #3b5998;
}
&__description {
font-size: 1rem;
color: #000000;
height: 150px;
overflow: hidden;
text-overflow: ellipsis;
}
&__email a {
text-decoration: none;
}
}
.myimg {
height: 200px;
border-radius: 30px !important;
}
.q-img {
&__image {
border-radius: 30px !important;
}
}
.q-card__section{
padding: 4px !important;
}

View File

@@ -0,0 +1,85 @@
import { computed, defineComponent, PropType, ref, toRef, watch } from 'vue'
import { tools } from '@store/Modules/tools'
import { IDiscipline, IEvents } from 'model'
import { useCalendarStore } from '@store/CalendarStore'
import CMyTeacher from '@/components/CMyTeacher/CMyTeacher'
// @ts-ignore
import MixinOperator from '../../mixins/mixin-operator'
import MixinUsers from '@/mixins/mixin-users'
export default defineComponent({
name: 'CCardDiscipline',
components: { CMyTeacher },
props: {
discipline: {
Type: Object as PropType<IDiscipline>,
required: true,
},
mystyle: {
type: String,
required: false,
default: '',
},
autoplay: {
type: Boolean,
required: false,
default: false,
},
},
setup(props) {
const nextlesson = ref()
const calendarStore = useCalendarStore()
const { getImgTeacherByUsername } = MixinOperator()
const { isValidUsername } = MixinUsers()
// const mydiscipline = toRef(props, 'discipline');
const getLinkEvent = computed(() => `event/${nextlesson.value.typol}/${nextlesson.value._id}`)
function getNextLesson(typol: any): IEvents | undefined {
// Get next lesson
const datenow = tools.addDays(tools.getDateNow(), -1)
return calendarStore.eventlist.find((myevent: IEvents) => (myevent.typol === typol) && (new Date(myevent.dateTimeEnd!) >= datenow))
}
function disciplinechanged(myrec: IDiscipline | any) {
nextlesson.value = getNextLesson(myrec.typol_code)
// console.log('nextlesson', this.nextlesson)
}
watch(() => props.discipline, (value: any, oldval: any) => {
nextlesson.value = getNextLesson(value.typol_code)
},
)
function ExistLesson() {
return !!nextlesson.value
}
function NextEventDate() {
return tools.getstrDateTimeEventSimple(nextlesson.value)
}
function created() {
disciplinechanged(props.discipline)
}
created()
return {
ExistLesson,
NextEventDate,
tools,
getImgTeacherByUsername,
getLinkEvent,
isValidUsername,
}
},
})

View File

@@ -0,0 +1,46 @@
<template>
<div class="my-card-shadow yes_shadow" style="opacity: 1 !important;">
<q-card class="my-card-discipline text-center inset-shadow" :style="mystyle">
<q-img :src="`statics/` + discipline.img_small" class="myimg" :alt="discipline.label">
<div class="absolute-bottom text-spacetrans">
<q-btn rounded :to="discipline.linkpage">
<div class="text-h5 disc__title shadow-max">{{ discipline.label }}</div>
</q-btn>
</div>
</q-img>
<q-card-section>
<div class="disc__description" v-html="discipline.description"></div>
</q-card-section>
<q-card-section v-if="ExistLesson()" class="text-blue">
<span v-if="!tools.isMobile()">{{ $t('cal.nextevent') }}:</span>
<q-btn rounded type="a" :to="getLinkEvent" color="primary" icon="event" :label="NextEventDate()">
</q-btn>
</q-card-section>
<span v-if="!tools.isMobile()"><q-separator></q-separator></span>
<q-card-section class="row justify-center">
<div
v-for="(teach, index) in discipline.teachers" :key="index">
<div v-if="getImgTeacherByUsername(teach) && isValidUsername(teach)">
<CMyTeacher :username="teach">
</CMyTeacher>
</div>
</div>
</q-card-section>
<q-btn
class="q-mb-md" rounded size="md" color="primary" :to="discipline.linkpage"
:label="$t('cal.readall')"></q-btn>
</q-card>
</div>
</template>
<script lang="ts" src="./CCardDiscipline.ts">
</script>
<style lang="scss" scoped>
@import './CCardDiscipline.scss';
</style>

View File

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

View File

@@ -0,0 +1,24 @@
import { CCard } from '@components'
import MixinOperator from '../../mixins/mixin-operator'
import { defineComponent, ref } from 'vue'
export default defineComponent({
name: 'CCardOperator',
components: { CCard },
props:{
username: {
type: String,
required: true,
},
},
setup(props) {
const tab = ref('one')
const { getOperatorByUsername } = MixinOperator()
return {
tab,
getOperatorByUsername,
}
},
})

View File

@@ -0,0 +1,14 @@
<template>
<div>
<CCard :op="getOperatorByUsername(username)" :tab="tab">
</CCard>
</div>
</template>
<script lang="ts" src="./CCardOperator.ts">
</script>
<style lang="scss" scoped>
@import './CCardOperator.scss';
</style>

View File

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

View File

@@ -0,0 +1,13 @@
.my-card-stat {
width: 100%;
max-width: 200px;
min-width: 120px;
padding: 1rem 1rem;
@media (max-width: 718px) {
// PER VERSIONE MOBILE
max-width: 150px;
padding: 0;
}
box-shadow: none;
}

View File

@@ -0,0 +1,37 @@
import { defineComponent } from 'vue'
import { tools } from '@store/Modules/tools'
export default defineComponent({
name: 'CCardStat',
props: {
mytext: {
type: String,
required: true,
default: '',
},
myval: {
type: Number,
required: true,
default: 0,
},
mycol: {
type: String,
required: false,
default: '',
},
},
setup() {
function getsize() {
if (tools.isMobile())
return '130px'
else
return '150px'
}
return {
getsize,
}
},
})

View File

@@ -0,0 +1,19 @@
<template>
<div class="row justify-between q-pa-xs-sm">
<div :style="' padding-right: 8px;'">
{{mytext}}
</div>
<div>
<q-badge :color="mycol">{{ myval }}</q-badge>
</div>
</div>
</template>
<script lang="ts" src="./CCardStat.ts">
</script>
<style lang="scss" scoped>
@import './CCardStat.scss';
</style>

View File

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

View File

@@ -0,0 +1,34 @@
.my-card-stat {
width: 100%;
max-width: 200px;
min-width: 120px;
padding: 1rem 1rem;
@media (max-width: 718px) {
// PER VERSIONE MOBILE
max-width: 150px;
padding: 0;
}
box-shadow: none;
}
.my-card-small-stat {
width: 100%;
max-width: 60px;
min-width: 40px;
@media (max-width: 718px) {
// PER VERSIONE MOBILE
max-width: 50px;
min-width: 40px;
}
box-shadow: none;
}
.text-h5-short {
line-height: 1.25rem !important;
@media (max-width: 718px) {
line-height: 1rem !important;
}
}

View File

@@ -0,0 +1,83 @@
import { defineComponent } from 'vue'
import { tools } from '@store/Modules/tools'
export default defineComponent({
name: 'CCardState',
props: {
myperc: {
type: Number,
required: true,
default: 0,
},
mytext: {
type: String,
required: false,
default: '',
},
myval: {
type: Number,
required: false,
default: 0,
},
imgsrc: {
type: String,
required: false,
default: '',
},
isperc: {
type: Boolean,
required: false,
default: false,
},
textadd: {
type: String,
required: false,
default: '',
},
mycolor: {
type: String,
required: false,
default: 'green',
},
size: {
type: String,
required: false,
default: '150px',
},
size_mob: {
type: String,
required: false,
default: '130px',
},
fontsize: {
type: String,
required: false,
default: '1rem',
},
mystyle: {
type: String,
required: false,
default: '',
},
myclass: {
type: String,
required: false,
default: 'my-card-stat',
},
},
components: {},
setup(props) {
function getsize() {
if (tools.isMobile())
return props.size_mob
else
return props.size
}
return {
getsize,
}
},
})

View File

@@ -0,0 +1,36 @@
<template>
<q-card :class="myclass +` text-center`" :style="mystyle">
<q-circular-progress
show-value
:font-size="fontsize"
:value="myperc"
:size="getsize"
:thickness="0.25"
:color="mycolor"
track-color="grey-3"
class="animated"
>
<q-avatar v-if="imgsrc" size="60px">
<img :src="imgsrc" alt="img">
</q-avatar>
<div class="column q-pa-sm text-center">
<div>
{{ mytext }}
</div>
<div v-if="myval" class="mlvalue text-h5 text-blue boldhigh text-h5-short"> {{ myval }} {{ textadd }}
</div>
<div v-if="isperc" class="cltexth5" >
{{ myperc.toFixed(1) }}%
</div>
</div>
</q-circular-progress>
</q-card>
</template>
<script lang="ts" src="./CCardState.ts">
</script>
<style lang="scss" scoped>
@import './CCardState.scss';
</style>

View File

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

View File

@@ -0,0 +1,47 @@
$heightBtn: 100%;
$grayshadow: #555;
.text-subtitle-gallery {
font-size: 1rem;
font-weight: 400;
line-height: 1.75rem;
letter-spacing: .00937em;
text-shadow: .1rem .1rem .1rem $grayshadow;
}
@media (max-width: 718px) {
// PER VERSIONE MOBILE
.text-subtitle-gallery {
font-size: 1rem;
}
}
.myimg {
border-radius: 10px !important;
height: 200px;
}
.myimg-view {
border-radius: 5px !important;
height: 80px;
}
.q-img {
&__image {
border-radius: 10px !important;
}
}
.my-card-gallery {
width: 100%;
max-width: 300px;
min-width: 200px;
padding: 1rem 1rem;
height: 350px;
}
.my-card-gallery-view {
width: 100px;
height: 100px;
padding: 0.5rem 0.5rem;
}

View File

@@ -0,0 +1,37 @@
import { tools } from '../../store/Modules/tools'
import { useQuasar } from 'quasar'
import { useI18n } from '@/boot/i18n'
import { useUserStore } from '@store/UserStore'
import { useGlobalStore } from '@store/globalStore'
import { defineComponent } from 'vue'
export default defineComponent({
name: 'CCopyBtn',
props: {
texttocopy: {
type: String,
required: true,
},
title: {
type: String,
required: false,
default: '',
},
},
components: {},
setup(props) {
const $q = useQuasar()
const { t } = useI18n()
const userStore = useUserStore()
const globalStore = useGlobalStore()
function copytoclip() {
tools.copyStringToClipboard(props.texttocopy, true)
}
return {
copytoclip,
tools,
}
},
})

View File

@@ -0,0 +1,22 @@
<template>
<div class="q-ma-sm">
<div class="column cursor-pointer" @click="copytoclip">
<q-field outlined :label="title" stack-label class="text-center cursor-pointer">
<template v-slot:prepend v-if="!tools.isMobile()">
<q-btn round dense flat icon="far fa-copy"/>
</template>
<template v-slot:control>
<div class="self-center full-width no-outline text-center wrapword text-h5" tabindex="0">{{texttocopy}}</div>
</template>
</q-field>
</div>
</div>
</template>
<script lang="ts" src="./CCopyBtn.ts">
</script>
<style lang="scss" scoped>
@import './CCopyBtn.scss';
</style>

View File

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

33
src/components/CDate/CDate.scss Executable file
View File

@@ -0,0 +1,33 @@
$heightBtn: 100%;
.progress-item {
margin: 1px;
padding: 2px;
padding-top: 4px;
padding-bottom: 4px;
flex: 1;
flex-direction: column;
order: 1;
}
.cpr-progrbar-item {
//height: 10px
padding-top: 7px;
height:15px;
}
.cpr-percProgress {
padding-top: 3px;
color: #888;
vertical-align: middle;
text-align: center;
//line-height: $heightitem;
}
.data_string {
font-size: 0.85rem;
@media (max-width: 600px) {
max-width: 22px;
// display: none;
}
}

67
src/components/CDate/CDate.ts Executable file
View File

@@ -0,0 +1,67 @@
import Vue from 'vue'
import { Component, Prop, Watch } from 'vue-property-decorator'
import { tools } from '@src/store/Modules/tools'
import { toolsext } from '@src/store/Modules/toolsext'
import { date } from 'quasar'
@Component({
name: 'CDate'
})
export default class CDate extends Vue {
@Prop() public mydate!: Date
@Prop({ required: false, default: '' }) public label: string
@Prop({ required: false, default: '' }) public data_class!: string
@Prop({ required: false, default: false }) public readonly!: boolean
@Prop({ required: false, default: false }) public disable!: boolean
@Prop({ required: false, default: '' }) public color!: string
@Prop({ required: false, default: false }) public rounded!: boolean
@Prop({ required: false, default: false }) public outlined!: boolean
@Prop({ required: false, default: true }) public dense!: boolean
public mystyleicon: string = 'font-size: 1.5rem;'
@Watch('mydate')
public valchanged(value) {
this.valueInternal = value
}
public $refs: {
datePicker
}
private valueInternal: Date = tools.getDateNull()
public created() {
this.valueInternal = this.mydate
if (this.data_class !== '') {
this.mystyleicon = 'font-size: 1rem;'
}
}
public changedate(value) {
const datavalida = tools.convertstrtoDate(value)
if (!!datavalida) {
this.valueInternal = datavalida
console.log('EMIT: changedate', datavalida.toString())
this.$emit('input', this.getDate())
} else {
console.log(' DATA NON VALIDAAAAAAAAAAAAA ', value, datavalida)
}
this.$refs.datePicker.hide()
}
get getdatestring() {
const mydate = tools.getstrDate(this.valueInternal)
console.log('getdatestring', mydate)
return mydate
}
get getdateyymmddstring() {
return tools.getstrYYMMDDDate(this.valueInternal)
}
private getDate() {
return this.valueInternal
}
}

22
src/components/CDate/CDate.vue Executable file
View File

@@ -0,0 +1,22 @@
<template>
<q-input :class="data_class" :bg-color="color" :readonly="readonly" :disable="disable" debounce="1000" :dense="dense"
:value="getdatestring" stack-label :label="label" @input="changedate" :rounded="rounded"
mask="##/##/####"
fill-mask
:outlined="outlined">
<template v-slot:append>
<q-icon name="event" class="cursor-pointer" :style="mystyleicon">
<q-popup-proxy v-if="!readonly" ref="datePicker">
<q-date :value="getdateyymmddstring" today-btn @input="changedate"></q-date>
</q-popup-proxy>
</q-icon>
</template>
</q-input>
</template>
<script lang="ts" src="./CDate.ts">
</script>
<style lang="scss" scoped>
@import './CDate.scss';
</style>

1
src/components/CDate/index.ts Executable file
View File

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

View File

@@ -0,0 +1,10 @@
.calendar_comp{
max-width: 170px;
@media (max-width: 400px) {
max-width: 400px;
}
}
.calendar_comp {
vertical-align: center;
}

View File

@@ -0,0 +1,130 @@
import Vue from 'vue'
import { Component, Prop, Watch } from 'vue-property-decorator'
import { tools } from '@src/store/Modules/tools'
import { toolsext } from '@src/store/Modules/toolsext'
import { date } from 'quasar'
import { CalendarStore } from '../../store/Modules'
import MixinBase from '../../mixins/mixin-base'
@Component({
name: 'CDateTime',
mixins: [MixinBase]
})
export default class CDateTime extends Vue {
public $q
public $t
@Prop({ required: false, default: null }) public value: Date
@Prop({ required: false, default: null }) public valueDate: Date
@Prop({ required: true, default: 'Val:' }) public label: string
@Prop({ required: false, default: '' }) public data_class!: string
@Prop({ required: false, default: true }) public canEdit!: boolean
@Prop({ required: false, default: false }) public disable!: boolean
@Prop({ required: false, default: '' }) public bgcolor!: string
@Prop({ required: false, default: false }) public dense: boolean
@Prop({ required: false, default: '5' }) public minuteinterval: boolean
@Prop({ required: false, default: 'date-time' }) public view: string
public mystyleicon: string = 'font-size: 1.5rem;'
public showDateTimeScroller: boolean = false
public saveit: boolean = false
public myvalue: Date = new Date()
public valueprec: Date = new Date()
get getclass() {
return 'calendar_comp ' + this.data_class
}
// @Watch('showDateTimeScroller')
public Opening() {
// console.log('Opening', 'myvalue', this.myvalue, 'value', this.value)
this.saveit = false
this.valueprec = this.myvalue
if (this.myvalue === undefined) {
this.valueDate = new Date()
this.myvalue = tools.getstrYYMMDDDateTime(this.valueDate)
}
// console.log('Opening', this.valueDate, this.myvalue)
this.$emit('show')
}
public Closing() {
// console.log('Closing')
if (!this.saveit) {
if (this.myvalue !== this.valueprec) {
this.myvalue = this.valueprec
tools.showNeutralNotif(this.$q, this.$t('db.reccanceled'))
}
}
}
@Watch('valueDate')
public changevalueDate() {
if (this.valueDate)
this.myvalue = tools.getstrYYMMDDDateTime(this.valueDate)
// console.log('changevalueDate myvalue', this.myvalue)
}
@Watch('value')
public changevalue() {
this.myvalue = this.value
// console.log('changevalue myvalue', this.myvalue)
}
public savetoclose() {
// console.log('Close')
this.saveit = true
this.showDateTimeScroller = false
this.$emit('savetoclose', this.myvalue, this.valueprec)
}
get scrollerPopupStyle280() {
if (this.$q.screen.lt.sm) {
return {
width: '100vw',
height: '100vh'
}
} else {
return {
maxHeight: '400px',
height: '400px',
width: '280px'
}
}
}
get locale() {
return CalendarStore.state.locale
}
public created() {
if (this.value !== null)
this.myvalue = this.value
else
this.myvalue = tools.getstrYYMMDDDateTime(this.valueDate)
// console.log('created myvalue', this.myvalue)
}
public changeval(newval) {
// console.log('changeval', newval, 'value=', this.value, 'myvalue=', this.myvalue)
this.$emit('update:value', newval)
}
public mystyle() {
if (this.label !== '')
return ''
else
return ''
}
public getstrDate(mydate) {
if (this.view === 'date-time') {
return tools.getstrDateTime(mydate)
} else {
return tools.getstrDate(mydate)
}
}
}

View File

@@ -0,0 +1,71 @@
<template>
<div class="" :style="mystyle">
<q-input v-model="myvalue"
v-show="false"
color="blue-6"
hide-bottom-space
outlined
borderless
:label="label"
:bg-color="bgcolor"
:readonly="true"
:dense="dense"
mask="####-##-## ##:##"
debounce="500"
@input="changeval"
:input-class="getclass"
>
</q-input>
<q-field
:label="label"
stack-label
:value="myvalue"
outlined
:dense="dense"
color="blue-6"
:bg-color="bgcolor"
debounce="500"
:input-class="getclass">
<template v-slot:control>
<div style="">
<div class="self-center full-width no-outline" :style="mystyle" tabindex="0">
{{ getstrDate(myvalue) }}
</div>
</div>
</template>
<template v-slot:append>
<q-icon v-if="canEdit" name="event" class="cursor-pointer">
<q-popup-proxy v-model="showDateTimeScroller" @before-show="Opening" @before-hide="Closing">
<q-scroller
v-model="myvalue"
:view="view"
:locale="toolsext.getLocale()"
:rounded-borders="true"
border-color="#2196f3"
bar-color="#2196f3"
text-color="white"
color="primary"
:minute-interval="minuteinterval"
inner-text-color="primary"
inner-color="white"
:style="scrollerPopupStyle280"
@input="changeval"
@close="() => { savetoclose(); }"
></q-scroller>
</q-popup-proxy>
</q-icon>
</template>
</q-field>
</div>
</template>
<script lang="ts" src="./CDateTime.ts">
</script>
<style lang="scss" scoped>
@import './CDateTime.scss';
</style>

View File

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

View File

@@ -1,5 +1,5 @@
import {
defineComponent, onBeforeMount, onBeforeUnmount, onMounted, ref, toRef, toRefs, watch,
defineComponent,
} from 'vue'
import { tools } from '@src/store/Modules/tools'

View File

@@ -0,0 +1,57 @@
import { CCardState } from '../CCardState'
import { computed, defineComponent } from 'vue'
import { useGlobalStore } from '@store/globalStore'
import { useProducts } from '@store/Products'
import CCopyBtn from '@/components/CCopyBtn/CCopyBtn'
import CSingleCart from '@/components/CSingleCart/CSingleCart'
import CTitleBanner from '@/components/CTitleBanner/CTitleBanner'
export default defineComponent({
name: 'CMyCart',
props: {},
components: { CTitleBanner, CCardState, CCopyBtn, CSingleCart },
setup() {
const globalStore = useGlobalStore()
const products = useProducts()
const myCart = computed(() => products.cart)
const myTotalPrice = computed(() => {
if (products.cart) {
return products.cart.totalPrice
} else {
return 0
}
})
const ordersCart = computed(() => {
if (!!products.cart) {
return products.cart.items
} else {
return null
}
})
const numOrders = computed(() => {
if (!!products.cart) {
return products.cart.items!.length
} else {
return 0
}
})
function closecart() {
globalStore.rightCartOpen = false
}
return {
myCart,
myTotalPrice,
ordersCart,
numOrders,
closecart,
}
},
})

View File

@@ -1,55 +0,0 @@
import { Component, Prop, Watch } from 'vue-property-decorator'
import { tools } from '../../store/Modules/tools'
import MixinBase from '@src/mixins/mixin-base'
import { CTitleBanner } from '@components'
import { CCardState } from '../CCardState'
import { CCopyBtn } from '../CCopyBtn'
import { IOrder, IProduct } from '@src/model'
import { CSingleCart } from '../../components/CSingleCart'
import MixinUsers from '@src/mixins/mixin-users'
import { computed, defineComponent, ref } from "vue"
import { useGlobalStore } from "@store/globalStore"
@Component({
name: 'CMyCart',
components: { CTitleBanner, CCardState, CCopyBtn, CSingleCart }
})
export default defineComponent({
name: 'CMyCart',
props: {},
setup() {
const globalStore = useGlobalStore()
const myCart = computed(() => Products.cart)
const myTotalPrice = computed(() => {
if (Products.cart) {
return Products.cart.totalPrice
} else {
return 0
}
})
const ordersCart = computed(() => {
if (!!Products.cart) {
return Products.cart.items
} else {
return null
}
})
const numOrders = computed(() => {
if (!!Products.cart) {
return Products.cart.items.length
} else {
return 0
}
})
function closecart() {
globalStore.rightCartOpen = false
}
}

View File

@@ -30,12 +30,12 @@
Il Carrello è Vuoto
</div>
<div v-else style="text-align: center">
<q-btn rounded icon="fas fa-shopping-cart" color="green" label="Vai alla Cassa" class="q-mb-sm" to="/checkout" @click="closecart"></q-btn>
<q-btn
rounded icon="fas fa-shopping-cart" color="green" label="Vai alla Cassa" class="q-mb-sm" to="/checkout"
@click="closecart"></q-btn>
</div>
</div>
</div>
</div>
</template>
<script lang="ts" src="./CMyCart.ts">

View File

@@ -0,0 +1,17 @@
.colmodif {
cursor: pointer;
}
.colmodif:hover {
background-color: #a8f0ff;
cursor: pointer;
}
.colsel {
background-color: #81b8ff;
}
.cldisable{
color: gray !important;
}

View File

@@ -0,0 +1,164 @@
import { Component, Prop, Watch } from 'vue-property-decorator'
import { tools } from '../../store/Modules/tools'
import { toolsext } from '@src/store/Modules/toolsext'
import { QEditor } from 'quasar'
import { CMyEditor } from '../CMyEditor'
import MixinBase from '../../mixins/mixin-base'
import { fieldsTable } from '../../store/Modules/fieldsTable'
import { IColGridTable } from '../../model'
import { CMySelect } from '../CMySelect'
import { GlobalStore, UserStore } from '../../store/Modules'
import { CMyChipList } from '../CMyChipList'
import { CMyToggleList } from '../CMyToggleList'
import translate from '@src/globalroutines/util'
import { CDateTime } from '../CDateTime'
@Component({
name: 'CMyFieldDb',
components: { CMyEditor, CMySelect, CMyChipList, CMyToggleList, CDateTime }
})
export default class CMyFieldDb extends MixinBase {
@Prop({ required: true }) public title
@Prop({ required: true }) public mykey: string
@Prop({ required: false, default: '' }) public mysubkey: string
@Prop({ required: true }) public type: number
@Prop({ required: false, default: false }) public serv: boolean
@Prop({ required: false, default: false }) public disable: boolean
@Prop({ required: false, default: '' }) public jointable: string
@Prop({ required: false, default: 'settings' }) public table: string
@Prop({ required: false, default: '' }) public myimg: string
@Prop({ required: false, default: '' }) public id: string
@Prop({ required: false, default: '' }) public idmain: string
public $t
public myvalue = ''
public col: IColGridTable = { name: 'test' }
public canEdit: boolean = true
public countryname = ''
public created() {
this.crea()
}
public crea() {
this.myvalue = this.getValDb(this.mykey, this.serv, '', this.table, this.mysubkey, this.id, this.idmain)
this.col.jointable = this.jointable
this.col.fieldtype = this.type
this.col.label = this.title
// console.log('CMyFieldDb crea', this.myvalue)
}
@Watch('id')
public idchanged(value) {
this.crea()
}
public getclassCol(col) {
if (col) {
let mycl = (this.disable || col.disable) ? '' : 'colmodif '
mycl += ((col.fieldtype === tools.FieldType.date) || (col.fieldtype === tools.FieldType.onlydate)) ? ' coldate flex flex-container ' : ''
return mycl
} else {
return ''
}
}
public visuValByType(val) {
if (this.col.fieldtype === tools.FieldType.date) {
if (val === undefined) {
return '[]'
} else {
return tools.getstrDateTime(val)
}
} else if (this.col.fieldtype === tools.FieldType.onlydate) {
if (val === undefined) {
return '[]'
} else {
return tools.getstrDate(val)
}
} else if (this.col.fieldtype === tools.FieldType.boolean) {
return (val) ? this.$t('dialog.yes') : this.$t('dialog.no')
} else if (this.col.fieldtype === tools.FieldType.binary) {
if (val === undefined)
return '[---]'
else
return fieldsTable.getArrStrByValueBinary(this, this.col, val)
} else if (this.col.fieldtype === tools.FieldType.select) {
if (val === undefined)
return '[---]'
else
return fieldsTable.getValueByTable(this.col, val)
} else if (this.col.fieldtype === tools.FieldType.multiselect) {
if (val === undefined)
return '[---]'
else
return fieldsTable.getMultiValueByTable(this.col, val)
} else if (this.col.fieldtype === tools.FieldType.multioption) {
if (val === undefined)
return '[---]'
else
return fieldsTable.getMultiValueByTable(this.col, val)
} else if (this.col.fieldtype === tools.FieldType.password) {
if (val === undefined)
return '[---]'
else
return '***************'
} else {
if (val === undefined)
return ' <span class="text-grey">(' + translate('reg.select') + ')</span> '
else if (val === '') {
return ' <span class="text-grey">(' + translate('reg.select') + ')</span> '
} else {
let mystr = tools.firstchars(val, 5000)
if (val) {
if (val.length > 5000)
mystr += '...'
} else {
return val
}
return mystr
}
}
}
get mycl() {
if (this.disable) {
return 'cldisable'
}
}
get myvalprinted() {
return this.visuValByType(this.myvalue)
}
public savefield(value, initialval) {
this.myvalue = value
this.setValDb(this.mykey, this.myvalue, this.type, this.serv, this.table, this.mysubkey, this.id)
}
public savefieldboolean(value) {
if (this.myvalue === undefined)
this.myvalue = 'true'
else
this.myvalue = value
this.setValDb(this.mykey, this.myvalue, this.type, this.serv, this.table, this.mysubkey, this.id)
}
public selectcountry({ name, iso2, dialCode }) {
// console.log(name, iso2, dialCode)
this.myvalue = iso2
this.countryname = name
}
public intcode_change(coderec) {
this.myvalue = '+' + coderec.dialCode
}
}

View File

@@ -0,0 +1,274 @@
<template>
<div class="text-center">
<div class="row items-center justify-center q-gutter-md q-ma-xs">
<div class="q-ma-xs">
<q-field rounded outlined bg-color="blue-1" dense style="min-width:110px;">
<template v-slot:control>
<div class="centermydiv">
<div v-if="myimg" class="text-center">
<q-img
:src="myimg"
class="text-center"
style="height: 50px; width: 50px;"
:alt="title">
</q-img>
</div>
<div class="self-center full-width no-outline text-center" tabindex="0">{{ title }}</div>
</div>
</template>
</q-field>
</div>
<div :class="getclassCol(col) + ` q-ma-sm q-pa-sm col-grow rounded-borders`" style="border: 1px solid #bbb">
<div v-if="type === tools.FieldType.date">
<CDateTime
:label="col.label"
class="cursor-pointer"
:value.sync="myvalue"
:readonly="false"
:dense="true"
:canEdit="canEdit"
>
</CDateTime>
</div>
<div v-else-if="type === tools.FieldType.onlydate">
<CDateTime
:label="col.label"
class="cursor-pointer"
:value.sync="myvalue"
:readonly="false"
:dense="true"
:canEdit="canEdit"
view="date"
>
</CDateTime>
</div>
<div v-else :class="mycl">
<div v-if="type === tools.FieldType.binary">
<CMyChipList
:type="tools.FieldType.binary"
:value="myvalue"
:options="db_fieldsTable.getTableJoinByName(col.jointable)"
:optval="db_fieldsTable.getKeyByTable(col.jointable)"
:optlab="db_fieldsTable.getLabelByTable(col.jointable)"
:opticon="db_fieldsTable.getIconByTable(col.jointable)"></CMyChipList>
</div>
<!-- Show Value -->
<div v-else-if="type === tools.FieldType.nationality">
<q-input
input-class="cursor-pointer text-center"
:readonly="true"
v-model="countryname"
rounded
dense
debounce="1000"
>
<div class="hidden">
<vue-country-code
:defaultCountry="myvalue"
:disabledFetchingCountry="true"
@onSelect="selectcountry"
:preferredCountries="tools.getprefCountries"
:dropdownOptions="{ disabledDialCode: true }">
</vue-country-code>
</div>
</q-input>
</div>
<div v-else-if="type === tools.FieldType.intcode">
<div v-html="myvalprinted"></div>
</div>
<div v-else-if="((type === tools.FieldType.multiselect) || (type === tools.FieldType.multioption))">
<CMyChipList
:type="type"
:value="myvalue"
:options="db_fieldsTable.getTableJoinByName(col.jointable)"
:optval="db_fieldsTable.getKeyByTable(col.jointable)"
:optlab="db_fieldsTable.getLabelByTable(col.jointable)"
:opticon="db_fieldsTable.getIconByTable(col.jointable)"></CMyChipList>
</div>
<div v-else-if="type === tools.FieldType.select">
<CMyChipList
myclass="text-center"
:type="tools.FieldType.select"
:value="myvalue"
:options="db_fieldsTable.getTableJoinByName(col.jointable)"
:optval="db_fieldsTable.getKeyByTable(col.jointable)"
:optlab="db_fieldsTable.getLabelByTable(col.jointable)"
:opticon="db_fieldsTable.getIconByTable(col.jointable)"></CMyChipList>
</div>
<div v-else-if="type === tools.FieldType.html">
<div v-html="myvalprinted">
</div>
</div>
<div v-else-if="type === tools.FieldType.boolean">
<q-toggle dark color="green" v-model="myvalue" :label="col.title"
@input="savefieldboolean"></q-toggle>
</div>
<div v-else>
<div v-html="myvalprinted"></div>
</div>
<q-popup-edit
v-if="(canEdit && type !== tools.FieldType.boolean) && !disable"
v-model="myvalue"
:disable="col.disable"
:title="col.title"
@save="savefield"
buttons
>
<div v-if="type === tools.FieldType.boolean">
<q-checkbox v-model="myvalue" :label="col.title">
</q-checkbox>
<div v-html="visuValByType(myvalue)">
</div>
</div>
<div v-else-if="type === tools.FieldType.string">
<q-input v-model="myvalue"
autogrow
@keyup.enter.stop
autofocus>
</q-input>
</div>
<div v-else-if="type === tools.FieldType.password">
<q-input v-model="myvalue"
type="password"
@keyup.enter.stop
autofocus>
</q-input>
</div>
<div v-else-if="type === tools.FieldType.number">
<q-input v-model="myvalue" type="number"
autofocus>
</q-input>
</div>
<div v-else-if="type === tools.FieldType.hours">
<CMySelect label="Ore" :value.sync="myvalue"
optval="_id" optlab="label"
:useinput="false"
o :options="tools.SelectHours">
</CMySelect>
</div>
<div v-else-if="type === tools.FieldType.binary">
<CMyToggleList :label="col.title"
:options="db_fieldsTable.getTableJoinByName(col.jointable)"
:value.sync="myvalue"
:optval="db_fieldsTable.getKeyByTable(col.jointable)"
:optlab="db_fieldsTable.getLabelByTable(col.jointable)">
</CMyToggleList>
</div>
<div v-else-if="type === tools.FieldType.html">
<CMyEditor :value.sync="myvalue" :title="title" @keyup.enter.stop>
</CMyEditor>
</div>
<div v-else-if="type === tools.FieldType.select">
<CMySelect :label="col.title"
:value.sync="myvalue"
:optval="db_fieldsTable.getKeyByTable(col.jointable)"
:optlab="db_fieldsTable.getLabelByTable(col.jointable)"
:options="db_fieldsTable.getTableJoinByName(col.jointable)"
:useinput="false">
</CMySelect>
</div>
<div v-else-if="col.fieldtype === tools.FieldType.nationality">
<div class="justify-center q-gutter-sm clgutter q-mt-sm">
<q-input
v-model="countryname"
:readonly="true"
rounded dense
debounce="1000"
:label="title">
<template v-slot:prepend>
<div style="font-size: 1rem;">
<vue-country-code
:defaultCountry="myvalue"
:disabledFetchingCountry="true"
@onSelect="selectcountry"
:preferredCountries="tools.getprefCountries"
:dropdownOptions="{ disabledDialCode: true }">
</vue-country-code>
</div>
</template>
</q-input>
<div style="height: 180px;">
</div>
</div>
</div>
<div v-else-if="col.fieldtype === tools.FieldType.intcode">
<div class="justify-center q-gutter-sm clgutter q-mt-sm">
<vue-tel-input
@country-changed="intcode_change"
v-model="myvalue"
:disabledFetchingCountry="true"
:preferredCountries="tools.getprefCountries"
:placeholder="$t('reg.cell')"
:enabledCountryCode="true"
inputClasses="clCell"
wrapperClasses="clCellCode">
</vue-tel-input>
<div style="height: 180px;">
</div>
</div>
</div>
<div v-else-if="col.fieldtype === tools.FieldType.multiselect">
<CMyToggleList :label="col.title"
:options="db_fieldsTable.getTableJoinByName(col.jointable)"
:value.sync="myvalue"
:optval="db_fieldsTable.getKeyByTable(col.jointable)"
:optlab="db_fieldsTable.getLabelByTable(col.jointable)"
:isarray="true">
</CMyToggleList>
<!--
<q-select
v-model="myvalue"
rounded
dense
outlined
multiple
options-dense
:display-value="db_fieldsTable.getTitleByTable(col.jointable)"
emit-value
map-options
:options="db_fieldsTable.getTableJoinByName(col.jointable)"
:option-label="db_fieldsTable.getLabelByTable(col.jointable)"
:option-value="db_fieldsTable.getKeyByTable(col.jointable)"
style="min-width: 150px"
>
</q-select>
-->
</div>
<div v-else-if="col.fieldtype === tools.FieldType.multioption">
</div>
</q-popup-edit>
</div>
</div>
</div>
</div>
</template>
<script lang="ts" src="./CMyFieldDb.ts">
</script>
<style lang="scss" scoped>
@import './CMyFieldDb.scss';
</style>

View File

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

View File

@@ -0,0 +1,92 @@
$heightBtn: 100%;
$grayshadow: #555;
.text-subtitle-carica {
font-size: 1rem;
font-weight: 400;
line-height: 1.75rem;
letter-spacing: .00937em;
text-shadow: .1rem .1rem .1rem $grayshadow;
}
.text-subtitle-certificato {
font-size: 0.75rem;
line-height: 1rem;
}
@media (max-width: 718px) {
// PER VERSIONE MOBILE
.text-subtitle-carica {
font-size: 1rem;
}
}
.op {
text-align: center !important;
font-size: 1rem;
font-weight: 400;
line-height: 1.75rem;
letter-spacing: .00937em;
text-shadow: .1rem .1rem .1rem $grayshadow;
&__cell {
font-size: 1rem;
color: red;
}
&__email {
font-size: 1rem;
color: #3b5998;
}
&__email a {
text-decoration: none;
}
&__facebook a {
font-size: 1rem;
text-decoration: none;
}
&__storia {
margin-top: 1rem;
margin-bottom: 1rem;
text-align: justify;
}
}
.myimg {
border-radius: 300px !important;
}
.q-img {
&__image {
border-radius: 300px !important;
}
}
.myflex {
display: flex;
flex: 1;
}
.mybase {
color: black;
font-size: 0.75rem;
font-weight: 400;
line-height: 1.25rem;
letter-spacing: 0.03333em;
&__teacher {
margin-top: 5px;
&-content {
color: darkblue;
}
&-content:hover {
}
}
}

View File

@@ -0,0 +1,58 @@
import { computed, defineComponent, ref, watch } from 'vue'
import { tools } from '@store/Modules/tools'
import { CMyAvatar } from '../CMyAvatar'
import MixinOperator from '../../mixins/mixin-operator'
import MixinUsers from '../../mixins/mixin-users'
import { useGlobalStore } from '@store/globalStore'
export default defineComponent({
name: 'CMyTeacher',
components: { CMyAvatar },
props: {
username: {
type: String,
required: true,
default: '',
},
},
setup(props) {
const globalStore = useGlobalStore()
const showuserdetails = ref(false)
const autoplaydiscsaved = ref(0)
const tab = ref('one')
const { getOperatorByUsername, getImgTeacherByUsername, getTeacherByUsername } = MixinOperator()
const { isValidUsername } = MixinUsers()
const myop = computed(() => {
return getOperatorByUsername(props.username)
})
watch(showuserdetails, (value: any, old: any) => {
if (!showuserdetails.value) {
globalStore.autoplaydisc = autoplaydiscsaved.value
}
})
function executeclick(event: any) {
console.log('executeclick')
showuserdetails.value = true
autoplaydiscsaved.value = globalStore.autoplaydisc
globalStore.autoplaydisc = 0
}
return {
tab,
executeclick,
showuserdetails,
getImgTeacherByUsername,
isValidUsername,
getTeacherByUsername,
myop,
tools,
}
},
})

View File

@@ -0,0 +1,84 @@
<template>
<span>
<q-dialog v-model="showuserdetails" v-if="myop">
<q-card :style="`min-width: `+ tools.myheight_dialog() + `px;`">
<q-toolbar class="bg-primary text-white">
<q-toolbar-title>
{{ myop.name }} {{ myop.surname }}
</q-toolbar-title>
<q-btn flat round color="white" icon="close" v-close-popup></q-btn>
</q-toolbar>
<q-card-section class="text-center inset-shadow">
<div style="width: 200px; float: left;">
<q-img :src="`statics/images/` + myop.img" class="myimg" :alt="`${myop.name} ${myop.surname}`">
</q-img>
</div>
<div class="text-h6 text-trans">{{ myop.name }} {{ myop.surname }}</div>
<div class="text-subtitle-carica text-trans">{{ myop.qualification }}</div>
<div class="text-subtitle-carica">{{ myop.disciplines }}</div>
<div v-if="myop.certifications" class="text-subtitle-certificato">{{ myop.certifications }}</div>
<div class="op__cell">
<q-icon class="flex-icon" name="mobile_friendly" v-if="myop.cell"></q-icon>
<span class="q-mx-sm">{{ myop.cell }}</span>
<div class="row justify-center margin_buttons">
<q-btn
v-if="myop.email" fab-mini icon="fas fa-envelope"
color="blue-grey-6" type="a"
size="sm"
:href="tools.getemailto(myop.email)" target="__blank">
</q-btn>
<q-btn
v-if="tools.getHttpForWhatsapp(myop.cell)" fab-mini icon="fab fa-whatsapp"
color="green" type="a"
size="sm"
:href="tools.getHttpForWhatsapp(myop.cell)" target="__blank">
</q-btn>
<q-btn
v-if="tools.getHttpForTelegram(myop.usertelegram)" fab-mini icon="fab fa-telegram"
color="blue" type="a"
size="sm"
:href="tools.getHttpForTelegram(myop.usertelegram)" target="__blank">
</q-btn>
</div>
</div>
<div class="op__email">
<q-icon class="flex-icon" name="contact_mail"></q-icon>&nbsp;
<a :href="tools.getemailto(myop.email)" target="_blank">{{ myop.email }}
</a>
</div>
<div class="op__facebook" v-if="myop.paginafb">
<a :href="myop.paginafb" target="_blank">
<i aria-hidden="true" class="q-icon fab fa-facebook-f icon_contact links"></i> Pagina
Facebook
</a>
</div>
<br>
<div class="op__storia" v-html="myop.info"></div>
</q-card-section>
<q-card-actions align="center">
<q-btn rounded dense :label="$t('dialog.close')" color="primary" v-close-popup></q-btn>
</q-card-actions>
</q-card>
</q-dialog>
<q-chip
clickable
v-if="getImgTeacherByUsername(username) && isValidUsername(username)" @click="executeclick"
class="mybase__teacher-content">
<CMyAvatar :myimg="getImgTeacherByUsername(username)"></CMyAvatar>
<span>{{ getTeacherByUsername(username) }}</span>
</q-chip>
</span>
</template>
<script lang="ts" src="./CMyTeacher.ts">
</script>
<style lang="scss" scoped>
@import './CMyTeacher.scss';
</style>

View File

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

View File

@@ -0,0 +1,5 @@
.signin {
width: 100%;
margin: 0 auto;
max-width: 450px;
}

View File

@@ -0,0 +1,22 @@
import Vue from 'vue'
import { GlobalStore } from '@store'
import { UserStore } from '../../store/Modules'
import { Component, Prop, Watch } from 'vue-property-decorator'
import { toolsext } from '@src/store/Modules/toolsext'
import { validationMixin } from 'vuelidate'
import MixinBase from '../../mixins/mixin-base'
@Component({
name: 'CProfile',
mixins: [validationMixin],
components: { }
})
export default class CProfile extends MixinBase {
public $v
public $t: any
}

View File

@@ -0,0 +1,16 @@
<template>
<div>
<form>
<div class="q-gutter-xs">
</div>
</form>
</div>
</template>
<script lang="ts" src="./CProfile.ts">
</script>
<style lang="scss" scoped>
@import './CProfile.scss';
</style>

View File

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

View File

@@ -0,0 +1,17 @@
import { ISigninOptions } from 'model'
import { required, minLength, email, sameAs } from 'vuelidate/lib/validators'
export type TSignin = { signin: ISigninOptions, validationGroup: string[] }
export const validations = {
signin: {
password: {
required,
minLength: minLength(8)
},
username: {
required,
minLength: minLength(6)
}
}
}

View File

@@ -0,0 +1,5 @@
.signin {
width: 100%;
margin: 0 auto;
max-width: 450px;
}

172
src/components/CSignIn/CSignIn.ts Executable file
View File

@@ -0,0 +1,172 @@
import Vue from 'vue'
import { GlobalStore } from '@store'
import { UserStore } from '../../store/Modules'
import { Component, Prop } from 'vue-property-decorator'
import { serv_constants } from '../../store/Modules/serv_constants'
import { tools } from '../../store/Modules/tools'
import { toolsext } from '@src/store/Modules/toolsext'
import { ISigninOptions, IUserState } from 'model'
import { validations } from './CSignIn-validate'
import { validationMixin } from 'vuelidate'
import { Logo } from '../logo'
import { static_data } from '../../db/static_data'
// import {Loading, QSpinnerFacebook, QSpinnerGears} from 'quasar'
@Component({
name: 'CSignIn',
mixins: [validationMixin],
validations,
components: { Logo }
})
export default class CSignIn extends Vue {
@Prop({required: true}) public showregbutt: boolean
public $v
public loading: boolean
public $t: any
public iswaitingforRes: boolean = false
public signin: ISigninOptions = {
username: process.env.TEST_USERNAME || '',
password: process.env.TEST_PASSWORD || ''
}
get static_data() {
return static_data
}
public created() {
this.$v.$reset()
if (UserStore.state.resStatus === serv_constants.RIS_CODE__HTTP_FORBIDDEN_INVALID_TOKEN) {
this.$emit('showNotif', 'fetch.error_doppiologin')
}
// this.$myconfig.socialLogin.facebook = true
// console.log('PROVA fb:', this.$myconfig.socialLogin.facebook)
}
public env() {
return process.env
}
public getlinkforgetpwd() {
return '/requestresetpwd'
}
public errorMsg(cosa: string, item: any) {
try {
if (!item.$error) {
return ''
}
if (item.$params.email && !item.email) {
return this.$t('reg.err.email')
}
if (!item.required) {
return this.$t('reg.err.required')
}
if (!item.minLength) {
return this.$t('reg.err.atleast') + ` ${item.$params.minLength.min} ` + this.$t('reg.err.char')
}
if (!item.maxLength) {
return this.$t('reg.err.notmore') + ` ${item.$params.maxLength.max} ` + this.$t('reg.err.char')
}
return ''
} catch (error) {
// console.log("ERR : " + error);
}
}
public redirect(response) {
this.loading = false
window.location.href = response.data.redirect
}
public error(error) {
this.loading = false
// this.$errorHandler(this, error)
}
public facebook() {
this.loading = true
// this.$axios.get('/backend/loginFacebook')
// .then((response) => this.redirect(response))
// .catch((error) => this.error(error))
}
public google() {
// ...
}
public submit() {
// console.log('submit LOGIN')
this.signin.username = tools.removespaces(this.signin.username)
this.$v.signin.$touch()
if (this.$v.signin.$error) {
this.$emit('showNotif', 'reg.err.errore_generico')
return
}
this.$emit('loginInCorso')
// disable Button Login:
this.iswaitingforRes = true
if (process.env.DEBUG) {
// console.log('this.signin', this.signin)
}
UserStore.actions.signin(this.signin)
.then((riscode) => {
// console.log('signin FINITO CALL: riscode=', riscode)
if (riscode === tools.OK) {
// router.push('/signin')
}
return riscode
})
.then((riscode) => {
if (process.env.DEBUG) {
// console.log(' riscode(1) =', riscode)
}
return riscode
})
.then((riscode) => {
if (riscode === tools.OK) {
// console.log(' -> eseguo $emit(loginOk)')
this.$emit('loginOk')
// GlobalStore.actions.createPushSubscription()
// .then((rissub) => {
// // ...
// })
// .catch((e) => {
// console.log('ERROR Subscription = ' + e)
// })
} else {
this.$emit('checkErrors', riscode)
}
this.iswaitingforRes = false
})
.catch((error) => {
// console.log('ERROR SIGNIN = ' + error)
this.$emit('checkErrors', error)
})
// console.log(' END submit')
}
}

View File

@@ -0,0 +1,79 @@
<template>
<div>
<div class="text-center">
<p>
<logo></logo>
</p>
</div>
<!--Prova URL : {{env('PROVA_PAOLO')}}-->
<form>
<div class="q-gutter-xs">
<q-input
v-model="signin.username"
rounded outlined dense
@blur="$v.signin.username.$touch"
:error="$v.signin.username.$error"
:error-message="`${errorMsg('username', $v.signin.username)}`"
:label="$t('reg.username_login')">
<template v-slot:prepend>
<q-icon name="person"/>
</template>
</q-input>
<q-input
v-model="signin.password"
type="password"
rounded outlined dense
v-on:keyup.enter="submit()"
@blur="$v.signin.password.$touch"
:error="$v.signin.password.$error"
:error-message="`${errorMsg('password', $v.signin.password)}`"
:label="$t('reg.password')">
<template v-slot:prepend>
<q-icon name="vpn_key"/>
</template>
</q-input>
<!--<q-card class="flex flex-center">-->
<!--&lt;!&ndash;<q-btn v-if="$myconfig.socialLogin.facebook" :loading="loading" class="q-mb-md q-mr-md" rounded icon="fab fa-facebook-f" size="sm" color="blue-10" text-color="white" @click="facebook" :label="$t('components.authentication.login.facebook')"/>&ndash;&gt;-->
<!--&lt;!&ndash;-->
<!--<q-btn v-if="$myconfig.socialLogin.facebook" class="q-mb-md q-mr-md" rounded icon="fab fa-facebook-f" size="sm" color="blue-10" text-color="white" @click="facebook" :label="$t('components.authentication.login.facebook')"/>-->
<!--<q-btn v-if="$myconfig.socialLogin.google" class="q-mb-md q-mr-md" rounded icon="fab fa-google" size="sm" color="deep-orange-14" text-color="white" @click="google" :label="$t('components.authentication.login.google')"/>-->
<!--&ndash;&gt;-->
<!--</q-card>-->
<div align="center">
<q-btn rounded size="md" color="primary" @click="submit"
:disable="$v.$error || iswaitingforRes">{{$t('login.enter')}}
</q-btn>
</div>
<br>
<div class="text-center" style="margin-bottom: 10px;">
<a :href="getlinkforgetpwd()" style="color:gray;">{{$t('reg.forgetpassword')}}</a>
</div>
<div v-if="static_data.functionality.ENABLE_REGISTRATION && showregbutt" align="center" style="margin-top:10px;">
Se non sei ancora Registrato:<br>
<q-btn rounded size="md" color="primary" to="/signup" :label="$t('reg.submit')">
</q-btn>
</div>
</div>
</form>
</div>
</template>
<script lang="ts" src="./CSignIn.ts">
</script>
<style lang="scss" scoped>
@import './CSignIn.scss';
</style>

View File

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

View File

@@ -0,0 +1,39 @@
import { ISignupOptions } from 'model'
import { email, minLength, required, sameAs } from 'vuelidate/lib/validators'
// import { ValidationRuleset } from 'vuelidate'
import { complexity, registeredemail, registereduser, aportadorexist } from '../../validation'
export interface TSignup { signup: ISignupOptions, validationGroup: string[] }
export const validations = {
signup: {
repeatPassword: {
required,
sameAsPassword: sameAs('password')
},
password: {
required,
minLength: minLength(8),
complexity
},
username: {
required,
minLength: minLength(6),
registereduser
},
name: {
required
},
surname: {
required
},
email: {
email,
registeredemail,
required
},
terms: {
required
}
}
}

View File

@@ -0,0 +1,34 @@
.signup {
width: 100%;
margin: 0 auto;
max-width: 450px;
}
.wrapper {
display: flex;
align-items: center;
justify-content: center;
}
.clCellCode {
border-radius: 32px;
border-right: #2d2260;
height: 50px;
font-size: 1rem;
padding: 8px;
}
.clCell {
border-radius: 32px;
border-right: #2d2260;
height: 50px;
font-size: 1rem;
padding: 8px;
}
.vue-country-select{
border-radius: 32px;
}

246
src/components/CSignUp/CSignUp.ts Executable file
View File

@@ -0,0 +1,246 @@
import Vue from 'vue'
import { Component, Prop, Watch } from 'vue-property-decorator'
import { UserStore } from '@store'
import { tools } from '../../store/Modules/tools'
import { toolsext } from '@src/store/Modules/toolsext'
import { ISignupOptions, IUserState, IUserFields } from 'model'
import { validations, TSignup } from './CSignUp-validate'
import { validationMixin } from 'vuelidate'
import { Logo } from '../../components/logo'
import { DefaultProfile } from '../../store/Modules/UserStore'
// import 'vue-country-code/dist/vue-country-code.css'
import { serv_constants } from '@src/store/Modules/serv_constants'
import VueCountryCode from 'vue-country-code'
import { registereduser } from '../../validation'
import MixinBase from '../../mixins/mixin-base'
import { CTitleBanner } from '../CTitleBanner'
Vue.use(VueCountryCode)
// import {Loading, QSpinnerFacebook, QSpinnerGears} from 'quasar'
@Component({
name: 'CSignUp',
mixins: [validationMixin],
validations,
components: { Logo, CTitleBanner }
})
export default class CSignUp extends MixinBase {
@Prop({ required: false, default: false }) public showadultcheck: boolean
@Prop({ required: false, default: false }) public showcell: boolean
@Prop({ required: false, default: false }) public shownationality: boolean
public $v
public $q
public $t: any
public countryname: string = ''
public iamadult: boolean = false
public duplicate_email: boolean = false
public duplicate_username: boolean = false
public signup: ISignupOptions = {
email: process.env.TEST_EMAIL || '',
username: process.env.TEST_USERNAME || '',
name: process.env.TEST_NAME || '',
surname: process.env.TEST_SURNAME || '',
password: process.env.TEST_PASSWORD || '',
repeatPassword: process.env.TEST_PASSWORD || '',
terms: !process.env.PROD,
profile: DefaultProfile,
aportador_solidario: '',
}
public created() {
this.$v.$reset()
}
get allowSubmit() {
let error = this.$v.$error || this.$v.$invalid
if (this.showadultcheck)
error = error || !this.iamadult
if (this.showcell)
error = error || this.signup.profile.cell.length <= 6
return !error
}
/*
validations: {
isAsync: true,
form: {
email: {
required, email,
isUnique: value => {
if (value === '') return true;
return axios.get(process.env.MONGODB_HOST + '/email/' + value)
.then(res => {
return (res.status !== 200)
}).catch((e) => {
return true;
})
}
},
password: {required, minLength: minLength(8), maxLength: maxLength(20)},
username: {
required, minLength: minLength(6), maxLength: maxLength(20),
isUnique: value => {
if (value === '') return true;
return axios.get(process.env.MONGODB_HOST + '/users/' + value)
.then(res => {
return (res.status !== 200)
}).catch((e) => {
return true;
})
}
},
repeatPassword: {
sameAsPassword: sameAs('password')
},
terms: {required},
}
}, */
public env() {
return process.env
}
public errorMsg(cosa: string, item: any) {
try {
if (!item.$error) {
return ''
}
console.log('item', item)
// console.log('errorMsg', cosa, item)
if (item.$params.email && !item.email) {
return this.$t('reg.err.email')
}
if (cosa === 'repeatpassword') {
if (!item.sameAsPassword) {
return this.$t('reg.err.sameaspassword')
}
}
// console.log('item', item)
if (item.minLength !== undefined) {
if (!item.minLength) {
return this.$t('reg.err.atleast') + ` ${item.$params.minLength.min} ` + this.$t('reg.err.char')
}
}
if (item.complexity !== undefined) {
if (!item.complexity) {
return this.$t('reg.err.complexity')
}
}
// if (!item.maxLength) { return this.$t('reg.err.notmore') + ` ${item.$params.maxLength.max} ` + this.$t('reg.err.char') }
if (item.required !== undefined) {
if (!item.required) {
return this.$t('reg.err.required')
}
}
// console.log(' ....avanti')
if (cosa === 'email') {
// console.log("EMAIL " + item.isUnique);
// console.log(item);
if (!item.isUnique) {
return this.$t('reg.err.duplicate_email')
}
} else if (cosa === 'username') {
// console.log(item);
console.log('username')
console.log(item.$error)
if (!item.isUnique) {
return this.$t('reg.err.duplicate_username')
}
} else if (cosa === 'aportador_solidario') {
// console.log(item);
if (!item.aportadorexist) {
// console.log('!item.aportadorexist !')
return this.$t('reg.err.aportador_not_exist')
}
} else if ((cosa === 'name') || (cosa === 'surname')) {
// console.log(item);
}
return ''
} catch (error) {
// console.log("ERR : " + error);
}
}
public changeemail(value) {
this.signup.email = tools.removespaces(this.signup.email)
this.signup.email = this.signup.email.toLowerCase()
this.$emit('update:value', this.signup.email)
}
public changeusername(value) {
this.signup.username = tools.removespaces(this.signup.username)
this.$emit('update:value', this.signup.username)
}
public submitOk() {
this.$v.signup.$touch()
this.signup.email = tools.removespaces(this.signup.email)
this.signup.email = this.signup.email.toLowerCase()
this.signup.username = tools.removespaces(this.signup.username)
this.duplicate_email = false
this.duplicate_username = false
if (!this.signup.terms) {
tools.showNotif(this.$q, this.$t('reg.err.terms'))
return
}
if (this.$v.signup.$error) {
tools.showNotif(this.$q, this.$t('reg.err.errore_generico'))
return
}
this.signup.name = tools.CapitalizeAllWords(this.signup.name)
this.signup.surname = tools.CapitalizeAllWords(this.signup.surname)
this.$q.loading.show({ message: this.$t('reg.incorso') })
console.log(this.signup)
return UserStore.actions.signup(tools.clone(this.signup))
.then((ris) => {
if (tools.SignUpcheckErrors(this, ris.code, ris.msg))
this.$q.loading.hide()
}).catch((error) => {
console.log('ERROR = ' + error)
this.$q.loading.hide()
})
}
public intcode_change(coderec) {
// console.log('intcode', coderec)
this.signup.profile.intcode_cell = '+' + coderec.dialCode
this.signup.profile.iso2_cell = coderec.iso2
}
public selectcountry({ name, iso2, dialCode }) {
// console.log(name, iso2, dialCode)
this.signup.profile.nationality = iso2
this.countryname = name
}
public inputUsername(value) {
this.signup.username = value.trim()
}
}

View File

@@ -0,0 +1,195 @@
<template>
<div>
<div class="text-center">
<p>
<logo></logo><CTitleBanner :title="$t('pages.SignUp')"></CTitleBanner>
</p>
</div>
<!--Prova URL : {{env('PROVA_PAOLO')}}-->
<div class="q-gutter-sm">
<q-input
v-model="signup.email"
rounded outlined
@blur="$v.signup.email.$touch"
@input="changeemail"
:error="$v.signup.email.$error"
:error-message="errorMsg('email', $v.signup.email)"
maxlength="50"
debounce="1000"
:label="$t('reg.email')">
<template v-slot:prepend>
<q-icon name="email"/>
</template>
</q-input>
<q-input
v-model="signup.username"
rounded outlined
@input="changeusername"
@blur="$v.signup.username.$touch"
:error="$v.signup.username.$error"
@keydown.native.54="(event) => event.preventDefault()"
@keydown.native.52="(event) => event.preventDefault()"
@keydown.space="(event) => event.preventDefault()"
maxlength="20"
debounce="1000"
:error-message="errorMsg('username', $v.signup.username)"
:label="$t('reg.username')">
<template v-slot:prepend>
<q-icon name="person"/>
</template>
</q-input>
<q-input
v-model="signup.name"
rounded outlined
@blur="$v.signup.name.$touch"
:error="$v.signup.name.$error"
maxlength="30"
debounce="1000"
:error-message="errorMsg('name', $v.signup.name)"
:label="$t('reg.name')">
<template v-slot:prepend>
<q-icon name="person"/>
</template>
</q-input>
<q-input
v-model="signup.surname"
rounded outlined
@blur="$v.signup.surname.$touch"
:error="$v.signup.surname.$error"
maxlength="30"
debounce="1000"
:error-message="errorMsg('surname', $v.signup.surname)"
:label="$t('reg.surname')">
<template v-slot:prepend>
<q-icon name="person"/>
</template>
</q-input>
<q-input
v-model="signup.password"
type="password"
rounded outlined
@blur="$v.signup.password.$touch"
:error="$v.signup.password.$error"
:error-message="`${errorMsg('password', $v.signup.password)}`"
maxlength="30"
:label="$t('reg.password')">
<template v-slot:prepend>
<q-icon name="vpn_key"/>
</template>
</q-input>
<q-input
v-model="signup.repeatPassword"
type="password"
maxlength="30"
rounded outlined
@blur="$v.signup.repeatPassword.$touch"
:error="$v.signup.repeatPassword.$error"
:error-message="`${errorMsg('repeatpassword', $v.signup.repeatPassword)}`"
:label="$t('reg.repeatPassword')">
<template v-slot:prepend>
<q-icon name="vpn_key"/>
</template>
</q-input>
<!--:hint="$t('reg.tips.repeatpassword')"-->
<q-input
v-if="shownationality"
v-model="countryname"
:readonly="true"
rounded outlined
debounce="1000"
:label="$t('reg.nationality')">
<template v-slot:prepend>
<vue-country-code
@onSelect="selectcountry"
:preferredCountries="tools.getprefCountries"
:dropdownOptions="{ disabledDialCode: true }"
>
</vue-country-code>
</template>
</q-input>
<div v-if="!tools.isMobile()"><br></div>
<vue-tel-input
v-if="showcell"
@country-changed="intcode_change"
v-model="signup.profile.cell"
:placeholder="$t('reg.cell')"
maxlength="20"
:enabledCountryCode="true"
inputClasses="clCell"
wrapperClasses="clCellCode">
</vue-tel-input>
<q-checkbox
v-model="signup.terms"
color="secondary"
@blur="$v.signup.terms.$touch"
:error="$v.signup.terms.$error"
:error-message="`${errorMsg('terms', $v.signup.terms)}`"
:label="$t('reg.terms')">
</q-checkbox>
<q-checkbox
v-if="showadultcheck"
v-model="iamadult"
color="secondary"
:label="$t('reg.onlyadult')">
</q-checkbox>
<div v-if="showadultcheck">
<br>
</div>
<div class="wrapper">
<q-btn rounded size="lg" color="positive" @click="submitOk" :disabled='!allowSubmit' :label="$t('reg.submit')">
</q-btn>
</div>
</div>
<!--
<div align="center">
<q-btn rounded size="lg" color="primary" @click="submitOk" :disable="">{{$t('reg.submit')}}
</q-btn>
</div>
-->
</div>
</template>
<script lang="ts" src="./CSignUp.ts">
</script>
<style lang="scss" scoped>
@import './CSignUp.scss';
</style>

View File

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

View File

View File

@@ -0,0 +1,37 @@
import Vue from 'vue'
import { Component, Prop, Watch } from 'vue-property-decorator'
import { CSignIn } from '../../components/CSignIn'
import { tools } from '../../store/Modules/tools'
@Component({
name: 'CSigninNoreg',
components: { CSignIn }
})
export default class CSigninNoreg extends Vue {
@Prop({ required: true }) public showregbutt: boolean
public $v
public $q
public $t
public loginOk() {
tools.loginOk(this, true)
}
public loginInCorso() {
tools.loginInCorso(this)
}
public checkErrors(riscode) {
tools.SignIncheckErrors(this, riscode, true)
}
public showNotif(msgcode) {
tools.showNotif(this.$q, this.$t(msgcode))
}
get mythis() {
return this
}
}

View File

@@ -0,0 +1,18 @@
<template>
<div>
<CSignIn :mythis="mythis"
@loginOk="loginOk"
@loginInCorso="loginInCorso"
:showregbutt="showregbutt"
@checkErrors="checkErrors"
@showNotif="showNotif">
</CSignIn>
</div>
</template>
<script lang="ts" src="./CSigninNoreg.ts">
</script>
<style lang="scss" scoped>
@import './CSigninNoreg.scss';
</style>

View File

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

View File

@@ -0,0 +1,16 @@
.text-title {
font-size: 0.9rem;
}
.centeritems{
place-content: center;
}
.imgNormal{
height: 80px;
width: 80px;
}
.imgSmall{
height: 50px;
width: 50px;
}

View File

@@ -0,0 +1,72 @@
import { tools } from '../../store/Modules/tools'
import { CCardState } from '../CCardState'
import { CCopyBtn } from '../CCopyBtn'
import { IOperators, IOrder, IProduct } from '@src/model'
import { defineComponent, PropType, toRef } from 'vue'
import CTitleBanner from '@/components/CTitleBanner/CTitleBanner'
import { useProducts } from '@store/Products'
export default defineComponent({
name: 'CSingleCart',
props: {
order: {
type: Object as PropType<IOrder>,
required: true,
},
showall: {
type: Boolean,
required: false,
default: false,
},
nomodif: {
type: Boolean,
required: false,
default: false,
},
},
components: { CTitleBanner, CCardState, CCopyBtn },
setup(props) {
const products = useProducts()
const order = toRef(props, 'order')
function myimgclass() {
if (props.showall) {
return 'imgNormal'
} else {
return 'imgSmall'
}
}
function addsubqty(addqty: boolean, subqty: boolean) {
if (addqty) {
if (props.order.quantity! >= 10)
return false
}
if (subqty) {
if (props.order.quantity === 0)
return false
}
products.addSubQtyToItem({
addqty,
subqty,
order: props.order,
}).then((newqty) => {
order.value.quantity = newqty
})
}
function removeFromCard() {
products.removeFromCart({ order: order.value })
}
return {
myimgclass,
addsubqty,
removeFromCard,
}
},
})

View File

@@ -0,0 +1,48 @@
<template>
<div class="q-pa-xs q-gutter-xs">
<div class="row items-center justify-evenly no-wrap">
<div class="col-2 text-h6 ellipsis">
<img
v-if="true" :src="`statics/` + order.product.img" :alt="order.product.name" :class="myimgclass">
</div>
<div class="col-4 q-ml-xs">
{{ order.product.name }}
<div v-if="showall">
<br><span class="text-grey">{{ order.product.description }}</span>
</div>
</div>
<div class="col-3">
<div class="row q-mb-xs no-wrap items-center centeritems">
<q-btn
v-if="showall && !nomodif" round size="xs" text-color="grey" icon="fas fa-minus"
@click="addsubqty(false, true)"></q-btn>
<!--<q-field outlined dense style="width: 25px; height: 20px; " class="q-mx-xs text-subtitle4">
<template v-slot:control>
<div class="self-center no-outline" tabindex="0" >{{ order.quantity }}</div>
</template>
</q-field>-->
<div class="q-mx-sm text-blue-14">{{ order.quantity }}</div>
<q-btn
v-if="showall && !nomodif" round size="xs" text-color="grey" icon="fas fa-plus"
@click="addsubqty(true, false)"></q-btn>
</div>
</div>
<div class="col-2 no-wrap text-subtitle3 q-mr-sm">
&nbsp;{{ (order.price * order.quantity).toFixed(2) }}
</div>
<div class="col-1">
<q-btn v-if="!nomodif" icon="fas fa-times" color="negative" round size="xs" @click="removeFromCard">
</q-btn>
</div>
</div>
</div>
</template>
<script lang="ts" src="./CSingleCart.ts">
</script>
<style lang="scss" scoped>
@import './CSingleCart.scss';
</style>

View File

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

View File

@@ -0,0 +1,9 @@
.myshad {
text-shadow: .125rem .125rem .125rem darkgray;
}
.nonvisibile{
border-radius: 16px;
border: red solid 3px;
padding: 4px;
}

View File

@@ -0,0 +1,93 @@
import { defineComponent, ref } from 'vue'
export default defineComponent({
name: 'CTitleBanner',
props: {
title: {
type: String,
required: true,
},
bgcolor: {
type: String,
required: false,
default: 'bg-primary',
},
clcolor: {
type: String,
required: false,
default: 'text-white',
},
mystyle: {
type: String,
required: false,
default: '',
},
myclass: {
type: String,
required: false,
default: '',
},
myclasstext: {
type: String,
required: false,
default: '',
},
icon: {
type: String,
required: false,
default: '',
},
visible: {
type: Boolean,
required: false,
default: true,
},
canopen: {
type: Boolean,
required: false,
default: false,
},
imgpreview: {
type: String,
required: false,
default: '',
},
},
components: {},
emits: ['apri'],
setup(props, { emit }) {
const myvisible = ref(false)
function created() {
myvisible.value = props.visible
}
function iconopen() {
if (!myvisible.value)
return 'fas fa-chevron-down q-icon q-expansion-item__toggle-icon q-focusable '
else
return 'fas fa-chevron-down q-icon q-expansion-item__toggle-icon q-focusable rotate-180'
}
function apri() {
myvisible.value = !myvisible.value
if (myvisible.value)
emit('apri')
}
function getclass() {
if (myvisible.value)
return 'isvisibile'
else
return 'nonvisibile glossy'
}
created()
return {
iconopen,
apri,
getclass,
}
},
})

View File

@@ -0,0 +1,37 @@
<template>
<div>
<q-banner
inline-actions
rounded dense
:class="bgcolor+` cursor-pointer q-my-sm `+clcolor+ ` ` + myclass + ' ' + getclass"
style="text-align: center; "
@click="apri()"
>
<template v-slot:avatar>
<q-icon v-if="canopen && icon" :name="icon" color="white"/>
</template>
<template v-slot:action>
<div class="cursor-pointer">
<q-icon v-if="canopen" :name="iconopen" color="white"/>
</div>
</template>
<span :class="`mybanner `+ myclasstext" :style="mystyle">{{title}}</span>
</q-banner>
<q-slide-transition>
<div v-if="myvisible" class="rounded-borders">
<slot></slot>
</div>
<div v-if="imgpreview" class="text-center cursor-pointer clBorderSteps" style="opacity: 0.5;" @click="myvisible = !myvisible">
<q-img :src="imgpreview" class="img"></q-img>
</div>
</q-slide-transition>
</div>
</template>
<script lang="ts" src="./CTitleBanner.ts">
</script>
<style lang="scss" scoped>
@import './CTitleBanner.scss';
</style>

View File

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

View File

@@ -7,14 +7,12 @@ import { static_data } from '@src/db/static_data'
import { useQuasar } from 'quasar'
import { useGlobalStore } from '@store/globalStore'
import { FormNewsletter } from '../FormNewsletter'
import { MixinBase } from '../../mixins/mixin-base'
import { Logo } from '../logo'
import { useI18n } from '@src/boot/i18n'
import { FormNewsletter } from '@components'
export default defineComponent({
name: 'Footer',
mixins: [MixinBase],
components: { Logo, FormNewsletter },
setup() {

View File

@@ -64,14 +64,15 @@ myclass="text-center" :fbimage="getValDb('FBPAGE_IMG', false)"
<i
v-if="getValDb('MAIN_EMAIL', false)" aria-hidden="true"
class="q-icon fas fa-envelope q-mx-sm"></i>
<a :href="`mailto:` + getValDb('MAIN_EMAIL', false)" class="links">{{ getValDb('MAIN_EMAIL', false)
<a :href="`mailto:` + getValDb('MAIN_EMAIL', false)" class="links">{{
getValDb('MAIN_EMAIL', false)
}}</a><br>
<div style="margin-bottom: 20px;"></div>
<div
v-for="(rec, index) in getarrValDb('CONTACTS_EMAIL_CELL', false)"
:key="index"
class="mycontacts_text margin_buttons_footer"
style="margin-bottom: 0px;">
style="margin-bottom: 0;">
<div>
{{ rec.name }}: {{ rec.phone }}
</div>
@@ -124,7 +125,9 @@ v-if="tools.getHttpForTelegram(rec.usertelegram)" fab-mini
<p class="text-center">
<router-link v-if="static_data.functionality.SHOW_ONLY_POLICY" to="/policy" custom v-slot="{ navigate }">
<span class="footer_link" @click="navigate" @keypress.enter="navigate" role="link">{{t('privacy_policy')}}</span></router-link>
<span class="footer_link" @click="navigate" @keypress.enter="navigate" role="link">{{
t('privacy_policy')
}}</span></router-link>
</p>
</div>
@@ -141,12 +144,13 @@ v-if="tools.getHttpForTelegram(rec.usertelegram)" fab-mini
</div>
<div v-else>
<router-link :to="myitemmenu.path" custom v-slot="{ navigate }">
<span class="footer_link" @click="navigate" @keypress.enter="navigate" role="link"><span
<span
class="footer_link" @click="navigate" @keypress.enter="navigate"
role="link"><span
v-if="myitemmenu.level_child > 0">&nbsp;&nbsp;&nbsp;</span>
{{ tools.getLabelByItem(myitemmenu) }}</span><br/>
</router-link>
</div>
<!--<a :href="myitemmenu.path"><span class="footer_link">{{tools.getLabelByItem(myitemmenu)}}</span></a><br/>-->
</div>
</div>
</div>

View File

@@ -6,12 +6,10 @@ import { useQuasar } from 'quasar'
import { useI18n } from '@src/boot/i18n'
import Api from '@api'
import { serv_constants } from '@store/Modules/serv_constants'
import { MixinBase } from '../../mixins/mixin-base'
import { toolsext } from '@src/store/Modules/toolsext'
export default defineComponent({
name: 'FormNewsletter',
mixins: [MixinBase],
props: {
name: {
required: false,
@@ -55,7 +53,7 @@ export default defineComponent({
const locale = toRef(props, 'locale')
const onSubmit = async function a2() {
if (accept.value !== true) {
if (!accept.value) {
$q.notify({
color: 'red-5',
textColor: 'white',

View File

@@ -7,6 +7,13 @@ export * from './BannerCookies'
export * from './testpao'
export * from './Footer'
export * from './FormNewsletter'
export * from './CCopyBtn'
export * from './CCard'
export * from './CCardOperator'
export * from './CCardCarousel'
export * from './CCardDiscipline'
export * from './CMyTeacher'
export * from './CSingleCart'
// export * from './PagePolicy'
// export * from './CFacebookFrame'
// export * from './CPreloadImages'

View File

@@ -2,18 +2,12 @@ import {
defineComponent,
} from 'vue'
import { tools } from '@src/store/Modules/tools'
import { static_data } from '@src/db/static_data'
import { useQuasar } from 'quasar'
import { useGlobalStore } from '@store/globalStore'
import { FormNewsletter } from '../FormNewsletter'
import { MixinBase } from '../../mixins/mixin-base'
import { Logo } from '../logo'
import { useI18n } from '@src/boot/i18n'
export default defineComponent({
name: 'TestPao',
mixins: [MixinBase],
components: { Logo, FormNewsletter },
props: {
mystyle: {

View File

@@ -9,48 +9,41 @@ import { useUserStore } from '@store/UserStore'
import { useGlobalStore } from '@store/globalStore'
import { useQuasar } from 'quasar'
import { IDataPass } from '@model'
import { shared_consts } from '../common/shared_vuejs'
import { tools } from '../store/Modules/tools'
import { func_tools } from '../store/Modules/toolsext'
import { costanti } from '@costanti'
import { fieldsTable } from '@store/Modules/fieldsTable'
// You can declare a mixin as the same style as components.
export const MixinBase = {
created() {
},
mythis() {
return this
},
showNotif(msg: string) {
export default function () {
function showNotif(msg: string) {
const $q = useQuasar()
const { t } = useI18n();
const { t } = useI18n()
tools.showNotif($q, t(msg))
},
}
db_fieldsTable() {
// return fieldsTable
},
function db_fieldsTable() {
return fieldsTable
}
getValDb(keystr: string, serv: boolean, def?: any, table?: string, subkey?: any, id?: any, idmain?: any) {
function getValDb(keystr: string, serv: boolean, def?: any, table?: string, subkey?: any, id?: any, idmain?: any) {
console.log('getValDb')
return toolsext.getValDb(keystr, serv, def, table, subkey, id, idmain)
},
}
getValDbLang(keystr: string, serv: boolean, def?: any, table?: string, subkey?: any) {
function getValDbLang(keystr: string, serv: boolean, def?: any, table?: string, subkey?: any) {
let ris = toolsext.getValDb(`${keystr}_${toolsext.getLocale()}`, serv, def, table, subkey)
if (ris === def) ris = toolsext.getValDb(`${keystr}_it`, serv, def, table, subkey)
return ris
},
}
async setValDb(key: string, value: any, type: any, serv: boolean, table?: string, subkey?: string, id?: any) {
async function setValDb(key: string, value: any, type: any, serv: boolean, table?: string, subkey?: string, id?: any) {
const userStore = useUserStore()
const globalStore = useGlobalStore()
const $q = useQuasar()
const { t } = useI18n();
const { t } = useI18n()
// console.log('setValDb', key, value, serv, table, subkey)
let mydatatosave: IDataPass | null = null
@@ -166,9 +159,9 @@ export const MixinBase = {
// Undo...
}
})
},
}
getarrValDb(keystr: string, serv: boolean) {
function getarrValDb(keystr: string, serv: boolean) {
const globalStore = useGlobalStore()
const myval = globalStore.getValueSettingsByKey(keystr, serv)
@@ -184,6 +177,14 @@ export const MixinBase = {
} catch (e) {
return []
}
},
}
return {
showNotif,
db_fieldsTable,
getValDb,
getValDbLang,
setValDb,
getarrValDb,
}
}

46
src/mixins/mixin-operator.ts Executable file
View File

@@ -0,0 +1,46 @@
import { useCalendarStore } from '@store/CalendarStore'
export default function () {
function isEstate(){
const now = new Date()
return (now.getMonth() === 5) || (now.getMonth() === 6) || (now.getMonth() === 7) || (now.getMonth() === 8)
}
function isEstateRiprenderanno(){
const now = new Date()
return (now.getMonth() === 9)
}
function getOperators() {
const calendarStore = useCalendarStore()
return calendarStore.operators
}
function getOperatorByUsername(username: string) {
const calendarStore = useCalendarStore()
return calendarStore.getOperatorByUsername(username)
}
function getImgTeacherByUsername(username: string) {
const calendarStore = useCalendarStore()
return 'statics/images/' + calendarStore.getImgTeacherByUsername(username)
}
function getTeacherByUsername(username: string) {
const op = getOperatorByUsername(username)
if (!!op) {
return op.name + ' ' + op.surname
} else {
return ''
}
}
return {
isEstate,
isEstateRiprenderanno,
getOperators,
getOperatorByUsername,
getImgTeacherByUsername,
getTeacherByUsername,
}
}

View File

@@ -1,7 +1,7 @@
import { IAction } from '@src/model/Projects'
import { IPaymentType } from '@src/model/UserStore'
import {
ICart, IDepartment, IProducer, IProduct, IShareWithUs, IStorehouse,
IDepartment, IProducer, IShareWithUs, IStorehouse,
} from '@src/model/Products'
export interface IPost {

View File

@@ -1,31 +1,35 @@
import { defineComponent } from 'vue'
import { defineComponent, ref, onMounted, watch, computed } from 'vue'
/*
import { Component, Prop, Watch } from 'vue-property-decorator'
import { GlobalStore, UserStore } from '@store'
import { tools } from '../../store/Modules/tools'
import { toolsext } from '../../store/Modules/toolsext'
import { static_data } from '../../db/static_data'
import { Screen } from 'quasar'
import { colmypage } from '@src/store/Modules/fieldsTable'
import { CImgText } from '../../components/CImgText/index'
import { CCard, CGridTableRec, CMyPage, CTitleBanner } from '@components'
import MixinMetaTags from '../../mixins/mixin-metatags'
import MixinBase from '@src/mixins/mixin-base'
import { IMyPage } from '@src/model/GlobalStore'
@Component({
mixins: [MixinBase],
components: { CImgText, CCard, CMyPage, CTitleBanner }
})*/
import { useGlobalStore } from '@store/globalStore'
import { useRoute } from 'vue-router'
export default defineComponent({
name: 'Mypage',
setup() {
return {}
const rec = ref({})
const globalStore = useGlobalStore()
const route = useRoute()
const path = computed(() => route.path)
async function created() {
// console.log('this.$route.path', this.$route.path)
rec.value = await globalStore.loadPage(route.path)
// console.log('mounted', this.rec)
}
watch(path, async (to: string, from: string) => {
rec.value = await globalStore.loadPage(to)
})
function meta() {
// return tools.metafunc(this)
}
onMounted(created)
return {
rec,
}
},
})
/*
@@ -36,14 +40,14 @@ export default class Mypage extends MixinMetaTags {
public async mounted() {
// console.log('this.$route.path', this.$route.path)
this.rec = await GlobalStore.actions.loadPage(this.$route.path)
this.rec = await GlobalStore.loadPage(this.$route.path)
// console.log('mounted', this.rec)
}
@Watch('$route.path')
public async changepage() {
// console.log('changepage')
this.rec = await GlobalStore.actions.loadPage(this.$route.path)
this.rec = await GlobalStore.loadPage(this.$route.path)
}
public meta() {

View File

@@ -1,6 +1,43 @@
<template>
<div>
Mia Pagina...
<CMyPage
:title="rec.title" :imgbackground="`statics/` + rec.imgback"
:sizes="`max-height: ` + rec.heightimg + `px`">
<span>{{
setmeta({
title: rec.title,
description: rec.description,
keywords: rec.keywords,
})
}}
</span>
<div class="q-ma-sm q-gutter-sm q-pa-xs">
<div v-if="!!rec.img1" class="text-center">
<q-img :src="`statics/`+ rec.img1" class="img"></q-img>
</div>
<div v-if="!!rec.content" v-html="rec.content"></div>
<q-video v-if="!!rec.video1" :src="rec.video1" :ratio="rec.ratio1">
</q-video>
<div v-if="!!rec.img2" class="text-center">
<q-img :src="`statics/`+ rec.img2" class="img"></q-img>
</div>
<div v-if="!!rec.content2" v-html="rec.content2"></div>
<q-video v-if="!!rec.video2" :src="rec.video2" :ratio="rec.ratio2"></q-video>
<div v-if="!!rec.img3" class="text-center">
<q-img :src="`statics/`+ rec.img2" class="img"></q-img>
</div>
<div v-if="!!rec.content3" v-html="rec.content3"></div>
<q-video v-if="!!rec.video3" :src="rec.video3" :ratio="rec.ratio3"></q-video>
<div v-if="!!rec.content4" v-html="rec.content4"></div>
</div>
</CMyPage>
</div>
</template>
<script lang="ts" src="./mypage.ts">
@@ -9,4 +46,3 @@
<style lang="scss" scoped>
@import 'mypage.scss';
</style>

View File

@@ -1,47 +0,0 @@
<template>
<div>
<CMyPage :title="rec.title" :imgbackground="`public/` + rec.imgback"
:sizes="`max-height: ` + rec.heightimg + `px`">
<span>{{
setmeta({
title: rec.title,
description: rec.description,
keywords: rec.keywords
})
}}
</span>
<div class="q-ma-sm q-gutter-sm q-pa-xs">
<div v-if="!!rec.img1" class="text-center">
<q-img :src="`public/`+ rec.img1" class="img"></q-img>
</div>
<div v-if="!!rec.content" v-html="rec.content"></div>
<q-video v-if="!!rec.video1" :src="rec.video1" :ratio="rec.ratio1">
</q-video>
<div v-if="!!rec.img2" class="text-center">
<q-img :src="`public/`+ rec.img2" class="img"></q-img>
</div>
<div v-if="!!rec.content2" v-html="rec.content2"></div>
<q-video v-if="!!rec.video2" :src="rec.video2" :ratio="rec.ratio2"></q-video>
<div v-if="!!rec.img3" class="text-center">
<q-img :src="`public/`+ rec.img2" class="img"></q-img>
</div>
<div v-if="!!rec.content3" v-html="rec.content3"></div>
<q-video v-if="!!rec.video3" :src="rec.video3" :ratio="rec.ratio3"></q-video>
<div v-if="!!rec.content4" v-html="rec.content4"></div>
</div>
</CMyPage>
</div>
</template>
<script lang="ts" src="./mypage.ts">
</script>
<style lang="scss" scoped>
@import 'mypage.scss';
</style>

View File

@@ -3723,13 +3723,15 @@ export const tools = {
return mystr.replace(/\s+/g, '')
},
copyStringToClipboard(mythis: any, mystr: string, show: boolean) {
copyStringToClipboard(mystr: string, show: boolean) {
const $q = useQuasar()
const { t } = useI18n()
copyToClipboard(mystr).then(() => {
let msg = mythis.t('dialog.copyclipboard')
let msg = t('dialog.copyclipboard')
if (show)
msg += ' \'' + mystr + '\''
this.showNotif(mythis.$q, msg)
this.showNotif($q, msg)
})
},

View File

@@ -290,7 +290,7 @@ export const useProducts = defineStore('Products', {
return ris
},
async addSubQtyToItem({ addqty, subqty, order } : { addqty: number, subqty: number, order: IOrder }) {
async addSubQtyToItem({ addqty, subqty, order } : { addqty: boolean, subqty: boolean, order: IOrder }) {
const userStore = useUserStore()
if (!static_data.functionality.ENABLE_ECOMMERCE)

View File

@@ -1,3 +1,4 @@
import { defineStore } from 'pinia'
import { IProject, IProjectsState, IDrag, IMenuList, IAction } from 'model'
import { Privacy, TipoVisu } from '@src/model'
@@ -13,7 +14,6 @@ import { RouteNames } from '@src/router/route-names'
import * as Types from '@src/store/Api/ApiTypes'
import { serv_constants } from '@src/store/Modules/serv_constants'
import { static_data } from '@src/db/static_data'
import { defineStore } from 'pinia'
import { useUserStore } from '@store/UserStore'
import { useGlobalStore } from '@store/globalStore'
@@ -26,7 +26,8 @@ const listFieldsToChange: string [] = ['descr', 'respUsername', 'viceRespUsernam
const listFieldsUpdateCalculation: string [] = ['hoursplanned', 'hoursleft', 'hoursworked', 'progressCalc', 'endwork_estimate']
export const useProjectStore = defineStore('Projects', {
export const useProjectStore = defineStore({
id: 'Projects',
state: (): IProjectsState => ({
showtype: costanti.ShowTypeTask.SHOW_LAST_N_COMPLETED,
projects: [],

View File

@@ -248,7 +248,8 @@ export const useUserStore = defineStore('UserStore', {
.then((res) => {
if (res) {
return (res.data.code === serv_constants.RIS_CODE_OK)
} return false
}
return false
})
.catch((error: any) => false)
},
@@ -312,6 +313,58 @@ export const useUserStore = defineStore('UserStore', {
.then((res) => res).catch((error) => ({ numtot: 0, numadded: 0, numalreadyexisted: 0 }))
},
async importExtraList(paramquery: any) {
return Api.SendReq('/users/import_extralist', 'POST', paramquery)
.then((res) => {
return res
}).catch((error) => {
return { numtot: 0, numadded: 0, numalreadyexisted: 0 }
})
},
async execDbOp(paramquery: any) {
return Api.SendReq('/users/dbop', 'POST', paramquery)
.then((res) => {
return res.data
}).catch((error) => {
return false
})
},
async newsletterload(paramquery: any) {
return Api.SendReq('/news/load', 'POST', paramquery)
.then((res) => {
// console.log('res', res)
return res.data
}).catch((error) => {
return null
})
},
async reportload(paramquery: any) {
return Api.SendReq('/report/load', 'POST', paramquery)
.then((res) => {
// console.log('res', res)
return res.data
}).catch((error) => {
return null
})
},
async newsletter_setactivate(paramquery: any) {
return Api.SendReq('/news/setactivate', 'POST', paramquery)
.then((res) => {
// console.log('res', res)
return res.data
}).catch((error) => {
return null
})
},
authUser(data: IUserFields) {
this.my = { ...data }
if (!this.my.profile) {
@@ -448,7 +501,7 @@ export const useUserStore = defineStore('UserStore', {
this.isLogged = isok && isLogged
// ++Todo conv if (static_data.functionality.ENABLE_TODOS_LOADING)
// ++Todo conv if (static_data.ality.ENABLE_TODOS_LOADING)
// await Todos.dbLoad({ checkPending: true })
// if (static_data.functionality.ENABLE_PROJECTS_LOADING)
@@ -533,6 +586,5 @@ export const useUserStore = defineStore('UserStore', {
return false
}
},
},
})

View File

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

View File

@@ -0,0 +1,59 @@
@Component({})
export default class TableOnlyView extends Vue {
public loading: boolean = false
public serverPagination: {
page: number,
rowsNumber: number // specifying this determines pagination is server-side
} = {page: 1, rowsNumber: 10}
public serverData: any [] = []
public columns: any[] = [
{
name: 'chiave',
required: true,
label: 'Chiave',
align: 'left',
field: 'chiave',
sortable: true,
},
{ name: 'valore', label: 'Valore', field: 'valore', sortable: false },
]
public filter: string = ''
public selected: any[] = []
public request(props) {
this.loading = true
setTimeout(() => {
this.serverPagination = props.pagination
let table = this.$refs.table,
rows = GlobalStore.state.cfgServer.slice(),
{ page, rowsPerPage, sortBy, descending } = props.pagination
// if (props.filter) {
// rows = table.filterMethod(rows, props.filter)
// }
// if (sortBy) {
// rows = table.sortMethod(rows, sortBy, descending)
// }
this.serverPagination.rowsNumber = rows.length
if (rowsPerPage) {
rows = rows.slice((page - 1) * rowsPerPage, page * rowsPerPage)
}
this.serverData = rows
this.loading = false
}, 1500)
}
public mounted() {
this.request({
pagination: this.serverPagination,
filter: this.filter,
})
}
}

View File

@@ -0,0 +1,29 @@
<template>
<q-page padding class="docs-table">
<p class="caption">TableOnlyView</p>
<q-table
ref="table"
color="primary"
title="Parametri di Configurazione Server"
:data="serverData"
:columns="columns"
:filter="filter"
selection="multiple"
v-model:selected="selected"
row-key="chiave"
v-model:pagination="serverPagination"
@request="request"
:loading="loading"
>
<template v-slot:top-right="props" >
<q-search hide-underline v-model="filter" />
</template>
</q-table>
</q-page>
</template>
<script lang="ts" src="tableOnlyView.ts">
</script>
<style lang="scss" scoped>
@import 'tableOnlyView';
</style>

View File

View File

@@ -0,0 +1,104 @@
import { computed, defineComponent, PropType, ref } from 'vue'
import { useQuasar } from 'quasar'
import { useI18n } from '@/boot/i18n'
import { useGlobalStore } from '@store/globalStore'
import { ICfgServer } from 'model'
interface IPageSrv {
page: number,
rowsPerPage: number // specifying this determines pagination is server-side
}
interface IPageS {
page: number,
}
export default defineComponent({
name: 'CfgServer',
props: {
loading: {
type: Boolean,
default: false,
required: true,
},
paginationControl: {
type: Object as PropType<IPageSrv>,
required: true,
default() {
return { page: 1, rowsPerPage: 20 }
},
},
pagination: {
type: Object as PropType<IPageS>,
required: true,
default() {
return { page: 1 }
},
},
},
setup() {
const $q = useQuasar()
const { t } = useI18n()
const globalStore = useGlobalStore()
const serverData = computed(() => globalStore.cfgServer.slice()) // [{ chiave: 'chiave1', valore: 'valore 1' }]
const columns = ref([
{
name: 'chiave',
required: true,
label: 'Chiave',
align: 'left',
field: 'chiave',
sortable: true,
},
{ name: 'idapp', label: 'idapp', field: 'idapp', sortable: true },
{ name: 'userid', label: 'UserId', field: 'userid', sortable: false },
{ name: 'valore', label: 'Valore', field: 'valore', sortable: false },
])
const colVisib = ref(['chiave', 'idapp', 'userid', 'valore'])
const separator = ref('horizontal')
const filter = ref('')
const selected = ref([])
const dark = ref(true)
const keysel = ref('')
const userIdsel = ref('')
function tableClass() {
if (dark.value) {
return 'bg-black'
}
}
function selItem(item: any) {
console.log('item', item)
keysel.value = item.chiave
userIdsel.value = item.userId
console.log('this.keysel', keysel.value)
}
function SaveValue(newVal: any, valinitial: any) {
// console.log('SaveValue', newVal, 'selected', this.selected)
const mydata: ICfgServer = {
chiave: keysel.value,
userId: userIdsel.value,
valore: newVal,
idapp: process.env.APP_ID!,
}
// Save on Server
globalStore.saveCfgServerKey(mydata)
}
return {
selItem,
SaveValue,
serverData,
columns,
filter,
}
},
})

View File

@@ -0,0 +1,52 @@
<template>
<q-table
:data="serverData"
:columns="columns"
:filter="filter"
title="Configurazione Server"
row-key="chiave"
>
<template v-slot:body="props">
<q-tr :props="props">
<q-td key="chiave" :props="props">
{{ props.row.chiave }}
<q-popup-edit v-model="props.row.chiave" disable>
<q-field count>
<q-input v-model="props.row.chiave"/>
</q-field>
</q-popup-edit>
</q-td>
<q-td key="idapp" :props="props">
{{ props.row.idapp }}
<q-popup-edit v-model="props.row.idapp" disable>
<q-field count>
<q-input v-model="props.row.idapp"/>
</q-field>
</q-popup-edit>
</q-td>
<q-td key="userid" :props="props">
{{ props.row.userId }}
<q-popup-edit v-model="props.row.userId" disable>
<q-field count>
<q-input v-model="props.row.userId"/>
</q-field>
</q-popup-edit>
</q-td>
<q-td key="valore" :props="props">
{{ props.row.valore }}
<q-popup-edit
v-model="props.row.valore" title="Aggiorna Valore" buttons @save="SaveValue"
@show="selItem(props.row)">
<q-input v-model="props.row.valore"/>
</q-popup-edit>
</q-td>
</q-tr>
</template>
</q-table>
</template>
<script lang="ts" src="./cfgServer.ts">
</script>
<style lang="scss" scoped>
@import './cfgServer';
</style>

Some files were not shown because too many files have changed in this diff Show More