feat: add vuelidate (#3438)
This commit is contained in:
+1
-1
@@ -14,7 +14,7 @@ indent_size = 4
|
|||||||
[*.blade.php]
|
[*.blade.php]
|
||||||
indent_size = 2
|
indent_size = 2
|
||||||
|
|
||||||
[*.{js,vue}]
|
[*.{js,vue,scss}]
|
||||||
indent_size = 2
|
indent_size = 2
|
||||||
|
|
||||||
[*.md]
|
[*.md]
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
### New features:
|
### New features:
|
||||||
|
|
||||||
|
* Add vue data validations
|
||||||
* Add ability to edit activities
|
* Add ability to edit activities
|
||||||
* Associate a photo to a gift
|
* Associate a photo to a gift
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -64,7 +64,8 @@
|
|||||||
"vue-i18n": "^8.8",
|
"vue-i18n": "^8.8",
|
||||||
"vue-js-toggle-button": "^1.2.2",
|
"vue-js-toggle-button": "^1.2.2",
|
||||||
"vue-notification": "^1.3.6",
|
"vue-notification": "^1.3.6",
|
||||||
"vue-select": "^3.0.2"
|
"vue-select": "^3.0.2",
|
||||||
|
"vuelidate": "^0.7.4"
|
||||||
},
|
},
|
||||||
"snyk": true
|
"snyk": true
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
@@ -1,9 +1,9 @@
|
|||||||
{
|
{
|
||||||
"/js/manifest.js": "/js/manifest.js?id=7db827d654313dce4250",
|
"/js/manifest.js": "/js/manifest.js?id=7db827d654313dce4250",
|
||||||
"/js/vendor.js": "/js/vendor.js?id=6ccef718ebd46e2c4f89",
|
"/js/vendor.js": "/js/vendor.js?id=773b341f83f70ee67b38",
|
||||||
"/js/app.js": "/js/app.js?id=9ed7ed32ce507eff51e4",
|
"/js/app.js": "/js/app.js?id=cb94afd4886fb56d9a38",
|
||||||
"/css/app-ltr.css": "/css/app-ltr.css?id=ff41d6c39e7fba5cf37e",
|
"/css/app-ltr.css": "/css/app-ltr.css?id=543870c3275cb99afc76",
|
||||||
"/css/app-rtl.css": "/css/app-rtl.css?id=ee3f6d81111cdc99f35d",
|
"/css/app-rtl.css": "/css/app-rtl.css?id=26aa1824e819b5990779",
|
||||||
"/css/stripe.css": "/css/stripe.css?id=76c70a7b11ae5f38a725",
|
"/css/stripe.css": "/css/stripe.css?id=76c70a7b11ae5f38a725",
|
||||||
"/js/stripe.js": "/js/stripe.js?id=5e5e1d73338a536f7ce9",
|
"/js/stripe.js": "/js/stripe.js?id=5e5e1d73338a536f7ce9",
|
||||||
"/js/u2f-api.js": "/js/u2f-api.js?id=1948d3efdfd801bed14a"
|
"/js/u2f-api.js": "/js/u2f-api.js?id=1948d3efdfd801bed14a"
|
||||||
|
|||||||
@@ -33,10 +33,11 @@
|
|||||||
<form-input
|
<form-input
|
||||||
:id="'age'"
|
:id="'age'"
|
||||||
ref="age"
|
ref="age"
|
||||||
:value="age"
|
v-model="selectedAge"
|
||||||
:input-type="'number'"
|
:input-type="'number'"
|
||||||
:width="50"
|
:width="50"
|
||||||
:required="true"
|
:required="true"
|
||||||
|
:validator="$v.selectedAge"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</form-radio>
|
</form-radio>
|
||||||
@@ -86,10 +87,12 @@
|
|||||||
<form-date
|
<form-date
|
||||||
:id="'birthdayDate'"
|
:id="'birthdayDate'"
|
||||||
ref="birthday"
|
ref="birthday"
|
||||||
:value="birthdate"
|
v-model="selectedDate"
|
||||||
:show-calendar-on-focus="true"
|
:show-calendar-on-focus="true"
|
||||||
:locale="locale"
|
:locale="locale"
|
||||||
|
:label="$t('people.information_edit_birthdate_label')"
|
||||||
:class="[ dirltr ? 'fl' : 'fr' ]"
|
:class="[ dirltr ? 'fl' : 'fr' ]"
|
||||||
|
:validator="$v.selectedDate"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</form-radio>
|
</form-radio>
|
||||||
@@ -112,8 +115,20 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import moment from 'moment';
|
||||||
|
import { validationMixin } from 'vuelidate';
|
||||||
|
import { required, numeric, helpers } from 'vuelidate/lib/validators';
|
||||||
|
|
||||||
|
const before = (param) =>
|
||||||
|
helpers.withParams(
|
||||||
|
{ type: 'before', date: param },
|
||||||
|
(value) => !helpers.req(value) || moment(value).isBefore(param)
|
||||||
|
);
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|
||||||
|
mixins: [validationMixin],
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
value: {
|
value: {
|
||||||
type: String,
|
type: String,
|
||||||
@@ -121,15 +136,11 @@ export default {
|
|||||||
},
|
},
|
||||||
days: {
|
days: {
|
||||||
type: Array,
|
type: Array,
|
||||||
default: function () {
|
default: () => [],
|
||||||
return [];
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
months: {
|
months: {
|
||||||
type: Array,
|
type: Array,
|
||||||
default: function () {
|
default: () => [],
|
||||||
return [];
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
day: {
|
day: {
|
||||||
type: Number,
|
type: Number,
|
||||||
@@ -158,12 +169,35 @@ export default {
|
|||||||
selectedDate: null,
|
selectedDate: null,
|
||||||
selectedOption: null,
|
selectedOption: null,
|
||||||
selectedOptionSave: null,
|
selectedOptionSave: null,
|
||||||
|
selectedAge: 0,
|
||||||
selectedMonth: 0,
|
selectedMonth: 0,
|
||||||
selectedDay: 0,
|
selectedDay: 0,
|
||||||
hasBirthdayReminder: false
|
hasBirthdayReminder: false
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
validations() {
|
||||||
|
switch (this.selectedOption) {
|
||||||
|
case 'approximate':
|
||||||
|
return {
|
||||||
|
selectedAge: {
|
||||||
|
required,
|
||||||
|
numeric,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case 'exact':
|
||||||
|
return {
|
||||||
|
selectedDate: {
|
||||||
|
required,
|
||||||
|
before: before(moment())
|
||||||
|
}
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
dirltr() {
|
dirltr() {
|
||||||
return this.$root.htmldir == 'ltr';
|
return this.$root.htmldir == 'ltr';
|
||||||
@@ -173,9 +207,25 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
watch: {
|
||||||
|
birthdate(val) {
|
||||||
|
this.selectedDate = val;
|
||||||
|
},
|
||||||
|
|
||||||
|
value(val) {
|
||||||
|
this.selectedOption = val;
|
||||||
|
},
|
||||||
|
|
||||||
|
age(val) {
|
||||||
|
this.selectedAge = val;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
|
this.selectedDate = this.birthdate;
|
||||||
this.selectedOption = this.value != '' ? this.value : 'unknown';
|
this.selectedOption = this.value != '' ? this.value : 'unknown';
|
||||||
this.selectedOptionSave = this.selectedOption;
|
this.selectedOptionSave = this.selectedOption;
|
||||||
|
this.selectedAge = this.age;
|
||||||
this.selectedMonth = this.month;
|
this.selectedMonth = this.month;
|
||||||
this.selectedDay = this.day;
|
this.selectedDay = this.day;
|
||||||
this.hasBirthdayReminder = this.reminder;
|
this.hasBirthdayReminder = this.reminder;
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<div class="pa4-ns ph3 pv2 bb b--gray-monica">
|
<div class="pa4-ns ph3 pv2 bb b--gray-monica">
|
||||||
<div class="mb3 mb0-ns">
|
<div class="mb3 mb0-ns">
|
||||||
<form-checkbox
|
<form-checkbox
|
||||||
v-model="value"
|
v-model.lazy="deceased"
|
||||||
:name="'is_deceased'"
|
:name="'is_deceased'"
|
||||||
:value="true"
|
:value="true"
|
||||||
:dclass="'flex mb2'"
|
:dclass="'flex mb2'"
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
{{ $t('people.deceased_mark_person_deceased') }}
|
{{ $t('people.deceased_mark_person_deceased') }}
|
||||||
</template>
|
</template>
|
||||||
</form-checkbox>
|
</form-checkbox>
|
||||||
<div v-show="value" :class="[ dirltr ? 'ml4' : 'mr4' ]">
|
<div v-show="deceased" :class="[ dirltr ? 'ml4' : 'mr4' ]">
|
||||||
<form-checkbox
|
<form-checkbox
|
||||||
v-model.lazy="dateKnown"
|
v-model.lazy="dateKnown"
|
||||||
:name="'is_deceased_date_known'"
|
:name="'is_deceased_date_known'"
|
||||||
@@ -31,11 +31,13 @@
|
|||||||
<form-date
|
<form-date
|
||||||
:id="'deceased_date'"
|
:id="'deceased_date'"
|
||||||
ref="deaceasedday"
|
ref="deaceasedday"
|
||||||
v-model="date"
|
v-model="selectedDate"
|
||||||
|
:label="$t('people.deceased_date_label')"
|
||||||
:show-calendar-on-focus="true"
|
:show-calendar-on-focus="true"
|
||||||
:locale="locale"
|
:locale="locale"
|
||||||
|
:validator="$v.selectedDate"
|
||||||
/>
|
/>
|
||||||
<div v-show="date != ''" class="mt2">
|
<div v-show="selectedDate != ''" class="mt2">
|
||||||
<form-checkbox
|
<form-checkbox
|
||||||
:name="'add_reminder_deceased'"
|
:name="'add_reminder_deceased'"
|
||||||
:value="true"
|
:value="true"
|
||||||
@@ -51,8 +53,20 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import moment from 'moment';
|
||||||
|
import { validationMixin } from 'vuelidate';
|
||||||
|
import { required, numeric, helpers } from 'vuelidate/lib/validators';
|
||||||
|
|
||||||
|
const before = (param) =>
|
||||||
|
helpers.withParams(
|
||||||
|
{ type: 'before', date: param },
|
||||||
|
(value) => !helpers.req(value) || moment(value).isBefore(param)
|
||||||
|
);
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|
||||||
|
mixins: [validationMixin],
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
value: {
|
value: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
@@ -70,10 +84,19 @@ export default {
|
|||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
deceased: false,
|
||||||
dateKnown: false,
|
dateKnown: false,
|
||||||
|
selectedDate: null,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
validations: {
|
||||||
|
selectedDate: {
|
||||||
|
required,
|
||||||
|
before: before(moment())
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
dirltr() {
|
dirltr() {
|
||||||
return this.$root.htmldir == 'ltr';
|
return this.$root.htmldir == 'ltr';
|
||||||
@@ -83,8 +106,20 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
watch: {
|
||||||
|
value(val) {
|
||||||
|
this.deceased = val;
|
||||||
|
},
|
||||||
|
|
||||||
|
date(val) {
|
||||||
|
this.selectedDate = val;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
|
this.deceased = this.value;
|
||||||
this.dateKnown = this.date != '';
|
this.dateKnown = this.date != '';
|
||||||
|
this.selectedDate = this.date;
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
|
<style scoped>
|
||||||
|
</style>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div :class="{ 'form-group-error': validator && validator.$error }">
|
||||||
<datepicker
|
<datepicker
|
||||||
ref="select"
|
ref="select"
|
||||||
:ref-name="'select'"
|
:ref-name="'select'"
|
||||||
@@ -8,15 +11,21 @@
|
|||||||
:parse-typed-date="formatTypedValue"
|
:parse-typed-date="formatTypedValue"
|
||||||
:language="locale"
|
:language="locale"
|
||||||
:monday-first="mondayFirst"
|
:monday-first="mondayFirst"
|
||||||
:input-class="'br2 f5 ba b--black-40 pa2 outline-0'"
|
:input-class="inputClass"
|
||||||
:typeable="true"
|
:typeable="true"
|
||||||
:clear-button="true"
|
:clear-button="true"
|
||||||
:show-calendar-on-focus="showCalendarOnFocus"
|
:show-calendar-on-focus="showCalendarOnFocus"
|
||||||
@input="$emit('input', exchangeValue($event))"
|
@input="onInput($event)"
|
||||||
@selected="update"
|
@selected="onSelected($event)"
|
||||||
@clearDate="update('')"
|
@clearDate="onSelected('')"
|
||||||
/>
|
/>
|
||||||
<input :name="id" type="hidden" :value="exchange" />
|
<input :name="id" type="hidden" :value="exchange" />
|
||||||
|
<small v-if="validator && (validator.$error && validator.required !== undefined && !validator.required)" class="error">
|
||||||
|
{{ requiredMessage }}
|
||||||
|
</small>
|
||||||
|
<small v-if="validator && (validator.$error && validator.before !== undefined && !validator.before)" class="error">
|
||||||
|
{{ beforeMessage }}
|
||||||
|
</small>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -44,6 +53,10 @@ export default {
|
|||||||
type: String,
|
type: String,
|
||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
|
label: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
defaultDate: {
|
defaultDate: {
|
||||||
type: String,
|
type: String,
|
||||||
default: '',
|
default: '',
|
||||||
@@ -55,7 +68,11 @@ export default {
|
|||||||
showCalendarOnFocus: {
|
showCalendarOnFocus: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
}
|
},
|
||||||
|
validator: {
|
||||||
|
type: Object,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
@@ -84,6 +101,25 @@ export default {
|
|||||||
displayFormat() {
|
displayFormat() {
|
||||||
return 'L';
|
return 'L';
|
||||||
},
|
},
|
||||||
|
|
||||||
|
inputClass() {
|
||||||
|
var c = ['br2 f5 ba b--black-40 pa2 outline-0'];
|
||||||
|
if (this.validator) {
|
||||||
|
c.push({ 'error': this.validator.$error });
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
},
|
||||||
|
|
||||||
|
requiredMessage() {
|
||||||
|
return this.$t('validation.vue.required', { field: this.label });
|
||||||
|
},
|
||||||
|
|
||||||
|
beforeMessage() {
|
||||||
|
return this.$t('validation.vue.max.numeric', {
|
||||||
|
field: this.label,
|
||||||
|
max: this.displayValue(this.validator.$params.before.date)
|
||||||
|
});
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
watch: {
|
watch: {
|
||||||
@@ -130,7 +166,6 @@ export default {
|
|||||||
}
|
}
|
||||||
this.exchange = mdate.format(this.exchangeFormat);
|
this.exchange = mdate.format(this.exchangeFormat);
|
||||||
}
|
}
|
||||||
this.$emit('input', this.exchange);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
updateExchange(date) {
|
updateExchange(date) {
|
||||||
@@ -156,8 +191,19 @@ export default {
|
|||||||
|
|
||||||
focus() {
|
focus() {
|
||||||
this.$refs.select.$children[0].$refs.select.focus();
|
this.$refs.select.$children[0].$refs.select.focus();
|
||||||
}
|
},
|
||||||
|
|
||||||
|
onInput(event) {
|
||||||
|
if (this.validator) {
|
||||||
|
this.validator.$touch();
|
||||||
|
}
|
||||||
|
this.$emit('input', this.exchangeValue(event));
|
||||||
|
},
|
||||||
|
|
||||||
|
onSelected(event) {
|
||||||
|
this.update(event);
|
||||||
|
this.onInput(event);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,21 +1,22 @@
|
|||||||
<style scoped>
|
<style scoped>
|
||||||
input {
|
.input {
|
||||||
transition: all;
|
transition: all;
|
||||||
transition-duration: 0.2s;
|
transition-duration: 0.2s;
|
||||||
border: 1px solid #c4cdd5;
|
border: 1px solid #c4cdd5;
|
||||||
}
|
}
|
||||||
input:focus {
|
|
||||||
|
.input:focus {
|
||||||
border: 1px solid #5c6ac4;
|
border: 1px solid #5c6ac4;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div :class="{ 'form-group-error': validator && validator.$error }">
|
||||||
<label
|
<label
|
||||||
v-if="title"
|
v-if="title"
|
||||||
:for="realid"
|
:for="realid"
|
||||||
class="mb2"
|
class="mb2"
|
||||||
:class="{ b: required }"
|
:class="{ b: required, error: validator && validator.$error }"
|
||||||
>
|
>
|
||||||
{{ title }}
|
{{ title }}
|
||||||
</label>
|
</label>
|
||||||
@@ -31,9 +32,20 @@ input:focus {
|
|||||||
:style="inputStyle"
|
:style="inputStyle"
|
||||||
:value="value"
|
:value="value"
|
||||||
:maxlength="maxlength"
|
:maxlength="maxlength"
|
||||||
@input="event => { $emit('input', event.target.value) }"
|
@input="onInput($event)"
|
||||||
@keyup.enter="event => { $emit('submit', event.target.value) }"
|
@blur="onBlur($event)"
|
||||||
|
@change="onChange($event)"
|
||||||
|
@keyup.enter="onSubmit($event)"
|
||||||
/>
|
/>
|
||||||
|
<small v-if="validator && (validator.$error && validator.required !== undefined && !validator.required)" class="error">
|
||||||
|
{{ requiredMessage }}
|
||||||
|
</small>
|
||||||
|
<small v-if="validator && (validator.$error && validator.maxLength !== undefined && !validator.maxLength)" class="error">
|
||||||
|
{{ maxLengthMessage }}
|
||||||
|
</small>
|
||||||
|
<small v-if="validator && (validator.$error && validator.url !== undefined && !validator.url)" class="error">
|
||||||
|
{{ urlMessage }}
|
||||||
|
</small>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -49,6 +61,10 @@ export default {
|
|||||||
type: String,
|
type: String,
|
||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
|
label: {
|
||||||
|
type: String,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
id: {
|
id: {
|
||||||
type: String,
|
type: String,
|
||||||
default: '',
|
default: '',
|
||||||
@@ -70,13 +86,17 @@ export default {
|
|||||||
default: -1,
|
default: -1,
|
||||||
},
|
},
|
||||||
iclass: {
|
iclass: {
|
||||||
type: String,
|
type: [String, Array],
|
||||||
default: ''
|
default: ''
|
||||||
},
|
},
|
||||||
maxlength: {
|
maxlength: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
||||||
|
validator: {
|
||||||
|
type: Object,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
@@ -84,17 +104,72 @@ export default {
|
|||||||
return this.id + this._uid;
|
return this.id + this._uid;
|
||||||
},
|
},
|
||||||
inputClass() {
|
inputClass() {
|
||||||
return this.iclass != '' ? this.iclass : 'br2 f5 w-100 ba b--black-40 pa2 outline-0';
|
var c = [this.iclass != '' ? this.iclass : 'br2 f5 w-100 ba b--black-40 pa2 outline-0'];
|
||||||
|
if (this.validator) {
|
||||||
|
c.push({ error: this.validator.$error });
|
||||||
|
}
|
||||||
|
c.push('input');
|
||||||
|
return c;
|
||||||
},
|
},
|
||||||
inputStyle() {
|
inputStyle() {
|
||||||
return this.width >= 0 ? 'width:' + this.width + 'px' : '';
|
return this.width >= 0 ? 'width:' + this.width + 'px' : '';
|
||||||
}
|
},
|
||||||
|
|
||||||
|
field() {
|
||||||
|
return this.label && this.label.length > 0 ? this.label : this.title;
|
||||||
|
},
|
||||||
|
requiredMessage() {
|
||||||
|
return this.$t('validation.vue.required', { field: this.field });
|
||||||
|
},
|
||||||
|
urlMessage() {
|
||||||
|
return this.$t('validation.vue.url', { field: this.field });
|
||||||
|
},
|
||||||
|
maxLengthMessage() {
|
||||||
|
var type = 'string';
|
||||||
|
switch (this.inputType) {
|
||||||
|
case 'number':
|
||||||
|
type = 'numeric';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return this.$t('validation.vue.max.'.type, {
|
||||||
|
field: this.field,
|
||||||
|
max: this.validator ? this.validator.$params.maxLength.max : '',
|
||||||
|
});
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
focus() {
|
focus() {
|
||||||
this.$refs.input.focus();
|
this.$refs.input.focus();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onInput(event) {
|
||||||
|
if (this.validator && event.data !== undefined) {
|
||||||
|
this.validator.$reset();
|
||||||
|
}
|
||||||
|
this.$emit('input', event.target.value);
|
||||||
|
},
|
||||||
|
|
||||||
|
onSubmit(event) {
|
||||||
|
if (this.validator) {
|
||||||
|
this.validator.$touch();
|
||||||
|
}
|
||||||
|
this.$emit('submit', event.target.value);
|
||||||
|
},
|
||||||
|
|
||||||
|
onBlur(event) {
|
||||||
|
if (this.validator && event.target.value !== '') {
|
||||||
|
this.validator.$touch();
|
||||||
|
}
|
||||||
|
this.$emit('blur', event.target.value);
|
||||||
|
},
|
||||||
|
|
||||||
|
onChange(event) {
|
||||||
|
if (this.validator) {
|
||||||
|
this.validator.$touch();
|
||||||
|
}
|
||||||
|
this.$emit('change', event.target.value);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<p-input
|
<p-input
|
||||||
ref="input"
|
ref="input"
|
||||||
v-model.lazy="modelValue"
|
v-model.lazy="prop"
|
||||||
:name="name"
|
:name="name"
|
||||||
:type="_type"
|
:type="_type"
|
||||||
:class="inputClass"
|
:class="inputClass"
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
:value="value"
|
:value="value"
|
||||||
:disabled="disabled"
|
:disabled="disabled"
|
||||||
:required="required"
|
:required="required"
|
||||||
@change="event => { $emit('change', event) }"
|
@change="$emit('change', $event)"
|
||||||
>
|
>
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
<slot slot="extra" name="inputextra"></slot>
|
<slot slot="extra" name="inputextra"></slot>
|
||||||
@@ -82,6 +82,12 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
prop: null
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
_type() {
|
_type() {
|
||||||
if (this.$options.input_type) {
|
if (this.$options.input_type) {
|
||||||
@@ -97,6 +103,16 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
watch: {
|
||||||
|
modelValue(val) {
|
||||||
|
this.prop = val;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
this.prop = this.modelValue;
|
||||||
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
select() {
|
select() {
|
||||||
if (this.disabled) {
|
if (this.disabled) {
|
||||||
|
|||||||
@@ -1,22 +1,22 @@
|
|||||||
<style scoped>
|
<style scoped>
|
||||||
select {
|
.select {
|
||||||
height: 34px;
|
height: 34px;
|
||||||
transition: all;
|
transition: all;
|
||||||
transition-duration: 0.2s;
|
transition-duration: 0.2s;
|
||||||
border: 1px solid #c4cdd5;
|
border: 1px solid #c4cdd5;
|
||||||
}
|
}
|
||||||
select:focus {
|
.select:focus {
|
||||||
border: 1px solid #5c6ac4;
|
border: 1px solid #5c6ac4;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div :class="{ 'form-group-error': validator && validator.$error }">
|
||||||
<label
|
<label
|
||||||
v-if="title"
|
v-if="title"
|
||||||
:for="realid"
|
:for="realid"
|
||||||
class="mb2"
|
class="mb2"
|
||||||
:class="{ b: required }"
|
:class="{ b: required, error: validator && validator.$error }"
|
||||||
>
|
>
|
||||||
{{ title }}
|
{{ title }}
|
||||||
</label>
|
</label>
|
||||||
@@ -27,7 +27,7 @@ select:focus {
|
|||||||
:name="id"
|
:name="id"
|
||||||
:required="required"
|
:required="required"
|
||||||
:class="selectClass"
|
:class="selectClass"
|
||||||
@input="event => { $emit('input', event.target.value) }"
|
@input="onInput"
|
||||||
>
|
>
|
||||||
<template v-if="Array.isArray(options)">
|
<template v-if="Array.isArray(options)">
|
||||||
<option
|
<option
|
||||||
@@ -54,6 +54,9 @@ select:focus {
|
|||||||
</optgroup>
|
</optgroup>
|
||||||
</template>
|
</template>
|
||||||
</select>
|
</select>
|
||||||
|
<small v-if="validator && (validator.$error && validator.required !== undefined && !validator.required)" class="error">
|
||||||
|
{{ requiredMessage }}
|
||||||
|
</small>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -73,6 +76,10 @@ export default {
|
|||||||
type: String,
|
type: String,
|
||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
|
label: {
|
||||||
|
type: String,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
id: {
|
id: {
|
||||||
type: String,
|
type: String,
|
||||||
default: '',
|
default: '',
|
||||||
@@ -89,6 +96,10 @@ export default {
|
|||||||
type: String,
|
type: String,
|
||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
|
validator: {
|
||||||
|
type: Object,
|
||||||
|
default: null,
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
@@ -102,8 +113,19 @@ export default {
|
|||||||
return this.id + this._uid;
|
return this.id + this._uid;
|
||||||
},
|
},
|
||||||
selectClass() {
|
selectClass() {
|
||||||
return this.iclass != '' ? this.iclass : 'br2 f5 w-100 ba b--black-40 pa2 outline-0';
|
var c = [this.iclass != '' ? this.iclass : 'br2 f5 w-100 ba b--black-40 pa2 outline-0'];
|
||||||
}
|
if (this.validator) {
|
||||||
|
c.push({ error: this.validator.$error });
|
||||||
|
}
|
||||||
|
c.push('select');
|
||||||
|
return c;
|
||||||
|
},
|
||||||
|
field() {
|
||||||
|
return this.label && this.label.length > 0 ? this.label : this.title;
|
||||||
|
},
|
||||||
|
requiredMessage() {
|
||||||
|
return this.$t('validation.vue.required', { field: this.field });
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
watch: {
|
watch: {
|
||||||
@@ -129,7 +151,14 @@ export default {
|
|||||||
|
|
||||||
focus() {
|
focus() {
|
||||||
this.$refs.select.focus();
|
this.$refs.select.focus();
|
||||||
}
|
},
|
||||||
|
|
||||||
|
onInput(event) {
|
||||||
|
if (this.validator) {
|
||||||
|
this.validator.$touch();
|
||||||
|
}
|
||||||
|
this.$emit('input', event.target.value);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -80,24 +80,26 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Create Client Modal -->
|
<!-- Create Client Modal -->
|
||||||
<sweet-modal ref="modalCreateClient" overlay-theme="dark" tabindex="-1" role="dialog"
|
<sweet-modal ref="modalClient" overlay-theme="dark" tabindex="-1" role="dialog"
|
||||||
:title="$t('settings.api_oauth_create')" @open="_focusCreateInput"
|
:title="form.id ? $t('settings.api_oauth_edit') : $t('settings.api_oauth_create')"
|
||||||
|
@open="_focusInput"
|
||||||
>
|
>
|
||||||
<!-- Form Errors -->
|
<!-- Form Errors -->
|
||||||
<error :errors="createForm.errors" />
|
<error :errors="form.errors" />
|
||||||
|
|
||||||
<!-- Create Client Form -->
|
<!-- Create Client Form -->
|
||||||
<form class="form-horizontal" role="form">
|
<form ref="form" class="form-horizontal" role="form">
|
||||||
<!-- Name -->
|
<!-- Name -->
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="col-md-auto">
|
<div class="col-md-auto">
|
||||||
<form-input
|
<form-input
|
||||||
:id="'create-client-name'"
|
:id="'client-name'"
|
||||||
ref="createClientName"
|
ref="clientName"
|
||||||
v-model="createForm.name"
|
v-model="form.name"
|
||||||
:iclass="'br2 f5 w-50 ba b--black-40 pa2 outline-0'"
|
:iclass="'br2 f5 w-50 ba b--black-40 pa2 outline-0'"
|
||||||
:required="true"
|
:required="true"
|
||||||
:title="$t('settings.api_oauth_name')"
|
:title="$t('settings.api_oauth_name')"
|
||||||
|
:validator="$v.form.name"
|
||||||
@submit="store"
|
@submit="store"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@@ -111,11 +113,12 @@
|
|||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="col-md-auto">
|
<div class="col-md-auto">
|
||||||
<form-input
|
<form-input
|
||||||
:id="'create-redirect-url'"
|
:id="'redirect-url'"
|
||||||
v-model="createForm.redirect"
|
v-model="form.redirect"
|
||||||
:iclass="'br2 f5 w-50 ba b--black-40 pa2 outline-0'"
|
:iclass="'br2 f5 w-50 ba b--black-40 pa2 outline-0'"
|
||||||
:required="true"
|
:required="true"
|
||||||
:title="$t('settings.api_oauth_redirecturl')"
|
:title="$t('settings.api_oauth_redirecturl')"
|
||||||
|
:validator="$v.form.redirect"
|
||||||
@submit="store"
|
@submit="store"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@@ -132,65 +135,7 @@
|
|||||||
{{ $t('app.close') }}
|
{{ $t('app.close') }}
|
||||||
</a>
|
</a>
|
||||||
<a class="btn btn-primary" href="" @click.prevent="store">
|
<a class="btn btn-primary" href="" @click.prevent="store">
|
||||||
{{ $t('app.create') }}
|
{{ form.id ? $t('app.save') : $t('app.create') }}
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</sweet-modal>
|
|
||||||
|
|
||||||
<!-- Edit Client Modal -->
|
|
||||||
<sweet-modal ref="modalEditClient" overlay-theme="dark" tabindex="-1" role="dialog"
|
|
||||||
:title="$t('settings.api_oauth_edit')" @open="_focusEditInput"
|
|
||||||
>
|
|
||||||
<!-- Form Errors -->
|
|
||||||
<error :errors="editForm.errors" />
|
|
||||||
|
|
||||||
<!-- Edit Client Form -->
|
|
||||||
<form class="form-horizontal" role="form">
|
|
||||||
<!-- Name -->
|
|
||||||
<div class="form-group">
|
|
||||||
<div class="col-md-auto">
|
|
||||||
<form-input
|
|
||||||
:id="'edit-client-name'"
|
|
||||||
ref="editClientName"
|
|
||||||
v-model="editForm.name"
|
|
||||||
:iclass="'br2 f5 w-50 ba b--black-40 pa2 outline-0'"
|
|
||||||
:required="true"
|
|
||||||
:title="$t('settings.api_oauth_name')"
|
|
||||||
@submit="update"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<small class="form-text text-muted">
|
|
||||||
{{ $t('settings.api_oauth_name_help') }}
|
|
||||||
</small>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Redirect URL -->
|
|
||||||
<div class="form-group">
|
|
||||||
<div class="col-md-auto">
|
|
||||||
<form-input
|
|
||||||
:id="'edit-redirect-url'"
|
|
||||||
v-model="editForm.redirect"
|
|
||||||
:iclass="'br2 f5 w-50 ba b--black-40 pa2 outline-0'"
|
|
||||||
:required="true"
|
|
||||||
:title="$t('settings.api_oauth_redirecturl')"
|
|
||||||
@submit="update"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<small class="form-text text-muted">
|
|
||||||
{{ $t('settings.api_oauth_redirecturl_help') }}
|
|
||||||
</small>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<!-- Modal Actions -->
|
|
||||||
<div slot="button">
|
|
||||||
<a class="btn" href="" @click.prevent="closeModal">
|
|
||||||
{{ $t('app.close') }}
|
|
||||||
</a>
|
|
||||||
<a class="btn btn-primary" href="" @click.prevent="update">
|
|
||||||
{{ $t('app.save') }}
|
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</sweet-modal>
|
</sweet-modal>
|
||||||
@@ -200,6 +145,8 @@
|
|||||||
<script>
|
<script>
|
||||||
import Error from '../partials/Error.vue';
|
import Error from '../partials/Error.vue';
|
||||||
import { SweetModal } from 'sweet-modal-vue';
|
import { SweetModal } from 'sweet-modal-vue';
|
||||||
|
import { validationMixin } from 'vuelidate';
|
||||||
|
import { required, url } from 'vuelidate/lib/validators';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|
||||||
@@ -208,17 +155,13 @@ export default {
|
|||||||
Error
|
Error
|
||||||
},
|
},
|
||||||
|
|
||||||
|
mixins: [validationMixin],
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
clients: [],
|
clients: [],
|
||||||
|
|
||||||
createForm: {
|
form: {
|
||||||
errors: [],
|
|
||||||
name: '',
|
|
||||||
redirect: ''
|
|
||||||
},
|
|
||||||
|
|
||||||
editForm: {
|
|
||||||
errors: [],
|
errors: [],
|
||||||
name: '',
|
name: '',
|
||||||
redirect: ''
|
redirect: ''
|
||||||
@@ -226,6 +169,18 @@ export default {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
validations: {
|
||||||
|
form: {
|
||||||
|
name: {
|
||||||
|
required,
|
||||||
|
},
|
||||||
|
redirect: {
|
||||||
|
required,
|
||||||
|
url,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
dirltr() {
|
dirltr() {
|
||||||
return this.$root.htmldir == 'ltr';
|
return this.$root.htmldir == 'ltr';
|
||||||
@@ -244,26 +199,16 @@ export default {
|
|||||||
/**
|
/**
|
||||||
* Focus on modal open.
|
* Focus on modal open.
|
||||||
*/
|
*/
|
||||||
_focusCreateInput() {
|
_focusInput() {
|
||||||
let vm = this;
|
let vm = this;
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
vm.$refs.createClientName.focus();
|
vm.$refs.clientName.focus();
|
||||||
}, 10);
|
}, 10);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Focus on modal open.
|
* Get all of the OAuth clients for the user.
|
||||||
*/
|
*/
|
||||||
_focusEditInput() {
|
|
||||||
let vm = this;
|
|
||||||
setTimeout(function() {
|
|
||||||
vm.$refs.editClientName.focus();
|
|
||||||
}, 10);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get all of the OAuth clients for the user.
|
|
||||||
*/
|
|
||||||
getClients() {
|
getClients() {
|
||||||
axios.get('oauth/clients')
|
axios.get('oauth/clients')
|
||||||
.then(response => {
|
.then(response => {
|
||||||
@@ -272,46 +217,41 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show the form for creating new clients.
|
* Show the form for creating new clients.
|
||||||
*/
|
*/
|
||||||
showCreateClientForm() {
|
showCreateClientForm() {
|
||||||
this.$refs.modalCreateClient.open();
|
this.resetField();
|
||||||
|
this.$refs.modalClient.open();
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new OAuth client for the user.
|
* Create a new OAuth client for the user.
|
||||||
*/
|
*/
|
||||||
store() {
|
store() {
|
||||||
this.persistClient(
|
this.$v.$touch();
|
||||||
'post', 'oauth/clients',
|
|
||||||
this.createForm
|
if (this.$v.$invalid) {
|
||||||
);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let method = this.form.id ? 'put' : 'post';
|
||||||
|
let url = this.form.id ? 'oauth/clients/' + this.form.id : 'oauth/clients';
|
||||||
|
|
||||||
|
this.persistClient(method, url, this.form);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Edit the given client.
|
* Edit the given client.
|
||||||
*/
|
*/
|
||||||
edit(client) {
|
edit(client) {
|
||||||
this.editForm.id = client.id;
|
this.form = Object.assign({errors:[]}, client);
|
||||||
this.editForm.name = client.name;
|
|
||||||
this.editForm.redirect = client.redirect;
|
|
||||||
|
|
||||||
this.$refs.modalEditClient.open();
|
this.$refs.modalClient.open();
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the client being edited.
|
* Persist the client to storage using the given form.
|
||||||
*/
|
*/
|
||||||
update() {
|
|
||||||
this.persistClient(
|
|
||||||
'put', 'oauth/clients/' + this.editForm.id,
|
|
||||||
this.editForm
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Persist the client to storage using the given form.
|
|
||||||
*/
|
|
||||||
persistClient(method, uri, form) {
|
persistClient(method, uri, form) {
|
||||||
form.errors = [];
|
form.errors = [];
|
||||||
|
|
||||||
@@ -319,10 +259,6 @@ export default {
|
|||||||
.then(response => {
|
.then(response => {
|
||||||
this.getClients();
|
this.getClients();
|
||||||
|
|
||||||
form.name = '';
|
|
||||||
form.redirect = '';
|
|
||||||
form.errors = [];
|
|
||||||
|
|
||||||
this.closeModal();
|
this.closeModal();
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
@@ -335,8 +271,8 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroy the given client.
|
* Destroy the given client.
|
||||||
*/
|
*/
|
||||||
destroy(client) {
|
destroy(client) {
|
||||||
axios.delete('oauth/clients/' + client.id)
|
axios.delete('oauth/clients/' + client.id)
|
||||||
.then(response => {
|
.then(response => {
|
||||||
@@ -345,8 +281,19 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
closeModal() {
|
closeModal() {
|
||||||
this.$refs.modalCreateClient.close();
|
this.resetField();
|
||||||
this.$refs.modalEditClient.close();
|
this.$v.$reset();
|
||||||
|
this.$refs.form.reset();
|
||||||
|
this.$refs.modalClient.close();
|
||||||
|
},
|
||||||
|
|
||||||
|
resetField() {
|
||||||
|
this.form = {
|
||||||
|
id: '',
|
||||||
|
errors:[],
|
||||||
|
name: '',
|
||||||
|
redirect: '',
|
||||||
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -69,7 +69,7 @@
|
|||||||
<error :errors="form.errors" />
|
<error :errors="form.errors" />
|
||||||
|
|
||||||
<!-- Create Token Form -->
|
<!-- Create Token Form -->
|
||||||
<form class="form-horizontal" role="form" @submit.prevent="store">
|
<form ref="form" class="form-horizontal" role="form" @submit.prevent="store">
|
||||||
<!-- Name -->
|
<!-- Name -->
|
||||||
<div class="col-md-auto">
|
<div class="col-md-auto">
|
||||||
<form-input
|
<form-input
|
||||||
@@ -80,6 +80,7 @@
|
|||||||
:iclass="'br2 f5 w-50 ba b--black-40 pa2 outline-0'"
|
:iclass="'br2 f5 w-50 ba b--black-40 pa2 outline-0'"
|
||||||
:required="true"
|
:required="true"
|
||||||
:title="$t('settings.api_token_name')"
|
:title="$t('settings.api_token_name')"
|
||||||
|
:validator="$v.form.name"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -141,6 +142,8 @@
|
|||||||
<script>
|
<script>
|
||||||
import Error from '../partials/Error.vue';
|
import Error from '../partials/Error.vue';
|
||||||
import { SweetModal } from 'sweet-modal-vue';
|
import { SweetModal } from 'sweet-modal-vue';
|
||||||
|
import { validationMixin } from 'vuelidate';
|
||||||
|
import { required } from 'vuelidate/lib/validators';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|
||||||
@@ -149,6 +152,8 @@ export default {
|
|||||||
Error
|
Error
|
||||||
},
|
},
|
||||||
|
|
||||||
|
mixins: [validationMixin],
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
endpoint: '',
|
endpoint: '',
|
||||||
@@ -165,6 +170,14 @@ export default {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
validations: {
|
||||||
|
form: {
|
||||||
|
name: {
|
||||||
|
required,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
dirltr() {
|
dirltr() {
|
||||||
return this.$root.htmldir == 'ltr';
|
return this.$root.htmldir == 'ltr';
|
||||||
@@ -207,6 +220,8 @@ export default {
|
|||||||
* Close all modals.
|
* Close all modals.
|
||||||
*/
|
*/
|
||||||
closeModal() {
|
closeModal() {
|
||||||
|
this.$refs.form.reset();
|
||||||
|
this.$v.$reset();
|
||||||
this.$refs.modalCreateToken.close();
|
this.$refs.modalCreateToken.close();
|
||||||
this.$refs.modalAccessToken.close();
|
this.$refs.modalAccessToken.close();
|
||||||
},
|
},
|
||||||
@@ -232,6 +247,12 @@ export default {
|
|||||||
* Create a new personal access token.
|
* Create a new personal access token.
|
||||||
*/
|
*/
|
||||||
store() {
|
store() {
|
||||||
|
this.$v.$touch();
|
||||||
|
|
||||||
|
if (this.$v.$invalid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.accessToken = null;
|
this.accessToken = null;
|
||||||
|
|
||||||
this.form.errors = [];
|
this.form.errors = [];
|
||||||
|
|||||||
@@ -1,4 +1,15 @@
|
|||||||
<style scoped>
|
<style scoped>
|
||||||
|
.error {
|
||||||
|
animation-name: shakeError;
|
||||||
|
animation-fill-mode: forwards;
|
||||||
|
animation-duration: .6s;
|
||||||
|
animation-timing-function: ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group-error {
|
||||||
|
display: block;
|
||||||
|
color:#f57f6c;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -113,16 +124,19 @@
|
|||||||
<div class="mb2">
|
<div class="mb2">
|
||||||
<toggle-button class="mr2" :sync="true" :labels="true" :value="stateInput" @change="stateInput = !stateInput" />
|
<toggle-button class="mr2" :sync="true" :labels="true" :value="stateInput" @change="stateInput = !stateInput" />
|
||||||
<div class="dib relative" style="top: -2px;">
|
<div class="dib relative" style="top: -2px;">
|
||||||
<stay-in-touch-label v-model="frequencyInput">
|
<stay-in-touch-label
|
||||||
|
v-model="frequencyInput"
|
||||||
|
:class="{ 'form-group-error': $v.frequencyInput.$error }"
|
||||||
|
>
|
||||||
<div class="dib">
|
<div class="dib">
|
||||||
<form-input
|
<form-input
|
||||||
:id="'frequency'"
|
:id="'frequency'"
|
||||||
v-model="frequencyInput"
|
v-model.number="frequencyInput"
|
||||||
:value="frequencyInput"
|
|
||||||
:input-type="'number'"
|
:input-type="'number'"
|
||||||
:width="60"
|
:width="60"
|
||||||
:required="true"
|
:required="true"
|
||||||
@input="stateInput = $event > 0"
|
:validator="$v.frequencyInput"
|
||||||
|
@input="onInput($event)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</stay-in-touch-label>
|
</stay-in-touch-label>
|
||||||
@@ -153,6 +167,8 @@
|
|||||||
<script>
|
<script>
|
||||||
import { SweetModal } from 'sweet-modal-vue';
|
import { SweetModal } from 'sweet-modal-vue';
|
||||||
import { ToggleButton } from 'vue-js-toggle-button';
|
import { ToggleButton } from 'vue-js-toggle-button';
|
||||||
|
import { validationMixin } from 'vuelidate';
|
||||||
|
import { required, numeric } from 'vuelidate/lib/validators';
|
||||||
|
|
||||||
let StayInTouchLabel = Vue.component('stay-in-touch-label', {
|
let StayInTouchLabel = Vue.component('stay-in-touch-label', {
|
||||||
|
|
||||||
@@ -181,6 +197,8 @@ export default {
|
|||||||
StayInTouchLabel,
|
StayInTouchLabel,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
mixins: [validationMixin],
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
hash: {
|
hash: {
|
||||||
type: String,
|
type: String,
|
||||||
@@ -196,6 +214,13 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
validations: {
|
||||||
|
frequencyInput: {
|
||||||
|
required,
|
||||||
|
numeric,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
frequency: 0,
|
frequency: 0,
|
||||||
@@ -250,10 +275,9 @@ export default {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// make sure we can't press update if the frequency is invalid
|
this.$v.$touch();
|
||||||
// and if the feature is activated
|
|
||||||
if ((this.frequencyInput == '' || this.frequencyInput < 1) && this.stateInput) {
|
if (this.$v.$invalid) {
|
||||||
this.errorMessage = this.$t('people.stay_in_touch_invalid');
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<style scoped>
|
<style scoped>
|
||||||
.photo {
|
.photo {
|
||||||
height: 200px;
|
height: 200px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -58,6 +58,7 @@
|
|||||||
:required="true"
|
:required="true"
|
||||||
:class="'dtc pr2'"
|
:class="'dtc pr2'"
|
||||||
:title="$t('people.gifts_add_gift_name')"
|
:title="$t('people.gifts_add_gift_name')"
|
||||||
|
:validator="$v.newGift.name"
|
||||||
@submit="store"
|
@submit="store"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -126,14 +127,16 @@
|
|||||||
<form-checkbox
|
<form-checkbox
|
||||||
v-model="hasRecipient"
|
v-model="hasRecipient"
|
||||||
:name="'has_recipient'"
|
:name="'has_recipient'"
|
||||||
@change="() => { this.$refs.recipient.focus() }"
|
@change="(val) => { if (val) { $refs.recipient.focus() } }"
|
||||||
>
|
>
|
||||||
{{ $t('people.gifts_add_someone', {name: ''}) }}
|
{{ $t('people.gifts_add_someone', {name: ''}) }}
|
||||||
</form-checkbox>
|
</form-checkbox>
|
||||||
<form-select
|
<form-select
|
||||||
ref="recipient"
|
ref="recipient"
|
||||||
v-model="newGift.recipient_id"
|
v-model="newGift.recipient_id"
|
||||||
|
:label="$t('people.gifts_add_recipient_field')"
|
||||||
:options="familyContacts"
|
:options="familyContacts"
|
||||||
|
:validator="$v.newGift.recipient_id"
|
||||||
@input="hasRecipient = true"
|
@input="hasRecipient = true"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -205,6 +208,8 @@
|
|||||||
|
|
||||||
import Error from '../../partials/Error.vue';
|
import Error from '../../partials/Error.vue';
|
||||||
import PhotoUpload from '../photo/PhotoUpload.vue';
|
import PhotoUpload from '../photo/PhotoUpload.vue';
|
||||||
|
import { validationMixin } from 'vuelidate';
|
||||||
|
import { required, maxLength } from 'vuelidate/lib/validators';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
@@ -212,6 +217,8 @@ export default {
|
|||||||
PhotoUpload
|
PhotoUpload
|
||||||
},
|
},
|
||||||
|
|
||||||
|
mixins: [validationMixin],
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
contactId: {
|
contactId: {
|
||||||
type: Number,
|
type: Number,
|
||||||
@@ -254,6 +261,27 @@ export default {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
validations() {
|
||||||
|
var v = {
|
||||||
|
newGift: {
|
||||||
|
name: {
|
||||||
|
required,
|
||||||
|
maxLength: maxLength(255),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (this.hasRecipient) {
|
||||||
|
v.newGift = Object.assign(v.newGift, {
|
||||||
|
recipient_id: {
|
||||||
|
required,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return v;
|
||||||
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
locale() {
|
locale() {
|
||||||
return this.$root.locale;
|
return this.$root.locale;
|
||||||
@@ -307,6 +335,7 @@ export default {
|
|||||||
this.displayUpload= this.gift ? this.gift.photos.length > 0 : false;
|
this.displayUpload= this.gift ? this.gift.photos.length > 0 : false;
|
||||||
|
|
||||||
this.errors = [];
|
this.errors = [];
|
||||||
|
this.$v.$reset();
|
||||||
},
|
},
|
||||||
|
|
||||||
close() {
|
close() {
|
||||||
@@ -319,6 +348,12 @@ export default {
|
|||||||
this.newGift.recipient_id = null;
|
this.newGift.recipient_id = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.$v.$touch();
|
||||||
|
|
||||||
|
if (this.$v.$invalid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let method = this.gift ? 'put' : 'post';
|
let method = this.gift ? 'put' : 'post';
|
||||||
let url = this.gift ? 'api/gifts/'+this.gift.id : 'api/gifts';
|
let url = this.gift ? 'api/gifts/'+this.gift.id : 'api/gifts';
|
||||||
|
|
||||||
|
|||||||
@@ -151,6 +151,7 @@ return [
|
|||||||
'information_edit_probably' => 'This person is probably...',
|
'information_edit_probably' => 'This person is probably...',
|
||||||
'information_edit_not_year' => 'I know the day and month of the birthdate of this person, but not the year…',
|
'information_edit_not_year' => 'I know the day and month of the birthdate of this person, but not the year…',
|
||||||
'information_edit_exact' => 'I know the exact birthdate of this person...',
|
'information_edit_exact' => 'I know the exact birthdate of this person...',
|
||||||
|
'information_edit_birthdate_label' => 'Birthdate',
|
||||||
'information_no_work_defined' => 'No work information defined',
|
'information_no_work_defined' => 'No work information defined',
|
||||||
'information_work_at' => 'at :company',
|
'information_work_at' => 'at :company',
|
||||||
'work_add_cta' => 'Update work information',
|
'work_add_cta' => 'Update work information',
|
||||||
@@ -308,6 +309,7 @@ return [
|
|||||||
'gifts_add_value' => 'Value (optional)',
|
'gifts_add_value' => 'Value (optional)',
|
||||||
'gifts_add_comment' => 'Comment (optional)',
|
'gifts_add_comment' => 'Comment (optional)',
|
||||||
'gifts_add_recipient' => 'Recipient (optional)',
|
'gifts_add_recipient' => 'Recipient (optional)',
|
||||||
|
'gifts_add_recipient_field' => 'Recipient',
|
||||||
'gifts_add_photo' => 'Photo (optional)',
|
'gifts_add_photo' => 'Photo (optional)',
|
||||||
'gifts_add_photo_title' => 'Add a photo for this gift',
|
'gifts_add_photo_title' => 'Add a photo for this gift',
|
||||||
'gifts_add_someone' => 'This gift is for someone in {name}’s family in particular',
|
'gifts_add_someone' => 'This gift is for someone in {name}’s family in particular',
|
||||||
@@ -366,6 +368,7 @@ return [
|
|||||||
'deceased_know_date' => 'I know the date this person died',
|
'deceased_know_date' => 'I know the date this person died',
|
||||||
'deceased_add_reminder' => 'Add a reminder for this date',
|
'deceased_add_reminder' => 'Add a reminder for this date',
|
||||||
'deceased_label' => 'Deceased',
|
'deceased_label' => 'Deceased',
|
||||||
|
'deceased_date_label' => 'Deceased date',
|
||||||
'deceased_label_with_date' => 'Deceased on :date',
|
'deceased_label_with_date' => 'Deceased on :date',
|
||||||
'deceased_age' => 'Age at death',
|
'deceased_age' => 'Age at death',
|
||||||
|
|
||||||
|
|||||||
@@ -120,4 +120,12 @@ return [
|
|||||||
|
|
||||||
'attributes' => [],
|
'attributes' => [],
|
||||||
|
|
||||||
|
'vue' => [
|
||||||
|
'max' => [
|
||||||
|
'numeric' => '{field} may not be greater than {max}.',
|
||||||
|
'string' => '{field} may not be greater than {max} characters.',
|
||||||
|
],
|
||||||
|
'required' => '{field} is required.',
|
||||||
|
'url' => '{field} is not a valid URL.',
|
||||||
|
],
|
||||||
];
|
];
|
||||||
|
|||||||
Vendored
+29
@@ -594,3 +594,32 @@ footer {
|
|||||||
svg {
|
svg {
|
||||||
vertical-align: baseline !important;
|
vertical-align: baseline !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Input error handle
|
||||||
|
.form-group-error {
|
||||||
|
animation-name: shake;
|
||||||
|
animation-fill-mode: forwards;
|
||||||
|
animation-duration: .6s;
|
||||||
|
animation-timing-function: ease-in-out;
|
||||||
|
z-index: 99;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group-error .error {
|
||||||
|
border-color: #f79483 !important;
|
||||||
|
color:#f57f6c;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shake animation
|
||||||
|
@keyframes shake {
|
||||||
|
0%, 100% {
|
||||||
|
transform: translateX(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
15%, 45%, 75% {
|
||||||
|
transform: translateX(0.375rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
30%, 60%, 90% {
|
||||||
|
transform: translateX(-0.375rem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -9673,6 +9673,11 @@ vue@^2.5.21:
|
|||||||
resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.11.tgz#76594d877d4b12234406e84e35275c6d514125c5"
|
resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.11.tgz#76594d877d4b12234406e84e35275c6d514125c5"
|
||||||
integrity sha512-VfPwgcGABbGAue9+sfrD4PuwFar7gPb1yl1UK1MwXoQPAw0BKSqWfoYCT/ThFrdEVWoI51dBuyCoiNU9bZDZxQ==
|
integrity sha512-VfPwgcGABbGAue9+sfrD4PuwFar7gPb1yl1UK1MwXoQPAw0BKSqWfoYCT/ThFrdEVWoI51dBuyCoiNU9bZDZxQ==
|
||||||
|
|
||||||
|
vuelidate@^0.7.4:
|
||||||
|
version "0.7.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/vuelidate/-/vuelidate-0.7.4.tgz#5a0e54be09ac0192f1aa3387d74b92e0945bf8aa"
|
||||||
|
integrity sha512-QHZWYOL325Zo+2K7VBNEJTZ496Kd8Z31p85aQJFldKudUUGBmgw4zu4ghl4CyqPwjRCmqZ9lDdx4FSdMnu4fGg==
|
||||||
|
|
||||||
watchpack@^1.6.0:
|
watchpack@^1.6.0:
|
||||||
version "1.6.0"
|
version "1.6.0"
|
||||||
resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.6.0.tgz#4bc12c2ebe8aa277a71f1d3f14d685c7b446cd00"
|
resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.6.0.tgz#4bc12c2ebe8aa277a71f1d3f14d685c7b446cd00"
|
||||||
|
|||||||
Reference in New Issue
Block a user