@cityway/bo-ui 1.0.0 → 1.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.
Files changed (208) hide show
  1. package/.eslintrc.json +37 -0
  2. package/ng-package.json +21 -0
  3. package/package.json +21 -32
  4. package/src/lib/bo-ui.config.ts +8 -0
  5. package/src/lib/components/accordions/accordions.component.html +16 -0
  6. package/src/lib/components/accordions/accordions.component.spec.ts +24 -0
  7. package/src/lib/components/accordions/accordions.component.ts +27 -0
  8. package/src/lib/components/accordions/components/accordions-content.component.spec.ts +24 -0
  9. package/src/lib/components/accordions/components/accordions-content.component.ts +28 -0
  10. package/src/lib/components/alert/alert.component.html +15 -0
  11. package/src/lib/components/alert/alert.component.spec.ts +24 -0
  12. package/src/lib/components/alert/alert.component.ts +36 -0
  13. package/src/lib/components/badge/badge.component.html +7 -0
  14. package/src/lib/components/badge/badge.component.spec.ts +24 -0
  15. package/src/lib/components/badge/badge.component.ts +24 -0
  16. package/src/lib/components/button/button.component.html +43 -0
  17. package/src/lib/components/button/button.component.spec.ts +25 -0
  18. package/src/lib/components/button/button.component.ts +47 -0
  19. package/src/lib/components/card/card.component.html +15 -0
  20. package/src/lib/components/card/card.component.spec.ts +25 -0
  21. package/src/lib/components/card/card.component.ts +30 -0
  22. package/src/lib/components/custom-list/custom-list.component.html +31 -0
  23. package/src/lib/components/custom-list/custom-list.component.spec.ts +24 -0
  24. package/src/lib/components/custom-list/custom-list.component.ts +42 -0
  25. package/src/lib/components/drag-n-drop-list/drag-n-drop-list.component.html +27 -0
  26. package/src/lib/components/drag-n-drop-list/drag-n-drop-list.component.spec.ts +24 -0
  27. package/src/lib/components/drag-n-drop-list/drag-n-drop-list.component.ts +40 -0
  28. package/src/lib/components/form-field/form-field.component.html +333 -0
  29. package/src/lib/components/form-field/form-field.component.spec.ts +24 -0
  30. package/src/lib/components/form-field/form-field.component.ts +256 -0
  31. package/src/lib/components/icon/icon.component.html +9 -0
  32. package/src/lib/components/icon/icon.component.spec.ts +25 -0
  33. package/src/lib/components/icon/icon.component.ts +31 -0
  34. package/src/lib/components/layout/admin-layout/admin-layout.component.html +17 -0
  35. package/src/lib/components/layout/admin-layout/admin-layout.component.ts +181 -0
  36. package/src/lib/components/layout/footer/footer.component.html +51 -0
  37. package/src/lib/components/layout/footer/footer.component.ts +65 -0
  38. package/src/lib/components/layout/header/header.component.html +71 -0
  39. package/src/lib/components/layout/header/header.component.ts +95 -0
  40. package/src/lib/components/layout/menu/menu.component.html +115 -0
  41. package/src/lib/components/layout/menu/menu.component.ts +75 -0
  42. package/src/lib/components/layout/menu-accordion/accordion.directive.ts +57 -0
  43. package/src/lib/components/layout/menu-accordion/accordionanchor.directive.ts +21 -0
  44. package/src/lib/components/layout/menu-accordion/accordionlink.directive.ts +45 -0
  45. package/src/lib/components/layout/menu-accordion/index.ts +3 -0
  46. package/src/lib/components/layout/sidebar/sidebar.component.html +62 -0
  47. package/src/lib/components/layout/sidebar/sidebar.component.ts +28 -0
  48. package/src/lib/components/layout/skip-links/skip-links.component.html +3 -0
  49. package/src/lib/components/layout/skip-links/skip-links.component.spec.ts +25 -0
  50. package/src/lib/components/layout/skip-links/skip-links.component.ts +19 -0
  51. package/src/lib/components/layout/title-breadcrumb/title-breadcrumb.component.html +10 -0
  52. package/src/lib/components/layout/title-breadcrumb/title-breadcrumb.component.spec.ts +25 -0
  53. package/src/lib/components/layout/title-breadcrumb/title-breadcrumb.component.ts +16 -0
  54. package/src/lib/components/legend/legend.component.html +23 -0
  55. package/src/lib/components/legend/legend.component.spec.ts +24 -0
  56. package/src/lib/components/legend/legend.component.ts +28 -0
  57. package/src/lib/components/loader/loader.component.html +4 -0
  58. package/src/lib/components/loader/loader.component.ts +16 -0
  59. package/src/lib/components/modals/modals.component.html +71 -0
  60. package/src/lib/components/modals/modals.component.spec.ts +25 -0
  61. package/src/lib/components/modals/modals.component.ts +49 -0
  62. package/src/lib/components/tab/components/tab-content.component.spec.ts +24 -0
  63. package/src/lib/components/tab/components/tab-content.component.ts +27 -0
  64. package/src/lib/components/tab/tab.component.html +59 -0
  65. package/src/lib/components/tab/tab.component.spec.ts +24 -0
  66. package/src/lib/components/tab/tab.component.ts +79 -0
  67. package/src/lib/components/table/components/actions-on-table/actions-on-table.component.html +50 -0
  68. package/src/lib/components/table/components/actions-on-table/actions-on-table.component.spec.ts +24 -0
  69. package/src/lib/components/table/components/actions-on-table/actions-on-table.component.ts +33 -0
  70. package/src/lib/components/table/components/filter/filter.component.html +21 -0
  71. package/src/lib/components/table/components/filter/filter.component.spec.ts +24 -0
  72. package/src/lib/components/table/components/filter/filter.component.ts +38 -0
  73. package/src/lib/components/table/table.component.html +104 -0
  74. package/src/lib/components/table/table.component.spec.ts +24 -0
  75. package/src/lib/components/table/table.component.ts +85 -0
  76. package/src/lib/components/wizard-stepper/components/wizard-step.component.spec.ts +25 -0
  77. package/src/lib/components/wizard-stepper/components/wizard-step.component.ts +16 -0
  78. package/src/lib/components/wizard-stepper/wizard-stepper.component.html +45 -0
  79. package/src/lib/components/wizard-stepper/wizard-stepper.component.spec.ts +25 -0
  80. package/src/lib/components/wizard-stepper/wizard-stepper.component.ts +70 -0
  81. package/src/lib/directives/double-scroll.ts +64 -0
  82. package/src/lib/directives/rwd-tabs.ts +99 -0
  83. package/src/lib/directives/show-hide-password.ts +61 -0
  84. package/src/lib/enum/drag-item.enum.ts +5 -0
  85. package/src/lib/enum/field-type.enum.ts +36 -0
  86. package/src/lib/enum/legend-type.enum.ts +5 -0
  87. package/src/lib/enum/modals.enum.ts +6 -0
  88. package/src/lib/enum/ui-type.enum.ts +11 -0
  89. package/src/lib/models/ui/custom-list.model.ts +14 -0
  90. package/src/lib/models/ui/legend.model.ts +17 -0
  91. package/src/lib/models/ui/table.model.ts +33 -0
  92. package/src/lib/services/ui/modals.service.ts +47 -0
  93. package/src/lib/services/version.service.ts +22 -0
  94. package/src/public-api.ts +49 -0
  95. package/tsconfig.lib.json +18 -0
  96. package/tsconfig.lib.prod.json +11 -0
  97. package/tsconfig.spec.json +14 -0
  98. package/tslint.json +17 -0
  99. package/cityway-bo-ui-1.0.0.tgz +0 -0
  100. package/fesm2022/cityway-bo-ui.mjs +0 -1598
  101. package/fesm2022/cityway-bo-ui.mjs.map +0 -1
  102. package/index.d.ts +0 -509
  103. package/styles.min.css +0 -5
  104. package/styles.min.css.map +0 -1
  105. /package/{lib → src/lib}/assets/fonts/bo/_variables.scss +0 -0
  106. /package/{lib → src/lib}/assets/fonts/bo/bo.scss +0 -0
  107. /package/{lib → src/lib}/assets/fonts/bo/bo.woff +0 -0
  108. /package/{lib → src/lib}/assets/fonts/bo/bo.woff2 +0 -0
  109. /package/{lib → src/lib}/assets/fonts/nunito/_nunito.scss +0 -0
  110. /package/{lib → src/lib}/assets/fonts/nunito/nunito-bold.woff +0 -0
  111. /package/{lib → src/lib}/assets/fonts/nunito/nunito-bold.woff2 +0 -0
  112. /package/{lib → src/lib}/assets/fonts/nunito/nunito-extrabold.woff +0 -0
  113. /package/{lib → src/lib}/assets/fonts/nunito/nunito-extrabold.woff2 +0 -0
  114. /package/{lib → src/lib}/assets/fonts/nunito/nunito-regular.woff +0 -0
  115. /package/{lib → src/lib}/assets/fonts/nunito/nunito-regular.woff2 +0 -0
  116. /package/{lib → src/lib}/assets/fonts/nunito/nunito-semi-bold.woff +0 -0
  117. /package/{lib → src/lib}/assets/fonts/nunito/nunito-semi-bold.woff2 +0 -0
  118. /package/{lib → src/lib}/assets/fonts/optyweb/_variables.scss +0 -0
  119. /package/{lib → src/lib}/assets/fonts/optyweb/optyweb.scss +0 -0
  120. /package/{lib → src/lib}/assets/fonts/optyweb/optyweb.woff +0 -0
  121. /package/{lib → src/lib}/assets/fonts/optyweb/optyweb.woff2 +0 -0
  122. /package/{lib → src/lib}/assets/i18n/common.en.json +0 -0
  123. /package/{lib → src/lib}/assets/i18n/common.fr.json +0 -0
  124. /package/{lib → src/lib}/assets/i18n/label.en.json +0 -0
  125. /package/{lib → src/lib}/assets/i18n/label.fr.json +0 -0
  126. /package/{lib → src/lib}/assets/images/common/bg-loader.svg +0 -0
  127. /package/{lib → src/lib}/assets/images/common/bg-menu.svg +0 -0
  128. /package/{lib → src/lib}/assets/images/common/bg-round.svg +0 -0
  129. /package/{lib → src/lib}/assets/images/common/check-mark.svg +0 -0
  130. /package/{lib → src/lib}/assets/images/common/loader.svg +0 -0
  131. /package/{lib → src/lib}/assets/images/common/logo-en-bw.svg +0 -0
  132. /package/{lib → src/lib}/assets/images/common/logo-en.svg +0 -0
  133. /package/{lib → src/lib}/assets/images/common/logo-fr-bw.svg +0 -0
  134. /package/{lib → src/lib}/assets/images/common/logo-fr.svg +0 -0
  135. /package/{lib → src/lib}/assets/images/favicon/android-chrome-192x192.png +0 -0
  136. /package/{lib → src/lib}/assets/images/favicon/android-chrome-512x512.png +0 -0
  137. /package/{lib → src/lib}/assets/images/favicon/apple-touch-icon.png +0 -0
  138. /package/{lib → src/lib}/assets/images/favicon/favicon-16x16.png +0 -0
  139. /package/{lib → src/lib}/assets/images/favicon/favicon-32x32.png +0 -0
  140. /package/{lib → src/lib}/assets/images/favicon/favicon-96x96.png +0 -0
  141. /package/{lib → src/lib}/assets/images/favicon/favicon.ico +0 -0
  142. /package/{lib → src/lib}/assets/images/favicon/site.webmanifest +0 -0
  143. /package/{lib → src/lib}/assets/images/icon/referential-icon.svg +0 -0
  144. /package/{lib → src/lib}/assets/images/login/login-bg.jpg +0 -0
  145. /package/{lib → src/lib}/assets/images/login/logo-cityway-baseline.svg +0 -0
  146. /package/{lib → src/lib}/assets/images/toast/warning.svg +0 -0
  147. /package/{lib → src/lib}/assets/styles/scss/_components.scss +0 -0
  148. /package/{lib → src/lib}/assets/styles/scss/_core.scss +0 -0
  149. /package/{lib → src/lib}/assets/styles/scss/_custom-bootstrap.scss +0 -0
  150. /package/{lib → src/lib}/assets/styles/scss/bootstrap/_accordion.scss +0 -0
  151. /package/{lib → src/lib}/assets/styles/scss/bootstrap/_alert.scss +0 -0
  152. /package/{lib → src/lib}/assets/styles/scss/bootstrap/_badge.scss +0 -0
  153. /package/{lib → src/lib}/assets/styles/scss/bootstrap/_breadcrumb.scss +0 -0
  154. /package/{lib → src/lib}/assets/styles/scss/bootstrap/_button-group.scss +0 -0
  155. /package/{lib → src/lib}/assets/styles/scss/bootstrap/_buttons.scss +0 -0
  156. /package/{lib → src/lib}/assets/styles/scss/bootstrap/_card.scss +0 -0
  157. /package/{lib → src/lib}/assets/styles/scss/bootstrap/_close.scss +0 -0
  158. /package/{lib → src/lib}/assets/styles/scss/bootstrap/_dropdown.scss +0 -0
  159. /package/{lib → src/lib}/assets/styles/scss/bootstrap/_forms.scss +0 -0
  160. /package/{lib → src/lib}/assets/styles/scss/bootstrap/_input-group.scss +0 -0
  161. /package/{lib → src/lib}/assets/styles/scss/bootstrap/_lists.scss +0 -0
  162. /package/{lib → src/lib}/assets/styles/scss/bootstrap/_modal.scss +0 -0
  163. /package/{lib → src/lib}/assets/styles/scss/bootstrap/_pagination.scss +0 -0
  164. /package/{lib → src/lib}/assets/styles/scss/bootstrap/_popover.scss +0 -0
  165. /package/{lib → src/lib}/assets/styles/scss/bootstrap/_progress.scss +0 -0
  166. /package/{lib → src/lib}/assets/styles/scss/bootstrap/_reboot.scss +0 -0
  167. /package/{lib → src/lib}/assets/styles/scss/bootstrap/_tables.scss +0 -0
  168. /package/{lib → src/lib}/assets/styles/scss/bootstrap/_tabs.scss +0 -0
  169. /package/{lib → src/lib}/assets/styles/scss/bootstrap/_tooltip.scss +0 -0
  170. /package/{lib → src/lib}/assets/styles/scss/bootstrap/_type.scss +0 -0
  171. /package/{lib → src/lib}/assets/styles/scss/components/_forms-firefox.scss +0 -0
  172. /package/{lib → src/lib}/assets/styles/scss/components/_leaflet.scss +0 -0
  173. /package/{lib → src/lib}/assets/styles/scss/components/_legend.scss +0 -0
  174. /package/{lib → src/lib}/assets/styles/scss/components/_ng-select.scss +0 -0
  175. /package/{lib → src/lib}/assets/styles/scss/components/_ng2-dragula.scss +0 -0
  176. /package/{lib → src/lib}/assets/styles/scss/components/_ng2-validation.scss +0 -0
  177. /package/{lib → src/lib}/assets/styles/scss/components/_ng5-slider.scss +0 -0
  178. /package/{lib → src/lib}/assets/styles/scss/components/_ngb-datepicker.scss +0 -0
  179. /package/{lib → src/lib}/assets/styles/scss/components/_ngb-timepicker.scss +0 -0
  180. /package/{lib → src/lib}/assets/styles/scss/components/_ngx-chips.scss +0 -0
  181. /package/{lib → src/lib}/assets/styles/scss/components/_ngx-editor.scss +0 -0
  182. /package/{lib → src/lib}/assets/styles/scss/components/_ngx-file-drop.scss +0 -0
  183. /package/{lib → src/lib}/assets/styles/scss/components/_ngx-intl-tel-input.scss +0 -0
  184. /package/{lib → src/lib}/assets/styles/scss/components/_ngx-slider.scss +0 -0
  185. /package/{lib → src/lib}/assets/styles/scss/components/_ngx-toast.scss +0 -0
  186. /package/{lib → src/lib}/assets/styles/scss/components/_pwd-policy.scss +0 -0
  187. /package/{lib → src/lib}/assets/styles/scss/components/_table.scss +0 -0
  188. /package/{lib → src/lib}/assets/styles/scss/components/_vis.scss +0 -0
  189. /package/{lib → src/lib}/assets/styles/scss/components/_wizard-stepper.scss +0 -0
  190. /package/{lib → src/lib}/assets/styles/scss/components/table/_table-action.scss +0 -0
  191. /package/{lib → src/lib}/assets/styles/scss/components/table/_table-bg-cell.scss +0 -0
  192. /package/{lib → src/lib}/assets/styles/scss/components/table/_table-double-scroll.scss +0 -0
  193. /package/{lib → src/lib}/assets/styles/scss/components/table/_table-filter.scss +0 -0
  194. /package/{lib → src/lib}/assets/styles/scss/components/table/_table-pagination.scss +0 -0
  195. /package/{lib → src/lib}/assets/styles/scss/components/table/_table-popover.scss +0 -0
  196. /package/{lib → src/lib}/assets/styles/scss/components/table/_table-sorting.scss +0 -0
  197. /package/{lib → src/lib}/assets/styles/scss/core/_footer.scss +0 -0
  198. /package/{lib → src/lib}/assets/styles/scss/core/_header.scss +0 -0
  199. /package/{lib → src/lib}/assets/styles/scss/core/_layout.scss +0 -0
  200. /package/{lib → src/lib}/assets/styles/scss/core/_menu.scss +0 -0
  201. /package/{lib → src/lib}/assets/styles/scss/core/_sidebar.scss +0 -0
  202. /package/{lib → src/lib}/assets/styles/scss/mixins/_utilities.scss +0 -0
  203. /package/{lib → src/lib}/assets/styles/scss/styles.scss +0 -0
  204. /package/{lib → src/lib}/assets/styles/scss/tools/_focus.scss +0 -0
  205. /package/{lib → src/lib}/assets/styles/scss/tools/_loader.scss +0 -0
  206. /package/{lib → src/lib}/assets/styles/scss/variables/_colors.scss +0 -0
  207. /package/{lib → src/lib}/assets/styles/scss/variables/_custom.scss +0 -0
  208. /package/{lib → src/lib}/assets/styles/scss/variables/_site.scss +0 -0
@@ -0,0 +1,256 @@
1
+ import { Component, EventEmitter, HostBinding, Input, OnInit, Output, TemplateRef } from '@angular/core';
2
+ import { AbstractControl, FormControl, FormGroup, FormsModule, ReactiveFormsModule, ValidationErrors } from '@angular/forms';
3
+ import { FormFieldOption, FormFieldTypeEnum } from '../../enum/field-type.enum';
4
+ import { NgxSliderModule, Options } from '@angular-slider/ngx-slider';
5
+ import { CommonModule } from '@angular/common';
6
+ import { TranslateModule } from '@ngx-translate/core';
7
+ import { NgSelectModule } from '@ng-select/ng-select';
8
+ import { NgbDropdownModule, NgbPopover } from '@ng-bootstrap/ng-bootstrap';
9
+ import { ShowHidePasswordDirective } from '../../directives/show-hide-password';
10
+ import { IconComponent } from '../icon/icon.component';
11
+
12
+ export function rangeValidator(group: AbstractControl, type: 'date' | 'time' | 'datetime'): ValidationErrors | null {
13
+ const startControl = group.get('start');
14
+ const endControl = group.get('end');
15
+ const start = startControl?.value;
16
+ const end = endControl?.value;
17
+
18
+ if (!start || !end) return null;
19
+
20
+ let startValue: number;
21
+ let endValue: number;
22
+
23
+ switch (type) {
24
+ case 'time':
25
+ startValue = parseTime(start);
26
+ endValue = parseTime(end);
27
+ break;
28
+ case 'datetime':
29
+ startValue = new Date(start).getTime();
30
+ endValue = new Date(end).getTime();
31
+ break;
32
+ default: // date
33
+ startValue = new Date(start).setHours(0, 0, 0, 0);
34
+ endValue = new Date(end).setHours(0, 0, 0, 0);
35
+ }
36
+
37
+ if (startValue > endValue) {
38
+ // Marquer les enfants comme invalid
39
+ startControl?.setErrors({ ...startControl.errors, rangeInvalid: true });
40
+ endControl?.setErrors({ ...endControl.errors, rangeInvalid: true });
41
+ return { rangeInvalid: true };
42
+ } else {
43
+ // Supprimer l’erreur rangeInvalid si présente
44
+ if (startControl?.errors?.['rangeInvalid']) {
45
+ const { rangeInvalid, ...rest } = startControl.errors!;
46
+ startControl.setErrors(Object.keys(rest).length ? rest : null);
47
+ }
48
+ if (endControl?.errors?.['rangeInvalid']) {
49
+ const { rangeInvalid, ...rest } = endControl.errors!;
50
+ endControl.setErrors(Object.keys(rest).length ? rest : null);
51
+ }
52
+ }
53
+ return null;
54
+ }
55
+
56
+ function parseTime(time: string): number {
57
+ const [h, m] = time.split(':').map(Number);
58
+ return h * 60 + m;
59
+ }
60
+
61
+
62
+ @Component({
63
+ selector: 'app-form-field',
64
+ templateUrl: './form-field.component.html',
65
+ standalone: true,
66
+ imports: [
67
+ CommonModule,
68
+ TranslateModule,
69
+ FormsModule,
70
+ ReactiveFormsModule,
71
+ NgSelectModule,
72
+ NgbDropdownModule,
73
+ NgxSliderModule,
74
+ NgbPopover,
75
+ ShowHidePasswordDirective,
76
+ IconComponent
77
+ ]
78
+ })
79
+
80
+ export class FormFieldComponent implements OnInit {
81
+
82
+ @Input() control!: AbstractControl;
83
+ @Input() formGroup!: FormGroup;
84
+ @Input() type: FormFieldTypeEnum;
85
+ @Input() label!: string;
86
+ @Input() name!: string;
87
+ @Input() placeholder!: string;
88
+ @Input() options: FormFieldOption[] = [];
89
+ @Input() isRequired = false;
90
+ @Input() help!: string;
91
+ @Input() tooltip!: string;
92
+ @Input() addonLeft!: TemplateRef<any>;
93
+ @Input() addonRight!: TemplateRef<any>;
94
+ @Input() isInAddon = false;
95
+ @Input() isReadonly = false;
96
+ @Input() isDisabled = false;
97
+ @Input() sliderValue!: number;
98
+ @Input() sliderOptions!: Options;
99
+ @Input() cssClass!: string;
100
+ @Input() inTableFilter = false;
101
+
102
+ @Output() clearFieldFilter = new EventEmitter<string>();
103
+ @Output() refreshEvent = new EventEmitter<void>();
104
+
105
+ public typeField = FormFieldTypeEnum;
106
+
107
+
108
+ @HostBinding('class')
109
+ get hostClasses(): string {
110
+ return 'position-relative';
111
+ }
112
+
113
+ constructor() { }
114
+
115
+ public get isRange(): boolean {
116
+ if (!this.control) return false;
117
+ return this.control instanceof FormGroup &&
118
+ 'start' in (this.control as any).controls &&
119
+ 'end' in (this.control as any).controls;
120
+ }
121
+
122
+ public get formControl(): FormControl {
123
+ return this.control as FormControl;
124
+ }
125
+
126
+ public get controlOrGroup() {
127
+ return this.control ?? this.formGroup?.get(this.name);
128
+ }
129
+
130
+ ngOnInit(): void {
131
+
132
+ console.log(this.isRange, this.control);
133
+
134
+ if (this.formGroup && this.name) {
135
+ const group = this.formGroup.get(this.name);
136
+ if (group instanceof FormGroup) {
137
+ switch (this.type) {
138
+ case this.typeField.dateToDate:
139
+ group.setValidators(g => rangeValidator(g, 'date'));
140
+ break;
141
+ case this.typeField.timeToTime:
142
+ group.setValidators(g => rangeValidator(g, 'time'));
143
+ break;
144
+ case this.typeField.dateTimeToDateTime:
145
+ group.setValidators(g => rangeValidator(g, 'datetime'));
146
+ break;
147
+ }
148
+ group.updateValueAndValidity();
149
+ }
150
+ }
151
+ }
152
+
153
+ public onCheckboxChange(event: Event) {
154
+ const checkbox = event.target as HTMLInputElement;
155
+ const valueArray = this.control.value || [];
156
+
157
+ if (checkbox.checked) {
158
+ this.control.setValue([...valueArray, checkbox.value]);
159
+ } else {
160
+ this.control.setValue(valueArray.filter((v: string) => v !== checkbox.value));
161
+ }
162
+
163
+ this.control.markAsTouched();
164
+ }
165
+
166
+ public onBlur() {
167
+ if (this.control && !this.control.touched) {
168
+ this.control.markAsTouched();
169
+ }
170
+ }
171
+
172
+ public isInInputGroup(): boolean {
173
+ const inInputGroup = [
174
+ this.typeField.text,
175
+ this.typeField.date,
176
+ this.typeField.time,
177
+ this.typeField.dateTime,
178
+ this.typeField.number,
179
+ this.typeField.email,
180
+ this.typeField.textarea,
181
+ this.typeField.password,
182
+ ].includes(this.type)
183
+ return inInputGroup;
184
+ }
185
+
186
+ public getControl(path: 'start' | 'end'): FormControl | null {
187
+ if (!this.isRange) return null;
188
+ const group = this.control as FormGroup<{ start: FormControl; end: FormControl }>;
189
+ return group.get(path) as FormControl;
190
+ }
191
+
192
+ public getInputType(): string {
193
+ switch (this.type) {
194
+ case this.typeField.dateToDate:
195
+ return 'date';
196
+ case this.typeField.timeToTime:
197
+ return 'time';
198
+ case this.typeField.dateTimeToDateTime:
199
+ return 'datetime-local';
200
+ default:
201
+ return 'text';
202
+ }
203
+ }
204
+
205
+ public onClearFieldFilter() {
206
+ this.clearFieldFilter.emit();
207
+ }
208
+
209
+ public onClearFieldPeriod(path: 'start' | 'end'): void {
210
+ const ctrl = this.getControl(path);
211
+ if (ctrl) {
212
+ ctrl.setValue(null);
213
+ ctrl.markAsPristine();
214
+ ctrl.markAsUntouched();
215
+ }
216
+ }
217
+
218
+ public onClearField(control: FormControl): void {
219
+ control?.setValue(null);
220
+ control?.markAsPristine();
221
+ control?.markAsUntouched();
222
+ }
223
+
224
+ public onDateAddDay(direction: 'prev' | 'next'): void {
225
+ const current = this.getDateValue();
226
+ if (current) {
227
+ const delta = direction === 'prev' ? -1 : 1;
228
+ current.setDate(current.getDate() + delta);
229
+ this.formControl.setValue(this.formatDate(current));
230
+ }
231
+ }
232
+
233
+ public onTodayAddDay(days: number): void {
234
+ const today = new Date();
235
+ today.setDate(today.getDate() + days);
236
+ this.formControl.setValue(this.formatDate(today));
237
+ }
238
+
239
+ public onRefresh(): void {
240
+ this.refreshEvent.emit();
241
+ }
242
+
243
+ private getDateValue(): Date | null {
244
+ const value = this.formControl.value;
245
+ if (!value) return null;
246
+ const date = new Date(value);
247
+ return isNaN(date.getTime()) ? null : date;
248
+ }
249
+
250
+ private formatDate(date: Date): string {
251
+ const year = date.getFullYear();
252
+ const month = (date.getMonth() + 1).toString().padStart(2, '0');
253
+ const day = date.getDate().toString().padStart(2, '0');
254
+ return `${year}-${month}-${day}`;
255
+ }
256
+ }
@@ -0,0 +1,9 @@
1
+ <span [class]="font + ' icon'" [ngClass]="[icon, !withOnlyIcon ? 'me-2' : '', iconCssClass ? iconCssClass : '']" aria-hidden="true"
2
+ [attr.style]="iconColorCustom ? 'color: ' + iconColorCustom : null"></span>
3
+
4
+ @if (!withOnlyIcon) {
5
+ <span>{{ label }}</span>
6
+ }
7
+ @else {
8
+ <span class="visually-hidden">{{ label }}</span>
9
+ }
@@ -0,0 +1,25 @@
1
+ import { ComponentFixture, TestBed } from '@angular/core/testing';
2
+
3
+ import { IconComponent } from './icon.component';
4
+
5
+ describe('IconComponent', () => {
6
+ let component: IconComponent;
7
+ let fixture: ComponentFixture<IconComponent>;
8
+
9
+ beforeEach(async () => {
10
+ await TestBed.configureTestingModule({
11
+ declarations: [ IconComponent ]
12
+ })
13
+ .compileComponents();
14
+ });
15
+
16
+ beforeEach(() => {
17
+ fixture = TestBed.createComponent(IconComponent);
18
+ component = fixture.componentInstance;
19
+ fixture.detectChanges();
20
+ });
21
+
22
+ it('should create', () => {
23
+ expect(component).toBeTruthy();
24
+ });
25
+ });
@@ -0,0 +1,31 @@
1
+ import { CommonModule } from '@angular/common';
2
+ import { Component, HostBinding, Input, OnInit } from '@angular/core';
3
+
4
+ @Component({
5
+ selector: 'app-icon',
6
+ templateUrl: './icon.component.html',
7
+ standalone: true,
8
+ imports: [
9
+ CommonModule
10
+ ]
11
+ })
12
+ export class IconComponent implements OnInit {
13
+
14
+ @Input() icon = 'cw-alert-help';
15
+ @Input() font = 'optyweb';
16
+ @Input() withOnlyIcon = false;
17
+ @Input() label: string;
18
+ @Input() iconCssClass?: string;
19
+ @Input() iconColorCustom?: string;
20
+
21
+ constructor() { }
22
+
23
+ @HostBinding('class')
24
+
25
+ get hostClasses(): string {
26
+ return 'd-inline-flex align-items-center';
27
+ }
28
+
29
+ ngOnInit(): void {
30
+ }
31
+ }
@@ -0,0 +1,17 @@
1
+ <ngx-loading-bar></ngx-loading-bar>
2
+
3
+ <app-skip-links></app-skip-links>
4
+
5
+
6
+ <div class="wrapper">
7
+ <app-sidebar [isOpened]="isMenuOpened" class="bg-cover" [ngClass]="{'bg-closed' : !isMenuOpened, 'bg-opened' : isMenuOpened, 'responsive-menu': menuReponsiveMode}" (toggleSidenav)="onToggleMenu()"></app-sidebar>
8
+ <div class="wrapper-content flex-grow-1" [ngClass]="{'wrapper-content-closed' : !isMenuOpened, 'wrapper-content-opened' : isMenuOpened, 'wrapper-content-responsive': menuReponsiveMode}">
9
+ <app-header (toggleSidenav)="onToggleMenu()" [heading]="routeOptions.heading" [isMenuOpened]="isMenuOpened"
10
+ [headingUrlParamsOptions]="urlParamsOptions.value" [parent]="parentProperties"></app-header>
11
+ <main role="main" id="content" class="main-content">
12
+ <router-outlet>
13
+ </router-outlet>
14
+ </main>
15
+ <app-footer></app-footer>
16
+ </div>
17
+ </div>
@@ -0,0 +1,181 @@
1
+ import { CommonModule } from '@angular/common';
2
+ import { Component, ElementRef, NgZone, OnDestroy, OnInit, ViewChild } from '@angular/core';
3
+ import { Title } from '@angular/platform-browser';
4
+ import { ActivatedRoute, NavigationEnd, Router } from '@angular/router';
5
+ import { LoadingBarRouterModule } from '@ngx-loading-bar/router';
6
+ import { LangChangeEvent, TranslateService } from '@ngx-translate/core';
7
+ import { Subscription } from 'rxjs';
8
+ import { filter } from 'rxjs/operators';
9
+ import { SidebarComponent } from '../sidebar/sidebar.component';
10
+ import { SkipLinksComponent } from '../skip-links/skip-links.component';
11
+ import { FooterComponent } from '../footer/footer.component';
12
+ import { HeaderComponent } from '../header/header.component';
13
+
14
+ const SMALL_WIDTH_BREAKPOINT = 1300;
15
+
16
+ export interface Options {
17
+ heading?: string;
18
+ parent?: Parent | Array<Parent>;
19
+ removeFooter?: boolean;
20
+ }
21
+
22
+ export interface Parent {
23
+ title: string;
24
+ link: string;
25
+ }
26
+
27
+ @Component({
28
+ selector: 'app-admin',
29
+ templateUrl: './admin-layout.component.html',
30
+ standalone: true,
31
+ imports: [
32
+ LoadingBarRouterModule,
33
+ CommonModule,
34
+ SidebarComponent,
35
+ SkipLinksComponent,
36
+ FooterComponent,
37
+ HeaderComponent
38
+ ]
39
+ })
40
+ export class AdminLayoutComponent implements OnInit, OnDestroy {
41
+
42
+ @ViewChild('sidebar', { static: false }) sidebar;
43
+ @ViewChild('sideMenu', { static: false }) sideMenu;
44
+
45
+ public parentProperties: Parent | Array<Parent>;
46
+ public routeOptions: Options;
47
+ public urlParamsOptions: any;
48
+ public formattedHeading: string;
49
+ public options = {
50
+ lang: 'en',
51
+ theme: 'test',
52
+ settings: false,
53
+ docked: false,
54
+ boxed: false,
55
+ opened: false
56
+ };
57
+ public lang: string = 'lang-fr';
58
+ public isMenuOpened: boolean = true;
59
+ public menuReponsiveMode: boolean;
60
+
61
+ private _router: Subscription;
62
+ private mediaMatcher: MediaQueryList = matchMedia(`(max-width: 992px)`);
63
+ private mediaMatcherLg: MediaQueryList = matchMedia(`(max-width: ${SMALL_WIDTH_BREAKPOINT}px)`);
64
+
65
+ constructor(
66
+ private _element: ElementRef,
67
+ private router: Router,
68
+ private route: ActivatedRoute,
69
+ public translate: TranslateService,
70
+ private titleService: Title,
71
+ private zone: NgZone
72
+ ) {
73
+ this.mediaMatcherLg.addEventListener('change', this.handleMediaMatcherLg);
74
+ this.mediaMatcher.addEventListener('change', this.handleMediaMatcher);
75
+
76
+ }
77
+
78
+ ngOnInit(): void {
79
+ this._router = this.router.events.pipe(filter(event => event instanceof NavigationEnd)).subscribe(() => {
80
+ // Scroll to top on view load
81
+ document.querySelector('.main-content').scrollTop = 0;
82
+ if (this.isOver()) {
83
+ this.sideMenu.close();
84
+ }
85
+ this.runOnRouteChange();
86
+ });
87
+ this.runOnRouteChange();
88
+ this.onLangChange();
89
+
90
+ this.lang = 'lang-' + localStorage.getItem('lang');
91
+
92
+ // Check résolution pour menu au chargement
93
+ this.handleMediaMatcherLg(this.mediaMatcherLg);
94
+ this.handleMediaMatcher(this.mediaMatcher);
95
+ }
96
+
97
+ ngOnDestroy() {
98
+ this._router.unsubscribe();
99
+
100
+ this.mediaMatcherLg.removeEventListener('change', this.handleMediaMatcherLg);
101
+ this.mediaMatcher.removeEventListener('change', this.handleMediaMatcher);
102
+ }
103
+
104
+ public isOver(): boolean {
105
+ return this.mediaMatcherLg.matches;
106
+ }
107
+
108
+ public isClosed(): void {
109
+ if (this.mediaMatcherLg.matches) {
110
+ }
111
+ console.log(this.sideMenu.opened);
112
+ }
113
+
114
+ public receiveMessage($event) {
115
+ this.options = $event;
116
+ }
117
+
118
+ public toggleFullscreen(): void {
119
+ const elem = this._element.nativeElement.querySelector('.main-content');
120
+ if (elem.requestFullscreen) {
121
+ elem.requestFullscreen();
122
+ } else if (elem.webkitRequestFullScreen) {
123
+ elem.webkitRequestFullScreen();
124
+ } else if (elem.mozRequestFullScreen) {
125
+ elem.mozRequestFullScreen();
126
+ } else if (elem.msRequestFullScreen) {
127
+ elem.msRequestFullScreen();
128
+ }
129
+ }
130
+
131
+ private runOnRouteChange(): void {
132
+ this.route.children.forEach((route: ActivatedRoute) => {
133
+ let activeRoute: ActivatedRoute = route;
134
+ while (activeRoute.firstChild) {
135
+ activeRoute = activeRoute.firstChild;
136
+ }
137
+ this.routeOptions = activeRoute.snapshot.data;
138
+ this.urlParamsOptions = activeRoute.params;
139
+ });
140
+
141
+ if (this.routeOptions.hasOwnProperty('heading')) {
142
+ // init a null des data qui seront envoye (permet d'avoir toujours un changement pour le OnChange dans l'enfant)
143
+ this.parentProperties = null;
144
+ // Si notre route a bien la propriete "Parent"
145
+ if (this.routeOptions.hasOwnProperty('parent')) {
146
+ // alors on remplie la variable qui sera envoyer a l'enfant
147
+ this.parentProperties = this.routeOptions.parent;
148
+ }
149
+ // set du titre
150
+ this.setTitle(this.translate.instant(this.routeOptions.heading, this.urlParamsOptions.value));
151
+ }
152
+ }
153
+
154
+ private onLangChange() {
155
+ this.translate.onLangChange.subscribe((event: LangChangeEvent) => {
156
+ this.setTitle(this.translate.instant(this.routeOptions.heading, this.urlParamsOptions.value));
157
+ });
158
+ }
159
+
160
+ private setTitle(newTitle: string) {
161
+ this.titleService.setTitle(
162
+ this.translate.instant(newTitle));
163
+ }
164
+
165
+ public onToggleMenu() {
166
+ this.isMenuOpened = !this.isMenuOpened;
167
+ }
168
+
169
+ private handleMediaMatcherLg = (event: MediaQueryList | MediaQueryListEvent) => {
170
+ this.zone.run(() => {
171
+ this.isMenuOpened = !event.matches;
172
+ });
173
+ };
174
+
175
+ private handleMediaMatcher = (event: MediaQueryList | MediaQueryListEvent) => {
176
+ this.zone.run(() => {
177
+ this.menuReponsiveMode = event.matches;
178
+ });
179
+ };
180
+
181
+ }
@@ -0,0 +1,51 @@
1
+ <footer role="contentinfo">
2
+ <nav class="navbar custom-navbar main-footer px-3">
3
+ <ul class="list-inline text-center mb-0">
4
+ <li class="list-inline-item">
5
+ <span class="me-1">Copyright &copy; {{today | date:'yyyy'}}</span>
6
+ Cityway
7
+ </li>
8
+ <!-- <li class="list-inline-item">
9
+ <a href="mailto:{{configuration.appSettings.emailSupport}}">{{configuration.appSettings.emailSupport}}</a>
10
+ </li>
11
+ <li class="list-inline-item">
12
+ @if (versions) {
13
+ <button type="button" class="btn btn-link p-0 border-0" (click)="open(modalversion, 'md')">
14
+ {{versions.bundle.version}}
15
+ </button>
16
+ }
17
+ @else {
18
+ {{configuration.appSettings.version}}
19
+ }
20
+ </li> -->
21
+ </ul>
22
+ </nav>
23
+ </footer>
24
+
25
+ <!-- <ng-template #modalversion let-c="close" let-d="dismiss">
26
+ <div class="modal-header">
27
+ <h1 id="modal-basic-title" class="modal-title">{{productVersion.name}} - {{productVersion.version}} </h1>
28
+ <button type="button" class="btn-close" attr.aria-label="{{'_COMMON._ACTION.CLOSE' | translate}}" (click)="close()">
29
+ </button>
30
+ </div>
31
+ <div class="modal-body">
32
+ <p class="fw-bold">{{'_COMMON._VERSION.INCLUDED' | translate}}</p>
33
+
34
+ <table class="table table-bordered table-striped">
35
+ <caption class="visually-hidden"
36
+ [innerHTML]="'_COMMON._TABLE.CAPTION' | translate: { label: '_COMMON._VERSION.INCLUDED' | translate } ">
37
+ </caption>
38
+ <tbody>
39
+ <tr *ngFor="let version of versions.bundle.projects">
40
+ <td>{{version.name}}</td>
41
+ <td>{{version.version}}</td>
42
+ </tr>
43
+ </tbody>
44
+ </table>
45
+ </div>
46
+ <div class="modal-footer">
47
+ <button type="button" class="btn btn-secondary" (click)="close()">
48
+ {{'_COMMON._ACTION.CLOSE' | translate}}
49
+ </button>
50
+ </div>
51
+ </ng-template> -->
@@ -0,0 +1,65 @@
1
+ import { CommonModule } from '@angular/common';
2
+ import { Component, OnInit } from '@angular/core';
3
+ import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
4
+ import { TranslateModule } from '@ngx-translate/core';
5
+ // import { Configuration } from '../../../models/configuration/configuration';
6
+ // import { KeyVersion, Version } from '../../../models/version';
7
+ // import { VersionService } from '../../../services/version.service';
8
+
9
+ @Component({
10
+ selector: 'app-footer',
11
+ templateUrl: './footer.component.html',
12
+ standalone: true,
13
+ imports: [
14
+ TranslateModule,
15
+ CommonModule
16
+ ]
17
+ })
18
+ export class FooterComponent implements OnInit {
19
+ // public configuration: Configuration;
20
+ // public versions: Version;
21
+ // public productVersion: KeyVersion;
22
+ public modalRef: NgbModalRef;
23
+
24
+ private _today: number = Date.now();
25
+
26
+ constructor(
27
+ // private versionService: VersionService,
28
+ private modalService: NgbModal
29
+ ) {
30
+ // this.configuration = JSON.parse(localStorage.getItem('configuration')) as Configuration;
31
+ }
32
+
33
+ public get today(): number {
34
+ return this._today;
35
+ }
36
+ public set today(value: number) {
37
+ this._today = value;
38
+ }
39
+
40
+ ngOnInit(): void {
41
+ // this.versionService.get().subscribe({
42
+ // next: (version: Version) => {
43
+ // this.versions = version;
44
+ // const keys = this.versions.bundle.projects.filter(x => x.name === this.configuration.appSettings.name);
45
+ // if (keys[0]) {
46
+ // this.productVersion = keys[0];
47
+ // }
48
+ // }
49
+ // });
50
+ }
51
+
52
+ public open(content, size: string = 'lg'): void {
53
+
54
+ this.modalRef = this.modalService.open(content, {
55
+ size,
56
+ ariaLabelledBy: 'modal-basic-title',
57
+ centered: true
58
+ });
59
+ }
60
+
61
+ public close(): void {
62
+ this.modalRef.dismiss();
63
+ }
64
+
65
+ }