@corp-products/ui-components 3.5.9 → 3.6.0

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 (148) hide show
  1. package/.storybook/main.ts +12 -0
  2. package/debug-storybook.log +53 -0
  3. package/ng-package.json +7 -0
  4. package/package.json +25 -36
  5. package/src/enums/date-formatter.ts +22 -0
  6. package/src/helper/date-handler.ts +142 -0
  7. package/src/lib/alert-dialog/alert-dialog.component.html +22 -0
  8. package/src/lib/alert-dialog/alert-dialog.component.scss +0 -0
  9. package/src/lib/alert-dialog/alert-dialog.component.spec.ts +22 -0
  10. package/src/lib/alert-dialog/alert-dialog.component.ts +44 -0
  11. package/src/lib/alert-dialog/alert-dialog.interface.ts +6 -0
  12. package/src/lib/alert-dialog/alert-dialog.service.ts +33 -0
  13. package/src/lib/app-accordion/app-accordion.component.html +15 -0
  14. package/src/lib/app-accordion/app-accordion.component.scss +0 -0
  15. package/src/lib/app-accordion/app-accordion.component.spec.ts +21 -0
  16. package/src/lib/app-accordion/app-accordion.component.ts +21 -0
  17. package/src/lib/app-accordion/index.ts +2 -0
  18. package/src/lib/app-breadcrumb/app-breadcrumb.component.html +7 -0
  19. package/src/lib/app-breadcrumb/app-breadcrumb.component.scss +25 -0
  20. package/src/lib/app-breadcrumb/app-breadcrumb.component.ts +140 -0
  21. package/src/lib/app-breadcrumb/app-breadcrumb.interface.ts +15 -0
  22. package/src/lib/app-button/app-button.component.html +7 -0
  23. package/src/lib/app-button/app-button.component.scss +0 -0
  24. package/src/lib/app-button/app-button.component.ts +14 -0
  25. package/src/lib/app-button/app-button.ts +15 -0
  26. package/src/lib/app-button/index.ts +2 -0
  27. package/src/lib/app-dropdown-menu/app-dropdown-menu.component.html +22 -0
  28. package/src/lib/app-dropdown-menu/app-dropdown-menu.component.scss +39 -0
  29. package/src/lib/app-dropdown-menu/app-dropdown-menu.component.spec.ts +21 -0
  30. package/src/lib/app-dropdown-menu/app-dropdown-menu.component.ts +43 -0
  31. package/src/lib/app-dropdown-menu/app-dropdown-menu.ts +17 -0
  32. package/src/lib/app-dropdown-menu/index.ts +2 -0
  33. package/src/lib/app-dropdown-menu/menu-popup.pipe.ts +18 -0
  34. package/src/lib/app-header/app-header.component.html +26 -0
  35. package/src/lib/app-header/app-header.component.scss +0 -0
  36. package/src/lib/app-header/app-header.component.ts +43 -0
  37. package/src/lib/app-side-menu/app-side-menu.component.html +20 -0
  38. package/src/lib/app-side-menu/app-side-menu.component.ts +28 -0
  39. package/src/lib/app-side-menu/routes-names.ts +28 -0
  40. package/src/lib/app-side-menu/side-menu-items.ts +45 -0
  41. package/src/lib/app-side-menu/side-menu.ts +12 -0
  42. package/src/lib/app-tabs/app-tab.interface.ts +27 -0
  43. package/src/lib/app-tabs/app-tabs.component.html +37 -0
  44. package/src/lib/app-tabs/app-tabs.component.scss +103 -0
  45. package/src/lib/app-tabs/app-tabs.component.spec.ts +21 -0
  46. package/src/lib/app-tabs/app-tabs.component.ts +67 -0
  47. package/src/lib/app-tabs/index.ts +2 -0
  48. package/src/lib/bottom-sheet/bottom-sheet.component.html +18 -0
  49. package/src/lib/bottom-sheet/bottom-sheet.component.scss +31 -0
  50. package/src/lib/bottom-sheet/bottom-sheet.component.ts +26 -0
  51. package/src/lib/confirmation-dialog/confirmation-dialog.component.html +37 -0
  52. package/src/lib/confirmation-dialog/confirmation-dialog.component.scss +0 -0
  53. package/src/lib/confirmation-dialog/confirmation-dialog.component.spec.ts +22 -0
  54. package/src/lib/confirmation-dialog/confirmation-dialog.component.ts +64 -0
  55. package/src/lib/confirmation-dialog/confirmation-dialog.interface.ts +13 -0
  56. package/src/lib/confirmation-dialog/confirmation-dialog.service.ts +34 -0
  57. package/src/lib/dual-calender/date-picker-switcher/date-picker-switcher.component.html +27 -0
  58. package/src/lib/dual-calender/date-picker-switcher/date-picker-switcher.component.scss +22 -0
  59. package/src/lib/dual-calender/date-picker-switcher/date-picker-switcher.component.ts +64 -0
  60. package/src/lib/dual-calender/dual-calendar.component.html +30 -0
  61. package/src/lib/dual-calender/dual-calendar.component.scss +265 -0
  62. package/src/lib/dual-calender/dual-calendar.component.ts +157 -0
  63. package/src/lib/dual-calender/gregorian-calendar/gregorian-calendar.component.html +21 -0
  64. package/src/lib/dual-calender/gregorian-calendar/gregorian-calendar.component.scss +0 -0
  65. package/src/lib/dual-calender/gregorian-calendar/gregorian-calendar.component.spec.ts +21 -0
  66. package/src/lib/dual-calender/gregorian-calendar/gregorian-calendar.component.ts +65 -0
  67. package/src/lib/dual-calender/hijri-calendar/hijri-calendar.component.html +10 -0
  68. package/src/lib/dual-calender/hijri-calendar/hijri-calendar.component.scss +0 -0
  69. package/src/lib/dual-calender/hijri-calendar/hijri-calendar.component.spec.ts +21 -0
  70. package/src/lib/dual-calender/hijri-calendar/hijri-calendar.component.ts +66 -0
  71. package/src/lib/dual-calender/services/gregorian-i18n.service.ts +123 -0
  72. package/src/lib/dual-calender/services/islamic-i18n.service.ts +119 -0
  73. package/src/lib/dual-calender/utils/date-i18n.utils.ts +58 -0
  74. package/src/lib/dynamic-form/dynamic-form.component.html +84 -0
  75. package/src/lib/dynamic-form/dynamic-form.component.scss +0 -0
  76. package/src/lib/dynamic-form/dynamic-form.component.spec.ts +21 -0
  77. package/src/lib/dynamic-form/dynamic-form.component.ts +58 -0
  78. package/src/lib/dynamic-form/dynamic-form.interface.ts +96 -0
  79. package/src/lib/dynamic-side-bar-v2/dynamic-sidebar.component.html +32 -0
  80. package/src/lib/dynamic-side-bar-v2/dynamic-sidebar.component.scss +3 -0
  81. package/src/lib/dynamic-side-bar-v2/dynamic-sidebar.component.ts +82 -0
  82. package/src/lib/dynamic-side-bar-v2/dynamic-sidebar.config.ts +31 -0
  83. package/src/lib/dynamic-side-bar-v2/dynamic-sidebar.service.ts +41 -0
  84. package/src/lib/form-components/@utils/form-utils.ts +12 -0
  85. package/src/lib/form-components/@utils/validations/error-keys.enum.ts +25 -0
  86. package/src/lib/form-components/@utils/validations/form-validation.service.ts +68 -0
  87. package/src/lib/form-components/@utils/validations/index.ts +4 -0
  88. package/src/lib/form-components/@utils/validations/numbers-only.validator.ts +10 -0
  89. package/src/lib/form-components/@utils/validations/validation-message.pipe.ts +24 -0
  90. package/src/lib/form-components/components/auto-complete/auto-complete.component.html +35 -0
  91. package/src/lib/form-components/components/auto-complete/auto-complete.component.scss +12 -0
  92. package/src/lib/form-components/components/auto-complete/auto-complete.component.spec.ts +21 -0
  93. package/src/lib/form-components/components/auto-complete/auto-complete.component.ts +82 -0
  94. package/src/lib/form-components/components/base-input.component.ts +35 -0
  95. package/src/lib/form-components/components/date-picker/date-picker.component.html +40 -0
  96. package/src/lib/form-components/components/date-picker/date-picker.component.scss +32 -0
  97. package/src/lib/form-components/components/date-picker/date-picker.component.spec.ts +21 -0
  98. package/src/lib/form-components/components/date-picker/date-picker.component.ts +81 -0
  99. package/src/lib/form-components/components/date-picker/date-picker.validator.ts +38 -0
  100. package/src/lib/form-components/components/input/input.component.html +80 -0
  101. package/src/lib/form-components/components/input/input.component.scss +46 -0
  102. package/src/lib/form-components/components/input/input.component.spec.ts +21 -0
  103. package/src/lib/form-components/components/input/input.component.ts +56 -0
  104. package/src/lib/form-components/components/select/select.component.html +123 -0
  105. package/src/lib/form-components/components/select/select.component.scss +53 -0
  106. package/src/lib/form-components/components/select/select.component.spec.ts +21 -0
  107. package/src/lib/form-components/components/select/select.component.ts +87 -0
  108. package/src/lib/form-components/components/select-button/select-button.component.html +21 -0
  109. package/src/lib/form-components/components/select-button/select-button.component.scss +0 -0
  110. package/src/lib/form-components/components/select-button/select-button.component.spec.ts +21 -0
  111. package/src/lib/form-components/components/select-button/select-button.component.ts +22 -0
  112. package/src/lib/form-components/components/switcher/switch.component.html +5 -0
  113. package/src/lib/form-components/components/switcher/switch.component.scss +0 -0
  114. package/src/lib/form-components/components/switcher/switch.component.spec.ts +21 -0
  115. package/src/lib/form-components/components/switcher/switch.component.ts +25 -0
  116. package/src/lib/form-components/index.ts +9 -0
  117. package/src/lib/form-components/interfaces/index.ts +1 -0
  118. package/src/lib/form-components/interfaces/label-value.ts +4 -0
  119. package/src/lib/ico-moon-icon/ico-moon-icon.component.ts +23 -0
  120. package/src/lib/read-more/read-more.component.html +17 -0
  121. package/src/lib/read-more/read-more.component.scss +0 -0
  122. package/src/lib/read-more/read-more.component.spec.ts +21 -0
  123. package/src/lib/read-more/read-more.component.ts +21 -0
  124. package/src/lib/side-bar/side-bar.component.html +24 -0
  125. package/src/lib/side-bar/side-bar.component.scss +22 -0
  126. package/src/lib/side-bar/side-bar.component.spec.ts +21 -0
  127. package/src/lib/side-bar/side-bar.component.ts +33 -0
  128. package/src/lib/side-bar-dynamic/data-injector.pipe.ts +15 -0
  129. package/src/lib/side-bar-dynamic/dynamic-sidebar.service.ts +116 -0
  130. package/src/lib/side-bar-dynamic/side-bar-dynamic.component.html +42 -0
  131. package/src/lib/side-bar-dynamic/side-bar-dynamic.component.scss +5 -0
  132. package/src/lib/side-bar-dynamic/side-bar-dynamic.component.spec.ts +21 -0
  133. package/src/lib/side-bar-dynamic/side-bar-dynamic.component.ts +37 -0
  134. package/src/lib/side-bar-dynamic/side-bar-utils.ts +30 -0
  135. package/src/lib/side-bar-dynamic/sidebar-config.ts +48 -0
  136. package/src/lib/user-autocomplete-card/user-autocomplete-card.component.html +20 -0
  137. package/src/lib/user-autocomplete-card/user-autocomplete-card.component.scss +0 -0
  138. package/src/lib/user-autocomplete-card/user-autocomplete-card.component.spec.ts +21 -0
  139. package/src/lib/user-autocomplete-card/user-autocomplete-card.component.ts +21 -0
  140. package/src/lib/user-info/user-info.component.html +10 -0
  141. package/src/lib/user-info/user-info.component.ts +11 -0
  142. package/src/public-api.ts +29 -0
  143. package/tsconfig.lib.json +18 -0
  144. package/tsconfig.lib.prod.json +11 -0
  145. package/tsconfig.spec.json +14 -0
  146. package/fesm2022/corp-products-ui-components.mjs +0 -2253
  147. package/fesm2022/corp-products-ui-components.mjs.map +0 -1
  148. package/index.d.ts +0 -721
@@ -0,0 +1,265 @@
1
+ .calendar-wrapper {
2
+ max-width: 375px;
3
+ padding: 15px;
4
+
5
+ .ngb-dp-header {
6
+ .ngb-dp-arrow.ngb-dp-arrow-next {
7
+ margin: 0 10px;
8
+ max-width: 20px;
9
+ }
10
+ }
11
+
12
+ .rtl {
13
+ .ngb-dp-header {
14
+ .ngb-dp-arrow.ngb-dp-arrow-next {
15
+ inset-inline-end: -6px;
16
+ transform: rotate(180deg);
17
+ margin: 0 10px;
18
+ max-width: 20px;
19
+ }
20
+
21
+ .ngb-dp-arrow.ngb-dp-arrow-prev {
22
+ inset-inline-end: 22px;
23
+ transform: rotate(180deg);
24
+ }
25
+ }
26
+ }
27
+
28
+ .ltr {
29
+ .ngb-dp-header {
30
+ .ngb-dp-arrow.ngb-dp-arrow-next {
31
+ inset-inline-end: -4px;
32
+ }
33
+
34
+ .ngb-dp-arrow.ngb-dp-arrow-prev {
35
+ inset-inline-end: 11px;
36
+ }
37
+ }
38
+ }
39
+ }
40
+
41
+ .header-tabs {
42
+ display: flex;
43
+ justify-content: space-between;
44
+ align-items: center;
45
+ gap: 10px;
46
+ margin-bottom: 10px;
47
+ }
48
+
49
+ .tabs {
50
+
51
+ background: #f0f0f5;
52
+ padding: 3px;
53
+ border-radius: 2px;
54
+ }
55
+
56
+ .tab-button {
57
+ flex: 1;
58
+ padding: 6px 10px;
59
+ font-size: 14px;
60
+ background: #f0f0f5;
61
+ border: none;
62
+ border-radius: 6px;
63
+ cursor: pointer;
64
+ transition: 0.3s;
65
+ }
66
+
67
+ .tab-button.active {
68
+ background: #dcd6f8;
69
+ color: #4a3fb4;
70
+ font-weight: 600;
71
+ }
72
+
73
+ .custom-datepicker {
74
+ width: 100%;
75
+ background: white;
76
+ border: 1px solid #e5e5e5;
77
+ border-radius: 8px;
78
+ padding: 12px;
79
+ }
80
+
81
+ /* Calendar Header (Month + Arrows) */
82
+ .custom-datepicker .ngb-dp-header {
83
+ display: flex;
84
+ justify-content: space-between;
85
+ align-items: center;
86
+ margin-bottom: 12px;
87
+ max-width: 375px;
88
+ }
89
+
90
+ .custom-datepicker .ngb-dp-arrow-btn {
91
+ background: none;
92
+ border: none;
93
+ cursor: pointer;
94
+ padding: 4px;
95
+
96
+ }
97
+
98
+ /* Weekdays Row */
99
+ .custom-datepicker .ngb-dp-weekdays {
100
+ margin-bottom: 6px;
101
+ }
102
+
103
+ .custom-datepicker .ngb-dp-weekday {
104
+ color: #9b9b9b;
105
+ font-weight: 600;
106
+ text-align: center;
107
+ }
108
+
109
+
110
+
111
+ /* Today style */
112
+ .custom-day.today {
113
+ border: 1px solid #6a41d8;
114
+ border-radius: 8px;
115
+ }
116
+
117
+ /* Outside month */
118
+ .custom-day.outside {
119
+ opacity: 0.3;
120
+ }
121
+
122
+ /* Disabled */
123
+ .custom-day.disabled {
124
+ opacity: 0.2;
125
+ pointer-events: none;
126
+ }
127
+
128
+ .calender-content {
129
+ position: relative;
130
+ }
131
+
132
+ .calendar-wrapper {
133
+ position: absolute;
134
+ top: 100%;
135
+ left: 0;
136
+ z-index: 50;
137
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
138
+ background-color: #fff;
139
+ border-radius: 4px;
140
+ overflow: hidden;
141
+ }
142
+
143
+
144
+ .ngb-datepicker {
145
+ width: 100%;
146
+
147
+ .ngb-dp-month {}
148
+ }
149
+
150
+ .custom-day {
151
+ display: inline-flex;
152
+ justify-content: center;
153
+ align-items: center;
154
+ margin: 2px;
155
+ border-radius: 50%;
156
+ cursor: pointer;
157
+ font-weight: 500;
158
+ }
159
+
160
+ .custom-day.today {
161
+ color: #4F008D;
162
+ border: 0 !important;
163
+
164
+ }
165
+
166
+ .ngb-dp-day:has(.selected) {
167
+ background-color: #EDE6F4 !important;
168
+ border: 0 !important;
169
+ color: #4F008D !important;
170
+ border-radius: 2px;
171
+ }
172
+
173
+ .custom-day.outside {
174
+ color: #ccc !important;
175
+ }
176
+
177
+ .custom-day.disabled {
178
+ color: #aaa !important;
179
+ pointer-events: none !important;
180
+ }
181
+
182
+ .ngb-dp-day,
183
+ .ngb-dp-weekday,
184
+ .ngb-dp-week-number {
185
+ width: 38px !important;
186
+ height: 44px !important;
187
+ display: flex;
188
+ margin: 5px;
189
+ justify-content: center;
190
+ align-items: center;
191
+ }
192
+
193
+ .ngb-dp-month:first-child .ngb-dp-week {
194
+ padding: 0 !important;
195
+ }
196
+
197
+ .ngb-dp-month:last-child .ngb-dp-week {
198
+ padding: 0 !important;
199
+ }
200
+
201
+ .ngb-dp-arrow-btn {
202
+ margin-inline-end: 0 !important;
203
+ outline: 0 !important;
204
+ padding: 0 !important;
205
+ margin: 0 !important;
206
+ }
207
+
208
+ .ngb-dp-header {
209
+ position: relative;
210
+
211
+ .ngb-dp-arrow {
212
+ position: absolute;
213
+
214
+ &.ngb-dp-arrow-prev {
215
+ inset-inline-end: 0;
216
+ }
217
+
218
+ &.ngb-dp-arrow-next {
219
+ inset-inline-end: 15px;
220
+ }
221
+
222
+ &:focus-visible,
223
+ .btn:focus-visible {
224
+ outline: 0 !important;
225
+ }
226
+ }
227
+
228
+ .visually-hidden {
229
+ display: none;
230
+ }
231
+ }
232
+
233
+ .ngb-dp-navigation-select {
234
+ max-width: 140px;
235
+ }
236
+
237
+ .ngb-dp-navigation-select {
238
+ select {
239
+ border: 0;
240
+
241
+ &:focus-visible {
242
+ outline: 0;
243
+ }
244
+ }
245
+ }
246
+
247
+ .ngb-datepicker-navigation-select>.form-select {
248
+ font-size: 14px;
249
+ font-weight: bold;
250
+ }
251
+
252
+ .ngb-dp-navigation-select,
253
+ .form-select:first-child {
254
+ appearance: none !important;
255
+ -webkit-appearance: none;
256
+ -moz-appearance: none;
257
+ }
258
+
259
+
260
+
261
+ .ngb-dp-navigation-chevron {
262
+ font-size: 18px;
263
+ border-width: .1em .1em 0 0 !important;
264
+ border-color: #000;
265
+ }
@@ -0,0 +1,157 @@
1
+ import { Component, effect, ElementRef, EventEmitter, HostListener, Input, Output, signal, ViewChild, ViewEncapsulation } from '@angular/core';
2
+ import { FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms';
3
+ import { NgbCalendar, NgbDateStruct, NgbCalendarIslamicUmalqura, NgbDatepickerModule, NgbDate } from '@ng-bootstrap/ng-bootstrap';
4
+ import { HijriCalendarComponent } from './hijri-calendar/hijri-calendar.component';
5
+ import { GregorianCalendarComponent } from './gregorian-calendar/gregorian-calendar.component';
6
+ import { FloatLabelModule } from 'primeng/floatlabel';
7
+ import { DatePickerModule } from 'primeng/datepicker';
8
+ import { trigger, state, style, transition, animate } from '@angular/animations';
9
+ import { DatePickerSwitcherComponent } from './date-picker-switcher/date-picker-switcher.component';
10
+ import '@angular/localize/init';
11
+ import { getGregorianMonthName, getHijriMonthName } from './utils/date-i18n.utils';
12
+ import { formatDate } from '@angular/common';
13
+ import { DateFormats } from '../../enums/date-formatter';
14
+ import { TranslatePipe } from '@ngx-translate/core';
15
+ @Component({
16
+ selector: 'app-dual-calendar',
17
+ animations: [
18
+ trigger('slideDown', [
19
+ state('closed', style({
20
+ height: '0px',
21
+ opacity: 0,
22
+ overflow: 'hidden'
23
+ })),
24
+ state('open', style({
25
+ height: '*',
26
+ opacity: 1,
27
+ overflow: 'hidden'
28
+ })),
29
+ transition('closed <=> open', [
30
+ animate('300ms ease')
31
+ ])
32
+ ])
33
+ ],
34
+ imports: [
35
+ NgbDatepickerModule,
36
+ FormsModule,
37
+ FormsModule,
38
+ ReactiveFormsModule,
39
+ DatePickerModule,
40
+ FloatLabelModule,
41
+ HijriCalendarComponent,
42
+ DatePickerSwitcherComponent,
43
+ TranslatePipe,
44
+ GregorianCalendarComponent
45
+ ],
46
+ providers: [
47
+ { provide: NgbCalendar, useClass: NgbCalendarIslamicUmalqura }
48
+ ],
49
+ templateUrl: './dual-calendar.component.html',
50
+ styleUrl: './dual-calendar.component.scss',
51
+ encapsulation: ViewEncapsulation.None
52
+ })
53
+ export class DualCalendarComponent {
54
+ selectedDate = ''
55
+ @Input() control: FormControl<any> = new FormControl({ value: null, disabled: false }, []);
56
+ @Input() label = '';
57
+ @Input() name = '';
58
+ @Input() withTime = true;
59
+ mode: 'gregorian' | 'hijri' = 'gregorian';
60
+ gregorianModel!: NgbDateStruct;
61
+ hijriModel!: NgbDateStruct;
62
+ @Input() currentLang = signal<'ar' | 'en'>('ar');
63
+ @Output() gregorianUTC = new EventEmitter<string>();
64
+ gregorianUTCValue = ''
65
+ isCalendarOpen = false
66
+ @ViewChild('calendarContainer') calendarContainer!: ElementRef;
67
+ hijriCal = new NgbCalendarIslamicUmalqura();
68
+ constructor() {
69
+ effect(() => {
70
+ this.currentLang(); // 👈 track signal
71
+ this.setDate(this.gregorianUTCValue)
72
+ });
73
+ }
74
+ ngOnInit() {
75
+ this.setDate(this.control?.value);
76
+
77
+ }
78
+ setDate(value: string | null) {
79
+ if (!value) return;
80
+
81
+ const jsDate = new Date(value);
82
+ if (isNaN(jsDate.getTime())) return;
83
+
84
+ const ngbDate: NgbDateStruct = {
85
+ year: jsDate.getFullYear(),
86
+ month: jsDate.getMonth() + 1,
87
+ day: jsDate.getDate()
88
+ };
89
+
90
+ // 🔥 Reuse existing logic
91
+ this.onSelectGregorian(ngbDate);
92
+ }
93
+ @HostListener('document:click', ['$event'])
94
+ onDocumentClick(event: MouseEvent) {
95
+ if (!this.calendarContainer) return;
96
+ const clickedInside = this.calendarContainer.nativeElement.contains(event.target);
97
+ if (!clickedInside) {
98
+ this.isCalendarOpen = false;
99
+ }
100
+ }
101
+ private structToNgbDate(d: NgbDateStruct): NgbDate {
102
+ return new NgbDate(d.year, d.month, d.day);
103
+ }
104
+
105
+ onSelectGregorian(date: NgbDateStruct) {
106
+ this.gregorianModel = date;
107
+ // Convert to NgbDate
108
+ const jsDate = new Date(date.year, date.month - 1, date.day);
109
+ // fromGregorian expects NgbDate or JS Date (depending on version)
110
+ const hijri = this.hijriCal.fromGregorian(jsDate);
111
+ const isoUTC = jsDate.toISOString();
112
+ this.gregorianUTCValue = this.withTime ? isoUTC : formatDate(jsDate, DateFormats.DATE_ONLY, 'en');
113
+ this.gregorianUTC.emit(this.gregorianUTCValue);
114
+ this.hijriModel = {
115
+ year: hijri.year,
116
+ month: hijri.month,
117
+ day: hijri.day
118
+ }; // datepicker
119
+
120
+ this.selectedDate = this.formatHijri(this.structToNgbDate(this.hijriModel)); //input
121
+ this.isCalendarOpen = false;
122
+ }
123
+
124
+ onSelectHijri(date: NgbDateStruct) {
125
+ this.hijriModel = date;
126
+ const ngbDate = this.structToNgbDate(date);
127
+ const greg = this.hijriCal.toGregorian(ngbDate);
128
+ const isoUTC = greg.toISOString();
129
+ this.gregorianModel = {
130
+ year: greg.getFullYear(),
131
+ month: greg.getMonth() + 1,
132
+ day: greg.getDate()
133
+ };
134
+ const jsDate = new Date(this.gregorianModel.year, this.gregorianModel.month - 1, this.gregorianModel.day);
135
+ this.gregorianUTCValue = this.withTime ? isoUTC : formatDate(jsDate, DateFormats.DATE_ONLY, 'en');
136
+ this.gregorianUTC.emit(this.gregorianUTCValue);
137
+ this.selectedDate = this.formatHijri(ngbDate);
138
+ this.isCalendarOpen = false;
139
+ }
140
+
141
+ showCalender(isOpen: boolean) {
142
+ this.isCalendarOpen = isOpen;
143
+ }
144
+
145
+ formatHijri(h: NgbDate): string {
146
+ const hijriDay = h.day;
147
+ const hijriMonth = getHijriMonthName(this.currentLang(), h.month);
148
+ const hijriYear = h.year;
149
+ const greg = this.hijriCal.toGregorian(h);
150
+ const gregorianDay = greg.getDate();
151
+ const gregorianMonth =
152
+ getGregorianMonthName(this.currentLang(), greg.getMonth() + 1);
153
+ const gregorianYear = greg.getFullYear();
154
+ return `${gregorianDay} ${gregorianMonth} ${gregorianYear} - ${hijriDay} ${hijriMonth} ${hijriYear}`;
155
+ }
156
+
157
+ }
@@ -0,0 +1,21 @@
1
+ @for(item of [calendarKey]; track item) {
2
+ <ngb-datepicker #dp
3
+ [class.rtl]="language === 'ar'"
4
+ [class.ltr]="language === 'en'"
5
+ [ngModel]="model"
6
+ [startDate]="startDate"
7
+ (ngModelChange)="onDateChange($event)"
8
+ (dateSelect)="dateSelected.emit($event)"
9
+ [dayTemplate]="dayTemplate"
10
+ [markDisabled]="isDisabled">
11
+ </ngb-datepicker>
12
+ <ng-template #dayTemplate let-date let-currentMonth="currentMonth" let-selected="selected" let-disabled="disabled">
13
+ <span class="custom-day"
14
+ [class.today]="isToday(date)"
15
+ [class.selected]="selected"
16
+ [class.outside]="date.month !== currentMonth"
17
+ [class.disabled]="disabled">
18
+ {{ date.day }}
19
+ </span>
20
+ </ng-template>
21
+ }
@@ -0,0 +1,21 @@
1
+ import { ComponentFixture, TestBed } from "@angular/core/testing";
2
+ import { GregorianCalendarComponent } from "./gregorian-calendar.component";
3
+
4
+ describe("ReadMoreComponent", () => {
5
+ let component: GregorianCalendarComponent;
6
+ let fixture: ComponentFixture<GregorianCalendarComponent>;
7
+
8
+ beforeEach(async () => {
9
+ await TestBed.configureTestingModule({
10
+ imports: [GregorianCalendarComponent]
11
+ }).compileComponents();
12
+
13
+ fixture = TestBed.createComponent(GregorianCalendarComponent);
14
+ component = fixture.componentInstance;
15
+ fixture.detectChanges();
16
+ });
17
+
18
+ it("should create", () => {
19
+ expect(component).toBeTruthy();
20
+ });
21
+ });
@@ -0,0 +1,65 @@
1
+ import { ChangeDetectorRef, Component, EventEmitter, inject, Input, OnChanges, Output, Renderer2, SimpleChanges, ViewEncapsulation } from '@angular/core';
2
+ import {
3
+ NgbCalendar,
4
+ NgbCalendarGregorian,
5
+ NgbDatepickerI18n,
6
+ NgbDatepickerModule,
7
+ NgbDateStruct,
8
+ } from '@ng-bootstrap/ng-bootstrap';
9
+ import { FormsModule } from '@angular/forms';
10
+ import { DynamicGregorianI18n } from './../services/gregorian-i18n.service';
11
+
12
+ @Component({
13
+ selector: "app-gregorian-calendar",
14
+ standalone: true,
15
+ imports: [NgbDatepickerModule, FormsModule],
16
+ providers: [
17
+ { provide: NgbCalendar, useClass: NgbCalendarGregorian },
18
+ { provide: NgbDatepickerI18n, useClass: DynamicGregorianI18n }
19
+ ],
20
+ templateUrl: "./gregorian-calendar.component.html",
21
+ styleUrl: "./gregorian-calendar.component.scss",
22
+ encapsulation: ViewEncapsulation.None,
23
+ })
24
+ export class GregorianCalendarComponent implements OnChanges {
25
+ @Input() model!: NgbDateStruct;
26
+ @Output() dateSelected = new EventEmitter<NgbDateStruct>();
27
+ renderer = inject(Renderer2)
28
+ @Input() language: 'ar' | 'en' = 'en';
29
+ startDate!: NgbDateStruct;
30
+ private calendar = new NgbCalendarGregorian();
31
+ i18n = inject(NgbDatepickerI18n)
32
+ cdr = inject(ChangeDetectorRef)
33
+ calendarKey = 0;
34
+
35
+ ngOnChanges(changes: SimpleChanges) {
36
+ if (changes['model'] && changes['model'].currentValue) {
37
+ this.startDate = { ...changes['model'].currentValue };
38
+ }
39
+ if (changes['language'] && this.i18n instanceof DynamicGregorianI18n) {
40
+ this.i18n.setLanguage(this.language);
41
+ this.calendarKey++; // Increment to force recreation
42
+ }
43
+ }
44
+
45
+ ngAfterViewInit() {
46
+ const buttons = document.querySelectorAll('.ngb-dp-arrow-btn');
47
+ buttons.forEach(btn => {
48
+ this.renderer.removeAttribute(btn, 'title');
49
+ });
50
+ }
51
+
52
+ onDateChange(date: NgbDateStruct) {
53
+ this.model = date;
54
+ this.startDate = { ...date };
55
+ }
56
+
57
+ isToday(date: NgbDateStruct): boolean {
58
+ const today = this.calendar.getToday();
59
+ return date.year === today.year &&
60
+ date.month === today.month &&
61
+ date.day === today.day;
62
+ }
63
+
64
+ isDisabled = () => false;
65
+ }
@@ -0,0 +1,10 @@
1
+ <ngb-datepicker #dp [class.rtl]="language === 'ar'" [class.ltr]="language === 'en'" [ngModel]="model"
2
+ [startDate]="startDate" (ngModelChange)="onDateChange($event)" (dateSelect)="dateSelected.emit($event)"
3
+ [dayTemplate]="dayTemplate" [markDisabled]="isDisabled">
4
+ </ngb-datepicker>
5
+ <ng-template #dayTemplate let-date let-currentMonth="currentMonth" let-selected="selected" let-disabled="disabled">
6
+ <span class="custom-day" [class.today]="isToday(date)" [class.selected]="selected"
7
+ [class.outside]="date.month !== currentMonth" [class.disabled]="disabled">
8
+ {{ date.day }}
9
+ </span>
10
+ </ng-template>
@@ -0,0 +1,21 @@
1
+ import { ComponentFixture, TestBed } from "@angular/core/testing";
2
+ import { HijriCalendarComponent } from "./hijri-calendar.component";
3
+
4
+ describe("ReadMoreComponent", () => {
5
+ let component: HijriCalendarComponent;
6
+ let fixture: ComponentFixture<HijriCalendarComponent>;
7
+
8
+ beforeEach(async () => {
9
+ await TestBed.configureTestingModule({
10
+ imports: [HijriCalendarComponent]
11
+ }).compileComponents();
12
+
13
+ fixture = TestBed.createComponent(HijriCalendarComponent);
14
+ component = fixture.componentInstance;
15
+ fixture.detectChanges();
16
+ });
17
+
18
+ it("should create", () => {
19
+ expect(component).toBeTruthy();
20
+ });
21
+ });
@@ -0,0 +1,66 @@
1
+ import { ChangeDetectorRef, Component, EventEmitter, inject, Input, OnChanges, Output, Renderer2, SimpleChanges } from '@angular/core';
2
+ import {
3
+ NgbCalendar,
4
+ NgbCalendarIslamicUmalqura,
5
+ NgbDatepickerI18n,
6
+ NgbDatepickerModule,
7
+ NgbDateStruct,
8
+ } from '@ng-bootstrap/ng-bootstrap';
9
+ import { FormsModule } from '@angular/forms';
10
+ import { DynamicHijriI18n } from '../services/islamic-i18n.service';
11
+
12
+ @Component({
13
+ selector: "app-hijri-calendar",
14
+ standalone: true,
15
+ imports: [NgbDatepickerModule, FormsModule],
16
+ providers: [
17
+ { provide: NgbCalendar, useClass: NgbCalendarIslamicUmalqura },
18
+ { provide: NgbDatepickerI18n, useClass: DynamicHijriI18n }
19
+ ],
20
+ templateUrl: "./hijri-calendar.component.html",
21
+ styleUrl: "./hijri-calendar.component.scss"
22
+ })
23
+ export class HijriCalendarComponent implements OnChanges {
24
+ @Input() model!: NgbDateStruct;
25
+ @Output() dateSelected = new EventEmitter<NgbDateStruct>();
26
+ @Input() language: 'ar' | 'en' = 'en';
27
+ renderer = inject(Renderer2)
28
+
29
+ startDate!: NgbDateStruct;
30
+ private calendar = new NgbCalendarIslamicUmalqura();
31
+ constructor(
32
+ private i18n: NgbDatepickerI18n,
33
+ private cdr: ChangeDetectorRef
34
+ ) {
35
+ }
36
+ ngOnChanges(changes: SimpleChanges) {
37
+ if (changes['model'] && changes['model'].currentValue) {
38
+ this.startDate = { ...changes['model'].currentValue };
39
+ console.log('Hijri navigating to:', this.startDate);
40
+ }
41
+
42
+ if (changes['language'] && this.i18n instanceof DynamicHijriI18n) {
43
+ this.i18n.setLanguage(this.language);
44
+ this.cdr.detectChanges(); // Force re-render to update labels
45
+ }
46
+ }
47
+ ngAfterViewInit() {
48
+ const buttons = document.querySelectorAll('.ngb-dp-arrow-btn');
49
+ buttons.forEach(btn => {
50
+ this.renderer.removeAttribute(btn, 'title');
51
+ });
52
+ }
53
+ onDateChange(date: NgbDateStruct) {
54
+ this.model = date;
55
+ this.startDate = { ...date };
56
+ }
57
+
58
+ isToday(date: NgbDateStruct): boolean {
59
+ const today = this.calendar.getToday();
60
+ return date.year === today.year &&
61
+ date.month === today.month &&
62
+ date.day === today.day;
63
+ }
64
+
65
+ isDisabled = () => false;
66
+ }