teraprox-core-sdk 0.3.11 → 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,6 +333,7 @@ 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) => {
@@ -292,19 +355,27 @@ var CoreServiceBuilder = class {
292
355
  const extraHeaders = { "x-teraprox-host": hostHeader };
293
356
  return this._tracing ? new TracingHttpAdapter(endpoint, extraHeaders) : new FetchHttpAdapter(endpoint, extraHeaders);
294
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.
295
362
  subscribe: (mo) => {
296
- console.log(`[CoreServiceBuilder RTDB] Subscribe > ${mo.context}`);
363
+ subscriptions.push(mo);
297
364
  },
298
365
  unsubscribe: (mo) => {
299
- 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);
300
370
  },
301
- subscribeEvent: (evt) => {
371
+ subscribeEvent: (_evt) => {
302
372
  },
303
- unsubscribeEvent: (evt) => {
373
+ unsubscribeEvent: (_evt) => {
304
374
  },
305
- handleLogout: () => console.log("Logout invocado no Standalone mode"),
375
+ handleLogout: () => console.log("[CoreServiceBuilder] Logout invocado no Standalone mode"),
306
376
  hostedByCore: this._hostedByCore,
307
- observability: this._observability
377
+ observability: this._observability,
378
+ rateLimits: {}
308
379
  };
309
380
  }
310
381
  };
@@ -425,15 +496,207 @@ function useObservability() {
425
496
  return useCoreService().observability;
426
497
  }
427
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
+
428
691
  // src/hooks/useFetchData.ts
429
- import { useState, useCallback as useCallback2, useRef } from "react";
692
+ import { useState as useState2, useCallback as useCallback3, useRef } from "react";
430
693
  function useFetchData() {
431
694
  const { createController } = useCoreService();
432
- const [data, setData] = useState(null);
433
- const [loading, setLoading] = useState(false);
434
- const [error, setError] = useState(null);
695
+ const [data, setData] = useState2(null);
696
+ const [loading, setLoading] = useState2(false);
697
+ const [error, setError] = useState2(null);
435
698
  const activeRef = useRef(true);
436
- const fetchData = useCallback2(
699
+ const fetchData = useCallback3(
437
700
  async (context, path, endpoint) => {
438
701
  const controller = createController(context, endpoint);
439
702
  setLoading(true);
@@ -451,7 +714,7 @@ function useFetchData() {
451
714
  },
452
715
  [createController]
453
716
  );
454
- const reset = useCallback2(() => {
717
+ const reset = useCallback3(() => {
455
718
  setData(null);
456
719
  setLoading(false);
457
720
  setError(null);
@@ -460,13 +723,13 @@ function useFetchData() {
460
723
  }
461
724
 
462
725
  // src/hooks/usePostData.ts
463
- import { useState as useState2, useCallback as useCallback3 } from "react";
726
+ import { useState as useState3, useCallback as useCallback4 } from "react";
464
727
  function usePostData() {
465
728
  const { createController } = useCoreService();
466
- const [result, setResult] = useState2(null);
467
- const [loading, setLoading] = useState2(false);
468
- const [error, setError] = useState2(null);
469
- 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(
470
733
  async (context, path, payload, endpoint) => {
471
734
  const controller = createController(context, endpoint);
472
735
  setLoading(true);
@@ -488,13 +751,13 @@ function usePostData() {
488
751
  }
489
752
 
490
753
  // src/hooks/useAnexoUpload.ts
491
- import { useState as useState3, useCallback as useCallback4 } from "react";
754
+ import { useState as useState4, useCallback as useCallback5 } from "react";
492
755
  function useAnexoUpload() {
493
756
  const { createController } = useCoreService();
494
757
  const toast = useToast();
495
- const [uploading, setUploading] = useState3(false);
496
- const [progress, setProgress] = useState3(0);
497
- const upload = useCallback4(
758
+ const [uploading, setUploading] = useState4(false);
759
+ const [progress, setProgress] = useState4(0);
760
+ const upload = useCallback5(
498
761
  async (context, path, file, extraHeaders) => {
499
762
  const controller = createController(context);
500
763
  setUploading(true);
@@ -517,7 +780,7 @@ function useAnexoUpload() {
517
780
  },
518
781
  [createController, toast]
519
782
  );
520
- const uploadMultiple = useCallback4(
783
+ const uploadMultiple = useCallback5(
521
784
  async (context, path, files, extraHeaders) => {
522
785
  const fileArray = Array.from(files);
523
786
  const results = [];
@@ -535,10 +798,10 @@ function useAnexoUpload() {
535
798
  }
536
799
 
537
800
  // src/hooks/useFormStorage.ts
538
- 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";
539
802
  function useFormStorage(key, initialValue) {
540
803
  const storageKey = `teraprox_form_${key}`;
541
- const [value, setValue] = useState4(() => {
804
+ const [value, setValue] = useState5(() => {
542
805
  try {
543
806
  const stored = localStorage.getItem(storageKey);
544
807
  return stored ? JSON.parse(stored) : initialValue;
@@ -552,7 +815,7 @@ function useFormStorage(key, initialValue) {
552
815
  } catch (e) {
553
816
  }
554
817
  }, [value, storageKey]);
555
- const clear = useCallback5(() => {
818
+ const clear = useCallback6(() => {
556
819
  localStorage.removeItem(storageKey);
557
820
  setValue(initialValue);
558
821
  }, [storageKey, initialValue]);
@@ -560,11 +823,11 @@ function useFormStorage(key, initialValue) {
560
823
  }
561
824
 
562
825
  // src/hooks/useSmartSearch.ts
563
- 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";
564
827
  function useSmartSearch(data, searchFields, options) {
565
- const [searchTerm, setSearchTerm] = useState5("");
828
+ const [searchTerm, setSearchTerm] = useState6("");
566
829
  const { caseSensitive = false, minLength = 1 } = options || {};
567
- const filteredData = useMemo2(() => {
830
+ const filteredData = useMemo3(() => {
568
831
  if (!searchTerm || searchTerm.length < minLength) return data;
569
832
  const term = caseSensitive ? searchTerm : searchTerm.toLowerCase();
570
833
  return data.filter(
@@ -576,16 +839,16 @@ function useSmartSearch(data, searchFields, options) {
576
839
  })
577
840
  );
578
841
  }, [data, searchTerm, searchFields, caseSensitive, minLength]);
579
- const clearSearch = useCallback6(() => setSearchTerm(""), []);
842
+ const clearSearch = useCallback7(() => setSearchTerm(""), []);
580
843
  return { searchTerm, setSearchTerm, filteredData, clearSearch };
581
844
  }
582
845
 
583
846
  // src/hooks/useValidation.ts
584
- import { useState as useState6, useCallback as useCallback7 } from "react";
847
+ import { useState as useState7, useCallback as useCallback8 } from "react";
585
848
  function useValidation(rules) {
586
849
  const toast = useToast();
587
- const [errors, setErrors] = useState6({});
588
- const validate = useCallback7(
850
+ const [errors, setErrors] = useState7({});
851
+ const validate = useCallback8(
589
852
  (form) => {
590
853
  const newErrors = {};
591
854
  let valid = true;
@@ -604,22 +867,523 @@ function useValidation(rules) {
604
867
  },
605
868
  [rules, toast]
606
869
  );
607
- const clearErrors = useCallback7(() => setErrors({}), []);
608
- const setFieldError = useCallback7(
870
+ const clearErrors = useCallback8(() => setErrors({}), []);
871
+ const setFieldError = useCallback8(
609
872
  (field, message) => setErrors((prev) => ({ ...prev, [field]: message })),
610
873
  []
611
874
  );
612
875
  return { errors, validate, clearErrors, setFieldError };
613
876
  }
614
877
 
615
- // src/components/recurso/RecursoDisplayer.tsx
616
- import { useEffect as useEffect6, useState as useState12 } from "react";
617
- import { Button } from "react-bootstrap";
618
- 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
+ });
619
897
 
620
- // 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
621
949
  import { createSlice } from "@reduxjs/toolkit";
950
+ var DEFAULT_KEY = "__default__";
951
+ var emptyValue = {
952
+ material: null,
953
+ quantidade: "",
954
+ unidade: null
955
+ };
622
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 = {
623
1387
  form: {
624
1388
  nome: "",
625
1389
  level: 0,
@@ -629,9 +1393,9 @@ var initialState = {
629
1393
  },
630
1394
  levels: []
631
1395
  };
632
- var branchLevelSlice = createSlice({
1396
+ var branchLevelSlice = createSlice3({
633
1397
  name: "branchLevelReducer",
634
- initialState,
1398
+ initialState: initialState3,
635
1399
  reducers: {
636
1400
  setNome(state, action) {
637
1401
  state.form.nome = action.payload;
@@ -655,7 +1419,7 @@ var branchLevelSlice = createSlice({
655
1419
  state.form = action.payload;
656
1420
  },
657
1421
  clear(state) {
658
- state.form = initialState.form;
1422
+ state.form = initialState3.form;
659
1423
  }
660
1424
  }
661
1425
  });
@@ -671,788 +1435,1282 @@ var {
671
1435
  } = branchLevelSlice.actions;
672
1436
  var branchLevelReducer_default = branchLevelSlice.reducer;
673
1437
 
674
- // src/components/recurso/BranchDropDisplay.tsx
675
- import { useEffect as useEffect3, useRef as useRef2, useState as useState7 } from "react";
676
- import { FaCheck, FaCheckSquare, FaSearch, FaChevronDown } from "react-icons/fa";
677
- import { MdClose } from "react-icons/md";
678
-
679
- // src/utils/colorUtils.ts
680
- function pickTextColorBasedOnBgColorAdvanced(bgColor, lightColor, darkColor) {
681
- const color = bgColor.charAt(0) === "#" ? bgColor.substring(1, 7) : bgColor;
682
- const r = parseInt(color.substring(0, 2), 16);
683
- const g = parseInt(color.substring(2, 4), 16);
684
- const b = parseInt(color.substring(4, 6), 16);
685
- const uicolors = [r / 255, g / 255, b / 255];
686
- const c = uicolors.map(
687
- (col) => col <= 0.03928 ? col / 12.92 : Math.pow((col + 0.055) / 1.055, 2.4)
688
- );
689
- const L = 0.2126 * c[0] + 0.7152 * c[1] + 0.0722 * c[2];
690
- return L > 0.179 ? darkColor : lightColor;
691
- }
692
-
693
- // src/components/recurso/BranchDropDisplay.tsx
694
- import { jsx, jsxs } from "react/jsx-runtime";
695
- var BranchDropDisplay = ({
696
- branch,
697
- addBranch,
698
- multiMode,
699
- setMultiMode,
700
- onSaveRecurso,
701
- backOnBranch,
702
- branches,
703
- singleReturn
704
- }) => {
705
- const [fontColor, setFontColor] = useState7("#000");
706
- const [searchTerm, setSearchTerm] = useState7("");
707
- const [show, setShow] = useState7(false);
708
- const [multiSelected, setMultiSelected] = useState7([]);
709
- 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);
710
1449
  useEffect3(() => {
711
- setFontColor(
712
- pickTextColorBasedOnBgColorAdvanced(branch.branchLevel.color, "#FFFFFF", "#000000")
713
- );
714
- }, [branch.branchLevel.color]);
715
- useEffect3(() => {
716
- const handleClickOutside = (event) => {
717
- if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
718
- 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([]);
719
1461
  }
720
- };
721
- document.addEventListener("mousedown", handleClickOutside);
722
- return () => document.removeEventListener("mousedown", handleClickOutside);
723
- }, [backOnBranch, branch]);
724
- const handleItemClick = (bn) => {
725
- const rec = bn.recurso;
726
- if (multiMode) {
727
- setMultiSelected(
728
- (prev) => prev.some((r) => r.id === rec.id) ? prev.filter((r) => r.id !== rec.id) : [...prev, rec]
729
- );
730
- } else {
731
- onSaveRecurso([rec]);
732
- addBranch(bn);
733
- 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);
734
1470
  }
735
- };
736
- const startMulti = () => {
737
- setMultiSelected([]);
738
- setMultiMode(true);
739
- setShow(true);
740
- };
741
- const handleConfirm = () => {
742
- setMultiMode(false);
743
- onSaveRecurso(multiSelected);
744
- setMultiSelected([]);
745
- setShow(false);
746
- };
747
- const cancelMulti = () => {
748
- setMultiMode(false);
749
- setMultiSelected([]);
750
- };
751
- const isLastBranchClicked = () => branches.length > 0 && branches[branches.length - 1].id === branch.id;
752
- const visibleNodes = (branch.branchNodes || []).filter(
753
- (bn) => bn.recurso.nome.toLowerCase().includes(searchTerm.toLowerCase())
754
- );
755
- return /* @__PURE__ */ jsxs(
756
- "div",
757
- {
758
- ref: dropdownRef,
759
- style: {
760
- position: "relative",
761
- marginBottom: "0.5rem",
762
- width: "100%",
763
- fontFamily: "Arial, sans-serif"
764
- },
765
- children: [
766
- /* @__PURE__ */ jsxs(
767
- "button",
768
- {
769
- onClick: () => setShow((s) => !s),
770
- style: {
771
- width: "100%",
772
- display: "flex",
773
- alignItems: "center",
774
- justifyContent: "space-between",
775
- padding: "0.5rem 1rem",
776
- borderRadius: "9999px",
777
- boxShadow: "0 1px 3px rgba(0, 0, 0, 0.1)",
778
- border: `1px solid ${branch.branchLevel.color}`,
779
- background: branch.branchLevel.color,
780
- color: fontColor,
781
- cursor: "pointer",
782
- outline: "none",
783
- textAlign: "left",
784
- fontSize: "1rem"
785
- },
786
- children: [
787
- /* @__PURE__ */ jsxs("span", { style: { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, children: [
788
- branch.nomeRecurso || branch.branchLevel.nome,
789
- branch.nomeRecurso && !multiMode && isLastBranchClicked() && /* @__PURE__ */ jsx("em", { style: { fontStyle: "italic", opacity: 0.8, marginLeft: "0.5rem" }, children: "(Selecionado)" })
790
- ] }),
791
- /* @__PURE__ */ jsx(FaChevronDown, {})
792
- ]
793
- }
794
- ),
795
- show && /* @__PURE__ */ jsxs(
796
- "div",
797
- {
798
- style: {
799
- position: "absolute",
800
- top: "100%",
801
- left: 0,
802
- width: "100%",
803
- background: "#f0f0f0",
804
- borderRadius: "8px",
805
- boxShadow: "0 2px 6px rgba(0, 0, 0, 0.15)",
806
- marginTop: "0.25rem",
807
- zIndex: 100,
808
- maxHeight: "300px",
809
- overflow: "auto"
810
- },
811
- children: [
812
- /* @__PURE__ */ jsxs(
813
- "div",
814
- {
815
- style: {
816
- display: "flex",
817
- alignItems: "center",
818
- padding: "0.5rem",
819
- borderBottom: "1px solid #ddd"
820
- },
821
- children: [
822
- /* @__PURE__ */ jsx(FaSearch, { style: { marginRight: "0.5rem", color: "#555" } }),
823
- /* @__PURE__ */ jsx(
824
- "input",
825
- {
826
- type: "text",
827
- placeholder: "Pesquisar recurso...",
828
- value: searchTerm,
829
- onChange: (e) => setSearchTerm(e.target.value),
830
- style: {
831
- flex: 1,
832
- padding: "0.5rem",
833
- border: "1px solid #ccc",
834
- borderRadius: "9999px",
835
- outline: "none",
836
- fontSize: "0.95rem"
837
- }
838
- }
839
- )
840
- ]
841
- }
842
- ),
843
- !multiMode && !singleReturn ? /* @__PURE__ */ jsxs(
844
- "button",
845
- {
846
- onClick: startMulti,
847
- style: {
848
- display: "flex",
849
- alignItems: "center",
850
- justifyContent: "center",
851
- width: "100%",
852
- padding: "0.5rem",
853
- borderRadius: "9999px",
854
- border: "none",
855
- background: "#ffc107",
856
- color: "#000",
857
- fontSize: "0.95rem",
858
- cursor: "pointer",
859
- margin: "0.5rem 0"
860
- },
861
- children: [
862
- /* @__PURE__ */ jsx(FaCheckSquare, { style: { marginRight: "0.5rem" } }),
863
- "Selecionar m\xFAltiplos"
864
- ]
865
- }
866
- ) : /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "0.5rem", margin: "0.5rem 0" }, children: [
867
- /* @__PURE__ */ jsxs(
868
- "button",
869
- {
870
- onClick: handleConfirm,
871
- style: {
872
- flex: 1,
873
- display: "flex",
874
- alignItems: "center",
875
- justifyContent: "center",
876
- padding: "0.5rem",
877
- borderRadius: "9999px",
878
- border: "none",
879
- background: "#28a745",
880
- color: "#fff",
881
- fontSize: "0.95rem",
882
- cursor: "pointer"
883
- },
884
- children: [
885
- /* @__PURE__ */ jsx(FaCheck, { style: { marginRight: "0.5rem" } }),
886
- "Confirmar sele\xE7\xE3o"
887
- ]
888
- }
889
- ),
890
- /* @__PURE__ */ jsxs(
891
- "button",
892
- {
893
- onClick: cancelMulti,
894
- style: {
895
- flex: 1,
896
- display: "flex",
897
- alignItems: "center",
898
- justifyContent: "center",
899
- padding: "0.5rem",
900
- borderRadius: "9999px",
901
- border: "none",
902
- background: "#6c757d",
903
- color: "#fff",
904
- fontSize: "0.95rem",
905
- cursor: "pointer"
906
- },
907
- children: [
908
- /* @__PURE__ */ jsx(MdClose, { style: { marginRight: "0.5rem" } }),
909
- "Cancelar"
910
- ]
911
- }
912
- )
913
- ] }),
914
- /* @__PURE__ */ jsx("div", { style: { padding: "0.5rem" }, children: visibleNodes.map((bn) => {
915
- const selected = multiMode ? multiSelected.some((r) => r.id === bn.recurso.id) : false;
916
- return /* @__PURE__ */ jsxs(
917
- "div",
918
- {
919
- onClick: () => handleItemClick(bn),
920
- style: {
921
- display: "flex",
922
- justifyContent: "space-between",
923
- alignItems: "center",
924
- padding: "0.5rem",
925
- borderBottom: "1px solid #ddd",
926
- background: selected ? "#e9ecef" : "transparent",
927
- cursor: "pointer",
928
- transition: "background 0.1s"
929
- },
930
- onMouseEnter: (e) => {
931
- if (!selected) e.currentTarget.style.background = "#e2e6ea";
932
- },
933
- onMouseLeave: (e) => {
934
- e.currentTarget.style.background = selected ? "#e9ecef" : "transparent";
935
- },
936
- children: [
937
- /* @__PURE__ */ jsx("span", { children: bn.recurso.nome }),
938
- selected && /* @__PURE__ */ jsx(FaCheck, {})
939
- ]
940
- },
941
- bn.recurso.id
942
- );
943
- }) })
944
- ]
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;
945
1487
  }
946
- )
947
- ]
948
- }
949
- );
950
- };
951
- var BranchDropDisplay_default = BranchDropDisplay;
952
-
953
- // src/components/recurso/FindRecursoByTagField.tsx
954
- import { useState as useState11 } from "react";
955
- import { GrCheckmark } from "react-icons/gr";
956
-
957
- // src/components/recurso/AutoComplete.tsx
958
- import { useEffect as useEffect4, useState as useState8 } from "react";
959
- import { FloatingLabel, Form, InputGroup, ListGroup } from "react-bootstrap";
960
- import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
961
- var AutoComplete = ({
962
- className,
963
- ops,
964
- sortKey,
965
- displayKey,
966
- displayKeys,
967
- onValueChanged,
968
- selectedKey,
969
- onSelectedClick,
970
- value,
971
- actionButton,
972
- actionButton2,
973
- placeH,
974
- title,
975
- filter,
976
- filterField,
977
- loadFunc,
978
- loadCondition,
979
- isBold,
980
- onBlurEvent,
981
- formatationFunc,
982
- onEscKeyDown,
983
- margT,
984
- hideComponent,
985
- disableComponent = false,
986
- disableSelect = false,
987
- margB,
988
- autoFocusConfig,
989
- onLoad,
990
- onMouseLv,
991
- useStandardLabel = false,
992
- isRequired = false,
993
- ty = "text"
994
- }) => {
995
- const [liItem, setListItem] = useState8([]);
996
- const [options, setOptions] = useState8([]);
997
- const [input, setInput] = useState8("");
998
- const [hide, setHide] = useState8(true);
999
- const [onLoaded, setOnLoaded] = useState8(false);
1000
- const sortOptions = (opts, key) => {
1001
- if (!key || !Array.isArray(opts)) return opts != null ? opts : [];
1002
- return [...opts].sort((a, b) => String(a[key]).localeCompare(String(b[key])));
1003
- };
1004
- useEffect4(() => {
1005
- if (value) setInput(value);
1006
- else setInput("");
1007
- }, [value]);
1008
- useEffect4(() => {
1009
- const sortedOptions = sortOptions(ops, sortKey);
1010
- setListItem(sortedOptions);
1011
- setOptions(sortedOptions);
1012
- }, [ops, sortKey]);
1013
- useEffect4(() => {
1014
- const loadFunction = async () => {
1015
- if (loadCondition && loadFunc) {
1016
- try {
1017
- const res = await loadFunc();
1018
- let newOps = res.content ? res.content : res;
1019
- newOps = newOps.filter((c) => c != null);
1020
- if (Array.isArray(newOps)) {
1021
- if (filter) {
1022
- 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);
1023
1495
  }
1024
- const sortedOptions = sortOptions(newOps, sortKey);
1025
- setListItem(sortedOptions);
1026
- setOptions(sortedOptions);
1496
+ } catch (e) {
1497
+ console.warn(
1498
+ "[RecursoDisplayerVM] Failed to fetch child branch:",
1499
+ e
1500
+ );
1027
1501
  }
1028
- if (onLoad) {
1029
- if (onLoaded) return;
1030
- setOnLoaded(true);
1031
- onLoad(newOps);
1032
- }
1033
- } catch (e) {
1034
- setListItem([]);
1035
1502
  }
1503
+ setBranches([...branchsToStay]);
1504
+ } finally {
1505
+ setIsLoading(false);
1036
1506
  }
1037
- };
1038
- loadFunction();
1039
- }, [loadCondition, filter, filterField, sortKey, onLoad]);
1040
- const onFieldUpdate = (val) => {
1041
- let newListItem;
1042
- if (val && val.length > 0) {
1043
- const regex = new RegExp(`${val}`, "i");
1044
- newListItem = options.filter((liI) => {
1045
- let textToTest;
1046
- if (formatationFunc) {
1047
- textToTest = formatationFunc(liI);
1048
- } else if (displayKey) {
1049
- textToTest = liI[displayKey];
1050
- } else if (displayKeys) {
1051
- textToTest = keysJoinner(liI);
1052
- } else {
1053
- 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);
1054
1516
  }
1055
- return regex.test(textToTest);
1056
- });
1057
- setListItem(newListItem);
1058
- } else {
1059
- 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 [];
1060
1550
  }
1061
- onValueChanged && onValueChanged(val);
1062
- setInput(val);
1063
- setHide(false);
1064
- };
1065
- const clear = () => {
1066
- setInput("");
1067
- };
1068
- const onOpSelected = (li, index, lItem) => {
1069
- if (formatationFunc) {
1070
- setInput(formatationFunc(li));
1071
- } else if (displayKey) {
1072
- setInput(li[displayKey]);
1073
- } else if (displayKeys) {
1074
- setInput(keysJoinner(li));
1075
- } else {
1076
- 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);
1077
1678
  }
1078
- onSelectedClick(li, index, lItem);
1079
- setHide(true);
1080
- };
1081
- const keysJoinner = (li) => {
1082
- if (!displayKeys || !Array.isArray(displayKeys)) return "";
1083
- const textToRender = displayKeys.map((key) => `${li[key]} `);
1084
- return textToRender.join("").trim();
1085
- };
1086
- const renderMoreThanOneKey = (li, index) => {
1087
- const buildedString = keysJoinner(li);
1088
- return /* @__PURE__ */ jsx2("li", { children: buildedString }, index);
1089
- };
1090
- const boldedPart = (text, key) => {
1091
- return /* @__PURE__ */ jsx2("li", { children: text }, key);
1092
- };
1093
- const displayListItens = (li, index) => {
1094
- if (formatationFunc) {
1095
- 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;
1096
1825
  }
1097
- if (displayKey) {
1098
- 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);
1099
1910
  }
1100
- if (displayKeys) {
1101
- 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: [] };
1102
2017
  }
1103
- 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: []
1104
2037
  };
1105
- const onKeyDownHandler = (event) => {
1106
- if (event.key === "Escape") {
1107
- setHide(true);
1108
- 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.";
1109
2048
  }
1110
- };
1111
- return /* @__PURE__ */ jsxs2(
1112
- "div",
1113
- {
1114
- className: `${className}`,
1115
- style: { marginTop: margT || 4, marginBottom: margB || 4, position: "relative" },
1116
- onBlur: (e) => {
1117
- setTimeout(() => {
1118
- if (onBlurEvent) onBlurEvent(e, input);
1119
- setHide(true);
1120
- }, 200);
1121
- },
1122
- onKeyDown: (event) => onKeyDownHandler(event),
1123
- onMouseLeave: () => {
1124
- setHide(true);
1125
- },
1126
- children: [
1127
- !hideComponent && /* @__PURE__ */ jsxs2(Fragment, { children: [
1128
- useStandardLabel && title && /* @__PURE__ */ jsxs2(Form.Label, { children: [
1129
- title,
1130
- isRequired && " *"
1131
- ] }),
1132
- /* @__PURE__ */ jsxs2(InputGroup, { children: [
1133
- useStandardLabel ? /* @__PURE__ */ jsx2(
1134
- Form.Control,
1135
- {
1136
- autoFocus: autoFocusConfig,
1137
- disabled: disableComponent || disableSelect,
1138
- placeholder: placeH,
1139
- autoComplete: "off",
1140
- value: input,
1141
- onClickCapture: () => {
1142
- setHide(false);
1143
- if (!input) {
1144
- onFieldUpdate("");
1145
- }
1146
- },
1147
- onChange: (event) => onFieldUpdate(event.currentTarget.value),
1148
- type: "text"
1149
- }
1150
- ) : /* @__PURE__ */ jsx2(FloatingLabel, { style: { zIndex: 0 }, label: title, controlId: "floatingInput", children: /* @__PURE__ */ jsx2(
1151
- Form.Control,
1152
- {
1153
- autoFocus: autoFocusConfig,
1154
- disabled: disableComponent || disableSelect,
1155
- placeholder: placeH,
1156
- autoComplete: "off",
1157
- value: input,
1158
- onClickCapture: () => {
1159
- setHide(false);
1160
- if (!input) {
1161
- onFieldUpdate("");
1162
- }
1163
- },
1164
- onChange: (event) => onFieldUpdate(event.currentTarget.value),
1165
- type: "text"
1166
- }
1167
- ) }),
1168
- !disableComponent && actionButton && actionButton(clear),
1169
- !disableComponent && actionButton2 && actionButton2(input)
1170
- ] })
1171
- ] }),
1172
- 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)) })
1173
- ]
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.";
1174
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)
1175
2072
  );
1176
- };
1177
- 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
+ }
1178
2171
 
1179
- // src/components/recurso/QrCodeScanButton.tsx
1180
- import { useState as useState10 } from "react";
1181
- 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";
1182
2175
 
1183
- // src/components/recurso/QrReader.tsx
1184
- import QrScanner from "qr-scanner";
1185
- import { useEffect as useEffect5, useRef as useRef3, useState as useState9 } from "react";
1186
- import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
1187
- var QrReader = ({ callback }) => {
1188
- const scanner = useRef3(null);
1189
- const videoEl = useRef3(null);
1190
- const qrBoxEl = useRef3(null);
1191
- const [qrOn, setQrOn] = useState9(true);
1192
- const [scannedResult, setScannedResult] = useState9("");
1193
- const onScanSuccess = (result) => {
1194
- setScannedResult(result == null ? void 0 : result.data);
1195
- callback(result == null ? void 0 : result.data);
1196
- };
1197
- const onScanFail = (err) => {
1198
- console.error(err);
1199
- };
1200
- useEffect5(() => {
1201
- if ((videoEl == null ? void 0 : videoEl.current) && !scanner.current) {
1202
- scanner.current = new QrScanner(videoEl.current, onScanSuccess, {
1203
- onDecodeError: onScanFail,
1204
- preferredCamera: "environment",
1205
- highlightScanRegion: true,
1206
- highlightCodeOutline: true,
1207
- overlay: (qrBoxEl == null ? void 0 : qrBoxEl.current) || void 0
1208
- });
1209
- scanner.current.start().then(() => setQrOn(true)).catch((err) => {
1210
- if (err) setQrOn(false);
1211
- });
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];
1212
2212
  }
1213
- return () => {
1214
- var _a;
1215
- if (!(videoEl == null ? void 0 : videoEl.current)) {
1216
- (_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
+ );
1217
2256
  }
1218
- };
1219
- }, []);
1220
- useEffect5(() => {
1221
- if (!qrOn)
1222
- alert(
1223
- "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" })
1224
2264
  );
1225
- }, [qrOn]);
1226
- return /* @__PURE__ */ jsxs3("div", { className: "qr-reader", children: [
1227
- /* @__PURE__ */ jsx3("video", { ref: videoEl }),
1228
- /* @__PURE__ */ jsx3("div", { ref: qrBoxEl, className: "qr-box" }),
1229
- scannedResult && /* @__PURE__ */ jsxs3(
1230
- "p",
1231
- {
1232
- style: {
1233
- position: "absolute",
1234
- top: 0,
1235
- left: 0,
1236
- zIndex: 99999,
1237
- color: "white"
1238
- },
1239
- children: [
1240
- "Scanned Result: ",
1241
- scannedResult
1242
- ]
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";
1243
2283
  }
1244
- )
1245
- ] });
1246
- };
1247
- 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
+ }
1248
2344
 
1249
- // src/components/recurso/QrCodeScanButton.tsx
1250
- import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
1251
- var QrCodeScanButton = ({ callback }) => {
1252
- const [showQr, setShowQr] = useState10(false);
1253
- const qrShowHandler = () => {
1254
- setShowQr((prev) => !prev);
1255
- };
1256
- return /* @__PURE__ */ jsxs4(
1257
- "div",
1258
- {
1259
- className: "hoverable-div",
1260
- style: {
1261
- border: "solid",
1262
- borderTopRightRadius: "3px",
1263
- borderBottomRightRadius: "3px",
1264
- padding: "8px",
1265
- borderLeft: "none",
1266
- borderColor: "#ccc",
1267
- borderWidth: "1px"
1268
- },
1269
- children: [
1270
- showQr && /* @__PURE__ */ jsx4(
1271
- QrReader_default,
1272
- {
1273
- callback: (v) => {
1274
- qrShowHandler();
1275
- callback(v);
1276
- }
1277
- }
1278
- ),
1279
- /* @__PURE__ */ jsx4(
1280
- BsQrCode,
1281
- {
1282
- size: 25,
1283
- onClick: () => {
1284
- qrShowHandler();
1285
- }
1286
- }
1287
- )
1288
- ]
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);
1289
2380
  }
2381
+ }, [saving, current, tarefaCtrl, tarefaId, fatherId, toast]);
2382
+ return useMemo14(
2383
+ () => ({ current, toggle, saving }),
2384
+ [current, toggle, saving]
1290
2385
  );
1291
- };
1292
- var QrCodeScanButton_default = QrCodeScanButton;
2386
+ }
1293
2387
 
1294
- // src/components/recurso/FindRecursoByTagField.tsx
1295
- import { jsx as jsx5 } from "react/jsx-runtime";
1296
- var FindRecursoByTagField = ({ callback }) => {
1297
- const recursoController = useHttpController("recurso");
1298
- const [selectedTag, setSelectedTag] = useState11(null);
1299
- const [reachedRecurso, setReachedRecurso] = useState11(null);
1300
- const findRecursoByTagIdHandler = async (tagId) => {
1301
- const r = await recursoController.read("findRecursoByTagId", tagId);
1302
- setReachedRecurso(r);
1303
- };
1304
- const findRecursoByTagDescriptionHandler = async (description) => {
1305
- const recurso = await recursoController.read(
1306
- "recurso/findByTagDescription",
1307
- description.replace(" ", "")
1308
- );
1309
- if (!callback) {
1310
- console.log(recurso);
1311
- } else {
1312
- callback(recurso, true);
1313
- }
1314
- };
1315
- const confirmRecursoSelectionButton = () => /* @__PURE__ */ jsx5(
1316
- "div",
1317
- {
1318
- className: "hoverable-div",
1319
- style: {
1320
- border: "solid",
1321
- borderTopRightRadius: "3px",
1322
- borderBottomRightRadius: "3px",
1323
- padding: "8px",
1324
- borderLeft: "none",
1325
- borderColor: "#ccc",
1326
- borderWidth: "1px"
1327
- },
1328
- children: /* @__PURE__ */ jsx5(GrCheckmark, { size: 25, onClick: () => callback(reachedRecurso, true) })
1329
- }
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]
1330
2399
  );
1331
- return /* @__PURE__ */ jsx5("div", { children: /* @__PURE__ */ jsx5(
1332
- AutoComplete_default,
1333
- {
1334
- sortKey: "id",
1335
- loadCondition: true,
1336
- loadFunc: () => recursoController.get("findActiveRecursosTags"),
1337
- displayKey: "descricao",
1338
- title: "Selecione ou Digite a TAG",
1339
- isBold: true,
1340
- actionButton: confirmRecursoSelectionButton,
1341
- actionButton2: () => /* @__PURE__ */ jsx5(
1342
- QrCodeScanButton_default,
1343
- {
1344
- callback: (description) => findRecursoByTagDescriptionHandler(description)
1345
- }
1346
- ),
1347
- onSelectedClick: (v) => {
1348
- setSelectedTag(v);
1349
- findRecursoByTagIdHandler(v.id);
1350
- },
1351
- 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);
1352
2417
  }
1353
- ) });
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
1354
2458
  };
1355
- 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;
1356
2489
 
1357
- // src/components/recurso/RecursoDisplayer.tsx
1358
- import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
1359
- var RecursoDisplayer = ({
1360
- selectedList = [],
1361
- onSaveRecurso,
1362
- singleReturn = false
1363
- }) => {
1364
- const arvoreEstruturalController = useHttpController("");
1365
- const branchLevelController = useHttpController("branchLevel");
1366
- const [branches, setBranches] = useState12([]);
1367
- const dispatch = useDispatch2();
1368
- const [localSelected, setLocalSelected] = useState12(selectedList);
1369
- const [selectorDisplay, setSelectorDisplay] = useState12("");
1370
- const [multiMode, setMultiMode] = useState12(false);
1371
- useEffect6(() => {
1372
- const init = async () => {
1373
- const b = await arvoreEstruturalController.get("branchByBranchLevel/1");
1374
- setBranches(b);
1375
- const lv = await branchLevelController.readAll();
1376
- dispatch(setLevels(lv));
1377
- };
1378
- init();
1379
- }, []);
1380
- const branchSetter = async (bn) => {
1381
- const copy = [...branches];
1382
- const branch = await arvoreEstruturalController.read("branch", bn.recurso.branch.id);
1383
- copy[bn.recurso.branch.branchLevel.level - 1] = {
1384
- ...branch,
1385
- nomeRecurso: bn.recurso.nome
1386
- };
1387
- setBranches(copy);
1388
- };
1389
- const backOnBranch = (branch) => {
1390
- const branchsToStay = branches.filter(
1391
- (bArray) => bArray.branchLevel.level <= branch.branchLevel.level
1392
- );
1393
- setBranches(branchsToStay);
1394
- };
1395
- return /* @__PURE__ */ jsxs5("div", { style: { width: "100%", padding: 0 }, children: [
1396
- /* @__PURE__ */ jsx6("div", { className: "d-flex justify-content-between align-items-center mb-3", children: /* @__PURE__ */ jsxs5("div", { children: [
1397
- /* @__PURE__ */ jsx6("label", { className: "me-2", children: "Selecionar Recurso Por:" }),
1398
- /* @__PURE__ */ jsx6(
1399
- Button,
1400
- {
1401
- size: "sm",
1402
- onClick: () => setSelectorDisplay("branch"),
1403
- variant: selectorDisplay === "branch" ? "primary" : "outline-primary",
1404
- className: "me-1",
1405
- 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
+ });
1406
2548
  }
1407
- ),
1408
- /* @__PURE__ */ jsx6(
1409
- Button,
1410
- {
1411
- size: "sm",
1412
- onClick: () => setSelectorDisplay("TAG"),
1413
- variant: selectorDisplay === "TAG" ? "primary" : "outline-primary",
1414
- 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
+ });
1415
2579
  }
1416
- )
1417
- ] }) }),
1418
- selectorDisplay === "branch" && branches.map((branch, i) => /* @__PURE__ */ jsx6(
1419
- BranchDropDisplay_default,
1420
- {
1421
- branch,
1422
- addBranch: branchSetter,
1423
- multiMode,
1424
- setMultiMode,
1425
- onSaveRecurso,
1426
- backOnBranch,
1427
- branches,
1428
- singleReturn
1429
- },
1430
- branch.id || i
1431
- )),
1432
- selectorDisplay === "TAG" && /* @__PURE__ */ jsx6(
1433
- FindRecursoByTagField_default,
1434
- {
1435
- callback: (rec, checked) => {
1436
- setLocalSelected([rec]);
1437
- 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) {
1438
2651
  }
2652
+ throw err;
1439
2653
  }
1440
- )
1441
- ] });
1442
- };
1443
- 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
+ }
1444
2702
 
1445
2703
  // src/reducers/pickerReducer.ts
1446
- import { createSlice as createSlice2 } from "@reduxjs/toolkit";
1447
- var initialState2 = {
2704
+ import { createSlice as createSlice8 } from "@reduxjs/toolkit";
2705
+ var initialState8 = {
1448
2706
  selected: null,
1449
2707
  items: [],
1450
2708
  visible: false,
1451
2709
  context: ""
1452
2710
  };
1453
- var pickerSlice = createSlice2({
2711
+ var pickerSlice = createSlice8({
1454
2712
  name: "picker",
1455
- initialState: initialState2,
2713
+ initialState: initialState8,
1456
2714
  reducers: {
1457
2715
  setPickerSelected(state, action) {
1458
2716
  state.selected = action.payload;
@@ -1467,7 +2725,7 @@ var pickerSlice = createSlice2({
1467
2725
  state.context = action.payload;
1468
2726
  },
1469
2727
  clearPicker() {
1470
- return initialState2;
2728
+ return initialState8;
1471
2729
  }
1472
2730
  }
1473
2731
  });
@@ -1480,6 +2738,20 @@ var {
1480
2738
  } = pickerSlice.actions;
1481
2739
  var pickerReducer_default = pickerSlice.reducer;
1482
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
+
1483
2755
  // src/utils/webVitals.ts
1484
2756
  function initWebVitals(observability) {
1485
2757
  if (typeof PerformanceObserver === "undefined") return;
@@ -1514,28 +2786,28 @@ function initWebVitals(observability) {
1514
2786
  }
1515
2787
 
1516
2788
  // src/utils/dateUtils.ts
1517
- import dayjs from "dayjs";
2789
+ import dayjs2 from "dayjs";
1518
2790
  function formatDate(date, format = "DD/MM/YYYY") {
1519
2791
  if (!date) return "";
1520
- return dayjs(date).format(format);
2792
+ return dayjs2(date).format(format);
1521
2793
  }
1522
2794
  function formatDateTime(date) {
1523
2795
  return formatDate(date, "DD/MM/YYYY HH:mm");
1524
2796
  }
1525
2797
  function isDateBefore(date1, date2) {
1526
- return dayjs(date1).isBefore(dayjs(date2));
2798
+ return dayjs2(date1).isBefore(dayjs2(date2));
1527
2799
  }
1528
2800
  function isDateAfter(date1, date2) {
1529
- return dayjs(date1).isAfter(dayjs(date2));
2801
+ return dayjs2(date1).isAfter(dayjs2(date2));
1530
2802
  }
1531
2803
  function daysBetween(start, end) {
1532
- return dayjs(end).diff(dayjs(start), "day");
2804
+ return dayjs2(end).diff(dayjs2(start), "day");
1533
2805
  }
1534
2806
  function addDays(date, days) {
1535
- return dayjs(date).add(days, "day").toDate();
2807
+ return dayjs2(date).add(days, "day").toDate();
1536
2808
  }
1537
2809
  function toISOString(date) {
1538
- return dayjs(date).toISOString();
2810
+ return dayjs2(date).toISOString();
1539
2811
  }
1540
2812
 
1541
2813
  // src/utils/stringUtils.ts
@@ -1557,62 +2829,134 @@ function isBlank(str) {
1557
2829
  return !str || str.trim().length === 0;
1558
2830
  }
1559
2831
  export {
2832
+ DEFAULT_KEY4 as CONTADOR_DEFAULT_KEY,
1560
2833
  CoreServiceBuilder,
1561
2834
  CoreServiceContext,
1562
2835
  DevAutoLogin,
2836
+ FILTER_COMBINE_MODES,
1563
2837
  FederatedBridge,
1564
2838
  FetchHttpAdapter,
2839
+ DEFAULT_KEY2 as INSPECAO_MODAL_DEFAULT_KEY,
1565
2840
  NullCoreService,
1566
2841
  NullHttpController,
1567
2842
  NullObservabilityAdapter,
1568
2843
  NullToastService,
1569
- RecursoDisplayer_default as RecursoDisplayer,
2844
+ DEFAULT_KEY3 as RECORRENCIA_DEFAULT_KEY,
1570
2845
  StandaloneProvider,
1571
2846
  TracingHttpAdapter,
2847
+ DEFAULT_KEY as UNIDADE_MATERIAL_DEFAULT_KEY,
2848
+ addContadorLimite,
1572
2849
  addDays,
1573
2850
  branchLevelReducer_default as branchLevelReducer,
1574
2851
  buildTraceparent,
1575
2852
  capitalize,
1576
2853
  clearBranchLevelForm,
2854
+ clearContador,
2855
+ clearInspecaoModal,
2856
+ clearMantenedorSlot,
1577
2857
  clearPicker,
2858
+ clearRecorrencia,
2859
+ clearUnidadeMaterial,
2860
+ contadorSlice_default as contadorReducer,
1578
2861
  createReducersBundle,
2862
+ createReducersFromManifest,
1579
2863
  daysBetween,
1580
2864
  formatDate,
1581
2865
  formatDateTime,
1582
2866
  generateSpanId,
1583
2867
  generateTraceId,
2868
+ groupMenuSections,
2869
+ hmsToSeconds,
1584
2870
  initWebVitals,
2871
+ inspecaoModalSlice_default as inspecaoModalReducer,
1585
2872
  isBlank,
1586
2873
  isDateAfter,
1587
2874
  isDateBefore,
2875
+ isHostedByCore,
2876
+ mantenedorPickerSlice_default as mantenedorPickerReducer,
2877
+ pickMantenedorTipoSlice_default as pickMantenedorTipoReducer,
1588
2878
  pickTextColorBasedOnBgColorAdvanced,
1589
2879
  pickerReducer_default as pickerReducer,
2880
+ populateContador,
2881
+ populateInspecaoModal,
2882
+ populateRecorrencia,
1590
2883
  populateToEdit,
2884
+ populateUnidadeMaterial,
2885
+ recorrenciaSlice_default as recorrenciaReducer,
1591
2886
  removeAccents,
2887
+ removeContadorLimiteAt,
2888
+ removeInspecaoLimiteAt,
2889
+ resetPickMantenedorTipo,
2890
+ secondsToHms,
2891
+ selectContador,
2892
+ selectInspecaoModal,
2893
+ selectRecorrencia,
2894
+ selectUnidadeMaterial,
1592
2895
  setColor,
2896
+ setContadorParametro,
2897
+ setContadorUnidade,
2898
+ setContadorValor,
1593
2899
  setExcludeLevels,
1594
2900
  setHaveComponente,
2901
+ setInspecaoLimites,
2902
+ setInspecaoNomeParametro,
2903
+ setInspecaoParametro,
2904
+ setInspecaoTipo,
2905
+ setInspecaoUnidadeParametro,
1595
2906
  setLevel,
1596
2907
  setLevels,
2908
+ setMantenedorError,
2909
+ setMantenedorLoading,
2910
+ setMantenedorOptions,
2911
+ setMantenedorPendingConfirm,
2912
+ setMantenedorSearchTerm,
1597
2913
  setNome,
2914
+ setPickMantenedorTipoAssigning,
2915
+ setPickMantenedorTipoError,
2916
+ setPickMantenedorTipoLoading,
2917
+ setPickMantenedorTipoOptions,
1598
2918
  setPickerContext,
1599
2919
  setPickerItems,
1600
2920
  setPickerSelected,
1601
2921
  setPickerVisible,
2922
+ setRecorrenciaDataInicio,
2923
+ setRecorrenciaEscala,
2924
+ setRecorrenciaValor,
2925
+ setMaterial as setUnidadeMaterialMaterial,
2926
+ setQuantidade as setUnidadeMaterialQuantidade,
2927
+ setUnidade as setUnidadeMaterialUnidade,
1602
2928
  slugify,
1603
2929
  toISOString,
1604
2930
  truncate,
2931
+ unidadeMaterialSlice_default as unidadeMaterialReducer,
2932
+ updateContadorLimiteAt,
2933
+ useAnexoManager,
2934
+ useAnexoManagerViewModel,
1605
2935
  useAnexoUpload,
2936
+ useContadorViewModel,
1606
2937
  useCoreService,
1607
2938
  useFetchData,
2939
+ useFilterCombineMode,
2940
+ useFindRecursoByTagViewModel,
1608
2941
  useFormStorage,
1609
2942
  useHttpController,
2943
+ useInspecaoModalViewModel,
2944
+ useJustificativaModalViewModel,
2945
+ useMantenedorPickerViewModel,
1610
2946
  useMatchingObject,
1611
2947
  useNavigator,
1612
2948
  useNotifications,
1613
2949
  useObservability,
2950
+ useObservacoesTarefaViewModel,
2951
+ usePickMantenedorTipoViewModel,
1614
2952
  usePostData,
2953
+ useRecorrenciaViewModel,
2954
+ useRecursoDisplayerViewModel,
1615
2955
  useSmartSearch,
2956
+ useTarefaItemViewModel,
2957
+ useTarefaStatusViewModel,
2958
+ useTimeFormat,
1616
2959
  useToast,
2960
+ useUnidadeMaterialViewModel,
1617
2961
  useValidation
1618
2962
  };