@masterteam/system-settings 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1053 @@
1
+ import { CommonModule } from '@angular/common';
2
+ import { HttpClient } from '@angular/common/http';
3
+ import * as i0 from '@angular/core';
4
+ import { input, ChangeDetectionStrategy, Component, inject, computed, effect, output, signal } from '@angular/core';
5
+ import { toSignal } from '@angular/core/rxjs-interop';
6
+ import * as i1 from '@angular/forms';
7
+ import { ReactiveFormsModule, FormGroup, FormControl, Validators } from '@angular/forms';
8
+ import { Router } from '@angular/router';
9
+ import { TranslocoDirective, TranslocoService } from '@jsverse/transloco';
10
+ import { Button } from '@masterteam/components/button';
11
+ import { Page } from '@masterteam/components/page';
12
+ import { ModalService } from '@masterteam/components/modal';
13
+ import { ToastService } from '@masterteam/components/toast';
14
+ import { Card } from '@masterteam/components/card';
15
+ import { MultiSelectField } from '@masterteam/components/multi-select-field';
16
+ import { SelectField } from '@masterteam/components/select-field';
17
+ import { ModalRef } from '@masterteam/components/dialog';
18
+ import { DateField } from '@masterteam/components/date-field';
19
+ import { TextField } from '@masterteam/components/text-field';
20
+ import { Table } from '@masterteam/components/table';
21
+
22
+ class SystemSettingsGeneralSection {
23
+ timezoneForm = input.required(...(ngDevMode ? [{ debugName: "timezoneForm" }] : /* istanbul ignore next */ []));
24
+ currencyForm = input.required(...(ngDevMode ? [{ debugName: "currencyForm" }] : /* istanbul ignore next */ []));
25
+ weekendForm = input.required(...(ngDevMode ? [{ debugName: "weekendForm" }] : /* istanbul ignore next */ []));
26
+ timezoneOptions = input([], ...(ngDevMode ? [{ debugName: "timezoneOptions" }] : /* istanbul ignore next */ []));
27
+ dateFormatOptions = input([], ...(ngDevMode ? [{ debugName: "dateFormatOptions" }] : /* istanbul ignore next */ []));
28
+ timeFormatOptions = input([], ...(ngDevMode ? [{ debugName: "timeFormatOptions" }] : /* istanbul ignore next */ []));
29
+ currencyOptions = input([], ...(ngDevMode ? [{ debugName: "currencyOptions" }] : /* istanbul ignore next */ []));
30
+ currencyFormatOptions = input([], ...(ngDevMode ? [{ debugName: "currencyFormatOptions" }] : /* istanbul ignore next */ []));
31
+ weekendOptions = input([], ...(ngDevMode ? [{ debugName: "weekendOptions" }] : /* istanbul ignore next */ []));
32
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: SystemSettingsGeneralSection, deps: [], target: i0.ɵɵFactoryTarget.Component });
33
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.8", type: SystemSettingsGeneralSection, isStandalone: true, selector: "mt-system-settings-general-section", inputs: { timezoneForm: { classPropertyName: "timezoneForm", publicName: "timezoneForm", isSignal: true, isRequired: true, transformFunction: null }, currencyForm: { classPropertyName: "currencyForm", publicName: "currencyForm", isSignal: true, isRequired: true, transformFunction: null }, weekendForm: { classPropertyName: "weekendForm", publicName: "weekendForm", isSignal: true, isRequired: true, transformFunction: null }, timezoneOptions: { classPropertyName: "timezoneOptions", publicName: "timezoneOptions", isSignal: true, isRequired: false, transformFunction: null }, dateFormatOptions: { classPropertyName: "dateFormatOptions", publicName: "dateFormatOptions", isSignal: true, isRequired: false, transformFunction: null }, timeFormatOptions: { classPropertyName: "timeFormatOptions", publicName: "timeFormatOptions", isSignal: true, isRequired: false, transformFunction: null }, currencyOptions: { classPropertyName: "currencyOptions", publicName: "currencyOptions", isSignal: true, isRequired: false, transformFunction: null }, currencyFormatOptions: { classPropertyName: "currencyFormatOptions", publicName: "currencyFormatOptions", isSignal: true, isRequired: false, transformFunction: null }, weekendOptions: { classPropertyName: "weekendOptions", publicName: "weekendOptions", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'system-settings'\">\r\n <div class=\"grid gap-6 xl:grid-cols-3\">\r\n <mt-card class=\"block\">\r\n <div [formGroup]=\"timezoneForm()\" class=\"space-y-4\">\r\n <div class=\"space-y-1\">\r\n <h4 class=\"text-base font-semibold text-neutral-900\">\r\n {{ t(\"timezone-title\") }}\r\n </h4>\r\n <p class=\"text-sm text-neutral-600\">\r\n {{ t(\"timezone-description\") }}\r\n </p>\r\n </div>\r\n\r\n <mt-select-field\r\n formControlName=\"regionId\"\r\n [options]=\"timezoneOptions()\"\r\n [optionLabel]=\"'name'\"\r\n [optionValue]=\"'id'\"\r\n [label]=\"t('timezone')\"\r\n [placeholder]=\"t('timezone-placeholder')\"\r\n [required]=\"true\"\r\n [filter]=\"true\"\r\n />\r\n\r\n <div class=\"grid gap-4 md:grid-cols-2\">\r\n <mt-select-field\r\n formControlName=\"dateFormat\"\r\n [options]=\"dateFormatOptions()\"\r\n [optionLabel]=\"'name'\"\r\n [optionValue]=\"'id'\"\r\n [label]=\"t('date-format')\"\r\n [placeholder]=\"t('date-format-placeholder')\"\r\n [required]=\"true\"\r\n />\r\n\r\n <mt-select-field\r\n formControlName=\"timeFormat\"\r\n [options]=\"timeFormatOptions()\"\r\n [optionLabel]=\"'name'\"\r\n [optionValue]=\"'id'\"\r\n [label]=\"t('time-format')\"\r\n [placeholder]=\"t('time-format-placeholder')\"\r\n [required]=\"true\"\r\n />\r\n </div>\r\n </div>\r\n </mt-card>\r\n\r\n <mt-card class=\"block\">\r\n <div [formGroup]=\"currencyForm()\" class=\"space-y-4\">\r\n <div class=\"space-y-1\">\r\n <h4 class=\"text-base font-semibold text-neutral-900\">\r\n {{ t(\"currency-title\") }}\r\n </h4>\r\n <p class=\"text-sm text-neutral-600\">\r\n {{ t(\"currency-description\") }}\r\n </p>\r\n </div>\r\n\r\n <mt-select-field\r\n formControlName=\"code\"\r\n [options]=\"currencyOptions()\"\r\n [optionLabel]=\"'name'\"\r\n [optionValue]=\"'id'\"\r\n [label]=\"t('currency')\"\r\n [placeholder]=\"t('currency-placeholder')\"\r\n [required]=\"true\"\r\n />\r\n\r\n <mt-select-field\r\n formControlName=\"format\"\r\n [options]=\"currencyFormatOptions()\"\r\n [optionLabel]=\"'name'\"\r\n [optionValue]=\"'id'\"\r\n [label]=\"t('currency-format')\"\r\n [placeholder]=\"t('currency-format-placeholder')\"\r\n [required]=\"true\"\r\n />\r\n </div>\r\n </mt-card>\r\n\r\n <mt-card class=\"block\">\r\n <div [formGroup]=\"weekendForm()\" class=\"space-y-4\">\r\n <div class=\"space-y-1\">\r\n <h4 class=\"text-base font-semibold text-neutral-900\">\r\n {{ t(\"weekend-title\") }}\r\n </h4>\r\n <p class=\"text-sm text-neutral-600\">\r\n {{ t(\"weekend-description\") }}\r\n </p>\r\n </div>\r\n\r\n <mt-multi-select-field\r\n formControlName=\"days\"\r\n [options]=\"weekendOptions()\"\r\n [optionLabel]=\"'name'\"\r\n [optionValue]=\"'dayNumber'\"\r\n [label]=\"t('weekend-days')\"\r\n [placeholder]=\"t('weekend-placeholder')\"\r\n [display]=\"'chip'\"\r\n [filter]=\"false\"\r\n [showClear]=\"true\"\r\n [maxSelectedLabels]=\"3\"\r\n />\r\n </div>\r\n </mt-card>\r\n </div>\r\n</ng-container>\r\n", styles: [":host{display:block}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: Card, selector: "mt-card", inputs: ["class", "title", "paddingless"] }, { kind: "component", type: SelectField, selector: "mt-select-field", inputs: ["field", "label", "placeholder", "hasPlaceholderPrefix", "class", "readonly", "pInputs", "options", "optionValue", "optionLabel", "filter", "filterBy", "dataKey", "showClear", "clearAfterSelect", "required", "group", "size", "optionGroupLabel", "optionGroupChildren", "loading", "optionIcon", "optionIconColor", "optionIconShape", "optionAvatarShape", "optionGroupIcon", "optionGroupIconColor", "optionGroupIconShape", "optionGroupAvatarShape"], outputs: ["onChange"] }, { kind: "component", type: MultiSelectField, selector: "mt-multi-select-field", inputs: ["field", "label", "placeholder", "class", "readonly", "pInputs", "options", "optionValue", "optionLabel", "filter", "filterBy", "dataKey", "showClear", "display", "required", "maxSelectedLabels", "group", "optionGroupLabel", "optionGroupChildren", "optionIcon", "optionIconColor", "optionIconShape", "optionAvatarShape", "optionGroupIcon", "optionGroupIconColor", "optionGroupIconShape", "optionGroupAvatarShape"], outputs: ["onChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
34
+ }
35
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: SystemSettingsGeneralSection, decorators: [{
36
+ type: Component,
37
+ args: [{ selector: 'mt-system-settings-general-section', imports: [
38
+ ReactiveFormsModule,
39
+ TranslocoDirective,
40
+ Card,
41
+ SelectField,
42
+ MultiSelectField,
43
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *transloco=\"let t; prefix: 'system-settings'\">\r\n <div class=\"grid gap-6 xl:grid-cols-3\">\r\n <mt-card class=\"block\">\r\n <div [formGroup]=\"timezoneForm()\" class=\"space-y-4\">\r\n <div class=\"space-y-1\">\r\n <h4 class=\"text-base font-semibold text-neutral-900\">\r\n {{ t(\"timezone-title\") }}\r\n </h4>\r\n <p class=\"text-sm text-neutral-600\">\r\n {{ t(\"timezone-description\") }}\r\n </p>\r\n </div>\r\n\r\n <mt-select-field\r\n formControlName=\"regionId\"\r\n [options]=\"timezoneOptions()\"\r\n [optionLabel]=\"'name'\"\r\n [optionValue]=\"'id'\"\r\n [label]=\"t('timezone')\"\r\n [placeholder]=\"t('timezone-placeholder')\"\r\n [required]=\"true\"\r\n [filter]=\"true\"\r\n />\r\n\r\n <div class=\"grid gap-4 md:grid-cols-2\">\r\n <mt-select-field\r\n formControlName=\"dateFormat\"\r\n [options]=\"dateFormatOptions()\"\r\n [optionLabel]=\"'name'\"\r\n [optionValue]=\"'id'\"\r\n [label]=\"t('date-format')\"\r\n [placeholder]=\"t('date-format-placeholder')\"\r\n [required]=\"true\"\r\n />\r\n\r\n <mt-select-field\r\n formControlName=\"timeFormat\"\r\n [options]=\"timeFormatOptions()\"\r\n [optionLabel]=\"'name'\"\r\n [optionValue]=\"'id'\"\r\n [label]=\"t('time-format')\"\r\n [placeholder]=\"t('time-format-placeholder')\"\r\n [required]=\"true\"\r\n />\r\n </div>\r\n </div>\r\n </mt-card>\r\n\r\n <mt-card class=\"block\">\r\n <div [formGroup]=\"currencyForm()\" class=\"space-y-4\">\r\n <div class=\"space-y-1\">\r\n <h4 class=\"text-base font-semibold text-neutral-900\">\r\n {{ t(\"currency-title\") }}\r\n </h4>\r\n <p class=\"text-sm text-neutral-600\">\r\n {{ t(\"currency-description\") }}\r\n </p>\r\n </div>\r\n\r\n <mt-select-field\r\n formControlName=\"code\"\r\n [options]=\"currencyOptions()\"\r\n [optionLabel]=\"'name'\"\r\n [optionValue]=\"'id'\"\r\n [label]=\"t('currency')\"\r\n [placeholder]=\"t('currency-placeholder')\"\r\n [required]=\"true\"\r\n />\r\n\r\n <mt-select-field\r\n formControlName=\"format\"\r\n [options]=\"currencyFormatOptions()\"\r\n [optionLabel]=\"'name'\"\r\n [optionValue]=\"'id'\"\r\n [label]=\"t('currency-format')\"\r\n [placeholder]=\"t('currency-format-placeholder')\"\r\n [required]=\"true\"\r\n />\r\n </div>\r\n </mt-card>\r\n\r\n <mt-card class=\"block\">\r\n <div [formGroup]=\"weekendForm()\" class=\"space-y-4\">\r\n <div class=\"space-y-1\">\r\n <h4 class=\"text-base font-semibold text-neutral-900\">\r\n {{ t(\"weekend-title\") }}\r\n </h4>\r\n <p class=\"text-sm text-neutral-600\">\r\n {{ t(\"weekend-description\") }}\r\n </p>\r\n </div>\r\n\r\n <mt-multi-select-field\r\n formControlName=\"days\"\r\n [options]=\"weekendOptions()\"\r\n [optionLabel]=\"'name'\"\r\n [optionValue]=\"'dayNumber'\"\r\n [label]=\"t('weekend-days')\"\r\n [placeholder]=\"t('weekend-placeholder')\"\r\n [display]=\"'chip'\"\r\n [filter]=\"false\"\r\n [showClear]=\"true\"\r\n [maxSelectedLabels]=\"3\"\r\n />\r\n </div>\r\n </mt-card>\r\n </div>\r\n</ng-container>\r\n", styles: [":host{display:block}\n"] }]
44
+ }], propDecorators: { timezoneForm: [{ type: i0.Input, args: [{ isSignal: true, alias: "timezoneForm", required: true }] }], currencyForm: [{ type: i0.Input, args: [{ isSignal: true, alias: "currencyForm", required: true }] }], weekendForm: [{ type: i0.Input, args: [{ isSignal: true, alias: "weekendForm", required: true }] }], timezoneOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "timezoneOptions", required: false }] }], dateFormatOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateFormatOptions", required: false }] }], timeFormatOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "timeFormatOptions", required: false }] }], currencyOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "currencyOptions", required: false }] }], currencyFormatOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "currencyFormatOptions", required: false }] }], weekendOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "weekendOptions", required: false }] }] } });
45
+
46
+ class SystemSettingsHolidayEditor {
47
+ ref = inject(ModalRef);
48
+ holiday = input(null, ...(ngDevMode ? [{ debugName: "holiday" }] : /* istanbul ignore next */ []));
49
+ isEditMode = input(false, ...(ngDevMode ? [{ debugName: "isEditMode" }] : /* istanbul ignore next */ []));
50
+ form = new FormGroup({
51
+ label: new FormControl('', {
52
+ nonNullable: true,
53
+ validators: [Validators.required],
54
+ }),
55
+ from: new FormControl(null, {
56
+ validators: [Validators.required],
57
+ }),
58
+ to: new FormControl(null, {
59
+ validators: [Validators.required],
60
+ }),
61
+ }, {
62
+ validators: [holidayRangeValidator()],
63
+ });
64
+ actionLabel = computed(() => this.isEditMode() ? 'update-holiday' : 'add-holiday', ...(ngDevMode ? [{ debugName: "actionLabel" }] : /* istanbul ignore next */ []));
65
+ constructor() {
66
+ effect(() => {
67
+ const holiday = this.holiday();
68
+ this.form.reset({
69
+ label: holiday?.label ?? '',
70
+ from: holiday?.from ?? null,
71
+ to: holiday?.to ?? null,
72
+ }, { emitEvent: false });
73
+ this.form.markAsPristine();
74
+ this.form.markAsUntouched();
75
+ });
76
+ }
77
+ onSave() {
78
+ this.form.markAllAsTouched();
79
+ if (this.form.invalid) {
80
+ return;
81
+ }
82
+ const value = this.form.getRawValue();
83
+ if (!(value.from instanceof Date) || !(value.to instanceof Date)) {
84
+ return;
85
+ }
86
+ this.ref.close({
87
+ label: value.label.trim(),
88
+ from: value.from,
89
+ to: value.to,
90
+ });
91
+ }
92
+ onCancel() {
93
+ this.ref.close(null);
94
+ }
95
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: SystemSettingsHolidayEditor, deps: [], target: i0.ɵɵFactoryTarget.Component });
96
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: SystemSettingsHolidayEditor, isStandalone: true, selector: "mt-system-settings-holiday-editor", inputs: { holiday: { classPropertyName: "holiday", publicName: "holiday", isSignal: true, isRequired: false, transformFunction: null }, isEditMode: { classPropertyName: "isEditMode", publicName: "isEditMode", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'system-settings'\">\r\n <form [formGroup]=\"form\" class=\"space-y-4 p-1\" (ngSubmit)=\"onSave()\">\r\n <mt-text-field\r\n formControlName=\"label\"\r\n [label]=\"t('holiday-name')\"\r\n [placeholder]=\"t('holiday-name-placeholder')\"\r\n [required]=\"true\"\r\n />\r\n\r\n <div class=\"grid gap-4 md:grid-cols-2\">\r\n <mt-date-field\r\n formControlName=\"from\"\r\n [label]=\"t('from-date')\"\r\n [placeholder]=\"t('from-date')\"\r\n [showIcon]=\"true\"\r\n [required]=\"true\"\r\n />\r\n\r\n <mt-date-field\r\n formControlName=\"to\"\r\n [label]=\"t('to-date')\"\r\n [placeholder]=\"t('to-date')\"\r\n [showIcon]=\"true\"\r\n [required]=\"true\"\r\n />\r\n </div>\r\n\r\n @if (form.errors?.[\"invalidRange\"] && (form.dirty || form.touched)) {\r\n <div class=\"text-sm text-red-600\">\r\n {{ t(\"holiday-range-error\") }}\r\n </div>\r\n }\r\n\r\n <div class=\"flex justify-end gap-3 pt-2\">\r\n <mt-button\r\n [label]=\"t('cancel')\"\r\n variant=\"outlined\"\r\n severity=\"secondary\"\r\n type=\"button\"\r\n (onClick)=\"onCancel()\"\r\n />\r\n <mt-button [label]=\"t(actionLabel())\" type=\"submit\" />\r\n </div>\r\n </form>\r\n</ng-container>\r\n", styles: [":host{display:block}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: DateField, selector: "mt-date-field", inputs: ["field", "label", "placeholder", "class", "readonly", "showIcon", "showClear", "showTime", "pInputs", "required"] }, { kind: "component", type: TextField, selector: "mt-text-field", inputs: ["field", "hint", "label", "placeholder", "class", "type", "readonly", "pInputs", "required", "icon", "iconPosition"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
97
+ }
98
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: SystemSettingsHolidayEditor, decorators: [{
99
+ type: Component,
100
+ args: [{ selector: 'mt-system-settings-holiday-editor', imports: [
101
+ ReactiveFormsModule,
102
+ TranslocoDirective,
103
+ Button,
104
+ DateField,
105
+ TextField,
106
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *transloco=\"let t; prefix: 'system-settings'\">\r\n <form [formGroup]=\"form\" class=\"space-y-4 p-1\" (ngSubmit)=\"onSave()\">\r\n <mt-text-field\r\n formControlName=\"label\"\r\n [label]=\"t('holiday-name')\"\r\n [placeholder]=\"t('holiday-name-placeholder')\"\r\n [required]=\"true\"\r\n />\r\n\r\n <div class=\"grid gap-4 md:grid-cols-2\">\r\n <mt-date-field\r\n formControlName=\"from\"\r\n [label]=\"t('from-date')\"\r\n [placeholder]=\"t('from-date')\"\r\n [showIcon]=\"true\"\r\n [required]=\"true\"\r\n />\r\n\r\n <mt-date-field\r\n formControlName=\"to\"\r\n [label]=\"t('to-date')\"\r\n [placeholder]=\"t('to-date')\"\r\n [showIcon]=\"true\"\r\n [required]=\"true\"\r\n />\r\n </div>\r\n\r\n @if (form.errors?.[\"invalidRange\"] && (form.dirty || form.touched)) {\r\n <div class=\"text-sm text-red-600\">\r\n {{ t(\"holiday-range-error\") }}\r\n </div>\r\n }\r\n\r\n <div class=\"flex justify-end gap-3 pt-2\">\r\n <mt-button\r\n [label]=\"t('cancel')\"\r\n variant=\"outlined\"\r\n severity=\"secondary\"\r\n type=\"button\"\r\n (onClick)=\"onCancel()\"\r\n />\r\n <mt-button [label]=\"t(actionLabel())\" type=\"submit\" />\r\n </div>\r\n </form>\r\n</ng-container>\r\n", styles: [":host{display:block}\n"] }]
107
+ }], ctorParameters: () => [], propDecorators: { holiday: [{ type: i0.Input, args: [{ isSignal: true, alias: "holiday", required: false }] }], isEditMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "isEditMode", required: false }] }] } });
108
+ function holidayRangeValidator() {
109
+ return (control) => {
110
+ const from = control.get('from')?.value;
111
+ const to = control.get('to')?.value;
112
+ if (!from || !to) {
113
+ return null;
114
+ }
115
+ return from <= to ? null : { invalidRange: true };
116
+ };
117
+ }
118
+
119
+ class SystemSettingsHolidaysSection {
120
+ transloco = inject(TranslocoService);
121
+ holidays = input([], ...(ngDevMode ? [{ debugName: "holidays" }] : /* istanbul ignore next */ []));
122
+ addHoliday = output();
123
+ editHoliday = output();
124
+ deleteHoliday = output();
125
+ columns = computed(() => [
126
+ {
127
+ key: 'label',
128
+ label: this.transloco.translate('system-settings.holiday-name'),
129
+ },
130
+ {
131
+ key: 'from',
132
+ label: this.transloco.translate('system-settings.from-date'),
133
+ },
134
+ {
135
+ key: 'to',
136
+ label: this.transloco.translate('system-settings.to-date'),
137
+ },
138
+ ], ...(ngDevMode ? [{ debugName: "columns" }] : /* istanbul ignore next */ []));
139
+ rowActions = computed(() => [
140
+ {
141
+ icon: 'general.edit-01',
142
+ tooltip: this.transloco.translate('system-settings.edit-holiday'),
143
+ color: 'secondary',
144
+ variant: 'outlined',
145
+ action: (row) => this.editHoliday.emit(row.rowIndex),
146
+ },
147
+ {
148
+ icon: 'general.trash-01',
149
+ tooltip: this.transloco.translate('system-settings.remove-holiday'),
150
+ color: 'danger',
151
+ variant: 'outlined',
152
+ action: (row) => this.deleteHoliday.emit(row.rowIndex),
153
+ },
154
+ ], ...(ngDevMode ? [{ debugName: "rowActions" }] : /* istanbul ignore next */ []));
155
+ hasHolidays = computed(() => this.holidays().length > 0, ...(ngDevMode ? [{ debugName: "hasHolidays" }] : /* istanbul ignore next */ []));
156
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: SystemSettingsHolidaysSection, deps: [], target: i0.ɵɵFactoryTarget.Component });
157
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: SystemSettingsHolidaysSection, isStandalone: true, selector: "mt-system-settings-holidays-section", inputs: { holidays: { classPropertyName: "holidays", publicName: "holidays", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { addHoliday: "addHoliday", editHoliday: "editHoliday", deleteHoliday: "deleteHoliday" }, ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'system-settings'\">\r\n <mt-card class=\"block\">\r\n <div class=\"space-y-6\">\r\n <div\r\n class=\"flex flex-col gap-4 md:flex-row md:items-start md:justify-between\"\r\n >\r\n <div class=\"space-y-1\">\r\n <h4 class=\"text-base font-semibold text-neutral-900\">\r\n {{ t(\"holidays-title\") }}\r\n </h4>\r\n <p class=\"text-sm text-neutral-600\">\r\n {{ t(\"holidays-description\") }}\r\n </p>\r\n </div>\r\n\r\n <mt-button\r\n [label]=\"t('add-holiday')\"\r\n icon=\"general.plus\"\r\n (onClick)=\"addHoliday.emit()\"\r\n />\r\n </div>\r\n\r\n @if (hasHolidays()) {\r\n <mt-table\r\n [data]=\"holidays()\"\r\n [columns]=\"columns()\"\r\n [rowActions]=\"rowActions()\"\r\n [generalSearch]=\"false\"\r\n [showFilters]=\"false\"\r\n [dataKey]=\"'rowKey'\"\r\n storageKey=\"admin-system-settings-holidays-table\"\r\n >\r\n </mt-table>\r\n } @else {\r\n <div\r\n class=\"rounded-xl border border-dashed border-neutral-300 bg-neutral-50 px-6 py-10 text-center\"\r\n >\r\n <h5 class=\"text-base font-semibold text-neutral-900\">\r\n {{ t(\"no-holidays-title\") }}\r\n </h5>\r\n <p class=\"mt-2 text-sm text-neutral-600\">\r\n {{ t(\"no-holidays-description\") }}\r\n </p>\r\n </div>\r\n }\r\n </div>\r\n </mt-card>\r\n</ng-container>\r\n", styles: [":host{display:block}\n"], dependencies: [{ kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: Card, selector: "mt-card", inputs: ["class", "title", "paddingless"] }, { kind: "component", type: Table, selector: "mt-table", inputs: ["filters", "data", "columns", "rowActions", "size", "showGridlines", "stripedRows", "selectableRows", "clickableRows", "generalSearch", "lazyLocalSearch", "showFilters", "loading", "updating", "lazy", "lazyLocalSort", "lazyTotalRecords", "reorderableColumns", "reorderableRows", "dataKey", "storageKey", "storageMode", "exportable", "exportFilename", "actionShape", "tableLayout", "noCard", "tabs", "tabsOptionLabel", "tabsOptionValue", "activeTab", "actions", "paginatorPosition", "alwaysShowPaginator", "rowsPerPageOptions", "pageSize", "currentPage", "first", "filterTerm"], outputs: ["selectionChange", "cellChange", "lazyLoad", "columnReorder", "rowReorder", "rowClick", "filtersChange", "activeTabChange", "onTabChange", "pageSizeChange", "currentPageChange", "firstChange", "filterTermChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
158
+ }
159
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: SystemSettingsHolidaysSection, decorators: [{
160
+ type: Component,
161
+ args: [{ selector: 'mt-system-settings-holidays-section', imports: [TranslocoDirective, Button, Card, Table], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *transloco=\"let t; prefix: 'system-settings'\">\r\n <mt-card class=\"block\">\r\n <div class=\"space-y-6\">\r\n <div\r\n class=\"flex flex-col gap-4 md:flex-row md:items-start md:justify-between\"\r\n >\r\n <div class=\"space-y-1\">\r\n <h4 class=\"text-base font-semibold text-neutral-900\">\r\n {{ t(\"holidays-title\") }}\r\n </h4>\r\n <p class=\"text-sm text-neutral-600\">\r\n {{ t(\"holidays-description\") }}\r\n </p>\r\n </div>\r\n\r\n <mt-button\r\n [label]=\"t('add-holiday')\"\r\n icon=\"general.plus\"\r\n (onClick)=\"addHoliday.emit()\"\r\n />\r\n </div>\r\n\r\n @if (hasHolidays()) {\r\n <mt-table\r\n [data]=\"holidays()\"\r\n [columns]=\"columns()\"\r\n [rowActions]=\"rowActions()\"\r\n [generalSearch]=\"false\"\r\n [showFilters]=\"false\"\r\n [dataKey]=\"'rowKey'\"\r\n storageKey=\"admin-system-settings-holidays-table\"\r\n >\r\n </mt-table>\r\n } @else {\r\n <div\r\n class=\"rounded-xl border border-dashed border-neutral-300 bg-neutral-50 px-6 py-10 text-center\"\r\n >\r\n <h5 class=\"text-base font-semibold text-neutral-900\">\r\n {{ t(\"no-holidays-title\") }}\r\n </h5>\r\n <p class=\"mt-2 text-sm text-neutral-600\">\r\n {{ t(\"no-holidays-description\") }}\r\n </p>\r\n </div>\r\n }\r\n </div>\r\n </mt-card>\r\n</ng-container>\r\n", styles: [":host{display:block}\n"] }]
162
+ }], propDecorators: { holidays: [{ type: i0.Input, args: [{ isSignal: true, alias: "holidays", required: false }] }], addHoliday: [{ type: i0.Output, args: ["addHoliday"] }], editHoliday: [{ type: i0.Output, args: ["editHoliday"] }], deleteHoliday: [{ type: i0.Output, args: ["deleteHoliday"] }] } });
163
+
164
+ class SystemSettingsSmtpSection {
165
+ smtpForm = input.required(...(ngDevMode ? [{ debugName: "smtpForm" }] : /* istanbul ignore next */ []));
166
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: SystemSettingsSmtpSection, deps: [], target: i0.ɵɵFactoryTarget.Component });
167
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.8", type: SystemSettingsSmtpSection, isStandalone: true, selector: "mt-system-settings-smtp-section", inputs: { smtpForm: { classPropertyName: "smtpForm", publicName: "smtpForm", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'system-settings'\">\r\n <mt-card class=\"block\">\r\n <div [formGroup]=\"smtpForm()\" class=\"space-y-4\">\r\n <div class=\"space-y-1\">\r\n <h4 class=\"text-base font-semibold text-neutral-900\">\r\n {{ t(\"smtp-title\") }}\r\n </h4>\r\n <p class=\"text-sm text-neutral-600\">\r\n {{ t(\"smtp-description\") }}\r\n </p>\r\n </div>\r\n\r\n <div class=\"grid gap-4 md:grid-cols-2\">\r\n <mt-text-field\r\n formControlName=\"mail\"\r\n [label]=\"t('smtp-mail')\"\r\n [placeholder]=\"t('smtp-mail-placeholder')\"\r\n type=\"email\"\r\n />\r\n\r\n <mt-text-field\r\n formControlName=\"name\"\r\n [label]=\"t('smtp-name')\"\r\n [placeholder]=\"t('smtp-name-placeholder')\"\r\n />\r\n\r\n <mt-text-field\r\n formControlName=\"host\"\r\n [label]=\"t('smtp-host')\"\r\n [placeholder]=\"t('smtp-host-placeholder')\"\r\n />\r\n\r\n <mt-text-field\r\n formControlName=\"port\"\r\n [label]=\"t('smtp-port')\"\r\n [placeholder]=\"t('smtp-port-placeholder')\"\r\n type=\"number\"\r\n />\r\n\r\n <div class=\"md:col-span-2\">\r\n <mt-text-field\r\n formControlName=\"password\"\r\n [label]=\"t('smtp-password')\"\r\n [placeholder]=\"t('smtp-password-placeholder')\"\r\n type=\"password\"\r\n />\r\n </div>\r\n </div>\r\n </div>\r\n </mt-card>\r\n</ng-container>\r\n", styles: [":host{display:block}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: Card, selector: "mt-card", inputs: ["class", "title", "paddingless"] }, { kind: "component", type: TextField, selector: "mt-text-field", inputs: ["field", "hint", "label", "placeholder", "class", "type", "readonly", "pInputs", "required", "icon", "iconPosition"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
168
+ }
169
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: SystemSettingsSmtpSection, decorators: [{
170
+ type: Component,
171
+ args: [{ selector: 'mt-system-settings-smtp-section', imports: [ReactiveFormsModule, TranslocoDirective, Card, TextField], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *transloco=\"let t; prefix: 'system-settings'\">\r\n <mt-card class=\"block\">\r\n <div [formGroup]=\"smtpForm()\" class=\"space-y-4\">\r\n <div class=\"space-y-1\">\r\n <h4 class=\"text-base font-semibold text-neutral-900\">\r\n {{ t(\"smtp-title\") }}\r\n </h4>\r\n <p class=\"text-sm text-neutral-600\">\r\n {{ t(\"smtp-description\") }}\r\n </p>\r\n </div>\r\n\r\n <div class=\"grid gap-4 md:grid-cols-2\">\r\n <mt-text-field\r\n formControlName=\"mail\"\r\n [label]=\"t('smtp-mail')\"\r\n [placeholder]=\"t('smtp-mail-placeholder')\"\r\n type=\"email\"\r\n />\r\n\r\n <mt-text-field\r\n formControlName=\"name\"\r\n [label]=\"t('smtp-name')\"\r\n [placeholder]=\"t('smtp-name-placeholder')\"\r\n />\r\n\r\n <mt-text-field\r\n formControlName=\"host\"\r\n [label]=\"t('smtp-host')\"\r\n [placeholder]=\"t('smtp-host-placeholder')\"\r\n />\r\n\r\n <mt-text-field\r\n formControlName=\"port\"\r\n [label]=\"t('smtp-port')\"\r\n [placeholder]=\"t('smtp-port-placeholder')\"\r\n type=\"number\"\r\n />\r\n\r\n <div class=\"md:col-span-2\">\r\n <mt-text-field\r\n formControlName=\"password\"\r\n [label]=\"t('smtp-password')\"\r\n [placeholder]=\"t('smtp-password-placeholder')\"\r\n type=\"password\"\r\n />\r\n </div>\r\n </div>\r\n </div>\r\n </mt-card>\r\n</ng-container>\r\n", styles: [":host{display:block}\n"] }]
172
+ }], propDecorators: { smtpForm: [{ type: i0.Input, args: [{ isSignal: true, alias: "smtpForm", required: true }] }] } });
173
+
174
+ const FIXED_CURRENCIES = [
175
+ {
176
+ code: 'SAR',
177
+ englishLabel: 'Saudi Riyal (SAR)',
178
+ arabicLabel: '???? ????? (SAR)',
179
+ unit: {
180
+ en: 'SAR',
181
+ ar: '???? ?????',
182
+ },
183
+ },
184
+ {
185
+ code: 'OMR',
186
+ englishLabel: 'Omani Rial (OMR)',
187
+ arabicLabel: '???? ????? (OMR)',
188
+ unit: {
189
+ en: 'OMR',
190
+ ar: '???? ?????',
191
+ },
192
+ },
193
+ {
194
+ code: 'AED',
195
+ englishLabel: 'UAE Dirham (AED)',
196
+ arabicLabel: '???? ??????? (AED)',
197
+ unit: {
198
+ en: 'AED',
199
+ ar: '???? ???????',
200
+ },
201
+ },
202
+ ];
203
+ const DEFAULT_DATE_FORMAT_OPTIONS = [
204
+ {
205
+ key: 'MM/dd/yyyy',
206
+ sample: 'MM/dd/yyyy [01/20/2023]',
207
+ isSelected: true,
208
+ },
209
+ {
210
+ key: 'yyyy/MM/dd',
211
+ sample: 'yyyy/MM/dd [2023/01/20]',
212
+ isSelected: false,
213
+ },
214
+ {
215
+ key: 'dd-MM-yyyy',
216
+ sample: 'dd-MM-yyyy [20-01-2023]',
217
+ isSelected: false,
218
+ },
219
+ {
220
+ key: 'yyyy-MM-dd',
221
+ sample: 'yyyy-MM-dd [2023-01-20]',
222
+ isSelected: false,
223
+ },
224
+ ];
225
+ const DEFAULT_TIME_FORMAT_OPTIONS = [
226
+ {
227
+ key: 'hh:mm tt',
228
+ sample: 'hh:mm tt [03:00 PM]',
229
+ isSelected: true,
230
+ },
231
+ {
232
+ key: 'HH:mm',
233
+ sample: 'HH:mm [15:00]',
234
+ isSelected: false,
235
+ },
236
+ {
237
+ key: 'H:mm:ss',
238
+ sample: 'H:mm:ss [15:00:00]',
239
+ isSelected: false,
240
+ },
241
+ {
242
+ key: 'hh:mm:ss',
243
+ sample: 'hh:mm:ss [03:00:00]',
244
+ isSelected: false,
245
+ },
246
+ ];
247
+ const WEEKEND_DAY_DEFINITIONS = [
248
+ { dayNumber: 1, translationKey: 'monday' },
249
+ { dayNumber: 2, translationKey: 'tuesday' },
250
+ { dayNumber: 3, translationKey: 'wednesday' },
251
+ { dayNumber: 4, translationKey: 'thursday' },
252
+ { dayNumber: 5, translationKey: 'friday' },
253
+ { dayNumber: 6, translationKey: 'saturday' },
254
+ { dayNumber: 7, translationKey: 'sunday' },
255
+ ];
256
+
257
+ class SystemSettings {
258
+ http = inject(HttpClient);
259
+ router = inject(Router);
260
+ transloco = inject(TranslocoService);
261
+ modal = inject(ModalService);
262
+ toast = inject(ToastService);
263
+ apiBasePath = input('settings', ...(ngDevMode ? [{ debugName: "apiBasePath" }] : /* istanbul ignore next */ []));
264
+ backRoute = input('/control-panel/product-settings', ...(ngDevMode ? [{ debugName: "backRoute" }] : /* istanbul ignore next */ []));
265
+ formatSchema = input(null, ...(ngDevMode ? [{ debugName: "formatSchema" }] : /* istanbul ignore next */ []));
266
+ form = new FormGroup({
267
+ timezone: new FormGroup({
268
+ regionId: new FormControl(null, Validators.required),
269
+ dateFormat: new FormControl(null, Validators.required),
270
+ timeFormat: new FormControl(null, Validators.required),
271
+ }),
272
+ currency: new FormGroup({
273
+ code: new FormControl(null, Validators.required),
274
+ format: new FormControl(null, Validators.required),
275
+ }),
276
+ weekend: new FormGroup({
277
+ days: new FormControl([], { nonNullable: true }),
278
+ }),
279
+ smtp: new FormGroup({
280
+ mail: new FormControl('', { nonNullable: true }),
281
+ name: new FormControl('', { nonNullable: true }),
282
+ password: new FormControl('', { nonNullable: true }),
283
+ host: new FormControl('', { nonNullable: true }),
284
+ port: new FormControl('', { nonNullable: true }),
285
+ }),
286
+ });
287
+ settings = signal(null, ...(ngDevMode ? [{ debugName: "settings" }] : /* istanbul ignore next */ []));
288
+ settingsLoading = signal(false, ...(ngDevMode ? [{ debugName: "settingsLoading" }] : /* istanbul ignore next */ []));
289
+ settingsError = signal(null, ...(ngDevMode ? [{ debugName: "settingsError" }] : /* istanbul ignore next */ []));
290
+ settingsLastUpdated = signal(null, ...(ngDevMode ? [{ debugName: "settingsLastUpdated" }] : /* istanbul ignore next */ []));
291
+ updating = signal(false, ...(ngDevMode ? [{ debugName: "updating" }] : /* istanbul ignore next */ []));
292
+ updateError = signal(null, ...(ngDevMode ? [{ debugName: "updateError" }] : /* istanbul ignore next */ []));
293
+ timezones = signal([], ...(ngDevMode ? [{ debugName: "timezones" }] : /* istanbul ignore next */ []));
294
+ timezonesLoading = signal(false, ...(ngDevMode ? [{ debugName: "timezonesLoading" }] : /* istanbul ignore next */ []));
295
+ timezonesError = signal(null, ...(ngDevMode ? [{ debugName: "timezonesError" }] : /* istanbul ignore next */ []));
296
+ holidayItems = signal([], ...(ngDevMode ? [{ debugName: "holidayItems" }] : /* istanbul ignore next */ []));
297
+ initialSnapshot = signal(null, ...(ngDevMode ? [{ debugName: "initialSnapshot" }] : /* istanbul ignore next */ []));
298
+ hydrationVersion = signal(null, ...(ngDevMode ? [{ debugName: "hydrationVersion" }] : /* istanbul ignore next */ []));
299
+ activeLang = toSignal(this.transloco.langChanges$, {
300
+ initialValue: this.transloco.getActiveLang(),
301
+ });
302
+ formStatus = toSignal(this.form.statusChanges, {
303
+ initialValue: this.form.status,
304
+ });
305
+ selectedDateFormat = toSignal(this.form.controls.timezone.controls.dateFormat.valueChanges, {
306
+ initialValue: this.form.controls.timezone.controls.dateFormat.value,
307
+ });
308
+ selectedTimeFormat = toSignal(this.form.controls.timezone.controls.timeFormat.valueChanges, {
309
+ initialValue: this.form.controls.timezone.controls.timeFormat.value,
310
+ });
311
+ selectedCurrencyCode = toSignal(this.form.controls.currency.controls.code.valueChanges, {
312
+ initialValue: this.form.controls.currency.controls.code.value,
313
+ });
314
+ holidaysSetting = computed(() => this.findSettingByKey('Holidays'), ...(ngDevMode ? [{ debugName: "holidaysSetting" }] : /* istanbul ignore next */ []));
315
+ timezoneSetting = computed(() => this.findSettingByKey('Timezone'), ...(ngDevMode ? [{ debugName: "timezoneSetting" }] : /* istanbul ignore next */ []));
316
+ currencySetting = computed(() => this.findSettingByKey('Currency'), ...(ngDevMode ? [{ debugName: "currencySetting" }] : /* istanbul ignore next */ []));
317
+ weekendSetting = computed(() => this.findSettingByKey('Weekend'), ...(ngDevMode ? [{ debugName: "weekendSetting" }] : /* istanbul ignore next */ []));
318
+ smtpSetting = computed(() => this.findSettingByKey('SMTP'), ...(ngDevMode ? [{ debugName: "smtpSetting" }] : /* istanbul ignore next */ []));
319
+ resolvedFormatSchema = computed(() => {
320
+ const schema = this.formatSchema();
321
+ return {
322
+ dateFormats: schema?.dateFormats ?? DEFAULT_DATE_FORMAT_OPTIONS,
323
+ timeFormats: schema?.timeFormats ?? DEFAULT_TIME_FORMAT_OPTIONS,
324
+ };
325
+ }, ...(ngDevMode ? [{ debugName: "resolvedFormatSchema" }] : /* istanbul ignore next */ []));
326
+ timezoneOptions = computed(() => this.timezones().map((timezone) => ({
327
+ ...timezone,
328
+ name: timezone.name ?? timezone.displayName,
329
+ })), ...(ngDevMode ? [{ debugName: "timezoneOptions" }] : /* istanbul ignore next */ []));
330
+ dateFormatOptions = computed(() => this.mapFormatOptions(this.resolvedFormatSchema().dateFormats, this.selectedDateFormat()), ...(ngDevMode ? [{ debugName: "dateFormatOptions" }] : /* istanbul ignore next */ []));
331
+ timeFormatOptions = computed(() => this.mapFormatOptions(this.resolvedFormatSchema().timeFormats, this.selectedTimeFormat()), ...(ngDevMode ? [{ debugName: "timeFormatOptions" }] : /* istanbul ignore next */ []));
332
+ currencyOptions = computed(() => {
333
+ const lang = this.activeLang();
334
+ return FIXED_CURRENCIES.map((currency) => ({
335
+ id: currency.code,
336
+ name: lang === 'ar' ? currency.arabicLabel : currency.englishLabel,
337
+ }));
338
+ }, ...(ngDevMode ? [{ debugName: "currencyOptions" }] : /* istanbul ignore next */ []));
339
+ currencyFormatOptions = computed(() => {
340
+ const currency = FIXED_CURRENCIES.find((item) => item.code === this.selectedCurrencyCode());
341
+ return this.buildCurrencyFormatOptions(currency);
342
+ }, ...(ngDevMode ? [{ debugName: "currencyFormatOptions" }] : /* istanbul ignore next */ []));
343
+ weekendOptions = computed(() => {
344
+ this.activeLang();
345
+ return WEEKEND_DAY_DEFINITIONS.map((day) => ({
346
+ id: `${day.dayNumber}`,
347
+ dayNumber: day.dayNumber,
348
+ name: this.transloco.translate(`system-settings.${day.translationKey}`),
349
+ }));
350
+ }, ...(ngDevMode ? [{ debugName: "weekendOptions" }] : /* istanbul ignore next */ []));
351
+ isReady = computed(() => this.hydrationVersion() !== null && this.initialSnapshot() !== null, ...(ngDevMode ? [{ debugName: "isReady" }] : /* istanbul ignore next */ []));
352
+ isLoading = computed(() => this.settingsLoading() || this.timezonesLoading() || !this.isReady(), ...(ngDevMode ? [{ debugName: "isLoading" }] : /* istanbul ignore next */ []));
353
+ canSaveSettings = computed(() => !this.isLoading() && !this.updating() && this.formStatus() === 'VALID', ...(ngDevMode ? [{ debugName: "canSaveSettings" }] : /* istanbul ignore next */ []));
354
+ holidayTableRows = computed(() => this.holidayItems().map((holiday, index) => ({
355
+ rowKey: `${index}`,
356
+ rowIndex: index,
357
+ label: holiday.label,
358
+ from: formatDateOnly(holiday.from),
359
+ to: formatDateOnly(holiday.to),
360
+ })), ...(ngDevMode ? [{ debugName: "holidayTableRows" }] : /* istanbul ignore next */ []));
361
+ constructor() {
362
+ effect(() => {
363
+ const version = [
364
+ this.settingsLastUpdated() ?? 'none',
365
+ this.settingsError() ?? 'none',
366
+ this.timezonesError() ?? 'none',
367
+ String(this.timezones().length),
368
+ JSON.stringify(this.resolvedFormatSchema()),
369
+ ].join('::');
370
+ if (this.settingsLoading() || this.timezonesLoading()) {
371
+ return;
372
+ }
373
+ if (version === this.hydrationVersion()) {
374
+ return;
375
+ }
376
+ this.hydrateForm(this.holidaysSetting() ?? this.createFallbackSetting('Holidays'), this.timezoneSetting() ?? this.createFallbackSetting('Timezone'), this.currencySetting() ?? this.createFallbackSetting('Currency'), this.weekendSetting() ?? this.createFallbackSetting('Weekend'), this.smtpSetting() ?? this.createFallbackSetting('SMTP'));
377
+ this.hydrationVersion.set(version);
378
+ });
379
+ }
380
+ ngOnInit() {
381
+ this.loadSettings();
382
+ this.loadTimezones();
383
+ }
384
+ goBack() {
385
+ const backRoute = this.backRoute();
386
+ if (!backRoute) {
387
+ return;
388
+ }
389
+ this.router.navigateByUrl(backRoute);
390
+ }
391
+ openAddHoliday() {
392
+ const modalRef = this.modal.openModal(SystemSettingsHolidayEditor, 'dialog', {
393
+ header: this.transloco.translate('system-settings.add-holiday'),
394
+ width: '42rem',
395
+ appendTo: 'body',
396
+ dismissableMask: true,
397
+ dismissible: true,
398
+ inputValues: {
399
+ holiday: null,
400
+ isEditMode: false,
401
+ },
402
+ });
403
+ modalRef.onClose.subscribe((result) => {
404
+ if (!result) {
405
+ return;
406
+ }
407
+ this.holidayItems.update((items) => [...items, result]);
408
+ });
409
+ }
410
+ editHoliday(index) {
411
+ const holiday = this.holidayItems()[index];
412
+ if (!holiday) {
413
+ return;
414
+ }
415
+ const modalRef = this.modal.openModal(SystemSettingsHolidayEditor, 'drawer', {
416
+ header: this.transloco.translate('system-settings.edit-holiday'),
417
+ styleClass: '!w-[30rem] !absolute !shadow-none',
418
+ position: 'end',
419
+ appendTo: 'page-content',
420
+ dismissible: true,
421
+ inputValues: {
422
+ holiday,
423
+ isEditMode: true,
424
+ },
425
+ });
426
+ modalRef.onClose.subscribe((result) => {
427
+ if (!result) {
428
+ return;
429
+ }
430
+ this.holidayItems.update((items) => items.map((item, itemIndex) => (itemIndex === index ? result : item)));
431
+ });
432
+ }
433
+ deleteHoliday(index) {
434
+ this.holidayItems.update((items) => items.filter((_, itemIndex) => itemIndex !== index));
435
+ }
436
+ onSave() {
437
+ this.form.markAllAsTouched();
438
+ const nextSnapshot = this.buildCurrentSnapshot();
439
+ const initialSnapshot = this.initialSnapshot();
440
+ if (!nextSnapshot || !initialSnapshot) {
441
+ return;
442
+ }
443
+ const values = [];
444
+ if (!this.areEqual(initialSnapshot.holidays, nextSnapshot.holidays)) {
445
+ values.push({
446
+ key: 'Holidays',
447
+ value: this.serializeHolidaysValue(nextSnapshot.holidays),
448
+ });
449
+ }
450
+ if (!this.areEqual(initialSnapshot.timezone, nextSnapshot.timezone)) {
451
+ values.push({
452
+ key: 'Timezone',
453
+ value: nextSnapshot.timezone,
454
+ });
455
+ }
456
+ if (!this.areEqual(initialSnapshot.currency, nextSnapshot.currency)) {
457
+ values.push({
458
+ key: 'Currency',
459
+ value: nextSnapshot.currency,
460
+ });
461
+ }
462
+ if (!this.areEqual(initialSnapshot.weekend, nextSnapshot.weekend)) {
463
+ values.push({
464
+ key: 'Weekend',
465
+ value: nextSnapshot.weekend,
466
+ });
467
+ }
468
+ if (!this.areEqual(initialSnapshot.smtp, nextSnapshot.smtp)) {
469
+ values.push({
470
+ key: 'SMTP',
471
+ value: nextSnapshot.smtp,
472
+ });
473
+ }
474
+ if (!values.length) {
475
+ this.toast.info(this.transloco.translate('system-settings.no-changes-message'));
476
+ return;
477
+ }
478
+ this.updateSettings(values);
479
+ }
480
+ loadSettings() {
481
+ this.settingsLoading.set(true);
482
+ this.settingsError.set(null);
483
+ this.http
484
+ .get(this.buildEndpoint('getsystemsettings'))
485
+ .subscribe({
486
+ next: (response) => {
487
+ this.settings.set(response.data ?? []);
488
+ this.settingsLoading.set(false);
489
+ this.settingsLastUpdated.set(new Date().toISOString());
490
+ },
491
+ error: (error) => {
492
+ this.settingsLoading.set(false);
493
+ this.settingsError.set(error?.message ?? 'Failed to load system settings');
494
+ this.settingsLastUpdated.set(new Date().toISOString());
495
+ },
496
+ });
497
+ }
498
+ loadTimezones() {
499
+ this.timezonesLoading.set(true);
500
+ this.timezonesError.set(null);
501
+ this.http
502
+ .get(this.buildEndpoint('timezones'))
503
+ .subscribe({
504
+ next: (response) => {
505
+ this.timezones.set(response.data ?? []);
506
+ this.timezonesLoading.set(false);
507
+ },
508
+ error: (error) => {
509
+ this.timezonesLoading.set(false);
510
+ this.timezonesError.set(error?.message ?? 'Failed to load timezone options');
511
+ },
512
+ });
513
+ }
514
+ updateSettings(values) {
515
+ this.updating.set(true);
516
+ this.updateError.set(null);
517
+ this.http
518
+ .put(this.buildEndpoint('updatesystemsettings'), {
519
+ values,
520
+ })
521
+ .subscribe({
522
+ next: () => {
523
+ const nextSettings = this.applyUpdatedSettings(this.settings() ?? [], values);
524
+ this.settings.set(nextSettings);
525
+ this.updating.set(false);
526
+ this.updateError.set(null);
527
+ this.settingsLastUpdated.set(new Date().toISOString());
528
+ this.toast.success(this.transloco.translate('system-settings.saved-successfully'));
529
+ },
530
+ error: (error) => {
531
+ this.updating.set(false);
532
+ this.updateError.set(error?.message ?? 'Failed to update system settings');
533
+ },
534
+ });
535
+ }
536
+ hydrateForm(holidaysSetting, timezoneSetting, currencySetting, weekendSetting, smtpSetting) {
537
+ const holidays = this.extractHolidaysValue(holidaysSetting);
538
+ const timezone = this.normalizeTimezoneSnapshot(this.extractTimezoneValue(timezoneSetting));
539
+ const currency = this.normalizeCurrencySnapshot(this.extractCurrencyValue(currencySetting));
540
+ const weekend = this.normalizeWeekendSnapshot(this.extractWeekendValue(weekendSetting));
541
+ const smtp = this.normalizeSmtpSnapshot(this.extractSmtpValue(smtpSetting));
542
+ this.holidayItems.set(holidays.data);
543
+ this.form.controls.timezone.setValue({
544
+ regionId: timezone.region?.id ?? null,
545
+ dateFormat: timezone.dateFormat,
546
+ timeFormat: timezone.timeFormat,
547
+ });
548
+ this.form.controls.currency.setValue({
549
+ code: this.resolveCurrencyCode(currency),
550
+ format: currency.format,
551
+ });
552
+ this.form.controls.weekend.setValue({
553
+ days: weekend.days,
554
+ });
555
+ this.form.controls.smtp.setValue({
556
+ mail: smtp.mail,
557
+ name: smtp.name,
558
+ password: smtp.password,
559
+ host: smtp.host,
560
+ port: smtp.port === null ? '' : String(smtp.port),
561
+ });
562
+ this.form.markAsPristine();
563
+ this.form.markAsUntouched();
564
+ this.initialSnapshot.set({
565
+ holidays,
566
+ timezone,
567
+ currency,
568
+ weekend,
569
+ smtp,
570
+ });
571
+ }
572
+ buildCurrentSnapshot() {
573
+ const timezone = this.buildTimezoneValue();
574
+ const currency = this.buildCurrencyValue();
575
+ if (!timezone || !currency || this.form.invalid) {
576
+ return null;
577
+ }
578
+ return {
579
+ holidays: {
580
+ data: this.holidayItems().map((item) => ({
581
+ label: item.label.trim(),
582
+ from: item.from,
583
+ to: item.to,
584
+ })),
585
+ },
586
+ timezone,
587
+ currency,
588
+ weekend: this.buildWeekendValue(),
589
+ smtp: this.buildSmtpValue(),
590
+ };
591
+ }
592
+ buildTimezoneValue() {
593
+ const timezoneForm = this.form.controls.timezone.getRawValue();
594
+ if (!timezoneForm.regionId ||
595
+ !timezoneForm.dateFormat ||
596
+ !timezoneForm.timeFormat) {
597
+ return null;
598
+ }
599
+ const region = this.timezones().find((item) => item.id === timezoneForm.regionId);
600
+ if (!region) {
601
+ return null;
602
+ }
603
+ return {
604
+ region: {
605
+ ...region,
606
+ name: region.name ?? region.displayName,
607
+ },
608
+ dateFormat: timezoneForm.dateFormat,
609
+ timeFormat: timezoneForm.timeFormat,
610
+ };
611
+ }
612
+ buildCurrencyValue() {
613
+ const currencyForm = this.form.controls.currency.getRawValue();
614
+ if (!currencyForm.code || !currencyForm.format) {
615
+ return null;
616
+ }
617
+ const currency = FIXED_CURRENCIES.find((item) => item.code === currencyForm.code);
618
+ if (!currency) {
619
+ return null;
620
+ }
621
+ return {
622
+ name: currency.code,
623
+ unit: currency.unit,
624
+ format: currencyForm.format,
625
+ };
626
+ }
627
+ buildWeekendValue() {
628
+ return {
629
+ days: normalizeWeekendDays(this.form.controls.weekend.controls.days.value),
630
+ };
631
+ }
632
+ buildSmtpValue() {
633
+ const smtpForm = this.form.controls.smtp.getRawValue();
634
+ return {
635
+ mail: smtpForm.mail.trim(),
636
+ name: smtpForm.name.trim(),
637
+ password: smtpForm.password,
638
+ host: smtpForm.host.trim(),
639
+ port: parsePort(smtpForm.port),
640
+ };
641
+ }
642
+ findSettingByKey(key) {
643
+ const normalizedKey = key.trim().toLowerCase();
644
+ return (this.settings()?.find((setting) => setting.key.trim().toLowerCase() === normalizedKey) ?? null);
645
+ }
646
+ extractHolidaysValue(setting) {
647
+ if (!isRecord(setting.value)) {
648
+ return { data: [] };
649
+ }
650
+ const rawData = setting.value['data'];
651
+ if (!Array.isArray(rawData)) {
652
+ return { data: [] };
653
+ }
654
+ return {
655
+ data: rawData
656
+ .map((item) => this.normalizeHolidayItem(item))
657
+ .filter((item) => item !== null),
658
+ };
659
+ }
660
+ extractTimezoneValue(setting) {
661
+ if (!isRecord(setting.value)) {
662
+ return {
663
+ region: null,
664
+ dateFormat: null,
665
+ timeFormat: null,
666
+ };
667
+ }
668
+ return {
669
+ region: this.normalizeTimezoneRegion(setting.value['region'] ?? setting.value['Region']),
670
+ dateFormat: getNullableString(setting.value['dateFormat'] ??
671
+ setting.value['DateFormat'] ??
672
+ setting.value['dateformat']),
673
+ timeFormat: getNullableString(setting.value['timeFormat'] ??
674
+ setting.value['TimeFormat'] ??
675
+ setting.value['timeformat']),
676
+ };
677
+ }
678
+ extractCurrencyValue(setting) {
679
+ if (!isRecord(setting.value)) {
680
+ return this.getDefaultCurrencyValue();
681
+ }
682
+ return {
683
+ name: getString(setting.value['name']) ?? FIXED_CURRENCIES[0].code,
684
+ unit: this.normalizeCurrencyUnit(setting.value['unit']),
685
+ format: getNullableString(setting.value['format']),
686
+ };
687
+ }
688
+ extractWeekendValue(setting) {
689
+ if (!isRecord(setting.value)) {
690
+ return { days: [] };
691
+ }
692
+ return {
693
+ days: normalizeWeekendDays(setting.value['days'] ?? setting.value['Days']),
694
+ };
695
+ }
696
+ extractSmtpValue(setting) {
697
+ if (!isRecord(setting.value)) {
698
+ return this.getDefaultSmtpValue();
699
+ }
700
+ return {
701
+ mail: getNullableString(setting.value['mail'] ?? setting.value['Mail']) ?? '',
702
+ name: getNullableString(setting.value['name'] ?? setting.value['Name']) ?? '',
703
+ password: getNullableString(setting.value['password'] ?? setting.value['Password']) ?? '',
704
+ host: getNullableString(setting.value['host'] ?? setting.value['Host']) ?? '',
705
+ port: getNullableNumber(setting.value['port'] ?? setting.value['Port']),
706
+ };
707
+ }
708
+ normalizeHolidayItem(value) {
709
+ if (!isRecord(value)) {
710
+ return null;
711
+ }
712
+ const label = getString(value['label'] ?? value['name']);
713
+ const from = normalizeDateInput(value['from']);
714
+ const to = normalizeDateInput(value['to']);
715
+ if (!label || !from || !to) {
716
+ return null;
717
+ }
718
+ return { label, from, to };
719
+ }
720
+ normalizeTimezoneRegion(value) {
721
+ if (typeof value === 'string' && value.trim()) {
722
+ const normalizedValue = value.trim().toLowerCase();
723
+ const region = this.timezones().find((item) => item.id.trim().toLowerCase() === normalizedValue) ?? null;
724
+ return region
725
+ ? {
726
+ ...region,
727
+ name: region.name ?? region.displayName,
728
+ }
729
+ : null;
730
+ }
731
+ if (!isRecord(value)) {
732
+ return null;
733
+ }
734
+ const id = getString(value['id'] ?? value['Id']);
735
+ if (!id) {
736
+ return null;
737
+ }
738
+ const matchedRegion = this.timezones().find((item) => item.id.trim().toLowerCase() === id.trim().toLowerCase());
739
+ if (matchedRegion) {
740
+ return {
741
+ ...matchedRegion,
742
+ name: getString(value['name'] ?? value['Name']) ??
743
+ matchedRegion.name ??
744
+ matchedRegion.displayName,
745
+ };
746
+ }
747
+ const standardName = getString(value['standardName'] ?? value['StandardName']) ?? id;
748
+ const displayName = getString(value['displayName'] ?? value['DisplayName']) ?? id;
749
+ return {
750
+ id,
751
+ baseUtcOffset: getString(value['baseUtcOffset'] ?? value['BaseUtcOffset']) ?? '',
752
+ standardName,
753
+ displayName,
754
+ daylightName: getString(value['daylightName'] ?? value['DaylightName']) ??
755
+ standardName,
756
+ name: getString(value['name'] ?? value['Name']) ?? displayName,
757
+ };
758
+ }
759
+ normalizeCurrencyUnit(value) {
760
+ if (!isRecord(value)) {
761
+ return FIXED_CURRENCIES[0].unit;
762
+ }
763
+ return {
764
+ en: getString(value['en']) ?? FIXED_CURRENCIES[0].unit.en,
765
+ ar: getString(value['ar']) ?? FIXED_CURRENCIES[0].unit.ar,
766
+ };
767
+ }
768
+ normalizeTimezoneSnapshot(value) {
769
+ const defaults = this.getDefaultTimezoneValue();
770
+ return {
771
+ region: value.region ?? defaults.region,
772
+ dateFormat: value.dateFormat ?? defaults.dateFormat,
773
+ timeFormat: value.timeFormat ?? defaults.timeFormat,
774
+ };
775
+ }
776
+ normalizeCurrencySnapshot(value) {
777
+ const code = this.resolveCurrencyCode(value);
778
+ const currency = FIXED_CURRENCIES.find((item) => item.code === code) ??
779
+ FIXED_CURRENCIES[0];
780
+ const defaultFormat = this.buildCurrencyFormatOptions(currency)[0]?.id ?? null;
781
+ return {
782
+ name: currency.code,
783
+ unit: currency.unit,
784
+ format: value.format ?? defaultFormat,
785
+ };
786
+ }
787
+ normalizeWeekendSnapshot(value) {
788
+ return {
789
+ days: normalizeWeekendDays(value.days),
790
+ };
791
+ }
792
+ normalizeSmtpSnapshot(value) {
793
+ return {
794
+ mail: value.mail.trim(),
795
+ name: value.name.trim(),
796
+ password: value.password,
797
+ host: value.host.trim(),
798
+ port: value.port,
799
+ };
800
+ }
801
+ createFallbackSetting(key) {
802
+ switch (key) {
803
+ case 'Holidays':
804
+ return { key, label: key, description: key, value: { data: [] } };
805
+ case 'Timezone':
806
+ return {
807
+ key,
808
+ label: key,
809
+ description: key,
810
+ value: this.getDefaultTimezoneValue(),
811
+ };
812
+ case 'Currency':
813
+ return {
814
+ key,
815
+ label: key,
816
+ description: key,
817
+ value: this.getDefaultCurrencyValue(),
818
+ };
819
+ case 'Weekend':
820
+ return { key, label: key, description: key, value: { days: [] } };
821
+ case 'SMTP':
822
+ return {
823
+ key,
824
+ label: key,
825
+ description: key,
826
+ value: this.getDefaultSmtpValue(),
827
+ };
828
+ }
829
+ }
830
+ getDefaultTimezoneValue() {
831
+ const region = this.timezones()[0] ?? null;
832
+ const defaultDateFormat = this.dateFormatOptions().find((option) => option.isSelected)?.id ??
833
+ this.dateFormatOptions()[0]?.id ??
834
+ null;
835
+ const defaultTimeFormat = this.timeFormatOptions().find((option) => option.isSelected)?.id ??
836
+ this.timeFormatOptions()[0]?.id ??
837
+ null;
838
+ return {
839
+ region: region
840
+ ? {
841
+ ...region,
842
+ name: region.name ?? region.displayName,
843
+ }
844
+ : null,
845
+ dateFormat: defaultDateFormat,
846
+ timeFormat: defaultTimeFormat,
847
+ };
848
+ }
849
+ getDefaultCurrencyValue() {
850
+ const currency = FIXED_CURRENCIES[0];
851
+ return {
852
+ name: currency.code,
853
+ unit: currency.unit,
854
+ format: this.buildCurrencyFormatOptions(currency)[0]?.id ?? null,
855
+ };
856
+ }
857
+ getDefaultSmtpValue() {
858
+ return {
859
+ mail: '',
860
+ name: '',
861
+ password: '',
862
+ host: '',
863
+ port: null,
864
+ };
865
+ }
866
+ resolveCurrencyCode(value) {
867
+ const candidates = [value.name, value.unit.en, value.unit.ar].filter((candidate) => !!candidate);
868
+ for (const candidate of candidates) {
869
+ const normalizedCandidate = candidate.trim().toLowerCase();
870
+ const extractedCode = candidate.match(/\(([A-Za-z]{3})\)/)?.[1]?.toUpperCase() ?? null;
871
+ if (extractedCode) {
872
+ const directCodeMatch = FIXED_CURRENCIES.find((item) => item.code === extractedCode);
873
+ if (directCodeMatch) {
874
+ return directCodeMatch.code;
875
+ }
876
+ }
877
+ const match = FIXED_CURRENCIES.find((item) => item.code.toLowerCase() === normalizedCandidate ||
878
+ item.englishLabel.toLowerCase() === normalizedCandidate ||
879
+ item.arabicLabel.toLowerCase() === normalizedCandidate ||
880
+ item.unit.en.toLowerCase() === normalizedCandidate ||
881
+ item.unit.ar.toLowerCase() === normalizedCandidate);
882
+ if (match) {
883
+ return match.code;
884
+ }
885
+ }
886
+ return FIXED_CURRENCIES[0].code;
887
+ }
888
+ mapFormatOptions(options, selectedKey) {
889
+ return options.map((option) => ({
890
+ id: option.key,
891
+ name: option.sample,
892
+ isSelected: selectedKey ? option.key === selectedKey : option.isSelected,
893
+ }));
894
+ }
895
+ serializeHolidaysValue(value) {
896
+ return {
897
+ data: value.data.map((item) => ({
898
+ label: item.label,
899
+ from: formatDateOnly(item.from),
900
+ to: formatDateOnly(item.to),
901
+ })),
902
+ };
903
+ }
904
+ buildCurrencyFormatOptions(currency) {
905
+ const unitLabel = this.getCurrencyFormatLabel(currency);
906
+ return [
907
+ { id: '{0:0}', name: `1000 ${unitLabel}` },
908
+ { id: '{0:0.0}', name: `1000.0 ${unitLabel}` },
909
+ { id: '{0:0.00}', name: `1000.00 ${unitLabel}` },
910
+ { id: '{0:#,0}', name: `1,000 ${unitLabel}` },
911
+ { id: '{0:#,0.0}', name: `1,000.0 ${unitLabel}` },
912
+ { id: '{0:#,0.00}', name: `1,000.00 ${unitLabel}` },
913
+ { id: '{0:#,0, K}', name: `1 K ${unitLabel}` },
914
+ { id: '{0:N3}', name: `1,000 N3 ${unitLabel}` },
915
+ ];
916
+ }
917
+ getCurrencyFormatLabel(currency) {
918
+ if (!currency) {
919
+ return '';
920
+ }
921
+ return this.activeLang() === 'ar' ? currency.unit.ar : currency.unit.en;
922
+ }
923
+ buildEndpoint(path) {
924
+ return `${this.apiBasePath().replace(/\/$/, '')}/${path}`;
925
+ }
926
+ applyUpdatedSettings(settings, values) {
927
+ const valueMap = new Map(values.map((item) => [item.key, item.value]));
928
+ const nextSettings = settings.map((setting) => {
929
+ if (!valueMap.has(setting.key)) {
930
+ return setting;
931
+ }
932
+ return {
933
+ ...setting,
934
+ value: valueMap.get(setting.key),
935
+ };
936
+ });
937
+ const existingKeys = new Set(nextSettings.map((setting) => setting.key));
938
+ for (const item of values) {
939
+ if (existingKeys.has(item.key)) {
940
+ continue;
941
+ }
942
+ nextSettings.push({
943
+ key: item.key,
944
+ label: item.key,
945
+ description: item.key,
946
+ value: item.value,
947
+ });
948
+ }
949
+ return nextSettings.sort((left, right) => left.key.localeCompare(right.key));
950
+ }
951
+ areEqual(left, right) {
952
+ return JSON.stringify(left) === JSON.stringify(right);
953
+ }
954
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: SystemSettings, deps: [], target: i0.ɵɵFactoryTarget.Component });
955
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: SystemSettings, isStandalone: true, selector: "mt-system-settings", inputs: { apiBasePath: { classPropertyName: "apiBasePath", publicName: "apiBasePath", isSignal: true, isRequired: false, transformFunction: null }, backRoute: { classPropertyName: "backRoute", publicName: "backRoute", isSignal: true, isRequired: false, transformFunction: null }, formatSchema: { classPropertyName: "formatSchema", publicName: "formatSchema", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<ng-container *transloco=\"let t; prefix: 'system-settings'\">\r\n <mt-page\r\n [title]=\"t('page-title')\"\r\n [avatarIcon]=\"'general.settings-02'\"\r\n (backButtonClick)=\"goBack()\"\r\n backButton\r\n >\r\n <div class=\"flex flex-col gap-6\">\r\n <div\r\n class=\"flex flex-col gap-4 md:flex-row md:items-start md:justify-between\"\r\n >\r\n <div class=\"space-y-2\">\r\n <h3 class=\"text-lg font-bold text-neutral-900\">\r\n {{ t(\"page-title\") }}\r\n </h3>\r\n <p class=\"max-w-3xl text-sm text-neutral-600\">\r\n {{ t(\"page-subtitle\") }}\r\n </p>\r\n </div>\r\n\r\n <mt-button\r\n [label]=\"t('save')\"\r\n [loading]=\"updating()\"\r\n [disabled]=\"!canSaveSettings()\"\r\n (onClick)=\"onSave()\"\r\n />\r\n </div>\r\n\r\n @if (isLoading()) {\r\n <div class=\"flex items-center justify-center py-16\">\r\n <div class=\"text-center\">\r\n <div\r\n class=\"inline-block h-8 w-8 animate-spin rounded-full border-4 border-solid border-current border-e-transparent align-[-0.125em]\"\r\n role=\"status\"\r\n >\r\n <span\r\n class=\"absolute -m-px h-px w-px overflow-hidden whitespace-nowrap border-0 p-0 [clip:rect(0,0,0,0)]\"\r\n >\r\n {{ t(\"loading\") }}\r\n </span>\r\n </div>\r\n <p class=\"mt-3 text-sm text-neutral-600\">\r\n {{ t(\"loading\") }}\r\n </p>\r\n </div>\r\n </div>\r\n } @else {\r\n <div class=\"space-y-4\">\r\n @if (timezonesError(); as timezonesErrorMessage) {\r\n <div\r\n class=\"rounded-xl border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700\"\r\n >\r\n {{ timezonesErrorMessage }}\r\n </div>\r\n }\r\n\r\n @if (settingsError(); as settingsErrorMessage) {\r\n <div\r\n class=\"rounded-xl border border-amber-200 bg-amber-50 px-4 py-3 text-sm text-amber-800\"\r\n >\r\n {{ settingsErrorMessage }}\r\n </div>\r\n }\r\n\r\n @if (updateError(); as saveErrorMessage) {\r\n <div\r\n class=\"rounded-xl border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700\"\r\n >\r\n {{ saveErrorMessage }}\r\n </div>\r\n }\r\n </div>\r\n\r\n <div class=\"space-y-6\">\r\n <mt-system-settings-holidays-section\r\n [holidays]=\"holidayTableRows()\"\r\n (addHoliday)=\"openAddHoliday()\"\r\n (editHoliday)=\"editHoliday($event)\"\r\n (deleteHoliday)=\"deleteHoliday($event)\"\r\n />\r\n\r\n <mt-system-settings-general-section\r\n [timezoneForm]=\"form.controls.timezone\"\r\n [currencyForm]=\"form.controls.currency\"\r\n [weekendForm]=\"form.controls.weekend\"\r\n [timezoneOptions]=\"timezoneOptions()\"\r\n [dateFormatOptions]=\"dateFormatOptions()\"\r\n [timeFormatOptions]=\"timeFormatOptions()\"\r\n [currencyOptions]=\"currencyOptions()\"\r\n [currencyFormatOptions]=\"currencyFormatOptions()\"\r\n [weekendOptions]=\"weekendOptions()\"\r\n />\r\n\r\n <mt-system-settings-smtp-section [smtpForm]=\"form.controls.smtp\" />\r\n </div>\r\n }\r\n </div>\r\n </mt-page>\r\n</ng-container>\r\n", styles: [":host{display:block}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: Page, selector: "mt-page", inputs: ["backButton", "backButtonIcon", "avatarIcon", "avatarStyle", "avatarShape", "title", "tabs", "activeTab", "contentClass", "contentId"], outputs: ["backButtonClick", "tabChange"] }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: SystemSettingsHolidaysSection, selector: "mt-system-settings-holidays-section", inputs: ["holidays"], outputs: ["addHoliday", "editHoliday", "deleteHoliday"] }, { kind: "component", type: SystemSettingsGeneralSection, selector: "mt-system-settings-general-section", inputs: ["timezoneForm", "currencyForm", "weekendForm", "timezoneOptions", "dateFormatOptions", "timeFormatOptions", "currencyOptions", "currencyFormatOptions", "weekendOptions"] }, { kind: "component", type: SystemSettingsSmtpSection, selector: "mt-system-settings-smtp-section", inputs: ["smtpForm"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
956
+ }
957
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: SystemSettings, decorators: [{
958
+ type: Component,
959
+ args: [{ selector: 'mt-system-settings', imports: [
960
+ CommonModule,
961
+ ReactiveFormsModule,
962
+ TranslocoDirective,
963
+ Page,
964
+ Button,
965
+ SystemSettingsHolidaysSection,
966
+ SystemSettingsGeneralSection,
967
+ SystemSettingsSmtpSection,
968
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *transloco=\"let t; prefix: 'system-settings'\">\r\n <mt-page\r\n [title]=\"t('page-title')\"\r\n [avatarIcon]=\"'general.settings-02'\"\r\n (backButtonClick)=\"goBack()\"\r\n backButton\r\n >\r\n <div class=\"flex flex-col gap-6\">\r\n <div\r\n class=\"flex flex-col gap-4 md:flex-row md:items-start md:justify-between\"\r\n >\r\n <div class=\"space-y-2\">\r\n <h3 class=\"text-lg font-bold text-neutral-900\">\r\n {{ t(\"page-title\") }}\r\n </h3>\r\n <p class=\"max-w-3xl text-sm text-neutral-600\">\r\n {{ t(\"page-subtitle\") }}\r\n </p>\r\n </div>\r\n\r\n <mt-button\r\n [label]=\"t('save')\"\r\n [loading]=\"updating()\"\r\n [disabled]=\"!canSaveSettings()\"\r\n (onClick)=\"onSave()\"\r\n />\r\n </div>\r\n\r\n @if (isLoading()) {\r\n <div class=\"flex items-center justify-center py-16\">\r\n <div class=\"text-center\">\r\n <div\r\n class=\"inline-block h-8 w-8 animate-spin rounded-full border-4 border-solid border-current border-e-transparent align-[-0.125em]\"\r\n role=\"status\"\r\n >\r\n <span\r\n class=\"absolute -m-px h-px w-px overflow-hidden whitespace-nowrap border-0 p-0 [clip:rect(0,0,0,0)]\"\r\n >\r\n {{ t(\"loading\") }}\r\n </span>\r\n </div>\r\n <p class=\"mt-3 text-sm text-neutral-600\">\r\n {{ t(\"loading\") }}\r\n </p>\r\n </div>\r\n </div>\r\n } @else {\r\n <div class=\"space-y-4\">\r\n @if (timezonesError(); as timezonesErrorMessage) {\r\n <div\r\n class=\"rounded-xl border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700\"\r\n >\r\n {{ timezonesErrorMessage }}\r\n </div>\r\n }\r\n\r\n @if (settingsError(); as settingsErrorMessage) {\r\n <div\r\n class=\"rounded-xl border border-amber-200 bg-amber-50 px-4 py-3 text-sm text-amber-800\"\r\n >\r\n {{ settingsErrorMessage }}\r\n </div>\r\n }\r\n\r\n @if (updateError(); as saveErrorMessage) {\r\n <div\r\n class=\"rounded-xl border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700\"\r\n >\r\n {{ saveErrorMessage }}\r\n </div>\r\n }\r\n </div>\r\n\r\n <div class=\"space-y-6\">\r\n <mt-system-settings-holidays-section\r\n [holidays]=\"holidayTableRows()\"\r\n (addHoliday)=\"openAddHoliday()\"\r\n (editHoliday)=\"editHoliday($event)\"\r\n (deleteHoliday)=\"deleteHoliday($event)\"\r\n />\r\n\r\n <mt-system-settings-general-section\r\n [timezoneForm]=\"form.controls.timezone\"\r\n [currencyForm]=\"form.controls.currency\"\r\n [weekendForm]=\"form.controls.weekend\"\r\n [timezoneOptions]=\"timezoneOptions()\"\r\n [dateFormatOptions]=\"dateFormatOptions()\"\r\n [timeFormatOptions]=\"timeFormatOptions()\"\r\n [currencyOptions]=\"currencyOptions()\"\r\n [currencyFormatOptions]=\"currencyFormatOptions()\"\r\n [weekendOptions]=\"weekendOptions()\"\r\n />\r\n\r\n <mt-system-settings-smtp-section [smtpForm]=\"form.controls.smtp\" />\r\n </div>\r\n }\r\n </div>\r\n </mt-page>\r\n</ng-container>\r\n", styles: [":host{display:block}\n"] }]
969
+ }], ctorParameters: () => [], propDecorators: { apiBasePath: [{ type: i0.Input, args: [{ isSignal: true, alias: "apiBasePath", required: false }] }], backRoute: [{ type: i0.Input, args: [{ isSignal: true, alias: "backRoute", required: false }] }], formatSchema: [{ type: i0.Input, args: [{ isSignal: true, alias: "formatSchema", required: false }] }] } });
970
+ function isRecord(value) {
971
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
972
+ }
973
+ function getString(value) {
974
+ if (typeof value !== 'string') {
975
+ return null;
976
+ }
977
+ const normalizedValue = value.trim();
978
+ return normalizedValue ? normalizedValue : null;
979
+ }
980
+ function getNullableString(value) {
981
+ if (typeof value !== 'string') {
982
+ return null;
983
+ }
984
+ return value.trim() || null;
985
+ }
986
+ function getNullableNumber(value) {
987
+ if (typeof value === 'number' && !Number.isNaN(value)) {
988
+ return value;
989
+ }
990
+ if (typeof value === 'string' && value.trim()) {
991
+ const parsedValue = Number(value);
992
+ return Number.isNaN(parsedValue) ? null : parsedValue;
993
+ }
994
+ return null;
995
+ }
996
+ function parsePort(value) {
997
+ const normalizedValue = value.trim();
998
+ if (!normalizedValue) {
999
+ return null;
1000
+ }
1001
+ const parsedValue = Number(normalizedValue);
1002
+ return Number.isNaN(parsedValue) ? null : parsedValue;
1003
+ }
1004
+ function normalizeWeekendDays(value) {
1005
+ if (!Array.isArray(value)) {
1006
+ return [];
1007
+ }
1008
+ return value
1009
+ .map((item) => (typeof item === 'number' ? item : Number(item)))
1010
+ .filter((item) => Number.isInteger(item) && item >= 1 && item <= 7)
1011
+ .sort((left, right) => left - right);
1012
+ }
1013
+ function normalizeDateInput(value) {
1014
+ if (value instanceof Date) {
1015
+ if (Number.isNaN(value.getTime())) {
1016
+ return null;
1017
+ }
1018
+ return createLocalDate(value.getFullYear(), value.getMonth() + 1, value.getDate());
1019
+ }
1020
+ if (typeof value !== 'string') {
1021
+ return null;
1022
+ }
1023
+ const normalizedValue = value.trim();
1024
+ if (!normalizedValue) {
1025
+ return null;
1026
+ }
1027
+ const dateOnlyMatch = normalizedValue.match(/^(\d{4})[-/](\d{2})[-/](\d{2})/);
1028
+ if (dateOnlyMatch) {
1029
+ const [, year, month, day] = dateOnlyMatch;
1030
+ return createLocalDate(Number(year), Number(month), Number(day));
1031
+ }
1032
+ const parsedDate = new Date(normalizedValue);
1033
+ if (Number.isNaN(parsedDate.getTime())) {
1034
+ return null;
1035
+ }
1036
+ return createLocalDate(parsedDate.getFullYear(), parsedDate.getMonth() + 1, parsedDate.getDate());
1037
+ }
1038
+ function createLocalDate(year, month, day) {
1039
+ return new Date(year, month - 1, day, 12, 0, 0, 0);
1040
+ }
1041
+ function formatDateOnly(value) {
1042
+ const year = value.getFullYear();
1043
+ const month = String(value.getMonth() + 1).padStart(2, '0');
1044
+ const day = String(value.getDate()).padStart(2, '0');
1045
+ return `${year}-${month}-${day}`;
1046
+ }
1047
+
1048
+ /**
1049
+ * Generated bundle index. Do not edit.
1050
+ */
1051
+
1052
+ export { DEFAULT_DATE_FORMAT_OPTIONS, DEFAULT_TIME_FORMAT_OPTIONS, FIXED_CURRENCIES, SystemSettings, SystemSettingsHolidayEditor, WEEKEND_DAY_DEFINITIONS };
1053
+ //# sourceMappingURL=masterteam-system-settings.mjs.map