UNPKG

@cnamts/vue-dot

Version:

Implementation of our Design System for the French Health Insurance

246 lines (190 loc) 5.24 kB
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); @Component<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); } } }