@cnc-ti/layout-basic 8.4.0 → 8.5.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/dist/index.mjs CHANGED
@@ -135,6 +135,28 @@ var createLucideIcon = (iconName, iconNode) => {
135
135
  return Component;
136
136
  };
137
137
 
138
+ // ../../node_modules/lucide-react/dist/esm/icons/bell-off.js
139
+ var BellOff = createLucideIcon("BellOff", [
140
+ ["path", { d: "M8.7 3A6 6 0 0 1 18 8a21.3 21.3 0 0 0 .6 5", key: "o7mx20" }],
141
+ ["path", { d: "M17 17H3s3-2 3-9a4.67 4.67 0 0 1 .3-1.7", key: "16f1lm" }],
142
+ ["path", { d: "M10.3 21a1.94 1.94 0 0 0 3.4 0", key: "qgo35s" }],
143
+ ["path", { d: "m2 2 20 20", key: "1ooewy" }]
144
+ ]);
145
+
146
+ // ../../node_modules/lucide-react/dist/esm/icons/bell-ring.js
147
+ var BellRing = createLucideIcon("BellRing", [
148
+ ["path", { d: "M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9", key: "1qo2s2" }],
149
+ ["path", { d: "M10.3 21a1.94 1.94 0 0 0 3.4 0", key: "qgo35s" }],
150
+ ["path", { d: "M4 2C2.8 3.7 2 5.7 2 8", key: "tap9e0" }],
151
+ ["path", { d: "M22 8c0-2.3-.8-4.3-2-6", key: "5bb3ad" }]
152
+ ]);
153
+
154
+ // ../../node_modules/lucide-react/dist/esm/icons/bell.js
155
+ var Bell = createLucideIcon("Bell", [
156
+ ["path", { d: "M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9", key: "1qo2s2" }],
157
+ ["path", { d: "M10.3 21a1.94 1.94 0 0 0 3.4 0", key: "qgo35s" }]
158
+ ]);
159
+
138
160
  // ../../node_modules/lucide-react/dist/esm/icons/check.js
139
161
  var Check = createLucideIcon("Check", [["path", { d: "M20 6 9 17l-5-5", key: "1gmf2c" }]]);
140
162
 
@@ -192,12 +214,39 @@ var LoaderCircle = createLucideIcon("LoaderCircle", [
192
214
  ["path", { d: "M21 12a9 9 0 1 1-6.219-8.56", key: "13zald" }]
193
215
  ]);
194
216
 
217
+ // ../../node_modules/lucide-react/dist/esm/icons/mail-open.js
218
+ var MailOpen = createLucideIcon("MailOpen", [
219
+ [
220
+ "path",
221
+ {
222
+ d: "M21.2 8.4c.5.38.8.97.8 1.6v10a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V10a2 2 0 0 1 .8-1.6l8-6a2 2 0 0 1 2.4 0l8 6Z",
223
+ key: "1jhwl8"
224
+ }
225
+ ],
226
+ ["path", { d: "m22 10-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 10", key: "1qfld7" }]
227
+ ]);
228
+
229
+ // ../../node_modules/lucide-react/dist/esm/icons/mail.js
230
+ var Mail = createLucideIcon("Mail", [
231
+ ["rect", { width: "20", height: "16", x: "2", y: "4", rx: "2", key: "18n3k1" }],
232
+ ["path", { d: "m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7", key: "1ocrg3" }]
233
+ ]);
234
+
195
235
  // ../../node_modules/lucide-react/dist/esm/icons/search.js
196
236
  var Search = createLucideIcon("Search", [
197
237
  ["circle", { cx: "11", cy: "11", r: "8", key: "4ej97u" }],
198
238
  ["path", { d: "m21 21-4.3-4.3", key: "1qie3q" }]
199
239
  ]);
200
240
 
241
+ // ../../node_modules/lucide-react/dist/esm/icons/trash-2.js
242
+ var Trash2 = createLucideIcon("Trash2", [
243
+ ["path", { d: "M3 6h18", key: "d0wm0j" }],
244
+ ["path", { d: "M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6", key: "4alrt4" }],
245
+ ["path", { d: "M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2", key: "v07s0e" }],
246
+ ["line", { x1: "10", x2: "10", y1: "11", y2: "17", key: "1uufr5" }],
247
+ ["line", { x1: "14", x2: "14", y1: "11", y2: "17", key: "xtxkd" }]
248
+ ]);
249
+
201
250
  // ../../node_modules/lucide-react/dist/esm/icons/x.js
202
251
  var X = createLucideIcon("X", [
203
252
  ["path", { d: "M18 6 6 18", key: "1bl5f8" }],
@@ -2927,6 +2976,7 @@ var HeaderContainer = ({
2927
2976
  container = false,
2928
2977
  logo,
2929
2978
  logoLink,
2979
+ notifications,
2930
2980
  children,
2931
2981
  ...props
2932
2982
  }) => {
@@ -2976,7 +3026,10 @@ var HeaderContainer = ({
2976
3026
  )
2977
3027
  }
2978
3028
  ) : !hasSidebar && renderLogo() }),
2979
- /* @__PURE__ */ jsx3("div", { className: "cnc-flex", children })
3029
+ /* @__PURE__ */ jsxs3("div", { className: "cnc-flex", children: [
3030
+ notifications && /* @__PURE__ */ jsx3("div", { className: "cnc-flex cnc-items-center cnc-pr-3", children: notifications }),
3031
+ children
3032
+ ] })
2980
3033
  ]
2981
3034
  }
2982
3035
  );
@@ -4621,6 +4674,725 @@ function CardList({
4621
4674
  }
4622
4675
  );
4623
4676
  }
4677
+
4678
+ // src/components/organisms/header-notifications/index.tsx
4679
+ import * as React18 from "react";
4680
+
4681
+ // src/components/organisms/header-notifications/cliente.ts
4682
+ var URL_PADRAO_NOTIFICACOES = "https://dev-apinotificacoes-b5feekb4bdfyb7c2.eastus2-01.azurewebsites.net/v1";
4683
+ var ErroNotificacoes = class _ErroNotificacoes extends Error {
4684
+ status;
4685
+ constructor(mensagem, status) {
4686
+ super(mensagem);
4687
+ this.name = "ErroNotificacoes";
4688
+ this.status = status;
4689
+ Object.setPrototypeOf(this, _ErroNotificacoes.prototype);
4690
+ }
4691
+ };
4692
+ function normalizarBaseUrl(baseUrl) {
4693
+ return baseUrl.replace(/\/+$/, "");
4694
+ }
4695
+ function extrairLista(payload) {
4696
+ if (Array.isArray(payload)) return payload;
4697
+ if (payload && typeof payload === "object") {
4698
+ const registro = payload;
4699
+ const chaves = ["dados", "data", "notificacoes", "items", "content"];
4700
+ for (const chave of chaves) {
4701
+ if (Array.isArray(registro[chave])) return registro[chave];
4702
+ }
4703
+ }
4704
+ return [];
4705
+ }
4706
+ async function buscarNotificacoes({
4707
+ baseUrl,
4708
+ email,
4709
+ sistema,
4710
+ filtros,
4711
+ signal
4712
+ }) {
4713
+ const parametros = new URLSearchParams({ email, sistema });
4714
+ for (const [chave, valor] of Object.entries(filtros ?? {})) {
4715
+ if (valor !== void 0 && valor !== null) parametros.set(chave, String(valor));
4716
+ }
4717
+ const resposta = await fetch(
4718
+ `${normalizarBaseUrl(baseUrl)}/notificacoes?${parametros.toString()}`,
4719
+ { method: "GET", headers: { Accept: "application/json" }, signal }
4720
+ );
4721
+ if (!resposta.ok) {
4722
+ throw new ErroNotificacoes(
4723
+ `Falha ao buscar notifica\xE7\xF5es de ${sistema}`,
4724
+ resposta.status
4725
+ );
4726
+ }
4727
+ return extrairLista(await resposta.json());
4728
+ }
4729
+ async function definirStatusLeitura({ baseUrl, id, signal }, statusLeitura) {
4730
+ const resposta = await fetch(
4731
+ `${normalizarBaseUrl(baseUrl)}/notificacoes/${encodeURIComponent(String(id))}`,
4732
+ {
4733
+ method: "PUT",
4734
+ headers: { "Content-Type": "application/json" },
4735
+ body: JSON.stringify({ statusLeitura }),
4736
+ signal
4737
+ }
4738
+ );
4739
+ if (!resposta.ok) {
4740
+ throw new ErroNotificacoes(
4741
+ `Falha ao definir a notifica\xE7\xE3o ${id} como ${statusLeitura}`,
4742
+ resposta.status
4743
+ );
4744
+ }
4745
+ }
4746
+ function marcarComoLida(parametros) {
4747
+ return definirStatusLeitura(parametros, "LIDO");
4748
+ }
4749
+ function marcarComoNaoLida(parametros) {
4750
+ return definirStatusLeitura(parametros, "NAO_LIDO");
4751
+ }
4752
+ async function excluirNotificacao({
4753
+ baseUrl,
4754
+ id,
4755
+ signal
4756
+ }) {
4757
+ const resposta = await fetch(
4758
+ `${normalizarBaseUrl(baseUrl)}/notificacoes/${encodeURIComponent(String(id))}`,
4759
+ { method: "DELETE", signal }
4760
+ );
4761
+ if (!resposta.ok) {
4762
+ throw new ErroNotificacoes(
4763
+ `Falha ao excluir a notifica\xE7\xE3o ${id}`,
4764
+ resposta.status
4765
+ );
4766
+ }
4767
+ }
4768
+ function normalizarId(id) {
4769
+ if (typeof id === "number") return id;
4770
+ return /^\d+$/.test(id) ? Number(id) : id;
4771
+ }
4772
+ async function marcarVariasComoLidas({
4773
+ baseUrl,
4774
+ ids,
4775
+ signal
4776
+ }) {
4777
+ if (ids.length === 0) return;
4778
+ const resposta = await fetch(`${normalizarBaseUrl(baseUrl)}/notificacoes/lote`, {
4779
+ method: "PUT",
4780
+ headers: { "Content-Type": "application/json" },
4781
+ body: JSON.stringify({
4782
+ notificacoes: ids.map((id) => ({
4783
+ id: normalizarId(id),
4784
+ statusLeitura: "LIDO"
4785
+ }))
4786
+ }),
4787
+ signal
4788
+ });
4789
+ if (!resposta.ok) {
4790
+ throw new ErroNotificacoes(
4791
+ `Falha ao marcar ${ids.length} notifica\xE7\xF5es como lidas`,
4792
+ resposta.status
4793
+ );
4794
+ }
4795
+ }
4796
+
4797
+ // src/components/organisms/header-notifications/mapear.ts
4798
+ var UM_MINUTO = 6e4;
4799
+ var UMA_HORA = 60 * UM_MINUTO;
4800
+ var UM_DIA = 24 * UMA_HORA;
4801
+ var SETE_DIAS = 7 * UM_DIA;
4802
+ function formatarDataRelativa(valor, agora = Date.now()) {
4803
+ if (!valor) return void 0;
4804
+ const data = new Date(valor);
4805
+ const instante = data.getTime();
4806
+ if (Number.isNaN(instante)) return void 0;
4807
+ const diferenca = agora - instante;
4808
+ const modulo = Math.abs(diferenca);
4809
+ if (diferenca >= SETE_DIAS) {
4810
+ return new Intl.DateTimeFormat("pt-BR", {
4811
+ day: "2-digit",
4812
+ month: "2-digit",
4813
+ year: "2-digit"
4814
+ }).format(data);
4815
+ }
4816
+ if (modulo < UM_MINUTO) return "agora";
4817
+ const formatador = new Intl.RelativeTimeFormat("pt-BR", { numeric: "auto" });
4818
+ const sinal = diferenca < 0 ? 1 : -1;
4819
+ if (modulo < UMA_HORA) {
4820
+ return formatador.format(sinal * Math.trunc(modulo / UM_MINUTO), "minute");
4821
+ }
4822
+ if (modulo < UM_DIA) {
4823
+ return formatador.format(sinal * Math.trunc(modulo / UMA_HORA), "hour");
4824
+ }
4825
+ return formatador.format(sinal * Math.trunc(modulo / UM_DIA), "day");
4826
+ }
4827
+ function instanteDe(notificacao) {
4828
+ const bruto = notificacao.disparadoEm ?? notificacao.dataReferencia;
4829
+ const instante = bruto ? new Date(bruto).getTime() : Number.NaN;
4830
+ return Number.isNaN(instante) ? 0 : instante;
4831
+ }
4832
+ var STATUS_OCULTOS = ["CANCELADO", "FALHOU"];
4833
+ function jaAconteceu(notificacao, agora) {
4834
+ if (notificacao.disparadoEm) return true;
4835
+ const referencia = notificacao.dataReferencia ? new Date(notificacao.dataReferencia).getTime() : Number.NaN;
4836
+ return !Number.isNaN(referencia) && referencia <= agora;
4837
+ }
4838
+ function selecionarVisiveis(notificacoes, limite = Number.POSITIVE_INFINITY, agora = Date.now()) {
4839
+ return notificacoes.filter(
4840
+ (notificacao) => Boolean(notificacao) && jaAconteceu(notificacao, agora) && !STATUS_OCULTOS.includes(notificacao.status)
4841
+ ).sort((a, b) => instanteDe(b) - instanteDe(a)).slice(0, limite);
4842
+ }
4843
+ function selecionarLembretesVencidos(notificacoes, agora = Date.now()) {
4844
+ return notificacoes.filter((notificacao) => {
4845
+ if (!notificacao?.lembrarNoDia) return false;
4846
+ if (notificacao.statusLeitura === "LIDO") return false;
4847
+ if (STATUS_OCULTOS.includes(notificacao.status)) return false;
4848
+ const lembrete = notificacao.dataLembrete ? new Date(notificacao.dataLembrete).getTime() : Number.NaN;
4849
+ return !Number.isNaN(lembrete) && lembrete <= agora;
4850
+ }).sort(
4851
+ (a, b) => new Date(b.dataLembrete ?? 0).getTime() - new Date(a.dataLembrete ?? 0).getTime()
4852
+ );
4853
+ }
4854
+ function contarNaoLidas(notificacoes) {
4855
+ return notificacoes.filter(
4856
+ (notificacao) => notificacao.statusLeitura !== "LIDO"
4857
+ ).length;
4858
+ }
4859
+ function mapearParaItem(notificacao, getHref, agora) {
4860
+ return {
4861
+ id: notificacao.id,
4862
+ title: notificacao.titulo,
4863
+ message: notificacao.mensagem ?? void 0,
4864
+ date: formatarDataRelativa(
4865
+ notificacao.disparadoEm ?? notificacao.dataReferencia,
4866
+ agora
4867
+ ),
4868
+ read: notificacao.statusLeitura === "LIDO",
4869
+ href: getHref?.(notificacao)
4870
+ };
4871
+ }
4872
+
4873
+ // src/components/organisms/header-notifications/modal-lembretes.tsx
4874
+ import { jsx as jsx25, jsxs as jsxs19 } from "react/jsx-runtime";
4875
+ function ModalLembretes({
4876
+ lembretes,
4877
+ aberto,
4878
+ onDispensar,
4879
+ titulo,
4880
+ rotuloDispensar = "Entendi"
4881
+ }) {
4882
+ const visivel = aberto && lembretes.length > 0;
4883
+ const tituloExibido = titulo ?? (lembretes.length === 1 ? "Voc\xEA tem um lembrete" : "Voc\xEA tem lembretes");
4884
+ return /* @__PURE__ */ jsx25(
4885
+ Dialog,
4886
+ {
4887
+ open: visivel,
4888
+ onOpenChange: (proximoEstado) => {
4889
+ if (!proximoEstado) onDispensar();
4890
+ },
4891
+ children: /* @__PURE__ */ jsxs19(
4892
+ DialogContent,
4893
+ {
4894
+ className: "cnc-max-w-[440px] cnc-rounded-lg cnc-bg-white cnc-p-0",
4895
+ onOpenAutoFocus: (evento) => evento.preventDefault(),
4896
+ children: [
4897
+ /* @__PURE__ */ jsxs19("div", { className: "cnc-flex cnc-items-center cnc-gap-3 cnc-border-b cnc-border-brand-gray-50 cnc-px-5 cnc-py-4", children: [
4898
+ /* @__PURE__ */ jsx25("span", { className: "cnc-flex cnc-h-9 cnc-w-9 cnc-shrink-0 cnc-items-center cnc-justify-center cnc-rounded-full cnc-bg-brand-blue-60", children: /* @__PURE__ */ jsx25(
4899
+ BellRing,
4900
+ {
4901
+ className: "cnc-h-[18px] cnc-w-[18px] cnc-text-brand-blue-400",
4902
+ "aria-hidden": "true"
4903
+ }
4904
+ ) }),
4905
+ /* @__PURE__ */ jsx25(DialogTitle, { className: "cnc-m-0 cnc-text-base cnc-font-extrabold cnc-text-brand-blue-900", children: tituloExibido })
4906
+ ] }),
4907
+ /* @__PURE__ */ jsx25("ul", { className: "cnc-m-0 cnc-max-h-[320px] cnc-list-none cnc-overflow-y-auto cnc-p-0", children: lembretes.map((lembrete) => /* @__PURE__ */ jsxs19(
4908
+ "li",
4909
+ {
4910
+ className: "cnc-flex cnc-flex-col cnc-gap-1 cnc-border-b cnc-border-brand-gray-50 cnc-px-5 cnc-py-4 last:cnc-border-b-0",
4911
+ children: [
4912
+ /* @__PURE__ */ jsxs19("div", { className: "cnc-flex cnc-items-baseline cnc-justify-between cnc-gap-3", children: [
4913
+ /* @__PURE__ */ jsx25("span", { className: "cnc-text-sm cnc-font-bold cnc-text-brand-blue-900", children: lembrete.titulo }),
4914
+ /* @__PURE__ */ jsx25("span", { className: "cnc-shrink-0 cnc-text-[11px] cnc-text-brand-gray-600", children: formatarDataRelativa(lembrete.dataLembrete) })
4915
+ ] }),
4916
+ lembrete.mensagem && /* @__PURE__ */ jsx25("span", { className: "cnc-text-xs cnc-leading-relaxed cnc-text-brand-gray-600", children: lembrete.mensagem })
4917
+ ]
4918
+ },
4919
+ lembrete.id
4920
+ )) }),
4921
+ /* @__PURE__ */ jsxs19("div", { className: "cnc-flex cnc-flex-col cnc-gap-2 cnc-border-t cnc-border-brand-gray-50 cnc-px-5 cnc-py-4", children: [
4922
+ /* @__PURE__ */ jsx25(Button, { variant: "confirm", className: "cnc-w-full", onClick: onDispensar, children: rotuloDispensar }),
4923
+ /* @__PURE__ */ jsx25("p", { className: "cnc-m-0 cnc-text-center cnc-text-[11px] cnc-text-brand-gray-600", children: lembretes.length === 1 ? "Ao fechar, este lembrete \xE9 marcado como lido." : `Ao fechar, os ${lembretes.length} lembretes s\xE3o marcados como lidos.` })
4924
+ ] })
4925
+ ]
4926
+ }
4927
+ )
4928
+ }
4929
+ );
4930
+ }
4931
+
4932
+ // src/components/organisms/header-notifications/usar-notificacoes.ts
4933
+ import * as React17 from "react";
4934
+ function foiAbortado(erro) {
4935
+ return erro?.name === "AbortError";
4936
+ }
4937
+ function usarNotificacoes({
4938
+ email,
4939
+ sistema,
4940
+ baseUrl,
4941
+ filtros,
4942
+ intervaloAtualizacao = 6e4,
4943
+ habilitado = true,
4944
+ onErro
4945
+ }) {
4946
+ const [notificacoes, setNotificacoes] = React17.useState([]);
4947
+ const [carregando, setCarregando] = React17.useState(habilitado);
4948
+ const notificacoesRef = React17.useRef(notificacoes);
4949
+ const controladorRef = React17.useRef(null);
4950
+ const jaCarregouRef = React17.useRef(false);
4951
+ const onErroRef = React17.useRef(onErro);
4952
+ React17.useEffect(() => {
4953
+ notificacoesRef.current = notificacoes;
4954
+ }, [notificacoes]);
4955
+ React17.useEffect(() => {
4956
+ onErroRef.current = onErro;
4957
+ }, [onErro]);
4958
+ const chaveFiltros = JSON.stringify(filtros ?? {});
4959
+ const atualizar = React17.useCallback(() => {
4960
+ if (!habilitado) return;
4961
+ controladorRef.current?.abort();
4962
+ const controlador = new AbortController();
4963
+ controladorRef.current = controlador;
4964
+ void (async () => {
4965
+ try {
4966
+ const lista = await buscarNotificacoes({
4967
+ baseUrl,
4968
+ email,
4969
+ sistema,
4970
+ filtros: JSON.parse(chaveFiltros),
4971
+ signal: controlador.signal
4972
+ });
4973
+ if (controlador.signal.aborted) return;
4974
+ setNotificacoes(lista);
4975
+ } catch (erro) {
4976
+ if (controlador.signal.aborted || foiAbortado(erro)) return;
4977
+ onErroRef.current?.(erro);
4978
+ } finally {
4979
+ if (!controlador.signal.aborted) {
4980
+ jaCarregouRef.current = true;
4981
+ setCarregando(false);
4982
+ }
4983
+ }
4984
+ })();
4985
+ }, [baseUrl, email, sistema, chaveFiltros, habilitado]);
4986
+ React17.useEffect(() => {
4987
+ if (!habilitado) {
4988
+ setCarregando(false);
4989
+ return;
4990
+ }
4991
+ if (!jaCarregouRef.current) setCarregando(true);
4992
+ atualizar();
4993
+ return () => controladorRef.current?.abort();
4994
+ }, [atualizar, habilitado]);
4995
+ React17.useEffect(() => {
4996
+ if (!habilitado || !intervaloAtualizacao) return;
4997
+ const temporizador = window.setInterval(() => {
4998
+ if (typeof document !== "undefined" && document.hidden) return;
4999
+ atualizar();
5000
+ }, intervaloAtualizacao);
5001
+ return () => window.clearInterval(temporizador);
5002
+ }, [atualizar, habilitado, intervaloAtualizacao]);
5003
+ const aplicarLeitura = React17.useCallback((ids) => {
5004
+ const alvos = new Set(ids.map(String));
5005
+ setNotificacoes(
5006
+ (atuais) => atuais.map(
5007
+ (notificacao) => alvos.has(String(notificacao.id)) ? { ...notificacao, statusLeitura: "LIDO" } : notificacao
5008
+ )
5009
+ );
5010
+ }, []);
5011
+ const reverterLeitura = React17.useCallback((anteriores) => {
5012
+ const original = new Map(
5013
+ anteriores.map((notificacao) => [String(notificacao.id), notificacao])
5014
+ );
5015
+ setNotificacoes(
5016
+ (atuais) => atuais.map((notificacao) => {
5017
+ const anterior = original.get(String(notificacao.id));
5018
+ return anterior ? {
5019
+ ...notificacao,
5020
+ statusLeitura: anterior.statusLeitura,
5021
+ lidoEm: anterior.lidoEm
5022
+ } : notificacao;
5023
+ })
5024
+ );
5025
+ }, []);
5026
+ const marcarUmaComoLida = React17.useCallback(
5027
+ (id) => {
5028
+ const alvo = notificacoesRef.current.find(
5029
+ (notificacao) => String(notificacao.id) === String(id)
5030
+ );
5031
+ if (!alvo || alvo.statusLeitura === "LIDO") return;
5032
+ aplicarLeitura([id]);
5033
+ void marcarComoLida({ baseUrl, id }).catch((erro) => {
5034
+ reverterLeitura([alvo]);
5035
+ onErroRef.current?.(erro);
5036
+ });
5037
+ },
5038
+ [baseUrl, aplicarLeitura, reverterLeitura]
5039
+ );
5040
+ const marcarComoLidas = React17.useCallback(
5041
+ (ids) => {
5042
+ const alvos = new Set(ids.map(String));
5043
+ const naoLidas = notificacoesRef.current.filter(
5044
+ (notificacao) => alvos.has(String(notificacao.id)) && notificacao.statusLeitura !== "LIDO"
5045
+ );
5046
+ if (naoLidas.length === 0) return;
5047
+ aplicarLeitura(naoLidas.map((notificacao) => notificacao.id));
5048
+ void marcarVariasComoLidas({
5049
+ baseUrl,
5050
+ ids: naoLidas.map((notificacao) => notificacao.id)
5051
+ }).catch((erro) => {
5052
+ reverterLeitura(naoLidas);
5053
+ onErroRef.current?.(erro);
5054
+ });
5055
+ },
5056
+ [baseUrl, aplicarLeitura, reverterLeitura]
5057
+ );
5058
+ const marcarTodasComoLidas = React17.useCallback(() => {
5059
+ marcarComoLidas(notificacoesRef.current.map((notificacao) => notificacao.id));
5060
+ }, [marcarComoLidas]);
5061
+ const marcarUmaComoNaoLida = React17.useCallback(
5062
+ (id) => {
5063
+ const alvo = notificacoesRef.current.find(
5064
+ (notificacao) => String(notificacao.id) === String(id)
5065
+ );
5066
+ if (!alvo || alvo.statusLeitura === "NAO_LIDO") return;
5067
+ setNotificacoes(
5068
+ (atuais) => atuais.map(
5069
+ (notificacao) => String(notificacao.id) === String(id) ? { ...notificacao, statusLeitura: "NAO_LIDO" } : notificacao
5070
+ )
5071
+ );
5072
+ void marcarComoNaoLida({ baseUrl, id }).catch((erro) => {
5073
+ reverterLeitura([alvo]);
5074
+ onErroRef.current?.(erro);
5075
+ });
5076
+ },
5077
+ [baseUrl, reverterLeitura]
5078
+ );
5079
+ const excluir = React17.useCallback(
5080
+ (id) => {
5081
+ const alvo = notificacoesRef.current.find(
5082
+ (notificacao) => String(notificacao.id) === String(id)
5083
+ );
5084
+ if (!alvo) return;
5085
+ setNotificacoes(
5086
+ (atuais) => atuais.filter((notificacao) => String(notificacao.id) !== String(id))
5087
+ );
5088
+ void excluirNotificacao({ baseUrl, id }).catch((erro) => {
5089
+ onErroRef.current?.(erro);
5090
+ atualizar();
5091
+ });
5092
+ },
5093
+ [baseUrl, atualizar]
5094
+ );
5095
+ return {
5096
+ notificacoes,
5097
+ carregando,
5098
+ atualizar,
5099
+ marcarUmaComoLida,
5100
+ marcarUmaComoNaoLida,
5101
+ marcarComoLidas,
5102
+ marcarTodasComoLidas,
5103
+ excluir
5104
+ };
5105
+ }
5106
+
5107
+ // src/components/organisms/header-notifications/index.tsx
5108
+ import { Fragment as Fragment6, jsx as jsx26, jsxs as jsxs20 } from "react/jsx-runtime";
5109
+ function HeaderNotifications(props) {
5110
+ const {
5111
+ items = [],
5112
+ isLoading = false,
5113
+ skeletonCount = 3,
5114
+ title = "Notifica\xE7\xF5es",
5115
+ emptyMessage = "Nenhuma notifica\xE7\xE3o",
5116
+ unreadCount,
5117
+ maxCount = 9,
5118
+ onSelect,
5119
+ onMarkAsRead,
5120
+ onMarkAsUnread,
5121
+ onDelete,
5122
+ onMarkAllAsRead,
5123
+ onOpenChange,
5124
+ footer,
5125
+ align = "end",
5126
+ className,
5127
+ contentClassName,
5128
+ email,
5129
+ sistema,
5130
+ baseUrl = URL_PADRAO_NOTIFICACOES,
5131
+ getHref,
5132
+ filtros,
5133
+ intervaloAtualizacao,
5134
+ limite = 20,
5135
+ onErro,
5136
+ alertarLembretes = false,
5137
+ tituloLembretes,
5138
+ rotuloDispensarLembretes
5139
+ } = props;
5140
+ const [aberto, setAberto] = React18.useState(false);
5141
+ const [lembretesEmAlerta, setLembretesEmAlerta] = React18.useState(
5142
+ []
5143
+ );
5144
+ const avaliouLembretesRef = React18.useRef(false);
5145
+ const conectado = Boolean(email && sistema);
5146
+ const remoto = usarNotificacoes({
5147
+ email: email ?? "",
5148
+ sistema: sistema ?? "",
5149
+ baseUrl,
5150
+ filtros,
5151
+ intervaloAtualizacao,
5152
+ habilitado: conectado,
5153
+ onErro
5154
+ });
5155
+ const elegiveis = React18.useMemo(
5156
+ () => conectado ? selecionarVisiveis(remoto.notificacoes) : [],
5157
+ [conectado, remoto.notificacoes]
5158
+ );
5159
+ const itensRemotos = React18.useMemo(
5160
+ () => elegiveis.slice(0, limite).map((notificacao) => mapearParaItem(notificacao, getHref)),
5161
+ [elegiveis, limite, getHref]
5162
+ );
5163
+ const itens = conectado ? itensRemotos : items;
5164
+ const carregandoLista = conectado ? remoto.carregando : isLoading;
5165
+ React18.useEffect(() => {
5166
+ if (!conectado || !alertarLembretes) return;
5167
+ if (remoto.carregando || avaliouLembretesRef.current) return;
5168
+ avaliouLembretesRef.current = true;
5169
+ setLembretesEmAlerta(selecionarLembretesVencidos(remoto.notificacoes));
5170
+ }, [conectado, alertarLembretes, remoto.carregando, remoto.notificacoes]);
5171
+ const dispensarLembretes = () => {
5172
+ remoto.marcarComoLidas(lembretesEmAlerta.map((lembrete) => lembrete.id));
5173
+ setLembretesEmAlerta([]);
5174
+ };
5175
+ const naoLidas = conectado ? contarNaoLidas(elegiveis) : unreadCount ?? items.filter((item) => !item.read).length;
5176
+ const rotuloContagem = naoLidas > maxCount ? `${maxCount}+` : `${naoLidas}`;
5177
+ const alterarAbertura = (proximoEstado) => {
5178
+ setAberto(proximoEstado);
5179
+ if (proximoEstado && conectado) remoto.atualizar();
5180
+ onOpenChange?.(proximoEstado);
5181
+ };
5182
+ const selecionar = (item) => {
5183
+ if (!item.read) {
5184
+ if (conectado) remoto.marcarUmaComoLida(item.id);
5185
+ onMarkAsRead?.(item);
5186
+ }
5187
+ if (!onSelect) return;
5188
+ onSelect(item);
5189
+ alterarAbertura(false);
5190
+ };
5191
+ const marcarTodas = () => {
5192
+ if (conectado) remoto.marcarTodasComoLidas();
5193
+ onMarkAllAsRead?.();
5194
+ };
5195
+ const alternarLeitura = (item) => {
5196
+ if (item.read) {
5197
+ if (conectado) remoto.marcarUmaComoNaoLida(item.id);
5198
+ onMarkAsUnread?.(item);
5199
+ return;
5200
+ }
5201
+ if (conectado) remoto.marcarUmaComoLida(item.id);
5202
+ onMarkAsRead?.(item);
5203
+ };
5204
+ const excluirItem = (item) => {
5205
+ if (conectado) remoto.excluir(item.id);
5206
+ onDelete?.(item);
5207
+ };
5208
+ const podeMarcarTodas = conectado || Boolean(onMarkAllAsRead);
5209
+ const podeAlternarLeitura = conectado || Boolean(onMarkAsUnread);
5210
+ const podeExcluir = conectado || Boolean(onDelete);
5211
+ const alvoClicavel = conectado || Boolean(onSelect) || Boolean(onMarkAsRead);
5212
+ const anelDeFoco = "focus-visible:cnc-ring-2 focus-visible:cnc-ring-inset focus-visible:cnc-ring-brand-gray-500/50";
5213
+ const renderarConteudo = () => {
5214
+ if (carregandoLista) {
5215
+ return /* @__PURE__ */ jsx26("div", { "aria-busy": "true", children: Array.from({ length: skeletonCount }).map((_, indice) => /* @__PURE__ */ jsx26(
5216
+ "div",
5217
+ {
5218
+ className: "cnc-flex cnc-border-b cnc-border-l-[3px] cnc-border-brand-gray-50 cnc-border-l-transparent cnc-py-3 cnc-pl-3 cnc-pr-4 last:cnc-border-b-0",
5219
+ children: /* @__PURE__ */ jsxs20("div", { className: "cnc-flex cnc-w-full cnc-flex-col cnc-gap-2", children: [
5220
+ /* @__PURE__ */ jsx26("div", { className: "cnc-h-3 cnc-w-1/2 cnc-animate-pulse cnc-rounded cnc-bg-brand-gray-20" }),
5221
+ /* @__PURE__ */ jsx26("div", { className: "cnc-h-3 cnc-w-3/4 cnc-animate-pulse cnc-rounded cnc-bg-brand-gray-20" })
5222
+ ] })
5223
+ },
5224
+ indice
5225
+ )) });
5226
+ }
5227
+ if (itens.length === 0) {
5228
+ return /* @__PURE__ */ jsxs20("div", { className: "cnc-flex cnc-flex-col cnc-items-center cnc-justify-center cnc-px-4 cnc-py-12 cnc-text-brand-gray-200", children: [
5229
+ /* @__PURE__ */ jsx26(BellOff, { className: "cnc-mb-2 cnc-h-7 cnc-w-7", "aria-hidden": "true" }),
5230
+ /* @__PURE__ */ jsx26("p", { className: "cnc-text-sm", children: emptyMessage })
5231
+ ] });
5232
+ }
5233
+ return /* @__PURE__ */ jsx26("ul", { className: "cnc-m-0 cnc-list-none cnc-p-0", children: itens.map((item) => {
5234
+ const conteudo = /* @__PURE__ */ jsxs20("span", { className: "cnc-flex cnc-min-w-0 cnc-flex-1 cnc-flex-col cnc-gap-0.5", children: [
5235
+ /* @__PURE__ */ jsxs20("span", { className: "cnc-flex cnc-items-baseline cnc-justify-between cnc-gap-2", children: [
5236
+ /* @__PURE__ */ jsx26(
5237
+ "span",
5238
+ {
5239
+ className: cn(
5240
+ "cnc-truncate cnc-text-sm cnc-text-brand-blue-900",
5241
+ item.read ? "cnc-font-medium" : "cnc-font-bold"
5242
+ ),
5243
+ children: item.title
5244
+ }
5245
+ ),
5246
+ item.date && /* @__PURE__ */ jsx26("span", { className: "cnc-shrink-0 cnc-text-[11px] cnc-text-brand-gray-600", children: item.date })
5247
+ ] }),
5248
+ item.message && /* @__PURE__ */ jsx26("span", { className: "cnc-line-clamp-2 cnc-text-xs cnc-text-brand-gray-600", children: item.message }),
5249
+ !item.read && /* @__PURE__ */ jsx26("span", { className: "cnc-sr-only", children: "N\xE3o lida" })
5250
+ ] });
5251
+ const classesLinha = cn(
5252
+ "cnc-flex cnc-w-full cnc-items-start cnc-border-l-[3px] cnc-transition cnc-duration-200",
5253
+ item.read ? "cnc-border-l-transparent hover:cnc-bg-brand-blue-50" : "cnc-border-l-brand-blue-400 cnc-bg-brand-blue-50 hover:cnc-bg-brand-blue-60"
5254
+ );
5255
+ const classesAlvo = cn(
5256
+ "cnc-flex cnc-min-w-0 cnc-flex-1 cnc-bg-transparent cnc-py-3 cnc-pl-3 cnc-pr-2 cnc-text-left cnc-no-underline cnc-outline-none",
5257
+ alvoClicavel && "cnc-cursor-pointer",
5258
+ anelDeFoco
5259
+ );
5260
+ const classesAcao = cn(
5261
+ "cnc-flex cnc-h-7 cnc-w-7 cnc-shrink-0 cnc-cursor-pointer cnc-items-center cnc-justify-center cnc-rounded cnc-border-0 cnc-bg-transparent cnc-p-0 cnc-text-brand-gray-200 cnc-outline-none cnc-transition cnc-duration-200 hover:cnc-bg-white",
5262
+ anelDeFoco
5263
+ );
5264
+ const renderarAlvo = () => alvoClicavel ? /* @__PURE__ */ jsx26(
5265
+ "button",
5266
+ {
5267
+ type: "button",
5268
+ onClick: () => selecionar(item),
5269
+ className: classesAlvo,
5270
+ children: conteudo
5271
+ }
5272
+ ) : /* @__PURE__ */ jsx26("div", { className: classesAlvo, children: conteudo });
5273
+ const rotuloLeitura = item.read ? "Marcar como n\xE3o lida" : "Marcar como lida";
5274
+ return /* @__PURE__ */ jsx26(
5275
+ "li",
5276
+ {
5277
+ className: "cnc-border-b cnc-border-brand-gray-50 last:cnc-border-b-0",
5278
+ children: /* @__PURE__ */ jsxs20("div", { className: classesLinha, children: [
5279
+ renderarAlvo(),
5280
+ (podeAlternarLeitura || podeExcluir) && /* @__PURE__ */ jsxs20("div", { className: "cnc-flex cnc-shrink-0 cnc-items-center cnc-gap-1 cnc-py-3 cnc-pr-2", children: [
5281
+ podeAlternarLeitura && /* @__PURE__ */ jsx26(
5282
+ "button",
5283
+ {
5284
+ type: "button",
5285
+ "aria-label": rotuloLeitura,
5286
+ title: rotuloLeitura,
5287
+ onClick: () => alternarLeitura(item),
5288
+ className: cn(
5289
+ classesAcao,
5290
+ "hover:cnc-text-brand-blue-400"
5291
+ ),
5292
+ children: item.read ? /* @__PURE__ */ jsx26(Mail, { className: "cnc-h-4 cnc-w-4", "aria-hidden": "true" }) : /* @__PURE__ */ jsx26(
5293
+ MailOpen,
5294
+ {
5295
+ className: "cnc-h-4 cnc-w-4",
5296
+ "aria-hidden": "true"
5297
+ }
5298
+ )
5299
+ }
5300
+ ),
5301
+ podeExcluir && /* @__PURE__ */ jsx26(
5302
+ "button",
5303
+ {
5304
+ type: "button",
5305
+ "aria-label": "Excluir notifica\xE7\xE3o",
5306
+ title: "Excluir notifica\xE7\xE3o",
5307
+ onClick: () => excluirItem(item),
5308
+ className: cn(classesAcao, "hover:cnc-text-brand-red-600"),
5309
+ children: /* @__PURE__ */ jsx26(Trash2, { className: "cnc-h-4 cnc-w-4", "aria-hidden": "true" })
5310
+ }
5311
+ )
5312
+ ] })
5313
+ ] })
5314
+ },
5315
+ item.id
5316
+ );
5317
+ }) });
5318
+ };
5319
+ const temRodapePadrao = podeMarcarTodas && naoLidas > 0;
5320
+ return /* @__PURE__ */ jsxs20(Fragment6, { children: [
5321
+ alertarLembretes && /* @__PURE__ */ jsx26(
5322
+ ModalLembretes,
5323
+ {
5324
+ lembretes: lembretesEmAlerta,
5325
+ aberto: lembretesEmAlerta.length > 0,
5326
+ onDispensar: dispensarLembretes,
5327
+ titulo: tituloLembretes,
5328
+ rotuloDispensar: rotuloDispensarLembretes
5329
+ }
5330
+ ),
5331
+ /* @__PURE__ */ jsxs20(Popover, { open: aberto, onOpenChange: alterarAbertura, children: [
5332
+ /* @__PURE__ */ jsx26(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs20(
5333
+ "button",
5334
+ {
5335
+ type: "button",
5336
+ "aria-label": naoLidas > 0 ? `${title}, ${naoLidas} n\xE3o ${naoLidas === 1 ? "lida" : "lidas"}` : title,
5337
+ className: cn(
5338
+ "cnc-relative cnc-flex cnc-h-10 cnc-w-10 cnc-items-center cnc-justify-center cnc-rounded-full cnc-transition cnc-duration-300 cnc-ease-in-out hover:cnc-bg-brand-blue-60 data-[state=open]:cnc-bg-brand-blue-60 cnc-cursor-pointer cnc-outline-none cnc-header-item",
5339
+ anelDeFoco,
5340
+ className
5341
+ ),
5342
+ children: [
5343
+ /* @__PURE__ */ jsx26(
5344
+ Bell,
5345
+ {
5346
+ className: "cnc-h-5 cnc-w-5 cnc-text-brand-blue-900 cnc-header-item",
5347
+ "aria-hidden": "true"
5348
+ }
5349
+ ),
5350
+ naoLidas > 0 && /* @__PURE__ */ jsx26(
5351
+ "span",
5352
+ {
5353
+ "aria-hidden": "true",
5354
+ className: "cnc-absolute -cnc-right-0.5 -cnc-top-0.5 cnc-flex cnc-h-[18px] cnc-min-w-[18px] cnc-items-center cnc-justify-center cnc-rounded-full cnc-border-2 cnc-border-white cnc-bg-brand-red-500 cnc-px-1 cnc-text-[10px] cnc-font-bold cnc-leading-none cnc-text-white",
5355
+ children: rotuloContagem
5356
+ }
5357
+ )
5358
+ ]
5359
+ }
5360
+ ) }),
5361
+ /* @__PURE__ */ jsxs20(
5362
+ PopoverContent,
5363
+ {
5364
+ align,
5365
+ sideOffset: 20,
5366
+ "aria-label": title,
5367
+ style: { width: "min(380px, calc(100vw - 2rem))", padding: 0 },
5368
+ className: cn(
5369
+ "cnc-overflow-hidden cnc-rounded-lg cnc-border cnc-border-brand-gray-50 cnc-bg-white cnc-shadow-custom",
5370
+ contentClassName
5371
+ ),
5372
+ children: [
5373
+ /* @__PURE__ */ jsxs20("div", { className: "cnc-flex cnc-items-center cnc-justify-between cnc-gap-2 cnc-border-b cnc-border-brand-gray-50 cnc-px-4 cnc-py-3", children: [
5374
+ /* @__PURE__ */ jsx26("h2", { className: "cnc-m-0 cnc-text-base cnc-font-extrabold cnc-text-brand-blue-900", children: title }),
5375
+ naoLidas > 0 && /* @__PURE__ */ jsx26("span", { className: "cnc-rounded-md cnc-bg-brand-blue-60 cnc-px-2 cnc-py-1 cnc-text-xs cnc-font-semibold cnc-text-brand-blue-400", children: naoLidas === 1 ? "1 nova" : `${naoLidas} novas` })
5376
+ ] }),
5377
+ /* @__PURE__ */ jsx26("div", { className: "cnc-max-h-[360px] cnc-overflow-y-auto", children: renderarConteudo() }),
5378
+ footer ? /* @__PURE__ */ jsx26("div", { className: "cnc-border-t cnc-border-brand-gray-50 cnc-px-4 cnc-py-3", children: footer }) : temRodapePadrao && /* @__PURE__ */ jsx26("div", { className: "cnc-flex cnc-justify-end cnc-border-t cnc-border-brand-gray-50 cnc-px-4 cnc-py-3", children: /* @__PURE__ */ jsx26(
5379
+ "button",
5380
+ {
5381
+ type: "button",
5382
+ onClick: marcarTodas,
5383
+ className: cn(
5384
+ "cnc-cursor-pointer cnc-rounded cnc-bg-transparent cnc-p-0 cnc-text-xs cnc-font-semibold cnc-text-brand-blue-100 cnc-outline-none hover:cnc-underline",
5385
+ anelDeFoco
5386
+ ),
5387
+ children: "Marcar todas como lidas"
5388
+ }
5389
+ ) })
5390
+ ]
5391
+ }
5392
+ )
5393
+ ] })
5394
+ ] });
5395
+ }
4624
5396
  export {
4625
5397
  AplicationsHeader,
4626
5398
  AppsMenu,
@@ -4671,9 +5443,11 @@ export {
4671
5443
  DropdownMenuSubContent,
4672
5444
  DropdownMenuSubTrigger,
4673
5445
  DropdownMenuTrigger,
5446
+ ErroNotificacoes,
4674
5447
  Filter,
4675
5448
  Header,
4676
5449
  HeaderContainer,
5450
+ HeaderNotifications,
4677
5451
  HeaderProfileHeader,
4678
5452
  HeaderProfileItem,
4679
5453
  Input,
@@ -4710,6 +5484,7 @@ export {
4710
5484
  TabsList,
4711
5485
  TabsTrigger,
4712
5486
  Title2 as Title,
5487
+ URL_PADRAO_NOTIFICACOES,
4713
5488
  availableApps,
4714
5489
  buttonVariants
4715
5490
  };
@@ -4747,6 +5522,30 @@ lucide-react/dist/esm/createLucideIcon.js:
4747
5522
  * See the LICENSE file in the root directory of this source tree.
4748
5523
  *)
4749
5524
 
5525
+ lucide-react/dist/esm/icons/bell-off.js:
5526
+ (**
5527
+ * @license lucide-react v0.453.0 - ISC
5528
+ *
5529
+ * This source code is licensed under the ISC license.
5530
+ * See the LICENSE file in the root directory of this source tree.
5531
+ *)
5532
+
5533
+ lucide-react/dist/esm/icons/bell-ring.js:
5534
+ (**
5535
+ * @license lucide-react v0.453.0 - ISC
5536
+ *
5537
+ * This source code is licensed under the ISC license.
5538
+ * See the LICENSE file in the root directory of this source tree.
5539
+ *)
5540
+
5541
+ lucide-react/dist/esm/icons/bell.js:
5542
+ (**
5543
+ * @license lucide-react v0.453.0 - ISC
5544
+ *
5545
+ * This source code is licensed under the ISC license.
5546
+ * See the LICENSE file in the root directory of this source tree.
5547
+ *)
5548
+
4750
5549
  lucide-react/dist/esm/icons/check.js:
4751
5550
  (**
4752
5551
  * @license lucide-react v0.453.0 - ISC
@@ -4827,6 +5626,22 @@ lucide-react/dist/esm/icons/loader-circle.js:
4827
5626
  * See the LICENSE file in the root directory of this source tree.
4828
5627
  *)
4829
5628
 
5629
+ lucide-react/dist/esm/icons/mail-open.js:
5630
+ (**
5631
+ * @license lucide-react v0.453.0 - ISC
5632
+ *
5633
+ * This source code is licensed under the ISC license.
5634
+ * See the LICENSE file in the root directory of this source tree.
5635
+ *)
5636
+
5637
+ lucide-react/dist/esm/icons/mail.js:
5638
+ (**
5639
+ * @license lucide-react v0.453.0 - ISC
5640
+ *
5641
+ * This source code is licensed under the ISC license.
5642
+ * See the LICENSE file in the root directory of this source tree.
5643
+ *)
5644
+
4830
5645
  lucide-react/dist/esm/icons/search.js:
4831
5646
  (**
4832
5647
  * @license lucide-react v0.453.0 - ISC
@@ -4835,6 +5650,14 @@ lucide-react/dist/esm/icons/search.js:
4835
5650
  * See the LICENSE file in the root directory of this source tree.
4836
5651
  *)
4837
5652
 
5653
+ lucide-react/dist/esm/icons/trash-2.js:
5654
+ (**
5655
+ * @license lucide-react v0.453.0 - ISC
5656
+ *
5657
+ * This source code is licensed under the ISC license.
5658
+ * See the LICENSE file in the root directory of this source tree.
5659
+ *)
5660
+
4838
5661
  lucide-react/dist/esm/icons/x.js:
4839
5662
  (**
4840
5663
  * @license lucide-react v0.453.0 - ISC