valtech-components 2.0.946 → 2.0.948
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.
- package/esm2022/lib/components/organisms/fun-modal/fun-modal.component.mjs +135 -0
- package/esm2022/lib/components/organisms/fun-modal/types.mjs +8 -0
- package/esm2022/lib/components/organisms/share-profile-modal/share-profile-modal.component.mjs +221 -0
- package/esm2022/lib/components/organisms/share-profile-modal/types.mjs +10 -0
- package/esm2022/lib/services/content/index.mjs +1 -1
- package/esm2022/lib/services/content-platform/config.mjs +40 -0
- package/esm2022/lib/services/content-platform/content.service.mjs +138 -0
- package/esm2022/lib/services/content-platform/index.mjs +10 -0
- package/esm2022/lib/services/content-platform/types.mjs +19 -0
- package/esm2022/lib/services/requests/request-firestore.service.mjs +55 -0
- package/esm2022/lib/services/requests/types.mjs +1 -1
- package/esm2022/lib/version.mjs +2 -2
- package/esm2022/public-api.mjs +10 -1
- package/fesm2022/valtech-components.mjs +597 -13
- package/fesm2022/valtech-components.mjs.map +1 -1
- package/lib/components/organisms/fun-modal/fun-modal.component.d.ts +44 -0
- package/lib/components/organisms/fun-modal/types.d.ts +37 -0
- package/lib/components/organisms/share-profile-modal/share-profile-modal.component.d.ts +49 -0
- package/lib/components/organisms/share-profile-modal/types.d.ts +45 -0
- package/lib/services/content/index.d.ts +1 -1
- package/lib/services/content-platform/config.d.ts +38 -0
- package/lib/services/content-platform/content.service.d.ts +70 -0
- package/lib/services/content-platform/index.d.ts +10 -0
- package/lib/services/content-platform/types.d.ts +117 -0
- package/lib/services/requests/request-firestore.service.d.ts +28 -0
- package/lib/services/requests/types.d.ts +4 -0
- package/lib/version.d.ts +1 -1
- package/package.json +1 -1
- package/public-api.d.ts +6 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { EventEmitter } from '@angular/core';
|
|
2
|
+
import { FunModalMetadata } from './types';
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
/**
|
|
5
|
+
* `val-fun-modal` — modal moderno tipo promo/onboarding: imagen o ilustración
|
|
6
|
+
* arriba, título, cuerpo y botones de acción, con redondeo personalizable.
|
|
7
|
+
* Sigue la Regla #5 (header canónico vía `val-modal-shell`).
|
|
8
|
+
*
|
|
9
|
+
* El padre controla `[isOpen]` y reacciona a `(dismissed)` / `(action)`.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```html
|
|
13
|
+
* <val-fun-modal
|
|
14
|
+
* [isOpen]="isOpen()"
|
|
15
|
+
* [props]="{
|
|
16
|
+
* image: '/promo.png',
|
|
17
|
+
* title: '¿Cómo se conecta Lucas con los Salmos?',
|
|
18
|
+
* subtitle: 'Pulsa la referencia cruzada para descubrirlo.',
|
|
19
|
+
* actions: { position: 'center', columned: false, buttons: [
|
|
20
|
+
* { text: 'Probar ahora', color: 'primary', shape: 'round', type: 'button', state: 'ENABLED', token: 'try' }
|
|
21
|
+
* ] }
|
|
22
|
+
* }"
|
|
23
|
+
* (action)="onAction($event)"
|
|
24
|
+
* (dismissed)="isOpen.set(false)"
|
|
25
|
+
* />
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export declare class FunModalComponent {
|
|
29
|
+
private _isOpen;
|
|
30
|
+
/** Controla la visibilidad del modal. */
|
|
31
|
+
set isOpen(value: boolean);
|
|
32
|
+
get isOpen(): boolean;
|
|
33
|
+
/** Configuración del modal. */
|
|
34
|
+
props: Partial<FunModalMetadata>;
|
|
35
|
+
/** Emite cuando el user cierra el modal (botón Cerrar o backdrop). */
|
|
36
|
+
dismissed: EventEmitter<void>;
|
|
37
|
+
/** Emite con el token del botón de acción presionado. */
|
|
38
|
+
action: EventEmitter<string>;
|
|
39
|
+
config: import("@angular/core").Signal<FunModalMetadata & Required<Pick<FunModalMetadata, "borderRadius" | "imageRadius">>>;
|
|
40
|
+
getBackground(): string | null;
|
|
41
|
+
close(): void;
|
|
42
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<FunModalComponent, never>;
|
|
43
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<FunModalComponent, "val-fun-modal", never, { "isOpen": { "alias": "isOpen"; "required": false; }; "props": { "alias": "props"; "required": false; }; }, { "dismissed": "dismissed"; "action": "action"; }, never, never, true, never>;
|
|
44
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { ButtonGroupMetadata } from '../../molecules/button-group/types';
|
|
2
|
+
/**
|
|
3
|
+
* Metadata for val-fun-modal.
|
|
4
|
+
*
|
|
5
|
+
* Modal moderno tipo promo/onboarding: imagen o ilustración arriba, título,
|
|
6
|
+
* cuerpo y botones de acción, con redondeo personalizable. Sigue la Regla #5
|
|
7
|
+
* (header canónico vía `val-modal-shell`).
|
|
8
|
+
*
|
|
9
|
+
* Content-driven — pasar strings ya resueltos. Botones reusan
|
|
10
|
+
* `ButtonGroupMetadata`.
|
|
11
|
+
*/
|
|
12
|
+
export interface FunModalMetadata {
|
|
13
|
+
/** Imagen / ilustración mostrada arriba del título */
|
|
14
|
+
image?: string;
|
|
15
|
+
/** Alt de la imagen */
|
|
16
|
+
imageAlt?: string;
|
|
17
|
+
/** Emoji decorativo (alternativa a la imagen) */
|
|
18
|
+
emoji?: string;
|
|
19
|
+
/** Título principal (val-display) */
|
|
20
|
+
title: string;
|
|
21
|
+
/** Cuerpo / subtítulo (val-title) */
|
|
22
|
+
subtitle?: string;
|
|
23
|
+
/** Botones de acción (reusa val-button-group) */
|
|
24
|
+
actions?: ButtonGroupMetadata;
|
|
25
|
+
/** Redondeo del modal en px. Default: 28 */
|
|
26
|
+
borderRadius?: number;
|
|
27
|
+
/** Redondeo de la imagen en px. Default: 16 */
|
|
28
|
+
imageRadius?: number;
|
|
29
|
+
/** Color de fondo del modal (Ionic color o CSS). Default: surface */
|
|
30
|
+
backgroundColor?: string;
|
|
31
|
+
/** Label del botón de cierre. Default: i18n `_global.close` */
|
|
32
|
+
closeLabel?: string;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Default values for FunModalMetadata.
|
|
36
|
+
*/
|
|
37
|
+
export declare const FUN_MODAL_DEFAULTS: Required<Pick<FunModalMetadata, 'borderRadius' | 'imageRadius'>>;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { EventEmitter } from '@angular/core';
|
|
2
|
+
import { QrResult } from '../../../services/qr-generator/types';
|
|
3
|
+
import { ShareEvent } from '../../molecules/share-buttons/types';
|
|
4
|
+
import { ShareProfileModalMetadata } from './types';
|
|
5
|
+
import * as i0 from "@angular/core";
|
|
6
|
+
/**
|
|
7
|
+
* `val-share-profile-modal` — modal reutilizable para compartir un perfil (o
|
|
8
|
+
* cualquier entidad) vía QR + URL. Sigue la Regla #5 (header canónico vía
|
|
9
|
+
* `val-modal-shell`).
|
|
10
|
+
*
|
|
11
|
+
* Self-contained: genera el QR con `QrGeneratorService` a partir de `url` al
|
|
12
|
+
* abrirse. El padre solo controla `[isOpen]` y reacciona a `(dismissed)`.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```html
|
|
16
|
+
* <val-share-profile-modal
|
|
17
|
+
* [isOpen]="isOpen()"
|
|
18
|
+
* [props]="{ name: 'Víctor Valenzuela', url: 'https://app.myvaltech.com/u/victor', avatarUrl: '/me.jpg' }"
|
|
19
|
+
* (dismissed)="isOpen.set(false)"
|
|
20
|
+
* />
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export declare class ShareProfileModalComponent {
|
|
24
|
+
private qrGenerator;
|
|
25
|
+
private i18n;
|
|
26
|
+
private _isOpen;
|
|
27
|
+
/** Controla la visibilidad. Al pasar de cerrado a abierto genera el QR. */
|
|
28
|
+
set isOpen(value: boolean);
|
|
29
|
+
get isOpen(): boolean;
|
|
30
|
+
/** Configuración del modal. */
|
|
31
|
+
props: Partial<ShareProfileModalMetadata>;
|
|
32
|
+
/** Emite cuando el user cierra el modal (botón Cerrar o backdrop). */
|
|
33
|
+
dismissed: EventEmitter<void>;
|
|
34
|
+
/** Emite al completar una acción de compartir. */
|
|
35
|
+
shared: EventEmitter<ShareEvent>;
|
|
36
|
+
private readonly _qr;
|
|
37
|
+
readonly qr: import("@angular/core").Signal<QrResult>;
|
|
38
|
+
private readonly _qrError;
|
|
39
|
+
readonly qrError: import("@angular/core").Signal<boolean>;
|
|
40
|
+
config: import("@angular/core").Signal<ShareProfileModalMetadata & Required<Pick<ShareProfileModalMetadata, "borderRadius" | "platforms" | "qrTheme" | "qrSize">>>;
|
|
41
|
+
displayName: import("@angular/core").Signal<string>;
|
|
42
|
+
caption: import("@angular/core").Signal<string>;
|
|
43
|
+
constructor();
|
|
44
|
+
private t;
|
|
45
|
+
private generateQr;
|
|
46
|
+
close(): void;
|
|
47
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<ShareProfileModalComponent, never>;
|
|
48
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<ShareProfileModalComponent, "val-share-profile-modal", never, { "isOpen": { "alias": "isOpen"; "required": false; }; "props": { "alias": "props"; "required": false; }; }, { "dismissed": "dismissed"; "shared": "shared"; }, never, never, true, never>;
|
|
49
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { SharePlatform } from '../../molecules/share-buttons/types';
|
|
2
|
+
import { QrDisplayTheme } from '../../atoms/qr-code/types';
|
|
3
|
+
/**
|
|
4
|
+
* Metadata for val-share-profile-modal.
|
|
5
|
+
*
|
|
6
|
+
* Reusable modal to share a profile (or any entity) via QR + URL: avatar,
|
|
7
|
+
* name, a QR code encoding the URL, an optional caption and share buttons
|
|
8
|
+
* (copy link / native / social).
|
|
9
|
+
*
|
|
10
|
+
* Content-driven: `name` + `url` are required; the rest is optional. Static
|
|
11
|
+
* chrome text (caption, button hints) auto-registra defaults i18n
|
|
12
|
+
* (namespace `ShareProfileModal`) — override pasando los campos directos.
|
|
13
|
+
*/
|
|
14
|
+
export interface ShareProfileModalMetadata {
|
|
15
|
+
/** Display name shown under the avatar (and default modal title) */
|
|
16
|
+
name: string;
|
|
17
|
+
/** URL encoded in the QR and shared by the buttons */
|
|
18
|
+
url: string;
|
|
19
|
+
/** Avatar image URL (falls back to initials of `name`) */
|
|
20
|
+
avatarUrl?: string;
|
|
21
|
+
/** Email — used for the avatar initials/color when no avatarUrl */
|
|
22
|
+
email?: string;
|
|
23
|
+
/** Modal title (val-display). Default: `name` */
|
|
24
|
+
title?: string;
|
|
25
|
+
/** Caption under the QR. Default: i18n `ShareProfileModal.caption` */
|
|
26
|
+
caption?: string;
|
|
27
|
+
/** Title used by the native share sheet. Default: `name` */
|
|
28
|
+
shareTitle?: string;
|
|
29
|
+
/** Text used by the native share sheet / social messages */
|
|
30
|
+
shareText?: string;
|
|
31
|
+
/** Platforms shown in the share buttons. Default: ['copy', 'native', 'whatsapp'] */
|
|
32
|
+
platforms?: SharePlatform[];
|
|
33
|
+
/** QR visual theme. Default: 'default' */
|
|
34
|
+
qrTheme?: QrDisplayTheme;
|
|
35
|
+
/** QR size in pixels. Default: 220 */
|
|
36
|
+
qrSize?: number;
|
|
37
|
+
/** Modal corner rounding in px. Default: 24 */
|
|
38
|
+
borderRadius?: number;
|
|
39
|
+
/** Close button label. Default: i18n `_global.close` */
|
|
40
|
+
closeLabel?: string;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Default values for ShareProfileModalMetadata.
|
|
44
|
+
*/
|
|
45
|
+
export declare const SHARE_PROFILE_MODAL_DEFAULTS: Required<Pick<ShareProfileModalMetadata, 'platforms' | 'qrTheme' | 'qrSize' | 'borderRadius'>>;
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
* const article = ContentTransformer.toArticle(json);
|
|
43
43
|
* ```
|
|
44
44
|
*/
|
|
45
|
-
export { ContentAuthor, ContentMeta, ContentConfig, ContentDocument, ContentBlock, HeadingBlock, ParagraphBlock, QuoteBlock, CodeBlock, ListBlock, ImageBlock, CalloutBlock, DividerBlock, ButtonBlock, CommandBlock, } from './types';
|
|
45
|
+
export { ContentAuthor, ContentMeta, ContentConfig, ContentDocument as ContentBuilderDocument, ContentBlock, HeadingBlock, ParagraphBlock, QuoteBlock, CodeBlock, ListBlock, ImageBlock, CalloutBlock, DividerBlock, ButtonBlock, CommandBlock, } from './types';
|
|
46
46
|
export { ContentTransformer, toArticle } from './transformer';
|
|
47
47
|
export { BlogPost, BlogPostBuilder, blogPost } from './content-types/blog';
|
|
48
48
|
export { Documentation, DocNavLink, DocsBuilder, docs } from './content-types/documentation';
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { EnvironmentProviders, InjectionToken } from '@angular/core';
|
|
2
|
+
import { ValtechContentConfig } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Token de inyección para la configuración de la plataforma de contenido.
|
|
5
|
+
*/
|
|
6
|
+
export declare const VALTECH_CONTENT_CONFIG: InjectionToken<ValtechContentConfig>;
|
|
7
|
+
/**
|
|
8
|
+
* Provee la plataforma de contenido (`ContentService`) a la aplicación Angular.
|
|
9
|
+
*
|
|
10
|
+
* Wire en el `main.ts` de la app consumer. El origen es **híbrido** (ADR-020):
|
|
11
|
+
* el backend siempre está disponible vía `apiUrl`; las `staticSources` son
|
|
12
|
+
* opcionales — factories lazy generadas build-time por `scripts/build-content.ts`
|
|
13
|
+
* (mismo patrón que `provideLegalContent`). Cada locale queda code-split por el
|
|
14
|
+
* `import()` dinámico.
|
|
15
|
+
*
|
|
16
|
+
* @param config - Configuración de contenido (`apiUrl`, `appId`, `staticSources?`).
|
|
17
|
+
* @returns EnvironmentProviders para usar en `bootstrapApplication`.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```typescript
|
|
21
|
+
* // main.ts — solo backend
|
|
22
|
+
* provideValtechContent({
|
|
23
|
+
* apiUrl: environment.apiUrl,
|
|
24
|
+
* appId: 'showcase',
|
|
25
|
+
* });
|
|
26
|
+
*
|
|
27
|
+
* // main.ts — híbrido (estático curado + backend)
|
|
28
|
+
* provideValtechContent({
|
|
29
|
+
* apiUrl: environment.apiUrl,
|
|
30
|
+
* appId: 'web',
|
|
31
|
+
* staticSources: {
|
|
32
|
+
* es: () => import('./app/generated/content-store.es').then(m => m.CONTENT_STORE_ES),
|
|
33
|
+
* en: () => import('./app/generated/content-store.en').then(m => m.CONTENT_STORE_EN),
|
|
34
|
+
* },
|
|
35
|
+
* });
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export declare function provideValtechContent(config: ValtechContentConfig): EnvironmentProviders;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { Observable } from 'rxjs';
|
|
2
|
+
import { ArticleMetadata } from '../../components/organisms/article/types';
|
|
3
|
+
import { ContentDocument, ContentDocumentType, ContentLoadOptions } from './types';
|
|
4
|
+
import * as i0 from "@angular/core";
|
|
5
|
+
/**
|
|
6
|
+
* Servicio de la plataforma de contenido (ADR-020 §2.5).
|
|
7
|
+
*
|
|
8
|
+
* Une dos orígenes (**híbrido**):
|
|
9
|
+
* - **Estático** — `staticSources` lazy por locale, generadas build-time.
|
|
10
|
+
* - **Backend** — DynamoDB + API (`/v2/content*`), publicación sin redeploy.
|
|
11
|
+
*
|
|
12
|
+
* Reglas de merge:
|
|
13
|
+
* - `list()` une ambos orígenes por `type`. Colisión de `slug` → **estático
|
|
14
|
+
* gana** (contenido curado). Ordena por `publishedAt` desc (sin fecha al final).
|
|
15
|
+
* - `load()` resuelve estático primero, con **fallback** al backend.
|
|
16
|
+
*
|
|
17
|
+
* Render: `toArticle(doc)` convierte `doc.body` (Markdown) a `ArticleMetadata`
|
|
18
|
+
* vía el `markdown-article-parser` existente — la page hace `<val-article [props]="...">`.
|
|
19
|
+
*
|
|
20
|
+
* Requiere `provideValtechContent({ apiUrl, appId, staticSources? })` en `main.ts`.
|
|
21
|
+
* Sin provider, el servicio queda inerte (`isConfigured() === false`).
|
|
22
|
+
*/
|
|
23
|
+
export declare class ContentService {
|
|
24
|
+
private readonly config;
|
|
25
|
+
private readonly http;
|
|
26
|
+
private readonly parser;
|
|
27
|
+
/** `true` si `provideValtechContent()` fue llamado en el bootstrap. */
|
|
28
|
+
readonly isConfigured: import("@angular/core").WritableSignal<boolean>;
|
|
29
|
+
/** Cache de las promesas de cada factory estática, keyed por locale. */
|
|
30
|
+
private readonly staticCache;
|
|
31
|
+
constructor();
|
|
32
|
+
/**
|
|
33
|
+
* Lista los documentos publicados de un `type`, uniendo estático + backend.
|
|
34
|
+
* Colisión de `slug` → estático gana. Ordenados por `publishedAt` desc.
|
|
35
|
+
*
|
|
36
|
+
* @param type - Tipo de contenido (`'blog'`, `'news'`, …).
|
|
37
|
+
* @param options - `{ locale }` (default `'es'`).
|
|
38
|
+
*/
|
|
39
|
+
list(type: ContentDocumentType, options?: ContentLoadOptions): Observable<ContentDocument[]>;
|
|
40
|
+
/**
|
|
41
|
+
* Carga un documento por `slug`: estático primero, fallback al backend.
|
|
42
|
+
*
|
|
43
|
+
* @param type - Tipo de contenido.
|
|
44
|
+
* @param slug - Slug del documento.
|
|
45
|
+
* @param options - `{ locale }` (default `'es'`).
|
|
46
|
+
*/
|
|
47
|
+
load(type: ContentDocumentType, slug: string, options?: ContentLoadOptions): Observable<ContentDocument>;
|
|
48
|
+
/**
|
|
49
|
+
* Convierte el `body` (Markdown) de un documento en `ArticleMetadata` para
|
|
50
|
+
* renderizar con `<val-article [props]="...">`. Usa el parser existente.
|
|
51
|
+
*
|
|
52
|
+
* @param doc - Documento de contenido a renderizar.
|
|
53
|
+
* @param config - Override parcial de la `ArticleMetadata` resultante.
|
|
54
|
+
*/
|
|
55
|
+
toArticle(doc: ContentDocument, config?: Partial<ArticleMetadata>): ArticleMetadata;
|
|
56
|
+
/** Limpia la cache de fuentes estáticas. Llamar al cambiar de locale en runtime. */
|
|
57
|
+
invalidate(): void;
|
|
58
|
+
/** Une estático + backend: estático gana por slug; orden por publishedAt desc. */
|
|
59
|
+
private merge;
|
|
60
|
+
/** Comparador: más reciente primero; sin `publishedAt` al final. */
|
|
61
|
+
private byPublishedDesc;
|
|
62
|
+
/** Carga (y cachea) los documentos estáticos de un locale, si hay factory. */
|
|
63
|
+
private loadStatic;
|
|
64
|
+
/** GET `{apiUrl}/v2/content?type=&locale=` — solo publicados. */
|
|
65
|
+
private listBackend;
|
|
66
|
+
/** GET `{apiUrl}/v2/content/{type}/{locale}/{slug}` — detalle publicado. */
|
|
67
|
+
private loadBackend;
|
|
68
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<ContentService, never>;
|
|
69
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<ContentService>;
|
|
70
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Content Platform — `ContentService` + `provideValtechContent` (ADR-020).
|
|
3
|
+
*
|
|
4
|
+
* Modelo canónico unificado (`ContentDocument`, flat + Markdown) con origen
|
|
5
|
+
* híbrido (estático build-time + backend DynamoDB/API). Render vía el
|
|
6
|
+
* `markdown-article-parser` existente.
|
|
7
|
+
*/
|
|
8
|
+
export { ContentDocumentType, ContentDocumentStatus, ContentDocumentSource, ContentDocument, ContentDocumentAuthor, ContentStaticFactory, ValtechContentConfig, ContentLoadOptions, } from './types';
|
|
9
|
+
export { VALTECH_CONTENT_CONFIG, provideValtechContent } from './config';
|
|
10
|
+
export { ContentService } from './content.service';
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Content Platform — modelo canónico de documento de contenido.
|
|
3
|
+
*
|
|
4
|
+
* Alineado con ADR-020 §2.1. Es el contrato compartido entre:
|
|
5
|
+
* - Backend (servicio `content/` — DynamoDB tabla `content`).
|
|
6
|
+
* - Pipeline estático (`scripts/build-content.ts` → `content-store.{locale}.ts`).
|
|
7
|
+
* - Esta lib (`ContentService` + `provideValtechContent`).
|
|
8
|
+
* - Web (`/blog`, `/news`, …).
|
|
9
|
+
*
|
|
10
|
+
* Modelo **unificado** con discriminador `type` — agregar un tipo de contenido
|
|
11
|
+
* NO requiere tocar backend ni lib. El `body` es Markdown plano, renderizado en
|
|
12
|
+
* la web vía el `markdown-article-parser` existente (`string MD → ArticleMetadata`).
|
|
13
|
+
*
|
|
14
|
+
* NOTA: existe un tipo homónimo `ContentDocument<T>` (block-based, builder) en
|
|
15
|
+
* `services/content/`, reexportado por el public-api como `ContentBuilderDocument`
|
|
16
|
+
* para evitar colisión. Este (flat, markdown) es el canónico de la plataforma.
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* Tipo de contenido (discriminador). Extensible — agregar un valor no impacta
|
|
20
|
+
* backend ni lib; solo la web decide qué rutas exponer.
|
|
21
|
+
*/
|
|
22
|
+
export type ContentDocumentType = 'blog' | 'news' | 'article' | 'documentation' | (string & {});
|
|
23
|
+
/**
|
|
24
|
+
* Estado de publicación del documento.
|
|
25
|
+
*/
|
|
26
|
+
export type ContentDocumentStatus = 'draft' | 'published' | 'archived';
|
|
27
|
+
/**
|
|
28
|
+
* Origen del documento — marca de la naturaleza híbrida del pipeline.
|
|
29
|
+
* - `static`: autoría en repo, build-time (contenido curado de la empresa).
|
|
30
|
+
* - `backend`: DynamoDB + API (publicación sin redeploy / editores).
|
|
31
|
+
*/
|
|
32
|
+
export type ContentDocumentSource = 'static' | 'backend';
|
|
33
|
+
/**
|
|
34
|
+
* Autor de un documento de contenido.
|
|
35
|
+
*/
|
|
36
|
+
export interface ContentDocumentAuthor {
|
|
37
|
+
/** Nombre visible del autor. */
|
|
38
|
+
name: string;
|
|
39
|
+
/** URL del avatar del autor. */
|
|
40
|
+
avatar?: string;
|
|
41
|
+
/** Rol o cargo del autor. */
|
|
42
|
+
role?: string;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Documento de contenido unificado (canónico — ADR-020 §2.1).
|
|
46
|
+
*/
|
|
47
|
+
export interface ContentDocument {
|
|
48
|
+
/** Identificador único — uuid (backend) o `static:{type}:{locale}:{slug}` (estático). */
|
|
49
|
+
id: string;
|
|
50
|
+
/** AppID del producto dueño del documento. */
|
|
51
|
+
appId: string;
|
|
52
|
+
/** Tipo de contenido (discriminador). */
|
|
53
|
+
type: ContentDocumentType;
|
|
54
|
+
/** Slug — único por (appId, type, locale). */
|
|
55
|
+
slug: string;
|
|
56
|
+
/** Locale del documento (`'es'` | `'en'` | …). */
|
|
57
|
+
locale: string;
|
|
58
|
+
/** Título del documento. */
|
|
59
|
+
title: string;
|
|
60
|
+
/** Resumen / extracto para listados y SEO. */
|
|
61
|
+
excerpt: string;
|
|
62
|
+
/** URL de la imagen de portada (S3 vía storage service). */
|
|
63
|
+
coverImage?: string;
|
|
64
|
+
/** Cuerpo en Markdown — render vía markdown-article-parser. */
|
|
65
|
+
body: string;
|
|
66
|
+
/** Autor del documento. */
|
|
67
|
+
author?: ContentDocumentAuthor;
|
|
68
|
+
/** Etiquetas para categorización. */
|
|
69
|
+
tags?: string[];
|
|
70
|
+
/** Categoría primaria. */
|
|
71
|
+
category?: string;
|
|
72
|
+
/** Estado de publicación. */
|
|
73
|
+
status: ContentDocumentStatus;
|
|
74
|
+
/** Origen del documento (marca híbrida). */
|
|
75
|
+
source: ContentDocumentSource;
|
|
76
|
+
/** Fecha de publicación (ISO 8601). */
|
|
77
|
+
publishedAt?: string;
|
|
78
|
+
/** Fecha de creación (ISO 8601). */
|
|
79
|
+
createdAt: string;
|
|
80
|
+
/** Fecha de última actualización (ISO 8601). */
|
|
81
|
+
updatedAt?: string;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Factory lazy de documentos estáticos para un locale. Generada build-time por
|
|
85
|
+
* `scripts/build-content.ts`. Se usa con `import()` dinámico para que cada locale
|
|
86
|
+
* quede code-split (igual patrón que `LegalContentFactory`).
|
|
87
|
+
*/
|
|
88
|
+
export type ContentStaticFactory = () => Promise<ContentDocument[]>;
|
|
89
|
+
/**
|
|
90
|
+
* Configuración de `provideValtechContent` (ADR-020 §2.5).
|
|
91
|
+
*/
|
|
92
|
+
export interface ValtechContentConfig {
|
|
93
|
+
/** Base URL de la API backend (sin trailing slash). Ej. `environment.apiUrl`. */
|
|
94
|
+
apiUrl: string;
|
|
95
|
+
/** AppID del producto — se envía como query param al backend. */
|
|
96
|
+
appId: string;
|
|
97
|
+
/**
|
|
98
|
+
* Fuentes estáticas lazy keyed por locale (generadas build-time). Opcional —
|
|
99
|
+
* si no hay, el servicio opera solo contra el backend.
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* staticSources: {
|
|
103
|
+
* es: () => import('./app/generated/content-store.es').then(m => m.CONTENT_STORE_ES),
|
|
104
|
+
* en: () => import('./app/generated/content-store.en').then(m => m.CONTENT_STORE_EN),
|
|
105
|
+
* }
|
|
106
|
+
*/
|
|
107
|
+
staticSources?: {
|
|
108
|
+
[locale: string]: ContentStaticFactory;
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Opciones de carga/listado de contenido.
|
|
113
|
+
*/
|
|
114
|
+
export interface ContentLoadOptions {
|
|
115
|
+
/** Locale a resolver (default `'es'`). */
|
|
116
|
+
locale?: string;
|
|
117
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { AppRequest, RequestTypeConfig } from './types';
|
|
2
|
+
import * as i0 from "@angular/core";
|
|
3
|
+
/**
|
|
4
|
+
* Lectura de Requests / RequestTypes desde Firestore (one-shot, sin listener).
|
|
5
|
+
*
|
|
6
|
+
* El backend proyecta DynamoDB → Firestore (réplica de solo-lectura); el cliente
|
|
7
|
+
* lee desde acá en vez de pegarle al REST, así no se expone un endpoint JSON
|
|
8
|
+
* replayable y el acceso queda gobernado por las security rules. Las mutaciones
|
|
9
|
+
* (create/update/transition) siguen yendo por `RequestService` (REST → backend).
|
|
10
|
+
*
|
|
11
|
+
* Los paths se prefijan automáticamente con `apps/{appId}/` (FirestoreService),
|
|
12
|
+
* resultando en:
|
|
13
|
+
* - apps/{appId}/users/{uid}/requests
|
|
14
|
+
* - apps/{appId}/orgs/{orgId}/requests
|
|
15
|
+
* - apps/{appId}/orgs/{orgId}/requestTypes
|
|
16
|
+
*/
|
|
17
|
+
export declare class RequestFirestoreService {
|
|
18
|
+
private factory;
|
|
19
|
+
private read;
|
|
20
|
+
/** Solicitudes enviadas por el usuario (scope usuario). */
|
|
21
|
+
listMyRequests(userId: string): Promise<AppRequest[]>;
|
|
22
|
+
/** Solicitudes de la organización (scope staff). */
|
|
23
|
+
listOrgRequests(orgId: string): Promise<AppRequest[]>;
|
|
24
|
+
/** Catálogo de tipos de solicitud de la organización. */
|
|
25
|
+
listRequestTypes(orgId: string): Promise<RequestTypeConfig[]>;
|
|
26
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<RequestFirestoreService, never>;
|
|
27
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<RequestFirestoreService>;
|
|
28
|
+
}
|
|
@@ -48,6 +48,8 @@ export interface FieldSchemaDef {
|
|
|
48
48
|
options?: FieldOption[];
|
|
49
49
|
order: number;
|
|
50
50
|
}
|
|
51
|
+
/** Quién puede leer un tipo de solicitud (y sus solicitudes públicas). */
|
|
52
|
+
export type RequestVisibility = 'PUBLIC' | 'ORG' | 'INTERNAL';
|
|
51
53
|
export interface RequestTypeConfig {
|
|
52
54
|
typeId: string;
|
|
53
55
|
appId: string;
|
|
@@ -56,6 +58,8 @@ export interface RequestTypeConfig {
|
|
|
56
58
|
labelEn: string;
|
|
57
59
|
fieldSchema: FieldSchemaDef[];
|
|
58
60
|
allowAnonymous: boolean;
|
|
61
|
+
/** PUBLIC: cualquiera · ORG/INTERNAL: solo miembros de la org. Default ORG. */
|
|
62
|
+
visibility?: RequestVisibility;
|
|
59
63
|
createdAt: string;
|
|
60
64
|
updatedAt: string;
|
|
61
65
|
}
|
package/lib/version.d.ts
CHANGED
package/package.json
CHANGED
package/public-api.d.ts
CHANGED
|
@@ -202,6 +202,10 @@ export * from './lib/components/organisms/banner/banner.component';
|
|
|
202
202
|
export * from './lib/components/organisms/banner/types';
|
|
203
203
|
export * from './lib/components/organisms/change-password-modal/change-password-modal.component';
|
|
204
204
|
export * from './lib/components/organisms/change-email-modal/change-email-modal.component';
|
|
205
|
+
export * from './lib/components/organisms/share-profile-modal/share-profile-modal.component';
|
|
206
|
+
export * from './lib/components/organisms/share-profile-modal/types';
|
|
207
|
+
export * from './lib/components/organisms/fun-modal/fun-modal.component';
|
|
208
|
+
export * from './lib/components/organisms/fun-modal/types';
|
|
205
209
|
export * from './lib/components/organisms/cookie-banner/cookie-banner.component';
|
|
206
210
|
export * from './lib/components/organisms/cookie-banner/types';
|
|
207
211
|
export * from './lib/components/organisms/debug-console/config';
|
|
@@ -314,6 +318,7 @@ export * from './lib/services/image';
|
|
|
314
318
|
export * from './lib/services/ads';
|
|
315
319
|
export * from './lib/components/molecules/ad-slot/ad-slot.component';
|
|
316
320
|
export * from './lib/services/content';
|
|
321
|
+
export * from './lib/services/content-platform';
|
|
317
322
|
export * from './lib/services/feedback';
|
|
318
323
|
export * from './lib/services/donation';
|
|
319
324
|
export * from './lib/components/molecules/feedback-form/feedback-form.component';
|
|
@@ -358,3 +363,4 @@ export { ValtechErrorService, VALTECH_NETWORK_ERROR_KEY, } from './lib/services/
|
|
|
358
363
|
export * from './lib/services/requests/types';
|
|
359
364
|
export * from './lib/services/requests/request.service';
|
|
360
365
|
export * from './lib/services/requests/request-form-builder.service';
|
|
366
|
+
export * from './lib/services/requests/request-firestore.service';
|