ancora su Typescript...

suddiviso i ts dai html e scss
This commit is contained in:
paolo
2018-11-07 22:42:22 +01:00
parent 7c1d07797e
commit 6811202571
31 changed files with 8875 additions and 314 deletions

View File

@@ -39,6 +39,7 @@
"vue-property-decorator": "^7.2.0", "vue-property-decorator": "^7.2.0",
"vue-router": "^3.0.1", "vue-router": "^3.0.1",
"vue-svgicon": "^3.1.0", "vue-svgicon": "^3.1.0",
"vuelidate": "^0.7.4",
"vuex": "^3.0.1", "vuex": "^3.0.1",
"vuex-class": "^0.3.1", "vuex-class": "^0.3.1",
"vuex-module-decorators": "^0.4.3" "vuex-module-decorators": "^0.4.3"

62
src/common/axios.ts Normal file
View File

@@ -0,0 +1,62 @@
import {
default as Axios,
AxiosError,
AxiosRequestConfig,
AxiosResponse
} from "axios";
import { default as VueRouter } from "vue-router";
import { TokenHelper } from "./token-helper";
let initialized: boolean = false;
interface IRequestConfig extends AxiosRequestConfig {
ignore: number[];
}
function handle(status: number, exclude: number[]) {
if (exclude.length === 0) return true;
else return exclude.find(o => o === status) === undefined;
}
export function UseAxios(router: VueRouter) {
if (!initialized) {
Axios.interceptors.request.use((config: IRequestConfig) => {
if (!config.headers["Authorization"]) {
// append authorization header
let bearerToken = TokenHelper.getBearerToken();
if (bearerToken.Authorization)
Object.assign(config.headers, bearerToken);
}
if (!config.maxRedirects || config.maxRedirects === 5)
// ensure axios does not follow redirects, so custom response interceptor below can push to app login page
config.maxRedirects = 0;
return config;
});
Axios.interceptors.response.use(undefined, (config: AxiosError) => {
let response: AxiosResponse = config.response;
let exclude = (<IRequestConfig>config.config).ignore || [];
if (response.status === 401 && handle(response.status, exclude)) {
let location: string =
response.headers["location"] || response.headers["Location"];
if (location) {
let redirectTo = "/" + location;
window.setTimeout(() => router.replace(redirectTo), 200);
}
}
if (response.status === 403 && handle(response.status, exclude)) {
window.setTimeout(() => router.replace("/forbidden"), 200);
}
return config;
});
initialized = true;
}
}

50
src/common/debounce.ts Normal file
View File

@@ -0,0 +1,50 @@
/**
* Returns a function, that, as long as it continues to be invoked, will not
* be triggered. The function will be called after it stops being called for
* N milliseconds. If `immediate` is passed, trigger the function on the
* leading edge, instead of the trailing. The function also has a property 'clear'
* that is a function which will clear the timer to prevent previously scheduled executions.
*
* @source underscore.js
* @see http://unscriptable.com/2009/03/20/debouncing-javascript-methods/
* @param {Function} function to wrap
* @param {Number} timeout in ms (`100`)
* @param {Boolean} whether to execute at the beginning (`false`)
* @api public
*/
export function Debounce(func: Function, wait?: number, immediate?: boolean) {
let timeout, args, context, timestamp, result
if (null == wait) wait = 100
function later() {
let last = Date.now() - timestamp
if (last < wait && last > 0) {
timeout = setTimeout(later, wait - last)
} else {
timeout = null
if (!immediate) {
result = func.apply(context, args)
context = args = null
}
}
}
let debounced = function () {
context = this
args = arguments
timestamp = Date.now()
let callNow = immediate && !timeout
if (!timeout) timeout = setTimeout(later, wait)
if (callNow) {
result = func.apply(context, args)
context = args = null
}
return result
}
return debounced
}

3
src/common/index.ts Normal file
View File

@@ -0,0 +1,3 @@
export * from './pattern'
export * from './axios'
export * from './debounce'

19
src/common/pattern.ts Normal file
View File

@@ -0,0 +1,19 @@
export class Patterns {
/**
* Alphanumeric, spaces and dashes allowed. Min 2 characters length.
*/
public static DisplayName: RegExp = /^[0-9a-zA-Z\s\-]{2,}/i;
/**
* Same pattern used by JQuery userName validation
*/
public static Email: RegExp = /^((“[\w-\s]+”)|([\w-]+(?:\.[\w-]+)*)|(“[\w-\s]+”)([\w-]+(?:\.[\w-]+)*))(@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$)|(@\[?((25[0-5]\.|2[0-4][0-9]\.|1[0-9]{2}\.|[0-9]{1,2}\.))((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[0-9]{1,2})\.){2}(25[0-5]|2[0-4][0-9]|1[0-9]{2}[0-9];{1,2})\]?$)/i;
/**
* 6 to 20 characters string with at least one digit, one upper case letter, one lower case letter and one special symbol
*/
public static Password: RegExp = /^((?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%]).{6,20})/i;
}

View File

@@ -1,7 +0,0 @@
export default {
msg: {
hello: 'Buongiorno',
myAppName: 'FreePlanet',
myDescriz: 'La prima App Libera e per Tutti'
}
}

8004
src/jquery.d.ts vendored Normal file

File diff suppressed because it is too large Load Diff

1
src/jwt-decode.d.ts vendored Normal file
View File

@@ -0,0 +1 @@
export function jwtDecode(token: string, options?: { header: boolean }): any

8
src/model/glob.ts Normal file
View File

@@ -0,0 +1,8 @@
export interface IGlobState {
conta: number
isLoginPage: boolean
layoutNeeded: boolean
mobileMode: boolean
menuCollapse: boolean
posts: string[]
}

4
src/model/index.ts Normal file
View File

@@ -0,0 +1,4 @@
export * from './user'
export * from './glob'
export * from './signup-option'
export * from './key-value'

1
src/model/key-value.ts Normal file
View File

@@ -0,0 +1 @@
export type KeyValue = { key: string, value: string };

View File

@@ -0,0 +1,8 @@
export interface ISignupOptions {
email?: string
username: string
password?: string
lang?: string
repeatPassword?: string
}

28
src/model/user.ts Normal file
View File

@@ -0,0 +1,28 @@
import { IToken } from '@/types'
export const DefaultUser = <IUserState>{
email: '',
username: '',
idapp: process.env.APP_ID,
password: '',
lang: 'it'
}
export interface IUserState {
_id?: string
email?: string
username: string
idapp?: any
password?: string
lang?: string
repeatPassword?: string
idToken?: string
userId?: number
tokens?: IToken[]
verifiedEmail?: boolean
tokenforgot?: string
}

47
src/mount.ts Normal file
View File

@@ -0,0 +1,47 @@
import './components/loader/loader.scss';
function show(el: HTMLElement) {
el.style.display = 'block';
el.style.visibility = 'visible';
}
function mountApp(e: Event) {
document.getElementsByClassName('loader-wrapper')[0].remove();
show(document.getElementById('app'));
window['EntryPoint'].run(function (vue) {
vue.$mount('#app');
});
};
(() => {
let elapsed: number = 0;
let handle: number = null;
let interval: number = 100;
show(<HTMLElement>document.getElementsByClassName('loader-wrapper')[0]);
show(<HTMLElement>document.getElementsByClassName('loader-status')[0]);
var el: HTMLElement = <HTMLElement>document.getElementsByClassName('loader-progress')[0];
let updateProgress = () => {
elapsed = elapsed + interval;
let data = (elapsed * 0.001).toString().split('.')
let progress = data[0].toString() + '.' + (data.length > 1 ? data[1].substring(0, 1) : 0);
el.innerText = progress + ' ms';
}
handle = window.setInterval(updateProgress, interval);
document.addEventListener('DOMContentLoaded', (e) => {
updateProgress();
window.clearInterval(handle);
mountApp(e);
});
})();

View File

@@ -3,7 +3,7 @@ import { RouteConfig } from 'vue-router'
const routes: RouteConfig[] = [ const routes: RouteConfig[] = [
{ path: '/', component: () => import('@/pages/Index.vue'), meta: { name: 'Home' } }, { path: '/', component: () => import('@/pages/Index.vue'), meta: { name: 'Home' } },
{ path: '/test', component: () => import('@/views/login/test.vue'), meta: { name: 'Test' } }, { path: '/test', component: () => import('@/views/login/test.vue'), meta: { name: 'Test' } },
{ path: '/signup', component: () => import('@/views/login/signup.vue'), meta: { name: 'Registration' } }, { path: '/signup', component: () => import('@/views/login/signup/signup.vue'), meta: { name: 'Registration' } },
/* /*
{ path: '/signin', component: () => import('@/views/login/signin.vue'), meta: { name: 'Login' } }, { path: '/signin', component: () => import('@/views/login/signin.vue'), meta: { name: 'Login' } },
{ path: '/vreg', component: () => import('@/views/login/vreg.vue'), meta: { name: 'Verify Reg' } }, { path: '/vreg', component: () => import('@/views/login/vreg.vue'), meta: { name: 'Verify Reg' } },

View File

@@ -1,7 +1,7 @@
import Vue from 'vue' import Vue from 'vue'
import Vuex from 'vuex' import Vuex from 'vuex'
import { IUserState, IGlobState } from '@/types' import { IUserState, IGlobState } from '@/model'
Vue.use(Vuex) Vue.use(Vuex)

View File

@@ -10,7 +10,8 @@ const bcrypt = require('bcryptjs')
import * as types from '@/store/mutation-types' import * as types from '@/store/mutation-types'
import { serv_constants } from '@/store/modules/serv_constants' import { serv_constants } from '@/store/modules/serv_constants'
import { IUserState, ILinkReg, IResult, IIdToken } from '@/types' import { IUserState } from '@/model'
import { ILinkReg, IResult, IIdToken } from '@/types'
export const ErroriMongoDb = { export const ErroriMongoDb = {

27
src/types/index.d.ts vendored
View File

@@ -3,33 +3,6 @@ export interface IToken {
token: string token: string
} }
export interface IUserState {
_id?: string
email?: string
username: string
idapp?: any
password?: string
lang?: string
repeatPassword?: string
idToken?: string
userId?: number
tokens?: IToken[]
verifiedEmail?: boolean
tokenforgot?: string
}
export interface IGlobState {
conta: number
isLoginPage: boolean
layoutNeeded: boolean
mobileMode: boolean
menuCollapse: boolean
posts: string[]
}
export interface ILinkReg { export interface ILinkReg {
idLink: string idLink: string

View File

@@ -0,0 +1,5 @@
import { Patterns } from '@/common'
export function complexity(password: string) {
return Patterns.Password.test(password)
}

View File

@@ -0,0 +1,23 @@
type t = string | number;
type fn = () => t[];
export function duplicate(matches: t[] | fn, ignoreCase: boolean = false) {
if (Array.isArray(matches)) return factory(matches, ignoreCase);
return value => {
let cb = factory(matches(), ignoreCase);
return cb(value);
};
}
function factory(values: t[], ignoreCase: boolean) {
return value => {
if (value === undefined || value === null || values.length === 0)
return true;
else{
let flags = ignoreCase ? "i" : "";
let exp = new RegExp(`^(${value})$`, flags);
return values.find(o => exp.test(o.toString())) === undefined;
}
};
}

3
src/validation/index.ts Normal file
View File

@@ -0,0 +1,3 @@
export { duplicate } from './duplicate'
export { registered } from './registered'
export { complexity } from './complexity'

View File

@@ -0,0 +1,22 @@
import { default as Axios, AxiosResponse } from 'axios';
import { IPayload } from '../model';
import { GlobalConfig, PayloadMessageTypes } from '../common';
const AUTH_URL = GlobalConfig.uri.auth;
const VALIDATE_USER_URL = AUTH_URL + 'validateuser';
export function registered(userName: string) {
let config = {
params: { userName: userName }
};
let onSuccess = (res: AxiosResponse) => {
let payload: IPayload<boolean> = res.data;
return payload.message.messageTypeId !== PayloadMessageTypes.failure;
}
return Axios.get(VALIDATE_USER_URL, config)
.then(onSuccess);
};

View File

@@ -1,270 +0,0 @@
<template>
<div>
<q-page padding class="signup">
<div class="text-center">
<p>
<!--<img src="../../../assets/quasar-logo-full.svg">-->
<img :src="`../../../assets/`+`${env('LOGO_REG')}`">
</p>
</div>
<!--Prova URL : {{env('PROVA_PAOLO')}}-->
<q-field
:error="$v.user.email.$error"
:error-label="`${errorMsg('email', $v.user.email)}`"
>
<q-input
v-model="user.email"
v-validate="'required|email|truthy'"
:value="user.email"
@change="val => { user.email = val }"
:before="[{icon: 'mail', handler () {}}]"
@blur="$v.user.email.$touch"
:error="$v.user.email.$error"
:float-label="$t('reg.email')"
/>
</q-field>
<q-field
:error="$v.user.username.$error"
:error-label="`${errorMsg('username', $v.user.username)}`"
>
<q-input
:value="user.username"
@change="val => { user.username = val }"
:before="[{icon: 'person', handler () {}}]"
@blur="$v.user.username.$touch"
:error="$v.user.username.$error"
:float-label="$t('reg.username')"
/>
</q-field>
<q-field
:error="$v.user.password.$error"
:error-label="`${errorMsg('password', $v.user.password)}`"
>
<q-input
v-model="user.password"
:before="[{icon: 'vpn_key', handler () {}}]"
@blur="$v.user.password.$touch"
:error="$v.user.password.$error"
:float-label="$t('reg.password')"
/>
</q-field>
<q-field
:error="$v.user.repeatPassword.$error"
:error-label="`${errorMsg('repeatpassword', $v.user.repeatPassword)}`"
>
<q-input
v-model="user.repeatPassword"
:before="[{icon: 'vpn_key', handler () {}}]"
@blur="$v.user.repeatPassword.$touch"
:error="$v.user.repeatPassword.$error"
:float-label="$t('reg.repeatPassword')"
/>
</q-field>
<q-field
:error="$v.user.terms.$error"
:error-label="`${errorMsg('terms', $v.user.terms)}`"
>
<q-checkbox
v-model="user.terms"
:before="[{icon: 'vpn_key', handler () {}}]"
color="secondary"
@blur="$v.user.terms.$touch"
:error="$v.user.terms.$error"
:float-label="$t('reg.terms')"
:label="$t('reg.terms')"
/>
</q-field>
<br>
<div align="center">
<q-btn rounded size="lg" color="primary" @click="submit" :disable="$v.$error">{{$t('reg.submit')}}
</q-btn>
</div>
</q-page>
</div>
</template>
<script type="ts">
import { Component, Vue, Prop } from 'vue-property-decorator'
import { UserModule } from '../../store/modules/user'
//import { IUserState } from "../../types";
import {ErroriMongoDb} from '../../store/modules/user'
/*
import VeeValidate from 'vee-validate'
Vue.use(VeeValidate)
import { Validator } from 'vee-validate'
Validator.extend('truthy', {
getMessage: field => 'The ' + field + ' value is not truthy.',
validate: value => !!value
})
*/
//import {Loading, QSpinnerFacebook, QSpinnerGears} from 'quasar'
@Component({})
export default class Signup extends Vue {
duplicate_email = false
duplicate_username = false
user = {
email: process.env.TEST_EMAIL,
username: process.env.TEST_USERNAME,
password: process.env.TEST_PASSWORD,
repeatPassword: process.env.TEST_PASSWORD,
dateOfBirth: '',
terms: true,
}
/*
...mapGetters("user", [
'getUsername',
'getPassword',
'getEmail',
'getDateOfBirth',
]),
...mapGetters("user", [
'getUserServer',
'getServerCode',
]),
*/
/*
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},
}
}, */
env() {
return env
}
showNotif(msg) {
this.$q.notify(msg)
}
errorMsg(cosa, item) {
try {
if (!item.$error) return ''
if (item.$params.email && !item.email) return this.$t('reg.err.email')
if (cosa === 'repeatpassword') {
if (!item.sameAsPassword) {
return this.$t('reg.err.sameaspassword')
}
}
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);
if (!item.isUnique) return this.$t('reg.err.duplicate_username')
}
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);
}
}
checkErrors(riscode) {
//console.log("RIS = " + riscode);
if (riscode === ErroriMongoDb.DUPLICATE_EMAIL_ID) {
this.showNotif(this.$t('reg.err.duplicate_email'))
} else if (riscode === ErroriMongoDb.DUPLICATE_USERNAME_ID) {
this.showNotif(this.$t('reg.err.duplicate_username'))
} else if (riscode === ErroriMongoDb.OK) {
this.$router.push('/')
} else {
this.showNotif("Errore num " + riscode)
}
}
submit() {
this.$v.user.$touch()
this.duplicate_email = false
this.duplicate_username = false
if (!this.user.terms) {
this.showNotif(this.$t('reg.err.terms'))
return
}
if (this.$v.user.$error) {
this.showNotif(this.$t('reg.err.errore_generico'))
return
}
this.$q.loading.show({ message: this.$t('reg.incorso') })
console.log(this.user)
UserModule.signup(this.user)
.then((riscode) => {
this.checkErrors(riscode)
this.$q.loading.hide()
}).catch(error => {
console.log("ERROR = " + error)
this.$q.loading.hide()
})
// ...
}
}
</script>
<style scoped>
.signup {
width: 100%;
margin: 0 auto;
max-width: 450px;
}
</style>

View File

@@ -62,10 +62,10 @@
} from 'vuelidate/lib/validators' } from 'vuelidate/lib/validators'
import {mapGetters, mapActions} from 'vuex' import {mapGetters, mapActions} from 'vuex'
import * as types from '../../store/mutation-types' import * as types from '../../../store/mutation-types'
//import {ErroriMongoDb} from '../../store/modules/user' //import {ErroriMongoDb} from '../../store/modules/user'
import {serv_constants} from "../../store/modules/serv_constants"; import {serv_constants} from "../../../store/modules/serv_constants";
import axios from 'axios'; import axios from 'axios';
import {Loading, QSpinnerFacebook, QSpinnerGears} from 'quasar' import {Loading, QSpinnerFacebook, QSpinnerGears} from 'quasar'

View File

@@ -0,0 +1,28 @@
import { ISignupOptions } from '@/model'
import { required, minLength, email, sameAs } from 'vuelidate/lib/validators'
import { ValidationRuleset } from 'vuelidate'
import { complexity, registered } from '@/validation'
export type TSignup = { signup: ISignupOptions, validationGroup: string[] }
export const validations: ValidationRuleset<TSignup> = {
signup: {
confirmPassword: {
required,
sameAsPassword: sameAs('password')
},
displayName: {
required,
minLength: minLength(2)
},
password: {
required,
complexity
},
userName: {
required,
email,
registered
}
}
}

View File

@@ -0,0 +1,100 @@
<div>
<q-page padding class="signup">
<div class="text-center">
<p>
<!--<img src="../../../assets/quasar-logo-full.svg">-->
<img :src="`../../../assets/`+`${env('LOGO_REG')}`">
</p>
</div>
PROVAA
<!--Prova URL : {{env('PROVA_PAOLO')}}-->
<!--
<q-field
:error="v.user.email.error"
error-label="{{ errors.first('email') }}"
>
<q-input
v-model="user.email"
v-validate="'required|email|truthy'"
:value="user.email"
@change="val => { user.email = val }"
:before="[{icon: 'mail', handler () {}}]"
@blur="v.user.email.touch"
:error="v.user.email.error"
:float-label="$t('reg.email')"
/>
</q-field>
<q-field
:error="v.user.username.$error"
:error-label="`${errorMsg('username', v.user.username)}`"
>
<q-input
:value="user.username"
@change="val => { user.username = val }"
:before="[{icon: 'person', handler () {}}]"
@blur="v.user.username.$touch"
:error="v.user.username.$error"
:float-label="$t('reg.username')"
/>
</q-field>
<q-field
:error="v.user.password.$error"
:error-label="`${errorMsg('password', v.user.password)}`"
>
<q-input
v-model="user.password"
:before="[{icon: 'vpn_key', handler () {}}]"
@blur="v.user.password.$touch"
:error="v.user.password.$error"
:float-label="$t('reg.password')"
/>
</q-field>
<q-field
:error="v.user.repeatPassword.$error"
:error-label="`${errorMsg('repeatpassword', v.user.repeatPassword)}`"
>
<q-input
v-model="user.repeatPassword"
:before="[{icon: 'vpn_key', handler () {}}]"
@blur="v.user.repeatPassword.$touch"
:error="v.user.repeatPassword.$error"
:float-label="$t('reg.repeatPassword')"
/>
</q-field>
<q-field
:error="v.user.terms.$error"
:error-label="`${errorMsg('terms', v.user.terms)}`"
>
<q-checkbox
v-model="user.terms"
:before="[{icon: 'vpn_key', handler () {}}]"
color="secondary"
@blur="v.user.terms.$touch"
:error="v.user.terms.$error"
:float-label="$t('reg.terms')"
:label="$t('reg.terms')"
/>
</q-field>
-->
<br>
<!--
<div align="center">
<q-btn rounded size="lg" color="primary" @click="submit" :disable="">{{$t('reg.submit')}}
</q-btn>
</div>
-->
</q-page>
</div>

View File

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

View File

@@ -0,0 +1,177 @@
import { Component, Vue, Prop } from 'vue-property-decorator'
import { UserModule } from '@/store/modules/user'
import { ErroriMongoDb } from '@/store/modules/user'
import { validationMixin } from 'vuelidate'
import { required, minValue } from 'vuelidate/lib/validators'
import { ISignupOptions, IUserState } from '@/model'
import { validations, TSignup } from './signup-validate'
// import './signup.scss'
// import {Loading, QSpinnerFacebook, QSpinnerGears} from 'quasar'
@Component({
mixins: [validationMixin],
name: 'Signup',
// template: require('./signup.html'),
validations: validations
})
export default class Signup extends Vue {
myProperty: string = ''
duplicate_email: boolean = false
duplicate_username: boolean = false
user: ISignupOptions = {
email: process.env.TEST_EMAIL,
username: process.env.TEST_USERNAME || '',
password: process.env.TEST_PASSWORD,
repeatPassword: process.env.TEST_PASSWORD
}
terms = true
$v: any
constructor() {
super()
}
created() {
}
mounted() {
if (this.$v) {
this.$v.$touch()
}
}
get allowSubmit() {
let error = this.$v.signup.$error || this.$v.signup.$invalid
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},
}
}, */
env() {
return process.env
}
showNotif(msg: any) {
this.$q.notify(msg)
}
/*
errorMsg(cosa: string, item: string) {
try {
if (!item.$error) return ''
if (item.$params.email && !item.email) return this.$t('reg.err.email')
if (cosa === 'repeatpassword') {
if (!item.sameAsPassword) {
return this.$t('reg.err.sameaspassword')
}
}
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);
if (!item.isUnique) return this.$t('reg.err.duplicate_username')
}
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);
}
}
checkErrors(riscode) {
//console.log("RIS = " + riscode);
if (riscode === ErroriMongoDb.DUPLICATE_EMAIL_ID) {
this.showNotif(this.$t('reg.err.duplicate_email'))
} else if (riscode === ErroriMongoDb.DUPLICATE_USERNAME_ID) {
this.showNotif(this.$t('reg.err.duplicate_username'))
} else if (riscode === ErroriMongoDb.OK) {
this.$router.push('/')
} else {
this.showNotif("Errore num " + riscode)
}
}
submit() {
this.$v.user.$touch()
this.duplicate_email = false
this.duplicate_username = false
if (!this.user.terms) {
this.showNotif(this.$t('reg.err.terms'))
return
}
if (this.v.user.$error) {
this.showNotif(this.$t('reg.err.errore_generico'))
return
}
this.$q.loading.show({ message: this.$t('reg.incorso') })
console.log(this.user)
UserModule.signup(this.user)
.then((riscode) => {
this.checkErrors(riscode)
this.$q.loading.hide()
}).catch(error => {
console.log("ERROR = " + error)
this.$q.loading.hide()
})
// ...
}
*/
}

View File

@@ -0,0 +1,8 @@
<template src="./signup.html">
</template>
<script lang='ts' src="signup.ts" >
</script>
<style src="signup.scss" lang="scss">
</style>

255
src/vuelidate.d.ts vendored Normal file
View File

@@ -0,0 +1,255 @@
declare module 'vuelidate' {
import { default as _Vue } from 'vue'
/**
* @module augmentation to ComponentOptions defined by Vue.js
*/
module 'vue/types/options' {
interface ComponentOptions<V extends _Vue> {
validations?: ValidationRuleset<{}>
}
}
module 'vue/types/vue' {
interface Vue {
$v: Vuelidate<any>
}
}
/**
* Represents an instance of validator class at runtime
*/
interface IValidator {
/**
* Indicates the state of validation for given model. becomes true when any of it's child validators specified in options returns a falsy value. In case of validation groups, all grouped validators are considered.
*/
readonly $invalid: boolean
/**
* A flag representing if the field under validation was touched by the user at least once. Usually it is used to decide if the message is supposed to be displayed to the end user. Flag is managed manually. You have to use $touch and $reset methods to manipulate it. The $dirty flag is considered true if given model was $touched or all of it's children are $dirty.
*/
$dirty: boolean
/**
* Convenience flag to easily decide if a message should be displayed. It is a shorthand to $invalid && $dirty.
*/
readonly $error: boolean
/**
* Indicates if any child async validator is currently pending. Always false if all validators are synchronous.
*/
$pending: boolean
/**
* Sets the $dirty flag of the model and all its children to true recursively.
*/
$touch(): void
/**
* Sets the $dirty flag of the model and all its children to false recursively.
*/
$reset(): void
}
/**
* Builtin validators
*/
interface IDefaultValidators {
/**
* Accepts only alphabet characters.
*/
alpha?: boolean
/**
* Accepts only alphanumerics.
*/
alphaNum?: boolean
/**
* Checks if a number is in specified bounds. Min and max are both inclusive.
*/
between?: boolean
/**
* Accepts valid email addresses. Keep in mind you still have to carefully verify it on your server, as it is impossible to tell if the address is real without sending verification email.
*/
email?: boolean
/**
* Requires the input to have a maximum specified length, inclusive. Works with arrays.
*/
maxLength?: boolean
/**
* Requires the input to have a minimum specified length, inclusive. Works with arrays.
*/
minLength?: boolean
/**
* Requires non-empty data. Checks for empty arrays and strings containing only whitespaces.
*/
required?: boolean
/**
* Checks for equality with a given property. Locator might be either a sibling property name or a function, that will get your component as this and nested model which sibling properties under second parameter.
*/
sameAs?: boolean
/**
* Passes when at least one of provided validators passes.
*/
or?: boolean
/**
* Passes when all of provided validators passes.
*/
and?: boolean
}
type EachByKey<T> = {
[K in keyof T]: Validator<T[K]>
}
/**
* Holds all validation models of collection validator. Always preserves the keys of original model, so it can be safely referenced in the v-for loop iterating over your data using the same index.
*/
type Each<T> =
& {[key: number]: EachByKey<T>}
& {$trackBy: string | Function}
& IValidator
global {
interface Array<T> {
/**
* Holds all validation models of collection validator. Always preserves the keys of original model, so it can be safely referenced in the v-for loop iterating over your data using the same index.
*/
$each: Each<T> & Vuelidate<T>
}
}
/**
* Represents an instance of validator class at runtime
*/
type Validator<T> = IValidator & IDefaultValidators & Each<T>
interface IPredicate {
(value: any, parentVm?: IValidationRule): boolean | Promise<boolean>
}
interface IPredicateGenerator {
(...args: any[]): IPredicate
}
interface IValidationRule {
[key: string]: ValidationPredicate | IValidationRule | IValidationRule[]
}
export type ValidationPredicate = IPredicateGenerator | IPredicate
/**
* Represents mixin data exposed by Vuelidate instance
*/
export type Vuelidate<T> = {
[K in keyof T]?: Vuelidate<T[K]> & Validator<T[K]>;
}
/**
* Represents component options used by Vuelidate
*/
export type ValidationRuleset<T> = {
[K in keyof T]?: ValidationPredicate | IValidationRule | IValidationRule[] | string[];
}
/**
* Represents Vuelidate mixin data extending a Vue component instance. Have your Vue component options implement this
* @param {Type} T - The interface or type being used to store model data requiring validation
*
* @example
* export class Foo implements IVuelidate<IBar> {
* data() {
* return { bar: { length: 0 } };
* }
* validations: {
* bar: {
* length: {
* between: between(1,5)
* }
* }
* }
* $v: Vuelidate<IBar>;
* }
*/
export interface IVuelidate<T> {
$v: Vuelidate<T>
}
/**
* Mixin object for supplying directly to components
*/
export const validationMixin: {
beforeCreate(): void;
}
/**
* Vuelidate function that creates a validator directly, given a model, and a set of rules
*/
export const validateModel: {
<T>(model: T, validations: ValidationRuleset<T>): IVuelidate<T>;
}
/**
* Vue plugin object
*/
export function Validation(Vue: typeof _Vue): void
export default Validation
}
declare module 'vuelidate/lib/validators' {
import { ValidationPredicate } from 'vuelidate'
/**
* Accepts only alphabet characters.
*/
function alpha(value: any): boolean
/**
* Accepts only alphanumerics.
*/
function alphaNum(value: any): boolean
/**
* Checks if a number is in specified bounds. Min and max are both inclusive.
*/
function between(min: number, max: number): (value: any) => boolean
/**
* Accepts valid email addresses. Keep in mind you still have to carefully verify it on your server, as it is impossible to tell if the address is real without sending verification email.
*/
function email(value: any): boolean
/**
* Requires the input to have a maximum specified length, inclusive. Works with arrays.
*/
function maxLength(max: number): (value: any) => boolean
/**
* Requires the input to have a minimum specified length, inclusive. Works with arrays.
*/
function minLength(min: number): (value: any) => boolean
/**
* Requires non-empty data. Checks for empty arrays and strings containing only whitespaces.
*/
function required(value: any): boolean
/**
* Checks for equality with a given property. Locator might be either a sibling property name or a function, that will get your component as this and nested model which sibling properties under second parameter.
*/
function sameAs(locator: string): (value: any, vm?: any) => boolean
function minValue(min: number): (value: any) => boolean
function maxValue(min: number): (value: any) => boolean
/**
* Passes when at least one of provided validators passes.
*/
function or(...validators: ValidationPredicate[]): () => boolean
/**
* Passes when all of provided validators passes.
*/
function and(...validators: ValidationPredicate[]): () => boolean
}

View File

@@ -1,16 +1,18 @@
{ {
"compilerOptions": { "compilerOptions": {
"target": "es5", "allowSyntheticDefaultImports": true,
"module": "esnext", "listEmittedFiles": false,
"module": "es2015",
"moduleResolution": "Node",
"target": "es2015",
"strict": true, "strict": true,
"esModuleInterop": true, "esModuleInterop": true,
"sourceMap": true, "sourceMap": true,
"experimentalDecorators": true, "experimentalDecorators": true,
"noImplicitAny": true, "noImplicitAny": true,
"moduleResolution": "node",
"lib": [ "lib": [
"es2015", "dom",
"dom" "es6"
], ],
"baseUrl": ".", "baseUrl": ".",
"paths": { "paths": {