teraprox-core-sdk 0.3.10 → 0.3.14

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
@@ -4,8 +4,11 @@ import {
4
4
  FederatedBridge,
5
5
  NullObservabilityAdapter,
6
6
  StandaloneProvider,
7
- createReducersBundle
8
- } from "./chunk-JK654W4P.mjs";
7
+ createReducersBundle,
8
+ createReducersFromManifest,
9
+ groupMenuSections,
10
+ isHostedByCore
11
+ } from "./chunk-CBKXJHPL.mjs";
9
12
 
10
13
  // src/adapters/null/NullObjectAdapters.ts
11
14
  var NullToastService = class {
@@ -75,6 +78,7 @@ var NullCoreService = {
75
78
  unsubscribeEvent: (evt) => console.log(`[CoreService Fallback] Desinscri\xE7\xE3o Evento: ${evt}`),
76
79
  handleLogout: () => console.log(`[CoreService Fallback] Realizando logout...`),
77
80
  hostedByCore: false,
81
+ rateLimits: {},
78
82
  observability: new NullObservabilityAdapter()
79
83
  };
80
84
 
@@ -169,60 +173,118 @@ var TracingHttpAdapter = class {
169
173
 
170
174
  // src/factories/CoreServiceBuilder.ts
171
175
  var FetchHttpAdapter = class {
172
- constructor(endpoint, extraHeaders) {
176
+ constructor(endpoint, extraHeaders, interceptors) {
173
177
  this.endpoint = endpoint;
174
178
  this.extraHeaders = extraHeaders;
179
+ this.interceptors = interceptors;
180
+ }
181
+ mergeHeaders(extraReqHeaders, hasJsonBody) {
182
+ return {
183
+ ...this.extraHeaders,
184
+ ...hasJsonBody ? { "Content-Type": "application/json" } : {},
185
+ ...extraReqHeaders
186
+ };
175
187
  }
176
- async request(method, extraPath, data) {
188
+ /** Join non-empty path segments, avoiding double slashes. */
189
+ joinPath(...parts) {
190
+ return parts.filter((p) => p != null && p !== "").map(String).join("/");
191
+ }
192
+ async request(method, extraPath, data, extraHeaders) {
177
193
  const url = extraPath ? `${this.endpoint}/${extraPath}` : this.endpoint;
194
+ const isFormData = typeof FormData !== "undefined" && data instanceof FormData;
195
+ const body = data !== void 0 ? isFormData ? data : JSON.stringify(data) : void 0;
196
+ const buildHeaders = async () => {
197
+ var _a;
198
+ let h = this.mergeHeaders(extraHeaders, data !== void 0 && !isFormData);
199
+ if ((_a = this.interceptors) == null ? void 0 : _a.onBeforeRequest) {
200
+ h = await this.interceptors.onBeforeRequest(h);
201
+ }
202
+ return h;
203
+ };
204
+ let interceptorRetryConsumed = false;
205
+ const doFetch = async () => {
206
+ var _a, _b;
207
+ const headers = await buildHeaders();
208
+ const res = await fetch(url, { method, headers, body });
209
+ if (!res.ok) {
210
+ const errorData = await res.json().catch(() => ({}));
211
+ if ((_a = this.interceptors) == null ? void 0 : _a.onError) {
212
+ return this.interceptors.onError(
213
+ { status: res.status, headers: res.headers, data: errorData, message: `HTTP ${res.status}` },
214
+ async () => {
215
+ if (interceptorRetryConsumed) {
216
+ const e = new Error(`HTTP ${res.status} (retry limit)`);
217
+ e.status = res.status;
218
+ e.data = errorData;
219
+ throw e;
220
+ }
221
+ interceptorRetryConsumed = true;
222
+ return doFetch();
223
+ }
224
+ );
225
+ }
226
+ throw new Error(`HTTP ${res.status}`);
227
+ }
228
+ const responseData = await res.json().catch(() => ({}));
229
+ if ((_b = this.interceptors) == null ? void 0 : _b.onResponse) {
230
+ return this.interceptors.onResponse(
231
+ { status: res.status, headers: res.headers, data: responseData },
232
+ method
233
+ );
234
+ }
235
+ return responseData;
236
+ };
237
+ if (this.interceptors) {
238
+ return await doFetch();
239
+ }
178
240
  try {
179
- const res = await fetch(url, {
180
- method,
181
- headers: {
182
- ...this.extraHeaders,
183
- ...data ? { "Content-Type": "application/json" } : {}
184
- },
185
- body: data ? JSON.stringify(data) : void 0
186
- });
187
- if (!res.ok) throw new Error(`HTTP ${res.status}`);
188
- return await res.json();
241
+ return await doFetch();
189
242
  } catch (e) {
190
- console.warn(`[FetchHttpAdapter] Falha ao fazer ${method} para ${url}:`, e);
243
+ console.warn(`[FetchHttpAdapter] ${method} ${url}:`, e);
191
244
  return [];
192
245
  }
193
246
  }
194
- get(path) {
195
- return this.request("GET", path || "");
247
+ qs(query) {
248
+ return query ? `?${query}` : "";
196
249
  }
197
- post(path, data) {
198
- return this.request("POST", path || "", data);
250
+ get(path, query) {
251
+ return this.request("GET", `${this.joinPath(path)}${this.qs(query)}`);
199
252
  }
200
- put(path, data) {
201
- return this.request("PUT", path || "", data);
253
+ post(path, data, extraHeaders, query) {
254
+ return this.request("POST", `${this.joinPath(path)}${this.qs(query)}`, data, extraHeaders);
202
255
  }
203
- patch(path, data) {
204
- return this.request("PATCH", path || "", data);
256
+ put(path, data, extraHeaders, query) {
257
+ return this.request("PUT", `${this.joinPath(path)}${this.qs(query)}`, data, extraHeaders);
205
258
  }
206
- delete(path, id) {
207
- return this.request("DELETE", `${path || ""}/${id}`);
259
+ patch(path, data, extraHeaders, query) {
260
+ return this.request("PATCH", `${this.joinPath(path)}${this.qs(query)}`, data, extraHeaders);
208
261
  }
209
- deleteSimple(path) {
210
- return this.request("DELETE", path || "");
262
+ delete(path, id, extraHeaders, query) {
263
+ return this.request("DELETE", `${this.joinPath(path, id)}${this.qs(query)}`, void 0, extraHeaders);
211
264
  }
212
- save(path, data) {
213
- return this.request("POST", path || "", data);
265
+ deleteSimple(path, extraHeaders, query) {
266
+ return this.request("DELETE", `${this.joinPath(path)}${this.qs(query)}`, void 0, extraHeaders);
214
267
  }
215
- read(path, id) {
216
- return this.request("GET", `${path || ""}/${id}`);
268
+ save(path, data, extraHeaders, query) {
269
+ if (data && (data.id || data._id)) {
270
+ const id = data.id || data._id;
271
+ return this.request("PUT", `${this.joinPath(path, id)}${this.qs(query)}`, data, extraHeaders);
272
+ }
273
+ return this.request("POST", `${this.joinPath(path)}${this.qs(query)}`, data, extraHeaders);
217
274
  }
218
- readAll(path) {
219
- return this.request("GET", path || "");
275
+ read(path, id, extraHeaders, query) {
276
+ return this.request("GET", `${this.joinPath(path, id)}${this.qs(query)}`, void 0, extraHeaders);
220
277
  }
221
- readAllwithPage(path) {
222
- return this.request("GET", path || "");
278
+ readAll(path, extraHeaders, query) {
279
+ return this.request("GET", `${this.joinPath(path)}${this.qs(query)}`, void 0, extraHeaders);
223
280
  }
224
- bulkDelete(path) {
225
- return this.request("DELETE", path || "");
281
+ readAllwithPage(path, page, size) {
282
+ return this.request("GET", `${this.joinPath(path)}?page=${page}&size=${size}`);
283
+ }
284
+ bulkDelete(path, ids, extraHeaders, query) {
285
+ const bulkParam = ids ? `ids=${ids.join(",")}` : "";
286
+ const fullQuery = query ? `${query}&${bulkParam}` : bulkParam;
287
+ return this.request("DELETE", `${this.joinPath(path)}?${fullQuery}`, void 0, extraHeaders);
226
288
  }
227
289
  };
228
290
  var CoreServiceBuilder = class {
@@ -271,13 +333,15 @@ var CoreServiceBuilder = class {
271
333
  return this;
272
334
  }
273
335
  build() {
336
+ const subscriptions = [];
274
337
  return {
275
338
  toast: this._toast,
276
339
  createController: (context, baseEndPoint) => {
277
340
  if (this._fallbackControllers[context]) {
278
341
  return this._fallbackControllers[context];
279
342
  }
280
- const endpoint = baseEndPoint != null ? baseEndPoint : this._httpEndpoint ? `${this._httpEndpoint}/${context}` : null;
343
+ const endpointStr = this._httpEndpoint ? context ? `${this._httpEndpoint}/${context}` : this._httpEndpoint : null;
344
+ const endpoint = baseEndPoint != null ? baseEndPoint : endpointStr;
281
345
  if (!endpoint) {
282
346
  console.warn(`[CoreServiceBuilder] HttpEndpoint nulo para "${context}". Usando NullHttpController.`);
283
347
  const controller = new NullHttpController();
@@ -291,19 +355,27 @@ var CoreServiceBuilder = class {
291
355
  const extraHeaders = { "x-teraprox-host": hostHeader };
292
356
  return this._tracing ? new TracingHttpAdapter(endpoint, extraHeaders) : new FetchHttpAdapter(endpoint, extraHeaders);
293
357
  },
358
+ // Subscriptions are properly managed so that:
359
+ // 1. Components using useMatchingObject() have their registrations tracked.
360
+ // 2. An external RtdbBridge / StandaloneProvider can dispatch to them.
361
+ // 3. Tests can inspect which subscriptions are active.
294
362
  subscribe: (mo) => {
295
- console.log(`[CoreServiceBuilder RTDB] Subscribe > ${mo.context}`);
363
+ subscriptions.push(mo);
296
364
  },
297
365
  unsubscribe: (mo) => {
298
- console.log(`[CoreServiceBuilder RTDB] Unsubscribe > ${mo.context}`);
366
+ const idx = subscriptions.findIndex(
367
+ (s) => s.context === mo.context && s.location === mo.location
368
+ );
369
+ if (idx >= 0) subscriptions.splice(idx, 1);
299
370
  },
300
- subscribeEvent: (evt) => {
371
+ subscribeEvent: (_evt) => {
301
372
  },
302
- unsubscribeEvent: (evt) => {
373
+ unsubscribeEvent: (_evt) => {
303
374
  },
304
- handleLogout: () => console.log("Logout invocado no Standalone mode"),
375
+ handleLogout: () => console.log("[CoreServiceBuilder] Logout invocado no Standalone mode"),
305
376
  hostedByCore: this._hostedByCore,
306
- observability: this._observability
377
+ observability: this._observability,
378
+ rateLimits: {}
307
379
  };
308
380
  }
309
381
  };
@@ -424,15 +496,207 @@ function useObservability() {
424
496
  return useCoreService().observability;
425
497
  }
426
498
 
499
+ // src/hooks/useAnexoManager.ts
500
+ import { useState, useCallback as useCallback2, useMemo as useMemo2 } from "react";
501
+ function generateLocalId() {
502
+ return `local_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
503
+ }
504
+ function mapRowToPersistido(raw) {
505
+ var _a, _b, _c, _d;
506
+ const r = (raw == null ? void 0 : raw.dataValues) != null ? { ...raw.dataValues, id: (_b = raw.id) != null ? _b : (_a = raw.dataValues) == null ? void 0 : _a.id } : raw;
507
+ if (!r || typeof r !== "object") {
508
+ return { id: "unknown", nome: "Anexo", tipo: "application/octet-stream" };
509
+ }
510
+ const nome = typeof r.nome === "string" && r.nome || typeof r.originalName === "string" && r.originalName || typeof r.fileName === "string" && r.fileName || typeof r.key === "string" && r.key.split("/").pop() || "Anexo";
511
+ const tipo = typeof r.contentType === "string" && r.contentType || typeof r.tipo === "string" && r.tipo || "application/octet-stream";
512
+ const id = (_d = (_c = r.id) != null ? _c : r.anexoId) != null ? _d : String(nome);
513
+ const tamanho = typeof r.size === "number" ? r.size : typeof r.tamanho === "number" ? r.tamanho : void 0;
514
+ return {
515
+ id,
516
+ nome,
517
+ tipo,
518
+ tamanho,
519
+ url: r.url,
520
+ signedUrl: r.signedUrl,
521
+ key: r.key,
522
+ createdAt: r.createdAt
523
+ };
524
+ }
525
+ function useAnexoManager({ context, entityId, port }) {
526
+ const { createController } = useCoreService();
527
+ const [persistidos, setPersistidos] = useState([]);
528
+ const [locais, setLocais] = useState([]);
529
+ const [loading, setLoading] = useState(false);
530
+ const anexoController = useMemo2(() => createController("anexo"), [createController]);
531
+ const getPort = useCallback2(() => {
532
+ if (port && typeof port === "object" && "readByEntity" in port) return port;
533
+ const ctrl = anexoController;
534
+ return {
535
+ intent: (params) => ctrl.post("intent", {
536
+ fileName: params.nome,
537
+ contentType: params.tipo,
538
+ size: params.tamanho,
539
+ dataId: String(params.entityId),
540
+ dataContext: params.context
541
+ }),
542
+ confirm: (params) => {
543
+ var _a, _b;
544
+ return ctrl.post("confirm", {
545
+ key: params.key,
546
+ fileName: (_a = params.fileName) != null ? _a : "",
547
+ contentType: (_b = params.contentType) != null ? _b : "",
548
+ dataId: String(params.entityId),
549
+ dataContext: params.context
550
+ });
551
+ },
552
+ uploadDirect: async ({ file, context: ctx, entityId: eid }) => {
553
+ const targetCtrl = createController(ctx);
554
+ return targetCtrl.put(`anexo/${eid}`, {
555
+ anexos: [{ nome: file.name, tipo: file.type, tamanho: file.size }]
556
+ });
557
+ },
558
+ readByEntity: (ctx, eid) => ctrl.post("readByData", { dataId: String(eid), dataContext: ctx }),
559
+ getSignedUrl: (anexoId, key) => key ? ctrl.post("signedUrl", { key }).then((r) => (r == null ? void 0 : r.signedUrl) || (r == null ? void 0 : r.url) || "") : ctrl.post("signedUrl", { anexoId }).then((r) => (r == null ? void 0 : r.url) || (r == null ? void 0 : r.signedUrl) || ""),
560
+ remove: (anexoId) => ctrl.delete("", anexoId)
561
+ };
562
+ }, [port, anexoController, createController]);
563
+ const loadAnexos = useCallback2(async () => {
564
+ setLoading(true);
565
+ try {
566
+ const data = await getPort().readByEntity(context, entityId);
567
+ setPersistidos((Array.isArray(data) ? data : []).map(mapRowToPersistido));
568
+ } catch (e) {
569
+ setPersistidos([]);
570
+ } finally {
571
+ setLoading(false);
572
+ }
573
+ }, [context, entityId, getPort]);
574
+ const addFiles = useCallback2((files) => {
575
+ const newLocais = files.map((file) => ({
576
+ localId: generateLocalId(),
577
+ file,
578
+ nome: file.name,
579
+ tipo: file.type,
580
+ tamanho: file.size,
581
+ progress: 0,
582
+ status: "pending"
583
+ }));
584
+ setLocais((prev) => [...prev, ...newLocais]);
585
+ }, []);
586
+ const removeLocal = useCallback2((localId2) => {
587
+ setLocais((prev) => prev.filter((a) => a.localId !== localId2));
588
+ }, []);
589
+ const uploadAll = useCallback2(async (overrideEntityId) => {
590
+ var _a, _b;
591
+ const pending = locais.filter((a) => a.status === "pending" || a.status === "error");
592
+ if (!pending.length) return [];
593
+ const eid = overrideEntityId != null ? overrideEntityId : entityId;
594
+ const results = [];
595
+ const p = getPort();
596
+ for (const anexo of pending) {
597
+ setLocais(
598
+ (prev) => prev.map((a) => a.localId === anexo.localId ? { ...a, status: "uploading", progress: 10 } : a)
599
+ );
600
+ try {
601
+ let intent = null;
602
+ try {
603
+ intent = await p.intent({
604
+ nome: anexo.nome,
605
+ tipo: anexo.tipo,
606
+ tamanho: anexo.tamanho,
607
+ context,
608
+ entityId: eid
609
+ });
610
+ } catch (e) {
611
+ }
612
+ setLocais(
613
+ (prev) => prev.map((a) => a.localId === anexo.localId ? { ...a, progress: 40 } : a)
614
+ );
615
+ let result;
616
+ const intentUrl = (intent == null ? void 0 : intent.uploadUrl) || (intent == null ? void 0 : intent.signedUrl);
617
+ if (intentUrl) {
618
+ const putRes = await fetch(intentUrl, {
619
+ method: "PUT",
620
+ body: anexo.file,
621
+ headers: { "Content-Type": anexo.tipo || "application/octet-stream" }
622
+ });
623
+ if (!putRes.ok) {
624
+ const hint = await putRes.text().catch(() => "");
625
+ throw new Error(
626
+ `Falha ao enviar ficheiro para o armazenamento (HTTP ${putRes.status}). ${hint ? hint.slice(0, 180) : ""}`.trim()
627
+ );
628
+ }
629
+ setLocais(
630
+ (prev) => prev.map((a) => a.localId === anexo.localId ? { ...a, progress: 80 } : a)
631
+ );
632
+ result = await p.confirm({
633
+ context,
634
+ entityId: eid,
635
+ key: intent.key,
636
+ fileName: (_a = intent.fileName) != null ? _a : anexo.nome,
637
+ contentType: (_b = intent.contentType) != null ? _b : anexo.tipo
638
+ });
639
+ } else {
640
+ result = await p.uploadDirect({ file: anexo.file, context, entityId: eid });
641
+ }
642
+ setLocais(
643
+ (prev) => prev.map((a) => a.localId === anexo.localId ? { ...a, status: "done", progress: 100 } : a)
644
+ );
645
+ results.push(mapRowToPersistido(result));
646
+ } catch (err) {
647
+ setLocais(
648
+ (prev) => prev.map(
649
+ (a) => a.localId === anexo.localId ? { ...a, status: "error", progress: 0, errorMessage: (err == null ? void 0 : err.message) || "Falha no upload" } : a
650
+ )
651
+ );
652
+ }
653
+ }
654
+ if (results.length) {
655
+ setPersistidos((prev) => [...prev, ...results]);
656
+ setLocais((prev) => prev.filter((a) => a.status !== "done"));
657
+ }
658
+ return results;
659
+ }, [locais, getPort, context, entityId]);
660
+ const removePersistido = useCallback2(async (anexoId) => {
661
+ try {
662
+ await getPort().remove(anexoId);
663
+ setPersistidos((prev) => prev.filter((a) => a.id !== anexoId));
664
+ } catch (e) {
665
+ }
666
+ }, [getPort]);
667
+ const getUrl = useCallback2(
668
+ async (anexoId, key) => {
669
+ let k = key;
670
+ if (k == null || k === "") {
671
+ const p = persistidos.find((a) => String(a.id) === String(anexoId));
672
+ k = p == null ? void 0 : p.key;
673
+ }
674
+ return getPort().getSignedUrl(anexoId, k);
675
+ },
676
+ [getPort, persistidos]
677
+ );
678
+ return {
679
+ persistidos,
680
+ locais,
681
+ loading,
682
+ loadAnexos,
683
+ addFiles,
684
+ removeLocal,
685
+ uploadAll,
686
+ removePersistido,
687
+ getUrl
688
+ };
689
+ }
690
+
427
691
  // src/hooks/useFetchData.ts
428
- import { useState, useCallback as useCallback2, useRef } from "react";
692
+ import { useState as useState2, useCallback as useCallback3, useRef } from "react";
429
693
  function useFetchData() {
430
694
  const { createController } = useCoreService();
431
- const [data, setData] = useState(null);
432
- const [loading, setLoading] = useState(false);
433
- const [error, setError] = useState(null);
695
+ const [data, setData] = useState2(null);
696
+ const [loading, setLoading] = useState2(false);
697
+ const [error, setError] = useState2(null);
434
698
  const activeRef = useRef(true);
435
- const fetchData = useCallback2(
699
+ const fetchData = useCallback3(
436
700
  async (context, path, endpoint) => {
437
701
  const controller = createController(context, endpoint);
438
702
  setLoading(true);
@@ -450,7 +714,7 @@ function useFetchData() {
450
714
  },
451
715
  [createController]
452
716
  );
453
- const reset = useCallback2(() => {
717
+ const reset = useCallback3(() => {
454
718
  setData(null);
455
719
  setLoading(false);
456
720
  setError(null);
@@ -459,13 +723,13 @@ function useFetchData() {
459
723
  }
460
724
 
461
725
  // src/hooks/usePostData.ts
462
- import { useState as useState2, useCallback as useCallback3 } from "react";
726
+ import { useState as useState3, useCallback as useCallback4 } from "react";
463
727
  function usePostData() {
464
728
  const { createController } = useCoreService();
465
- const [result, setResult] = useState2(null);
466
- const [loading, setLoading] = useState2(false);
467
- const [error, setError] = useState2(null);
468
- const postData = useCallback3(
729
+ const [result, setResult] = useState3(null);
730
+ const [loading, setLoading] = useState3(false);
731
+ const [error, setError] = useState3(null);
732
+ const postData = useCallback4(
469
733
  async (context, path, payload, endpoint) => {
470
734
  const controller = createController(context, endpoint);
471
735
  setLoading(true);
@@ -487,13 +751,13 @@ function usePostData() {
487
751
  }
488
752
 
489
753
  // src/hooks/useAnexoUpload.ts
490
- import { useState as useState3, useCallback as useCallback4 } from "react";
754
+ import { useState as useState4, useCallback as useCallback5 } from "react";
491
755
  function useAnexoUpload() {
492
756
  const { createController } = useCoreService();
493
757
  const toast = useToast();
494
- const [uploading, setUploading] = useState3(false);
495
- const [progress, setProgress] = useState3(0);
496
- const upload = useCallback4(
758
+ const [uploading, setUploading] = useState4(false);
759
+ const [progress, setProgress] = useState4(0);
760
+ const upload = useCallback5(
497
761
  async (context, path, file, extraHeaders) => {
498
762
  const controller = createController(context);
499
763
  setUploading(true);
@@ -516,7 +780,7 @@ function useAnexoUpload() {
516
780
  },
517
781
  [createController, toast]
518
782
  );
519
- const uploadMultiple = useCallback4(
783
+ const uploadMultiple = useCallback5(
520
784
  async (context, path, files, extraHeaders) => {
521
785
  const fileArray = Array.from(files);
522
786
  const results = [];
@@ -534,10 +798,10 @@ function useAnexoUpload() {
534
798
  }
535
799
 
536
800
  // src/hooks/useFormStorage.ts
537
- import { useState as useState4, useCallback as useCallback5, useEffect as useEffect2 } from "react";
801
+ import { useState as useState5, useCallback as useCallback6, useEffect as useEffect2 } from "react";
538
802
  function useFormStorage(key, initialValue) {
539
803
  const storageKey = `teraprox_form_${key}`;
540
- const [value, setValue] = useState4(() => {
804
+ const [value, setValue] = useState5(() => {
541
805
  try {
542
806
  const stored = localStorage.getItem(storageKey);
543
807
  return stored ? JSON.parse(stored) : initialValue;
@@ -551,7 +815,7 @@ function useFormStorage(key, initialValue) {
551
815
  } catch (e) {
552
816
  }
553
817
  }, [value, storageKey]);
554
- const clear = useCallback5(() => {
818
+ const clear = useCallback6(() => {
555
819
  localStorage.removeItem(storageKey);
556
820
  setValue(initialValue);
557
821
  }, [storageKey, initialValue]);
@@ -559,11 +823,11 @@ function useFormStorage(key, initialValue) {
559
823
  }
560
824
 
561
825
  // src/hooks/useSmartSearch.ts
562
- import { useState as useState5, useMemo as useMemo2, useCallback as useCallback6 } from "react";
826
+ import { useState as useState6, useMemo as useMemo3, useCallback as useCallback7 } from "react";
563
827
  function useSmartSearch(data, searchFields, options) {
564
- const [searchTerm, setSearchTerm] = useState5("");
828
+ const [searchTerm, setSearchTerm] = useState6("");
565
829
  const { caseSensitive = false, minLength = 1 } = options || {};
566
- const filteredData = useMemo2(() => {
830
+ const filteredData = useMemo3(() => {
567
831
  if (!searchTerm || searchTerm.length < minLength) return data;
568
832
  const term = caseSensitive ? searchTerm : searchTerm.toLowerCase();
569
833
  return data.filter(
@@ -575,16 +839,16 @@ function useSmartSearch(data, searchFields, options) {
575
839
  })
576
840
  );
577
841
  }, [data, searchTerm, searchFields, caseSensitive, minLength]);
578
- const clearSearch = useCallback6(() => setSearchTerm(""), []);
842
+ const clearSearch = useCallback7(() => setSearchTerm(""), []);
579
843
  return { searchTerm, setSearchTerm, filteredData, clearSearch };
580
844
  }
581
845
 
582
846
  // src/hooks/useValidation.ts
583
- import { useState as useState6, useCallback as useCallback7 } from "react";
847
+ import { useState as useState7, useCallback as useCallback8 } from "react";
584
848
  function useValidation(rules) {
585
849
  const toast = useToast();
586
- const [errors, setErrors] = useState6({});
587
- const validate = useCallback7(
850
+ const [errors, setErrors] = useState7({});
851
+ const validate = useCallback8(
588
852
  (form) => {
589
853
  const newErrors = {};
590
854
  let valid = true;
@@ -603,22 +867,523 @@ function useValidation(rules) {
603
867
  },
604
868
  [rules, toast]
605
869
  );
606
- const clearErrors = useCallback7(() => setErrors({}), []);
607
- const setFieldError = useCallback7(
870
+ const clearErrors = useCallback8(() => setErrors({}), []);
871
+ const setFieldError = useCallback8(
608
872
  (field, message) => setErrors((prev) => ({ ...prev, [field]: message })),
609
873
  []
610
874
  );
611
875
  return { errors, validate, clearErrors, setFieldError };
612
876
  }
613
877
 
614
- // src/components/recurso/RecursoDisplayer.tsx
615
- import { useEffect as useEffect6, useState as useState12 } from "react";
616
- import { Button } from "react-bootstrap";
617
- import { useDispatch as useDispatch2 } from "react-redux";
878
+ // src/hooks/useTimeFormat.ts
879
+ import dayjs from "dayjs";
880
+ import duration from "dayjs/plugin/duration.js";
881
+ dayjs.extend(duration);
882
+ var secondsToHms = (seconds) => {
883
+ const s = typeof seconds === "number" && !Number.isNaN(seconds) ? seconds : 0;
884
+ return dayjs.duration(s, "seconds").format("HH:mm:ss");
885
+ };
886
+ var hmsToSeconds = (value) => {
887
+ if (!value) return null;
888
+ const parts = value.split(":").map(Number);
889
+ const [h = 0, m = 0, s = 0] = parts;
890
+ if ([h, m, s].some(Number.isNaN)) return null;
891
+ return h * 3600 + m * 60 + s;
892
+ };
893
+ var useTimeFormat = () => ({
894
+ secondsToHms,
895
+ hmsToSeconds
896
+ });
618
897
 
619
- // src/reducers/branchLevelReducer.ts
898
+ // src/hooks/useFilterCombineMode.ts
899
+ import { useCallback as useCallback9, useMemo as useMemo4, useState as useState8 } from "react";
900
+ var FILTER_COMBINE_MODES = [
901
+ "union",
902
+ "intersection",
903
+ "xor"
904
+ ];
905
+ var nextMode = {
906
+ union: "intersection",
907
+ intersection: "xor",
908
+ xor: "union"
909
+ };
910
+ function useFilterCombineMode(initialMode = "union") {
911
+ const [mode, setMode] = useState8(initialMode);
912
+ const cycleMode = useCallback9(() => {
913
+ setMode((prev) => nextMode[prev]);
914
+ }, []);
915
+ const matches = useCallback9(
916
+ (predicates, item) => {
917
+ if (!predicates || predicates.length === 0) return true;
918
+ if (mode === "union") {
919
+ for (let i = 0; i < predicates.length; i++) {
920
+ if (predicates[i](item)) return true;
921
+ }
922
+ return false;
923
+ }
924
+ if (mode === "intersection") {
925
+ for (let i = 0; i < predicates.length; i++) {
926
+ if (!predicates[i](item)) return false;
927
+ }
928
+ return true;
929
+ }
930
+ let hits = 0;
931
+ for (let i = 0; i < predicates.length; i++) {
932
+ if (predicates[i](item)) hits++;
933
+ }
934
+ return hits % 2 === 1;
935
+ },
936
+ [mode]
937
+ );
938
+ return useMemo4(
939
+ () => ({ mode, setMode, cycleMode, matches }),
940
+ [mode, cycleMode, matches]
941
+ );
942
+ }
943
+
944
+ // src/viewmodels/ReduxUnidadeMaterialAdapter.ts
945
+ import { useCallback as useCallback10, useMemo as useMemo5, useState as useState9 } from "react";
946
+ import { useDispatch as useDispatch2, useSelector as useSelector3 } from "react-redux";
947
+
948
+ // src/viewmodels/unidadeMaterialSlice.ts
620
949
  import { createSlice } from "@reduxjs/toolkit";
950
+ var DEFAULT_KEY = "__default__";
951
+ var emptyValue = {
952
+ material: null,
953
+ quantidade: "",
954
+ unidade: null
955
+ };
621
956
  var initialState = {
957
+ byTarefa: {}
958
+ };
959
+ var keyOf = (tarefaId) => tarefaId === void 0 || tarefaId === null || tarefaId === "" ? DEFAULT_KEY : String(tarefaId);
960
+ var ensure = (state, key) => {
961
+ if (!state.byTarefa[key]) {
962
+ state.byTarefa[key] = { ...emptyValue };
963
+ }
964
+ return state.byTarefa[key];
965
+ };
966
+ var unidadeMaterialSlice = createSlice({
967
+ name: "unidadeMaterialVm",
968
+ initialState,
969
+ reducers: {
970
+ setMaterial(state, action) {
971
+ const key = keyOf(action.payload.tarefaId);
972
+ ensure(state, key).material = action.payload.value;
973
+ },
974
+ setQuantidade(state, action) {
975
+ const key = keyOf(action.payload.tarefaId);
976
+ ensure(state, key).quantidade = action.payload.value;
977
+ },
978
+ setUnidade(state, action) {
979
+ const key = keyOf(action.payload.tarefaId);
980
+ ensure(state, key).unidade = action.payload.value;
981
+ },
982
+ populate(state, action) {
983
+ const key = keyOf(action.payload.tarefaId);
984
+ state.byTarefa[key] = { ...emptyValue, ...action.payload.value };
985
+ },
986
+ clearUnidadeMaterial(state, action) {
987
+ var _a;
988
+ const key = keyOf((_a = action.payload) == null ? void 0 : _a.tarefaId);
989
+ state.byTarefa[key] = { ...emptyValue };
990
+ }
991
+ }
992
+ });
993
+ var {
994
+ setMaterial,
995
+ setQuantidade,
996
+ setUnidade,
997
+ populate: populateUnidadeMaterial,
998
+ clearUnidadeMaterial
999
+ } = unidadeMaterialSlice.actions;
1000
+ var selectUnidadeMaterial = (state, tarefaId) => {
1001
+ var _a, _b, _c;
1002
+ const key = keyOf(tarefaId);
1003
+ const slice3 = (_a = state == null ? void 0 : state.unidadeMaterialVm) != null ? _a : state == null ? void 0 : state.unidadeMaterial;
1004
+ return (_c = (_b = slice3 == null ? void 0 : slice3.byTarefa) == null ? void 0 : _b[key]) != null ? _c : emptyValue;
1005
+ };
1006
+ var unidadeMaterialSlice_default = unidadeMaterialSlice.reducer;
1007
+
1008
+ // src/viewmodels/ReduxUnidadeMaterialAdapter.ts
1009
+ function runValidate(value) {
1010
+ const errors = {};
1011
+ if (!(value == null ? void 0 : value.material)) {
1012
+ errors.material = "O material \xE9 obrigat\xF3rio.";
1013
+ }
1014
+ if (!(value == null ? void 0 : value.unidade)) {
1015
+ errors.unidade = "A unidade \xE9 obrigat\xF3ria.";
1016
+ }
1017
+ const qtd = value == null ? void 0 : value.quantidade;
1018
+ const qtdNum = typeof qtd === "number" ? qtd : Number(qtd);
1019
+ if (qtd === "" || qtd === null || qtd === void 0 || isNaN(qtdNum) || qtdNum <= 0) {
1020
+ errors.quantidade = "A quantidade deve ser um n\xFAmero maior que zero.";
1021
+ }
1022
+ return { ok: Object.keys(errors).length === 0, errors };
1023
+ }
1024
+ function useUnidadeMaterialViewModel(tarefaId) {
1025
+ const dispatch = useDispatch2();
1026
+ const toast = useToast();
1027
+ const materialCtrl = useHttpController("material");
1028
+ const unidadeCtrl = useHttpController("unidade");
1029
+ const tarefaUnidadeMaterialCtrl = useHttpController("tarefaUnidadeMaterial");
1030
+ const value = useSelector3(
1031
+ (state) => selectUnidadeMaterial(state, tarefaId)
1032
+ );
1033
+ const [isSubmitting, setIsSubmitting] = useState9(false);
1034
+ const onMaterialSelected = useCallback10(
1035
+ (material) => {
1036
+ dispatch(setMaterial({ tarefaId, value: material != null ? material : null }));
1037
+ },
1038
+ [dispatch, tarefaId]
1039
+ );
1040
+ const onQuantidadeUpdate = useCallback10(
1041
+ (qtd) => {
1042
+ dispatch(setQuantidade({ tarefaId, value: qtd }));
1043
+ },
1044
+ [dispatch, tarefaId]
1045
+ );
1046
+ const onUnidadeSelected = useCallback10(
1047
+ (unidade) => {
1048
+ dispatch(setUnidade({ tarefaId, value: unidade != null ? unidade : null }));
1049
+ },
1050
+ [dispatch, tarefaId]
1051
+ );
1052
+ const loadMaterials = useCallback10(async () => {
1053
+ var _a;
1054
+ const res = await materialCtrl.readAll();
1055
+ return Array.isArray(res) ? res : (_a = res == null ? void 0 : res.data) != null ? _a : [];
1056
+ }, [materialCtrl]);
1057
+ const loadUnidades = useCallback10(async () => {
1058
+ var _a;
1059
+ const res = await unidadeCtrl.readAll();
1060
+ return Array.isArray(res) ? res : (_a = res == null ? void 0 : res.data) != null ? _a : [];
1061
+ }, [unidadeCtrl]);
1062
+ const clear = useCallback10(() => {
1063
+ dispatch(clearUnidadeMaterial({ tarefaId }));
1064
+ }, [dispatch, tarefaId]);
1065
+ const populate = useCallback10(
1066
+ (next) => {
1067
+ dispatch(populateUnidadeMaterial({ tarefaId, value: next }));
1068
+ },
1069
+ [dispatch, tarefaId]
1070
+ );
1071
+ const validate = useCallback10(() => {
1072
+ return runValidate(value);
1073
+ }, [value]);
1074
+ const reset = useCallback10(() => {
1075
+ dispatch(clearUnidadeMaterial({ tarefaId }));
1076
+ }, [dispatch, tarefaId]);
1077
+ const submit = useCallback10(async () => {
1078
+ var _a;
1079
+ setIsSubmitting(true);
1080
+ try {
1081
+ const result = runValidate(value);
1082
+ if (!result.ok) {
1083
+ const firstErr = (_a = Object.values(result.errors)[0]) != null ? _a : "Dados invalidos.";
1084
+ throw new Error(firstErr);
1085
+ }
1086
+ return value;
1087
+ } finally {
1088
+ setIsSubmitting(false);
1089
+ }
1090
+ }, [value]);
1091
+ const updateQuantidade = useCallback10(
1092
+ async (tumId, quantidade) => {
1093
+ try {
1094
+ const body = {
1095
+ quantidade
1096
+ };
1097
+ if (tarefaId !== void 0 && tarefaId !== null) {
1098
+ body.tarefaId = tarefaId;
1099
+ }
1100
+ await tarefaUnidadeMaterialCtrl.put(String(tumId), body);
1101
+ } catch (err) {
1102
+ const msg = (err == null ? void 0 : err.message) || "Nao foi possivel atualizar a quantidade do material.";
1103
+ try {
1104
+ toast.warning(msg);
1105
+ } catch (e) {
1106
+ }
1107
+ throw err;
1108
+ }
1109
+ },
1110
+ [tarefaUnidadeMaterialCtrl, tarefaId, toast]
1111
+ );
1112
+ const isValid = useMemo5(() => runValidate(value).ok, [value]);
1113
+ return useMemo5(
1114
+ () => ({
1115
+ value,
1116
+ isValid,
1117
+ isSubmitting,
1118
+ onMaterialSelected,
1119
+ onQuantidadeUpdate,
1120
+ onUnidadeSelected,
1121
+ loadMaterials,
1122
+ loadUnidades,
1123
+ clear,
1124
+ populate,
1125
+ validate,
1126
+ submit,
1127
+ reset,
1128
+ updateQuantidade
1129
+ }),
1130
+ [
1131
+ value,
1132
+ isValid,
1133
+ isSubmitting,
1134
+ onMaterialSelected,
1135
+ onQuantidadeUpdate,
1136
+ onUnidadeSelected,
1137
+ loadMaterials,
1138
+ loadUnidades,
1139
+ clear,
1140
+ populate,
1141
+ validate,
1142
+ submit,
1143
+ reset,
1144
+ updateQuantidade
1145
+ ]
1146
+ );
1147
+ }
1148
+
1149
+ // src/viewmodels/ReduxInspecaoModalAdapter.ts
1150
+ import { useCallback as useCallback11, useMemo as useMemo6, useState as useState10 } from "react";
1151
+ import { useDispatch as useDispatch3, useSelector as useSelector4 } from "react-redux";
1152
+
1153
+ // src/viewmodels/inspecaoModalSlice.ts
1154
+ import { createSlice as createSlice2 } from "@reduxjs/toolkit";
1155
+ var DEFAULT_KEY2 = "__default__";
1156
+ var emptyValue2 = {
1157
+ tipo: "",
1158
+ nomeParametro: "",
1159
+ unidadeParametro: "",
1160
+ parametroId: "",
1161
+ limitesDeControle: []
1162
+ };
1163
+ var initialState2 = {
1164
+ byTarefa: {}
1165
+ };
1166
+ var keyOf2 = (tarefaId) => tarefaId === void 0 || tarefaId === null || tarefaId === "" ? DEFAULT_KEY2 : String(tarefaId);
1167
+ var ensure2 = (state, key) => {
1168
+ if (!state.byTarefa[key]) {
1169
+ state.byTarefa[key] = { ...emptyValue2, limitesDeControle: [] };
1170
+ }
1171
+ return state.byTarefa[key];
1172
+ };
1173
+ var inspecaoModalSlice = createSlice2({
1174
+ name: "inspecaoModalVm",
1175
+ initialState: initialState2,
1176
+ reducers: {
1177
+ setTipo(state, action) {
1178
+ const key = keyOf2(action.payload.tarefaId);
1179
+ ensure2(state, key).tipo = action.payload.value;
1180
+ },
1181
+ setNomeParametro(state, action) {
1182
+ const key = keyOf2(action.payload.tarefaId);
1183
+ ensure2(state, key).nomeParametro = action.payload.value;
1184
+ },
1185
+ setUnidadeParametro(state, action) {
1186
+ const key = keyOf2(action.payload.tarefaId);
1187
+ ensure2(state, key).unidadeParametro = action.payload.value;
1188
+ },
1189
+ setParametro(state, action) {
1190
+ var _a, _b, _c, _d, _e, _f, _g, _h;
1191
+ const key = keyOf2(action.payload.tarefaId);
1192
+ const slot = ensure2(state, key);
1193
+ const p = (_a = action.payload.value) != null ? _a : {};
1194
+ slot.nomeParametro = (_c = (_b = p.nome) != null ? _b : p.nomeParametro) != null ? _c : "";
1195
+ slot.unidadeParametro = (_f = (_e = (_d = p.labelUnidade) != null ? _d : p.unidade) != null ? _e : p.unidadeParametro) != null ? _f : "";
1196
+ slot.parametroId = (_h = (_g = p.id) != null ? _g : p.parametroId) != null ? _h : "";
1197
+ },
1198
+ setLimites(state, action) {
1199
+ var _a;
1200
+ const key = keyOf2(action.payload.tarefaId);
1201
+ ensure2(state, key).limitesDeControle = (_a = action.payload.value) != null ? _a : [];
1202
+ },
1203
+ removeLimiteAt(state, action) {
1204
+ var _a;
1205
+ const key = keyOf2(action.payload.tarefaId);
1206
+ const slot = ensure2(state, key);
1207
+ const { idx } = action.payload;
1208
+ if ((_a = slot.limitesDeControle) == null ? void 0 : _a[idx]) {
1209
+ slot.limitesDeControle[idx] = {
1210
+ ...slot.limitesDeControle[idx],
1211
+ removed: true
1212
+ };
1213
+ }
1214
+ },
1215
+ populate(state, action) {
1216
+ var _a, _b;
1217
+ const key = keyOf2(action.payload.tarefaId);
1218
+ state.byTarefa[key] = {
1219
+ ...emptyValue2,
1220
+ ...action.payload.value,
1221
+ limitesDeControle: (_b = (_a = action.payload.value) == null ? void 0 : _a.limitesDeControle) != null ? _b : []
1222
+ };
1223
+ },
1224
+ clearInspecaoModal(state, action) {
1225
+ var _a;
1226
+ const key = keyOf2((_a = action.payload) == null ? void 0 : _a.tarefaId);
1227
+ state.byTarefa[key] = { ...emptyValue2, limitesDeControle: [] };
1228
+ }
1229
+ }
1230
+ });
1231
+ var {
1232
+ setTipo: setInspecaoTipo,
1233
+ setNomeParametro: setInspecaoNomeParametro,
1234
+ setUnidadeParametro: setInspecaoUnidadeParametro,
1235
+ setParametro: setInspecaoParametro,
1236
+ setLimites: setInspecaoLimites,
1237
+ removeLimiteAt: removeInspecaoLimiteAt,
1238
+ populate: populateInspecaoModal,
1239
+ clearInspecaoModal
1240
+ } = inspecaoModalSlice.actions;
1241
+ var selectInspecaoModal = (state, tarefaId) => {
1242
+ var _a, _b, _c;
1243
+ const key = keyOf2(tarefaId);
1244
+ const slice3 = (_a = state == null ? void 0 : state.inspecaoModalVm) != null ? _a : state == null ? void 0 : state.inspecaoModal;
1245
+ return (_c = (_b = slice3 == null ? void 0 : slice3.byTarefa) == null ? void 0 : _b[key]) != null ? _c : { ...emptyValue2, limitesDeControle: [] };
1246
+ };
1247
+ var inspecaoModalSlice_default = inspecaoModalSlice.reducer;
1248
+
1249
+ // src/viewmodels/ReduxInspecaoModalAdapter.ts
1250
+ var TIPO_NUMERICO = "Numerico";
1251
+ var TIPO_NUMERICO_ACENTUADO = "Num\xE9rico";
1252
+ function isNumericoTipo(tipo) {
1253
+ if (!tipo) return false;
1254
+ const normalized = tipo.trim();
1255
+ return normalized === TIPO_NUMERICO || normalized === TIPO_NUMERICO_ACENTUADO || normalized.toLowerCase() === "numerico" || normalized.toLowerCase() === "num\xE9rico";
1256
+ }
1257
+ function runValidate2(value) {
1258
+ var _a;
1259
+ const errors = {};
1260
+ if (!(value == null ? void 0 : value.tipo) || String(value.tipo).trim() === "") {
1261
+ errors.tipo = "O tipo de dado \xE9 obrigat\xF3rio.";
1262
+ }
1263
+ if (isNumericoTipo(value == null ? void 0 : value.tipo)) {
1264
+ const ativos = ((_a = value == null ? void 0 : value.limitesDeControle) != null ? _a : []).filter(
1265
+ (l) => l && l.removed !== true
1266
+ );
1267
+ if (ativos.length === 0) {
1268
+ errors.limitesDeControle = "Adicione ao menos um limite de controle para par\xE2metros num\xE9ricos.";
1269
+ }
1270
+ }
1271
+ return { ok: Object.keys(errors).length === 0, errors };
1272
+ }
1273
+ function useInspecaoModalViewModel(tarefaId) {
1274
+ const dispatch = useDispatch3();
1275
+ const value = useSelector4(
1276
+ (state) => selectInspecaoModal(state, tarefaId)
1277
+ );
1278
+ const [isSubmitting, setIsSubmitting] = useState10(false);
1279
+ const onTipoDeDado = useCallback11(
1280
+ (tipo) => {
1281
+ dispatch(setInspecaoTipo({ tarefaId, value: tipo }));
1282
+ },
1283
+ [dispatch, tarefaId]
1284
+ );
1285
+ const onNomeParametro = useCallback11(
1286
+ (nome) => {
1287
+ dispatch(setInspecaoNomeParametro({ tarefaId, value: nome }));
1288
+ },
1289
+ [dispatch, tarefaId]
1290
+ );
1291
+ const onParametroSelected = useCallback11(
1292
+ (parametro) => {
1293
+ dispatch(setInspecaoParametro({ tarefaId, value: parametro }));
1294
+ },
1295
+ [dispatch, tarefaId]
1296
+ );
1297
+ const onUnidadeParametro = useCallback11(
1298
+ (unidade) => {
1299
+ dispatch(setInspecaoUnidadeParametro({ tarefaId, value: unidade }));
1300
+ },
1301
+ [dispatch, tarefaId]
1302
+ );
1303
+ const onLimitesChange = useCallback11(
1304
+ (limites) => {
1305
+ dispatch(setInspecaoLimites({ tarefaId, value: limites }));
1306
+ },
1307
+ [dispatch, tarefaId]
1308
+ );
1309
+ const removeLimite = useCallback11(
1310
+ (idx) => {
1311
+ dispatch(removeInspecaoLimiteAt({ tarefaId, idx }));
1312
+ },
1313
+ [dispatch, tarefaId]
1314
+ );
1315
+ const editLimite = useCallback11((_limite) => {
1316
+ }, []);
1317
+ const validate = useCallback11(() => {
1318
+ return runValidate2(value);
1319
+ }, [value]);
1320
+ const reset = useCallback11(() => {
1321
+ dispatch(clearInspecaoModal({ tarefaId }));
1322
+ }, [dispatch, tarefaId]);
1323
+ const populateFromExisting = useCallback11(
1324
+ (inspecao) => {
1325
+ dispatch(populateInspecaoModal({ tarefaId, value: inspecao }));
1326
+ },
1327
+ [dispatch, tarefaId]
1328
+ );
1329
+ const submit = useCallback11(async () => {
1330
+ var _a;
1331
+ setIsSubmitting(true);
1332
+ try {
1333
+ const result = runValidate2(value);
1334
+ if (!result.ok) {
1335
+ const firstErr = (_a = Object.values(result.errors)[0]) != null ? _a : "Dados invalidos.";
1336
+ throw new Error(firstErr);
1337
+ }
1338
+ return value;
1339
+ } finally {
1340
+ setIsSubmitting(false);
1341
+ }
1342
+ }, [value]);
1343
+ const isValid = useMemo6(() => runValidate2(value).ok, [value]);
1344
+ return useMemo6(
1345
+ () => ({
1346
+ value,
1347
+ isValid,
1348
+ isSubmitting,
1349
+ onTipoDeDado,
1350
+ onNomeParametro,
1351
+ onParametroSelected,
1352
+ onUnidadeParametro,
1353
+ onLimitesChange,
1354
+ removeLimite,
1355
+ editLimite,
1356
+ validate,
1357
+ submit,
1358
+ reset,
1359
+ populateFromExisting
1360
+ }),
1361
+ [
1362
+ value,
1363
+ isValid,
1364
+ isSubmitting,
1365
+ onTipoDeDado,
1366
+ onNomeParametro,
1367
+ onParametroSelected,
1368
+ onUnidadeParametro,
1369
+ onLimitesChange,
1370
+ removeLimite,
1371
+ editLimite,
1372
+ validate,
1373
+ submit,
1374
+ reset,
1375
+ populateFromExisting
1376
+ ]
1377
+ );
1378
+ }
1379
+
1380
+ // src/viewmodels/ReduxRecursoDisplayerAdapter.ts
1381
+ import { useCallback as useCallback12, useEffect as useEffect3, useMemo as useMemo7, useRef as useRef2, useState as useState11 } from "react";
1382
+ import { useDispatch as useDispatch4 } from "react-redux";
1383
+
1384
+ // src/reducers/branchLevelReducer.ts
1385
+ import { createSlice as createSlice3 } from "@reduxjs/toolkit";
1386
+ var initialState3 = {
622
1387
  form: {
623
1388
  nome: "",
624
1389
  level: 0,
@@ -628,9 +1393,9 @@ var initialState = {
628
1393
  },
629
1394
  levels: []
630
1395
  };
631
- var branchLevelSlice = createSlice({
1396
+ var branchLevelSlice = createSlice3({
632
1397
  name: "branchLevelReducer",
633
- initialState,
1398
+ initialState: initialState3,
634
1399
  reducers: {
635
1400
  setNome(state, action) {
636
1401
  state.form.nome = action.payload;
@@ -654,7 +1419,7 @@ var branchLevelSlice = createSlice({
654
1419
  state.form = action.payload;
655
1420
  },
656
1421
  clear(state) {
657
- state.form = initialState.form;
1422
+ state.form = initialState3.form;
658
1423
  }
659
1424
  }
660
1425
  });
@@ -670,788 +1435,1282 @@ var {
670
1435
  } = branchLevelSlice.actions;
671
1436
  var branchLevelReducer_default = branchLevelSlice.reducer;
672
1437
 
673
- // src/components/recurso/BranchDropDisplay.tsx
674
- import { useEffect as useEffect3, useRef as useRef2, useState as useState7 } from "react";
675
- import { FaCheck, FaCheckSquare, FaSearch, FaChevronDown } from "react-icons/fa";
676
- import { MdClose } from "react-icons/md";
677
-
678
- // src/utils/colorUtils.ts
679
- function pickTextColorBasedOnBgColorAdvanced(bgColor, lightColor, darkColor) {
680
- const color = bgColor.charAt(0) === "#" ? bgColor.substring(1, 7) : bgColor;
681
- const r = parseInt(color.substring(0, 2), 16);
682
- const g = parseInt(color.substring(2, 4), 16);
683
- const b = parseInt(color.substring(4, 6), 16);
684
- const uicolors = [r / 255, g / 255, b / 255];
685
- const c = uicolors.map(
686
- (col) => col <= 0.03928 ? col / 12.92 : Math.pow((col + 0.055) / 1.055, 2.4)
687
- );
688
- const L = 0.2126 * c[0] + 0.7152 * c[1] + 0.0722 * c[2];
689
- return L > 0.179 ? darkColor : lightColor;
690
- }
691
-
692
- // src/components/recurso/BranchDropDisplay.tsx
693
- import { jsx, jsxs } from "react/jsx-runtime";
694
- var BranchDropDisplay = ({
695
- branch,
696
- addBranch,
697
- multiMode,
698
- setMultiMode,
699
- onSaveRecurso,
700
- backOnBranch,
701
- branches,
702
- singleReturn
703
- }) => {
704
- const [fontColor, setFontColor] = useState7("#000");
705
- const [searchTerm, setSearchTerm] = useState7("");
706
- const [show, setShow] = useState7(false);
707
- const [multiSelected, setMultiSelected] = useState7([]);
708
- const dropdownRef = useRef2(null);
1438
+ // src/viewmodels/ReduxRecursoDisplayerAdapter.ts
1439
+ function useRecursoDisplayerViewModel(overrides = {}) {
1440
+ var _a, _b;
1441
+ const dispatch = useDispatch4();
1442
+ const defaultArvore = useHttpController("");
1443
+ const defaultBranchLevel = useHttpController("branchLevel");
1444
+ const arvoreCtrl = (_a = overrides.arvoreEstruturalController) != null ? _a : defaultArvore;
1445
+ const branchLevelCtrl = (_b = overrides.branchLevelController) != null ? _b : defaultBranchLevel;
1446
+ const [branches, setBranches] = useState11([]);
1447
+ const [isLoading, setIsLoading] = useState11(false);
1448
+ const branchesRef = useRef2(branches);
709
1449
  useEffect3(() => {
710
- setFontColor(
711
- pickTextColorBasedOnBgColorAdvanced(branch.branchLevel.color, "#FFFFFF", "#000000")
712
- );
713
- }, [branch.branchLevel.color]);
714
- useEffect3(() => {
715
- const handleClickOutside = (event) => {
716
- if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
717
- setShow(false);
1450
+ branchesRef.current = branches;
1451
+ }, [branches]);
1452
+ const loadInitialBranches = useCallback12(async () => {
1453
+ setIsLoading(true);
1454
+ try {
1455
+ try {
1456
+ const b = await arvoreCtrl.get("branchByBranchLevel/1");
1457
+ setBranches(Array.isArray(b) ? b : []);
1458
+ } catch (err) {
1459
+ console.warn("[RecursoDisplayerVM] branchByBranchLevel/1 failed:", err);
1460
+ setBranches([]);
718
1461
  }
719
- };
720
- document.addEventListener("mousedown", handleClickOutside);
721
- return () => document.removeEventListener("mousedown", handleClickOutside);
722
- }, [backOnBranch, branch]);
723
- const handleItemClick = (bn) => {
724
- const rec = bn.recurso;
725
- if (multiMode) {
726
- setMultiSelected(
727
- (prev) => prev.some((r) => r.id === rec.id) ? prev.filter((r) => r.id !== rec.id) : [...prev, rec]
728
- );
729
- } else {
730
- onSaveRecurso([rec]);
731
- addBranch(bn);
732
- setShow(false);
1462
+ try {
1463
+ const lv = await branchLevelCtrl.readAll();
1464
+ dispatch(setLevels(Array.isArray(lv) ? lv : []));
1465
+ } catch (err) {
1466
+ console.warn("[RecursoDisplayerVM] branchLevel.readAll failed:", err);
1467
+ }
1468
+ } finally {
1469
+ setIsLoading(false);
733
1470
  }
734
- };
735
- const startMulti = () => {
736
- setMultiSelected([]);
737
- setMultiMode(true);
738
- setShow(true);
739
- };
740
- const handleConfirm = () => {
741
- setMultiMode(false);
742
- onSaveRecurso(multiSelected);
743
- setMultiSelected([]);
744
- setShow(false);
745
- };
746
- const cancelMulti = () => {
747
- setMultiMode(false);
748
- setMultiSelected([]);
749
- };
750
- const isLastBranchClicked = () => branches.length > 0 && branches[branches.length - 1].id === branch.id;
751
- const visibleNodes = (branch.branchNodes || []).filter(
752
- (bn) => bn.recurso.nome.toLowerCase().includes(searchTerm.toLowerCase())
753
- );
754
- return /* @__PURE__ */ jsxs(
755
- "div",
756
- {
757
- ref: dropdownRef,
758
- style: {
759
- position: "relative",
760
- marginBottom: "0.5rem",
761
- width: "100%",
762
- fontFamily: "Arial, sans-serif"
763
- },
764
- children: [
765
- /* @__PURE__ */ jsxs(
766
- "button",
767
- {
768
- onClick: () => setShow((s) => !s),
769
- style: {
770
- width: "100%",
771
- display: "flex",
772
- alignItems: "center",
773
- justifyContent: "space-between",
774
- padding: "0.5rem 1rem",
775
- borderRadius: "9999px",
776
- boxShadow: "0 1px 3px rgba(0, 0, 0, 0.1)",
777
- border: `1px solid ${branch.branchLevel.color}`,
778
- background: branch.branchLevel.color,
779
- color: fontColor,
780
- cursor: "pointer",
781
- outline: "none",
782
- textAlign: "left",
783
- fontSize: "1rem"
784
- },
785
- children: [
786
- /* @__PURE__ */ jsxs("span", { style: { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, children: [
787
- branch.nomeRecurso || branch.branchLevel.nome,
788
- branch.nomeRecurso && !multiMode && isLastBranchClicked() && /* @__PURE__ */ jsx("em", { style: { fontStyle: "italic", opacity: 0.8, marginLeft: "0.5rem" }, children: "(Selecionado)" })
789
- ] }),
790
- /* @__PURE__ */ jsx(FaChevronDown, {})
791
- ]
792
- }
793
- ),
794
- show && /* @__PURE__ */ jsxs(
795
- "div",
796
- {
797
- style: {
798
- position: "absolute",
799
- top: "100%",
800
- left: 0,
801
- width: "100%",
802
- background: "#f0f0f0",
803
- borderRadius: "8px",
804
- boxShadow: "0 2px 6px rgba(0, 0, 0, 0.15)",
805
- marginTop: "0.25rem",
806
- zIndex: 100,
807
- maxHeight: "300px",
808
- overflow: "auto"
809
- },
810
- children: [
811
- /* @__PURE__ */ jsxs(
812
- "div",
813
- {
814
- style: {
815
- display: "flex",
816
- alignItems: "center",
817
- padding: "0.5rem",
818
- borderBottom: "1px solid #ddd"
819
- },
820
- children: [
821
- /* @__PURE__ */ jsx(FaSearch, { style: { marginRight: "0.5rem", color: "#555" } }),
822
- /* @__PURE__ */ jsx(
823
- "input",
824
- {
825
- type: "text",
826
- placeholder: "Pesquisar recurso...",
827
- value: searchTerm,
828
- onChange: (e) => setSearchTerm(e.target.value),
829
- style: {
830
- flex: 1,
831
- padding: "0.5rem",
832
- border: "1px solid #ccc",
833
- borderRadius: "9999px",
834
- outline: "none",
835
- fontSize: "0.95rem"
836
- }
837
- }
838
- )
839
- ]
840
- }
841
- ),
842
- !multiMode && !singleReturn ? /* @__PURE__ */ jsxs(
843
- "button",
844
- {
845
- onClick: startMulti,
846
- style: {
847
- display: "flex",
848
- alignItems: "center",
849
- justifyContent: "center",
850
- width: "100%",
851
- padding: "0.5rem",
852
- borderRadius: "9999px",
853
- border: "none",
854
- background: "#ffc107",
855
- color: "#000",
856
- fontSize: "0.95rem",
857
- cursor: "pointer",
858
- margin: "0.5rem 0"
859
- },
860
- children: [
861
- /* @__PURE__ */ jsx(FaCheckSquare, { style: { marginRight: "0.5rem" } }),
862
- "Selecionar m\xFAltiplos"
863
- ]
864
- }
865
- ) : /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "0.5rem", margin: "0.5rem 0" }, children: [
866
- /* @__PURE__ */ jsxs(
867
- "button",
868
- {
869
- onClick: handleConfirm,
870
- style: {
871
- flex: 1,
872
- display: "flex",
873
- alignItems: "center",
874
- justifyContent: "center",
875
- padding: "0.5rem",
876
- borderRadius: "9999px",
877
- border: "none",
878
- background: "#28a745",
879
- color: "#fff",
880
- fontSize: "0.95rem",
881
- cursor: "pointer"
882
- },
883
- children: [
884
- /* @__PURE__ */ jsx(FaCheck, { style: { marginRight: "0.5rem" } }),
885
- "Confirmar sele\xE7\xE3o"
886
- ]
887
- }
888
- ),
889
- /* @__PURE__ */ jsxs(
890
- "button",
891
- {
892
- onClick: cancelMulti,
893
- style: {
894
- flex: 1,
895
- display: "flex",
896
- alignItems: "center",
897
- justifyContent: "center",
898
- padding: "0.5rem",
899
- borderRadius: "9999px",
900
- border: "none",
901
- background: "#6c757d",
902
- color: "#fff",
903
- fontSize: "0.95rem",
904
- cursor: "pointer"
905
- },
906
- children: [
907
- /* @__PURE__ */ jsx(MdClose, { style: { marginRight: "0.5rem" } }),
908
- "Cancelar"
909
- ]
910
- }
911
- )
912
- ] }),
913
- /* @__PURE__ */ jsx("div", { style: { padding: "0.5rem" }, children: visibleNodes.map((bn) => {
914
- const selected = multiMode ? multiSelected.some((r) => r.id === bn.recurso.id) : false;
915
- return /* @__PURE__ */ jsxs(
916
- "div",
917
- {
918
- onClick: () => handleItemClick(bn),
919
- style: {
920
- display: "flex",
921
- justifyContent: "space-between",
922
- alignItems: "center",
923
- padding: "0.5rem",
924
- borderBottom: "1px solid #ddd",
925
- background: selected ? "#e9ecef" : "transparent",
926
- cursor: "pointer",
927
- transition: "background 0.1s"
928
- },
929
- onMouseEnter: (e) => {
930
- if (!selected) e.currentTarget.style.background = "#e2e6ea";
931
- },
932
- onMouseLeave: (e) => {
933
- e.currentTarget.style.background = selected ? "#e9ecef" : "transparent";
934
- },
935
- children: [
936
- /* @__PURE__ */ jsx("span", { children: bn.recurso.nome }),
937
- selected && /* @__PURE__ */ jsx(FaCheck, {})
938
- ]
939
- },
940
- bn.recurso.id
941
- );
942
- }) })
943
- ]
1471
+ }, [arvoreCtrl, branchLevelCtrl, dispatch]);
1472
+ const advanceBranch = useCallback12(
1473
+ async (bn) => {
1474
+ var _a2, _b2, _c, _d;
1475
+ setIsLoading(true);
1476
+ try {
1477
+ const current = branchesRef.current;
1478
+ const parentBranch = current.find((b) => b.id === bn.branchId);
1479
+ const currentLevel = (_b2 = (_a2 = parentBranch == null ? void 0 : parentBranch.branchLevel) == null ? void 0 : _a2.level) != null ? _b2 : 1;
1480
+ const branchsToStay = current.filter((b) => {
1481
+ var _a3, _b3;
1482
+ return ((_b3 = (_a3 = b.branchLevel) == null ? void 0 : _a3.level) != null ? _b3 : 0) <= currentLevel;
1483
+ }).map(
1484
+ (b) => {
1485
+ var _a3;
1486
+ return ((_a3 = b.branchLevel) == null ? void 0 : _a3.level) === currentLevel ? { ...b, nomeRecurso: bn.recurso.nome } : b;
944
1487
  }
945
- )
946
- ]
947
- }
948
- );
949
- };
950
- var BranchDropDisplay_default = BranchDropDisplay;
951
-
952
- // src/components/recurso/FindRecursoByTagField.tsx
953
- import { useState as useState11 } from "react";
954
- import { GrCheckmark } from "react-icons/gr";
955
-
956
- // src/components/recurso/AutoComplete.tsx
957
- import { useEffect as useEffect4, useState as useState8 } from "react";
958
- import { FloatingLabel, Form, InputGroup, ListGroup } from "react-bootstrap";
959
- import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
960
- var AutoComplete = ({
961
- className,
962
- ops,
963
- sortKey,
964
- displayKey,
965
- displayKeys,
966
- onValueChanged,
967
- selectedKey,
968
- onSelectedClick,
969
- value,
970
- actionButton,
971
- actionButton2,
972
- placeH,
973
- title,
974
- filter,
975
- filterField,
976
- loadFunc,
977
- loadCondition,
978
- isBold,
979
- onBlurEvent,
980
- formatationFunc,
981
- onEscKeyDown,
982
- margT,
983
- hideComponent,
984
- disableComponent = false,
985
- disableSelect = false,
986
- margB,
987
- autoFocusConfig,
988
- onLoad,
989
- onMouseLv,
990
- useStandardLabel = false,
991
- isRequired = false,
992
- ty = "text"
993
- }) => {
994
- const [liItem, setListItem] = useState8([]);
995
- const [options, setOptions] = useState8([]);
996
- const [input, setInput] = useState8("");
997
- const [hide, setHide] = useState8(true);
998
- const [onLoaded, setOnLoaded] = useState8(false);
999
- const sortOptions = (opts, key) => {
1000
- if (!key || !Array.isArray(opts)) return opts != null ? opts : [];
1001
- return [...opts].sort((a, b) => String(a[key]).localeCompare(String(b[key])));
1002
- };
1003
- useEffect4(() => {
1004
- if (value) setInput(value);
1005
- else setInput("");
1006
- }, [value]);
1007
- useEffect4(() => {
1008
- const sortedOptions = sortOptions(ops, sortKey);
1009
- setListItem(sortedOptions);
1010
- setOptions(sortedOptions);
1011
- }, [ops, sortKey]);
1012
- useEffect4(() => {
1013
- const loadFunction = async () => {
1014
- if (loadCondition && loadFunc) {
1015
- try {
1016
- const res = await loadFunc();
1017
- let newOps = res.content ? res.content : res;
1018
- newOps = newOps.filter((c) => c != null);
1019
- if (Array.isArray(newOps)) {
1020
- if (filter) {
1021
- newOps = newOps.filter((op) => op[filterField] === filter);
1488
+ );
1489
+ const nextBranchId = (_d = bn.recurso.branchId) != null ? _d : (_c = bn.recurso.branch) == null ? void 0 : _c.id;
1490
+ if (nextBranchId) {
1491
+ try {
1492
+ const nextBranch = await arvoreCtrl.read("branch", nextBranchId);
1493
+ if (nextBranch && nextBranch.branchLevel) {
1494
+ branchsToStay.push(nextBranch);
1022
1495
  }
1023
- const sortedOptions = sortOptions(newOps, sortKey);
1024
- setListItem(sortedOptions);
1025
- setOptions(sortedOptions);
1496
+ } catch (e) {
1497
+ console.warn(
1498
+ "[RecursoDisplayerVM] Failed to fetch child branch:",
1499
+ e
1500
+ );
1026
1501
  }
1027
- if (onLoad) {
1028
- if (onLoaded) return;
1029
- setOnLoaded(true);
1030
- onLoad(newOps);
1031
- }
1032
- } catch (e) {
1033
- setListItem([]);
1034
1502
  }
1503
+ setBranches([...branchsToStay]);
1504
+ } finally {
1505
+ setIsLoading(false);
1035
1506
  }
1036
- };
1037
- loadFunction();
1038
- }, [loadCondition, filter, filterField, sortKey, onLoad]);
1039
- const onFieldUpdate = (val) => {
1040
- let newListItem;
1041
- if (val && val.length > 0) {
1042
- const regex = new RegExp(`${val}`, "i");
1043
- newListItem = options.filter((liI) => {
1044
- let textToTest;
1045
- if (formatationFunc) {
1046
- textToTest = formatationFunc(liI);
1047
- } else if (displayKey) {
1048
- textToTest = liI[displayKey];
1049
- } else if (displayKeys) {
1050
- textToTest = keysJoinner(liI);
1051
- } else {
1052
- textToTest = liI;
1507
+ },
1508
+ [arvoreCtrl]
1509
+ );
1510
+ const backToBranch = useCallback12((branch) => {
1511
+ setBranches(
1512
+ (prev) => prev.filter(
1513
+ (b) => {
1514
+ var _a2, _b2, _c, _d;
1515
+ return ((_b2 = (_a2 = b.branchLevel) == null ? void 0 : _a2.level) != null ? _b2 : 0) <= ((_d = (_c = branch.branchLevel) == null ? void 0 : _c.level) != null ? _d : 0);
1053
1516
  }
1054
- return regex.test(textToTest);
1055
- });
1056
- setListItem(newListItem);
1057
- } else {
1058
- setListItem(options);
1517
+ )
1518
+ );
1519
+ }, []);
1520
+ const reset = useCallback12(() => {
1521
+ setBranches([]);
1522
+ }, []);
1523
+ return useMemo7(
1524
+ () => ({
1525
+ branches,
1526
+ isLoading,
1527
+ loadInitialBranches,
1528
+ advanceBranch,
1529
+ backToBranch,
1530
+ reset
1531
+ }),
1532
+ [branches, isLoading, loadInitialBranches, advanceBranch, backToBranch, reset]
1533
+ );
1534
+ }
1535
+
1536
+ // src/viewmodels/ReduxFindRecursoByTagAdapter.ts
1537
+ import { useCallback as useCallback13, useMemo as useMemo8, useState as useState12 } from "react";
1538
+ function useFindRecursoByTagViewModel(overrides = {}) {
1539
+ var _a;
1540
+ const defaultRecurso = useHttpController("recurso");
1541
+ const recursoCtrl = (_a = overrides.recursoController) != null ? _a : defaultRecurso;
1542
+ const [isSearching, setIsSearching] = useState12(false);
1543
+ const loadActiveTags = useCallback13(async () => {
1544
+ try {
1545
+ const res = await recursoCtrl.get("findActiveRecursosTags");
1546
+ return Array.isArray(res) ? res : [];
1547
+ } catch (err) {
1548
+ console.warn("[FindRecursoByTagVM] loadActiveTags failed:", err);
1549
+ return [];
1059
1550
  }
1060
- onValueChanged && onValueChanged(val);
1061
- setInput(val);
1062
- setHide(false);
1063
- };
1064
- const clear = () => {
1065
- setInput("");
1066
- };
1067
- const onOpSelected = (li, index, lItem) => {
1068
- if (formatationFunc) {
1069
- setInput(formatationFunc(li));
1070
- } else if (displayKey) {
1071
- setInput(li[displayKey]);
1072
- } else if (displayKeys) {
1073
- setInput(keysJoinner(li));
1074
- } else {
1075
- setInput(li);
1551
+ }, [recursoCtrl]);
1552
+ const searchByTagId = useCallback13(
1553
+ async (tagId) => {
1554
+ setIsSearching(true);
1555
+ try {
1556
+ const r = await recursoCtrl.read("findRecursoByTagId", tagId);
1557
+ return r != null ? r : null;
1558
+ } catch (err) {
1559
+ console.error("[FindRecursoByTagVM] searchByTagId failed:", err);
1560
+ return null;
1561
+ } finally {
1562
+ setIsSearching(false);
1563
+ }
1564
+ },
1565
+ [recursoCtrl]
1566
+ );
1567
+ const searchByTag = useCallback13(
1568
+ async (description) => {
1569
+ setIsSearching(true);
1570
+ try {
1571
+ const formatted = description.replace(/\s/g, "");
1572
+ const r = await recursoCtrl.read(
1573
+ "recurso/findByTagDescription",
1574
+ formatted
1575
+ );
1576
+ return r != null ? r : null;
1577
+ } catch (err) {
1578
+ console.error("[FindRecursoByTagVM] searchByTag failed:", err);
1579
+ return null;
1580
+ } finally {
1581
+ setIsSearching(false);
1582
+ }
1583
+ },
1584
+ [recursoCtrl]
1585
+ );
1586
+ return useMemo8(
1587
+ () => ({
1588
+ isSearching,
1589
+ loadActiveTags,
1590
+ searchByTagId,
1591
+ searchByTag
1592
+ }),
1593
+ [isSearching, loadActiveTags, searchByTagId, searchByTag]
1594
+ );
1595
+ }
1596
+
1597
+ // src/viewmodels/ReduxJustificativaModalAdapter.ts
1598
+ import { useCallback as useCallback14, useEffect as useEffect4, useMemo as useMemo9, useRef as useRef3, useState as useState13 } from "react";
1599
+ function localId() {
1600
+ return `local_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
1601
+ }
1602
+ function runValidate3(draft) {
1603
+ const errors = {};
1604
+ if (!draft || !draft.trim()) {
1605
+ errors.draft = "Descreva o motivo antes de adicionar.";
1606
+ }
1607
+ return { ok: Object.keys(errors).length === 0, errors };
1608
+ }
1609
+ function useJustificativaModalViewModel(opts) {
1610
+ const { initialJustificativas = [], currentUser, onUpdate } = opts;
1611
+ const [justificativas, setJustificativas] = useState13(
1612
+ initialJustificativas
1613
+ );
1614
+ const [draft, setDraft] = useState13("");
1615
+ const [editingId, setEditingId] = useState13(null);
1616
+ const [isSubmitting, setIsSubmitting] = useState13(false);
1617
+ const initialRef = useRef3(initialJustificativas);
1618
+ useEffect4(() => {
1619
+ initialRef.current = initialJustificativas;
1620
+ setJustificativas(initialJustificativas);
1621
+ }, [initialJustificativas]);
1622
+ const commit = useCallback14(
1623
+ async (next) => {
1624
+ setJustificativas(next);
1625
+ if (!onUpdate) return next;
1626
+ try {
1627
+ const maybe = await Promise.resolve(onUpdate(next));
1628
+ if (Array.isArray(maybe)) {
1629
+ setJustificativas(maybe);
1630
+ return maybe;
1631
+ }
1632
+ } catch (e) {
1633
+ }
1634
+ return next;
1635
+ },
1636
+ [onUpdate]
1637
+ );
1638
+ const startEdit = useCallback14(
1639
+ (id) => {
1640
+ var _a;
1641
+ const target = justificativas.find((j) => j.id === id);
1642
+ if (!target || target.removed) return;
1643
+ setEditingId(id);
1644
+ setDraft((_a = target.descricao) != null ? _a : "");
1645
+ },
1646
+ [justificativas]
1647
+ );
1648
+ const cancelEdit = useCallback14(() => {
1649
+ setEditingId(null);
1650
+ setDraft("");
1651
+ }, []);
1652
+ const addOrEdit = useCallback14(async () => {
1653
+ const result = runValidate3(draft);
1654
+ if (!result.ok) return justificativas;
1655
+ setIsSubmitting(true);
1656
+ try {
1657
+ let next;
1658
+ if (editingId != null) {
1659
+ next = justificativas.map(
1660
+ (j) => j.id === editingId ? { ...j, descricao: draft } : j
1661
+ );
1662
+ } else {
1663
+ const nova = {
1664
+ id: localId(),
1665
+ descricao: draft,
1666
+ user: currentUser,
1667
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1668
+ isNew: true
1669
+ };
1670
+ next = [...justificativas, nova];
1671
+ }
1672
+ const committed = await commit(next);
1673
+ setDraft("");
1674
+ setEditingId(null);
1675
+ return committed;
1676
+ } finally {
1677
+ setIsSubmitting(false);
1076
1678
  }
1077
- onSelectedClick(li, index, lItem);
1078
- setHide(true);
1079
- };
1080
- const keysJoinner = (li) => {
1081
- if (!displayKeys || !Array.isArray(displayKeys)) return "";
1082
- const textToRender = displayKeys.map((key) => `${li[key]} `);
1083
- return textToRender.join("").trim();
1084
- };
1085
- const renderMoreThanOneKey = (li, index) => {
1086
- const buildedString = keysJoinner(li);
1087
- return /* @__PURE__ */ jsx2("li", { children: buildedString }, index);
1088
- };
1089
- const boldedPart = (text, key) => {
1090
- return /* @__PURE__ */ jsx2("li", { children: text }, key);
1091
- };
1092
- const displayListItens = (li, index) => {
1093
- if (formatationFunc) {
1094
- return boldedPart(formatationFunc(li), index);
1679
+ }, [draft, editingId, justificativas, currentUser, commit]);
1680
+ const remove = useCallback14(
1681
+ async (id) => {
1682
+ const next = justificativas.map(
1683
+ (j) => j.id === id ? { ...j, removed: true } : j
1684
+ );
1685
+ return commit(next);
1686
+ },
1687
+ [justificativas, commit]
1688
+ );
1689
+ const undoRemove = useCallback14(
1690
+ async (id) => {
1691
+ const next = justificativas.map(
1692
+ (j) => j.id === id ? { ...j, removed: false } : j
1693
+ );
1694
+ return commit(next);
1695
+ },
1696
+ [justificativas, commit]
1697
+ );
1698
+ const validate = useCallback14(
1699
+ () => runValidate3(draft),
1700
+ [draft]
1701
+ );
1702
+ const reset = useCallback14(() => {
1703
+ setJustificativas(initialRef.current);
1704
+ setDraft("");
1705
+ setEditingId(null);
1706
+ }, []);
1707
+ const populateFromExisting = useCallback14((list) => {
1708
+ initialRef.current = list;
1709
+ setJustificativas(list);
1710
+ setDraft("");
1711
+ setEditingId(null);
1712
+ }, []);
1713
+ return useMemo9(
1714
+ () => ({
1715
+ justificativas,
1716
+ draft,
1717
+ editingId,
1718
+ isSubmitting,
1719
+ setDraft,
1720
+ startEdit,
1721
+ cancelEdit,
1722
+ addOrEdit,
1723
+ remove,
1724
+ undoRemove,
1725
+ validate,
1726
+ reset,
1727
+ populateFromExisting
1728
+ }),
1729
+ [
1730
+ justificativas,
1731
+ draft,
1732
+ editingId,
1733
+ isSubmitting,
1734
+ startEdit,
1735
+ cancelEdit,
1736
+ addOrEdit,
1737
+ remove,
1738
+ undoRemove,
1739
+ validate,
1740
+ reset,
1741
+ populateFromExisting
1742
+ ]
1743
+ );
1744
+ }
1745
+
1746
+ // src/viewmodels/ReduxAnexoManagerAdapter.ts
1747
+ import { useMemo as useMemo10 } from "react";
1748
+ function useAnexoManagerViewModel(opts) {
1749
+ const base = useAnexoManager(opts);
1750
+ return useMemo10(
1751
+ () => ({
1752
+ persistidos: base.persistidos,
1753
+ locais: base.locais,
1754
+ loading: base.loading,
1755
+ loadAnexos: base.loadAnexos,
1756
+ addFiles: base.addFiles,
1757
+ removeLocal: base.removeLocal,
1758
+ uploadAll: base.uploadAll,
1759
+ removePersistido: base.removePersistido,
1760
+ getUrl: base.getUrl
1761
+ }),
1762
+ [
1763
+ base.persistidos,
1764
+ base.locais,
1765
+ base.loading,
1766
+ base.loadAnexos,
1767
+ base.addFiles,
1768
+ base.removeLocal,
1769
+ base.uploadAll,
1770
+ base.removePersistido,
1771
+ base.getUrl
1772
+ ]
1773
+ );
1774
+ }
1775
+
1776
+ // src/viewmodels/useRecorrenciaViewModel.ts
1777
+ import { useCallback as useCallback15, useMemo as useMemo11, useState as useState14 } from "react";
1778
+ import { useDispatch as useDispatch5, useSelector as useSelector5 } from "react-redux";
1779
+
1780
+ // src/viewmodels/recorrenciaSlice.ts
1781
+ import { createSlice as createSlice4 } from "@reduxjs/toolkit";
1782
+ var DEFAULT_KEY3 = "__default__";
1783
+ var initialState4 = {
1784
+ byEntity: {}
1785
+ };
1786
+ var keyOf3 = (entityId) => entityId === void 0 || entityId === null || entityId === "" ? DEFAULT_KEY3 : String(entityId);
1787
+ var ensureSlot = (state, key) => {
1788
+ const existing = state.byEntity[key];
1789
+ if (!existing) {
1790
+ const fresh = {
1791
+ valor: 1,
1792
+ escala: "day",
1793
+ dataInicio: void 0
1794
+ };
1795
+ state.byEntity[key] = fresh;
1796
+ return fresh;
1797
+ }
1798
+ return existing;
1799
+ };
1800
+ var recorrenciaSlice = createSlice4({
1801
+ name: "recorrenciaVm",
1802
+ initialState: initialState4,
1803
+ reducers: {
1804
+ setValor(state, action) {
1805
+ const key = keyOf3(action.payload.entityId);
1806
+ ensureSlot(state, key).valor = action.payload.value;
1807
+ },
1808
+ setEscala(state, action) {
1809
+ const key = keyOf3(action.payload.entityId);
1810
+ ensureSlot(state, key).escala = action.payload.value;
1811
+ },
1812
+ setDataInicio(state, action) {
1813
+ const key = keyOf3(action.payload.entityId);
1814
+ const next = action.payload.value;
1815
+ ensureSlot(state, key).dataInicio = next === null || next === void 0 || next === "" ? void 0 : next;
1816
+ },
1817
+ populate(state, action) {
1818
+ const key = keyOf3(action.payload.entityId);
1819
+ state.byEntity[key] = action.payload.value ? { ...action.payload.value } : null;
1820
+ },
1821
+ clearRecorrencia(state, action) {
1822
+ var _a;
1823
+ const key = keyOf3((_a = action.payload) == null ? void 0 : _a.entityId);
1824
+ state.byEntity[key] = null;
1095
1825
  }
1096
- if (displayKey) {
1097
- return boldedPart(li[displayKey], index);
1826
+ }
1827
+ });
1828
+ var {
1829
+ setValor: setRecorrenciaValor,
1830
+ setEscala: setRecorrenciaEscala,
1831
+ setDataInicio: setRecorrenciaDataInicio,
1832
+ populate: populateRecorrencia,
1833
+ clearRecorrencia
1834
+ } = recorrenciaSlice.actions;
1835
+ var selectRecorrencia = (state, entityId) => {
1836
+ var _a, _b;
1837
+ const key = keyOf3(entityId);
1838
+ const slice3 = (_a = state == null ? void 0 : state.recorrenciaVm) != null ? _a : state == null ? void 0 : state.recorrencia;
1839
+ const slot = (_b = slice3 == null ? void 0 : slice3.byEntity) == null ? void 0 : _b[key];
1840
+ return slot === void 0 ? null : slot;
1841
+ };
1842
+ var recorrenciaSlice_default = recorrenciaSlice.reducer;
1843
+
1844
+ // src/viewmodels/useRecorrenciaViewModel.ts
1845
+ function runValidate4(value) {
1846
+ const errors = {};
1847
+ if (value === null) {
1848
+ errors._absent = "Sem recorrencia definida.";
1849
+ return { ok: false, errors };
1850
+ }
1851
+ const valor = Number(value.valor);
1852
+ if (!Number.isFinite(valor) || valor < 1) {
1853
+ errors.valor = "O valor da recorrencia deve ser >= 1.";
1854
+ }
1855
+ if (!value.escala) {
1856
+ errors.escala = "A escala eh obrigatoria.";
1857
+ }
1858
+ return { ok: Object.keys(errors).length === 0, errors };
1859
+ }
1860
+ function useRecorrenciaViewModel(entityId) {
1861
+ const dispatch = useDispatch5();
1862
+ const value = useSelector5(
1863
+ (state) => selectRecorrencia(state, entityId)
1864
+ );
1865
+ const [isSubmitting, setIsSubmitting] = useState14(false);
1866
+ const onValorChange = useCallback15(
1867
+ (valor) => {
1868
+ dispatch(setRecorrenciaValor({ entityId, value: valor }));
1869
+ },
1870
+ [dispatch, entityId]
1871
+ );
1872
+ const onEscalaChange = useCallback15(
1873
+ (escala) => {
1874
+ dispatch(setRecorrenciaEscala({ entityId, value: escala }));
1875
+ },
1876
+ [dispatch, entityId]
1877
+ );
1878
+ const onDataInicioChange = useCallback15(
1879
+ (dataInicio) => {
1880
+ dispatch(setRecorrenciaDataInicio({ entityId, value: dataInicio }));
1881
+ },
1882
+ [dispatch, entityId]
1883
+ );
1884
+ const clear = useCallback15(() => {
1885
+ dispatch(clearRecorrencia({ entityId }));
1886
+ }, [dispatch, entityId]);
1887
+ const populateFromExisting = useCallback15(
1888
+ (next) => {
1889
+ dispatch(populateRecorrencia({ entityId, value: next }));
1890
+ },
1891
+ [dispatch, entityId]
1892
+ );
1893
+ const validate = useCallback15(
1894
+ () => runValidate4(value),
1895
+ [value]
1896
+ );
1897
+ const submit = useCallback15(async () => {
1898
+ var _a;
1899
+ setIsSubmitting(true);
1900
+ try {
1901
+ if (value === null) return null;
1902
+ const result = runValidate4(value);
1903
+ if (!result.ok) {
1904
+ const firstErr = (_a = Object.values(result.errors)[0]) != null ? _a : "Dados invalidos.";
1905
+ throw new Error(firstErr);
1906
+ }
1907
+ return value;
1908
+ } finally {
1909
+ setIsSubmitting(false);
1098
1910
  }
1099
- if (displayKeys) {
1100
- return renderMoreThanOneKey(li, index);
1911
+ }, [value]);
1912
+ const isValid = useMemo11(() => runValidate4(value).ok, [value]);
1913
+ return useMemo11(
1914
+ () => ({
1915
+ value,
1916
+ isValid,
1917
+ isSubmitting,
1918
+ onValorChange,
1919
+ onEscalaChange,
1920
+ onDataInicioChange,
1921
+ clear,
1922
+ populateFromExisting,
1923
+ validate,
1924
+ submit,
1925
+ reset: clear
1926
+ }),
1927
+ [
1928
+ value,
1929
+ isValid,
1930
+ isSubmitting,
1931
+ onValorChange,
1932
+ onEscalaChange,
1933
+ onDataInicioChange,
1934
+ clear,
1935
+ populateFromExisting,
1936
+ validate,
1937
+ submit
1938
+ ]
1939
+ );
1940
+ }
1941
+
1942
+ // src/viewmodels/useContadorViewModel.ts
1943
+ import { useCallback as useCallback16, useMemo as useMemo12, useState as useState15 } from "react";
1944
+ import { useDispatch as useDispatch6, useSelector as useSelector6 } from "react-redux";
1945
+
1946
+ // src/viewmodels/contadorSlice.ts
1947
+ import { createSlice as createSlice5 } from "@reduxjs/toolkit";
1948
+ var DEFAULT_KEY4 = "__default__";
1949
+ var emptyValue3 = {
1950
+ valor: null,
1951
+ unidade: null,
1952
+ parametro: null,
1953
+ limitesDeControle: []
1954
+ };
1955
+ var initialState5 = {
1956
+ byEntity: {}
1957
+ };
1958
+ var keyOf4 = (entityId) => entityId === void 0 || entityId === null || entityId === "" ? DEFAULT_KEY4 : String(entityId);
1959
+ var ensure3 = (state, key) => {
1960
+ if (!state.byEntity[key]) {
1961
+ state.byEntity[key] = { ...emptyValue3, limitesDeControle: [] };
1962
+ }
1963
+ return state.byEntity[key];
1964
+ };
1965
+ var contadorSlice = createSlice5({
1966
+ name: "contadorVm",
1967
+ initialState: initialState5,
1968
+ reducers: {
1969
+ setValor(state, action) {
1970
+ ensure3(state, keyOf4(action.payload.entityId)).valor = action.payload.value;
1971
+ },
1972
+ setUnidade(state, action) {
1973
+ ensure3(state, keyOf4(action.payload.entityId)).unidade = action.payload.value;
1974
+ },
1975
+ setParametro(state, action) {
1976
+ ensure3(state, keyOf4(action.payload.entityId)).parametro = action.payload.value;
1977
+ },
1978
+ addLimite(state, action) {
1979
+ var _a;
1980
+ const slot = ensure3(state, keyOf4(action.payload.entityId));
1981
+ slot.limitesDeControle = [
1982
+ ...(_a = slot.limitesDeControle) != null ? _a : [],
1983
+ action.payload.value
1984
+ ];
1985
+ },
1986
+ removeLimiteAt(state, action) {
1987
+ var _a;
1988
+ const slot = ensure3(state, keyOf4(action.payload.entityId));
1989
+ const list = (_a = slot.limitesDeControle) != null ? _a : [];
1990
+ slot.limitesDeControle = list.filter(
1991
+ (_, i) => i !== action.payload.index
1992
+ );
1993
+ },
1994
+ updateLimiteAt(state, action) {
1995
+ var _a;
1996
+ const slot = ensure3(state, keyOf4(action.payload.entityId));
1997
+ const list = [...(_a = slot.limitesDeControle) != null ? _a : []];
1998
+ if (action.payload.index >= 0 && action.payload.index < list.length) {
1999
+ list[action.payload.index] = action.payload.value;
2000
+ slot.limitesDeControle = list;
2001
+ }
2002
+ },
2003
+ populate(state, action) {
2004
+ var _a;
2005
+ const key = keyOf4(action.payload.entityId);
2006
+ const v = (_a = action.payload.value) != null ? _a : emptyValue3;
2007
+ state.byEntity[key] = {
2008
+ ...emptyValue3,
2009
+ ...v,
2010
+ limitesDeControle: Array.isArray(v.limitesDeControle) ? [...v.limitesDeControle] : []
2011
+ };
2012
+ },
2013
+ clearContador(state, action) {
2014
+ var _a;
2015
+ const key = keyOf4((_a = action.payload) == null ? void 0 : _a.entityId);
2016
+ state.byEntity[key] = { ...emptyValue3, limitesDeControle: [] };
1101
2017
  }
1102
- return boldedPart(li, index);
2018
+ }
2019
+ });
2020
+ var {
2021
+ setValor: setContadorValor,
2022
+ setUnidade: setContadorUnidade,
2023
+ setParametro: setContadorParametro,
2024
+ addLimite: addContadorLimite,
2025
+ removeLimiteAt: removeContadorLimiteAt,
2026
+ updateLimiteAt: updateContadorLimiteAt,
2027
+ populate: populateContador,
2028
+ clearContador
2029
+ } = contadorSlice.actions;
2030
+ var selectContador = (state, entityId) => {
2031
+ var _a, _b, _c;
2032
+ const key = keyOf4(entityId);
2033
+ const slice3 = (_a = state == null ? void 0 : state.contadorVm) != null ? _a : state == null ? void 0 : state.contador;
2034
+ return (_c = (_b = slice3 == null ? void 0 : slice3.byEntity) == null ? void 0 : _b[key]) != null ? _c : {
2035
+ ...emptyValue3,
2036
+ limitesDeControle: []
1103
2037
  };
1104
- const onKeyDownHandler = (event) => {
1105
- if (event.key === "Escape") {
1106
- setHide(true);
1107
- onEscKeyDown && onEscKeyDown();
2038
+ };
2039
+ var contadorSlice_default = contadorSlice.reducer;
2040
+
2041
+ // src/viewmodels/useContadorViewModel.ts
2042
+ function runValidate5(value) {
2043
+ var _a;
2044
+ const errors = {};
2045
+ if ((value == null ? void 0 : value.valor) !== null && (value == null ? void 0 : value.valor) !== void 0) {
2046
+ if (!Number.isFinite(Number(value.valor))) {
2047
+ errors.valor = "O valor deve ser um n\xFAmero finito.";
1108
2048
  }
1109
- };
1110
- return /* @__PURE__ */ jsxs2(
1111
- "div",
1112
- {
1113
- className: `${className}`,
1114
- style: { marginTop: margT || 4, marginBottom: margB || 4, position: "relative" },
1115
- onBlur: (e) => {
1116
- setTimeout(() => {
1117
- if (onBlurEvent) onBlurEvent(e, input);
1118
- setHide(true);
1119
- }, 200);
1120
- },
1121
- onKeyDown: (event) => onKeyDownHandler(event),
1122
- onMouseLeave: () => {
1123
- setHide(true);
1124
- },
1125
- children: [
1126
- !hideComponent && /* @__PURE__ */ jsxs2(Fragment, { children: [
1127
- useStandardLabel && title && /* @__PURE__ */ jsxs2(Form.Label, { children: [
1128
- title,
1129
- isRequired && " *"
1130
- ] }),
1131
- /* @__PURE__ */ jsxs2(InputGroup, { children: [
1132
- useStandardLabel ? /* @__PURE__ */ jsx2(
1133
- Form.Control,
1134
- {
1135
- autoFocus: autoFocusConfig,
1136
- disabled: disableComponent || disableSelect,
1137
- placeholder: placeH,
1138
- autoComplete: "off",
1139
- value: input,
1140
- onClickCapture: () => {
1141
- setHide(false);
1142
- if (!input) {
1143
- onFieldUpdate("");
1144
- }
1145
- },
1146
- onChange: (event) => onFieldUpdate(event.currentTarget.value),
1147
- type: "text"
1148
- }
1149
- ) : /* @__PURE__ */ jsx2(FloatingLabel, { style: { zIndex: 0 }, label: title, controlId: "floatingInput", children: /* @__PURE__ */ jsx2(
1150
- Form.Control,
1151
- {
1152
- autoFocus: autoFocusConfig,
1153
- disabled: disableComponent || disableSelect,
1154
- placeholder: placeH,
1155
- autoComplete: "off",
1156
- value: input,
1157
- onClickCapture: () => {
1158
- setHide(false);
1159
- if (!input) {
1160
- onFieldUpdate("");
1161
- }
1162
- },
1163
- onChange: (event) => onFieldUpdate(event.currentTarget.value),
1164
- type: "text"
1165
- }
1166
- ) }),
1167
- !disableComponent && actionButton && actionButton(clear),
1168
- !disableComponent && actionButton2 && actionButton2(input)
1169
- ] })
1170
- ] }),
1171
- liItem && /* @__PURE__ */ jsx2(ListGroup, { className: "listgroup-autocomplete", hidden: hide, children: liItem.map((li, index) => /* @__PURE__ */ jsx2(ListGroup.Item, { action: true, onClick: () => onOpSelected(li, index, liItem), children: displayListItens(li, index) }, index)) })
1172
- ]
2049
+ }
2050
+ if ((value == null ? void 0 : value.valor) !== null && (value == null ? void 0 : value.valor) !== void 0 && (!value.unidade || String(value.unidade).trim() === "")) {
2051
+ errors.unidade = "Informe a unidade de medida.";
2052
+ }
2053
+ const limites = (_a = value == null ? void 0 : value.limitesDeControle) != null ? _a : [];
2054
+ limites.forEach((l, idx) => {
2055
+ if (!(l == null ? void 0 : l.nome) || String(l.nome).trim() === "") {
2056
+ errors[`limitesDeControle[${idx}].nome`] = "Nome do limite \xE9 obrigat\xF3rio.";
2057
+ }
2058
+ if (!(l == null ? void 0 : l.boundRule)) {
2059
+ errors[`limitesDeControle[${idx}].boundRule`] = "Regra de compara\xE7\xE3o \xE9 obrigat\xF3ria.";
1173
2060
  }
2061
+ const v = Number(l == null ? void 0 : l.valor);
2062
+ if (!Number.isFinite(v)) {
2063
+ errors[`limitesDeControle[${idx}].valor`] = "Valor do limite deve ser num\xE9rico.";
2064
+ }
2065
+ });
2066
+ return { ok: Object.keys(errors).length === 0, errors };
2067
+ }
2068
+ function useContadorViewModel(entityId) {
2069
+ const dispatch = useDispatch6();
2070
+ const value = useSelector6(
2071
+ (state) => selectContador(state, entityId)
1174
2072
  );
1175
- };
1176
- var AutoComplete_default = AutoComplete;
2073
+ const [isSubmitting, setIsSubmitting] = useState15(false);
2074
+ const onValorChange = useCallback16(
2075
+ (v) => {
2076
+ dispatch(setContadorValor({ entityId, value: v }));
2077
+ },
2078
+ [dispatch, entityId]
2079
+ );
2080
+ const onUnidadeChange = useCallback16(
2081
+ (u) => {
2082
+ dispatch(setContadorUnidade({ entityId, value: u }));
2083
+ },
2084
+ [dispatch, entityId]
2085
+ );
2086
+ const onParametroChange = useCallback16(
2087
+ (p) => {
2088
+ dispatch(setContadorParametro({ entityId, value: p }));
2089
+ },
2090
+ [dispatch, entityId]
2091
+ );
2092
+ const onLimiteAdd = useCallback16(
2093
+ (limite) => {
2094
+ dispatch(addContadorLimite({ entityId, value: limite }));
2095
+ },
2096
+ [dispatch, entityId]
2097
+ );
2098
+ const onLimiteRemove = useCallback16(
2099
+ (index) => {
2100
+ dispatch(removeContadorLimiteAt({ entityId, index }));
2101
+ },
2102
+ [dispatch, entityId]
2103
+ );
2104
+ const onLimiteUpdate = useCallback16(
2105
+ (index, limite) => {
2106
+ dispatch(updateContadorLimiteAt({ entityId, index, value: limite }));
2107
+ },
2108
+ [dispatch, entityId]
2109
+ );
2110
+ const validate = useCallback16(
2111
+ () => runValidate5(value),
2112
+ [value]
2113
+ );
2114
+ const reset = useCallback16(() => {
2115
+ dispatch(clearContador({ entityId }));
2116
+ }, [dispatch, entityId]);
2117
+ const populateFromExisting = useCallback16(
2118
+ (next) => {
2119
+ dispatch(populateContador({ entityId, value: next }));
2120
+ },
2121
+ [dispatch, entityId]
2122
+ );
2123
+ const submit = useCallback16(async () => {
2124
+ var _a;
2125
+ setIsSubmitting(true);
2126
+ try {
2127
+ const result = runValidate5(value);
2128
+ if (!result.ok) {
2129
+ const firstErr = (_a = Object.values(result.errors)[0]) != null ? _a : "Dados inv\xE1lidos.";
2130
+ throw new Error(firstErr);
2131
+ }
2132
+ return value;
2133
+ } finally {
2134
+ setIsSubmitting(false);
2135
+ }
2136
+ }, [value]);
2137
+ const isValid = useMemo12(() => runValidate5(value).ok, [value]);
2138
+ return useMemo12(
2139
+ () => ({
2140
+ value,
2141
+ isValid,
2142
+ isSubmitting,
2143
+ onValorChange,
2144
+ onUnidadeChange,
2145
+ onParametroChange,
2146
+ onLimiteAdd,
2147
+ onLimiteRemove,
2148
+ onLimiteUpdate,
2149
+ validate,
2150
+ submit,
2151
+ reset,
2152
+ populateFromExisting
2153
+ }),
2154
+ [
2155
+ value,
2156
+ isValid,
2157
+ isSubmitting,
2158
+ onValorChange,
2159
+ onUnidadeChange,
2160
+ onParametroChange,
2161
+ onLimiteAdd,
2162
+ onLimiteRemove,
2163
+ onLimiteUpdate,
2164
+ validate,
2165
+ submit,
2166
+ reset,
2167
+ populateFromExisting
2168
+ ]
2169
+ );
2170
+ }
1177
2171
 
1178
- // src/components/recurso/QrCodeScanButton.tsx
1179
- import { useState as useState10 } from "react";
1180
- import { BsQrCode } from "react-icons/bs";
2172
+ // src/viewmodels/useMantenedorPickerViewModel.ts
2173
+ import { useCallback as useCallback17, useEffect as useEffect5, useMemo as useMemo13 } from "react";
2174
+ import { useDispatch as useDispatch7, useSelector as useSelector7 } from "react-redux";
1181
2175
 
1182
- // src/components/recurso/QrReader.tsx
1183
- import QrScanner from "qr-scanner";
1184
- import { useEffect as useEffect5, useRef as useRef3, useState as useState9 } from "react";
1185
- import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
1186
- var QrReader = ({ callback }) => {
1187
- const scanner = useRef3(null);
1188
- const videoEl = useRef3(null);
1189
- const qrBoxEl = useRef3(null);
1190
- const [qrOn, setQrOn] = useState9(true);
1191
- const [scannedResult, setScannedResult] = useState9("");
1192
- const onScanSuccess = (result) => {
1193
- setScannedResult(result == null ? void 0 : result.data);
1194
- callback(result == null ? void 0 : result.data);
1195
- };
1196
- const onScanFail = (err) => {
1197
- console.error(err);
1198
- };
1199
- useEffect5(() => {
1200
- if ((videoEl == null ? void 0 : videoEl.current) && !scanner.current) {
1201
- scanner.current = new QrScanner(videoEl.current, onScanSuccess, {
1202
- onDecodeError: onScanFail,
1203
- preferredCamera: "environment",
1204
- highlightScanRegion: true,
1205
- highlightCodeOutline: true,
1206
- overlay: (qrBoxEl == null ? void 0 : qrBoxEl.current) || void 0
1207
- });
1208
- scanner.current.start().then(() => setQrOn(true)).catch((err) => {
1209
- if (err) setQrOn(false);
1210
- });
2176
+ // src/viewmodels/mantenedorPickerSlice.ts
2177
+ import { createSlice as createSlice6 } from "@reduxjs/toolkit";
2178
+ var initialState6 = { byEntity: {} };
2179
+ function ensureSlot2(state, key) {
2180
+ if (!state.byEntity[key]) {
2181
+ state.byEntity[key] = {
2182
+ options: [],
2183
+ searchTerm: "",
2184
+ isLoading: false,
2185
+ error: null,
2186
+ pendingConfirm: null
2187
+ };
2188
+ }
2189
+ return state.byEntity[key];
2190
+ }
2191
+ var slice = createSlice6({
2192
+ name: "mantenedorPicker",
2193
+ initialState: initialState6,
2194
+ reducers: {
2195
+ setOptions(state, action) {
2196
+ ensureSlot2(state, action.payload.key).options = action.payload.options;
2197
+ },
2198
+ setSearchTerm(state, action) {
2199
+ ensureSlot2(state, action.payload.key).searchTerm = action.payload.term;
2200
+ },
2201
+ setLoading(state, action) {
2202
+ ensureSlot2(state, action.payload.key).isLoading = action.payload.loading;
2203
+ },
2204
+ setError(state, action) {
2205
+ ensureSlot2(state, action.payload.key).error = action.payload.error;
2206
+ },
2207
+ setPendingConfirm(state, action) {
2208
+ ensureSlot2(state, action.payload.key).pendingConfirm = action.payload.item;
2209
+ },
2210
+ clearSlot(state, action) {
2211
+ delete state.byEntity[action.payload.key];
1211
2212
  }
1212
- return () => {
1213
- var _a;
1214
- if (!(videoEl == null ? void 0 : videoEl.current)) {
1215
- (_a = scanner == null ? void 0 : scanner.current) == null ? void 0 : _a.stop();
2213
+ }
2214
+ });
2215
+ var {
2216
+ setOptions: setMantenedorOptions,
2217
+ setSearchTerm: setMantenedorSearchTerm,
2218
+ setLoading: setMantenedorLoading,
2219
+ setError: setMantenedorError,
2220
+ setPendingConfirm: setMantenedorPendingConfirm,
2221
+ clearSlot: clearMantenedorSlot
2222
+ } = slice.actions;
2223
+ var mantenedorPickerSlice_default = slice.reducer;
2224
+
2225
+ // src/viewmodels/useMantenedorPickerViewModel.ts
2226
+ var DEFAULT_KEY5 = "__default__";
2227
+ function useMantenedorPickerViewModel(entityId) {
2228
+ var _a, _b, _c, _d, _e;
2229
+ const key = entityId != null && entityId !== "" ? String(entityId) : DEFAULT_KEY5;
2230
+ const dispatch = useDispatch7();
2231
+ const core = useCoreService();
2232
+ const slot = useSelector7(
2233
+ (s) => {
2234
+ var _a2, _b2;
2235
+ return (_b2 = (_a2 = s.mantenedorPicker) == null ? void 0 : _a2.byEntity[key]) != null ? _b2 : null;
2236
+ }
2237
+ );
2238
+ const options = (_a = slot == null ? void 0 : slot.options) != null ? _a : [];
2239
+ const searchTerm = (_b = slot == null ? void 0 : slot.searchTerm) != null ? _b : "";
2240
+ const isLoading = (_c = slot == null ? void 0 : slot.isLoading) != null ? _c : false;
2241
+ const error = (_d = slot == null ? void 0 : slot.error) != null ? _d : null;
2242
+ const pendingConfirm = (_e = slot == null ? void 0 : slot.pendingConfirm) != null ? _e : null;
2243
+ const refresh = useCallback17(async () => {
2244
+ var _a2;
2245
+ dispatch(setMantenedorLoading({ key, loading: true }));
2246
+ dispatch(setMantenedorError({ key, error: null }));
2247
+ try {
2248
+ const controller = core.createController("mantenedor");
2249
+ const raw = await controller.get("mantenedorDashboard");
2250
+ const list = Array.isArray(raw) ? raw : Array.isArray(raw == null ? void 0 : raw.content) ? raw.content : Array.isArray(raw == null ? void 0 : raw.data) ? raw.data : Array.isArray(raw == null ? void 0 : raw.items) ? raw.items : [];
2251
+ if (typeof window !== "undefined" && window.__DEV__ !== false) {
2252
+ console.debug(
2253
+ `[MantenedorPickerVM] refresh key="${key}" \u2192 ${list.length} options`,
2254
+ { rawType: Array.isArray(raw) ? "array" : typeof raw }
2255
+ );
1216
2256
  }
1217
- };
1218
- }, []);
1219
- useEffect5(() => {
1220
- if (!qrOn)
1221
- alert(
1222
- "Camera est\xE1 bloqueada ou inacess\xEDvel. Por Favor habilite a camera nas permiss\xF5es do seu navegador e recarregue a p\xE1gina."
2257
+ dispatch(setMantenedorOptions({ key, options: list }));
2258
+ } catch (e) {
2259
+ if (typeof window !== "undefined" && window.__DEV__ !== false) {
2260
+ console.error("[MantenedorPickerVM] refresh failed", e);
2261
+ }
2262
+ dispatch(
2263
+ setMantenedorError({ key, error: (_a2 = e == null ? void 0 : e.message) != null ? _a2 : "fetch error" })
1223
2264
  );
1224
- }, [qrOn]);
1225
- return /* @__PURE__ */ jsxs3("div", { className: "qr-reader", children: [
1226
- /* @__PURE__ */ jsx3("video", { ref: videoEl }),
1227
- /* @__PURE__ */ jsx3("div", { ref: qrBoxEl, className: "qr-box" }),
1228
- scannedResult && /* @__PURE__ */ jsxs3(
1229
- "p",
1230
- {
1231
- style: {
1232
- position: "absolute",
1233
- top: 0,
1234
- left: 0,
1235
- zIndex: 99999,
1236
- color: "white"
1237
- },
1238
- children: [
1239
- "Scanned Result: ",
1240
- scannedResult
1241
- ]
2265
+ } finally {
2266
+ dispatch(setMantenedorLoading({ key, loading: false }));
2267
+ }
2268
+ }, [dispatch, key, core]);
2269
+ useEffect5(() => {
2270
+ refresh();
2271
+ }, [key]);
2272
+ const search = useCallback17(
2273
+ (term) => {
2274
+ dispatch(setMantenedorSearchTerm({ key, term }));
2275
+ },
2276
+ [dispatch, key]
2277
+ );
2278
+ const requestSelect = useCallback17(
2279
+ (item, currentOsId) => {
2280
+ if (item._busy && item.osId != null && item.osId !== currentOsId) {
2281
+ dispatch(setMantenedorPendingConfirm({ key, item }));
2282
+ return "confirm";
1242
2283
  }
1243
- )
1244
- ] });
1245
- };
1246
- var QrReader_default = QrReader;
2284
+ return "immediate";
2285
+ },
2286
+ [dispatch, key]
2287
+ );
2288
+ const confirmSelect = useCallback17(() => {
2289
+ const item = pendingConfirm;
2290
+ dispatch(setMantenedorPendingConfirm({ key, item: null }));
2291
+ return item;
2292
+ }, [dispatch, key, pendingConfirm]);
2293
+ const cancelConfirm = useCallback17(() => {
2294
+ dispatch(setMantenedorPendingConfirm({ key, item: null }));
2295
+ }, [dispatch, key]);
2296
+ const reset = useCallback17(() => {
2297
+ dispatch(clearMantenedorSlot({ key }));
2298
+ }, [dispatch, key]);
2299
+ const filteredOptions = useMemo13(() => {
2300
+ const term = searchTerm.toLowerCase();
2301
+ return [...options].filter(
2302
+ (o) => {
2303
+ var _a2;
2304
+ return ((_a2 = o.nomeUsuario) != null ? _a2 : "").toLowerCase().includes(term);
2305
+ }
2306
+ ).sort(
2307
+ (a, b) => {
2308
+ var _a2, _b2;
2309
+ return ((_a2 = a.nomeUsuario) != null ? _a2 : "").toLowerCase().localeCompare(((_b2 = b.nomeUsuario) != null ? _b2 : "").toLowerCase());
2310
+ }
2311
+ );
2312
+ }, [options, searchTerm]);
2313
+ return useMemo13(
2314
+ () => ({
2315
+ options,
2316
+ filteredOptions,
2317
+ searchTerm,
2318
+ isLoading,
2319
+ error,
2320
+ pendingConfirm,
2321
+ search,
2322
+ refresh,
2323
+ requestSelect,
2324
+ confirmSelect,
2325
+ cancelConfirm,
2326
+ reset
2327
+ }),
2328
+ [
2329
+ options,
2330
+ filteredOptions,
2331
+ searchTerm,
2332
+ isLoading,
2333
+ error,
2334
+ pendingConfirm,
2335
+ search,
2336
+ refresh,
2337
+ requestSelect,
2338
+ confirmSelect,
2339
+ cancelConfirm,
2340
+ reset
2341
+ ]
2342
+ );
2343
+ }
1247
2344
 
1248
- // src/components/recurso/QrCodeScanButton.tsx
1249
- import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
1250
- var QrCodeScanButton = ({ callback }) => {
1251
- const [showQr, setShowQr] = useState10(false);
1252
- const qrShowHandler = () => {
1253
- setShowQr((prev) => !prev);
1254
- };
1255
- return /* @__PURE__ */ jsxs4(
1256
- "div",
1257
- {
1258
- className: "hoverable-div",
1259
- style: {
1260
- border: "solid",
1261
- borderTopRightRadius: "3px",
1262
- borderBottomRightRadius: "3px",
1263
- padding: "8px",
1264
- borderLeft: "none",
1265
- borderColor: "#ccc",
1266
- borderWidth: "1px"
1267
- },
1268
- children: [
1269
- showQr && /* @__PURE__ */ jsx4(
1270
- QrReader_default,
1271
- {
1272
- callback: (v) => {
1273
- qrShowHandler();
1274
- callback(v);
1275
- }
1276
- }
1277
- ),
1278
- /* @__PURE__ */ jsx4(
1279
- BsQrCode,
1280
- {
1281
- size: 25,
1282
- onClick: () => {
1283
- qrShowHandler();
1284
- }
1285
- }
1286
- )
1287
- ]
2345
+ // src/viewmodels/ReduxTarefaStatusAdapter.ts
2346
+ import { useCallback as useCallback18, useMemo as useMemo14, useState as useState16 } from "react";
2347
+ function useTarefaStatusViewModel(opts) {
2348
+ const { tarefaId, fatherId, initialStatus = "PENDENTE" } = opts;
2349
+ const { createController } = useCoreService();
2350
+ const toast = useToast();
2351
+ const [current, setCurrent] = useState16(initialStatus);
2352
+ const [saving, setSaving] = useState16(false);
2353
+ const tarefaCtrl = useMemo14(
2354
+ () => createController("tarefa"),
2355
+ [createController]
2356
+ );
2357
+ const toggle = useCallback18(async () => {
2358
+ if (saving) return;
2359
+ const previous = current;
2360
+ const next = previous === "ENCERRADO" ? "PENDENTE" : "ENCERRADO";
2361
+ setCurrent(next);
2362
+ setSaving(true);
2363
+ try {
2364
+ const body = {
2365
+ status: next
2366
+ };
2367
+ if (fatherId !== void 0 && fatherId !== null) {
2368
+ body.fatherId = fatherId;
2369
+ }
2370
+ await tarefaCtrl.put(String(tarefaId), body);
2371
+ } catch (err) {
2372
+ setCurrent(previous);
2373
+ const msg = (err == null ? void 0 : err.message) || "Nao foi possivel atualizar o status da tarefa.";
2374
+ try {
2375
+ toast.warning(msg);
2376
+ } catch (e) {
2377
+ }
2378
+ } finally {
2379
+ setSaving(false);
1288
2380
  }
2381
+ }, [saving, current, tarefaCtrl, tarefaId, fatherId, toast]);
2382
+ return useMemo14(
2383
+ () => ({ current, toggle, saving }),
2384
+ [current, toggle, saving]
1289
2385
  );
1290
- };
1291
- var QrCodeScanButton_default = QrCodeScanButton;
2386
+ }
1292
2387
 
1293
- // src/components/recurso/FindRecursoByTagField.tsx
1294
- import { jsx as jsx5 } from "react/jsx-runtime";
1295
- var FindRecursoByTagField = ({ callback }) => {
1296
- const recursoController = useHttpController("recurso");
1297
- const [selectedTag, setSelectedTag] = useState11(null);
1298
- const [reachedRecurso, setReachedRecurso] = useState11(null);
1299
- const findRecursoByTagIdHandler = async (tagId) => {
1300
- const r = await recursoController.read("findRecursoByTagId", tagId);
1301
- setReachedRecurso(r);
1302
- };
1303
- const findRecursoByTagDescriptionHandler = async (description) => {
1304
- const recurso = await recursoController.read(
1305
- "recurso/findByTagDescription",
1306
- description.replace(" ", "")
1307
- );
1308
- if (!callback) {
1309
- console.log(recurso);
1310
- } else {
1311
- callback(recurso, true);
1312
- }
1313
- };
1314
- const confirmRecursoSelectionButton = () => /* @__PURE__ */ jsx5(
1315
- "div",
1316
- {
1317
- className: "hoverable-div",
1318
- style: {
1319
- border: "solid",
1320
- borderTopRightRadius: "3px",
1321
- borderBottomRightRadius: "3px",
1322
- padding: "8px",
1323
- borderLeft: "none",
1324
- borderColor: "#ccc",
1325
- borderWidth: "1px"
1326
- },
1327
- children: /* @__PURE__ */ jsx5(GrCheckmark, { size: 25, onClick: () => callback(reachedRecurso, true) })
1328
- }
2388
+ // src/viewmodels/ReduxObservacoesTarefaAdapter.ts
2389
+ import { useCallback as useCallback19, useMemo as useMemo15, useState as useState17 } from "react";
2390
+ function useObservacoesTarefaViewModel(opts) {
2391
+ const { tarefaId } = opts;
2392
+ const { createController } = useCoreService();
2393
+ const toast = useToast();
2394
+ const [list, setList] = useState17([]);
2395
+ const [loading, setLoading] = useState17(false);
2396
+ const tarefaCtrl = useMemo15(
2397
+ () => createController("tarefa"),
2398
+ [createController]
1329
2399
  );
1330
- return /* @__PURE__ */ jsx5("div", { children: /* @__PURE__ */ jsx5(
1331
- AutoComplete_default,
1332
- {
1333
- sortKey: "id",
1334
- loadCondition: true,
1335
- loadFunc: () => recursoController.get("findActiveRecursosTags"),
1336
- displayKey: "descricao",
1337
- title: "Selecione ou Digite a TAG",
1338
- isBold: true,
1339
- actionButton: confirmRecursoSelectionButton,
1340
- actionButton2: () => /* @__PURE__ */ jsx5(
1341
- QrCodeScanButton_default,
1342
- {
1343
- callback: (description) => findRecursoByTagDescriptionHandler(description)
1344
- }
1345
- ),
1346
- onSelectedClick: (v) => {
1347
- setSelectedTag(v);
1348
- findRecursoByTagIdHandler(v.id);
1349
- },
1350
- value: selectedTag == null ? void 0 : selectedTag.descricao
2400
+ const load = useCallback19(async () => {
2401
+ var _a;
2402
+ setLoading(true);
2403
+ try {
2404
+ const res = await tarefaCtrl.get(
2405
+ `readObservacoesTarefa/${tarefaId}`
2406
+ );
2407
+ setList(Array.isArray(res) ? res : (_a = res == null ? void 0 : res.data) != null ? _a : []);
2408
+ } catch (err) {
2409
+ setList([]);
2410
+ const msg = (err == null ? void 0 : err.message) || "Nao foi possivel carregar as observacoes.";
2411
+ try {
2412
+ toast.warning(msg);
2413
+ } catch (e) {
2414
+ }
2415
+ } finally {
2416
+ setLoading(false);
1351
2417
  }
1352
- ) });
2418
+ }, [tarefaCtrl, tarefaId, toast]);
2419
+ const add = useCallback19(
2420
+ async (obs) => {
2421
+ setLoading(true);
2422
+ try {
2423
+ await tarefaCtrl.post(
2424
+ `addObservacaoTarefa/${tarefaId}`,
2425
+ obs
2426
+ );
2427
+ await load();
2428
+ } catch (err) {
2429
+ const msg = (err == null ? void 0 : err.message) || "Nao foi possivel adicionar a observacao.";
2430
+ try {
2431
+ toast.warning(msg);
2432
+ } catch (e) {
2433
+ }
2434
+ } finally {
2435
+ setLoading(false);
2436
+ }
2437
+ },
2438
+ [tarefaCtrl, tarefaId, load, toast]
2439
+ );
2440
+ return useMemo15(
2441
+ () => ({ list, loading, load, add }),
2442
+ [list, loading, load, add]
2443
+ );
2444
+ }
2445
+
2446
+ // src/viewmodels/usePickMantenedorTipoViewModel.ts
2447
+ import { useCallback as useCallback20, useMemo as useMemo16 } from "react";
2448
+ import { useDispatch as useDispatch8, useSelector as useSelector8 } from "react-redux";
2449
+
2450
+ // src/viewmodels/pickMantenedorTipoSlice.ts
2451
+ import { createSlice as createSlice7 } from "@reduxjs/toolkit";
2452
+ var initialState7 = {
2453
+ mantenedores: [],
2454
+ tiposDeOrdem: [],
2455
+ loading: false,
2456
+ assigning: false,
2457
+ error: null
1353
2458
  };
1354
- var FindRecursoByTagField_default = FindRecursoByTagField;
2459
+ var slice2 = createSlice7({
2460
+ name: "pickMantenedorTipo",
2461
+ initialState: initialState7,
2462
+ reducers: {
2463
+ setOptions(state, action) {
2464
+ state.mantenedores = action.payload.mantenedores;
2465
+ state.tiposDeOrdem = action.payload.tiposDeOrdem;
2466
+ },
2467
+ setLoading(state, action) {
2468
+ state.loading = action.payload;
2469
+ },
2470
+ setAssigning(state, action) {
2471
+ state.assigning = action.payload;
2472
+ },
2473
+ setError(state, action) {
2474
+ state.error = action.payload;
2475
+ },
2476
+ reset() {
2477
+ return initialState7;
2478
+ }
2479
+ }
2480
+ });
2481
+ var {
2482
+ setOptions: setPickMantenedorTipoOptions,
2483
+ setLoading: setPickMantenedorTipoLoading,
2484
+ setAssigning: setPickMantenedorTipoAssigning,
2485
+ setError: setPickMantenedorTipoError,
2486
+ reset: resetPickMantenedorTipo
2487
+ } = slice2.actions;
2488
+ var pickMantenedorTipoSlice_default = slice2.reducer;
1355
2489
 
1356
- // src/components/recurso/RecursoDisplayer.tsx
1357
- import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
1358
- var RecursoDisplayer = ({
1359
- selectedList = [],
1360
- onSaveRecurso,
1361
- singleReturn = false
1362
- }) => {
1363
- const arvoreEstruturalController = useHttpController("arvoreEstrutural");
1364
- const branchLevelController = useHttpController("branchLevel");
1365
- const [branches, setBranches] = useState12([]);
1366
- const dispatch = useDispatch2();
1367
- const [localSelected, setLocalSelected] = useState12(selectedList);
1368
- const [selectorDisplay, setSelectorDisplay] = useState12("");
1369
- const [multiMode, setMultiMode] = useState12(false);
1370
- useEffect6(() => {
1371
- const init = async () => {
1372
- const b = await arvoreEstruturalController.get("branchByBranchLevel/1");
1373
- setBranches(b);
1374
- const lv = await branchLevelController.readAll();
1375
- dispatch(setLevels(lv));
1376
- };
1377
- init();
1378
- }, []);
1379
- const branchSetter = async (bn) => {
1380
- const copy = [...branches];
1381
- const branch = await arvoreEstruturalController.read("branch", bn.recurso.branch.id);
1382
- copy[bn.recurso.branch.branchLevel.level - 1] = {
1383
- ...branch,
1384
- nomeRecurso: bn.recurso.nome
1385
- };
1386
- setBranches(copy);
1387
- };
1388
- const backOnBranch = (branch) => {
1389
- const branchsToStay = branches.filter(
1390
- (bArray) => bArray.branchLevel.level <= branch.branchLevel.level
1391
- );
1392
- setBranches(branchsToStay);
1393
- };
1394
- return /* @__PURE__ */ jsxs5("div", { style: { width: "100%", padding: 0 }, children: [
1395
- /* @__PURE__ */ jsx6("div", { className: "d-flex justify-content-between align-items-center mb-3", children: /* @__PURE__ */ jsxs5("div", { children: [
1396
- /* @__PURE__ */ jsx6("label", { className: "me-2", children: "Selecionar Recurso Por:" }),
1397
- /* @__PURE__ */ jsx6(
1398
- Button,
1399
- {
1400
- size: "sm",
1401
- onClick: () => setSelectorDisplay("branch"),
1402
- variant: selectorDisplay === "branch" ? "primary" : "outline-primary",
1403
- className: "me-1",
1404
- children: "\xC1rvore"
2490
+ // src/viewmodels/usePickMantenedorTipoViewModel.ts
2491
+ var unwrapList = (raw) => {
2492
+ if (Array.isArray(raw)) return raw;
2493
+ const r = raw;
2494
+ if (Array.isArray(r == null ? void 0 : r.content)) return r.content;
2495
+ if (Array.isArray(r == null ? void 0 : r.data)) return r.data;
2496
+ if (Array.isArray(r == null ? void 0 : r.items)) return r.items;
2497
+ return [];
2498
+ };
2499
+ function usePickMantenedorTipoViewModel() {
2500
+ var _a, _b, _c, _d, _e;
2501
+ const dispatch = useDispatch8();
2502
+ const core = useCoreService();
2503
+ const state = useSelector8(
2504
+ (s) => s.pickMantenedorTipo
2505
+ );
2506
+ const mantenedores = (_a = state == null ? void 0 : state.mantenedores) != null ? _a : [];
2507
+ const tiposDeOrdem = (_b = state == null ? void 0 : state.tiposDeOrdem) != null ? _b : [];
2508
+ const loading = (_c = state == null ? void 0 : state.loading) != null ? _c : false;
2509
+ const assigning = (_d = state == null ? void 0 : state.assigning) != null ? _d : false;
2510
+ const error = (_e = state == null ? void 0 : state.error) != null ? _e : null;
2511
+ const loadOptions = useCallback20(async () => {
2512
+ dispatch(setPickMantenedorTipoLoading(true));
2513
+ dispatch(setPickMantenedorTipoError(null));
2514
+ try {
2515
+ const mantenedorCtl = core.createController("mantenedor");
2516
+ const tipoCtl = core.createController("tipoDeOrdem");
2517
+ const [mRaw, tRaw] = await Promise.all([
2518
+ mantenedorCtl.get("mantenedorDashboard"),
2519
+ tipoCtl.readAll()
2520
+ ]);
2521
+ const mantenedoresList = unwrapList(mRaw);
2522
+ const tiposList = unwrapList(tRaw);
2523
+ dispatch(
2524
+ setPickMantenedorTipoOptions({
2525
+ mantenedores: mantenedoresList,
2526
+ tiposDeOrdem: tiposList
2527
+ })
2528
+ );
2529
+ } catch (e) {
2530
+ const msg = e instanceof Error ? e.message : "fetch error";
2531
+ dispatch(setPickMantenedorTipoError(msg));
2532
+ } finally {
2533
+ dispatch(setPickMantenedorTipoLoading(false));
2534
+ }
2535
+ }, [dispatch, core]);
2536
+ const assignMantenedores = useCallback20(
2537
+ async (osId, items) => {
2538
+ if (!items || items.length === 0) return;
2539
+ dispatch(setPickMantenedorTipoAssigning(true));
2540
+ try {
2541
+ const ctl = core.createController("ordemDeServico");
2542
+ for (const m of items) {
2543
+ await ctl.post(`atribuirMantenedor/${osId}`, {
2544
+ mantenedorId: m.id,
2545
+ id: null,
2546
+ userId: m.userId
2547
+ });
1405
2548
  }
1406
- ),
1407
- /* @__PURE__ */ jsx6(
1408
- Button,
1409
- {
1410
- size: "sm",
1411
- onClick: () => setSelectorDisplay("TAG"),
1412
- variant: selectorDisplay === "TAG" ? "primary" : "outline-primary",
1413
- children: "TAG"
2549
+ } finally {
2550
+ dispatch(setPickMantenedorTipoAssigning(false));
2551
+ }
2552
+ },
2553
+ [dispatch, core]
2554
+ );
2555
+ const assignTipo = useCallback20(
2556
+ async (osId, tipoId) => {
2557
+ dispatch(setPickMantenedorTipoAssigning(true));
2558
+ try {
2559
+ const ctl = core.createController("ordemDeServico");
2560
+ await ctl.put(`updateTipoDeOrdem/${osId}`, { tipoOs: tipoId });
2561
+ } finally {
2562
+ dispatch(setPickMantenedorTipoAssigning(false));
2563
+ }
2564
+ },
2565
+ [dispatch, core]
2566
+ );
2567
+ const assignMantenedoresMultiOs = useCallback20(
2568
+ async (osIds, items) => {
2569
+ if (!osIds.length || !items.length) return;
2570
+ dispatch(setPickMantenedorTipoAssigning(true));
2571
+ try {
2572
+ const ctl = core.createController("ordemDeServico");
2573
+ for (const m of items) {
2574
+ await ctl.post("atribuirMantenedorBulk", {
2575
+ osIds,
2576
+ mantenedorId: m.id,
2577
+ userId: m.userId
2578
+ });
1414
2579
  }
1415
- )
1416
- ] }) }),
1417
- selectorDisplay === "branch" && branches.map((branch, i) => /* @__PURE__ */ jsx6(
1418
- BranchDropDisplay_default,
1419
- {
1420
- branch,
1421
- addBranch: branchSetter,
1422
- multiMode,
1423
- setMultiMode,
1424
- onSaveRecurso,
1425
- backOnBranch,
1426
- branches,
1427
- singleReturn
1428
- },
1429
- branch.id || i
1430
- )),
1431
- selectorDisplay === "TAG" && /* @__PURE__ */ jsx6(
1432
- FindRecursoByTagField_default,
1433
- {
1434
- callback: (rec, checked) => {
1435
- setLocalSelected([rec]);
1436
- onSaveRecurso([rec], checked);
2580
+ } finally {
2581
+ dispatch(setPickMantenedorTipoAssigning(false));
2582
+ }
2583
+ },
2584
+ [dispatch, core]
2585
+ );
2586
+ const assignTipoMultiOs = useCallback20(
2587
+ async (osIds, tipoId) => {
2588
+ if (!osIds.length) return;
2589
+ dispatch(setPickMantenedorTipoAssigning(true));
2590
+ try {
2591
+ const ctl = core.createController("ordemDeServico");
2592
+ await ctl.post("updateTipoBulk", { osIds, tipoId });
2593
+ } finally {
2594
+ dispatch(setPickMantenedorTipoAssigning(false));
2595
+ }
2596
+ },
2597
+ [dispatch, core]
2598
+ );
2599
+ const reset = useCallback20(() => {
2600
+ dispatch(resetPickMantenedorTipo());
2601
+ }, [dispatch]);
2602
+ return useMemo16(
2603
+ () => ({
2604
+ mantenedores,
2605
+ tiposDeOrdem,
2606
+ loading,
2607
+ assigning,
2608
+ error,
2609
+ loadOptions,
2610
+ assignMantenedores,
2611
+ assignTipo,
2612
+ assignMantenedoresMultiOs,
2613
+ assignTipoMultiOs,
2614
+ reset
2615
+ }),
2616
+ [mantenedores, tiposDeOrdem, loading, assigning, error, loadOptions, assignMantenedores, assignTipo, assignMantenedoresMultiOs, assignTipoMultiOs, reset]
2617
+ );
2618
+ }
2619
+
2620
+ // src/viewmodels/ReduxTarefaItemAdapter.ts
2621
+ import { useCallback as useCallback21, useMemo as useMemo17, useRef as useRef4 } from "react";
2622
+ function useTarefaItemViewModel(opts) {
2623
+ const { tarefaId, mode, fatherId, initialStatus } = opts;
2624
+ const { createController, subscribe, unsubscribe } = useCoreService();
2625
+ const toast = useToast();
2626
+ const tarefaCtrl = useMemo17(
2627
+ () => createController("tarefa"),
2628
+ [createController]
2629
+ );
2630
+ const status = useTarefaStatusViewModel({ tarefaId, fatherId, initialStatus });
2631
+ const observacoes = useObservacoesTarefaViewModel({ tarefaId });
2632
+ const inspecao = useInspecaoModalViewModel(tarefaId);
2633
+ const unidadeMaterial = useUnidadeMaterialViewModel(tarefaId);
2634
+ const anexos = useAnexoManagerViewModel({
2635
+ context: "tarefa",
2636
+ entityId: tarefaId
2637
+ });
2638
+ const observacoesRef = useRef4(observacoes);
2639
+ observacoesRef.current = observacoes;
2640
+ const anexosRef = useRef4(anexos);
2641
+ anexosRef.current = anexos;
2642
+ const updateDescricao = useCallback21(
2643
+ async (texto) => {
2644
+ try {
2645
+ await tarefaCtrl.put(String(tarefaId), { descricao: texto });
2646
+ } catch (err) {
2647
+ const msg = (err == null ? void 0 : err.message) || "Nao foi possivel atualizar a descricao da tarefa.";
2648
+ try {
2649
+ toast.warning(msg);
2650
+ } catch (e) {
1437
2651
  }
2652
+ throw err;
1438
2653
  }
1439
- )
1440
- ] });
1441
- };
1442
- var RecursoDisplayer_default = RecursoDisplayer;
2654
+ },
2655
+ [tarefaCtrl, tarefaId, toast]
2656
+ );
2657
+ const subscribeLive = useCallback21(() => {
2658
+ if (mode !== "execute") {
2659
+ return () => {
2660
+ };
2661
+ }
2662
+ const refresher = () => {
2663
+ };
2664
+ const moTarefa = {
2665
+ context: `tarefa${tarefaId}`,
2666
+ location: "*",
2667
+ refresher
2668
+ };
2669
+ const moTarefaJus = {
2670
+ context: `tarefaJus${tarefaId}`,
2671
+ location: "*",
2672
+ refresher
2673
+ };
2674
+ subscribe(moTarefa);
2675
+ subscribe(moTarefaJus);
2676
+ return () => {
2677
+ unsubscribe(moTarefa);
2678
+ unsubscribe(moTarefaJus);
2679
+ };
2680
+ }, [mode, tarefaId, subscribe, unsubscribe]);
2681
+ return useMemo17(
2682
+ () => ({
2683
+ status,
2684
+ observacoes,
2685
+ inspecao,
2686
+ unidadeMaterial,
2687
+ anexos,
2688
+ updateDescricao,
2689
+ subscribeLive
2690
+ }),
2691
+ [
2692
+ status,
2693
+ observacoes,
2694
+ inspecao,
2695
+ unidadeMaterial,
2696
+ anexos,
2697
+ updateDescricao,
2698
+ subscribeLive
2699
+ ]
2700
+ );
2701
+ }
1443
2702
 
1444
2703
  // src/reducers/pickerReducer.ts
1445
- import { createSlice as createSlice2 } from "@reduxjs/toolkit";
1446
- var initialState2 = {
2704
+ import { createSlice as createSlice8 } from "@reduxjs/toolkit";
2705
+ var initialState8 = {
1447
2706
  selected: null,
1448
2707
  items: [],
1449
2708
  visible: false,
1450
2709
  context: ""
1451
2710
  };
1452
- var pickerSlice = createSlice2({
2711
+ var pickerSlice = createSlice8({
1453
2712
  name: "picker",
1454
- initialState: initialState2,
2713
+ initialState: initialState8,
1455
2714
  reducers: {
1456
2715
  setPickerSelected(state, action) {
1457
2716
  state.selected = action.payload;
@@ -1466,7 +2725,7 @@ var pickerSlice = createSlice2({
1466
2725
  state.context = action.payload;
1467
2726
  },
1468
2727
  clearPicker() {
1469
- return initialState2;
2728
+ return initialState8;
1470
2729
  }
1471
2730
  }
1472
2731
  });
@@ -1479,6 +2738,20 @@ var {
1479
2738
  } = pickerSlice.actions;
1480
2739
  var pickerReducer_default = pickerSlice.reducer;
1481
2740
 
2741
+ // src/utils/colorUtils.ts
2742
+ function pickTextColorBasedOnBgColorAdvanced(bgColor, lightColor, darkColor) {
2743
+ const color = bgColor.charAt(0) === "#" ? bgColor.substring(1, 7) : bgColor;
2744
+ const r = parseInt(color.substring(0, 2), 16);
2745
+ const g = parseInt(color.substring(2, 4), 16);
2746
+ const b = parseInt(color.substring(4, 6), 16);
2747
+ const uicolors = [r / 255, g / 255, b / 255];
2748
+ const c = uicolors.map(
2749
+ (col) => col <= 0.03928 ? col / 12.92 : Math.pow((col + 0.055) / 1.055, 2.4)
2750
+ );
2751
+ const L = 0.2126 * c[0] + 0.7152 * c[1] + 0.0722 * c[2];
2752
+ return L > 0.179 ? darkColor : lightColor;
2753
+ }
2754
+
1482
2755
  // src/utils/webVitals.ts
1483
2756
  function initWebVitals(observability) {
1484
2757
  if (typeof PerformanceObserver === "undefined") return;
@@ -1513,28 +2786,28 @@ function initWebVitals(observability) {
1513
2786
  }
1514
2787
 
1515
2788
  // src/utils/dateUtils.ts
1516
- import dayjs from "dayjs";
2789
+ import dayjs2 from "dayjs";
1517
2790
  function formatDate(date, format = "DD/MM/YYYY") {
1518
2791
  if (!date) return "";
1519
- return dayjs(date).format(format);
2792
+ return dayjs2(date).format(format);
1520
2793
  }
1521
2794
  function formatDateTime(date) {
1522
2795
  return formatDate(date, "DD/MM/YYYY HH:mm");
1523
2796
  }
1524
2797
  function isDateBefore(date1, date2) {
1525
- return dayjs(date1).isBefore(dayjs(date2));
2798
+ return dayjs2(date1).isBefore(dayjs2(date2));
1526
2799
  }
1527
2800
  function isDateAfter(date1, date2) {
1528
- return dayjs(date1).isAfter(dayjs(date2));
2801
+ return dayjs2(date1).isAfter(dayjs2(date2));
1529
2802
  }
1530
2803
  function daysBetween(start, end) {
1531
- return dayjs(end).diff(dayjs(start), "day");
2804
+ return dayjs2(end).diff(dayjs2(start), "day");
1532
2805
  }
1533
2806
  function addDays(date, days) {
1534
- return dayjs(date).add(days, "day").toDate();
2807
+ return dayjs2(date).add(days, "day").toDate();
1535
2808
  }
1536
2809
  function toISOString(date) {
1537
- return dayjs(date).toISOString();
2810
+ return dayjs2(date).toISOString();
1538
2811
  }
1539
2812
 
1540
2813
  // src/utils/stringUtils.ts
@@ -1556,62 +2829,134 @@ function isBlank(str) {
1556
2829
  return !str || str.trim().length === 0;
1557
2830
  }
1558
2831
  export {
2832
+ DEFAULT_KEY4 as CONTADOR_DEFAULT_KEY,
1559
2833
  CoreServiceBuilder,
1560
2834
  CoreServiceContext,
1561
2835
  DevAutoLogin,
2836
+ FILTER_COMBINE_MODES,
1562
2837
  FederatedBridge,
1563
2838
  FetchHttpAdapter,
2839
+ DEFAULT_KEY2 as INSPECAO_MODAL_DEFAULT_KEY,
1564
2840
  NullCoreService,
1565
2841
  NullHttpController,
1566
2842
  NullObservabilityAdapter,
1567
2843
  NullToastService,
1568
- RecursoDisplayer_default as RecursoDisplayer,
2844
+ DEFAULT_KEY3 as RECORRENCIA_DEFAULT_KEY,
1569
2845
  StandaloneProvider,
1570
2846
  TracingHttpAdapter,
2847
+ DEFAULT_KEY as UNIDADE_MATERIAL_DEFAULT_KEY,
2848
+ addContadorLimite,
1571
2849
  addDays,
1572
2850
  branchLevelReducer_default as branchLevelReducer,
1573
2851
  buildTraceparent,
1574
2852
  capitalize,
1575
2853
  clearBranchLevelForm,
2854
+ clearContador,
2855
+ clearInspecaoModal,
2856
+ clearMantenedorSlot,
1576
2857
  clearPicker,
2858
+ clearRecorrencia,
2859
+ clearUnidadeMaterial,
2860
+ contadorSlice_default as contadorReducer,
1577
2861
  createReducersBundle,
2862
+ createReducersFromManifest,
1578
2863
  daysBetween,
1579
2864
  formatDate,
1580
2865
  formatDateTime,
1581
2866
  generateSpanId,
1582
2867
  generateTraceId,
2868
+ groupMenuSections,
2869
+ hmsToSeconds,
1583
2870
  initWebVitals,
2871
+ inspecaoModalSlice_default as inspecaoModalReducer,
1584
2872
  isBlank,
1585
2873
  isDateAfter,
1586
2874
  isDateBefore,
2875
+ isHostedByCore,
2876
+ mantenedorPickerSlice_default as mantenedorPickerReducer,
2877
+ pickMantenedorTipoSlice_default as pickMantenedorTipoReducer,
1587
2878
  pickTextColorBasedOnBgColorAdvanced,
1588
2879
  pickerReducer_default as pickerReducer,
2880
+ populateContador,
2881
+ populateInspecaoModal,
2882
+ populateRecorrencia,
1589
2883
  populateToEdit,
2884
+ populateUnidadeMaterial,
2885
+ recorrenciaSlice_default as recorrenciaReducer,
1590
2886
  removeAccents,
2887
+ removeContadorLimiteAt,
2888
+ removeInspecaoLimiteAt,
2889
+ resetPickMantenedorTipo,
2890
+ secondsToHms,
2891
+ selectContador,
2892
+ selectInspecaoModal,
2893
+ selectRecorrencia,
2894
+ selectUnidadeMaterial,
1591
2895
  setColor,
2896
+ setContadorParametro,
2897
+ setContadorUnidade,
2898
+ setContadorValor,
1592
2899
  setExcludeLevels,
1593
2900
  setHaveComponente,
2901
+ setInspecaoLimites,
2902
+ setInspecaoNomeParametro,
2903
+ setInspecaoParametro,
2904
+ setInspecaoTipo,
2905
+ setInspecaoUnidadeParametro,
1594
2906
  setLevel,
1595
2907
  setLevels,
2908
+ setMantenedorError,
2909
+ setMantenedorLoading,
2910
+ setMantenedorOptions,
2911
+ setMantenedorPendingConfirm,
2912
+ setMantenedorSearchTerm,
1596
2913
  setNome,
2914
+ setPickMantenedorTipoAssigning,
2915
+ setPickMantenedorTipoError,
2916
+ setPickMantenedorTipoLoading,
2917
+ setPickMantenedorTipoOptions,
1597
2918
  setPickerContext,
1598
2919
  setPickerItems,
1599
2920
  setPickerSelected,
1600
2921
  setPickerVisible,
2922
+ setRecorrenciaDataInicio,
2923
+ setRecorrenciaEscala,
2924
+ setRecorrenciaValor,
2925
+ setMaterial as setUnidadeMaterialMaterial,
2926
+ setQuantidade as setUnidadeMaterialQuantidade,
2927
+ setUnidade as setUnidadeMaterialUnidade,
1601
2928
  slugify,
1602
2929
  toISOString,
1603
2930
  truncate,
2931
+ unidadeMaterialSlice_default as unidadeMaterialReducer,
2932
+ updateContadorLimiteAt,
2933
+ useAnexoManager,
2934
+ useAnexoManagerViewModel,
1604
2935
  useAnexoUpload,
2936
+ useContadorViewModel,
1605
2937
  useCoreService,
1606
2938
  useFetchData,
2939
+ useFilterCombineMode,
2940
+ useFindRecursoByTagViewModel,
1607
2941
  useFormStorage,
1608
2942
  useHttpController,
2943
+ useInspecaoModalViewModel,
2944
+ useJustificativaModalViewModel,
2945
+ useMantenedorPickerViewModel,
1609
2946
  useMatchingObject,
1610
2947
  useNavigator,
1611
2948
  useNotifications,
1612
2949
  useObservability,
2950
+ useObservacoesTarefaViewModel,
2951
+ usePickMantenedorTipoViewModel,
1613
2952
  usePostData,
2953
+ useRecorrenciaViewModel,
2954
+ useRecursoDisplayerViewModel,
1614
2955
  useSmartSearch,
2956
+ useTarefaItemViewModel,
2957
+ useTarefaStatusViewModel,
2958
+ useTimeFormat,
1615
2959
  useToast,
2960
+ useUnidadeMaterialViewModel,
1616
2961
  useValidation
1617
2962
  };