@cnamts/vue-dot
Version:
Implementation of our Design System for the French Health Insurance
246 lines (190 loc) • 5.24 kB
text/typescript
import Vue from 'vue';
import Component, { mixins } from 'vue-class-component';
import { parseDate } from '../../../helpers/parseDate';
import { Options } from '../../../mixins/customizable';
import { Refs } from '../../../types';
export const INTERNAL_FORMAT = 'YYYY-MM-DD';
export const INTERNAL_FORMAT_REGEX = /\d{4}[- /.](0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])/;
const locales = {
invalidDate: 'La date saisie n’est pas valide.'
};
const Props = Vue.extend({
props: {
dateFormat: {
type: String,
default: 'DD/MM/YYYY'
},
dateFormatReturn: {
type: String,
default: 'YYYY-MM-DD'
},
value: {
type: String,
default: ''
}
}
});
const MixinsDeclaration = mixins(Props);
<DateLogic>({
watch: {
value: {
handler(date: string): void {
if (!date) {
this.clearInternalModel();
return;
}
const parsed = this.parseDateForModel(date);
if (!parsed) {
return;
}
this.date = parsed;
this.setTextFieldModel();
this.validate(this.textFieldDate);
this.validateVuetify();
},
immediate: true
},
/**
* This method is fired every time textFieldDate changes,
* that means on every key strokes, so don't validate
* on input if validateOnBlur is true
*/
textFieldDate(value: string): void {
if (!this.validateOnBlurEnabled) {
this.validate(value);
}
}
}
})
export class DateLogic extends MixinsDeclaration {
$refs!: Refs<{
menu: {
save: (date: string) => void;
};
input: {
validate: () => boolean;
hasFocused: boolean;
hasError: boolean;
};
}>;
// DatePicker mixin
options!: Options;
// WarningRules mixin
validate!: (value: string) => void;
/** YYYY-MM-DD format */
date = '';
/** DDMMYYYY format */
textFieldDate = '';
errorMessages: string[] | null = null;
mounted() {
// Watch VTextField 'hasError' computed value since 'update:error' event isn't reliable
// (it's not fired at initial state and 'validateOnBlur' can cause issues as well)
this.$watch(
() => this.$refs.input.hasError,
(error: boolean) => {
this.$emit('error', error);
},
{
deep: true // Required since watching $refs object
}
);
}
get validateOnBlurEnabled(): boolean {
return Boolean(this.options.textField?.validateOnBlur);
}
/** Parse a date with dateFormatReturn format to internal format */
parseDateForModel(date: string): string | null {
const parsed = parseDate(date, this.dateFormatReturn);
if (!parsed.isValid()) {
return null;
}
return parsed.format(INTERNAL_FORMAT);
}
parseTextFieldDate(date: string): string | null {
const parsed = parseDate(date, this.dateFormat);
const formatted = parsed.format(INTERNAL_FORMAT);
if (!parsed.isValid() || !formatted.match(INTERNAL_FORMAT_REGEX)) {
this.errorMessages = [locales.invalidDate];
return null;
}
return formatted;
}
setTextFieldModel(): void {
this.textFieldDate = parseDate(this.date, INTERNAL_FORMAT).format(this.dateFormat);
}
get dateFormatted(): string {
if (this.date === '') {
return '';
}
return parseDate(this.date, INTERNAL_FORMAT).format(this.dateFormat);
}
set dateFormatted(value: string) {
this.textFieldDate = value;
}
async saveFromCalendar(): Promise<void> {
this.$refs.menu.save(this.date);
this.setTextFieldModel();
await this.$nextTick();
// Trigger validation when the calendar is clicked since
// the input loose focus and fires textFieldBlur
this.validate(this.textFieldDate);
if (this.validateOnBlurEnabled) {
// Validate the VTextField since no blur event is emitted
this.validateVuetify();
}
await this.$nextTick();
this.emitChangeEvent();
}
saveFromTextField(): void {
if (!this.textFieldDate) {
this.$emit('change', '');
this.clearInternalModel();
return;
}
const formatted = this.parseTextFieldDate(this.textFieldDate);
if (!formatted) {
return;
}
this.date = formatted;
this.emitChangeEvent();
}
saveFromPasted(event: ClipboardEvent): void {
const value = event.clipboardData?.getData('text/plain');
if (!value) {
return;
}
const parsedWithDisplayFormat = parseDate(value, this.dateFormat);
if (parsedWithDisplayFormat.isValid()) {
this.date = parsedWithDisplayFormat.format(INTERNAL_FORMAT);
}
const parsedWithReturnFormat = parseDate(value, this.dateFormatReturn);
if (parsedWithReturnFormat.isValid()) {
this.date = parsedWithReturnFormat.format(INTERNAL_FORMAT);
}
this.emitChangeEvent();
}
clearInternalModel(): void {
this.date = '';
this.textFieldDate = '';
}
emitChangeEvent(): void {
this.$emit('change', parseDate(this.date, INTERNAL_FORMAT).format(this.dateFormatReturn));
}
validateVuetify(): void {
this.$nextTick(() => {
// Set hasFocused to true on VTextField
// to fix https://github.com/vuetifyjs/vuetify/issues/7876
// (error messages aren't shown if the input hasn't been focused)
if (this.$refs.input.hasFocused !== undefined) {
this.$refs.input.hasFocused = true;
}
this.$refs.input.validate();
});
}
textFieldBlur(): void {
this.saveFromTextField();
if (this.validateOnBlurEnabled) {
this.validate(this.textFieldDate);
}
}
}