@orechio/platform-angular 0.6.0 → 0.7.2
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 +134 -64
- package/fesm2022/orechio-platform-angular-account-account-client-mPl0tzMg.mjs.map +1 -1
- package/fesm2022/{orechio-platform-angular-account-forgot-password.page-5_8R5B4m.mjs → orechio-platform-angular-account-forgot-password.page-L-Z-s49p.mjs} +85 -85
- package/fesm2022/orechio-platform-angular-account-forgot-password.page-L-Z-s49p.mjs.map +1 -0
- package/fesm2022/{orechio-platform-angular-account-initial-branch.page-Cmy07JGF.mjs → orechio-platform-angular-account-initial-branch.page-C8a1eU3L.mjs} +61 -61
- package/fesm2022/orechio-platform-angular-account-initial-branch.page-C8a1eU3L.mjs.map +1 -0
- package/fesm2022/{orechio-platform-angular-account-resend-verification.page-qckKAlPk.mjs → orechio-platform-angular-account-resend-verification.page-C3lk1vNj.mjs} +69 -69
- package/fesm2022/orechio-platform-angular-account-resend-verification.page-C3lk1vNj.mjs.map +1 -0
- package/fesm2022/{orechio-platform-angular-account-token-password.page-AHqb8mFk.mjs → orechio-platform-angular-account-token-password.page-1vn5XGVu.mjs} +73 -73
- package/fesm2022/orechio-platform-angular-account-token-password.page-1vn5XGVu.mjs.map +1 -0
- package/fesm2022/{orechio-platform-angular-account-verify-email.page-CHs0EwDf.mjs → orechio-platform-angular-account-verify-email.page-xulVDiOn.mjs} +35 -35
- package/fesm2022/orechio-platform-angular-account-verify-email.page-xulVDiOn.mjs.map +1 -0
- package/fesm2022/orechio-platform-angular-account.mjs +6 -6
- package/fesm2022/orechio-platform-angular-account.mjs.map +1 -1
- package/fesm2022/orechio-platform-angular-billing-billing-format-DFY2U19Y.mjs +303 -0
- package/fesm2022/orechio-platform-angular-billing-billing-format-DFY2U19Y.mjs.map +1 -0
- package/fesm2022/orechio-platform-angular-billing-checkout.page-CNl0PPiE.mjs +186 -0
- package/fesm2022/orechio-platform-angular-billing-checkout.page-CNl0PPiE.mjs.map +1 -0
- package/fesm2022/orechio-platform-angular-billing-invoice.page-CLojIJkf.mjs +136 -0
- package/fesm2022/orechio-platform-angular-billing-invoice.page-CLojIJkf.mjs.map +1 -0
- package/fesm2022/orechio-platform-angular-billing-invoices.page-COsCT5NY.mjs +105 -0
- package/fesm2022/orechio-platform-angular-billing-invoices.page-COsCT5NY.mjs.map +1 -0
- package/fesm2022/orechio-platform-angular-billing-pix-panel.component-fdORTehK.mjs +83 -0
- package/fesm2022/orechio-platform-angular-billing-pix-panel.component-fdORTehK.mjs.map +1 -0
- package/fesm2022/orechio-platform-angular-billing-profile.page-DHjsB3jJ.mjs +309 -0
- package/fesm2022/orechio-platform-angular-billing-profile.page-DHjsB3jJ.mjs.map +1 -0
- package/fesm2022/orechio-platform-angular-billing-subscription.page-Cotupt22.mjs +160 -0
- package/fesm2022/orechio-platform-angular-billing-subscription.page-Cotupt22.mjs.map +1 -0
- package/fesm2022/orechio-platform-angular-billing.mjs +69 -0
- package/fesm2022/orechio-platform-angular-billing.mjs.map +1 -0
- package/fesm2022/orechio-platform-angular.mjs +8 -4
- package/fesm2022/orechio-platform-angular.mjs.map +1 -1
- package/package.json +5 -1
- package/types/orechio-platform-angular-billing.d.ts +32 -0
- package/types/orechio-platform-angular.d.ts +8 -4
- package/fesm2022/orechio-platform-angular-account-forgot-password.page-5_8R5B4m.mjs.map +0 -1
- package/fesm2022/orechio-platform-angular-account-initial-branch.page-Cmy07JGF.mjs.map +0 -1
- package/fesm2022/orechio-platform-angular-account-resend-verification.page-qckKAlPk.mjs.map +0 -1
- package/fesm2022/orechio-platform-angular-account-token-password.page-AHqb8mFk.mjs.map +0 -1
- package/fesm2022/orechio-platform-angular-account-verify-email.page-CHs0EwDf.mjs.map +0 -1
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { inject, signal, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
|
+
import { NgTemplateOutlet } from '@angular/common';
|
|
4
|
+
import * as i1 from '@angular/forms';
|
|
5
|
+
import { FormsModule } from '@angular/forms';
|
|
6
|
+
import { Router, ActivatedRoute, RouterLink } from '@angular/router';
|
|
7
|
+
import { m as mascararCep, b as mascararTelefone, c as mascararDocumento, B as BillingClient, e as mascararCpf, f as mascararCnpj, s as soDigitos, a as BillingErrorComponent } from './orechio-platform-angular-billing-billing-format-DFY2U19Y.mjs';
|
|
8
|
+
|
|
9
|
+
function doPerfil(perfil) {
|
|
10
|
+
const tipo = perfil.documentType ?? 'Cnpj';
|
|
11
|
+
return {
|
|
12
|
+
documentType: tipo,
|
|
13
|
+
documentNumber: mascararDocumento(tipo, perfil.documentNumber ?? ''),
|
|
14
|
+
legalName: perfil.legalName ?? '',
|
|
15
|
+
tradeName: perfil.tradeName ?? '',
|
|
16
|
+
billingEmail: perfil.billingEmail ?? '',
|
|
17
|
+
phone: mascararTelefone(perfil.phone ?? ''),
|
|
18
|
+
mobilePhone: mascararTelefone(perfil.mobilePhone ?? ''),
|
|
19
|
+
postalCode: mascararCep(perfil.postalCode ?? ''),
|
|
20
|
+
street: perfil.street ?? '',
|
|
21
|
+
number: perfil.number ?? '',
|
|
22
|
+
complement: perfil.complement ?? '',
|
|
23
|
+
neighborhood: perfil.neighborhood ?? '',
|
|
24
|
+
city: perfil.city ?? '',
|
|
25
|
+
state: perfil.state ?? '',
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/** Campo opcional vazio vai como `null`, que é o que a Platform espera nos `string?`. */
|
|
29
|
+
function opcional(valor) {
|
|
30
|
+
const limpo = valor.trim();
|
|
31
|
+
return limpo ? limpo : null;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Perfil de cobrança (ADR-021 §3.5, item 2). Cria com `POST profile`; edita por partes, como a
|
|
35
|
+
* Platform: `PATCH profile/contact` e `PATCH profile/address` — não existe PUT.
|
|
36
|
+
*/
|
|
37
|
+
class ProfilePage {
|
|
38
|
+
client = inject(BillingClient);
|
|
39
|
+
router = inject(Router);
|
|
40
|
+
route = inject(ActivatedRoute);
|
|
41
|
+
form = doPerfil({});
|
|
42
|
+
perfil = signal(null, /* @ts-ignore */
|
|
43
|
+
...(ngDevMode ? [{ debugName: "perfil" }] : /* istanbul ignore next */ []));
|
|
44
|
+
travado = signal(false, /* @ts-ignore */
|
|
45
|
+
...(ngDevMode ? [{ debugName: "travado" }] : /* istanbul ignore next */ []));
|
|
46
|
+
enviando = signal(false, /* @ts-ignore */
|
|
47
|
+
...(ngDevMode ? [{ debugName: "enviando" }] : /* istanbul ignore next */ []));
|
|
48
|
+
salvo = signal(false, /* @ts-ignore */
|
|
49
|
+
...(ngDevMode ? [{ debugName: "salvo" }] : /* istanbul ignore next */ []));
|
|
50
|
+
erro = signal(null, /* @ts-ignore */
|
|
51
|
+
...(ngDevMode ? [{ debugName: "erro" }] : /* istanbul ignore next */ []));
|
|
52
|
+
ngOnInit() {
|
|
53
|
+
this.carregar();
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Máscara ao digitar: o campo é reescrito pela máscara e o formulário guarda o texto
|
|
57
|
+
* mascarado. Sem `ngModel` de propósito — com ele, digitar um caractere que a máscara
|
|
58
|
+
* descarta deixaria o valor do modelo igual ao anterior, e o campo continuaria mostrando
|
|
59
|
+
* o caractere digitado.
|
|
60
|
+
*/
|
|
61
|
+
mascarar(campo, evento) {
|
|
62
|
+
const entrada = evento.target;
|
|
63
|
+
const mascarado = this.mascara(campo)(entrada.value);
|
|
64
|
+
entrada.value = mascarado;
|
|
65
|
+
this.form[campo] = mascarado;
|
|
66
|
+
}
|
|
67
|
+
trocarTipo(tipo) {
|
|
68
|
+
this.form.documentType = tipo;
|
|
69
|
+
this.form.documentNumber = mascararDocumento(tipo, this.form.documentNumber);
|
|
70
|
+
}
|
|
71
|
+
mascara(campo) {
|
|
72
|
+
switch (campo) {
|
|
73
|
+
case 'documentNumber':
|
|
74
|
+
return this.form.documentType === 'Cpf' ? mascararCpf : mascararCnpj;
|
|
75
|
+
case 'postalCode':
|
|
76
|
+
return mascararCep;
|
|
77
|
+
default:
|
|
78
|
+
return mascararTelefone;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
criar() {
|
|
82
|
+
this.enviar(this.client.createProfile({ ...this.contato(), ...this.endereco() }), () => {
|
|
83
|
+
// Quem veio do pagamento volta para ele: foi o checkout que mandou para cá.
|
|
84
|
+
if (this.route.snapshot.queryParamMap.get('next') === 'checkout') {
|
|
85
|
+
void this.router.navigate(['../checkout'], { relativeTo: this.route });
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
this.carregar();
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
salvarContato() {
|
|
92
|
+
this.enviar(this.client.updateProfileContact(this.contato()), () => this.salvo.set(true));
|
|
93
|
+
}
|
|
94
|
+
salvarEndereco() {
|
|
95
|
+
this.enviar(this.client.updateProfileAddress(this.endereco()), () => this.salvo.set(true));
|
|
96
|
+
}
|
|
97
|
+
carregar() {
|
|
98
|
+
this.client.getProfile().subscribe({
|
|
99
|
+
next: (perfil) => {
|
|
100
|
+
this.form = doPerfil(perfil);
|
|
101
|
+
this.travado.set(perfil.isDocumentLocked === true);
|
|
102
|
+
this.perfil.set(perfil);
|
|
103
|
+
},
|
|
104
|
+
error: (problema) => this.erro.set(problema),
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
enviar(chamada, depois) {
|
|
108
|
+
if (this.enviando())
|
|
109
|
+
return;
|
|
110
|
+
this.enviando.set(true);
|
|
111
|
+
this.salvo.set(false);
|
|
112
|
+
this.erro.set(null);
|
|
113
|
+
chamada.subscribe({
|
|
114
|
+
next: () => {
|
|
115
|
+
this.enviando.set(false);
|
|
116
|
+
depois();
|
|
117
|
+
},
|
|
118
|
+
error: (problema) => {
|
|
119
|
+
this.enviando.set(false);
|
|
120
|
+
this.erro.set(problema);
|
|
121
|
+
},
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
contato() {
|
|
125
|
+
return {
|
|
126
|
+
documentType: this.form.documentType,
|
|
127
|
+
documentNumber: soDigitos(this.form.documentNumber),
|
|
128
|
+
legalName: this.form.legalName.trim(),
|
|
129
|
+
tradeName: opcional(this.form.tradeName),
|
|
130
|
+
billingEmail: this.form.billingEmail.trim(),
|
|
131
|
+
phone: opcional(soDigitos(this.form.phone)),
|
|
132
|
+
mobilePhone: opcional(soDigitos(this.form.mobilePhone)),
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
endereco() {
|
|
136
|
+
return {
|
|
137
|
+
postalCode: soDigitos(this.form.postalCode),
|
|
138
|
+
street: this.form.street.trim(),
|
|
139
|
+
number: this.form.number.trim(),
|
|
140
|
+
complement: opcional(this.form.complement),
|
|
141
|
+
neighborhood: this.form.neighborhood.trim(),
|
|
142
|
+
city: this.form.city.trim(),
|
|
143
|
+
state: this.form.state.trim().toUpperCase(),
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: ProfilePage, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
147
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.2", type: ProfilePage, isStandalone: true, selector: "orechio-billing-profile", ngImport: i0, template: `
|
|
148
|
+
<section class="orechio-billing">
|
|
149
|
+
<h1>Dados de cobrança</h1>
|
|
150
|
+
|
|
151
|
+
@if (perfil(); as p) {
|
|
152
|
+
@if (!p.exists) {
|
|
153
|
+
<p class="orechio-billing__muted">
|
|
154
|
+
Informe os dados que vão na cobrança. O CPF ou CNPJ é exigido pelo emissor do PIX.
|
|
155
|
+
</p>
|
|
156
|
+
<form data-criar (ngSubmit)="criar()">
|
|
157
|
+
<ng-container *ngTemplateOutlet="contato" />
|
|
158
|
+
<ng-container *ngTemplateOutlet="endereco" />
|
|
159
|
+
<button type="submit" [disabled]="enviando()">{{ enviando() ? 'Salvando…' : 'Salvar' }}</button>
|
|
160
|
+
</form>
|
|
161
|
+
} @else {
|
|
162
|
+
<form data-contato (ngSubmit)="salvarContato()">
|
|
163
|
+
<h2>Contato</h2>
|
|
164
|
+
<ng-container *ngTemplateOutlet="contato" />
|
|
165
|
+
<button type="submit" [disabled]="enviando()">Salvar contato</button>
|
|
166
|
+
</form>
|
|
167
|
+
|
|
168
|
+
<form data-endereco (ngSubmit)="salvarEndereco()">
|
|
169
|
+
<h2>Endereço</h2>
|
|
170
|
+
<ng-container *ngTemplateOutlet="endereco" />
|
|
171
|
+
<button type="submit" [disabled]="enviando()">Salvar endereço</button>
|
|
172
|
+
</form>
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
@if (salvo()) {
|
|
176
|
+
<p role="status">Dados salvos.</p>
|
|
177
|
+
}
|
|
178
|
+
<a routerLink="..">Voltar para a assinatura</a>
|
|
179
|
+
} @else if (!erro()) {
|
|
180
|
+
<p class="orechio-billing__muted">Carregando…</p>
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
@if (erro(); as problema) {
|
|
184
|
+
<orechio-billing-error [problema]="problema" />
|
|
185
|
+
}
|
|
186
|
+
</section>
|
|
187
|
+
|
|
188
|
+
<ng-template #contato>
|
|
189
|
+
<label>Tipo de documento
|
|
190
|
+
<select name="documentType" [ngModel]="form.documentType" (ngModelChange)="trocarTipo($event)" [disabled]="travado()">
|
|
191
|
+
<option value="Cpf">CPF</option>
|
|
192
|
+
<option value="Cnpj">CNPJ</option>
|
|
193
|
+
</select>
|
|
194
|
+
</label>
|
|
195
|
+
<label>{{ form.documentType === 'Cpf' ? 'CPF' : 'CNPJ' }}
|
|
196
|
+
<input name="documentNumber" inputmode="numeric" [value]="form.documentNumber" (input)="mascarar('documentNumber', $event)" [disabled]="travado()" required />
|
|
197
|
+
</label>
|
|
198
|
+
<label>{{ form.documentType === 'Cpf' ? 'Nome completo' : 'Razão social' }}
|
|
199
|
+
<input name="legalName" [(ngModel)]="form.legalName" [disabled]="travado()" required />
|
|
200
|
+
</label>
|
|
201
|
+
<label>Nome fantasia (opcional)
|
|
202
|
+
<input name="tradeName" [(ngModel)]="form.tradeName" />
|
|
203
|
+
</label>
|
|
204
|
+
<label>E-mail de cobrança
|
|
205
|
+
<input name="billingEmail" type="email" autocomplete="email" [(ngModel)]="form.billingEmail" required />
|
|
206
|
+
</label>
|
|
207
|
+
<label>Telefone (opcional)
|
|
208
|
+
<input name="phone" type="tel" [value]="form.phone" (input)="mascarar('phone', $event)" />
|
|
209
|
+
</label>
|
|
210
|
+
<label>Celular (opcional)
|
|
211
|
+
<input name="mobilePhone" type="tel" [value]="form.mobilePhone" (input)="mascarar('mobilePhone', $event)" />
|
|
212
|
+
</label>
|
|
213
|
+
</ng-template>
|
|
214
|
+
|
|
215
|
+
<ng-template #endereco>
|
|
216
|
+
<label>CEP <input name="postalCode" inputmode="numeric" autocomplete="postal-code" [value]="form.postalCode" (input)="mascarar('postalCode', $event)" required /></label>
|
|
217
|
+
<label>Rua <input name="street" autocomplete="address-line1" [(ngModel)]="form.street" required /></label>
|
|
218
|
+
<label>Número <input name="number" [(ngModel)]="form.number" required /></label>
|
|
219
|
+
<label>Complemento (opcional) <input name="complement" autocomplete="address-line2" [(ngModel)]="form.complement" /></label>
|
|
220
|
+
<label>Bairro <input name="neighborhood" [(ngModel)]="form.neighborhood" required /></label>
|
|
221
|
+
<label>Cidade <input name="city" autocomplete="address-level2" [(ngModel)]="form.city" required /></label>
|
|
222
|
+
<label>UF <input name="state" maxlength="2" autocomplete="address-level1" [(ngModel)]="form.state" required /></label>
|
|
223
|
+
</ng-template>
|
|
224
|
+
`, 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
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: ProfilePage, decorators: [{
|
|
227
|
+
type: Component,
|
|
228
|
+
args: [{ selector: 'orechio-billing-profile', standalone: true, imports: [FormsModule, NgTemplateOutlet, RouterLink, BillingErrorComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
229
|
+
<section class="orechio-billing">
|
|
230
|
+
<h1>Dados de cobrança</h1>
|
|
231
|
+
|
|
232
|
+
@if (perfil(); as p) {
|
|
233
|
+
@if (!p.exists) {
|
|
234
|
+
<p class="orechio-billing__muted">
|
|
235
|
+
Informe os dados que vão na cobrança. O CPF ou CNPJ é exigido pelo emissor do PIX.
|
|
236
|
+
</p>
|
|
237
|
+
<form data-criar (ngSubmit)="criar()">
|
|
238
|
+
<ng-container *ngTemplateOutlet="contato" />
|
|
239
|
+
<ng-container *ngTemplateOutlet="endereco" />
|
|
240
|
+
<button type="submit" [disabled]="enviando()">{{ enviando() ? 'Salvando…' : 'Salvar' }}</button>
|
|
241
|
+
</form>
|
|
242
|
+
} @else {
|
|
243
|
+
<form data-contato (ngSubmit)="salvarContato()">
|
|
244
|
+
<h2>Contato</h2>
|
|
245
|
+
<ng-container *ngTemplateOutlet="contato" />
|
|
246
|
+
<button type="submit" [disabled]="enviando()">Salvar contato</button>
|
|
247
|
+
</form>
|
|
248
|
+
|
|
249
|
+
<form data-endereco (ngSubmit)="salvarEndereco()">
|
|
250
|
+
<h2>Endereço</h2>
|
|
251
|
+
<ng-container *ngTemplateOutlet="endereco" />
|
|
252
|
+
<button type="submit" [disabled]="enviando()">Salvar endereço</button>
|
|
253
|
+
</form>
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
@if (salvo()) {
|
|
257
|
+
<p role="status">Dados salvos.</p>
|
|
258
|
+
}
|
|
259
|
+
<a routerLink="..">Voltar para a assinatura</a>
|
|
260
|
+
} @else if (!erro()) {
|
|
261
|
+
<p class="orechio-billing__muted">Carregando…</p>
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
@if (erro(); as problema) {
|
|
265
|
+
<orechio-billing-error [problema]="problema" />
|
|
266
|
+
}
|
|
267
|
+
</section>
|
|
268
|
+
|
|
269
|
+
<ng-template #contato>
|
|
270
|
+
<label>Tipo de documento
|
|
271
|
+
<select name="documentType" [ngModel]="form.documentType" (ngModelChange)="trocarTipo($event)" [disabled]="travado()">
|
|
272
|
+
<option value="Cpf">CPF</option>
|
|
273
|
+
<option value="Cnpj">CNPJ</option>
|
|
274
|
+
</select>
|
|
275
|
+
</label>
|
|
276
|
+
<label>{{ form.documentType === 'Cpf' ? 'CPF' : 'CNPJ' }}
|
|
277
|
+
<input name="documentNumber" inputmode="numeric" [value]="form.documentNumber" (input)="mascarar('documentNumber', $event)" [disabled]="travado()" required />
|
|
278
|
+
</label>
|
|
279
|
+
<label>{{ form.documentType === 'Cpf' ? 'Nome completo' : 'Razão social' }}
|
|
280
|
+
<input name="legalName" [(ngModel)]="form.legalName" [disabled]="travado()" required />
|
|
281
|
+
</label>
|
|
282
|
+
<label>Nome fantasia (opcional)
|
|
283
|
+
<input name="tradeName" [(ngModel)]="form.tradeName" />
|
|
284
|
+
</label>
|
|
285
|
+
<label>E-mail de cobrança
|
|
286
|
+
<input name="billingEmail" type="email" autocomplete="email" [(ngModel)]="form.billingEmail" required />
|
|
287
|
+
</label>
|
|
288
|
+
<label>Telefone (opcional)
|
|
289
|
+
<input name="phone" type="tel" [value]="form.phone" (input)="mascarar('phone', $event)" />
|
|
290
|
+
</label>
|
|
291
|
+
<label>Celular (opcional)
|
|
292
|
+
<input name="mobilePhone" type="tel" [value]="form.mobilePhone" (input)="mascarar('mobilePhone', $event)" />
|
|
293
|
+
</label>
|
|
294
|
+
</ng-template>
|
|
295
|
+
|
|
296
|
+
<ng-template #endereco>
|
|
297
|
+
<label>CEP <input name="postalCode" inputmode="numeric" autocomplete="postal-code" [value]="form.postalCode" (input)="mascarar('postalCode', $event)" required /></label>
|
|
298
|
+
<label>Rua <input name="street" autocomplete="address-line1" [(ngModel)]="form.street" required /></label>
|
|
299
|
+
<label>Número <input name="number" [(ngModel)]="form.number" required /></label>
|
|
300
|
+
<label>Complemento (opcional) <input name="complement" autocomplete="address-line2" [(ngModel)]="form.complement" /></label>
|
|
301
|
+
<label>Bairro <input name="neighborhood" [(ngModel)]="form.neighborhood" required /></label>
|
|
302
|
+
<label>Cidade <input name="city" autocomplete="address-level2" [(ngModel)]="form.city" required /></label>
|
|
303
|
+
<label>UF <input name="state" maxlength="2" autocomplete="address-level1" [(ngModel)]="form.state" required /></label>
|
|
304
|
+
</ng-template>
|
|
305
|
+
`, 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"] }]
|
|
306
|
+
}] });
|
|
307
|
+
|
|
308
|
+
export { ProfilePage };
|
|
309
|
+
//# sourceMappingURL=orechio-platform-angular-billing-profile.page-DHjsB3jJ.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orechio-platform-angular-billing-profile.page-DHjsB3jJ.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":"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"}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { inject, signal, computed, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
|
+
import { RouterLink } from '@angular/router';
|
|
4
|
+
import { d as data, B as BillingClient, a as BillingErrorComponent } from './orechio-platform-angular-billing-billing-format-DFY2U19Y.mjs';
|
|
5
|
+
|
|
6
|
+
const DIA = 24 * 60 * 60 * 1000;
|
|
7
|
+
const EM_ABERTO = ['Created', 'Pending', 'Overdue'];
|
|
8
|
+
const emAtraso = (assinatura) => assinatura.status === 'Grace' || assinatura.status === 'Suspended';
|
|
9
|
+
/**
|
|
10
|
+
* A ação de cada estado segue o que a Platform aceita: o checkout serve `Trial`,
|
|
11
|
+
* `PendingPayment` e, desde a BILLING-2b, `Grace` e `Suspended` — mas só sem fatura aberta
|
|
12
|
+
* (`Created|Pending|Overdue`; com ela, `checkout.open_invoice_exists`). Em carência e suspensão
|
|
13
|
+
* a ação depende disso: fatura aberta → o detalhe dela; nenhuma → o checkout. Cancelada e
|
|
14
|
+
* expirada não têm ação de pagamento nesta versão: reativar é v2 (ADR-021 §3.5).
|
|
15
|
+
*/
|
|
16
|
+
function situacao(assinatura, agora, emAberto) {
|
|
17
|
+
const pagar = { texto: 'Pagar agora', link: 'checkout' };
|
|
18
|
+
const faturas = { texto: 'Ver faturas', link: 'invoices' };
|
|
19
|
+
const acaoDeAtraso = emAberto
|
|
20
|
+
? { texto: 'Pagar fatura em aberto', link: `invoices/${emAberto.id}` }
|
|
21
|
+
: { texto: 'Pagar', link: 'checkout' };
|
|
22
|
+
const orientacao = emAberto ? 'Pague a fatura em aberto' : 'Faça o pagamento';
|
|
23
|
+
switch (assinatura.status) {
|
|
24
|
+
case 'Trial': {
|
|
25
|
+
const dias = Math.max(0, Math.ceil((Date.parse(assinatura.trialEndsAt) - agora) / DIA));
|
|
26
|
+
const restante = dias === 0 ? 'O período de teste termina hoje.'
|
|
27
|
+
: dias === 1 ? 'Falta 1 dia para o fim do período de teste.'
|
|
28
|
+
: `Faltam ${dias} dias para o fim do período de teste.`;
|
|
29
|
+
return { titulo: 'Período de teste', detalhe: restante, acao: { texto: 'Assinar agora', link: 'checkout' } };
|
|
30
|
+
}
|
|
31
|
+
case 'PendingPayment':
|
|
32
|
+
return {
|
|
33
|
+
titulo: 'Pagamento pendente',
|
|
34
|
+
detalhe: 'A assinatura começa assim que o primeiro pagamento for confirmado.',
|
|
35
|
+
acao: pagar,
|
|
36
|
+
};
|
|
37
|
+
case 'Active':
|
|
38
|
+
return {
|
|
39
|
+
titulo: 'Assinatura ativa',
|
|
40
|
+
detalhe: assinatura.currentPeriodEndsAt
|
|
41
|
+
? `Próxima renovação em ${data(assinatura.currentPeriodEndsAt)}.`
|
|
42
|
+
: 'Tudo em dia.',
|
|
43
|
+
acao: faturas,
|
|
44
|
+
};
|
|
45
|
+
case 'Grace':
|
|
46
|
+
return {
|
|
47
|
+
titulo: 'Pagamento em atraso',
|
|
48
|
+
detalhe: assinatura.graceEndsAt
|
|
49
|
+
? `O acesso continua até ${data(assinatura.graceEndsAt)}. ${orientacao} para não ter o acesso suspenso.`
|
|
50
|
+
: `${orientacao} para não ter o acesso suspenso.`,
|
|
51
|
+
acao: acaoDeAtraso,
|
|
52
|
+
};
|
|
53
|
+
case 'Suspended':
|
|
54
|
+
return {
|
|
55
|
+
titulo: 'Assinatura suspensa',
|
|
56
|
+
detalhe: `O acesso foi suspenso por falta de pagamento. ${orientacao} para voltar a usar.`,
|
|
57
|
+
acao: acaoDeAtraso,
|
|
58
|
+
};
|
|
59
|
+
case 'Cancelled':
|
|
60
|
+
return {
|
|
61
|
+
titulo: 'Assinatura cancelada',
|
|
62
|
+
detalhe: assinatura.cancelEffectiveAt
|
|
63
|
+
? `O cancelamento vale a partir de ${data(assinatura.cancelEffectiveAt)}. Para reativar, fale com o suporte.`
|
|
64
|
+
: 'Para reativar, fale com o suporte.',
|
|
65
|
+
acao: faturas,
|
|
66
|
+
};
|
|
67
|
+
case 'Expired':
|
|
68
|
+
return {
|
|
69
|
+
titulo: 'Assinatura expirada',
|
|
70
|
+
detalhe: 'Para voltar a assinar, fale com o suporte.',
|
|
71
|
+
acao: faturas,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
class SubscriptionPage {
|
|
76
|
+
client = inject(BillingClient);
|
|
77
|
+
assinatura = signal(null, /* @ts-ignore */
|
|
78
|
+
...(ngDevMode ? [{ debugName: "assinatura" }] : /* istanbul ignore next */ []));
|
|
79
|
+
/** Só preenchido em Grace/Suspended: `undefined` = ainda não respondeu; `null` = nenhuma aberta. */
|
|
80
|
+
emAberto = signal(undefined, /* @ts-ignore */
|
|
81
|
+
...(ngDevMode ? [{ debugName: "emAberto" }] : /* istanbul ignore next */ []));
|
|
82
|
+
erro = signal(null, /* @ts-ignore */
|
|
83
|
+
...(ngDevMode ? [{ debugName: "erro" }] : /* istanbul ignore next */ []));
|
|
84
|
+
atual = computed(() => {
|
|
85
|
+
const assinatura = this.assinatura();
|
|
86
|
+
if (!assinatura)
|
|
87
|
+
return null;
|
|
88
|
+
const aberta = this.emAberto();
|
|
89
|
+
// Sem a resposta das faturas não se sabe o destino da ação: não se adivinha.
|
|
90
|
+
if (emAtraso(assinatura) && aberta === undefined)
|
|
91
|
+
return null;
|
|
92
|
+
return situacao(assinatura, Date.now(), aberta ?? null);
|
|
93
|
+
}, /* @ts-ignore */
|
|
94
|
+
...(ngDevMode ? [{ debugName: "atual" }] : /* istanbul ignore next */ []));
|
|
95
|
+
ngOnInit() {
|
|
96
|
+
this.client.getSubscription().subscribe({
|
|
97
|
+
next: (assinatura) => {
|
|
98
|
+
this.assinatura.set(assinatura);
|
|
99
|
+
if (emAtraso(assinatura))
|
|
100
|
+
this.buscarFaturaEmAberto();
|
|
101
|
+
},
|
|
102
|
+
error: (problema) => this.erro.set(problema),
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
buscarFaturaEmAberto() {
|
|
106
|
+
this.client.listInvoices().subscribe({
|
|
107
|
+
next: (pagina) => this.emAberto.set(pagina.invoices.find((f) => EM_ABERTO.includes(f.status)) ?? null),
|
|
108
|
+
error: (problema) => this.erro.set(problema),
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: SubscriptionPage, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
112
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.2", type: SubscriptionPage, isStandalone: true, selector: "orechio-billing-subscription", ngImport: i0, template: `
|
|
113
|
+
<section class="orechio-billing">
|
|
114
|
+
<h1>Assinatura</h1>
|
|
115
|
+
|
|
116
|
+
@if (erro(); as problema) {
|
|
117
|
+
<orechio-billing-error [problema]="problema" />
|
|
118
|
+
} @else if (atual(); as s) {
|
|
119
|
+
<h2>{{ s.titulo }}</h2>
|
|
120
|
+
<p>{{ s.detalhe }}</p>
|
|
121
|
+
<a data-acao class="orechio-billing__acao" [routerLink]="s.acao.link">{{ s.acao.texto }}</a>
|
|
122
|
+
|
|
123
|
+
<nav class="orechio-billing__muted">
|
|
124
|
+
<a routerLink="profile">Dados de cobrança</a>
|
|
125
|
+
·
|
|
126
|
+
<a routerLink="invoices">Faturas</a>
|
|
127
|
+
</nav>
|
|
128
|
+
} @else {
|
|
129
|
+
<p class="orechio-billing__muted">Carregando…</p>
|
|
130
|
+
}
|
|
131
|
+
</section>
|
|
132
|
+
`, 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: "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 });
|
|
133
|
+
}
|
|
134
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: SubscriptionPage, decorators: [{
|
|
135
|
+
type: Component,
|
|
136
|
+
args: [{ selector: 'orechio-billing-subscription', standalone: true, imports: [RouterLink, BillingErrorComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
137
|
+
<section class="orechio-billing">
|
|
138
|
+
<h1>Assinatura</h1>
|
|
139
|
+
|
|
140
|
+
@if (erro(); as problema) {
|
|
141
|
+
<orechio-billing-error [problema]="problema" />
|
|
142
|
+
} @else if (atual(); as s) {
|
|
143
|
+
<h2>{{ s.titulo }}</h2>
|
|
144
|
+
<p>{{ s.detalhe }}</p>
|
|
145
|
+
<a data-acao class="orechio-billing__acao" [routerLink]="s.acao.link">{{ s.acao.texto }}</a>
|
|
146
|
+
|
|
147
|
+
<nav class="orechio-billing__muted">
|
|
148
|
+
<a routerLink="profile">Dados de cobrança</a>
|
|
149
|
+
·
|
|
150
|
+
<a routerLink="invoices">Faturas</a>
|
|
151
|
+
</nav>
|
|
152
|
+
} @else {
|
|
153
|
+
<p class="orechio-billing__muted">Carregando…</p>
|
|
154
|
+
}
|
|
155
|
+
</section>
|
|
156
|
+
`, 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"] }]
|
|
157
|
+
}] });
|
|
158
|
+
|
|
159
|
+
export { SubscriptionPage };
|
|
160
|
+
//# sourceMappingURL=orechio-platform-angular-billing-subscription.page-Cotupt22.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orechio-platform-angular-billing-subscription.page-Cotupt22.mjs","sources":["../../../projects/platform-angular/billing/src/pages/subscription.page.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, OnInit, computed, inject, signal } from '@angular/core';\r\nimport { RouterLink } from '@angular/router';\r\nimport { ProblemDetails } from '@orechio/platform-angular';\r\nimport { BillingClient } from '../billing-client';\r\nimport { BillingErrorComponent } from '../billing-error.component';\r\nimport { ESTILO_BASE, data } from '../billing-format';\r\nimport { InvoiceListItem, InvoiceStatus, Subscription } from '../billing-models';\r\n\r\nconst DIA = 24 * 60 * 60 * 1000;\r\nconst EM_ABERTO: InvoiceStatus[] = ['Created', 'Pending', 'Overdue'];\r\n\r\nconst emAtraso = (assinatura: Subscription) =>\r\n assinatura.status === 'Grace' || assinatura.status === 'Suspended';\r\n\r\ninterface Situacao {\r\n titulo: string;\r\n detalhe: string;\r\n acao: { texto: string; link: string };\r\n}\r\n\r\n/**\r\n * A ação de cada estado segue o que a Platform aceita: o checkout serve `Trial`,\r\n * `PendingPayment` e, desde a BILLING-2b, `Grace` e `Suspended` — mas só sem fatura aberta\r\n * (`Created|Pending|Overdue`; com ela, `checkout.open_invoice_exists`). Em carência e suspensão\r\n * a ação depende disso: fatura aberta → o detalhe dela; nenhuma → o checkout. Cancelada e\r\n * expirada não têm ação de pagamento nesta versão: reativar é v2 (ADR-021 §3.5).\r\n */\r\nfunction situacao(assinatura: Subscription, agora: number, emAberto: InvoiceListItem | null): Situacao {\r\n const pagar = { texto: 'Pagar agora', link: 'checkout' };\r\n const faturas = { texto: 'Ver faturas', link: 'invoices' };\r\n const acaoDeAtraso = emAberto\r\n ? { texto: 'Pagar fatura em aberto', link: `invoices/${emAberto.id}` }\r\n : { texto: 'Pagar', link: 'checkout' };\r\n const orientacao = emAberto ? 'Pague a fatura em aberto' : 'Faça o pagamento';\r\n\r\n switch (assinatura.status) {\r\n case 'Trial': {\r\n const dias = Math.max(0, Math.ceil((Date.parse(assinatura.trialEndsAt) - agora) / DIA));\r\n const restante =\r\n dias === 0 ? 'O período de teste termina hoje.'\r\n : dias === 1 ? 'Falta 1 dia para o fim do período de teste.'\r\n : `Faltam ${dias} dias para o fim do período de teste.`;\r\n return { titulo: 'Período de teste', detalhe: restante, acao: { texto: 'Assinar agora', link: 'checkout' } };\r\n }\r\n case 'PendingPayment':\r\n return {\r\n titulo: 'Pagamento pendente',\r\n detalhe: 'A assinatura começa assim que o primeiro pagamento for confirmado.',\r\n acao: pagar,\r\n };\r\n case 'Active':\r\n return {\r\n titulo: 'Assinatura ativa',\r\n detalhe: assinatura.currentPeriodEndsAt\r\n ? `Próxima renovação em ${data(assinatura.currentPeriodEndsAt)}.`\r\n : 'Tudo em dia.',\r\n acao: faturas,\r\n };\r\n case 'Grace':\r\n return {\r\n titulo: 'Pagamento em atraso',\r\n detalhe: assinatura.graceEndsAt\r\n ? `O acesso continua até ${data(assinatura.graceEndsAt)}. ${orientacao} para não ter o acesso suspenso.`\r\n : `${orientacao} para não ter o acesso suspenso.`,\r\n acao: acaoDeAtraso,\r\n };\r\n case 'Suspended':\r\n return {\r\n titulo: 'Assinatura suspensa',\r\n detalhe: `O acesso foi suspenso por falta de pagamento. ${orientacao} para voltar a usar.`,\r\n acao: acaoDeAtraso,\r\n };\r\n case 'Cancelled':\r\n return {\r\n titulo: 'Assinatura cancelada',\r\n detalhe: assinatura.cancelEffectiveAt\r\n ? `O cancelamento vale a partir de ${data(assinatura.cancelEffectiveAt)}. Para reativar, fale com o suporte.`\r\n : 'Para reativar, fale com o suporte.',\r\n acao: faturas,\r\n };\r\n case 'Expired':\r\n return {\r\n titulo: 'Assinatura expirada',\r\n detalhe: 'Para voltar a assinar, fale com o suporte.',\r\n acao: faturas,\r\n };\r\n }\r\n}\r\n\r\n@Component({\r\n selector: 'orechio-billing-subscription',\r\n standalone: true,\r\n imports: [RouterLink, BillingErrorComponent],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n template: `\r\n <section class=\"orechio-billing\">\r\n <h1>Assinatura</h1>\r\n\r\n @if (erro(); as problema) {\r\n <orechio-billing-error [problema]=\"problema\" />\r\n } @else if (atual(); as s) {\r\n <h2>{{ s.titulo }}</h2>\r\n <p>{{ s.detalhe }}</p>\r\n <a data-acao class=\"orechio-billing__acao\" [routerLink]=\"s.acao.link\">{{ s.acao.texto }}</a>\r\n\r\n <nav class=\"orechio-billing__muted\">\r\n <a routerLink=\"profile\">Dados de cobrança</a>\r\n ·\r\n <a routerLink=\"invoices\">Faturas</a>\r\n </nav>\r\n } @else {\r\n <p class=\"orechio-billing__muted\">Carregando…</p>\r\n }\r\n </section>\r\n `,\r\n styles: ESTILO_BASE,\r\n})\r\nexport class SubscriptionPage implements OnInit {\r\n private readonly client = inject(BillingClient);\r\n\r\n private readonly assinatura = signal<Subscription | null>(null);\r\n /** Só preenchido em Grace/Suspended: `undefined` = ainda não respondeu; `null` = nenhuma aberta. */\r\n private readonly emAberto = signal<InvoiceListItem | null | undefined>(undefined);\r\n protected readonly erro = signal<ProblemDetails | null>(null);\r\n protected readonly atual = computed(() => {\r\n const assinatura = this.assinatura();\r\n if (!assinatura) return null;\r\n\r\n const aberta = this.emAberto();\r\n // Sem a resposta das faturas não se sabe o destino da ação: não se adivinha.\r\n if (emAtraso(assinatura) && aberta === undefined) return null;\r\n\r\n return situacao(assinatura, Date.now(), aberta ?? null);\r\n });\r\n\r\n ngOnInit(): void {\r\n this.client.getSubscription().subscribe({\r\n next: (assinatura) => {\r\n this.assinatura.set(assinatura);\r\n if (emAtraso(assinatura)) this.buscarFaturaEmAberto();\r\n },\r\n error: (problema: ProblemDetails) => this.erro.set(problema),\r\n });\r\n }\r\n\r\n private buscarFaturaEmAberto(): void {\r\n this.client.listInvoices().subscribe({\r\n next: (pagina) => this.emAberto.set(pagina.invoices.find((f) => EM_ABERTO.includes(f.status)) ?? null),\r\n error: (problema: ProblemDetails) => this.erro.set(problema),\r\n });\r\n }\r\n}\r\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { InjectionToken } from '@angular/core';
|
|
2
|
+
|
|
3
|
+
const ORECHIO_BILLING_CONFIG = new InjectionToken('ORECHIO_BILLING_CONFIG');
|
|
4
|
+
function provideOrechioBilling(options = {}) {
|
|
5
|
+
const bruto = options.basePath ?? '/api/billing';
|
|
6
|
+
// Mesma regra do `BillingRoutePrefix` do BFF, no mesmo momento: na composição. Uma URL
|
|
7
|
+
// absoluta aqui levaria a cobrança para fora do domínio do produto, onde o cookie de sessão
|
|
8
|
+
// não vai junto.
|
|
9
|
+
if (!bruto.startsWith('/') || bruto.startsWith('//')) {
|
|
10
|
+
throw new Error(`provideOrechioBilling: \`basePath\` precisa ser um caminho same-origin começando com '/': '${bruto}'.`);
|
|
11
|
+
}
|
|
12
|
+
const config = { basePath: bruto.replace(/\/+$/, '') };
|
|
13
|
+
return [{ provide: ORECHIO_BILLING_CONFIG, useValue: config }];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* As rotas de cobrança. O host as monta em `/billing` — é para lá que os e-mails de cobrança
|
|
18
|
+
* da Platform apontam (`{base}/billing`, ADR-021 §3.2):
|
|
19
|
+
*
|
|
20
|
+
* <pre>
|
|
21
|
+
* { path: 'billing', children: ORECHIO_BILLING_ROUTES }
|
|
22
|
+
* </pre>
|
|
23
|
+
*
|
|
24
|
+
* Os caminhos ENTRE as telas são fixos (a situação leva a `checkout` e `invoices`, o
|
|
25
|
+
* pagamento sem perfil leva a `profile`). Todas com `loadComponent`, como as de conta.
|
|
26
|
+
*/
|
|
27
|
+
const ORECHIO_BILLING_ROUTES = [
|
|
28
|
+
{
|
|
29
|
+
path: '',
|
|
30
|
+
pathMatch: 'full',
|
|
31
|
+
title: 'Assinatura',
|
|
32
|
+
loadComponent: () => import('./orechio-platform-angular-billing-subscription.page-Cotupt22.mjs').then((m) => m.SubscriptionPage),
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
path: 'profile',
|
|
36
|
+
title: 'Dados de cobrança',
|
|
37
|
+
loadComponent: () => import('./orechio-platform-angular-billing-profile.page-DHjsB3jJ.mjs').then((m) => m.ProfilePage),
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
path: 'checkout',
|
|
41
|
+
title: 'Pagar assinatura',
|
|
42
|
+
loadComponent: () => import('./orechio-platform-angular-billing-checkout.page-CNl0PPiE.mjs').then((m) => m.CheckoutPage),
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
path: 'invoices',
|
|
46
|
+
title: 'Faturas',
|
|
47
|
+
loadComponent: () => import('./orechio-platform-angular-billing-invoices.page-COsCT5NY.mjs').then((m) => m.InvoicesPage),
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
path: 'invoices/:id',
|
|
51
|
+
title: 'Fatura',
|
|
52
|
+
loadComponent: () => import('./orechio-platform-angular-billing-invoice.page-CLojIJkf.mjs').then((m) => m.InvoicePage),
|
|
53
|
+
},
|
|
54
|
+
];
|
|
55
|
+
|
|
56
|
+
/*
|
|
57
|
+
* Public API Surface of @orechio/platform-angular/billing
|
|
58
|
+
*
|
|
59
|
+
* BILLING-3 — as telas de cobrança do titular (ADR-021 §3.5). Mesmo contrato do entry
|
|
60
|
+
* `account`: `BillingClient` e as páginas NÃO são exportados. As telas são alcançadas por
|
|
61
|
+
* `ORECHIO_BILLING_ROUTES`, e os caminhos entre elas só valem montados juntos.
|
|
62
|
+
*/
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Generated bundle index. Do not edit.
|
|
66
|
+
*/
|
|
67
|
+
|
|
68
|
+
export { ORECHIO_BILLING_CONFIG, ORECHIO_BILLING_ROUTES, provideOrechioBilling };
|
|
69
|
+
//# sourceMappingURL=orechio-platform-angular-billing.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orechio-platform-angular-billing.mjs","sources":["../../../projects/platform-angular/billing/src/billing-config.ts","../../../projects/platform-angular/billing/src/billing.routes.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}\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}\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 config: OrechioBillingConfig = { basePath: bruto.replace(/\\/+$/, '') };\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","/*\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","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;MAUa,sBAAsB,GAAG,IAAI,cAAc,CACtD,wBAAwB;AAQpB,SAAU,qBAAqB,CAAC,OAAA,GAAiC,EAAE,EAAA;AACvE,IAAA,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,IAAI,cAAc;;;;AAKhD,IAAA,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE;AACpD,QAAA,MAAM,IAAI,KAAK,CACb,8FAA8F,KAAK,CAAA,EAAA,CAAI,CACxG;IACH;AAEA,IAAA,MAAM,MAAM,GAAyB,EAAE,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE;IAC5E,OAAO,CAAC,EAAE,OAAO,EAAE,sBAAsB,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;AAChE;;AC/BA;;;;;;;;;;AAUG;AACI,MAAM,sBAAsB,GAAW;AAC5C,IAAA;AACE,QAAA,IAAI,EAAE,EAAE;AACR,QAAA,SAAS,EAAE,MAAM;AACjB,QAAA,KAAK,EAAE,YAAY;AACnB,QAAA,aAAa,EAAE,MAAM,OAAO,mEAA2B,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,gBAAgB,CAAC;AACzF,KAAA;AACD,IAAA;AACE,QAAA,IAAI,EAAE,SAAS;AACf,QAAA,KAAK,EAAE,mBAAmB;AAC1B,QAAA,aAAa,EAAE,MAAM,OAAO,8DAAsB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC;AAC/E,KAAA;AACD,IAAA;AACE,QAAA,IAAI,EAAE,UAAU;AAChB,QAAA,KAAK,EAAE,kBAAkB;AACzB,QAAA,aAAa,EAAE,MAAM,OAAO,+DAAuB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC;AACjF,KAAA;AACD,IAAA;AACE,QAAA,IAAI,EAAE,UAAU;AAChB,QAAA,KAAK,EAAE,SAAS;AAChB,QAAA,aAAa,EAAE,MAAM,OAAO,+DAAuB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC;AACjF,KAAA;AACD,IAAA;AACE,QAAA,IAAI,EAAE,cAAc;AACpB,QAAA,KAAK,EAAE,QAAQ;AACf,QAAA,aAAa,EAAE,MAAM,OAAO,8DAAsB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC;AAC/E,KAAA;;;ACvCH;;;;;;AAMG;;ACNH;;AAEG;;;;"}
|