uitec-ng-header 1.1.0 → 1.2.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 +11 -182
- package/esm2020/lib/ui-header.component.mjs +20 -26
- package/esm2020/lib/ui-header.module.mjs +4 -10
- package/esm2020/public-api.mjs +1 -17
- package/fesm2015/uitec-ng-header.mjs +24 -1808
- package/fesm2015/uitec-ng-header.mjs.map +1 -1
- package/fesm2020/uitec-ng-header.mjs +24 -1771
- package/fesm2020/uitec-ng-header.mjs.map +1 -1
- package/lib/ui-header.component.d.ts +8 -11
- package/lib/ui-header.module.d.ts +1 -2
- package/package.json +2 -3
- package/public-api.d.ts +0 -15
- package/esm2020/lib/assistant/components/assistant-action-card/ui-assistant-action-card.component.mjs +0 -102
- package/esm2020/lib/assistant/components/assistant-button/ui-assistant-button.component.mjs +0 -18
- package/esm2020/lib/assistant/components/assistant-composer/ui-assistant-composer.component.mjs +0 -79
- package/esm2020/lib/assistant/components/assistant-layout/ui-assistant-layout.component.mjs +0 -140
- package/esm2020/lib/assistant/components/assistant-messages/ui-assistant-messages.component.mjs +0 -144
- package/esm2020/lib/assistant/components/assistant-panel/ui-assistant-panel.component.mjs +0 -156
- package/esm2020/lib/assistant/components/assistant-text/ui-assistant-text.component.mjs +0 -26
- package/esm2020/lib/assistant/models/uiny-api.models.mjs +0 -12
- package/esm2020/lib/assistant/models/uiny.models.mjs +0 -2
- package/esm2020/lib/assistant/services/ui-assistant.service.mjs +0 -137
- package/esm2020/lib/assistant/services/uiny-api.service.mjs +0 -149
- package/esm2020/lib/assistant/services/uiny-chat.service.mjs +0 -368
- package/esm2020/lib/assistant/services/uiny-session.service.mjs +0 -74
- package/esm2020/lib/assistant/ui-assistant.module.mjs +0 -59
- package/esm2020/lib/assistant/uiny.config.mjs +0 -53
- package/esm2020/lib/assistant/utils/uiny-api.adapter.mjs +0 -154
- package/esm2020/lib/assistant/utils/uiny-contexto.mjs +0 -43
- package/esm2020/lib/assistant/utils/uiny-markdown.mjs +0 -122
- package/lib/assistant/components/assistant-action-card/ui-assistant-action-card.component.d.ts +0 -33
- package/lib/assistant/components/assistant-button/ui-assistant-button.component.d.ts +0 -9
- package/lib/assistant/components/assistant-composer/ui-assistant-composer.component.d.ts +0 -24
- package/lib/assistant/components/assistant-layout/ui-assistant-layout.component.d.ts +0 -51
- package/lib/assistant/components/assistant-messages/ui-assistant-messages.component.d.ts +0 -38
- package/lib/assistant/components/assistant-panel/ui-assistant-panel.component.d.ts +0 -53
- package/lib/assistant/components/assistant-text/ui-assistant-text.component.d.ts +0 -14
- package/lib/assistant/models/uiny-api.models.d.ts +0 -109
- package/lib/assistant/models/uiny.models.d.ts +0 -104
- package/lib/assistant/services/ui-assistant.service.d.ts +0 -55
- package/lib/assistant/services/uiny-api.service.d.ts +0 -38
- package/lib/assistant/services/uiny-chat.service.d.ts +0 -82
- package/lib/assistant/services/uiny-session.service.d.ts +0 -38
- package/lib/assistant/ui-assistant.module.d.ts +0 -19
- package/lib/assistant/uiny.config.d.ts +0 -31
- package/lib/assistant/utils/uiny-api.adapter.d.ts +0 -22
- package/lib/assistant/utils/uiny-contexto.d.ts +0 -7
- package/lib/assistant/utils/uiny-markdown.d.ts +0 -37
|
@@ -1,22 +1,16 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { Injectable,
|
|
3
|
-
import * as
|
|
2
|
+
import { Injectable, EventEmitter, Component, Input, Output, Inject, ContentChild, NgModule } from '@angular/core';
|
|
3
|
+
import * as i2 from '@angular/common';
|
|
4
4
|
import { DOCUMENT, CommonModule } from '@angular/common';
|
|
5
5
|
import * as i1 from 'uitec-ng-core';
|
|
6
6
|
import { UsuarioMenuDTO } from 'uitec-ng-core';
|
|
7
|
-
import
|
|
8
|
-
import { startWith, map, distinctUntilChanged, shareReplay, timeout, catchError, filter, switchMap, takeUntil, finalize } from 'rxjs/operators';
|
|
9
|
-
import * as i1$1 from '@angular/common/http';
|
|
10
|
-
import { HttpClient, HttpParams, HttpHeaders, HttpErrorResponse } from '@angular/common/http';
|
|
11
|
-
import * as i2 from 'uitec-ng-icon';
|
|
7
|
+
import * as i3 from 'uitec-ng-icon';
|
|
12
8
|
import { UiIconModule } from 'uitec-ng-icon';
|
|
13
|
-
import * as
|
|
9
|
+
import * as i4$1 from 'primeng/tooltip';
|
|
14
10
|
import { TooltipModule } from 'primeng/tooltip';
|
|
15
11
|
import * as i4 from 'uitec-ng-user-top';
|
|
16
12
|
import { UiUserTopModule } from 'uitec-ng-user-top';
|
|
17
13
|
import { ReactiveFormsModule } from '@angular/forms';
|
|
18
|
-
import * as i2$1 from '@angular/router';
|
|
19
|
-
import { NavigationEnd } from '@angular/router';
|
|
20
14
|
|
|
21
15
|
class UiHeaderService {
|
|
22
16
|
constructor() { }
|
|
@@ -30,617 +24,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
|
|
|
30
24
|
}]
|
|
31
25
|
}], ctorParameters: function () { return []; } });
|
|
32
26
|
|
|
33
|
-
const UINY_CONFIG = new InjectionToken('UINY_CONFIG');
|
|
34
|
-
const UINY_AVATAR_PADRAO = 'assets/images/uiny/avatar.svg';
|
|
35
|
-
const UINY_LARGURA_PADRAO = 380;
|
|
36
|
-
const UINY_LARGURA_MIN = 340;
|
|
37
|
-
const UINY_LARGURA_MAX = 400;
|
|
38
|
-
const UINY_LADO_A_LADO_PADRAO = 1200;
|
|
39
|
-
/** Mesmo limite padrão do backend (UINY_MENSAGEM_MAX_CARACTERES no uishop-ia). */
|
|
40
|
-
const UINY_MENSAGEM_MAX_CARACTERES = 2000;
|
|
41
|
-
/** O backend limita cada mensagem a UINY_TEMPO_MAXIMO_SEGUNDOS (90 s); damos uma folga. */
|
|
42
|
-
const UINY_TIMEOUT_MENSAGEM_MS = 100000;
|
|
43
|
-
const UINY_TIMEOUT_ACAO_MS = 60000;
|
|
44
|
-
const UINY_TIMEOUT_CONSULTA_MS = 20000;
|
|
45
|
-
/**
|
|
46
|
-
* Resolve a URL-base: forRoot({ apiUrl }) tem prioridade; depois APP_ENVIRONMENT.domain.uiny.
|
|
47
|
-
* Sem barra no final. Retorna null quando não configurada (o recurso fica indisponível).
|
|
48
|
-
*/
|
|
49
|
-
function resolverUrlUiny(config, env) {
|
|
50
|
-
var _a;
|
|
51
|
-
const url = (config === null || config === void 0 ? void 0 : config.apiUrl) || ((_a = env === null || env === void 0 ? void 0 : env.domain) === null || _a === void 0 ? void 0 : _a.uiny) || null;
|
|
52
|
-
if (!url || typeof url !== 'string')
|
|
53
|
-
return null;
|
|
54
|
-
if (!/^https?:\/\//i.test(url))
|
|
55
|
-
return null;
|
|
56
|
-
return url.replace(/\/+$/, '');
|
|
57
|
-
}
|
|
58
|
-
function larguraPainel(config) {
|
|
59
|
-
const largura = (config === null || config === void 0 ? void 0 : config.larguraPainel) || UINY_LARGURA_PADRAO;
|
|
60
|
-
return Math.min(UINY_LARGURA_MAX, Math.max(UINY_LARGURA_MIN, largura));
|
|
61
|
-
}
|
|
62
|
-
/**
|
|
63
|
-
* Sugestões do primeiro acesso. A API não expõe o catálogo de ferramentas, então a lista
|
|
64
|
-
* acompanha as ferramentas implementadas no uishop-ia (README, "Ferramentas implementadas").
|
|
65
|
-
* Ao adicionar ou remover ferramentas no backend, atualize aqui.
|
|
66
|
-
*/
|
|
67
|
-
const UINY_SUGESTOES = {
|
|
68
|
-
studio: {
|
|
69
|
-
textos: [
|
|
70
|
-
'Quais lojas e temas eu tenho?',
|
|
71
|
-
'Quais são as cores do meu tema?',
|
|
72
|
-
'Troque a cor principal do tema para #e8590c',
|
|
73
|
-
],
|
|
74
|
-
// studio_alterar_cor_tema exige confirmação
|
|
75
|
-
alteracoes: true,
|
|
76
|
-
},
|
|
77
|
-
erp: {
|
|
78
|
-
textos: [
|
|
79
|
-
'Quais produtos estão sem estoque?',
|
|
80
|
-
'Como foram minhas vendas neste mês?',
|
|
81
|
-
],
|
|
82
|
-
alteracoes: false,
|
|
83
|
-
},
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
/** Mesma regra de ContextoTela no backend. */
|
|
87
|
-
const TELA_VALIDA = /^[a-z0-9_\-\/.]{1,60}$/i;
|
|
88
|
-
const CAMPOS_ID = ['idLoja', 'idLojaLeiaute', 'idTema', 'idProduto', 'idPedido'];
|
|
89
|
-
function idPositivo(valor) {
|
|
90
|
-
return typeof valor === 'number' && Number.isInteger(valor) && valor > 0 && valor <= 2147483647 ? valor : null;
|
|
91
|
-
}
|
|
92
|
-
/** Normaliza o contexto informado pelo consumidor: só campos conhecidos e valores válidos. */
|
|
93
|
-
function normalizarContexto(contexto) {
|
|
94
|
-
const resultado = {};
|
|
95
|
-
if (!contexto)
|
|
96
|
-
return resultado;
|
|
97
|
-
const tela = typeof contexto.tela === 'string' ? contexto.tela.trim() : '';
|
|
98
|
-
if (tela && TELA_VALIDA.test(tela))
|
|
99
|
-
resultado.tela = tela;
|
|
100
|
-
CAMPOS_ID.forEach(campo => {
|
|
101
|
-
const id = idPositivo(contexto[campo]);
|
|
102
|
-
if (id)
|
|
103
|
-
resultado[campo] = id;
|
|
104
|
-
});
|
|
105
|
-
return resultado;
|
|
106
|
-
}
|
|
107
|
-
/** Converte para o formato de ContextoTela (campos extras geram 422 no backend). */
|
|
108
|
-
function contextoParaApi(sistema, contexto) {
|
|
109
|
-
const api = { sistema };
|
|
110
|
-
if (contexto.tela)
|
|
111
|
-
api.tela = contexto.tela;
|
|
112
|
-
if (contexto.idLoja)
|
|
113
|
-
api.id_loja = contexto.idLoja;
|
|
114
|
-
if (contexto.idLojaLeiaute)
|
|
115
|
-
api.id_loja_leiaute = contexto.idLojaLeiaute;
|
|
116
|
-
if (contexto.idTema)
|
|
117
|
-
api.id_tema = contexto.idTema;
|
|
118
|
-
if (contexto.idProduto)
|
|
119
|
-
api.id_produto = contexto.idProduto;
|
|
120
|
-
if (contexto.idPedido)
|
|
121
|
-
api.id_pedido = contexto.idPedido;
|
|
122
|
-
return api;
|
|
123
|
-
}
|
|
124
|
-
function mesmoContexto(a, b) {
|
|
125
|
-
var _a, _b;
|
|
126
|
-
return ((_a = a.tela) !== null && _a !== void 0 ? _a : null) === ((_b = b.tela) !== null && _b !== void 0 ? _b : null)
|
|
127
|
-
&& CAMPOS_ID.every(campo => { var _a, _b; return ((_a = a[campo]) !== null && _a !== void 0 ? _a : null) === ((_b = b[campo]) !== null && _b !== void 0 ? _b : null); });
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* Deriva a sessão do AuthService do uitec-ng-core (mesma fonte do JwtInterceptor).
|
|
132
|
-
* Não lê cookies nem localStorage diretamente e não guarda o token.
|
|
133
|
-
*/
|
|
134
|
-
class UinySessionService {
|
|
135
|
-
constructor(authService, zone) {
|
|
136
|
-
this.authService = authService;
|
|
137
|
-
this.zone = zone;
|
|
138
|
-
/** Chave recusada pela API (401). Fica sem sessão até o AuthService mudar. */
|
|
139
|
-
this.chaveRecusada$ = new BehaviorSubject(null);
|
|
140
|
-
this.sequencia = 0;
|
|
141
|
-
this.ultimaChave = null;
|
|
142
|
-
this.ultimaSessao = null;
|
|
143
|
-
const usuario$ = this.authService.currentUser.pipe(startWith(this.authService.currentUserValue));
|
|
144
|
-
const acesso$ = this.authService.currentAccess.pipe(startWith(this.authService.currentAccessValue));
|
|
145
|
-
this.sessao$ = combineLatest([usuario$, acesso$, this.chaveRecusada$]).pipe(map(([usuario, acesso, recusada]) => {
|
|
146
|
-
const chave = this.chave(usuario, acesso);
|
|
147
|
-
if (!chave || chave === recusada)
|
|
148
|
-
return null;
|
|
149
|
-
return this.sessaoDaChave(chave, usuario, acesso);
|
|
150
|
-
}), distinctUntilChanged(), shareReplay({ bufferSize: 1, refCount: false }));
|
|
151
|
-
this.online$ = typeof window === 'undefined'
|
|
152
|
-
? of(true)
|
|
153
|
-
: merge(fromEvent(window, 'online').pipe(map(() => true)), fromEvent(window, 'offline').pipe(map(() => false))).pipe(startWith(typeof navigator === 'undefined' ? true : navigator.onLine !== false), distinctUntilChanged(), shareReplay({ bufferSize: 1, refCount: false }));
|
|
154
|
-
}
|
|
155
|
-
/** Token da sessão atual, lido do AuthService no momento da requisição. */
|
|
156
|
-
token() {
|
|
157
|
-
const usuario = this.authService.currentUserValue;
|
|
158
|
-
return (usuario === null || usuario === void 0 ? void 0 : usuario.token) || null;
|
|
159
|
-
}
|
|
160
|
-
/** A API recusou a sessão (401): esconde a Uiny até o usuário autenticar de novo. */
|
|
161
|
-
recusarSessaoAtual() {
|
|
162
|
-
const chave = this.chave(this.authService.currentUserValue, this.acessoAtual(this.authService.currentUserValue, this.authService.currentAccessValue));
|
|
163
|
-
if (chave)
|
|
164
|
-
this.zone.run(() => this.chaveRecusada$.next(chave));
|
|
165
|
-
}
|
|
166
|
-
acessoAtual(usuario, acesso) {
|
|
167
|
-
var _a;
|
|
168
|
-
if (!usuario)
|
|
169
|
-
return null;
|
|
170
|
-
return acesso || ((_a = usuario.acessos) === null || _a === void 0 ? void 0 : _a.find(a => a.in_atual)) || null;
|
|
171
|
-
}
|
|
172
|
-
chave(usuario, acesso) {
|
|
173
|
-
var _a;
|
|
174
|
-
const atual = this.acessoAtual(usuario, acesso);
|
|
175
|
-
const idUsuario = (_a = usuario === null || usuario === void 0 ? void 0 : usuario.usuario) === null || _a === void 0 ? void 0 : _a.id_usuario;
|
|
176
|
-
if (!(usuario === null || usuario === void 0 ? void 0 : usuario.token) || !idUsuario || !(atual === null || atual === void 0 ? void 0 : atual.id_empresa))
|
|
177
|
-
return null;
|
|
178
|
-
return `${idUsuario}|${atual.id_empresa}|${usuario.token}`;
|
|
179
|
-
}
|
|
180
|
-
sessaoDaChave(chave, usuario, acesso) {
|
|
181
|
-
if (chave === this.ultimaChave && this.ultimaSessao)
|
|
182
|
-
return this.ultimaSessao;
|
|
183
|
-
const atual = this.acessoAtual(usuario, acesso);
|
|
184
|
-
this.ultimaChave = chave;
|
|
185
|
-
this.ultimaSessao = {
|
|
186
|
-
id: ++this.sequencia,
|
|
187
|
-
idUsuario: Number(usuario.usuario.id_usuario),
|
|
188
|
-
idEmpresa: Number(atual.id_empresa),
|
|
189
|
-
};
|
|
190
|
-
return this.ultimaSessao;
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
UinySessionService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: UinySessionService, deps: [{ token: i1.AuthService }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
194
|
-
UinySessionService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: UinySessionService, providedIn: 'root' });
|
|
195
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: UinySessionService, decorators: [{
|
|
196
|
-
type: Injectable,
|
|
197
|
-
args: [{ providedIn: 'root' }]
|
|
198
|
-
}], ctorParameters: function () { return [{ type: i1.AuthService }, { type: i0.NgZone }]; } });
|
|
199
|
-
|
|
200
|
-
/** Situação da API (Constants::ACAO_*) -> estado da tela. */
|
|
201
|
-
const ESTADOS = {
|
|
202
|
-
pendente: 'pendente',
|
|
203
|
-
executando: 'executando',
|
|
204
|
-
executada: 'concluida',
|
|
205
|
-
cancelada: 'cancelada',
|
|
206
|
-
expirada: 'expirada',
|
|
207
|
-
invalidada: 'invalidada',
|
|
208
|
-
falhou: 'falha',
|
|
209
|
-
indeterminada: 'indeterminada',
|
|
210
|
-
};
|
|
211
|
-
const UUID = /^[0-9a-f-]{36}$/i;
|
|
212
|
-
const MAX_DETALHES = 12;
|
|
213
|
-
const MAX_VALOR = 200;
|
|
214
|
-
/** Datas do backend: "Y-m-d H:i:s" (America/Sao_Paulo) ou ISO. */
|
|
215
|
-
function lerData(valor) {
|
|
216
|
-
if (typeof valor !== 'string' || !valor)
|
|
217
|
-
return null;
|
|
218
|
-
const iso = /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}(:\d{2})?$/.test(valor) ? valor.replace(' ', 'T') + '-03:00' : valor;
|
|
219
|
-
const data = new Date(iso);
|
|
220
|
-
return isNaN(data.getTime()) ? null : data;
|
|
221
|
-
}
|
|
222
|
-
function idValido(valor) {
|
|
223
|
-
return typeof valor === 'string' && UUID.test(valor) ? valor : null;
|
|
224
|
-
}
|
|
225
|
-
function inteiro(valor) {
|
|
226
|
-
const n = typeof valor === 'string' && valor.trim() !== '' ? Number(valor) : valor;
|
|
227
|
-
return typeof n === 'number' && Number.isInteger(n) && n > 0 ? n : null;
|
|
228
|
-
}
|
|
229
|
-
function texto(valor, max = 20000) {
|
|
230
|
-
if (typeof valor !== 'string')
|
|
231
|
-
return '';
|
|
232
|
-
return valor.length > max ? valor.slice(0, max) : valor;
|
|
233
|
-
}
|
|
234
|
-
function adaptarConversa(api) {
|
|
235
|
-
const id = idValido(api === null || api === void 0 ? void 0 : api.id);
|
|
236
|
-
if (!id)
|
|
237
|
-
return null;
|
|
238
|
-
return {
|
|
239
|
-
id,
|
|
240
|
-
titulo: texto(api.titulo, 120) || null,
|
|
241
|
-
sistemaOrigem: api.sistema_origem,
|
|
242
|
-
idLoja: inteiro(api.id_loja),
|
|
243
|
-
atualizadaEm: lerData(api.dt_alteracao),
|
|
244
|
-
};
|
|
245
|
-
}
|
|
246
|
-
function adaptarMensagem(api) {
|
|
247
|
-
var _a;
|
|
248
|
-
const id = idValido(api === null || api === void 0 ? void 0 : api.id);
|
|
249
|
-
if (!id || (api.papel !== 'usuario' && api.papel !== 'assistente'))
|
|
250
|
-
return null;
|
|
251
|
-
return {
|
|
252
|
-
id,
|
|
253
|
-
papel: api.papel,
|
|
254
|
-
estado: typeof api.estado === 'string' ? api.estado : null,
|
|
255
|
-
texto: texto(api.texto),
|
|
256
|
-
idAcao: idValido((_a = api.acao_pendente) === null || _a === void 0 ? void 0 : _a.id),
|
|
257
|
-
opcoes: adaptarOpcoes(api.apresentacao),
|
|
258
|
-
criadaEm: lerData(api.dt_criacao),
|
|
259
|
-
};
|
|
260
|
-
}
|
|
261
|
-
/** Bloco "opcoes" do esclarecimento: só strings curtas. */
|
|
262
|
-
function adaptarOpcoes(apresentacao) {
|
|
263
|
-
var _a;
|
|
264
|
-
if (!Array.isArray(apresentacao))
|
|
265
|
-
return [];
|
|
266
|
-
const bloco = apresentacao.find(b => b && typeof b === 'object' && b.tipo === 'opcoes');
|
|
267
|
-
const opcoes = (_a = bloco === null || bloco === void 0 ? void 0 : bloco.dados) === null || _a === void 0 ? void 0 : _a.opcoes;
|
|
268
|
-
if (!Array.isArray(opcoes))
|
|
269
|
-
return [];
|
|
270
|
-
return opcoes.filter(o => typeof o === 'string' && o.trim()).map(o => o.trim().slice(0, 80)).slice(0, 6);
|
|
271
|
-
}
|
|
272
|
-
function adaptarAcao(api) {
|
|
273
|
-
var _a;
|
|
274
|
-
const id = idValido(api === null || api === void 0 ? void 0 : api.id);
|
|
275
|
-
if (!id)
|
|
276
|
-
return null;
|
|
277
|
-
return {
|
|
278
|
-
id,
|
|
279
|
-
ferramenta: texto(api.ferramenta, 80),
|
|
280
|
-
resumo: texto(api.resumo, 2000),
|
|
281
|
-
detalhes: adaptarDetalhes(api.detalhes),
|
|
282
|
-
// situação desconhecida: não afirmamos sucesso nem falha
|
|
283
|
-
estado: (_a = ESTADOS[api.situacao]) !== null && _a !== void 0 ? _a : 'indeterminada',
|
|
284
|
-
expiraEm: lerData(api.dt_expiracao),
|
|
285
|
-
};
|
|
286
|
-
}
|
|
287
|
-
/**
|
|
288
|
-
* "detalhes" vem da PropostaAlteracao da ferramenta. Só aproveitamos pares rótulo/valor
|
|
289
|
-
* com valores primitivos; nada é interpretado como HTML. Identificadores internos
|
|
290
|
-
* (tipo, id_*) não são exibidos.
|
|
291
|
-
*/
|
|
292
|
-
function adaptarDetalhes(detalhes) {
|
|
293
|
-
var _a;
|
|
294
|
-
const itens = [];
|
|
295
|
-
const adicionar = (rotulo, valor) => {
|
|
296
|
-
if (itens.length >= MAX_DETALHES)
|
|
297
|
-
return;
|
|
298
|
-
if (typeof rotulo !== 'string' || !rotulo.trim())
|
|
299
|
-
return;
|
|
300
|
-
if (typeof valor !== 'string' && typeof valor !== 'number' && typeof valor !== 'boolean')
|
|
301
|
-
return;
|
|
302
|
-
const v = typeof valor === 'boolean' ? (valor ? 'Sim' : 'Não') : String(valor);
|
|
303
|
-
if (!v.trim())
|
|
304
|
-
return;
|
|
305
|
-
itens.push({ rotulo: humanizar(rotulo).slice(0, 80), valor: v.slice(0, MAX_VALOR) });
|
|
306
|
-
};
|
|
307
|
-
if (Array.isArray(detalhes)) {
|
|
308
|
-
detalhes.forEach(item => {
|
|
309
|
-
var _a;
|
|
310
|
-
if (item && typeof item === 'object')
|
|
311
|
-
adicionar((_a = item.rotulo) !== null && _a !== void 0 ? _a : item.campo, item.valor);
|
|
312
|
-
});
|
|
313
|
-
return itens;
|
|
314
|
-
}
|
|
315
|
-
if (!detalhes || typeof detalhes !== 'object')
|
|
316
|
-
return itens;
|
|
317
|
-
const d = detalhes;
|
|
318
|
-
if (d.tipo === 'alteracao_cor') {
|
|
319
|
-
// tools/studio/AlterarCorTemaStudio.php
|
|
320
|
-
adicionar('Tema', d.tema);
|
|
321
|
-
adicionar('Loja', d.loja);
|
|
322
|
-
adicionar('Cor', d.rotulo);
|
|
323
|
-
adicionar('Valor atual', (_a = d.valor_atual) !== null && _a !== void 0 ? _a : 'sem valor definido');
|
|
324
|
-
adicionar('Novo valor', d.valor_novo);
|
|
325
|
-
return itens;
|
|
326
|
-
}
|
|
327
|
-
Object.keys(d)
|
|
328
|
-
.filter(chave => chave !== 'tipo' && !/^id(_|$)/.test(chave))
|
|
329
|
-
.forEach(chave => adicionar(chave, d[chave]));
|
|
330
|
-
return itens;
|
|
331
|
-
}
|
|
332
|
-
function humanizar(chave) {
|
|
333
|
-
if (/[A-Z ]/.test(chave))
|
|
334
|
-
return chave;
|
|
335
|
-
const t = chave.replace(/[_-]+/g, ' ').trim();
|
|
336
|
-
return t.charAt(0).toUpperCase() + t.slice(1);
|
|
337
|
-
}
|
|
338
|
-
/**
|
|
339
|
-
* Converte instrucoes_interface (Constants::INSTRUCOES_INTERFACE) em eventos tipados.
|
|
340
|
-
* Tipos fora da lista e campos inesperados são descartados. Nada é executado nem navegado aqui.
|
|
341
|
-
*/
|
|
342
|
-
function adaptarInstrucoes(instrucoes) {
|
|
343
|
-
if (!Array.isArray(instrucoes))
|
|
344
|
-
return [];
|
|
345
|
-
const eventos = [];
|
|
346
|
-
for (const item of instrucoes.slice(0, 10)) {
|
|
347
|
-
if (!item || typeof item !== 'object')
|
|
348
|
-
continue;
|
|
349
|
-
const bruto = item;
|
|
350
|
-
if (bruto.tipo === 'atualizar_preview_tema') {
|
|
351
|
-
const idLojaLeiaute = inteiro(bruto.id_loja_leiaute);
|
|
352
|
-
if (idLojaLeiaute)
|
|
353
|
-
eventos.push({ tipo: 'tema_atualizado', idLojaLeiaute });
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
return eventos;
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
const MENSAGENS_PADRAO = {
|
|
360
|
-
sessao: 'Sua sessão expirou. Entre novamente na Uishop para continuar com a Uiny.',
|
|
361
|
-
rede: 'Não foi possível conectar à Uiny. Verifique sua internet e tente de novo.',
|
|
362
|
-
timeout: 'A Uiny demorou demais para responder. Tente de novo em instantes.',
|
|
363
|
-
conflito: 'Não foi possível concluir agora. Atualize e tente de novo.',
|
|
364
|
-
nao_encontrado: 'Não encontramos o que você pediu. Ele pode ter sido removido.',
|
|
365
|
-
invalido: 'Não foi possível processar esse pedido.',
|
|
366
|
-
limite: 'Você enviou muitas mensagens em pouco tempo. Aguarde um pouco e tente de novo.',
|
|
367
|
-
servidor: 'A Uiny está com instabilidade no momento. Tente de novo em instantes.',
|
|
368
|
-
configuracao: 'A Uiny não está configurada neste sistema.',
|
|
369
|
-
};
|
|
370
|
-
/**
|
|
371
|
-
* Cliente HTTP da API da Uiny (uishop-ia, /api/v1).
|
|
372
|
-
*
|
|
373
|
-
* Usa um HttpClient sobre o HttpBackend, sem os interceptors da aplicação:
|
|
374
|
-
* - o ErrorInterceptor do uitec-ng-core troca o erro por uma string (perde status e o corpo,
|
|
375
|
-
* necessários para sessão expirada, ação expirada/invalidada e conflitos) e abre um toast global;
|
|
376
|
-
* - o SpinnerInterceptor cobriria a tela a cada mensagem.
|
|
377
|
-
* O token é o mesmo usado pelo JwtInterceptor (AuthService.currentUserValue.token) e só é
|
|
378
|
-
* anexado a requisições cuja URL começa com a URL-base configurada da Uiny.
|
|
379
|
-
*/
|
|
380
|
-
class UinyApiService {
|
|
381
|
-
constructor(httpBackend, session, config, env) {
|
|
382
|
-
this.session = session;
|
|
383
|
-
this.http = new HttpClient(httpBackend);
|
|
384
|
-
this.baseUrl = resolverUrlUiny(config, env);
|
|
385
|
-
}
|
|
386
|
-
get configurada() {
|
|
387
|
-
return !!this.baseUrl;
|
|
388
|
-
}
|
|
389
|
-
listarConversas() {
|
|
390
|
-
return defer(() => this.request('GET', '/conversas', null, UINY_TIMEOUT_CONSULTA_MS, new HttpParams().set('page', 1).set('per_page', 20)));
|
|
391
|
-
}
|
|
392
|
-
criarConversa(contexto) {
|
|
393
|
-
return defer(() => this.request('POST', '/conversas', { contexto }, UINY_TIMEOUT_CONSULTA_MS));
|
|
394
|
-
}
|
|
395
|
-
/** Página mais recente do histórico (até 100 mensagens), em ordem cronológica. */
|
|
396
|
-
historico(idConversa) {
|
|
397
|
-
return defer(() => this.request('GET', `/conversas/${this.id(idConversa)}`, null, UINY_TIMEOUT_CONSULTA_MS, new HttpParams().set('page', 1).set('per_page', 100)));
|
|
398
|
-
}
|
|
399
|
-
enviarMensagem(idConversa, texto, contexto) {
|
|
400
|
-
return defer(() => this.request('POST', `/conversas/${this.id(idConversa)}/mensagens`, { texto, contexto }, UINY_TIMEOUT_MENSAGEM_MS));
|
|
401
|
-
}
|
|
402
|
-
/** Confirma pelo id da ação persistida. Nenhum argumento é enviado. Nunca é repetida automaticamente. */
|
|
403
|
-
confirmarAcao(idAcao) {
|
|
404
|
-
return defer(() => this.request('POST', `/acoes/${this.id(idAcao)}/confirmar`, {}, UINY_TIMEOUT_ACAO_MS));
|
|
405
|
-
}
|
|
406
|
-
cancelarAcao(idAcao) {
|
|
407
|
-
return defer(() => this.request('POST', `/acoes/${this.id(idAcao)}/cancelar`, {}, UINY_TIMEOUT_CONSULTA_MS));
|
|
408
|
-
}
|
|
409
|
-
id(valor) {
|
|
410
|
-
const id = idValido(valor);
|
|
411
|
-
if (!id)
|
|
412
|
-
throw this.erro('invalido', 0);
|
|
413
|
-
return id;
|
|
414
|
-
}
|
|
415
|
-
request(method, path, body, timeoutMs, params) {
|
|
416
|
-
if (!this.baseUrl) {
|
|
417
|
-
return throwError(() => this.erro('configuracao', 0));
|
|
418
|
-
}
|
|
419
|
-
const url = this.baseUrl + path;
|
|
420
|
-
const token = this.session.token();
|
|
421
|
-
if (!token) {
|
|
422
|
-
return throwError(() => this.erro('sessao', 401));
|
|
423
|
-
}
|
|
424
|
-
let headers = new HttpHeaders({ 'Accept': 'application/json' });
|
|
425
|
-
// Garantia explícita: o token só segue para a URL-base da Uiny.
|
|
426
|
-
if (url.startsWith(this.baseUrl + '/')) {
|
|
427
|
-
headers = headers.set('Authorization', `Bearer ${token}`);
|
|
428
|
-
}
|
|
429
|
-
if (method === 'POST') {
|
|
430
|
-
headers = headers.set('Content-Type', 'application/json');
|
|
431
|
-
}
|
|
432
|
-
return this.http.request(method, url, { body: body !== null && body !== void 0 ? body : undefined, headers, params, responseType: 'json' }).pipe(timeout(timeoutMs), catchError(err => throwError(() => this.normalizarErro(err))));
|
|
433
|
-
}
|
|
434
|
-
normalizarErro(err) {
|
|
435
|
-
var _a, _b, _c;
|
|
436
|
-
if (err instanceof TimeoutError) {
|
|
437
|
-
return this.erro('timeout', 0);
|
|
438
|
-
}
|
|
439
|
-
if (!(err instanceof HttpErrorResponse)) {
|
|
440
|
-
return this.erro('servidor', 0);
|
|
441
|
-
}
|
|
442
|
-
const corpo = err.error && typeof err.error === 'object' ? err.error : null;
|
|
443
|
-
const correlacao = this.textoSeguro(corpo === null || corpo === void 0 ? void 0 : corpo.id_correlacao, 64) || this.textoSeguro((_a = err.headers) === null || _a === void 0 ? void 0 : _a.get('X-Correlation-Id'), 64);
|
|
444
|
-
const codigo = this.textoSeguro((_b = corpo === null || corpo === void 0 ? void 0 : corpo.erro) === null || _b === void 0 ? void 0 : _b.codigo, 60);
|
|
445
|
-
const mensagemApi = this.textoSeguro((_c = corpo === null || corpo === void 0 ? void 0 : corpo.erro) === null || _c === void 0 ? void 0 : _c.mensagem, 300);
|
|
446
|
-
let tipo;
|
|
447
|
-
if (err.status === 0)
|
|
448
|
-
tipo = 'rede';
|
|
449
|
-
else if (err.status === 401)
|
|
450
|
-
tipo = 'sessao';
|
|
451
|
-
else if (err.status === 404)
|
|
452
|
-
tipo = 'nao_encontrado';
|
|
453
|
-
else if (err.status === 409)
|
|
454
|
-
tipo = 'conflito';
|
|
455
|
-
else if (err.status === 429)
|
|
456
|
-
tipo = 'limite';
|
|
457
|
-
else if (err.status === 400 || err.status === 403 || err.status === 422)
|
|
458
|
-
tipo = 'invalido';
|
|
459
|
-
else
|
|
460
|
-
tipo = 'servidor';
|
|
461
|
-
if (tipo === 'sessao') {
|
|
462
|
-
this.session.recusarSessaoAtual();
|
|
463
|
-
}
|
|
464
|
-
// 502/503/504 trazem mensagens próprias e seguras (INTEGRACAO_*, PROVEDOR_IA_INDISPONIVEL).
|
|
465
|
-
// 500 (INTERNO) e falhas de rede usam sempre o texto padrão.
|
|
466
|
-
const usarMensagemApi = tipo !== 'rede' && tipo !== 'sessao' && err.status !== 500;
|
|
467
|
-
const mensagem = (usarMensagemApi && mensagemApi) || MENSAGENS_PADRAO[tipo];
|
|
468
|
-
return { tipo, status: err.status, codigo, mensagem, correlacao, corpo };
|
|
469
|
-
}
|
|
470
|
-
erro(tipo, status) {
|
|
471
|
-
return { tipo, status, codigo: null, mensagem: MENSAGENS_PADRAO[tipo], correlacao: null };
|
|
472
|
-
}
|
|
473
|
-
textoSeguro(valor, max) {
|
|
474
|
-
if (typeof valor !== 'string')
|
|
475
|
-
return null;
|
|
476
|
-
const texto = valor.trim();
|
|
477
|
-
if (!texto || /bearer\s/i.test(texto))
|
|
478
|
-
return null;
|
|
479
|
-
return texto.length > max ? texto.slice(0, max) + '…' : texto;
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
UinyApiService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: UinyApiService, deps: [{ token: i1$1.HttpBackend }, { token: UinySessionService }, { token: UINY_CONFIG, optional: true }, { token: 'APP_ENVIRONMENT', optional: true }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
483
|
-
UinyApiService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: UinyApiService, providedIn: 'root' });
|
|
484
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: UinyApiService, decorators: [{
|
|
485
|
-
type: Injectable,
|
|
486
|
-
args: [{ providedIn: 'root' }]
|
|
487
|
-
}], ctorParameters: function () {
|
|
488
|
-
return [{ type: i1$1.HttpBackend }, { type: UinySessionService }, { type: undefined, decorators: [{
|
|
489
|
-
type: Optional
|
|
490
|
-
}, {
|
|
491
|
-
type: Inject,
|
|
492
|
-
args: [UINY_CONFIG]
|
|
493
|
-
}] }, { type: undefined, decorators: [{
|
|
494
|
-
type: Optional
|
|
495
|
-
}, {
|
|
496
|
-
type: Inject,
|
|
497
|
-
args: ['APP_ENVIRONMENT']
|
|
498
|
-
}] }];
|
|
499
|
-
} });
|
|
500
|
-
|
|
501
|
-
/**
|
|
502
|
-
* Estado compartilhado da Uiny: quem habilitou (o header), quem hospeda o painel
|
|
503
|
-
* (o ui-assistant-layout), se está aberto, o contexto da tela e os eventos de saída.
|
|
504
|
-
*
|
|
505
|
-
* O painel só fica disponível quando TODAS as condições valem:
|
|
506
|
-
* - algum ui-header está com [showAssistant]="true";
|
|
507
|
-
* - existe um ui-assistant-layout na página para receber o painel;
|
|
508
|
-
* - há sessão autenticada no AuthService (e a API não a recusou);
|
|
509
|
-
* - a URL da API está configurada.
|
|
510
|
-
*/
|
|
511
|
-
class UiAssistantService {
|
|
512
|
-
constructor(session, api, config) {
|
|
513
|
-
this.session = session;
|
|
514
|
-
this.api = api;
|
|
515
|
-
this.config = config;
|
|
516
|
-
this.habilitadores$ = new BehaviorSubject(new Set());
|
|
517
|
-
this.hosts$ = new BehaviorSubject(0);
|
|
518
|
-
this.abertoInterno$ = new BehaviorSubject(false);
|
|
519
|
-
this.contextoInterno$ = new BehaviorSubject({});
|
|
520
|
-
this.eventosInternos$ = new Subject();
|
|
521
|
-
this.gatilho = null;
|
|
522
|
-
this.avisouSemHost = false;
|
|
523
|
-
this.contexto$ = this.contextoInterno$.pipe(distinctUntilChanged(mesmoContexto));
|
|
524
|
-
/** Ações concluídas e instruções de interface vindas da API, já validadas. */
|
|
525
|
-
this.eventos$ = this.eventosInternos$.asObservable();
|
|
526
|
-
this.disponivel$ = combineLatest([this.habilitadores$, this.hosts$, this.session.sessao$]).pipe(map(([habilitadores, hosts, sessao]) => habilitadores.size > 0 && hosts > 0 && !!sessao && this.api.configurada && !!this.config), distinctUntilChanged(), shareReplay({ bufferSize: 1, refCount: false }));
|
|
527
|
-
this.aberto$ = combineLatest([this.abertoInterno$, this.disponivel$]).pipe(map(([aberto, disponivel]) => aberto && disponivel), distinctUntilChanged(), shareReplay({ bufferSize: 1, refCount: false }));
|
|
528
|
-
// Indisponível (logout, sessão recusada, header sem a flag): fecha sem devolver foco.
|
|
529
|
-
this.disponivel$.subscribe(disponivel => {
|
|
530
|
-
if (!disponivel && this.abertoInterno$.value) {
|
|
531
|
-
this.gatilho = null;
|
|
532
|
-
this.abertoInterno$.next(false);
|
|
533
|
-
}
|
|
534
|
-
});
|
|
535
|
-
combineLatest([this.habilitadores$, this.hosts$]).subscribe(([habilitadores, hosts]) => this.diagnosticar(habilitadores.size > 0, hosts));
|
|
536
|
-
}
|
|
537
|
-
get aberto() {
|
|
538
|
-
return this.abertoInterno$.value;
|
|
539
|
-
}
|
|
540
|
-
get sistemaOrigem() {
|
|
541
|
-
var _a, _b;
|
|
542
|
-
return (_b = (_a = this.config) === null || _a === void 0 ? void 0 : _a.sistemaOrigem) !== null && _b !== void 0 ? _b : null;
|
|
543
|
-
}
|
|
544
|
-
abrir(gatilho) {
|
|
545
|
-
if (gatilho)
|
|
546
|
-
this.gatilho = gatilho;
|
|
547
|
-
this.abertoInterno$.next(true);
|
|
548
|
-
}
|
|
549
|
-
/** Fecha o painel e devolve o foco ao botão que o abriu, se ele ainda existir. */
|
|
550
|
-
fechar(devolverFoco = true) {
|
|
551
|
-
if (!this.abertoInterno$.value)
|
|
552
|
-
return;
|
|
553
|
-
this.abertoInterno$.next(false);
|
|
554
|
-
const gatilho = this.gatilho;
|
|
555
|
-
this.gatilho = null;
|
|
556
|
-
if (devolverFoco && gatilho) {
|
|
557
|
-
// espera o layout reexibir a aplicação (no celular ela fica recolhida)
|
|
558
|
-
setTimeout(() => gatilho.isConnected && gatilho.focus());
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
alternar(gatilho) {
|
|
562
|
-
this.abertoInterno$.value ? this.fechar() : this.abrir(gatilho);
|
|
563
|
-
}
|
|
564
|
-
/** Substitui o contexto da tela atual. Campos fora do tipo UinyContexto são ignorados. */
|
|
565
|
-
definirContexto(contexto) {
|
|
566
|
-
this.contextoInterno$.next(normalizarContexto(contexto));
|
|
567
|
-
}
|
|
568
|
-
/** Altera apenas os campos informados do contexto. */
|
|
569
|
-
atualizarContexto(parcial) {
|
|
570
|
-
this.contextoInterno$.next(normalizarContexto(Object.assign(Object.assign({}, this.contextoInterno$.value), parcial)));
|
|
571
|
-
}
|
|
572
|
-
get contexto() {
|
|
573
|
-
return this.contextoInterno$.value;
|
|
574
|
-
}
|
|
575
|
-
/** @internal usado pelo ui-header */
|
|
576
|
-
definirHabilitado(origem, habilitado) {
|
|
577
|
-
const atual = new Set(this.habilitadores$.value);
|
|
578
|
-
habilitado ? atual.add(origem) : atual.delete(origem);
|
|
579
|
-
if (atual.size !== this.habilitadores$.value.size)
|
|
580
|
-
this.habilitadores$.next(atual);
|
|
581
|
-
}
|
|
582
|
-
/** @internal usado pelo ui-assistant-layout */
|
|
583
|
-
registrarHost() {
|
|
584
|
-
this.hosts$.next(this.hosts$.value + 1);
|
|
585
|
-
let removido = false;
|
|
586
|
-
return () => {
|
|
587
|
-
if (removido)
|
|
588
|
-
return;
|
|
589
|
-
removido = true;
|
|
590
|
-
this.hosts$.next(Math.max(0, this.hosts$.value - 1));
|
|
591
|
-
};
|
|
592
|
-
}
|
|
593
|
-
/** @internal usado pelo serviço de conversa */
|
|
594
|
-
emitir(evento) {
|
|
595
|
-
this.eventosInternos$.next(evento);
|
|
596
|
-
}
|
|
597
|
-
diagnosticar(habilitado, hosts) {
|
|
598
|
-
if (!isDevMode() || !habilitado)
|
|
599
|
-
return;
|
|
600
|
-
if (!this.config) {
|
|
601
|
-
console.error('[Uiny] showAssistant está ativo, mas UiAssistantModule.forRoot({ sistemaOrigem }) não foi importado.');
|
|
602
|
-
}
|
|
603
|
-
else if (!this.api.configurada) {
|
|
604
|
-
console.error('[Uiny] URL da API não configurada. Informe APP_ENVIRONMENT.domain.uiny ou forRoot({ apiUrl }).');
|
|
605
|
-
}
|
|
606
|
-
else if (hosts === 0 && !this.avisouSemHost) {
|
|
607
|
-
// o layout pode ser criado logo depois do header; avisa só se continuar faltando
|
|
608
|
-
this.avisouSemHost = true;
|
|
609
|
-
setTimeout(() => {
|
|
610
|
-
if (this.hosts$.value === 0) {
|
|
611
|
-
console.warn('[Uiny] showAssistant está ativo, mas nenhum <ui-assistant-layout> envolve a aplicação. O botão fica oculto.');
|
|
612
|
-
}
|
|
613
|
-
}, 2000);
|
|
614
|
-
}
|
|
615
|
-
}
|
|
616
|
-
}
|
|
617
|
-
UiAssistantService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: UiAssistantService, deps: [{ token: UinySessionService }, { token: UinyApiService }, { token: UINY_CONFIG, optional: true }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
618
|
-
UiAssistantService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: UiAssistantService, providedIn: 'root' });
|
|
619
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: UiAssistantService, decorators: [{
|
|
620
|
-
type: Injectable,
|
|
621
|
-
args: [{ providedIn: 'root' }]
|
|
622
|
-
}], ctorParameters: function () {
|
|
623
|
-
return [{ type: UinySessionService }, { type: UinyApiService }, { type: undefined, decorators: [{
|
|
624
|
-
type: Optional
|
|
625
|
-
}, {
|
|
626
|
-
type: Inject,
|
|
627
|
-
args: [UINY_CONFIG]
|
|
628
|
-
}] }];
|
|
629
|
-
} });
|
|
630
|
-
|
|
631
|
-
/** Botão que abre/fecha a Uiny. Só aparece quando a assistente está disponível. */
|
|
632
|
-
class UiAssistantButtonComponent {
|
|
633
|
-
constructor(assistant) {
|
|
634
|
-
this.assistant = assistant;
|
|
635
|
-
}
|
|
636
|
-
}
|
|
637
|
-
UiAssistantButtonComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: UiAssistantButtonComponent, deps: [{ token: UiAssistantService }], target: i0.ɵɵFactoryTarget.Component });
|
|
638
|
-
UiAssistantButtonComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: UiAssistantButtonComponent, selector: "ui-assistant-button", ngImport: i0, template: "<button *ngIf=\"assistant.disponivel$ | async\" #botao type=\"button\" class=\"uiny-trigger\"\n [class.is-open]=\"assistant.aberto$ | async\"\n [attr.aria-expanded]=\"(assistant.aberto$ | async) ? 'true' : 'false'\"\n aria-controls=\"uiny-painel\"\n [attr.aria-label]=\"(assistant.aberto$ | async) ? 'Fechar a Uiny, assistente da Uishop' : 'Abrir a Uiny, assistente da Uishop'\"\n [title]=\"(assistant.aberto$ | async) ? 'Fechar a Uiny' : 'Falar com a Uiny'\"\n (click)=\"assistant.alternar(botao)\">\n <svg class=\"uiny-trigger__mark\" viewBox=\"0 0 24 24\" width=\"18\" height=\"18\" aria-hidden=\"true\" focusable=\"false\">\n <path d=\"M12 2.5c.5 3.9 2.6 6.9 6.4 8.2.5.2.5.9 0 1.1-3.8 1.3-5.9 4.3-6.4 8.2-.1.6-.9.6-1 0-.5-3.9-2.6-6.9-6.4-8.2-.5-.2-.5-.9 0-1.1 3.8-1.3 5.9-4.3 6.4-8.2.1-.6.9-.6 1 0Z\" fill=\"currentColor\"/>\n <path d=\"M19 2.8c.2 1.3.9 2.2 2.1 2.6.2.1.2.3 0 .4-1.2.4-1.9 1.3-2.1 2.6 0 .2-.3.2-.3 0-.2-1.3-.9-2.2-2.1-2.6-.2-.1-.2-.3 0-.4 1.2-.4 1.9-1.3 2.1-2.6 0-.2.3-.2.3 0Z\" fill=\"currentColor\" opacity=\".7\"/>\n </svg>\n <span class=\"uiny-trigger__label\">Uiny</span>\n</button>\n", styles: [":host{display:inline-flex}.uiny-trigger{display:inline-flex;align-items:center;gap:6px;height:34px;padding:0 14px 0 10px;border:1px solid rgba(115,102,255,.28);border-radius:999px;background:rgba(115,102,255,.08);color:var(--theme-default, #7366ff);font-size:13px;font-weight:600;line-height:1;cursor:pointer;transition:background-color .15s ease,border-color .15s ease,color .15s ease}.uiny-trigger:hover{background:rgba(115,102,255,.14);border-color:#7366ff73}.uiny-trigger:focus-visible{outline:2px solid var(--theme-default, #7366ff);outline-offset:2px}.uiny-trigger.is-open{background:var(--theme-default, #7366ff);border-color:var(--theme-default, #7366ff);color:#fff}.uiny-trigger__mark{flex:0 0 auto}@media (max-width: 575.98px){.uiny-trigger{width:34px;padding:0;justify-content:center}.uiny-trigger__label{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}}@media (prefers-reduced-motion: reduce){.uiny-trigger{transition:none}}\n"], dependencies: [{ kind: "directive", type: i1$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i1$2.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
639
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: UiAssistantButtonComponent, decorators: [{
|
|
640
|
-
type: Component,
|
|
641
|
-
args: [{ selector: 'ui-assistant-button', changeDetection: ChangeDetectionStrategy.OnPush, template: "<button *ngIf=\"assistant.disponivel$ | async\" #botao type=\"button\" class=\"uiny-trigger\"\n [class.is-open]=\"assistant.aberto$ | async\"\n [attr.aria-expanded]=\"(assistant.aberto$ | async) ? 'true' : 'false'\"\n aria-controls=\"uiny-painel\"\n [attr.aria-label]=\"(assistant.aberto$ | async) ? 'Fechar a Uiny, assistente da Uishop' : 'Abrir a Uiny, assistente da Uishop'\"\n [title]=\"(assistant.aberto$ | async) ? 'Fechar a Uiny' : 'Falar com a Uiny'\"\n (click)=\"assistant.alternar(botao)\">\n <svg class=\"uiny-trigger__mark\" viewBox=\"0 0 24 24\" width=\"18\" height=\"18\" aria-hidden=\"true\" focusable=\"false\">\n <path d=\"M12 2.5c.5 3.9 2.6 6.9 6.4 8.2.5.2.5.9 0 1.1-3.8 1.3-5.9 4.3-6.4 8.2-.1.6-.9.6-1 0-.5-3.9-2.6-6.9-6.4-8.2-.5-.2-.5-.9 0-1.1 3.8-1.3 5.9-4.3 6.4-8.2.1-.6.9-.6 1 0Z\" fill=\"currentColor\"/>\n <path d=\"M19 2.8c.2 1.3.9 2.2 2.1 2.6.2.1.2.3 0 .4-1.2.4-1.9 1.3-2.1 2.6 0 .2-.3.2-.3 0-.2-1.3-.9-2.2-2.1-2.6-.2-.1-.2-.3 0-.4 1.2-.4 1.9-1.3 2.1-2.6 0-.2.3-.2.3 0Z\" fill=\"currentColor\" opacity=\".7\"/>\n </svg>\n <span class=\"uiny-trigger__label\">Uiny</span>\n</button>\n", styles: [":host{display:inline-flex}.uiny-trigger{display:inline-flex;align-items:center;gap:6px;height:34px;padding:0 14px 0 10px;border:1px solid rgba(115,102,255,.28);border-radius:999px;background:rgba(115,102,255,.08);color:var(--theme-default, #7366ff);font-size:13px;font-weight:600;line-height:1;cursor:pointer;transition:background-color .15s ease,border-color .15s ease,color .15s ease}.uiny-trigger:hover{background:rgba(115,102,255,.14);border-color:#7366ff73}.uiny-trigger:focus-visible{outline:2px solid var(--theme-default, #7366ff);outline-offset:2px}.uiny-trigger.is-open{background:var(--theme-default, #7366ff);border-color:var(--theme-default, #7366ff);color:#fff}.uiny-trigger__mark{flex:0 0 auto}@media (max-width: 575.98px){.uiny-trigger{width:34px;padding:0;justify-content:center}.uiny-trigger__label{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}}@media (prefers-reduced-motion: reduce){.uiny-trigger{transition:none}}\n"] }]
|
|
642
|
-
}], ctorParameters: function () { return [{ type: UiAssistantService }]; } });
|
|
643
|
-
|
|
644
27
|
class MyAccountComponent {
|
|
645
28
|
constructor(authService, urlService) {
|
|
646
29
|
this.authService = authService;
|
|
@@ -665,7 +48,7 @@ class MyAccountComponent {
|
|
|
665
48
|
}
|
|
666
49
|
}
|
|
667
50
|
MyAccountComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MyAccountComponent, deps: [{ token: i1.AuthService }, { token: i1.BaseUrlService }], target: i0.ɵɵFactoryTarget.Component });
|
|
668
|
-
MyAccountComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: MyAccountComponent, selector: "my-account", inputs: { menus: "menus" }, outputs: { onNavigate: "onNavigate" }, ngImport: i0, template: "<ui-user-top [urlImage]=\"urlService.imagemUsuario({model: userObs?.usuario})\" [usuario]=\"userObs?.usuario\"\r\n [acesso]=\"accessObs\"></ui-user-top>\r\n\r\n<ul class=\"profile-dropdown onhover-show-div\">\r\n <li *ngFor=\"let col of menus\">\r\n <a (click)=\"clickMenu(col)\">\r\n <ui-icon [icon]=\"col.ds_icone\" size=\"20\"></ui-icon>\r\n <span>{{col.no_funcionalidade}}</span>\r\n </a>\r\n </li>\r\n <li>\r\n <a href=\"javascript:void(0)\" (click)=\"logout()\" class=\"text-danger\">\r\n <ui-icon icon=\"login\" size=\"20\"></ui-icon>\r\n <span>Sair</span>\r\n </a>\r\n </li>\r\n</ul>\r\n", styles: ["a{display:flex!important;align-items:center!important}ui-icon{display:flex;padding-right:1rem}ui-image{margin-top:4px}\n"], dependencies: [{ kind: "directive", type:
|
|
51
|
+
MyAccountComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: MyAccountComponent, selector: "my-account", inputs: { menus: "menus" }, outputs: { onNavigate: "onNavigate" }, ngImport: i0, template: "<ui-user-top [urlImage]=\"urlService.imagemUsuario({model: userObs?.usuario})\" [usuario]=\"userObs?.usuario\"\r\n [acesso]=\"accessObs\"></ui-user-top>\r\n\r\n<ul class=\"profile-dropdown onhover-show-div\">\r\n <li *ngFor=\"let col of menus\">\r\n <a (click)=\"clickMenu(col)\">\r\n <ui-icon [icon]=\"col.ds_icone\" size=\"20\"></ui-icon>\r\n <span>{{col.no_funcionalidade}}</span>\r\n </a>\r\n </li>\r\n <li>\r\n <a href=\"javascript:void(0)\" (click)=\"logout()\" class=\"text-danger\">\r\n <ui-icon icon=\"login\" size=\"20\"></ui-icon>\r\n <span>Sair</span>\r\n </a>\r\n </li>\r\n</ul>\r\n", styles: ["a{display:flex!important;align-items:center!important}ui-icon{display:flex;padding-right:1rem}ui-image{margin-top:4px}\n"], dependencies: [{ kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: i3.UiIconComponent, selector: "ui-icon", inputs: ["icon", "size", "class"] }, { kind: "component", type: i4.UiUserTopComponent, selector: "ui-user-top", inputs: ["urlImage", "usuario", "acesso"] }] });
|
|
669
52
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MyAccountComponent, decorators: [{
|
|
670
53
|
type: Component,
|
|
671
54
|
args: [{ selector: 'my-account', template: "<ui-user-top [urlImage]=\"urlService.imagemUsuario({model: userObs?.usuario})\" [usuario]=\"userObs?.usuario\"\r\n [acesso]=\"accessObs\"></ui-user-top>\r\n\r\n<ul class=\"profile-dropdown onhover-show-div\">\r\n <li *ngFor=\"let col of menus\">\r\n <a (click)=\"clickMenu(col)\">\r\n <ui-icon [icon]=\"col.ds_icone\" size=\"20\"></ui-icon>\r\n <span>{{col.no_funcionalidade}}</span>\r\n </a>\r\n </li>\r\n <li>\r\n <a href=\"javascript:void(0)\" (click)=\"logout()\" class=\"text-danger\">\r\n <ui-icon icon=\"login\" size=\"20\"></ui-icon>\r\n <span>Sair</span>\r\n </a>\r\n </li>\r\n</ul>\r\n", styles: ["a{display:flex!important;align-items:center!important}ui-icon{display:flex;padding-right:1rem}ui-image{margin-top:4px}\n"] }]
|
|
@@ -676,30 +59,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
|
|
|
676
59
|
}] } });
|
|
677
60
|
|
|
678
61
|
class UiHeaderComponent {
|
|
679
|
-
constructor(authService, urlService, layoutService, iframeService,
|
|
62
|
+
constructor(authService, urlService, layoutService, iframeService, document) {
|
|
680
63
|
this.authService = authService;
|
|
681
64
|
this.urlService = urlService;
|
|
682
65
|
this.layoutService = layoutService;
|
|
683
66
|
this.iframeService = iframeService;
|
|
684
|
-
this.assistantService = assistantService;
|
|
685
67
|
this.document = document;
|
|
686
68
|
this.sidebar = true;
|
|
69
|
+
this.fullWidth = false;
|
|
687
70
|
this.redirectHome = true;
|
|
688
71
|
this.darkDefault = "light";
|
|
689
|
-
/** Exibe o botão da Uiny (assistente virtual). Exige um <ui-assistant-layout> envolvendo a aplicação. */
|
|
690
|
-
this.showAssistant = false;
|
|
691
72
|
this.collapseSidebarChange = new EventEmitter();
|
|
692
73
|
this.fullScreenChange = new EventEmitter();
|
|
693
74
|
this.headerBackdropChange = new EventEmitter();
|
|
694
75
|
this.onNavigate = new EventEmitter();
|
|
695
|
-
|
|
696
|
-
ngOnChanges(changes) {
|
|
697
|
-
if (changes['showAssistant']) {
|
|
698
|
-
this.assistantService.definirHabilitado(this, !!this.showAssistant);
|
|
699
|
-
}
|
|
700
|
-
}
|
|
701
|
-
ngOnDestroy() {
|
|
702
|
-
this.assistantService.definirHabilitado(this, false);
|
|
76
|
+
this.onUpgrade = new EventEmitter();
|
|
703
77
|
}
|
|
704
78
|
ngOnInit() {
|
|
705
79
|
this.elem = document.documentElement;
|
|
@@ -765,6 +139,10 @@ class UiHeaderComponent {
|
|
|
765
139
|
this.statuSidebar = this.collapseSidebar;
|
|
766
140
|
localStorage.setItem('local', this.statuSidebar);
|
|
767
141
|
}
|
|
142
|
+
fecharBackdrop() {
|
|
143
|
+
this.headerBackdrop = null;
|
|
144
|
+
this.headerBackdropChange.emit(false);
|
|
145
|
+
}
|
|
768
146
|
sidebarToggle() {
|
|
769
147
|
this.collapseSidebar = !this.collapseSidebar;
|
|
770
148
|
this.setStatusSideBar();
|
|
@@ -839,13 +217,13 @@ class UiHeaderComponent {
|
|
|
839
217
|
}
|
|
840
218
|
}
|
|
841
219
|
}
|
|
842
|
-
UiHeaderComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: UiHeaderComponent, deps: [{ token: i1.AuthService }, { token: i1.BaseUrlService }, { token: i1.LayoutService }, { token: i1.IframeService }, { token:
|
|
843
|
-
UiHeaderComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: UiHeaderComponent, selector: "ui-header", inputs: { collapseSidebar: "collapseSidebar", fullScreen: "fullScreen", headerBackdrop: "headerBackdrop", isFree: "isFree", menus: "menus", sidebar: "sidebar",
|
|
220
|
+
UiHeaderComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: UiHeaderComponent, deps: [{ token: i1.AuthService }, { token: i1.BaseUrlService }, { token: i1.LayoutService }, { token: i1.IframeService }, { token: DOCUMENT }], target: i0.ɵɵFactoryTarget.Component });
|
|
221
|
+
UiHeaderComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: UiHeaderComponent, selector: "ui-header", inputs: { collapseSidebar: "collapseSidebar", fullScreen: "fullScreen", headerBackdrop: "headerBackdrop", isFree: "isFree", menus: "menus", sidebar: "sidebar", fullWidth: "fullWidth", redirectHome: "redirectHome", darkDefault: "darkDefault" }, outputs: { collapseSidebarChange: "collapseSidebarChange", fullScreenChange: "fullScreenChange", headerBackdropChange: "headerBackdropChange", onNavigate: "onNavigate", onUpgrade: "onUpgrade" }, queries: [{ propertyName: "left", first: true, predicate: ["left"], descendants: true }, { propertyName: "center", first: true, predicate: ["center"], descendants: true }, { propertyName: "right", first: true, predicate: ["right"], descendants: true }], ngImport: i0, template: "<!-- Page Header Backdrop -->\r\n<div *ngIf=\"headerBackdrop\" (click)=\"fecharBackdrop()\" class=\"header-backgrop\"></div>\r\n\r\n<!-- Page Header Start -->\r\n<div class=\"page-header\" [class.close_icon]=\"collapseSidebar\" [class.not-sidebar]=\"!sidebar\"\r\n [class.full-width]=\"fullWidth\">\r\n <div class=\"header-wrapper d-flex m-0 justify-content-between\">\r\n <div class=\"header-logo-wrapper col-auto d-lg-none px-0\">\r\n <div *ngIf=\"sidebar\" class=\"toggle-sidebar\" (click)=\"sidebarToggle()\">\r\n <ui-icon icon=\"menu\" class=\"status_toggle middle\"></ui-icon>\r\n </div>\r\n <a (click)=\"home()\" [class.cursor-pointer]=\"redirectHome\">\r\n <img class=\"img-fluid for-dark image-logo d-md-none\" src=\"assets/images/logo/logo_dark.png\" alt=\"\" />\r\n </a>\r\n </div>\r\n\r\n <div class=\"left-header horizontal-wrapper ps-0\">\r\n <ng-container [ngTemplateOutlet]=\"left\"></ng-container>\r\n </div>\r\n\r\n <div class=\"nav-center\">\r\n <ng-container [ngTemplateOutlet]=\"center\"></ng-container>\r\n </div>\r\n\r\n <div class=\"nav-right p-0\">\r\n <ul class=\"nav-menus\">\r\n <!-- <li class=\"language-nav\" (click)=\"languageToggle()\">\r\n <header-languages></header-languages>\r\n </li> -->\r\n <ng-container *ngIf=\"isFree; then liUpgrade; else liEmpty\"></ng-container>\r\n\r\n <ng-template #liUpgrade>\r\n <li>\r\n <button\r\n class=\"d-flex align-items-center justify-content-center border-0 rounded-pill gap-2 b-color\"\r\n (click)=\"onUpgrade.emit()\">\r\n <img src=\"assets/images/coroa.svg\" class=\"w-auto\" alt=\"icone-coroa\" />\r\n Fa\u00E7a Upgrade\r\n </button>\r\n </li>\r\n </ng-template>\r\n <ng-template #liEmpty>\r\n <li></li>\r\n </ng-template>\r\n\r\n <ng-container [ngTemplateOutlet]=\"right\"></ng-container>\r\n\r\n <li>\r\n <div class=\"mode cursor-pointer\" (click)=\"layoutToggle()\">\r\n <ui-icon pTooltip=\"Ativar Modo Escuro\" tooltipPosition=\"bottom\" icon=\"dark_mode\" size=\"24\"\r\n *ngIf=\"!dark\"></ui-icon>\r\n <ui-icon pTooltip=\"Ativar Modo Claro\" tooltipPosition=\"bottom\" icon=\"sunny\" size=\"24\"\r\n *ngIf=\"dark\"></ui-icon>\r\n\r\n </div>\r\n </li>\r\n\r\n <li class=\"maximize\">\r\n <a pTooltip=\"Maximizar\" tooltipPosition=\"bottom\" class=\"text-dark cursor-pointer\"\r\n href=\"javascript:void(0)\" (click)=\"toggleFullScreen()\">\r\n <ui-icon icon=\"fullscreen\" size=\"24\"></ui-icon>\r\n </a>\r\n </li>\r\n <li class=\"profile-nav onhover-dropdown p-0 ps-2\">\r\n <my-account [menus]=\"menus\" (onNavigate)=\"onNavigate.emit($event)\"></my-account>\r\n </li>\r\n </ul>\r\n </div>\r\n </div>\r\n</div>\r\n<!-- Page Header Ends -->\r\n", styles: ["@charset \"UTF-8\";::ng-deep .ambiente{position:fixed;top:0;right:0;left:0;height:2px;z-index:999;text-align:center}::ng-deep .ambiente span{content:\"\";position:absolute;height:20px;width:100px;right:0;margin:auto;border-radius:0 0 0 20px;text-align:center;color:#fff;font-size:12px;padding:0}::ng-deep .ambiente.ambiente-develop{background-color:#09b409}::ng-deep .ambiente.ambiente-develop span{background-color:#09b409}::ng-deep .ambiente.ambiente-homolog{background-color:#ff5d22}::ng-deep .ambiente.ambiente-homolog span{background-color:#ff5d22}::ng-deep .header-backgrop{position:fixed;inset:0;z-index:8}::ng-deep .header-backgrop .page-header{z-index:11!important}::ng-deep .image-logo{width:auto;height:20px}::ng-deep .header-logo-wrapper.col-auto.d-lg-none.px-0{height:20px}::ng-deep ui-icon.status_toggle.middle{color:#7366ff}::ng-deep ui-icon.icons-menu{height:20px}::ng-deep .mode.d-none.d-md-block{height:20px}::ng-deep .b-color{color:#e9e7ff;background:var(--theme-default, #7366ff);height:36px;width:136px}::ng-deep .b-color img{height:15px}::ng-deep .page-wrapper .page-header.not-sidebar,::ng-deep .page-wrapper .page-header.full-width{margin-left:0!important;width:100%!important}::ng-deep .page-wrapper .page-header .header-wrapper{flex-direction:row}::ng-deep .page-wrapper .page-header .header-wrapper .nav-right>ul li{padding:0 10px!important;margin-right:0}::ng-deep .page-wrapper .page-header .header-wrapper .nav-right>ul li .profile-media img{width:100%!important}@media (min-width: 577px){::ng-deep .page-wrapper .page-header.not-sidebar .header-logo-wrapper{display:block!important}::ng-deep .page-wrapper .page-header.not-sidebar .header-logo-wrapper img{display:block!important}}@media (max-width: 576px){::ng-deep .hide-mobile{display:none!important}}@media only screen and (max-width: 575.98px){::ng-deep .nav-menus{margin-right:0!important}::ng-deep .page-wrapper .header-wrapper{flex-direction:row}::ng-deep .page-wrapper .header-wrapper .nav-right>ul li{padding:0 10px!important}::ng-deep .page-wrapper .header-wrapper .nav-right>ul li:last-child{padding-right:0!important}::ng-deep .page-wrapper .header-wrapper .nav-right>ul li .profile-media img{width:100%!important}}::ng-deep body .dark-only li.maximize .text-dark span{color:#ffffffb3!important}\n"], dependencies: [{ kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: i3.UiIconComponent, selector: "ui-icon", inputs: ["icon", "size", "class"] }, { kind: "directive", type: i4$1.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "appendTo", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions"] }, { kind: "component", type: MyAccountComponent, selector: "my-account", inputs: ["menus"], outputs: ["onNavigate"] }] });
|
|
844
222
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: UiHeaderComponent, decorators: [{
|
|
845
223
|
type: Component,
|
|
846
|
-
args: [{ selector: 'ui-header', template: "<!-- Page Header Backdrop -->\r\n<div *ngIf=\"headerBackdrop\" (click)=\"
|
|
224
|
+
args: [{ selector: 'ui-header', template: "<!-- Page Header Backdrop -->\r\n<div *ngIf=\"headerBackdrop\" (click)=\"fecharBackdrop()\" class=\"header-backgrop\"></div>\r\n\r\n<!-- Page Header Start -->\r\n<div class=\"page-header\" [class.close_icon]=\"collapseSidebar\" [class.not-sidebar]=\"!sidebar\"\r\n [class.full-width]=\"fullWidth\">\r\n <div class=\"header-wrapper d-flex m-0 justify-content-between\">\r\n <div class=\"header-logo-wrapper col-auto d-lg-none px-0\">\r\n <div *ngIf=\"sidebar\" class=\"toggle-sidebar\" (click)=\"sidebarToggle()\">\r\n <ui-icon icon=\"menu\" class=\"status_toggle middle\"></ui-icon>\r\n </div>\r\n <a (click)=\"home()\" [class.cursor-pointer]=\"redirectHome\">\r\n <img class=\"img-fluid for-dark image-logo d-md-none\" src=\"assets/images/logo/logo_dark.png\" alt=\"\" />\r\n </a>\r\n </div>\r\n\r\n <div class=\"left-header horizontal-wrapper ps-0\">\r\n <ng-container [ngTemplateOutlet]=\"left\"></ng-container>\r\n </div>\r\n\r\n <div class=\"nav-center\">\r\n <ng-container [ngTemplateOutlet]=\"center\"></ng-container>\r\n </div>\r\n\r\n <div class=\"nav-right p-0\">\r\n <ul class=\"nav-menus\">\r\n <!-- <li class=\"language-nav\" (click)=\"languageToggle()\">\r\n <header-languages></header-languages>\r\n </li> -->\r\n <ng-container *ngIf=\"isFree; then liUpgrade; else liEmpty\"></ng-container>\r\n\r\n <ng-template #liUpgrade>\r\n <li>\r\n <button\r\n class=\"d-flex align-items-center justify-content-center border-0 rounded-pill gap-2 b-color\"\r\n (click)=\"onUpgrade.emit()\">\r\n <img src=\"assets/images/coroa.svg\" class=\"w-auto\" alt=\"icone-coroa\" />\r\n Fa\u00E7a Upgrade\r\n </button>\r\n </li>\r\n </ng-template>\r\n <ng-template #liEmpty>\r\n <li></li>\r\n </ng-template>\r\n\r\n <ng-container [ngTemplateOutlet]=\"right\"></ng-container>\r\n\r\n <li>\r\n <div class=\"mode cursor-pointer\" (click)=\"layoutToggle()\">\r\n <ui-icon pTooltip=\"Ativar Modo Escuro\" tooltipPosition=\"bottom\" icon=\"dark_mode\" size=\"24\"\r\n *ngIf=\"!dark\"></ui-icon>\r\n <ui-icon pTooltip=\"Ativar Modo Claro\" tooltipPosition=\"bottom\" icon=\"sunny\" size=\"24\"\r\n *ngIf=\"dark\"></ui-icon>\r\n\r\n </div>\r\n </li>\r\n\r\n <li class=\"maximize\">\r\n <a pTooltip=\"Maximizar\" tooltipPosition=\"bottom\" class=\"text-dark cursor-pointer\"\r\n href=\"javascript:void(0)\" (click)=\"toggleFullScreen()\">\r\n <ui-icon icon=\"fullscreen\" size=\"24\"></ui-icon>\r\n </a>\r\n </li>\r\n <li class=\"profile-nav onhover-dropdown p-0 ps-2\">\r\n <my-account [menus]=\"menus\" (onNavigate)=\"onNavigate.emit($event)\"></my-account>\r\n </li>\r\n </ul>\r\n </div>\r\n </div>\r\n</div>\r\n<!-- Page Header Ends -->\r\n", styles: ["@charset \"UTF-8\";::ng-deep .ambiente{position:fixed;top:0;right:0;left:0;height:2px;z-index:999;text-align:center}::ng-deep .ambiente span{content:\"\";position:absolute;height:20px;width:100px;right:0;margin:auto;border-radius:0 0 0 20px;text-align:center;color:#fff;font-size:12px;padding:0}::ng-deep .ambiente.ambiente-develop{background-color:#09b409}::ng-deep .ambiente.ambiente-develop span{background-color:#09b409}::ng-deep .ambiente.ambiente-homolog{background-color:#ff5d22}::ng-deep .ambiente.ambiente-homolog span{background-color:#ff5d22}::ng-deep .header-backgrop{position:fixed;inset:0;z-index:8}::ng-deep .header-backgrop .page-header{z-index:11!important}::ng-deep .image-logo{width:auto;height:20px}::ng-deep .header-logo-wrapper.col-auto.d-lg-none.px-0{height:20px}::ng-deep ui-icon.status_toggle.middle{color:#7366ff}::ng-deep ui-icon.icons-menu{height:20px}::ng-deep .mode.d-none.d-md-block{height:20px}::ng-deep .b-color{color:#e9e7ff;background:var(--theme-default, #7366ff);height:36px;width:136px}::ng-deep .b-color img{height:15px}::ng-deep .page-wrapper .page-header.not-sidebar,::ng-deep .page-wrapper .page-header.full-width{margin-left:0!important;width:100%!important}::ng-deep .page-wrapper .page-header .header-wrapper{flex-direction:row}::ng-deep .page-wrapper .page-header .header-wrapper .nav-right>ul li{padding:0 10px!important;margin-right:0}::ng-deep .page-wrapper .page-header .header-wrapper .nav-right>ul li .profile-media img{width:100%!important}@media (min-width: 577px){::ng-deep .page-wrapper .page-header.not-sidebar .header-logo-wrapper{display:block!important}::ng-deep .page-wrapper .page-header.not-sidebar .header-logo-wrapper img{display:block!important}}@media (max-width: 576px){::ng-deep .hide-mobile{display:none!important}}@media only screen and (max-width: 575.98px){::ng-deep .nav-menus{margin-right:0!important}::ng-deep .page-wrapper .header-wrapper{flex-direction:row}::ng-deep .page-wrapper .header-wrapper .nav-right>ul li{padding:0 10px!important}::ng-deep .page-wrapper .header-wrapper .nav-right>ul li:last-child{padding-right:0!important}::ng-deep .page-wrapper .header-wrapper .nav-right>ul li .profile-media img{width:100%!important}}::ng-deep body .dark-only li.maximize .text-dark span{color:#ffffffb3!important}\n"] }]
|
|
847
225
|
}], ctorParameters: function () {
|
|
848
|
-
return [{ type: i1.AuthService }, { type: i1.BaseUrlService }, { type: i1.LayoutService }, { type: i1.IframeService }, { type:
|
|
226
|
+
return [{ type: i1.AuthService }, { type: i1.BaseUrlService }, { type: i1.LayoutService }, { type: i1.IframeService }, { type: undefined, decorators: [{
|
|
849
227
|
type: Inject,
|
|
850
228
|
args: [DOCUMENT]
|
|
851
229
|
}] }];
|
|
@@ -861,12 +239,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
|
|
|
861
239
|
type: Input
|
|
862
240
|
}], sidebar: [{
|
|
863
241
|
type: Input
|
|
242
|
+
}], fullWidth: [{
|
|
243
|
+
type: Input
|
|
864
244
|
}], redirectHome: [{
|
|
865
245
|
type: Input
|
|
866
246
|
}], darkDefault: [{
|
|
867
247
|
type: Input
|
|
868
|
-
}], showAssistant: [{
|
|
869
|
-
type: Input
|
|
870
248
|
}], collapseSidebarChange: [{
|
|
871
249
|
type: Output
|
|
872
250
|
}], fullScreenChange: [{
|
|
@@ -875,6 +253,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
|
|
|
875
253
|
type: Output
|
|
876
254
|
}], onNavigate: [{
|
|
877
255
|
type: Output
|
|
256
|
+
}], onUpgrade: [{
|
|
257
|
+
type: Output
|
|
878
258
|
}], left: [{
|
|
879
259
|
type: ContentChild,
|
|
880
260
|
args: ['left']
|
|
@@ -886,1165 +266,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
|
|
|
886
266
|
args: ['right']
|
|
887
267
|
}] } });
|
|
888
268
|
|
|
889
|
-
const ROTULOS = {
|
|
890
|
-
pendente: 'Aguardando sua confirmação',
|
|
891
|
-
executando: 'Executando…',
|
|
892
|
-
concluida: 'Concluída',
|
|
893
|
-
cancelada: 'Cancelada',
|
|
894
|
-
expirada: 'Expirada',
|
|
895
|
-
invalidada: 'Precisa de nova confirmação',
|
|
896
|
-
falha: 'Não concluída',
|
|
897
|
-
indeterminada: 'Resultado a verificar',
|
|
898
|
-
};
|
|
899
|
-
const DESCRICOES = {
|
|
900
|
-
concluida: 'A alteração foi aplicada.',
|
|
901
|
-
cancelada: 'Nada foi alterado.',
|
|
902
|
-
expirada: 'O prazo para confirmar terminou. Nada foi alterado; peça de novo se ainda quiser.',
|
|
903
|
-
invalidada: 'Os dados mudaram desde a proposta. Peça a alteração de novo para revisar.',
|
|
904
|
-
falha: 'A alteração não foi aplicada.',
|
|
905
|
-
};
|
|
906
|
-
/**
|
|
907
|
-
* Card de ação pendente. A confirmação só acontece pelo clique em "Confirmar":
|
|
908
|
-
* o card emite apenas o id da ação persistida, sem argumentos.
|
|
909
|
-
*/
|
|
910
|
-
class UiAssistantActionCardComponent {
|
|
911
|
-
constructor(cdr, zone) {
|
|
912
|
-
this.cdr = cdr;
|
|
913
|
-
this.zone = zone;
|
|
914
|
-
this.confirmar = new EventEmitter();
|
|
915
|
-
this.cancelar = new EventEmitter();
|
|
916
|
-
this.verificar = new EventEmitter();
|
|
917
|
-
this.agora = Date.now();
|
|
918
|
-
}
|
|
919
|
-
ngOnChanges() {
|
|
920
|
-
this.agendar();
|
|
921
|
-
}
|
|
922
|
-
ngOnDestroy() {
|
|
923
|
-
clearInterval(this.timer);
|
|
924
|
-
}
|
|
925
|
-
/** O servidor decide a expiração; aqui só evitamos oferecer um clique que já vai falhar. */
|
|
926
|
-
get expiradaLocalmente() {
|
|
927
|
-
var _a;
|
|
928
|
-
return ((_a = this.acao) === null || _a === void 0 ? void 0 : _a.estado) === 'pendente' && !!this.acao.expiraEm && this.acao.expiraEm.getTime() <= this.agora;
|
|
929
|
-
}
|
|
930
|
-
get estado() {
|
|
931
|
-
var _a;
|
|
932
|
-
return this.expiradaLocalmente ? 'expirada' : (_a = this.acao) === null || _a === void 0 ? void 0 : _a.estado;
|
|
933
|
-
}
|
|
934
|
-
get rotulo() {
|
|
935
|
-
var _a;
|
|
936
|
-
return (_a = ROTULOS[this.estado]) !== null && _a !== void 0 ? _a : '';
|
|
937
|
-
}
|
|
938
|
-
get descricao() {
|
|
939
|
-
var _a;
|
|
940
|
-
return ((_a = this.acao) === null || _a === void 0 ? void 0 : _a.aviso) || DESCRICOES[this.estado] || null;
|
|
941
|
-
}
|
|
942
|
-
get podeDecidir() {
|
|
943
|
-
return this.estado === 'pendente' && !this.acao.enviando;
|
|
944
|
-
}
|
|
945
|
-
get minutosRestantes() {
|
|
946
|
-
if (this.estado !== 'pendente' || !this.acao.expiraEm)
|
|
947
|
-
return null;
|
|
948
|
-
return Math.max(1, Math.ceil((this.acao.expiraEm.getTime() - this.agora) / 60000));
|
|
949
|
-
}
|
|
950
|
-
ehCor(valor) {
|
|
951
|
-
return /^#(?:[0-9a-f]{3}|[0-9a-f]{6}|[0-9a-f]{8})$/i.test(valor);
|
|
952
|
-
}
|
|
953
|
-
aoConfirmar() {
|
|
954
|
-
if (this.podeDecidir)
|
|
955
|
-
this.confirmar.emit(this.acao.id);
|
|
956
|
-
}
|
|
957
|
-
aoCancelar() {
|
|
958
|
-
if (this.podeDecidir)
|
|
959
|
-
this.cancelar.emit(this.acao.id);
|
|
960
|
-
}
|
|
961
|
-
agendar() {
|
|
962
|
-
var _a;
|
|
963
|
-
clearInterval(this.timer);
|
|
964
|
-
this.agora = Date.now();
|
|
965
|
-
if (((_a = this.acao) === null || _a === void 0 ? void 0 : _a.estado) !== 'pendente' || !this.acao.expiraEm)
|
|
966
|
-
return;
|
|
967
|
-
this.zone.runOutsideAngular(() => {
|
|
968
|
-
this.timer = setInterval(() => this.zone.run(() => {
|
|
969
|
-
this.agora = Date.now();
|
|
970
|
-
if (this.expiradaLocalmente)
|
|
971
|
-
clearInterval(this.timer);
|
|
972
|
-
this.cdr.markForCheck();
|
|
973
|
-
}), 15000);
|
|
974
|
-
});
|
|
975
|
-
}
|
|
976
|
-
}
|
|
977
|
-
UiAssistantActionCardComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: UiAssistantActionCardComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component });
|
|
978
|
-
UiAssistantActionCardComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: UiAssistantActionCardComponent, selector: "ui-assistant-action-card", inputs: { acao: "acao" }, outputs: { confirmar: "confirmar", cancelar: "cancelar", verificar: "verificar" }, usesOnChanges: true, ngImport: i0, template: "<article class=\"uiny-acao\" [ngClass]=\"'uiny-acao--' + estado\" [attr.aria-busy]=\"acao.enviando ? 'true' : null\"\n [attr.aria-labelledby]=\"'uiny-acao-' + acao.id\">\n <header class=\"uiny-acao__topo\">\n <span class=\"uiny-acao__selo\">\n <span *ngIf=\"estado === 'executando' || acao.enviando\" class=\"uiny-acao__spinner\" aria-hidden=\"true\"></span>\n <ui-icon *ngIf=\"estado === 'concluida'\" icon=\"check_circle\" size=\"16\"></ui-icon>\n <ui-icon *ngIf=\"estado === 'falha' || estado === 'indeterminada'\" icon=\"error\" size=\"16\"></ui-icon>\n <ui-icon *ngIf=\"estado === 'pendente' && !acao.enviando\" icon=\"pending_actions\" size=\"16\"></ui-icon>\n {{ rotulo }}\n </span>\n <span *ngIf=\"minutosRestantes\" class=\"uiny-acao__prazo\">expira em {{ minutosRestantes }} min</span>\n </header>\n\n <p class=\"uiny-acao__resumo\" [id]=\"'uiny-acao-' + acao.id\">{{ acao.resumo }}</p>\n\n <dl *ngIf=\"acao.detalhes?.length\" class=\"uiny-acao__detalhes\">\n <div *ngFor=\"let d of acao.detalhes\" class=\"uiny-acao__item\">\n <dt>{{ d.rotulo }}</dt>\n <dd>\n <span *ngIf=\"ehCor(d.valor)\" class=\"uiny-acao__cor\" [style.background-color]=\"d.valor\" aria-hidden=\"true\"></span>\n {{ d.valor }}\n </dd>\n </div>\n </dl>\n\n <p *ngIf=\"descricao\" class=\"uiny-acao__descricao\" role=\"status\">{{ descricao }}</p>\n\n <div *ngIf=\"estado === 'pendente'\" class=\"uiny-acao__botoes\">\n <button type=\"button\" class=\"uiny-acao__botao uiny-acao__botao--secundario\" [disabled]=\"!podeDecidir\" (click)=\"aoCancelar()\">\n Cancelar\n </button>\n <button type=\"button\" class=\"uiny-acao__botao uiny-acao__botao--primario\" [disabled]=\"!podeDecidir\" (click)=\"aoConfirmar()\">\n Confirmar\n </button>\n </div>\n\n <div *ngIf=\"estado === 'indeterminada'\" class=\"uiny-acao__botoes\">\n <button type=\"button\" class=\"uiny-acao__botao uiny-acao__botao--secundario\" [disabled]=\"acao.enviando\" (click)=\"verificar.emit(acao.id)\">\n Verificar resultado\n </button>\n </div>\n</article>\n", styles: [":host{display:block;margin-top:8px}.uiny-acao{padding:12px 14px;border:1px solid var(--uiny-borda, #ececf3);border-left:3px solid var(--uiny-primaria, #7366ff);border-radius:12px;background:var(--uiny-fundo, #fff);box-shadow:0 2px 10px #1f1b4d0d}.uiny-acao--concluida{border-left-color:#1aa467}.uiny-acao--falha,.uiny-acao--indeterminada{border-left-color:var(--uiny-erro, #d9364f)}.uiny-acao--cancelada,.uiny-acao--expirada,.uiny-acao--invalidada{border-left-color:var(--uiny-texto-suave, #6b6b80)}.uiny-acao__topo{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:6px}.uiny-acao__selo{display:inline-flex;align-items:center;gap:5px;font-size:12px;font-weight:600;color:var(--uiny-primaria, #7366ff)}.uiny-acao--concluida .uiny-acao__selo{color:#1aa467}.uiny-acao--falha .uiny-acao__selo,.uiny-acao--indeterminada .uiny-acao__selo{color:var(--uiny-erro, #d9364f)}.uiny-acao--cancelada .uiny-acao__selo,.uiny-acao--expirada .uiny-acao__selo,.uiny-acao--invalidada .uiny-acao__selo{color:var(--uiny-texto-suave, #6b6b80)}.uiny-acao__prazo{font-size:11px;color:var(--uiny-texto-suave, #6b6b80)}.uiny-acao__resumo{margin:0;font-weight:600;line-height:1.45;color:var(--uiny-texto, #2b2b2b);overflow-wrap:anywhere}.uiny-acao__detalhes{margin:10px 0 0;padding:8px 10px;border-radius:9px;background:var(--uiny-fundo-suave, #f7f7fb);font-size:13px}.uiny-acao__item{display:flex;justify-content:space-between;gap:12px}.uiny-acao__item+.uiny-acao__item{margin-top:4px}.uiny-acao__item dt{font-weight:400;color:var(--uiny-texto-suave, #6b6b80)}.uiny-acao__item dd{display:inline-flex;align-items:center;gap:6px;margin:0;font-weight:600;text-align:right;overflow-wrap:anywhere}.uiny-acao__cor{flex:0 0 auto;width:14px;height:14px;border:1px solid rgba(0,0,0,.12);border-radius:4px}.uiny-acao__descricao{margin:8px 0 0;font-size:12.5px;line-height:1.45;color:var(--uiny-texto-suave, #6b6b80)}.uiny-acao__botoes{display:flex;justify-content:flex-end;gap:8px;margin-top:12px}.uiny-acao__botao{min-height:34px;padding:0 14px;border-radius:9px;font-size:13px;font-weight:600;cursor:pointer}.uiny-acao__botao:disabled{opacity:.5;cursor:not-allowed}.uiny-acao__botao:focus-visible{outline:2px solid var(--uiny-primaria, #7366ff);outline-offset:2px}.uiny-acao__botao--primario{border:1px solid var(--uiny-primaria, #7366ff);background:var(--uiny-primaria, #7366ff);color:#fff}.uiny-acao__botao--secundario{border:1px solid var(--uiny-borda, #ececf3);background:transparent;color:var(--uiny-texto, #2b2b2b)}.uiny-acao__spinner{width:12px;height:12px;border:2px solid var(--uiny-borda, #ececf3);border-top-color:var(--uiny-primaria, #7366ff);border-radius:50%;animation:uiny-girar .8s linear infinite}@keyframes uiny-girar{to{transform:rotate(360deg)}}@media (prefers-reduced-motion: reduce){.uiny-acao__spinner{animation-duration:2.4s}}\n"], dependencies: [{ kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2.UiIconComponent, selector: "ui-icon", inputs: ["icon", "size", "class"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
979
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: UiAssistantActionCardComponent, decorators: [{
|
|
980
|
-
type: Component,
|
|
981
|
-
args: [{ selector: 'ui-assistant-action-card', changeDetection: ChangeDetectionStrategy.OnPush, template: "<article class=\"uiny-acao\" [ngClass]=\"'uiny-acao--' + estado\" [attr.aria-busy]=\"acao.enviando ? 'true' : null\"\n [attr.aria-labelledby]=\"'uiny-acao-' + acao.id\">\n <header class=\"uiny-acao__topo\">\n <span class=\"uiny-acao__selo\">\n <span *ngIf=\"estado === 'executando' || acao.enviando\" class=\"uiny-acao__spinner\" aria-hidden=\"true\"></span>\n <ui-icon *ngIf=\"estado === 'concluida'\" icon=\"check_circle\" size=\"16\"></ui-icon>\n <ui-icon *ngIf=\"estado === 'falha' || estado === 'indeterminada'\" icon=\"error\" size=\"16\"></ui-icon>\n <ui-icon *ngIf=\"estado === 'pendente' && !acao.enviando\" icon=\"pending_actions\" size=\"16\"></ui-icon>\n {{ rotulo }}\n </span>\n <span *ngIf=\"minutosRestantes\" class=\"uiny-acao__prazo\">expira em {{ minutosRestantes }} min</span>\n </header>\n\n <p class=\"uiny-acao__resumo\" [id]=\"'uiny-acao-' + acao.id\">{{ acao.resumo }}</p>\n\n <dl *ngIf=\"acao.detalhes?.length\" class=\"uiny-acao__detalhes\">\n <div *ngFor=\"let d of acao.detalhes\" class=\"uiny-acao__item\">\n <dt>{{ d.rotulo }}</dt>\n <dd>\n <span *ngIf=\"ehCor(d.valor)\" class=\"uiny-acao__cor\" [style.background-color]=\"d.valor\" aria-hidden=\"true\"></span>\n {{ d.valor }}\n </dd>\n </div>\n </dl>\n\n <p *ngIf=\"descricao\" class=\"uiny-acao__descricao\" role=\"status\">{{ descricao }}</p>\n\n <div *ngIf=\"estado === 'pendente'\" class=\"uiny-acao__botoes\">\n <button type=\"button\" class=\"uiny-acao__botao uiny-acao__botao--secundario\" [disabled]=\"!podeDecidir\" (click)=\"aoCancelar()\">\n Cancelar\n </button>\n <button type=\"button\" class=\"uiny-acao__botao uiny-acao__botao--primario\" [disabled]=\"!podeDecidir\" (click)=\"aoConfirmar()\">\n Confirmar\n </button>\n </div>\n\n <div *ngIf=\"estado === 'indeterminada'\" class=\"uiny-acao__botoes\">\n <button type=\"button\" class=\"uiny-acao__botao uiny-acao__botao--secundario\" [disabled]=\"acao.enviando\" (click)=\"verificar.emit(acao.id)\">\n Verificar resultado\n </button>\n </div>\n</article>\n", styles: [":host{display:block;margin-top:8px}.uiny-acao{padding:12px 14px;border:1px solid var(--uiny-borda, #ececf3);border-left:3px solid var(--uiny-primaria, #7366ff);border-radius:12px;background:var(--uiny-fundo, #fff);box-shadow:0 2px 10px #1f1b4d0d}.uiny-acao--concluida{border-left-color:#1aa467}.uiny-acao--falha,.uiny-acao--indeterminada{border-left-color:var(--uiny-erro, #d9364f)}.uiny-acao--cancelada,.uiny-acao--expirada,.uiny-acao--invalidada{border-left-color:var(--uiny-texto-suave, #6b6b80)}.uiny-acao__topo{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:6px}.uiny-acao__selo{display:inline-flex;align-items:center;gap:5px;font-size:12px;font-weight:600;color:var(--uiny-primaria, #7366ff)}.uiny-acao--concluida .uiny-acao__selo{color:#1aa467}.uiny-acao--falha .uiny-acao__selo,.uiny-acao--indeterminada .uiny-acao__selo{color:var(--uiny-erro, #d9364f)}.uiny-acao--cancelada .uiny-acao__selo,.uiny-acao--expirada .uiny-acao__selo,.uiny-acao--invalidada .uiny-acao__selo{color:var(--uiny-texto-suave, #6b6b80)}.uiny-acao__prazo{font-size:11px;color:var(--uiny-texto-suave, #6b6b80)}.uiny-acao__resumo{margin:0;font-weight:600;line-height:1.45;color:var(--uiny-texto, #2b2b2b);overflow-wrap:anywhere}.uiny-acao__detalhes{margin:10px 0 0;padding:8px 10px;border-radius:9px;background:var(--uiny-fundo-suave, #f7f7fb);font-size:13px}.uiny-acao__item{display:flex;justify-content:space-between;gap:12px}.uiny-acao__item+.uiny-acao__item{margin-top:4px}.uiny-acao__item dt{font-weight:400;color:var(--uiny-texto-suave, #6b6b80)}.uiny-acao__item dd{display:inline-flex;align-items:center;gap:6px;margin:0;font-weight:600;text-align:right;overflow-wrap:anywhere}.uiny-acao__cor{flex:0 0 auto;width:14px;height:14px;border:1px solid rgba(0,0,0,.12);border-radius:4px}.uiny-acao__descricao{margin:8px 0 0;font-size:12.5px;line-height:1.45;color:var(--uiny-texto-suave, #6b6b80)}.uiny-acao__botoes{display:flex;justify-content:flex-end;gap:8px;margin-top:12px}.uiny-acao__botao{min-height:34px;padding:0 14px;border-radius:9px;font-size:13px;font-weight:600;cursor:pointer}.uiny-acao__botao:disabled{opacity:.5;cursor:not-allowed}.uiny-acao__botao:focus-visible{outline:2px solid var(--uiny-primaria, #7366ff);outline-offset:2px}.uiny-acao__botao--primario{border:1px solid var(--uiny-primaria, #7366ff);background:var(--uiny-primaria, #7366ff);color:#fff}.uiny-acao__botao--secundario{border:1px solid var(--uiny-borda, #ececf3);background:transparent;color:var(--uiny-texto, #2b2b2b)}.uiny-acao__spinner{width:12px;height:12px;border:2px solid var(--uiny-borda, #ececf3);border-top-color:var(--uiny-primaria, #7366ff);border-radius:50%;animation:uiny-girar .8s linear infinite}@keyframes uiny-girar{to{transform:rotate(360deg)}}@media (prefers-reduced-motion: reduce){.uiny-acao__spinner{animation-duration:2.4s}}\n"] }]
|
|
982
|
-
}], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }, { type: i0.NgZone }]; }, propDecorators: { acao: [{
|
|
983
|
-
type: Input
|
|
984
|
-
}], confirmar: [{
|
|
985
|
-
type: Output
|
|
986
|
-
}], cancelar: [{
|
|
987
|
-
type: Output
|
|
988
|
-
}], verificar: [{
|
|
989
|
-
type: Output
|
|
990
|
-
}] } });
|
|
991
|
-
|
|
992
|
-
const ALTURA_MAXIMA = 160;
|
|
993
|
-
/** Campo de mensagem: Enter envia, Shift+Enter quebra linha, cresce até ALTURA_MAXIMA. */
|
|
994
|
-
class UiAssistantComposerComponent {
|
|
995
|
-
constructor() {
|
|
996
|
-
this.desabilitado = false;
|
|
997
|
-
this.enviando = false;
|
|
998
|
-
/** Explica por que o envio está bloqueado (sem internet, carregando...). */
|
|
999
|
-
this.motivo = null;
|
|
1000
|
-
this.enviar = new EventEmitter();
|
|
1001
|
-
this.max = UINY_MENSAGEM_MAX_CARACTERES;
|
|
1002
|
-
this.texto = '';
|
|
1003
|
-
}
|
|
1004
|
-
get vazio() {
|
|
1005
|
-
return !this.texto.trim();
|
|
1006
|
-
}
|
|
1007
|
-
get bloqueado() {
|
|
1008
|
-
return this.desabilitado || this.enviando || this.vazio || this.texto.length > this.max;
|
|
1009
|
-
}
|
|
1010
|
-
get mostrarContador() {
|
|
1011
|
-
return this.texto.length > this.max - 400;
|
|
1012
|
-
}
|
|
1013
|
-
focar() {
|
|
1014
|
-
var _a;
|
|
1015
|
-
(_a = this.campo) === null || _a === void 0 ? void 0 : _a.nativeElement.focus({ preventScroll: true });
|
|
1016
|
-
}
|
|
1017
|
-
limpar() {
|
|
1018
|
-
this.texto = '';
|
|
1019
|
-
if (this.campo) {
|
|
1020
|
-
this.campo.nativeElement.value = '';
|
|
1021
|
-
this.ajustarAltura();
|
|
1022
|
-
}
|
|
1023
|
-
}
|
|
1024
|
-
aoDigitar(valor) {
|
|
1025
|
-
this.texto = valor;
|
|
1026
|
-
this.ajustarAltura();
|
|
1027
|
-
}
|
|
1028
|
-
aoTeclar(evento) {
|
|
1029
|
-
if (evento.key !== 'Enter' || evento.shiftKey)
|
|
1030
|
-
return;
|
|
1031
|
-
// durante a composição (IME, acentos em alguns teclados) Enter confirma o caractere
|
|
1032
|
-
if (evento.isComposing || evento.keyCode === 229)
|
|
1033
|
-
return;
|
|
1034
|
-
evento.preventDefault();
|
|
1035
|
-
this.submeter();
|
|
1036
|
-
}
|
|
1037
|
-
submeter() {
|
|
1038
|
-
if (this.bloqueado)
|
|
1039
|
-
return;
|
|
1040
|
-
this.enviar.emit(this.texto.trim());
|
|
1041
|
-
}
|
|
1042
|
-
ajustarAltura() {
|
|
1043
|
-
const el = this.campo.nativeElement;
|
|
1044
|
-
el.style.height = 'auto';
|
|
1045
|
-
el.style.height = Math.min(el.scrollHeight, ALTURA_MAXIMA) + 'px';
|
|
1046
|
-
el.style.overflowY = el.scrollHeight > ALTURA_MAXIMA ? 'auto' : 'hidden';
|
|
1047
|
-
}
|
|
1048
|
-
}
|
|
1049
|
-
UiAssistantComposerComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: UiAssistantComposerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1050
|
-
UiAssistantComposerComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: UiAssistantComposerComponent, selector: "ui-assistant-composer", inputs: { desabilitado: "desabilitado", enviando: "enviando", motivo: "motivo" }, outputs: { enviar: "enviar" }, viewQueries: [{ propertyName: "campo", first: true, predicate: ["campo"], descendants: true, static: true }], ngImport: i0, template: "<form class=\"uiny-composer\" (submit)=\"$event.preventDefault(); submeter()\">\n <label for=\"uiny-campo\" class=\"uiny-sr\">Mensagem para a Uiny</label>\n <div class=\"uiny-composer__caixa\" [class.is-desabilitado]=\"desabilitado\">\n <textarea #campo id=\"uiny-campo\" class=\"uiny-composer__campo\" rows=\"1\"\n placeholder=\"Pergunte algo para a Uiny\"\n [value]=\"texto\"\n [attr.aria-describedby]=\"motivo ? 'uiny-campo-motivo' : 'uiny-campo-dica'\"\n [attr.maxlength]=\"max + 200\"\n (input)=\"aoDigitar(campo.value)\"\n (keydown)=\"aoTeclar($event)\"></textarea>\n\n <button type=\"submit\" class=\"uiny-composer__enviar\" [disabled]=\"bloqueado\"\n [attr.aria-label]=\"enviando ? 'Aguardando a resposta da Uiny' : 'Enviar mensagem'\"\n [title]=\"enviando ? 'Aguardando a resposta' : 'Enviar (Enter)'\">\n <span *ngIf=\"enviando\" class=\"uiny-composer__spinner\" aria-hidden=\"true\"></span>\n <ui-icon *ngIf=\"!enviando\" icon=\"arrow_upward\" size=\"20\"></ui-icon>\n </button>\n </div>\n\n <div class=\"uiny-composer__rodape\">\n <span *ngIf=\"motivo\" id=\"uiny-campo-motivo\" class=\"uiny-composer__motivo\">{{ motivo }}</span>\n <span *ngIf=\"!motivo\" id=\"uiny-campo-dica\">Enter envia \u00B7 Shift+Enter quebra a linha</span>\n <span *ngIf=\"mostrarContador\" class=\"uiny-composer__contador\" [class.is-excedido]=\"texto.length > max\">\n {{ texto.length }}/{{ max }}\n </span>\n </div>\n</form>\n", styles: [":host{display:block;padding:10px 12px 12px;border-top:1px solid var(--uiny-borda, #ececf3);background:var(--uiny-fundo, #fff)}.uiny-composer__caixa{display:flex;align-items:flex-end;gap:8px;padding:6px 6px 6px 12px;border:1px solid var(--uiny-borda, #ececf3);border-radius:14px;background:var(--uiny-fundo-suave, #f7f7fb);transition:border-color .15s ease,box-shadow .15s ease}.uiny-composer__caixa:focus-within{border-color:var(--uiny-primaria, #7366ff);box-shadow:0 0 0 3px #7366ff26}.uiny-composer__caixa.is-desabilitado{opacity:.75}.uiny-composer__campo{flex:1 1 auto;min-width:0;max-height:160px;padding:6px 0;border:0;outline:0;background:transparent;color:var(--uiny-texto, #2b2b2b);font:inherit;font-size:14px;line-height:1.45;resize:none;overflow-y:hidden}.uiny-composer__campo::placeholder{color:var(--uiny-texto-suave, #6b6b80)}.uiny-composer__enviar{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;width:34px;height:34px;border:0;border-radius:10px;background:var(--uiny-primaria, #7366ff);color:#fff;cursor:pointer;transition:opacity .15s ease}.uiny-composer__enviar:disabled{opacity:.35;cursor:not-allowed}.uiny-composer__enviar:focus-visible{outline:2px solid var(--uiny-primaria, #7366ff);outline-offset:2px}.uiny-composer__spinner{width:16px;height:16px;border:2px solid rgba(255,255,255,.4);border-top-color:#fff;border-radius:50%;animation:uiny-girar .8s linear infinite}.uiny-composer__rodape{display:flex;justify-content:space-between;gap:8px;margin-top:6px;padding:0 4px;font-size:11px;color:var(--uiny-texto-suave, #6b6b80)}.uiny-composer__motivo{color:var(--uiny-offline-texto, #8a5300)}.uiny-composer__contador.is-excedido{color:var(--uiny-erro, #d9364f);font-weight:600}.uiny-sr{position:absolute;width:1px;height:1px;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}@keyframes uiny-girar{to{transform:rotate(360deg)}}@media (prefers-reduced-motion: reduce){.uiny-composer__caixa,.uiny-composer__enviar{transition:none}.uiny-composer__spinner{animation-duration:2.4s}}\n"], dependencies: [{ kind: "directive", type: i1$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2.UiIconComponent, selector: "ui-icon", inputs: ["icon", "size", "class"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1051
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: UiAssistantComposerComponent, decorators: [{
|
|
1052
|
-
type: Component,
|
|
1053
|
-
args: [{ selector: 'ui-assistant-composer', changeDetection: ChangeDetectionStrategy.OnPush, template: "<form class=\"uiny-composer\" (submit)=\"$event.preventDefault(); submeter()\">\n <label for=\"uiny-campo\" class=\"uiny-sr\">Mensagem para a Uiny</label>\n <div class=\"uiny-composer__caixa\" [class.is-desabilitado]=\"desabilitado\">\n <textarea #campo id=\"uiny-campo\" class=\"uiny-composer__campo\" rows=\"1\"\n placeholder=\"Pergunte algo para a Uiny\"\n [value]=\"texto\"\n [attr.aria-describedby]=\"motivo ? 'uiny-campo-motivo' : 'uiny-campo-dica'\"\n [attr.maxlength]=\"max + 200\"\n (input)=\"aoDigitar(campo.value)\"\n (keydown)=\"aoTeclar($event)\"></textarea>\n\n <button type=\"submit\" class=\"uiny-composer__enviar\" [disabled]=\"bloqueado\"\n [attr.aria-label]=\"enviando ? 'Aguardando a resposta da Uiny' : 'Enviar mensagem'\"\n [title]=\"enviando ? 'Aguardando a resposta' : 'Enviar (Enter)'\">\n <span *ngIf=\"enviando\" class=\"uiny-composer__spinner\" aria-hidden=\"true\"></span>\n <ui-icon *ngIf=\"!enviando\" icon=\"arrow_upward\" size=\"20\"></ui-icon>\n </button>\n </div>\n\n <div class=\"uiny-composer__rodape\">\n <span *ngIf=\"motivo\" id=\"uiny-campo-motivo\" class=\"uiny-composer__motivo\">{{ motivo }}</span>\n <span *ngIf=\"!motivo\" id=\"uiny-campo-dica\">Enter envia \u00B7 Shift+Enter quebra a linha</span>\n <span *ngIf=\"mostrarContador\" class=\"uiny-composer__contador\" [class.is-excedido]=\"texto.length > max\">\n {{ texto.length }}/{{ max }}\n </span>\n </div>\n</form>\n", styles: [":host{display:block;padding:10px 12px 12px;border-top:1px solid var(--uiny-borda, #ececf3);background:var(--uiny-fundo, #fff)}.uiny-composer__caixa{display:flex;align-items:flex-end;gap:8px;padding:6px 6px 6px 12px;border:1px solid var(--uiny-borda, #ececf3);border-radius:14px;background:var(--uiny-fundo-suave, #f7f7fb);transition:border-color .15s ease,box-shadow .15s ease}.uiny-composer__caixa:focus-within{border-color:var(--uiny-primaria, #7366ff);box-shadow:0 0 0 3px #7366ff26}.uiny-composer__caixa.is-desabilitado{opacity:.75}.uiny-composer__campo{flex:1 1 auto;min-width:0;max-height:160px;padding:6px 0;border:0;outline:0;background:transparent;color:var(--uiny-texto, #2b2b2b);font:inherit;font-size:14px;line-height:1.45;resize:none;overflow-y:hidden}.uiny-composer__campo::placeholder{color:var(--uiny-texto-suave, #6b6b80)}.uiny-composer__enviar{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;width:34px;height:34px;border:0;border-radius:10px;background:var(--uiny-primaria, #7366ff);color:#fff;cursor:pointer;transition:opacity .15s ease}.uiny-composer__enviar:disabled{opacity:.35;cursor:not-allowed}.uiny-composer__enviar:focus-visible{outline:2px solid var(--uiny-primaria, #7366ff);outline-offset:2px}.uiny-composer__spinner{width:16px;height:16px;border:2px solid rgba(255,255,255,.4);border-top-color:#fff;border-radius:50%;animation:uiny-girar .8s linear infinite}.uiny-composer__rodape{display:flex;justify-content:space-between;gap:8px;margin-top:6px;padding:0 4px;font-size:11px;color:var(--uiny-texto-suave, #6b6b80)}.uiny-composer__motivo{color:var(--uiny-offline-texto, #8a5300)}.uiny-composer__contador.is-excedido{color:var(--uiny-erro, #d9364f);font-weight:600}.uiny-sr{position:absolute;width:1px;height:1px;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}@keyframes uiny-girar{to{transform:rotate(360deg)}}@media (prefers-reduced-motion: reduce){.uiny-composer__caixa,.uiny-composer__enviar{transition:none}.uiny-composer__spinner{animation-duration:2.4s}}\n"] }]
|
|
1054
|
-
}], propDecorators: { desabilitado: [{
|
|
1055
|
-
type: Input
|
|
1056
|
-
}], enviando: [{
|
|
1057
|
-
type: Input
|
|
1058
|
-
}], motivo: [{
|
|
1059
|
-
type: Input
|
|
1060
|
-
}], enviar: [{
|
|
1061
|
-
type: Output
|
|
1062
|
-
}], campo: [{
|
|
1063
|
-
type: ViewChild,
|
|
1064
|
-
args: ['campo', { static: true }]
|
|
1065
|
-
}] } });
|
|
1066
|
-
|
|
1067
|
-
const ESTADO_INICIAL = {
|
|
1068
|
-
conversa: null,
|
|
1069
|
-
mensagens: [],
|
|
1070
|
-
acoes: {},
|
|
1071
|
-
enviando: false,
|
|
1072
|
-
carregandoConversa: false,
|
|
1073
|
-
erro: null,
|
|
1074
|
-
aviso: null,
|
|
1075
|
-
conversas: null,
|
|
1076
|
-
carregandoConversas: false,
|
|
1077
|
-
textoComFalha: null,
|
|
1078
|
-
};
|
|
1079
|
-
/**
|
|
1080
|
-
* Estado da conversa, só em memória. Nada vai para localStorage/sessionStorage.
|
|
1081
|
-
*
|
|
1082
|
-
* Limpeza: qualquer mudança de sessão (logout, outro usuário, outra empresa, novo token,
|
|
1083
|
-
* 401 da API) ou a Uiny ficar indisponível cancela as requisições em andamento e
|
|
1084
|
-
* descarta todo o estado.
|
|
1085
|
-
*/
|
|
1086
|
-
class UinyChatService {
|
|
1087
|
-
constructor(api, session, assistant) {
|
|
1088
|
-
this.api = api;
|
|
1089
|
-
this.session = session;
|
|
1090
|
-
this.assistant = assistant;
|
|
1091
|
-
this.estado$ = new BehaviorSubject(ESTADO_INICIAL);
|
|
1092
|
-
/** Emite para abortar as requisições da sessão/conversa atual. */
|
|
1093
|
-
this.cancelarConversa$ = new Subject();
|
|
1094
|
-
this.cancelarSessao$ = new Subject();
|
|
1095
|
-
this.anuncios$ = new Subject();
|
|
1096
|
-
this.subs = new Subscription();
|
|
1097
|
-
this.sessao = null;
|
|
1098
|
-
this.idLocal = 0;
|
|
1099
|
-
/** Loja usada ao criar a conversa atual: o backend restringe a conversa a ela. */
|
|
1100
|
-
this.escopoLoja = null;
|
|
1101
|
-
this.estado = this.estado$.asObservable();
|
|
1102
|
-
/** Textos curtos para a região aria-live do painel. */
|
|
1103
|
-
this.anuncios = this.anuncios$.asObservable();
|
|
1104
|
-
this.subs.add(this.session.sessao$.subscribe(sessao => {
|
|
1105
|
-
var _a;
|
|
1106
|
-
if ((sessao === null || sessao === void 0 ? void 0 : sessao.id) !== ((_a = this.sessao) === null || _a === void 0 ? void 0 : _a.id)) {
|
|
1107
|
-
this.sessao = sessao;
|
|
1108
|
-
this.limparTudo();
|
|
1109
|
-
}
|
|
1110
|
-
}));
|
|
1111
|
-
this.subs.add(this.assistant.disponivel$.pipe(filter(d => !d)).subscribe(() => this.limparTudo()));
|
|
1112
|
-
// Trocar de loja muda o escopo da conversa: não reaproveitamos a anterior.
|
|
1113
|
-
this.subs.add(this.assistant.contexto$.pipe(map(c => { var _a; return (_a = c.idLoja) !== null && _a !== void 0 ? _a : null; }), distinctUntilChanged()).subscribe(idLoja => {
|
|
1114
|
-
if (this.valor.conversa && this.escopoLoja !== idLoja) {
|
|
1115
|
-
this.encerrarConversa('Você mudou de loja. Começamos uma nova conversa para manter os assuntos separados.');
|
|
1116
|
-
}
|
|
1117
|
-
}));
|
|
1118
|
-
}
|
|
1119
|
-
ngOnDestroy() {
|
|
1120
|
-
this.cancelarSessao$.next();
|
|
1121
|
-
this.subs.unsubscribe();
|
|
1122
|
-
}
|
|
1123
|
-
get valor() {
|
|
1124
|
-
return this.estado$.value;
|
|
1125
|
-
}
|
|
1126
|
-
get ocupado() {
|
|
1127
|
-
const v = this.valor;
|
|
1128
|
-
return v.enviando || Object.values(v.acoes).some(a => a.enviando || a.estado === 'executando');
|
|
1129
|
-
}
|
|
1130
|
-
enviar(textoBruto) {
|
|
1131
|
-
const texto = (textoBruto || '').trim();
|
|
1132
|
-
const sistema = this.assistant.sistemaOrigem;
|
|
1133
|
-
if (!texto || !sistema || !this.sessao || this.valor.enviando)
|
|
1134
|
-
return false;
|
|
1135
|
-
if (texto.length > UINY_MENSAGEM_MAX_CARACTERES) {
|
|
1136
|
-
this.patch({ erro: this.erroLocal('invalido', `A mensagem pode ter até ${UINY_MENSAGEM_MAX_CARACTERES} caracteres.`) });
|
|
1137
|
-
return false;
|
|
1138
|
-
}
|
|
1139
|
-
const contexto = contextoParaApi(sistema, this.assistant.contexto);
|
|
1140
|
-
const local = {
|
|
1141
|
-
id: this.novoIdLocal(), papel: 'usuario', estado: null, texto, idAcao: null, opcoes: [], criadaEm: new Date(),
|
|
1142
|
-
};
|
|
1143
|
-
this.patch({
|
|
1144
|
-
mensagens: [...this.valor.mensagens.filter(m => !m.erro), local],
|
|
1145
|
-
enviando: true,
|
|
1146
|
-
erro: null,
|
|
1147
|
-
aviso: null,
|
|
1148
|
-
textoComFalha: null,
|
|
1149
|
-
});
|
|
1150
|
-
this.anuncios$.next('A Uiny está respondendo…');
|
|
1151
|
-
const conversa$ = this.valor.conversa
|
|
1152
|
-
? of(this.valor.conversa)
|
|
1153
|
-
: this.api.criarConversa(contexto).pipe(map(r => {
|
|
1154
|
-
var _a;
|
|
1155
|
-
const conversa = adaptarConversa(r === null || r === void 0 ? void 0 : r.conversa);
|
|
1156
|
-
if (!conversa)
|
|
1157
|
-
throw this.erroLocal('servidor', 'Não foi possível iniciar a conversa.');
|
|
1158
|
-
this.escopoLoja = (_a = contexto.id_loja) !== null && _a !== void 0 ? _a : null;
|
|
1159
|
-
this.patch({ conversa, conversas: null });
|
|
1160
|
-
return conversa;
|
|
1161
|
-
}));
|
|
1162
|
-
conversa$.pipe(switchMap(conversa => this.api.enviarMensagem(conversa.id, texto, contexto)), takeUntil(this.cancelarConversa$), finalize(() => this.valor.enviando && this.patch({ enviando: false }))).subscribe({
|
|
1163
|
-
next: resposta => {
|
|
1164
|
-
this.aplicarResposta(resposta, true);
|
|
1165
|
-
this.patch({ enviando: false });
|
|
1166
|
-
this.anuncios$.next((resposta === null || resposta === void 0 ? void 0 : resposta.mensagem) ? 'Nova resposta da Uiny.' : '');
|
|
1167
|
-
},
|
|
1168
|
-
error: err => {
|
|
1169
|
-
var _a;
|
|
1170
|
-
const erro = this.normalizar(err);
|
|
1171
|
-
// erros da API podem trazer a mensagem da Uiny (ex.: falha do provedor registrada)
|
|
1172
|
-
if ((_a = erro.corpo) === null || _a === void 0 ? void 0 : _a.mensagem)
|
|
1173
|
-
this.aplicarResposta(erro.corpo, false);
|
|
1174
|
-
this.patch({
|
|
1175
|
-
mensagens: this.valor.mensagens.map(m => m.id === local.id ? Object.assign(Object.assign({}, m), { erro: true }) : m),
|
|
1176
|
-
enviando: false,
|
|
1177
|
-
erro,
|
|
1178
|
-
textoComFalha: erro.tipo === 'sessao' ? null : texto,
|
|
1179
|
-
});
|
|
1180
|
-
this.anuncios$.next(erro.mensagem);
|
|
1181
|
-
},
|
|
1182
|
-
});
|
|
1183
|
-
return true;
|
|
1184
|
-
}
|
|
1185
|
-
/** Começa do zero. Bloqueado enquanto há envio ou ação em execução. */
|
|
1186
|
-
novaConversa() {
|
|
1187
|
-
if (this.ocupado)
|
|
1188
|
-
return false;
|
|
1189
|
-
this.encerrarConversa(null);
|
|
1190
|
-
return true;
|
|
1191
|
-
}
|
|
1192
|
-
listarConversas() {
|
|
1193
|
-
if (!this.sessao || this.valor.carregandoConversas)
|
|
1194
|
-
return;
|
|
1195
|
-
this.patch({ carregandoConversas: true, erro: null });
|
|
1196
|
-
this.api.listarConversas().pipe(takeUntil(this.cancelarSessao$), finalize(() => this.patch({ carregandoConversas: false }))).subscribe({
|
|
1197
|
-
next: r => this.patch({
|
|
1198
|
-
conversas: (Array.isArray(r === null || r === void 0 ? void 0 : r.data) ? r.data : []).map(adaptarConversa).filter(c => !!c && this.doContextoAtual(c)),
|
|
1199
|
-
}),
|
|
1200
|
-
error: err => this.patch({ erro: this.normalizar(err), conversas: [] }),
|
|
1201
|
-
});
|
|
1202
|
-
}
|
|
1203
|
-
abrirConversa(id) {
|
|
1204
|
-
var _a;
|
|
1205
|
-
const resumo = (_a = this.valor.conversas) === null || _a === void 0 ? void 0 : _a.find(c => c.id === id);
|
|
1206
|
-
if (!resumo || this.ocupado || !this.doContextoAtual(resumo))
|
|
1207
|
-
return;
|
|
1208
|
-
this.encerrarConversa(null);
|
|
1209
|
-
this.patch({ carregandoConversa: true });
|
|
1210
|
-
this.api.historico(id).pipe(takeUntil(this.cancelarConversa$), finalize(() => this.patch({ carregandoConversa: false }))).subscribe({
|
|
1211
|
-
next: r => {
|
|
1212
|
-
var _a;
|
|
1213
|
-
const conversa = (_a = adaptarConversa(r === null || r === void 0 ? void 0 : r.conversa)) !== null && _a !== void 0 ? _a : resumo;
|
|
1214
|
-
if (!this.doContextoAtual(conversa)) {
|
|
1215
|
-
this.patch({ aviso: 'Essa conversa pertence a outro contexto e não pode ser continuada aqui.' });
|
|
1216
|
-
return;
|
|
1217
|
-
}
|
|
1218
|
-
this.escopoLoja = conversa.idLoja;
|
|
1219
|
-
const mensagensApi = Array.isArray(r === null || r === void 0 ? void 0 : r.data) ? r.data : [];
|
|
1220
|
-
this.patch({
|
|
1221
|
-
conversa,
|
|
1222
|
-
mensagens: mensagensApi.map(adaptarMensagem).filter(Boolean),
|
|
1223
|
-
acoes: this.mesclarAcoes(mensagensApi.map(m => m === null || m === void 0 ? void 0 : m.acao_pendente)),
|
|
1224
|
-
});
|
|
1225
|
-
// Histórico não reemite instruções de interface: elas já foram tratadas quando chegaram.
|
|
1226
|
-
},
|
|
1227
|
-
error: err => this.patch({ erro: this.normalizar(err) }),
|
|
1228
|
-
});
|
|
1229
|
-
}
|
|
1230
|
-
/**
|
|
1231
|
-
* Confirma pelo id da ação persistida no backend. Só é chamado pelo clique no card;
|
|
1232
|
-
* nenhum texto da conversa dispara isto. Nunca há repetição automática.
|
|
1233
|
-
*/
|
|
1234
|
-
confirmar(idAcao) {
|
|
1235
|
-
const acao = this.valor.acoes[idAcao];
|
|
1236
|
-
if (!acao || acao.enviando || acao.estado !== 'pendente')
|
|
1237
|
-
return;
|
|
1238
|
-
if (acao.expiraEm && acao.expiraEm.getTime() <= Date.now()) {
|
|
1239
|
-
this.atualizarAcao(idAcao, { estado: 'expirada', aviso: 'O prazo para confirmar terminou. Peça a alteração de novo.' });
|
|
1240
|
-
return;
|
|
1241
|
-
}
|
|
1242
|
-
this.atualizarAcao(idAcao, { enviando: true, estado: 'executando', aviso: null });
|
|
1243
|
-
this.anuncios$.next('Executando a alteração…');
|
|
1244
|
-
this.api.confirmarAcao(idAcao).pipe(takeUntil(this.cancelarSessao$)).subscribe({
|
|
1245
|
-
next: resposta => this.concluirDecisao(idAcao, resposta, null, true),
|
|
1246
|
-
error: err => {
|
|
1247
|
-
var _a, _b;
|
|
1248
|
-
const erro = this.normalizar(err);
|
|
1249
|
-
if (((_a = erro.corpo) === null || _a === void 0 ? void 0 : _a.acao_pendente) || ((_b = erro.corpo) === null || _b === void 0 ? void 0 : _b.acao_anterior)) {
|
|
1250
|
-
// 409 (expirada, invalidada com nova proposta, em execução) ou 502/504: o corpo traz o estado real
|
|
1251
|
-
this.concluirDecisao(idAcao, erro.corpo, erro, true);
|
|
1252
|
-
}
|
|
1253
|
-
else if (erro.tipo === 'timeout' || erro.tipo === 'rede' || erro.tipo === 'servidor') {
|
|
1254
|
-
// A operação pode ter sido executada. Não repetimos: o usuário verifica o estado.
|
|
1255
|
-
this.atualizarAcao(idAcao, {
|
|
1256
|
-
enviando: false,
|
|
1257
|
-
estado: 'indeterminada',
|
|
1258
|
-
aviso: 'Não recebemos a resposta da confirmação. Verifique o resultado antes de pedir de novo.',
|
|
1259
|
-
});
|
|
1260
|
-
}
|
|
1261
|
-
else if (erro.tipo === 'conflito' || erro.tipo === 'nao_encontrado') {
|
|
1262
|
-
this.atualizarAcao(idAcao, { enviando: false, estado: 'indeterminada', aviso: erro.mensagem });
|
|
1263
|
-
this.verificarAcao(idAcao);
|
|
1264
|
-
}
|
|
1265
|
-
else {
|
|
1266
|
-
this.atualizarAcao(idAcao, { enviando: false, estado: 'pendente', aviso: erro.mensagem });
|
|
1267
|
-
}
|
|
1268
|
-
this.anuncios$.next(erro.mensagem);
|
|
1269
|
-
},
|
|
1270
|
-
});
|
|
1271
|
-
}
|
|
1272
|
-
cancelar(idAcao) {
|
|
1273
|
-
const acao = this.valor.acoes[idAcao];
|
|
1274
|
-
if (!acao || acao.enviando || acao.estado !== 'pendente')
|
|
1275
|
-
return;
|
|
1276
|
-
this.atualizarAcao(idAcao, { enviando: true, aviso: null });
|
|
1277
|
-
this.api.cancelarAcao(idAcao).pipe(takeUntil(this.cancelarSessao$)).subscribe({
|
|
1278
|
-
next: resposta => this.concluirDecisao(idAcao, resposta, null, false),
|
|
1279
|
-
error: err => {
|
|
1280
|
-
var _a;
|
|
1281
|
-
const erro = this.normalizar(err);
|
|
1282
|
-
if ((_a = erro.corpo) === null || _a === void 0 ? void 0 : _a.acao_pendente) {
|
|
1283
|
-
this.concluirDecisao(idAcao, erro.corpo, erro, false);
|
|
1284
|
-
}
|
|
1285
|
-
else {
|
|
1286
|
-
this.atualizarAcao(idAcao, { enviando: false, aviso: erro.mensagem });
|
|
1287
|
-
}
|
|
1288
|
-
},
|
|
1289
|
-
});
|
|
1290
|
-
}
|
|
1291
|
-
/** Consulta a situação real da ação relendo o histórico da conversa. */
|
|
1292
|
-
verificarAcao(idAcao) {
|
|
1293
|
-
var _a;
|
|
1294
|
-
const acao = this.valor.acoes[idAcao];
|
|
1295
|
-
const idConversa = (_a = this.valor.conversa) === null || _a === void 0 ? void 0 : _a.id;
|
|
1296
|
-
if (!acao || !idConversa)
|
|
1297
|
-
return;
|
|
1298
|
-
this.atualizarAcao(idAcao, { enviando: true });
|
|
1299
|
-
this.api.historico(idConversa).pipe(takeUntil(this.cancelarSessao$)).subscribe({
|
|
1300
|
-
next: r => {
|
|
1301
|
-
const mensagens = Array.isArray(r === null || r === void 0 ? void 0 : r.data) ? r.data : [];
|
|
1302
|
-
const atual = mensagens.map(m => adaptarAcao(m === null || m === void 0 ? void 0 : m.acao_pendente)).find(a => (a === null || a === void 0 ? void 0 : a.id) === idAcao);
|
|
1303
|
-
if (atual) {
|
|
1304
|
-
this.atualizarAcao(idAcao, Object.assign(Object.assign({}, atual), { enviando: false, aviso: atual.estado === 'indeterminada' ? 'Confira no sistema se a alteração foi aplicada.' : null }));
|
|
1305
|
-
this.patch({ mensagens: this.mesclar(this.valor.mensagens, mensagens.map(adaptarMensagem).filter(Boolean)) });
|
|
1306
|
-
}
|
|
1307
|
-
else {
|
|
1308
|
-
this.atualizarAcao(idAcao, {
|
|
1309
|
-
enviando: false,
|
|
1310
|
-
aviso: 'Não foi possível consultar o estado desta ação. Confira na tela correspondente se a alteração foi aplicada.',
|
|
1311
|
-
});
|
|
1312
|
-
}
|
|
1313
|
-
},
|
|
1314
|
-
error: err => this.atualizarAcao(idAcao, { enviando: false, aviso: this.normalizar(err).mensagem }),
|
|
1315
|
-
});
|
|
1316
|
-
}
|
|
1317
|
-
limparErro() {
|
|
1318
|
-
this.patch({ erro: null, aviso: null });
|
|
1319
|
-
}
|
|
1320
|
-
/* ---------------- internos ---------------- */
|
|
1321
|
-
/** Aplica uma resposta de confirmar/cancelar (de sucesso ou de erro com corpo). */
|
|
1322
|
-
concluirDecisao(idAcao, resposta, erro, confirmacao) {
|
|
1323
|
-
var _a, _b;
|
|
1324
|
-
const anterior = this.valor.acoes[idAcao];
|
|
1325
|
-
this.aplicarResposta(resposta, !erro);
|
|
1326
|
-
const atual = this.valor.acoes[idAcao];
|
|
1327
|
-
// sem a ação na resposta, o resultado é desconhecido
|
|
1328
|
-
if (!atual || atual === anterior) {
|
|
1329
|
-
this.atualizarAcao(idAcao, {
|
|
1330
|
-
enviando: false,
|
|
1331
|
-
estado: confirmacao ? 'indeterminada' : anterior === null || anterior === void 0 ? void 0 : anterior.estado,
|
|
1332
|
-
aviso: (_a = erro === null || erro === void 0 ? void 0 : erro.mensagem) !== null && _a !== void 0 ? _a : 'A API não informou o resultado. Confira se a alteração foi aplicada.',
|
|
1333
|
-
});
|
|
1334
|
-
}
|
|
1335
|
-
else {
|
|
1336
|
-
this.atualizarAcao(idAcao, { enviando: false, aviso: (_b = erro === null || erro === void 0 ? void 0 : erro.mensagem) !== null && _b !== void 0 ? _b : null });
|
|
1337
|
-
}
|
|
1338
|
-
const final = this.valor.acoes[idAcao];
|
|
1339
|
-
// Sucesso só quando a API devolve a ação como executada.
|
|
1340
|
-
if (confirmacao && (final === null || final === void 0 ? void 0 : final.estado) === 'concluida') {
|
|
1341
|
-
this.assistant.emitir({ tipo: 'acao_concluida', idAcao, ferramenta: final.ferramenta });
|
|
1342
|
-
this.anuncios$.next('Alteração concluída.');
|
|
1343
|
-
}
|
|
1344
|
-
else if ((final === null || final === void 0 ? void 0 : final.estado) === 'falha') {
|
|
1345
|
-
this.anuncios$.next('A alteração não foi concluída.');
|
|
1346
|
-
}
|
|
1347
|
-
}
|
|
1348
|
-
/** Resposta padrão (ApresentadorConversa::resposta): conversa, mensagem e ação pendente. */
|
|
1349
|
-
aplicarResposta(resposta, emitirInstrucoes) {
|
|
1350
|
-
var _a, _b, _c;
|
|
1351
|
-
if (!resposta || typeof resposta !== 'object')
|
|
1352
|
-
return;
|
|
1353
|
-
const mensagem = adaptarMensagem(resposta.mensagem);
|
|
1354
|
-
this.patch({
|
|
1355
|
-
conversa: (_a = adaptarConversa(resposta.conversa)) !== null && _a !== void 0 ? _a : this.valor.conversa,
|
|
1356
|
-
mensagens: mensagem ? this.mesclar(this.valor.mensagens, [mensagem]) : this.valor.mensagens,
|
|
1357
|
-
acoes: this.mesclarAcoes([resposta.acao_anterior, (_b = resposta.mensagem) === null || _b === void 0 ? void 0 : _b.acao_pendente, resposta.acao_pendente]),
|
|
1358
|
-
});
|
|
1359
|
-
if (emitirInstrucoes && ((_c = resposta.mensagem) === null || _c === void 0 ? void 0 : _c.papel) === 'assistente') {
|
|
1360
|
-
adaptarInstrucoes(resposta.mensagem.instrucoes_interface).forEach(e => this.assistant.emitir(e));
|
|
1361
|
-
}
|
|
1362
|
-
}
|
|
1363
|
-
mesclar(atuais, novas) {
|
|
1364
|
-
const ids = new Set(atuais.map(m => m.id));
|
|
1365
|
-
return [...atuais, ...novas.filter(m => !ids.has(m.id))];
|
|
1366
|
-
}
|
|
1367
|
-
mesclarAcoes(novas) {
|
|
1368
|
-
const acoes = Object.assign({}, this.valor.acoes);
|
|
1369
|
-
novas.map(adaptarAcao).filter(Boolean).forEach(a => {
|
|
1370
|
-
// uma ação já resolvida localmente não volta a "pendente" por uma resposta antiga
|
|
1371
|
-
const anterior = acoes[a.id];
|
|
1372
|
-
acoes[a.id] = anterior && anterior.estado !== 'pendente' && anterior.estado !== 'executando' && a.estado === 'pendente'
|
|
1373
|
-
? anterior
|
|
1374
|
-
: Object.assign(Object.assign({}, a), { enviando: anterior === null || anterior === void 0 ? void 0 : anterior.enviando, aviso: anterior === null || anterior === void 0 ? void 0 : anterior.aviso });
|
|
1375
|
-
});
|
|
1376
|
-
return acoes;
|
|
1377
|
-
}
|
|
1378
|
-
atualizarAcao(id, parcial) {
|
|
1379
|
-
const atual = this.valor.acoes[id];
|
|
1380
|
-
if (!atual)
|
|
1381
|
-
return;
|
|
1382
|
-
this.patch({ acoes: Object.assign(Object.assign({}, this.valor.acoes), { [id]: Object.assign(Object.assign(Object.assign({}, atual), parcial), { id }) }) });
|
|
1383
|
-
}
|
|
1384
|
-
doContextoAtual(conversa) {
|
|
1385
|
-
var _a, _b;
|
|
1386
|
-
const sistema = this.assistant.sistemaOrigem;
|
|
1387
|
-
const idLoja = (_a = this.assistant.contexto.idLoja) !== null && _a !== void 0 ? _a : null;
|
|
1388
|
-
return conversa.sistemaOrigem === sistema && ((_b = conversa.idLoja) !== null && _b !== void 0 ? _b : null) === idLoja;
|
|
1389
|
-
}
|
|
1390
|
-
encerrarConversa(aviso) {
|
|
1391
|
-
this.cancelarConversa$.next();
|
|
1392
|
-
this.escopoLoja = null;
|
|
1393
|
-
this.patch({
|
|
1394
|
-
conversa: null,
|
|
1395
|
-
mensagens: [],
|
|
1396
|
-
acoes: {},
|
|
1397
|
-
enviando: false,
|
|
1398
|
-
carregandoConversa: false,
|
|
1399
|
-
erro: null,
|
|
1400
|
-
aviso,
|
|
1401
|
-
conversas: null,
|
|
1402
|
-
textoComFalha: null,
|
|
1403
|
-
});
|
|
1404
|
-
}
|
|
1405
|
-
limparTudo() {
|
|
1406
|
-
this.cancelarConversa$.next();
|
|
1407
|
-
this.cancelarSessao$.next();
|
|
1408
|
-
this.escopoLoja = null;
|
|
1409
|
-
this.estado$.next(ESTADO_INICIAL);
|
|
1410
|
-
}
|
|
1411
|
-
patch(parcial) {
|
|
1412
|
-
this.estado$.next(Object.assign(Object.assign({}, this.estado$.value), parcial));
|
|
1413
|
-
}
|
|
1414
|
-
novoIdLocal() {
|
|
1415
|
-
return 'local-' + (++this.idLocal);
|
|
1416
|
-
}
|
|
1417
|
-
normalizar(err) {
|
|
1418
|
-
if (err && typeof err === 'object' && typeof err.tipo === 'string' && typeof err.mensagem === 'string')
|
|
1419
|
-
return err;
|
|
1420
|
-
return this.erroLocal('servidor', 'Algo deu errado ao falar com a Uiny. Tente de novo.');
|
|
1421
|
-
}
|
|
1422
|
-
erroLocal(tipo, mensagem) {
|
|
1423
|
-
return { tipo, status: 0, codigo: null, mensagem, correlacao: null };
|
|
1424
|
-
}
|
|
1425
|
-
}
|
|
1426
|
-
UinyChatService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: UinyChatService, deps: [{ token: UinyApiService }, { token: UinySessionService }, { token: UiAssistantService }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1427
|
-
UinyChatService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: UinyChatService, providedIn: 'root' });
|
|
1428
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: UinyChatService, decorators: [{
|
|
1429
|
-
type: Injectable,
|
|
1430
|
-
args: [{ providedIn: 'root' }]
|
|
1431
|
-
}], ctorParameters: function () { return [{ type: UinyApiService }, { type: UinySessionService }, { type: UiAssistantService }]; } });
|
|
1432
|
-
|
|
1433
|
-
/*
|
|
1434
|
-
* Subconjunto seguro de Markdown para as respostas da Uiny.
|
|
1435
|
-
*
|
|
1436
|
-
* O texto vira uma árvore de tokens renderizada pelo template com interpolação
|
|
1437
|
-
* ({{ }}), sem innerHTML e sem bypass do sanitizador do Angular. HTML presente no
|
|
1438
|
-
* texto aparece literalmente. Links só com http, https ou mailto.
|
|
1439
|
-
*
|
|
1440
|
-
* Suporta: parágrafos, quebras de linha, listas (- * 1.), títulos (#, ##, ###),
|
|
1441
|
-
* blocos de código (```), `código`, **negrito**, *itálico*, [texto](url) e URLs soltas.
|
|
1442
|
-
*/
|
|
1443
|
-
const PROTOCOLOS = ['http:', 'https:', 'mailto:'];
|
|
1444
|
-
function urlPermitida(url) {
|
|
1445
|
-
const bruto = (url || '').trim();
|
|
1446
|
-
if (!bruto || bruto.length > 2000)
|
|
1447
|
-
return null;
|
|
1448
|
-
try {
|
|
1449
|
-
const u = new URL(bruto);
|
|
1450
|
-
return PROTOCOLOS.includes(u.protocol) ? u.href : null;
|
|
1451
|
-
}
|
|
1452
|
-
catch (_a) {
|
|
1453
|
-
return null;
|
|
1454
|
-
}
|
|
1455
|
-
}
|
|
1456
|
-
const INLINE = /(`[^`\n]+`)|(\*\*[^*\n]+\*\*)|(\[[^\]\n]{1,300}\]\([^()\s]{1,2000}\))|(\bhttps?:\/\/[^\s<>()]*[^\s<>().,;:!?'"])|(\*[^*\s][^*\n]*\*)/g;
|
|
1457
|
-
function parseInline(texto) {
|
|
1458
|
-
const saida = [];
|
|
1459
|
-
let ultimo = 0;
|
|
1460
|
-
INLINE.lastIndex = 0;
|
|
1461
|
-
let m;
|
|
1462
|
-
while ((m = INLINE.exec(texto)) !== null) {
|
|
1463
|
-
if (m.index > ultimo)
|
|
1464
|
-
saida.push({ t: 'text', v: texto.slice(ultimo, m.index) });
|
|
1465
|
-
const token = m[0];
|
|
1466
|
-
if (m[1]) {
|
|
1467
|
-
saida.push({ t: 'code', v: token.slice(1, -1) });
|
|
1468
|
-
}
|
|
1469
|
-
else if (m[2]) {
|
|
1470
|
-
saida.push({ t: 'strong', v: token.slice(2, -2) });
|
|
1471
|
-
}
|
|
1472
|
-
else if (m[3]) {
|
|
1473
|
-
const fim = token.indexOf('](');
|
|
1474
|
-
const rotulo = token.slice(1, fim);
|
|
1475
|
-
const href = urlPermitida(token.slice(fim + 2, -1));
|
|
1476
|
-
saida.push(href ? { t: 'link', v: rotulo, href } : { t: 'text', v: rotulo });
|
|
1477
|
-
}
|
|
1478
|
-
else if (m[4]) {
|
|
1479
|
-
const href = urlPermitida(token);
|
|
1480
|
-
saida.push(href ? { t: 'link', v: token, href } : { t: 'text', v: token });
|
|
1481
|
-
}
|
|
1482
|
-
else {
|
|
1483
|
-
saida.push({ t: 'em', v: token.slice(1, -1) });
|
|
1484
|
-
}
|
|
1485
|
-
ultimo = m.index + token.length;
|
|
1486
|
-
}
|
|
1487
|
-
if (ultimo < texto.length)
|
|
1488
|
-
saida.push({ t: 'text', v: texto.slice(ultimo) });
|
|
1489
|
-
return saida;
|
|
1490
|
-
}
|
|
1491
|
-
function parseMarkdown(texto) {
|
|
1492
|
-
const linhas = (texto || '').replace(/\r\n?/g, '\n').split('\n');
|
|
1493
|
-
const blocos = [];
|
|
1494
|
-
let paragrafo = [];
|
|
1495
|
-
let lista = null;
|
|
1496
|
-
const fecharParagrafo = () => {
|
|
1497
|
-
if (paragrafo.length)
|
|
1498
|
-
blocos.push({ t: 'p', linhas: paragrafo });
|
|
1499
|
-
paragrafo = [];
|
|
1500
|
-
};
|
|
1501
|
-
const fecharLista = () => {
|
|
1502
|
-
if (lista)
|
|
1503
|
-
blocos.push(lista.t === 'ul' ? { t: 'ul', itens: lista.itens } : { t: 'ol', itens: lista.itens, inicio: lista.inicio });
|
|
1504
|
-
lista = null;
|
|
1505
|
-
};
|
|
1506
|
-
for (let i = 0; i < linhas.length; i++) {
|
|
1507
|
-
const linha = linhas[i];
|
|
1508
|
-
if (/^\s*```/.test(linha)) {
|
|
1509
|
-
fecharParagrafo();
|
|
1510
|
-
fecharLista();
|
|
1511
|
-
const codigo = [];
|
|
1512
|
-
i++;
|
|
1513
|
-
while (i < linhas.length && !/^\s*```/.test(linhas[i]))
|
|
1514
|
-
codigo.push(linhas[i++]);
|
|
1515
|
-
blocos.push({ t: 'code', v: codigo.join('\n') });
|
|
1516
|
-
continue;
|
|
1517
|
-
}
|
|
1518
|
-
if (!linha.trim()) {
|
|
1519
|
-
fecharParagrafo();
|
|
1520
|
-
fecharLista();
|
|
1521
|
-
continue;
|
|
1522
|
-
}
|
|
1523
|
-
const titulo = /^\s{0,3}#{1,3}\s+(.*)$/.exec(linha);
|
|
1524
|
-
if (titulo) {
|
|
1525
|
-
fecharParagrafo();
|
|
1526
|
-
fecharLista();
|
|
1527
|
-
blocos.push({ t: 'h', inlines: parseInline(titulo[1]) });
|
|
1528
|
-
continue;
|
|
1529
|
-
}
|
|
1530
|
-
const ul = /^\s*[-*•]\s+(.*)$/.exec(linha);
|
|
1531
|
-
const ol = /^\s*(\d{1,3})[.)]\s+(.*)$/.exec(linha);
|
|
1532
|
-
if (ul || ol) {
|
|
1533
|
-
fecharParagrafo();
|
|
1534
|
-
const tipo = ul ? 'ul' : 'ol';
|
|
1535
|
-
if (!lista || lista.t !== tipo) {
|
|
1536
|
-
fecharLista();
|
|
1537
|
-
lista = { t: tipo, itens: [], inicio: ol ? Number(ol[1]) : 1 };
|
|
1538
|
-
}
|
|
1539
|
-
lista.itens.push(parseInline(ul ? ul[1] : ol[2]));
|
|
1540
|
-
continue;
|
|
1541
|
-
}
|
|
1542
|
-
if (lista && /^\s{2,}\S/.test(linha)) {
|
|
1543
|
-
// continuação do último item da lista
|
|
1544
|
-
lista.itens[lista.itens.length - 1].push({ t: 'text', v: ' ' }, ...parseInline(linha.trim()));
|
|
1545
|
-
continue;
|
|
1546
|
-
}
|
|
1547
|
-
fecharLista();
|
|
1548
|
-
paragrafo.push(parseInline(linha));
|
|
1549
|
-
}
|
|
1550
|
-
fecharParagrafo();
|
|
1551
|
-
fecharLista();
|
|
1552
|
-
return blocos;
|
|
1553
|
-
}
|
|
1554
|
-
|
|
1555
|
-
/**
|
|
1556
|
-
* Exibe o texto da Uiny com um subconjunto de Markdown. Tudo é renderizado por
|
|
1557
|
-
* interpolação: HTML vindo da API aparece como texto, nunca é interpretado.
|
|
1558
|
-
*/
|
|
1559
|
-
class UiAssistantTextComponent {
|
|
1560
|
-
constructor() {
|
|
1561
|
-
this.texto = '';
|
|
1562
|
-
this.blocos = [];
|
|
1563
|
-
}
|
|
1564
|
-
ngOnChanges() {
|
|
1565
|
-
this.blocos = parseMarkdown(this.texto || '');
|
|
1566
|
-
}
|
|
1567
|
-
}
|
|
1568
|
-
UiAssistantTextComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: UiAssistantTextComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1569
|
-
UiAssistantTextComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: UiAssistantTextComponent, selector: "ui-assistant-text", inputs: { texto: "texto" }, usesOnChanges: true, ngImport: i0, template: "<ng-template #inlines let-lista>\n <ng-container *ngFor=\"let i of lista\" [ngSwitch]=\"i.t\">\n <strong *ngSwitchCase=\"'strong'\">{{ i.v }}</strong>\n <em *ngSwitchCase=\"'em'\">{{ i.v }}</em>\n <code *ngSwitchCase=\"'code'\">{{ i.v }}</code>\n <a *ngSwitchCase=\"'link'\" [href]=\"i.href\" target=\"_blank\" rel=\"noopener noreferrer nofollow\">{{ i.v }}</a>\n <ng-container *ngSwitchDefault>{{ i.v }}</ng-container>\n </ng-container>\n</ng-template>\n\n<ng-container *ngFor=\"let b of blocos\" [ngSwitch]=\"b.t\">\n <p *ngSwitchCase=\"'p'\">\n <ng-container *ngFor=\"let linha of $any(b).linhas; let ultima = last\">\n <ng-container *ngTemplateOutlet=\"inlines; context: { $implicit: linha }\"></ng-container><br *ngIf=\"!ultima\">\n </ng-container>\n </p>\n <p *ngSwitchCase=\"'h'\" class=\"uiny-texto__titulo\">\n <ng-container *ngTemplateOutlet=\"inlines; context: { $implicit: $any(b).inlines }\"></ng-container>\n </p>\n <ul *ngSwitchCase=\"'ul'\">\n <li *ngFor=\"let item of $any(b).itens\">\n <ng-container *ngTemplateOutlet=\"inlines; context: { $implicit: item }\"></ng-container>\n </li>\n </ul>\n <ol *ngSwitchCase=\"'ol'\" [attr.start]=\"$any(b).inicio !== 1 ? $any(b).inicio : null\">\n <li *ngFor=\"let item of $any(b).itens\">\n <ng-container *ngTemplateOutlet=\"inlines; context: { $implicit: item }\"></ng-container>\n </li>\n </ol>\n <pre *ngSwitchCase=\"'code'\"><code>{{ $any(b).v }}</code></pre>\n</ng-container>\n", styles: [":host{display:block;line-height:1.55;overflow-wrap:anywhere}p,ul,ol,pre{margin:0 0 8px}p:last-child,ul:last-child,ol:last-child,pre:last-child{margin-bottom:0}ul,ol{padding-left:20px}li+li{margin-top:3px}.uiny-texto__titulo{font-weight:700;margin-top:4px}strong{font-weight:700}code{padding:1px 5px;border-radius:5px;background:var(--uiny-fundo-suave, #f7f7fb);font-size:12.5px}pre{padding:10px 12px;border-radius:10px;background:var(--uiny-fundo-suave, #f7f7fb);overflow-x:auto;white-space:pre}pre code{padding:0;background:none}a{color:var(--uiny-primaria, #7366ff);text-decoration:underline;text-underline-offset:2px}\n"], dependencies: [{ kind: "directive", type: i1$2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1$2.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i1$2.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: i1$2.NgSwitchDefault, selector: "[ngSwitchDefault]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1570
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: UiAssistantTextComponent, decorators: [{
|
|
1571
|
-
type: Component,
|
|
1572
|
-
args: [{ selector: 'ui-assistant-text', changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-template #inlines let-lista>\n <ng-container *ngFor=\"let i of lista\" [ngSwitch]=\"i.t\">\n <strong *ngSwitchCase=\"'strong'\">{{ i.v }}</strong>\n <em *ngSwitchCase=\"'em'\">{{ i.v }}</em>\n <code *ngSwitchCase=\"'code'\">{{ i.v }}</code>\n <a *ngSwitchCase=\"'link'\" [href]=\"i.href\" target=\"_blank\" rel=\"noopener noreferrer nofollow\">{{ i.v }}</a>\n <ng-container *ngSwitchDefault>{{ i.v }}</ng-container>\n </ng-container>\n</ng-template>\n\n<ng-container *ngFor=\"let b of blocos\" [ngSwitch]=\"b.t\">\n <p *ngSwitchCase=\"'p'\">\n <ng-container *ngFor=\"let linha of $any(b).linhas; let ultima = last\">\n <ng-container *ngTemplateOutlet=\"inlines; context: { $implicit: linha }\"></ng-container><br *ngIf=\"!ultima\">\n </ng-container>\n </p>\n <p *ngSwitchCase=\"'h'\" class=\"uiny-texto__titulo\">\n <ng-container *ngTemplateOutlet=\"inlines; context: { $implicit: $any(b).inlines }\"></ng-container>\n </p>\n <ul *ngSwitchCase=\"'ul'\">\n <li *ngFor=\"let item of $any(b).itens\">\n <ng-container *ngTemplateOutlet=\"inlines; context: { $implicit: item }\"></ng-container>\n </li>\n </ul>\n <ol *ngSwitchCase=\"'ol'\" [attr.start]=\"$any(b).inicio !== 1 ? $any(b).inicio : null\">\n <li *ngFor=\"let item of $any(b).itens\">\n <ng-container *ngTemplateOutlet=\"inlines; context: { $implicit: item }\"></ng-container>\n </li>\n </ol>\n <pre *ngSwitchCase=\"'code'\"><code>{{ $any(b).v }}</code></pre>\n</ng-container>\n", styles: [":host{display:block;line-height:1.55;overflow-wrap:anywhere}p,ul,ol,pre{margin:0 0 8px}p:last-child,ul:last-child,ol:last-child,pre:last-child{margin-bottom:0}ul,ol{padding-left:20px}li+li{margin-top:3px}.uiny-texto__titulo{font-weight:700;margin-top:4px}strong{font-weight:700}code{padding:1px 5px;border-radius:5px;background:var(--uiny-fundo-suave, #f7f7fb);font-size:12.5px}pre{padding:10px 12px;border-radius:10px;background:var(--uiny-fundo-suave, #f7f7fb);overflow-x:auto;white-space:pre}pre code{padding:0;background:none}a{color:var(--uiny-primaria, #7366ff);text-decoration:underline;text-underline-offset:2px}\n"] }]
|
|
1573
|
-
}], propDecorators: { texto: [{
|
|
1574
|
-
type: Input
|
|
1575
|
-
}] } });
|
|
1576
|
-
|
|
1577
|
-
/** Distância do fim (px) até onde ainda consideramos que o usuário está "no fim". */
|
|
1578
|
-
const PERTO_DO_FIM = 96;
|
|
1579
|
-
class UiAssistantMessagesComponent {
|
|
1580
|
-
constructor(cdr, zone) {
|
|
1581
|
-
this.cdr = cdr;
|
|
1582
|
-
this.mensagens = [];
|
|
1583
|
-
this.acoes = {};
|
|
1584
|
-
this.enviando = false;
|
|
1585
|
-
this.carregando = false;
|
|
1586
|
-
this.sugestoes = [];
|
|
1587
|
-
this.capacidades = [];
|
|
1588
|
-
this.temAlteracoes = false;
|
|
1589
|
-
this.podeEnviar = true;
|
|
1590
|
-
this.sugestao = new EventEmitter();
|
|
1591
|
-
this.confirmar = new EventEmitter();
|
|
1592
|
-
this.cancelar = new EventEmitter();
|
|
1593
|
-
this.verificar = new EventEmitter();
|
|
1594
|
-
this.novas = false;
|
|
1595
|
-
this.pertoDoFim = true;
|
|
1596
|
-
this.rolarPendente = true;
|
|
1597
|
-
// o listener roda fora da zona: só reentra quando o indicador muda
|
|
1598
|
-
zone.runOutsideAngular(() => setTimeout(() => {
|
|
1599
|
-
var _a;
|
|
1600
|
-
const el = (_a = this.area) === null || _a === void 0 ? void 0 : _a.nativeElement;
|
|
1601
|
-
if (!el)
|
|
1602
|
-
return;
|
|
1603
|
-
const aoRolar = () => {
|
|
1604
|
-
const perto = this.calcularPertoDoFim();
|
|
1605
|
-
if (perto === this.pertoDoFim)
|
|
1606
|
-
return;
|
|
1607
|
-
this.pertoDoFim = perto;
|
|
1608
|
-
if (perto && this.novas)
|
|
1609
|
-
zone.run(() => {
|
|
1610
|
-
this.novas = false;
|
|
1611
|
-
this.cdr.markForCheck();
|
|
1612
|
-
});
|
|
1613
|
-
};
|
|
1614
|
-
el.addEventListener('scroll', aoRolar, { passive: true });
|
|
1615
|
-
this.removerScroll = () => el.removeEventListener('scroll', aoRolar);
|
|
1616
|
-
}));
|
|
1617
|
-
}
|
|
1618
|
-
ngOnChanges(changes) {
|
|
1619
|
-
var _a, _b, _c;
|
|
1620
|
-
const mudou = changes['mensagens'] || changes['enviando'] || changes['acoes'];
|
|
1621
|
-
if (!mudou)
|
|
1622
|
-
return;
|
|
1623
|
-
const mensagensMudaram = !!changes['mensagens'];
|
|
1624
|
-
const anterior = ((_a = changes['mensagens']) === null || _a === void 0 ? void 0 : _a.previousValue) || [];
|
|
1625
|
-
const atual = this.mensagens || [];
|
|
1626
|
-
const conversaTrocada = mensagensMudaram && (!anterior.length || !atual.length || ((_b = anterior[0]) === null || _b === void 0 ? void 0 : _b.id) !== ((_c = atual[0]) === null || _c === void 0 ? void 0 : _c.id));
|
|
1627
|
-
const ultima = atual[atual.length - 1];
|
|
1628
|
-
// quem acabou de enviar quer ver a própria mensagem
|
|
1629
|
-
const ultimaDoUsuario = mensagensMudaram && (ultima === null || ultima === void 0 ? void 0 : ultima.papel) === 'usuario' && ultima.id.startsWith('local-');
|
|
1630
|
-
if (conversaTrocada || ultimaDoUsuario || this.pertoDoFim) {
|
|
1631
|
-
this.rolarPendente = true;
|
|
1632
|
-
}
|
|
1633
|
-
else if (mensagensMudaram && atual.length > anterior.length) {
|
|
1634
|
-
// o usuário está lendo mensagens antigas: preserva a posição
|
|
1635
|
-
this.novas = true;
|
|
1636
|
-
}
|
|
1637
|
-
}
|
|
1638
|
-
ngAfterViewChecked() {
|
|
1639
|
-
if (!this.rolarPendente)
|
|
1640
|
-
return;
|
|
1641
|
-
this.rolarPendente = false;
|
|
1642
|
-
this.irParaOFim(false);
|
|
1643
|
-
}
|
|
1644
|
-
ngOnDestroy() {
|
|
1645
|
-
var _a;
|
|
1646
|
-
(_a = this.removerScroll) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
1647
|
-
}
|
|
1648
|
-
irParaOFim(suave = true) {
|
|
1649
|
-
var _a, _b;
|
|
1650
|
-
const el = (_a = this.area) === null || _a === void 0 ? void 0 : _a.nativeElement;
|
|
1651
|
-
if (!el)
|
|
1652
|
-
return;
|
|
1653
|
-
const reduzir = typeof window !== 'undefined' && ((_b = window.matchMedia) === null || _b === void 0 ? void 0 : _b.call(window, '(prefers-reduced-motion: reduce)').matches);
|
|
1654
|
-
if (suave && !reduzir && el.scrollTo) {
|
|
1655
|
-
el.scrollTo({ top: el.scrollHeight, behavior: 'smooth' });
|
|
1656
|
-
}
|
|
1657
|
-
else {
|
|
1658
|
-
el.scrollTop = el.scrollHeight;
|
|
1659
|
-
}
|
|
1660
|
-
this.pertoDoFim = true;
|
|
1661
|
-
if (this.novas) {
|
|
1662
|
-
this.novas = false;
|
|
1663
|
-
this.cdr.markForCheck();
|
|
1664
|
-
}
|
|
1665
|
-
}
|
|
1666
|
-
acaoDa(mensagem) {
|
|
1667
|
-
var _a, _b;
|
|
1668
|
-
return mensagem.idAcao ? (_b = (_a = this.acoes) === null || _a === void 0 ? void 0 : _a[mensagem.idAcao]) !== null && _b !== void 0 ? _b : null : null;
|
|
1669
|
-
}
|
|
1670
|
-
/** Ações devolvidas pela API sem mensagem que as referencie: aparecem no fim. */
|
|
1671
|
-
get acoesSemMensagem() {
|
|
1672
|
-
const referenciadas = new Set((this.mensagens || []).map(m => m.idAcao).filter(Boolean));
|
|
1673
|
-
return Object.values(this.acoes || {}).filter(a => !referenciadas.has(a.id));
|
|
1674
|
-
}
|
|
1675
|
-
trackMensagem(_, m) {
|
|
1676
|
-
return m.id;
|
|
1677
|
-
}
|
|
1678
|
-
trackAcao(_, a) {
|
|
1679
|
-
return a.id;
|
|
1680
|
-
}
|
|
1681
|
-
calcularPertoDoFim() {
|
|
1682
|
-
const el = this.area.nativeElement;
|
|
1683
|
-
return el.scrollHeight - el.scrollTop - el.clientHeight <= PERTO_DO_FIM;
|
|
1684
|
-
}
|
|
1685
|
-
}
|
|
1686
|
-
UiAssistantMessagesComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: UiAssistantMessagesComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component });
|
|
1687
|
-
UiAssistantMessagesComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: UiAssistantMessagesComponent, selector: "ui-assistant-messages", inputs: { mensagens: "mensagens", acoes: "acoes", enviando: "enviando", carregando: "carregando", sugestoes: "sugestoes", capacidades: "capacidades", temAlteracoes: "temAlteracoes", podeEnviar: "podeEnviar" }, outputs: { sugestao: "sugestao", confirmar: "confirmar", cancelar: "cancelar", verificar: "verificar" }, viewQueries: [{ propertyName: "area", first: true, predicate: ["area"], descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: "<div #area class=\"uiny-msgs\" role=\"log\" aria-live=\"off\" aria-label=\"Mensagens da conversa com a Uiny\" tabindex=\"0\">\r\n\r\n <div *ngIf=\"carregando\" class=\"uiny-msgs__carregando\" role=\"status\">\r\n <span class=\"uiny-spinner\" aria-hidden=\"true\"></span> Carregando a conversa\u2026\r\n </div>\r\n\r\n <div *ngIf=\"!carregando && !mensagens?.length\" class=\"uiny-boas-vindas\">\r\n <p class=\"uiny-boas-vindas__titulo\">Ol\u00E1! Eu sou a Uiny.</p>\r\n <p class=\"uiny-boas-vindas__texto\">Sou a assistente virtual da Uishop. Conte o que voc\u00EA precisa e eu ajudo por aqui.</p>\r\n <p *ngIf=\"temAlteracoes\" class=\"uiny-boas-vindas__nota\">\r\n <ui-icon icon=\"verified_user\" size=\"16\"></ui-icon>\r\n <span>Antes de alterar qualquer informa\u00E7\u00E3o, eu mostro o que vai mudar e s\u00F3 sigo com a sua confirma\u00E7\u00E3o.</span>\r\n </p>\r\n\r\n <div *ngIf=\"sugestoes?.length\" class=\"uiny-sugestoes\" aria-label=\"Sugest\u00F5es\">\r\n <button *ngFor=\"let s of sugestoes\" type=\"button\" class=\"uiny-sugestao\" [disabled]=\"!podeEnviar\" (click)=\"sugestao.emit(s)\">\r\n {{ s }}\r\n </button>\r\n </div>\r\n\r\n <div *ngIf=\"capacidades?.length\" class=\"uiny-capacidades\">\r\n <p class=\"uiny-capacidades__titulo\">Posso ajudar com:</p>\r\n <ul>\r\n <li *ngFor=\"let c of capacidades\">{{ c }}</li>\r\n </ul>\r\n </div>\r\n </div>\r\n\r\n <div *ngFor=\"let m of mensagens; trackBy: trackMensagem\" class=\"uiny-msg\"\r\n [class.uiny-msg--usuario]=\"m.papel === 'usuario'\"\r\n [class.uiny-msg--assistente]=\"m.papel !== 'usuario'\"\r\n [class.uiny-msg--falha]=\"m.erro\">\r\n <span class=\"uiny-sr\">{{ m.papel === 'usuario' ? 'Voc\u00EA:' : 'Uiny:' }}</span>\r\n <div class=\"uiny-msg__balao\">\r\n <p *ngIf=\"m.papel === 'usuario'\" class=\"uiny-msg__simples\">{{ m.texto }}</p>\r\n <ui-assistant-text *ngIf=\"m.papel !== 'usuario'\" [texto]=\"m.texto\"></ui-assistant-text>\r\n </div>\r\n\r\n <ui-assistant-action-card *ngIf=\"acaoDa(m) as acao\" [acao]=\"acao\"\r\n (confirmar)=\"confirmar.emit($event)\" (cancelar)=\"cancelar.emit($event)\" (verificar)=\"verificar.emit($event)\">\r\n </ui-assistant-action-card>\r\n\r\n <!-- esclarecimento: op\u00E7\u00F5es s\u00F3 na \u00FAltima mensagem, enviadas como texto -->\r\n <div *ngIf=\"m.opcoes?.length && m === mensagens[mensagens.length - 1]\" class=\"uiny-sugestoes uiny-msg__opcoes\" aria-label=\"Op\u00E7\u00F5es de resposta\">\r\n <button *ngFor=\"let o of m.opcoes\" type=\"button\" class=\"uiny-sugestao\" [disabled]=\"!podeEnviar || enviando\" (click)=\"sugestao.emit(o)\">\r\n {{ o }}\r\n </button>\r\n </div>\r\n\r\n <div class=\"uiny-msg__meta\">\r\n <span *ngIf=\"m.erro\" class=\"uiny-msg__nao-enviada\">\r\n <ui-icon icon=\"error\" size=\"14\"></ui-icon> N\u00E3o enviada\r\n </span>\r\n <time *ngIf=\"m.criadaEm && !m.erro\" [attr.datetime]=\"m.criadaEm.toISOString()\">{{ m.criadaEm | date:'HH:mm' }}</time>\r\n </div>\r\n </div>\r\n\r\n <ui-assistant-action-card *ngFor=\"let acao of acoesSemMensagem; trackBy: trackAcao\" class=\"uiny-msgs__acao-solta\" [acao]=\"acao\"\r\n (confirmar)=\"confirmar.emit($event)\" (cancelar)=\"cancelar.emit($event)\" (verificar)=\"verificar.emit($event)\">\r\n </ui-assistant-action-card>\r\n\r\n <div *ngIf=\"enviando\" class=\"uiny-digitando\">\r\n <span class=\"uiny-digitando__pontos\" aria-hidden=\"true\"><i></i><i></i><i></i></span>\r\n <span class=\"uiny-digitando__texto\">A Uiny est\u00E1 pensando\u2026</span>\r\n </div>\r\n</div>\r\n\r\n<button *ngIf=\"novas\" type=\"button\" class=\"uiny-novas\" (click)=\"irParaOFim()\">\r\n <ui-icon icon=\"arrow_downward\" size=\"16\"></ui-icon> Novas mensagens\r\n</button>\r\n", styles: [":host{position:relative;display:flex;flex-direction:column;min-height:0}.uiny-msgs{flex:1 1 auto;min-height:0;overflow-y:auto;overflow-x:hidden;overscroll-behavior:contain;padding:16px 14px 8px;scrollbar-width:thin}.uiny-msgs:focus-visible{outline:2px solid var(--uiny-primaria, #7366ff);outline-offset:-2px}.uiny-msgs__carregando{display:flex;align-items:center;gap:8px;color:var(--uiny-texto-suave, #6b6b80);font-size:13px}.uiny-spinner{width:14px;height:14px;border:2px solid var(--uiny-borda, #ececf3);border-top-color:var(--uiny-primaria, #7366ff);border-radius:50%;animation:uiny-girar .8s linear infinite}.uiny-boas-vindas{padding:8px 2px 4px}.uiny-boas-vindas__titulo{margin:0 0 4px;font-size:18px;font-weight:700;color:var(--uiny-texto, #2b2b2b)}.uiny-boas-vindas__texto{margin:0 0 12px;color:var(--uiny-texto-suave, #6b6b80);line-height:1.5}.uiny-boas-vindas__nota{display:flex;gap:6px;margin:0 0 14px;padding:8px 10px;border-radius:10px;background:var(--uiny-fundo-suave, #f7f7fb);color:var(--uiny-texto-suave, #6b6b80);font-size:12.5px;line-height:1.45}.uiny-boas-vindas__nota ui-icon{flex:0 0 auto;color:var(--uiny-primaria, #7366ff)}.uiny-sugestoes{display:flex;flex-direction:column;align-items:flex-start;gap:6px}.uiny-sugestao{max-width:100%;padding:8px 12px;border:1px solid var(--uiny-borda, #ececf3);border-radius:12px;background:var(--uiny-fundo, #fff);color:var(--uiny-texto, #2b2b2b);font-size:13px;text-align:left;line-height:1.35;cursor:pointer;transition:border-color .15s ease,background-color .15s ease}.uiny-sugestao:hover:not(:disabled){border-color:var(--uiny-primaria, #7366ff);background:var(--uiny-aviso-fundo, #f1effe)}.uiny-sugestao:disabled{opacity:.5;cursor:not-allowed}.uiny-sugestao:focus-visible{outline:2px solid var(--uiny-primaria, #7366ff);outline-offset:2px}.uiny-capacidades{font-size:13px;color:var(--uiny-texto-suave, #6b6b80)}.uiny-capacidades ul{margin:0;padding-left:18px}.uiny-capacidades li+li{margin-top:2px}.uiny-capacidades__titulo{margin:0 0 4px;font-weight:600;color:var(--uiny-texto, #2b2b2b)}.uiny-msg{display:flex;flex-direction:column;margin-top:14px}.uiny-msg:first-of-type{margin-top:0}.uiny-msg--usuario{align-items:flex-end}.uiny-msg--usuario .uiny-msg__balao{max-width:85%;padding:9px 13px;border-radius:16px 16px 4px;background:var(--uiny-primaria, #7366ff);color:#fff}.uiny-msg--assistente{align-items:stretch}.uiny-msg--assistente .uiny-msg__balao{max-width:100%;color:var(--uiny-texto, #2b2b2b)}.uiny-msg--falha .uiny-msg__balao{opacity:.65}.uiny-msg__simples{margin:0;white-space:pre-wrap;overflow-wrap:anywhere;line-height:1.45}.uiny-msg__meta{margin-top:3px;font-size:11px;color:var(--uiny-texto-suave, #6b6b80)}.uiny-msg__meta time{opacity:.8}.uiny-msg__nao-enviada{display:inline-flex;align-items:center;gap:3px;color:var(--uiny-erro, #d9364f)}.uiny-msg__opcoes{margin-top:8px}.uiny-msgs__acao-solta{display:block;margin-top:14px}.uiny-digitando{display:flex;align-items:center;gap:8px;margin-top:14px;color:var(--uiny-texto-suave, #6b6b80);font-size:13px}.uiny-digitando__pontos{display:inline-flex;gap:3px}.uiny-digitando__pontos i{width:6px;height:6px;border-radius:50%;background:var(--uiny-primaria, #7366ff);animation:uiny-pulsar 1.2s ease-in-out infinite}.uiny-digitando__pontos i:nth-child(2){animation-delay:.15s}.uiny-digitando__pontos i:nth-child(3){animation-delay:.3s}.uiny-novas{position:absolute;left:50%;bottom:10px;transform:translate(-50%);display:inline-flex;align-items:center;gap:4px;padding:6px 12px;border:0;border-radius:999px;background:var(--uiny-primaria, #7366ff);color:#fff;font-size:12px;font-weight:600;box-shadow:0 6px 16px #1f1b4d33;cursor:pointer}.uiny-novas:focus-visible{outline:2px solid var(--uiny-primaria, #7366ff);outline-offset:2px}.uiny-sr{position:absolute;width:1px;height:1px;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}@keyframes uiny-girar{to{transform:rotate(360deg)}}@keyframes uiny-pulsar{0%,80%,to{opacity:.25;transform:scale(.8)}40%{opacity:1;transform:scale(1)}}@media (prefers-reduced-motion: reduce){.uiny-digitando__pontos i{animation:none;opacity:.6}.uiny-spinner{animation-duration:2.4s}.uiny-sugestao{transition:none}}\n"], dependencies: [{ kind: "directive", type: i1$2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2.UiIconComponent, selector: "ui-icon", inputs: ["icon", "size", "class"] }, { kind: "component", type: UiAssistantTextComponent, selector: "ui-assistant-text", inputs: ["texto"] }, { kind: "component", type: UiAssistantActionCardComponent, selector: "ui-assistant-action-card", inputs: ["acao"], outputs: ["confirmar", "cancelar", "verificar"] }, { kind: "pipe", type: i1$2.DatePipe, name: "date" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1688
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: UiAssistantMessagesComponent, decorators: [{
|
|
1689
|
-
type: Component,
|
|
1690
|
-
args: [{ selector: 'ui-assistant-messages', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div #area class=\"uiny-msgs\" role=\"log\" aria-live=\"off\" aria-label=\"Mensagens da conversa com a Uiny\" tabindex=\"0\">\r\n\r\n <div *ngIf=\"carregando\" class=\"uiny-msgs__carregando\" role=\"status\">\r\n <span class=\"uiny-spinner\" aria-hidden=\"true\"></span> Carregando a conversa\u2026\r\n </div>\r\n\r\n <div *ngIf=\"!carregando && !mensagens?.length\" class=\"uiny-boas-vindas\">\r\n <p class=\"uiny-boas-vindas__titulo\">Ol\u00E1! Eu sou a Uiny.</p>\r\n <p class=\"uiny-boas-vindas__texto\">Sou a assistente virtual da Uishop. Conte o que voc\u00EA precisa e eu ajudo por aqui.</p>\r\n <p *ngIf=\"temAlteracoes\" class=\"uiny-boas-vindas__nota\">\r\n <ui-icon icon=\"verified_user\" size=\"16\"></ui-icon>\r\n <span>Antes de alterar qualquer informa\u00E7\u00E3o, eu mostro o que vai mudar e s\u00F3 sigo com a sua confirma\u00E7\u00E3o.</span>\r\n </p>\r\n\r\n <div *ngIf=\"sugestoes?.length\" class=\"uiny-sugestoes\" aria-label=\"Sugest\u00F5es\">\r\n <button *ngFor=\"let s of sugestoes\" type=\"button\" class=\"uiny-sugestao\" [disabled]=\"!podeEnviar\" (click)=\"sugestao.emit(s)\">\r\n {{ s }}\r\n </button>\r\n </div>\r\n\r\n <div *ngIf=\"capacidades?.length\" class=\"uiny-capacidades\">\r\n <p class=\"uiny-capacidades__titulo\">Posso ajudar com:</p>\r\n <ul>\r\n <li *ngFor=\"let c of capacidades\">{{ c }}</li>\r\n </ul>\r\n </div>\r\n </div>\r\n\r\n <div *ngFor=\"let m of mensagens; trackBy: trackMensagem\" class=\"uiny-msg\"\r\n [class.uiny-msg--usuario]=\"m.papel === 'usuario'\"\r\n [class.uiny-msg--assistente]=\"m.papel !== 'usuario'\"\r\n [class.uiny-msg--falha]=\"m.erro\">\r\n <span class=\"uiny-sr\">{{ m.papel === 'usuario' ? 'Voc\u00EA:' : 'Uiny:' }}</span>\r\n <div class=\"uiny-msg__balao\">\r\n <p *ngIf=\"m.papel === 'usuario'\" class=\"uiny-msg__simples\">{{ m.texto }}</p>\r\n <ui-assistant-text *ngIf=\"m.papel !== 'usuario'\" [texto]=\"m.texto\"></ui-assistant-text>\r\n </div>\r\n\r\n <ui-assistant-action-card *ngIf=\"acaoDa(m) as acao\" [acao]=\"acao\"\r\n (confirmar)=\"confirmar.emit($event)\" (cancelar)=\"cancelar.emit($event)\" (verificar)=\"verificar.emit($event)\">\r\n </ui-assistant-action-card>\r\n\r\n <!-- esclarecimento: op\u00E7\u00F5es s\u00F3 na \u00FAltima mensagem, enviadas como texto -->\r\n <div *ngIf=\"m.opcoes?.length && m === mensagens[mensagens.length - 1]\" class=\"uiny-sugestoes uiny-msg__opcoes\" aria-label=\"Op\u00E7\u00F5es de resposta\">\r\n <button *ngFor=\"let o of m.opcoes\" type=\"button\" class=\"uiny-sugestao\" [disabled]=\"!podeEnviar || enviando\" (click)=\"sugestao.emit(o)\">\r\n {{ o }}\r\n </button>\r\n </div>\r\n\r\n <div class=\"uiny-msg__meta\">\r\n <span *ngIf=\"m.erro\" class=\"uiny-msg__nao-enviada\">\r\n <ui-icon icon=\"error\" size=\"14\"></ui-icon> N\u00E3o enviada\r\n </span>\r\n <time *ngIf=\"m.criadaEm && !m.erro\" [attr.datetime]=\"m.criadaEm.toISOString()\">{{ m.criadaEm | date:'HH:mm' }}</time>\r\n </div>\r\n </div>\r\n\r\n <ui-assistant-action-card *ngFor=\"let acao of acoesSemMensagem; trackBy: trackAcao\" class=\"uiny-msgs__acao-solta\" [acao]=\"acao\"\r\n (confirmar)=\"confirmar.emit($event)\" (cancelar)=\"cancelar.emit($event)\" (verificar)=\"verificar.emit($event)\">\r\n </ui-assistant-action-card>\r\n\r\n <div *ngIf=\"enviando\" class=\"uiny-digitando\">\r\n <span class=\"uiny-digitando__pontos\" aria-hidden=\"true\"><i></i><i></i><i></i></span>\r\n <span class=\"uiny-digitando__texto\">A Uiny est\u00E1 pensando\u2026</span>\r\n </div>\r\n</div>\r\n\r\n<button *ngIf=\"novas\" type=\"button\" class=\"uiny-novas\" (click)=\"irParaOFim()\">\r\n <ui-icon icon=\"arrow_downward\" size=\"16\"></ui-icon> Novas mensagens\r\n</button>\r\n", styles: [":host{position:relative;display:flex;flex-direction:column;min-height:0}.uiny-msgs{flex:1 1 auto;min-height:0;overflow-y:auto;overflow-x:hidden;overscroll-behavior:contain;padding:16px 14px 8px;scrollbar-width:thin}.uiny-msgs:focus-visible{outline:2px solid var(--uiny-primaria, #7366ff);outline-offset:-2px}.uiny-msgs__carregando{display:flex;align-items:center;gap:8px;color:var(--uiny-texto-suave, #6b6b80);font-size:13px}.uiny-spinner{width:14px;height:14px;border:2px solid var(--uiny-borda, #ececf3);border-top-color:var(--uiny-primaria, #7366ff);border-radius:50%;animation:uiny-girar .8s linear infinite}.uiny-boas-vindas{padding:8px 2px 4px}.uiny-boas-vindas__titulo{margin:0 0 4px;font-size:18px;font-weight:700;color:var(--uiny-texto, #2b2b2b)}.uiny-boas-vindas__texto{margin:0 0 12px;color:var(--uiny-texto-suave, #6b6b80);line-height:1.5}.uiny-boas-vindas__nota{display:flex;gap:6px;margin:0 0 14px;padding:8px 10px;border-radius:10px;background:var(--uiny-fundo-suave, #f7f7fb);color:var(--uiny-texto-suave, #6b6b80);font-size:12.5px;line-height:1.45}.uiny-boas-vindas__nota ui-icon{flex:0 0 auto;color:var(--uiny-primaria, #7366ff)}.uiny-sugestoes{display:flex;flex-direction:column;align-items:flex-start;gap:6px}.uiny-sugestao{max-width:100%;padding:8px 12px;border:1px solid var(--uiny-borda, #ececf3);border-radius:12px;background:var(--uiny-fundo, #fff);color:var(--uiny-texto, #2b2b2b);font-size:13px;text-align:left;line-height:1.35;cursor:pointer;transition:border-color .15s ease,background-color .15s ease}.uiny-sugestao:hover:not(:disabled){border-color:var(--uiny-primaria, #7366ff);background:var(--uiny-aviso-fundo, #f1effe)}.uiny-sugestao:disabled{opacity:.5;cursor:not-allowed}.uiny-sugestao:focus-visible{outline:2px solid var(--uiny-primaria, #7366ff);outline-offset:2px}.uiny-capacidades{font-size:13px;color:var(--uiny-texto-suave, #6b6b80)}.uiny-capacidades ul{margin:0;padding-left:18px}.uiny-capacidades li+li{margin-top:2px}.uiny-capacidades__titulo{margin:0 0 4px;font-weight:600;color:var(--uiny-texto, #2b2b2b)}.uiny-msg{display:flex;flex-direction:column;margin-top:14px}.uiny-msg:first-of-type{margin-top:0}.uiny-msg--usuario{align-items:flex-end}.uiny-msg--usuario .uiny-msg__balao{max-width:85%;padding:9px 13px;border-radius:16px 16px 4px;background:var(--uiny-primaria, #7366ff);color:#fff}.uiny-msg--assistente{align-items:stretch}.uiny-msg--assistente .uiny-msg__balao{max-width:100%;color:var(--uiny-texto, #2b2b2b)}.uiny-msg--falha .uiny-msg__balao{opacity:.65}.uiny-msg__simples{margin:0;white-space:pre-wrap;overflow-wrap:anywhere;line-height:1.45}.uiny-msg__meta{margin-top:3px;font-size:11px;color:var(--uiny-texto-suave, #6b6b80)}.uiny-msg__meta time{opacity:.8}.uiny-msg__nao-enviada{display:inline-flex;align-items:center;gap:3px;color:var(--uiny-erro, #d9364f)}.uiny-msg__opcoes{margin-top:8px}.uiny-msgs__acao-solta{display:block;margin-top:14px}.uiny-digitando{display:flex;align-items:center;gap:8px;margin-top:14px;color:var(--uiny-texto-suave, #6b6b80);font-size:13px}.uiny-digitando__pontos{display:inline-flex;gap:3px}.uiny-digitando__pontos i{width:6px;height:6px;border-radius:50%;background:var(--uiny-primaria, #7366ff);animation:uiny-pulsar 1.2s ease-in-out infinite}.uiny-digitando__pontos i:nth-child(2){animation-delay:.15s}.uiny-digitando__pontos i:nth-child(3){animation-delay:.3s}.uiny-novas{position:absolute;left:50%;bottom:10px;transform:translate(-50%);display:inline-flex;align-items:center;gap:4px;padding:6px 12px;border:0;border-radius:999px;background:var(--uiny-primaria, #7366ff);color:#fff;font-size:12px;font-weight:600;box-shadow:0 6px 16px #1f1b4d33;cursor:pointer}.uiny-novas:focus-visible{outline:2px solid var(--uiny-primaria, #7366ff);outline-offset:2px}.uiny-sr{position:absolute;width:1px;height:1px;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}@keyframes uiny-girar{to{transform:rotate(360deg)}}@keyframes uiny-pulsar{0%,80%,to{opacity:.25;transform:scale(.8)}40%{opacity:1;transform:scale(1)}}@media (prefers-reduced-motion: reduce){.uiny-digitando__pontos i{animation:none;opacity:.6}.uiny-spinner{animation-duration:2.4s}.uiny-sugestao{transition:none}}\n"] }]
|
|
1691
|
-
}], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }, { type: i0.NgZone }]; }, propDecorators: { mensagens: [{
|
|
1692
|
-
type: Input
|
|
1693
|
-
}], acoes: [{
|
|
1694
|
-
type: Input
|
|
1695
|
-
}], enviando: [{
|
|
1696
|
-
type: Input
|
|
1697
|
-
}], carregando: [{
|
|
1698
|
-
type: Input
|
|
1699
|
-
}], sugestoes: [{
|
|
1700
|
-
type: Input
|
|
1701
|
-
}], capacidades: [{
|
|
1702
|
-
type: Input
|
|
1703
|
-
}], temAlteracoes: [{
|
|
1704
|
-
type: Input
|
|
1705
|
-
}], podeEnviar: [{
|
|
1706
|
-
type: Input
|
|
1707
|
-
}], sugestao: [{
|
|
1708
|
-
type: Output
|
|
1709
|
-
}], confirmar: [{
|
|
1710
|
-
type: Output
|
|
1711
|
-
}], cancelar: [{
|
|
1712
|
-
type: Output
|
|
1713
|
-
}], verificar: [{
|
|
1714
|
-
type: Output
|
|
1715
|
-
}], area: [{
|
|
1716
|
-
type: ViewChild,
|
|
1717
|
-
args: ['area', { static: true }]
|
|
1718
|
-
}] } });
|
|
1719
|
-
|
|
1720
|
-
class UiAssistantPanelComponent {
|
|
1721
|
-
constructor(chat, assistant, session, cdr, config) {
|
|
1722
|
-
this.chat = chat;
|
|
1723
|
-
this.assistant = assistant;
|
|
1724
|
-
this.session = session;
|
|
1725
|
-
this.cdr = cdr;
|
|
1726
|
-
/** Painel em largura total (celular/tablet): o botão de fechar vira "Voltar". */
|
|
1727
|
-
this.empilhado = false;
|
|
1728
|
-
this.online = true;
|
|
1729
|
-
this.anuncio = '';
|
|
1730
|
-
this.vendoHistorico = false;
|
|
1731
|
-
this.mensagens = [];
|
|
1732
|
-
this.acoes = {};
|
|
1733
|
-
this.sugestoes = [];
|
|
1734
|
-
this.capacidades = [];
|
|
1735
|
-
this.temAlteracoes = false;
|
|
1736
|
-
/** A imagem não carregou: usa o ícone padrão. */
|
|
1737
|
-
this.avatarFalhou = false;
|
|
1738
|
-
this.subs = new Subscription();
|
|
1739
|
-
this.avatarUrl = (config === null || config === void 0 ? void 0 : config.avatarUrl) || UINY_AVATAR_PADRAO;
|
|
1740
|
-
}
|
|
1741
|
-
ngOnInit() {
|
|
1742
|
-
this.subs.add(this.chat.estado.subscribe(estado => {
|
|
1743
|
-
this.estado = estado;
|
|
1744
|
-
this.mensagens = estado.mensagens;
|
|
1745
|
-
this.acoes = estado.acoes;
|
|
1746
|
-
this.cdr.markForCheck();
|
|
1747
|
-
}));
|
|
1748
|
-
this.subs.add(this.session.online$.subscribe(online => {
|
|
1749
|
-
this.online = online;
|
|
1750
|
-
this.cdr.markForCheck();
|
|
1751
|
-
}));
|
|
1752
|
-
this.subs.add(this.chat.anuncios.subscribe(texto => this.anunciar(texto)));
|
|
1753
|
-
this.montarBoasVindas();
|
|
1754
|
-
}
|
|
1755
|
-
ngAfterViewInit() {
|
|
1756
|
-
// espera a transição começar para não rolar a página no focus
|
|
1757
|
-
setTimeout(() => { var _a; return (_a = this.composer) === null || _a === void 0 ? void 0 : _a.focar(); }, 60);
|
|
1758
|
-
}
|
|
1759
|
-
ngOnDestroy() {
|
|
1760
|
-
clearTimeout(this.timerAnuncio);
|
|
1761
|
-
this.subs.unsubscribe();
|
|
1762
|
-
}
|
|
1763
|
-
aoEscape(evento) {
|
|
1764
|
-
if (evento.defaultPrevented)
|
|
1765
|
-
return;
|
|
1766
|
-
if (this.vendoHistorico) {
|
|
1767
|
-
this.vendoHistorico = false;
|
|
1768
|
-
return;
|
|
1769
|
-
}
|
|
1770
|
-
evento.preventDefault();
|
|
1771
|
-
this.assistant.fechar();
|
|
1772
|
-
}
|
|
1773
|
-
get podeEnviar() {
|
|
1774
|
-
var _a, _b;
|
|
1775
|
-
return this.online && !((_a = this.estado) === null || _a === void 0 ? void 0 : _a.enviando) && !((_b = this.estado) === null || _b === void 0 ? void 0 : _b.carregandoConversa);
|
|
1776
|
-
}
|
|
1777
|
-
get motivoBloqueio() {
|
|
1778
|
-
var _a;
|
|
1779
|
-
if (!this.online)
|
|
1780
|
-
return 'Sem conexão com a internet.';
|
|
1781
|
-
if ((_a = this.estado) === null || _a === void 0 ? void 0 : _a.carregandoConversa)
|
|
1782
|
-
return 'Carregando a conversa…';
|
|
1783
|
-
return null;
|
|
1784
|
-
}
|
|
1785
|
-
fechar() {
|
|
1786
|
-
this.assistant.fechar();
|
|
1787
|
-
}
|
|
1788
|
-
enviar(texto) {
|
|
1789
|
-
var _a;
|
|
1790
|
-
if (!this.podeEnviar)
|
|
1791
|
-
return;
|
|
1792
|
-
if (this.chat.enviar(texto)) {
|
|
1793
|
-
(_a = this.composer) === null || _a === void 0 ? void 0 : _a.limpar();
|
|
1794
|
-
this.vendoHistorico = false;
|
|
1795
|
-
}
|
|
1796
|
-
}
|
|
1797
|
-
reenviar() {
|
|
1798
|
-
var _a;
|
|
1799
|
-
const texto = (_a = this.estado) === null || _a === void 0 ? void 0 : _a.textoComFalha;
|
|
1800
|
-
if (texto && this.podeEnviar)
|
|
1801
|
-
this.chat.enviar(texto);
|
|
1802
|
-
}
|
|
1803
|
-
usarSugestao(texto) {
|
|
1804
|
-
this.enviar(texto);
|
|
1805
|
-
}
|
|
1806
|
-
novaConversa() {
|
|
1807
|
-
if (this.chat.novaConversa()) {
|
|
1808
|
-
this.vendoHistorico = false;
|
|
1809
|
-
this.anunciar('Nova conversa iniciada.');
|
|
1810
|
-
setTimeout(() => { var _a; return (_a = this.composer) === null || _a === void 0 ? void 0 : _a.focar(); });
|
|
1811
|
-
}
|
|
1812
|
-
}
|
|
1813
|
-
alternarHistorico() {
|
|
1814
|
-
this.vendoHistorico = !this.vendoHistorico;
|
|
1815
|
-
if (this.vendoHistorico)
|
|
1816
|
-
this.chat.listarConversas();
|
|
1817
|
-
}
|
|
1818
|
-
abrirConversa(id) {
|
|
1819
|
-
this.vendoHistorico = false;
|
|
1820
|
-
this.chat.abrirConversa(id);
|
|
1821
|
-
setTimeout(() => { var _a; return (_a = this.composer) === null || _a === void 0 ? void 0 : _a.focar(); });
|
|
1822
|
-
}
|
|
1823
|
-
trackConversa(_, c) {
|
|
1824
|
-
return c.id;
|
|
1825
|
-
}
|
|
1826
|
-
montarBoasVindas() {
|
|
1827
|
-
var _a;
|
|
1828
|
-
const sugestoes = (_a = UINY_SUGESTOES[this.assistant.sistemaOrigem]) !== null && _a !== void 0 ? _a : { textos: [], alteracoes: false };
|
|
1829
|
-
this.sugestoes = sugestoes.textos;
|
|
1830
|
-
this.capacidades = [];
|
|
1831
|
-
this.temAlteracoes = sugestoes.alteracoes;
|
|
1832
|
-
}
|
|
1833
|
-
anunciar(texto) {
|
|
1834
|
-
// limpa antes para leitores de tela repetirem anúncios iguais
|
|
1835
|
-
this.anuncio = '';
|
|
1836
|
-
this.cdr.markForCheck();
|
|
1837
|
-
clearTimeout(this.timerAnuncio);
|
|
1838
|
-
if (!texto)
|
|
1839
|
-
return;
|
|
1840
|
-
this.timerAnuncio = setTimeout(() => {
|
|
1841
|
-
this.anuncio = texto;
|
|
1842
|
-
this.cdr.markForCheck();
|
|
1843
|
-
}, 50);
|
|
1844
|
-
}
|
|
1845
|
-
}
|
|
1846
|
-
UiAssistantPanelComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: UiAssistantPanelComponent, deps: [{ token: UinyChatService }, { token: UiAssistantService }, { token: UinySessionService }, { token: i0.ChangeDetectorRef }, { token: UINY_CONFIG, optional: true }], target: i0.ɵɵFactoryTarget.Component });
|
|
1847
|
-
UiAssistantPanelComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: UiAssistantPanelComponent, selector: "ui-assistant-panel", inputs: { empilhado: "empilhado" }, host: { listeners: { "keydown.escape": "aoEscape($event)" } }, viewQueries: [{ propertyName: "composer", first: true, predicate: UiAssistantComposerComponent, descendants: true }], ngImport: i0, template: "<section class=\"uiny\" aria-labelledby=\"uiny-titulo\">\r\n <header class=\"uiny__topo\">\r\n <div class=\"uiny__marca\">\r\n <img *ngIf=\"!avatarFalhou\" class=\"uiny__avatar uiny__avatar--imagem\" [src]=\"avatarUrl\" alt=\"\"\r\n width=\"34\" height=\"34\" (error)=\"avatarFalhou = true\">\r\n <span *ngIf=\"avatarFalhou\" class=\"uiny__avatar\" aria-hidden=\"true\">\r\n <svg viewBox=\"0 0 24 24\" width=\"18\" height=\"18\" focusable=\"false\">\r\n <path d=\"M12 2.5c.5 3.9 2.6 6.9 6.4 8.2.5.2.5.9 0 1.1-3.8 1.3-5.9 4.3-6.4 8.2-.1.6-.9.6-1 0-.5-3.9-2.6-6.9-6.4-8.2-.5-.2-.5-.9 0-1.1 3.8-1.3 5.9-4.3 6.4-8.2.1-.6.9-.6 1 0Z\" fill=\"currentColor\"/>\r\n </svg>\r\n </span>\r\n <div class=\"uiny__identidade\">\r\n <h2 id=\"uiny-titulo\" class=\"uiny__nome\">Uiny</h2>\r\n <p class=\"uiny__sub\">Assistente da Uishop</p>\r\n </div>\r\n </div>\r\n\r\n <div class=\"uiny__comandos\">\r\n <button type=\"button\" class=\"uiny__icone\" [class.is-ativo]=\"vendoHistorico\"\r\n [attr.aria-pressed]=\"vendoHistorico ? 'true' : 'false'\"\r\n aria-label=\"Conversas anteriores\" title=\"Conversas anteriores\"\r\n (click)=\"alternarHistorico()\">\r\n <ui-icon icon=\"history\" size=\"20\"></ui-icon>\r\n </button>\r\n <button type=\"button\" class=\"uiny__icone\" aria-label=\"Nova conversa\" title=\"Nova conversa\"\r\n [disabled]=\"chat.ocupado\" (click)=\"novaConversa()\">\r\n <ui-icon icon=\"edit_square\" size=\"20\"></ui-icon>\r\n </button>\r\n <button type=\"button\" class=\"uiny__icone\" (click)=\"fechar()\"\r\n [attr.aria-label]=\"empilhado ? 'Voltar para a aplica\u00E7\u00E3o' : 'Fechar a Uiny'\"\r\n [title]=\"empilhado ? 'Voltar para a aplica\u00E7\u00E3o' : 'Fechar (Esc)'\">\r\n <ui-icon [icon]=\"empilhado ? 'arrow_back' : 'close'\" size=\"20\"></ui-icon>\r\n </button>\r\n </div>\r\n </header>\r\n\r\n <div *ngIf=\"!online\" class=\"uiny__faixa uiny__faixa--offline\" role=\"status\">\r\n <ui-icon icon=\"wifi_off\" size=\"18\"></ui-icon>\r\n <span>Sem conex\u00E3o com a internet. Voc\u00EA poder\u00E1 enviar mensagens quando ela voltar.</span>\r\n </div>\r\n\r\n <div *ngIf=\"estado?.aviso\" class=\"uiny__faixa uiny__faixa--info\" role=\"status\">\r\n <ui-icon icon=\"info\" size=\"18\"></ui-icon>\r\n <span>{{ estado.aviso }}</span>\r\n <button type=\"button\" class=\"uiny__faixa-fechar\" aria-label=\"Dispensar aviso\" (click)=\"chat.limparErro()\">\r\n <ui-icon icon=\"close\" size=\"16\"></ui-icon>\r\n </button>\r\n </div>\r\n\r\n <div *ngIf=\"vendoHistorico; else conversaAtual\" class=\"uiny__historico\">\r\n <div class=\"uiny__historico-topo\">\r\n <h3 class=\"uiny__historico-titulo\">Conversas anteriores</h3>\r\n <button type=\"button\" class=\"uiny__link\" (click)=\"vendoHistorico = false\">Voltar \u00E0 conversa</button>\r\n </div>\r\n\r\n <div *ngIf=\"estado?.carregandoConversas\" class=\"uiny__vazio\" role=\"status\">\r\n <span class=\"uiny__spinner\" aria-hidden=\"true\"></span> Carregando conversas\u2026\r\n </div>\r\n\r\n <p *ngIf=\"!estado?.carregandoConversas && estado?.conversas?.length === 0\" class=\"uiny__vazio\">\r\n Nenhuma conversa anterior neste contexto.\r\n </p>\r\n\r\n <ul *ngIf=\"estado?.conversas?.length\" class=\"uiny__lista-conversas\">\r\n <li *ngFor=\"let c of estado.conversas; trackBy: trackConversa\">\r\n <button type=\"button\" class=\"uiny__conversa\" [class.is-atual]=\"c.id === estado.conversa?.id\"\r\n [attr.aria-current]=\"c.id === estado.conversa?.id ? 'true' : null\"\r\n [disabled]=\"chat.ocupado\" (click)=\"abrirConversa(c.id)\">\r\n <span class=\"uiny__conversa-titulo\">{{ c.titulo || 'Conversa sem t\u00EDtulo' }}</span>\r\n <span *ngIf=\"c.atualizadaEm\" class=\"uiny__conversa-data\">{{ c.atualizadaEm | date:'dd/MM/yyyy HH:mm' }}</span>\r\n </button>\r\n </li>\r\n </ul>\r\n </div>\r\n\r\n <ng-template #conversaAtual>\r\n <ui-assistant-messages class=\"uiny__mensagens\"\r\n [mensagens]=\"mensagens\"\r\n [acoes]=\"acoes\"\r\n [enviando]=\"estado?.enviando\"\r\n [carregando]=\"estado?.carregandoConversa\"\r\n [sugestoes]=\"sugestoes\"\r\n [capacidades]=\"capacidades\"\r\n [temAlteracoes]=\"temAlteracoes\"\r\n [podeEnviar]=\"podeEnviar\"\r\n (sugestao)=\"usarSugestao($event)\"\r\n (confirmar)=\"chat.confirmar($event)\"\r\n (cancelar)=\"chat.cancelar($event)\"\r\n (verificar)=\"chat.verificarAcao($event)\">\r\n </ui-assistant-messages>\r\n </ng-template>\r\n\r\n <div *ngIf=\"estado?.erro\" class=\"uiny__erro\" role=\"alert\">\r\n <ui-icon icon=\"error\" size=\"18\"></ui-icon>\r\n <div class=\"uiny__erro-texto\">\r\n <span>{{ estado.erro.mensagem }}</span>\r\n <small *ngIf=\"estado.erro.correlacao\">C\u00F3digo para o suporte: {{ estado.erro.correlacao }}</small>\r\n </div>\r\n <button *ngIf=\"estado.textoComFalha && podeEnviar\" type=\"button\" class=\"uiny__link\" (click)=\"reenviar()\">\r\n Tentar de novo\r\n </button>\r\n <button type=\"button\" class=\"uiny__faixa-fechar\" aria-label=\"Dispensar erro\" (click)=\"chat.limparErro()\">\r\n <ui-icon icon=\"close\" size=\"16\"></ui-icon>\r\n </button>\r\n </div>\r\n\r\n <ui-assistant-composer class=\"uiny__composer\"\r\n [desabilitado]=\"!podeEnviar\"\r\n [enviando]=\"estado?.enviando\"\r\n [motivo]=\"motivoBloqueio\"\r\n (enviar)=\"enviar($event)\">\r\n </ui-assistant-composer>\r\n\r\n <div class=\"uiny-sr\" aria-live=\"polite\" aria-atomic=\"true\">{{ anuncio }}</div>\r\n</section>\r\n", styles: [":host{--uiny-primaria: var(--theme-default, #7366ff);--uiny-fundo: #ffffff;--uiny-fundo-suave: #f7f7fb;--uiny-borda: #ececf3;--uiny-texto: #2b2b2b;--uiny-texto-suave: #6b6b80;--uiny-erro: #d9364f;--uiny-erro-fundo: #fdeef1;--uiny-aviso-fundo: #f1effe;--uiny-offline-fundo: #fff4e5;--uiny-offline-texto: #8a5300;display:block;height:100%;color:var(--uiny-texto);font-size:14px}:host-context(.dark-only){--uiny-fundo: #262932;--uiny-fundo-suave: #1d1e26;--uiny-borda: #374558;--uiny-texto: rgba(255, 255, 255, .85);--uiny-texto-suave: #98a6ad;--uiny-erro-fundo: rgba(217, 54, 79, .16);--uiny-aviso-fundo: rgba(115, 102, 255, .16);--uiny-offline-fundo: rgba(255, 170, 0, .14);--uiny-offline-texto: #ffc76b}.uiny{display:flex;flex-direction:column;height:100%;background:var(--uiny-fundo);border-left:1px solid var(--uiny-borda);box-shadow:-4px 0 24px #1f1b4d0f}.uiny__topo{flex:0 0 auto;display:flex;align-items:center;justify-content:space-between;gap:8px;padding:14px 12px 14px 16px;border-bottom:1px solid var(--uiny-borda)}.uiny__marca{display:flex;align-items:center;gap:10px;min-width:0}.uiny__avatar{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;width:34px;height:34px;border-radius:11px;color:#fff;background:linear-gradient(135deg,var(--uiny-primaria) 0%,#a26cf8 100%)}.uiny__avatar--imagem{object-fit:cover;background:var(--uiny-fundo-suave)}.uiny__identidade{min-width:0}.uiny__nome{margin:0;font-size:16px;font-weight:700;line-height:1.2;color:var(--uiny-texto)}.uiny__sub{margin:0;font-size:12px;line-height:1.3;color:var(--uiny-texto-suave)}.uiny__comandos{display:flex;align-items:center;gap:2px}.uiny__icone{display:inline-flex;align-items:center;justify-content:center;width:34px;height:34px;padding:0;border:0;border-radius:9px;background:transparent;color:var(--uiny-texto-suave);cursor:pointer}.uiny__icone:hover:not(:disabled),.uiny__icone.is-ativo{background:var(--uiny-fundo-suave);color:var(--uiny-primaria)}.uiny__icone:disabled{opacity:.4;cursor:not-allowed}button:focus-visible{outline:2px solid var(--uiny-primaria);outline-offset:2px}.uiny__faixa,.uiny__erro{flex:0 0 auto;display:flex;align-items:flex-start;gap:8px;margin:10px 12px 0;padding:9px 10px;border-radius:10px;font-size:13px;line-height:1.4}.uiny__faixa>ui-icon,.uiny__erro>ui-icon{flex:0 0 auto;margin-top:1px}.uiny__faixa>span,.uiny__faixa .uiny__erro-texto,.uiny__erro>span,.uiny__erro .uiny__erro-texto{flex:1 1 auto;min-width:0}.uiny__faixa--offline{background:var(--uiny-offline-fundo);color:var(--uiny-offline-texto)}.uiny__faixa--info{background:var(--uiny-aviso-fundo);color:var(--uiny-texto)}.uiny__erro{margin:0 12px 8px;background:var(--uiny-erro-fundo);color:var(--uiny-erro);align-items:center}.uiny__erro .uiny__erro-texto{display:flex;flex-direction:column;gap:2px}.uiny__erro .uiny__erro-texto small{opacity:.8;font-size:11px}.uiny__faixa-fechar{flex:0 0 auto;display:inline-flex;padding:2px;border:0;border-radius:6px;background:transparent;color:inherit;cursor:pointer;opacity:.7}.uiny__faixa-fechar:hover{opacity:1}.uiny__link{flex:0 0 auto;padding:0;border:0;background:none;color:var(--uiny-primaria);font-size:13px;font-weight:600;cursor:pointer;white-space:nowrap}.uiny__link:hover{text-decoration:underline}.uiny__mensagens{flex:1 1 auto;min-height:0}.uiny__historico{flex:1 1 auto;min-height:0;overflow-y:auto;padding:14px 12px}.uiny__historico-topo{display:flex;align-items:center;justify-content:space-between;margin-bottom:10px;padding:0 4px}.uiny__historico-titulo{margin:0;font-size:13px;font-weight:700;color:var(--uiny-texto)}.uiny__lista-conversas{margin:0;padding:0;list-style:none}.uiny__conversa{display:flex;flex-direction:column;gap:2px;width:100%;padding:10px 12px;border:1px solid transparent;border-radius:10px;background:transparent;color:var(--uiny-texto);text-align:left;cursor:pointer}.uiny__conversa:hover:not(:disabled){background:var(--uiny-fundo-suave)}.uiny__conversa.is-atual{border-color:var(--uiny-borda);background:var(--uiny-fundo-suave)}.uiny__conversa:disabled{opacity:.5;cursor:not-allowed}.uiny__conversa-titulo{overflow:hidden;font-weight:600;text-overflow:ellipsis;white-space:nowrap}.uiny__conversa-data{font-size:12px;color:var(--uiny-texto-suave)}.uiny__vazio{display:flex;align-items:center;gap:8px;margin:18px 4px;color:var(--uiny-texto-suave);font-size:13px}.uiny__spinner{width:14px;height:14px;border:2px solid var(--uiny-borda);border-top-color:var(--uiny-primaria);border-radius:50%;animation:uiny-girar .8s linear infinite}.uiny__composer{flex:0 0 auto}.uiny-sr{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}@keyframes uiny-girar{to{transform:rotate(360deg)}}@media (prefers-reduced-motion: reduce){.uiny__spinner{animation-duration:2.4s}}\n"], dependencies: [{ kind: "directive", type: i1$2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2.UiIconComponent, selector: "ui-icon", inputs: ["icon", "size", "class"] }, { kind: "component", type: UiAssistantMessagesComponent, selector: "ui-assistant-messages", inputs: ["mensagens", "acoes", "enviando", "carregando", "sugestoes", "capacidades", "temAlteracoes", "podeEnviar"], outputs: ["sugestao", "confirmar", "cancelar", "verificar"] }, { kind: "component", type: UiAssistantComposerComponent, selector: "ui-assistant-composer", inputs: ["desabilitado", "enviando", "motivo"], outputs: ["enviar"] }, { kind: "pipe", type: i1$2.DatePipe, name: "date" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1848
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: UiAssistantPanelComponent, decorators: [{
|
|
1849
|
-
type: Component,
|
|
1850
|
-
args: [{ selector: 'ui-assistant-panel', changeDetection: ChangeDetectionStrategy.OnPush, template: "<section class=\"uiny\" aria-labelledby=\"uiny-titulo\">\r\n <header class=\"uiny__topo\">\r\n <div class=\"uiny__marca\">\r\n <img *ngIf=\"!avatarFalhou\" class=\"uiny__avatar uiny__avatar--imagem\" [src]=\"avatarUrl\" alt=\"\"\r\n width=\"34\" height=\"34\" (error)=\"avatarFalhou = true\">\r\n <span *ngIf=\"avatarFalhou\" class=\"uiny__avatar\" aria-hidden=\"true\">\r\n <svg viewBox=\"0 0 24 24\" width=\"18\" height=\"18\" focusable=\"false\">\r\n <path d=\"M12 2.5c.5 3.9 2.6 6.9 6.4 8.2.5.2.5.9 0 1.1-3.8 1.3-5.9 4.3-6.4 8.2-.1.6-.9.6-1 0-.5-3.9-2.6-6.9-6.4-8.2-.5-.2-.5-.9 0-1.1 3.8-1.3 5.9-4.3 6.4-8.2.1-.6.9-.6 1 0Z\" fill=\"currentColor\"/>\r\n </svg>\r\n </span>\r\n <div class=\"uiny__identidade\">\r\n <h2 id=\"uiny-titulo\" class=\"uiny__nome\">Uiny</h2>\r\n <p class=\"uiny__sub\">Assistente da Uishop</p>\r\n </div>\r\n </div>\r\n\r\n <div class=\"uiny__comandos\">\r\n <button type=\"button\" class=\"uiny__icone\" [class.is-ativo]=\"vendoHistorico\"\r\n [attr.aria-pressed]=\"vendoHistorico ? 'true' : 'false'\"\r\n aria-label=\"Conversas anteriores\" title=\"Conversas anteriores\"\r\n (click)=\"alternarHistorico()\">\r\n <ui-icon icon=\"history\" size=\"20\"></ui-icon>\r\n </button>\r\n <button type=\"button\" class=\"uiny__icone\" aria-label=\"Nova conversa\" title=\"Nova conversa\"\r\n [disabled]=\"chat.ocupado\" (click)=\"novaConversa()\">\r\n <ui-icon icon=\"edit_square\" size=\"20\"></ui-icon>\r\n </button>\r\n <button type=\"button\" class=\"uiny__icone\" (click)=\"fechar()\"\r\n [attr.aria-label]=\"empilhado ? 'Voltar para a aplica\u00E7\u00E3o' : 'Fechar a Uiny'\"\r\n [title]=\"empilhado ? 'Voltar para a aplica\u00E7\u00E3o' : 'Fechar (Esc)'\">\r\n <ui-icon [icon]=\"empilhado ? 'arrow_back' : 'close'\" size=\"20\"></ui-icon>\r\n </button>\r\n </div>\r\n </header>\r\n\r\n <div *ngIf=\"!online\" class=\"uiny__faixa uiny__faixa--offline\" role=\"status\">\r\n <ui-icon icon=\"wifi_off\" size=\"18\"></ui-icon>\r\n <span>Sem conex\u00E3o com a internet. Voc\u00EA poder\u00E1 enviar mensagens quando ela voltar.</span>\r\n </div>\r\n\r\n <div *ngIf=\"estado?.aviso\" class=\"uiny__faixa uiny__faixa--info\" role=\"status\">\r\n <ui-icon icon=\"info\" size=\"18\"></ui-icon>\r\n <span>{{ estado.aviso }}</span>\r\n <button type=\"button\" class=\"uiny__faixa-fechar\" aria-label=\"Dispensar aviso\" (click)=\"chat.limparErro()\">\r\n <ui-icon icon=\"close\" size=\"16\"></ui-icon>\r\n </button>\r\n </div>\r\n\r\n <div *ngIf=\"vendoHistorico; else conversaAtual\" class=\"uiny__historico\">\r\n <div class=\"uiny__historico-topo\">\r\n <h3 class=\"uiny__historico-titulo\">Conversas anteriores</h3>\r\n <button type=\"button\" class=\"uiny__link\" (click)=\"vendoHistorico = false\">Voltar \u00E0 conversa</button>\r\n </div>\r\n\r\n <div *ngIf=\"estado?.carregandoConversas\" class=\"uiny__vazio\" role=\"status\">\r\n <span class=\"uiny__spinner\" aria-hidden=\"true\"></span> Carregando conversas\u2026\r\n </div>\r\n\r\n <p *ngIf=\"!estado?.carregandoConversas && estado?.conversas?.length === 0\" class=\"uiny__vazio\">\r\n Nenhuma conversa anterior neste contexto.\r\n </p>\r\n\r\n <ul *ngIf=\"estado?.conversas?.length\" class=\"uiny__lista-conversas\">\r\n <li *ngFor=\"let c of estado.conversas; trackBy: trackConversa\">\r\n <button type=\"button\" class=\"uiny__conversa\" [class.is-atual]=\"c.id === estado.conversa?.id\"\r\n [attr.aria-current]=\"c.id === estado.conversa?.id ? 'true' : null\"\r\n [disabled]=\"chat.ocupado\" (click)=\"abrirConversa(c.id)\">\r\n <span class=\"uiny__conversa-titulo\">{{ c.titulo || 'Conversa sem t\u00EDtulo' }}</span>\r\n <span *ngIf=\"c.atualizadaEm\" class=\"uiny__conversa-data\">{{ c.atualizadaEm | date:'dd/MM/yyyy HH:mm' }}</span>\r\n </button>\r\n </li>\r\n </ul>\r\n </div>\r\n\r\n <ng-template #conversaAtual>\r\n <ui-assistant-messages class=\"uiny__mensagens\"\r\n [mensagens]=\"mensagens\"\r\n [acoes]=\"acoes\"\r\n [enviando]=\"estado?.enviando\"\r\n [carregando]=\"estado?.carregandoConversa\"\r\n [sugestoes]=\"sugestoes\"\r\n [capacidades]=\"capacidades\"\r\n [temAlteracoes]=\"temAlteracoes\"\r\n [podeEnviar]=\"podeEnviar\"\r\n (sugestao)=\"usarSugestao($event)\"\r\n (confirmar)=\"chat.confirmar($event)\"\r\n (cancelar)=\"chat.cancelar($event)\"\r\n (verificar)=\"chat.verificarAcao($event)\">\r\n </ui-assistant-messages>\r\n </ng-template>\r\n\r\n <div *ngIf=\"estado?.erro\" class=\"uiny__erro\" role=\"alert\">\r\n <ui-icon icon=\"error\" size=\"18\"></ui-icon>\r\n <div class=\"uiny__erro-texto\">\r\n <span>{{ estado.erro.mensagem }}</span>\r\n <small *ngIf=\"estado.erro.correlacao\">C\u00F3digo para o suporte: {{ estado.erro.correlacao }}</small>\r\n </div>\r\n <button *ngIf=\"estado.textoComFalha && podeEnviar\" type=\"button\" class=\"uiny__link\" (click)=\"reenviar()\">\r\n Tentar de novo\r\n </button>\r\n <button type=\"button\" class=\"uiny__faixa-fechar\" aria-label=\"Dispensar erro\" (click)=\"chat.limparErro()\">\r\n <ui-icon icon=\"close\" size=\"16\"></ui-icon>\r\n </button>\r\n </div>\r\n\r\n <ui-assistant-composer class=\"uiny__composer\"\r\n [desabilitado]=\"!podeEnviar\"\r\n [enviando]=\"estado?.enviando\"\r\n [motivo]=\"motivoBloqueio\"\r\n (enviar)=\"enviar($event)\">\r\n </ui-assistant-composer>\r\n\r\n <div class=\"uiny-sr\" aria-live=\"polite\" aria-atomic=\"true\">{{ anuncio }}</div>\r\n</section>\r\n", styles: [":host{--uiny-primaria: var(--theme-default, #7366ff);--uiny-fundo: #ffffff;--uiny-fundo-suave: #f7f7fb;--uiny-borda: #ececf3;--uiny-texto: #2b2b2b;--uiny-texto-suave: #6b6b80;--uiny-erro: #d9364f;--uiny-erro-fundo: #fdeef1;--uiny-aviso-fundo: #f1effe;--uiny-offline-fundo: #fff4e5;--uiny-offline-texto: #8a5300;display:block;height:100%;color:var(--uiny-texto);font-size:14px}:host-context(.dark-only){--uiny-fundo: #262932;--uiny-fundo-suave: #1d1e26;--uiny-borda: #374558;--uiny-texto: rgba(255, 255, 255, .85);--uiny-texto-suave: #98a6ad;--uiny-erro-fundo: rgba(217, 54, 79, .16);--uiny-aviso-fundo: rgba(115, 102, 255, .16);--uiny-offline-fundo: rgba(255, 170, 0, .14);--uiny-offline-texto: #ffc76b}.uiny{display:flex;flex-direction:column;height:100%;background:var(--uiny-fundo);border-left:1px solid var(--uiny-borda);box-shadow:-4px 0 24px #1f1b4d0f}.uiny__topo{flex:0 0 auto;display:flex;align-items:center;justify-content:space-between;gap:8px;padding:14px 12px 14px 16px;border-bottom:1px solid var(--uiny-borda)}.uiny__marca{display:flex;align-items:center;gap:10px;min-width:0}.uiny__avatar{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;width:34px;height:34px;border-radius:11px;color:#fff;background:linear-gradient(135deg,var(--uiny-primaria) 0%,#a26cf8 100%)}.uiny__avatar--imagem{object-fit:cover;background:var(--uiny-fundo-suave)}.uiny__identidade{min-width:0}.uiny__nome{margin:0;font-size:16px;font-weight:700;line-height:1.2;color:var(--uiny-texto)}.uiny__sub{margin:0;font-size:12px;line-height:1.3;color:var(--uiny-texto-suave)}.uiny__comandos{display:flex;align-items:center;gap:2px}.uiny__icone{display:inline-flex;align-items:center;justify-content:center;width:34px;height:34px;padding:0;border:0;border-radius:9px;background:transparent;color:var(--uiny-texto-suave);cursor:pointer}.uiny__icone:hover:not(:disabled),.uiny__icone.is-ativo{background:var(--uiny-fundo-suave);color:var(--uiny-primaria)}.uiny__icone:disabled{opacity:.4;cursor:not-allowed}button:focus-visible{outline:2px solid var(--uiny-primaria);outline-offset:2px}.uiny__faixa,.uiny__erro{flex:0 0 auto;display:flex;align-items:flex-start;gap:8px;margin:10px 12px 0;padding:9px 10px;border-radius:10px;font-size:13px;line-height:1.4}.uiny__faixa>ui-icon,.uiny__erro>ui-icon{flex:0 0 auto;margin-top:1px}.uiny__faixa>span,.uiny__faixa .uiny__erro-texto,.uiny__erro>span,.uiny__erro .uiny__erro-texto{flex:1 1 auto;min-width:0}.uiny__faixa--offline{background:var(--uiny-offline-fundo);color:var(--uiny-offline-texto)}.uiny__faixa--info{background:var(--uiny-aviso-fundo);color:var(--uiny-texto)}.uiny__erro{margin:0 12px 8px;background:var(--uiny-erro-fundo);color:var(--uiny-erro);align-items:center}.uiny__erro .uiny__erro-texto{display:flex;flex-direction:column;gap:2px}.uiny__erro .uiny__erro-texto small{opacity:.8;font-size:11px}.uiny__faixa-fechar{flex:0 0 auto;display:inline-flex;padding:2px;border:0;border-radius:6px;background:transparent;color:inherit;cursor:pointer;opacity:.7}.uiny__faixa-fechar:hover{opacity:1}.uiny__link{flex:0 0 auto;padding:0;border:0;background:none;color:var(--uiny-primaria);font-size:13px;font-weight:600;cursor:pointer;white-space:nowrap}.uiny__link:hover{text-decoration:underline}.uiny__mensagens{flex:1 1 auto;min-height:0}.uiny__historico{flex:1 1 auto;min-height:0;overflow-y:auto;padding:14px 12px}.uiny__historico-topo{display:flex;align-items:center;justify-content:space-between;margin-bottom:10px;padding:0 4px}.uiny__historico-titulo{margin:0;font-size:13px;font-weight:700;color:var(--uiny-texto)}.uiny__lista-conversas{margin:0;padding:0;list-style:none}.uiny__conversa{display:flex;flex-direction:column;gap:2px;width:100%;padding:10px 12px;border:1px solid transparent;border-radius:10px;background:transparent;color:var(--uiny-texto);text-align:left;cursor:pointer}.uiny__conversa:hover:not(:disabled){background:var(--uiny-fundo-suave)}.uiny__conversa.is-atual{border-color:var(--uiny-borda);background:var(--uiny-fundo-suave)}.uiny__conversa:disabled{opacity:.5;cursor:not-allowed}.uiny__conversa-titulo{overflow:hidden;font-weight:600;text-overflow:ellipsis;white-space:nowrap}.uiny__conversa-data{font-size:12px;color:var(--uiny-texto-suave)}.uiny__vazio{display:flex;align-items:center;gap:8px;margin:18px 4px;color:var(--uiny-texto-suave);font-size:13px}.uiny__spinner{width:14px;height:14px;border:2px solid var(--uiny-borda);border-top-color:var(--uiny-primaria);border-radius:50%;animation:uiny-girar .8s linear infinite}.uiny__composer{flex:0 0 auto}.uiny-sr{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}@keyframes uiny-girar{to{transform:rotate(360deg)}}@media (prefers-reduced-motion: reduce){.uiny__spinner{animation-duration:2.4s}}\n"] }]
|
|
1851
|
-
}], ctorParameters: function () {
|
|
1852
|
-
return [{ type: UinyChatService }, { type: UiAssistantService }, { type: UinySessionService }, { type: i0.ChangeDetectorRef }, { type: undefined, decorators: [{
|
|
1853
|
-
type: Optional
|
|
1854
|
-
}, {
|
|
1855
|
-
type: Inject,
|
|
1856
|
-
args: [UINY_CONFIG]
|
|
1857
|
-
}] }];
|
|
1858
|
-
}, propDecorators: { empilhado: [{
|
|
1859
|
-
type: Input
|
|
1860
|
-
}], composer: [{
|
|
1861
|
-
type: ViewChild,
|
|
1862
|
-
args: [UiAssistantComposerComponent]
|
|
1863
|
-
}], aoEscape: [{
|
|
1864
|
-
type: HostListener,
|
|
1865
|
-
args: ['keydown.escape', ['$event']]
|
|
1866
|
-
}] } });
|
|
1867
|
-
|
|
1868
|
-
const DURACAO_TRANSICAO_MS = 240;
|
|
1869
|
-
/**
|
|
1870
|
-
* Contêiner que hospeda a Uiny ao lado da aplicação.
|
|
1871
|
-
*
|
|
1872
|
-
* Envolve TODO o layout da aplicação (inclusive o header e a sidebar fixos):
|
|
1873
|
-
*
|
|
1874
|
-
* <ui-assistant-layout (assistantEvent)="...">
|
|
1875
|
-
* <div class="page-wrapper">...</div>
|
|
1876
|
-
* </ui-assistant-layout>
|
|
1877
|
-
*
|
|
1878
|
-
* Fechado, não altera nada: a página rola normalmente pela janela.
|
|
1879
|
-
* Aberto no desktop, vira uma linha flex [aplicação | painel]: a coluna da aplicação passa
|
|
1880
|
-
* a ser o bloco de contenção dos elementos position:fixed (contain: layout) e ganha rolagem
|
|
1881
|
-
* própria. Assim o header e a sidebar fixos ocupam a coluna da esquerda, sem serem cobertos.
|
|
1882
|
-
* Em telas estreitas o painel ocupa a largura toda e a aplicação fica recolhida até voltar.
|
|
1883
|
-
*/
|
|
1884
|
-
class UiAssistantLayoutComponent {
|
|
1885
|
-
constructor(assistant, cdr, zone, config, router) {
|
|
1886
|
-
this.assistant = assistant;
|
|
1887
|
-
this.cdr = cdr;
|
|
1888
|
-
this.zone = zone;
|
|
1889
|
-
this.router = router;
|
|
1890
|
-
/** Ações concluídas e instruções de interface (tema atualizado, atualizar listagem, abrir prévia). */
|
|
1891
|
-
this.assistantEvent = new EventEmitter();
|
|
1892
|
-
/** Painel montado e layout em modo contido (inclui a animação de fechamento). */
|
|
1893
|
-
this.contido = false;
|
|
1894
|
-
/** Painel com a largura final (classe que dispara a transição). */
|
|
1895
|
-
this.expandido = false;
|
|
1896
|
-
/** Tela estreita: painel em largura total, aplicação recolhida. */
|
|
1897
|
-
this.empilhado = false;
|
|
1898
|
-
this.disponivel = false;
|
|
1899
|
-
this.subs = new Subscription();
|
|
1900
|
-
this.midia = null;
|
|
1901
|
-
this.scrollJanela = 0;
|
|
1902
|
-
this.largura = larguraPainel(config);
|
|
1903
|
-
const ladoALado = (config === null || config === void 0 ? void 0 : config.larguraMinimaLadoALado) || UINY_LADO_A_LADO_PADRAO;
|
|
1904
|
-
if (typeof window !== 'undefined' && window.matchMedia) {
|
|
1905
|
-
this.midia = window.matchMedia(`(max-width: ${ladoALado - 0.02}px)`);
|
|
1906
|
-
this.empilhado = this.midia.matches;
|
|
1907
|
-
}
|
|
1908
|
-
}
|
|
1909
|
-
ngOnInit() {
|
|
1910
|
-
this.removerHost = this.assistant.registrarHost();
|
|
1911
|
-
this.subs.add(this.assistant.disponivel$.subscribe(d => {
|
|
1912
|
-
this.disponivel = d;
|
|
1913
|
-
this.cdr.markForCheck();
|
|
1914
|
-
}));
|
|
1915
|
-
this.subs.add(this.assistant.aberto$.subscribe(aberto => aberto ? this.abrir() : this.fechar()));
|
|
1916
|
-
this.subs.add(this.assistant.eventos$.subscribe(e => this.assistantEvent.emit(e)));
|
|
1917
|
-
// Com o layout contido a janela não rola: replica o scroll ao topo da navegação.
|
|
1918
|
-
if (this.router) {
|
|
1919
|
-
this.subs.add(this.router.events.pipe(filter(e => e instanceof NavigationEnd)).subscribe(() => {
|
|
1920
|
-
if (this.contido && this.rolagem)
|
|
1921
|
-
this.rolagem.nativeElement.scrollTop = 0;
|
|
1922
|
-
}));
|
|
1923
|
-
}
|
|
1924
|
-
if (this.midia) {
|
|
1925
|
-
const aoMudar = (e) => this.zone.run(() => {
|
|
1926
|
-
this.empilhado = e.matches;
|
|
1927
|
-
this.cdr.markForCheck();
|
|
1928
|
-
});
|
|
1929
|
-
this.midia.addEventListener ? this.midia.addEventListener('change', aoMudar) : this.midia.addListener(aoMudar);
|
|
1930
|
-
this.subs.add(() => this.midia.removeEventListener
|
|
1931
|
-
? this.midia.removeEventListener('change', aoMudar)
|
|
1932
|
-
: this.midia.removeListener(aoMudar));
|
|
1933
|
-
}
|
|
1934
|
-
}
|
|
1935
|
-
ngOnDestroy() {
|
|
1936
|
-
var _a;
|
|
1937
|
-
clearTimeout(this.timerFechamento);
|
|
1938
|
-
this.subs.unsubscribe();
|
|
1939
|
-
(_a = this.removerHost) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
1940
|
-
if (this.contido)
|
|
1941
|
-
this.restaurarJanela();
|
|
1942
|
-
}
|
|
1943
|
-
abrir() {
|
|
1944
|
-
clearTimeout(this.timerFechamento);
|
|
1945
|
-
if (!this.contido) {
|
|
1946
|
-
this.scrollJanela = window.scrollY || 0;
|
|
1947
|
-
this.contido = true;
|
|
1948
|
-
this.cdr.detectChanges();
|
|
1949
|
-
// a rolagem passa da janela para a coluna da aplicação, na mesma posição
|
|
1950
|
-
this.rolagem.nativeElement.scrollTop = this.scrollJanela;
|
|
1951
|
-
}
|
|
1952
|
-
// próximo frame: a largura sai de 0 e a transição acontece
|
|
1953
|
-
requestAnimationFrame(() => {
|
|
1954
|
-
this.expandido = true;
|
|
1955
|
-
this.cdr.detectChanges();
|
|
1956
|
-
});
|
|
1957
|
-
}
|
|
1958
|
-
fechar() {
|
|
1959
|
-
if (!this.contido)
|
|
1960
|
-
return;
|
|
1961
|
-
this.expandido = false;
|
|
1962
|
-
this.cdr.detectChanges();
|
|
1963
|
-
clearTimeout(this.timerFechamento);
|
|
1964
|
-
this.timerFechamento = setTimeout(() => {
|
|
1965
|
-
this.restaurarJanela();
|
|
1966
|
-
this.cdr.detectChanges();
|
|
1967
|
-
}, this.semAnimacao() ? 0 : DURACAO_TRANSICAO_MS);
|
|
1968
|
-
}
|
|
1969
|
-
restaurarJanela() {
|
|
1970
|
-
var _a, _b;
|
|
1971
|
-
const topo = this.empilhado ? this.scrollJanela : ((_b = (_a = this.rolagem) === null || _a === void 0 ? void 0 : _a.nativeElement.scrollTop) !== null && _b !== void 0 ? _b : 0);
|
|
1972
|
-
this.contido = false;
|
|
1973
|
-
this.cdr.detectChanges();
|
|
1974
|
-
window.scrollTo(0, topo);
|
|
1975
|
-
}
|
|
1976
|
-
semAnimacao() {
|
|
1977
|
-
return typeof window !== 'undefined' && !!window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
1978
|
-
}
|
|
1979
|
-
}
|
|
1980
|
-
UiAssistantLayoutComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: UiAssistantLayoutComponent, deps: [{ token: UiAssistantService }, { token: i0.ChangeDetectorRef }, { token: i0.NgZone }, { token: UINY_CONFIG, optional: true }, { token: i2$1.Router, optional: true }], target: i0.ɵɵFactoryTarget.Component });
|
|
1981
|
-
UiAssistantLayoutComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: UiAssistantLayoutComponent, selector: "ui-assistant-layout", outputs: { assistantEvent: "assistantEvent" }, viewQueries: [{ propertyName: "rolagem", first: true, predicate: ["rolagem"], descendants: true, static: true }], ngImport: i0, template: "<div class=\"uiny-layout\"\n [class.uiny-layout--contido]=\"contido\"\n [class.uiny-layout--expandido]=\"expandido\"\n [class.uiny-layout--empilhado]=\"empilhado\"\n [style.--uiny-largura]=\"largura + 'px'\">\n\n <div class=\"uiny-layout__app\"\n [attr.inert]=\"contido && expandido && empilhado ? '' : null\"\n [attr.aria-hidden]=\"contido && expandido && empilhado ? 'true' : null\">\n <div #rolagem class=\"uiny-layout__rolagem\">\n <ng-content></ng-content>\n </div>\n </div>\n\n <aside *ngIf=\"disponivel && contido\" id=\"uiny-painel\" class=\"uiny-layout__painel\"\n aria-label=\"Uiny, assistente da Uishop\"\n [attr.aria-hidden]=\"expandido ? null : 'true'\"\n [attr.inert]=\"expandido ? null : ''\">\n <div class=\"uiny-layout__painel-conteudo\">\n <ui-assistant-panel [empilhado]=\"empilhado\"></ui-assistant-panel>\n </div>\n </aside>\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:block}.uiny-layout,.uiny-layout__app,.uiny-layout__rolagem{display:block}.uiny-layout--contido{display:flex;width:100%;height:100vh;height:100dvh;overflow:hidden}.uiny-layout--contido .uiny-layout__app{flex:1 1 0;min-width:0;height:100%;position:relative;contain:layout paint;overflow:hidden}.uiny-layout--contido .uiny-layout__rolagem{height:100%;overflow-x:hidden;overflow-y:auto;overscroll-behavior:contain}.uiny-layout__painel{flex:0 0 auto;width:0;height:100%;overflow:hidden;position:relative;z-index:2;transition:width .24s cubic-bezier(.2,.8,.2,1)}.uiny-layout__painel-conteudo{width:var(--uiny-largura, 380px);height:100%}.uiny-layout--expandido .uiny-layout__painel{width:var(--uiny-largura, 380px)}.uiny-layout--empilhado .uiny-layout__painel,.uiny-layout--empilhado .uiny-layout__painel-conteudo{width:100%}.uiny-layout--empilhado .uiny-layout__painel{transition:opacity .18s ease;opacity:0}.uiny-layout--empilhado.uiny-layout--expandido .uiny-layout__painel{width:100%;opacity:1}.uiny-layout--empilhado.uiny-layout--expandido .uiny-layout__app{display:none}@media (prefers-reduced-motion: reduce){.uiny-layout__painel,.uiny-layout--empilhado .uiny-layout__painel{transition:none}}@media print{.uiny-layout__painel{display:none}}\n"], dependencies: [{ kind: "directive", type: i1$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: UiAssistantPanelComponent, selector: "ui-assistant-panel", inputs: ["empilhado"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1982
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: UiAssistantLayoutComponent, decorators: [{
|
|
1983
|
-
type: Component,
|
|
1984
|
-
args: [{ selector: 'ui-assistant-layout', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"uiny-layout\"\n [class.uiny-layout--contido]=\"contido\"\n [class.uiny-layout--expandido]=\"expandido\"\n [class.uiny-layout--empilhado]=\"empilhado\"\n [style.--uiny-largura]=\"largura + 'px'\">\n\n <div class=\"uiny-layout__app\"\n [attr.inert]=\"contido && expandido && empilhado ? '' : null\"\n [attr.aria-hidden]=\"contido && expandido && empilhado ? 'true' : null\">\n <div #rolagem class=\"uiny-layout__rolagem\">\n <ng-content></ng-content>\n </div>\n </div>\n\n <aside *ngIf=\"disponivel && contido\" id=\"uiny-painel\" class=\"uiny-layout__painel\"\n aria-label=\"Uiny, assistente da Uishop\"\n [attr.aria-hidden]=\"expandido ? null : 'true'\"\n [attr.inert]=\"expandido ? null : ''\">\n <div class=\"uiny-layout__painel-conteudo\">\n <ui-assistant-panel [empilhado]=\"empilhado\"></ui-assistant-panel>\n </div>\n </aside>\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:block}.uiny-layout,.uiny-layout__app,.uiny-layout__rolagem{display:block}.uiny-layout--contido{display:flex;width:100%;height:100vh;height:100dvh;overflow:hidden}.uiny-layout--contido .uiny-layout__app{flex:1 1 0;min-width:0;height:100%;position:relative;contain:layout paint;overflow:hidden}.uiny-layout--contido .uiny-layout__rolagem{height:100%;overflow-x:hidden;overflow-y:auto;overscroll-behavior:contain}.uiny-layout__painel{flex:0 0 auto;width:0;height:100%;overflow:hidden;position:relative;z-index:2;transition:width .24s cubic-bezier(.2,.8,.2,1)}.uiny-layout__painel-conteudo{width:var(--uiny-largura, 380px);height:100%}.uiny-layout--expandido .uiny-layout__painel{width:var(--uiny-largura, 380px)}.uiny-layout--empilhado .uiny-layout__painel,.uiny-layout--empilhado .uiny-layout__painel-conteudo{width:100%}.uiny-layout--empilhado .uiny-layout__painel{transition:opacity .18s ease;opacity:0}.uiny-layout--empilhado.uiny-layout--expandido .uiny-layout__painel{width:100%;opacity:1}.uiny-layout--empilhado.uiny-layout--expandido .uiny-layout__app{display:none}@media (prefers-reduced-motion: reduce){.uiny-layout__painel,.uiny-layout--empilhado .uiny-layout__painel{transition:none}}@media print{.uiny-layout__painel{display:none}}\n"] }]
|
|
1985
|
-
}], ctorParameters: function () {
|
|
1986
|
-
return [{ type: UiAssistantService }, { type: i0.ChangeDetectorRef }, { type: i0.NgZone }, { type: undefined, decorators: [{
|
|
1987
|
-
type: Optional
|
|
1988
|
-
}, {
|
|
1989
|
-
type: Inject,
|
|
1990
|
-
args: [UINY_CONFIG]
|
|
1991
|
-
}] }, { type: i2$1.Router, decorators: [{
|
|
1992
|
-
type: Optional
|
|
1993
|
-
}] }];
|
|
1994
|
-
}, propDecorators: { assistantEvent: [{
|
|
1995
|
-
type: Output
|
|
1996
|
-
}], rolagem: [{
|
|
1997
|
-
type: ViewChild,
|
|
1998
|
-
args: ['rolagem', { static: true }]
|
|
1999
|
-
}] } });
|
|
2000
|
-
|
|
2001
|
-
const COMPONENTES = [
|
|
2002
|
-
UiAssistantButtonComponent,
|
|
2003
|
-
UiAssistantLayoutComponent,
|
|
2004
|
-
UiAssistantPanelComponent,
|
|
2005
|
-
UiAssistantMessagesComponent,
|
|
2006
|
-
UiAssistantTextComponent,
|
|
2007
|
-
UiAssistantComposerComponent,
|
|
2008
|
-
UiAssistantActionCardComponent,
|
|
2009
|
-
];
|
|
2010
|
-
class UiAssistantModule {
|
|
2011
|
-
/** Importe uma vez no AppModule do consumidor. */
|
|
2012
|
-
static forRoot(config) {
|
|
2013
|
-
return {
|
|
2014
|
-
ngModule: UiAssistantModule,
|
|
2015
|
-
providers: [{ provide: UINY_CONFIG, useValue: config }]
|
|
2016
|
-
};
|
|
2017
|
-
}
|
|
2018
|
-
}
|
|
2019
|
-
UiAssistantModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: UiAssistantModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
2020
|
-
UiAssistantModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.10", ngImport: i0, type: UiAssistantModule, declarations: [UiAssistantButtonComponent,
|
|
2021
|
-
UiAssistantLayoutComponent,
|
|
2022
|
-
UiAssistantPanelComponent,
|
|
2023
|
-
UiAssistantMessagesComponent,
|
|
2024
|
-
UiAssistantTextComponent,
|
|
2025
|
-
UiAssistantComposerComponent,
|
|
2026
|
-
UiAssistantActionCardComponent], imports: [CommonModule,
|
|
2027
|
-
UiIconModule], exports: [UiAssistantButtonComponent,
|
|
2028
|
-
UiAssistantLayoutComponent,
|
|
2029
|
-
UiAssistantPanelComponent,
|
|
2030
|
-
UiAssistantMessagesComponent,
|
|
2031
|
-
UiAssistantTextComponent,
|
|
2032
|
-
UiAssistantComposerComponent,
|
|
2033
|
-
UiAssistantActionCardComponent] });
|
|
2034
|
-
UiAssistantModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: UiAssistantModule, imports: [CommonModule,
|
|
2035
|
-
UiIconModule] });
|
|
2036
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: UiAssistantModule, decorators: [{
|
|
2037
|
-
type: NgModule,
|
|
2038
|
-
args: [{
|
|
2039
|
-
declarations: COMPONENTES,
|
|
2040
|
-
imports: [
|
|
2041
|
-
CommonModule,
|
|
2042
|
-
UiIconModule
|
|
2043
|
-
],
|
|
2044
|
-
exports: COMPONENTES
|
|
2045
|
-
}]
|
|
2046
|
-
}] });
|
|
2047
|
-
|
|
2048
269
|
class UiHeaderModule {
|
|
2049
270
|
}
|
|
2050
271
|
UiHeaderModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: UiHeaderModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
@@ -2053,15 +274,12 @@ UiHeaderModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version:
|
|
|
2053
274
|
ReactiveFormsModule,
|
|
2054
275
|
UiIconModule,
|
|
2055
276
|
UiUserTopModule,
|
|
2056
|
-
TooltipModule,
|
|
2057
|
-
UiAssistantModule], exports: [UiHeaderComponent,
|
|
2058
|
-
UiAssistantModule] });
|
|
277
|
+
TooltipModule], exports: [UiHeaderComponent] });
|
|
2059
278
|
UiHeaderModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: UiHeaderModule, imports: [CommonModule,
|
|
2060
279
|
ReactiveFormsModule,
|
|
2061
280
|
UiIconModule,
|
|
2062
281
|
UiUserTopModule,
|
|
2063
|
-
TooltipModule
|
|
2064
|
-
UiAssistantModule, UiAssistantModule] });
|
|
282
|
+
TooltipModule] });
|
|
2065
283
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: UiHeaderModule, decorators: [{
|
|
2066
284
|
type: NgModule,
|
|
2067
285
|
args: [{
|
|
@@ -2074,12 +292,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
|
|
|
2074
292
|
ReactiveFormsModule,
|
|
2075
293
|
UiIconModule,
|
|
2076
294
|
UiUserTopModule,
|
|
2077
|
-
TooltipModule
|
|
2078
|
-
UiAssistantModule
|
|
295
|
+
TooltipModule
|
|
2079
296
|
],
|
|
2080
297
|
exports: [
|
|
2081
298
|
UiHeaderComponent,
|
|
2082
|
-
UiAssistantModule,
|
|
2083
299
|
]
|
|
2084
300
|
}]
|
|
2085
301
|
}] });
|
|
@@ -2092,5 +308,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
|
|
|
2092
308
|
* Generated bundle index. Do not edit.
|
|
2093
309
|
*/
|
|
2094
310
|
|
|
2095
|
-
export {
|
|
311
|
+
export { UiHeaderComponent, UiHeaderModule, UiHeaderService };
|
|
2096
312
|
//# sourceMappingURL=uitec-ng-header.mjs.map
|