tickera-angular-components 0.0.1-dev.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.
@@ -0,0 +1,4586 @@
1
+ import * as i0 from '@angular/core';
2
+ import { InjectionToken, makeEnvironmentProviders, PLATFORM_ID, Inject, Injectable, signal, LOCALE_ID, computed, inject, EventEmitter, Input, Output, ViewEncapsulation, Component, Self, Optional, Injector, HostListener, forwardRef } from '@angular/core';
3
+ import * as i1 from '@angular/common/http';
4
+ import { HttpHeaders } from '@angular/common/http';
5
+ import { throwError, BehaviorSubject, Subject, of } from 'rxjs';
6
+ import { catchError, distinctUntilChanged, debounceTime, switchMap, takeUntil, map } from 'rxjs/operators';
7
+ import * as i1$2 from '@angular/common';
8
+ import { isPlatformBrowser, formatDate, CommonModule, DatePipe } from '@angular/common';
9
+ import { toast } from 'ngx-sonner';
10
+ import { toObservable } from '@angular/core/rxjs-interop';
11
+ import * as i2 from '@jsverse/transloco';
12
+ import { TranslocoModule } from '@jsverse/transloco';
13
+ import { RouterLink } from '@angular/router';
14
+ import * as i1$1 from '@angular/forms';
15
+ import { FormsModule, ReactiveFormsModule, Validators, NgControl, NG_VALUE_ACCESSOR, NG_VALIDATORS } from '@angular/forms';
16
+ import { DEFAULT_TOOLBAR, Editor, toHTML, NgxEditorComponent, NgxEditorMenuComponent } from 'ngx-editor';
17
+ import * as i2$1 from '@ng-select/ng-select';
18
+ import { NgSelectModule } from '@ng-select/ng-select';
19
+
20
+ const TICKERA_COMPONENTS_CONFIG = new InjectionToken('TICKERA_COMPONENTS_CONFIG');
21
+ function provideTickeraComponents(config) {
22
+ return makeEnvironmentProviders([{ provide: TICKERA_COMPONENTS_CONFIG, useValue: config }]);
23
+ }
24
+
25
+ const ALERT_BASE_CLASSES = 'border rounded relative flex items-center gap-2 px-4 py-2';
26
+ const ALERT_COLOR_CLASSES = {
27
+ success: 'bg-green-100 border-green-400 text-green-700',
28
+ error: 'bg-red-100 border-red-400 text-red-700',
29
+ warning: 'bg-yellow-100 border-yellow-400 text-yellow-700',
30
+ info: 'bg-blue-100 border-blue-400 text-blue-700',
31
+ };
32
+ const ALERT_SIZE_CLASSES = {
33
+ xs: 'px-2 py-1 text-xs',
34
+ sm: 'px-4 py-2 text-sm',
35
+ md: 'px-6 py-3 text-base',
36
+ lg: 'px-8 py-4 text-lg',
37
+ };
38
+ const ALERT_ICONS = {
39
+ success: 'ri-check-line',
40
+ error: 'ri-error-warning-line',
41
+ warning: 'ri-alert-line',
42
+ info: 'ri-info-line',
43
+ };
44
+
45
+ const BUTTON_VARIANT_CLASSES = {
46
+ primary: 'bg-red-600 hover:bg-red-700 focus:ring-red-500 text-white',
47
+ secondary: 'bg-purple-600 hover:bg-purple-700 focus:ring-purple-500 text-white',
48
+ terciary: 'bg-gray-500 hover:bg-gray-600 focus:ring-gray-500 text-white',
49
+ success: 'bg-green-600 hover:bg-green-700 focus:ring-green-500 text-green-900',
50
+ transparent: 'bg-transparent hover:bg-gray-100 focus:ring-gray-500 text-gray-700 ',
51
+ };
52
+ const BASE_BUTTON_CLASSES = [
53
+ 'w-full',
54
+ 'cursor-pointer',
55
+ 'flex',
56
+ 'justify-center',
57
+ 'gap-2',
58
+ 'border',
59
+ 'border-transparent',
60
+ 'rounded-md',
61
+ 'font-medium',
62
+ 'focus:outline-none',
63
+ 'focus:ring-2',
64
+ 'focus:ring-offset-2',
65
+ 'disabled:opacity-50',
66
+ 'disabled:cursor-not-allowed',
67
+ ].join(' ');
68
+ const BUTTON_SIZES_CLASSES = {
69
+ xs: 'text-xs py-1 px-2',
70
+ sm: 'text-sm py-2 px-4',
71
+ md: 'text-base py-3 px-6',
72
+ lg: 'text-lg py-4 px-8',
73
+ };
74
+
75
+ const FORM_ERROR_MESSAGES = {
76
+ required: 'Este campo es requerido',
77
+ minlength: 'Debe tener al menos caracteres',
78
+ maxlength: 'Debe tener al menos caracteres',
79
+ pattern: 'El formato no es válido',
80
+ email: 'El formato no es válido',
81
+ mustMatch: 'Las contraseñas no coinciden',
82
+ matDatepickerMin: 'La fecha no puede ser anterior a la fecha mínima permitida',
83
+ matDatepickerMax: 'La fecha no puede ser posterior a la fecha máxima permitida',
84
+ };
85
+
86
+ const BASE_INPUT_CLASSES = [
87
+ 'block',
88
+ 'w-full',
89
+ 'rounded-md',
90
+ 'px-3',
91
+ 'py-1.5',
92
+ 'text-base',
93
+ 'text-gray-900',
94
+ 'outline-1',
95
+ '-outline-offset-1',
96
+ 'outline-gray-300',
97
+ 'placeholder:text-gray-400',
98
+ 'focus:outline-2',
99
+ 'focus:-outline-offset-2',
100
+ 'focus:outline-indigo-600',
101
+ 'sm:text-sm/6',
102
+ ].join(' ');
103
+ const ERROR_INPUT_CLASSES = BASE_INPUT_CLASSES + ' outline-red-500 dark:outline-red-500';
104
+
105
+ const ADMIN_API_ROUTES = {
106
+ FIND_ALL: '/admins',
107
+ CREATE: '/admins/auth/register',
108
+ updateOne: (id) => `/admins/${id}`,
109
+ deleteOne: (id) => `/admins/${id}`,
110
+ };
111
+
112
+ const CITY_API_ENDPOINTS = {
113
+ findAll: '/cities',
114
+ create: '/cities',
115
+ findById: (id) => `/cities/${id}`,
116
+ update: (id) => `/cities/${id}`,
117
+ delete: (id) => `/cities/${id}`,
118
+ };
119
+
120
+ const COUNTRY_API_ENDPOINTS = {
121
+ findAll: '/countries',
122
+ create: '/countries',
123
+ findById: (id) => `/countries/${id}`,
124
+ update: (id) => `/countries/${id}`,
125
+ delete: (id) => `/countries/${id}`,
126
+ };
127
+
128
+ const STATE_API_ENDPOINTS = {
129
+ findAll: '/states',
130
+ create: '/states',
131
+ findById: (id) => `/states/${id}`,
132
+ update: (id) => `/states/${id}`,
133
+ delete: (id) => `/states/${id}`,
134
+ };
135
+
136
+ const PERFORMANCES_API_ROUTES = {
137
+ findAll: '/performances',
138
+ create: '/performances',
139
+ createBulk: '/performances/bulk',
140
+ findOneById: (id) => `/performances/${id}`,
141
+ findOneBookingData: (id) => `/performances/${id}/booking-data`,
142
+ update: (id) => `/performances/${id}`,
143
+ delete: (id) => `/performances/${id}`,
144
+ deleteMany: '/performances/bulk',
145
+ cancel: (id) => `/performances/${id}/cancel`,
146
+ publishInventory: (id) => `/performances/${id}/publish-inventory`,
147
+ reserve: (id) => `/performances/${id}/reserve`,
148
+ ticketQrToken: (uuid) => `/performances/tickets/${uuid}/qr-token`,
149
+ getAvailableDays: '/performances/available-days',
150
+ publicAvailablePerformances: '/public/performances/daily',
151
+ };
152
+
153
+ const PRODUCTS_API_ROUTES = {
154
+ FIND_ALL: '/products',
155
+ CREATE: '/products',
156
+ findOneById: (id) => `/products/${id}`,
157
+ update: (id) => `/products/${id}`,
158
+ delete: (id) => `/products/${id}`,
159
+ };
160
+
161
+ const SHOWS_API_ROUTES = {
162
+ findAll: '/shows',
163
+ create: '/shows',
164
+ findOneById: (id) => `/shows/${id}`,
165
+ update: (id) => `/shows/${id}`,
166
+ delete: (id) => `/shows/${id}`,
167
+ getImages: (id) => `/shows/${id}/images`,
168
+ uploadGallery: (id) => `/shows/${id}/images`,
169
+ deleteOneImage: (showId, imageId) => `/shows/${showId}/images/${imageId}`,
170
+ publicAvailablePerformances: '/public/shows/available',
171
+ };
172
+
173
+ const CUSTOMERS_API_ROUTES = {
174
+ findAll: '/customers',
175
+ create: '/customers/auth/register',
176
+ findOne: (id) => `/customers/${id}`,
177
+ update: (id) => `/customers/${id}`,
178
+ delete: (id) => `/customers/${id}`,
179
+ };
180
+
181
+ const PRICE_ZONES_API_ROUTES = {
182
+ FIND_ALL: '/price-zones',
183
+ CREATE: '/price-zones',
184
+ findOneById: (id) => `/price-zones/${id}`,
185
+ update: (id) => `/price-zones/${id}`,
186
+ delete: (id) => `/price-zones/${id}`,
187
+ updateElements: (id) => `/price-zones/${id}/elements`,
188
+ duplicate: (id) => `/price-zones/${id}/duplicate`,
189
+ };
190
+
191
+ const VENUES_API_ROUTES = {
192
+ findAll: '/venues',
193
+ create: '/venues',
194
+ findOneById: (id) => '/venues/' + id,
195
+ update: (id) => '/venues/' + id,
196
+ delete: (id) => '/venues/' + id,
197
+ getGallery: (id) => '/venues/' + id + '/images',
198
+ uploadGallery: (id) => '/venues/' + id + '/images',
199
+ deleteOneImage: (venueId, imageId) => '/venues/' + venueId + '/images/' + imageId,
200
+ };
201
+
202
+ var FileType;
203
+ (function (FileType) {
204
+ FileType["IMAGE"] = "image";
205
+ FileType["PDF"] = "pdf";
206
+ FileType["EXCEL"] = "excel";
207
+ FileType["WORD"] = "word";
208
+ FileType["TEXT"] = "text";
209
+ FileType["DEFAULT"] = "default";
210
+ })(FileType || (FileType = {}));
211
+
212
+ var CouponApplicability;
213
+ (function (CouponApplicability) {
214
+ CouponApplicability["GENERAL"] = "GENERAL";
215
+ CouponApplicability["CUSTOMER_EMAIL"] = "CUSTOMER_EMAIL";
216
+ CouponApplicability["MEMBERSHIP_TYPE"] = "MEMBERSHIP_TYPE";
217
+ CouponApplicability["SHOWS"] = "SHOWS";
218
+ CouponApplicability["PERFORMANCES"] = "PERFORMANCES";
219
+ })(CouponApplicability || (CouponApplicability = {}));
220
+
221
+ var CouponDiscountType;
222
+ (function (CouponDiscountType) {
223
+ CouponDiscountType["PERCENTAGE"] = "PERCENTAGE";
224
+ CouponDiscountType["FIXED"] = "FIXED";
225
+ })(CouponDiscountType || (CouponDiscountType = {}));
226
+
227
+ var CorporateBondStatus;
228
+ (function (CorporateBondStatus) {
229
+ CorporateBondStatus["ACTIVE"] = "ACTIVE";
230
+ CorporateBondStatus["INACTIVE"] = "INACTIVE";
231
+ CorporateBondStatus["EXPIRED"] = "EXPIRED";
232
+ })(CorporateBondStatus || (CorporateBondStatus = {}));
233
+
234
+ var PerformanceStatus;
235
+ (function (PerformanceStatus) {
236
+ PerformanceStatus["ACTIVE"] = "active";
237
+ PerformanceStatus["CANCELLED"] = "cancelled";
238
+ PerformanceStatus["FINISHED"] = "finished";
239
+ PerformanceStatus["POSTPONED"] = "postponed";
240
+ })(PerformanceStatus || (PerformanceStatus = {}));
241
+
242
+ var PerformanceTicketStatus;
243
+ (function (PerformanceTicketStatus) {
244
+ PerformanceTicketStatus["AVAILABLE"] = "available";
245
+ PerformanceTicketStatus["RESERVED"] = "reserved";
246
+ PerformanceTicketStatus["SOLD"] = "sold";
247
+ PerformanceTicketStatus["BLOCKED"] = "blocked";
248
+ })(PerformanceTicketStatus || (PerformanceTicketStatus = {}));
249
+
250
+ var RoomMapElementOrientation;
251
+ (function (RoomMapElementOrientation) {
252
+ RoomMapElementOrientation["TOP"] = "top";
253
+ RoomMapElementOrientation["RIGHT"] = "right";
254
+ RoomMapElementOrientation["BOTTOM"] = "bottom";
255
+ RoomMapElementOrientation["LEFT"] = "left";
256
+ RoomMapElementOrientation["CENTER"] = "center";
257
+ })(RoomMapElementOrientation || (RoomMapElementOrientation = {}));
258
+
259
+ var RoomMapElementType;
260
+ (function (RoomMapElementType) {
261
+ RoomMapElementType["SEAT_BLOCK"] = "seat_block";
262
+ RoomMapElementType["TABLE"] = "table";
263
+ RoomMapElementType["ZONE"] = "zone";
264
+ RoomMapElementType["EXIT"] = "exit";
265
+ RoomMapElementType["STAGE"] = "stage";
266
+ RoomMapElementType["PRODUCTION_AREA"] = "production_area";
267
+ RoomMapElementType["UNAVAILABLE_SPACE"] = "unavailable_space";
268
+ RoomMapElementType["STAIR"] = "stair";
269
+ RoomMapElementType["HALLWAY"] = "hallway";
270
+ })(RoomMapElementType || (RoomMapElementType = {}));
271
+
272
+ var OrderItemType;
273
+ (function (OrderItemType) {
274
+ OrderItemType["TICKET"] = "TICKET";
275
+ OrderItemType["PRODUCT"] = "PRODUCT";
276
+ })(OrderItemType || (OrderItemType = {}));
277
+
278
+ var OrderStatus;
279
+ (function (OrderStatus) {
280
+ OrderStatus["PENDING"] = "PENDING";
281
+ OrderStatus["COMPLETED"] = "COMPLETED";
282
+ OrderStatus["FAILED"] = "FAILED";
283
+ OrderStatus["CANCELLED"] = "CANCELLED";
284
+ })(OrderStatus || (OrderStatus = {}));
285
+
286
+ const getCustomerFullname = (customer) => {
287
+ return `${customer.first_name || ''} ${customer.last_name || ''}`.trim();
288
+ };
289
+
290
+ function parseJsonToFormDataAdvanced(imageGallery) {
291
+ const formData = new FormData();
292
+ if (!Array.isArray(imageGallery)) {
293
+ throw new Error('imageGallery debe ser un array');
294
+ }
295
+ if (imageGallery.length === 0) {
296
+ throw new Error('No hay imágenes para procesar');
297
+ }
298
+ if (imageGallery.length > 10) {
299
+ throw new Error('El backend acepta máximo 10 archivos por petición');
300
+ }
301
+ const processedFiles = [];
302
+ imageGallery.forEach((image, index) => {
303
+ try {
304
+ if (!image.name) {
305
+ throw new Error(`La imagen ${index + 1} no tiene nombre`);
306
+ }
307
+ if (!image.type || !image.type.startsWith('image/')) {
308
+ throw new Error(`La imagen ${index + 1} no tiene un tipo MIME válido`);
309
+ }
310
+ if (!image.preview) {
311
+ throw new Error(`La imagen ${index + 1} no tiene datos de preview`);
312
+ }
313
+ if (!image.preview.includes('data:image/') || !image.preview.includes('base64,')) {
314
+ throw new Error(`La imagen ${index + 1} no tiene un formato base64 válido`);
315
+ }
316
+ const base64Data = image.preview.split(',')[1];
317
+ const byteCharacters = atob(base64Data);
318
+ const byteNumbers = new Array(byteCharacters.length);
319
+ for (let i = 0; i < byteCharacters.length; i++) {
320
+ byteNumbers[i] = byteCharacters.charCodeAt(i);
321
+ }
322
+ const byteArray = new Uint8Array(byteNumbers);
323
+ const blob = new Blob([byteArray], { type: image.type });
324
+ const file = new File([blob], image.name, {
325
+ type: image.type,
326
+ lastModified: Date.now(),
327
+ });
328
+ if (file.size === 0) {
329
+ throw new Error(`El archivo ${image.name} está vacío`);
330
+ }
331
+ formData.append('files', file);
332
+ processedFiles.push({
333
+ name: image.name,
334
+ size: file.size,
335
+ type: file.type,
336
+ });
337
+ }
338
+ catch (error) {
339
+ console.error(`Error procesando imagen ${index + 1}:`, error);
340
+ throw new Error(`Error procesando ${image.name || 'imagen ' + (index + 1)}: ${error?.message}`);
341
+ }
342
+ });
343
+ return formData;
344
+ }
345
+
346
+ const transformImageToFile = (image) => {
347
+ return {
348
+ preview: image.full_url,
349
+ name: image.original_name,
350
+ size: image.size,
351
+ type: image.mime_type,
352
+ extension: image.extension,
353
+ };
354
+ };
355
+
356
+ const formatCitiesResponseToSelect = (res) => {
357
+ if (!res.data.cities || res.data.cities.length < 1) {
358
+ return [];
359
+ }
360
+ return res.data.cities?.map(({ id, name, search_text }) => ({
361
+ value: id,
362
+ label: search_text ?? name,
363
+ }));
364
+ };
365
+
366
+ function MinTodayValidator(controlName) {
367
+ return (formGroup) => {
368
+ const group = formGroup;
369
+ const control = group.get(controlName);
370
+ if (!control || !control.value) {
371
+ return null;
372
+ }
373
+ const today = new Date();
374
+ today.setHours(0, 0, 0, 0);
375
+ let selectedDate;
376
+ if (control.value instanceof Date) {
377
+ selectedDate = new Date(control.value);
378
+ }
379
+ else if (typeof control.value === 'string') {
380
+ const [year, month, day] = control.value.split('-').map(Number);
381
+ selectedDate = new Date(Date.UTC(year, month - 1, day));
382
+ }
383
+ else {
384
+ return null;
385
+ }
386
+ selectedDate.setUTCHours(0, 0, 0, 0);
387
+ if (selectedDate < today) {
388
+ control.setErrors({ minToday: true });
389
+ return { minToday: true };
390
+ }
391
+ else {
392
+ const currentErrors = control.errors;
393
+ if (currentErrors) {
394
+ delete currentErrors['minToday'];
395
+ control.setErrors(Object.keys(currentErrors).length > 0 ? currentErrors : null);
396
+ }
397
+ return null;
398
+ }
399
+ };
400
+ }
401
+ function EndDateGreaterThanStartValidator(startDateControlName, endDateControlName) {
402
+ return (formGroup) => {
403
+ const group = formGroup;
404
+ const startDateControl = group.get(startDateControlName);
405
+ const endDateControl = group.get(endDateControlName);
406
+ if (!startDateControl || !endDateControl || !startDateControl.value || !endDateControl.value) {
407
+ return null;
408
+ }
409
+ let startDate;
410
+ let endDate;
411
+ if (startDateControl.value instanceof Date) {
412
+ startDate = new Date(startDateControl.value);
413
+ }
414
+ else if (typeof startDateControl.value === 'string') {
415
+ const [startYear, startMonth, startDay] = startDateControl.value.split('-').map(Number);
416
+ startDate = new Date(Date.UTC(startYear, startMonth - 1, startDay));
417
+ }
418
+ else {
419
+ return null;
420
+ }
421
+ if (endDateControl.value instanceof Date) {
422
+ endDate = new Date(endDateControl.value);
423
+ }
424
+ else if (typeof endDateControl.value === 'string') {
425
+ const [endYear, endMonth, endDay] = endDateControl.value.split('-').map(Number);
426
+ endDate = new Date(Date.UTC(endYear, endMonth - 1, endDay));
427
+ }
428
+ else {
429
+ return null;
430
+ }
431
+ startDate.setUTCHours(0, 0, 0, 0);
432
+ endDate.setUTCHours(0, 0, 0, 0);
433
+ if (endDate <= startDate) {
434
+ endDateControl.setErrors({ endDateGreaterThanStart: true });
435
+ return { endDateGreaterThanStart: true };
436
+ }
437
+ else {
438
+ const currentErrors = endDateControl.errors;
439
+ if (currentErrors) {
440
+ delete currentErrors['endDateGreaterThanStart'];
441
+ endDateControl.setErrors(Object.keys(currentErrors).length > 0 ? currentErrors : null);
442
+ }
443
+ return null;
444
+ }
445
+ };
446
+ }
447
+
448
+ function MustMatchValidator(controlName, matchingControlName) {
449
+ return (formGroup) => {
450
+ const group = formGroup;
451
+ const control = group.get(controlName);
452
+ const matchingControl = group.get(matchingControlName);
453
+ if (!control || !matchingControl) {
454
+ return null;
455
+ }
456
+ if (control.value !== matchingControl.value) {
457
+ matchingControl.setErrors({ mustMatch: true });
458
+ return { mustMatch: true };
459
+ }
460
+ else {
461
+ matchingControl.setErrors(null);
462
+ return null;
463
+ }
464
+ };
465
+ }
466
+
467
+ class ApiService {
468
+ http;
469
+ platformId;
470
+ config;
471
+ apiUrl;
472
+ constructor(http, platformId, config) {
473
+ this.http = http;
474
+ this.platformId = platformId;
475
+ this.config = config;
476
+ this.apiUrl = config.apiUrl;
477
+ }
478
+ getHeaders(contentType) {
479
+ let headers = new HttpHeaders();
480
+ if (contentType) {
481
+ headers = headers.set('Content-Type', contentType);
482
+ }
483
+ return headers;
484
+ }
485
+ validateContentType(body) {
486
+ if (body instanceof FormData) {
487
+ return undefined;
488
+ }
489
+ return 'application/json';
490
+ }
491
+ handleError(error) {
492
+ if (error.status === 401 && isPlatformBrowser(this.platformId)) {
493
+ const currentRoute = window.location.pathname;
494
+ if (currentRoute.startsWith('/admin')) {
495
+ localStorage.removeItem('access_token');
496
+ window.location.href = '/';
497
+ }
498
+ }
499
+ return throwError(() => error);
500
+ }
501
+ get(path) {
502
+ const headers = this.getHeaders(this.validateContentType(null));
503
+ return this.http
504
+ .get(`${this.apiUrl}${path}`, { headers })
505
+ .pipe(catchError(this.handleError.bind(this)));
506
+ }
507
+ post(path, body) {
508
+ const headers = this.getHeaders(this.validateContentType(body));
509
+ return this.http
510
+ .post(`${this.apiUrl}${path}`, body, { headers })
511
+ .pipe(catchError(this.handleError.bind(this)));
512
+ }
513
+ patch(path, body) {
514
+ const headers = this.getHeaders(this.validateContentType(body));
515
+ return this.http
516
+ .patch(`${this.apiUrl}${path}`, body, { headers })
517
+ .pipe(catchError(this.handleError.bind(this)));
518
+ }
519
+ put(path, body) {
520
+ const headers = this.getHeaders(this.validateContentType(body));
521
+ return this.http
522
+ .put(`${this.apiUrl}${path}`, body, { headers })
523
+ .pipe(catchError(this.handleError.bind(this)));
524
+ }
525
+ delete(path, body) {
526
+ const headers = this.getHeaders(this.validateContentType(body));
527
+ return this.http
528
+ .request('DELETE', `${this.apiUrl}${path}`, { headers, body })
529
+ .pipe(catchError(this.handleError.bind(this)));
530
+ }
531
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: ApiService, deps: [{ token: i1.HttpClient }, { token: PLATFORM_ID }, { token: TICKERA_COMPONENTS_CONFIG }], target: i0.ɵɵFactoryTarget.Injectable });
532
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: ApiService, providedIn: 'root' });
533
+ }
534
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: ApiService, decorators: [{
535
+ type: Injectable,
536
+ args: [{
537
+ providedIn: 'root',
538
+ }]
539
+ }], ctorParameters: () => [{ type: i1.HttpClient }, { type: Object, decorators: [{
540
+ type: Inject,
541
+ args: [PLATFORM_ID]
542
+ }] }, { type: undefined, decorators: [{
543
+ type: Inject,
544
+ args: [TICKERA_COMPONENTS_CONFIG]
545
+ }] }] });
546
+
547
+ class ToastService {
548
+ show(message, type = 'info') {
549
+ toast[type](message);
550
+ }
551
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: ToastService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
552
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: ToastService, providedIn: 'root' });
553
+ }
554
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: ToastService, decorators: [{
555
+ type: Injectable,
556
+ args: [{ providedIn: 'root' }]
557
+ }] });
558
+
559
+ class LoadingModalService {
560
+ title = signal('', ...(ngDevMode ? [{ debugName: "title" }] : []));
561
+ isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : []));
562
+ get modalIsOpen() {
563
+ return this.isOpen;
564
+ }
565
+ open(title) {
566
+ this.title.set(title ?? 'Cargando...');
567
+ this.isOpen.set(true);
568
+ }
569
+ close() {
570
+ this.isOpen.set(false);
571
+ }
572
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: LoadingModalService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
573
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: LoadingModalService, providedIn: 'root' });
574
+ }
575
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: LoadingModalService, decorators: [{
576
+ type: Injectable,
577
+ args: [{ providedIn: 'root' }]
578
+ }] });
579
+
580
+ class DeleteConfirmationService {
581
+ title = signal('Confirmar eliminación', ...(ngDevMode ? [{ debugName: "title" }] : []));
582
+ resourceName = signal('', ...(ngDevMode ? [{ debugName: "resourceName" }] : []));
583
+ confirmationText = signal('', ...(ngDevMode ? [{ debugName: "confirmationText" }] : []));
584
+ isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : []));
585
+ confirmDeleteCallback = null;
586
+ get modalTitle() {
587
+ return this.title;
588
+ }
589
+ get modalResourceName() {
590
+ return this.resourceName;
591
+ }
592
+ get modalConfirmationText() {
593
+ return this.confirmationText;
594
+ }
595
+ get modalIsOpen() {
596
+ return this.isOpen;
597
+ }
598
+ open({ title, resourceName, confirmationText }, confirmCallback) {
599
+ this.title.set(title);
600
+ this.resourceName.set(resourceName);
601
+ this.confirmationText.set(confirmationText);
602
+ this.confirmDeleteCallback = confirmCallback || null;
603
+ this.isOpen.set(true);
604
+ }
605
+ close() {
606
+ this.title.set('Confirmar eliminación');
607
+ this.resourceName.set('');
608
+ this.confirmationText.set('');
609
+ this.confirmDeleteCallback = null;
610
+ this.isOpen.set(false);
611
+ }
612
+ getConfirmDeleteCallback() {
613
+ return this.confirmDeleteCallback;
614
+ }
615
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: DeleteConfirmationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
616
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: DeleteConfirmationService, providedIn: 'root' });
617
+ }
618
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: DeleteConfirmationService, decorators: [{
619
+ type: Injectable,
620
+ args: [{ providedIn: 'root' }]
621
+ }] });
622
+
623
+ class ChangePasswordFormService {
624
+ resourceId = signal(0, ...(ngDevMode ? [{ debugName: "resourceId" }] : []));
625
+ isCustomer = signal(false, ...(ngDevMode ? [{ debugName: "isCustomer" }] : []));
626
+ isAdmin = signal(false, ...(ngDevMode ? [{ debugName: "isAdmin" }] : []));
627
+ isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : []));
628
+ get modalIsOpen() {
629
+ return this.isOpen;
630
+ }
631
+ get isCustomerMode() {
632
+ return this.isCustomer;
633
+ }
634
+ get isAdminMode() {
635
+ return this.isAdmin;
636
+ }
637
+ get resourceIdValue() {
638
+ return this.resourceId;
639
+ }
640
+ open(resourceId, isAdmin = false) {
641
+ this.resourceId.set(resourceId);
642
+ this.isCustomer.set(!isAdmin);
643
+ this.isAdmin.set(isAdmin);
644
+ this.isOpen.set(true);
645
+ }
646
+ close() {
647
+ this.isOpen.set(false);
648
+ }
649
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: ChangePasswordFormService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
650
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: ChangePasswordFormService, providedIn: 'root' });
651
+ }
652
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: ChangePasswordFormService, decorators: [{
653
+ type: Injectable,
654
+ args: [{ providedIn: 'root' }]
655
+ }] });
656
+
657
+ class DateService {
658
+ locale;
659
+ constructor(locale) {
660
+ this.locale = locale;
661
+ }
662
+ formatDate(date, format = 'yyyy-MM-dd') {
663
+ const formattedDate = formatDate(date, format, this.locale);
664
+ return formattedDate;
665
+ }
666
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: DateService, deps: [{ token: LOCALE_ID }], target: i0.ɵɵFactoryTarget.Injectable });
667
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: DateService, providedIn: 'root' });
668
+ }
669
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: DateService, decorators: [{
670
+ type: Injectable,
671
+ args: [{ providedIn: 'root' }]
672
+ }], ctorParameters: () => [{ type: undefined, decorators: [{
673
+ type: Inject,
674
+ args: [LOCALE_ID]
675
+ }] }] });
676
+
677
+ class AdminService {
678
+ apiService;
679
+ constructor(apiService) {
680
+ this.apiService = apiService;
681
+ }
682
+ fetchAdmins(page = 1, search = '', limit = 20) {
683
+ const queryParams = new URLSearchParams();
684
+ if (page)
685
+ queryParams.append('page', page.toString());
686
+ if (search)
687
+ queryParams.append('search', search);
688
+ if (limit)
689
+ queryParams.append('limit', limit.toString());
690
+ const queryString = queryParams.toString();
691
+ const apiRoute = `${ADMIN_API_ROUTES.FIND_ALL}${queryString ? '?' + queryString : ''}`;
692
+ return this.apiService.get(apiRoute);
693
+ }
694
+ deleteOne(id) {
695
+ return this.apiService.delete(ADMIN_API_ROUTES.deleteOne(id));
696
+ }
697
+ createOne(data) {
698
+ return this.apiService.post(ADMIN_API_ROUTES.CREATE, data);
699
+ }
700
+ updateOne(id, data) {
701
+ return this.apiService.patch(ADMIN_API_ROUTES.updateOne(id), data);
702
+ }
703
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: AdminService, deps: [{ token: ApiService }], target: i0.ɵɵFactoryTarget.Injectable });
704
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: AdminService, providedIn: 'root' });
705
+ }
706
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: AdminService, decorators: [{
707
+ type: Injectable,
708
+ args: [{ providedIn: 'root' }]
709
+ }], ctorParameters: () => [{ type: ApiService }] });
710
+
711
+ class CitiesService {
712
+ apiService;
713
+ constructor(apiService) {
714
+ this.apiService = apiService;
715
+ }
716
+ fetchCities({ page, search, stateId }) {
717
+ const queryParams = new URLSearchParams();
718
+ if (page)
719
+ queryParams.append('page', page.toString());
720
+ if (search)
721
+ queryParams.append('search', search);
722
+ if (stateId)
723
+ queryParams.append('state_id', stateId.toString());
724
+ const queryString = queryParams.toString();
725
+ const apiRoute = `${CITY_API_ENDPOINTS.findAll}${queryString ? '?' + queryString : ''}`;
726
+ return this.apiService.get(apiRoute);
727
+ }
728
+ createOne(data) {
729
+ return this.apiService.post(CITY_API_ENDPOINTS.create, data);
730
+ }
731
+ updateOne(id, data) {
732
+ return this.apiService.patch(CITY_API_ENDPOINTS.update(id), data);
733
+ }
734
+ deleteOne(id) {
735
+ return this.apiService.delete(CITY_API_ENDPOINTS.delete(id));
736
+ }
737
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: CitiesService, deps: [{ token: ApiService }], target: i0.ɵɵFactoryTarget.Injectable });
738
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: CitiesService, providedIn: 'root' });
739
+ }
740
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: CitiesService, decorators: [{
741
+ type: Injectable,
742
+ args: [{ providedIn: 'root' }]
743
+ }], ctorParameters: () => [{ type: ApiService }] });
744
+
745
+ class CountryService {
746
+ apiService;
747
+ constructor(apiService) {
748
+ this.apiService = apiService;
749
+ }
750
+ fetchCountries(page, search) {
751
+ const queryParams = new URLSearchParams();
752
+ if (page)
753
+ queryParams.append('page', page.toString());
754
+ if (search)
755
+ queryParams.append('search', search);
756
+ const queryString = queryParams.toString();
757
+ const apiRoute = `${COUNTRY_API_ENDPOINTS.findAll}${queryString ? '?' + queryString : ''}`;
758
+ return this.apiService.get(apiRoute);
759
+ }
760
+ createOne(data) {
761
+ return this.apiService.post(COUNTRY_API_ENDPOINTS.create, data);
762
+ }
763
+ updateOne(id, data) {
764
+ return this.apiService.patch(COUNTRY_API_ENDPOINTS.update(id), data);
765
+ }
766
+ deleteOne(id) {
767
+ return this.apiService.delete(COUNTRY_API_ENDPOINTS.delete(id));
768
+ }
769
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: CountryService, deps: [{ token: ApiService }], target: i0.ɵɵFactoryTarget.Injectable });
770
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: CountryService, providedIn: 'root' });
771
+ }
772
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: CountryService, decorators: [{
773
+ type: Injectable,
774
+ args: [{ providedIn: 'root' }]
775
+ }], ctorParameters: () => [{ type: ApiService }] });
776
+
777
+ class StatesService {
778
+ apiService;
779
+ constructor(apiService) {
780
+ this.apiService = apiService;
781
+ }
782
+ fetchStates(page, search, countryId) {
783
+ const queryParams = new URLSearchParams();
784
+ if (page)
785
+ queryParams.append('page', page.toString());
786
+ if (search)
787
+ queryParams.append('search', search);
788
+ if (countryId)
789
+ queryParams.append('country_id', countryId.toString());
790
+ const queryString = queryParams.toString();
791
+ const apiRoute = `${STATE_API_ENDPOINTS.findAll}${queryString ? '?' + queryString : ''}`;
792
+ return this.apiService.get(apiRoute);
793
+ }
794
+ fetchStatesByCountryId(countryId) {
795
+ const apiRoute = `${STATE_API_ENDPOINTS.findAll}?country_id=${countryId}`;
796
+ return this.apiService.get(apiRoute);
797
+ }
798
+ createOne(data) {
799
+ return this.apiService.post(STATE_API_ENDPOINTS.create, data);
800
+ }
801
+ updateOne(id, data) {
802
+ return this.apiService.patch(STATE_API_ENDPOINTS.update(id), data);
803
+ }
804
+ deleteOne(id) {
805
+ return this.apiService.delete(STATE_API_ENDPOINTS.delete(id));
806
+ }
807
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: StatesService, deps: [{ token: ApiService }], target: i0.ɵɵFactoryTarget.Injectable });
808
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: StatesService, providedIn: 'root' });
809
+ }
810
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: StatesService, decorators: [{
811
+ type: Injectable,
812
+ args: [{ providedIn: 'root' }]
813
+ }], ctorParameters: () => [{ type: ApiService }] });
814
+
815
+ class PerformanceService {
816
+ apiService;
817
+ performancesSubject = new BehaviorSubject([]);
818
+ performances$ = this.performancesSubject.asObservable();
819
+ constructor(apiService) {
820
+ this.apiService = apiService;
821
+ }
822
+ fetchPerformances(showId, search) {
823
+ const queryParams = new URLSearchParams();
824
+ if (showId)
825
+ queryParams.append('show_id', showId.toString());
826
+ if (search)
827
+ queryParams.append('search', search);
828
+ queryParams.append('limit', '100');
829
+ const queryString = queryParams.toString();
830
+ const apiRoute = `${PERFORMANCES_API_ROUTES.findAll}${queryString ? '?' + queryString : ''}`;
831
+ return this.apiService.get(apiRoute);
832
+ }
833
+ fetchDailyPerformances({ show_id, search, limit, date, }) {
834
+ const queryParams = new URLSearchParams();
835
+ if (date)
836
+ queryParams.append('date', date.toString());
837
+ if (show_id)
838
+ queryParams.append('show_id', show_id.toString());
839
+ if (search)
840
+ queryParams.append('search', search);
841
+ queryParams.append('limit', limit?.toString() ?? '100');
842
+ const queryString = queryParams.toString();
843
+ const apiRoute = `${PERFORMANCES_API_ROUTES.publicAvailablePerformances}${queryString ? '?' + queryString : ''}`;
844
+ return this.apiService.get(apiRoute);
845
+ }
846
+ loadPerformances({ showId, search } = {}) {
847
+ this.fetchPerformances(showId, search).subscribe({
848
+ next: ({ data }) => {
849
+ this.performancesSubject.next(data?.performances ?? []);
850
+ },
851
+ error: () => {
852
+ this.performancesSubject.next([]);
853
+ },
854
+ });
855
+ }
856
+ getCurrentPerformances() {
857
+ return this.performancesSubject.value;
858
+ }
859
+ fetchOneById(id) {
860
+ return this.apiService.get(PERFORMANCES_API_ROUTES.findOneById(id));
861
+ }
862
+ fetchOneBookingData(id) {
863
+ const apiRoute = PERFORMANCES_API_ROUTES.findOneBookingData(id);
864
+ return this.apiService.get(apiRoute);
865
+ }
866
+ fetchAvailableDays(params) {
867
+ const queryParams = new URLSearchParams();
868
+ if (params?.show_id)
869
+ queryParams.append('show_id', params.show_id.toString());
870
+ const queryString = queryParams.toString();
871
+ const apiRoute = `${PERFORMANCES_API_ROUTES.getAvailableDays}${queryString ? '?' + queryString : ''}`;
872
+ return this.apiService.get(apiRoute);
873
+ }
874
+ createOne(data) {
875
+ return this.apiService.post(PERFORMANCES_API_ROUTES.create, data);
876
+ }
877
+ createMany(data) {
878
+ return this.apiService.post(PERFORMANCES_API_ROUTES.createBulk, { performances: data });
879
+ }
880
+ updateOne(id, data) {
881
+ return this.apiService.patch(PERFORMANCES_API_ROUTES.update(id), data);
882
+ }
883
+ deleteOne(id) {
884
+ return this.apiService.delete(PERFORMANCES_API_ROUTES.delete(id));
885
+ }
886
+ deleteMany(ids) {
887
+ return this.apiService.delete(PERFORMANCES_API_ROUTES.deleteMany, { ids });
888
+ }
889
+ cancelPerformance(id, notifyUsers) {
890
+ return this.apiService.patch(PERFORMANCES_API_ROUTES.cancel(id), { notify_users: notifyUsers });
891
+ }
892
+ publishInvenotry(id) {
893
+ const apiRoute = PERFORMANCES_API_ROUTES.publishInventory(id);
894
+ return this.apiService.post(apiRoute, {});
895
+ }
896
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: PerformanceService, deps: [{ token: ApiService }], target: i0.ɵɵFactoryTarget.Injectable });
897
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: PerformanceService, providedIn: 'root' });
898
+ }
899
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: PerformanceService, decorators: [{
900
+ type: Injectable,
901
+ args: [{ providedIn: 'root' }]
902
+ }], ctorParameters: () => [{ type: ApiService }] });
903
+
904
+ class PerformancesListEventsService {
905
+ _selectedDay = signal(null, ...(ngDevMode ? [{ debugName: "_selectedDay" }] : []));
906
+ _selectedPerformance = signal(null, ...(ngDevMode ? [{ debugName: "_selectedPerformance" }] : []));
907
+ _filteredShowId = signal(null, ...(ngDevMode ? [{ debugName: "_filteredShowId" }] : []));
908
+ selectedDay = computed(() => this._selectedDay(), ...(ngDevMode ? [{ debugName: "selectedDay" }] : []));
909
+ selectedDayDate = computed(() => this._selectedDay()?.date, ...(ngDevMode ? [{ debugName: "selectedDayDate" }] : []));
910
+ selectedPerformance = computed(() => this._selectedPerformance(), ...(ngDevMode ? [{ debugName: "selectedPerformance" }] : []));
911
+ filteredShowId = computed(() => this._filteredShowId(), ...(ngDevMode ? [{ debugName: "filteredShowId" }] : []));
912
+ setSelectedDay(day) {
913
+ this._selectedDay.set(day);
914
+ }
915
+ setSelectedPerformance(performance) {
916
+ this._selectedPerformance.set(performance);
917
+ }
918
+ setFilteredShowId(id) {
919
+ this._filteredShowId.set(id);
920
+ }
921
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: PerformancesListEventsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
922
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: PerformancesListEventsService, providedIn: 'root' });
923
+ }
924
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: PerformancesListEventsService, decorators: [{
925
+ type: Injectable,
926
+ args: [{ providedIn: 'root' }]
927
+ }] });
928
+
929
+ class ProductService {
930
+ apiService;
931
+ productsSubject = new BehaviorSubject([]);
932
+ products$ = this.productsSubject.asObservable();
933
+ constructor(apiService) {
934
+ this.apiService = apiService;
935
+ }
936
+ fetchProducts(page, search) {
937
+ const queryParams = new URLSearchParams();
938
+ if (page)
939
+ queryParams.append('page', page.toString());
940
+ if (search)
941
+ queryParams.append('search', search);
942
+ const queryString = queryParams.toString();
943
+ const apiRoute = `${PRODUCTS_API_ROUTES.FIND_ALL}${queryString ? '?' + queryString : ''}`;
944
+ return this.apiService.get(apiRoute);
945
+ }
946
+ loadProducts({ page, search } = {}) {
947
+ this.fetchProducts(page ?? 1, search ?? '').subscribe({
948
+ next: ({ data }) => {
949
+ this.productsSubject.next(data?.products ?? []);
950
+ },
951
+ error: () => {
952
+ this.productsSubject.next([]);
953
+ },
954
+ });
955
+ }
956
+ getCurrentProducts() {
957
+ return this.productsSubject.value;
958
+ }
959
+ fetchOneById(id) {
960
+ return this.apiService.get(PRODUCTS_API_ROUTES.findOneById(id));
961
+ }
962
+ createOne(data) {
963
+ return this.apiService.post(PRODUCTS_API_ROUTES.CREATE, data);
964
+ }
965
+ updateOne(id, data) {
966
+ return this.apiService.patch(PRODUCTS_API_ROUTES.update(id), data);
967
+ }
968
+ deleteOne(id) {
969
+ return this.apiService.delete(PRODUCTS_API_ROUTES.delete(id));
970
+ }
971
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: ProductService, deps: [{ token: ApiService }], target: i0.ɵɵFactoryTarget.Injectable });
972
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: ProductService, providedIn: 'root' });
973
+ }
974
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: ProductService, decorators: [{
975
+ type: Injectable,
976
+ args: [{ providedIn: 'root' }]
977
+ }], ctorParameters: () => [{ type: ApiService }] });
978
+
979
+ class ShowService {
980
+ apiService;
981
+ showsSubject = new BehaviorSubject([]);
982
+ shows$ = this.showsSubject.asObservable();
983
+ constructor(apiService) {
984
+ this.apiService = apiService;
985
+ }
986
+ loadShows({ page, search } = {}) {
987
+ this.fetchShows({ page, search }).subscribe({
988
+ next: ({ data }) => {
989
+ this.showsSubject.next(data?.shows ?? []);
990
+ },
991
+ error: () => {
992
+ this.showsSubject.next([]);
993
+ },
994
+ });
995
+ }
996
+ getCurrentShows() {
997
+ return this.showsSubject.value;
998
+ }
999
+ fetchShows({ limit, page, search }) {
1000
+ const queryParams = new URLSearchParams();
1001
+ if (page)
1002
+ queryParams.append('page', page.toString());
1003
+ if (limit)
1004
+ queryParams.append('limit', limit.toString());
1005
+ if (search)
1006
+ queryParams.append('search', search);
1007
+ const queryString = queryParams.toString();
1008
+ const apiRoute = `${SHOWS_API_ROUTES.findAll}${queryString ? '?' + queryString : ''}`;
1009
+ return this.apiService.get(apiRoute);
1010
+ }
1011
+ fetchAvailableShows({ date, limit, page, search, }) {
1012
+ const queryParams = new URLSearchParams();
1013
+ if (date)
1014
+ queryParams.append('date', date);
1015
+ if (page)
1016
+ queryParams.append('page', page.toString());
1017
+ if (search)
1018
+ queryParams.append('search', search);
1019
+ if (limit)
1020
+ queryParams.append('limit', limit.toString());
1021
+ const queryString = queryParams.toString();
1022
+ const apiRoute = `${SHOWS_API_ROUTES.publicAvailablePerformances}${queryString ? '?' + queryString : ''}`;
1023
+ return this.apiService.get(apiRoute);
1024
+ }
1025
+ fetchOneById(id) {
1026
+ return this.apiService.get(SHOWS_API_ROUTES.findOneById(id));
1027
+ }
1028
+ createOne(data) {
1029
+ return this.apiService.post(SHOWS_API_ROUTES.create, data);
1030
+ }
1031
+ updateOne(id, data) {
1032
+ return this.apiService.patch(SHOWS_API_ROUTES.update(id), data);
1033
+ }
1034
+ deleteOne(id) {
1035
+ return this.apiService.delete(SHOWS_API_ROUTES.delete(id));
1036
+ }
1037
+ fetchImages(id) {
1038
+ return this.apiService.get(SHOWS_API_ROUTES.getImages(id));
1039
+ }
1040
+ uploadImages(id, files) {
1041
+ return this.apiService.post(SHOWS_API_ROUTES.uploadGallery(id), files);
1042
+ }
1043
+ deleteOneImage(showId, imageId) {
1044
+ return this.apiService.delete(SHOWS_API_ROUTES.deleteOneImage(showId, imageId));
1045
+ }
1046
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: ShowService, deps: [{ token: ApiService }], target: i0.ɵɵFactoryTarget.Injectable });
1047
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: ShowService, providedIn: 'root' });
1048
+ }
1049
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: ShowService, decorators: [{
1050
+ type: Injectable,
1051
+ args: [{ providedIn: 'root' }]
1052
+ }], ctorParameters: () => [{ type: ApiService }] });
1053
+
1054
+ class CustomerService {
1055
+ apiService;
1056
+ constructor(apiService) {
1057
+ this.apiService = apiService;
1058
+ }
1059
+ createOne(data) {
1060
+ return this.apiService.post(CUSTOMERS_API_ROUTES.create, data);
1061
+ }
1062
+ fetchCustomers(page, search, limit) {
1063
+ const queryParams = new URLSearchParams();
1064
+ if (page)
1065
+ queryParams.append('page', page.toString());
1066
+ if (search)
1067
+ queryParams.append('search', search);
1068
+ if (limit)
1069
+ queryParams.append('limit', limit.toString());
1070
+ const queryString = queryParams.toString();
1071
+ const apiRoute = `${CUSTOMERS_API_ROUTES.findAll}${queryString ? '?' + queryString : ''}`;
1072
+ return this.apiService.get(apiRoute);
1073
+ }
1074
+ fetchOneById(id) {
1075
+ return this.apiService.get(CUSTOMERS_API_ROUTES.findOne(id));
1076
+ }
1077
+ updateOne(id, data) {
1078
+ return this.apiService.patch(CUSTOMERS_API_ROUTES.update(id), data);
1079
+ }
1080
+ deleteOne(id) {
1081
+ return this.apiService.delete(CUSTOMERS_API_ROUTES.delete(id));
1082
+ }
1083
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: CustomerService, deps: [{ token: ApiService }], target: i0.ɵɵFactoryTarget.Injectable });
1084
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: CustomerService, providedIn: 'root' });
1085
+ }
1086
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: CustomerService, decorators: [{
1087
+ type: Injectable,
1088
+ args: [{ providedIn: 'root' }]
1089
+ }], ctorParameters: () => [{ type: ApiService }] });
1090
+
1091
+ class PriceZoneService {
1092
+ apiService;
1093
+ priceZonesSubject = new BehaviorSubject([]);
1094
+ priceZones$ = this.priceZonesSubject.asObservable();
1095
+ constructor(apiService) {
1096
+ this.apiService = apiService;
1097
+ }
1098
+ fetchPriceZones({ roomMapId, page, search, limit, } = {}) {
1099
+ const queryParams = new URLSearchParams();
1100
+ if (roomMapId)
1101
+ queryParams.append('room_map_id', roomMapId.toString());
1102
+ if (page)
1103
+ queryParams.append('page', page.toString());
1104
+ if (search)
1105
+ queryParams.append('search', search);
1106
+ if (limit)
1107
+ queryParams.append('limit', limit.toString());
1108
+ const queryString = queryParams.toString();
1109
+ const apiRoute = `${PRICE_ZONES_API_ROUTES.FIND_ALL}${queryString ? '?' + queryString : ''}`;
1110
+ return this.apiService.get(apiRoute);
1111
+ }
1112
+ loadPriceZones({ roomMapId, page, search, limit } = {}) {
1113
+ this.fetchPriceZones({ roomMapId, page, search, limit }).subscribe({
1114
+ next: ({ data }) => {
1115
+ this.priceZonesSubject.next(data?.price_zones ?? []);
1116
+ },
1117
+ error: () => {
1118
+ this.priceZonesSubject.next([]);
1119
+ },
1120
+ });
1121
+ }
1122
+ getCurrentPriceZones() {
1123
+ return this.priceZonesSubject.value;
1124
+ }
1125
+ fetchOneById(id) {
1126
+ return this.apiService.get(PRICE_ZONES_API_ROUTES.findOneById(id));
1127
+ }
1128
+ createOne(data) {
1129
+ return this.apiService.post(PRICE_ZONES_API_ROUTES.CREATE, data);
1130
+ }
1131
+ duplicateOne(id, name) {
1132
+ return this.apiService.post(PRICE_ZONES_API_ROUTES.duplicate(id), { name });
1133
+ }
1134
+ updateOne(id, data) {
1135
+ return this.apiService.patch(PRICE_ZONES_API_ROUTES.update(id), data);
1136
+ }
1137
+ deleteOne(id) {
1138
+ return this.apiService.delete(PRICE_ZONES_API_ROUTES.delete(id));
1139
+ }
1140
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: PriceZoneService, deps: [{ token: ApiService }], target: i0.ɵɵFactoryTarget.Injectable });
1141
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: PriceZoneService, providedIn: 'root' });
1142
+ }
1143
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: PriceZoneService, decorators: [{
1144
+ type: Injectable,
1145
+ args: [{ providedIn: 'root' }]
1146
+ }], ctorParameters: () => [{ type: ApiService }] });
1147
+
1148
+ class PriceZoneEventService {
1149
+ priceZoneDeleted$ = new Subject();
1150
+ priceZoneSaved$ = new Subject();
1151
+ _selectedPriceZone = signal(null, ...(ngDevMode ? [{ debugName: "_selectedPriceZone" }] : []));
1152
+ selectedPriceZone$ = toObservable(this._selectedPriceZone);
1153
+ onPriceZoneDeleted() {
1154
+ this.priceZoneDeleted$.next();
1155
+ }
1156
+ getPriceZoneDeleted() {
1157
+ return this.priceZoneDeleted$.asObservable();
1158
+ }
1159
+ onPriceZoneSaved() {
1160
+ this.priceZoneSaved$.next();
1161
+ }
1162
+ getPriceZoneSaved() {
1163
+ return this.priceZoneSaved$.asObservable();
1164
+ }
1165
+ setSelectedPriceZone(priceZone) {
1166
+ this._selectedPriceZone.set(priceZone);
1167
+ }
1168
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: PriceZoneEventService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1169
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: PriceZoneEventService, providedIn: 'root' });
1170
+ }
1171
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: PriceZoneEventService, decorators: [{
1172
+ type: Injectable,
1173
+ args: [{ providedIn: 'root' }]
1174
+ }] });
1175
+
1176
+ class PriceZoneFormModalService {
1177
+ priceZoneEventService;
1178
+ priceZone = signal(null, ...(ngDevMode ? [{ debugName: "priceZone" }] : []));
1179
+ isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : []));
1180
+ constructor(priceZoneEventService) {
1181
+ this.priceZoneEventService = priceZoneEventService;
1182
+ }
1183
+ get modalIsOpen() {
1184
+ return this.isOpen;
1185
+ }
1186
+ get currentPriceZone() {
1187
+ return this.priceZone;
1188
+ }
1189
+ open(priceZone = null) {
1190
+ this.priceZone.set(priceZone);
1191
+ this.priceZoneEventService.setSelectedPriceZone(priceZone);
1192
+ this.isOpen.set(true);
1193
+ }
1194
+ close() {
1195
+ this.isOpen.set(false);
1196
+ this.priceZone.set(null);
1197
+ }
1198
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: PriceZoneFormModalService, deps: [{ token: PriceZoneEventService }], target: i0.ɵɵFactoryTarget.Injectable });
1199
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: PriceZoneFormModalService, providedIn: 'root' });
1200
+ }
1201
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: PriceZoneFormModalService, decorators: [{
1202
+ type: Injectable,
1203
+ args: [{ providedIn: 'root' }]
1204
+ }], ctorParameters: () => [{ type: PriceZoneEventService }] });
1205
+
1206
+ const authInterceptor = (req, next) => {
1207
+ const platformId = inject(PLATFORM_ID);
1208
+ const config = inject(TICKERA_COMPONENTS_CONFIG);
1209
+ if (isPlatformBrowser(platformId)) {
1210
+ const key = config.accessTokenKey ?? 'access_token';
1211
+ const token = localStorage.getItem(key);
1212
+ if (token) {
1213
+ req = req.clone({
1214
+ setHeaders: { Authorization: `Bearer ${token}` },
1215
+ });
1216
+ }
1217
+ }
1218
+ return next(req);
1219
+ };
1220
+
1221
+ class AppButtonComponent {
1222
+ clicked = new EventEmitter();
1223
+ disabled = false;
1224
+ loading = false;
1225
+ type = 'button';
1226
+ variant = 'primary';
1227
+ text = '';
1228
+ size = 'md';
1229
+ loadingText = '';
1230
+ icon = '';
1231
+ handleClick() {
1232
+ this.clicked.emit();
1233
+ }
1234
+ get buttonClasses() {
1235
+ const disabledClasses = this.disabled ? 'opacity-50 cursor-not-allowed' : '';
1236
+ const variantClasses = BUTTON_VARIANT_CLASSES[this.variant];
1237
+ const loadingClasses = this.loading ? 'opacity-50 cursor-not-allowed' : '';
1238
+ const sizeClasses = BUTTON_SIZES_CLASSES[this.size];
1239
+ return `${BASE_BUTTON_CLASSES} ${disabledClasses} ${variantClasses} ${loadingClasses} ${sizeClasses}`;
1240
+ }
1241
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: AppButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1242
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.25", type: AppButtonComponent, isStandalone: true, selector: "app-button", inputs: { disabled: "disabled", loading: "loading", type: "type", variant: "variant", text: "text", size: "size", loadingText: "loadingText", icon: "icon" }, outputs: { clicked: "clicked" }, ngImport: i0, template: "<button\n [type]=\"type\"\n [disabled]=\"loading || disabled\"\n class=\"{{ buttonClasses }}\"\n (click)=\"handleClick()\"\n>\n @if (icon && !loading) {\n <i class=\"{{ icon }}\"></i>\n }\n\n @if (loading) {\n <i class=\"ri-refresh-line animate-spin\"></i>\n }\n\n {{ loading ? loadingText : text }}\n</button>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }], encapsulation: i0.ViewEncapsulation.None });
1243
+ }
1244
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: AppButtonComponent, decorators: [{
1245
+ type: Component,
1246
+ args: [{ selector: 'app-button', standalone: true, imports: [CommonModule], encapsulation: ViewEncapsulation.None, template: "<button\n [type]=\"type\"\n [disabled]=\"loading || disabled\"\n class=\"{{ buttonClasses }}\"\n (click)=\"handleClick()\"\n>\n @if (icon && !loading) {\n <i class=\"{{ icon }}\"></i>\n }\n\n @if (loading) {\n <i class=\"ri-refresh-line animate-spin\"></i>\n }\n\n {{ loading ? loadingText : text }}\n</button>\n" }]
1247
+ }], propDecorators: { clicked: [{
1248
+ type: Output
1249
+ }], disabled: [{
1250
+ type: Input
1251
+ }], loading: [{
1252
+ type: Input
1253
+ }], type: [{
1254
+ type: Input
1255
+ }], variant: [{
1256
+ type: Input
1257
+ }], text: [{
1258
+ type: Input
1259
+ }], size: [{
1260
+ type: Input
1261
+ }], loadingText: [{
1262
+ type: Input
1263
+ }], icon: [{
1264
+ type: Input
1265
+ }] } });
1266
+
1267
+ class AppLinkButtonComponent {
1268
+ BASE_BUTTON_CLASSES = BASE_BUTTON_CLASSES;
1269
+ disabled = false;
1270
+ loading = false;
1271
+ target = '_self';
1272
+ text = '';
1273
+ icon = '';
1274
+ loadingText = '';
1275
+ route = '';
1276
+ queryParams = {};
1277
+ size = 'md';
1278
+ variant = 'primary';
1279
+ get buttonClasses() {
1280
+ const disabledClasses = this.disabled ? 'opacity-50 cursor-not-allowed' : '';
1281
+ const variantClasses = BUTTON_VARIANT_CLASSES[this.variant];
1282
+ const loadingClasses = this.loading ? 'opacity-50 cursor-not-allowed' : '';
1283
+ const sizeClasses = BUTTON_SIZES_CLASSES[this.size] || 'text-base';
1284
+ return [BASE_BUTTON_CLASSES, disabledClasses, variantClasses, loadingClasses, sizeClasses].join(' ');
1285
+ }
1286
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: AppLinkButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1287
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.25", type: AppLinkButtonComponent, isStandalone: true, selector: "app-link-button", inputs: { disabled: "disabled", loading: "loading", target: "target", text: "text", icon: "icon", loadingText: "loadingText", route: "route", queryParams: "queryParams", size: "size", variant: "variant" }, ngImport: i0, template: "<a class=\"{{ buttonClasses }}\" [routerLink]=\"!disabled ? route : null\" [queryParams]=\"queryParams\" [target]=\"target\">\n @if (icon) {\n <i [class]=\"icon\"></i>\n }\n\n {{ loading ? loadingText : text }}\n</a>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: TranslocoModule }], encapsulation: i0.ViewEncapsulation.None });
1288
+ }
1289
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: AppLinkButtonComponent, decorators: [{
1290
+ type: Component,
1291
+ args: [{ selector: 'app-link-button', standalone: true, imports: [CommonModule, RouterLink, TranslocoModule], encapsulation: ViewEncapsulation.None, template: "<a class=\"{{ buttonClasses }}\" [routerLink]=\"!disabled ? route : null\" [queryParams]=\"queryParams\" [target]=\"target\">\n @if (icon) {\n <i [class]=\"icon\"></i>\n }\n\n {{ loading ? loadingText : text }}\n</a>\n" }]
1292
+ }], propDecorators: { disabled: [{
1293
+ type: Input
1294
+ }], loading: [{
1295
+ type: Input
1296
+ }], target: [{
1297
+ type: Input
1298
+ }], text: [{
1299
+ type: Input
1300
+ }], icon: [{
1301
+ type: Input
1302
+ }], loadingText: [{
1303
+ type: Input
1304
+ }], route: [{
1305
+ type: Input
1306
+ }], queryParams: [{
1307
+ type: Input
1308
+ }], size: [{
1309
+ type: Input
1310
+ }], variant: [{
1311
+ type: Input
1312
+ }] } });
1313
+
1314
+ class AppAlertComponent {
1315
+ type = 'success';
1316
+ text = '';
1317
+ closeable = false;
1318
+ size = 'md';
1319
+ get alertColorClasses() {
1320
+ return ALERT_COLOR_CLASSES[this.type] ?? ALERT_COLOR_CLASSES.success;
1321
+ }
1322
+ get alertSizeClasses() {
1323
+ return ALERT_SIZE_CLASSES[this.size] ?? ALERT_SIZE_CLASSES.sm;
1324
+ }
1325
+ get alertClasses() {
1326
+ return `${ALERT_BASE_CLASSES} ${this.alertColorClasses} ${this.alertSizeClasses}`;
1327
+ }
1328
+ get alertIcon() {
1329
+ return ALERT_ICONS[this.type] ?? ALERT_ICONS.info;
1330
+ }
1331
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: AppAlertComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1332
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.25", type: AppAlertComponent, isStandalone: true, selector: "app-alert", inputs: { type: "type", text: "text", closeable: "closeable", size: "size" }, ngImport: i0, template: "<div class=\"{{ alertClasses }}\" role=\"alert\">\n <div class=\"flex items-center gap-2\">\n <i class=\"{{ alertIcon }}\"></i>\n <span>{{ text }}</span>\n </div>\n\n @if (closeable) {\n <span\n class=\"absolute top-0 bottom-0 right-0 h-full w-8 flex items-center justify-center cursor-pointer\"\n >\n <i class=\"ri-close-line\"></i>\n </span>\n }\n</div>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }], encapsulation: i0.ViewEncapsulation.None });
1333
+ }
1334
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: AppAlertComponent, decorators: [{
1335
+ type: Component,
1336
+ args: [{ selector: 'app-alert', standalone: true, imports: [CommonModule], encapsulation: ViewEncapsulation.None, template: "<div class=\"{{ alertClasses }}\" role=\"alert\">\n <div class=\"flex items-center gap-2\">\n <i class=\"{{ alertIcon }}\"></i>\n <span>{{ text }}</span>\n </div>\n\n @if (closeable) {\n <span\n class=\"absolute top-0 bottom-0 right-0 h-full w-8 flex items-center justify-center cursor-pointer\"\n >\n <i class=\"ri-close-line\"></i>\n </span>\n }\n</div>\n" }]
1337
+ }], propDecorators: { type: [{
1338
+ type: Input
1339
+ }], text: [{
1340
+ type: Input
1341
+ }], closeable: [{
1342
+ type: Input
1343
+ }], size: [{
1344
+ type: Input
1345
+ }] } });
1346
+
1347
+ class AppModalComponent {
1348
+ title = '';
1349
+ disableClose = false;
1350
+ isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : []));
1351
+ size = 'md';
1352
+ closeModal = new EventEmitter();
1353
+ onCloseModal() {
1354
+ if (this.disableClose)
1355
+ return;
1356
+ this.closeModal.emit();
1357
+ }
1358
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: AppModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1359
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.25", type: AppModalComponent, isStandalone: true, selector: "app-modal", inputs: { title: "title", disableClose: "disableClose", isOpen: "isOpen", size: "size" }, outputs: { closeModal: "closeModal" }, ngImport: i0, template: "@if (isOpen()) {\n <div class=\"fixed inset-0 flex items-center justify-center z-50\">\n <div class=\"absolute inset-0 bg-black opacity-50\" (click)=\"onCloseModal()\"></div>\n\n <div\n [class]=\"`bg-white rounded-lg max-h-screen overflow-y-auto shadow-xl relative z-10 max-w-${size} w-full`\"\n >\n @if (!disableClose || !!title) {\n <div class=\"flex justify-between items-center p-5 border-b border-gray-200\">\n <h3 class=\"text-lg font-semibold text-gray-800 m-0\">{{ title }}</h3>\n\n @if (!disableClose) {\n <button\n class=\"bg-none border-none text-2xl cursor-pointer text-gray-600 p-0 w-7.5 h-7.5 flex items-center justify-center hover:text-gray-800\"\n (click)=\"onCloseModal()\"\n >\n &times;\n </button>\n }\n </div>\n }\n\n <div class=\"p-5\">\n <ng-content></ng-content>\n </div>\n </div>\n </div>\n}\n", styles: [".max-w-xl{max-width:36rem}.max-w-2xl{max-width:42rem}.max-w-3xl{max-width:48rem}.max-w-4xl{max-width:56rem}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }], encapsulation: i0.ViewEncapsulation.None });
1360
+ }
1361
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: AppModalComponent, decorators: [{
1362
+ type: Component,
1363
+ args: [{ selector: 'app-modal', standalone: true, imports: [CommonModule], encapsulation: ViewEncapsulation.None, template: "@if (isOpen()) {\n <div class=\"fixed inset-0 flex items-center justify-center z-50\">\n <div class=\"absolute inset-0 bg-black opacity-50\" (click)=\"onCloseModal()\"></div>\n\n <div\n [class]=\"`bg-white rounded-lg max-h-screen overflow-y-auto shadow-xl relative z-10 max-w-${size} w-full`\"\n >\n @if (!disableClose || !!title) {\n <div class=\"flex justify-between items-center p-5 border-b border-gray-200\">\n <h3 class=\"text-lg font-semibold text-gray-800 m-0\">{{ title }}</h3>\n\n @if (!disableClose) {\n <button\n class=\"bg-none border-none text-2xl cursor-pointer text-gray-600 p-0 w-7.5 h-7.5 flex items-center justify-center hover:text-gray-800\"\n (click)=\"onCloseModal()\"\n >\n &times;\n </button>\n }\n </div>\n }\n\n <div class=\"p-5\">\n <ng-content></ng-content>\n </div>\n </div>\n </div>\n}\n", styles: [".max-w-xl{max-width:36rem}.max-w-2xl{max-width:42rem}.max-w-3xl{max-width:48rem}.max-w-4xl{max-width:56rem}\n"] }]
1364
+ }], propDecorators: { title: [{
1365
+ type: Input
1366
+ }], disableClose: [{
1367
+ type: Input
1368
+ }], isOpen: [{
1369
+ type: Input
1370
+ }], size: [{
1371
+ type: Input
1372
+ }], closeModal: [{
1373
+ type: Output
1374
+ }] } });
1375
+
1376
+ class LoadingmModalComponent {
1377
+ loadingModalService;
1378
+ constructor(loadingModalService) {
1379
+ this.loadingModalService = loadingModalService;
1380
+ }
1381
+ get isOpen() {
1382
+ return this.loadingModalService.modalIsOpen;
1383
+ }
1384
+ get title() {
1385
+ return this.loadingModalService.title;
1386
+ }
1387
+ closeModal() {
1388
+ this.loadingModalService.close();
1389
+ }
1390
+ onCitySaved() {
1391
+ this.loadingModalService.close();
1392
+ }
1393
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: LoadingmModalComponent, deps: [{ token: LoadingModalService }], target: i0.ɵɵFactoryTarget.Component });
1394
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.25", type: LoadingmModalComponent, isStandalone: true, selector: "loading-modal", ngImport: i0, template: "<app-modal [disableClose]=\"true\" [isOpen]=\"isOpen\" (closeModal)=\"closeModal()\">\n <div class=\"flex flex-col gap-4 py-6 w-full\">\n <div role=\"status\">\n <div class=\"flex items-center justify-center\">\n <div\n class=\"h-14 w-14 animate-spin rounded-full border-8 border-solid border-red-500 border-t-transparent\"\n ></div>\n </div>\n <span class=\"sr-only\">Loading...</span>\n </div>\n\n <p class=\"font-bold text-md text-center\">{{ title() }}</p>\n </div>\n</app-modal>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: AppModalComponent, selector: "app-modal", inputs: ["title", "disableClose", "isOpen", "size"], outputs: ["closeModal"] }] });
1395
+ }
1396
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: LoadingmModalComponent, decorators: [{
1397
+ type: Component,
1398
+ args: [{ selector: 'loading-modal', standalone: true, imports: [CommonModule, AppModalComponent], template: "<app-modal [disableClose]=\"true\" [isOpen]=\"isOpen\" (closeModal)=\"closeModal()\">\n <div class=\"flex flex-col gap-4 py-6 w-full\">\n <div role=\"status\">\n <div class=\"flex items-center justify-center\">\n <div\n class=\"h-14 w-14 animate-spin rounded-full border-8 border-solid border-red-500 border-t-transparent\"\n ></div>\n </div>\n <span class=\"sr-only\">Loading...</span>\n </div>\n\n <p class=\"font-bold text-md text-center\">{{ title() }}</p>\n </div>\n</app-modal>\n" }]
1399
+ }], ctorParameters: () => [{ type: LoadingModalService }] });
1400
+
1401
+ class FormInputComponent {
1402
+ ngControl;
1403
+ transloco;
1404
+ label = '';
1405
+ type = 'text';
1406
+ name = '';
1407
+ id = '';
1408
+ placeholder = '';
1409
+ required = false;
1410
+ readonly = false;
1411
+ minlength = null;
1412
+ min = null;
1413
+ step = 1;
1414
+ pattern = null;
1415
+ fieldGroupClass = '';
1416
+ autocomplete = true;
1417
+ value = '';
1418
+ disabled = false;
1419
+ onChange = () => { };
1420
+ onTouched = () => { };
1421
+ constructor(ngControl, transloco) {
1422
+ this.ngControl = ngControl;
1423
+ this.transloco = transloco;
1424
+ if (this.ngControl) {
1425
+ this.ngControl.valueAccessor = this;
1426
+ }
1427
+ }
1428
+ writeValue(value) {
1429
+ this.value = value;
1430
+ }
1431
+ registerOnChange(fn) {
1432
+ this.onChange = fn;
1433
+ }
1434
+ registerOnTouched(fn) {
1435
+ this.onTouched = fn;
1436
+ }
1437
+ setDisabledState(isDisabled) {
1438
+ this.disabled = isDisabled;
1439
+ }
1440
+ onInput(value) {
1441
+ this.value = value;
1442
+ this.onChange(value);
1443
+ this.onTouched();
1444
+ }
1445
+ get inputId() {
1446
+ return this.id || this.name;
1447
+ }
1448
+ get showError() {
1449
+ if (!this.ngControl || !this.ngControl.control)
1450
+ return false;
1451
+ const control = this.ngControl.control;
1452
+ const dirty = control.dirty;
1453
+ const touched = control.touched;
1454
+ return control.invalid ? dirty || touched : false;
1455
+ }
1456
+ get errorMessage() {
1457
+ if (!this.ngControl?.errors)
1458
+ return '';
1459
+ const errors = this.ngControl.errors;
1460
+ const errorKey = Object.keys(errors)[0];
1461
+ if (errorKey === 'minlength') {
1462
+ return this.transloco.translate('formErrors.minlength', {
1463
+ length: errors[errorKey].requiredLength,
1464
+ });
1465
+ }
1466
+ if (errorKey === 'maxlength') {
1467
+ return this.transloco.translate('formErrors.maxlength', {
1468
+ length: errors[errorKey].requiredLength,
1469
+ });
1470
+ }
1471
+ if (errorKey === 'email') {
1472
+ return this.transloco.translate('formErrors.email');
1473
+ }
1474
+ return this.transloco.translate(`formErrors.${errorKey}`);
1475
+ }
1476
+ get inputClasses() {
1477
+ return this.showError ? ERROR_INPUT_CLASSES : BASE_INPUT_CLASSES;
1478
+ }
1479
+ get fieldGroupClasses() {
1480
+ let baseClasses = '';
1481
+ if (this.fieldGroupClass) {
1482
+ baseClasses += ` ${this.fieldGroupClass}`;
1483
+ }
1484
+ else {
1485
+ baseClasses += ' w-full';
1486
+ }
1487
+ return baseClasses;
1488
+ }
1489
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: FormInputComponent, deps: [{ token: i1$1.NgControl, optional: true, self: true }, { token: i2.TranslocoService }], target: i0.ɵɵFactoryTarget.Component });
1490
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.25", type: FormInputComponent, isStandalone: true, selector: "form-input", inputs: { label: "label", type: "type", name: "name", id: "id", placeholder: "placeholder", required: "required", readonly: "readonly", minlength: "minlength", min: "min", step: "step", pattern: "pattern", fieldGroupClass: "fieldGroupClass", autocomplete: "autocomplete" }, ngImport: i0, template: "<div [class]=\"fieldGroupClasses\">\n @if (label) {\n <label [for]=\"inputId\" class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n {{ label }}\n\n @if (required) {\n <span class=\"text-red-500\">*</span>\n }\n </label>\n }\n\n <div class=\"relative\">\n <input\n [type]=\"type\"\n [id]=\"inputId\"\n [name]=\"name\"\n [placeholder]=\"placeholder\"\n [required]=\"required\"\n [minlength]=\"minlength\"\n [pattern]=\"pattern || ''\"\n [(ngModel)]=\"value\"\n (ngModelChange)=\"onInput($event)\"\n (blur)=\"onTouched()\"\n [readonly]=\"readonly\"\n [disabled]=\"disabled\"\n [class.bg-white]=\"!readonly\"\n [class.bg-gray-200]=\"readonly\"\n [class.cursor-not-allowed]=\"readonly\"\n [class]=\"inputClasses\"\n [autocomplete]=\"autocomplete\"\n [min]=\"min\"\n [step]=\"step\"\n />\n </div>\n\n @if (showError) {\n <div class=\"text-red-500 text-xs mt-1\">\n {{ errorMessage }}\n </div>\n }\n</div>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$1.MinLengthValidator, selector: "[minlength][formControlName],[minlength][formControl],[minlength][ngModel]", inputs: ["minlength"] }, { kind: "directive", type: i1$1.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }] });
1491
+ }
1492
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: FormInputComponent, decorators: [{
1493
+ type: Component,
1494
+ args: [{ selector: 'form-input', standalone: true, imports: [FormsModule, CommonModule, ReactiveFormsModule], template: "<div [class]=\"fieldGroupClasses\">\n @if (label) {\n <label [for]=\"inputId\" class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n {{ label }}\n\n @if (required) {\n <span class=\"text-red-500\">*</span>\n }\n </label>\n }\n\n <div class=\"relative\">\n <input\n [type]=\"type\"\n [id]=\"inputId\"\n [name]=\"name\"\n [placeholder]=\"placeholder\"\n [required]=\"required\"\n [minlength]=\"minlength\"\n [pattern]=\"pattern || ''\"\n [(ngModel)]=\"value\"\n (ngModelChange)=\"onInput($event)\"\n (blur)=\"onTouched()\"\n [readonly]=\"readonly\"\n [disabled]=\"disabled\"\n [class.bg-white]=\"!readonly\"\n [class.bg-gray-200]=\"readonly\"\n [class.cursor-not-allowed]=\"readonly\"\n [class]=\"inputClasses\"\n [autocomplete]=\"autocomplete\"\n [min]=\"min\"\n [step]=\"step\"\n />\n </div>\n\n @if (showError) {\n <div class=\"text-red-500 text-xs mt-1\">\n {{ errorMessage }}\n </div>\n }\n</div>\n" }]
1495
+ }], ctorParameters: () => [{ type: i1$1.NgControl, decorators: [{
1496
+ type: Self
1497
+ }, {
1498
+ type: Optional
1499
+ }] }, { type: i2.TranslocoService }], propDecorators: { label: [{
1500
+ type: Input
1501
+ }], type: [{
1502
+ type: Input
1503
+ }], name: [{
1504
+ type: Input
1505
+ }], id: [{
1506
+ type: Input
1507
+ }], placeholder: [{
1508
+ type: Input
1509
+ }], required: [{
1510
+ type: Input
1511
+ }], readonly: [{
1512
+ type: Input
1513
+ }], minlength: [{
1514
+ type: Input
1515
+ }], min: [{
1516
+ type: Input
1517
+ }], step: [{
1518
+ type: Input
1519
+ }], pattern: [{
1520
+ type: Input
1521
+ }], fieldGroupClass: [{
1522
+ type: Input
1523
+ }], autocomplete: [{
1524
+ type: Input
1525
+ }] } });
1526
+
1527
+ class DeleteConfirmationComponent {
1528
+ fb;
1529
+ deleteConfirmationService;
1530
+ transloco;
1531
+ deleteConfirmationForm;
1532
+ constructor(fb, deleteConfirmationService, transloco) {
1533
+ this.fb = fb;
1534
+ this.deleteConfirmationService = deleteConfirmationService;
1535
+ this.transloco = transloco;
1536
+ this.deleteConfirmationForm = this.fb.group({
1537
+ confirmationText: ['', [Validators.required]],
1538
+ });
1539
+ }
1540
+ get title() {
1541
+ return this.deleteConfirmationService.modalTitle();
1542
+ }
1543
+ get resourceName() {
1544
+ return this.deleteConfirmationService.modalResourceName();
1545
+ }
1546
+ get confirmationText() {
1547
+ return this.deleteConfirmationService.modalConfirmationText();
1548
+ }
1549
+ get isOpen() {
1550
+ return this.deleteConfirmationService.modalIsOpen;
1551
+ }
1552
+ get isConfirmationValid() {
1553
+ const value = this.deleteConfirmationForm.value.confirmationText?.trim()?.toLowerCase();
1554
+ const confirmation = this.confirmationText?.trim()?.toLowerCase();
1555
+ return value == confirmation;
1556
+ }
1557
+ onCloseModal() {
1558
+ this.deleteConfirmationForm.reset();
1559
+ this.deleteConfirmationService.close();
1560
+ }
1561
+ onConfirmDelete() {
1562
+ const callback = this.deleteConfirmationService.getConfirmDeleteCallback();
1563
+ if (callback) {
1564
+ callback();
1565
+ }
1566
+ this.deleteConfirmationForm.reset();
1567
+ this.deleteConfirmationService.close();
1568
+ }
1569
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: DeleteConfirmationComponent, deps: [{ token: i1$1.FormBuilder }, { token: DeleteConfirmationService }, { token: i2.TranslocoService }], target: i0.ɵɵFactoryTarget.Component });
1570
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.25", type: DeleteConfirmationComponent, isStandalone: true, selector: "delete-confirmation", ngImport: i0, template: "@if (isOpen()) {\n <app-modal [title]=\"title\" [isOpen]=\"isOpen\" (closeModal)=\"onCloseModal()\">\n <form\n [formGroup]=\"deleteConfirmationForm\"\n method=\"POST\"\n class=\"flex flex-col gap-4\"\n (ngSubmit)=\"onConfirmDelete()\"\n >\n <app-alert\n type=\"warning\"\n [text]=\"'deleteConfirmation.warning' | transloco\"\n size=\"sm\"\n [closeable]=\"false\"\n />\n\n <p class=\"text-xs text-gray-600\">\n {{ 'deleteConfirmation.instructions' | transloco }}\n\n <span\n class=\"inline-flex bg-gray-200 items-center px-2 py-1 gap-1 text-red-600 font-semibold text-sm rounded mt-1\"\n >\n {{ confirmationText }}\n </span>\n </p>\n\n <form-input\n name=\"confirmationText\"\n type=\"text\"\n class=\"flex-1\"\n [required]=\"true\"\n [autocomplete]=\"false\"\n formControlName=\"confirmationText\"\n [placeholder]=\"\n transloco.translate('deleteConfirmation.placeholder', { text: confirmationText })\n \"\n />\n\n <div class=\"flex space-x-3\">\n <app-button\n variant=\"terciary\"\n [text]=\"'deleteConfirmation.cancel' | transloco\"\n (click)=\"onCloseModal()\"\n size=\"sm\"\n />\n\n <app-button\n type=\"submit\"\n variant=\"primary\"\n [text]=\"'deleteConfirmation.delete' | transloco\"\n [disabled]=\"!isConfirmationValid\"\n size=\"sm\"\n />\n </div>\n </form>\n </app-modal>\n}\n", styles: [".delete-confirmation-modal{animation:fadeIn .3s ease-out}.delete-confirmation-content{animation:slideUp .3s ease-out}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}@keyframes slideUp{0%{transform:translateY(20px);opacity:0}to{transform:translateY(0);opacity:1}}.confirmation-input{transition:all .2s ease}.confirmation-input:focus{box-shadow:0 0 0 3px #ef44441a}.confirmation-input.invalid{border-color:#dc2626}.confirmation-input.invalid:focus{border-color:#dc2626;box-shadow:0 0 0 3px #dc26261a}.delete-button{transition:all .2s ease}.delete-button:disabled{opacity:.5;cursor:not-allowed}.delete-button:not(:disabled):hover{transform:translateY(-1px);box-shadow:0 4px 12px #dc26264d}.warning-message{border-left:4px solid #f59e0b;background:linear-gradient(135deg,#fef3c7,#fde68a)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: TranslocoModule }, { kind: "component", type: AppButtonComponent, selector: "app-button", inputs: ["disabled", "loading", "type", "variant", "text", "size", "loadingText", "icon"], outputs: ["clicked"] }, { kind: "component", type: FormInputComponent, selector: "form-input", inputs: ["label", "type", "name", "id", "placeholder", "required", "readonly", "minlength", "min", "step", "pattern", "fieldGroupClass", "autocomplete"] }, { kind: "component", type: AppModalComponent, selector: "app-modal", inputs: ["title", "disableClose", "isOpen", "size"], outputs: ["closeModal"] }, { kind: "component", type: AppAlertComponent, selector: "app-alert", inputs: ["type", "text", "closeable", "size"] }, { kind: "pipe", type: i2.TranslocoPipe, name: "transloco" }], encapsulation: i0.ViewEncapsulation.None });
1571
+ }
1572
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: DeleteConfirmationComponent, decorators: [{
1573
+ type: Component,
1574
+ args: [{ selector: 'delete-confirmation', standalone: true, imports: [
1575
+ CommonModule,
1576
+ ReactiveFormsModule,
1577
+ TranslocoModule,
1578
+ AppButtonComponent,
1579
+ FormInputComponent,
1580
+ AppModalComponent,
1581
+ AppAlertComponent,
1582
+ ], encapsulation: ViewEncapsulation.None, template: "@if (isOpen()) {\n <app-modal [title]=\"title\" [isOpen]=\"isOpen\" (closeModal)=\"onCloseModal()\">\n <form\n [formGroup]=\"deleteConfirmationForm\"\n method=\"POST\"\n class=\"flex flex-col gap-4\"\n (ngSubmit)=\"onConfirmDelete()\"\n >\n <app-alert\n type=\"warning\"\n [text]=\"'deleteConfirmation.warning' | transloco\"\n size=\"sm\"\n [closeable]=\"false\"\n />\n\n <p class=\"text-xs text-gray-600\">\n {{ 'deleteConfirmation.instructions' | transloco }}\n\n <span\n class=\"inline-flex bg-gray-200 items-center px-2 py-1 gap-1 text-red-600 font-semibold text-sm rounded mt-1\"\n >\n {{ confirmationText }}\n </span>\n </p>\n\n <form-input\n name=\"confirmationText\"\n type=\"text\"\n class=\"flex-1\"\n [required]=\"true\"\n [autocomplete]=\"false\"\n formControlName=\"confirmationText\"\n [placeholder]=\"\n transloco.translate('deleteConfirmation.placeholder', { text: confirmationText })\n \"\n />\n\n <div class=\"flex space-x-3\">\n <app-button\n variant=\"terciary\"\n [text]=\"'deleteConfirmation.cancel' | transloco\"\n (click)=\"onCloseModal()\"\n size=\"sm\"\n />\n\n <app-button\n type=\"submit\"\n variant=\"primary\"\n [text]=\"'deleteConfirmation.delete' | transloco\"\n [disabled]=\"!isConfirmationValid\"\n size=\"sm\"\n />\n </div>\n </form>\n </app-modal>\n}\n", styles: [".delete-confirmation-modal{animation:fadeIn .3s ease-out}.delete-confirmation-content{animation:slideUp .3s ease-out}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}@keyframes slideUp{0%{transform:translateY(20px);opacity:0}to{transform:translateY(0);opacity:1}}.confirmation-input{transition:all .2s ease}.confirmation-input:focus{box-shadow:0 0 0 3px #ef44441a}.confirmation-input.invalid{border-color:#dc2626}.confirmation-input.invalid:focus{border-color:#dc2626;box-shadow:0 0 0 3px #dc26261a}.delete-button{transition:all .2s ease}.delete-button:disabled{opacity:.5;cursor:not-allowed}.delete-button:not(:disabled):hover{transform:translateY(-1px);box-shadow:0 4px 12px #dc26264d}.warning-message{border-left:4px solid #f59e0b;background:linear-gradient(135deg,#fef3c7,#fde68a)}\n"] }]
1583
+ }], ctorParameters: () => [{ type: i1$1.FormBuilder }, { type: DeleteConfirmationService }, { type: i2.TranslocoService }] });
1584
+
1585
+ class AuditInformationComponent {
1586
+ data = null;
1587
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: AuditInformationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1588
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.25", type: AuditInformationComponent, isStandalone: true, selector: "app-audit-information", inputs: { data: "data" }, ngImport: i0, template: "@if (data) {\n <div class=\"w-full bg-white rounded-lg shadow-lg overflow-hidden\">\n <div class=\"border-b border-gray-200 last:border-b-0\">\n <div class=\"flex items-center justify-between p-4 bg-gray-50 border-b border-gray-200\">\n <p class=\"text-sm font-semibold\">Informaci\u00F3n de auditoria</p>\n </div>\n\n <div class=\"p-4 w-full\">\n <ul class=\"flex flex-col gap-4 list-none p-0 m-0 w-full text-xs\">\n <li class=\"flex flex-col items-start\">\n <span class=\"font-bold\">Fecha de creaci\u00F3n:</span>\n <span>{{ data.created_at | date: 'medium' }}</span>\n </li>\n\n @if (data.created_by_admin) {\n <li class=\"flex flex-col items-start\">\n <span class=\"font-bold\">Creado por:</span>\n <span>\n {{ data.created_by_admin.first_name }} - {{ data.created_by_admin.email }}\n </span>\n </li>\n }\n\n @if (data.updated_at) {\n <li class=\"flex flex-col items-start\">\n <span class=\"font-bold\">\u00DAltima actualizaci\u00F3n:</span>\n <span>{{ data.updated_at | date: 'medium' }}</span>\n </li>\n }\n\n @if (data.updated_by_admin) {\n <li class=\"flex flex-col items-start\">\n <span class=\"font-bold\">Actualizado por:</span>\n <span>\n {{ data.updated_by_admin.first_name }} - {{ data.updated_by_admin.email }}\n </span>\n </li>\n }\n\n @if (data.is_published && data.published_at) {\n <li class=\"flex flex-col items-start\">\n <span class=\"font-bold\">Fecha de publicaci\u00F3n:</span>\n <span>{{ data.published_at | date: 'medium' }}</span>\n </li>\n }\n\n @if (data.is_published && data.published_by_admin) {\n <li class=\"flex flex-col items-start\">\n <span class=\"font-bold\">Publicado por:</span>\n <span>\n {{ data.published_by_admin.first_name }} - {{ data.published_by_admin.email }}\n </span>\n </li>\n }\n </ul>\n </div>\n </div>\n </div>\n}\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "pipe", type: i1$2.DatePipe, name: "date" }] });
1589
+ }
1590
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: AuditInformationComponent, decorators: [{
1591
+ type: Component,
1592
+ args: [{ selector: 'app-audit-information', standalone: true, imports: [CommonModule, DatePipe], template: "@if (data) {\n <div class=\"w-full bg-white rounded-lg shadow-lg overflow-hidden\">\n <div class=\"border-b border-gray-200 last:border-b-0\">\n <div class=\"flex items-center justify-between p-4 bg-gray-50 border-b border-gray-200\">\n <p class=\"text-sm font-semibold\">Informaci\u00F3n de auditoria</p>\n </div>\n\n <div class=\"p-4 w-full\">\n <ul class=\"flex flex-col gap-4 list-none p-0 m-0 w-full text-xs\">\n <li class=\"flex flex-col items-start\">\n <span class=\"font-bold\">Fecha de creaci\u00F3n:</span>\n <span>{{ data.created_at | date: 'medium' }}</span>\n </li>\n\n @if (data.created_by_admin) {\n <li class=\"flex flex-col items-start\">\n <span class=\"font-bold\">Creado por:</span>\n <span>\n {{ data.created_by_admin.first_name }} - {{ data.created_by_admin.email }}\n </span>\n </li>\n }\n\n @if (data.updated_at) {\n <li class=\"flex flex-col items-start\">\n <span class=\"font-bold\">\u00DAltima actualizaci\u00F3n:</span>\n <span>{{ data.updated_at | date: 'medium' }}</span>\n </li>\n }\n\n @if (data.updated_by_admin) {\n <li class=\"flex flex-col items-start\">\n <span class=\"font-bold\">Actualizado por:</span>\n <span>\n {{ data.updated_by_admin.first_name }} - {{ data.updated_by_admin.email }}\n </span>\n </li>\n }\n\n @if (data.is_published && data.published_at) {\n <li class=\"flex flex-col items-start\">\n <span class=\"font-bold\">Fecha de publicaci\u00F3n:</span>\n <span>{{ data.published_at | date: 'medium' }}</span>\n </li>\n }\n\n @if (data.is_published && data.published_by_admin) {\n <li class=\"flex flex-col items-start\">\n <span class=\"font-bold\">Publicado por:</span>\n <span>\n {{ data.published_by_admin.first_name }} - {{ data.published_by_admin.email }}\n </span>\n </li>\n }\n </ul>\n </div>\n </div>\n </div>\n}\n" }]
1593
+ }], propDecorators: { data: [{
1594
+ type: Input
1595
+ }] } });
1596
+
1597
+ class DynamicTableComponent {
1598
+ injector;
1599
+ constructor(injector) {
1600
+ this.injector = injector;
1601
+ }
1602
+ title = '';
1603
+ data = [];
1604
+ headers = [];
1605
+ columnComponents = {};
1606
+ // Inputs necesarios para la paginación remota
1607
+ isLoading = true;
1608
+ totalItems = 0;
1609
+ itemsPerPage = 10;
1610
+ currentPage = 1;
1611
+ // Eventos para avisar al Backend
1612
+ pageChange = new EventEmitter();
1613
+ searchChange = new EventEmitter();
1614
+ // Visualización de paginación
1615
+ showPagination = true;
1616
+ // Visualización de búsqueda
1617
+ showSearch = true;
1618
+ // Visualización de título
1619
+ showTitle = true;
1620
+ get totalPages() {
1621
+ return Math.ceil(this.totalItems / this.itemsPerPage) || 1;
1622
+ }
1623
+ onSearch(event) {
1624
+ this.data = [];
1625
+ const value = event.target.value;
1626
+ this.searchChange.emit(value); // El padre recibe el término y hace el fetch
1627
+ }
1628
+ changePage(delta) {
1629
+ const newPage = this.currentPage + delta;
1630
+ if (newPage > 0 && newPage <= this.totalPages) {
1631
+ this.pageChange.emit(newPage); // El padre recibe la nueva página
1632
+ }
1633
+ }
1634
+ createInjector(row) {
1635
+ return Injector.create({
1636
+ providers: [{ provide: 'ROW_DATA', useValue: row }],
1637
+ parent: this.injector,
1638
+ });
1639
+ }
1640
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: DynamicTableComponent, deps: [{ token: i0.Injector }], target: i0.ɵɵFactoryTarget.Component });
1641
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.25", type: DynamicTableComponent, isStandalone: true, selector: "dynamic-table", inputs: { title: "title", data: "data", headers: "headers", columnComponents: "columnComponents", isLoading: "isLoading", totalItems: "totalItems", itemsPerPage: "itemsPerPage", currentPage: "currentPage", showPagination: "showPagination", showSearch: "showSearch", showTitle: "showTitle" }, outputs: { pageChange: "pageChange", searchChange: "searchChange" }, ngImport: i0, template: "<div\n class=\"bg-white rounded-lg overflow-hidden border border-gray-200 dark:bg-gray-800 dark:border-gray-700\"\n>\n @if (showTitle || showSearch) {\n <div class=\"p-4 border-b border-gray-200 flex items-center justify-start dark:border-gray-700\">\n @if (showTitle) {\n <h2 class=\"text-lg font-semibold dark:text-white\">{{ title }}</h2>\n }\n\n @if (showSearch) {\n <input\n type=\"text\"\n (input)=\"onSearch($event)\"\n placeholder=\"Buscar...\"\n class=\"ml-auto block w-sm rounded-md bg-white px-3 py-1.5 text-base text-gray-900 outline-1 -outline-offset-1 outline-gray-300 placeholder:text-gray-400 focus:outline-2 focus:-outline-offset-2 focus:outline-indigo-600 sm:text-sm/6 dark:bg-white/5 dark:text-white dark:outline-white/10 dark:placeholder:text-gray-500 dark:focus:outline-indigo-500\"\n />\n }\n </div>\n }\n\n <div class=\"overflow-x-auto\">\n <table class=\"w-full text-left border-collapse\">\n <thead class=\"bg-gray-100 text-gray-600 text-xs dark:bg-gray-700 dark:text-gray-300\">\n <tr>\n @for (header of headers; track header.key) {\n <th class=\"p-3 border-b border-gray-300 whitespace-nowrap dark:border-gray-600\">\n {{ header.label }}\n </th>\n }\n </tr>\n </thead>\n\n <tbody class=\"text-gray-700 text-xs dark:text-gray-200\">\n @if (isLoading) {\n <tr\n class=\"border-b even:bg-gray-100 border-gray-200 last:border-none transition-colors dark:even:bg-gray-700/50 dark:border-gray-700\"\n >\n @for (header of headers; track header.key) {\n <td class=\"p-3\">\n <div class=\"h-5 bg-gray-200 rounded animate-pulse w-full dark:bg-gray-600\"></div>\n </td>\n }\n </tr>\n }\n\n @for (row of data; track row) {\n <tr\n class=\"hover:bg-gray-200 border-b even:bg-gray-100 border-gray-200 last:border-none transition-colors dark:hover:bg-gray-700 dark:even:bg-gray-700/50 dark:border-gray-700\"\n >\n @for (header of headers; track header.key) {\n <td class=\"p-3 whitespace-nowrap\">\n @if (columnComponents[header.key]) {\n <ng-container\n *ngComponentOutlet=\"columnComponents[header.key]; injector: createInjector(row)\"\n ></ng-container>\n } @else {\n {{ row[header.key] || '---' }}\n }\n </td>\n }\n </tr>\n }\n\n @if ((!data || data.length < 1) && !isLoading) {\n <tr>\n <td\n [attr.colspan]=\"headers.length\"\n class=\"p-6 text-center text-gray-400 italic dark:text-gray-500\"\n >\n No se encontraron registros en el servidor.\n </td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n\n @if (showPagination) {\n <div\n class=\"p-4 flex items-center justify-between bg-gray-50 border-gray-300 border-t dark:bg-gray-800/50 dark:border-gray-700\"\n >\n <div class=\"text-sm text-gray-500 dark:text-gray-400\">\n Mostrando p\u00E1gina\n <span class=\"font-semibold text-gray-800 dark:text-white\">{{ currentPage }}</span> de\n <span class=\"font-semibold text-gray-800 dark:text-white\">{{ totalPages }}</span>\n <span class=\"ml-1\">({{ totalItems }} registros totales)</span>\n </div>\n\n <div class=\"flex gap-2\">\n <button\n (click)=\"changePage(-1)\"\n [disabled]=\"currentPage === 1\"\n class=\"flex items-center px-4 py-2 border rounded-lg bg-white text-sm font-medium hover:bg-gray-100 disabled:opacity-40 disabled:cursor-not-allowed transition-all dark:bg-gray-700 dark:hover:bg-gray-600 dark:border-gray-600 dark:text-white\"\n >\n Anterior\n </button>\n <button\n (click)=\"changePage(1)\"\n [disabled]=\"currentPage >= totalPages\"\n class=\"flex items-center px-4 py-2 border rounded-lg bg-white text-sm font-medium hover:bg-gray-100 disabled:opacity-40 disabled:cursor-not-allowed transition-all dark:bg-gray-700 dark:hover:bg-gray-600 dark:border-gray-600 dark:text-white\"\n >\n Siguiente\n </button>\n </div>\n </div>\n }\n</div>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"], exportAs: ["ngComponentOutlet"] }] });
1642
+ }
1643
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: DynamicTableComponent, decorators: [{
1644
+ type: Component,
1645
+ args: [{ selector: 'dynamic-table', standalone: true, imports: [CommonModule], template: "<div\n class=\"bg-white rounded-lg overflow-hidden border border-gray-200 dark:bg-gray-800 dark:border-gray-700\"\n>\n @if (showTitle || showSearch) {\n <div class=\"p-4 border-b border-gray-200 flex items-center justify-start dark:border-gray-700\">\n @if (showTitle) {\n <h2 class=\"text-lg font-semibold dark:text-white\">{{ title }}</h2>\n }\n\n @if (showSearch) {\n <input\n type=\"text\"\n (input)=\"onSearch($event)\"\n placeholder=\"Buscar...\"\n class=\"ml-auto block w-sm rounded-md bg-white px-3 py-1.5 text-base text-gray-900 outline-1 -outline-offset-1 outline-gray-300 placeholder:text-gray-400 focus:outline-2 focus:-outline-offset-2 focus:outline-indigo-600 sm:text-sm/6 dark:bg-white/5 dark:text-white dark:outline-white/10 dark:placeholder:text-gray-500 dark:focus:outline-indigo-500\"\n />\n }\n </div>\n }\n\n <div class=\"overflow-x-auto\">\n <table class=\"w-full text-left border-collapse\">\n <thead class=\"bg-gray-100 text-gray-600 text-xs dark:bg-gray-700 dark:text-gray-300\">\n <tr>\n @for (header of headers; track header.key) {\n <th class=\"p-3 border-b border-gray-300 whitespace-nowrap dark:border-gray-600\">\n {{ header.label }}\n </th>\n }\n </tr>\n </thead>\n\n <tbody class=\"text-gray-700 text-xs dark:text-gray-200\">\n @if (isLoading) {\n <tr\n class=\"border-b even:bg-gray-100 border-gray-200 last:border-none transition-colors dark:even:bg-gray-700/50 dark:border-gray-700\"\n >\n @for (header of headers; track header.key) {\n <td class=\"p-3\">\n <div class=\"h-5 bg-gray-200 rounded animate-pulse w-full dark:bg-gray-600\"></div>\n </td>\n }\n </tr>\n }\n\n @for (row of data; track row) {\n <tr\n class=\"hover:bg-gray-200 border-b even:bg-gray-100 border-gray-200 last:border-none transition-colors dark:hover:bg-gray-700 dark:even:bg-gray-700/50 dark:border-gray-700\"\n >\n @for (header of headers; track header.key) {\n <td class=\"p-3 whitespace-nowrap\">\n @if (columnComponents[header.key]) {\n <ng-container\n *ngComponentOutlet=\"columnComponents[header.key]; injector: createInjector(row)\"\n ></ng-container>\n } @else {\n {{ row[header.key] || '---' }}\n }\n </td>\n }\n </tr>\n }\n\n @if ((!data || data.length < 1) && !isLoading) {\n <tr>\n <td\n [attr.colspan]=\"headers.length\"\n class=\"p-6 text-center text-gray-400 italic dark:text-gray-500\"\n >\n No se encontraron registros en el servidor.\n </td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n\n @if (showPagination) {\n <div\n class=\"p-4 flex items-center justify-between bg-gray-50 border-gray-300 border-t dark:bg-gray-800/50 dark:border-gray-700\"\n >\n <div class=\"text-sm text-gray-500 dark:text-gray-400\">\n Mostrando p\u00E1gina\n <span class=\"font-semibold text-gray-800 dark:text-white\">{{ currentPage }}</span> de\n <span class=\"font-semibold text-gray-800 dark:text-white\">{{ totalPages }}</span>\n <span class=\"ml-1\">({{ totalItems }} registros totales)</span>\n </div>\n\n <div class=\"flex gap-2\">\n <button\n (click)=\"changePage(-1)\"\n [disabled]=\"currentPage === 1\"\n class=\"flex items-center px-4 py-2 border rounded-lg bg-white text-sm font-medium hover:bg-gray-100 disabled:opacity-40 disabled:cursor-not-allowed transition-all dark:bg-gray-700 dark:hover:bg-gray-600 dark:border-gray-600 dark:text-white\"\n >\n Anterior\n </button>\n <button\n (click)=\"changePage(1)\"\n [disabled]=\"currentPage >= totalPages\"\n class=\"flex items-center px-4 py-2 border rounded-lg bg-white text-sm font-medium hover:bg-gray-100 disabled:opacity-40 disabled:cursor-not-allowed transition-all dark:bg-gray-700 dark:hover:bg-gray-600 dark:border-gray-600 dark:text-white\"\n >\n Siguiente\n </button>\n </div>\n </div>\n }\n</div>\n" }]
1646
+ }], ctorParameters: () => [{ type: i0.Injector }], propDecorators: { title: [{
1647
+ type: Input
1648
+ }], data: [{
1649
+ type: Input
1650
+ }], headers: [{
1651
+ type: Input
1652
+ }], columnComponents: [{
1653
+ type: Input
1654
+ }], isLoading: [{
1655
+ type: Input
1656
+ }], totalItems: [{
1657
+ type: Input
1658
+ }], itemsPerPage: [{
1659
+ type: Input
1660
+ }], currentPage: [{
1661
+ type: Input
1662
+ }], pageChange: [{
1663
+ type: Output
1664
+ }], searchChange: [{
1665
+ type: Output
1666
+ }], showPagination: [{
1667
+ type: Input
1668
+ }], showSearch: [{
1669
+ type: Input
1670
+ }], showTitle: [{
1671
+ type: Input
1672
+ }] } });
1673
+
1674
+ class LanguageSwitcherComponent {
1675
+ transloco;
1676
+ availableLangs = ['es', 'en'];
1677
+ constructor(transloco) {
1678
+ this.transloco = transloco;
1679
+ }
1680
+ get activeLang() {
1681
+ return this.transloco.getActiveLang();
1682
+ }
1683
+ switchLang(lang) {
1684
+ this.transloco.setActiveLang(lang);
1685
+ }
1686
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: LanguageSwitcherComponent, deps: [{ token: i2.TranslocoService }], target: i0.ɵɵFactoryTarget.Component });
1687
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.25", type: LanguageSwitcherComponent, isStandalone: true, selector: "language-switcher", ngImport: i0, template: `
1688
+ <div class="flex items-center gap-1">
1689
+ @for (lang of availableLangs; track lang) {
1690
+ <button
1691
+ (click)="switchLang(lang)"
1692
+ class="cursor-pointer px-2 py-1 text-xs font-medium rounded transition-colors"
1693
+ [class.bg-gray-800]="activeLang === lang"
1694
+ [class.text-white]="activeLang === lang"
1695
+ [class.text-gray-400]="activeLang !== lang"
1696
+ [class.hover:text-white]="activeLang !== lang"
1697
+ >
1698
+ {{ lang | uppercase }}
1699
+ </button>
1700
+ }
1701
+ </div>
1702
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: TranslocoModule }, { kind: "pipe", type: i1$2.UpperCasePipe, name: "uppercase" }] });
1703
+ }
1704
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: LanguageSwitcherComponent, decorators: [{
1705
+ type: Component,
1706
+ args: [{
1707
+ selector: 'language-switcher',
1708
+ standalone: true,
1709
+ imports: [CommonModule, TranslocoModule],
1710
+ template: `
1711
+ <div class="flex items-center gap-1">
1712
+ @for (lang of availableLangs; track lang) {
1713
+ <button
1714
+ (click)="switchLang(lang)"
1715
+ class="cursor-pointer px-2 py-1 text-xs font-medium rounded transition-colors"
1716
+ [class.bg-gray-800]="activeLang === lang"
1717
+ [class.text-white]="activeLang === lang"
1718
+ [class.text-gray-400]="activeLang !== lang"
1719
+ [class.hover:text-white]="activeLang !== lang"
1720
+ >
1721
+ {{ lang | uppercase }}
1722
+ </button>
1723
+ }
1724
+ </div>
1725
+ `,
1726
+ }]
1727
+ }], ctorParameters: () => [{ type: i2.TranslocoService }] });
1728
+
1729
+ class FormSelectComponent {
1730
+ ngControl;
1731
+ transloco;
1732
+ label = '';
1733
+ name = '';
1734
+ id = '';
1735
+ placeholder = 'Seleccione una opción';
1736
+ required = false;
1737
+ disabled = false;
1738
+ readonly = false;
1739
+ options = [];
1740
+ fieldGroupClass = '';
1741
+ showDefaultOption = true;
1742
+ defaultOptionLabel = '';
1743
+ value = '';
1744
+ onChange = () => { };
1745
+ onTouched = () => { };
1746
+ constructor(ngControl, transloco) {
1747
+ this.ngControl = ngControl;
1748
+ this.transloco = transloco;
1749
+ if (this.ngControl) {
1750
+ this.ngControl.valueAccessor = this;
1751
+ }
1752
+ }
1753
+ writeValue(value) {
1754
+ this.value = value;
1755
+ }
1756
+ registerOnChange(fn) {
1757
+ this.onChange = fn;
1758
+ }
1759
+ registerOnTouched(fn) {
1760
+ this.onTouched = fn;
1761
+ }
1762
+ setDisabledState(isDisabled) {
1763
+ this.disabled = isDisabled;
1764
+ }
1765
+ onSelectChange(value) {
1766
+ this.value = value;
1767
+ this.onChange(value);
1768
+ this.onTouched();
1769
+ }
1770
+ get inputId() {
1771
+ return this.id || this.name;
1772
+ }
1773
+ get showError() {
1774
+ if (!this.ngControl || !this.ngControl.control)
1775
+ return false;
1776
+ const control = this.ngControl.control;
1777
+ const dirty = control.dirty;
1778
+ const touched = control.touched;
1779
+ return control.invalid ? dirty || touched : false;
1780
+ }
1781
+ get errorMessage() {
1782
+ if (!this.ngControl?.errors)
1783
+ return '';
1784
+ const errors = this.ngControl.errors;
1785
+ const errorKey = Object.keys(errors)[0];
1786
+ return this.transloco.translate(`formErrors.${errorKey}`, {}, this.transloco.translate('formErrors.invalidSelection'));
1787
+ }
1788
+ get resolvedDefaultOptionLabel() {
1789
+ return this.defaultOptionLabel || this.transloco.translate('common.selectOption');
1790
+ }
1791
+ get selectClasses() {
1792
+ return this.showError ? ERROR_INPUT_CLASSES : BASE_INPUT_CLASSES;
1793
+ }
1794
+ get fieldGroupClasses() {
1795
+ let baseClasses = '';
1796
+ if (this.fieldGroupClass) {
1797
+ baseClasses += ` ${this.fieldGroupClass}`;
1798
+ }
1799
+ else {
1800
+ baseClasses += ' w-full';
1801
+ }
1802
+ return baseClasses;
1803
+ }
1804
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: FormSelectComponent, deps: [{ token: i1$1.NgControl, optional: true, self: true }, { token: i2.TranslocoService }], target: i0.ɵɵFactoryTarget.Component });
1805
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.25", type: FormSelectComponent, isStandalone: true, selector: "form-select", inputs: { label: "label", name: "name", id: "id", placeholder: "placeholder", required: "required", disabled: "disabled", readonly: "readonly", options: "options", fieldGroupClass: "fieldGroupClass", showDefaultOption: "showDefaultOption", defaultOptionLabel: "defaultOptionLabel" }, ngImport: i0, template: "<div [class]=\"fieldGroupClasses\">\n @if (label) {\n <label [for]=\"inputId\" class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n {{ label }}\n\n @if (required) {\n <span class=\"text-red-500\">*</span>\n }\n </label>\n }\n\n <div class=\"relative\">\n <select\n [id]=\"inputId\"\n [name]=\"name\"\n [required]=\"required\"\n [disabled]=\"disabled\"\n [(ngModel)]=\"value\"\n (ngModelChange)=\"onSelectChange($event)\"\n (blur)=\"onTouched()\"\n [class]=\"selectClasses\"\n [class.bg-white]=\"!readonly\"\n [class.bg-gray-200]=\"readonly\"\n [class.cursor-not-allowed]=\"readonly\"\n >\n @if (showDefaultOption) {\n <option [value]=\"null\" disabled selected>{{ resolvedDefaultOptionLabel }}</option>\n }\n\n @for (option of options; track option.value) {\n <option [value]=\"option.value\" [disabled]=\"option.disabled\">\n {{ option.label }}\n </option>\n }\n </select>\n </div>\n\n @if (showError) {\n <div class=\"text-red-500 text-xs mt-1\">\n {{ errorMessage }}\n </div>\n }\n</div>\n", styles: ["select{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-image:url(\"data:image/svg+xml;charset=US-ASCII,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%236b7280' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E\");background-repeat:no-repeat;background-position:right .75rem center;background-size:1em;padding-right:2.5rem}select::-ms-expand{display:none}@-moz-document url-prefix(){select{text-indent:.01px;text-overflow:\"\";padding-right:.75rem}}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }] });
1806
+ }
1807
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: FormSelectComponent, decorators: [{
1808
+ type: Component,
1809
+ args: [{ selector: 'form-select', standalone: true, imports: [FormsModule, CommonModule, ReactiveFormsModule], template: "<div [class]=\"fieldGroupClasses\">\n @if (label) {\n <label [for]=\"inputId\" class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n {{ label }}\n\n @if (required) {\n <span class=\"text-red-500\">*</span>\n }\n </label>\n }\n\n <div class=\"relative\">\n <select\n [id]=\"inputId\"\n [name]=\"name\"\n [required]=\"required\"\n [disabled]=\"disabled\"\n [(ngModel)]=\"value\"\n (ngModelChange)=\"onSelectChange($event)\"\n (blur)=\"onTouched()\"\n [class]=\"selectClasses\"\n [class.bg-white]=\"!readonly\"\n [class.bg-gray-200]=\"readonly\"\n [class.cursor-not-allowed]=\"readonly\"\n >\n @if (showDefaultOption) {\n <option [value]=\"null\" disabled selected>{{ resolvedDefaultOptionLabel }}</option>\n }\n\n @for (option of options; track option.value) {\n <option [value]=\"option.value\" [disabled]=\"option.disabled\">\n {{ option.label }}\n </option>\n }\n </select>\n </div>\n\n @if (showError) {\n <div class=\"text-red-500 text-xs mt-1\">\n {{ errorMessage }}\n </div>\n }\n</div>\n", styles: ["select{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-image:url(\"data:image/svg+xml;charset=US-ASCII,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%236b7280' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E\");background-repeat:no-repeat;background-position:right .75rem center;background-size:1em;padding-right:2.5rem}select::-ms-expand{display:none}@-moz-document url-prefix(){select{text-indent:.01px;text-overflow:\"\";padding-right:.75rem}}\n"] }]
1810
+ }], ctorParameters: () => [{ type: i1$1.NgControl, decorators: [{
1811
+ type: Self
1812
+ }, {
1813
+ type: Optional
1814
+ }] }, { type: i2.TranslocoService }], propDecorators: { label: [{
1815
+ type: Input
1816
+ }], name: [{
1817
+ type: Input
1818
+ }], id: [{
1819
+ type: Input
1820
+ }], placeholder: [{
1821
+ type: Input
1822
+ }], required: [{
1823
+ type: Input
1824
+ }], disabled: [{
1825
+ type: Input
1826
+ }], readonly: [{
1827
+ type: Input
1828
+ }], options: [{
1829
+ type: Input
1830
+ }], fieldGroupClass: [{
1831
+ type: Input
1832
+ }], showDefaultOption: [{
1833
+ type: Input
1834
+ }], defaultOptionLabel: [{
1835
+ type: Input
1836
+ }] } });
1837
+
1838
+ class FormTextareaComponent {
1839
+ ngControl;
1840
+ transloco;
1841
+ label = '';
1842
+ name = '';
1843
+ id = '';
1844
+ placeholder = '';
1845
+ required = false;
1846
+ readonly = false;
1847
+ minlength = null;
1848
+ maxlength = null;
1849
+ rows = 4;
1850
+ cols = null;
1851
+ fieldGroupClass = '';
1852
+ value = '';
1853
+ disabled = false;
1854
+ onChange = () => { };
1855
+ onTouched = () => { };
1856
+ constructor(ngControl, transloco) {
1857
+ this.ngControl = ngControl;
1858
+ this.transloco = transloco;
1859
+ if (this.ngControl) {
1860
+ this.ngControl.valueAccessor = this;
1861
+ }
1862
+ }
1863
+ writeValue(value) {
1864
+ this.value = value;
1865
+ }
1866
+ registerOnChange(fn) {
1867
+ this.onChange = fn;
1868
+ }
1869
+ registerOnTouched(fn) {
1870
+ this.onTouched = fn;
1871
+ }
1872
+ setDisabledState(isDisabled) {
1873
+ this.disabled = isDisabled;
1874
+ }
1875
+ onInput(value) {
1876
+ this.value = value;
1877
+ this.onChange(value);
1878
+ this.onTouched();
1879
+ }
1880
+ get inputId() {
1881
+ return this.id || this.name;
1882
+ }
1883
+ get showError() {
1884
+ if (!this.ngControl || !this.ngControl.control)
1885
+ return false;
1886
+ const control = this.ngControl.control;
1887
+ const dirty = control.dirty;
1888
+ const touched = control.touched;
1889
+ return control.invalid ? dirty || touched : false;
1890
+ }
1891
+ get errorMessage() {
1892
+ if (!this.ngControl?.errors)
1893
+ return '';
1894
+ const errors = this.ngControl.errors;
1895
+ const errorKey = Object.keys(errors)[0];
1896
+ if (errorKey === 'minlength') {
1897
+ return this.transloco.translate('formErrors.minlength', {
1898
+ length: errors[errorKey].requiredLength,
1899
+ });
1900
+ }
1901
+ if (errorKey === 'maxlength') {
1902
+ return this.transloco.translate('formErrors.maxlength', {
1903
+ length: errors[errorKey].requiredLength,
1904
+ });
1905
+ }
1906
+ return this.transloco.translate(`formErrors.${errorKey}`);
1907
+ }
1908
+ get inputClasses() {
1909
+ return this.showError ? ERROR_INPUT_CLASSES : BASE_INPUT_CLASSES;
1910
+ }
1911
+ get fieldGroupClasses() {
1912
+ let baseClasses = '';
1913
+ if (this.fieldGroupClass) {
1914
+ baseClasses += ` ${this.fieldGroupClass}`;
1915
+ }
1916
+ else {
1917
+ baseClasses += ' w-full';
1918
+ }
1919
+ return baseClasses;
1920
+ }
1921
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: FormTextareaComponent, deps: [{ token: i1$1.NgControl, optional: true, self: true }, { token: i2.TranslocoService }], target: i0.ɵɵFactoryTarget.Component });
1922
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.25", type: FormTextareaComponent, isStandalone: true, selector: "form-textarea", inputs: { label: "label", name: "name", id: "id", placeholder: "placeholder", required: "required", readonly: "readonly", minlength: "minlength", maxlength: "maxlength", rows: "rows", cols: "cols", fieldGroupClass: "fieldGroupClass" }, ngImport: i0, template: "<div [class]=\"fieldGroupClasses\">\n @if (label) {\n <label [for]=\"inputId\" class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n {{ label }}\n\n @if (required) {\n <span class=\"text-red-500\">*</span>\n }\n </label>\n }\n\n <div class=\"relative\">\n <textarea\n [id]=\"inputId\"\n [name]=\"name\"\n [placeholder]=\"placeholder\"\n [required]=\"required\"\n [minlength]=\"minlength\"\n [maxlength]=\"maxlength\"\n [rows]=\"rows\"\n [cols]=\"cols\"\n [(ngModel)]=\"value\"\n (ngModelChange)=\"onInput($event)\"\n (blur)=\"onTouched()\"\n [readonly]=\"readonly\"\n [disabled]=\"disabled\"\n [class.bg-white]=\"!readonly\"\n [class.bg-gray-200]=\"readonly\"\n [class.cursor-not-allowed]=\"readonly\"\n [class]=\"inputClasses\"\n ></textarea>\n </div>\n\n @if (showError) {\n <div class=\"text-red-500 text-xs mt-1\">\n {{ errorMessage }}\n </div>\n }\n</div>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$1.MinLengthValidator, selector: "[minlength][formControlName],[minlength][formControl],[minlength][ngModel]", inputs: ["minlength"] }, { kind: "directive", type: i1$1.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }] });
1923
+ }
1924
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: FormTextareaComponent, decorators: [{
1925
+ type: Component,
1926
+ args: [{ selector: 'form-textarea', standalone: true, imports: [FormsModule, CommonModule, ReactiveFormsModule], template: "<div [class]=\"fieldGroupClasses\">\n @if (label) {\n <label [for]=\"inputId\" class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n {{ label }}\n\n @if (required) {\n <span class=\"text-red-500\">*</span>\n }\n </label>\n }\n\n <div class=\"relative\">\n <textarea\n [id]=\"inputId\"\n [name]=\"name\"\n [placeholder]=\"placeholder\"\n [required]=\"required\"\n [minlength]=\"minlength\"\n [maxlength]=\"maxlength\"\n [rows]=\"rows\"\n [cols]=\"cols\"\n [(ngModel)]=\"value\"\n (ngModelChange)=\"onInput($event)\"\n (blur)=\"onTouched()\"\n [readonly]=\"readonly\"\n [disabled]=\"disabled\"\n [class.bg-white]=\"!readonly\"\n [class.bg-gray-200]=\"readonly\"\n [class.cursor-not-allowed]=\"readonly\"\n [class]=\"inputClasses\"\n ></textarea>\n </div>\n\n @if (showError) {\n <div class=\"text-red-500 text-xs mt-1\">\n {{ errorMessage }}\n </div>\n }\n</div>\n" }]
1927
+ }], ctorParameters: () => [{ type: i1$1.NgControl, decorators: [{
1928
+ type: Self
1929
+ }, {
1930
+ type: Optional
1931
+ }] }, { type: i2.TranslocoService }], propDecorators: { label: [{
1932
+ type: Input
1933
+ }], name: [{
1934
+ type: Input
1935
+ }], id: [{
1936
+ type: Input
1937
+ }], placeholder: [{
1938
+ type: Input
1939
+ }], required: [{
1940
+ type: Input
1941
+ }], readonly: [{
1942
+ type: Input
1943
+ }], minlength: [{
1944
+ type: Input
1945
+ }], maxlength: [{
1946
+ type: Input
1947
+ }], rows: [{
1948
+ type: Input
1949
+ }], cols: [{
1950
+ type: Input
1951
+ }], fieldGroupClass: [{
1952
+ type: Input
1953
+ }] } });
1954
+
1955
+ class FormEditorComponent {
1956
+ ngControl;
1957
+ transloco;
1958
+ label = '';
1959
+ name = '';
1960
+ id = '';
1961
+ placeholder = '';
1962
+ required = false;
1963
+ readonly = false;
1964
+ toolbar = DEFAULT_TOOLBAR;
1965
+ fieldGroupClass = '';
1966
+ editor;
1967
+ value = '';
1968
+ disabled = false;
1969
+ onChange = () => { };
1970
+ onTouched = () => { };
1971
+ subscription = null;
1972
+ constructor(ngControl, transloco) {
1973
+ this.ngControl = ngControl;
1974
+ this.transloco = transloco;
1975
+ if (this.ngControl) {
1976
+ this.ngControl.valueAccessor = this;
1977
+ }
1978
+ }
1979
+ ngOnInit() {
1980
+ this.editor = new Editor();
1981
+ if (this.value) {
1982
+ this.editor.setContent(this.value);
1983
+ }
1984
+ this.subscription = this.editor.valueChanges
1985
+ .pipe(distinctUntilChanged())
1986
+ .subscribe((doc) => {
1987
+ this.value = toHTML(doc);
1988
+ this.onChange(this.value);
1989
+ this.onTouched();
1990
+ });
1991
+ }
1992
+ ngOnDestroy() {
1993
+ this.subscription?.unsubscribe();
1994
+ this.editor?.destroy();
1995
+ }
1996
+ writeValue(value) {
1997
+ this.value = value ?? '';
1998
+ if (this.editor) {
1999
+ this.editor.setContent(value ?? null);
2000
+ }
2001
+ }
2002
+ registerOnChange(fn) {
2003
+ this.onChange = fn;
2004
+ }
2005
+ registerOnTouched(fn) {
2006
+ this.onTouched = fn;
2007
+ }
2008
+ setDisabledState(isDisabled) {
2009
+ this.disabled = isDisabled;
2010
+ }
2011
+ get inputId() {
2012
+ return this.id || this.name;
2013
+ }
2014
+ get showError() {
2015
+ if (!this.ngControl || !this.ngControl.control)
2016
+ return false;
2017
+ const control = this.ngControl.control;
2018
+ return control.invalid ? control.dirty || control.touched : false;
2019
+ }
2020
+ get errorMessage() {
2021
+ if (!this.ngControl?.errors)
2022
+ return '';
2023
+ const errors = this.ngControl.errors;
2024
+ const errorKey = Object.keys(errors)[0];
2025
+ if (errorKey === 'minlength') {
2026
+ return this.transloco.translate('formErrors.minlength', {
2027
+ length: errors[errorKey].requiredLength,
2028
+ });
2029
+ }
2030
+ if (errorKey === 'maxlength') {
2031
+ return this.transloco.translate('formErrors.maxlength', {
2032
+ length: errors[errorKey].requiredLength,
2033
+ });
2034
+ }
2035
+ return this.transloco.translate(`formErrors.${errorKey}`, {}, this.transloco.translate('formErrors.invalidField'));
2036
+ }
2037
+ get fieldGroupClasses() {
2038
+ let baseClasses = '';
2039
+ if (this.fieldGroupClass) {
2040
+ baseClasses += ` ${this.fieldGroupClass}`;
2041
+ }
2042
+ else {
2043
+ baseClasses += ' w-full';
2044
+ }
2045
+ return baseClasses;
2046
+ }
2047
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: FormEditorComponent, deps: [{ token: i1$1.NgControl, optional: true, self: true }, { token: i2.TranslocoService }], target: i0.ɵɵFactoryTarget.Component });
2048
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.25", type: FormEditorComponent, isStandalone: true, selector: "form-editor", inputs: { label: "label", name: "name", id: "id", placeholder: "placeholder", required: "required", readonly: "readonly", toolbar: "toolbar", fieldGroupClass: "fieldGroupClass" }, ngImport: i0, template: "<div [class]=\"fieldGroupClasses\">\n @if (label) {\n <label [for]=\"inputId\" class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n {{ label }}\n\n @if (required) {\n <span class=\"text-red-500\">*</span>\n }\n </label>\n }\n\n <div\n class=\"relative\"\n [class.opacity-50]=\"disabled\"\n [class.pointer-events-none]=\"disabled\"\n [class.cursor-not-allowed]=\"disabled\"\n >\n <ngx-editor [editor]=\"editor\" outputFormat=\"html\" [placeholder]=\"placeholder\">\n <ngx-editor-menu\n [editor]=\"editor\"\n [toolbar]=\"toolbar\"\n [disabled]=\"disabled\"\n ></ngx-editor-menu>\n </ngx-editor>\n </div>\n\n @if (showError) {\n <div class=\"text-red-500 text-xs mt-1\">\n {{ errorMessage }}\n </div>\n }\n</div>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "component", type: NgxEditorComponent, selector: "ngx-editor", inputs: ["editor", "outputFormat", "placeholder"], outputs: ["focusOut", "focusIn"] }, { kind: "component", type: NgxEditorMenuComponent, selector: "ngx-editor-menu", inputs: ["toolbar", "colorPresets", "disabled", "editor", "customMenuRef", "dropdownPlacement"] }] });
2049
+ }
2050
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: FormEditorComponent, decorators: [{
2051
+ type: Component,
2052
+ args: [{ selector: 'form-editor', standalone: true, imports: [
2053
+ FormsModule,
2054
+ CommonModule,
2055
+ ReactiveFormsModule,
2056
+ NgxEditorComponent,
2057
+ NgxEditorMenuComponent,
2058
+ ], template: "<div [class]=\"fieldGroupClasses\">\n @if (label) {\n <label [for]=\"inputId\" class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n {{ label }}\n\n @if (required) {\n <span class=\"text-red-500\">*</span>\n }\n </label>\n }\n\n <div\n class=\"relative\"\n [class.opacity-50]=\"disabled\"\n [class.pointer-events-none]=\"disabled\"\n [class.cursor-not-allowed]=\"disabled\"\n >\n <ngx-editor [editor]=\"editor\" outputFormat=\"html\" [placeholder]=\"placeholder\">\n <ngx-editor-menu\n [editor]=\"editor\"\n [toolbar]=\"toolbar\"\n [disabled]=\"disabled\"\n ></ngx-editor-menu>\n </ngx-editor>\n </div>\n\n @if (showError) {\n <div class=\"text-red-500 text-xs mt-1\">\n {{ errorMessage }}\n </div>\n }\n</div>\n" }]
2059
+ }], ctorParameters: () => [{ type: i1$1.NgControl, decorators: [{
2060
+ type: Self
2061
+ }, {
2062
+ type: Optional
2063
+ }] }, { type: i2.TranslocoService }], propDecorators: { label: [{
2064
+ type: Input
2065
+ }], name: [{
2066
+ type: Input
2067
+ }], id: [{
2068
+ type: Input
2069
+ }], placeholder: [{
2070
+ type: Input
2071
+ }], required: [{
2072
+ type: Input
2073
+ }], readonly: [{
2074
+ type: Input
2075
+ }], toolbar: [{
2076
+ type: Input
2077
+ }], fieldGroupClass: [{
2078
+ type: Input
2079
+ }] } });
2080
+
2081
+ class ColorPickerComponent {
2082
+ ngControl;
2083
+ elementRef;
2084
+ label = '';
2085
+ name = '';
2086
+ id = '';
2087
+ placeholder = '#000000';
2088
+ required = false;
2089
+ readonly = false;
2090
+ fieldGroupClass = '';
2091
+ showPreview = true;
2092
+ presetColors = [
2093
+ '#000000',
2094
+ '#FFFFFF',
2095
+ '#EF4444',
2096
+ '#F97316',
2097
+ '#F59E0B',
2098
+ '#EAB308',
2099
+ '#84CC16',
2100
+ '#22C55E',
2101
+ '#10B981',
2102
+ '#14B8A6',
2103
+ '#06B6D4',
2104
+ '#0EA5E9',
2105
+ '#3B82F6',
2106
+ '#6366F1',
2107
+ '#8B5CF6',
2108
+ '#A855F7',
2109
+ '#D946EF',
2110
+ '#EC4899',
2111
+ '#F43F5E',
2112
+ '#6B7280',
2113
+ ];
2114
+ colorChange = new EventEmitter();
2115
+ value = '#000000';
2116
+ disabled = false;
2117
+ isDropdownOpen = false;
2118
+ onChange = () => { };
2119
+ onTouched = () => { };
2120
+ constructor(ngControl, elementRef) {
2121
+ this.ngControl = ngControl;
2122
+ this.elementRef = elementRef;
2123
+ if (this.ngControl) {
2124
+ this.ngControl.valueAccessor = this;
2125
+ }
2126
+ }
2127
+ onDocumentClick(event) {
2128
+ const clickedInside = this.elementRef.nativeElement.contains(event.target);
2129
+ if (!clickedInside && this.isDropdownOpen) {
2130
+ this.isDropdownOpen = false;
2131
+ }
2132
+ }
2133
+ // Control value accessor methods
2134
+ writeValue(value) {
2135
+ if (value) {
2136
+ this.value = value;
2137
+ }
2138
+ }
2139
+ registerOnChange(fn) {
2140
+ this.onChange = fn;
2141
+ }
2142
+ registerOnTouched(fn) {
2143
+ this.onTouched = fn;
2144
+ }
2145
+ setDisabledState(isDisabled) {
2146
+ this.disabled = isDisabled;
2147
+ }
2148
+ onColorChange(color) {
2149
+ this.value = color;
2150
+ this.onChange(color);
2151
+ this.onTouched();
2152
+ }
2153
+ onInputColorChange(event) {
2154
+ const input = event.target;
2155
+ this.value = input.value;
2156
+ this.onChange(input.value);
2157
+ this.onTouched();
2158
+ this.colorChange.emit(input.value);
2159
+ }
2160
+ toggleDropdown() {
2161
+ if (this.disabled || this.readonly)
2162
+ return;
2163
+ this.isDropdownOpen = !this.isDropdownOpen;
2164
+ }
2165
+ selectPresetColor(color) {
2166
+ this.onColorChange(color);
2167
+ this.colorChange.emit(color);
2168
+ this.isDropdownOpen = false;
2169
+ }
2170
+ get inputId() {
2171
+ return this.id || this.name;
2172
+ }
2173
+ get showError() {
2174
+ if (!this.ngControl || !this.ngControl.control)
2175
+ return false;
2176
+ const control = this.ngControl.control;
2177
+ const dirty = control.dirty;
2178
+ const touched = control.touched;
2179
+ return control.invalid ? dirty || touched : false;
2180
+ }
2181
+ get inputClasses() {
2182
+ return this.showError ? ERROR_INPUT_CLASSES : BASE_INPUT_CLASSES;
2183
+ }
2184
+ get fieldGroupClasses() {
2185
+ let baseClasses = '';
2186
+ if (this.fieldGroupClass) {
2187
+ baseClasses += ` ${this.fieldGroupClass}`;
2188
+ }
2189
+ else {
2190
+ baseClasses += ' w-full';
2191
+ }
2192
+ return baseClasses;
2193
+ }
2194
+ isValidHexColor(color) {
2195
+ return /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/.test(color);
2196
+ }
2197
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: ColorPickerComponent, deps: [{ token: i1$1.NgControl, optional: true, self: true }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
2198
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.25", type: ColorPickerComponent, isStandalone: true, selector: "color-picker", inputs: { label: "label", name: "name", id: "id", placeholder: "placeholder", required: "required", readonly: "readonly", fieldGroupClass: "fieldGroupClass", showPreview: "showPreview", presetColors: "presetColors" }, outputs: { colorChange: "colorChange" }, host: { listeners: { "document:click": "onDocumentClick($event)" } }, ngImport: i0, template: "<div [class]=\"fieldGroupClasses\">\n @if (label) {\n <label [for]=\"inputId\" class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n {{ label }}\n\n @if (required) {\n <span class=\"text-red-500\">*</span>\n }\n </label>\n }\n\n <div class=\"relative\">\n <div class=\"flex gap-2 items-center\">\n <!-- Color Input -->\n <div class=\"relative flex-1\">\n <input\n type=\"text\"\n [id]=\"inputId\"\n [name]=\"name\"\n [placeholder]=\"placeholder\"\n [required]=\"required\"\n [(ngModel)]=\"value\"\n (ngModelChange)=\"onInputColorChange($event)\"\n (blur)=\"onTouched()\"\n [readonly]=\"readonly\"\n [disabled]=\"disabled\"\n [class.bg-white]=\"!readonly\"\n [class.bg-gray-200]=\"readonly\"\n [class.cursor-not-allowed]=\"readonly\"\n [class]=\"inputClasses\"\n pattern=\"^#[0-9A-Fa-f]{6}$\"\n />\n\n <!-- Native Color Picker (Hidden) -->\n <input\n type=\"color\"\n class=\"absolute inset-0 opacity-0 cursor-pointer\"\n [disabled]=\"disabled || readonly\"\n [(ngModel)]=\"value\"\n (ngModelChange)=\"onColorChange($event)\"\n />\n </div>\n\n <!-- Color Preview -->\n @if (showPreview) {\n <div class=\"flex items-center\">\n <div\n class=\"w-[37px] h-[37px] rounded-md border border-gray-300 cursor-pointer transition-all hover:scale-105\"\n [style.background-color]=\"value\"\n (click)=\"toggleDropdown()\"\n [class.cursor-not-allowed]=\"disabled || readonly\"\n [class.opacity-50]=\"disabled\"\n ></div>\n </div>\n }\n </div>\n\n <!-- Color Presets Dropdown -->\n @if (isDropdownOpen && !disabled && !readonly) {\n <div\n class=\"absolute z-50 mt-2 p-3 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg shadow-lg\"\n >\n <div class=\"grid grid-cols-5 gap-2 min-w-[200px]\">\n @for (color of presetColors; track color) {\n <button\n type=\"button\"\n class=\"w-8 h-8 rounded-md border-2 border-gray-300 hover:border-gray-400 transition-all hover:scale-110 focus:outline-none focus:ring-2 focus:ring-indigo-500\"\n [style.background-color]=\"color\"\n (click)=\"selectPresetColor(color)\"\n [attr.aria-label]=\"`Select color ${color}`\"\n ></button>\n }\n </div>\n\n <!-- Custom Color Input -->\n <div class=\"mt-3 pt-3 border-t border-gray-200 dark:border-gray-700\">\n <label class=\"text-xs text-gray-600 dark:text-gray-400 block mb-1\">Custom color:</label>\n <input\n type=\"color\"\n class=\"w-full h-8 rounded cursor-pointer\"\n [(ngModel)]=\"value\"\n (ngModelChange)=\"onColorChange($event)\"\n />\n </div>\n </div>\n }\n </div>\n\n @if (showError) {\n <div class=\"text-red-500 text-xs mt-1\">Please enter a valid hex color (e.g., #FF5733)</div>\n }\n</div>\n", styles: [":host{display:block}.color-picker-dropdown{z-index:9999}.color-preview{transition:all .2s ease-in-out}.color-preset-button{transition:all .15s ease-in-out}.color-preset-button:focus{outline:2px solid #4f46e5;outline-offset:2px}@media(prefers-color-scheme:dark){.color-picker-dropdown{background-color:#1f2937;border-color:#374151}}@keyframes dropdownFadeIn{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}.color-picker-dropdown{animation:dropdownFadeIn .15s ease-out}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$1.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }] });
2199
+ }
2200
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: ColorPickerComponent, decorators: [{
2201
+ type: Component,
2202
+ args: [{ selector: 'color-picker', standalone: true, imports: [FormsModule, CommonModule, ReactiveFormsModule], template: "<div [class]=\"fieldGroupClasses\">\n @if (label) {\n <label [for]=\"inputId\" class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n {{ label }}\n\n @if (required) {\n <span class=\"text-red-500\">*</span>\n }\n </label>\n }\n\n <div class=\"relative\">\n <div class=\"flex gap-2 items-center\">\n <!-- Color Input -->\n <div class=\"relative flex-1\">\n <input\n type=\"text\"\n [id]=\"inputId\"\n [name]=\"name\"\n [placeholder]=\"placeholder\"\n [required]=\"required\"\n [(ngModel)]=\"value\"\n (ngModelChange)=\"onInputColorChange($event)\"\n (blur)=\"onTouched()\"\n [readonly]=\"readonly\"\n [disabled]=\"disabled\"\n [class.bg-white]=\"!readonly\"\n [class.bg-gray-200]=\"readonly\"\n [class.cursor-not-allowed]=\"readonly\"\n [class]=\"inputClasses\"\n pattern=\"^#[0-9A-Fa-f]{6}$\"\n />\n\n <!-- Native Color Picker (Hidden) -->\n <input\n type=\"color\"\n class=\"absolute inset-0 opacity-0 cursor-pointer\"\n [disabled]=\"disabled || readonly\"\n [(ngModel)]=\"value\"\n (ngModelChange)=\"onColorChange($event)\"\n />\n </div>\n\n <!-- Color Preview -->\n @if (showPreview) {\n <div class=\"flex items-center\">\n <div\n class=\"w-[37px] h-[37px] rounded-md border border-gray-300 cursor-pointer transition-all hover:scale-105\"\n [style.background-color]=\"value\"\n (click)=\"toggleDropdown()\"\n [class.cursor-not-allowed]=\"disabled || readonly\"\n [class.opacity-50]=\"disabled\"\n ></div>\n </div>\n }\n </div>\n\n <!-- Color Presets Dropdown -->\n @if (isDropdownOpen && !disabled && !readonly) {\n <div\n class=\"absolute z-50 mt-2 p-3 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg shadow-lg\"\n >\n <div class=\"grid grid-cols-5 gap-2 min-w-[200px]\">\n @for (color of presetColors; track color) {\n <button\n type=\"button\"\n class=\"w-8 h-8 rounded-md border-2 border-gray-300 hover:border-gray-400 transition-all hover:scale-110 focus:outline-none focus:ring-2 focus:ring-indigo-500\"\n [style.background-color]=\"color\"\n (click)=\"selectPresetColor(color)\"\n [attr.aria-label]=\"`Select color ${color}`\"\n ></button>\n }\n </div>\n\n <!-- Custom Color Input -->\n <div class=\"mt-3 pt-3 border-t border-gray-200 dark:border-gray-700\">\n <label class=\"text-xs text-gray-600 dark:text-gray-400 block mb-1\">Custom color:</label>\n <input\n type=\"color\"\n class=\"w-full h-8 rounded cursor-pointer\"\n [(ngModel)]=\"value\"\n (ngModelChange)=\"onColorChange($event)\"\n />\n </div>\n </div>\n }\n </div>\n\n @if (showError) {\n <div class=\"text-red-500 text-xs mt-1\">Please enter a valid hex color (e.g., #FF5733)</div>\n }\n</div>\n", styles: [":host{display:block}.color-picker-dropdown{z-index:9999}.color-preview{transition:all .2s ease-in-out}.color-preset-button{transition:all .15s ease-in-out}.color-preset-button:focus{outline:2px solid #4f46e5;outline-offset:2px}@media(prefers-color-scheme:dark){.color-picker-dropdown{background-color:#1f2937;border-color:#374151}}@keyframes dropdownFadeIn{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}.color-picker-dropdown{animation:dropdownFadeIn .15s ease-out}\n"] }]
2203
+ }], ctorParameters: () => [{ type: i1$1.NgControl, decorators: [{
2204
+ type: Self
2205
+ }, {
2206
+ type: Optional
2207
+ }] }, { type: i0.ElementRef }], propDecorators: { label: [{
2208
+ type: Input
2209
+ }], name: [{
2210
+ type: Input
2211
+ }], id: [{
2212
+ type: Input
2213
+ }], placeholder: [{
2214
+ type: Input
2215
+ }], required: [{
2216
+ type: Input
2217
+ }], readonly: [{
2218
+ type: Input
2219
+ }], fieldGroupClass: [{
2220
+ type: Input
2221
+ }], showPreview: [{
2222
+ type: Input
2223
+ }], presetColors: [{
2224
+ type: Input
2225
+ }], colorChange: [{
2226
+ type: Output
2227
+ }], onDocumentClick: [{
2228
+ type: HostListener,
2229
+ args: ['document:click', ['$event']]
2230
+ }] } });
2231
+
2232
+ class DateInputComponent {
2233
+ ngControl;
2234
+ transloco;
2235
+ label = '';
2236
+ type = 'date';
2237
+ includeTime = false;
2238
+ name = '';
2239
+ id = '';
2240
+ placeholder = '';
2241
+ required = false;
2242
+ readonly = false;
2243
+ min = null;
2244
+ max = null;
2245
+ fieldGroupClass = '';
2246
+ dateFormat = 'yyyy-MM-dd';
2247
+ value = '';
2248
+ disabled = false;
2249
+ onChange = () => { };
2250
+ onTouched = () => { };
2251
+ constructor(ngControl, transloco) {
2252
+ this.ngControl = ngControl;
2253
+ this.transloco = transloco;
2254
+ if (this.ngControl) {
2255
+ this.ngControl.valueAccessor = this;
2256
+ }
2257
+ }
2258
+ writeValue(value) {
2259
+ if (value) {
2260
+ if (value instanceof Date) {
2261
+ this.value = this.formatDateForInput(value);
2262
+ }
2263
+ else if (typeof value === 'string') {
2264
+ this.value = value;
2265
+ }
2266
+ else {
2267
+ this.value = '';
2268
+ }
2269
+ }
2270
+ else {
2271
+ this.value = '';
2272
+ }
2273
+ }
2274
+ registerOnChange(fn) {
2275
+ this.onChange = fn;
2276
+ }
2277
+ registerOnTouched(fn) {
2278
+ this.onTouched = fn;
2279
+ }
2280
+ setDisabledState(isDisabled) {
2281
+ this.disabled = isDisabled;
2282
+ }
2283
+ onInput(value) {
2284
+ this.value = value;
2285
+ const dateValue = value ? new Date(value) : null;
2286
+ this.onChange(dateValue);
2287
+ this.onTouched();
2288
+ }
2289
+ formatDateForInput(date) {
2290
+ const year = date.getFullYear();
2291
+ const month = String(date.getMonth() + 1).padStart(2, '0');
2292
+ const day = String(date.getDate()).padStart(2, '0');
2293
+ if (this.includeTime) {
2294
+ const hours = String(date.getHours()).padStart(2, '0');
2295
+ const minutes = String(date.getMinutes()).padStart(2, '0');
2296
+ return `${year}-${month}-${day}T${hours}:${minutes}`;
2297
+ }
2298
+ return `${year}-${month}-${day}`;
2299
+ }
2300
+ parseDateFromString(dateString) {
2301
+ if (!dateString)
2302
+ return null;
2303
+ const date = new Date(dateString);
2304
+ return isNaN(date.getTime()) ? null : date;
2305
+ }
2306
+ get inputId() {
2307
+ return this.id || this.name;
2308
+ }
2309
+ get showError() {
2310
+ if (!this.ngControl || !this.ngControl.control)
2311
+ return false;
2312
+ const control = this.ngControl.control;
2313
+ const dirty = control.dirty;
2314
+ const touched = control.touched;
2315
+ return control.invalid ? dirty || touched : false;
2316
+ }
2317
+ get errorMessage() {
2318
+ if (!this.ngControl?.errors)
2319
+ return '';
2320
+ const errors = this.ngControl.errors;
2321
+ const errorKey = Object.keys(errors)[0];
2322
+ if (errorKey === 'minlength') {
2323
+ return this.transloco.translate('formErrors.minlength', {
2324
+ length: errors[errorKey].requiredLength,
2325
+ });
2326
+ }
2327
+ return this.transloco.translate(`formErrors.${errorKey}`, {}, this.transloco.translate('formErrors.invalidField'));
2328
+ }
2329
+ get inputClasses() {
2330
+ return this.showError ? ERROR_INPUT_CLASSES : BASE_INPUT_CLASSES;
2331
+ }
2332
+ get fieldGroupClasses() {
2333
+ let baseClasses = '';
2334
+ if (this.fieldGroupClass) {
2335
+ baseClasses += ` ${this.fieldGroupClass}`;
2336
+ }
2337
+ else {
2338
+ baseClasses += ' w-full';
2339
+ }
2340
+ return baseClasses;
2341
+ }
2342
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: DateInputComponent, deps: [{ token: i1$1.NgControl, optional: true, self: true }, { token: i2.TranslocoService }], target: i0.ɵɵFactoryTarget.Component });
2343
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.25", type: DateInputComponent, isStandalone: true, selector: "date-input", inputs: { label: "label", type: "type", includeTime: "includeTime", name: "name", id: "id", placeholder: "placeholder", required: "required", readonly: "readonly", min: "min", max: "max", fieldGroupClass: "fieldGroupClass", dateFormat: "dateFormat" }, ngImport: i0, template: "<div [class]=\"fieldGroupClasses\">\n @if (label) {\n <label [for]=\"inputId\" class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n {{ label }}\n\n @if (required) {\n <span class=\"text-red-500\">*</span>\n }\n </label>\n }\n\n <div class=\"relative\">\n <input\n [type]=\"includeTime ? 'datetime-local' : type\"\n [id]=\"inputId\"\n [name]=\"name\"\n [placeholder]=\"placeholder\"\n [required]=\"required\"\n [min]=\"min\"\n [max]=\"max\"\n [(ngModel)]=\"value\"\n (ngModelChange)=\"onInput($event)\"\n (blur)=\"onTouched()\"\n [disabled]=\"disabled\"\n [class]=\"inputClasses\"\n [readonly]=\"readonly\"\n />\n </div>\n\n @if (showError) {\n <div class=\"text-red-500 text-xs mt-1\">\n {{ errorMessage }}\n </div>\n }\n</div>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }] });
2344
+ }
2345
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: DateInputComponent, decorators: [{
2346
+ type: Component,
2347
+ args: [{ selector: 'date-input', standalone: true, imports: [FormsModule, CommonModule, ReactiveFormsModule], template: "<div [class]=\"fieldGroupClasses\">\n @if (label) {\n <label [for]=\"inputId\" class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n {{ label }}\n\n @if (required) {\n <span class=\"text-red-500\">*</span>\n }\n </label>\n }\n\n <div class=\"relative\">\n <input\n [type]=\"includeTime ? 'datetime-local' : type\"\n [id]=\"inputId\"\n [name]=\"name\"\n [placeholder]=\"placeholder\"\n [required]=\"required\"\n [min]=\"min\"\n [max]=\"max\"\n [(ngModel)]=\"value\"\n (ngModelChange)=\"onInput($event)\"\n (blur)=\"onTouched()\"\n [disabled]=\"disabled\"\n [class]=\"inputClasses\"\n [readonly]=\"readonly\"\n />\n </div>\n\n @if (showError) {\n <div class=\"text-red-500 text-xs mt-1\">\n {{ errorMessage }}\n </div>\n }\n</div>\n" }]
2348
+ }], ctorParameters: () => [{ type: i1$1.NgControl, decorators: [{
2349
+ type: Self
2350
+ }, {
2351
+ type: Optional
2352
+ }] }, { type: i2.TranslocoService }], propDecorators: { label: [{
2353
+ type: Input
2354
+ }], type: [{
2355
+ type: Input
2356
+ }], includeTime: [{
2357
+ type: Input
2358
+ }], name: [{
2359
+ type: Input
2360
+ }], id: [{
2361
+ type: Input
2362
+ }], placeholder: [{
2363
+ type: Input
2364
+ }], required: [{
2365
+ type: Input
2366
+ }], readonly: [{
2367
+ type: Input
2368
+ }], min: [{
2369
+ type: Input
2370
+ }], max: [{
2371
+ type: Input
2372
+ }], fieldGroupClass: [{
2373
+ type: Input
2374
+ }], dateFormat: [{
2375
+ type: Input
2376
+ }] } });
2377
+
2378
+ class ToggleSwitchComponent {
2379
+ ngControl;
2380
+ label = '';
2381
+ name = '';
2382
+ id = '';
2383
+ required = false;
2384
+ disabled = false;
2385
+ size = 'md';
2386
+ fieldGroupClass = '';
2387
+ description = '';
2388
+ toggleClick = new EventEmitter();
2389
+ value = false;
2390
+ onChange = () => { };
2391
+ onTouched = () => { };
2392
+ constructor(ngControl) {
2393
+ this.ngControl = ngControl;
2394
+ if (this.ngControl) {
2395
+ this.ngControl.valueAccessor = this;
2396
+ }
2397
+ }
2398
+ // Control value accessor methods
2399
+ writeValue(value) {
2400
+ this.value = value ?? false;
2401
+ }
2402
+ registerOnChange(fn) {
2403
+ this.onChange = fn;
2404
+ }
2405
+ registerOnTouched(fn) {
2406
+ this.onTouched = fn;
2407
+ }
2408
+ setDisabledState(isDisabled) {
2409
+ this.disabled = isDisabled;
2410
+ }
2411
+ onToggle() {
2412
+ this.value = !this.value;
2413
+ this.onChange(this.value);
2414
+ this.onTouched();
2415
+ this.toggleClick.emit(this.value);
2416
+ }
2417
+ get inputId() {
2418
+ return this.id || this.name;
2419
+ }
2420
+ get toggleSizeClasses() {
2421
+ switch (this.size) {
2422
+ case 'sm':
2423
+ return 'h-4 w-7';
2424
+ case 'lg':
2425
+ return 'h-7 w-14';
2426
+ default:
2427
+ return 'h-5 w-9';
2428
+ }
2429
+ }
2430
+ get toggleThumbSizeClasses() {
2431
+ switch (this.size) {
2432
+ case 'sm':
2433
+ return 'h-3 w-3';
2434
+ case 'lg':
2435
+ return 'h-6 w-6';
2436
+ default:
2437
+ return 'h-4 w-4';
2438
+ }
2439
+ }
2440
+ get toggleThumbTranslateClasses() {
2441
+ switch (this.size) {
2442
+ case 'sm':
2443
+ return 'translate-x-3';
2444
+ case 'lg':
2445
+ return 'translate-x-7';
2446
+ default:
2447
+ return 'translate-x-5';
2448
+ }
2449
+ }
2450
+ get fieldGroupClasses() {
2451
+ let baseClasses = '';
2452
+ if (this.fieldGroupClass) {
2453
+ baseClasses += ` ${this.fieldGroupClass}`;
2454
+ }
2455
+ else {
2456
+ baseClasses += ' w-full';
2457
+ }
2458
+ return baseClasses;
2459
+ }
2460
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: ToggleSwitchComponent, deps: [{ token: i1$1.NgControl, optional: true, self: true }], target: i0.ɵɵFactoryTarget.Component });
2461
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.25", type: ToggleSwitchComponent, isStandalone: true, selector: "toggle-switch", inputs: { label: "label", name: "name", id: "id", required: "required", disabled: "disabled", size: "size", fieldGroupClass: "fieldGroupClass", description: "description" }, outputs: { toggleClick: "toggleClick" }, ngImport: i0, template: "<div [class]=\"fieldGroupClasses\">\n @if (label) {\n <label [for]=\"inputId\" class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n {{ label }}\n\n @if (required) {\n <span class=\"text-red-500\">*</span>\n }\n </label>\n }\n\n <div class=\"flex items-center\">\n <button\n type=\"button\"\n role=\"switch\"\n [id]=\"inputId\"\n [name]=\"name\"\n [attr.aria-checked]=\"value\"\n [attr.aria-required]=\"required\"\n [disabled]=\"disabled\"\n [class]=\"\n 'toggle-switch ' +\n size +\n (value ? ' checked' : ' unchecked') +\n (disabled ? ' disabled' : '')\n \"\n (click)=\"onToggle()\"\n >\n <span\n [class]=\"\n 'toggle-thumb ' +\n size +\n (value ? ' checked' : ' unchecked') +\n (disabled ? ' disabled' : '')\n \"\n ></span>\n </button>\n\n @if (description) {\n <span class=\"ml-3 text-sm text-gray-500 dark:text-gray-400\">{{ description }}</span>\n }\n </div>\n\n <!-- Hidden checkbox for form submission and accessibility -->\n <input\n type=\"checkbox\"\n [id]=\"inputId + '-hidden'\"\n [name]=\"name\"\n [checked]=\"value\"\n [disabled]=\"disabled\"\n [required]=\"required\"\n class=\"sr-only\"\n (change)=\"onToggle()\"\n />\n</div>\n", styles: [".toggle-switch{display:inline-flex;flex-shrink:0;position:relative;border:2px solid transparent;border-radius:9999px;cursor:pointer;transition:background-color .2s ease-in-out;outline:none}.toggle-switch:focus{box-shadow:0 0 0 2px #fff,0 0 0 4px #4f46e5}.toggle-switch.checked:not(.disabled){background-color:#4f46e5}.toggle-switch.unchecked:not(.disabled){background-color:#e5e7eb}.toggle-switch.disabled{background-color:#d1d5db;cursor:not-allowed;opacity:.5}.toggle-switch.sm{height:1rem;width:1.75rem;padding:0 2px;box-sizing:border-box}.toggle-switch.sm .toggle-thumb{height:calc(1rem - 6px);width:calc(1rem - 6px)}.toggle-switch.sm .toggle-thumb.checked{transform:translate(calc(.75rem - 2px))}.toggle-switch.md{height:1.25rem;width:2.25rem;padding:0 2px;box-sizing:border-box}.toggle-switch.md .toggle-thumb{height:calc(1.25rem - 6px);width:calc(1.25rem - 6px)}.toggle-switch.md .toggle-thumb.checked{transform:translate(calc(1rem - 2px))}.toggle-switch.lg{height:1.75rem;width:3.5rem;padding:0 2px;box-sizing:border-box}.toggle-switch.lg .toggle-thumb{height:calc(1.75rem - 6px);width:calc(1.75rem - 6px)}.toggle-switch.lg .toggle-thumb.checked{transform:translate(calc(1.75rem - 2px))}.toggle-thumb{pointer-events:none;display:inline-block;border-radius:50%;background-color:#fff;box-shadow:0 10px 15px -3px #0000001a;transition:transform .2s ease-in-out;margin:auto 0}.disabled .toggle-thumb{background-color:#9ca3af}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }] });
2462
+ }
2463
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: ToggleSwitchComponent, decorators: [{
2464
+ type: Component,
2465
+ args: [{ selector: 'toggle-switch', standalone: true, imports: [FormsModule, CommonModule, ReactiveFormsModule], template: "<div [class]=\"fieldGroupClasses\">\n @if (label) {\n <label [for]=\"inputId\" class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n {{ label }}\n\n @if (required) {\n <span class=\"text-red-500\">*</span>\n }\n </label>\n }\n\n <div class=\"flex items-center\">\n <button\n type=\"button\"\n role=\"switch\"\n [id]=\"inputId\"\n [name]=\"name\"\n [attr.aria-checked]=\"value\"\n [attr.aria-required]=\"required\"\n [disabled]=\"disabled\"\n [class]=\"\n 'toggle-switch ' +\n size +\n (value ? ' checked' : ' unchecked') +\n (disabled ? ' disabled' : '')\n \"\n (click)=\"onToggle()\"\n >\n <span\n [class]=\"\n 'toggle-thumb ' +\n size +\n (value ? ' checked' : ' unchecked') +\n (disabled ? ' disabled' : '')\n \"\n ></span>\n </button>\n\n @if (description) {\n <span class=\"ml-3 text-sm text-gray-500 dark:text-gray-400\">{{ description }}</span>\n }\n </div>\n\n <!-- Hidden checkbox for form submission and accessibility -->\n <input\n type=\"checkbox\"\n [id]=\"inputId + '-hidden'\"\n [name]=\"name\"\n [checked]=\"value\"\n [disabled]=\"disabled\"\n [required]=\"required\"\n class=\"sr-only\"\n (change)=\"onToggle()\"\n />\n</div>\n", styles: [".toggle-switch{display:inline-flex;flex-shrink:0;position:relative;border:2px solid transparent;border-radius:9999px;cursor:pointer;transition:background-color .2s ease-in-out;outline:none}.toggle-switch:focus{box-shadow:0 0 0 2px #fff,0 0 0 4px #4f46e5}.toggle-switch.checked:not(.disabled){background-color:#4f46e5}.toggle-switch.unchecked:not(.disabled){background-color:#e5e7eb}.toggle-switch.disabled{background-color:#d1d5db;cursor:not-allowed;opacity:.5}.toggle-switch.sm{height:1rem;width:1.75rem;padding:0 2px;box-sizing:border-box}.toggle-switch.sm .toggle-thumb{height:calc(1rem - 6px);width:calc(1rem - 6px)}.toggle-switch.sm .toggle-thumb.checked{transform:translate(calc(.75rem - 2px))}.toggle-switch.md{height:1.25rem;width:2.25rem;padding:0 2px;box-sizing:border-box}.toggle-switch.md .toggle-thumb{height:calc(1.25rem - 6px);width:calc(1.25rem - 6px)}.toggle-switch.md .toggle-thumb.checked{transform:translate(calc(1rem - 2px))}.toggle-switch.lg{height:1.75rem;width:3.5rem;padding:0 2px;box-sizing:border-box}.toggle-switch.lg .toggle-thumb{height:calc(1.75rem - 6px);width:calc(1.75rem - 6px)}.toggle-switch.lg .toggle-thumb.checked{transform:translate(calc(1.75rem - 2px))}.toggle-thumb{pointer-events:none;display:inline-block;border-radius:50%;background-color:#fff;box-shadow:0 10px 15px -3px #0000001a;transition:transform .2s ease-in-out;margin:auto 0}.disabled .toggle-thumb{background-color:#9ca3af}\n"] }]
2466
+ }], ctorParameters: () => [{ type: i1$1.NgControl, decorators: [{
2467
+ type: Self
2468
+ }, {
2469
+ type: Optional
2470
+ }] }], propDecorators: { label: [{
2471
+ type: Input
2472
+ }], name: [{
2473
+ type: Input
2474
+ }], id: [{
2475
+ type: Input
2476
+ }], required: [{
2477
+ type: Input
2478
+ }], disabled: [{
2479
+ type: Input
2480
+ }], size: [{
2481
+ type: Input
2482
+ }], fieldGroupClass: [{
2483
+ type: Input
2484
+ }], description: [{
2485
+ type: Input
2486
+ }], toggleClick: [{
2487
+ type: Output
2488
+ }] } });
2489
+
2490
+ class FileUploadPreviewComponent {
2491
+ file = {};
2492
+ remove = new EventEmitter();
2493
+ removeFile() {
2494
+ this.remove.emit(this.file);
2495
+ }
2496
+ getFileType(file) {
2497
+ if (file.type.startsWith('image/'))
2498
+ return FileType.IMAGE;
2499
+ if (file.type === 'application/pdf')
2500
+ return FileType.PDF;
2501
+ if (file.type.includes('spreadsheet') ||
2502
+ file.type.includes('excel') ||
2503
+ file.extension === 'xlsx' ||
2504
+ file.extension === 'xls' ||
2505
+ file.extension === 'csv') {
2506
+ return FileType.EXCEL;
2507
+ }
2508
+ if (file.type.includes('word') ||
2509
+ file.type.includes('document') ||
2510
+ file.extension === 'docx' ||
2511
+ file.extension === 'doc') {
2512
+ return FileType.WORD;
2513
+ }
2514
+ if (file.type.startsWith('text/') || file.extension === 'txt') {
2515
+ return FileType.TEXT;
2516
+ }
2517
+ return FileType.DEFAULT;
2518
+ }
2519
+ getFileIcon(fileType) {
2520
+ switch (fileType) {
2521
+ case FileType.IMAGE:
2522
+ return 'ri-image-line';
2523
+ case FileType.PDF:
2524
+ return 'ri-file-pdf-line';
2525
+ case FileType.EXCEL:
2526
+ return 'ri-file-excel-line';
2527
+ case FileType.WORD:
2528
+ return 'ri-file-word-line';
2529
+ case FileType.TEXT:
2530
+ return 'ri-file-text-line';
2531
+ default:
2532
+ return 'ri-file-line';
2533
+ }
2534
+ }
2535
+ getFileTypeIcon(file) {
2536
+ return this.getFileIcon(this.getFileType(file));
2537
+ }
2538
+ formatFileSize(bytes) {
2539
+ if (bytes === 0)
2540
+ return '0 Bytes';
2541
+ const k = 1024;
2542
+ const sizes = ['Bytes', 'KB', 'MB', 'GB'];
2543
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
2544
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
2545
+ }
2546
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: FileUploadPreviewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2547
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.25", type: FileUploadPreviewComponent, isStandalone: true, selector: "file-upload-preview", inputs: { file: "file" }, outputs: { remove: "remove" }, ngImport: i0, template: "<div class=\"flex items-center justify-between p-3 bg-gray-50 rounded-lg border border-gray-200\">\n <div class=\"flex items-center space-x-3 flex-1 min-w-0\">\n <!-- File Preview/Icon -->\n <div class=\"flex-shrink-0\">\n @if (file.preview) {\n <img [src]=\"file.preview\" [alt]=\"file.name\" class=\"w-10 h-10 object-cover rounded-md\" />\n } @else {\n <div class=\"w-10 h-10 bg-gray-200 rounded-md flex items-center justify-center\">\n <i [class]=\"getFileTypeIcon(file) + ' text-gray-600 text-lg'\"></i>\n </div>\n }\n </div>\n\n <!-- File Info -->\n <div class=\"flex-1 min-w-0\">\n <p class=\"text-sm font-medium text-gray-900 truncate\">\n {{ file.name }}\n </p>\n <p class=\"text-xs text-gray-500\">\n @if (!!file.size) {\n {{ formatFileSize(file.size) }}\n }\n @if (file.extension) {\n \u2022 {{ file.extension.toUpperCase() }}\n }\n </p>\n </div>\n </div>\n\n <!-- Actions -->\n <div class=\"flex items-center space-x-2 ml-4\">\n <app-button\n icon=\"ri-delete-bin-line\"\n (clicked)=\"removeFile()\"\n variant=\"primary\"\n size=\"xs\"\n title=\"Eliminar archivo\"\n />\n </div>\n</div>\n", styles: [".file-upload__drag-over{border-color:#60a5fa;background-color:#eff6ff}.file-upload__disabled{border-color:#e5e7eb;background-color:#f9fafb;cursor:not-allowed}.file-upload__preview{transition:all .2s ease-in-out}.file-upload__preview:hover{transform:scale(1.05)}.file-upload__file-item{transition:all .2s ease-in-out}.file-upload__file-item:hover{background-color:#f3f4f6;border-color:#d1d5db}.file-upload__remove-btn{transition:all .2s ease-in-out}.file-upload__remove-btn:hover{background-color:#fef2f2}.file-upload__remove-btn:active{transform:scale(.95)}@keyframes pulse{0%,to{opacity:1}50%{opacity:.5}}.file-upload__drag-active{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}.file-upload__file-list{max-height:15rem;overflow-y:auto}.file-upload__file-list::-webkit-scrollbar{width:.5rem}.file-upload__file-list::-webkit-scrollbar-track{background-color:#f3f4f6;border-radius:9999px}.file-upload__file-list::-webkit-scrollbar-thumb{background-color:#d1d5db;border-radius:9999px}.file-upload__file-list::-webkit-scrollbar-thumb:hover{background-color:#9ca3af}.file-type-icon--image{color:#3b82f6}.file-type-icon--pdf{color:#ef4444}.file-type-icon--excel{color:#10b981}.file-type-icon--word{color:#2563eb}.file-type-icon--text{color:#6b7280}.file-type-icon--default{color:#9ca3af}@media(max-width:640px){.file-upload__file-item{padding:.5rem}.file-upload__file-info{font-size:.75rem}.file-upload__preview{width:2rem;height:2rem}}@media(prefers-color-scheme:dark){.file-upload__file-item{background-color:#1f2937;border-color:#374151}.file-upload__file-item:hover{background-color:#111827;border-color:#4b5563}.file-upload__file-info{color:#d1d5db}.file-upload__file-name{color:#f3f4f6}.file-upload__file-size{color:#9ca3af}}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "component", type: AppButtonComponent, selector: "app-button", inputs: ["disabled", "loading", "type", "variant", "text", "size", "loadingText", "icon"], outputs: ["clicked"] }] });
2548
+ }
2549
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: FileUploadPreviewComponent, decorators: [{
2550
+ type: Component,
2551
+ args: [{ selector: 'file-upload-preview', standalone: true, imports: [FormsModule, CommonModule, ReactiveFormsModule, AppButtonComponent], template: "<div class=\"flex items-center justify-between p-3 bg-gray-50 rounded-lg border border-gray-200\">\n <div class=\"flex items-center space-x-3 flex-1 min-w-0\">\n <!-- File Preview/Icon -->\n <div class=\"flex-shrink-0\">\n @if (file.preview) {\n <img [src]=\"file.preview\" [alt]=\"file.name\" class=\"w-10 h-10 object-cover rounded-md\" />\n } @else {\n <div class=\"w-10 h-10 bg-gray-200 rounded-md flex items-center justify-center\">\n <i [class]=\"getFileTypeIcon(file) + ' text-gray-600 text-lg'\"></i>\n </div>\n }\n </div>\n\n <!-- File Info -->\n <div class=\"flex-1 min-w-0\">\n <p class=\"text-sm font-medium text-gray-900 truncate\">\n {{ file.name }}\n </p>\n <p class=\"text-xs text-gray-500\">\n @if (!!file.size) {\n {{ formatFileSize(file.size) }}\n }\n @if (file.extension) {\n \u2022 {{ file.extension.toUpperCase() }}\n }\n </p>\n </div>\n </div>\n\n <!-- Actions -->\n <div class=\"flex items-center space-x-2 ml-4\">\n <app-button\n icon=\"ri-delete-bin-line\"\n (clicked)=\"removeFile()\"\n variant=\"primary\"\n size=\"xs\"\n title=\"Eliminar archivo\"\n />\n </div>\n</div>\n", styles: [".file-upload__drag-over{border-color:#60a5fa;background-color:#eff6ff}.file-upload__disabled{border-color:#e5e7eb;background-color:#f9fafb;cursor:not-allowed}.file-upload__preview{transition:all .2s ease-in-out}.file-upload__preview:hover{transform:scale(1.05)}.file-upload__file-item{transition:all .2s ease-in-out}.file-upload__file-item:hover{background-color:#f3f4f6;border-color:#d1d5db}.file-upload__remove-btn{transition:all .2s ease-in-out}.file-upload__remove-btn:hover{background-color:#fef2f2}.file-upload__remove-btn:active{transform:scale(.95)}@keyframes pulse{0%,to{opacity:1}50%{opacity:.5}}.file-upload__drag-active{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}.file-upload__file-list{max-height:15rem;overflow-y:auto}.file-upload__file-list::-webkit-scrollbar{width:.5rem}.file-upload__file-list::-webkit-scrollbar-track{background-color:#f3f4f6;border-radius:9999px}.file-upload__file-list::-webkit-scrollbar-thumb{background-color:#d1d5db;border-radius:9999px}.file-upload__file-list::-webkit-scrollbar-thumb:hover{background-color:#9ca3af}.file-type-icon--image{color:#3b82f6}.file-type-icon--pdf{color:#ef4444}.file-type-icon--excel{color:#10b981}.file-type-icon--word{color:#2563eb}.file-type-icon--text{color:#6b7280}.file-type-icon--default{color:#9ca3af}@media(max-width:640px){.file-upload__file-item{padding:.5rem}.file-upload__file-info{font-size:.75rem}.file-upload__preview{width:2rem;height:2rem}}@media(prefers-color-scheme:dark){.file-upload__file-item{background-color:#1f2937;border-color:#374151}.file-upload__file-item:hover{background-color:#111827;border-color:#4b5563}.file-upload__file-info{color:#d1d5db}.file-upload__file-name{color:#f3f4f6}.file-upload__file-size{color:#9ca3af}}\n"] }]
2552
+ }], propDecorators: { file: [{
2553
+ type: Input,
2554
+ args: [{ required: true }]
2555
+ }], remove: [{
2556
+ type: Output
2557
+ }] } });
2558
+
2559
+ class FileUploadComponent {
2560
+ ngControl;
2561
+ transloco;
2562
+ label = '';
2563
+ name = '';
2564
+ id = '';
2565
+ required = false;
2566
+ readonly = false;
2567
+ fieldGroupClass = '';
2568
+ config = {};
2569
+ accept = '*/*';
2570
+ fileSelected = new EventEmitter();
2571
+ fileRemoved = new EventEmitter();
2572
+ validationError = new EventEmitter();
2573
+ files = [];
2574
+ disabled = false;
2575
+ onChange = () => { };
2576
+ onTouched = () => { };
2577
+ dragOver = false;
2578
+ constructor(ngControl, transloco) {
2579
+ this.ngControl = ngControl;
2580
+ this.transloco = transloco;
2581
+ if (this.ngControl) {
2582
+ this.ngControl.valueAccessor = this;
2583
+ }
2584
+ }
2585
+ writeValue(value) {
2586
+ this.files = value || [];
2587
+ }
2588
+ registerOnChange(fn) {
2589
+ this.onChange = fn;
2590
+ }
2591
+ registerOnTouched(fn) {
2592
+ this.onTouched = fn;
2593
+ }
2594
+ setDisabledState(isDisabled) {
2595
+ this.disabled = isDisabled;
2596
+ }
2597
+ onFileSelect(event) {
2598
+ const input = event.target;
2599
+ if (input.files && input.files.length > 0) {
2600
+ this.handleFiles(Array.from(input.files));
2601
+ }
2602
+ input.value = '';
2603
+ }
2604
+ onDrop(event) {
2605
+ event.preventDefault();
2606
+ this.dragOver = false;
2607
+ if (event.dataTransfer?.files && event.dataTransfer.files.length > 0) {
2608
+ this.handleFiles(Array.from(event.dataTransfer.files));
2609
+ }
2610
+ }
2611
+ onDragOver(event) {
2612
+ event.preventDefault();
2613
+ this.dragOver = true;
2614
+ }
2615
+ onDragLeave(event) {
2616
+ event.preventDefault();
2617
+ this.dragOver = false;
2618
+ }
2619
+ async handleFiles(fileList) {
2620
+ const newFiles = [];
2621
+ for (const file of fileList) {
2622
+ const validationError = this.validateFile(file);
2623
+ if (validationError) {
2624
+ this.validationError.emit(validationError);
2625
+ continue;
2626
+ }
2627
+ const uploadedFile = {
2628
+ file,
2629
+ name: file.name,
2630
+ size: file.size,
2631
+ type: file.type,
2632
+ extension: this.getFileExtension(file.name),
2633
+ };
2634
+ if (this.isImage(file)) {
2635
+ uploadedFile.preview = await this.generateImagePreview(file);
2636
+ }
2637
+ newFiles.push(uploadedFile);
2638
+ }
2639
+ if (this.config.multiple) {
2640
+ const maxFiles = this.config.maxFiles || 10;
2641
+ const totalFiles = [...this.files, ...newFiles].slice(0, maxFiles);
2642
+ this.files = totalFiles;
2643
+ }
2644
+ else {
2645
+ this.files = newFiles.slice(0, 1);
2646
+ }
2647
+ this.onChange(this.files);
2648
+ this.onTouched();
2649
+ this.fileSelected.emit(this.files);
2650
+ }
2651
+ validateFile(file) {
2652
+ if (this.config.maxFileSize && file.size > this.config.maxFileSize) {
2653
+ const maxSizeMB = this.config.maxFileSize / (1024 * 1024);
2654
+ return this.transloco.translate('fileUpload.sizeError', {
2655
+ fileName: file.name,
2656
+ maxSize: maxSizeMB.toFixed(2),
2657
+ });
2658
+ }
2659
+ if (this.config.allowedExtensions && this.config.allowedExtensions.length > 0) {
2660
+ const extension = this.getFileExtension(file.name);
2661
+ if (!this.config.allowedExtensions.includes(extension)) {
2662
+ return this.transloco.translate('fileUpload.extensionError', {
2663
+ fileName: file.name,
2664
+ extensions: this.config.allowedExtensions.join(', '),
2665
+ });
2666
+ }
2667
+ }
2668
+ return null;
2669
+ }
2670
+ getFileExtension(filename) {
2671
+ return filename.split('.').pop()?.toLowerCase() || '';
2672
+ }
2673
+ isImage(file) {
2674
+ return file.type.startsWith('image/');
2675
+ }
2676
+ async generateImagePreview(file) {
2677
+ return new Promise((resolve) => {
2678
+ const reader = new FileReader();
2679
+ reader.onload = (e) => {
2680
+ resolve(e.target?.result);
2681
+ };
2682
+ reader.readAsDataURL(file);
2683
+ });
2684
+ }
2685
+ removeFile(index) {
2686
+ const removedFile = this.files[index];
2687
+ this.files.splice(index, 1);
2688
+ this.onChange(this.files);
2689
+ this.onTouched();
2690
+ this.fileRemoved.emit(removedFile);
2691
+ }
2692
+ getFileType(file) {
2693
+ if (file.type.startsWith('image/'))
2694
+ return FileType.IMAGE;
2695
+ if (file.type === 'application/pdf')
2696
+ return FileType.PDF;
2697
+ if (file.type.includes('spreadsheet') ||
2698
+ file.type.includes('excel') ||
2699
+ file.extension === 'xlsx' ||
2700
+ file.extension === 'xls' ||
2701
+ file.extension === 'csv') {
2702
+ return FileType.EXCEL;
2703
+ }
2704
+ if (file.type.includes('word') ||
2705
+ file.type.includes('document') ||
2706
+ file.extension === 'docx' ||
2707
+ file.extension === 'doc') {
2708
+ return FileType.WORD;
2709
+ }
2710
+ if (file.type.startsWith('text/') || file.extension === 'txt') {
2711
+ return FileType.TEXT;
2712
+ }
2713
+ return FileType.DEFAULT;
2714
+ }
2715
+ getFileIcon(fileType) {
2716
+ switch (fileType) {
2717
+ case FileType.IMAGE:
2718
+ return 'ri-image-line';
2719
+ case FileType.PDF:
2720
+ return 'ri-file-pdf-line';
2721
+ case FileType.EXCEL:
2722
+ return 'ri-file-excel-line';
2723
+ case FileType.WORD:
2724
+ return 'ri-file-word-line';
2725
+ case FileType.TEXT:
2726
+ return 'ri-file-text-line';
2727
+ default:
2728
+ return 'ri-file-line';
2729
+ }
2730
+ }
2731
+ getFileTypeIcon(file) {
2732
+ return this.getFileIcon(this.getFileType(file));
2733
+ }
2734
+ triggerFileInput() {
2735
+ const inputElement = document.getElementById(this.inputId);
2736
+ if (inputElement) {
2737
+ inputElement.click();
2738
+ }
2739
+ }
2740
+ formatFileSize(bytes) {
2741
+ if (bytes === 0)
2742
+ return '0 Bytes';
2743
+ const k = 1024;
2744
+ const sizes = ['Bytes', 'KB', 'MB', 'GB'];
2745
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
2746
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
2747
+ }
2748
+ get inputId() {
2749
+ return this.id || this.name;
2750
+ }
2751
+ get showError() {
2752
+ if (!this.ngControl || !this.ngControl.control)
2753
+ return false;
2754
+ const control = this.ngControl.control;
2755
+ const dirty = control.dirty;
2756
+ const touched = control.touched;
2757
+ return control.invalid ? dirty || touched : false;
2758
+ }
2759
+ get errorMessage() {
2760
+ if (!this.ngControl?.errors)
2761
+ return '';
2762
+ const errors = this.ngControl.errors;
2763
+ const errorKey = Object.keys(errors)[0];
2764
+ return this.transloco.translate(`formErrors.${errorKey}`, {}, this.transloco.translate('formErrors.invalidField'));
2765
+ }
2766
+ get fieldGroupClasses() {
2767
+ let baseClasses = '';
2768
+ if (this.fieldGroupClass) {
2769
+ baseClasses += ` ${this.fieldGroupClass}`;
2770
+ }
2771
+ else {
2772
+ baseClasses += ' w-full';
2773
+ }
2774
+ return baseClasses;
2775
+ }
2776
+ get uploadAreaClasses() {
2777
+ const baseClasses = 'border-2 border-dashed rounded-lg p-6 text-center transition-colors cursor-pointer';
2778
+ if (this.disabled) {
2779
+ return `${baseClasses} border-gray-200 bg-gray-50 cursor-not-allowed`;
2780
+ }
2781
+ if (this.dragOver) {
2782
+ return `${baseClasses} border-blue-400 bg-blue-50`;
2783
+ }
2784
+ return `${baseClasses} border-gray-300 hover:border-gray-400 hover:bg-gray-50`;
2785
+ }
2786
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: FileUploadComponent, deps: [{ token: i1$1.NgControl, optional: true, self: true }, { token: i2.TranslocoService }], target: i0.ɵɵFactoryTarget.Component });
2787
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.25", type: FileUploadComponent, isStandalone: true, selector: "file-upload", inputs: { label: "label", name: "name", id: "id", required: "required", readonly: "readonly", fieldGroupClass: "fieldGroupClass", config: "config", accept: "accept" }, outputs: { fileSelected: "fileSelected", fileRemoved: "fileRemoved", validationError: "validationError" }, ngImport: i0, template: "<div [class]=\"fieldGroupClasses\">\n @if (label) {\n <label [for]=\"inputId\" class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n {{ label }}\n\n @if (required) {\n <span class=\"text-red-500\">*</span>\n }\n </label>\n }\n\n <!-- Upload Area -->\n <div\n class=\"relative\"\n (drop)=\"onDrop($event)\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n >\n <div [class]=\"uploadAreaClasses\" (click)=\"!disabled && triggerFileInput()\">\n <input\n [id]=\"inputId\"\n [name]=\"name\"\n type=\"file\"\n [accept]=\"accept\"\n [multiple]=\"config.multiple\"\n [disabled]=\"disabled\"\n [required]=\"required\"\n (change)=\"onFileSelect($event)\"\n (blur)=\"onTouched()\"\n class=\"hidden\"\n />\n\n <div class=\"flex flex-col items-center space-y-2\">\n <i class=\"ri-upload-cloud-2-line text-3xl text-gray-400\"></i>\n <div class=\"text-sm text-gray-600\">\n <p class=\"font-medium\">\n @if (config.multiple) {\n {{ 'fileUpload.dropMultiple' | transloco }}\n } @else {\n {{ 'fileUpload.dropSingle' | transloco }}\n }\n </p>\n <p class=\"text-xs text-gray-500 mt-1\">\n @if (config.allowedExtensions && config.allowedExtensions.length > 0) {\n {{ 'fileUpload.allowedExtensions' | transloco }}\n {{ config.allowedExtensions.join(', ') }}\n }\n @if (config.maxFileSize) {\n \u2022 {{ 'fileUpload.maxSize' | transloco }} {{ formatFileSize(config.maxFileSize) }}\n }\n </p>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Files Preview -->\n @if (files.length > 0) {\n <div class=\"flex flex-col gap-2 mt-4\">\n @for (file of files; track file; let i = $index) {\n <file-upload-preview [file]=\"file\" (remove)=\"removeFile(i)\" />\n }\n </div>\n }\n\n <!-- Validation Error -->\n @if (showError) {\n <div class=\"text-red-500 text-xs mt-1\">\n {{ errorMessage }}\n </div>\n }\n\n <!-- File Type Legend -->\n @if (files.length === 0) {\n <div class=\"mt-3 flex flex-wrap gap-4 text-xs text-gray-500\">\n <div class=\"flex items-center space-x-1\">\n <i class=\"ri-image-line text-blue-500\"></i>\n <span>{{ 'fileUpload.fileTypeImages' | transloco }}</span>\n </div>\n <div class=\"flex items-center space-x-1\">\n <i class=\"ri-file-pdf-line text-red-500\"></i>\n <span>PDF</span>\n </div>\n <div class=\"flex items-center space-x-1\">\n <i class=\"ri-file-excel-line text-green-500\"></i>\n <span>{{ 'fileUpload.fileTypeExcel' | transloco }}</span>\n </div>\n <div class=\"flex items-center space-x-1\">\n <i class=\"ri-file-word-line text-blue-600\"></i>\n <span>{{ 'fileUpload.fileTypeWord' | transloco }}</span>\n </div>\n <div class=\"flex items-center space-x-1\">\n <i class=\"ri-file-text-line text-gray-500\"></i>\n <span>{{ 'fileUpload.fileTypeText' | transloco }}</span>\n </div>\n <div class=\"flex items-center space-x-1\">\n <i class=\"ri-file-line text-gray-400\"></i>\n <span>{{ 'fileUpload.fileTypeOther' | transloco }}</span>\n </div>\n </div>\n }\n</div>\n", styles: [".file-upload__drag-over{border-color:#60a5fa;background-color:#eff6ff}.file-upload__disabled{border-color:#e5e7eb;background-color:#f9fafb;cursor:not-allowed}.file-upload__preview{transition:all .2s ease-in-out}.file-upload__preview:hover{transform:scale(1.05)}.file-upload__file-item{transition:all .2s ease-in-out}.file-upload__file-item:hover{background-color:#f3f4f6;border-color:#d1d5db}.file-upload__remove-btn{transition:all .2s ease-in-out}.file-upload__remove-btn:hover{background-color:#fef2f2}.file-upload__remove-btn:active{transform:scale(.95)}@keyframes pulse{0%,to{opacity:1}50%{opacity:.5}}.file-upload__drag-active{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}.file-upload__file-list{max-height:15rem;overflow-y:auto}.file-upload__file-list::-webkit-scrollbar{width:.5rem}.file-upload__file-list::-webkit-scrollbar-track{background-color:#f3f4f6;border-radius:9999px}.file-upload__file-list::-webkit-scrollbar-thumb{background-color:#d1d5db;border-radius:9999px}.file-upload__file-list::-webkit-scrollbar-thumb:hover{background-color:#9ca3af}.file-type-icon--image{color:#3b82f6}.file-type-icon--pdf{color:#ef4444}.file-type-icon--excel{color:#10b981}.file-type-icon--word{color:#2563eb}.file-type-icon--text{color:#6b7280}.file-type-icon--default{color:#9ca3af}@media(max-width:640px){.file-upload__file-item{padding:.5rem}.file-upload__file-info{font-size:.75rem}.file-upload__preview{width:2rem;height:2rem}}@media(prefers-color-scheme:dark){.file-upload__file-item{background-color:#1f2937;border-color:#374151}.file-upload__file-item:hover{background-color:#111827;border-color:#4b5563}.file-upload__file-info{color:#d1d5db}.file-upload__file-name{color:#f3f4f6}.file-upload__file-size{color:#9ca3af}}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: TranslocoModule }, { kind: "component", type: FileUploadPreviewComponent, selector: "file-upload-preview", inputs: ["file"], outputs: ["remove"] }, { kind: "pipe", type: i2.TranslocoPipe, name: "transloco" }] });
2788
+ }
2789
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: FileUploadComponent, decorators: [{
2790
+ type: Component,
2791
+ args: [{ selector: 'file-upload', standalone: true, imports: [
2792
+ FormsModule,
2793
+ CommonModule,
2794
+ ReactiveFormsModule,
2795
+ TranslocoModule,
2796
+ FileUploadPreviewComponent,
2797
+ ], template: "<div [class]=\"fieldGroupClasses\">\n @if (label) {\n <label [for]=\"inputId\" class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n {{ label }}\n\n @if (required) {\n <span class=\"text-red-500\">*</span>\n }\n </label>\n }\n\n <!-- Upload Area -->\n <div\n class=\"relative\"\n (drop)=\"onDrop($event)\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n >\n <div [class]=\"uploadAreaClasses\" (click)=\"!disabled && triggerFileInput()\">\n <input\n [id]=\"inputId\"\n [name]=\"name\"\n type=\"file\"\n [accept]=\"accept\"\n [multiple]=\"config.multiple\"\n [disabled]=\"disabled\"\n [required]=\"required\"\n (change)=\"onFileSelect($event)\"\n (blur)=\"onTouched()\"\n class=\"hidden\"\n />\n\n <div class=\"flex flex-col items-center space-y-2\">\n <i class=\"ri-upload-cloud-2-line text-3xl text-gray-400\"></i>\n <div class=\"text-sm text-gray-600\">\n <p class=\"font-medium\">\n @if (config.multiple) {\n {{ 'fileUpload.dropMultiple' | transloco }}\n } @else {\n {{ 'fileUpload.dropSingle' | transloco }}\n }\n </p>\n <p class=\"text-xs text-gray-500 mt-1\">\n @if (config.allowedExtensions && config.allowedExtensions.length > 0) {\n {{ 'fileUpload.allowedExtensions' | transloco }}\n {{ config.allowedExtensions.join(', ') }}\n }\n @if (config.maxFileSize) {\n \u2022 {{ 'fileUpload.maxSize' | transloco }} {{ formatFileSize(config.maxFileSize) }}\n }\n </p>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Files Preview -->\n @if (files.length > 0) {\n <div class=\"flex flex-col gap-2 mt-4\">\n @for (file of files; track file; let i = $index) {\n <file-upload-preview [file]=\"file\" (remove)=\"removeFile(i)\" />\n }\n </div>\n }\n\n <!-- Validation Error -->\n @if (showError) {\n <div class=\"text-red-500 text-xs mt-1\">\n {{ errorMessage }}\n </div>\n }\n\n <!-- File Type Legend -->\n @if (files.length === 0) {\n <div class=\"mt-3 flex flex-wrap gap-4 text-xs text-gray-500\">\n <div class=\"flex items-center space-x-1\">\n <i class=\"ri-image-line text-blue-500\"></i>\n <span>{{ 'fileUpload.fileTypeImages' | transloco }}</span>\n </div>\n <div class=\"flex items-center space-x-1\">\n <i class=\"ri-file-pdf-line text-red-500\"></i>\n <span>PDF</span>\n </div>\n <div class=\"flex items-center space-x-1\">\n <i class=\"ri-file-excel-line text-green-500\"></i>\n <span>{{ 'fileUpload.fileTypeExcel' | transloco }}</span>\n </div>\n <div class=\"flex items-center space-x-1\">\n <i class=\"ri-file-word-line text-blue-600\"></i>\n <span>{{ 'fileUpload.fileTypeWord' | transloco }}</span>\n </div>\n <div class=\"flex items-center space-x-1\">\n <i class=\"ri-file-text-line text-gray-500\"></i>\n <span>{{ 'fileUpload.fileTypeText' | transloco }}</span>\n </div>\n <div class=\"flex items-center space-x-1\">\n <i class=\"ri-file-line text-gray-400\"></i>\n <span>{{ 'fileUpload.fileTypeOther' | transloco }}</span>\n </div>\n </div>\n }\n</div>\n", styles: [".file-upload__drag-over{border-color:#60a5fa;background-color:#eff6ff}.file-upload__disabled{border-color:#e5e7eb;background-color:#f9fafb;cursor:not-allowed}.file-upload__preview{transition:all .2s ease-in-out}.file-upload__preview:hover{transform:scale(1.05)}.file-upload__file-item{transition:all .2s ease-in-out}.file-upload__file-item:hover{background-color:#f3f4f6;border-color:#d1d5db}.file-upload__remove-btn{transition:all .2s ease-in-out}.file-upload__remove-btn:hover{background-color:#fef2f2}.file-upload__remove-btn:active{transform:scale(.95)}@keyframes pulse{0%,to{opacity:1}50%{opacity:.5}}.file-upload__drag-active{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}.file-upload__file-list{max-height:15rem;overflow-y:auto}.file-upload__file-list::-webkit-scrollbar{width:.5rem}.file-upload__file-list::-webkit-scrollbar-track{background-color:#f3f4f6;border-radius:9999px}.file-upload__file-list::-webkit-scrollbar-thumb{background-color:#d1d5db;border-radius:9999px}.file-upload__file-list::-webkit-scrollbar-thumb:hover{background-color:#9ca3af}.file-type-icon--image{color:#3b82f6}.file-type-icon--pdf{color:#ef4444}.file-type-icon--excel{color:#10b981}.file-type-icon--word{color:#2563eb}.file-type-icon--text{color:#6b7280}.file-type-icon--default{color:#9ca3af}@media(max-width:640px){.file-upload__file-item{padding:.5rem}.file-upload__file-info{font-size:.75rem}.file-upload__preview{width:2rem;height:2rem}}@media(prefers-color-scheme:dark){.file-upload__file-item{background-color:#1f2937;border-color:#374151}.file-upload__file-item:hover{background-color:#111827;border-color:#4b5563}.file-upload__file-info{color:#d1d5db}.file-upload__file-name{color:#f3f4f6}.file-upload__file-size{color:#9ca3af}}\n"] }]
2798
+ }], ctorParameters: () => [{ type: i1$1.NgControl, decorators: [{
2799
+ type: Self
2800
+ }, {
2801
+ type: Optional
2802
+ }] }, { type: i2.TranslocoService }], propDecorators: { label: [{
2803
+ type: Input
2804
+ }], name: [{
2805
+ type: Input
2806
+ }], id: [{
2807
+ type: Input
2808
+ }], required: [{
2809
+ type: Input
2810
+ }], readonly: [{
2811
+ type: Input
2812
+ }], fieldGroupClass: [{
2813
+ type: Input
2814
+ }], config: [{
2815
+ type: Input
2816
+ }], accept: [{
2817
+ type: Input
2818
+ }], fileSelected: [{
2819
+ type: Output
2820
+ }], fileRemoved: [{
2821
+ type: Output
2822
+ }], validationError: [{
2823
+ type: Output
2824
+ }] } });
2825
+
2826
+ class AsyncSelectComponent {
2827
+ config;
2828
+ items = [];
2829
+ parentId;
2830
+ label = '';
2831
+ placeholder = 'Seleccione...';
2832
+ name = '';
2833
+ required = false;
2834
+ multiple = false;
2835
+ clearable = true;
2836
+ searchable = true;
2837
+ loading = false;
2838
+ virtualScroll = false;
2839
+ notFoundText = 'No se encontraron resultados';
2840
+ bindLabel = 'label';
2841
+ bindValue = 'value';
2842
+ value = null;
2843
+ onChange = () => { };
2844
+ onTouched = () => { };
2845
+ displayItems = [];
2846
+ loadingSignal = signal(false, ...(ngDevMode ? [{ debugName: "loadingSignal" }] : []));
2847
+ searchTerm$ = new Subject();
2848
+ destroy$ = new Subject();
2849
+ injector = inject(Injector);
2850
+ _ngControl = null;
2851
+ constructor() { }
2852
+ get ngControl() {
2853
+ if (!this._ngControl) {
2854
+ this._ngControl = this.injector.get(NgControl, null);
2855
+ }
2856
+ return this._ngControl;
2857
+ }
2858
+ ngOnInit() {
2859
+ this.setupSearch();
2860
+ if (this.config) {
2861
+ this.loadAndMap();
2862
+ }
2863
+ else {
2864
+ this.displayItems = this.items;
2865
+ this.searchMode();
2866
+ }
2867
+ }
2868
+ ngOnChanges(changes) {
2869
+ if (changes['parentId'] && !changes['parentId'].firstChange) {
2870
+ this.handleParentIdChange();
2871
+ }
2872
+ if (changes['items'] && !changes['items'].firstChange && !this.config) {
2873
+ this.displayItems = this.items;
2874
+ }
2875
+ }
2876
+ ngOnDestroy() {
2877
+ this.destroy$.next();
2878
+ this.destroy$.complete();
2879
+ }
2880
+ setupSearch() {
2881
+ this.searchTerm$
2882
+ .pipe(debounceTime(400), distinctUntilChanged(), switchMap((term) => {
2883
+ if (this.config) {
2884
+ this.loadingSignal.set(true);
2885
+ return this.fetchData({ search: term });
2886
+ }
2887
+ return of(this.displayItems);
2888
+ }), takeUntil(this.destroy$))
2889
+ .subscribe((options) => {
2890
+ this.displayItems = options;
2891
+ this.loadingSignal.set(false);
2892
+ });
2893
+ }
2894
+ searchMode() {
2895
+ this.searchTerm$
2896
+ .pipe(debounceTime(400), distinctUntilChanged(), switchMap((term) => {
2897
+ this.loadingSignal.set(true);
2898
+ setTimeout(() => this.loadingSignal.set(false), 150);
2899
+ return of(this.items.filter((item) => item.label.toLowerCase().includes(term.toLowerCase())));
2900
+ }), takeUntil(this.destroy$))
2901
+ .subscribe((options) => {
2902
+ this.displayItems = options;
2903
+ });
2904
+ }
2905
+ loadAndMap(params) {
2906
+ if (!this.config)
2907
+ return;
2908
+ this.loadingSignal.set(true);
2909
+ this.fetchData(params)
2910
+ .pipe(takeUntil(this.destroy$))
2911
+ .subscribe((options) => {
2912
+ this.displayItems = options;
2913
+ this.loadingSignal.set(false);
2914
+ });
2915
+ }
2916
+ fetchData(params) {
2917
+ if (!this.config)
2918
+ return of([]);
2919
+ const mergedParams = { ...params };
2920
+ if (this.parentId != null && mergedParams.parentId == null) {
2921
+ mergedParams.parentId = this.parentId;
2922
+ }
2923
+ return this.config.load(mergedParams).pipe(map((res) => this.config.map(res)), catchError(() => of([])));
2924
+ }
2925
+ handleParentIdChange() {
2926
+ this.value = this.multiple ? [] : null;
2927
+ this.onChange(this.value);
2928
+ if (this.parentId != null && this.config) {
2929
+ this.loadAndMap({ parentId: this.parentId });
2930
+ }
2931
+ else if (this.config) {
2932
+ this.displayItems = [];
2933
+ this.loadingSignal.set(false);
2934
+ }
2935
+ }
2936
+ onSearch(event) {
2937
+ const term = event?.term || '';
2938
+ this.searchTerm$.next(term);
2939
+ }
2940
+ onSelectChange(value) {
2941
+ this.value = value;
2942
+ this.onChange(value);
2943
+ this.onTouched();
2944
+ }
2945
+ get typeahead$() {
2946
+ return this.searchTerm$;
2947
+ }
2948
+ get showError() {
2949
+ if (!this.ngControl || !this.ngControl.control)
2950
+ return false;
2951
+ const control = this.ngControl.control;
2952
+ return control.invalid ? control.dirty || control.touched : false;
2953
+ }
2954
+ get errorMessage() {
2955
+ if (!this.ngControl?.errors)
2956
+ return '';
2957
+ const errorKey = Object.keys(this.ngControl.errors)[0];
2958
+ return 'Campo inválido';
2959
+ }
2960
+ writeValue(value) {
2961
+ this.value = value;
2962
+ }
2963
+ registerOnChange(fn) {
2964
+ this.onChange = fn;
2965
+ }
2966
+ registerOnTouched(fn) {
2967
+ this.onTouched = fn;
2968
+ }
2969
+ setDisabledState(isDisabled) {
2970
+ this.loading = isDisabled;
2971
+ }
2972
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: AsyncSelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2973
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.25", type: AsyncSelectComponent, isStandalone: true, selector: "async-select", inputs: { config: "config", items: "items", parentId: "parentId", label: "label", placeholder: "placeholder", name: "name", required: "required", multiple: "multiple", clearable: "clearable", searchable: "searchable", loading: "loading", virtualScroll: "virtualScroll", notFoundText: "notFoundText", bindLabel: "bindLabel", bindValue: "bindValue" }, providers: [
2974
+ {
2975
+ provide: NG_VALUE_ACCESSOR,
2976
+ useExisting: forwardRef(() => AsyncSelectComponent),
2977
+ multi: true,
2978
+ },
2979
+ ], usesOnChanges: true, ngImport: i0, template: "<div class=\"w-full\">\n @if (label) {\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n {{ label }}\n @if (required) {\n <span class=\"text-red-500\">*</span>\n }\n </label>\n }\n\n <ng-select\n [items]=\"displayItems\"\n [multiple]=\"multiple\"\n [searchable]=\"searchable\"\n [clearable]=\"clearable\"\n [placeholder]=\"placeholder\"\n [loading]=\"loading || loadingSignal()\"\n [virtualScroll]=\"virtualScroll\"\n [notFoundText]=\"notFoundText\"\n [bindLabel]=\"bindLabel\"\n [bindValue]=\"bindValue\"\n [ngModel]=\"value\"\n [typeahead]=\"typeahead$\"\n [closeOnSelect]=\"!multiple\"\n (ngModelChange)=\"onSelectChange($event)\"\n (blur)=\"onTouched()\"\n (search)=\"onSearch($event)\"\n />\n\n @if (showError) {\n <div class=\"text-red-500 text-xs mt-1\">\n {{ errorMessage }}\n </div>\n }\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: NgSelectModule }, { kind: "component", type: i2$1.NgSelectComponent, selector: "ng-select", inputs: ["ariaLabelDropdown", "ariaLabel", "markFirst", "placeholder", "fixedPlaceholder", "notFoundText", "typeToSearchText", "preventToggleOnRightClick", "addTagText", "loadingText", "clearAllText", "dropdownPosition", "appendTo", "outsideClickEvent", "loading", "closeOnSelect", "hideSelected", "selectOnTab", "openOnEnter", "maxSelectedItems", "groupBy", "groupValue", "bufferAmount", "virtualScroll", "selectableGroup", "tabFocusOnClearButton", "selectableGroupAsModel", "searchFn", "trackByFn", "clearOnBackspace", "labelForId", "inputAttrs", "tabIndex", "readonly", "searchWhileComposing", "minTermLength", "editableSearchTerm", "ngClass", "typeahead", "multiple", "addTag", "searchable", "clearable", "deselectOnClick", "clearSearchOnAdd", "compareWith", "keyDownFn", "bindLabel", "bindValue", "appearance", "isOpen", "items"], outputs: ["bindLabelChange", "bindValueChange", "appearanceChange", "isOpenChange", "itemsChange", "blur", "focus", "change", "open", "close", "search", "clear", "add", "remove", "scroll", "scrollToEnd"], exportAs: ["ngSelect"] }] });
2980
+ }
2981
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: AsyncSelectComponent, decorators: [{
2982
+ type: Component,
2983
+ args: [{ selector: 'async-select', standalone: true, imports: [CommonModule, FormsModule, NgSelectModule], providers: [
2984
+ {
2985
+ provide: NG_VALUE_ACCESSOR,
2986
+ useExisting: forwardRef(() => AsyncSelectComponent),
2987
+ multi: true,
2988
+ },
2989
+ ], template: "<div class=\"w-full\">\n @if (label) {\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n {{ label }}\n @if (required) {\n <span class=\"text-red-500\">*</span>\n }\n </label>\n }\n\n <ng-select\n [items]=\"displayItems\"\n [multiple]=\"multiple\"\n [searchable]=\"searchable\"\n [clearable]=\"clearable\"\n [placeholder]=\"placeholder\"\n [loading]=\"loading || loadingSignal()\"\n [virtualScroll]=\"virtualScroll\"\n [notFoundText]=\"notFoundText\"\n [bindLabel]=\"bindLabel\"\n [bindValue]=\"bindValue\"\n [ngModel]=\"value\"\n [typeahead]=\"typeahead$\"\n [closeOnSelect]=\"!multiple\"\n (ngModelChange)=\"onSelectChange($event)\"\n (blur)=\"onTouched()\"\n (search)=\"onSearch($event)\"\n />\n\n @if (showError) {\n <div class=\"text-red-500 text-xs mt-1\">\n {{ errorMessage }}\n </div>\n }\n</div>\n" }]
2990
+ }], ctorParameters: () => [], propDecorators: { config: [{
2991
+ type: Input
2992
+ }], items: [{
2993
+ type: Input
2994
+ }], parentId: [{
2995
+ type: Input
2996
+ }], label: [{
2997
+ type: Input
2998
+ }], placeholder: [{
2999
+ type: Input
3000
+ }], name: [{
3001
+ type: Input
3002
+ }], required: [{
3003
+ type: Input
3004
+ }], multiple: [{
3005
+ type: Input
3006
+ }], clearable: [{
3007
+ type: Input
3008
+ }], searchable: [{
3009
+ type: Input
3010
+ }], loading: [{
3011
+ type: Input
3012
+ }], virtualScroll: [{
3013
+ type: Input
3014
+ }], notFoundText: [{
3015
+ type: Input
3016
+ }], bindLabel: [{
3017
+ type: Input
3018
+ }], bindValue: [{
3019
+ type: Input
3020
+ }] } });
3021
+
3022
+ class ChangePasswordFormComponent {
3023
+ fb;
3024
+ changePasswordFormService;
3025
+ customerService;
3026
+ adminService;
3027
+ toastService;
3028
+ transloco;
3029
+ changePasswordForm;
3030
+ loading = signal(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
3031
+ constructor(fb, changePasswordFormService, customerService, adminService, toastService, transloco) {
3032
+ this.fb = fb;
3033
+ this.changePasswordFormService = changePasswordFormService;
3034
+ this.customerService = customerService;
3035
+ this.adminService = adminService;
3036
+ this.toastService = toastService;
3037
+ this.transloco = transloco;
3038
+ this.changePasswordForm = this.fb.group({
3039
+ password: ['', [Validators.required, Validators.minLength(6)]],
3040
+ confirm_password: ['', [Validators.required, Validators.minLength(6)]],
3041
+ }, {
3042
+ validators: MustMatchValidator('password', 'confirm_password'),
3043
+ });
3044
+ }
3045
+ get isOpen() {
3046
+ return this.changePasswordFormService.modalIsOpen;
3047
+ }
3048
+ get resourceId() {
3049
+ return this.changePasswordFormService.resourceId;
3050
+ }
3051
+ onCloseModal() {
3052
+ this.changePasswordForm.reset();
3053
+ this.changePasswordFormService.close();
3054
+ }
3055
+ onConfirmDelete() {
3056
+ this.loading.set(true);
3057
+ const service = this.changePasswordFormService.isAdminMode()
3058
+ ? this.adminService
3059
+ : this.customerService;
3060
+ const isAdmin = this.changePasswordFormService.isAdminMode();
3061
+ const successKey = isAdmin ? 'changePassword.adminSuccess' : 'changePassword.customerSuccess';
3062
+ const errorKey = isAdmin ? 'changePassword.adminError' : 'changePassword.customerError';
3063
+ service.updateOne(this.resourceId(), this.changePasswordForm.value).subscribe({
3064
+ next: () => {
3065
+ this.toastService.show(this.transloco.translate(successKey), 'success');
3066
+ this.changePasswordForm.reset();
3067
+ this.changePasswordFormService.close();
3068
+ this.loading.set(false);
3069
+ },
3070
+ error: (error) => {
3071
+ console.error('Error al actualizar contraseña:', error);
3072
+ this.toastService.show(this.transloco.translate(errorKey), 'error');
3073
+ this.loading.set(false);
3074
+ },
3075
+ });
3076
+ }
3077
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: ChangePasswordFormComponent, deps: [{ token: i1$1.FormBuilder }, { token: ChangePasswordFormService }, { token: CustomerService }, { token: AdminService }, { token: ToastService }, { token: i2.TranslocoService }], target: i0.ɵɵFactoryTarget.Component });
3078
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.25", type: ChangePasswordFormComponent, isStandalone: true, selector: "change-password-form", providers: [AdminService, CustomerService], ngImport: i0, template: "@if (isOpen()) {\n <app-modal\n [title]=\"'changePassword.title' | transloco\"\n [isOpen]=\"isOpen\"\n (closeModal)=\"onCloseModal()\"\n >\n <form\n [formGroup]=\"changePasswordForm\"\n method=\"POST\"\n class=\"flex flex-col gap-4\"\n (ngSubmit)=\"onConfirmDelete()\"\n >\n <form-input\n [label]=\"'changePassword.newPasswordLabel' | transloco\"\n [placeholder]=\"'changePassword.newPasswordPlaceholder' | transloco\"\n name=\"password\"\n type=\"password\"\n class=\"flex-1\"\n [required]=\"true\"\n [autocomplete]=\"false\"\n formControlName=\"password\"\n />\n\n <form-input\n [label]=\"'changePassword.confirmPasswordLabel' | transloco\"\n [placeholder]=\"'changePassword.confirmPasswordPlaceholder' | transloco\"\n name=\"confirm_password\"\n type=\"password\"\n class=\"flex-1\"\n [required]=\"true\"\n [autocomplete]=\"false\"\n formControlName=\"confirm_password\"\n />\n\n <div class=\"flex space-x-3\">\n <app-button\n variant=\"terciary\"\n [text]=\"'changePassword.cancel' | transloco\"\n (click)=\"onCloseModal()\"\n size=\"sm\"\n />\n\n <app-button\n [disabled]=\"loading() || changePasswordForm.invalid || changePasswordForm.pristine\"\n [loading]=\"loading()\"\n type=\"submit\"\n variant=\"primary\"\n [text]=\"'changePassword.save' | transloco\"\n [loadingText]=\"'changePassword.saving' | transloco\"\n size=\"sm\"\n />\n </div>\n </form>\n </app-modal>\n}\n", styles: [".delete-confirmation-modal{animation:fadeIn .3s ease-out}.delete-confirmation-content{animation:slideUp .3s ease-out}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}@keyframes slideUp{0%{transform:translateY(20px);opacity:0}to{transform:translateY(0);opacity:1}}.confirmation-input{transition:all .2s ease}.confirmation-input:focus{box-shadow:0 0 0 3px #ef44441a}.confirmation-input.invalid{border-color:#dc2626}.confirmation-input.invalid:focus{border-color:#dc2626;box-shadow:0 0 0 3px #dc26261a}.delete-button{transition:all .2s ease}.delete-button:disabled{opacity:.5;cursor:not-allowed}.delete-button:not(:disabled):hover{transform:translateY(-1px);box-shadow:0 4px 12px #dc26264d}.warning-message{border-left:4px solid #f59e0b;background:linear-gradient(135deg,#fef3c7,#fde68a)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: TranslocoModule }, { kind: "component", type: AppButtonComponent, selector: "app-button", inputs: ["disabled", "loading", "type", "variant", "text", "size", "loadingText", "icon"], outputs: ["clicked"] }, { kind: "component", type: FormInputComponent, selector: "form-input", inputs: ["label", "type", "name", "id", "placeholder", "required", "readonly", "minlength", "min", "step", "pattern", "fieldGroupClass", "autocomplete"] }, { kind: "component", type: AppModalComponent, selector: "app-modal", inputs: ["title", "disableClose", "isOpen", "size"], outputs: ["closeModal"] }, { kind: "pipe", type: i2.TranslocoPipe, name: "transloco" }], encapsulation: i0.ViewEncapsulation.None });
3079
+ }
3080
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: ChangePasswordFormComponent, decorators: [{
3081
+ type: Component,
3082
+ args: [{ selector: 'change-password-form', standalone: true, imports: [
3083
+ CommonModule,
3084
+ ReactiveFormsModule,
3085
+ TranslocoModule,
3086
+ AppButtonComponent,
3087
+ FormInputComponent,
3088
+ AppModalComponent,
3089
+ ], providers: [AdminService, CustomerService], encapsulation: ViewEncapsulation.None, template: "@if (isOpen()) {\n <app-modal\n [title]=\"'changePassword.title' | transloco\"\n [isOpen]=\"isOpen\"\n (closeModal)=\"onCloseModal()\"\n >\n <form\n [formGroup]=\"changePasswordForm\"\n method=\"POST\"\n class=\"flex flex-col gap-4\"\n (ngSubmit)=\"onConfirmDelete()\"\n >\n <form-input\n [label]=\"'changePassword.newPasswordLabel' | transloco\"\n [placeholder]=\"'changePassword.newPasswordPlaceholder' | transloco\"\n name=\"password\"\n type=\"password\"\n class=\"flex-1\"\n [required]=\"true\"\n [autocomplete]=\"false\"\n formControlName=\"password\"\n />\n\n <form-input\n [label]=\"'changePassword.confirmPasswordLabel' | transloco\"\n [placeholder]=\"'changePassword.confirmPasswordPlaceholder' | transloco\"\n name=\"confirm_password\"\n type=\"password\"\n class=\"flex-1\"\n [required]=\"true\"\n [autocomplete]=\"false\"\n formControlName=\"confirm_password\"\n />\n\n <div class=\"flex space-x-3\">\n <app-button\n variant=\"terciary\"\n [text]=\"'changePassword.cancel' | transloco\"\n (click)=\"onCloseModal()\"\n size=\"sm\"\n />\n\n <app-button\n [disabled]=\"loading() || changePasswordForm.invalid || changePasswordForm.pristine\"\n [loading]=\"loading()\"\n type=\"submit\"\n variant=\"primary\"\n [text]=\"'changePassword.save' | transloco\"\n [loadingText]=\"'changePassword.saving' | transloco\"\n size=\"sm\"\n />\n </div>\n </form>\n </app-modal>\n}\n", styles: [".delete-confirmation-modal{animation:fadeIn .3s ease-out}.delete-confirmation-content{animation:slideUp .3s ease-out}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}@keyframes slideUp{0%{transform:translateY(20px);opacity:0}to{transform:translateY(0);opacity:1}}.confirmation-input{transition:all .2s ease}.confirmation-input:focus{box-shadow:0 0 0 3px #ef44441a}.confirmation-input.invalid{border-color:#dc2626}.confirmation-input.invalid:focus{border-color:#dc2626;box-shadow:0 0 0 3px #dc26261a}.delete-button{transition:all .2s ease}.delete-button:disabled{opacity:.5;cursor:not-allowed}.delete-button:not(:disabled):hover{transform:translateY(-1px);box-shadow:0 4px 12px #dc26264d}.warning-message{border-left:4px solid #f59e0b;background:linear-gradient(135deg,#fef3c7,#fde68a)}\n"] }]
3090
+ }], ctorParameters: () => [{ type: i1$1.FormBuilder }, { type: ChangePasswordFormService }, { type: CustomerService }, { type: AdminService }, { type: ToastService }, { type: i2.TranslocoService }] });
3091
+
3092
+ class AdminSelectComponent {
3093
+ platformId;
3094
+ adminService;
3095
+ label = 'Equipo de trabajo';
3096
+ placeholder = 'Selecciona un equipo de trabajo';
3097
+ name = 'admin_id';
3098
+ required = false;
3099
+ readonly = false;
3100
+ showError = true;
3101
+ customClass = '';
3102
+ control = null;
3103
+ adminChange = new EventEmitter();
3104
+ admins = signal([], ...(ngDevMode ? [{ debugName: "admins" }] : []));
3105
+ loading = signal(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
3106
+ destroy$ = new Subject();
3107
+ // ControlValueAccessor properties
3108
+ value = null;
3109
+ onChange = () => { };
3110
+ onTouched = () => { };
3111
+ constructor(platformId, adminService) {
3112
+ this.platformId = platformId;
3113
+ this.adminService = adminService;
3114
+ }
3115
+ ngOnInit() {
3116
+ if (isPlatformBrowser(this.platformId)) {
3117
+ this.loadAdmins();
3118
+ }
3119
+ }
3120
+ // Update the formControl getter to handle the AbstractControl
3121
+ get formControl() {
3122
+ return this.control;
3123
+ }
3124
+ ngOnDestroy() {
3125
+ this.destroy$.next();
3126
+ this.destroy$.complete();
3127
+ }
3128
+ loadAdmins() {
3129
+ this.loading.set(true);
3130
+ this.adminService
3131
+ .fetchAdmins()
3132
+ .pipe(takeUntil(this.destroy$))
3133
+ .subscribe({
3134
+ next: ({ data: { admins } }) => {
3135
+ this.admins.set(admins?.map((admin) => ({
3136
+ value: admin.id,
3137
+ label: `${admin.first_name} ${admin.last_name} - ${admin.email}`,
3138
+ })) || []);
3139
+ this.loading.set(false);
3140
+ },
3141
+ error: () => {
3142
+ this.admins.set([]);
3143
+ this.loading.set(false);
3144
+ },
3145
+ });
3146
+ }
3147
+ // In admin-select.component.ts
3148
+ onAdminSelected(event) {
3149
+ const select = event.target;
3150
+ const value = select.value ? Number(select.value) : null;
3151
+ // Update the local value
3152
+ this.value = value;
3153
+ // Update the form control if it exists
3154
+ if (this.control) {
3155
+ this.control.setValue(value);
3156
+ this.control.markAsTouched();
3157
+ }
3158
+ // Emit the change event
3159
+ this.adminChange.emit(value);
3160
+ }
3161
+ // ControlValueAccessor methods
3162
+ writeValue(value) {
3163
+ this.value = value;
3164
+ }
3165
+ registerOnChange(fn) {
3166
+ this.onChange = fn;
3167
+ }
3168
+ registerOnTouched(fn) {
3169
+ this.onTouched = fn;
3170
+ }
3171
+ // Validator method
3172
+ validate(control) {
3173
+ if (this.required && !control.value) {
3174
+ return { required: true };
3175
+ }
3176
+ return null;
3177
+ }
3178
+ // Helper method to check if control is invalid
3179
+ get isInvalid() {
3180
+ return false;
3181
+ }
3182
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: AdminSelectComponent, deps: [{ token: PLATFORM_ID }, { token: AdminService }], target: i0.ɵɵFactoryTarget.Component });
3183
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.25", type: AdminSelectComponent, isStandalone: true, selector: "admin-select", inputs: { label: "label", placeholder: "placeholder", name: "name", required: "required", readonly: "readonly", showError: "showError", customClass: "customClass", control: "control" }, outputs: { adminChange: "adminChange" }, ngImport: i0, template: "<form-select\n [label]=\"label\"\n [placeholder]=\"placeholder\"\n [name]=\"name || 'country_id'\"\n [class]=\"customClass\"\n [options]=\"admins()\"\n [required]=\"required\"\n [readonly]=\"readonly\"\n [formControl]=\"formControl\"\n (change)=\"onAdminSelected($event)\"\n/>\n", styles: [":host{display:block;width:100%}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: FormSelectComponent, selector: "form-select", inputs: ["label", "name", "id", "placeholder", "required", "disabled", "readonly", "options", "fieldGroupClass", "showDefaultOption", "defaultOptionLabel"] }] });
3184
+ }
3185
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: AdminSelectComponent, decorators: [{
3186
+ type: Component,
3187
+ args: [{ selector: 'admin-select', standalone: true, imports: [CommonModule, ReactiveFormsModule, FormSelectComponent], template: "<form-select\n [label]=\"label\"\n [placeholder]=\"placeholder\"\n [name]=\"name || 'country_id'\"\n [class]=\"customClass\"\n [options]=\"admins()\"\n [required]=\"required\"\n [readonly]=\"readonly\"\n [formControl]=\"formControl\"\n (change)=\"onAdminSelected($event)\"\n/>\n", styles: [":host{display:block;width:100%}\n"] }]
3188
+ }], ctorParameters: () => [{ type: undefined, decorators: [{
3189
+ type: Inject,
3190
+ args: [PLATFORM_ID]
3191
+ }] }, { type: AdminService }], propDecorators: { label: [{
3192
+ type: Input
3193
+ }], placeholder: [{
3194
+ type: Input
3195
+ }], name: [{
3196
+ type: Input
3197
+ }], required: [{
3198
+ type: Input
3199
+ }], readonly: [{
3200
+ type: Input
3201
+ }], showError: [{
3202
+ type: Input
3203
+ }], customClass: [{
3204
+ type: Input
3205
+ }], control: [{
3206
+ type: Input
3207
+ }], adminChange: [{
3208
+ type: Output
3209
+ }] } });
3210
+
3211
+ class CitySelectComponent {
3212
+ citiesService;
3213
+ label = 'Ciudad';
3214
+ name = 'city_id';
3215
+ placeholder = 'Selecciona una ciudad';
3216
+ required = false;
3217
+ disabled = false;
3218
+ readonly = false;
3219
+ stateId = null;
3220
+ showError = true;
3221
+ customClass = '';
3222
+ control = null;
3223
+ cityChange = new EventEmitter();
3224
+ cities = signal([], ...(ngDevMode ? [{ debugName: "cities" }] : []));
3225
+ loading = false;
3226
+ destroy$ = new Subject();
3227
+ // ControlValueAccessor properties
3228
+ value = null;
3229
+ onChange = () => { };
3230
+ onTouched = () => { };
3231
+ constructor(citiesService) {
3232
+ this.citiesService = citiesService;
3233
+ }
3234
+ // Update the formControl getter to handle the AbstractControl
3235
+ get formControl() {
3236
+ return this.control;
3237
+ }
3238
+ ngOnInit() {
3239
+ this.loadCities();
3240
+ }
3241
+ ngOnChanges(changes) {
3242
+ if (changes['stateId'] && !changes['stateId'].firstChange) {
3243
+ this.value = null;
3244
+ this.onChange(null);
3245
+ this.cityChange.emit(null);
3246
+ if (this.stateId) {
3247
+ this.loadCities();
3248
+ }
3249
+ else {
3250
+ this.cities.set([]);
3251
+ }
3252
+ }
3253
+ }
3254
+ ngOnDestroy() {
3255
+ this.destroy$.next();
3256
+ this.destroy$.complete();
3257
+ }
3258
+ loadCities() {
3259
+ this.loading = true;
3260
+ this.citiesService
3261
+ .fetchCities({ stateId: this.stateId ?? undefined })
3262
+ .pipe(takeUntil(this.destroy$))
3263
+ .subscribe({
3264
+ next: (response) => {
3265
+ this.cities.set(formatCitiesResponseToSelect(response));
3266
+ this.loading = false;
3267
+ },
3268
+ error: () => {
3269
+ this.cities.set([]);
3270
+ this.loading = false;
3271
+ },
3272
+ });
3273
+ }
3274
+ onCitySelected(event) {
3275
+ const select = event.target;
3276
+ const value = select.value ? Number(select.value) : null;
3277
+ this.value = value;
3278
+ this.onChange(value);
3279
+ this.onTouched();
3280
+ this.cityChange.emit(value);
3281
+ }
3282
+ // ControlValueAccessor methods
3283
+ writeValue(value) {
3284
+ this.value = value;
3285
+ }
3286
+ registerOnChange(fn) {
3287
+ this.onChange = fn;
3288
+ }
3289
+ registerOnTouched(fn) {
3290
+ this.onTouched = fn;
3291
+ }
3292
+ setDisabledState(isDisabled) {
3293
+ this.disabled = isDisabled;
3294
+ }
3295
+ // Validator method
3296
+ validate(control) {
3297
+ if (this.required && !control.value) {
3298
+ return { required: true };
3299
+ }
3300
+ return null;
3301
+ }
3302
+ get isInvalid() {
3303
+ return false;
3304
+ }
3305
+ get isDisabled() {
3306
+ return this.disabled || this.readonly || !this.stateId || this.loading;
3307
+ }
3308
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: CitySelectComponent, deps: [{ token: CitiesService }], target: i0.ɵɵFactoryTarget.Component });
3309
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.25", type: CitySelectComponent, isStandalone: true, selector: "city-select", inputs: { label: "label", name: "name", placeholder: "placeholder", required: "required", disabled: "disabled", readonly: "readonly", stateId: "stateId", showError: "showError", customClass: "customClass", control: "control" }, outputs: { cityChange: "cityChange" }, providers: [
3310
+ {
3311
+ provide: NG_VALUE_ACCESSOR,
3312
+ useExisting: forwardRef(() => CitySelectComponent),
3313
+ multi: true,
3314
+ },
3315
+ {
3316
+ provide: NG_VALIDATORS,
3317
+ useExisting: forwardRef(() => CitySelectComponent),
3318
+ multi: true,
3319
+ },
3320
+ ], usesOnChanges: true, ngImport: i0, template: "<form-select\n [label]=\"label\"\n [placeholder]=\"placeholder\"\n [name]=\"name\"\n [class]=\"customClass\"\n [required]=\"required\"\n [options]=\"cities()\"\n [readonly]=\"readonly\"\n [formControl]=\"formControl\"\n (change)=\"onCitySelected($event)\"\n/>\n", styles: [":host{display:block;width:100%}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: FormSelectComponent, selector: "form-select", inputs: ["label", "name", "id", "placeholder", "required", "disabled", "readonly", "options", "fieldGroupClass", "showDefaultOption", "defaultOptionLabel"] }], encapsulation: i0.ViewEncapsulation.None });
3321
+ }
3322
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: CitySelectComponent, decorators: [{
3323
+ type: Component,
3324
+ args: [{ selector: 'city-select', standalone: true, imports: [CommonModule, ReactiveFormsModule, FormSelectComponent], encapsulation: ViewEncapsulation.None, providers: [
3325
+ {
3326
+ provide: NG_VALUE_ACCESSOR,
3327
+ useExisting: forwardRef(() => CitySelectComponent),
3328
+ multi: true,
3329
+ },
3330
+ {
3331
+ provide: NG_VALIDATORS,
3332
+ useExisting: forwardRef(() => CitySelectComponent),
3333
+ multi: true,
3334
+ },
3335
+ ], template: "<form-select\n [label]=\"label\"\n [placeholder]=\"placeholder\"\n [name]=\"name\"\n [class]=\"customClass\"\n [required]=\"required\"\n [options]=\"cities()\"\n [readonly]=\"readonly\"\n [formControl]=\"formControl\"\n (change)=\"onCitySelected($event)\"\n/>\n", styles: [":host{display:block;width:100%}\n"] }]
3336
+ }], ctorParameters: () => [{ type: CitiesService }], propDecorators: { label: [{
3337
+ type: Input
3338
+ }], name: [{
3339
+ type: Input
3340
+ }], placeholder: [{
3341
+ type: Input
3342
+ }], required: [{
3343
+ type: Input
3344
+ }], disabled: [{
3345
+ type: Input
3346
+ }], readonly: [{
3347
+ type: Input
3348
+ }], stateId: [{
3349
+ type: Input
3350
+ }], showError: [{
3351
+ type: Input
3352
+ }], customClass: [{
3353
+ type: Input
3354
+ }], control: [{
3355
+ type: Input
3356
+ }], cityChange: [{
3357
+ type: Output
3358
+ }] } });
3359
+
3360
+ class CountrySelectComponent {
3361
+ platformId;
3362
+ countryService;
3363
+ label = 'País';
3364
+ placeholder = 'Selecciona un país';
3365
+ name = 'country_id';
3366
+ required = false;
3367
+ readonly = false;
3368
+ showError = true;
3369
+ customClass = '';
3370
+ control = null;
3371
+ countryChange = new EventEmitter();
3372
+ countries = signal([], ...(ngDevMode ? [{ debugName: "countries" }] : []));
3373
+ loading = signal(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
3374
+ destroy$ = new Subject();
3375
+ // ControlValueAccessor properties
3376
+ value = null;
3377
+ onChange = () => { };
3378
+ onTouched = () => { };
3379
+ constructor(platformId, countryService) {
3380
+ this.platformId = platformId;
3381
+ this.countryService = countryService;
3382
+ }
3383
+ ngOnInit() {
3384
+ if (isPlatformBrowser(this.platformId)) {
3385
+ this.loadCountries();
3386
+ }
3387
+ }
3388
+ // Update the formControl getter to handle the AbstractControl
3389
+ get formControl() {
3390
+ return this.control;
3391
+ }
3392
+ ngOnDestroy() {
3393
+ this.destroy$.next();
3394
+ this.destroy$.complete();
3395
+ }
3396
+ loadCountries() {
3397
+ this.loading.set(true);
3398
+ this.countryService
3399
+ .fetchCountries()
3400
+ .pipe(takeUntil(this.destroy$))
3401
+ .subscribe({
3402
+ next: ({ data: { countries } }) => {
3403
+ this.countries.set(countries?.map((country) => ({
3404
+ value: country.id,
3405
+ label: country.name,
3406
+ })) || []);
3407
+ this.loading.set(false);
3408
+ },
3409
+ error: () => {
3410
+ this.countries.set([]);
3411
+ this.loading.set(false);
3412
+ },
3413
+ });
3414
+ }
3415
+ // In country-select.component.ts
3416
+ onCountrySelected(event) {
3417
+ const select = event.target;
3418
+ const value = select.value ? Number(select.value) : null;
3419
+ // Update the local value
3420
+ this.value = value;
3421
+ // Update the form control if it exists
3422
+ if (this.control) {
3423
+ this.control.setValue(value);
3424
+ this.control.markAsTouched();
3425
+ }
3426
+ // Emit the change event
3427
+ this.countryChange.emit(value);
3428
+ }
3429
+ // ControlValueAccessor methods
3430
+ writeValue(value) {
3431
+ this.value = value;
3432
+ }
3433
+ registerOnChange(fn) {
3434
+ this.onChange = fn;
3435
+ }
3436
+ registerOnTouched(fn) {
3437
+ this.onTouched = fn;
3438
+ }
3439
+ // Validator method
3440
+ validate(control) {
3441
+ if (this.required && !control.value) {
3442
+ return { required: true };
3443
+ }
3444
+ return null;
3445
+ }
3446
+ // Helper method to check if control is invalid
3447
+ get isInvalid() {
3448
+ return false;
3449
+ }
3450
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: CountrySelectComponent, deps: [{ token: PLATFORM_ID }, { token: CountryService }], target: i0.ɵɵFactoryTarget.Component });
3451
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.25", type: CountrySelectComponent, isStandalone: true, selector: "country-select", inputs: { label: "label", placeholder: "placeholder", name: "name", required: "required", readonly: "readonly", showError: "showError", customClass: "customClass", control: "control" }, outputs: { countryChange: "countryChange" }, ngImport: i0, template: "<form-select\n [label]=\"label\"\n [placeholder]=\"placeholder\"\n [name]=\"name || 'country_id'\"\n [class]=\"customClass\"\n [options]=\"countries()\"\n [required]=\"required\"\n [readonly]=\"readonly\"\n [formControl]=\"formControl\"\n (change)=\"onCountrySelected($event)\"\n></form-select>\n", styles: [":host{display:block;width:100%}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: FormSelectComponent, selector: "form-select", inputs: ["label", "name", "id", "placeholder", "required", "disabled", "readonly", "options", "fieldGroupClass", "showDefaultOption", "defaultOptionLabel"] }] });
3452
+ }
3453
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: CountrySelectComponent, decorators: [{
3454
+ type: Component,
3455
+ args: [{ selector: 'country-select', standalone: true, imports: [CommonModule, ReactiveFormsModule, FormSelectComponent], template: "<form-select\n [label]=\"label\"\n [placeholder]=\"placeholder\"\n [name]=\"name || 'country_id'\"\n [class]=\"customClass\"\n [options]=\"countries()\"\n [required]=\"required\"\n [readonly]=\"readonly\"\n [formControl]=\"formControl\"\n (change)=\"onCountrySelected($event)\"\n></form-select>\n", styles: [":host{display:block;width:100%}\n"] }]
3456
+ }], ctorParameters: () => [{ type: undefined, decorators: [{
3457
+ type: Inject,
3458
+ args: [PLATFORM_ID]
3459
+ }] }, { type: CountryService }], propDecorators: { label: [{
3460
+ type: Input
3461
+ }], placeholder: [{
3462
+ type: Input
3463
+ }], name: [{
3464
+ type: Input
3465
+ }], required: [{
3466
+ type: Input
3467
+ }], readonly: [{
3468
+ type: Input
3469
+ }], showError: [{
3470
+ type: Input
3471
+ }], customClass: [{
3472
+ type: Input
3473
+ }], control: [{
3474
+ type: Input
3475
+ }], countryChange: [{
3476
+ type: Output
3477
+ }] } });
3478
+
3479
+ class StateSelectComponent {
3480
+ statesService;
3481
+ label = 'Departamento';
3482
+ name = 'state_id';
3483
+ placeholder = 'Selecciona un departamento';
3484
+ required = false;
3485
+ readonly = false;
3486
+ countryId = null;
3487
+ showError = true;
3488
+ customClass = '';
3489
+ control = null;
3490
+ stateChange = new EventEmitter();
3491
+ states = signal([], ...(ngDevMode ? [{ debugName: "states" }] : []));
3492
+ loading = false;
3493
+ destroy$ = new Subject();
3494
+ // ControlValueAccessor properties
3495
+ value = null;
3496
+ onChange = () => { };
3497
+ onTouched = () => { };
3498
+ constructor(statesService) {
3499
+ this.statesService = statesService;
3500
+ }
3501
+ ngOnInit() {
3502
+ this.loadStates();
3503
+ }
3504
+ // Update the formControl getter to handle the AbstractControl
3505
+ get formControl() {
3506
+ return this.control;
3507
+ }
3508
+ ngOnChanges(changes) {
3509
+ if (changes['countryId'] && !changes['countryId'].firstChange) {
3510
+ this.value = null;
3511
+ this.onChange(null);
3512
+ this.stateChange.emit(null);
3513
+ if (this.countryId) {
3514
+ this.loadStates();
3515
+ }
3516
+ else {
3517
+ this.states.set([]);
3518
+ }
3519
+ }
3520
+ }
3521
+ ngOnDestroy() {
3522
+ this.destroy$.next();
3523
+ this.destroy$.complete();
3524
+ }
3525
+ loadStates() {
3526
+ this.loading = true;
3527
+ this.statesService
3528
+ .fetchStates(1, undefined, this.countryId)
3529
+ .pipe(takeUntil(this.destroy$))
3530
+ .subscribe({
3531
+ next: ({ data: { states } }) => {
3532
+ this.states.set(states?.map(({ id, name }) => ({ value: id, label: name })) || []);
3533
+ this.loading = false;
3534
+ },
3535
+ error: () => {
3536
+ this.states.set([]);
3537
+ this.loading = false;
3538
+ },
3539
+ });
3540
+ }
3541
+ onStateSelected(event) {
3542
+ const select = event.target;
3543
+ const value = select.value ? Number(select.value) : null;
3544
+ this.value = value;
3545
+ this.onChange(value);
3546
+ this.onTouched();
3547
+ this.stateChange.emit(value);
3548
+ }
3549
+ writeValue(value) {
3550
+ this.value = value;
3551
+ }
3552
+ registerOnChange(fn) {
3553
+ this.onChange = fn;
3554
+ }
3555
+ registerOnTouched(fn) {
3556
+ this.onTouched = fn;
3557
+ }
3558
+ validate(control) {
3559
+ if (this.required && !control.value) {
3560
+ return { required: true };
3561
+ }
3562
+ return null;
3563
+ }
3564
+ get isInvalid() {
3565
+ return false;
3566
+ }
3567
+ get isDisabled() {
3568
+ return this.readonly || !this.countryId || this.loading;
3569
+ }
3570
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: StateSelectComponent, deps: [{ token: StatesService }], target: i0.ɵɵFactoryTarget.Component });
3571
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.25", type: StateSelectComponent, isStandalone: true, selector: "state-select", inputs: { label: "label", name: "name", placeholder: "placeholder", required: "required", readonly: "readonly", countryId: "countryId", showError: "showError", customClass: "customClass", control: "control" }, outputs: { stateChange: "stateChange" }, providers: [
3572
+ {
3573
+ provide: NG_VALUE_ACCESSOR,
3574
+ useExisting: forwardRef(() => StateSelectComponent),
3575
+ multi: true,
3576
+ },
3577
+ {
3578
+ provide: NG_VALIDATORS,
3579
+ useExisting: forwardRef(() => StateSelectComponent),
3580
+ multi: true,
3581
+ },
3582
+ ], usesOnChanges: true, ngImport: i0, template: "<form-select\n [label]=\"label\"\n [placeholder]=\"placeholder\"\n [name]=\"name || 'state_id'\"\n [class]=\"customClass\"\n [options]=\"states()\"\n [required]=\"required\"\n [readonly]=\"readonly\"\n [formControl]=\"formControl\"\n (change)=\"onStateSelected($event)\"\n></form-select>\n", styles: [":host{display:block;width:100%}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: FormSelectComponent, selector: "form-select", inputs: ["label", "name", "id", "placeholder", "required", "disabled", "readonly", "options", "fieldGroupClass", "showDefaultOption", "defaultOptionLabel"] }], encapsulation: i0.ViewEncapsulation.None });
3583
+ }
3584
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: StateSelectComponent, decorators: [{
3585
+ type: Component,
3586
+ args: [{ selector: 'state-select', standalone: true, imports: [CommonModule, ReactiveFormsModule, FormSelectComponent], encapsulation: ViewEncapsulation.None, providers: [
3587
+ {
3588
+ provide: NG_VALUE_ACCESSOR,
3589
+ useExisting: forwardRef(() => StateSelectComponent),
3590
+ multi: true,
3591
+ },
3592
+ {
3593
+ provide: NG_VALIDATORS,
3594
+ useExisting: forwardRef(() => StateSelectComponent),
3595
+ multi: true,
3596
+ },
3597
+ ], template: "<form-select\n [label]=\"label\"\n [placeholder]=\"placeholder\"\n [name]=\"name || 'state_id'\"\n [class]=\"customClass\"\n [options]=\"states()\"\n [required]=\"required\"\n [readonly]=\"readonly\"\n [formControl]=\"formControl\"\n (change)=\"onStateSelected($event)\"\n></form-select>\n", styles: [":host{display:block;width:100%}\n"] }]
3598
+ }], ctorParameters: () => [{ type: StatesService }], propDecorators: { label: [{
3599
+ type: Input
3600
+ }], name: [{
3601
+ type: Input
3602
+ }], placeholder: [{
3603
+ type: Input
3604
+ }], required: [{
3605
+ type: Input
3606
+ }], readonly: [{
3607
+ type: Input
3608
+ }], countryId: [{
3609
+ type: Input
3610
+ }], showError: [{
3611
+ type: Input
3612
+ }], customClass: [{
3613
+ type: Input
3614
+ }], control: [{
3615
+ type: Input
3616
+ }], stateChange: [{
3617
+ type: Output
3618
+ }] } });
3619
+
3620
+ class CustomerSelectComponent {
3621
+ customerService;
3622
+ label = 'Cliente';
3623
+ placeholder = 'Selecciona un cliente';
3624
+ name = 'customer_id';
3625
+ required = false;
3626
+ readonly = false;
3627
+ multiple = false;
3628
+ customerChange = new EventEmitter();
3629
+ value = null;
3630
+ onChange = () => { };
3631
+ onTouched = () => { };
3632
+ config = {
3633
+ load: (params) => this.customerService.fetchCustomers(1, params?.search || '', 50),
3634
+ map: (res) => res.data.customers?.map((customer) => ({
3635
+ value: customer.id,
3636
+ label: `${getCustomerFullname(customer)} - ${customer.email}`.trim(),
3637
+ })) || [],
3638
+ };
3639
+ constructor(customerService) {
3640
+ this.customerService = customerService;
3641
+ }
3642
+ onInternalChange(value) {
3643
+ this.value = value;
3644
+ this.onChange(value);
3645
+ this.onTouched();
3646
+ this.customerChange.emit(value);
3647
+ }
3648
+ writeValue(value) {
3649
+ this.value = value;
3650
+ }
3651
+ registerOnChange(fn) {
3652
+ this.onChange = fn;
3653
+ }
3654
+ registerOnTouched(fn) {
3655
+ this.onTouched = fn;
3656
+ }
3657
+ validate(control) {
3658
+ if (this.required && !control.value) {
3659
+ return { required: true };
3660
+ }
3661
+ return null;
3662
+ }
3663
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: CustomerSelectComponent, deps: [{ token: CustomerService }], target: i0.ɵɵFactoryTarget.Component });
3664
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.25", type: CustomerSelectComponent, isStandalone: true, selector: "customer-select", inputs: { label: "label", placeholder: "placeholder", name: "name", required: "required", readonly: "readonly", multiple: "multiple" }, outputs: { customerChange: "customerChange" }, providers: [
3665
+ {
3666
+ provide: NG_VALUE_ACCESSOR,
3667
+ useExisting: forwardRef(() => CustomerSelectComponent),
3668
+ multi: true,
3669
+ },
3670
+ {
3671
+ provide: NG_VALIDATORS,
3672
+ useExisting: forwardRef(() => CustomerSelectComponent),
3673
+ multi: true,
3674
+ },
3675
+ ], ngImport: i0, template: "<async-select\n [config]=\"config\"\n [label]=\"label\"\n [placeholder]=\"placeholder\"\n [name]=\"name || 'customer_id'\"\n [required]=\"required\"\n [multiple]=\"multiple\"\n [clearable]=\"true\"\n bindLabel=\"label\"\n bindValue=\"value\"\n [ngModel]=\"value\"\n (ngModelChange)=\"onInternalChange($event)\"\n/>\n", dependencies: [{ kind: "component", type: AsyncSelectComponent, selector: "async-select", inputs: ["config", "items", "parentId", "label", "placeholder", "name", "required", "multiple", "clearable", "searchable", "loading", "virtualScroll", "notFoundText", "bindLabel", "bindValue"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] });
3676
+ }
3677
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: CustomerSelectComponent, decorators: [{
3678
+ type: Component,
3679
+ args: [{ selector: 'customer-select', standalone: true, imports: [AsyncSelectComponent, FormsModule], providers: [
3680
+ {
3681
+ provide: NG_VALUE_ACCESSOR,
3682
+ useExisting: forwardRef(() => CustomerSelectComponent),
3683
+ multi: true,
3684
+ },
3685
+ {
3686
+ provide: NG_VALIDATORS,
3687
+ useExisting: forwardRef(() => CustomerSelectComponent),
3688
+ multi: true,
3689
+ },
3690
+ ], template: "<async-select\n [config]=\"config\"\n [label]=\"label\"\n [placeholder]=\"placeholder\"\n [name]=\"name || 'customer_id'\"\n [required]=\"required\"\n [multiple]=\"multiple\"\n [clearable]=\"true\"\n bindLabel=\"label\"\n bindValue=\"value\"\n [ngModel]=\"value\"\n (ngModelChange)=\"onInternalChange($event)\"\n/>\n" }]
3691
+ }], ctorParameters: () => [{ type: CustomerService }], propDecorators: { label: [{
3692
+ type: Input
3693
+ }], placeholder: [{
3694
+ type: Input
3695
+ }], name: [{
3696
+ type: Input
3697
+ }], required: [{
3698
+ type: Input
3699
+ }], readonly: [{
3700
+ type: Input
3701
+ }], multiple: [{
3702
+ type: Input
3703
+ }], customerChange: [{
3704
+ type: Output
3705
+ }] } });
3706
+
3707
+ class PerformanceSelectComponent {
3708
+ platformId;
3709
+ performanceService;
3710
+ label = 'Función';
3711
+ placeholder = 'Selecciona una función';
3712
+ name = 'performance_id';
3713
+ required = false;
3714
+ readonly = false;
3715
+ showError = true;
3716
+ customClass = '';
3717
+ control = null;
3718
+ performanceChange = new EventEmitter();
3719
+ performances = signal([], ...(ngDevMode ? [{ debugName: "performances" }] : []));
3720
+ loading = signal(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
3721
+ searchTerm = '';
3722
+ searchSubject = new Subject();
3723
+ destroy$ = new Subject();
3724
+ value = null;
3725
+ onChange = () => { };
3726
+ onTouched = () => { };
3727
+ constructor(platformId, performanceService) {
3728
+ this.platformId = platformId;
3729
+ this.performanceService = performanceService;
3730
+ }
3731
+ ngOnInit() {
3732
+ if (isPlatformBrowser(this.platformId)) {
3733
+ this.performanceService.loadPerformances({ search: this.searchTerm });
3734
+ this.performanceService.performances$
3735
+ .pipe(takeUntil(this.destroy$))
3736
+ .subscribe((performances) => {
3737
+ this.performances.set(performances?.map((p) => ({
3738
+ value: p.id,
3739
+ label: `${p.show?.title || `Show #${p.show_id}`} - ${new Date(p.start_time).toLocaleDateString()}`,
3740
+ })) || []);
3741
+ this.loading.set(false);
3742
+ });
3743
+ this.searchSubject
3744
+ .pipe(debounceTime(400), distinctUntilChanged(), takeUntil(this.destroy$))
3745
+ .subscribe((search) => {
3746
+ this.searchTerm = search;
3747
+ this.performanceService.loadPerformances({ search: this.searchTerm });
3748
+ });
3749
+ }
3750
+ }
3751
+ get formControl() {
3752
+ return this.control;
3753
+ }
3754
+ ngOnDestroy() {
3755
+ this.destroy$.next();
3756
+ this.destroy$.complete();
3757
+ }
3758
+ onSearchChange(search) {
3759
+ this.searchSubject.next(search);
3760
+ }
3761
+ onPerformanceSelected(event) {
3762
+ const select = event.target;
3763
+ const value = select.value ? Number(select.value) : null;
3764
+ this.value = value;
3765
+ if (this.control) {
3766
+ this.control.setValue(value);
3767
+ this.control.markAsTouched();
3768
+ }
3769
+ this.performanceChange.emit(value);
3770
+ }
3771
+ writeValue(value) {
3772
+ this.value = value;
3773
+ }
3774
+ registerOnChange(fn) {
3775
+ this.onChange = fn;
3776
+ }
3777
+ registerOnTouched(fn) {
3778
+ this.onTouched = fn;
3779
+ }
3780
+ validate(control) {
3781
+ if (this.required && !control.value) {
3782
+ return { required: true };
3783
+ }
3784
+ return null;
3785
+ }
3786
+ get isInvalid() {
3787
+ return false;
3788
+ }
3789
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: PerformanceSelectComponent, deps: [{ token: PLATFORM_ID }, { token: PerformanceService }], target: i0.ɵɵFactoryTarget.Component });
3790
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.25", type: PerformanceSelectComponent, isStandalone: true, selector: "performance-select", inputs: { label: "label", placeholder: "placeholder", name: "name", required: "required", readonly: "readonly", showError: "showError", customClass: "customClass", control: "control" }, outputs: { performanceChange: "performanceChange" }, providers: [
3791
+ {
3792
+ provide: NG_VALUE_ACCESSOR,
3793
+ useExisting: forwardRef(() => PerformanceSelectComponent),
3794
+ multi: true,
3795
+ },
3796
+ {
3797
+ provide: NG_VALIDATORS,
3798
+ useExisting: forwardRef(() => PerformanceSelectComponent),
3799
+ multi: true,
3800
+ },
3801
+ ], ngImport: i0, template: "<form-select\n [label]=\"label\"\n [placeholder]=\"placeholder\"\n [name]=\"name || 'performance_id'\"\n [class]=\"customClass\"\n [options]=\"performances()\"\n [required]=\"required\"\n [readonly]=\"readonly\"\n [formControl]=\"formControl\"\n (change)=\"onPerformanceSelected($event)\"\n></form-select>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: FormSelectComponent, selector: "form-select", inputs: ["label", "name", "id", "placeholder", "required", "disabled", "readonly", "options", "fieldGroupClass", "showDefaultOption", "defaultOptionLabel"] }] });
3802
+ }
3803
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: PerformanceSelectComponent, decorators: [{
3804
+ type: Component,
3805
+ args: [{ selector: 'performance-select', standalone: true, imports: [CommonModule, ReactiveFormsModule, FormSelectComponent], providers: [
3806
+ {
3807
+ provide: NG_VALUE_ACCESSOR,
3808
+ useExisting: forwardRef(() => PerformanceSelectComponent),
3809
+ multi: true,
3810
+ },
3811
+ {
3812
+ provide: NG_VALIDATORS,
3813
+ useExisting: forwardRef(() => PerformanceSelectComponent),
3814
+ multi: true,
3815
+ },
3816
+ ], template: "<form-select\n [label]=\"label\"\n [placeholder]=\"placeholder\"\n [name]=\"name || 'performance_id'\"\n [class]=\"customClass\"\n [options]=\"performances()\"\n [required]=\"required\"\n [readonly]=\"readonly\"\n [formControl]=\"formControl\"\n (change)=\"onPerformanceSelected($event)\"\n></form-select>\n" }]
3817
+ }], ctorParameters: () => [{ type: undefined, decorators: [{
3818
+ type: Inject,
3819
+ args: [PLATFORM_ID]
3820
+ }] }, { type: PerformanceService }], propDecorators: { label: [{
3821
+ type: Input
3822
+ }], placeholder: [{
3823
+ type: Input
3824
+ }], name: [{
3825
+ type: Input
3826
+ }], required: [{
3827
+ type: Input
3828
+ }], readonly: [{
3829
+ type: Input
3830
+ }], showError: [{
3831
+ type: Input
3832
+ }], customClass: [{
3833
+ type: Input
3834
+ }], control: [{
3835
+ type: Input
3836
+ }], performanceChange: [{
3837
+ type: Output
3838
+ }] } });
3839
+
3840
+ class PerformanceMultiSelectComponent {
3841
+ platformId;
3842
+ performanceService;
3843
+ label = 'Funciones';
3844
+ placeholder = 'Buscar funciones...';
3845
+ allPerformances = signal([], ...(ngDevMode ? [{ debugName: "allPerformances" }] : []));
3846
+ filteredPerformances = signal([], ...(ngDevMode ? [{ debugName: "filteredPerformances" }] : []));
3847
+ loading = signal(true, ...(ngDevMode ? [{ debugName: "loading" }] : []));
3848
+ selectedIds = [];
3849
+ searchTerm = '';
3850
+ searchSubject = new Subject();
3851
+ destroy$ = new Subject();
3852
+ onChange = () => { };
3853
+ onTouched = () => { };
3854
+ constructor(platformId, performanceService) {
3855
+ this.platformId = platformId;
3856
+ this.performanceService = performanceService;
3857
+ }
3858
+ ngOnInit() {
3859
+ if (isPlatformBrowser(this.platformId)) {
3860
+ this.performanceService.loadPerformances({});
3861
+ this.performanceService.performances$
3862
+ .pipe(takeUntil(this.destroy$))
3863
+ .subscribe((performances) => {
3864
+ this.allPerformances.set(performances?.map((p) => ({
3865
+ value: p.id,
3866
+ label: `${p.show?.title || `Show #${p.show_id}`} - ${new Date(p.start_time).toLocaleString()}`,
3867
+ })) || []);
3868
+ this.applyFilter();
3869
+ this.loading.set(false);
3870
+ });
3871
+ this.searchSubject
3872
+ .pipe(debounceTime(400), distinctUntilChanged(), takeUntil(this.destroy$))
3873
+ .subscribe((search) => {
3874
+ this.searchTerm = search;
3875
+ this.performanceService.loadPerformances({ search: this.searchTerm });
3876
+ });
3877
+ }
3878
+ }
3879
+ ngOnDestroy() {
3880
+ this.destroy$.next();
3881
+ this.destroy$.complete();
3882
+ }
3883
+ applyFilter() {
3884
+ if (this.searchTerm) {
3885
+ const term = this.searchTerm.toLowerCase();
3886
+ this.filteredPerformances.set(this.allPerformances().filter((p) => p.label.toLowerCase().includes(term)));
3887
+ }
3888
+ else {
3889
+ this.filteredPerformances.set([...this.allPerformances()]);
3890
+ }
3891
+ }
3892
+ onSearchChange(event) {
3893
+ const value = event.target.value;
3894
+ this.searchSubject.next(value);
3895
+ }
3896
+ isSelected(id) {
3897
+ return this.selectedIds.includes(id);
3898
+ }
3899
+ togglePerformance(id) {
3900
+ const index = this.selectedIds.indexOf(id);
3901
+ if (index > -1) {
3902
+ this.selectedIds = this.selectedIds.filter((v) => v !== id);
3903
+ }
3904
+ else {
3905
+ this.selectedIds = [...this.selectedIds, id];
3906
+ }
3907
+ this.onChange(this.selectedIds);
3908
+ this.onTouched();
3909
+ }
3910
+ removePerformance(id) {
3911
+ this.togglePerformance(id);
3912
+ }
3913
+ getPerformanceLabel(id) {
3914
+ return this.allPerformances().find((p) => p.value === id)?.label || '';
3915
+ }
3916
+ writeValue(value) {
3917
+ this.selectedIds = value || [];
3918
+ }
3919
+ registerOnChange(fn) {
3920
+ this.onChange = fn;
3921
+ }
3922
+ registerOnTouched(fn) {
3923
+ this.onTouched = fn;
3924
+ }
3925
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: PerformanceMultiSelectComponent, deps: [{ token: PLATFORM_ID }, { token: PerformanceService }], target: i0.ɵɵFactoryTarget.Component });
3926
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.25", type: PerformanceMultiSelectComponent, isStandalone: true, selector: "performance-multi-select", inputs: { label: "label", placeholder: "placeholder" }, providers: [
3927
+ {
3928
+ provide: NG_VALUE_ACCESSOR,
3929
+ useExisting: forwardRef(() => PerformanceMultiSelectComponent),
3930
+ multi: true,
3931
+ },
3932
+ ], ngImport: i0, template: "<div class=\"w-full\">\n @if (label) {\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n {{ label }}\n </label>\n }\n\n @if (selectedIds.length > 0) {\n <div class=\"flex flex-wrap gap-1 mb-2\">\n @for (id of selectedIds; track id) {\n <span\n class=\"inline-flex items-center gap-1 px-2 py-1 rounded-full text-xs font-medium bg-green-100 text-green-800\"\n >\n {{ getPerformanceLabel(id) }}\n <button\n type=\"button\"\n class=\"ml-1 hover:text-green-600 leading-none\"\n (click)=\"removePerformance(id)\"\n >\n &times;\n </button>\n </span>\n }\n </div>\n }\n\n <input\n type=\"text\"\n [placeholder]=\"placeholder\"\n class=\"w-full px-3 py-2 border border-gray-300 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-green-500 focus:border-transparent\"\n (input)=\"onSearchChange($event)\"\n />\n\n @if (loading()) {\n <div class=\"flex items-center gap-2 mt-2 text-sm text-gray-500\">\n <div\n class=\"w-4 h-4 border-2 border-gray-200 border-t-green-500 rounded-full animate-spin\"\n ></div>\n Cargando funciones...\n </div>\n }\n\n @if (!loading() && filteredPerformances().length > 0) {\n <div\n class=\"mt-1 max-h-48 overflow-y-auto border border-gray-200 rounded-md divide-y divide-gray-100\"\n >\n @for (p of filteredPerformances(); track p.value) {\n <label class=\"flex items-center gap-2 px-3 py-2 hover:bg-gray-50 cursor-pointer text-sm\">\n <input\n type=\"checkbox\"\n [checked]=\"isSelected(p.value)\"\n (change)=\"togglePerformance(p.value)\"\n class=\"w-4 h-4 accent-green-500 cursor-pointer\"\n />\n <span class=\"text-gray-700 select-none\">{{ p.label }}</span>\n </label>\n }\n </div>\n }\n\n @if (!loading() && filteredPerformances().length === 0) {\n <p class=\"text-sm text-gray-500 mt-1\">No se encontraron funciones</p>\n }\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }] });
3933
+ }
3934
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: PerformanceMultiSelectComponent, decorators: [{
3935
+ type: Component,
3936
+ args: [{ selector: 'performance-multi-select', standalone: true, imports: [CommonModule], providers: [
3937
+ {
3938
+ provide: NG_VALUE_ACCESSOR,
3939
+ useExisting: forwardRef(() => PerformanceMultiSelectComponent),
3940
+ multi: true,
3941
+ },
3942
+ ], template: "<div class=\"w-full\">\n @if (label) {\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n {{ label }}\n </label>\n }\n\n @if (selectedIds.length > 0) {\n <div class=\"flex flex-wrap gap-1 mb-2\">\n @for (id of selectedIds; track id) {\n <span\n class=\"inline-flex items-center gap-1 px-2 py-1 rounded-full text-xs font-medium bg-green-100 text-green-800\"\n >\n {{ getPerformanceLabel(id) }}\n <button\n type=\"button\"\n class=\"ml-1 hover:text-green-600 leading-none\"\n (click)=\"removePerformance(id)\"\n >\n &times;\n </button>\n </span>\n }\n </div>\n }\n\n <input\n type=\"text\"\n [placeholder]=\"placeholder\"\n class=\"w-full px-3 py-2 border border-gray-300 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-green-500 focus:border-transparent\"\n (input)=\"onSearchChange($event)\"\n />\n\n @if (loading()) {\n <div class=\"flex items-center gap-2 mt-2 text-sm text-gray-500\">\n <div\n class=\"w-4 h-4 border-2 border-gray-200 border-t-green-500 rounded-full animate-spin\"\n ></div>\n Cargando funciones...\n </div>\n }\n\n @if (!loading() && filteredPerformances().length > 0) {\n <div\n class=\"mt-1 max-h-48 overflow-y-auto border border-gray-200 rounded-md divide-y divide-gray-100\"\n >\n @for (p of filteredPerformances(); track p.value) {\n <label class=\"flex items-center gap-2 px-3 py-2 hover:bg-gray-50 cursor-pointer text-sm\">\n <input\n type=\"checkbox\"\n [checked]=\"isSelected(p.value)\"\n (change)=\"togglePerformance(p.value)\"\n class=\"w-4 h-4 accent-green-500 cursor-pointer\"\n />\n <span class=\"text-gray-700 select-none\">{{ p.label }}</span>\n </label>\n }\n </div>\n }\n\n @if (!loading() && filteredPerformances().length === 0) {\n <p class=\"text-sm text-gray-500 mt-1\">No se encontraron funciones</p>\n }\n</div>\n" }]
3943
+ }], ctorParameters: () => [{ type: undefined, decorators: [{
3944
+ type: Inject,
3945
+ args: [PLATFORM_ID]
3946
+ }] }, { type: PerformanceService }], propDecorators: { label: [{
3947
+ type: Input
3948
+ }], placeholder: [{
3949
+ type: Input
3950
+ }] } });
3951
+
3952
+ class ProductSelectComponent {
3953
+ platformId;
3954
+ productService;
3955
+ label = 'Producto';
3956
+ placeholder = 'Selecciona un producto';
3957
+ name = 'product_id';
3958
+ required = false;
3959
+ readonly = false;
3960
+ showError = true;
3961
+ customClass = '';
3962
+ control = null;
3963
+ productChange = new EventEmitter();
3964
+ products = signal([], ...(ngDevMode ? [{ debugName: "products" }] : []));
3965
+ loading = signal(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
3966
+ searchTerm = '';
3967
+ searchSubject = new Subject();
3968
+ destroy$ = new Subject();
3969
+ value = null;
3970
+ onChange = () => { };
3971
+ onTouched = () => { };
3972
+ constructor(platformId, productService) {
3973
+ this.platformId = platformId;
3974
+ this.productService = productService;
3975
+ }
3976
+ ngOnInit() {
3977
+ if (isPlatformBrowser(this.platformId)) {
3978
+ this.productService.loadProducts({ search: this.searchTerm });
3979
+ this.productService.products$
3980
+ .pipe(takeUntil(this.destroy$))
3981
+ .subscribe((products) => {
3982
+ this.products.set(products?.map((product) => ({
3983
+ value: product.id,
3984
+ label: product.name,
3985
+ })) || []);
3986
+ this.loading.set(false);
3987
+ });
3988
+ this.searchSubject
3989
+ .pipe(debounceTime(400), distinctUntilChanged(), takeUntil(this.destroy$))
3990
+ .subscribe((search) => {
3991
+ this.searchTerm = search;
3992
+ this.productService.loadProducts({ search: this.searchTerm });
3993
+ });
3994
+ }
3995
+ }
3996
+ get formControl() {
3997
+ return this.control;
3998
+ }
3999
+ ngOnDestroy() {
4000
+ this.destroy$.next();
4001
+ this.destroy$.complete();
4002
+ }
4003
+ onSearchChange(search) {
4004
+ this.searchSubject.next(search);
4005
+ }
4006
+ onProductSelected(event) {
4007
+ const select = event.target;
4008
+ const value = select.value ? Number(select.value) : null;
4009
+ this.value = value;
4010
+ if (this.control) {
4011
+ this.control.setValue(value);
4012
+ this.control.markAsTouched();
4013
+ }
4014
+ this.productChange.emit(value);
4015
+ }
4016
+ writeValue(value) {
4017
+ this.value = value;
4018
+ }
4019
+ registerOnChange(fn) {
4020
+ this.onChange = fn;
4021
+ }
4022
+ registerOnTouched(fn) {
4023
+ this.onTouched = fn;
4024
+ }
4025
+ validate(control) {
4026
+ if (this.required && !control.value) {
4027
+ return { required: true };
4028
+ }
4029
+ return null;
4030
+ }
4031
+ get isInvalid() {
4032
+ return false;
4033
+ }
4034
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: ProductSelectComponent, deps: [{ token: PLATFORM_ID }, { token: ProductService }], target: i0.ɵɵFactoryTarget.Component });
4035
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.25", type: ProductSelectComponent, isStandalone: true, selector: "product-select", inputs: { label: "label", placeholder: "placeholder", name: "name", required: "required", readonly: "readonly", showError: "showError", customClass: "customClass", control: "control" }, outputs: { productChange: "productChange" }, providers: [
4036
+ {
4037
+ provide: NG_VALUE_ACCESSOR,
4038
+ useExisting: forwardRef(() => ProductSelectComponent),
4039
+ multi: true,
4040
+ },
4041
+ {
4042
+ provide: NG_VALIDATORS,
4043
+ useExisting: forwardRef(() => ProductSelectComponent),
4044
+ multi: true,
4045
+ },
4046
+ ], ngImport: i0, template: "<form-select\n [label]=\"label\"\n [placeholder]=\"placeholder\"\n [name]=\"name || 'product_id'\"\n [class]=\"customClass\"\n [options]=\"products()\"\n [required]=\"required\"\n [readonly]=\"readonly\"\n [formControl]=\"formControl\"\n (change)=\"onProductSelected($event)\"\n></form-select>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: FormSelectComponent, selector: "form-select", inputs: ["label", "name", "id", "placeholder", "required", "disabled", "readonly", "options", "fieldGroupClass", "showDefaultOption", "defaultOptionLabel"] }] });
4047
+ }
4048
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: ProductSelectComponent, decorators: [{
4049
+ type: Component,
4050
+ args: [{ selector: 'product-select', standalone: true, imports: [CommonModule, ReactiveFormsModule, FormSelectComponent], providers: [
4051
+ {
4052
+ provide: NG_VALUE_ACCESSOR,
4053
+ useExisting: forwardRef(() => ProductSelectComponent),
4054
+ multi: true,
4055
+ },
4056
+ {
4057
+ provide: NG_VALIDATORS,
4058
+ useExisting: forwardRef(() => ProductSelectComponent),
4059
+ multi: true,
4060
+ },
4061
+ ], template: "<form-select\n [label]=\"label\"\n [placeholder]=\"placeholder\"\n [name]=\"name || 'product_id'\"\n [class]=\"customClass\"\n [options]=\"products()\"\n [required]=\"required\"\n [readonly]=\"readonly\"\n [formControl]=\"formControl\"\n (change)=\"onProductSelected($event)\"\n></form-select>\n" }]
4062
+ }], ctorParameters: () => [{ type: undefined, decorators: [{
4063
+ type: Inject,
4064
+ args: [PLATFORM_ID]
4065
+ }] }, { type: ProductService }], propDecorators: { label: [{
4066
+ type: Input
4067
+ }], placeholder: [{
4068
+ type: Input
4069
+ }], name: [{
4070
+ type: Input
4071
+ }], required: [{
4072
+ type: Input
4073
+ }], readonly: [{
4074
+ type: Input
4075
+ }], showError: [{
4076
+ type: Input
4077
+ }], customClass: [{
4078
+ type: Input
4079
+ }], control: [{
4080
+ type: Input
4081
+ }], productChange: [{
4082
+ type: Output
4083
+ }] } });
4084
+
4085
+ class ProductMultiSelectComponent {
4086
+ platformId;
4087
+ productService;
4088
+ label = 'Productos';
4089
+ placeholder = 'Buscar productos...';
4090
+ set initialSelection(ids) {
4091
+ this.selectedIds = ids ?? [];
4092
+ }
4093
+ selectionChange = new EventEmitter();
4094
+ allProducts = signal([], ...(ngDevMode ? [{ debugName: "allProducts" }] : []));
4095
+ filteredProducts = signal([], ...(ngDevMode ? [{ debugName: "filteredProducts" }] : []));
4096
+ loading = signal(true, ...(ngDevMode ? [{ debugName: "loading" }] : []));
4097
+ selectedIds = [];
4098
+ searchTerm = '';
4099
+ searchSubject = new Subject();
4100
+ destroy$ = new Subject();
4101
+ onChange = () => { };
4102
+ onTouched = () => { };
4103
+ constructor(platformId, productService) {
4104
+ this.platformId = platformId;
4105
+ this.productService = productService;
4106
+ }
4107
+ ngOnInit() {
4108
+ if (isPlatformBrowser(this.platformId)) {
4109
+ this.productService.loadProducts({ search: this.searchTerm });
4110
+ this.productService.products$
4111
+ .pipe(takeUntil(this.destroy$))
4112
+ .subscribe((products) => {
4113
+ this.allProducts.set(products?.map((p) => ({
4114
+ value: p.id,
4115
+ label: p.name,
4116
+ imageUrl: p.images?.[0]?.full_url ?? null,
4117
+ })) || []);
4118
+ this.applyFilter();
4119
+ this.loading.set(false);
4120
+ });
4121
+ this.searchSubject
4122
+ .pipe(debounceTime(400), distinctUntilChanged(), takeUntil(this.destroy$))
4123
+ .subscribe((search) => {
4124
+ this.searchTerm = search;
4125
+ this.productService.loadProducts({ search: this.searchTerm });
4126
+ });
4127
+ }
4128
+ }
4129
+ ngOnDestroy() {
4130
+ this.destroy$.next();
4131
+ this.destroy$.complete();
4132
+ }
4133
+ applyFilter() {
4134
+ if (this.searchTerm) {
4135
+ const term = this.searchTerm.toLowerCase();
4136
+ this.filteredProducts.set(this.allProducts().filter((p) => p.label.toLowerCase().includes(term)));
4137
+ }
4138
+ else {
4139
+ this.filteredProducts.set([...this.allProducts()]);
4140
+ }
4141
+ }
4142
+ onSearchChange(event) {
4143
+ const value = event.target.value;
4144
+ this.searchSubject.next(value);
4145
+ }
4146
+ isSelected(id) {
4147
+ return this.selectedIds.includes(id);
4148
+ }
4149
+ toggleProduct(id) {
4150
+ const index = this.selectedIds.indexOf(id);
4151
+ if (index > -1) {
4152
+ this.selectedIds = this.selectedIds.filter((v) => v !== id);
4153
+ }
4154
+ else {
4155
+ this.selectedIds = [...this.selectedIds, id];
4156
+ }
4157
+ this.onChange(this.selectedIds);
4158
+ this.onTouched();
4159
+ this.selectionChange.emit(this.selectedIds);
4160
+ }
4161
+ removeProduct(id) {
4162
+ this.toggleProduct(id);
4163
+ }
4164
+ getProductOption(id) {
4165
+ return this.allProducts().find((p) => p.value === id);
4166
+ }
4167
+ writeValue(value) {
4168
+ this.selectedIds = value || [];
4169
+ }
4170
+ registerOnChange(fn) {
4171
+ this.onChange = fn;
4172
+ }
4173
+ registerOnTouched(fn) {
4174
+ this.onTouched = fn;
4175
+ }
4176
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: ProductMultiSelectComponent, deps: [{ token: PLATFORM_ID }, { token: ProductService }], target: i0.ɵɵFactoryTarget.Component });
4177
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.25", type: ProductMultiSelectComponent, isStandalone: true, selector: "product-multi-select", inputs: { label: "label", placeholder: "placeholder", initialSelection: "initialSelection" }, outputs: { selectionChange: "selectionChange" }, providers: [
4178
+ {
4179
+ provide: NG_VALUE_ACCESSOR,
4180
+ useExisting: forwardRef(() => ProductMultiSelectComponent),
4181
+ multi: true,
4182
+ },
4183
+ ], ngImport: i0, template: "<div class=\"w-full\">\n @if (label) {\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n {{ label }}\n </label>\n }\n\n @if (selectedIds.length > 0) {\n <div class=\"flex flex-wrap gap-1 mb-2\">\n @for (id of selectedIds; track id) {\n @let product = getProductOption(id);\n <span\n class=\"inline-flex items-center gap-1 px-2 py-1 rounded-full text-xs font-medium bg-green-100 text-green-800\"\n >\n @if (product?.imageUrl) {\n <img [src]=\"product!.imageUrl\" alt=\"\" class=\"w-4 h-4 rounded-full object-cover\" />\n }\n {{ product?.label ?? id }}\n <button\n type=\"button\"\n class=\"ml-1 hover:text-green-600 leading-none\"\n (click)=\"removeProduct(id)\"\n >\n &times;\n </button>\n </span>\n }\n </div>\n }\n\n <input\n type=\"text\"\n [placeholder]=\"placeholder\"\n class=\"w-full px-3 py-2 border border-gray-300 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-green-500 focus:border-transparent\"\n (input)=\"onSearchChange($event)\"\n />\n\n @if (loading()) {\n <div class=\"flex items-center gap-2 mt-2 text-sm text-gray-500\">\n <div\n class=\"w-4 h-4 border-2 border-gray-200 border-t-green-500 rounded-full animate-spin\"\n ></div>\n Cargando productos...\n </div>\n }\n\n @if (!loading() && filteredProducts().length > 0) {\n <div\n class=\"mt-1 max-h-48 overflow-y-auto border border-gray-200 rounded-md divide-y divide-gray-100\"\n >\n @for (p of filteredProducts(); track p.value) {\n <label class=\"flex items-center gap-2 px-3 py-2 hover:bg-gray-50 cursor-pointer text-sm\">\n <input\n type=\"checkbox\"\n [checked]=\"isSelected(p.value)\"\n (change)=\"toggleProduct(p.value)\"\n class=\"w-4 h-4 accent-green-500 cursor-pointer\"\n />\n @if (p.imageUrl) {\n <img [src]=\"p.imageUrl\" alt=\"\" class=\"w-6 h-6 rounded object-cover\" />\n } @else {\n <div class=\"w-6 h-6 rounded bg-gray-200 flex items-center justify-center\">\n <i class=\"ri-image-line text-gray-400 text-xs\"></i>\n </div>\n }\n <span class=\"text-gray-700 select-none\">{{ p.label }}</span>\n </label>\n }\n </div>\n }\n\n @if (!loading() && filteredProducts().length === 0) {\n <p class=\"text-sm text-gray-500 mt-1\">No se encontraron productos</p>\n }\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }] });
4184
+ }
4185
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: ProductMultiSelectComponent, decorators: [{
4186
+ type: Component,
4187
+ args: [{ selector: 'product-multi-select', standalone: true, imports: [CommonModule], providers: [
4188
+ {
4189
+ provide: NG_VALUE_ACCESSOR,
4190
+ useExisting: forwardRef(() => ProductMultiSelectComponent),
4191
+ multi: true,
4192
+ },
4193
+ ], template: "<div class=\"w-full\">\n @if (label) {\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n {{ label }}\n </label>\n }\n\n @if (selectedIds.length > 0) {\n <div class=\"flex flex-wrap gap-1 mb-2\">\n @for (id of selectedIds; track id) {\n @let product = getProductOption(id);\n <span\n class=\"inline-flex items-center gap-1 px-2 py-1 rounded-full text-xs font-medium bg-green-100 text-green-800\"\n >\n @if (product?.imageUrl) {\n <img [src]=\"product!.imageUrl\" alt=\"\" class=\"w-4 h-4 rounded-full object-cover\" />\n }\n {{ product?.label ?? id }}\n <button\n type=\"button\"\n class=\"ml-1 hover:text-green-600 leading-none\"\n (click)=\"removeProduct(id)\"\n >\n &times;\n </button>\n </span>\n }\n </div>\n }\n\n <input\n type=\"text\"\n [placeholder]=\"placeholder\"\n class=\"w-full px-3 py-2 border border-gray-300 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-green-500 focus:border-transparent\"\n (input)=\"onSearchChange($event)\"\n />\n\n @if (loading()) {\n <div class=\"flex items-center gap-2 mt-2 text-sm text-gray-500\">\n <div\n class=\"w-4 h-4 border-2 border-gray-200 border-t-green-500 rounded-full animate-spin\"\n ></div>\n Cargando productos...\n </div>\n }\n\n @if (!loading() && filteredProducts().length > 0) {\n <div\n class=\"mt-1 max-h-48 overflow-y-auto border border-gray-200 rounded-md divide-y divide-gray-100\"\n >\n @for (p of filteredProducts(); track p.value) {\n <label class=\"flex items-center gap-2 px-3 py-2 hover:bg-gray-50 cursor-pointer text-sm\">\n <input\n type=\"checkbox\"\n [checked]=\"isSelected(p.value)\"\n (change)=\"toggleProduct(p.value)\"\n class=\"w-4 h-4 accent-green-500 cursor-pointer\"\n />\n @if (p.imageUrl) {\n <img [src]=\"p.imageUrl\" alt=\"\" class=\"w-6 h-6 rounded object-cover\" />\n } @else {\n <div class=\"w-6 h-6 rounded bg-gray-200 flex items-center justify-center\">\n <i class=\"ri-image-line text-gray-400 text-xs\"></i>\n </div>\n }\n <span class=\"text-gray-700 select-none\">{{ p.label }}</span>\n </label>\n }\n </div>\n }\n\n @if (!loading() && filteredProducts().length === 0) {\n <p class=\"text-sm text-gray-500 mt-1\">No se encontraron productos</p>\n }\n</div>\n" }]
4194
+ }], ctorParameters: () => [{ type: undefined, decorators: [{
4195
+ type: Inject,
4196
+ args: [PLATFORM_ID]
4197
+ }] }, { type: ProductService }], propDecorators: { label: [{
4198
+ type: Input
4199
+ }], placeholder: [{
4200
+ type: Input
4201
+ }], initialSelection: [{
4202
+ type: Input
4203
+ }], selectionChange: [{
4204
+ type: Output
4205
+ }] } });
4206
+
4207
+ class ShowSelectComponent {
4208
+ platformId;
4209
+ showService;
4210
+ label = 'Función';
4211
+ placeholder = 'Selecciona una función';
4212
+ name = 'show_id';
4213
+ required = false;
4214
+ readonly = false;
4215
+ showError = true;
4216
+ customClass = '';
4217
+ control = null;
4218
+ showChange = new EventEmitter();
4219
+ shows = signal([], ...(ngDevMode ? [{ debugName: "shows" }] : []));
4220
+ loading = signal(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
4221
+ searchTerm = '';
4222
+ searchSubject = new Subject();
4223
+ destroy$ = new Subject();
4224
+ value = null;
4225
+ onChange = () => { };
4226
+ onTouched = () => { };
4227
+ constructor(platformId, showService) {
4228
+ this.platformId = platformId;
4229
+ this.showService = showService;
4230
+ }
4231
+ ngOnInit() {
4232
+ if (isPlatformBrowser(this.platformId)) {
4233
+ this.showService.loadShows({ search: this.searchTerm });
4234
+ this.showService.shows$.pipe(takeUntil(this.destroy$)).subscribe((shows) => {
4235
+ const formatted = shows?.map((show) => ({ value: show.id, label: show.title })) || [];
4236
+ this.shows.set(formatted);
4237
+ this.loading.set(false);
4238
+ });
4239
+ this.searchSubject
4240
+ .pipe(debounceTime(400), distinctUntilChanged(), takeUntil(this.destroy$))
4241
+ .subscribe((search) => {
4242
+ this.searchTerm = search;
4243
+ this.showService.loadShows({ search: this.searchTerm });
4244
+ });
4245
+ }
4246
+ }
4247
+ get formControl() {
4248
+ return this.control;
4249
+ }
4250
+ ngOnDestroy() {
4251
+ this.destroy$.next();
4252
+ this.destroy$.complete();
4253
+ }
4254
+ onSearchChange(search) {
4255
+ this.searchSubject.next(search);
4256
+ }
4257
+ onShowSelected(event) {
4258
+ const select = event.target;
4259
+ const value = select.value ? Number(select.value) : null;
4260
+ this.value = value;
4261
+ if (this.control) {
4262
+ this.control.setValue(value);
4263
+ this.control.markAsTouched();
4264
+ }
4265
+ this.showChange.emit(value);
4266
+ }
4267
+ writeValue(value) {
4268
+ this.value = value;
4269
+ }
4270
+ registerOnChange(fn) {
4271
+ this.onChange = fn;
4272
+ }
4273
+ registerOnTouched(fn) {
4274
+ this.onTouched = fn;
4275
+ }
4276
+ validate(control) {
4277
+ if (this.required && !control.value) {
4278
+ return { required: true };
4279
+ }
4280
+ return null;
4281
+ }
4282
+ get isInvalid() {
4283
+ return false;
4284
+ }
4285
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: ShowSelectComponent, deps: [{ token: PLATFORM_ID }, { token: ShowService }], target: i0.ɵɵFactoryTarget.Component });
4286
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.25", type: ShowSelectComponent, isStandalone: true, selector: "show-select", inputs: { label: "label", placeholder: "placeholder", name: "name", required: "required", readonly: "readonly", showError: "showError", customClass: "customClass", control: "control" }, outputs: { showChange: "showChange" }, providers: [
4287
+ {
4288
+ provide: NG_VALUE_ACCESSOR,
4289
+ useExisting: forwardRef(() => ShowSelectComponent),
4290
+ multi: true,
4291
+ },
4292
+ {
4293
+ provide: NG_VALIDATORS,
4294
+ useExisting: forwardRef(() => ShowSelectComponent),
4295
+ multi: true,
4296
+ },
4297
+ ], ngImport: i0, template: "<form-select\n [label]=\"label\"\n [placeholder]=\"placeholder\"\n [name]=\"name || 'show_id'\"\n [class]=\"customClass\"\n [options]=\"shows()\"\n [required]=\"required\"\n [readonly]=\"readonly\"\n [formControl]=\"formControl\"\n (change)=\"onShowSelected($event)\"\n></form-select>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: FormSelectComponent, selector: "form-select", inputs: ["label", "name", "id", "placeholder", "required", "disabled", "readonly", "options", "fieldGroupClass", "showDefaultOption", "defaultOptionLabel"] }] });
4298
+ }
4299
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: ShowSelectComponent, decorators: [{
4300
+ type: Component,
4301
+ args: [{ selector: 'show-select', standalone: true, imports: [CommonModule, ReactiveFormsModule, FormSelectComponent], providers: [
4302
+ {
4303
+ provide: NG_VALUE_ACCESSOR,
4304
+ useExisting: forwardRef(() => ShowSelectComponent),
4305
+ multi: true,
4306
+ },
4307
+ {
4308
+ provide: NG_VALIDATORS,
4309
+ useExisting: forwardRef(() => ShowSelectComponent),
4310
+ multi: true,
4311
+ },
4312
+ ], template: "<form-select\n [label]=\"label\"\n [placeholder]=\"placeholder\"\n [name]=\"name || 'show_id'\"\n [class]=\"customClass\"\n [options]=\"shows()\"\n [required]=\"required\"\n [readonly]=\"readonly\"\n [formControl]=\"formControl\"\n (change)=\"onShowSelected($event)\"\n></form-select>\n" }]
4313
+ }], ctorParameters: () => [{ type: undefined, decorators: [{
4314
+ type: Inject,
4315
+ args: [PLATFORM_ID]
4316
+ }] }, { type: ShowService }], propDecorators: { label: [{
4317
+ type: Input
4318
+ }], placeholder: [{
4319
+ type: Input
4320
+ }], name: [{
4321
+ type: Input
4322
+ }], required: [{
4323
+ type: Input
4324
+ }], readonly: [{
4325
+ type: Input
4326
+ }], showError: [{
4327
+ type: Input
4328
+ }], customClass: [{
4329
+ type: Input
4330
+ }], control: [{
4331
+ type: Input
4332
+ }], showChange: [{
4333
+ type: Output
4334
+ }] } });
4335
+
4336
+ class ShowMultiSelectComponent {
4337
+ platformId;
4338
+ showService;
4339
+ label = 'Funciones';
4340
+ placeholder = 'Buscar funciones...';
4341
+ allShows = signal([], ...(ngDevMode ? [{ debugName: "allShows" }] : []));
4342
+ filteredShows = signal([], ...(ngDevMode ? [{ debugName: "filteredShows" }] : []));
4343
+ loading = signal(true, ...(ngDevMode ? [{ debugName: "loading" }] : []));
4344
+ selectedIds = [];
4345
+ searchTerm = '';
4346
+ searchSubject = new Subject();
4347
+ destroy$ = new Subject();
4348
+ onChange = () => { };
4349
+ onTouched = () => { };
4350
+ constructor(platformId, showService) {
4351
+ this.platformId = platformId;
4352
+ this.showService = showService;
4353
+ }
4354
+ ngOnInit() {
4355
+ if (isPlatformBrowser(this.platformId)) {
4356
+ this.showService.loadShows({});
4357
+ this.showService.shows$.pipe(takeUntil(this.destroy$)).subscribe((shows) => {
4358
+ this.allShows.set(shows?.map((show) => ({
4359
+ value: show.id,
4360
+ label: show.title,
4361
+ })) || []);
4362
+ this.applyFilter();
4363
+ this.loading.set(false);
4364
+ });
4365
+ this.searchSubject
4366
+ .pipe(debounceTime(400), distinctUntilChanged(), takeUntil(this.destroy$))
4367
+ .subscribe((search) => {
4368
+ this.searchTerm = search;
4369
+ this.showService.loadShows({ search: this.searchTerm });
4370
+ });
4371
+ }
4372
+ }
4373
+ ngOnDestroy() {
4374
+ this.destroy$.next();
4375
+ this.destroy$.complete();
4376
+ }
4377
+ applyFilter() {
4378
+ if (this.searchTerm) {
4379
+ const term = this.searchTerm.toLowerCase();
4380
+ this.filteredShows.set(this.allShows().filter((s) => s.label.toLowerCase().includes(term)));
4381
+ }
4382
+ else {
4383
+ this.filteredShows.set([...this.allShows()]);
4384
+ }
4385
+ }
4386
+ onSearchChange(event) {
4387
+ const value = event.target.value;
4388
+ this.searchSubject.next(value);
4389
+ }
4390
+ isSelected(id) {
4391
+ return this.selectedIds.includes(id);
4392
+ }
4393
+ toggleShow(id) {
4394
+ const index = this.selectedIds.indexOf(id);
4395
+ if (index > -1) {
4396
+ this.selectedIds = this.selectedIds.filter((v) => v !== id);
4397
+ }
4398
+ else {
4399
+ this.selectedIds = [...this.selectedIds, id];
4400
+ }
4401
+ this.onChange(this.selectedIds);
4402
+ this.onTouched();
4403
+ }
4404
+ removeShow(id) {
4405
+ this.toggleShow(id);
4406
+ }
4407
+ getShowLabel(id) {
4408
+ return this.allShows().find((s) => s.value === id)?.label || '';
4409
+ }
4410
+ writeValue(value) {
4411
+ this.selectedIds = value || [];
4412
+ }
4413
+ registerOnChange(fn) {
4414
+ this.onChange = fn;
4415
+ }
4416
+ registerOnTouched(fn) {
4417
+ this.onTouched = fn;
4418
+ }
4419
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: ShowMultiSelectComponent, deps: [{ token: PLATFORM_ID }, { token: ShowService }], target: i0.ɵɵFactoryTarget.Component });
4420
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.25", type: ShowMultiSelectComponent, isStandalone: true, selector: "show-multi-select", inputs: { label: "label", placeholder: "placeholder" }, providers: [
4421
+ {
4422
+ provide: NG_VALUE_ACCESSOR,
4423
+ useExisting: forwardRef(() => ShowMultiSelectComponent),
4424
+ multi: true,
4425
+ },
4426
+ ], ngImport: i0, template: "<div class=\"w-full\">\n @if (label) {\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n {{ label }}\n </label>\n }\n\n @if (selectedIds.length > 0) {\n <div class=\"flex flex-wrap gap-1 mb-2\">\n @for (id of selectedIds; track id) {\n <span\n class=\"inline-flex items-center gap-1 px-2 py-1 rounded-full text-xs font-medium bg-blue-100 text-blue-800\"\n >\n {{ getShowLabel(id) }}\n <button\n type=\"button\"\n class=\"ml-1 hover:text-blue-600 leading-none\"\n (click)=\"removeShow(id)\"\n >\n &times;\n </button>\n </span>\n }\n </div>\n }\n\n <input\n type=\"text\"\n [placeholder]=\"placeholder\"\n class=\"w-full px-3 py-2 border border-gray-300 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent\"\n (input)=\"onSearchChange($event)\"\n />\n\n @if (loading()) {\n <div class=\"flex items-center gap-2 mt-2 text-sm text-gray-500\">\n <div\n class=\"w-4 h-4 border-2 border-gray-200 border-t-blue-500 rounded-full animate-spin\"\n ></div>\n Cargando funciones...\n </div>\n }\n\n @if (!loading() && filteredShows().length > 0) {\n <div\n class=\"mt-1 max-h-48 overflow-y-auto border border-gray-200 rounded-md divide-y divide-gray-100\"\n >\n @for (show of filteredShows(); track show.value) {\n <label class=\"flex items-center gap-2 px-3 py-2 hover:bg-gray-50 cursor-pointer text-sm\">\n <input\n type=\"checkbox\"\n [checked]=\"isSelected(show.value)\"\n (change)=\"toggleShow(show.value)\"\n class=\"w-4 h-4 accent-blue-500 cursor-pointer\"\n />\n <span class=\"text-gray-700 select-none\">{{ show.label }}</span>\n </label>\n }\n </div>\n }\n\n @if (!loading() && filteredShows().length === 0) {\n <p class=\"text-sm text-gray-500 mt-1\">No se encontraron funciones</p>\n }\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }] });
4427
+ }
4428
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: ShowMultiSelectComponent, decorators: [{
4429
+ type: Component,
4430
+ args: [{ selector: 'show-multi-select', standalone: true, imports: [CommonModule], providers: [
4431
+ {
4432
+ provide: NG_VALUE_ACCESSOR,
4433
+ useExisting: forwardRef(() => ShowMultiSelectComponent),
4434
+ multi: true,
4435
+ },
4436
+ ], template: "<div class=\"w-full\">\n @if (label) {\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n {{ label }}\n </label>\n }\n\n @if (selectedIds.length > 0) {\n <div class=\"flex flex-wrap gap-1 mb-2\">\n @for (id of selectedIds; track id) {\n <span\n class=\"inline-flex items-center gap-1 px-2 py-1 rounded-full text-xs font-medium bg-blue-100 text-blue-800\"\n >\n {{ getShowLabel(id) }}\n <button\n type=\"button\"\n class=\"ml-1 hover:text-blue-600 leading-none\"\n (click)=\"removeShow(id)\"\n >\n &times;\n </button>\n </span>\n }\n </div>\n }\n\n <input\n type=\"text\"\n [placeholder]=\"placeholder\"\n class=\"w-full px-3 py-2 border border-gray-300 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent\"\n (input)=\"onSearchChange($event)\"\n />\n\n @if (loading()) {\n <div class=\"flex items-center gap-2 mt-2 text-sm text-gray-500\">\n <div\n class=\"w-4 h-4 border-2 border-gray-200 border-t-blue-500 rounded-full animate-spin\"\n ></div>\n Cargando funciones...\n </div>\n }\n\n @if (!loading() && filteredShows().length > 0) {\n <div\n class=\"mt-1 max-h-48 overflow-y-auto border border-gray-200 rounded-md divide-y divide-gray-100\"\n >\n @for (show of filteredShows(); track show.value) {\n <label class=\"flex items-center gap-2 px-3 py-2 hover:bg-gray-50 cursor-pointer text-sm\">\n <input\n type=\"checkbox\"\n [checked]=\"isSelected(show.value)\"\n (change)=\"toggleShow(show.value)\"\n class=\"w-4 h-4 accent-blue-500 cursor-pointer\"\n />\n <span class=\"text-gray-700 select-none\">{{ show.label }}</span>\n </label>\n }\n </div>\n }\n\n @if (!loading() && filteredShows().length === 0) {\n <p class=\"text-sm text-gray-500 mt-1\">No se encontraron funciones</p>\n }\n</div>\n" }]
4437
+ }], ctorParameters: () => [{ type: undefined, decorators: [{
4438
+ type: Inject,
4439
+ args: [PLATFORM_ID]
4440
+ }] }, { type: ShowService }], propDecorators: { label: [{
4441
+ type: Input
4442
+ }], placeholder: [{
4443
+ type: Input
4444
+ }] } });
4445
+
4446
+ class PriceZoneSelectComponent {
4447
+ platformId;
4448
+ priceZoneService;
4449
+ label = 'Categoría';
4450
+ placeholder = 'Selecciona una categoría';
4451
+ name = 'price_zone_id';
4452
+ required = false;
4453
+ readonly = false;
4454
+ showError = true;
4455
+ customClass = '';
4456
+ control = null;
4457
+ priceZoneChange = new EventEmitter();
4458
+ priceZones = signal([], ...(ngDevMode ? [{ debugName: "priceZones" }] : []));
4459
+ loading = signal(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
4460
+ searchTerm = '';
4461
+ searchSubject = new Subject();
4462
+ destroy$ = new Subject();
4463
+ value = null;
4464
+ onChange = () => { };
4465
+ onTouched = () => { };
4466
+ constructor(platformId, priceZoneService) {
4467
+ this.platformId = platformId;
4468
+ this.priceZoneService = priceZoneService;
4469
+ }
4470
+ ngOnInit() {
4471
+ if (isPlatformBrowser(this.platformId)) {
4472
+ this.priceZoneService.loadPriceZones({ search: this.searchTerm });
4473
+ this.priceZoneService.priceZones$
4474
+ .pipe(takeUntil(this.destroy$))
4475
+ .subscribe((priceZones) => {
4476
+ this.priceZones.set(priceZones?.map((pz) => ({
4477
+ value: pz.id,
4478
+ label: pz.name,
4479
+ })) || []);
4480
+ this.loading.set(false);
4481
+ });
4482
+ this.searchSubject
4483
+ .pipe(debounceTime(400), distinctUntilChanged(), takeUntil(this.destroy$))
4484
+ .subscribe((search) => {
4485
+ this.searchTerm = search;
4486
+ this.priceZoneService.loadPriceZones({ search: this.searchTerm });
4487
+ });
4488
+ }
4489
+ }
4490
+ get formControl() {
4491
+ return this.control;
4492
+ }
4493
+ ngOnDestroy() {
4494
+ this.destroy$.next();
4495
+ this.destroy$.complete();
4496
+ }
4497
+ onSearchChange(search) {
4498
+ this.searchSubject.next(search);
4499
+ }
4500
+ onPriceZoneSelected(event) {
4501
+ const select = event.target;
4502
+ const value = select.value ? Number(select.value) : null;
4503
+ this.value = value;
4504
+ if (this.control) {
4505
+ this.control.setValue(value);
4506
+ this.control.markAsTouched();
4507
+ }
4508
+ this.priceZoneChange.emit(value);
4509
+ }
4510
+ writeValue(value) {
4511
+ this.value = value;
4512
+ }
4513
+ registerOnChange(fn) {
4514
+ this.onChange = fn;
4515
+ }
4516
+ registerOnTouched(fn) {
4517
+ this.onTouched = fn;
4518
+ }
4519
+ validate(control) {
4520
+ if (this.required && !control.value) {
4521
+ return { required: true };
4522
+ }
4523
+ return null;
4524
+ }
4525
+ get isInvalid() {
4526
+ return false;
4527
+ }
4528
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: PriceZoneSelectComponent, deps: [{ token: PLATFORM_ID }, { token: PriceZoneService }], target: i0.ɵɵFactoryTarget.Component });
4529
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.25", type: PriceZoneSelectComponent, isStandalone: true, selector: "price-zone-select", inputs: { label: "label", placeholder: "placeholder", name: "name", required: "required", readonly: "readonly", showError: "showError", customClass: "customClass", control: "control" }, outputs: { priceZoneChange: "priceZoneChange" }, providers: [
4530
+ {
4531
+ provide: NG_VALUE_ACCESSOR,
4532
+ useExisting: forwardRef(() => PriceZoneSelectComponent),
4533
+ multi: true,
4534
+ },
4535
+ {
4536
+ provide: NG_VALIDATORS,
4537
+ useExisting: forwardRef(() => PriceZoneSelectComponent),
4538
+ multi: true,
4539
+ },
4540
+ ], ngImport: i0, template: "<form-select\n [label]=\"label\"\n [placeholder]=\"placeholder\"\n [name]=\"name || 'price_zone_id'\"\n [class]=\"customClass\"\n [options]=\"priceZones()\"\n [required]=\"required\"\n [readonly]=\"readonly\"\n [formControl]=\"formControl\"\n (change)=\"onPriceZoneSelected($event)\"\n></form-select>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: FormSelectComponent, selector: "form-select", inputs: ["label", "name", "id", "placeholder", "required", "disabled", "readonly", "options", "fieldGroupClass", "showDefaultOption", "defaultOptionLabel"] }] });
4541
+ }
4542
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: PriceZoneSelectComponent, decorators: [{
4543
+ type: Component,
4544
+ args: [{ selector: 'price-zone-select', standalone: true, imports: [CommonModule, ReactiveFormsModule, FormSelectComponent], providers: [
4545
+ {
4546
+ provide: NG_VALUE_ACCESSOR,
4547
+ useExisting: forwardRef(() => PriceZoneSelectComponent),
4548
+ multi: true,
4549
+ },
4550
+ {
4551
+ provide: NG_VALIDATORS,
4552
+ useExisting: forwardRef(() => PriceZoneSelectComponent),
4553
+ multi: true,
4554
+ },
4555
+ ], template: "<form-select\n [label]=\"label\"\n [placeholder]=\"placeholder\"\n [name]=\"name || 'price_zone_id'\"\n [class]=\"customClass\"\n [options]=\"priceZones()\"\n [required]=\"required\"\n [readonly]=\"readonly\"\n [formControl]=\"formControl\"\n (change)=\"onPriceZoneSelected($event)\"\n></form-select>\n" }]
4556
+ }], ctorParameters: () => [{ type: undefined, decorators: [{
4557
+ type: Inject,
4558
+ args: [PLATFORM_ID]
4559
+ }] }, { type: PriceZoneService }], propDecorators: { label: [{
4560
+ type: Input
4561
+ }], placeholder: [{
4562
+ type: Input
4563
+ }], name: [{
4564
+ type: Input
4565
+ }], required: [{
4566
+ type: Input
4567
+ }], readonly: [{
4568
+ type: Input
4569
+ }], showError: [{
4570
+ type: Input
4571
+ }], customClass: [{
4572
+ type: Input
4573
+ }], control: [{
4574
+ type: Input
4575
+ }], priceZoneChange: [{
4576
+ type: Output
4577
+ }] } });
4578
+
4579
+ // Config
4580
+
4581
+ /**
4582
+ * Generated bundle index. Do not edit.
4583
+ */
4584
+
4585
+ export { ADMIN_API_ROUTES, ALERT_BASE_CLASSES, ALERT_COLOR_CLASSES, ALERT_ICONS, ALERT_SIZE_CLASSES, AdminSelectComponent, AdminService, ApiService, AppAlertComponent, AppButtonComponent, AppLinkButtonComponent, AppModalComponent, AsyncSelectComponent, AuditInformationComponent, BASE_BUTTON_CLASSES, BASE_INPUT_CLASSES, BUTTON_SIZES_CLASSES, BUTTON_VARIANT_CLASSES, CITY_API_ENDPOINTS, COUNTRY_API_ENDPOINTS, CUSTOMERS_API_ROUTES, ChangePasswordFormComponent, ChangePasswordFormService, CitiesService, CitySelectComponent, ColorPickerComponent, CorporateBondStatus, CountrySelectComponent, CountryService, CouponApplicability, CouponDiscountType, CustomerSelectComponent, CustomerService, DateInputComponent, DateService, DeleteConfirmationComponent, DeleteConfirmationService, DynamicTableComponent, ERROR_INPUT_CLASSES, EndDateGreaterThanStartValidator, FORM_ERROR_MESSAGES, FileType, FileUploadComponent, FileUploadPreviewComponent, FormEditorComponent, FormInputComponent, FormSelectComponent, FormTextareaComponent, LanguageSwitcherComponent, LoadingModalService, LoadingmModalComponent, MinTodayValidator, MustMatchValidator, OrderItemType, OrderStatus, PERFORMANCES_API_ROUTES, PRICE_ZONES_API_ROUTES, PRODUCTS_API_ROUTES, PerformanceMultiSelectComponent, PerformanceSelectComponent, PerformanceService, PerformanceStatus, PerformanceTicketStatus, PerformancesListEventsService, PriceZoneEventService, PriceZoneFormModalService, PriceZoneSelectComponent, PriceZoneService, ProductMultiSelectComponent, ProductSelectComponent, ProductService, RoomMapElementOrientation, RoomMapElementType, SHOWS_API_ROUTES, STATE_API_ENDPOINTS, ShowMultiSelectComponent, ShowSelectComponent, ShowService, StateSelectComponent, StatesService, TICKERA_COMPONENTS_CONFIG, ToastService, ToggleSwitchComponent, VENUES_API_ROUTES, authInterceptor, formatCitiesResponseToSelect, getCustomerFullname, parseJsonToFormDataAdvanced, provideTickeraComponents, transformImageToFile };
4586
+ //# sourceMappingURL=tickera-angular-components.mjs.map