Skip to content

Commit

Permalink
refactor: remove moment, add luxon
Browse files Browse the repository at this point in the history
* Refactors the date validator.

Co-Authored-by: Bertrand Zuchuat <[email protected]>
  • Loading branch information
Garfield-fr committed Oct 10, 2024
1 parent 3b5b8ed commit fea1bf4
Show file tree
Hide file tree
Showing 10 changed files with 265 additions and 88 deletions.
18 changes: 9 additions & 9 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
"@angular/platform-browser": "^17.1.0",
"@angular/platform-browser-dynamic": "^17.1.0",
"@angular/router": "^17.1.0",
"@biesbjerg/ngx-translate-extract-marker": "^1.0.0",
"@ngx-formly/core": "^6.3.6",
"@ngx-formly/primeng": "^6.3.6",
"@ngx-translate/core": "^15.0.0",
Expand All @@ -35,8 +34,8 @@
"font-awesome": "^4.7.0",
"js-generate-password": "^0.1.0",
"lodash-es": "^4.17.21",
"luxon": "^3.5.0",
"marked": "^10.0.0",
"moment": "^2.30.1",
"ngx-spinner": "^16.0.2",
"primeflex": "^3.3.1",
"primeicons": "^7.0.0",
Expand All @@ -56,6 +55,7 @@
"@angular/cli": "^17.1.0",
"@angular/compiler-cli": "^17.1.0",
"@angular/language-service": "^17.1.0",
"@biesbjerg/ngx-translate-extract-marker": "^1.0.0",
"@ngx-formly/schematics": "^6.3.6",
"@types/jasmine": "^5.1.4",
"@typescript-eslint/eslint-plugin": "^6.19.1",
Expand Down
68 changes: 8 additions & 60 deletions projects/rero/ng-core/src/lib/record/editor/extensions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ import { UntypedFormControl } from '@angular/forms';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { FormlyExtension, FormlyFieldConfig } from '@ngx-formly/core';
import { TranslateService } from '@ngx-translate/core';
import moment from 'moment';
import { isObservable, of } from 'rxjs';
import { map } from 'rxjs/operators';
import { RecordService } from '../record.service';
import { isEmpty, removeEmptyValues } from './utils';
import { Validators } from '../../validator/validators';

export class NgCoreFormlyExtension {

Expand Down Expand Up @@ -326,68 +326,16 @@ export class NgCoreFormlyExtension {
};
}
// The start date must be less than the end date.
if (customValidators.dateMustBeLessThan) {
const startDate: string = customValidators.dateMustBeLessThan.startDate;
const endDate: string = customValidators.dateMustBeLessThan.endDate;
const strict: boolean = customValidators.dateMustBeLessThan.strict || false;
const updateOn: 'change' | 'blur' | 'submit' = customValidators.dateMustBeLessThan.strict || 'blur';
if (customValidators.dateGreaterThan) {
const dateFirst: string = customValidators.dateGreaterThan.dateFirst;
const dateLast: string = customValidators.dateGreaterThan.dateLast;
const strict: boolean = customValidators.dateGreaterThan.strict || false;
const updateOn: 'change' | 'blur' | 'submit' = customValidators.dateGreaterThan.strict || 'blur';
field.validators = {
dateMustBeLessThan: {
dateGreaterThan: {
updateOn,
expression: (control: UntypedFormControl) => {
const startDateFc = control.parent.get(startDate);
const endDateFc = control.parent.get(endDate);
if (startDateFc.value !== null && endDateFc.value !== null) {
const dateStart = moment(startDateFc.value, 'YYYY-MM-DD');
const dateEnd = moment(endDateFc.value, 'YYYY-MM-DD');
const isMustLessThan = strict
? dateStart >= dateEnd
? false
: true
: dateStart > dateEnd
? false
: true;
if (isMustLessThan) {
endDateFc.setErrors(null);
endDateFc.markAsDirty();
}
return isMustLessThan;
}
return false;
},
},
};
}

// The end date must be greater than the start date.
if (customValidators.dateMustBeGreaterThan) {
const startDate: string = customValidators.dateMustBeGreaterThan.startDate;
const endDate: string = customValidators.dateMustBeGreaterThan.endDate;
const strict: boolean = customValidators.dateMustBeGreaterThan.strict || false;
const updateOn: 'change' | 'blur' | 'submit' = customValidators.dateMustBeGreaterThan.strict || 'blur';
field.validators = {
datesMustBeGreaterThan: {
updateOn,
expression: (control: UntypedFormControl) => {
const startDateFc = control.parent.get(startDate);
const endDateFc = control.parent.get(endDate);
if (startDateFc.value !== null && endDateFc.value !== null) {
const dateStart = moment(startDateFc.value, 'YYYY-MM-DD');
const dateEnd = moment(endDateFc.value, 'YYYY-MM-DD');
const isMustBeGreaterThan = strict
? dateStart <= dateEnd
? true
: false
: dateStart < dateEnd
? true
: false;
if (isMustBeGreaterThan) {
startDateFc.setErrors(null);
startDateFc.markAsDirty();
}
return isMustBeGreaterThan;
}
return false;
return Validators.dateGreaterThan(dateFirst, dateLast, strict)(control)
},
},
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { TestBed } from "@angular/core/testing";
import { NgCoreTranslateService } from "./translate-service";
import { PrimeNGConfig } from "primeng/api";
import { TranslateModule } from "@ngx-translate/core";
import moment from "moment";
import { DateTime } from "luxon";
import { PrimeNGConfig } from "primeng/api";
import { NgCoreTranslateService } from "./translate-service";

describe('NgCoreTranslateService', () => {
let service: NgCoreTranslateService;
Expand Down Expand Up @@ -46,6 +46,6 @@ describe('NgCoreTranslateService', () => {
it('should have changed the local service', () => {
service.use('fr');
expect(primeConfig.translation.today).toEqual("Aujourd'hui");
expect(moment().locale()).toEqual('fr');
expect(DateTime.locale).toEqual('fr');
});
});
6 changes: 3 additions & 3 deletions projects/rero/ng-core/src/lib/translate/translate-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,21 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { registerLocaleData } from '@angular/common';
import localeDe from '@angular/common/locales/de';
import localeEn from '@angular/common/locales/en-GB';
import localeFr from '@angular/common/locales/fr';
import localeIt from '@angular/common/locales/it';
import { inject, Injectable } from "@angular/core";
import { TranslateService } from "@ngx-translate/core";
import moment from "moment";
import { DateTime } from "luxon";
import de from 'primelocale/de.json';
import en from 'primelocale/en.json';
import fr from 'primelocale/fr.json';
import it from 'primelocale/it.json';
import { PrimeNGConfig } from "primeng/api";
import { Observable } from "rxjs";
import { CoreConfigService } from "../core-config.service";
import { registerLocaleData } from '@angular/common';

@Injectable({
providedIn: 'root'
Expand Down Expand Up @@ -62,7 +62,7 @@ export class NgCoreTranslateService extends TranslateService {
}

use(lang: string): Observable<any> {
moment.locale(lang);
DateTime.locale = lang;
this.primengConfig.setTranslation(this.locales[lang].primeng[lang]);

return super.use(lang);
Expand Down
104 changes: 104 additions & 0 deletions projects/rero/ng-core/src/lib/validator/time.validator.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/*
* RERO angular core
* Copyright (C) 2024 RERO
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { TestBed } from '@angular/core/testing';
import { TimeValidator } from './time.validator';
import { FormBuilder, FormControl, FormsModule } from '@angular/forms';

describe('TimeValidator', () => {
let formBuilder: FormBuilder;

beforeEach(() => {
TestBed.configureTestingModule({
imports: [
FormsModule
],
providers: [
FormBuilder
]
});
formBuilder = TestBed.inject(FormBuilder);
});

it('should return the value of the validator greaterThanValidator', () => {
let formGroup = formBuilder.group({
start_time: new FormControl('07:00'),
end_time: new FormControl('08:00')
});
let result = TimeValidator.greaterThanValidator('start_time', 'end_time')(formGroup);
expect(result).toBeNull();

formGroup = formBuilder.group({
start_time: new FormControl('12:00'),
end_time: new FormControl('08:00')
});
result = TimeValidator.greaterThanValidator('start_time', 'end_time')(formGroup);
expect(result).toEqual({ lessThan: { value: true }});
});

it('should return the value of the validator RangePeriodValidator', () => {
const formGroup = formBuilder.group({
'times': formBuilder.array([
formBuilder.group({
start_time: new FormControl('08:00'),
end_time: new FormControl('11:00')
}),
formBuilder.group({
start_time: new FormControl('13:00'),
end_time: new FormControl('17:00')
}),
]),
'day': ['monday'],
'is_open': true
});
let result = TimeValidator.RangePeriodValidator()(formGroup);
expect(result).toBeNull();

const formGroup2 = formBuilder.group({
'times': formBuilder.array([
formBuilder.group({
start_time: new FormControl('08:00'),
end_time: new FormControl('11:00')
}),
formBuilder.group({
start_time: new FormControl('10:00'),
end_time: new FormControl('12:00')
}),
]),
'day': ['monday'],
'is_open': true
});
result = TimeValidator.RangePeriodValidator()(formGroup2);
expect(result).toEqual({ rangeLessThan: { value: true }});

const formGroup3 = formBuilder.group({
'times': formBuilder.array([
formBuilder.group({
start_time: new FormControl('14:00'),
end_time: new FormControl('16:00')
}),
formBuilder.group({
start_time: new FormControl('13:00'),
end_time: new FormControl('15:00')
}),
]),
'day': ['monday'],
'is_open': true
});
result = TimeValidator.RangePeriodValidator()(formGroup3);
expect(result).toEqual({ rangeLessThan: { value: true }});
});
});
22 changes: 12 additions & 10 deletions projects/rero/ng-core/src/lib/validator/time.validator.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* RERO angular core
* Copyright (C) 2020 RERO
* Copyright (C) 2020-2024 RERO
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
Expand All @@ -15,11 +15,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import {AbstractControl, UntypedFormArray, ValidationErrors, ValidatorFn} from '@angular/forms';
import moment from 'moment';
import { DateTime } from "luxon";

// @dynamic
export class TimeValidator {

static readonly FORMAT = 'hh:mm';

/**
* Allow to control if time interval limits are well formed : the end limit should be 'older' the start limit
* @param start: the field name where to find the start limit value
Expand All @@ -31,9 +33,9 @@ export class TimeValidator {
let isLessThan = false;
const startTime = control.get(start);
const endTime = control.get(end);
const startDate = moment(startTime.value, 'HH:mm');
const endDate = moment(endTime.value, 'HH:mm');
if (startDate.format('HH:mm') !== '00:00' || endDate.format('HH:mm') !== '00:00') {
const startDate = DateTime.fromFormat(startTime.value, TimeValidator.FORMAT);
const endDate = DateTime.fromFormat(endTime.value, TimeValidator.FORMAT);
if (startDate.toFormat(TimeValidator.FORMAT) !== '00:00' || endDate.toFormat(TimeValidator.FORMAT) !== '00:00') {
isLessThan = startDate.diff(endDate) >= 0;
}
return (isLessThan)
Expand All @@ -49,10 +51,10 @@ export class TimeValidator {
let isRangeLessThan = false;
const times = control.get('times') as UntypedFormArray;
if (control.get('is_open').value && times.value.length > 1) {
const firstStartDate = moment(times.at(0).get('start_time').value, 'HH:mm');
const firstEndDate = moment(times.at(0).get('end_time').value, 'HH:mm');
const lastStartDate = moment(times.at(1).get('start_time').value, 'HH:mm');
const lastEndDate = moment(times.at(1).get('end_time').value, 'HH:mm');
const firstStartDate = DateTime.fromFormat(times.at(0).get('start_time').value, TimeValidator.FORMAT);
const firstEndDate = DateTime.fromFormat(times.at(0).get('end_time').value, TimeValidator.FORMAT);
const lastStartDate = DateTime.fromFormat(times.at(1).get('start_time').value, TimeValidator.FORMAT);
const lastEndDate = DateTime.fromFormat(times.at(1).get('end_time').value, TimeValidator.FORMAT);
if (firstStartDate > lastStartDate) {
isRangeLessThan = firstStartDate.diff(lastStartDate) <= 0
|| firstStartDate.diff(lastEndDate) <= 0;
Expand All @@ -62,7 +64,7 @@ export class TimeValidator {
}
}
return (isRangeLessThan)
? ({ rangeLessThan: { value: isRangeLessThan}})
? ({ rangeLessThan: { value: isRangeLessThan }})
: null;
}
};
Expand Down
Loading

0 comments on commit fea1bf4

Please sign in to comment.