@orechio/platform-angular 0.9.0 → 0.10.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 +6 -0
- package/fesm2022/{orechio-platform-angular-billing-billing-format-CuDtE7fj.mjs → orechio-platform-angular-billing-billing-format-CN53uJAG.mjs} +4 -1
- package/fesm2022/orechio-platform-angular-billing-billing-format-CN53uJAG.mjs.map +1 -0
- package/fesm2022/{orechio-platform-angular-billing-checkout.page-BhUYGMkL.mjs → orechio-platform-angular-billing-checkout.page-Q1Toeh07.mjs} +25 -9
- package/fesm2022/orechio-platform-angular-billing-checkout.page-Q1Toeh07.mjs.map +1 -0
- package/fesm2022/{orechio-platform-angular-billing-invoice.page-CELLNkLd.mjs → orechio-platform-angular-billing-invoice.page-nURMELXG.mjs} +4 -4
- package/fesm2022/{orechio-platform-angular-billing-invoice.page-CELLNkLd.mjs.map → orechio-platform-angular-billing-invoice.page-nURMELXG.mjs.map} +1 -1
- package/fesm2022/{orechio-platform-angular-billing-invoices.page-CfWDUFv6.mjs → orechio-platform-angular-billing-invoices.page-BtVgaP_j.mjs} +3 -3
- package/fesm2022/{orechio-platform-angular-billing-invoices.page-CfWDUFv6.mjs.map → orechio-platform-angular-billing-invoices.page-BtVgaP_j.mjs.map} +1 -1
- package/fesm2022/{orechio-platform-angular-billing-orechio-platform-angular-billing-C8Q1JSAC.mjs → orechio-platform-angular-billing-orechio-platform-angular-billing-CkUiNOLp.mjs} +6 -6
- package/fesm2022/{orechio-platform-angular-billing-orechio-platform-angular-billing-C8Q1JSAC.mjs.map → orechio-platform-angular-billing-orechio-platform-angular-billing-CkUiNOLp.mjs.map} +1 -1
- package/fesm2022/{orechio-platform-angular-billing-pix-panel.component-BiNCJuB_.mjs → orechio-platform-angular-billing-pix-panel.component-CxJl6ahY.mjs} +2 -2
- package/fesm2022/{orechio-platform-angular-billing-pix-panel.component-BiNCJuB_.mjs.map → orechio-platform-angular-billing-pix-panel.component-CxJl6ahY.mjs.map} +1 -1
- package/fesm2022/{orechio-platform-angular-billing-profile.page-DufY3HDA.mjs → orechio-platform-angular-billing-profile.page-CrYtBaOi.mjs} +3 -3
- package/fesm2022/{orechio-platform-angular-billing-profile.page-DufY3HDA.mjs.map → orechio-platform-angular-billing-profile.page-CrYtBaOi.mjs.map} +1 -1
- package/fesm2022/{orechio-platform-angular-billing-subscription.page-Bi6w7yq_.mjs → orechio-platform-angular-billing-subscription.page-Cp4Hz_ta.mjs} +15 -11
- package/fesm2022/orechio-platform-angular-billing-subscription.page-Cp4Hz_ta.mjs.map +1 -0
- package/fesm2022/orechio-platform-angular-billing.mjs +1 -1
- package/package.json +1 -1
- package/fesm2022/orechio-platform-angular-billing-billing-format-CuDtE7fj.mjs.map +0 -1
- package/fesm2022/orechio-platform-angular-billing-checkout.page-BhUYGMkL.mjs.map +0 -1
- package/fesm2022/orechio-platform-angular-billing-subscription.page-Bi6w7yq_.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -90,6 +90,12 @@ provideHttpClient(withInterceptors([subscriptionAccessInterceptor])); // renov
|
|
|
90
90
|
provideOrechioBilling({ uiRoute: '/billing' }); // default
|
|
91
91
|
```
|
|
92
92
|
|
|
93
|
+
#### Reativar a assinatura expirada (0.10.0)
|
|
94
|
+
|
|
95
|
+
Com a REACT-1 da Platform, a expirada paga pelo checkout e volta ao plano vigente. A tela da
|
|
96
|
+
assinatura mostra "Reativar assinatura" (ou "Pagar fatura em aberto", se houver uma), e o checkout
|
|
97
|
+
avisa quando o plano vigente não é o da assinatura. Cancelada continua sem reativação.
|
|
98
|
+
|
|
93
99
|
## Code scaffolding
|
|
94
100
|
|
|
95
101
|
Angular CLI includes powerful code scaffolding tools. To generate a new component, run:
|
|
@@ -5,6 +5,7 @@ const ENDERECO_INCOMPLETO = 'Preencha o endereço completo.';
|
|
|
5
5
|
const DOCUMENTO_INVALIDO = 'CPF ou CNPJ inválido.';
|
|
6
6
|
const DOCUMENTO_TRAVADO = 'O documento e o nome já foram usados em uma cobrança e não podem mais ser alterados.';
|
|
7
7
|
const PLANO_INDISPONIVEL = 'O plano da assinatura não está disponível. Fale com o suporte.';
|
|
8
|
+
const PLANO_MAX_FILIAIS = 'O plano vigente não comporta o número de filiais da conta. Fale com o suporte.';
|
|
8
9
|
const SO_O_TITULAR = 'Só o titular da conta pode ver e pagar a cobrança.';
|
|
9
10
|
/**
|
|
10
11
|
* Os codes que as rotas de cobrança da Platform e do BFF emitem de fato
|
|
@@ -47,6 +48,8 @@ const MENSAGENS = {
|
|
|
47
48
|
'plan.not_found': PLANO_INDISPONIVEL,
|
|
48
49
|
'plan.not_available': PLANO_INDISPONIVEL,
|
|
49
50
|
'subscription.plan_inactive': PLANO_INDISPONIVEL,
|
|
51
|
+
'subscription.no_current_plan': PLANO_INDISPONIVEL,
|
|
52
|
+
'subscription.plan_max_branches_exceeded': PLANO_MAX_FILIAIS,
|
|
50
53
|
'invoice.not_found': 'Fatura não encontrada.',
|
|
51
54
|
'invoice.payment_unavailable': 'Esta cobrança não está mais disponível para pagamento. Fale com o suporte.',
|
|
52
55
|
'invoice.refresh_not_allowed': 'Esta fatura não está mais em aberto.',
|
|
@@ -248,4 +251,4 @@ const ESTILO_BASE = `
|
|
|
248
251
|
`;
|
|
249
252
|
|
|
250
253
|
export { BillingErrorComponent as B, STATUS_DA_FATURA as S, mascararTelefone as a, mascararDocumento as b, mascararCpf as c, data as d, mascararCnpj as e, moeda as f, dataDoVencimento as g, mascararCep as m, soDigitos as s, validadeDoPix as v };
|
|
251
|
-
//# sourceMappingURL=orechio-platform-angular-billing-billing-format-
|
|
254
|
+
//# sourceMappingURL=orechio-platform-angular-billing-billing-format-CN53uJAG.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orechio-platform-angular-billing-billing-format-CN53uJAG.mjs","sources":["../../../projects/platform-angular/billing/src/billing-errors.ts","../../../projects/platform-angular/billing/src/billing-error.component.ts","../../../projects/platform-angular/billing/src/billing-format.ts"],"sourcesContent":["import { ProblemDetails } from '@orechio/platform-angular';\r\n\r\nexport interface MensagemDeErro {\r\n texto: string;\r\n /** Só para code desconhecido: é o que o suporte cruza com o log dos dois lados. */\r\n correlationId?: string;\r\n}\r\n\r\nconst ENDERECO_INCOMPLETO = 'Preencha o endereço completo.';\r\nconst DOCUMENTO_INVALIDO = 'CPF ou CNPJ inválido.';\r\nconst DOCUMENTO_TRAVADO =\r\n 'O documento e o nome já foram usados em uma cobrança e não podem mais ser alterados.';\r\nconst PLANO_INDISPONIVEL = 'O plano da assinatura não está disponível. Fale com o suporte.';\r\nconst PLANO_MAX_FILIAIS =\r\n 'O plano vigente não comporta o número de filiais da conta. Fale com o suporte.';\r\nconst SO_O_TITULAR = 'Só o titular da conta pode ver e pagar a cobrança.';\r\n\r\n/**\r\n * Os codes que as rotas de cobrança da Platform e do BFF emitem de fato\r\n * (`Commerce*Endpoints`, handlers de `Billing/`, value objects de perfil,\r\n * `PermissionAuthorization`, `Bff.Account`).\r\n */\r\nconst MENSAGENS: Record<string, string> = {\r\n 'session.missing': 'Sua sessão expirou. Entre novamente para continuar.',\r\n 'platform.unavailable':\r\n 'O serviço de cobrança está indisponível no momento. Tente novamente em instantes.',\r\n 'http.0': 'Sem conexão com o servidor. Verifique sua internet e tente novamente.',\r\n rate_limit_exceeded: 'Muitas tentativas. Aguarde alguns minutos e tente novamente.',\r\n\r\n 'access.platform_only': SO_O_TITULAR,\r\n 'permission.denied': SO_O_TITULAR,\r\n\r\n 'subscription.not_found': 'Nenhuma assinatura encontrada para esta conta.',\r\n\r\n 'billing_profile.not_found': 'Cadastre os dados de cobrança antes de pagar.',\r\n 'billing_profile.already_exists': 'Os dados de cobrança já estão cadastrados.',\r\n 'billing_profile.legal_name_required': 'Informe o nome completo ou a razão social.',\r\n 'billing_profile.billing_email_required': 'Informe o e-mail de cobrança.',\r\n 'billing_profile.billing_email_invalid': 'Informe um e-mail de cobrança válido.',\r\n 'billing_profile.mobile_phone_too_long': 'O celular informado é longo demais.',\r\n 'billing_profile.document_type_locked': DOCUMENTO_TRAVADO,\r\n 'billing_profile.document_number_locked': DOCUMENTO_TRAVADO,\r\n 'billing_profile.legal_name_locked': DOCUMENTO_TRAVADO,\r\n 'tax_document.value_required': 'Informe o CPF ou o CNPJ.',\r\n 'tax_document.length_invalid': DOCUMENTO_INVALIDO,\r\n 'tax_document.checksum_invalid': DOCUMENTO_INVALIDO,\r\n 'address.postal_code_invalid': 'CEP inválido.',\r\n 'address.state_invalid': 'UF inválida. Use a sigla do estado, como SP.',\r\n 'address.street_required': ENDERECO_INCOMPLETO,\r\n 'address.number_required': ENDERECO_INCOMPLETO,\r\n 'address.neighborhood_required': ENDERECO_INCOMPLETO,\r\n 'address.city_required': ENDERECO_INCOMPLETO,\r\n\r\n 'checkout.subscription_not_eligible':\r\n 'Não há pagamento de assinatura a fazer agora. Veja as faturas em aberto.',\r\n 'checkout.open_invoice_exists':\r\n 'Já existe uma fatura em aberto. Pague a fatura em aberto em vez de gerar uma nova cobrança.',\r\n 'checkout.pending_other_method':\r\n 'Já existe uma cobrança em aberto por outro meio de pagamento. Veja as faturas.',\r\n 'checkout.credit_card_not_supported': 'Pagamento por cartão ainda não está disponível.',\r\n 'checkout.invoice_in_inconsistent_state':\r\n 'A cobrança anterior ficou incompleta. Tente novamente em alguns minutos.',\r\n 'billing.cycle_invalid': 'Escolha um ciclo de cobrança válido.',\r\n 'pricing_preview.cycle_invalid': 'Escolha um ciclo de cobrança válido.',\r\n 'plan.not_found': PLANO_INDISPONIVEL,\r\n 'plan.not_available': PLANO_INDISPONIVEL,\r\n 'subscription.plan_inactive': PLANO_INDISPONIVEL,\r\n 'subscription.no_current_plan': PLANO_INDISPONIVEL,\r\n 'subscription.plan_max_branches_exceeded': PLANO_MAX_FILIAIS,\r\n\r\n 'invoice.not_found': 'Fatura não encontrada.',\r\n 'invoice.payment_unavailable':\r\n 'Esta cobrança não está mais disponível para pagamento. Fale com o suporte.',\r\n 'invoice.refresh_not_allowed': 'Esta fatura não está mais em aberto.',\r\n 'invoice.refresh_pix_only': 'Só é possível gerar QR para faturas PIX.',\r\n 'invoice.no_external_payment':\r\n 'Esta fatura ainda não tem cobrança gerada. Tente novamente em alguns minutos.',\r\n};\r\n\r\nconst GENERICA =\r\n 'Não foi possível concluir a operação. Tente novamente; se continuar, informe o código de atendimento ao suporte.';\r\n\r\n/**\r\n * O texto de tela para um erro do BFF, escolhido por `code`. O corpo do erro (`message`) nunca\r\n * vira texto: ele é escrito para log, não para o cliente.\r\n */\r\nexport function mensagemDeErro(problema: ProblemDetails): MensagemDeErro {\r\n const conhecida = MENSAGENS[problema.code];\r\n if (conhecida) return { texto: conhecida };\r\n\r\n return problema.correlationId\r\n ? { texto: GENERICA, correlationId: problema.correlationId }\r\n : { texto: GENERICA };\r\n}\r\n","import { ChangeDetectionStrategy, Component, computed, input } from '@angular/core';\r\nimport { ProblemDetails } from '@orechio/platform-angular';\r\nimport { mensagemDeErro } from './billing-errors';\r\n\r\n@Component({\r\n selector: 'orechio-billing-error',\r\n standalone: true,\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n template: `\r\n <div class=\"orechio-billing__error\" role=\"alert\">\r\n <p>{{ mensagem().texto }}</p>\r\n @if (mensagem().correlationId; as id) {\r\n <p>Código de atendimento: <code>{{ id }}</code></p>\r\n }\r\n </div>\r\n `,\r\n styles: `.orechio-billing__error { color: var(--orechio-color-danger, #b00020); }`,\r\n})\r\nexport class BillingErrorComponent {\r\n readonly problema = input.required<ProblemDetails>();\r\n protected readonly mensagem = computed(() => mensagemDeErro(this.problema()));\r\n}\r\n","import { InvoiceStatus } from './billing-models';\r\n\r\nconst MOEDA = new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL' });\r\n\r\nexport function moeda(valor: number): string {\r\n return MOEDA.format(valor);\r\n}\r\n\r\nexport function data(iso: string | null | undefined): string {\r\n return iso ? new Date(iso).toLocaleDateString('pt-BR') : '';\r\n}\r\n\r\n/**\r\n * O vencimento para a tela: \"02/10/2026\". É uma DATA, sem hora: a Platform a manda como meia-noite\r\n * UTC (\"2026-10-02T00:00:00Z\") ou \"2026-10-02\", e passar por `new Date()` a deslocaria para o dia\r\n * anterior no fuso do navegador (Manaus, Brasília). Lê os 10 primeiros caracteres AAAA-MM-DD e\r\n * formata por PARTES DO TEXTO. Formato inesperado volta como veio.\r\n */\r\nexport function dataDoVencimento(valor: string): string {\r\n const partes = /^(\\d{4})-(\\d{2})-(\\d{2})(?![\\d])/.exec(valor.trim());\r\n if (!partes) return valor;\r\n const [, ano, mes, dia] = partes;\r\n return `${dia}/${mes}/${ano}`;\r\n}\r\n\r\nconst FUSO_DE_BRASILIA = 'America/Sao_Paulo';\r\nconst SUFIXO_DE_BRASILIA = '(horário de Brasília)';\r\n\r\n/** \"AAAA-MM-DD HH:mm[:ss]\" — o `expirationDate` do ASAAS: sem fuso, já em horário de Brasília. */\r\nconst SEM_FUSO = /^(\\d{4})-(\\d{2})-(\\d{2})[ T](\\d{2}):(\\d{2})(?::(\\d{2})(?:\\.\\d+)?)?$/;\r\n/** O mesmo, com fuso explícito: `Z` ou `±hh:mm` / `±hhmm`. */\r\nconst COM_FUSO = /^\\d{4}-\\d{2}-\\d{2}[ T]\\d{2}:\\d{2}(?::\\d{2}(?:\\.\\d+)?)?(?:Z|[+-]\\d{2}:?\\d{2})$/i;\r\n\r\n/**\r\n * A validade do PIX para a tela: \"02/10/2026 às 23:59 (horário de Brasília)\".\r\n *\r\n * O valor do ASAAS NÃO passa por `new Date()`: sem fuso, o construtor o leria no fuso do\r\n * navegador e a hora exibida se deslocaria. Ele é formatado por PARTES DO TEXTO. Só o valor\r\n * com fuso explícito é convertido (para America/Sao_Paulo). Formato não reconhecido volta como\r\n * veio — nunca \"Invalid Date\".\r\n */\r\nexport function validadeDoPix(valor: string): string {\r\n const texto = valor.trim();\r\n\r\n const semFuso = SEM_FUSO.exec(texto);\r\n if (semFuso) {\r\n const [, ano, mes, dia, hora, minuto] = semFuso;\r\n return dataValida(+ano, +mes, +dia, +hora, +minuto)\r\n ? `${dia}/${mes}/${ano} às ${hora}:${minuto} ${SUFIXO_DE_BRASILIA}`\r\n : valor;\r\n }\r\n\r\n if (COM_FUSO.test(texto)) {\r\n const instante = new Date(texto.replace(' ', 'T'));\r\n if (Number.isNaN(instante.getTime())) return valor;\r\n\r\n const partes = Object.fromEntries(\r\n new Intl.DateTimeFormat('pt-BR', {\r\n timeZone: FUSO_DE_BRASILIA,\r\n day: '2-digit',\r\n month: '2-digit',\r\n year: 'numeric',\r\n hour: '2-digit',\r\n minute: '2-digit',\r\n hourCycle: 'h23',\r\n })\r\n .formatToParts(instante)\r\n .map((parte) => [parte.type, parte.value]),\r\n );\r\n return `${partes['day']}/${partes['month']}/${partes['year']} às ${partes['hour']}:${partes['minute']} ${SUFIXO_DE_BRASILIA}`;\r\n }\r\n\r\n return valor;\r\n}\r\n\r\nfunction dataValida(ano: number, mes: number, dia: number, hora: number, minuto: number): boolean {\r\n if (mes < 1 || mes > 12 || hora > 23 || minuto > 59 || dia < 1) return false;\r\n return dia <= new Date(Date.UTC(ano, mes, 0)).getUTCDate();\r\n}\r\n\r\n// ── máscaras (perfil de cobrança) ────────────────────────────────────────────\r\n\r\nexport function soDigitos(valor: string): string {\r\n return valor.replace(/\\D/g, '');\r\n}\r\n\r\n/** Junta os grupos de dígitos com os separadores, parando no primeiro grupo vazio. */\r\nfunction agrupar(digitos: string, grupos: readonly number[], separadores: readonly string[]): string {\r\n let saida = '';\r\n let posicao = 0;\r\n for (let i = 0; i < grupos.length; i++) {\r\n const grupo = digitos.slice(posicao, posicao + grupos[i]);\r\n if (!grupo) break;\r\n saida += (i === 0 ? '' : separadores[i - 1]) + grupo;\r\n posicao += grupos[i];\r\n }\r\n return saida;\r\n}\r\n\r\n/** CPF `000.000.000-00`, progressivo enquanto se digita. */\r\nexport function mascararCpf(valor: string): string {\r\n return agrupar(soDigitos(valor).slice(0, 11), [3, 3, 3, 2], ['.', '.', '-']);\r\n}\r\n\r\n/** CNPJ `00.000.000/0000-00`, progressivo enquanto se digita. */\r\nexport function mascararCnpj(valor: string): string {\r\n return agrupar(soDigitos(valor).slice(0, 14), [2, 3, 3, 4, 2], ['.', '.', '/', '-']);\r\n}\r\n\r\n/** O documento conforme o tipo escolhido. */\r\nexport function mascararDocumento(tipo: 'Cpf' | 'Cnpj', valor: string): string {\r\n return tipo === 'Cpf' ? mascararCpf(valor) : mascararCnpj(valor);\r\n}\r\n\r\n/** CEP `00000-000`. */\r\nexport function mascararCep(valor: string): string {\r\n return agrupar(soDigitos(valor).slice(0, 8), [5, 3], ['-']);\r\n}\r\n\r\n/** Telefone `(00) 0000-0000` (10 dígitos) ou celular `(00) 00000-0000` (11). */\r\nexport function mascararTelefone(valor: string): string {\r\n const digitos = soDigitos(valor).slice(0, 11);\r\n if (!digitos) return '';\r\n\r\n const ddd = digitos.slice(0, 2);\r\n if (digitos.length <= 2) return `(${ddd}`;\r\n\r\n const numero = digitos.slice(2);\r\n const tamanhoDoPrimeiroBloco = digitos.length > 10 ? 5 : 4;\r\n const corpo =\r\n numero.length > tamanhoDoPrimeiroBloco\r\n ? `${numero.slice(0, tamanhoDoPrimeiroBloco)}-${numero.slice(tamanhoDoPrimeiroBloco)}`\r\n : numero;\r\n return `(${ddd}) ${corpo}`;\r\n}\r\n\r\nexport const STATUS_DA_FATURA: Record<InvoiceStatus, string> = {\r\n Created: 'Em emissão',\r\n Pending: 'Em aberto',\r\n Paid: 'Paga',\r\n Overdue: 'Vencida',\r\n Refunded: 'Estornada',\r\n Cancelled: 'Cancelada',\r\n};\r\n\r\nexport const ESTILO_BASE = `\r\n .orechio-billing {\r\n display: flex;\r\n flex-direction: column;\r\n gap: var(--orechio-space-3, 0.75rem);\r\n max-width: 40rem;\r\n margin: 0 auto;\r\n padding: var(--orechio-space-6, 1.5rem);\r\n color: var(--orechio-color-text, inherit);\r\n font-family: var(--orechio-font-body, inherit);\r\n }\r\n .orechio-billing form { display: flex; flex-direction: column; gap: var(--orechio-space-2, 0.5rem); }\r\n .orechio-billing__muted { color: var(--orechio-color-text-muted, #666); }\r\n .orechio-billing__error { color: var(--orechio-color-danger, #b00020); }\r\n .orechio-billing__acao {\r\n align-self: flex-start;\r\n display: inline-block;\r\n padding: var(--orechio-space-2, 0.5rem) var(--orechio-space-4, 1rem);\r\n border-radius: var(--orechio-radius, 0.375rem);\r\n background: var(--orechio-color-primary, #1a56db);\r\n color: var(--orechio-color-on-primary, #fff);\r\n font-weight: 600;\r\n text-decoration: none;\r\n }\r\n .orechio-billing__acao:hover,\r\n .orechio-billing__acao:focus-visible {\r\n background: var(--orechio-color-primary-hover, var(--orechio-color-primary, #1446b0));\r\n }\r\n`;\r\n"],"names":[],"mappings":"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"}
|
|
@@ -2,11 +2,11 @@ import * as i0 from '@angular/core';
|
|
|
2
2
|
import { inject, signal, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
3
|
import { Router, ActivatedRoute, RouterLink } from '@angular/router';
|
|
4
4
|
import { forkJoin } from 'rxjs';
|
|
5
|
-
import { B as BillingClient } from './orechio-platform-angular-billing-orechio-platform-angular-billing-
|
|
6
|
-
import { f as moeda, B as BillingErrorComponent } from './orechio-platform-angular-billing-billing-format-
|
|
7
|
-
import { P as PixPanelComponent } from './orechio-platform-angular-billing-pix-panel.component-
|
|
5
|
+
import { B as BillingClient } from './orechio-platform-angular-billing-orechio-platform-angular-billing-CkUiNOLp.mjs';
|
|
6
|
+
import { f as moeda, B as BillingErrorComponent } from './orechio-platform-angular-billing-billing-format-CN53uJAG.mjs';
|
|
7
|
+
import { P as PixPanelComponent } from './orechio-platform-angular-billing-pix-panel.component-CxJl6ahY.mjs';
|
|
8
8
|
|
|
9
|
-
const STATUS_COM_CHECKOUT = ['Trial', 'PendingPayment', 'Grace', 'Suspended'];
|
|
9
|
+
const STATUS_COM_CHECKOUT = ['Trial', 'PendingPayment', 'Grace', 'Suspended', 'Expired'];
|
|
10
10
|
const CICLOS = [
|
|
11
11
|
{ valor: 'Monthly', rotulo: 'Mensal' },
|
|
12
12
|
{ valor: 'Yearly', rotulo: 'Anual' },
|
|
@@ -24,6 +24,9 @@ class CheckoutPage {
|
|
|
24
24
|
...(ngDevMode ? [{ debugName: "previas" }] : /* istanbul ignore next */ []));
|
|
25
25
|
ciclo = signal('Monthly', /* @ts-ignore */
|
|
26
26
|
...(ngDevMode ? [{ debugName: "ciclo" }] : /* istanbul ignore next */ []));
|
|
27
|
+
/** Só em Expired: o preview devolve o plano vigente, que pode não ser o da assinatura. */
|
|
28
|
+
planoMudou = signal(false, /* @ts-ignore */
|
|
29
|
+
...(ngDevMode ? [{ debugName: "planoMudou" }] : /* istanbul ignore next */ []));
|
|
27
30
|
inelegivel = signal(false, /* @ts-ignore */
|
|
28
31
|
...(ngDevMode ? [{ debugName: "inelegivel" }] : /* istanbul ignore next */ []));
|
|
29
32
|
enviando = signal(false, /* @ts-ignore */
|
|
@@ -44,8 +47,8 @@ class CheckoutPage {
|
|
|
44
47
|
ngOnInit() {
|
|
45
48
|
forkJoin({ assinatura: this.client.getSubscription(), perfil: this.client.getProfile() }).subscribe({
|
|
46
49
|
next: ({ assinatura, perfil }) => {
|
|
47
|
-
// O checkout serve Trial, PendingPayment, Grace e
|
|
48
|
-
// passo 4; os
|
|
50
|
+
// O checkout serve Trial, PendingPayment, Grace, Suspended e Expired (`InitiateCheckoutCommand`,
|
|
51
|
+
// passo 4; os três últimos só sem fatura aberta — ver `pagar`).
|
|
49
52
|
// Checado antes do perfil: não se pede cadastro para um pagamento que não existe.
|
|
50
53
|
if (!STATUS_COM_CHECKOUT.includes(assinatura.status)) {
|
|
51
54
|
this.inelegivel.set(true);
|
|
@@ -84,7 +87,7 @@ class CheckoutPage {
|
|
|
84
87
|
},
|
|
85
88
|
error: (problema) => {
|
|
86
89
|
this.enviando.set(false);
|
|
87
|
-
// Em Grace/Suspended com fatura aberta a Platform recusa: a aberta é a que se paga.
|
|
90
|
+
// Em Grace/Suspended/Expired com fatura aberta a Platform recusa: a aberta é a que se paga.
|
|
88
91
|
if (problema.code === 'checkout.open_invoice_exists') {
|
|
89
92
|
void this.router.navigate(['../invoices'], { relativeTo: this.route });
|
|
90
93
|
return;
|
|
@@ -95,7 +98,10 @@ class CheckoutPage {
|
|
|
95
98
|
}
|
|
96
99
|
carregarPrecos(assinatura) {
|
|
97
100
|
forkJoin(CICLOS.map(({ valor }) => this.client.previewPricing(assinatura.planId, assinatura.branchCountSnapshot, valor))).subscribe({
|
|
98
|
-
next: (previas) =>
|
|
101
|
+
next: (previas) => {
|
|
102
|
+
this.planoMudou.set(assinatura.status === 'Expired' && previas[0].planId !== assinatura.planId);
|
|
103
|
+
this.previas.set(previas);
|
|
104
|
+
},
|
|
99
105
|
error: (problema) => this.erro.set(problema),
|
|
100
106
|
});
|
|
101
107
|
}
|
|
@@ -113,6 +119,11 @@ class CheckoutPage {
|
|
|
113
119
|
<a routerLink="../invoices">Ver faturas</a>
|
|
114
120
|
} @else if (previas().length) {
|
|
115
121
|
<h2>{{ previas()[0].planName }}</h2>
|
|
122
|
+
@if (planoMudou()) {
|
|
123
|
+
<p data-plano-vigente>
|
|
124
|
+
Os planos mudaram enquanto a assinatura estava expirada. Este é o plano vigente.
|
|
125
|
+
</p>
|
|
126
|
+
}
|
|
116
127
|
|
|
117
128
|
<fieldset>
|
|
118
129
|
<legend>Ciclo de cobrança</legend>
|
|
@@ -158,6 +169,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.3", ngImpor
|
|
|
158
169
|
<a routerLink="../invoices">Ver faturas</a>
|
|
159
170
|
} @else if (previas().length) {
|
|
160
171
|
<h2>{{ previas()[0].planName }}</h2>
|
|
172
|
+
@if (planoMudou()) {
|
|
173
|
+
<p data-plano-vigente>
|
|
174
|
+
Os planos mudaram enquanto a assinatura estava expirada. Este é o plano vigente.
|
|
175
|
+
</p>
|
|
176
|
+
}
|
|
161
177
|
|
|
162
178
|
<fieldset>
|
|
163
179
|
<legend>Ciclo de cobrança</legend>
|
|
@@ -190,4 +206,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.3", ngImpor
|
|
|
190
206
|
}] });
|
|
191
207
|
|
|
192
208
|
export { CheckoutPage };
|
|
193
|
-
//# sourceMappingURL=orechio-platform-angular-billing-checkout.page-
|
|
209
|
+
//# sourceMappingURL=orechio-platform-angular-billing-checkout.page-Q1Toeh07.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orechio-platform-angular-billing-checkout.page-Q1Toeh07.mjs","sources":["../../../projects/platform-angular/billing/src/pages/checkout.page.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, OnInit, inject, signal } from '@angular/core';\r\nimport { ActivatedRoute, Router, RouterLink } from '@angular/router';\r\nimport { forkJoin } from 'rxjs';\r\nimport { ProblemDetails } from '@orechio/platform-angular';\r\nimport { BillingClient } from '../billing-client';\r\nimport { BillingErrorComponent } from '../billing-error.component';\r\nimport { ESTILO_BASE, moeda } from '../billing-format';\r\nimport { BillingCycle, PixData, PricingPreview, Subscription, SubscriptionStatus } from '../billing-models';\r\nimport { PixPanelComponent } from '../pix-panel.component';\r\n\r\nconst STATUS_COM_CHECKOUT: SubscriptionStatus[] = ['Trial', 'PendingPayment', 'Grace', 'Suspended', 'Expired'];\r\n\r\nconst CICLOS: { valor: BillingCycle; rotulo: string }[] = [\r\n { valor: 'Monthly', rotulo: 'Mensal' },\r\n { valor: 'Yearly', rotulo: 'Anual' },\r\n];\r\n\r\n/**\r\n * Pagar a assinatura (ADR-021 §3.5, item 3): o plano ATUAL — trocar de plano é v2 —, o preço\r\n * de cada ciclo vindo de `pricing/preview`, e o checkout PIX.\r\n */\r\n@Component({\r\n selector: 'orechio-billing-checkout',\r\n standalone: true,\r\n imports: [RouterLink, BillingErrorComponent, PixPanelComponent],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n template: `\r\n <section class=\"orechio-billing\">\r\n <h1>Pagar assinatura</h1>\r\n\r\n @if (pix(); as dados) {\r\n <p>Pague o PIX abaixo. A assinatura é atualizada assim que o pagamento for confirmado.</p>\r\n <orechio-billing-pix [pix]=\"dados\" [invoiceUrl]=\"invoiceUrl()\" [valor]=\"valor()\" [vencimento]=\"vencimento()\" />\r\n <a routerLink=\"..\">Voltar para a assinatura</a>\r\n } @else if (inelegivel()) {\r\n <p>Não há pagamento de assinatura a fazer agora.</p>\r\n <a routerLink=\"../invoices\">Ver faturas</a>\r\n } @else if (previas().length) {\r\n <h2>{{ previas()[0].planName }}</h2>\r\n @if (planoMudou()) {\r\n <p data-plano-vigente>\r\n Os planos mudaram enquanto a assinatura estava expirada. Este é o plano vigente.\r\n </p>\r\n }\r\n\r\n <fieldset>\r\n <legend>Ciclo de cobrança</legend>\r\n @for (previa of previas(); track previa.cycle) {\r\n <label>\r\n <input\r\n type=\"radio\"\r\n name=\"ciclo\"\r\n [value]=\"previa.cycle\"\r\n [checked]=\"ciclo() === previa.cycle\"\r\n (change)=\"ciclo.set(previa.cycle)\"\r\n />\r\n {{ rotulo(previa.cycle) }} — {{ moeda(previa.total) }}\r\n </label>\r\n }\r\n </fieldset>\r\n\r\n <button type=\"button\" data-gerar-pix (click)=\"pagar()\" [disabled]=\"enviando()\">\r\n {{ enviando() ? 'Gerando PIX…' : 'Gerar PIX' }}\r\n </button>\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 styles: ESTILO_BASE,\r\n})\r\nexport class CheckoutPage 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 readonly moeda = moeda;\r\n protected readonly previas = signal<PricingPreview[]>([]);\r\n protected readonly ciclo = signal<BillingCycle>('Monthly');\r\n /** Só em Expired: o preview devolve o plano vigente, que pode não ser o da assinatura. */\r\n protected readonly planoMudou = signal(false);\r\n protected readonly inelegivel = signal(false);\r\n protected readonly enviando = signal(false);\r\n protected readonly pix = signal<PixData | null>(null);\r\n protected readonly invoiceUrl = signal<string | null>(null);\r\n protected readonly valor = signal<number | null>(null);\r\n protected readonly vencimento = signal<string | null>(null);\r\n protected readonly erro = signal<ProblemDetails | null>(null);\r\n\r\n protected rotulo(ciclo: BillingCycle): string {\r\n return CICLOS.find((c) => c.valor === ciclo)?.rotulo ?? ciclo;\r\n }\r\n\r\n ngOnInit(): void {\r\n forkJoin({ assinatura: this.client.getSubscription(), perfil: this.client.getProfile() }).subscribe({\r\n next: ({ assinatura, perfil }) => {\r\n // O checkout serve Trial, PendingPayment, Grace, Suspended e Expired (`InitiateCheckoutCommand`,\r\n // passo 4; os três últimos só sem fatura aberta — ver `pagar`).\r\n // Checado antes do perfil: não se pede cadastro para um pagamento que não existe.\r\n if (!STATUS_COM_CHECKOUT.includes(assinatura.status)) {\r\n this.inelegivel.set(true);\r\n return;\r\n }\r\n\r\n // O checkout recusa sem perfil (`billing_profile.not_found`). Mandar para o perfil\r\n // ANTES poupa o cliente de escolher o ciclo para receber um erro.\r\n if (!perfil.exists || !perfil.isComplete) {\r\n void this.router.navigate(['../profile'], {\r\n relativeTo: this.route,\r\n queryParams: { next: 'checkout' },\r\n });\r\n return;\r\n }\r\n\r\n this.ciclo.set(assinatura.cycle);\r\n this.carregarPrecos(assinatura);\r\n },\r\n error: (problema: ProblemDetails) => this.erro.set(problema),\r\n });\r\n }\r\n\r\n protected pagar(): void {\r\n if (this.enviando()) return;\r\n this.enviando.set(true);\r\n this.erro.set(null);\r\n\r\n this.client.checkout(this.ciclo()).subscribe({\r\n next: (resultado) => {\r\n this.enviando.set(false);\r\n this.invoiceUrl.set(resultado.invoiceUrl ?? null);\r\n this.valor.set(resultado.amount);\r\n this.vencimento.set(resultado.dueDate);\r\n if (resultado.pix) this.pix.set(resultado.pix);\r\n else this.erro.set({ code: 'checkout.pix_missing', status: 200 });\r\n },\r\n error: (problema: ProblemDetails) => {\r\n this.enviando.set(false);\r\n // Em Grace/Suspended/Expired com fatura aberta a Platform recusa: a aberta é a que se paga.\r\n if (problema.code === 'checkout.open_invoice_exists') {\r\n void this.router.navigate(['../invoices'], { relativeTo: this.route });\r\n return;\r\n }\r\n this.erro.set(problema);\r\n },\r\n });\r\n }\r\n\r\n private carregarPrecos(assinatura: Subscription): void {\r\n forkJoin(\r\n CICLOS.map(({ valor }) =>\r\n this.client.previewPricing(assinatura.planId, assinatura.branchCountSnapshot, valor),\r\n ),\r\n ).subscribe({\r\n next: (previas) => {\r\n this.planoMudou.set(assinatura.status === 'Expired' && previas[0].planId !== assinatura.planId);\r\n this.previas.set(previas);\r\n },\r\n error: (problema: ProblemDetails) => this.erro.set(problema),\r\n });\r\n }\r\n}\r\n"],"names":[],"mappings":"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"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { inject, signal, computed, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
3
|
import { ActivatedRoute, RouterLink } from '@angular/router';
|
|
4
|
-
import { B as BillingClient } from './orechio-platform-angular-billing-orechio-platform-angular-billing-
|
|
5
|
-
import { S as STATUS_DA_FATURA, f as moeda, d as data, g as dataDoVencimento, B as BillingErrorComponent } from './orechio-platform-angular-billing-billing-format-
|
|
6
|
-
import { P as PixPanelComponent } from './orechio-platform-angular-billing-pix-panel.component-
|
|
4
|
+
import { B as BillingClient } from './orechio-platform-angular-billing-orechio-platform-angular-billing-CkUiNOLp.mjs';
|
|
5
|
+
import { S as STATUS_DA_FATURA, f as moeda, d as data, g as dataDoVencimento, B as BillingErrorComponent } from './orechio-platform-angular-billing-billing-format-CN53uJAG.mjs';
|
|
6
|
+
import { P as PixPanelComponent } from './orechio-platform-angular-billing-pix-panel.component-CxJl6ahY.mjs';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Detalhe de fatura. O detalhe da Platform não traz dado de pagamento (`InvoiceDetailDto`):
|
|
@@ -135,4 +135,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.3", ngImpor
|
|
|
135
135
|
}] });
|
|
136
136
|
|
|
137
137
|
export { InvoicePage };
|
|
138
|
-
//# sourceMappingURL=orechio-platform-angular-billing-invoice.page-
|
|
138
|
+
//# sourceMappingURL=orechio-platform-angular-billing-invoice.page-nURMELXG.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"orechio-platform-angular-billing-invoice.page-
|
|
1
|
+
{"version":3,"file":"orechio-platform-angular-billing-invoice.page-nURMELXG.mjs","sources":["../../../projects/platform-angular/billing/src/pages/invoice.page.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, OnInit, computed, inject, signal } from '@angular/core';\r\nimport { ActivatedRoute, 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, STATUS_DA_FATURA, data, dataDoVencimento, moeda } from '../billing-format';\r\nimport { InvoiceDetail, PixData } from '../billing-models';\r\nimport { PixPanelComponent } from '../pix-panel.component';\r\n\r\n/**\r\n * Detalhe de fatura. O detalhe da Platform não traz dado de pagamento (`InvoiceDetailDto`):\r\n * o QR vem do refresh, que a Platform aceita para fatura PIX `Pending` ou `Overdue`\r\n * (`RefreshPaymentDataCommand`, passo 2) — o que inclui a fatura de renovação.\r\n */\r\n@Component({\r\n selector: 'orechio-billing-invoice',\r\n standalone: true,\r\n imports: [RouterLink, BillingErrorComponent, PixPanelComponent],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n template: `\r\n <section class=\"orechio-billing\">\r\n @if (fatura(); as f) {\r\n <h1>Fatura {{ f.number }}</h1>\r\n <p>{{ status[f.status] }} — {{ moeda(f.amount) }} — vence em {{ dataDoVencimento(f.dueDate) }}</p>\r\n <p class=\"orechio-billing__muted\">\r\n {{ f.planNameAtTime }}, de {{ data(f.periodStartsAt) }} a {{ data(f.periodEndsAt) }}\r\n </p>\r\n\r\n <ul>\r\n @for (item of f.items; track item.order) {\r\n <li>{{ item.description }} — {{ item.quantity }} × {{ moeda(item.unitAmount) }} = {{ moeda(item.totalAmount) }}</li>\r\n }\r\n </ul>\r\n\r\n @if (podeGerarQr()) {\r\n <button type=\"button\" data-gerar-qr (click)=\"gerarQr()\" [disabled]=\"gerando()\">\r\n {{ gerando() ? 'Gerando…' : 'Gerar novo QR' }}\r\n </button>\r\n }\r\n\r\n @if (pix(); as dados) {\r\n <orechio-billing-pix [pix]=\"dados\" [invoiceUrl]=\"invoiceUrl()\" [valor]=\"f.amount\" [vencimento]=\"f.dueDate\" />\r\n }\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\r\n <a routerLink=\"..\">Voltar para as faturas</a>\r\n </section>\r\n `,\r\n styles: ESTILO_BASE,\r\n})\r\nexport class InvoicePage implements OnInit {\r\n private readonly client = inject(BillingClient);\r\n private readonly route = inject(ActivatedRoute);\r\n\r\n protected readonly status = STATUS_DA_FATURA;\r\n protected readonly moeda = moeda;\r\n protected readonly data = data;\r\n protected readonly dataDoVencimento = dataDoVencimento;\r\n protected readonly fatura = signal<InvoiceDetail | null>(null);\r\n protected readonly pix = signal<PixData | null>(null);\r\n protected readonly invoiceUrl = signal<string | null>(null);\r\n protected readonly gerando = signal(false);\r\n protected readonly erro = signal<ProblemDetails | null>(null);\r\n protected readonly podeGerarQr = computed(() => {\r\n const f = this.fatura();\r\n return !!f && f.paymentMethod === 'Pix' && (f.status === 'Pending' || f.status === 'Overdue');\r\n });\r\n\r\n ngOnInit(): void {\r\n const id = this.route.snapshot.paramMap.get('id') ?? '';\r\n this.client.getInvoice(id).subscribe({\r\n next: (fatura) => this.fatura.set(fatura),\r\n error: (problema: ProblemDetails) => this.erro.set(problema),\r\n });\r\n }\r\n\r\n protected gerarQr(): void {\r\n const f = this.fatura();\r\n if (!f || this.gerando()) return;\r\n\r\n this.gerando.set(true);\r\n this.erro.set(null);\r\n this.client.refreshInvoicePix(f.id).subscribe({\r\n next: (pix) => {\r\n this.gerando.set(false);\r\n // O refresh traz o PIX e o `invoiceUrl` juntos: o link acompanha o QR que está na tela.\r\n this.invoiceUrl.set(pix.invoiceUrl ?? null);\r\n this.pix.set(pix);\r\n },\r\n error: (problema: ProblemDetails) => {\r\n this.gerando.set(false);\r\n this.erro.set(problema);\r\n },\r\n });\r\n }\r\n}\r\n"],"names":[],"mappings":"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"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { inject, signal, computed, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
3
|
import { RouterLink } from '@angular/router';
|
|
4
|
-
import { B as BillingClient } from './orechio-platform-angular-billing-orechio-platform-angular-billing-
|
|
5
|
-
import { S as STATUS_DA_FATURA, f as moeda, d as data, g as dataDoVencimento, B as BillingErrorComponent } from './orechio-platform-angular-billing-billing-format-
|
|
4
|
+
import { B as BillingClient } from './orechio-platform-angular-billing-orechio-platform-angular-billing-CkUiNOLp.mjs';
|
|
5
|
+
import { S as STATUS_DA_FATURA, f as moeda, d as data, g as dataDoVencimento, B as BillingErrorComponent } from './orechio-platform-angular-billing-billing-format-CN53uJAG.mjs';
|
|
6
6
|
|
|
7
7
|
const TAMANHO_DA_PAGINA = 20;
|
|
8
8
|
class InvoicesPage {
|
|
@@ -104,4 +104,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.3", ngImpor
|
|
|
104
104
|
}] });
|
|
105
105
|
|
|
106
106
|
export { InvoicesPage };
|
|
107
|
-
//# sourceMappingURL=orechio-platform-angular-billing-invoices.page-
|
|
107
|
+
//# sourceMappingURL=orechio-platform-angular-billing-invoices.page-BtVgaP_j.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"orechio-platform-angular-billing-invoices.page-
|
|
1
|
+
{"version":3,"file":"orechio-platform-angular-billing-invoices.page-BtVgaP_j.mjs","sources":["../../../projects/platform-angular/billing/src/pages/invoices.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, STATUS_DA_FATURA, data, dataDoVencimento, moeda } from '../billing-format';\r\nimport { InvoicesPage as PaginaDeFaturas } from '../billing-models';\r\n\r\nconst TAMANHO_DA_PAGINA = 20;\r\n\r\n@Component({\r\n selector: 'orechio-billing-invoices',\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>Faturas</h1>\r\n\r\n @if (erro(); as problema) {\r\n <orechio-billing-error [problema]=\"problema\" />\r\n } @else if (pagina(); as p) {\r\n @if (p.invoices.length === 0) {\r\n <p class=\"orechio-billing__muted\">Nenhuma fatura ainda.</p>\r\n } @else {\r\n <ul>\r\n @for (fatura of p.invoices; track fatura.id) {\r\n <li>\r\n <a [routerLink]=\"fatura.id\">Fatura {{ fatura.number }}</a>\r\n — {{ status[fatura.status] }} — {{ moeda(fatura.amount) }} — vence em {{ dataDoVencimento(fatura.dueDate) }}\r\n </li>\r\n }\r\n </ul>\r\n\r\n <nav>\r\n @if (p.page > 1) {\r\n <button type=\"button\" (click)=\"carregar(p.page - 1)\">Anteriores</button>\r\n }\r\n @if (temProxima()) {\r\n <button type=\"button\" (click)=\"carregar(p.page + 1)\">Próximas</button>\r\n }\r\n </nav>\r\n }\r\n <a routerLink=\"..\">Voltar para a assinatura</a>\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 InvoicesPage implements OnInit {\r\n private readonly client = inject(BillingClient);\r\n\r\n protected readonly status = STATUS_DA_FATURA;\r\n protected readonly moeda = moeda;\r\n protected readonly data = data;\r\n protected readonly dataDoVencimento = dataDoVencimento;\r\n protected readonly pagina = signal<PaginaDeFaturas | null>(null);\r\n protected readonly erro = signal<ProblemDetails | null>(null);\r\n protected readonly temProxima = computed(() => {\r\n const p = this.pagina();\r\n return !!p && p.page * p.pageSize < p.total;\r\n });\r\n\r\n ngOnInit(): void {\r\n this.carregar(1);\r\n }\r\n\r\n protected carregar(pagina: number): void {\r\n this.client.listInvoices(pagina, TAMANHO_DA_PAGINA).subscribe({\r\n next: (resultado) => this.pagina.set(resultado),\r\n error: (problema: ProblemDetails) => this.erro.set(problema),\r\n });\r\n }\r\n}\r\n"],"names":[],"mappings":";;;;;;AAQA,MAAM,iBAAiB,GAAG,EAAE;MA2Cf,YAAY,CAAA;AACN,IAAA,MAAM,GAAG,MAAM,CAAC,aAAa,CAAC;IAE5B,MAAM,GAAG,gBAAgB;IACzB,KAAK,GAAG,KAAK;IACb,IAAI,GAAG,IAAI;IACX,gBAAgB,GAAG,gBAAgB;IACnC,MAAM,GAAG,MAAM,CAAyB,IAAI;+EAAC;IAC7C,IAAI,GAAG,MAAM,CAAwB,IAAI;6EAAC;AAC1C,IAAA,UAAU,GAAG,QAAQ,CAAC,MAAK;AAC5C,QAAA,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE;AACvB,QAAA,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,KAAK;IAC7C,CAAC;mFAAC;IAEF,QAAQ,GAAA;AACN,QAAA,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;IAClB;AAEU,IAAA,QAAQ,CAAC,MAAc,EAAA;QAC/B,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC,SAAS,CAAC;AAC5D,YAAA,IAAI,EAAE,CAAC,SAAS,KAAK,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC;AAC/C,YAAA,KAAK,EAAE,CAAC,QAAwB,KAAK,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC;AAC7D,SAAA,CAAC;IACJ;uGAvBW,YAAY,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAZ,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,YAAY,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,0BAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EApCb,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCT,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,o6BAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAnCS,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;;2FAsChC,YAAY,EAAA,UAAA,EAAA,CAAA;kBAzCxB,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,0BAA0B,EAAA,UAAA,EACxB,IAAI,EAAA,OAAA,EACP,CAAC,UAAU,EAAE,qBAAqB,CAAC,EAAA,eAAA,EAC3B,uBAAuB,CAAC,MAAM,EAAA,QAAA,EACrC,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiCT,EAAA,CAAA,EAAA,MAAA,EAAA,CAAA,o6BAAA,CAAA,EAAA;;;;;"}
|
|
@@ -39,27 +39,27 @@ const ORECHIO_BILLING_ROUTES = [
|
|
|
39
39
|
path: '',
|
|
40
40
|
pathMatch: 'full',
|
|
41
41
|
title: 'Assinatura',
|
|
42
|
-
loadComponent: () => import('./orechio-platform-angular-billing-subscription.page-
|
|
42
|
+
loadComponent: () => import('./orechio-platform-angular-billing-subscription.page-Cp4Hz_ta.mjs').then((m) => m.SubscriptionPage),
|
|
43
43
|
},
|
|
44
44
|
{
|
|
45
45
|
path: 'profile',
|
|
46
46
|
title: 'Dados de cobrança',
|
|
47
|
-
loadComponent: () => import('./orechio-platform-angular-billing-profile.page-
|
|
47
|
+
loadComponent: () => import('./orechio-platform-angular-billing-profile.page-CrYtBaOi.mjs').then((m) => m.ProfilePage),
|
|
48
48
|
},
|
|
49
49
|
{
|
|
50
50
|
path: 'checkout',
|
|
51
51
|
title: 'Pagar assinatura',
|
|
52
|
-
loadComponent: () => import('./orechio-platform-angular-billing-checkout.page-
|
|
52
|
+
loadComponent: () => import('./orechio-platform-angular-billing-checkout.page-Q1Toeh07.mjs').then((m) => m.CheckoutPage),
|
|
53
53
|
},
|
|
54
54
|
{
|
|
55
55
|
path: 'invoices',
|
|
56
56
|
title: 'Faturas',
|
|
57
|
-
loadComponent: () => import('./orechio-platform-angular-billing-invoices.page-
|
|
57
|
+
loadComponent: () => import('./orechio-platform-angular-billing-invoices.page-BtVgaP_j.mjs').then((m) => m.InvoicesPage),
|
|
58
58
|
},
|
|
59
59
|
{
|
|
60
60
|
path: 'invoices/:id',
|
|
61
61
|
title: 'Fatura',
|
|
62
|
-
loadComponent: () => import('./orechio-platform-angular-billing-invoice.page-
|
|
62
|
+
loadComponent: () => import('./orechio-platform-angular-billing-invoice.page-nURMELXG.mjs').then((m) => m.InvoicePage),
|
|
63
63
|
},
|
|
64
64
|
];
|
|
65
65
|
|
|
@@ -310,4 +310,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.3", ngImpor
|
|
|
310
310
|
*/
|
|
311
311
|
|
|
312
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-
|
|
313
|
+
//# sourceMappingURL=orechio-platform-angular-billing-orechio-platform-angular-billing-CkUiNOLp.mjs.map
|
|
@@ -1 +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
|
+
{"version":3,"file":"orechio-platform-angular-billing-orechio-platform-angular-billing-CkUiNOLp.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 { f as moeda, g as dataDoVencimento, v as validadeDoPix } from './orechio-platform-angular-billing-billing-format-
|
|
3
|
+
import { f as moeda, g as dataDoVencimento, v as validadeDoPix } from './orechio-platform-angular-billing-billing-format-CN53uJAG.mjs';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* O QR e o copia-e-cola, como a Platform os devolveu. O `encodedImage` é PNG em base64
|
|
@@ -100,4 +100,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.3", 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-CxJl6ahY.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-CxJl6ahY.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,8 +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 { B as BillingClient } from './orechio-platform-angular-billing-orechio-platform-angular-billing-
|
|
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-
|
|
7
|
+
import { B as BillingClient } from './orechio-platform-angular-billing-orechio-platform-angular-billing-CkUiNOLp.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-CN53uJAG.mjs';
|
|
9
9
|
|
|
10
10
|
function doPerfil(perfil) {
|
|
11
11
|
const tipo = perfil.documentType ?? 'Cnpj';
|
|
@@ -307,4 +307,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.3", ngImpor
|
|
|
307
307
|
}] });
|
|
308
308
|
|
|
309
309
|
export { ProfilePage };
|
|
310
|
-
//# sourceMappingURL=orechio-platform-angular-billing-profile.page-
|
|
310
|
+
//# sourceMappingURL=orechio-platform-angular-billing-profile.page-CrYtBaOi.mjs.map
|
|
@@ -1 +1 @@
|
|
|
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":"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"}
|
|
1
|
+
{"version":3,"file":"orechio-platform-angular-billing-profile.page-CrYtBaOi.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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"}
|
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { inject, signal, computed, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
3
|
import { RouterLink } from '@angular/router';
|
|
4
|
-
import { B as BillingClient, S as SubscriptionAccessState } from './orechio-platform-angular-billing-orechio-platform-angular-billing-
|
|
5
|
-
import { d as data, B as BillingErrorComponent } from './orechio-platform-angular-billing-billing-format-
|
|
4
|
+
import { B as BillingClient, S as SubscriptionAccessState } from './orechio-platform-angular-billing-orechio-platform-angular-billing-CkUiNOLp.mjs';
|
|
5
|
+
import { d as data, B as BillingErrorComponent } from './orechio-platform-angular-billing-billing-format-CN53uJAG.mjs';
|
|
6
6
|
|
|
7
7
|
const DIA = 24 * 60 * 60 * 1000;
|
|
8
8
|
const EM_ABERTO = ['Created', 'Pending', 'Overdue'];
|
|
9
|
-
|
|
9
|
+
/** Estados cuja ação depende de haver fatura aberta (a Platform recusa o checkout com ela). */
|
|
10
|
+
const dependeDeFaturas = (assinatura) => assinatura.status === 'Grace' || assinatura.status === 'Suspended' || assinatura.status === 'Expired';
|
|
10
11
|
/**
|
|
11
12
|
* A ação de cada estado segue o que a Platform aceita: o checkout serve `Trial`,
|
|
12
13
|
* `PendingPayment` e, desde a BILLING-2b, `Grace` e `Suspended` — mas só sem fatura aberta
|
|
13
14
|
* (`Created|Pending|Overdue`; com ela, `checkout.open_invoice_exists`). Em carência e suspensão
|
|
14
|
-
* a ação depende disso: fatura aberta → o detalhe dela; nenhuma → o checkout.
|
|
15
|
-
*
|
|
15
|
+
* a ação depende disso: fatura aberta → o detalhe dela; nenhuma → o checkout. A expirada segue a
|
|
16
|
+
* mesma regra (desde a REACT-1 o checkout a reativa ao pagar, no plano vigente). A cancelada não
|
|
17
|
+
* tem ação de pagamento nesta versão: reativar é v2 (ADR-021 §3.5).
|
|
16
18
|
*/
|
|
17
19
|
function situacao(assinatura, agora, emAberto) {
|
|
18
20
|
const pagar = { texto: 'Pagar agora', link: 'checkout' };
|
|
@@ -68,8 +70,10 @@ function situacao(assinatura, agora, emAberto) {
|
|
|
68
70
|
case 'Expired':
|
|
69
71
|
return {
|
|
70
72
|
titulo: 'Assinatura expirada',
|
|
71
|
-
detalhe:
|
|
72
|
-
|
|
73
|
+
detalhe: emAberto
|
|
74
|
+
? 'O acesso acabou. Pague a fatura em aberto para voltar a usar.'
|
|
75
|
+
: 'O acesso acabou. Reative a assinatura para voltar a usar.',
|
|
76
|
+
acao: emAberto ? acaoDeAtraso : { texto: 'Reativar assinatura', link: 'checkout' },
|
|
73
77
|
};
|
|
74
78
|
}
|
|
75
79
|
}
|
|
@@ -78,7 +82,7 @@ class SubscriptionPage {
|
|
|
78
82
|
acesso = inject(SubscriptionAccessState);
|
|
79
83
|
assinatura = signal(null, /* @ts-ignore */
|
|
80
84
|
...(ngDevMode ? [{ debugName: "assinatura" }] : /* istanbul ignore next */ []));
|
|
81
|
-
/** Só preenchido em Grace/Suspended: `undefined` = ainda não respondeu; `null` = nenhuma aberta. */
|
|
85
|
+
/** Só preenchido em Grace/Suspended/Expired: `undefined` = ainda não respondeu; `null` = nenhuma aberta. */
|
|
82
86
|
emAberto = signal(undefined, /* @ts-ignore */
|
|
83
87
|
...(ngDevMode ? [{ debugName: "emAberto" }] : /* istanbul ignore next */ []));
|
|
84
88
|
erro = signal(null, /* @ts-ignore */
|
|
@@ -89,7 +93,7 @@ class SubscriptionPage {
|
|
|
89
93
|
return null;
|
|
90
94
|
const aberta = this.emAberto();
|
|
91
95
|
// Sem a resposta das faturas não se sabe o destino da ação: não se adivinha.
|
|
92
|
-
if (
|
|
96
|
+
if (dependeDeFaturas(assinatura) && aberta === undefined)
|
|
93
97
|
return null;
|
|
94
98
|
return situacao(assinatura, Date.now(), aberta ?? null);
|
|
95
99
|
}, /* @ts-ignore */
|
|
@@ -99,7 +103,7 @@ class SubscriptionPage {
|
|
|
99
103
|
next: (assinatura) => {
|
|
100
104
|
this.assinatura.set(assinatura);
|
|
101
105
|
this.acesso.atualizar(assinatura.status);
|
|
102
|
-
if (
|
|
106
|
+
if (dependeDeFaturas(assinatura))
|
|
103
107
|
this.buscarFaturaEmAberto();
|
|
104
108
|
},
|
|
105
109
|
error: (problema) => this.erro.set(problema),
|
|
@@ -160,4 +164,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.3", ngImpor
|
|
|
160
164
|
}] });
|
|
161
165
|
|
|
162
166
|
export { SubscriptionPage };
|
|
163
|
-
//# sourceMappingURL=orechio-platform-angular-billing-subscription.page-
|
|
167
|
+
//# sourceMappingURL=orechio-platform-angular-billing-subscription.page-Cp4Hz_ta.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orechio-platform-angular-billing-subscription.page-Cp4Hz_ta.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\nimport { SubscriptionAccessState } from '../subscription-access.state';\r\n\r\nconst DIA = 24 * 60 * 60 * 1000;\r\nconst EM_ABERTO: InvoiceStatus[] = ['Created', 'Pending', 'Overdue'];\r\n\r\n/** Estados cuja ação depende de haver fatura aberta (a Platform recusa o checkout com ela). */\r\nconst dependeDeFaturas = (assinatura: Subscription) =>\r\n assinatura.status === 'Grace' || assinatura.status === 'Suspended' || assinatura.status === 'Expired';\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. A expirada segue a\r\n * mesma regra (desde a REACT-1 o checkout a reativa ao pagar, no plano vigente). A cancelada não\r\n * tem 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: emAberto\r\n ? 'O acesso acabou. Pague a fatura em aberto para voltar a usar.'\r\n : 'O acesso acabou. Reative a assinatura para voltar a usar.',\r\n acao: emAberto ? acaoDeAtraso : { texto: 'Reativar assinatura', link: 'checkout' },\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 private readonly acesso = inject(SubscriptionAccessState);\r\n\r\n private readonly assinatura = signal<Subscription | null>(null);\r\n /** Só preenchido em Grace/Suspended/Expired: `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 (dependeDeFaturas(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 this.acesso.atualizar(assinatura.status);\r\n if (dependeDeFaturas(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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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { O as ORECHIO_BILLING_CONFIG, a as ORECHIO_BILLING_ROUTES, b as OrechioSubscriptionNotice, p as provideOrechioBilling, r as requireSubscriptionAccess, s as subscriptionAccessInterceptor } from './orechio-platform-angular-billing-orechio-platform-angular-billing-
|
|
1
|
+
export { O as ORECHIO_BILLING_CONFIG, a as ORECHIO_BILLING_ROUTES, b as OrechioSubscriptionNotice, p as provideOrechioBilling, r as requireSubscriptionAccess, s as subscriptionAccessInterceptor } from './orechio-platform-angular-billing-orechio-platform-angular-billing-CkUiNOLp.mjs';
|
|
2
2
|
//# sourceMappingURL=orechio-platform-angular-billing.mjs.map
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"orechio-platform-angular-billing-billing-format-CuDtE7fj.mjs","sources":["../../../projects/platform-angular/billing/src/billing-errors.ts","../../../projects/platform-angular/billing/src/billing-error.component.ts","../../../projects/platform-angular/billing/src/billing-format.ts"],"sourcesContent":["import { ProblemDetails } from '@orechio/platform-angular';\r\n\r\nexport interface MensagemDeErro {\r\n texto: string;\r\n /** Só para code desconhecido: é o que o suporte cruza com o log dos dois lados. */\r\n correlationId?: string;\r\n}\r\n\r\nconst ENDERECO_INCOMPLETO = 'Preencha o endereço completo.';\r\nconst DOCUMENTO_INVALIDO = 'CPF ou CNPJ inválido.';\r\nconst DOCUMENTO_TRAVADO =\r\n 'O documento e o nome já foram usados em uma cobrança e não podem mais ser alterados.';\r\nconst PLANO_INDISPONIVEL = 'O plano da assinatura não está disponível. Fale com o suporte.';\r\nconst SO_O_TITULAR = 'Só o titular da conta pode ver e pagar a cobrança.';\r\n\r\n/**\r\n * Os codes que as rotas de cobrança da Platform e do BFF emitem de fato\r\n * (`Commerce*Endpoints`, handlers de `Billing/`, value objects de perfil,\r\n * `PermissionAuthorization`, `Bff.Account`).\r\n */\r\nconst MENSAGENS: Record<string, string> = {\r\n 'session.missing': 'Sua sessão expirou. Entre novamente para continuar.',\r\n 'platform.unavailable':\r\n 'O serviço de cobrança está indisponível no momento. Tente novamente em instantes.',\r\n 'http.0': 'Sem conexão com o servidor. Verifique sua internet e tente novamente.',\r\n rate_limit_exceeded: 'Muitas tentativas. Aguarde alguns minutos e tente novamente.',\r\n\r\n 'access.platform_only': SO_O_TITULAR,\r\n 'permission.denied': SO_O_TITULAR,\r\n\r\n 'subscription.not_found': 'Nenhuma assinatura encontrada para esta conta.',\r\n\r\n 'billing_profile.not_found': 'Cadastre os dados de cobrança antes de pagar.',\r\n 'billing_profile.already_exists': 'Os dados de cobrança já estão cadastrados.',\r\n 'billing_profile.legal_name_required': 'Informe o nome completo ou a razão social.',\r\n 'billing_profile.billing_email_required': 'Informe o e-mail de cobrança.',\r\n 'billing_profile.billing_email_invalid': 'Informe um e-mail de cobrança válido.',\r\n 'billing_profile.mobile_phone_too_long': 'O celular informado é longo demais.',\r\n 'billing_profile.document_type_locked': DOCUMENTO_TRAVADO,\r\n 'billing_profile.document_number_locked': DOCUMENTO_TRAVADO,\r\n 'billing_profile.legal_name_locked': DOCUMENTO_TRAVADO,\r\n 'tax_document.value_required': 'Informe o CPF ou o CNPJ.',\r\n 'tax_document.length_invalid': DOCUMENTO_INVALIDO,\r\n 'tax_document.checksum_invalid': DOCUMENTO_INVALIDO,\r\n 'address.postal_code_invalid': 'CEP inválido.',\r\n 'address.state_invalid': 'UF inválida. Use a sigla do estado, como SP.',\r\n 'address.street_required': ENDERECO_INCOMPLETO,\r\n 'address.number_required': ENDERECO_INCOMPLETO,\r\n 'address.neighborhood_required': ENDERECO_INCOMPLETO,\r\n 'address.city_required': ENDERECO_INCOMPLETO,\r\n\r\n 'checkout.subscription_not_eligible':\r\n 'Não há pagamento de assinatura a fazer agora. Veja as faturas em aberto.',\r\n 'checkout.open_invoice_exists':\r\n 'Já existe uma fatura em aberto. Pague a fatura em aberto em vez de gerar uma nova cobrança.',\r\n 'checkout.pending_other_method':\r\n 'Já existe uma cobrança em aberto por outro meio de pagamento. Veja as faturas.',\r\n 'checkout.credit_card_not_supported': 'Pagamento por cartão ainda não está disponível.',\r\n 'checkout.invoice_in_inconsistent_state':\r\n 'A cobrança anterior ficou incompleta. Tente novamente em alguns minutos.',\r\n 'billing.cycle_invalid': 'Escolha um ciclo de cobrança válido.',\r\n 'pricing_preview.cycle_invalid': 'Escolha um ciclo de cobrança válido.',\r\n 'plan.not_found': PLANO_INDISPONIVEL,\r\n 'plan.not_available': PLANO_INDISPONIVEL,\r\n 'subscription.plan_inactive': PLANO_INDISPONIVEL,\r\n\r\n 'invoice.not_found': 'Fatura não encontrada.',\r\n 'invoice.payment_unavailable':\r\n 'Esta cobrança não está mais disponível para pagamento. Fale com o suporte.',\r\n 'invoice.refresh_not_allowed': 'Esta fatura não está mais em aberto.',\r\n 'invoice.refresh_pix_only': 'Só é possível gerar QR para faturas PIX.',\r\n 'invoice.no_external_payment':\r\n 'Esta fatura ainda não tem cobrança gerada. Tente novamente em alguns minutos.',\r\n};\r\n\r\nconst GENERICA =\r\n 'Não foi possível concluir a operação. Tente novamente; se continuar, informe o código de atendimento ao suporte.';\r\n\r\n/**\r\n * O texto de tela para um erro do BFF, escolhido por `code`. O corpo do erro (`message`) nunca\r\n * vira texto: ele é escrito para log, não para o cliente.\r\n */\r\nexport function mensagemDeErro(problema: ProblemDetails): MensagemDeErro {\r\n const conhecida = MENSAGENS[problema.code];\r\n if (conhecida) return { texto: conhecida };\r\n\r\n return problema.correlationId\r\n ? { texto: GENERICA, correlationId: problema.correlationId }\r\n : { texto: GENERICA };\r\n}\r\n","import { ChangeDetectionStrategy, Component, computed, input } from '@angular/core';\r\nimport { ProblemDetails } from '@orechio/platform-angular';\r\nimport { mensagemDeErro } from './billing-errors';\r\n\r\n@Component({\r\n selector: 'orechio-billing-error',\r\n standalone: true,\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n template: `\r\n <div class=\"orechio-billing__error\" role=\"alert\">\r\n <p>{{ mensagem().texto }}</p>\r\n @if (mensagem().correlationId; as id) {\r\n <p>Código de atendimento: <code>{{ id }}</code></p>\r\n }\r\n </div>\r\n `,\r\n styles: `.orechio-billing__error { color: var(--orechio-color-danger, #b00020); }`,\r\n})\r\nexport class BillingErrorComponent {\r\n readonly problema = input.required<ProblemDetails>();\r\n protected readonly mensagem = computed(() => mensagemDeErro(this.problema()));\r\n}\r\n","import { InvoiceStatus } from './billing-models';\r\n\r\nconst MOEDA = new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL' });\r\n\r\nexport function moeda(valor: number): string {\r\n return MOEDA.format(valor);\r\n}\r\n\r\nexport function data(iso: string | null | undefined): string {\r\n return iso ? new Date(iso).toLocaleDateString('pt-BR') : '';\r\n}\r\n\r\n/**\r\n * O vencimento para a tela: \"02/10/2026\". É uma DATA, sem hora: a Platform a manda como meia-noite\r\n * UTC (\"2026-10-02T00:00:00Z\") ou \"2026-10-02\", e passar por `new Date()` a deslocaria para o dia\r\n * anterior no fuso do navegador (Manaus, Brasília). Lê os 10 primeiros caracteres AAAA-MM-DD e\r\n * formata por PARTES DO TEXTO. Formato inesperado volta como veio.\r\n */\r\nexport function dataDoVencimento(valor: string): string {\r\n const partes = /^(\\d{4})-(\\d{2})-(\\d{2})(?![\\d])/.exec(valor.trim());\r\n if (!partes) return valor;\r\n const [, ano, mes, dia] = partes;\r\n return `${dia}/${mes}/${ano}`;\r\n}\r\n\r\nconst FUSO_DE_BRASILIA = 'America/Sao_Paulo';\r\nconst SUFIXO_DE_BRASILIA = '(horário de Brasília)';\r\n\r\n/** \"AAAA-MM-DD HH:mm[:ss]\" — o `expirationDate` do ASAAS: sem fuso, já em horário de Brasília. */\r\nconst SEM_FUSO = /^(\\d{4})-(\\d{2})-(\\d{2})[ T](\\d{2}):(\\d{2})(?::(\\d{2})(?:\\.\\d+)?)?$/;\r\n/** O mesmo, com fuso explícito: `Z` ou `±hh:mm` / `±hhmm`. */\r\nconst COM_FUSO = /^\\d{4}-\\d{2}-\\d{2}[ T]\\d{2}:\\d{2}(?::\\d{2}(?:\\.\\d+)?)?(?:Z|[+-]\\d{2}:?\\d{2})$/i;\r\n\r\n/**\r\n * A validade do PIX para a tela: \"02/10/2026 às 23:59 (horário de Brasília)\".\r\n *\r\n * O valor do ASAAS NÃO passa por `new Date()`: sem fuso, o construtor o leria no fuso do\r\n * navegador e a hora exibida se deslocaria. Ele é formatado por PARTES DO TEXTO. Só o valor\r\n * com fuso explícito é convertido (para America/Sao_Paulo). Formato não reconhecido volta como\r\n * veio — nunca \"Invalid Date\".\r\n */\r\nexport function validadeDoPix(valor: string): string {\r\n const texto = valor.trim();\r\n\r\n const semFuso = SEM_FUSO.exec(texto);\r\n if (semFuso) {\r\n const [, ano, mes, dia, hora, minuto] = semFuso;\r\n return dataValida(+ano, +mes, +dia, +hora, +minuto)\r\n ? `${dia}/${mes}/${ano} às ${hora}:${minuto} ${SUFIXO_DE_BRASILIA}`\r\n : valor;\r\n }\r\n\r\n if (COM_FUSO.test(texto)) {\r\n const instante = new Date(texto.replace(' ', 'T'));\r\n if (Number.isNaN(instante.getTime())) return valor;\r\n\r\n const partes = Object.fromEntries(\r\n new Intl.DateTimeFormat('pt-BR', {\r\n timeZone: FUSO_DE_BRASILIA,\r\n day: '2-digit',\r\n month: '2-digit',\r\n year: 'numeric',\r\n hour: '2-digit',\r\n minute: '2-digit',\r\n hourCycle: 'h23',\r\n })\r\n .formatToParts(instante)\r\n .map((parte) => [parte.type, parte.value]),\r\n );\r\n return `${partes['day']}/${partes['month']}/${partes['year']} às ${partes['hour']}:${partes['minute']} ${SUFIXO_DE_BRASILIA}`;\r\n }\r\n\r\n return valor;\r\n}\r\n\r\nfunction dataValida(ano: number, mes: number, dia: number, hora: number, minuto: number): boolean {\r\n if (mes < 1 || mes > 12 || hora > 23 || minuto > 59 || dia < 1) return false;\r\n return dia <= new Date(Date.UTC(ano, mes, 0)).getUTCDate();\r\n}\r\n\r\n// ── máscaras (perfil de cobrança) ────────────────────────────────────────────\r\n\r\nexport function soDigitos(valor: string): string {\r\n return valor.replace(/\\D/g, '');\r\n}\r\n\r\n/** Junta os grupos de dígitos com os separadores, parando no primeiro grupo vazio. */\r\nfunction agrupar(digitos: string, grupos: readonly number[], separadores: readonly string[]): string {\r\n let saida = '';\r\n let posicao = 0;\r\n for (let i = 0; i < grupos.length; i++) {\r\n const grupo = digitos.slice(posicao, posicao + grupos[i]);\r\n if (!grupo) break;\r\n saida += (i === 0 ? '' : separadores[i - 1]) + grupo;\r\n posicao += grupos[i];\r\n }\r\n return saida;\r\n}\r\n\r\n/** CPF `000.000.000-00`, progressivo enquanto se digita. */\r\nexport function mascararCpf(valor: string): string {\r\n return agrupar(soDigitos(valor).slice(0, 11), [3, 3, 3, 2], ['.', '.', '-']);\r\n}\r\n\r\n/** CNPJ `00.000.000/0000-00`, progressivo enquanto se digita. */\r\nexport function mascararCnpj(valor: string): string {\r\n return agrupar(soDigitos(valor).slice(0, 14), [2, 3, 3, 4, 2], ['.', '.', '/', '-']);\r\n}\r\n\r\n/** O documento conforme o tipo escolhido. */\r\nexport function mascararDocumento(tipo: 'Cpf' | 'Cnpj', valor: string): string {\r\n return tipo === 'Cpf' ? mascararCpf(valor) : mascararCnpj(valor);\r\n}\r\n\r\n/** CEP `00000-000`. */\r\nexport function mascararCep(valor: string): string {\r\n return agrupar(soDigitos(valor).slice(0, 8), [5, 3], ['-']);\r\n}\r\n\r\n/** Telefone `(00) 0000-0000` (10 dígitos) ou celular `(00) 00000-0000` (11). */\r\nexport function mascararTelefone(valor: string): string {\r\n const digitos = soDigitos(valor).slice(0, 11);\r\n if (!digitos) return '';\r\n\r\n const ddd = digitos.slice(0, 2);\r\n if (digitos.length <= 2) return `(${ddd}`;\r\n\r\n const numero = digitos.slice(2);\r\n const tamanhoDoPrimeiroBloco = digitos.length > 10 ? 5 : 4;\r\n const corpo =\r\n numero.length > tamanhoDoPrimeiroBloco\r\n ? `${numero.slice(0, tamanhoDoPrimeiroBloco)}-${numero.slice(tamanhoDoPrimeiroBloco)}`\r\n : numero;\r\n return `(${ddd}) ${corpo}`;\r\n}\r\n\r\nexport const STATUS_DA_FATURA: Record<InvoiceStatus, string> = {\r\n Created: 'Em emissão',\r\n Pending: 'Em aberto',\r\n Paid: 'Paga',\r\n Overdue: 'Vencida',\r\n Refunded: 'Estornada',\r\n Cancelled: 'Cancelada',\r\n};\r\n\r\nexport const ESTILO_BASE = `\r\n .orechio-billing {\r\n display: flex;\r\n flex-direction: column;\r\n gap: var(--orechio-space-3, 0.75rem);\r\n max-width: 40rem;\r\n margin: 0 auto;\r\n padding: var(--orechio-space-6, 1.5rem);\r\n color: var(--orechio-color-text, inherit);\r\n font-family: var(--orechio-font-body, inherit);\r\n }\r\n .orechio-billing form { display: flex; flex-direction: column; gap: var(--orechio-space-2, 0.5rem); }\r\n .orechio-billing__muted { color: var(--orechio-color-text-muted, #666); }\r\n .orechio-billing__error { color: var(--orechio-color-danger, #b00020); }\r\n .orechio-billing__acao {\r\n align-self: flex-start;\r\n display: inline-block;\r\n padding: var(--orechio-space-2, 0.5rem) var(--orechio-space-4, 1rem);\r\n border-radius: var(--orechio-radius, 0.375rem);\r\n background: var(--orechio-color-primary, #1a56db);\r\n color: var(--orechio-color-on-primary, #fff);\r\n font-weight: 600;\r\n text-decoration: none;\r\n }\r\n .orechio-billing__acao:hover,\r\n .orechio-billing__acao:focus-visible {\r\n background: var(--orechio-color-primary-hover, var(--orechio-color-primary, #1446b0));\r\n }\r\n`;\r\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"orechio-platform-angular-billing-checkout.page-BhUYGMkL.mjs","sources":["../../../projects/platform-angular/billing/src/pages/checkout.page.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, OnInit, inject, signal } from '@angular/core';\r\nimport { ActivatedRoute, Router, RouterLink } from '@angular/router';\r\nimport { forkJoin } from 'rxjs';\r\nimport { ProblemDetails } from '@orechio/platform-angular';\r\nimport { BillingClient } from '../billing-client';\r\nimport { BillingErrorComponent } from '../billing-error.component';\r\nimport { ESTILO_BASE, moeda } from '../billing-format';\r\nimport { BillingCycle, PixData, PricingPreview, Subscription, SubscriptionStatus } from '../billing-models';\r\nimport { PixPanelComponent } from '../pix-panel.component';\r\n\r\nconst STATUS_COM_CHECKOUT: SubscriptionStatus[] = ['Trial', 'PendingPayment', 'Grace', 'Suspended'];\r\n\r\nconst CICLOS: { valor: BillingCycle; rotulo: string }[] = [\r\n { valor: 'Monthly', rotulo: 'Mensal' },\r\n { valor: 'Yearly', rotulo: 'Anual' },\r\n];\r\n\r\n/**\r\n * Pagar a assinatura (ADR-021 §3.5, item 3): o plano ATUAL — trocar de plano é v2 —, o preço\r\n * de cada ciclo vindo de `pricing/preview`, e o checkout PIX.\r\n */\r\n@Component({\r\n selector: 'orechio-billing-checkout',\r\n standalone: true,\r\n imports: [RouterLink, BillingErrorComponent, PixPanelComponent],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n template: `\r\n <section class=\"orechio-billing\">\r\n <h1>Pagar assinatura</h1>\r\n\r\n @if (pix(); as dados) {\r\n <p>Pague o PIX abaixo. A assinatura é atualizada assim que o pagamento for confirmado.</p>\r\n <orechio-billing-pix [pix]=\"dados\" [invoiceUrl]=\"invoiceUrl()\" [valor]=\"valor()\" [vencimento]=\"vencimento()\" />\r\n <a routerLink=\"..\">Voltar para a assinatura</a>\r\n } @else if (inelegivel()) {\r\n <p>Não há pagamento de assinatura a fazer agora.</p>\r\n <a routerLink=\"../invoices\">Ver faturas</a>\r\n } @else if (previas().length) {\r\n <h2>{{ previas()[0].planName }}</h2>\r\n\r\n <fieldset>\r\n <legend>Ciclo de cobrança</legend>\r\n @for (previa of previas(); track previa.cycle) {\r\n <label>\r\n <input\r\n type=\"radio\"\r\n name=\"ciclo\"\r\n [value]=\"previa.cycle\"\r\n [checked]=\"ciclo() === previa.cycle\"\r\n (change)=\"ciclo.set(previa.cycle)\"\r\n />\r\n {{ rotulo(previa.cycle) }} — {{ moeda(previa.total) }}\r\n </label>\r\n }\r\n </fieldset>\r\n\r\n <button type=\"button\" data-gerar-pix (click)=\"pagar()\" [disabled]=\"enviando()\">\r\n {{ enviando() ? 'Gerando PIX…' : 'Gerar PIX' }}\r\n </button>\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 styles: ESTILO_BASE,\r\n})\r\nexport class CheckoutPage 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 readonly moeda = moeda;\r\n protected readonly previas = signal<PricingPreview[]>([]);\r\n protected readonly ciclo = signal<BillingCycle>('Monthly');\r\n protected readonly inelegivel = signal(false);\r\n protected readonly enviando = signal(false);\r\n protected readonly pix = signal<PixData | null>(null);\r\n protected readonly invoiceUrl = signal<string | null>(null);\r\n protected readonly valor = signal<number | null>(null);\r\n protected readonly vencimento = signal<string | null>(null);\r\n protected readonly erro = signal<ProblemDetails | null>(null);\r\n\r\n protected rotulo(ciclo: BillingCycle): string {\r\n return CICLOS.find((c) => c.valor === ciclo)?.rotulo ?? ciclo;\r\n }\r\n\r\n ngOnInit(): void {\r\n forkJoin({ assinatura: this.client.getSubscription(), perfil: this.client.getProfile() }).subscribe({\r\n next: ({ assinatura, perfil }) => {\r\n // O checkout serve Trial, PendingPayment, Grace e Suspended (`InitiateCheckoutCommand`,\r\n // passo 4; os dois últimos desde a BILLING-2b, e só sem fatura aberta — ver `pagar`).\r\n // Checado antes do perfil: não se pede cadastro para um pagamento que não existe.\r\n if (!STATUS_COM_CHECKOUT.includes(assinatura.status)) {\r\n this.inelegivel.set(true);\r\n return;\r\n }\r\n\r\n // O checkout recusa sem perfil (`billing_profile.not_found`). Mandar para o perfil\r\n // ANTES poupa o cliente de escolher o ciclo para receber um erro.\r\n if (!perfil.exists || !perfil.isComplete) {\r\n void this.router.navigate(['../profile'], {\r\n relativeTo: this.route,\r\n queryParams: { next: 'checkout' },\r\n });\r\n return;\r\n }\r\n\r\n this.ciclo.set(assinatura.cycle);\r\n this.carregarPrecos(assinatura);\r\n },\r\n error: (problema: ProblemDetails) => this.erro.set(problema),\r\n });\r\n }\r\n\r\n protected pagar(): void {\r\n if (this.enviando()) return;\r\n this.enviando.set(true);\r\n this.erro.set(null);\r\n\r\n this.client.checkout(this.ciclo()).subscribe({\r\n next: (resultado) => {\r\n this.enviando.set(false);\r\n this.invoiceUrl.set(resultado.invoiceUrl ?? null);\r\n this.valor.set(resultado.amount);\r\n this.vencimento.set(resultado.dueDate);\r\n if (resultado.pix) this.pix.set(resultado.pix);\r\n else this.erro.set({ code: 'checkout.pix_missing', status: 200 });\r\n },\r\n error: (problema: ProblemDetails) => {\r\n this.enviando.set(false);\r\n // Em Grace/Suspended com fatura aberta a Platform recusa: a aberta é a que se paga.\r\n if (problema.code === 'checkout.open_invoice_exists') {\r\n void this.router.navigate(['../invoices'], { relativeTo: this.route });\r\n return;\r\n }\r\n this.erro.set(problema);\r\n },\r\n });\r\n }\r\n\r\n private carregarPrecos(assinatura: Subscription): void {\r\n forkJoin(\r\n CICLOS.map(({ valor }) =>\r\n this.client.previewPricing(assinatura.planId, assinatura.branchCountSnapshot, valor),\r\n ),\r\n ).subscribe({\r\n next: (previas) => this.previas.set(previas),\r\n error: (problema: ProblemDetails) => this.erro.set(problema),\r\n });\r\n }\r\n}\r\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"orechio-platform-angular-billing-subscription.page-Bi6w7yq_.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\nimport { SubscriptionAccessState } from '../subscription-access.state';\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 private readonly acesso = inject(SubscriptionAccessState);\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 this.acesso.atualizar(assinatura.status);\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":";;;;;;AASA,MAAM,GAAG,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI;AAC/B,MAAM,SAAS,GAAoB,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,CAAC;AAEpE,MAAM,QAAQ,GAAG,CAAC,UAAwB,KACxC,UAAU,CAAC,MAAM,KAAK,OAAO,IAAI,UAAU,CAAC,MAAM,KAAK,WAAW;AAQpE;;;;;;AAMG;AACH,SAAS,QAAQ,CAAC,UAAwB,EAAE,KAAa,EAAE,QAAgC,EAAA;IACzF,MAAM,KAAK,GAAG,EAAE,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,UAAU,EAAE;IACxD,MAAM,OAAO,GAAG,EAAE,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,UAAU,EAAE;IAC1D,MAAM,YAAY,GAAG;AACnB,UAAE,EAAE,KAAK,EAAE,wBAAwB,EAAE,IAAI,EAAE,CAAA,SAAA,EAAY,QAAQ,CAAC,EAAE,EAAE;UAClE,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE;IACxC,MAAM,UAAU,GAAG,QAAQ,GAAG,0BAA0B,GAAG,kBAAkB;AAE7E,IAAA,QAAQ,UAAU,CAAC,MAAM;QACvB,KAAK,OAAO,EAAE;AACZ,YAAA,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,WAAW,CAAC,GAAG,KAAK,IAAI,GAAG,CAAC,CAAC;YACvF,MAAM,QAAQ,GACZ,IAAI,KAAK,CAAC,GAAG;AACb,kBAAE,IAAI,KAAK,CAAC,GAAG;AACf,sBAAE,CAAA,OAAA,EAAU,IAAI,CAAA,qCAAA,CAAuC;YACzD,OAAO,EAAE,MAAM,EAAE,kBAAkB,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,eAAe,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE;QAC9G;AACA,QAAA,KAAK,gBAAgB;YACnB,OAAO;AACL,gBAAA,MAAM,EAAE,oBAAoB;AAC5B,gBAAA,OAAO,EAAE,oEAAoE;AAC7E,gBAAA,IAAI,EAAE,KAAK;aACZ;AACH,QAAA,KAAK,QAAQ;YACX,OAAO;AACL,gBAAA,MAAM,EAAE,kBAAkB;gBAC1B,OAAO,EAAE,UAAU,CAAC;sBAChB,wBAAwB,IAAI,CAAC,UAAU,CAAC,mBAAmB,CAAC,CAAA,CAAA;AAC9D,sBAAE,cAAc;AAClB,gBAAA,IAAI,EAAE,OAAO;aACd;AACH,QAAA,KAAK,OAAO;YACV,OAAO;AACL,gBAAA,MAAM,EAAE,qBAAqB;gBAC7B,OAAO,EAAE,UAAU,CAAC;sBAChB,CAAA,sBAAA,EAAyB,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,CAAA,EAAA,EAAK,UAAU,CAAA,gCAAA;sBACpE,CAAA,EAAG,UAAU,CAAA,gCAAA,CAAkC;AACnD,gBAAA,IAAI,EAAE,YAAY;aACnB;AACH,QAAA,KAAK,WAAW;YACd,OAAO;AACL,gBAAA,MAAM,EAAE,qBAAqB;gBAC7B,OAAO,EAAE,CAAA,8CAAA,EAAiD,UAAU,CAAA,oBAAA,CAAsB;AAC1F,gBAAA,IAAI,EAAE,YAAY;aACnB;AACH,QAAA,KAAK,WAAW;YACd,OAAO;AACL,gBAAA,MAAM,EAAE,sBAAsB;gBAC9B,OAAO,EAAE,UAAU,CAAC;sBAChB,mCAAmC,IAAI,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAA,oCAAA;AACvE,sBAAE,oCAAoC;AACxC,gBAAA,IAAI,EAAE,OAAO;aACd;AACH,QAAA,KAAK,SAAS;YACZ,OAAO;AACL,gBAAA,MAAM,EAAE,qBAAqB;AAC7B,gBAAA,OAAO,EAAE,4CAA4C;AACrD,gBAAA,IAAI,EAAE,OAAO;aACd;;AAEP;MA8Ba,gBAAgB,CAAA;AACV,IAAA,MAAM,GAAG,MAAM,CAAC,aAAa,CAAC;AAC9B,IAAA,MAAM,GAAG,MAAM,CAAC,uBAAuB,CAAC;IAExC,UAAU,GAAG,MAAM,CAAsB,IAAI;mFAAC;;IAE9C,QAAQ,GAAG,MAAM,CAAqC,SAAS;iFAAC;IAC9D,IAAI,GAAG,MAAM,CAAwB,IAAI;6EAAC;AAC1C,IAAA,KAAK,GAAG,QAAQ,CAAC,MAAK;AACvC,QAAA,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,EAAE;AACpC,QAAA,IAAI,CAAC,UAAU;AAAE,YAAA,OAAO,IAAI;AAE5B,QAAA,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,EAAE;;AAE9B,QAAA,IAAI,QAAQ,CAAC,UAAU,CAAC,IAAI,MAAM,KAAK,SAAS;AAAE,YAAA,OAAO,IAAI;AAE7D,QAAA,OAAO,QAAQ,CAAC,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,MAAM,IAAI,IAAI,CAAC;IACzD,CAAC;8EAAC;IAEF,QAAQ,GAAA;AACN,QAAA,IAAI,CAAC,MAAM,CAAC,eAAe,EAAE,CAAC,SAAS,CAAC;AACtC,YAAA,IAAI,EAAE,CAAC,UAAU,KAAI;AACnB,gBAAA,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,UAAU,CAAC;gBAC/B,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,MAAM,CAAC;gBACxC,IAAI,QAAQ,CAAC,UAAU,CAAC;oBAAE,IAAI,CAAC,oBAAoB,EAAE;YACvD,CAAC;AACD,YAAA,KAAK,EAAE,CAAC,QAAwB,KAAK,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC;AAC7D,SAAA,CAAC;IACJ;IAEQ,oBAAoB,GAAA;AAC1B,QAAA,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC,SAAS,CAAC;AACnC,YAAA,IAAI,EAAE,CAAC,MAAM,KAAK,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,IAAI,CAAC;AACtG,YAAA,KAAK,EAAE,CAAC,QAAwB,KAAK,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC;AAC7D,SAAA,CAAC;IACJ;uGAnCW,gBAAgB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAhB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,gBAAgB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,8BAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EAvBjB,CAAA;;;;;;;;;;;;;;;;;;;;GAoBT,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,o6BAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAtBS,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;;2FAyBhC,gBAAgB,EAAA,UAAA,EAAA,CAAA;kBA5B5B,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,8BAA8B,EAAA,UAAA,EAC5B,IAAI,EAAA,OAAA,EACP,CAAC,UAAU,EAAE,qBAAqB,CAAC,EAAA,eAAA,EAC3B,uBAAuB,CAAC,MAAM,EAAA,QAAA,EACrC,CAAA;;;;;;;;;;;;;;;;;;;;AAoBT,EAAA,CAAA,EAAA,MAAA,EAAA,CAAA,o6BAAA,CAAA,EAAA;;;;;"}
|