@orechio/platform-angular 0.8.1 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -0
- package/fesm2022/{orechio-platform-angular-account-account-client-mPl0tzMg.mjs → orechio-platform-angular-account-account-client-BjRRo_f3.mjs} +4 -4
- package/fesm2022/{orechio-platform-angular-account-account-client-mPl0tzMg.mjs.map → orechio-platform-angular-account-account-client-BjRRo_f3.mjs.map} +1 -1
- package/fesm2022/{orechio-platform-angular-account-forgot-password.page-L-Z-s49p.mjs → orechio-platform-angular-account-forgot-password.page-dSIZ21HJ.mjs} +5 -5
- package/fesm2022/{orechio-platform-angular-account-forgot-password.page-L-Z-s49p.mjs.map → orechio-platform-angular-account-forgot-password.page-dSIZ21HJ.mjs.map} +1 -1
- package/fesm2022/{orechio-platform-angular-account-initial-branch.page-BY2cxcxd.mjs → orechio-platform-angular-account-initial-branch.page-vLp57syM.mjs} +5 -5
- package/fesm2022/{orechio-platform-angular-account-initial-branch.page-BY2cxcxd.mjs.map → orechio-platform-angular-account-initial-branch.page-vLp57syM.mjs.map} +1 -1
- package/fesm2022/{orechio-platform-angular-account-resend-verification.page-C3lk1vNj.mjs → orechio-platform-angular-account-resend-verification.page-BO--Lmyi.mjs} +5 -5
- package/fesm2022/{orechio-platform-angular-account-resend-verification.page-C3lk1vNj.mjs.map → orechio-platform-angular-account-resend-verification.page-BO--Lmyi.mjs.map} +1 -1
- package/fesm2022/{orechio-platform-angular-account-token-password.page-1vn5XGVu.mjs → orechio-platform-angular-account-token-password.page-WfTzcecr.mjs} +5 -5
- package/fesm2022/{orechio-platform-angular-account-token-password.page-1vn5XGVu.mjs.map → orechio-platform-angular-account-token-password.page-WfTzcecr.mjs.map} +1 -1
- package/fesm2022/{orechio-platform-angular-account-verify-email.page-xulVDiOn.mjs → orechio-platform-angular-account-verify-email.page-DCVh128a.mjs} +5 -5
- package/fesm2022/{orechio-platform-angular-account-verify-email.page-xulVDiOn.mjs.map → orechio-platform-angular-account-verify-email.page-DCVh128a.mjs.map} +1 -1
- package/fesm2022/orechio-platform-angular-account.mjs +9 -9
- package/fesm2022/{orechio-platform-angular-billing-billing-format-C8QPXulm.mjs → orechio-platform-angular-billing-billing-format-CuDtE7fj.mjs} +6 -71
- package/fesm2022/orechio-platform-angular-billing-billing-format-CuDtE7fj.mjs.map +1 -0
- package/fesm2022/{orechio-platform-angular-billing-checkout.page-Dr6ZGDkd.mjs → orechio-platform-angular-billing-checkout.page-BhUYGMkL.mjs} +7 -6
- package/fesm2022/{orechio-platform-angular-billing-checkout.page-Dr6ZGDkd.mjs.map → orechio-platform-angular-billing-checkout.page-BhUYGMkL.mjs.map} +1 -1
- package/fesm2022/{orechio-platform-angular-billing-invoice.page-CWThsx-_.mjs → orechio-platform-angular-billing-invoice.page-CELLNkLd.mjs} +7 -6
- package/fesm2022/{orechio-platform-angular-billing-invoice.page-CWThsx-_.mjs.map → orechio-platform-angular-billing-invoice.page-CELLNkLd.mjs.map} +1 -1
- package/fesm2022/{orechio-platform-angular-billing-invoices.page-DytE1Lcz.mjs → orechio-platform-angular-billing-invoices.page-CfWDUFv6.mjs} +6 -5
- package/fesm2022/{orechio-platform-angular-billing-invoices.page-DytE1Lcz.mjs.map → orechio-platform-angular-billing-invoices.page-CfWDUFv6.mjs.map} +1 -1
- package/fesm2022/orechio-platform-angular-billing-orechio-platform-angular-billing-C8Q1JSAC.mjs +313 -0
- package/fesm2022/orechio-platform-angular-billing-orechio-platform-angular-billing-C8Q1JSAC.mjs.map +1 -0
- package/fesm2022/{orechio-platform-angular-billing-pix-panel.component-DrfNi22S.mjs → orechio-platform-angular-billing-pix-panel.component-BiNCJuB_.mjs} +5 -5
- package/fesm2022/{orechio-platform-angular-billing-pix-panel.component-DrfNi22S.mjs.map → orechio-platform-angular-billing-pix-panel.component-BiNCJuB_.mjs.map} +1 -1
- package/fesm2022/{orechio-platform-angular-billing-profile.page-DRkoYOZa.mjs → orechio-platform-angular-billing-profile.page-DufY3HDA.mjs} +6 -5
- package/fesm2022/{orechio-platform-angular-billing-profile.page-DRkoYOZa.mjs.map → orechio-platform-angular-billing-profile.page-DufY3HDA.mjs.map} +1 -1
- package/fesm2022/{orechio-platform-angular-billing-subscription.page-Dbk-Znvg.mjs → orechio-platform-angular-billing-subscription.page-Bi6w7yq_.mjs} +8 -5
- package/fesm2022/orechio-platform-angular-billing-subscription.page-Bi6w7yq_.mjs.map +1 -0
- package/fesm2022/orechio-platform-angular-billing.mjs +1 -68
- package/fesm2022/orechio-platform-angular-billing.mjs.map +1 -1
- package/fesm2022/orechio-platform-angular.mjs +15 -15
- package/package.json +1 -1
- package/types/orechio-platform-angular-billing.d.ts +67 -3
- package/types/orechio-platform-angular.d.ts +2 -2
- package/fesm2022/orechio-platform-angular-billing-billing-format-C8QPXulm.mjs.map +0 -1
- package/fesm2022/orechio-platform-angular-billing-subscription.page-Dbk-Znvg.mjs.map +0 -1
package/fesm2022/orechio-platform-angular-billing-orechio-platform-angular-billing-C8Q1JSAC.mjs
ADDED
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { InjectionToken, inject, Injectable, signal, Injector, DestroyRef, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
|
+
import { HttpClient, HttpParams, HttpErrorResponse } from '@angular/common/http';
|
|
4
|
+
import { Router, RouterLink } from '@angular/router';
|
|
5
|
+
import { catchError, throwError, map, tap, of, shareReplay, switchMap } from 'rxjs';
|
|
6
|
+
import { normalizeProblemDetails, AuthClient } from '@orechio/platform-angular';
|
|
7
|
+
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
8
|
+
|
|
9
|
+
const ORECHIO_BILLING_CONFIG = new InjectionToken('ORECHIO_BILLING_CONFIG');
|
|
10
|
+
function provideOrechioBilling(options = {}) {
|
|
11
|
+
const bruto = options.basePath ?? '/api/billing';
|
|
12
|
+
// Mesma regra do `BillingRoutePrefix` do BFF, no mesmo momento: na composição. Uma URL
|
|
13
|
+
// absoluta aqui levaria a cobrança para fora do domínio do produto, onde o cookie de sessão
|
|
14
|
+
// não vai junto.
|
|
15
|
+
if (!bruto.startsWith('/') || bruto.startsWith('//')) {
|
|
16
|
+
throw new Error(`provideOrechioBilling: \`basePath\` precisa ser um caminho same-origin começando com '/': '${bruto}'.`);
|
|
17
|
+
}
|
|
18
|
+
const rota = options.uiRoute ?? '/billing';
|
|
19
|
+
if (!rota.startsWith('/') || rota.startsWith('//')) {
|
|
20
|
+
throw new Error(`provideOrechioBilling: \`uiRoute\` precisa ser um caminho começando com '/': '${rota}'.`);
|
|
21
|
+
}
|
|
22
|
+
const config = { basePath: bruto.replace(/\/+$/, ''), uiRoute: rota };
|
|
23
|
+
return [{ provide: ORECHIO_BILLING_CONFIG, useValue: config }];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* As rotas de cobrança. O host as monta em `/billing` — é para lá que os e-mails de cobrança
|
|
28
|
+
* da Platform apontam (`{base}/billing`, ADR-021 §3.2):
|
|
29
|
+
*
|
|
30
|
+
* <pre>
|
|
31
|
+
* { path: 'billing', children: ORECHIO_BILLING_ROUTES }
|
|
32
|
+
* </pre>
|
|
33
|
+
*
|
|
34
|
+
* Os caminhos ENTRE as telas são fixos (a situação leva a `checkout` e `invoices`, o
|
|
35
|
+
* pagamento sem perfil leva a `profile`). Todas com `loadComponent`, como as de conta.
|
|
36
|
+
*/
|
|
37
|
+
const ORECHIO_BILLING_ROUTES = [
|
|
38
|
+
{
|
|
39
|
+
path: '',
|
|
40
|
+
pathMatch: 'full',
|
|
41
|
+
title: 'Assinatura',
|
|
42
|
+
loadComponent: () => import('./orechio-platform-angular-billing-subscription.page-Bi6w7yq_.mjs').then((m) => m.SubscriptionPage),
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
path: 'profile',
|
|
46
|
+
title: 'Dados de cobrança',
|
|
47
|
+
loadComponent: () => import('./orechio-platform-angular-billing-profile.page-DufY3HDA.mjs').then((m) => m.ProfilePage),
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
path: 'checkout',
|
|
51
|
+
title: 'Pagar assinatura',
|
|
52
|
+
loadComponent: () => import('./orechio-platform-angular-billing-checkout.page-BhUYGMkL.mjs').then((m) => m.CheckoutPage),
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
path: 'invoices',
|
|
56
|
+
title: 'Faturas',
|
|
57
|
+
loadComponent: () => import('./orechio-platform-angular-billing-invoices.page-CfWDUFv6.mjs').then((m) => m.InvoicesPage),
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
path: 'invoices/:id',
|
|
61
|
+
title: 'Fatura',
|
|
62
|
+
loadComponent: () => import('./orechio-platform-angular-billing-invoice.page-CELLNkLd.mjs').then((m) => m.InvoicePage),
|
|
63
|
+
},
|
|
64
|
+
];
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* O cliente do BFF de cobrança (`Orechio.Platform.Bff.Account` 0.2.0,
|
|
68
|
+
* `MapOrechioBillingEndpoints`). Same-origin, só com o BFF do host — mesmo desenho do
|
|
69
|
+
* `AccountClient`, e o erro sai pelo mesmo `normalizeProblemDetails`.
|
|
70
|
+
*/
|
|
71
|
+
class BillingClient {
|
|
72
|
+
http = inject(HttpClient);
|
|
73
|
+
config = inject(ORECHIO_BILLING_CONFIG);
|
|
74
|
+
getSubscription() {
|
|
75
|
+
return this.falha(this.http.get(this.url('/subscription')));
|
|
76
|
+
}
|
|
77
|
+
getProfile() {
|
|
78
|
+
return this.falha(this.http.get(this.url('/profile')));
|
|
79
|
+
}
|
|
80
|
+
createProfile(request) {
|
|
81
|
+
return this.falha(this.http.post(this.url('/profile'), request));
|
|
82
|
+
}
|
|
83
|
+
updateProfileContact(request) {
|
|
84
|
+
return this.falha(this.http.patch(this.url('/profile/contact'), request));
|
|
85
|
+
}
|
|
86
|
+
updateProfileAddress(request) {
|
|
87
|
+
return this.falha(this.http.patch(this.url('/profile/address'), request));
|
|
88
|
+
}
|
|
89
|
+
listPlans() {
|
|
90
|
+
return this.falha(this.http.get(this.url('/plans')));
|
|
91
|
+
}
|
|
92
|
+
previewPricing(planId, branchCount, cycle) {
|
|
93
|
+
const params = new HttpParams({ fromObject: { planId, branchCount, cycle } });
|
|
94
|
+
return this.falha(this.http.get(this.url('/pricing/preview'), { params }));
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Checkout PIX. O corpo é o `CheckoutRequest` da Platform (`cycle`, `method`), sem
|
|
98
|
+
* `applicationId`: com o token de produto, a Platform usa o app do token.
|
|
99
|
+
*/
|
|
100
|
+
checkout(cycle) {
|
|
101
|
+
return this.falha(this.http.post(this.url('/checkout'), { cycle, method: 'pix' }));
|
|
102
|
+
}
|
|
103
|
+
listInvoices(page = 1, pageSize = 20) {
|
|
104
|
+
const params = new HttpParams({ fromObject: { page, pageSize } });
|
|
105
|
+
return this.falha(this.http.get(this.url('/invoices'), { params }));
|
|
106
|
+
}
|
|
107
|
+
getInvoice(id) {
|
|
108
|
+
return this.falha(this.http.get(this.url(`/invoices/${encodeURIComponent(id)}`)));
|
|
109
|
+
}
|
|
110
|
+
refreshInvoicePix(id) {
|
|
111
|
+
return this.falha(this.http.post(this.url(`/invoices/${encodeURIComponent(id)}/refresh`), null));
|
|
112
|
+
}
|
|
113
|
+
url(path) {
|
|
114
|
+
return `${this.config.basePath}${path}`;
|
|
115
|
+
}
|
|
116
|
+
falha(chamada) {
|
|
117
|
+
return chamada.pipe(catchError((error) => throwError(() => normalizeProblemDetails(error))));
|
|
118
|
+
}
|
|
119
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.2.3", ngImport: i0, type: BillingClient, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
120
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.2.3", ngImport: i0, type: BillingClient, providedIn: 'root' });
|
|
121
|
+
}
|
|
122
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.3", ngImport: i0, type: BillingClient, decorators: [{
|
|
123
|
+
type: Injectable,
|
|
124
|
+
args: [{ providedIn: 'root' }]
|
|
125
|
+
}] });
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* A situação da assinatura que a faixa, a guarda e o interceptor compartilham. Interno ao
|
|
129
|
+
* entry: não é exportado. A leitura acontece uma vez por aplicação; a tela de situação
|
|
130
|
+
* atualiza o estado com o que ela já carregou.
|
|
131
|
+
*/
|
|
132
|
+
class SubscriptionAccessState {
|
|
133
|
+
client = inject(BillingClient);
|
|
134
|
+
leitura;
|
|
135
|
+
/** `null` enquanto desconhecida, inclusive quando a leitura falhou. */
|
|
136
|
+
status = signal(null, /* @ts-ignore */
|
|
137
|
+
...(ngDevMode ? [{ debugName: "status" }] : /* istanbul ignore next */ []));
|
|
138
|
+
avisoAberto = signal(false, /* @ts-ignore */
|
|
139
|
+
...(ngDevMode ? [{ debugName: "avisoAberto" }] : /* istanbul ignore next */ []));
|
|
140
|
+
/** Lê a situação uma única vez. Falha da cobrança vira `null`, e a próxima chamada tenta de novo. */
|
|
141
|
+
carregar() {
|
|
142
|
+
this.leitura ??= this.client.getSubscription().pipe(map((assinatura) => assinatura.status), tap((status) => this.status.set(status)), catchError(() => {
|
|
143
|
+
this.leitura = undefined;
|
|
144
|
+
return of(null);
|
|
145
|
+
}), shareReplay(1));
|
|
146
|
+
return this.leitura;
|
|
147
|
+
}
|
|
148
|
+
atualizar(status) {
|
|
149
|
+
this.status.set(status);
|
|
150
|
+
this.leitura = of(status);
|
|
151
|
+
}
|
|
152
|
+
abrirAviso() {
|
|
153
|
+
this.avisoAberto.set(true);
|
|
154
|
+
}
|
|
155
|
+
fecharAviso() {
|
|
156
|
+
this.avisoAberto.set(false);
|
|
157
|
+
}
|
|
158
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.2.3", ngImport: i0, type: SubscriptionAccessState, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
159
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.2.3", ngImport: i0, type: SubscriptionAccessState, providedIn: 'root' });
|
|
160
|
+
}
|
|
161
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.3", ngImport: i0, type: SubscriptionAccessState, decorators: [{
|
|
162
|
+
type: Injectable,
|
|
163
|
+
args: [{ providedIn: 'root' }]
|
|
164
|
+
}] });
|
|
165
|
+
|
|
166
|
+
const SO_LEITURA = 'subscription.read_only';
|
|
167
|
+
const EXPIRADA = 'subscription.expired';
|
|
168
|
+
function codigoDaRecusa(erro) {
|
|
169
|
+
if (!(erro instanceof HttpErrorResponse) || erro.status !== 403)
|
|
170
|
+
return null;
|
|
171
|
+
const { code } = normalizeProblemDetails(erro);
|
|
172
|
+
return code === SO_LEITURA || code === EXPIRADA ? code : null;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Trata as recusas de assinatura do backend do produto (Orechio.Platform.Client 1.6.0). O token
|
|
176
|
+
* da sessão pode estar atrasado em relação ao pagamento, então a primeira resposta é renovar a
|
|
177
|
+
* sessão e repetir o pedido uma vez. Se continuar recusado, suspensa abre o aviso e expirada leva
|
|
178
|
+
* à assinatura. Nunca desloga, e o erro devolvido é sempre o original.
|
|
179
|
+
*/
|
|
180
|
+
const subscriptionAccessInterceptor = (req, next) => {
|
|
181
|
+
const config = inject(ORECHIO_BILLING_CONFIG);
|
|
182
|
+
const injector = inject(Injector);
|
|
183
|
+
// A cobrança é o caminho para sair da recusa: nunca é renovada nem repetida.
|
|
184
|
+
const { basePath } = config;
|
|
185
|
+
if (req.url === basePath || req.url.startsWith(`${basePath}/`) || req.url.startsWith(`${basePath}?`)) {
|
|
186
|
+
return next(req);
|
|
187
|
+
}
|
|
188
|
+
return next(req).pipe(catchError((original) => {
|
|
189
|
+
const codigo = codigoDaRecusa(original);
|
|
190
|
+
if (!codigo)
|
|
191
|
+
return throwError(() => original);
|
|
192
|
+
const estado = injector.get(SubscriptionAccessState);
|
|
193
|
+
const router = injector.get(Router);
|
|
194
|
+
const recusado = () => {
|
|
195
|
+
if (codigo === SO_LEITURA)
|
|
196
|
+
estado.abrirAviso();
|
|
197
|
+
else
|
|
198
|
+
void router.navigateByUrl(config.uiRoute);
|
|
199
|
+
return throwError(() => original);
|
|
200
|
+
};
|
|
201
|
+
return injector.get(AuthClient).refresh().pipe(catchError(recusado), switchMap(() => next(req).pipe(catchError((repetida) => codigoDaRecusa(repetida) === codigo ? recusado() : throwError(() => repetida)))));
|
|
202
|
+
}));
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Expirada vai para a tela da assinatura. Qualquer outra situação entra, inclusive quando a
|
|
207
|
+
* leitura falhou: falha da cobrança nunca tranca (ADR-036), e a barreira de servidor continua
|
|
208
|
+
* valendo. Aplique nas rotas do produto, não nas de `/billing`.
|
|
209
|
+
*/
|
|
210
|
+
const requireSubscriptionAccess = () => {
|
|
211
|
+
const router = inject(Router);
|
|
212
|
+
const { uiRoute } = inject(ORECHIO_BILLING_CONFIG);
|
|
213
|
+
return inject(SubscriptionAccessState)
|
|
214
|
+
.carregar()
|
|
215
|
+
.pipe(map((status) => (status === 'Expired' ? router.parseUrl(uiRoute) : true)));
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* A faixa fixa da assinatura suspensa e o aviso de gravação recusada. Ponha a tag uma vez no
|
|
220
|
+
* layout do produto. O texto é fixo: nada do corpo do erro vai para a tela.
|
|
221
|
+
*/
|
|
222
|
+
class OrechioSubscriptionNotice {
|
|
223
|
+
estado = inject(SubscriptionAccessState);
|
|
224
|
+
uiRoute = inject(ORECHIO_BILLING_CONFIG).uiRoute;
|
|
225
|
+
router = inject(Router);
|
|
226
|
+
destroyRef = inject(DestroyRef);
|
|
227
|
+
ngOnInit() {
|
|
228
|
+
this.estado.carregar().pipe(takeUntilDestroyed(this.destroyRef)).subscribe();
|
|
229
|
+
}
|
|
230
|
+
irParaAssinatura() {
|
|
231
|
+
this.estado.fecharAviso();
|
|
232
|
+
void this.router.navigateByUrl(this.uiRoute);
|
|
233
|
+
}
|
|
234
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.2.3", ngImport: i0, type: OrechioSubscriptionNotice, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
235
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.2.3", type: OrechioSubscriptionNotice, isStandalone: true, selector: "orechio-subscription-notice", ngImport: i0, template: `
|
|
236
|
+
@if (estado.status() === 'Suspended') {
|
|
237
|
+
<div class="orechio-notice__faixa" data-testid="subscription-banner" role="status">
|
|
238
|
+
<span>
|
|
239
|
+
Assinatura suspensa: você pode consultar tudo, mas não pode salvar alterações até
|
|
240
|
+
regularizar o pagamento.
|
|
241
|
+
</span>
|
|
242
|
+
<a [routerLink]="uiRoute">Pagar agora</a>
|
|
243
|
+
</div>
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
@if (estado.avisoAberto()) {
|
|
247
|
+
<div class="orechio-notice__fundo">
|
|
248
|
+
<div
|
|
249
|
+
class="orechio-notice__aviso"
|
|
250
|
+
data-testid="subscription-readonly-dialog"
|
|
251
|
+
role="dialog"
|
|
252
|
+
aria-modal="true"
|
|
253
|
+
aria-labelledby="orechio-notice-titulo"
|
|
254
|
+
>
|
|
255
|
+
<h2 id="orechio-notice-titulo">Assinatura suspensa</h2>
|
|
256
|
+
<p>Esta alteração não foi salva. Para voltar a salvar, regularize o pagamento.</p>
|
|
257
|
+
<div class="orechio-notice__botoes">
|
|
258
|
+
<button type="button" (click)="estado.fecharAviso()">Agora não</button>
|
|
259
|
+
<button type="button" (click)="irParaAssinatura()">Ir para a assinatura</button>
|
|
260
|
+
</div>
|
|
261
|
+
</div>
|
|
262
|
+
</div>
|
|
263
|
+
}
|
|
264
|
+
`, isInline: true, styles: [".orechio-notice__faixa{display:flex;flex-wrap:wrap;gap:.5rem 1rem;align-items:center;justify-content:space-between;padding:.75rem 1rem;background:#fff4d6;color:#5c3b00;border-bottom:1px solid #e6c36a}.orechio-notice__faixa a{font-weight:600;color:inherit}.orechio-notice__fundo{position:fixed;inset:0;display:grid;place-items:center;padding:1rem;background:#00000073}.orechio-notice__aviso{max-width:28rem;padding:1.5rem;border-radius:.5rem;background:#fff;color:#1a1a1a}.orechio-notice__aviso h2{margin:0 0 .5rem;font-size:1.125rem}.orechio-notice__botoes{display:flex;flex-wrap:wrap;gap:.5rem;justify-content:flex-end;margin-top:1rem}\n"], dependencies: [{ kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "browserUrl", "routerLink"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
265
|
+
}
|
|
266
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.3", ngImport: i0, type: OrechioSubscriptionNotice, decorators: [{
|
|
267
|
+
type: Component,
|
|
268
|
+
args: [{ selector: 'orechio-subscription-notice', standalone: true, imports: [RouterLink], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
269
|
+
@if (estado.status() === 'Suspended') {
|
|
270
|
+
<div class="orechio-notice__faixa" data-testid="subscription-banner" role="status">
|
|
271
|
+
<span>
|
|
272
|
+
Assinatura suspensa: você pode consultar tudo, mas não pode salvar alterações até
|
|
273
|
+
regularizar o pagamento.
|
|
274
|
+
</span>
|
|
275
|
+
<a [routerLink]="uiRoute">Pagar agora</a>
|
|
276
|
+
</div>
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
@if (estado.avisoAberto()) {
|
|
280
|
+
<div class="orechio-notice__fundo">
|
|
281
|
+
<div
|
|
282
|
+
class="orechio-notice__aviso"
|
|
283
|
+
data-testid="subscription-readonly-dialog"
|
|
284
|
+
role="dialog"
|
|
285
|
+
aria-modal="true"
|
|
286
|
+
aria-labelledby="orechio-notice-titulo"
|
|
287
|
+
>
|
|
288
|
+
<h2 id="orechio-notice-titulo">Assinatura suspensa</h2>
|
|
289
|
+
<p>Esta alteração não foi salva. Para voltar a salvar, regularize o pagamento.</p>
|
|
290
|
+
<div class="orechio-notice__botoes">
|
|
291
|
+
<button type="button" (click)="estado.fecharAviso()">Agora não</button>
|
|
292
|
+
<button type="button" (click)="irParaAssinatura()">Ir para a assinatura</button>
|
|
293
|
+
</div>
|
|
294
|
+
</div>
|
|
295
|
+
</div>
|
|
296
|
+
}
|
|
297
|
+
`, styles: [".orechio-notice__faixa{display:flex;flex-wrap:wrap;gap:.5rem 1rem;align-items:center;justify-content:space-between;padding:.75rem 1rem;background:#fff4d6;color:#5c3b00;border-bottom:1px solid #e6c36a}.orechio-notice__faixa a{font-weight:600;color:inherit}.orechio-notice__fundo{position:fixed;inset:0;display:grid;place-items:center;padding:1rem;background:#00000073}.orechio-notice__aviso{max-width:28rem;padding:1.5rem;border-radius:.5rem;background:#fff;color:#1a1a1a}.orechio-notice__aviso h2{margin:0 0 .5rem;font-size:1.125rem}.orechio-notice__botoes{display:flex;flex-wrap:wrap;gap:.5rem;justify-content:flex-end;margin-top:1rem}\n"] }]
|
|
298
|
+
}] });
|
|
299
|
+
|
|
300
|
+
/*
|
|
301
|
+
* Public API Surface of @orechio/platform-angular/billing
|
|
302
|
+
*
|
|
303
|
+
* BILLING-3 — as telas de cobrança do titular (ADR-021 §3.5). Mesmo contrato do entry
|
|
304
|
+
* `account`: `BillingClient` e as páginas NÃO são exportados. As telas são alcançadas por
|
|
305
|
+
* `ORECHIO_BILLING_ROUTES`, e os caminhos entre elas só valem montados juntos.
|
|
306
|
+
*/
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Generated bundle index. Do not edit.
|
|
310
|
+
*/
|
|
311
|
+
|
|
312
|
+
export { BillingClient as B, ORECHIO_BILLING_CONFIG as O, SubscriptionAccessState as S, ORECHIO_BILLING_ROUTES as a, OrechioSubscriptionNotice as b, provideOrechioBilling as p, requireSubscriptionAccess as r, subscriptionAccessInterceptor as s };
|
|
313
|
+
//# sourceMappingURL=orechio-platform-angular-billing-orechio-platform-angular-billing-C8Q1JSAC.mjs.map
|
package/fesm2022/orechio-platform-angular-billing-orechio-platform-angular-billing-C8Q1JSAC.mjs.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orechio-platform-angular-billing-orechio-platform-angular-billing-C8Q1JSAC.mjs","sources":["../../../projects/platform-angular/billing/src/billing-config.ts","../../../projects/platform-angular/billing/src/billing.routes.ts","../../../projects/platform-angular/billing/src/billing-client.ts","../../../projects/platform-angular/billing/src/subscription-access.state.ts","../../../projects/platform-angular/billing/src/subscription-access.interceptor.ts","../../../projects/platform-angular/billing/src/subscription-access.guard.ts","../../../projects/platform-angular/billing/src/subscription-notice.component.ts","../../../projects/platform-angular/billing/src/public-api.ts","../../../projects/platform-angular/billing/src/orechio-platform-angular-billing.ts"],"sourcesContent":["import { InjectionToken, Provider } from '@angular/core';\r\n\r\nexport interface OrechioBillingConfig {\r\n /**\r\n * Prefixo do BFF de cobrança (`MapOrechioBillingEndpoints`), same-origin. O BFF lê a sessão\r\n * do host e fala com a Platform; o browser nunca vê token nem fala com a Platform.\r\n */\r\n basePath: string;\r\n /** Rota da tela de assinatura no produto, para onde a faixa, o aviso e a guarda levam. */\r\n uiRoute: string;\r\n}\r\n\r\nexport const ORECHIO_BILLING_CONFIG = new InjectionToken<OrechioBillingConfig>(\r\n 'ORECHIO_BILLING_CONFIG',\r\n);\r\n\r\nexport interface OrechioBillingOptions {\r\n /** Default `/api/billing`, o mesmo `BillingRoutePrefix` default do BFF. */\r\n basePath?: string;\r\n /** Default `/billing` (ADR-021 §3.2). Caminho começando com `/`, nunca `//`. */\r\n uiRoute?: string;\r\n}\r\n\r\nexport function provideOrechioBilling(options: OrechioBillingOptions = {}): Provider[] {\r\n const bruto = options.basePath ?? '/api/billing';\r\n\r\n // Mesma regra do `BillingRoutePrefix` do BFF, no mesmo momento: na composição. Uma URL\r\n // absoluta aqui levaria a cobrança para fora do domínio do produto, onde o cookie de sessão\r\n // não vai junto.\r\n if (!bruto.startsWith('/') || bruto.startsWith('//')) {\r\n throw new Error(\r\n `provideOrechioBilling: \\`basePath\\` precisa ser um caminho same-origin começando com '/': '${bruto}'.`,\r\n );\r\n }\r\n\r\n const rota = options.uiRoute ?? '/billing';\r\n if (!rota.startsWith('/') || rota.startsWith('//')) {\r\n throw new Error(\r\n `provideOrechioBilling: \\`uiRoute\\` precisa ser um caminho começando com '/': '${rota}'.`,\r\n );\r\n }\r\n\r\n const config: OrechioBillingConfig = { basePath: bruto.replace(/\\/+$/, ''), uiRoute: rota };\r\n return [{ provide: ORECHIO_BILLING_CONFIG, useValue: config }];\r\n}\r\n","import { Routes } from '@angular/router';\r\n\r\n/**\r\n * As rotas de cobrança. O host as monta em `/billing` — é para lá que os e-mails de cobrança\r\n * da Platform apontam (`{base}/billing`, ADR-021 §3.2):\r\n *\r\n * <pre>\r\n * { path: 'billing', children: ORECHIO_BILLING_ROUTES }\r\n * </pre>\r\n *\r\n * Os caminhos ENTRE as telas são fixos (a situação leva a `checkout` e `invoices`, o\r\n * pagamento sem perfil leva a `profile`). Todas com `loadComponent`, como as de conta.\r\n */\r\nexport const ORECHIO_BILLING_ROUTES: Routes = [\r\n {\r\n path: '',\r\n pathMatch: 'full',\r\n title: 'Assinatura',\r\n loadComponent: () => import('./pages/subscription.page').then((m) => m.SubscriptionPage),\r\n },\r\n {\r\n path: 'profile',\r\n title: 'Dados de cobrança',\r\n loadComponent: () => import('./pages/profile.page').then((m) => m.ProfilePage),\r\n },\r\n {\r\n path: 'checkout',\r\n title: 'Pagar assinatura',\r\n loadComponent: () => import('./pages/checkout.page').then((m) => m.CheckoutPage),\r\n },\r\n {\r\n path: 'invoices',\r\n title: 'Faturas',\r\n loadComponent: () => import('./pages/invoices.page').then((m) => m.InvoicesPage),\r\n },\r\n {\r\n path: 'invoices/:id',\r\n title: 'Fatura',\r\n loadComponent: () => import('./pages/invoice.page').then((m) => m.InvoicePage),\r\n },\r\n];\r\n","import { HttpClient, HttpErrorResponse, HttpParams } from '@angular/common/http';\r\nimport { Injectable, inject } from '@angular/core';\r\nimport { Observable, catchError, throwError } from 'rxjs';\r\nimport { ProblemDetails, normalizeProblemDetails } from '@orechio/platform-angular';\r\nimport { ORECHIO_BILLING_CONFIG } from './billing-config';\r\nimport {\r\n BillingAddressRequest,\r\n BillingContactRequest,\r\n BillingCycle,\r\n BillingProfile,\r\n CheckoutResult,\r\n CreateBillingProfileRequest,\r\n InvoiceDetail,\r\n InvoicesPage,\r\n Plan,\r\n PricingPreview,\r\n RefreshedPayment,\r\n Subscription,\r\n} from './billing-models';\r\n\r\n/**\r\n * O cliente do BFF de cobrança (`Orechio.Platform.Bff.Account` 0.2.0,\r\n * `MapOrechioBillingEndpoints`). Same-origin, só com o BFF do host — mesmo desenho do\r\n * `AccountClient`, e o erro sai pelo mesmo `normalizeProblemDetails`.\r\n */\r\n@Injectable({ providedIn: 'root' })\r\nexport class BillingClient {\r\n private readonly http = inject(HttpClient);\r\n private readonly config = inject(ORECHIO_BILLING_CONFIG);\r\n\r\n getSubscription(): Observable<Subscription> {\r\n return this.falha(this.http.get<Subscription>(this.url('/subscription')));\r\n }\r\n\r\n getProfile(): Observable<BillingProfile> {\r\n return this.falha(this.http.get<BillingProfile>(this.url('/profile')));\r\n }\r\n\r\n createProfile(request: CreateBillingProfileRequest): Observable<{ id: string }> {\r\n return this.falha(this.http.post<{ id: string }>(this.url('/profile'), request));\r\n }\r\n\r\n updateProfileContact(request: BillingContactRequest): Observable<void> {\r\n return this.falha(this.http.patch<void>(this.url('/profile/contact'), request));\r\n }\r\n\r\n updateProfileAddress(request: BillingAddressRequest): Observable<void> {\r\n return this.falha(this.http.patch<void>(this.url('/profile/address'), request));\r\n }\r\n\r\n listPlans(): Observable<Plan[]> {\r\n return this.falha(this.http.get<Plan[]>(this.url('/plans')));\r\n }\r\n\r\n previewPricing(planId: string, branchCount: number, cycle: BillingCycle): Observable<PricingPreview> {\r\n const params = new HttpParams({ fromObject: { planId, branchCount, cycle } });\r\n return this.falha(this.http.get<PricingPreview>(this.url('/pricing/preview'), { params }));\r\n }\r\n\r\n /**\r\n * Checkout PIX. O corpo é o `CheckoutRequest` da Platform (`cycle`, `method`), sem\r\n * `applicationId`: com o token de produto, a Platform usa o app do token.\r\n */\r\n checkout(cycle: BillingCycle): Observable<CheckoutResult> {\r\n return this.falha(this.http.post<CheckoutResult>(this.url('/checkout'), { cycle, method: 'pix' }));\r\n }\r\n\r\n listInvoices(page = 1, pageSize = 20): Observable<InvoicesPage> {\r\n const params = new HttpParams({ fromObject: { page, pageSize } });\r\n return this.falha(this.http.get<InvoicesPage>(this.url('/invoices'), { params }));\r\n }\r\n\r\n getInvoice(id: string): Observable<InvoiceDetail> {\r\n return this.falha(this.http.get<InvoiceDetail>(this.url(`/invoices/${encodeURIComponent(id)}`)));\r\n }\r\n\r\n refreshInvoicePix(id: string): Observable<RefreshedPayment> {\r\n return this.falha(this.http.post<RefreshedPayment>(this.url(`/invoices/${encodeURIComponent(id)}/refresh`), null));\r\n }\r\n\r\n private url(path: string): string {\r\n return `${this.config.basePath}${path}`;\r\n }\r\n\r\n private falha<T>(chamada: Observable<T>): Observable<T> {\r\n return chamada.pipe(\r\n catchError((error: HttpErrorResponse) =>\r\n throwError((): ProblemDetails => normalizeProblemDetails(error)),\r\n ),\r\n );\r\n }\r\n}\r\n","import { Injectable, inject, signal } from '@angular/core';\r\nimport { Observable, catchError, map, of, shareReplay, tap } from 'rxjs';\r\nimport { BillingClient } from './billing-client';\r\nimport { SubscriptionStatus } from './billing-models';\r\n\r\n/**\r\n * A situação da assinatura que a faixa, a guarda e o interceptor compartilham. Interno ao\r\n * entry: não é exportado. A leitura acontece uma vez por aplicação; a tela de situação\r\n * atualiza o estado com o que ela já carregou.\r\n */\r\n@Injectable({ providedIn: 'root' })\r\nexport class SubscriptionAccessState {\r\n private readonly client = inject(BillingClient);\r\n private leitura?: Observable<SubscriptionStatus | null>;\r\n\r\n /** `null` enquanto desconhecida, inclusive quando a leitura falhou. */\r\n readonly status = signal<SubscriptionStatus | null>(null);\r\n readonly avisoAberto = signal(false);\r\n\r\n /** Lê a situação uma única vez. Falha da cobrança vira `null`, e a próxima chamada tenta de novo. */\r\n carregar(): Observable<SubscriptionStatus | null> {\r\n this.leitura ??= this.client.getSubscription().pipe(\r\n map((assinatura) => assinatura.status),\r\n tap((status) => this.status.set(status)),\r\n catchError(() => {\r\n this.leitura = undefined;\r\n return of(null);\r\n }),\r\n shareReplay(1),\r\n );\r\n return this.leitura;\r\n }\r\n\r\n atualizar(status: SubscriptionStatus): void {\r\n this.status.set(status);\r\n this.leitura = of(status);\r\n }\r\n\r\n abrirAviso(): void {\r\n this.avisoAberto.set(true);\r\n }\r\n\r\n fecharAviso(): void {\r\n this.avisoAberto.set(false);\r\n }\r\n}\r\n","import { HttpErrorResponse, HttpInterceptorFn } from '@angular/common/http';\r\nimport { Injector, inject } from '@angular/core';\r\nimport { Router } from '@angular/router';\r\nimport { catchError, switchMap, throwError } from 'rxjs';\r\nimport { AuthClient, normalizeProblemDetails } from '@orechio/platform-angular';\r\nimport { ORECHIO_BILLING_CONFIG } from './billing-config';\r\nimport { SubscriptionAccessState } from './subscription-access.state';\r\n\r\nconst SO_LEITURA = 'subscription.read_only';\r\nconst EXPIRADA = 'subscription.expired';\r\n\r\nfunction codigoDaRecusa(erro: unknown): string | null {\r\n if (!(erro instanceof HttpErrorResponse) || erro.status !== 403) return null;\r\n const { code } = normalizeProblemDetails(erro);\r\n return code === SO_LEITURA || code === EXPIRADA ? code : null;\r\n}\r\n\r\n/**\r\n * Trata as recusas de assinatura do backend do produto (Orechio.Platform.Client 1.6.0). O token\r\n * da sessão pode estar atrasado em relação ao pagamento, então a primeira resposta é renovar a\r\n * sessão e repetir o pedido uma vez. Se continuar recusado, suspensa abre o aviso e expirada leva\r\n * à assinatura. Nunca desloga, e o erro devolvido é sempre o original.\r\n */\r\nexport const subscriptionAccessInterceptor: HttpInterceptorFn = (req, next) => {\r\n const config = inject(ORECHIO_BILLING_CONFIG);\r\n const injector = inject(Injector);\r\n\r\n // A cobrança é o caminho para sair da recusa: nunca é renovada nem repetida.\r\n const { basePath } = config;\r\n if (req.url === basePath || req.url.startsWith(`${basePath}/`) || req.url.startsWith(`${basePath}?`)) {\r\n return next(req);\r\n }\r\n\r\n return next(req).pipe(\r\n catchError((original: unknown) => {\r\n const codigo = codigoDaRecusa(original);\r\n if (!codigo) return throwError(() => original);\r\n\r\n const estado = injector.get(SubscriptionAccessState);\r\n const router = injector.get(Router);\r\n const recusado = () => {\r\n if (codigo === SO_LEITURA) estado.abrirAviso();\r\n else void router.navigateByUrl(config.uiRoute);\r\n return throwError(() => original);\r\n };\r\n\r\n return injector.get(AuthClient).refresh().pipe(\r\n catchError(recusado),\r\n switchMap(() =>\r\n next(req).pipe(\r\n catchError((repetida: unknown) =>\r\n codigoDaRecusa(repetida) === codigo ? recusado() : throwError(() => repetida),\r\n ),\r\n ),\r\n ),\r\n );\r\n }),\r\n );\r\n};\r\n","import { inject } from '@angular/core';\r\nimport { CanActivateFn, Router, UrlTree } from '@angular/router';\r\nimport { Observable, map } from 'rxjs';\r\nimport { ORECHIO_BILLING_CONFIG } from './billing-config';\r\nimport { SubscriptionAccessState } from './subscription-access.state';\r\n\r\n/**\r\n * Expirada vai para a tela da assinatura. Qualquer outra situação entra, inclusive quando a\r\n * leitura falhou: falha da cobrança nunca tranca (ADR-036), e a barreira de servidor continua\r\n * valendo. Aplique nas rotas do produto, não nas de `/billing`.\r\n */\r\nexport const requireSubscriptionAccess: CanActivateFn = (): Observable<boolean | UrlTree> => {\r\n const router = inject(Router);\r\n const { uiRoute } = inject(ORECHIO_BILLING_CONFIG);\r\n\r\n return inject(SubscriptionAccessState)\r\n .carregar()\r\n .pipe(map((status) => (status === 'Expired' ? router.parseUrl(uiRoute) : true)));\r\n};\r\n","import { ChangeDetectionStrategy, Component, DestroyRef, OnInit, inject } from '@angular/core';\r\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\r\nimport { Router, RouterLink } from '@angular/router';\r\nimport { ORECHIO_BILLING_CONFIG } from './billing-config';\r\nimport { SubscriptionAccessState } from './subscription-access.state';\r\n\r\n/**\r\n * A faixa fixa da assinatura suspensa e o aviso de gravação recusada. Ponha a tag uma vez no\r\n * layout do produto. O texto é fixo: nada do corpo do erro vai para a tela.\r\n */\r\n@Component({\r\n selector: 'orechio-subscription-notice',\r\n standalone: true,\r\n imports: [RouterLink],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n template: `\r\n @if (estado.status() === 'Suspended') {\r\n <div class=\"orechio-notice__faixa\" data-testid=\"subscription-banner\" role=\"status\">\r\n <span>\r\n Assinatura suspensa: você pode consultar tudo, mas não pode salvar alterações até\r\n regularizar o pagamento.\r\n </span>\r\n <a [routerLink]=\"uiRoute\">Pagar agora</a>\r\n </div>\r\n }\r\n\r\n @if (estado.avisoAberto()) {\r\n <div class=\"orechio-notice__fundo\">\r\n <div\r\n class=\"orechio-notice__aviso\"\r\n data-testid=\"subscription-readonly-dialog\"\r\n role=\"dialog\"\r\n aria-modal=\"true\"\r\n aria-labelledby=\"orechio-notice-titulo\"\r\n >\r\n <h2 id=\"orechio-notice-titulo\">Assinatura suspensa</h2>\r\n <p>Esta alteração não foi salva. Para voltar a salvar, regularize o pagamento.</p>\r\n <div class=\"orechio-notice__botoes\">\r\n <button type=\"button\" (click)=\"estado.fecharAviso()\">Agora não</button>\r\n <button type=\"button\" (click)=\"irParaAssinatura()\">Ir para a assinatura</button>\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n `,\r\n styles: `\r\n .orechio-notice__faixa {\r\n display: flex; flex-wrap: wrap; gap: 0.5rem 1rem; align-items: center; justify-content: space-between;\r\n padding: 0.75rem 1rem; background: #fff4d6; color: #5c3b00; border-bottom: 1px solid #e6c36a;\r\n }\r\n .orechio-notice__faixa a { font-weight: 600; color: inherit; }\r\n .orechio-notice__fundo {\r\n position: fixed; inset: 0; display: grid; place-items: center; padding: 1rem; background: rgb(0 0 0 / 0.45);\r\n }\r\n .orechio-notice__aviso { max-width: 28rem; padding: 1.5rem; border-radius: 0.5rem; background: #fff; color: #1a1a1a; }\r\n .orechio-notice__aviso h2 { margin: 0 0 0.5rem; font-size: 1.125rem; }\r\n .orechio-notice__botoes { display: flex; flex-wrap: wrap; gap: 0.5rem; justify-content: flex-end; margin-top: 1rem; }\r\n `,\r\n})\r\nexport class OrechioSubscriptionNotice implements OnInit {\r\n protected readonly estado = inject(SubscriptionAccessState);\r\n protected readonly uiRoute = inject(ORECHIO_BILLING_CONFIG).uiRoute;\r\n private readonly router = inject(Router);\r\n private readonly destroyRef = inject(DestroyRef);\r\n\r\n ngOnInit(): void {\r\n this.estado.carregar().pipe(takeUntilDestroyed(this.destroyRef)).subscribe();\r\n }\r\n\r\n protected irParaAssinatura(): void {\r\n this.estado.fecharAviso();\r\n void this.router.navigateByUrl(this.uiRoute);\r\n }\r\n}\r\n","/*\r\n * Public API Surface of @orechio/platform-angular/billing\r\n *\r\n * BILLING-3 — as telas de cobrança do titular (ADR-021 §3.5). Mesmo contrato do entry\r\n * `account`: `BillingClient` e as páginas NÃO são exportados. As telas são alcançadas por\r\n * `ORECHIO_BILLING_ROUTES`, e os caminhos entre elas só valem montados juntos.\r\n */\r\n\r\nexport type { OrechioBillingConfig, OrechioBillingOptions } from './billing-config';\r\nexport { ORECHIO_BILLING_CONFIG, provideOrechioBilling } from './billing-config';\r\n\r\nexport { ORECHIO_BILLING_ROUTES } from './billing.routes';\r\n\r\nexport { subscriptionAccessInterceptor } from './subscription-access.interceptor';\r\nexport { requireSubscriptionAccess } from './subscription-access.guard';\r\nexport { OrechioSubscriptionNotice } from './subscription-notice.component';\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { input, signal, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
|
-
import {
|
|
3
|
+
import { f as moeda, g as dataDoVencimento, v as validadeDoPix } from './orechio-platform-angular-billing-billing-format-CuDtE7fj.mjs';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* O QR e o copia-e-cola, como a Platform os devolveu. O `encodedImage` é PNG em base64
|
|
@@ -33,8 +33,8 @@ class PixPanelComponent {
|
|
|
33
33
|
}
|
|
34
34
|
areaDeTransferencia.writeText(this.pix().payload).then(() => this.copiado.set(true), () => this.semAreaDeTransferencia.set(true));
|
|
35
35
|
}
|
|
36
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
37
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.
|
|
36
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.2.3", ngImport: i0, type: PixPanelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
37
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.2.3", type: PixPanelComponent, isStandalone: true, selector: "orechio-billing-pix", inputs: { pix: { classPropertyName: "pix", publicName: "pix", isSignal: true, isRequired: true, transformFunction: null }, invoiceUrl: { classPropertyName: "invoiceUrl", publicName: "invoiceUrl", isSignal: true, isRequired: false, transformFunction: null }, valor: { classPropertyName: "valor", publicName: "valor", isSignal: true, isRequired: false, transformFunction: null }, vencimento: { classPropertyName: "vencimento", publicName: "vencimento", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
|
38
38
|
<div class="orechio-billing-pix">
|
|
39
39
|
@if (valor() !== null && valor() !== undefined) {
|
|
40
40
|
<p data-valor>Valor: {{ moeda(valor()!) }}</p>
|
|
@@ -65,7 +65,7 @@ class PixPanelComponent {
|
|
|
65
65
|
</div>
|
|
66
66
|
`, isInline: true, styles: [".orechio-billing-pix{display:flex;flex-direction:column;align-items:flex-start;gap:var(--orechio-space-2, .5rem)}.orechio-billing-pix__codigo{word-break:break-all}.orechio-billing-pix__aviso{color:var(--orechio-color-text-muted, #666)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
67
67
|
}
|
|
68
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
68
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.3", ngImport: i0, type: PixPanelComponent, decorators: [{
|
|
69
69
|
type: Component,
|
|
70
70
|
args: [{ selector: 'orechio-billing-pix', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
71
71
|
<div class="orechio-billing-pix">
|
|
@@ -100,4 +100,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.2", ngImpor
|
|
|
100
100
|
}], propDecorators: { pix: [{ type: i0.Input, args: [{ isSignal: true, alias: "pix", required: true }] }], invoiceUrl: [{ type: i0.Input, args: [{ isSignal: true, alias: "invoiceUrl", required: false }] }], valor: [{ type: i0.Input, args: [{ isSignal: true, alias: "valor", required: false }] }], vencimento: [{ type: i0.Input, args: [{ isSignal: true, alias: "vencimento", required: false }] }] } });
|
|
101
101
|
|
|
102
102
|
export { PixPanelComponent as P };
|
|
103
|
-
//# sourceMappingURL=orechio-platform-angular-billing-pix-panel.component-
|
|
103
|
+
//# sourceMappingURL=orechio-platform-angular-billing-pix-panel.component-BiNCJuB_.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"orechio-platform-angular-billing-pix-panel.component-
|
|
1
|
+
{"version":3,"file":"orechio-platform-angular-billing-pix-panel.component-BiNCJuB_.mjs","sources":["../../../projects/platform-angular/billing/src/pix-panel.component.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, input, signal } from '@angular/core';\r\nimport { dataDoVencimento, moeda, validadeDoPix } from './billing-format';\r\nimport { PixData } from './billing-models';\r\n\r\n/**\r\n * O QR e o copia-e-cola, como a Platform os devolveu. O `encodedImage` é PNG em base64\r\n * (ASAAS); o `payload` é o código que o app do banco aceita colado.\r\n */\r\n@Component({\r\n selector: 'orechio-billing-pix',\r\n standalone: true,\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n template: `\r\n <div class=\"orechio-billing-pix\">\r\n @if (valor() !== null && valor() !== undefined) {\r\n <p data-valor>Valor: {{ moeda(valor()!) }}</p>\r\n }\r\n @if (vencimento(); as data) {\r\n <p data-vencimento>Vencimento: {{ dataDoVencimento(data) }}</p>\r\n }\r\n <img data-qr [src]=\"'data:image/png;base64,' + pix().encodedImage\" alt=\"QR Code PIX\" width=\"240\" height=\"240\" />\r\n\r\n <p>Ou copie o código PIX e cole no app do seu banco:</p>\r\n <code class=\"orechio-billing-pix__codigo\">{{ pix().payload }}</code>\r\n <button type=\"button\" data-copiar (click)=\"copiar()\">\r\n {{ copiado() ? 'Código copiado' : 'Copiar código' }}\r\n </button>\r\n @if (semAreaDeTransferencia()) {\r\n <p class=\"orechio-billing-pix__aviso\">Selecione o código acima e copie manualmente.</p>\r\n }\r\n\r\n @if (pix().expirationDate; as validade) {\r\n <p class=\"orechio-billing-pix__aviso\">QR válido até {{ validadeDoPix(validade) }}.</p>\r\n }\r\n\r\n @if (invoiceUrl(); as url) {\r\n <a data-invoice-url [href]=\"url\" target=\"_blank\" rel=\"noopener noreferrer\">\r\n Pagar pelo site do ASAAS\r\n </a>\r\n }\r\n </div>\r\n `,\r\n styles: `\r\n .orechio-billing-pix { display: flex; flex-direction: column; align-items: flex-start; gap: var(--orechio-space-2, 0.5rem); }\r\n .orechio-billing-pix__codigo { word-break: break-all; }\r\n .orechio-billing-pix__aviso { color: var(--orechio-color-text-muted, #666); }\r\n `,\r\n})\r\nexport class PixPanelComponent {\r\n readonly pix = input.required<PixData>();\r\n /** Página de pagamento do ASAAS, aberta em nova aba; sem ela, o link não aparece. */\r\n readonly invoiceUrl = input<string | null | undefined>(null);\r\n\r\n /** Valor da fatura; sem ele, a linha \"Valor\" não aparece. */\r\n readonly valor = input<number | null | undefined>(null);\r\n /** Vencimento da fatura (data sem hora); sem ele, a linha \"Vencimento\" não aparece. */\r\n readonly vencimento = input<string | null | undefined>(null);\r\n\r\n protected readonly moeda = moeda;\r\n protected readonly dataDoVencimento = dataDoVencimento;\r\n protected readonly validadeDoPix = validadeDoPix;\r\n protected readonly copiado = signal(false);\r\n protected readonly semAreaDeTransferencia = signal(false);\r\n\r\n protected copiar(): void {\r\n const areaDeTransferencia = globalThis.navigator?.clipboard;\r\n if (!areaDeTransferencia) {\r\n this.semAreaDeTransferencia.set(true);\r\n return;\r\n }\r\n\r\n areaDeTransferencia.writeText(this.pix().payload).then(\r\n () => this.copiado.set(true),\r\n () => this.semAreaDeTransferencia.set(true),\r\n );\r\n }\r\n}\r\n"],"names":[],"mappings":";;;;AAIA;;;AAGG;MAyCU,iBAAiB,CAAA;IACnB,GAAG,GAAG,KAAK,CAAC,QAAQ;4EAAW;;IAE/B,UAAU,GAAG,KAAK,CAA4B,IAAI;mFAAC;;IAGnD,KAAK,GAAG,KAAK,CAA4B,IAAI;8EAAC;;IAE9C,UAAU,GAAG,KAAK,CAA4B,IAAI;mFAAC;IAEzC,KAAK,GAAG,KAAK;IACb,gBAAgB,GAAG,gBAAgB;IACnC,aAAa,GAAG,aAAa;IAC7B,OAAO,GAAG,MAAM,CAAC,KAAK;gFAAC;IACvB,sBAAsB,GAAG,MAAM,CAAC,KAAK;+FAAC;IAE/C,MAAM,GAAA;AACd,QAAA,MAAM,mBAAmB,GAAG,UAAU,CAAC,SAAS,EAAE,SAAS;QAC3D,IAAI,CAAC,mBAAmB,EAAE;AACxB,YAAA,IAAI,CAAC,sBAAsB,CAAC,GAAG,CAAC,IAAI,CAAC;YACrC;QACF;AAEA,QAAA,mBAAmB,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,CAAC,IAAI,CACpD,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAC5B,MAAM,IAAI,CAAC,sBAAsB,CAAC,GAAG,CAAC,IAAI,CAAC,CAC5C;IACH;uGA3BW,iBAAiB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAjB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,iBAAiB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,qBAAA,EAAA,MAAA,EAAA,EAAA,GAAA,EAAA,EAAA,iBAAA,EAAA,KAAA,EAAA,UAAA,EAAA,KAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,iBAAA,EAAA,YAAA,EAAA,UAAA,EAAA,YAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,KAAA,EAAA,EAAA,iBAAA,EAAA,OAAA,EAAA,UAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,iBAAA,EAAA,YAAA,EAAA,UAAA,EAAA,YAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EApClB,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BT,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,+OAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAOU,iBAAiB,EAAA,UAAA,EAAA,CAAA;kBAxC7B,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,qBAAqB,cACnB,IAAI,EAAA,eAAA,EACC,uBAAuB,CAAC,MAAM,EAAA,QAAA,EACrC,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BT,EAAA,CAAA,EAAA,MAAA,EAAA,CAAA,+OAAA,CAAA,EAAA;;;;;"}
|
|
@@ -4,7 +4,8 @@ import { NgTemplateOutlet } from '@angular/common';
|
|
|
4
4
|
import * as i1 from '@angular/forms';
|
|
5
5
|
import { FormsModule } from '@angular/forms';
|
|
6
6
|
import { Router, ActivatedRoute, RouterLink } from '@angular/router';
|
|
7
|
-
import {
|
|
7
|
+
import { B as BillingClient } from './orechio-platform-angular-billing-orechio-platform-angular-billing-C8Q1JSAC.mjs';
|
|
8
|
+
import { m as mascararCep, a as mascararTelefone, b as mascararDocumento, c as mascararCpf, e as mascararCnpj, s as soDigitos, B as BillingErrorComponent } from './orechio-platform-angular-billing-billing-format-CuDtE7fj.mjs';
|
|
8
9
|
|
|
9
10
|
function doPerfil(perfil) {
|
|
10
11
|
const tipo = perfil.documentType ?? 'Cnpj';
|
|
@@ -143,8 +144,8 @@ class ProfilePage {
|
|
|
143
144
|
state: this.form.state.trim().toUpperCase(),
|
|
144
145
|
};
|
|
145
146
|
}
|
|
146
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
147
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.
|
|
147
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.2.3", ngImport: i0, type: ProfilePage, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
148
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.2.3", type: ProfilePage, isStandalone: true, selector: "orechio-billing-profile", ngImport: i0, template: `
|
|
148
149
|
<section class="orechio-billing">
|
|
149
150
|
<h1>Dados de cobrança</h1>
|
|
150
151
|
|
|
@@ -223,7 +224,7 @@ class ProfilePage {
|
|
|
223
224
|
</ng-template>
|
|
224
225
|
`, isInline: true, styles: [".orechio-billing{display:flex;flex-direction:column;gap:var(--orechio-space-3, .75rem);max-width:40rem;margin:0 auto;padding:var(--orechio-space-6, 1.5rem);color:var(--orechio-color-text, inherit);font-family:var(--orechio-font-body, inherit)}.orechio-billing form{display:flex;flex-direction:column;gap:var(--orechio-space-2, .5rem)}.orechio-billing__muted{color:var(--orechio-color-text-muted, #666)}.orechio-billing__error{color:var(--orechio-color-danger, #b00020)}.orechio-billing__acao{align-self:flex-start;display:inline-block;padding:var(--orechio-space-2, .5rem) var(--orechio-space-4, 1rem);border-radius:var(--orechio-radius, .375rem);background:var(--orechio-color-primary, #1a56db);color:var(--orechio-color-on-primary, #fff);font-weight:600;text-decoration:none}.orechio-billing__acao:hover,.orechio-billing__acao:focus-visible{background:var(--orechio-color-primary-hover, var(--orechio-color-primary, #1446b0))}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox]):not([ngNoCva])[formControlName],textarea:not([ngNoCva])[formControlName],input:not([type=checkbox]):not([ngNoCva])[formControl],textarea:not([ngNoCva])[formControl],input:not([type=checkbox]):not([ngNoCva])[ngModel],textarea:not([ngNoCva])[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple]):not([ngNoCva])[formControlName],select:not([multiple]):not([ngNoCva])[formControl],select:not([multiple]):not([ngNoCva])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i1.NgForm, selector: "form:not([ngNoForm]):not([formGroup]):not([formArray]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "browserUrl", "routerLink"] }, { kind: "component", type: BillingErrorComponent, selector: "orechio-billing-error", inputs: ["problema"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
225
226
|
}
|
|
226
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
227
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.3", ngImport: i0, type: ProfilePage, decorators: [{
|
|
227
228
|
type: Component,
|
|
228
229
|
args: [{ selector: 'orechio-billing-profile', standalone: true, imports: [FormsModule, NgTemplateOutlet, RouterLink, BillingErrorComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
229
230
|
<section class="orechio-billing">
|
|
@@ -306,4 +307,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.2", ngImpor
|
|
|
306
307
|
}] });
|
|
307
308
|
|
|
308
309
|
export { ProfilePage };
|
|
309
|
-
//# sourceMappingURL=orechio-platform-angular-billing-profile.page-
|
|
310
|
+
//# sourceMappingURL=orechio-platform-angular-billing-profile.page-DufY3HDA.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"orechio-platform-angular-billing-profile.page-DRkoYOZa.mjs","sources":["../../../projects/platform-angular/billing/src/pages/profile.page.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, OnInit, inject, signal } from '@angular/core';\r\nimport { NgTemplateOutlet } from '@angular/common';\r\nimport { FormsModule } from '@angular/forms';\r\nimport { ActivatedRoute, Router, RouterLink } from '@angular/router';\r\nimport { Observable } from 'rxjs';\r\nimport { ProblemDetails } from '@orechio/platform-angular';\r\nimport { BillingClient } from '../billing-client';\r\nimport { BillingErrorComponent } from '../billing-error.component';\r\nimport {\r\n ESTILO_BASE,\r\n mascararCep,\r\n mascararCpf,\r\n mascararCnpj,\r\n mascararDocumento,\r\n mascararTelefone,\r\n soDigitos,\r\n} from '../billing-format';\r\nimport {\r\n BillingAddressRequest,\r\n BillingContactRequest,\r\n BillingProfile,\r\n DocumentType,\r\n} from '../billing-models';\r\n\r\ninterface Formulario {\r\n documentType: DocumentType;\r\n documentNumber: string;\r\n legalName: string;\r\n tradeName: string;\r\n billingEmail: string;\r\n phone: string;\r\n mobilePhone: string;\r\n postalCode: string;\r\n street: string;\r\n number: string;\r\n complement: string;\r\n neighborhood: string;\r\n city: string;\r\n state: string;\r\n}\r\n\r\n/** Os campos que levam máscara, e qual máscara cada um leva (o documento depende do tipo). */\r\ntype CampoMascarado = 'documentNumber' | 'phone' | 'mobilePhone' | 'postalCode';\r\n\r\nfunction doPerfil(perfil: BillingProfile): Formulario {\r\n const tipo = perfil.documentType ?? 'Cnpj';\r\n return {\r\n documentType: tipo,\r\n documentNumber: mascararDocumento(tipo, perfil.documentNumber ?? ''),\r\n legalName: perfil.legalName ?? '',\r\n tradeName: perfil.tradeName ?? '',\r\n billingEmail: perfil.billingEmail ?? '',\r\n phone: mascararTelefone(perfil.phone ?? ''),\r\n mobilePhone: mascararTelefone(perfil.mobilePhone ?? ''),\r\n postalCode: mascararCep(perfil.postalCode ?? ''),\r\n street: perfil.street ?? '',\r\n number: perfil.number ?? '',\r\n complement: perfil.complement ?? '',\r\n neighborhood: perfil.neighborhood ?? '',\r\n city: perfil.city ?? '',\r\n state: perfil.state ?? '',\r\n };\r\n}\r\n\r\n/** Campo opcional vazio vai como `null`, que é o que a Platform espera nos `string?`. */\r\nfunction opcional(valor: string): string | null {\r\n const limpo = valor.trim();\r\n return limpo ? limpo : null;\r\n}\r\n\r\n/**\r\n * Perfil de cobrança (ADR-021 §3.5, item 2). Cria com `POST profile`; edita por partes, como a\r\n * Platform: `PATCH profile/contact` e `PATCH profile/address` — não existe PUT.\r\n */\r\n@Component({\r\n selector: 'orechio-billing-profile',\r\n standalone: true,\r\n imports: [FormsModule, NgTemplateOutlet, RouterLink, BillingErrorComponent],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n template: `\r\n <section class=\"orechio-billing\">\r\n <h1>Dados de cobrança</h1>\r\n\r\n @if (perfil(); as p) {\r\n @if (!p.exists) {\r\n <p class=\"orechio-billing__muted\">\r\n Informe os dados que vão na cobrança. O CPF ou CNPJ é exigido pelo emissor do PIX.\r\n </p>\r\n <form data-criar (ngSubmit)=\"criar()\">\r\n <ng-container *ngTemplateOutlet=\"contato\" />\r\n <ng-container *ngTemplateOutlet=\"endereco\" />\r\n <button type=\"submit\" [disabled]=\"enviando()\">{{ enviando() ? 'Salvando…' : 'Salvar' }}</button>\r\n </form>\r\n } @else {\r\n <form data-contato (ngSubmit)=\"salvarContato()\">\r\n <h2>Contato</h2>\r\n <ng-container *ngTemplateOutlet=\"contato\" />\r\n <button type=\"submit\" [disabled]=\"enviando()\">Salvar contato</button>\r\n </form>\r\n\r\n <form data-endereco (ngSubmit)=\"salvarEndereco()\">\r\n <h2>Endereço</h2>\r\n <ng-container *ngTemplateOutlet=\"endereco\" />\r\n <button type=\"submit\" [disabled]=\"enviando()\">Salvar endereço</button>\r\n </form>\r\n }\r\n\r\n @if (salvo()) {\r\n <p role=\"status\">Dados salvos.</p>\r\n }\r\n <a routerLink=\"..\">Voltar para a assinatura</a>\r\n } @else if (!erro()) {\r\n <p class=\"orechio-billing__muted\">Carregando…</p>\r\n }\r\n\r\n @if (erro(); as problema) {\r\n <orechio-billing-error [problema]=\"problema\" />\r\n }\r\n </section>\r\n\r\n <ng-template #contato>\r\n <label>Tipo de documento\r\n <select name=\"documentType\" [ngModel]=\"form.documentType\" (ngModelChange)=\"trocarTipo($event)\" [disabled]=\"travado()\">\r\n <option value=\"Cpf\">CPF</option>\r\n <option value=\"Cnpj\">CNPJ</option>\r\n </select>\r\n </label>\r\n <label>{{ form.documentType === 'Cpf' ? 'CPF' : 'CNPJ' }}\r\n <input name=\"documentNumber\" inputmode=\"numeric\" [value]=\"form.documentNumber\" (input)=\"mascarar('documentNumber', $event)\" [disabled]=\"travado()\" required />\r\n </label>\r\n <label>{{ form.documentType === 'Cpf' ? 'Nome completo' : 'Razão social' }}\r\n <input name=\"legalName\" [(ngModel)]=\"form.legalName\" [disabled]=\"travado()\" required />\r\n </label>\r\n <label>Nome fantasia (opcional)\r\n <input name=\"tradeName\" [(ngModel)]=\"form.tradeName\" />\r\n </label>\r\n <label>E-mail de cobrança\r\n <input name=\"billingEmail\" type=\"email\" autocomplete=\"email\" [(ngModel)]=\"form.billingEmail\" required />\r\n </label>\r\n <label>Telefone (opcional)\r\n <input name=\"phone\" type=\"tel\" [value]=\"form.phone\" (input)=\"mascarar('phone', $event)\" />\r\n </label>\r\n <label>Celular (opcional)\r\n <input name=\"mobilePhone\" type=\"tel\" [value]=\"form.mobilePhone\" (input)=\"mascarar('mobilePhone', $event)\" />\r\n </label>\r\n </ng-template>\r\n\r\n <ng-template #endereco>\r\n <label>CEP <input name=\"postalCode\" inputmode=\"numeric\" autocomplete=\"postal-code\" [value]=\"form.postalCode\" (input)=\"mascarar('postalCode', $event)\" required /></label>\r\n <label>Rua <input name=\"street\" autocomplete=\"address-line1\" [(ngModel)]=\"form.street\" required /></label>\r\n <label>Número <input name=\"number\" [(ngModel)]=\"form.number\" required /></label>\r\n <label>Complemento (opcional) <input name=\"complement\" autocomplete=\"address-line2\" [(ngModel)]=\"form.complement\" /></label>\r\n <label>Bairro <input name=\"neighborhood\" [(ngModel)]=\"form.neighborhood\" required /></label>\r\n <label>Cidade <input name=\"city\" autocomplete=\"address-level2\" [(ngModel)]=\"form.city\" required /></label>\r\n <label>UF <input name=\"state\" maxlength=\"2\" autocomplete=\"address-level1\" [(ngModel)]=\"form.state\" required /></label>\r\n </ng-template>\r\n `,\r\n styles: ESTILO_BASE,\r\n})\r\nexport class ProfilePage implements OnInit {\r\n private readonly client = inject(BillingClient);\r\n private readonly router = inject(Router);\r\n private readonly route = inject(ActivatedRoute);\r\n\r\n protected form: Formulario = doPerfil({} as BillingProfile);\r\n protected readonly perfil = signal<BillingProfile | null>(null);\r\n protected readonly travado = signal(false);\r\n protected readonly enviando = signal(false);\r\n protected readonly salvo = signal(false);\r\n protected readonly erro = signal<ProblemDetails | null>(null);\r\n\r\n ngOnInit(): void {\r\n this.carregar();\r\n }\r\n\r\n /**\r\n * Máscara ao digitar: o campo é reescrito pela máscara e o formulário guarda o texto\r\n * mascarado. Sem `ngModel` de propósito — com ele, digitar um caractere que a máscara\r\n * descarta deixaria o valor do modelo igual ao anterior, e o campo continuaria mostrando\r\n * o caractere digitado.\r\n */\r\n protected mascarar(campo: CampoMascarado, evento: Event): void {\r\n const entrada = evento.target as HTMLInputElement;\r\n const mascarado = this.mascara(campo)(entrada.value);\r\n entrada.value = mascarado;\r\n this.form[campo] = mascarado;\r\n }\r\n\r\n protected trocarTipo(tipo: DocumentType): void {\r\n this.form.documentType = tipo;\r\n this.form.documentNumber = mascararDocumento(tipo, this.form.documentNumber);\r\n }\r\n\r\n private mascara(campo: CampoMascarado): (valor: string) => string {\r\n switch (campo) {\r\n case 'documentNumber':\r\n return this.form.documentType === 'Cpf' ? mascararCpf : mascararCnpj;\r\n case 'postalCode':\r\n return mascararCep;\r\n default:\r\n return mascararTelefone;\r\n }\r\n }\r\n\r\n protected criar(): void {\r\n this.enviar(this.client.createProfile({ ...this.contato(), ...this.endereco() }), () => {\r\n // Quem veio do pagamento volta para ele: foi o checkout que mandou para cá.\r\n if (this.route.snapshot.queryParamMap.get('next') === 'checkout') {\r\n void this.router.navigate(['../checkout'], { relativeTo: this.route });\r\n return;\r\n }\r\n this.carregar();\r\n });\r\n }\r\n\r\n protected salvarContato(): void {\r\n this.enviar(this.client.updateProfileContact(this.contato()), () => this.salvo.set(true));\r\n }\r\n\r\n protected salvarEndereco(): void {\r\n this.enviar(this.client.updateProfileAddress(this.endereco()), () => this.salvo.set(true));\r\n }\r\n\r\n private carregar(): void {\r\n this.client.getProfile().subscribe({\r\n next: (perfil) => {\r\n this.form = doPerfil(perfil);\r\n this.travado.set(perfil.isDocumentLocked === true);\r\n this.perfil.set(perfil);\r\n },\r\n error: (problema: ProblemDetails) => this.erro.set(problema),\r\n });\r\n }\r\n\r\n private enviar(chamada: Observable<unknown>, depois: () => void): void {\r\n if (this.enviando()) return;\r\n this.enviando.set(true);\r\n this.salvo.set(false);\r\n this.erro.set(null);\r\n\r\n chamada.subscribe({\r\n next: () => {\r\n this.enviando.set(false);\r\n depois();\r\n },\r\n error: (problema: ProblemDetails) => {\r\n this.enviando.set(false);\r\n this.erro.set(problema);\r\n },\r\n });\r\n }\r\n\r\n private contato(): BillingContactRequest {\r\n return {\r\n documentType: this.form.documentType,\r\n documentNumber: soDigitos(this.form.documentNumber),\r\n legalName: this.form.legalName.trim(),\r\n tradeName: opcional(this.form.tradeName),\r\n billingEmail: this.form.billingEmail.trim(),\r\n phone: opcional(soDigitos(this.form.phone)),\r\n mobilePhone: opcional(soDigitos(this.form.mobilePhone)),\r\n };\r\n }\r\n\r\n private endereco(): BillingAddressRequest {\r\n return {\r\n postalCode: soDigitos(this.form.postalCode),\r\n street: this.form.street.trim(),\r\n number: this.form.number.trim(),\r\n complement: opcional(this.form.complement),\r\n neighborhood: this.form.neighborhood.trim(),\r\n city: this.form.city.trim(),\r\n state: this.form.state.trim().toUpperCase(),\r\n };\r\n }\r\n}\r\n"],"names":[],"mappings":";;;;;;;;AA4CA,SAAS,QAAQ,CAAC,MAAsB,EAAA;AACtC,IAAA,MAAM,IAAI,GAAG,MAAM,CAAC,YAAY,IAAI,MAAM;IAC1C,OAAO;AACL,QAAA,YAAY,EAAE,IAAI;QAClB,cAAc,EAAE,iBAAiB,CAAC,IAAI,EAAE,MAAM,CAAC,cAAc,IAAI,EAAE,CAAC;AACpE,QAAA,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,EAAE;AACjC,QAAA,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,EAAE;AACjC,QAAA,YAAY,EAAE,MAAM,CAAC,YAAY,IAAI,EAAE;QACvC,KAAK,EAAE,gBAAgB,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC;QAC3C,WAAW,EAAE,gBAAgB,CAAC,MAAM,CAAC,WAAW,IAAI,EAAE,CAAC;QACvD,UAAU,EAAE,WAAW,CAAC,MAAM,CAAC,UAAU,IAAI,EAAE,CAAC;AAChD,QAAA,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,EAAE;AAC3B,QAAA,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,EAAE;AAC3B,QAAA,UAAU,EAAE,MAAM,CAAC,UAAU,IAAI,EAAE;AACnC,QAAA,YAAY,EAAE,MAAM,CAAC,YAAY,IAAI,EAAE;AACvC,QAAA,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,EAAE;AACvB,QAAA,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,EAAE;KAC1B;AACH;AAEA;AACA,SAAS,QAAQ,CAAC,KAAa,EAAA;AAC7B,IAAA,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,EAAE;IAC1B,OAAO,KAAK,GAAG,KAAK,GAAG,IAAI;AAC7B;AAEA;;;AAGG;MAsFU,WAAW,CAAA;AACL,IAAA,MAAM,GAAG,MAAM,CAAC,aAAa,CAAC;AAC9B,IAAA,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;AACvB,IAAA,KAAK,GAAG,MAAM,CAAC,cAAc,CAAC;AAErC,IAAA,IAAI,GAAe,QAAQ,CAAC,EAAoB,CAAC;IACxC,MAAM,GAAG,MAAM,CAAwB,IAAI;+EAAC;IAC5C,OAAO,GAAG,MAAM,CAAC,KAAK;gFAAC;IACvB,QAAQ,GAAG,MAAM,CAAC,KAAK;iFAAC;IACxB,KAAK,GAAG,MAAM,CAAC,KAAK;8EAAC;IACrB,IAAI,GAAG,MAAM,CAAwB,IAAI;6EAAC;IAE7D,QAAQ,GAAA;QACN,IAAI,CAAC,QAAQ,EAAE;IACjB;AAEA;;;;;AAKG;IACO,QAAQ,CAAC,KAAqB,EAAE,MAAa,EAAA;AACrD,QAAA,MAAM,OAAO,GAAG,MAAM,CAAC,MAA0B;AACjD,QAAA,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;AACpD,QAAA,OAAO,CAAC,KAAK,GAAG,SAAS;AACzB,QAAA,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,SAAS;IAC9B;AAEU,IAAA,UAAU,CAAC,IAAkB,EAAA;AACrC,QAAA,IAAI,CAAC,IAAI,CAAC,YAAY,GAAG,IAAI;AAC7B,QAAA,IAAI,CAAC,IAAI,CAAC,cAAc,GAAG,iBAAiB,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC;IAC9E;AAEQ,IAAA,OAAO,CAAC,KAAqB,EAAA;QACnC,QAAQ,KAAK;AACX,YAAA,KAAK,gBAAgB;AACnB,gBAAA,OAAO,IAAI,CAAC,IAAI,CAAC,YAAY,KAAK,KAAK,GAAG,WAAW,GAAG,YAAY;AACtE,YAAA,KAAK,YAAY;AACf,gBAAA,OAAO,WAAW;AACpB,YAAA;AACE,gBAAA,OAAO,gBAAgB;;IAE7B;IAEU,KAAK,GAAA;QACb,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,GAAG,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC,EAAE,MAAK;;AAErF,YAAA,IAAI,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,UAAU,EAAE;AAChE,gBAAA,KAAK,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,EAAE,EAAE,UAAU,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC;gBACtE;YACF;YACA,IAAI,CAAC,QAAQ,EAAE;AACjB,QAAA,CAAC,CAAC;IACJ;IAEU,aAAa,GAAA;QACrB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC3F;IAEU,cAAc,GAAA;QACtB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,EAAE,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC5F;IAEQ,QAAQ,GAAA;AACd,QAAA,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,SAAS,CAAC;AACjC,YAAA,IAAI,EAAE,CAAC,MAAM,KAAI;AACf,gBAAA,IAAI,CAAC,IAAI,GAAG,QAAQ,CAAC,MAAM,CAAC;gBAC5B,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,gBAAgB,KAAK,IAAI,CAAC;AAClD,gBAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC;YACzB,CAAC;AACD,YAAA,KAAK,EAAE,CAAC,QAAwB,KAAK,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC;AAC7D,SAAA,CAAC;IACJ;IAEQ,MAAM,CAAC,OAA4B,EAAE,MAAkB,EAAA;QAC7D,IAAI,IAAI,CAAC,QAAQ,EAAE;YAAE;AACrB,QAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC;AACvB,QAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC;AACrB,QAAA,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;QAEnB,OAAO,CAAC,SAAS,CAAC;YAChB,IAAI,EAAE,MAAK;AACT,gBAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC;AACxB,gBAAA,MAAM,EAAE;YACV,CAAC;AACD,YAAA,KAAK,EAAE,CAAC,QAAwB,KAAI;AAClC,gBAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC;AACxB,gBAAA,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC;YACzB,CAAC;AACF,SAAA,CAAC;IACJ;IAEQ,OAAO,GAAA;QACb,OAAO;AACL,YAAA,YAAY,EAAE,IAAI,CAAC,IAAI,CAAC,YAAY;YACpC,cAAc,EAAE,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC;YACnD,SAAS,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE;YACrC,SAAS,EAAE,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC;YACxC,YAAY,EAAE,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE;YAC3C,KAAK,EAAE,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC3C,WAAW,EAAE,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;SACxD;IACH;IAEQ,QAAQ,GAAA;QACd,OAAO;YACL,UAAU,EAAE,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC;YAC3C,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE;YAC/B,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE;YAC/B,UAAU,EAAE,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC;YAC1C,YAAY,EAAE,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE;YAC3C,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;YAC3B,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE;SAC5C;IACH;uGAnHW,WAAW,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAX,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,WAAW,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,yBAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EAhFZ,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6ET,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,o6BAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EA/ES,WAAW,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,aAAA,EAAA,QAAA,EAAA,8CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,cAAA,EAAA,QAAA,EAAA,QAAA,EAAA,MAAA,EAAA,CAAA,SAAA,EAAA,OAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,uBAAA,EAAA,QAAA,EAAA,QAAA,EAAA,MAAA,EAAA,CAAA,SAAA,EAAA,OAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,oBAAA,EAAA,QAAA,EAAA,wSAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,0BAAA,EAAA,QAAA,EAAA,0JAAA,EAAA,MAAA,EAAA,CAAA,aAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,eAAA,EAAA,QAAA,EAAA,2CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,oBAAA,EAAA,QAAA,EAAA,sGAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,iBAAA,EAAA,QAAA,EAAA,wIAAA,EAAA,MAAA,EAAA,CAAA,UAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,kBAAA,EAAA,QAAA,EAAA,4EAAA,EAAA,MAAA,EAAA,CAAA,WAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,OAAA,EAAA,QAAA,EAAA,qDAAA,EAAA,MAAA,EAAA,CAAA,MAAA,EAAA,UAAA,EAAA,SAAA,EAAA,gBAAA,CAAA,EAAA,OAAA,EAAA,CAAA,eAAA,CAAA,EAAA,QAAA,EAAA,CAAA,SAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,MAAA,EAAA,QAAA,EAAA,yEAAA,EAAA,MAAA,EAAA,CAAA,eAAA,CAAA,EAAA,OAAA,EAAA,CAAA,UAAA,CAAA,EAAA,QAAA,EAAA,CAAA,QAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAE,gBAAgB,EAAA,QAAA,EAAA,oBAAA,EAAA,MAAA,EAAA,CAAA,yBAAA,EAAA,kBAAA,EAAA,0BAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAE,UAAU,kPAAE,qBAAqB,EAAA,QAAA,EAAA,uBAAA,EAAA,MAAA,EAAA,CAAA,UAAA,CAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAkF/D,WAAW,EAAA,UAAA,EAAA,CAAA;kBArFvB,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,yBAAyB,cACvB,IAAI,EAAA,OAAA,EACP,CAAC,WAAW,EAAE,gBAAgB,EAAE,UAAU,EAAE,qBAAqB,CAAC,EAAA,eAAA,EAC1D,uBAAuB,CAAC,MAAM,EAAA,QAAA,EACrC,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6ET,EAAA,CAAA,EAAA,MAAA,EAAA,CAAA,o6BAAA,CAAA,EAAA;;;;;"}
|
|
1
|
+
{"version":3,"file":"orechio-platform-angular-billing-profile.page-DufY3HDA.mjs","sources":["../../../projects/platform-angular/billing/src/pages/profile.page.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, OnInit, inject, signal } from '@angular/core';\r\nimport { NgTemplateOutlet } from '@angular/common';\r\nimport { FormsModule } from '@angular/forms';\r\nimport { ActivatedRoute, Router, RouterLink } from '@angular/router';\r\nimport { Observable } from 'rxjs';\r\nimport { ProblemDetails } from '@orechio/platform-angular';\r\nimport { BillingClient } from '../billing-client';\r\nimport { BillingErrorComponent } from '../billing-error.component';\r\nimport {\r\n ESTILO_BASE,\r\n mascararCep,\r\n mascararCpf,\r\n mascararCnpj,\r\n mascararDocumento,\r\n mascararTelefone,\r\n soDigitos,\r\n} from '../billing-format';\r\nimport {\r\n BillingAddressRequest,\r\n BillingContactRequest,\r\n BillingProfile,\r\n DocumentType,\r\n} from '../billing-models';\r\n\r\ninterface Formulario {\r\n documentType: DocumentType;\r\n documentNumber: string;\r\n legalName: string;\r\n tradeName: string;\r\n billingEmail: string;\r\n phone: string;\r\n mobilePhone: string;\r\n postalCode: string;\r\n street: string;\r\n number: string;\r\n complement: string;\r\n neighborhood: string;\r\n city: string;\r\n state: string;\r\n}\r\n\r\n/** Os campos que levam máscara, e qual máscara cada um leva (o documento depende do tipo). */\r\ntype CampoMascarado = 'documentNumber' | 'phone' | 'mobilePhone' | 'postalCode';\r\n\r\nfunction doPerfil(perfil: BillingProfile): Formulario {\r\n const tipo = perfil.documentType ?? 'Cnpj';\r\n return {\r\n documentType: tipo,\r\n documentNumber: mascararDocumento(tipo, perfil.documentNumber ?? ''),\r\n legalName: perfil.legalName ?? '',\r\n tradeName: perfil.tradeName ?? '',\r\n billingEmail: perfil.billingEmail ?? '',\r\n phone: mascararTelefone(perfil.phone ?? ''),\r\n mobilePhone: mascararTelefone(perfil.mobilePhone ?? ''),\r\n postalCode: mascararCep(perfil.postalCode ?? ''),\r\n street: perfil.street ?? '',\r\n number: perfil.number ?? '',\r\n complement: perfil.complement ?? '',\r\n neighborhood: perfil.neighborhood ?? '',\r\n city: perfil.city ?? '',\r\n state: perfil.state ?? '',\r\n };\r\n}\r\n\r\n/** Campo opcional vazio vai como `null`, que é o que a Platform espera nos `string?`. */\r\nfunction opcional(valor: string): string | null {\r\n const limpo = valor.trim();\r\n return limpo ? limpo : null;\r\n}\r\n\r\n/**\r\n * Perfil de cobrança (ADR-021 §3.5, item 2). Cria com `POST profile`; edita por partes, como a\r\n * Platform: `PATCH profile/contact` e `PATCH profile/address` — não existe PUT.\r\n */\r\n@Component({\r\n selector: 'orechio-billing-profile',\r\n standalone: true,\r\n imports: [FormsModule, NgTemplateOutlet, RouterLink, BillingErrorComponent],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n template: `\r\n <section class=\"orechio-billing\">\r\n <h1>Dados de cobrança</h1>\r\n\r\n @if (perfil(); as p) {\r\n @if (!p.exists) {\r\n <p class=\"orechio-billing__muted\">\r\n Informe os dados que vão na cobrança. O CPF ou CNPJ é exigido pelo emissor do PIX.\r\n </p>\r\n <form data-criar (ngSubmit)=\"criar()\">\r\n <ng-container *ngTemplateOutlet=\"contato\" />\r\n <ng-container *ngTemplateOutlet=\"endereco\" />\r\n <button type=\"submit\" [disabled]=\"enviando()\">{{ enviando() ? 'Salvando…' : 'Salvar' }}</button>\r\n </form>\r\n } @else {\r\n <form data-contato (ngSubmit)=\"salvarContato()\">\r\n <h2>Contato</h2>\r\n <ng-container *ngTemplateOutlet=\"contato\" />\r\n <button type=\"submit\" [disabled]=\"enviando()\">Salvar contato</button>\r\n </form>\r\n\r\n <form data-endereco (ngSubmit)=\"salvarEndereco()\">\r\n <h2>Endereço</h2>\r\n <ng-container *ngTemplateOutlet=\"endereco\" />\r\n <button type=\"submit\" [disabled]=\"enviando()\">Salvar endereço</button>\r\n </form>\r\n }\r\n\r\n @if (salvo()) {\r\n <p role=\"status\">Dados salvos.</p>\r\n }\r\n <a routerLink=\"..\">Voltar para a assinatura</a>\r\n } @else if (!erro()) {\r\n <p class=\"orechio-billing__muted\">Carregando…</p>\r\n }\r\n\r\n @if (erro(); as problema) {\r\n <orechio-billing-error [problema]=\"problema\" />\r\n }\r\n </section>\r\n\r\n <ng-template #contato>\r\n <label>Tipo de documento\r\n <select name=\"documentType\" [ngModel]=\"form.documentType\" (ngModelChange)=\"trocarTipo($event)\" [disabled]=\"travado()\">\r\n <option value=\"Cpf\">CPF</option>\r\n <option value=\"Cnpj\">CNPJ</option>\r\n </select>\r\n </label>\r\n <label>{{ form.documentType === 'Cpf' ? 'CPF' : 'CNPJ' }}\r\n <input name=\"documentNumber\" inputmode=\"numeric\" [value]=\"form.documentNumber\" (input)=\"mascarar('documentNumber', $event)\" [disabled]=\"travado()\" required />\r\n </label>\r\n <label>{{ form.documentType === 'Cpf' ? 'Nome completo' : 'Razão social' }}\r\n <input name=\"legalName\" [(ngModel)]=\"form.legalName\" [disabled]=\"travado()\" required />\r\n </label>\r\n <label>Nome fantasia (opcional)\r\n <input name=\"tradeName\" [(ngModel)]=\"form.tradeName\" />\r\n </label>\r\n <label>E-mail de cobrança\r\n <input name=\"billingEmail\" type=\"email\" autocomplete=\"email\" [(ngModel)]=\"form.billingEmail\" required />\r\n </label>\r\n <label>Telefone (opcional)\r\n <input name=\"phone\" type=\"tel\" [value]=\"form.phone\" (input)=\"mascarar('phone', $event)\" />\r\n </label>\r\n <label>Celular (opcional)\r\n <input name=\"mobilePhone\" type=\"tel\" [value]=\"form.mobilePhone\" (input)=\"mascarar('mobilePhone', $event)\" />\r\n </label>\r\n </ng-template>\r\n\r\n <ng-template #endereco>\r\n <label>CEP <input name=\"postalCode\" inputmode=\"numeric\" autocomplete=\"postal-code\" [value]=\"form.postalCode\" (input)=\"mascarar('postalCode', $event)\" required /></label>\r\n <label>Rua <input name=\"street\" autocomplete=\"address-line1\" [(ngModel)]=\"form.street\" required /></label>\r\n <label>Número <input name=\"number\" [(ngModel)]=\"form.number\" required /></label>\r\n <label>Complemento (opcional) <input name=\"complement\" autocomplete=\"address-line2\" [(ngModel)]=\"form.complement\" /></label>\r\n <label>Bairro <input name=\"neighborhood\" [(ngModel)]=\"form.neighborhood\" required /></label>\r\n <label>Cidade <input name=\"city\" autocomplete=\"address-level2\" [(ngModel)]=\"form.city\" required /></label>\r\n <label>UF <input name=\"state\" maxlength=\"2\" autocomplete=\"address-level1\" [(ngModel)]=\"form.state\" required /></label>\r\n </ng-template>\r\n `,\r\n styles: ESTILO_BASE,\r\n})\r\nexport class ProfilePage implements OnInit {\r\n private readonly client = inject(BillingClient);\r\n private readonly router = inject(Router);\r\n private readonly route = inject(ActivatedRoute);\r\n\r\n protected form: Formulario = doPerfil({} as BillingProfile);\r\n protected readonly perfil = signal<BillingProfile | null>(null);\r\n protected readonly travado = signal(false);\r\n protected readonly enviando = signal(false);\r\n protected readonly salvo = signal(false);\r\n protected readonly erro = signal<ProblemDetails | null>(null);\r\n\r\n ngOnInit(): void {\r\n this.carregar();\r\n }\r\n\r\n /**\r\n * Máscara ao digitar: o campo é reescrito pela máscara e o formulário guarda o texto\r\n * mascarado. Sem `ngModel` de propósito — com ele, digitar um caractere que a máscara\r\n * descarta deixaria o valor do modelo igual ao anterior, e o campo continuaria mostrando\r\n * o caractere digitado.\r\n */\r\n protected mascarar(campo: CampoMascarado, evento: Event): void {\r\n const entrada = evento.target as HTMLInputElement;\r\n const mascarado = this.mascara(campo)(entrada.value);\r\n entrada.value = mascarado;\r\n this.form[campo] = mascarado;\r\n }\r\n\r\n protected trocarTipo(tipo: DocumentType): void {\r\n this.form.documentType = tipo;\r\n this.form.documentNumber = mascararDocumento(tipo, this.form.documentNumber);\r\n }\r\n\r\n private mascara(campo: CampoMascarado): (valor: string) => string {\r\n switch (campo) {\r\n case 'documentNumber':\r\n return this.form.documentType === 'Cpf' ? mascararCpf : mascararCnpj;\r\n case 'postalCode':\r\n return mascararCep;\r\n default:\r\n return mascararTelefone;\r\n }\r\n }\r\n\r\n protected criar(): void {\r\n this.enviar(this.client.createProfile({ ...this.contato(), ...this.endereco() }), () => {\r\n // Quem veio do pagamento volta para ele: foi o checkout que mandou para cá.\r\n if (this.route.snapshot.queryParamMap.get('next') === 'checkout') {\r\n void this.router.navigate(['../checkout'], { relativeTo: this.route });\r\n return;\r\n }\r\n this.carregar();\r\n });\r\n }\r\n\r\n protected salvarContato(): void {\r\n this.enviar(this.client.updateProfileContact(this.contato()), () => this.salvo.set(true));\r\n }\r\n\r\n protected salvarEndereco(): void {\r\n this.enviar(this.client.updateProfileAddress(this.endereco()), () => this.salvo.set(true));\r\n }\r\n\r\n private carregar(): void {\r\n this.client.getProfile().subscribe({\r\n next: (perfil) => {\r\n this.form = doPerfil(perfil);\r\n this.travado.set(perfil.isDocumentLocked === true);\r\n this.perfil.set(perfil);\r\n },\r\n error: (problema: ProblemDetails) => this.erro.set(problema),\r\n });\r\n }\r\n\r\n private enviar(chamada: Observable<unknown>, depois: () => void): void {\r\n if (this.enviando()) return;\r\n this.enviando.set(true);\r\n this.salvo.set(false);\r\n this.erro.set(null);\r\n\r\n chamada.subscribe({\r\n next: () => {\r\n this.enviando.set(false);\r\n depois();\r\n },\r\n error: (problema: ProblemDetails) => {\r\n this.enviando.set(false);\r\n this.erro.set(problema);\r\n },\r\n });\r\n }\r\n\r\n private contato(): BillingContactRequest {\r\n return {\r\n documentType: this.form.documentType,\r\n documentNumber: soDigitos(this.form.documentNumber),\r\n legalName: this.form.legalName.trim(),\r\n tradeName: opcional(this.form.tradeName),\r\n billingEmail: this.form.billingEmail.trim(),\r\n phone: opcional(soDigitos(this.form.phone)),\r\n mobilePhone: opcional(soDigitos(this.form.mobilePhone)),\r\n };\r\n }\r\n\r\n private endereco(): BillingAddressRequest {\r\n return {\r\n postalCode: soDigitos(this.form.postalCode),\r\n street: this.form.street.trim(),\r\n number: this.form.number.trim(),\r\n complement: opcional(this.form.complement),\r\n neighborhood: this.form.neighborhood.trim(),\r\n city: this.form.city.trim(),\r\n state: this.form.state.trim().toUpperCase(),\r\n };\r\n }\r\n}\r\n"],"names":[],"mappings":";;;;;;;;;AA4CA,SAAS,QAAQ,CAAC,MAAsB,EAAA;AACtC,IAAA,MAAM,IAAI,GAAG,MAAM,CAAC,YAAY,IAAI,MAAM;IAC1C,OAAO;AACL,QAAA,YAAY,EAAE,IAAI;QAClB,cAAc,EAAE,iBAAiB,CAAC,IAAI,EAAE,MAAM,CAAC,cAAc,IAAI,EAAE,CAAC;AACpE,QAAA,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,EAAE;AACjC,QAAA,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,EAAE;AACjC,QAAA,YAAY,EAAE,MAAM,CAAC,YAAY,IAAI,EAAE;QACvC,KAAK,EAAE,gBAAgB,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC;QAC3C,WAAW,EAAE,gBAAgB,CAAC,MAAM,CAAC,WAAW,IAAI,EAAE,CAAC;QACvD,UAAU,EAAE,WAAW,CAAC,MAAM,CAAC,UAAU,IAAI,EAAE,CAAC;AAChD,QAAA,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,EAAE;AAC3B,QAAA,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,EAAE;AAC3B,QAAA,UAAU,EAAE,MAAM,CAAC,UAAU,IAAI,EAAE;AACnC,QAAA,YAAY,EAAE,MAAM,CAAC,YAAY,IAAI,EAAE;AACvC,QAAA,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,EAAE;AACvB,QAAA,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,EAAE;KAC1B;AACH;AAEA;AACA,SAAS,QAAQ,CAAC,KAAa,EAAA;AAC7B,IAAA,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,EAAE;IAC1B,OAAO,KAAK,GAAG,KAAK,GAAG,IAAI;AAC7B;AAEA;;;AAGG;MAsFU,WAAW,CAAA;AACL,IAAA,MAAM,GAAG,MAAM,CAAC,aAAa,CAAC;AAC9B,IAAA,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;AACvB,IAAA,KAAK,GAAG,MAAM,CAAC,cAAc,CAAC;AAErC,IAAA,IAAI,GAAe,QAAQ,CAAC,EAAoB,CAAC;IACxC,MAAM,GAAG,MAAM,CAAwB,IAAI;+EAAC;IAC5C,OAAO,GAAG,MAAM,CAAC,KAAK;gFAAC;IACvB,QAAQ,GAAG,MAAM,CAAC,KAAK;iFAAC;IACxB,KAAK,GAAG,MAAM,CAAC,KAAK;8EAAC;IACrB,IAAI,GAAG,MAAM,CAAwB,IAAI;6EAAC;IAE7D,QAAQ,GAAA;QACN,IAAI,CAAC,QAAQ,EAAE;IACjB;AAEA;;;;;AAKG;IACO,QAAQ,CAAC,KAAqB,EAAE,MAAa,EAAA;AACrD,QAAA,MAAM,OAAO,GAAG,MAAM,CAAC,MAA0B;AACjD,QAAA,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;AACpD,QAAA,OAAO,CAAC,KAAK,GAAG,SAAS;AACzB,QAAA,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,SAAS;IAC9B;AAEU,IAAA,UAAU,CAAC,IAAkB,EAAA;AACrC,QAAA,IAAI,CAAC,IAAI,CAAC,YAAY,GAAG,IAAI;AAC7B,QAAA,IAAI,CAAC,IAAI,CAAC,cAAc,GAAG,iBAAiB,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC;IAC9E;AAEQ,IAAA,OAAO,CAAC,KAAqB,EAAA;QACnC,QAAQ,KAAK;AACX,YAAA,KAAK,gBAAgB;AACnB,gBAAA,OAAO,IAAI,CAAC,IAAI,CAAC,YAAY,KAAK,KAAK,GAAG,WAAW,GAAG,YAAY;AACtE,YAAA,KAAK,YAAY;AACf,gBAAA,OAAO,WAAW;AACpB,YAAA;AACE,gBAAA,OAAO,gBAAgB;;IAE7B;IAEU,KAAK,GAAA;QACb,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,GAAG,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC,EAAE,MAAK;;AAErF,YAAA,IAAI,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,UAAU,EAAE;AAChE,gBAAA,KAAK,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,EAAE,EAAE,UAAU,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC;gBACtE;YACF;YACA,IAAI,CAAC,QAAQ,EAAE;AACjB,QAAA,CAAC,CAAC;IACJ;IAEU,aAAa,GAAA;QACrB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC3F;IAEU,cAAc,GAAA;QACtB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,EAAE,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC5F;IAEQ,QAAQ,GAAA;AACd,QAAA,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,SAAS,CAAC;AACjC,YAAA,IAAI,EAAE,CAAC,MAAM,KAAI;AACf,gBAAA,IAAI,CAAC,IAAI,GAAG,QAAQ,CAAC,MAAM,CAAC;gBAC5B,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,gBAAgB,KAAK,IAAI,CAAC;AAClD,gBAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC;YACzB,CAAC;AACD,YAAA,KAAK,EAAE,CAAC,QAAwB,KAAK,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC;AAC7D,SAAA,CAAC;IACJ;IAEQ,MAAM,CAAC,OAA4B,EAAE,MAAkB,EAAA;QAC7D,IAAI,IAAI,CAAC,QAAQ,EAAE;YAAE;AACrB,QAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC;AACvB,QAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC;AACrB,QAAA,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;QAEnB,OAAO,CAAC,SAAS,CAAC;YAChB,IAAI,EAAE,MAAK;AACT,gBAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC;AACxB,gBAAA,MAAM,EAAE;YACV,CAAC;AACD,YAAA,KAAK,EAAE,CAAC,QAAwB,KAAI;AAClC,gBAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC;AACxB,gBAAA,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC;YACzB,CAAC;AACF,SAAA,CAAC;IACJ;IAEQ,OAAO,GAAA;QACb,OAAO;AACL,YAAA,YAAY,EAAE,IAAI,CAAC,IAAI,CAAC,YAAY;YACpC,cAAc,EAAE,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC;YACnD,SAAS,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE;YACrC,SAAS,EAAE,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC;YACxC,YAAY,EAAE,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE;YAC3C,KAAK,EAAE,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC3C,WAAW,EAAE,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;SACxD;IACH;IAEQ,QAAQ,GAAA;QACd,OAAO;YACL,UAAU,EAAE,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC;YAC3C,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE;YAC/B,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE;YAC/B,UAAU,EAAE,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC;YAC1C,YAAY,EAAE,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE;YAC3C,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;YAC3B,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE;SAC5C;IACH;uGAnHW,WAAW,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAX,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,WAAW,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,yBAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EAhFZ,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6ET,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,o6BAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EA/ES,WAAW,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,aAAA,EAAA,QAAA,EAAA,8CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,cAAA,EAAA,QAAA,EAAA,QAAA,EAAA,MAAA,EAAA,CAAA,SAAA,EAAA,OAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,uBAAA,EAAA,QAAA,EAAA,QAAA,EAAA,MAAA,EAAA,CAAA,SAAA,EAAA,OAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,oBAAA,EAAA,QAAA,EAAA,wSAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,0BAAA,EAAA,QAAA,EAAA,0JAAA,EAAA,MAAA,EAAA,CAAA,aAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,eAAA,EAAA,QAAA,EAAA,2CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,oBAAA,EAAA,QAAA,EAAA,sGAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,iBAAA,EAAA,QAAA,EAAA,wIAAA,EAAA,MAAA,EAAA,CAAA,UAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,kBAAA,EAAA,QAAA,EAAA,4EAAA,EAAA,MAAA,EAAA,CAAA,WAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,OAAA,EAAA,QAAA,EAAA,qDAAA,EAAA,MAAA,EAAA,CAAA,MAAA,EAAA,UAAA,EAAA,SAAA,EAAA,gBAAA,CAAA,EAAA,OAAA,EAAA,CAAA,eAAA,CAAA,EAAA,QAAA,EAAA,CAAA,SAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,MAAA,EAAA,QAAA,EAAA,yEAAA,EAAA,MAAA,EAAA,CAAA,eAAA,CAAA,EAAA,OAAA,EAAA,CAAA,UAAA,CAAA,EAAA,QAAA,EAAA,CAAA,QAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAE,gBAAgB,EAAA,QAAA,EAAA,oBAAA,EAAA,MAAA,EAAA,CAAA,yBAAA,EAAA,kBAAA,EAAA,0BAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAE,UAAU,kPAAE,qBAAqB,EAAA,QAAA,EAAA,uBAAA,EAAA,MAAA,EAAA,CAAA,UAAA,CAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAkF/D,WAAW,EAAA,UAAA,EAAA,CAAA;kBArFvB,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,yBAAyB,cACvB,IAAI,EAAA,OAAA,EACP,CAAC,WAAW,EAAE,gBAAgB,EAAE,UAAU,EAAE,qBAAqB,CAAC,EAAA,eAAA,EAC1D,uBAAuB,CAAC,MAAM,EAAA,QAAA,EACrC,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6ET,EAAA,CAAA,EAAA,MAAA,EAAA,CAAA,o6BAAA,CAAA,EAAA;;;;;"}
|