valtech-components 2.0.1026 → 2.0.1028
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/molecules/footer-links/footer-links.component.mjs +3 -3
- package/esm2022/lib/components/organisms/login/login.component.mjs +9 -3
- package/esm2022/lib/version.mjs +2 -2
- package/fesm2022/valtech-components.mjs +181 -176
- package/fesm2022/valtech-components.mjs.map +1 -1
- package/lib/components/atoms/text/text.component.d.ts +1 -1
- package/lib/components/atoms/user-avatar/user-avatar.component.d.ts +1 -1
- package/lib/components/molecules/features-list/features-list.component.d.ts +1 -1
- package/lib/components/organisms/article/article.component.d.ts +4 -4
- package/lib/components/organisms/landing-steps/landing-steps.component.d.ts +1 -1
- package/lib/components/organisms/login/login.component.d.ts +3 -0
- package/lib/version.d.ts +1 -1
- package/package.json +1 -1
|
@@ -55,7 +55,7 @@ import { BrowserMultiFormatReader } from '@zxing/browser';
|
|
|
55
55
|
* Current version of valtech-components.
|
|
56
56
|
* This is automatically updated during the publish process.
|
|
57
57
|
*/
|
|
58
|
-
const VERSION = '2.0.
|
|
58
|
+
const VERSION = '2.0.1028';
|
|
59
59
|
|
|
60
60
|
// Control de estado de refresco (singleton a nivel de módulo)
|
|
61
61
|
let isRefreshing = false;
|
|
@@ -25684,7 +25684,7 @@ class FooterLinksComponent {
|
|
|
25684
25684
|
</ion-col>
|
|
25685
25685
|
</ion-row>
|
|
25686
25686
|
</div>
|
|
25687
|
-
`, isInline: true, styles: [".footer-links .mobile-layout{display:block;text-align:center;padding:8px 0}.footer-links .desktop-layout{display:none;align-items:flex-end;justify-content:space-between;margin-top:16px;padding:8px 0}.footer-links .social-links-container{display:flex;align-items:center;justify-content:center;gap:12px;margin-top:8px;flex-wrap:wrap}.footer-links .social-button{--color: #666;--color-hover: #333;transition:all .2s ease;min-height:40px;min-width:40px;margin:0}.footer-links .social-button:hover{--color: #333;transform:translateY(-1px)}.footer-links .social-button ion-icon{font-size:1.25rem}.footer-links .logo-clickable{cursor:pointer}.footer-links .footer-logo--css-var{display:block;background-image:var(--logo-var);background-size:contain;background-repeat:no-repeat;background-position:center;transition:opacity .2s ease}.footer-links .footer-logo--css-var:hover{opacity:.8}.footer-links .mobile-layout .footer-logo--css-var{margin-left:auto;margin-right:auto}.footer-links .footer-logo--light{display:block}.footer-links .footer-logo--dark{display:none}.footer-links :host-context(.dark) .footer-logo--light,.footer-links :host-context(.ion-palette-dark) .footer-logo--light,.footer-links :host-context(html.ion-palette-dark) .footer-logo--light,.footer-links :host-context(body.dark) .footer-logo--light,.footer-links :host-context([data-theme=dark]) .footer-logo--light{display:none}.footer-links :host-context(.dark) .footer-logo--dark,.footer-links :host-context(.ion-palette-dark) .footer-logo--dark,.footer-links :host-context(html.ion-palette-dark) .footer-logo--dark,.footer-links :host-context(body.dark) .footer-logo--dark,.footer-links :host-context([data-theme=dark]) .footer-logo--dark{display:block}@media (min-width: 768px){.footer-links .mobile-layout{display:none!important}.footer-links .desktop-layout{display:flex!important}.footer-links .social-links-container{margin-top:0;justify-content:flex-end}}@media (max-width: 767px){.footer-links .mobile-layout{display:block!important}.footer-links .desktop-layout{display:none!important}.footer-links .social-links-container{justify-content:center;margin-bottom:8px}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$5.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: IonCol, selector: "ion-col", inputs: ["offset", "offsetLg", "offsetMd", "offsetSm", "offsetXl", "offsetXs", "pull", "pullLg", "pullMd", "pullSm", "pullXl", "pullXs", "push", "pushLg", "pushMd", "pushSm", "pushXl", "pushXs", "size", "sizeLg", "sizeMd", "sizeSm", "sizeXl", "sizeXs"] }, { kind: "component", type: IonRow, selector: "ion-row" }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: DividerComponent, selector: "val-divider", inputs: ["props"] }, { kind: "component", type: ImageComponent, selector: "val-image", inputs: ["props"] }, { kind: "component", type: LinksCakeComponent, selector: "val-links-cake", inputs: ["props"] }, { kind: "component", type: LanguageSelectorComponent, selector: "val-language-selector", inputs: ["props"], outputs: ["languageChange"] }] }); }
|
|
25687
|
+
`, isInline: true, styles: [".footer-links .mobile-layout{display:block;text-align:center;padding:8px 0}.footer-links .desktop-layout{display:none;align-items:flex-end;justify-content:space-between;margin-top:16px;padding:8px 0}.footer-links .social-links-container{display:flex;align-items:center;justify-content:center;gap:12px;margin-top:8px;flex-wrap:wrap}.footer-links .social-button{--color: #666;--color-hover: #333;transition:all .2s ease;min-height:40px;min-width:40px;margin:0}.footer-links .social-button:hover{--color: #333;transform:translateY(-1px)}.footer-links .social-button ion-icon{font-size:1.25rem}.footer-links .logo-clickable{cursor:pointer}.footer-links .footer-logo--css-var{display:block;background-image:var(--logo-var);background-size:contain;background-repeat:no-repeat;background-position:left center;transition:opacity .2s ease}.footer-links .footer-logo--css-var:hover{opacity:.8}.footer-links .mobile-layout .footer-logo--css-var{background-position:center;margin-left:auto;margin-right:auto}.footer-links .footer-logo--light{display:block}.footer-links .footer-logo--dark{display:none}.footer-links :host-context(.dark) .footer-logo--light,.footer-links :host-context(.ion-palette-dark) .footer-logo--light,.footer-links :host-context(html.ion-palette-dark) .footer-logo--light,.footer-links :host-context(body.dark) .footer-logo--light,.footer-links :host-context([data-theme=dark]) .footer-logo--light{display:none}.footer-links :host-context(.dark) .footer-logo--dark,.footer-links :host-context(.ion-palette-dark) .footer-logo--dark,.footer-links :host-context(html.ion-palette-dark) .footer-logo--dark,.footer-links :host-context(body.dark) .footer-logo--dark,.footer-links :host-context([data-theme=dark]) .footer-logo--dark{display:block}@media (min-width: 768px){.footer-links .mobile-layout{display:none!important}.footer-links .desktop-layout{display:flex!important}.footer-links .social-links-container{margin-top:0;justify-content:flex-end}}@media (max-width: 767px){.footer-links .mobile-layout{display:block!important}.footer-links .desktop-layout{display:none!important}.footer-links .social-links-container{justify-content:center;margin-bottom:8px}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$5.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: IonCol, selector: "ion-col", inputs: ["offset", "offsetLg", "offsetMd", "offsetSm", "offsetXl", "offsetXs", "pull", "pullLg", "pullMd", "pullSm", "pullXl", "pullXs", "push", "pushLg", "pushMd", "pushSm", "pushXl", "pushXs", "size", "sizeLg", "sizeMd", "sizeSm", "sizeXl", "sizeXs"] }, { kind: "component", type: IonRow, selector: "ion-row" }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: DividerComponent, selector: "val-divider", inputs: ["props"] }, { kind: "component", type: ImageComponent, selector: "val-image", inputs: ["props"] }, { kind: "component", type: LinksCakeComponent, selector: "val-links-cake", inputs: ["props"] }, { kind: "component", type: LanguageSelectorComponent, selector: "val-language-selector", inputs: ["props"], outputs: ["languageChange"] }] }); }
|
|
25688
25688
|
}
|
|
25689
25689
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FooterLinksComponent, decorators: [{
|
|
25690
25690
|
type: Component,
|
|
@@ -25851,7 +25851,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
25851
25851
|
</ion-col>
|
|
25852
25852
|
</ion-row>
|
|
25853
25853
|
</div>
|
|
25854
|
-
`, styles: [".footer-links .mobile-layout{display:block;text-align:center;padding:8px 0}.footer-links .desktop-layout{display:none;align-items:flex-end;justify-content:space-between;margin-top:16px;padding:8px 0}.footer-links .social-links-container{display:flex;align-items:center;justify-content:center;gap:12px;margin-top:8px;flex-wrap:wrap}.footer-links .social-button{--color: #666;--color-hover: #333;transition:all .2s ease;min-height:40px;min-width:40px;margin:0}.footer-links .social-button:hover{--color: #333;transform:translateY(-1px)}.footer-links .social-button ion-icon{font-size:1.25rem}.footer-links .logo-clickable{cursor:pointer}.footer-links .footer-logo--css-var{display:block;background-image:var(--logo-var);background-size:contain;background-repeat:no-repeat;background-position:center;transition:opacity .2s ease}.footer-links .footer-logo--css-var:hover{opacity:.8}.footer-links .mobile-layout .footer-logo--css-var{margin-left:auto;margin-right:auto}.footer-links .footer-logo--light{display:block}.footer-links .footer-logo--dark{display:none}.footer-links :host-context(.dark) .footer-logo--light,.footer-links :host-context(.ion-palette-dark) .footer-logo--light,.footer-links :host-context(html.ion-palette-dark) .footer-logo--light,.footer-links :host-context(body.dark) .footer-logo--light,.footer-links :host-context([data-theme=dark]) .footer-logo--light{display:none}.footer-links :host-context(.dark) .footer-logo--dark,.footer-links :host-context(.ion-palette-dark) .footer-logo--dark,.footer-links :host-context(html.ion-palette-dark) .footer-logo--dark,.footer-links :host-context(body.dark) .footer-logo--dark,.footer-links :host-context([data-theme=dark]) .footer-logo--dark{display:block}@media (min-width: 768px){.footer-links .mobile-layout{display:none!important}.footer-links .desktop-layout{display:flex!important}.footer-links .social-links-container{margin-top:0;justify-content:flex-end}}@media (max-width: 767px){.footer-links .mobile-layout{display:block!important}.footer-links .desktop-layout{display:none!important}.footer-links .social-links-container{justify-content:center;margin-bottom:8px}}\n"] }]
|
|
25854
|
+
`, styles: [".footer-links .mobile-layout{display:block;text-align:center;padding:8px 0}.footer-links .desktop-layout{display:none;align-items:flex-end;justify-content:space-between;margin-top:16px;padding:8px 0}.footer-links .social-links-container{display:flex;align-items:center;justify-content:center;gap:12px;margin-top:8px;flex-wrap:wrap}.footer-links .social-button{--color: #666;--color-hover: #333;transition:all .2s ease;min-height:40px;min-width:40px;margin:0}.footer-links .social-button:hover{--color: #333;transform:translateY(-1px)}.footer-links .social-button ion-icon{font-size:1.25rem}.footer-links .logo-clickable{cursor:pointer}.footer-links .footer-logo--css-var{display:block;background-image:var(--logo-var);background-size:contain;background-repeat:no-repeat;background-position:left center;transition:opacity .2s ease}.footer-links .footer-logo--css-var:hover{opacity:.8}.footer-links .mobile-layout .footer-logo--css-var{background-position:center;margin-left:auto;margin-right:auto}.footer-links .footer-logo--light{display:block}.footer-links .footer-logo--dark{display:none}.footer-links :host-context(.dark) .footer-logo--light,.footer-links :host-context(.ion-palette-dark) .footer-logo--light,.footer-links :host-context(html.ion-palette-dark) .footer-logo--light,.footer-links :host-context(body.dark) .footer-logo--light,.footer-links :host-context([data-theme=dark]) .footer-logo--light{display:none}.footer-links :host-context(.dark) .footer-logo--dark,.footer-links :host-context(.ion-palette-dark) .footer-logo--dark,.footer-links :host-context(html.ion-palette-dark) .footer-logo--dark,.footer-links :host-context(body.dark) .footer-logo--dark,.footer-links :host-context([data-theme=dark]) .footer-logo--dark{display:block}@media (min-width: 768px){.footer-links .mobile-layout{display:none!important}.footer-links .desktop-layout{display:flex!important}.footer-links .social-links-container{margin-top:0;justify-content:flex-end}}@media (max-width: 767px){.footer-links .mobile-layout{display:block!important}.footer-links .desktop-layout{display:none!important}.footer-links .social-links-container{justify-content:center;margin-bottom:8px}}\n"] }]
|
|
25855
25855
|
}], propDecorators: { props: [{
|
|
25856
25856
|
type: Input
|
|
25857
25857
|
}], logoClick: [{
|
|
@@ -39115,6 +39115,177 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
39115
39115
|
type: Output
|
|
39116
39116
|
}] } });
|
|
39117
39117
|
|
|
39118
|
+
/**
|
|
39119
|
+
* Standard cross-app site links (env-aware)
|
|
39120
|
+
*
|
|
39121
|
+
* En el factory MyValtech cada producto satélite (showcase, sigify, …) enlaza a
|
|
39122
|
+
* `web` —la landing de marca— para soporte, contacto y contenido legal. `web`
|
|
39123
|
+
* es el dueño canónico de esas rutas. Este módulo centraliza:
|
|
39124
|
+
*
|
|
39125
|
+
* 1. El mapa ambiente → base URL de `web` (`VALTECH_WEB_BASE_URLS`).
|
|
39126
|
+
* 2. El catálogo de paths estándar que viven en `web` (`VALTECH_SITE_PATHS`).
|
|
39127
|
+
*
|
|
39128
|
+
* El ambiente se decide en BUILD TIME (campo `valtechEnv` en el `environment*.ts`
|
|
39129
|
+
* de cada app), igual que `apiUrl`. Es el mecanismo más confiable: detectar por
|
|
39130
|
+
* hostname en runtime se rompe con dominios custom / `web.app` / variantes de
|
|
39131
|
+
* localhost.
|
|
39132
|
+
*
|
|
39133
|
+
* La resolución real (join baseUrl + path, abrir en tab nueva, `?lang=`) la hace
|
|
39134
|
+
* `LegalLinkService`; este módulo solo le entrega el `baseUrl` correcto por env.
|
|
39135
|
+
*
|
|
39136
|
+
* @see provideValtechSite — wiring de una sola línea para apps satélite.
|
|
39137
|
+
*/
|
|
39138
|
+
/**
|
|
39139
|
+
* Base URL de `web` (landing de marca) por ambiente.
|
|
39140
|
+
*
|
|
39141
|
+
* - `local` → `ng serve` de `web` (puerto 8100).
|
|
39142
|
+
* - `dev` → proyecto Firebase `myvaltech-dev`.
|
|
39143
|
+
* - `prod` → dominio custom de producción.
|
|
39144
|
+
*
|
|
39145
|
+
* Sin trailing slash (lo asume `LegalLinkService`).
|
|
39146
|
+
*/
|
|
39147
|
+
const VALTECH_WEB_BASE_URLS = {
|
|
39148
|
+
local: 'http://localhost:8100',
|
|
39149
|
+
dev: 'https://myvaltech-dev.web.app',
|
|
39150
|
+
prod: 'https://myvaltech.com',
|
|
39151
|
+
};
|
|
39152
|
+
/**
|
|
39153
|
+
* Resuelve la base URL de `web` para un ambiente.
|
|
39154
|
+
*
|
|
39155
|
+
* Fallback a `prod` cuando el env es desconocido o falta: ante la duda, apuntar
|
|
39156
|
+
* a producción es lo seguro (nunca enlaza a un host local/dev inexistente).
|
|
39157
|
+
*/
|
|
39158
|
+
function resolveWebBaseUrl(env) {
|
|
39159
|
+
if (env && env in VALTECH_WEB_BASE_URLS) {
|
|
39160
|
+
return VALTECH_WEB_BASE_URLS[env];
|
|
39161
|
+
}
|
|
39162
|
+
return VALTECH_WEB_BASE_URLS.prod;
|
|
39163
|
+
}
|
|
39164
|
+
/**
|
|
39165
|
+
* Catálogo de paths estándar que viven en `web`. Las apps resuelven estos
|
|
39166
|
+
* contra la base URL del ambiente vía `LegalLinkService.resolve(path)`.
|
|
39167
|
+
*
|
|
39168
|
+
* Mantener alineado con las rutas reales de `web/src/app/app.routes.ts` y con
|
|
39169
|
+
* `VALTECH_COMPANY_LINKS` (footer).
|
|
39170
|
+
*/
|
|
39171
|
+
const VALTECH_SITE_PATHS = {
|
|
39172
|
+
home: '/',
|
|
39173
|
+
support: '/contact',
|
|
39174
|
+
contact: '/contact',
|
|
39175
|
+
faq: '/faq',
|
|
39176
|
+
about: '/about',
|
|
39177
|
+
terms: '/legal/terms',
|
|
39178
|
+
privacy: '/legal/privacy',
|
|
39179
|
+
cookies: '/legal/cookies',
|
|
39180
|
+
legalNotice: '/legal/legal-notice',
|
|
39181
|
+
};
|
|
39182
|
+
|
|
39183
|
+
const VALTECH_LEGAL_CONFIG = new InjectionToken('VALTECH_LEGAL_CONFIG');
|
|
39184
|
+
/**
|
|
39185
|
+
* Resolves legal/site paths against a configurable main-site base URL.
|
|
39186
|
+
*
|
|
39187
|
+
* - **Main site mode**: no `provideValtechLegal` called → `resolve('/legal/terms')` returns `/legal/terms` (relative).
|
|
39188
|
+
* - **Satellite mode**: `provideValtechLegal({ baseUrl: 'https://myvaltech.com' })` → `resolve('/legal/terms')` returns `'https://myvaltech.com/legal/terms'` and `isExternal('/legal/terms')` returns `true`.
|
|
39189
|
+
*
|
|
39190
|
+
* Absolute URLs passed in are returned unchanged (no double-prefix).
|
|
39191
|
+
*/
|
|
39192
|
+
class LegalLinkService {
|
|
39193
|
+
constructor() {
|
|
39194
|
+
this.config = inject(VALTECH_LEGAL_CONFIG, { optional: true }) ?? {};
|
|
39195
|
+
}
|
|
39196
|
+
/** Effective base URL (null if running as main site). */
|
|
39197
|
+
get baseUrl() {
|
|
39198
|
+
return this.config.baseUrl?.replace(/\/$/, '') ?? null;
|
|
39199
|
+
}
|
|
39200
|
+
/** Whether resolved external links should open in a new tab. */
|
|
39201
|
+
get openInNewTab() {
|
|
39202
|
+
return this.config.openInNewTab ?? Boolean(this.config.baseUrl);
|
|
39203
|
+
}
|
|
39204
|
+
/**
|
|
39205
|
+
* Returns the URL to use for a given internal path. Absolute URLs pass through.
|
|
39206
|
+
*
|
|
39207
|
+
* When `locale` is provided AND the resolved URL would be cross-origin, appends
|
|
39208
|
+
* `?lang={locale}` so the main site can render the legal doc in the user's
|
|
39209
|
+
* active language (instead of its default). Locale is omitted for same-origin
|
|
39210
|
+
* resolves since the main site reads locale from its own `LocaleService`.
|
|
39211
|
+
*
|
|
39212
|
+
* @example
|
|
39213
|
+
* resolve('/legal/terms')
|
|
39214
|
+
* // main site: '/legal/terms'
|
|
39215
|
+
* // satellite: 'https://myvaltech.com/legal/terms'
|
|
39216
|
+
*
|
|
39217
|
+
* resolve('/legal/terms', { locale: 'pt' })
|
|
39218
|
+
* // main site: '/legal/terms' (locale stays implicit)
|
|
39219
|
+
* // satellite: 'https://myvaltech.com/legal/terms?lang=pt'
|
|
39220
|
+
*
|
|
39221
|
+
* resolve('https://x.com/y') // unchanged
|
|
39222
|
+
*/
|
|
39223
|
+
resolve(path, options) {
|
|
39224
|
+
if (!path)
|
|
39225
|
+
return path;
|
|
39226
|
+
if (/^https?:\/\//i.test(path))
|
|
39227
|
+
return path;
|
|
39228
|
+
const base = this.baseUrl;
|
|
39229
|
+
if (!base)
|
|
39230
|
+
return path;
|
|
39231
|
+
const url = `${base}${path.startsWith('/') ? '' : '/'}${path}`;
|
|
39232
|
+
if (options?.locale) {
|
|
39233
|
+
const sep = url.includes('?') ? '&' : '?';
|
|
39234
|
+
return `${url}${sep}lang=${encodeURIComponent(options.locale)}`;
|
|
39235
|
+
}
|
|
39236
|
+
return url;
|
|
39237
|
+
}
|
|
39238
|
+
/** `true` if the path would be resolved to a cross-origin URL. */
|
|
39239
|
+
isExternal(path) {
|
|
39240
|
+
if (/^https?:\/\//i.test(path))
|
|
39241
|
+
return true;
|
|
39242
|
+
return this.baseUrl !== null;
|
|
39243
|
+
}
|
|
39244
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LegalLinkService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
39245
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LegalLinkService, providedIn: 'root' }); }
|
|
39246
|
+
}
|
|
39247
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LegalLinkService, decorators: [{
|
|
39248
|
+
type: Injectable,
|
|
39249
|
+
args: [{ providedIn: 'root' }]
|
|
39250
|
+
}] });
|
|
39251
|
+
/**
|
|
39252
|
+
* Wires `LegalLinkService` for satellite apps. Omit in the main site (the one
|
|
39253
|
+
* that hosts the canonical /legal/* routes) so links stay relative.
|
|
39254
|
+
*
|
|
39255
|
+
* @example
|
|
39256
|
+
* // main.ts of showcase / sigify / etc.
|
|
39257
|
+
* provideValtechLegal({
|
|
39258
|
+
* baseUrl: 'https://myvaltech.com',
|
|
39259
|
+
* openInNewTab: true,
|
|
39260
|
+
* }),
|
|
39261
|
+
*/
|
|
39262
|
+
function provideValtechLegal(config) {
|
|
39263
|
+
return { provide: VALTECH_LEGAL_CONFIG, useValue: config };
|
|
39264
|
+
}
|
|
39265
|
+
/**
|
|
39266
|
+
* Wiring de una sola línea para que una app satélite apunte sus links de sitio
|
|
39267
|
+
* (legal, soporte, contacto, …) a `web` —la landing de marca— en el ambiente
|
|
39268
|
+
* correcto. Resuelve el `baseUrl` desde `VALTECH_WEB_BASE_URLS` según el `env`
|
|
39269
|
+
* baked en build-time (`environment.valtechEnv`) y delega en `provideValtechLegal`.
|
|
39270
|
+
*
|
|
39271
|
+
* Ambiente desconocido/ausente → fallback a `prod` (ver `resolveWebBaseUrl`).
|
|
39272
|
+
* El main site (`web`) NO llama esto — sus links quedan relativos.
|
|
39273
|
+
*
|
|
39274
|
+
* @example
|
|
39275
|
+
* // main.ts de showcase / sigify / …
|
|
39276
|
+
* import { environment } from './environments/environment';
|
|
39277
|
+
* provideValtechSite(environment.valtechEnv), // 'local' | 'dev' | 'prod'
|
|
39278
|
+
*
|
|
39279
|
+
* @see resolveWebBaseUrl
|
|
39280
|
+
* @see VALTECH_SITE_PATHS — catálogo de paths estándar que viven en `web`.
|
|
39281
|
+
*/
|
|
39282
|
+
function provideValtechSite(env, options) {
|
|
39283
|
+
return provideValtechLegal({
|
|
39284
|
+
baseUrl: resolveWebBaseUrl(env),
|
|
39285
|
+
openInNewTab: options?.openInNewTab ?? true,
|
|
39286
|
+
});
|
|
39287
|
+
}
|
|
39288
|
+
|
|
39118
39289
|
/**
|
|
39119
39290
|
* Default values for LoginMetadata
|
|
39120
39291
|
*/
|
|
@@ -39138,6 +39309,7 @@ class LoginComponent {
|
|
|
39138
39309
|
this.router = inject(Router);
|
|
39139
39310
|
this.i18n = inject(I18nService);
|
|
39140
39311
|
this.i18nHelper = inject(InputI18nHelper);
|
|
39312
|
+
this.legalLink = inject(LegalLinkService);
|
|
39141
39313
|
// Timers
|
|
39142
39314
|
this.resendTimer = null;
|
|
39143
39315
|
this.resetResendTimer = null;
|
|
@@ -39460,6 +39632,10 @@ class LoginComponent {
|
|
|
39460
39632
|
});
|
|
39461
39633
|
});
|
|
39462
39634
|
}
|
|
39635
|
+
/** URL del sitio principal resuelta por ambiente — fallback cuando el consumer no pasa companyLink. */
|
|
39636
|
+
get resolvedCompanyLink() {
|
|
39637
|
+
return this.props.legal?.companyLink ?? this.legalLink.baseUrl ?? undefined;
|
|
39638
|
+
}
|
|
39463
39639
|
/**
|
|
39464
39640
|
* Helper method for translating auth-related strings.
|
|
39465
39641
|
* Exposed to template for dynamic text.
|
|
@@ -39832,7 +40008,7 @@ class LoginComponent {
|
|
|
39832
40008
|
this.stopResetResendCooldown();
|
|
39833
40009
|
}
|
|
39834
40010
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LoginComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
39835
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: LoginComponent, isStandalone: true, selector: "val-login", inputs: { props: "props" }, outputs: { onSuccess: "onSuccess", onError: "onError", onMFARequired: "onMFARequired" }, ngImport: i0, template: "<div class=\"val-login\" [class.val-login--card]=\"config.showCard\">\n <!-- Logo -->\n @if (props.logo) {\n <div class=\"logo-container\">\n <val-image [props]=\"props.logo\" />\n </div>\n }\n\n <!-- Login Form -->\n <val-form [props]=\"loginFormProps()\" (onSubmit)=\"loginHandler($event)\" />\n\n <!-- OAuth Section -->\n @if (config.showOAuth && config.oauthProviders.length > 0) {\n <div class=\"oauth-separator\">\n <span>{{ t('orContinueWith') }}</span>\n </div>\n\n <div class=\"oauth-buttons\">\n @for (provider of config.oauthProviders; track provider) {\n <ion-button\n expand=\"block\"\n fill=\"outline\"\n color=\"dark\"\n (click)=\"loginWithOAuth(provider)\"\n [disabled]=\"isOAuthLoading\"\n >\n @switch (provider) { @case ('google') {\n <ion-icon slot=\"start\" name=\"logo-google\"></ion-icon>\n {{ isOAuthLoading ? t('connecting') : t('continueWithGoogle') }} } @case ('apple') {\n <ion-icon slot=\"start\" name=\"logo-apple\"></ion-icon>\n {{ isOAuthLoading ? t('connecting') : t('continueWithApple') }} } @case ('microsoft') {\n <ion-icon slot=\"start\" name=\"logo-microsoft\"></ion-icon>\n {{ isOAuthLoading ? t('connecting') : t('continueWithMicrosoft') }} } }\n </ion-button>\n }\n </div>\n }\n\n <!-- Register Link -->\n @if (config.showRegister) {\n <div class=\"auth-link\">\n <ion-text color=\"dark\">\n {{ t('noAccount') }}\n <a (click)=\"openRegisterModal()\">{{ t('register') }}</a>\n </ion-text>\n </div>\n }\n\n <!-- Forgot Password Link -->\n @if (config.showForgotPassword) {\n <div class=\"auth-link forgot-password\">\n <ion-text color=\"dark\">\n {{ t('forgotLink') }}\n <a (click)=\"openForgotPasswordModal()\">{{ t('recoverPassword') }}</a>\n </ion-text>\n </div>\n }\n\n <!-- Legal Notice -->\n @if (props.legal) {\n <div class=\"legal-notice\">\n <ion-text color=\"dark\">\n <p>\n {{ t('legalPrefix') }} @if (props.legal.companyLink) {\n <a [href]=\"props.legal.companyLink\"><strong>{{ props.legal.companyName }}</strong></a>\n } @else {\n <strong>{{ props.legal.companyName }}</strong>\n } {{ t('legalSuffix') }} @if (props.legal.termsLink) {\n <a [href]=\"props.legal.termsLink\">{{ t('termsAndConditions') }}</a>\n } @else {\n <span>{{ t('termsAndConditions') }}</span>\n } {{ t('and') }} @if (props.legal.privacyLink) {\n <a [href]=\"props.legal.privacyLink\">{{ t('privacyPolicy') }}</a>\n } @else {\n <span>{{ t('privacyPolicy') }}</span>\n }.\n </p>\n </ion-text>\n </div>\n }\n</div>\n\n<!-- Register Modal -->\n<ion-modal [isOpen]=\"isRegisterModalOpen\" (didDismiss)=\"closeRegisterModal()\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" (click)=\"closeRegisterModal()\">\n <ion-icon name=\"close-outline\"></ion-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n @if (props.logo) {\n <div class=\"logo-container\">\n <val-image [props]=\"props.logo\" />\n </div>\n }\n <val-form [props]=\"registerFormProps()\" (onSubmit)=\"registerHandler($event)\" />\n <div class=\"auth-link\">\n <ion-text color=\"dark\">\n {{ t('hasAccount') }}\n <a (click)=\"closeRegisterModal()\">{{ t('signIn') }}</a>\n </ion-text>\n </div>\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- Verify Email Modal -->\n<ion-modal [isOpen]=\"isVerifyModalOpen\" [backdropDismiss]=\"false\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" (click)=\"closeVerifyModal()\">\n <ion-icon name=\"close-outline\"></ion-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n @if (props.logo) {\n <div class=\"logo-container\">\n <val-image [props]=\"props.logo\" />\n </div>\n }\n <val-form [props]=\"verifyFormProps()\" (onSubmit)=\"verifyHandler($event)\" />\n <div class=\"resend-link\">\n <ion-text color=\"dark\">\n {{ t('noCodeReceived') }} @if (resendCooldown > 0) {\n <span class=\"cooldown\">{{ t('resendIn', { seconds: resendCooldown.toString() }) }}</span>\n } @else {\n <a (click)=\"resendCode()\">{{ t('resend') }}</a>\n }\n </ion-text>\n </div>\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- Forgot Password Modal -->\n<ion-modal [isOpen]=\"isForgotPasswordModalOpen\" (didDismiss)=\"closeForgotPasswordModal()\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" (click)=\"closeForgotPasswordModal()\">\n <ion-icon name=\"close-outline\"></ion-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n @if (props.logo) {\n <div class=\"logo-container\">\n <val-image [props]=\"props.logo\" />\n </div>\n }\n <val-form [props]=\"forgotPasswordFormProps()\" (onSubmit)=\"forgotPasswordHandler($event)\" />\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- Reset Password Modal -->\n<ion-modal [isOpen]=\"isResetPasswordModalOpen\" [backdropDismiss]=\"false\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" (click)=\"closeResetPasswordModal()\">\n <ion-icon name=\"close-outline\"></ion-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n @if (props.logo) {\n <div class=\"logo-container\">\n <val-image [props]=\"props.logo\" />\n </div>\n }\n <val-form [props]=\"resetPasswordFormProps()\" (onSubmit)=\"resetPasswordHandler($event)\" />\n <div class=\"resend-link\">\n <ion-text color=\"dark\">\n {{ t('noCodeReceived') }} @if (resetResendCooldown > 0) {\n <span class=\"cooldown\">{{ t('resendIn', { seconds: resetResendCooldown.toString() }) }}</span>\n } @else {\n <a (click)=\"resendResetCode()\">{{ t('resend') }}</a>\n }\n </ion-text>\n </div>\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- MFA Verify Modal -->\n<ion-modal [isOpen]=\"isMFAVerifyModalOpen\" [backdropDismiss]=\"false\" (didDismiss)=\"onMFAVerifyDismissed()\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" (click)=\"closeMFAVerifyModal()\">\n <ion-icon name=\"close-outline\"></ion-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n @if (props.logo) {\n <div class=\"logo-container\">\n <val-image [props]=\"props.logo\" />\n </div>\n }\n <val-form [props]=\"mfaVerifyFormProps()\" (onSubmit)=\"verifyMFAHandler($event)\" />\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n", styles: [".val-login{width:100%}.val-login--card{padding:1rem .75rem;background:var(--ion-color-light);border-radius:16px;box-shadow:0 2px 8px #00000014}.logo-container{max-width:130px;margin-bottom:1.5rem}.auth-link{text-align:center;margin-top:1rem;font-size:.9rem}.auth-link a{color:var(--ion-color-primary);text-decoration:none;font-weight:500;cursor:pointer}.auth-link a:hover{text-decoration:underline}.oauth-separator{display:flex;align-items:center;margin:1.5rem 0}.oauth-separator:before,.oauth-separator:after{content:\"\";flex:1;height:1px;background:var(--ion-color-medium-tint)}.oauth-separator span{padding:0 1rem;color:var(--ion-color-dark);font-size:.85rem}.oauth-buttons{margin-bottom:1rem}.oauth-buttons ion-button{--border-radius: 8px;--border-width: 1px}.oauth-buttons ion-icon{font-size:1.2rem;margin-right:.5rem}.legal-notice{margin-top:1.5rem;padding-top:1rem;border-top:1px solid var(--ion-color-medium-tint)}.legal-notice p{font-size:.75rem;line-height:1.5;text-align:center;margin:0}.legal-notice a{color:var(--ion-color-primary);text-decoration:none}.legal-notice a:hover{text-decoration:underline}.resend-link{text-align:center;margin-top:1rem;font-size:.9rem}.resend-link a{color:var(--ion-color-primary);cursor:pointer;font-weight:500}.resend-link a:hover{text-decoration:underline}.resend-link .cooldown{color:var(--ion-color-medium)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { kind: "component", type: IonContent, selector: "ion-content", inputs: ["color", "fixedSlotPlacement", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: IonHeader, selector: "ion-header", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: IonModal, selector: "ion-modal" }, { kind: "component", type: IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "component", type: FormComponent, selector: "val-form", inputs: ["props"], outputs: ["onSubmit", "onInvalid", "onSelectChange"] }, { kind: "component", type: ImageComponent, selector: "val-image", inputs: ["props"] }] }); }
|
|
40011
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: LoginComponent, isStandalone: true, selector: "val-login", inputs: { props: "props" }, outputs: { onSuccess: "onSuccess", onError: "onError", onMFARequired: "onMFARequired" }, ngImport: i0, template: "<div class=\"val-login\" [class.val-login--card]=\"config.showCard\">\n <!-- Logo -->\n @if (props.logo) {\n <div class=\"logo-container\">\n <val-image [props]=\"props.logo\" />\n </div>\n }\n\n <!-- Login Form -->\n <val-form [props]=\"loginFormProps()\" (onSubmit)=\"loginHandler($event)\" />\n\n <!-- OAuth Section -->\n @if (config.showOAuth && config.oauthProviders.length > 0) {\n <div class=\"oauth-separator\">\n <span>{{ t('orContinueWith') }}</span>\n </div>\n\n <div class=\"oauth-buttons\">\n @for (provider of config.oauthProviders; track provider) {\n <ion-button\n expand=\"block\"\n fill=\"outline\"\n color=\"dark\"\n (click)=\"loginWithOAuth(provider)\"\n [disabled]=\"isOAuthLoading\"\n >\n @switch (provider) { @case ('google') {\n <ion-icon slot=\"start\" name=\"logo-google\"></ion-icon>\n {{ isOAuthLoading ? t('connecting') : t('continueWithGoogle') }} } @case ('apple') {\n <ion-icon slot=\"start\" name=\"logo-apple\"></ion-icon>\n {{ isOAuthLoading ? t('connecting') : t('continueWithApple') }} } @case ('microsoft') {\n <ion-icon slot=\"start\" name=\"logo-microsoft\"></ion-icon>\n {{ isOAuthLoading ? t('connecting') : t('continueWithMicrosoft') }} } }\n </ion-button>\n }\n </div>\n }\n\n <!-- Register Link -->\n @if (config.showRegister) {\n <div class=\"auth-link\">\n <ion-text color=\"dark\">\n {{ t('noAccount') }}\n <a (click)=\"openRegisterModal()\">{{ t('register') }}</a>\n </ion-text>\n </div>\n }\n\n <!-- Forgot Password Link -->\n @if (config.showForgotPassword) {\n <div class=\"auth-link forgot-password\">\n <ion-text color=\"dark\">\n {{ t('forgotLink') }}\n <a (click)=\"openForgotPasswordModal()\">{{ t('recoverPassword') }}</a>\n </ion-text>\n </div>\n }\n\n <!-- Legal Notice -->\n @if (props.legal) {\n <div class=\"legal-notice\">\n <ion-text color=\"dark\">\n <p>\n {{ t('legalPrefix') }} @if (resolvedCompanyLink) {\n <a [href]=\"resolvedCompanyLink\" target=\"_blank\" rel=\"noopener noreferrer\"\n ><strong>{{ props.legal.companyName }}</strong></a\n >\n } @else {\n <strong>{{ props.legal.companyName }}</strong>\n } {{ t('legalSuffix') }} @if (props.legal.termsLink) {\n <a [href]=\"props.legal.termsLink\">{{ t('termsAndConditions') }}</a>\n } @else {\n <span>{{ t('termsAndConditions') }}</span>\n } {{ t('and') }} @if (props.legal.privacyLink) {\n <a [href]=\"props.legal.privacyLink\">{{ t('privacyPolicy') }}</a>\n } @else {\n <span>{{ t('privacyPolicy') }}</span>\n }.\n </p>\n </ion-text>\n </div>\n }\n</div>\n\n<!-- Register Modal -->\n<ion-modal [isOpen]=\"isRegisterModalOpen\" (didDismiss)=\"closeRegisterModal()\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" (click)=\"closeRegisterModal()\">\n <ion-icon name=\"close-outline\"></ion-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n @if (props.logo) {\n <div class=\"logo-container\">\n <val-image [props]=\"props.logo\" />\n </div>\n }\n <val-form [props]=\"registerFormProps()\" (onSubmit)=\"registerHandler($event)\" />\n <div class=\"auth-link\">\n <ion-text color=\"dark\">\n {{ t('hasAccount') }}\n <a (click)=\"closeRegisterModal()\">{{ t('signIn') }}</a>\n </ion-text>\n </div>\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- Verify Email Modal -->\n<ion-modal [isOpen]=\"isVerifyModalOpen\" [backdropDismiss]=\"false\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" (click)=\"closeVerifyModal()\">\n <ion-icon name=\"close-outline\"></ion-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n @if (props.logo) {\n <div class=\"logo-container\">\n <val-image [props]=\"props.logo\" />\n </div>\n }\n <val-form [props]=\"verifyFormProps()\" (onSubmit)=\"verifyHandler($event)\" />\n <div class=\"resend-link\">\n <ion-text color=\"dark\">\n {{ t('noCodeReceived') }} @if (resendCooldown > 0) {\n <span class=\"cooldown\">{{ t('resendIn', { seconds: resendCooldown.toString() }) }}</span>\n } @else {\n <a (click)=\"resendCode()\">{{ t('resend') }}</a>\n }\n </ion-text>\n </div>\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- Forgot Password Modal -->\n<ion-modal [isOpen]=\"isForgotPasswordModalOpen\" (didDismiss)=\"closeForgotPasswordModal()\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" (click)=\"closeForgotPasswordModal()\">\n <ion-icon name=\"close-outline\"></ion-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n @if (props.logo) {\n <div class=\"logo-container\">\n <val-image [props]=\"props.logo\" />\n </div>\n }\n <val-form [props]=\"forgotPasswordFormProps()\" (onSubmit)=\"forgotPasswordHandler($event)\" />\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- Reset Password Modal -->\n<ion-modal [isOpen]=\"isResetPasswordModalOpen\" [backdropDismiss]=\"false\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" (click)=\"closeResetPasswordModal()\">\n <ion-icon name=\"close-outline\"></ion-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n @if (props.logo) {\n <div class=\"logo-container\">\n <val-image [props]=\"props.logo\" />\n </div>\n }\n <val-form [props]=\"resetPasswordFormProps()\" (onSubmit)=\"resetPasswordHandler($event)\" />\n <div class=\"resend-link\">\n <ion-text color=\"dark\">\n {{ t('noCodeReceived') }} @if (resetResendCooldown > 0) {\n <span class=\"cooldown\">{{ t('resendIn', { seconds: resetResendCooldown.toString() }) }}</span>\n } @else {\n <a (click)=\"resendResetCode()\">{{ t('resend') }}</a>\n }\n </ion-text>\n </div>\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- MFA Verify Modal -->\n<ion-modal [isOpen]=\"isMFAVerifyModalOpen\" [backdropDismiss]=\"false\" (didDismiss)=\"onMFAVerifyDismissed()\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" (click)=\"closeMFAVerifyModal()\">\n <ion-icon name=\"close-outline\"></ion-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n @if (props.logo) {\n <div class=\"logo-container\">\n <val-image [props]=\"props.logo\" />\n </div>\n }\n <val-form [props]=\"mfaVerifyFormProps()\" (onSubmit)=\"verifyMFAHandler($event)\" />\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n", styles: [".val-login{width:100%}.val-login--card{padding:1rem .75rem;background:var(--ion-color-light);border-radius:16px;box-shadow:0 2px 8px #00000014}.logo-container{max-width:130px;margin-bottom:1.5rem}.auth-link{text-align:center;margin-top:1rem;font-size:.9rem}.auth-link a{color:var(--ion-color-primary);text-decoration:none;font-weight:500;cursor:pointer}.auth-link a:hover{text-decoration:underline}.oauth-separator{display:flex;align-items:center;margin:1.5rem 0}.oauth-separator:before,.oauth-separator:after{content:\"\";flex:1;height:1px;background:var(--ion-color-medium-tint)}.oauth-separator span{padding:0 1rem;color:var(--ion-color-dark);font-size:.85rem}.oauth-buttons{margin-bottom:1rem}.oauth-buttons ion-button{--border-radius: 8px;--border-width: 1px}.oauth-buttons ion-icon{font-size:1.2rem;margin-right:.5rem}.legal-notice{margin-top:1.5rem;padding-top:1rem;border-top:1px solid var(--ion-color-medium-tint)}.legal-notice p{font-size:.75rem;line-height:1.5;text-align:center;margin:0}.legal-notice a{color:var(--ion-color-primary);text-decoration:none}.legal-notice a:hover{text-decoration:underline}.resend-link{text-align:center;margin-top:1rem;font-size:.9rem}.resend-link a{color:var(--ion-color-primary);cursor:pointer;font-weight:500}.resend-link a:hover{text-decoration:underline}.resend-link .cooldown{color:var(--ion-color-medium)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { kind: "component", type: IonContent, selector: "ion-content", inputs: ["color", "fixedSlotPlacement", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: IonHeader, selector: "ion-header", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: IonModal, selector: "ion-modal" }, { kind: "component", type: IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "component", type: FormComponent, selector: "val-form", inputs: ["props"], outputs: ["onSubmit", "onInvalid", "onSelectChange"] }, { kind: "component", type: ImageComponent, selector: "val-image", inputs: ["props"] }] }); }
|
|
39836
40012
|
}
|
|
39837
40013
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LoginComponent, decorators: [{
|
|
39838
40014
|
type: Component,
|
|
@@ -39848,7 +40024,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
39848
40024
|
IonToolbar,
|
|
39849
40025
|
FormComponent,
|
|
39850
40026
|
ImageComponent,
|
|
39851
|
-
], template: "<div class=\"val-login\" [class.val-login--card]=\"config.showCard\">\n <!-- Logo -->\n @if (props.logo) {\n <div class=\"logo-container\">\n <val-image [props]=\"props.logo\" />\n </div>\n }\n\n <!-- Login Form -->\n <val-form [props]=\"loginFormProps()\" (onSubmit)=\"loginHandler($event)\" />\n\n <!-- OAuth Section -->\n @if (config.showOAuth && config.oauthProviders.length > 0) {\n <div class=\"oauth-separator\">\n <span>{{ t('orContinueWith') }}</span>\n </div>\n\n <div class=\"oauth-buttons\">\n @for (provider of config.oauthProviders; track provider) {\n <ion-button\n expand=\"block\"\n fill=\"outline\"\n color=\"dark\"\n (click)=\"loginWithOAuth(provider)\"\n [disabled]=\"isOAuthLoading\"\n >\n @switch (provider) { @case ('google') {\n <ion-icon slot=\"start\" name=\"logo-google\"></ion-icon>\n {{ isOAuthLoading ? t('connecting') : t('continueWithGoogle') }} } @case ('apple') {\n <ion-icon slot=\"start\" name=\"logo-apple\"></ion-icon>\n {{ isOAuthLoading ? t('connecting') : t('continueWithApple') }} } @case ('microsoft') {\n <ion-icon slot=\"start\" name=\"logo-microsoft\"></ion-icon>\n {{ isOAuthLoading ? t('connecting') : t('continueWithMicrosoft') }} } }\n </ion-button>\n }\n </div>\n }\n\n <!-- Register Link -->\n @if (config.showRegister) {\n <div class=\"auth-link\">\n <ion-text color=\"dark\">\n {{ t('noAccount') }}\n <a (click)=\"openRegisterModal()\">{{ t('register') }}</a>\n </ion-text>\n </div>\n }\n\n <!-- Forgot Password Link -->\n @if (config.showForgotPassword) {\n <div class=\"auth-link forgot-password\">\n <ion-text color=\"dark\">\n {{ t('forgotLink') }}\n <a (click)=\"openForgotPasswordModal()\">{{ t('recoverPassword') }}</a>\n </ion-text>\n </div>\n }\n\n <!-- Legal Notice -->\n @if (props.legal) {\n <div class=\"legal-notice\">\n <ion-text color=\"dark\">\n <p>\n {{ t('legalPrefix') }} @if (
|
|
40027
|
+
], template: "<div class=\"val-login\" [class.val-login--card]=\"config.showCard\">\n <!-- Logo -->\n @if (props.logo) {\n <div class=\"logo-container\">\n <val-image [props]=\"props.logo\" />\n </div>\n }\n\n <!-- Login Form -->\n <val-form [props]=\"loginFormProps()\" (onSubmit)=\"loginHandler($event)\" />\n\n <!-- OAuth Section -->\n @if (config.showOAuth && config.oauthProviders.length > 0) {\n <div class=\"oauth-separator\">\n <span>{{ t('orContinueWith') }}</span>\n </div>\n\n <div class=\"oauth-buttons\">\n @for (provider of config.oauthProviders; track provider) {\n <ion-button\n expand=\"block\"\n fill=\"outline\"\n color=\"dark\"\n (click)=\"loginWithOAuth(provider)\"\n [disabled]=\"isOAuthLoading\"\n >\n @switch (provider) { @case ('google') {\n <ion-icon slot=\"start\" name=\"logo-google\"></ion-icon>\n {{ isOAuthLoading ? t('connecting') : t('continueWithGoogle') }} } @case ('apple') {\n <ion-icon slot=\"start\" name=\"logo-apple\"></ion-icon>\n {{ isOAuthLoading ? t('connecting') : t('continueWithApple') }} } @case ('microsoft') {\n <ion-icon slot=\"start\" name=\"logo-microsoft\"></ion-icon>\n {{ isOAuthLoading ? t('connecting') : t('continueWithMicrosoft') }} } }\n </ion-button>\n }\n </div>\n }\n\n <!-- Register Link -->\n @if (config.showRegister) {\n <div class=\"auth-link\">\n <ion-text color=\"dark\">\n {{ t('noAccount') }}\n <a (click)=\"openRegisterModal()\">{{ t('register') }}</a>\n </ion-text>\n </div>\n }\n\n <!-- Forgot Password Link -->\n @if (config.showForgotPassword) {\n <div class=\"auth-link forgot-password\">\n <ion-text color=\"dark\">\n {{ t('forgotLink') }}\n <a (click)=\"openForgotPasswordModal()\">{{ t('recoverPassword') }}</a>\n </ion-text>\n </div>\n }\n\n <!-- Legal Notice -->\n @if (props.legal) {\n <div class=\"legal-notice\">\n <ion-text color=\"dark\">\n <p>\n {{ t('legalPrefix') }} @if (resolvedCompanyLink) {\n <a [href]=\"resolvedCompanyLink\" target=\"_blank\" rel=\"noopener noreferrer\"\n ><strong>{{ props.legal.companyName }}</strong></a\n >\n } @else {\n <strong>{{ props.legal.companyName }}</strong>\n } {{ t('legalSuffix') }} @if (props.legal.termsLink) {\n <a [href]=\"props.legal.termsLink\">{{ t('termsAndConditions') }}</a>\n } @else {\n <span>{{ t('termsAndConditions') }}</span>\n } {{ t('and') }} @if (props.legal.privacyLink) {\n <a [href]=\"props.legal.privacyLink\">{{ t('privacyPolicy') }}</a>\n } @else {\n <span>{{ t('privacyPolicy') }}</span>\n }.\n </p>\n </ion-text>\n </div>\n }\n</div>\n\n<!-- Register Modal -->\n<ion-modal [isOpen]=\"isRegisterModalOpen\" (didDismiss)=\"closeRegisterModal()\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" (click)=\"closeRegisterModal()\">\n <ion-icon name=\"close-outline\"></ion-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n @if (props.logo) {\n <div class=\"logo-container\">\n <val-image [props]=\"props.logo\" />\n </div>\n }\n <val-form [props]=\"registerFormProps()\" (onSubmit)=\"registerHandler($event)\" />\n <div class=\"auth-link\">\n <ion-text color=\"dark\">\n {{ t('hasAccount') }}\n <a (click)=\"closeRegisterModal()\">{{ t('signIn') }}</a>\n </ion-text>\n </div>\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- Verify Email Modal -->\n<ion-modal [isOpen]=\"isVerifyModalOpen\" [backdropDismiss]=\"false\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" (click)=\"closeVerifyModal()\">\n <ion-icon name=\"close-outline\"></ion-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n @if (props.logo) {\n <div class=\"logo-container\">\n <val-image [props]=\"props.logo\" />\n </div>\n }\n <val-form [props]=\"verifyFormProps()\" (onSubmit)=\"verifyHandler($event)\" />\n <div class=\"resend-link\">\n <ion-text color=\"dark\">\n {{ t('noCodeReceived') }} @if (resendCooldown > 0) {\n <span class=\"cooldown\">{{ t('resendIn', { seconds: resendCooldown.toString() }) }}</span>\n } @else {\n <a (click)=\"resendCode()\">{{ t('resend') }}</a>\n }\n </ion-text>\n </div>\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- Forgot Password Modal -->\n<ion-modal [isOpen]=\"isForgotPasswordModalOpen\" (didDismiss)=\"closeForgotPasswordModal()\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" (click)=\"closeForgotPasswordModal()\">\n <ion-icon name=\"close-outline\"></ion-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n @if (props.logo) {\n <div class=\"logo-container\">\n <val-image [props]=\"props.logo\" />\n </div>\n }\n <val-form [props]=\"forgotPasswordFormProps()\" (onSubmit)=\"forgotPasswordHandler($event)\" />\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- Reset Password Modal -->\n<ion-modal [isOpen]=\"isResetPasswordModalOpen\" [backdropDismiss]=\"false\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" (click)=\"closeResetPasswordModal()\">\n <ion-icon name=\"close-outline\"></ion-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n @if (props.logo) {\n <div class=\"logo-container\">\n <val-image [props]=\"props.logo\" />\n </div>\n }\n <val-form [props]=\"resetPasswordFormProps()\" (onSubmit)=\"resetPasswordHandler($event)\" />\n <div class=\"resend-link\">\n <ion-text color=\"dark\">\n {{ t('noCodeReceived') }} @if (resetResendCooldown > 0) {\n <span class=\"cooldown\">{{ t('resendIn', { seconds: resetResendCooldown.toString() }) }}</span>\n } @else {\n <a (click)=\"resendResetCode()\">{{ t('resend') }}</a>\n }\n </ion-text>\n </div>\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n\n<!-- MFA Verify Modal -->\n<ion-modal [isOpen]=\"isMFAVerifyModalOpen\" [backdropDismiss]=\"false\" (didDismiss)=\"onMFAVerifyDismissed()\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot=\"end\">\n <ion-button fill=\"clear\" (click)=\"closeMFAVerifyModal()\">\n <ion-icon name=\"close-outline\"></ion-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"modal-form-section\">\n @if (props.logo) {\n <div class=\"logo-container\">\n <val-image [props]=\"props.logo\" />\n </div>\n }\n <val-form [props]=\"mfaVerifyFormProps()\" (onSubmit)=\"verifyMFAHandler($event)\" />\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n", styles: [".val-login{width:100%}.val-login--card{padding:1rem .75rem;background:var(--ion-color-light);border-radius:16px;box-shadow:0 2px 8px #00000014}.logo-container{max-width:130px;margin-bottom:1.5rem}.auth-link{text-align:center;margin-top:1rem;font-size:.9rem}.auth-link a{color:var(--ion-color-primary);text-decoration:none;font-weight:500;cursor:pointer}.auth-link a:hover{text-decoration:underline}.oauth-separator{display:flex;align-items:center;margin:1.5rem 0}.oauth-separator:before,.oauth-separator:after{content:\"\";flex:1;height:1px;background:var(--ion-color-medium-tint)}.oauth-separator span{padding:0 1rem;color:var(--ion-color-dark);font-size:.85rem}.oauth-buttons{margin-bottom:1rem}.oauth-buttons ion-button{--border-radius: 8px;--border-width: 1px}.oauth-buttons ion-icon{font-size:1.2rem;margin-right:.5rem}.legal-notice{margin-top:1.5rem;padding-top:1rem;border-top:1px solid var(--ion-color-medium-tint)}.legal-notice p{font-size:.75rem;line-height:1.5;text-align:center;margin:0}.legal-notice a{color:var(--ion-color-primary);text-decoration:none}.legal-notice a:hover{text-decoration:underline}.resend-link{text-align:center;margin-top:1rem;font-size:.9rem}.resend-link a{color:var(--ion-color-primary);cursor:pointer;font-weight:500}.resend-link a:hover{text-decoration:underline}.resend-link .cooldown{color:var(--ion-color-medium)}\n"] }]
|
|
39852
40028
|
}], propDecorators: { props: [{
|
|
39853
40029
|
type: Input
|
|
39854
40030
|
}], onSuccess: [{
|
|
@@ -44121,177 +44297,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
44121
44297
|
type: Input
|
|
44122
44298
|
}] } });
|
|
44123
44299
|
|
|
44124
|
-
/**
|
|
44125
|
-
* Standard cross-app site links (env-aware)
|
|
44126
|
-
*
|
|
44127
|
-
* En el factory MyValtech cada producto satélite (showcase, sigify, …) enlaza a
|
|
44128
|
-
* `web` —la landing de marca— para soporte, contacto y contenido legal. `web`
|
|
44129
|
-
* es el dueño canónico de esas rutas. Este módulo centraliza:
|
|
44130
|
-
*
|
|
44131
|
-
* 1. El mapa ambiente → base URL de `web` (`VALTECH_WEB_BASE_URLS`).
|
|
44132
|
-
* 2. El catálogo de paths estándar que viven en `web` (`VALTECH_SITE_PATHS`).
|
|
44133
|
-
*
|
|
44134
|
-
* El ambiente se decide en BUILD TIME (campo `valtechEnv` en el `environment*.ts`
|
|
44135
|
-
* de cada app), igual que `apiUrl`. Es el mecanismo más confiable: detectar por
|
|
44136
|
-
* hostname en runtime se rompe con dominios custom / `web.app` / variantes de
|
|
44137
|
-
* localhost.
|
|
44138
|
-
*
|
|
44139
|
-
* La resolución real (join baseUrl + path, abrir en tab nueva, `?lang=`) la hace
|
|
44140
|
-
* `LegalLinkService`; este módulo solo le entrega el `baseUrl` correcto por env.
|
|
44141
|
-
*
|
|
44142
|
-
* @see provideValtechSite — wiring de una sola línea para apps satélite.
|
|
44143
|
-
*/
|
|
44144
|
-
/**
|
|
44145
|
-
* Base URL de `web` (landing de marca) por ambiente.
|
|
44146
|
-
*
|
|
44147
|
-
* - `local` → `ng serve` de `web` (puerto 8100).
|
|
44148
|
-
* - `dev` → proyecto Firebase `myvaltech-dev`.
|
|
44149
|
-
* - `prod` → dominio custom de producción.
|
|
44150
|
-
*
|
|
44151
|
-
* Sin trailing slash (lo asume `LegalLinkService`).
|
|
44152
|
-
*/
|
|
44153
|
-
const VALTECH_WEB_BASE_URLS = {
|
|
44154
|
-
local: 'http://localhost:8100',
|
|
44155
|
-
dev: 'https://myvaltech-dev.web.app',
|
|
44156
|
-
prod: 'https://myvaltech.com',
|
|
44157
|
-
};
|
|
44158
|
-
/**
|
|
44159
|
-
* Resuelve la base URL de `web` para un ambiente.
|
|
44160
|
-
*
|
|
44161
|
-
* Fallback a `prod` cuando el env es desconocido o falta: ante la duda, apuntar
|
|
44162
|
-
* a producción es lo seguro (nunca enlaza a un host local/dev inexistente).
|
|
44163
|
-
*/
|
|
44164
|
-
function resolveWebBaseUrl(env) {
|
|
44165
|
-
if (env && env in VALTECH_WEB_BASE_URLS) {
|
|
44166
|
-
return VALTECH_WEB_BASE_URLS[env];
|
|
44167
|
-
}
|
|
44168
|
-
return VALTECH_WEB_BASE_URLS.prod;
|
|
44169
|
-
}
|
|
44170
|
-
/**
|
|
44171
|
-
* Catálogo de paths estándar que viven en `web`. Las apps resuelven estos
|
|
44172
|
-
* contra la base URL del ambiente vía `LegalLinkService.resolve(path)`.
|
|
44173
|
-
*
|
|
44174
|
-
* Mantener alineado con las rutas reales de `web/src/app/app.routes.ts` y con
|
|
44175
|
-
* `VALTECH_COMPANY_LINKS` (footer).
|
|
44176
|
-
*/
|
|
44177
|
-
const VALTECH_SITE_PATHS = {
|
|
44178
|
-
home: '/',
|
|
44179
|
-
support: '/contact',
|
|
44180
|
-
contact: '/contact',
|
|
44181
|
-
faq: '/faq',
|
|
44182
|
-
about: '/about',
|
|
44183
|
-
terms: '/legal/terms',
|
|
44184
|
-
privacy: '/legal/privacy',
|
|
44185
|
-
cookies: '/legal/cookies',
|
|
44186
|
-
legalNotice: '/legal/legal-notice',
|
|
44187
|
-
};
|
|
44188
|
-
|
|
44189
|
-
const VALTECH_LEGAL_CONFIG = new InjectionToken('VALTECH_LEGAL_CONFIG');
|
|
44190
|
-
/**
|
|
44191
|
-
* Resolves legal/site paths against a configurable main-site base URL.
|
|
44192
|
-
*
|
|
44193
|
-
* - **Main site mode**: no `provideValtechLegal` called → `resolve('/legal/terms')` returns `/legal/terms` (relative).
|
|
44194
|
-
* - **Satellite mode**: `provideValtechLegal({ baseUrl: 'https://myvaltech.com' })` → `resolve('/legal/terms')` returns `'https://myvaltech.com/legal/terms'` and `isExternal('/legal/terms')` returns `true`.
|
|
44195
|
-
*
|
|
44196
|
-
* Absolute URLs passed in are returned unchanged (no double-prefix).
|
|
44197
|
-
*/
|
|
44198
|
-
class LegalLinkService {
|
|
44199
|
-
constructor() {
|
|
44200
|
-
this.config = inject(VALTECH_LEGAL_CONFIG, { optional: true }) ?? {};
|
|
44201
|
-
}
|
|
44202
|
-
/** Effective base URL (null if running as main site). */
|
|
44203
|
-
get baseUrl() {
|
|
44204
|
-
return this.config.baseUrl?.replace(/\/$/, '') ?? null;
|
|
44205
|
-
}
|
|
44206
|
-
/** Whether resolved external links should open in a new tab. */
|
|
44207
|
-
get openInNewTab() {
|
|
44208
|
-
return this.config.openInNewTab ?? Boolean(this.config.baseUrl);
|
|
44209
|
-
}
|
|
44210
|
-
/**
|
|
44211
|
-
* Returns the URL to use for a given internal path. Absolute URLs pass through.
|
|
44212
|
-
*
|
|
44213
|
-
* When `locale` is provided AND the resolved URL would be cross-origin, appends
|
|
44214
|
-
* `?lang={locale}` so the main site can render the legal doc in the user's
|
|
44215
|
-
* active language (instead of its default). Locale is omitted for same-origin
|
|
44216
|
-
* resolves since the main site reads locale from its own `LocaleService`.
|
|
44217
|
-
*
|
|
44218
|
-
* @example
|
|
44219
|
-
* resolve('/legal/terms')
|
|
44220
|
-
* // main site: '/legal/terms'
|
|
44221
|
-
* // satellite: 'https://myvaltech.com/legal/terms'
|
|
44222
|
-
*
|
|
44223
|
-
* resolve('/legal/terms', { locale: 'pt' })
|
|
44224
|
-
* // main site: '/legal/terms' (locale stays implicit)
|
|
44225
|
-
* // satellite: 'https://myvaltech.com/legal/terms?lang=pt'
|
|
44226
|
-
*
|
|
44227
|
-
* resolve('https://x.com/y') // unchanged
|
|
44228
|
-
*/
|
|
44229
|
-
resolve(path, options) {
|
|
44230
|
-
if (!path)
|
|
44231
|
-
return path;
|
|
44232
|
-
if (/^https?:\/\//i.test(path))
|
|
44233
|
-
return path;
|
|
44234
|
-
const base = this.baseUrl;
|
|
44235
|
-
if (!base)
|
|
44236
|
-
return path;
|
|
44237
|
-
const url = `${base}${path.startsWith('/') ? '' : '/'}${path}`;
|
|
44238
|
-
if (options?.locale) {
|
|
44239
|
-
const sep = url.includes('?') ? '&' : '?';
|
|
44240
|
-
return `${url}${sep}lang=${encodeURIComponent(options.locale)}`;
|
|
44241
|
-
}
|
|
44242
|
-
return url;
|
|
44243
|
-
}
|
|
44244
|
-
/** `true` if the path would be resolved to a cross-origin URL. */
|
|
44245
|
-
isExternal(path) {
|
|
44246
|
-
if (/^https?:\/\//i.test(path))
|
|
44247
|
-
return true;
|
|
44248
|
-
return this.baseUrl !== null;
|
|
44249
|
-
}
|
|
44250
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LegalLinkService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
44251
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LegalLinkService, providedIn: 'root' }); }
|
|
44252
|
-
}
|
|
44253
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LegalLinkService, decorators: [{
|
|
44254
|
-
type: Injectable,
|
|
44255
|
-
args: [{ providedIn: 'root' }]
|
|
44256
|
-
}] });
|
|
44257
|
-
/**
|
|
44258
|
-
* Wires `LegalLinkService` for satellite apps. Omit in the main site (the one
|
|
44259
|
-
* that hosts the canonical /legal/* routes) so links stay relative.
|
|
44260
|
-
*
|
|
44261
|
-
* @example
|
|
44262
|
-
* // main.ts of showcase / sigify / etc.
|
|
44263
|
-
* provideValtechLegal({
|
|
44264
|
-
* baseUrl: 'https://myvaltech.com',
|
|
44265
|
-
* openInNewTab: true,
|
|
44266
|
-
* }),
|
|
44267
|
-
*/
|
|
44268
|
-
function provideValtechLegal(config) {
|
|
44269
|
-
return { provide: VALTECH_LEGAL_CONFIG, useValue: config };
|
|
44270
|
-
}
|
|
44271
|
-
/**
|
|
44272
|
-
* Wiring de una sola línea para que una app satélite apunte sus links de sitio
|
|
44273
|
-
* (legal, soporte, contacto, …) a `web` —la landing de marca— en el ambiente
|
|
44274
|
-
* correcto. Resuelve el `baseUrl` desde `VALTECH_WEB_BASE_URLS` según el `env`
|
|
44275
|
-
* baked en build-time (`environment.valtechEnv`) y delega en `provideValtechLegal`.
|
|
44276
|
-
*
|
|
44277
|
-
* Ambiente desconocido/ausente → fallback a `prod` (ver `resolveWebBaseUrl`).
|
|
44278
|
-
* El main site (`web`) NO llama esto — sus links quedan relativos.
|
|
44279
|
-
*
|
|
44280
|
-
* @example
|
|
44281
|
-
* // main.ts de showcase / sigify / …
|
|
44282
|
-
* import { environment } from './environments/environment';
|
|
44283
|
-
* provideValtechSite(environment.valtechEnv), // 'local' | 'dev' | 'prod'
|
|
44284
|
-
*
|
|
44285
|
-
* @see resolveWebBaseUrl
|
|
44286
|
-
* @see VALTECH_SITE_PATHS — catálogo de paths estándar que viven en `web`.
|
|
44287
|
-
*/
|
|
44288
|
-
function provideValtechSite(env, options) {
|
|
44289
|
-
return provideValtechLegal({
|
|
44290
|
-
baseUrl: resolveWebBaseUrl(env),
|
|
44291
|
-
openInNewTab: options?.openInNewTab ?? true,
|
|
44292
|
-
});
|
|
44293
|
-
}
|
|
44294
|
-
|
|
44295
44300
|
/**
|
|
44296
44301
|
* Default modal sizes.
|
|
44297
44302
|
*/
|