valtech-components 2.0.427 → 2.0.429

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/esm2022/lib/components/molecules/glow-card/glow-card.component.mjs +49 -20
  2. package/esm2022/lib/components/molecules/glow-card/types.mjs +1 -1
  3. package/esm2022/lib/components/organisms/article/article.component.mjs +28 -3
  4. package/esm2022/lib/services/firebase/config.mjs +108 -0
  5. package/esm2022/lib/services/firebase/firebase.service.mjs +285 -0
  6. package/esm2022/lib/services/firebase/firestore-collection.mjs +266 -0
  7. package/esm2022/lib/services/firebase/firestore.service.mjs +508 -0
  8. package/esm2022/lib/services/firebase/index.mjs +46 -0
  9. package/esm2022/lib/services/firebase/messaging.service.mjs +503 -0
  10. package/esm2022/lib/services/firebase/storage.service.mjs +421 -0
  11. package/esm2022/lib/services/firebase/types.mjs +8 -0
  12. package/esm2022/lib/services/firebase/utils/path-builder.mjs +195 -0
  13. package/esm2022/lib/services/firebase/utils/query-builder.mjs +302 -0
  14. package/esm2022/public-api.mjs +3 -4
  15. package/fesm2022/valtech-components.mjs +2886 -230
  16. package/fesm2022/valtech-components.mjs.map +1 -1
  17. package/lib/components/molecules/glow-card/glow-card.component.d.ts +1 -0
  18. package/lib/components/molecules/glow-card/types.d.ts +7 -5
  19. package/lib/components/organisms/article/article.component.d.ts +6 -1
  20. package/lib/services/firebase/config.d.ts +49 -0
  21. package/lib/services/firebase/firebase.service.d.ts +140 -0
  22. package/lib/services/firebase/firestore-collection.d.ts +195 -0
  23. package/lib/services/firebase/firestore.service.d.ts +303 -0
  24. package/lib/services/firebase/index.d.ts +38 -0
  25. package/lib/services/firebase/messaging.service.d.ts +254 -0
  26. package/lib/services/firebase/storage.service.d.ts +204 -0
  27. package/lib/services/firebase/types.d.ts +281 -0
  28. package/lib/services/firebase/utils/path-builder.d.ts +132 -0
  29. package/lib/services/firebase/utils/query-builder.d.ts +210 -0
  30. package/package.json +3 -1
  31. package/public-api.d.ts +1 -0
@@ -0,0 +1,303 @@
1
+ import { FieldValue } from '@angular/fire/firestore';
2
+ import { Observable } from 'rxjs';
3
+ import { FirestoreDocument, PaginatedResult, QueryOptions } from './types';
4
+ import * as i0 from "@angular/core";
5
+ /**
6
+ * Servicio para operaciones CRUD en Firestore.
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * interface User extends FirestoreDocument {
11
+ * name: string;
12
+ * email: string;
13
+ * role: 'admin' | 'user';
14
+ * }
15
+ *
16
+ * @Component({...})
17
+ * export class UsersComponent {
18
+ * private firestore = inject(FirestoreService);
19
+ *
20
+ * // Lectura one-time
21
+ * async loadUser(id: string) {
22
+ * const user = await this.firestore.getDoc<User>('users', id);
23
+ * }
24
+ *
25
+ * // Subscripción real-time
26
+ * users$ = this.firestore.collectionChanges<User>('users', {
27
+ * where: [{ field: 'role', operator: '==', value: 'admin' }],
28
+ * orderBy: [{ field: 'name', direction: 'asc' }]
29
+ * });
30
+ *
31
+ * // Crear documento
32
+ * async createUser(data: Omit<User, 'id'>) {
33
+ * const user = await this.firestore.addDoc<User>('users', data);
34
+ * }
35
+ * }
36
+ * ```
37
+ */
38
+ export declare class FirestoreService {
39
+ private firestore;
40
+ /**
41
+ * Obtiene un documento por ID (lectura única).
42
+ *
43
+ * @param collectionPath - Ruta de la colección
44
+ * @param docId - ID del documento
45
+ * @returns Documento o null si no existe
46
+ *
47
+ * @example
48
+ * ```typescript
49
+ * const user = await firestoreService.getDoc<User>('users', 'abc123');
50
+ * if (user) {
51
+ * console.log(user.name);
52
+ * }
53
+ * ```
54
+ */
55
+ getDoc<T extends FirestoreDocument>(collectionPath: string, docId: string): Promise<T | null>;
56
+ /**
57
+ * Obtiene múltiples documentos con opciones de query.
58
+ *
59
+ * @param collectionPath - Ruta de la colección
60
+ * @param options - Opciones de query (where, orderBy, limit)
61
+ * @returns Array de documentos
62
+ *
63
+ * @example
64
+ * ```typescript
65
+ * // Todos los usuarios activos ordenados por nombre
66
+ * const users = await firestoreService.getDocs<User>('users', {
67
+ * where: [{ field: 'active', operator: '==', value: true }],
68
+ * orderBy: [{ field: 'name', direction: 'asc' }],
69
+ * limit: 50
70
+ * });
71
+ * ```
72
+ */
73
+ getDocs<T extends FirestoreDocument>(collectionPath: string, options?: QueryOptions): Promise<T[]>;
74
+ /**
75
+ * Obtiene documentos con paginación basada en cursores.
76
+ *
77
+ * @param collectionPath - Ruta de la colección
78
+ * @param options - Opciones de query (debe incluir limit)
79
+ * @returns Resultado paginado con cursor para la siguiente página
80
+ *
81
+ * @example
82
+ * ```typescript
83
+ * // Primera página
84
+ * const page1 = await firestoreService.getPaginated<User>('users', {
85
+ * orderBy: [{ field: 'createdAt', direction: 'desc' }],
86
+ * limit: 10
87
+ * });
88
+ *
89
+ * // Siguiente página
90
+ * if (page1.hasMore) {
91
+ * const page2 = await firestoreService.getPaginated<User>('users', {
92
+ * orderBy: [{ field: 'createdAt', direction: 'desc' }],
93
+ * limit: 10,
94
+ * startAfter: page1.lastDoc
95
+ * });
96
+ * }
97
+ * ```
98
+ */
99
+ getPaginated<T extends FirestoreDocument>(collectionPath: string, options: QueryOptions & {
100
+ limit: number;
101
+ }): Promise<PaginatedResult<T>>;
102
+ /**
103
+ * Verifica si un documento existe.
104
+ *
105
+ * @param collectionPath - Ruta de la colección
106
+ * @param docId - ID del documento
107
+ * @returns true si el documento existe
108
+ */
109
+ exists(collectionPath: string, docId: string): Promise<boolean>;
110
+ /**
111
+ * Suscribe a cambios de un documento (real-time).
112
+ *
113
+ * @param collectionPath - Ruta de la colección
114
+ * @param docId - ID del documento
115
+ * @returns Observable que emite cuando el documento cambia
116
+ *
117
+ * @example
118
+ * ```typescript
119
+ * // En el componente
120
+ * user$ = this.firestoreService.docChanges<User>('users', this.userId);
121
+ *
122
+ * // En el template
123
+ * @if (user$ | async; as user) {
124
+ * <p>{{ user.name }}</p>
125
+ * }
126
+ * ```
127
+ */
128
+ docChanges<T extends FirestoreDocument>(collectionPath: string, docId: string): Observable<T | null>;
129
+ /**
130
+ * Suscribe a cambios de una colección (real-time).
131
+ *
132
+ * @param collectionPath - Ruta de la colección
133
+ * @param options - Opciones de query
134
+ * @returns Observable que emite cuando la colección cambia
135
+ *
136
+ * @example
137
+ * ```typescript
138
+ * // Usuarios activos en tiempo real
139
+ * activeUsers$ = this.firestoreService.collectionChanges<User>('users', {
140
+ * where: [{ field: 'status', operator: '==', value: 'online' }]
141
+ * });
142
+ * ```
143
+ */
144
+ collectionChanges<T extends FirestoreDocument>(collectionPath: string, options?: QueryOptions): Observable<T[]>;
145
+ /**
146
+ * Agrega un documento con ID auto-generado.
147
+ *
148
+ * @param collectionPath - Ruta de la colección
149
+ * @param data - Datos del documento (sin id, createdAt, updatedAt)
150
+ * @returns Documento creado con su ID
151
+ *
152
+ * @example
153
+ * ```typescript
154
+ * const newUser = await firestoreService.addDoc<User>('users', {
155
+ * name: 'John Doe',
156
+ * email: 'john@example.com',
157
+ * role: 'user'
158
+ * });
159
+ * console.log('Created user with ID:', newUser.id);
160
+ * ```
161
+ */
162
+ addDoc<T extends FirestoreDocument>(collectionPath: string, data: Omit<T, 'id' | 'createdAt' | 'updatedAt'>): Promise<T>;
163
+ /**
164
+ * Crea o sobrescribe un documento con ID específico.
165
+ *
166
+ * @param collectionPath - Ruta de la colección
167
+ * @param docId - ID del documento
168
+ * @param data - Datos del documento
169
+ * @param options - Opciones (merge: true para merge en lugar de sobrescribir)
170
+ *
171
+ * @example
172
+ * ```typescript
173
+ * // Sobrescribir completamente
174
+ * await firestoreService.setDoc<User>('users', 'user123', userData);
175
+ *
176
+ * // Merge con datos existentes
177
+ * await firestoreService.setDoc<User>('users', 'user123', { name: 'New Name' }, { merge: true });
178
+ * ```
179
+ */
180
+ setDoc<T extends FirestoreDocument>(collectionPath: string, docId: string, data: Omit<T, 'id'>, options?: {
181
+ merge?: boolean;
182
+ }): Promise<void>;
183
+ /**
184
+ * Actualiza campos específicos de un documento.
185
+ *
186
+ * @param collectionPath - Ruta de la colección
187
+ * @param docId - ID del documento
188
+ * @param data - Campos a actualizar
189
+ *
190
+ * @example
191
+ * ```typescript
192
+ * await firestoreService.updateDoc<User>('users', 'user123', {
193
+ * name: 'Updated Name',
194
+ * lastLogin: new Date()
195
+ * });
196
+ * ```
197
+ */
198
+ updateDoc<T extends FirestoreDocument>(collectionPath: string, docId: string, data: Partial<Omit<T, 'id' | 'createdAt'>>): Promise<void>;
199
+ /**
200
+ * Elimina un documento.
201
+ *
202
+ * @param collectionPath - Ruta de la colección
203
+ * @param docId - ID del documento
204
+ *
205
+ * @example
206
+ * ```typescript
207
+ * await firestoreService.deleteDoc('users', 'user123');
208
+ * ```
209
+ */
210
+ deleteDoc(collectionPath: string, docId: string): Promise<void>;
211
+ /**
212
+ * Ejecuta múltiples operaciones de escritura de forma atómica.
213
+ *
214
+ * @param operations - Función que recibe el batch y agrega operaciones
215
+ *
216
+ * @example
217
+ * ```typescript
218
+ * await firestoreService.batch((batch) => {
219
+ * batch.set('users/user1', { name: 'User 1' });
220
+ * batch.update('users/user2', { status: 'inactive' });
221
+ * batch.delete('users/user3');
222
+ * });
223
+ * ```
224
+ */
225
+ batch(operations: (batch: {
226
+ set: <T>(path: string, data: T) => void;
227
+ update: <T>(path: string, data: Partial<T>) => void;
228
+ delete: (path: string) => void;
229
+ }) => void): Promise<void>;
230
+ /**
231
+ * Construye una ruta a partir de un template.
232
+ *
233
+ * @param template - Template con placeholders {param}
234
+ * @param params - Valores para los placeholders
235
+ * @returns Ruta construida
236
+ *
237
+ * @example
238
+ * ```typescript
239
+ * const path = firestoreService.buildPath('users/{userId}/documents/{docId}', {
240
+ * userId: 'user123',
241
+ * docId: 'doc456'
242
+ * });
243
+ * // => 'users/user123/documents/doc456'
244
+ * ```
245
+ */
246
+ buildPath(template: string, params: Record<string, string>): string;
247
+ /**
248
+ * Genera un ID único para un documento (sin crearlo).
249
+ *
250
+ * @param collectionPath - Ruta de la colección
251
+ * @returns ID único generado por Firestore
252
+ */
253
+ generateId(collectionPath: string): string;
254
+ /**
255
+ * Retorna un valor de timestamp del servidor.
256
+ * Usar en campos de fecha para que Firestore asigne el timestamp.
257
+ */
258
+ serverTimestamp(): FieldValue;
259
+ /**
260
+ * Retorna un valor para agregar elementos a un array.
261
+ *
262
+ * @example
263
+ * ```typescript
264
+ * await firestoreService.updateDoc('users', 'user123', {
265
+ * tags: firestoreService.arrayUnion('new-tag')
266
+ * });
267
+ * ```
268
+ */
269
+ arrayUnion(...elements: unknown[]): FieldValue;
270
+ /**
271
+ * Retorna un valor para remover elementos de un array.
272
+ */
273
+ arrayRemove(...elements: unknown[]): FieldValue;
274
+ /**
275
+ * Retorna un valor para incrementar un campo numérico.
276
+ *
277
+ * @example
278
+ * ```typescript
279
+ * await firestoreService.updateDoc('users', 'user123', {
280
+ * loginCount: firestoreService.increment(1)
281
+ * });
282
+ * ```
283
+ */
284
+ increment(n: number): FieldValue;
285
+ /**
286
+ * Construye los QueryConstraints a partir de QueryOptions
287
+ */
288
+ private buildQueryConstraints;
289
+ /**
290
+ * Mapea un DocumentSnapshot a nuestro tipo
291
+ */
292
+ private mapDocument;
293
+ /**
294
+ * Convierte Timestamps de Firestore a Date de JavaScript
295
+ */
296
+ private convertTimestamps;
297
+ /**
298
+ * Divide una ruta de documento en colección e ID
299
+ */
300
+ private splitPath;
301
+ static ɵfac: i0.ɵɵFactoryDeclaration<FirestoreService, never>;
302
+ static ɵprov: i0.ɵɵInjectableDeclaration<FirestoreService>;
303
+ }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Firebase Services
3
+ *
4
+ * Servicios reutilizables para integración con Firebase.
5
+ *
6
+ * @example
7
+ * ```typescript
8
+ * // En main.ts
9
+ * import { provideValtechFirebase } from 'valtech-components';
10
+ *
11
+ * bootstrapApplication(AppComponent, {
12
+ * providers: [
13
+ * provideValtechFirebase({
14
+ * firebase: environment.firebase,
15
+ * persistence: true,
16
+ * }),
17
+ * ],
18
+ * });
19
+ *
20
+ * // En componentes
21
+ * import { FirebaseService, FirestoreService } from 'valtech-components';
22
+ *
23
+ * @Component({...})
24
+ * export class MyComponent {
25
+ * private firebase = inject(FirebaseService);
26
+ * private firestore = inject(FirestoreService);
27
+ * }
28
+ * ```
29
+ */
30
+ export * from './types';
31
+ export { VALTECH_FIREBASE_CONFIG, hasEmulators, provideValtechFirebase } from './config';
32
+ export { FirebaseService } from './firebase.service';
33
+ export { FirestoreService } from './firestore.service';
34
+ export { CollectionOptions, FirestoreCollection, SubCollectionRef } from './firestore-collection';
35
+ export { QueryBuilder, query } from './utils/query-builder';
36
+ export { buildPath, extractPathParams, getCollectionPath, getDocumentId, isCollectionPath, isDocumentPath, isValidPath, joinPath, } from './utils/path-builder';
37
+ export { StorageService } from './storage.service';
38
+ export { MessagingService } from './messaging.service';
@@ -0,0 +1,254 @@
1
+ import { Observable } from 'rxjs';
2
+ import { NotificationAction, NotificationClickEvent, NotificationPayload, NotificationPermission } from './types';
3
+ import * as i0 from "@angular/core";
4
+ /**
5
+ * Estado interno del servicio de messaging
6
+ */
7
+ interface MessagingState {
8
+ token: string | null;
9
+ permission: NotificationPermission;
10
+ isSupported: boolean;
11
+ }
12
+ /**
13
+ * Servicio para Firebase Cloud Messaging (FCM).
14
+ *
15
+ * Permite recibir notificaciones push en la aplicación web.
16
+ * Requiere VAPID key configurada en ValtechFirebaseConfig.
17
+ *
18
+ * @example
19
+ * ```typescript
20
+ * @Component({...})
21
+ * export class NotificationComponent {
22
+ * private messaging = inject(MessagingService);
23
+ *
24
+ * token = signal<string | null>(null);
25
+ *
26
+ * async enableNotifications() {
27
+ * // Solicitar permiso y obtener token
28
+ * const token = await this.messaging.requestPermission();
29
+ *
30
+ * if (token) {
31
+ * this.token.set(token);
32
+ * // Enviar token a tu backend para almacenarlo
33
+ * await this.backend.registerDeviceToken(token);
34
+ * }
35
+ * }
36
+ *
37
+ * // Escuchar mensajes en foreground
38
+ * messages$ = this.messaging.onMessage();
39
+ * }
40
+ * ```
41
+ */
42
+ export declare class MessagingService {
43
+ private messaging;
44
+ private config;
45
+ private platformId;
46
+ private ngZone;
47
+ private messageSubject;
48
+ private notificationClickSubject;
49
+ private stateSubject;
50
+ private unsubscribeOnMessage?;
51
+ constructor();
52
+ /**
53
+ * Inicializa el servicio de messaging
54
+ */
55
+ private initializeMessaging;
56
+ /**
57
+ * Configura listener para mensajes del Service Worker.
58
+ * Recibe eventos cuando el usuario hace click en una notificación background.
59
+ */
60
+ private setupServiceWorkerListener;
61
+ /**
62
+ * Verifica si FCM está soportado en el navegador actual
63
+ */
64
+ private checkSupport;
65
+ /**
66
+ * Solicita permiso de notificaciones y obtiene el token FCM.
67
+ *
68
+ * @returns Token FCM si se otorgó permiso, null si se denegó
69
+ *
70
+ * @example
71
+ * ```typescript
72
+ * const token = await messaging.requestPermission();
73
+ * if (token) {
74
+ * console.log('Token FCM:', token);
75
+ * // Enviar a backend
76
+ * } else {
77
+ * console.log('Permiso denegado o no soportado');
78
+ * }
79
+ * ```
80
+ */
81
+ requestPermission(): Promise<string | null>;
82
+ /**
83
+ * Obtiene el token FCM actual (sin solicitar permiso).
84
+ *
85
+ * @returns Token FCM si está disponible, null si no
86
+ *
87
+ * @example
88
+ * ```typescript
89
+ * const token = await messaging.getToken();
90
+ * ```
91
+ */
92
+ getToken(): Promise<string | null>;
93
+ /**
94
+ * Elimina el token FCM actual (unsubscribe de notificaciones).
95
+ *
96
+ * @example
97
+ * ```typescript
98
+ * await messaging.deleteToken();
99
+ * console.log('Token eliminado, no recibirá más notificaciones');
100
+ * ```
101
+ */
102
+ deleteToken(): Promise<void>;
103
+ /**
104
+ * Observable de mensajes recibidos en foreground.
105
+ *
106
+ * IMPORTANTE: Los mensajes en background son manejados por el Service Worker.
107
+ *
108
+ * @returns Observable que emite cuando llega un mensaje en foreground
109
+ *
110
+ * @example
111
+ * ```typescript
112
+ * messaging.onMessage().subscribe(payload => {
113
+ * console.log('Mensaje recibido:', payload);
114
+ * // Mostrar notificación custom o actualizar UI
115
+ * });
116
+ * ```
117
+ */
118
+ onMessage(): Observable<NotificationPayload>;
119
+ /**
120
+ * Configura el listener de mensajes en foreground
121
+ */
122
+ private setupMessageListener;
123
+ /**
124
+ * Obtiene el estado actual del permiso de notificaciones.
125
+ *
126
+ * @returns 'granted' | 'denied' | 'default'
127
+ *
128
+ * @example
129
+ * ```typescript
130
+ * const permission = messaging.getPermissionState();
131
+ * if (permission === 'granted') {
132
+ * // Ya tiene permiso
133
+ * } else if (permission === 'default') {
134
+ * // Puede solicitar permiso
135
+ * } else {
136
+ * // Denegado, debe habilitar manualmente
137
+ * }
138
+ * ```
139
+ */
140
+ getPermissionState(): NotificationPermission;
141
+ /**
142
+ * Verifica si FCM está soportado en el navegador actual.
143
+ *
144
+ * @returns true si FCM está soportado
145
+ *
146
+ * @example
147
+ * ```typescript
148
+ * if (await messaging.isSupported()) {
149
+ * // Puede usar notificaciones push
150
+ * } else {
151
+ * // Navegador no soporta o no tiene Service Worker
152
+ * }
153
+ * ```
154
+ */
155
+ isSupported(): Promise<boolean>;
156
+ /**
157
+ * Obtiene el token actual sin hacer request.
158
+ *
159
+ * @returns Token almacenado o null
160
+ */
161
+ get currentToken(): string | null;
162
+ /**
163
+ * Observable del estado completo del servicio de messaging.
164
+ */
165
+ get state$(): Observable<MessagingState>;
166
+ /**
167
+ * Verifica si el usuario ya otorgó permiso de notificaciones.
168
+ */
169
+ get hasPermission(): boolean;
170
+ /**
171
+ * Observable de clicks en notificaciones.
172
+ *
173
+ * Emite cuando el usuario hace click en una notificación (foreground o background).
174
+ * Usa este observable para navegar a la página correspondiente.
175
+ *
176
+ * @returns Observable que emite NotificationClickEvent
177
+ *
178
+ * @example
179
+ * ```typescript
180
+ * @Component({...})
181
+ * export class AppComponent {
182
+ * private messaging = inject(MessagingService);
183
+ * private router = inject(Router);
184
+ *
185
+ * constructor() {
186
+ * this.messaging.onNotificationClick().subscribe(event => {
187
+ * if (event.action.route) {
188
+ * this.router.navigate([event.action.route], {
189
+ * queryParams: event.action.queryParams
190
+ * });
191
+ * }
192
+ * });
193
+ * }
194
+ * }
195
+ * ```
196
+ */
197
+ onNotificationClick(): Observable<NotificationClickEvent>;
198
+ /**
199
+ * Extrae la acción de navegación de los datos de una notificación.
200
+ *
201
+ * Busca campos específicos en el payload de datos:
202
+ * - `route`: Ruta interna de la app (ej: '/orders/123')
203
+ * - `url`: URL externa (ej: 'https://example.com')
204
+ * - `action_type`: Tipo de acción personalizada
205
+ * - Campos con prefijo `action_`: Datos adicionales
206
+ *
207
+ * @param data - Datos del payload de la notificación
208
+ * @returns Acción de navegación extraída
209
+ *
210
+ * @example
211
+ * ```typescript
212
+ * // Payload desde el backend:
213
+ * // { route: '/orders/123', action_type: 'view_order', action_orderId: '123' }
214
+ *
215
+ * const action = messaging.extractActionFromData(notification.data);
216
+ * // { route: '/orders/123', actionType: 'view_order', actionData: { orderId: '123' } }
217
+ * ```
218
+ */
219
+ extractActionFromData(data?: Record<string, string>): NotificationAction;
220
+ /**
221
+ * Emite manualmente un evento de click en notificación.
222
+ *
223
+ * Útil para manejar clicks en notificaciones foreground donde
224
+ * la app decide mostrar un banner custom.
225
+ *
226
+ * @param notification - Payload de la notificación
227
+ *
228
+ * @example
229
+ * ```typescript
230
+ * messaging.onMessage().subscribe(notification => {
231
+ * // Mostrar banner custom
232
+ * this.showBanner(notification, () => {
233
+ * // Usuario hizo click en el banner
234
+ * messaging.handleNotificationClick(notification);
235
+ * });
236
+ * });
237
+ * ```
238
+ */
239
+ handleNotificationClick(notification: NotificationPayload): void;
240
+ /**
241
+ * Verifica si una notificación tiene acción de navegación.
242
+ *
243
+ * @param data - Datos del payload
244
+ * @returns true si tiene route o url
245
+ */
246
+ hasNavigationAction(data?: Record<string, string>): boolean;
247
+ /**
248
+ * Parsea un query string en un objeto.
249
+ */
250
+ private parseQueryString;
251
+ static ɵfac: i0.ɵɵFactoryDeclaration<MessagingService, never>;
252
+ static ɵprov: i0.ɵɵInjectableDeclaration<MessagingService>;
253
+ }
254
+ export {};