diff --git a/package-lock.json b/package-lock.json
index 3f2b9e07..e7d7f037 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -29,8 +29,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",
@@ -10858,6 +10858,14 @@
"yallist": "^3.0.2"
}
},
+ "node_modules/luxon": {
+ "version": "3.5.0",
+ "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.5.0.tgz",
+ "integrity": "sha512-rh+Zjr6DNfUYR3bPwJEnuwDdqMbxZW7LOQfUN4B54+Cl+0o5zaU9RJ6bcidfDtC1cWCZXQ+nvX8bf6bAji37QQ==",
+ "engines": {
+ "node": ">=12"
+ }
+ },
"node_modules/magic-string": {
"version": "0.30.8",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.8.tgz",
@@ -11304,14 +11312,6 @@
"mkdirp": "bin/cmd.js"
}
},
- "node_modules/moment": {
- "version": "2.30.1",
- "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz",
- "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==",
- "engines": {
- "node": "*"
- }
- },
"node_modules/mrmime": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz",
diff --git a/package.json b/package.json
index 7fe59051..f005ffa7 100644
--- a/package.json
+++ b/package.json
@@ -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",
@@ -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",
@@ -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",
diff --git a/projects/rero/ng-core/src/lib/record/editor/extensions.ts b/projects/rero/ng-core/src/lib/record/editor/extensions.ts
index 0356a24b..3b913dde 100644
--- a/projects/rero/ng-core/src/lib/record/editor/extensions.ts
+++ b/projects/rero/ng-core/src/lib/record/editor/extensions.ts
@@ -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 {
@@ -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)
},
},
};
diff --git a/projects/rero/ng-core/src/lib/translate/translate-service.spec.ts b/projects/rero/ng-core/src/lib/translate/translate-service.spec.ts
index 5eab7f71..f2fdfa77 100644
--- a/projects/rero/ng-core/src/lib/translate/translate-service.spec.ts
+++ b/projects/rero/ng-core/src/lib/translate/translate-service.spec.ts
@@ -15,10 +15,10 @@
* along with this program. If not, see .
*/
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;
@@ -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');
});
});
diff --git a/projects/rero/ng-core/src/lib/translate/translate-service.ts b/projects/rero/ng-core/src/lib/translate/translate-service.ts
index 77221202..853c26df 100644
--- a/projects/rero/ng-core/src/lib/translate/translate-service.ts
+++ b/projects/rero/ng-core/src/lib/translate/translate-service.ts
@@ -14,13 +14,14 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
+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';
@@ -28,7 +29,6 @@ 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'
@@ -62,7 +62,7 @@ export class NgCoreTranslateService extends TranslateService {
}
use(lang: string): Observable {
- moment.locale(lang);
+ DateTime.locale = lang;
this.primengConfig.setTranslation(this.locales[lang].primeng[lang]);
return super.use(lang);
diff --git a/projects/rero/ng-core/src/lib/validator/time.validator.spec.ts b/projects/rero/ng-core/src/lib/validator/time.validator.spec.ts
new file mode 100644
index 00000000..81f230d2
--- /dev/null
+++ b/projects/rero/ng-core/src/lib/validator/time.validator.spec.ts
@@ -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 .
+ */
+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 }});
+ });
+});
diff --git a/projects/rero/ng-core/src/lib/validator/time.validator.ts b/projects/rero/ng-core/src/lib/validator/time.validator.ts
index 9510c7a3..ab1f2952 100644
--- a/projects/rero/ng-core/src/lib/validator/time.validator.ts
+++ b/projects/rero/ng-core/src/lib/validator/time.validator.ts
@@ -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
@@ -15,11 +15,13 @@
* along with this program. If not, see .
*/
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
@@ -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)
@@ -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;
@@ -62,7 +64,7 @@ export class TimeValidator {
}
}
return (isRangeLessThan)
- ? ({ rangeLessThan: { value: isRangeLessThan}})
+ ? ({ rangeLessThan: { value: isRangeLessThan }})
: null;
}
};
diff --git a/projects/rero/ng-core/src/lib/validator/validators.spec.ts b/projects/rero/ng-core/src/lib/validator/validators.spec.ts
new file mode 100644
index 00000000..f54cf339
--- /dev/null
+++ b/projects/rero/ng-core/src/lib/validator/validators.spec.ts
@@ -0,0 +1,76 @@
+/*
+ * 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 .
+ */
+import { TestBed } from '@angular/core/testing';
+import { FormBuilder, FormControl, FormsModule } from '@angular/forms';
+import { Validators } from './validators';
+
+describe('Validators', () => {
+ let formBuilder: FormBuilder;
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ imports: [
+ FormsModule
+ ],
+ providers: [
+ FormBuilder
+ ]
+ });
+
+ formBuilder = TestBed.inject(FormBuilder);
+ });
+
+ it('should return the value of the validator dateGreaterThan', () => {
+ const validatorResponse = { dateGreaterThan: { value: true }};
+ let formControl = new FormControl();
+ let formGroup = formBuilder.group({
+ start_date: new FormControl('2024-10-01'),
+ end_date: new FormControl('2024-10-02')
+ });
+ formControl.setParent(formGroup);
+ let result = Validators.dateGreaterThan('start_date', 'end_date')(formControl);
+ expect(result).toBeNull();
+
+ formControl = new FormControl();
+ formGroup = formBuilder.group({
+ start_date: new FormControl('2024-10-11'),
+ end_date: new FormControl('2024-10-11')
+ });
+ formControl.setParent(formGroup);
+ result = Validators.dateGreaterThan('start_date', 'end_date')(formControl);
+ expect(result).toBeNull();
+
+ formControl = new FormControl();
+ formGroup = formBuilder.group({
+ start_date: new FormControl('2024-10-11'),
+ end_date: new FormControl('2024-10-11')
+ });
+ formControl.setParent(formGroup);
+ // With strict mode
+ result = Validators.dateGreaterThan('start_date', 'end_date', true)(formControl);
+ expect(result).toEqual(validatorResponse);
+
+ formControl = new FormControl();
+ formGroup = formBuilder.group({
+ start_date: new FormControl('2024-10-11'),
+ end_date: new FormControl('2024-10-01')
+ });
+ formControl.setParent(formGroup);
+ result = Validators.dateGreaterThan('start_date', 'end_date')(formControl);
+ expect(result).toEqual(validatorResponse);
+ });
+});
diff --git a/projects/rero/ng-core/src/lib/validator/validators.ts b/projects/rero/ng-core/src/lib/validator/validators.ts
new file mode 100644
index 00000000..4ca44647
--- /dev/null
+++ b/projects/rero/ng-core/src/lib/validator/validators.ts
@@ -0,0 +1,46 @@
+/*
+ * 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 .
+ */
+import { AbstractControl, ValidationErrors, ValidatorFn } from "@angular/forms";
+import { DateTime } from "luxon";
+
+export class Validators {
+ static dateGreaterThan(dateFirstName: string, dateLastName: string, strictMode: boolean = false): ValidatorFn {
+ return dateGreaterThanValidator(dateFirstName, dateLastName, strictMode);
+ }
+}
+
+export function dateGreaterThanValidator(dateFirstName: string, dateLastName: string, strict: boolean): ValidatorFn {
+ return (control: AbstractControl): ValidationErrors | null => {
+ const dateFormat = 'yyyy-MM-dd';
+ const dateFirst = control.parent.get(dateFirstName);
+ const dateLast = control.parent.get(dateLastName);
+ if (dateFirst.value !== null && dateLast.value !== null) {
+ const dateTimeFirst = DateTime.fromFormat(dateFirst.value, dateFormat);
+ const dateTimeLast = DateTime.fromFormat(dateLast.value, dateFormat);
+ const status = strict ? dateTimeFirst >= dateTimeLast : dateTimeFirst > dateTimeLast;
+
+ if (status) {
+ dateLast.setErrors(null);
+ dateLast.markAsDirty();
+ }
+
+ return status ? { dateGreaterThan: { value: true }} : null;
+ }
+
+ return null;
+ }
+}
diff --git a/projects/rero/ng-core/src/public-api.ts b/projects/rero/ng-core/src/public-api.ts
index 8d30a731..a372cd32 100644
--- a/projects/rero/ng-core/src/public-api.ts
+++ b/projects/rero/ng-core/src/public-api.ts
@@ -90,6 +90,7 @@ export * from './lib/utils/sort-by-keys';
export * from './lib/utils/utils';
export * from './lib/validator/time.validator';
export * from './lib/validator/unique.validator';
+export * from './lib/validator/validators';
export * from './lib/widget/menu/menu.component';
export * from './lib/widget/sort-list/sort-list.component';
@@ -101,3 +102,5 @@ export * from './lib/record/editor/formly/primeng/multi-select/multi-select';
export * from './lib/record/editor/formly/primeng/remote-autocomplete/remote-autocomplete';
export * from './lib/record/editor/formly/primeng/select/select';
export * from './lib/record/editor/formly/primeng/tree-select/tree-select';
+
+export * from './lib/validator/validators';