@bluemarble/bm-components 2.4.2 → 2.4.3
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.cjs +1119 -1123
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +87 -86
- package/dist/index.d.ts +87 -86
- package/dist/index.js +1137 -1141
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1179,6 +1179,114 @@ var require_react_is2 = __commonJS({
|
|
|
1179
1179
|
}
|
|
1180
1180
|
});
|
|
1181
1181
|
|
|
1182
|
+
// packages/nookies/index.ts
|
|
1183
|
+
import * as cookie from "cookie";
|
|
1184
|
+
import * as setCookieParser from "set-cookie-parser";
|
|
1185
|
+
|
|
1186
|
+
// packages/nookies/util.ts
|
|
1187
|
+
function isBrowser() {
|
|
1188
|
+
return typeof window !== "undefined";
|
|
1189
|
+
}
|
|
1190
|
+
function createCookie(name, value, options) {
|
|
1191
|
+
let sameSite = options.sameSite;
|
|
1192
|
+
if (sameSite === true) {
|
|
1193
|
+
sameSite = "strict";
|
|
1194
|
+
}
|
|
1195
|
+
if (sameSite === void 0 || sameSite === false) {
|
|
1196
|
+
sameSite = "lax";
|
|
1197
|
+
}
|
|
1198
|
+
const cookieToSet = { ...options, sameSite };
|
|
1199
|
+
delete cookieToSet.encode;
|
|
1200
|
+
return {
|
|
1201
|
+
name,
|
|
1202
|
+
value,
|
|
1203
|
+
...cookieToSet
|
|
1204
|
+
};
|
|
1205
|
+
}
|
|
1206
|
+
function hasSameProperties(a, b) {
|
|
1207
|
+
const aProps = Object.getOwnPropertyNames(a);
|
|
1208
|
+
const bProps = Object.getOwnPropertyNames(b);
|
|
1209
|
+
if (aProps.length !== bProps.length) {
|
|
1210
|
+
return false;
|
|
1211
|
+
}
|
|
1212
|
+
for (let i = 0; i < aProps.length; i++) {
|
|
1213
|
+
const propName = aProps[i];
|
|
1214
|
+
if (a[propName] !== b[propName]) {
|
|
1215
|
+
return false;
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
return true;
|
|
1219
|
+
}
|
|
1220
|
+
function areCookiesEqual(a, b) {
|
|
1221
|
+
let sameSiteSame = a.sameSite === b.sameSite;
|
|
1222
|
+
if (typeof a.sameSite === "string" && typeof b.sameSite === "string") {
|
|
1223
|
+
sameSiteSame = a.sameSite.toLowerCase() === b.sameSite.toLowerCase();
|
|
1224
|
+
}
|
|
1225
|
+
return hasSameProperties(
|
|
1226
|
+
{ ...a, sameSite: void 0 },
|
|
1227
|
+
{ ...b, sameSite: void 0 }
|
|
1228
|
+
) && sameSiteSame;
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
// packages/nookies/index.ts
|
|
1232
|
+
function parseCookies(ctx, options) {
|
|
1233
|
+
if (ctx?.req?.headers?.cookie) {
|
|
1234
|
+
return cookie.parse(ctx.req.headers.cookie, options);
|
|
1235
|
+
}
|
|
1236
|
+
if (isBrowser()) {
|
|
1237
|
+
return cookie.parse(document.cookie, options);
|
|
1238
|
+
}
|
|
1239
|
+
return {};
|
|
1240
|
+
}
|
|
1241
|
+
function setCookie(ctx, name, value, options = {}) {
|
|
1242
|
+
if (ctx?.res?.getHeader && ctx.res.setHeader) {
|
|
1243
|
+
if (ctx?.res?.finished) {
|
|
1244
|
+
console.warn(`Not setting "${name}" cookie. Response has finished.`);
|
|
1245
|
+
console.warn(`You should set cookie before res.send()`);
|
|
1246
|
+
return {};
|
|
1247
|
+
}
|
|
1248
|
+
let cookies = ctx.res.getHeader("Set-Cookie") || [];
|
|
1249
|
+
if (typeof cookies === "string") cookies = [cookies];
|
|
1250
|
+
if (typeof cookies === "number") cookies = [];
|
|
1251
|
+
const parsedCookies = setCookieParser.parse(cookies, {
|
|
1252
|
+
decodeValues: false
|
|
1253
|
+
});
|
|
1254
|
+
const newCookie = createCookie(name, value, options);
|
|
1255
|
+
let cookiesToSet = [];
|
|
1256
|
+
parsedCookies.forEach((parsedCookie) => {
|
|
1257
|
+
if (!areCookiesEqual(parsedCookie, newCookie)) {
|
|
1258
|
+
const serializedCookie = cookie.serialize(
|
|
1259
|
+
parsedCookie.name,
|
|
1260
|
+
parsedCookie.value,
|
|
1261
|
+
{
|
|
1262
|
+
// we prevent reencoding by default, but you might override it
|
|
1263
|
+
encode: (val) => val,
|
|
1264
|
+
...parsedCookie
|
|
1265
|
+
}
|
|
1266
|
+
);
|
|
1267
|
+
cookiesToSet.push(serializedCookie);
|
|
1268
|
+
}
|
|
1269
|
+
});
|
|
1270
|
+
cookiesToSet.push(cookie.serialize(name, value, options));
|
|
1271
|
+
ctx.res.setHeader("Set-Cookie", cookiesToSet);
|
|
1272
|
+
}
|
|
1273
|
+
if (isBrowser()) {
|
|
1274
|
+
if (options && options.httpOnly) {
|
|
1275
|
+
throw new Error("Can not set a httpOnly cookie in the browser.");
|
|
1276
|
+
}
|
|
1277
|
+
document.cookie = cookie.serialize(name, value, options);
|
|
1278
|
+
}
|
|
1279
|
+
return {};
|
|
1280
|
+
}
|
|
1281
|
+
function destroyCookie(ctx, name, options) {
|
|
1282
|
+
return setCookie(ctx, name, "", { ...options || {}, maxAge: -1 });
|
|
1283
|
+
}
|
|
1284
|
+
var nookies = {
|
|
1285
|
+
set: setCookie,
|
|
1286
|
+
get: parseCookies,
|
|
1287
|
+
destroy: destroyCookie
|
|
1288
|
+
};
|
|
1289
|
+
|
|
1182
1290
|
// src/components/Grid/Grid.tsx
|
|
1183
1291
|
import React7, {
|
|
1184
1292
|
useEffect,
|
|
@@ -4480,1222 +4588,1110 @@ var BaseDialog = {
|
|
|
4480
4588
|
Body: BaseDialogBody
|
|
4481
4589
|
};
|
|
4482
4590
|
|
|
4483
|
-
// src/
|
|
4484
|
-
|
|
4485
|
-
|
|
4486
|
-
|
|
4487
|
-
|
|
4488
|
-
|
|
4489
|
-
this.status = status;
|
|
4490
|
-
}
|
|
4591
|
+
// src/contexts/FormHelperProvider.tsx
|
|
4592
|
+
import React30 from "react";
|
|
4593
|
+
import { createContext as createContext3 } from "react";
|
|
4594
|
+
var FormHelperContext = createContext3({});
|
|
4595
|
+
var FormHelperProvider = ({ formatErrorMessage, api, children }) => {
|
|
4596
|
+
return /* @__PURE__ */ React30.createElement(FormHelperContext.Provider, { value: { formatErrorMessage, api } }, children);
|
|
4491
4597
|
};
|
|
4492
4598
|
|
|
4493
|
-
// src/
|
|
4494
|
-
|
|
4495
|
-
|
|
4496
|
-
super(message);
|
|
4497
|
-
this.message = message;
|
|
4498
|
-
this.stack = `DomainError: ${message}`;
|
|
4499
|
-
}
|
|
4500
|
-
};
|
|
4599
|
+
// src/contexts/AlertContext.tsx
|
|
4600
|
+
import React32, { useCallback as useCallback2 } from "react";
|
|
4601
|
+
import { createContext as createContext4, useState as useState6 } from "react";
|
|
4501
4602
|
|
|
4502
|
-
// src/
|
|
4503
|
-
|
|
4504
|
-
|
|
4505
|
-
|
|
4506
|
-
|
|
4507
|
-
|
|
4508
|
-
|
|
4509
|
-
|
|
4510
|
-
|
|
4511
|
-
|
|
4512
|
-
|
|
4513
|
-
|
|
4514
|
-
|
|
4515
|
-
|
|
4516
|
-
|
|
4517
|
-
|
|
4518
|
-
|
|
4519
|
-
|
|
4520
|
-
|
|
4521
|
-
|
|
4522
|
-
|
|
4523
|
-
|
|
4524
|
-
|
|
4525
|
-
|
|
4526
|
-
|
|
4527
|
-
|
|
4528
|
-
|
|
4529
|
-
|
|
4530
|
-
|
|
4531
|
-
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
|
|
4535
|
-
if (!currentMethod) throw new HttpError(500, "M\xE9todo n\xE3o encontrado");
|
|
4536
|
-
const methodWithMiddlewares = this.middlewares.reduce(
|
|
4537
|
-
(acc, fn) => fn(acc, options),
|
|
4538
|
-
currentMethod
|
|
4539
|
-
);
|
|
4540
|
-
return await methodWithMiddlewares(req, res, options);
|
|
4541
|
-
} catch (error) {
|
|
4542
|
-
if (error instanceof DomainError) return res.status(400).json(error.message);
|
|
4543
|
-
if (error instanceof HttpError) return res.status(error.status).json(error.message);
|
|
4544
|
-
this.onError(req, res, error);
|
|
4545
|
-
throw error;
|
|
4546
|
-
} finally {
|
|
4547
|
-
await this.onFinally(req, res);
|
|
4548
|
-
}
|
|
4549
|
-
};
|
|
4550
|
-
}
|
|
4551
|
-
buildFactory(factory) {
|
|
4552
|
-
const options = {
|
|
4553
|
-
public: this.public
|
|
4554
|
-
};
|
|
4555
|
-
return async (req, res) => {
|
|
4556
|
-
const methods = factory(req, res);
|
|
4557
|
-
const handler = methods[req.method];
|
|
4558
|
-
if (!handler) throw new HttpError(405, "M\xE9todo inv\xE1lido");
|
|
4559
|
-
const methodWithMiddlewares = this.middlewares.reduce((acc, fn) => {
|
|
4560
|
-
return fn(acc, options);
|
|
4561
|
-
}, handler);
|
|
4562
|
-
return await methodWithMiddlewares(req, res, options);
|
|
4563
|
-
};
|
|
4564
|
-
}
|
|
4565
|
-
static build(factory, options) {
|
|
4566
|
-
const helper = new _ApiHelper({
|
|
4567
|
-
...options
|
|
4568
|
-
}).buildFactory(factory);
|
|
4569
|
-
return helper;
|
|
4570
|
-
}
|
|
4571
|
-
static parse(body, parser) {
|
|
4572
|
-
try {
|
|
4573
|
-
const object = parser.parse(body);
|
|
4574
|
-
return object;
|
|
4575
|
-
} catch (error) {
|
|
4576
|
-
throw new HttpError(400, {
|
|
4577
|
-
code: "invalid.body",
|
|
4578
|
-
error: "Dados inv\xE1lidos",
|
|
4579
|
-
details: error
|
|
4580
|
-
});
|
|
4581
|
-
}
|
|
4582
|
-
}
|
|
4583
|
-
/** @deprecated Use {@Link ApiHelper.build} instead. */
|
|
4584
|
-
static create({ onFinally }) {
|
|
4585
|
-
return new _ApiHelper({
|
|
4586
|
-
onFinally
|
|
4587
|
-
});
|
|
4588
|
-
}
|
|
4603
|
+
// src/components/Toast/index.tsx
|
|
4604
|
+
import React31 from "react";
|
|
4605
|
+
import { Alert, IconButton as IconButton5, Snackbar } from "@mui/material";
|
|
4606
|
+
import { MdClose as MdClose3 } from "react-icons/md";
|
|
4607
|
+
var Toast = ({ open, onClose, severity, message }) => {
|
|
4608
|
+
return /* @__PURE__ */ React31.createElement(React31.Fragment, null, /* @__PURE__ */ React31.createElement(
|
|
4609
|
+
Snackbar,
|
|
4610
|
+
{
|
|
4611
|
+
open,
|
|
4612
|
+
autoHideDuration: 6e3,
|
|
4613
|
+
onClose,
|
|
4614
|
+
anchorOrigin: { vertical: "top", horizontal: "right" },
|
|
4615
|
+
sx: { zIndex: 99999999 }
|
|
4616
|
+
},
|
|
4617
|
+
/* @__PURE__ */ React31.createElement(
|
|
4618
|
+
Alert,
|
|
4619
|
+
{
|
|
4620
|
+
severity,
|
|
4621
|
+
elevation: 2,
|
|
4622
|
+
action: /* @__PURE__ */ React31.createElement(
|
|
4623
|
+
IconButton5,
|
|
4624
|
+
{
|
|
4625
|
+
"aria-label": "close",
|
|
4626
|
+
color: "inherit",
|
|
4627
|
+
size: "small",
|
|
4628
|
+
onClick: onClose
|
|
4629
|
+
},
|
|
4630
|
+
/* @__PURE__ */ React31.createElement(MdClose3, { fontSize: "inherit" })
|
|
4631
|
+
)
|
|
4632
|
+
},
|
|
4633
|
+
message
|
|
4634
|
+
)
|
|
4635
|
+
));
|
|
4589
4636
|
};
|
|
4590
|
-
/** @deprecated Use {@link ApiHelper.parser} instead. */
|
|
4591
|
-
_ApiHelper.parserErrorWrapper = _ApiHelper.parse;
|
|
4592
|
-
var ApiHelper = _ApiHelper;
|
|
4593
|
-
|
|
4594
|
-
// src/helpers/authHelper.ts
|
|
4595
|
-
import { serialize as serialize2 } from "cookie";
|
|
4596
|
-
import jwt from "jsonwebtoken";
|
|
4597
|
-
|
|
4598
|
-
// packages/nookies/index.ts
|
|
4599
|
-
import * as cookie from "cookie";
|
|
4600
|
-
import * as setCookieParser from "set-cookie-parser";
|
|
4601
4637
|
|
|
4602
|
-
//
|
|
4603
|
-
|
|
4604
|
-
|
|
4638
|
+
// src/contexts/AlertContext.tsx
|
|
4639
|
+
var AlertContext = createContext4({});
|
|
4640
|
+
var AlertProvider = ({ children }) => {
|
|
4641
|
+
const [severity, setSeverity] = useState6("info");
|
|
4642
|
+
const [message, setMessage] = useState6("");
|
|
4643
|
+
const [isVisible, setIsVisible] = useState6(false);
|
|
4644
|
+
const createAlert = useCallback2(
|
|
4645
|
+
(newMessage, severity2) => {
|
|
4646
|
+
setMessage(newMessage);
|
|
4647
|
+
setSeverity(severity2);
|
|
4648
|
+
setIsVisible(true);
|
|
4649
|
+
},
|
|
4650
|
+
[]
|
|
4651
|
+
);
|
|
4652
|
+
const onCloseToast = useCallback2(() => {
|
|
4653
|
+
setIsVisible(false);
|
|
4654
|
+
}, []);
|
|
4655
|
+
return /* @__PURE__ */ React32.createElement(AlertContext.Provider, { value: { createAlert } }, children, /* @__PURE__ */ React32.createElement(
|
|
4656
|
+
Toast,
|
|
4657
|
+
{
|
|
4658
|
+
open: isVisible,
|
|
4659
|
+
onClose: onCloseToast,
|
|
4660
|
+
severity,
|
|
4661
|
+
message
|
|
4662
|
+
}
|
|
4663
|
+
));
|
|
4664
|
+
};
|
|
4665
|
+
|
|
4666
|
+
// src/contexts/AuthContext.tsx
|
|
4667
|
+
import React33, { useCallback as useCallback8 } from "react";
|
|
4668
|
+
import {
|
|
4669
|
+
createContext as createContext5,
|
|
4670
|
+
useEffect as useEffect8,
|
|
4671
|
+
useState as useState11
|
|
4672
|
+
} from "react";
|
|
4673
|
+
|
|
4674
|
+
// src/hooks/useGrid.ts
|
|
4675
|
+
import { useCallback as useCallback4, useEffect as useEffect4, useMemo as useMemo3, useState as useState8 } from "react";
|
|
4676
|
+
|
|
4677
|
+
// src/hooks/useFilter.ts
|
|
4678
|
+
import { useCallback as useCallback3, useState as useState7 } from "react";
|
|
4679
|
+
|
|
4680
|
+
// src/components/utils/getObjectValue.ts
|
|
4681
|
+
function getObjectValue(obj) {
|
|
4682
|
+
return (prop) => {
|
|
4683
|
+
try {
|
|
4684
|
+
return prop.split(".").reduce((o, k) => o[k], obj);
|
|
4685
|
+
} catch (_) {
|
|
4686
|
+
return void 0;
|
|
4687
|
+
}
|
|
4688
|
+
};
|
|
4605
4689
|
}
|
|
4606
|
-
|
|
4607
|
-
|
|
4608
|
-
|
|
4609
|
-
|
|
4610
|
-
|
|
4611
|
-
|
|
4612
|
-
|
|
4690
|
+
|
|
4691
|
+
// src/hooks/useFilter.ts
|
|
4692
|
+
function useFilter(props = { defaultFilters: [] }) {
|
|
4693
|
+
const [selectedFilters, setSelectedFilters] = useState7(() => {
|
|
4694
|
+
const { defaultFilters } = props;
|
|
4695
|
+
return defaultFilters || [];
|
|
4696
|
+
});
|
|
4697
|
+
const filterBy = useCallback3((newFilter) => {
|
|
4698
|
+
const propToCompare = newFilter?.id ? "id" : "prop";
|
|
4699
|
+
function removeRepeatedFilters(filter) {
|
|
4700
|
+
return filter[propToCompare] !== newFilter[propToCompare];
|
|
4701
|
+
}
|
|
4702
|
+
setSelectedFilters((filters) => [
|
|
4703
|
+
...filters.filter(removeRepeatedFilters),
|
|
4704
|
+
newFilter
|
|
4705
|
+
]);
|
|
4706
|
+
}, []);
|
|
4707
|
+
const removeFilter = useCallback3(
|
|
4708
|
+
(prop, isId) => {
|
|
4709
|
+
const propToCompare = isId ? "id" : "prop";
|
|
4710
|
+
setSelectedFilters(
|
|
4711
|
+
selectedFilters.filter((filter) => filter[propToCompare] !== prop)
|
|
4712
|
+
);
|
|
4713
|
+
},
|
|
4714
|
+
[selectedFilters]
|
|
4715
|
+
);
|
|
4716
|
+
function clearAllFilters() {
|
|
4717
|
+
setSelectedFilters([]);
|
|
4613
4718
|
}
|
|
4614
|
-
const cookieToSet = { ...options, sameSite };
|
|
4615
|
-
delete cookieToSet.encode;
|
|
4616
4719
|
return {
|
|
4617
|
-
|
|
4618
|
-
|
|
4619
|
-
|
|
4720
|
+
filters: selectedFilters,
|
|
4721
|
+
filterBy,
|
|
4722
|
+
removeFilter,
|
|
4723
|
+
createFilter,
|
|
4724
|
+
clearAllFilters
|
|
4620
4725
|
};
|
|
4621
4726
|
}
|
|
4622
|
-
function
|
|
4623
|
-
|
|
4624
|
-
|
|
4625
|
-
|
|
4626
|
-
return false;
|
|
4627
|
-
}
|
|
4628
|
-
for (let i = 0; i < aProps.length; i++) {
|
|
4629
|
-
const propName = aProps[i];
|
|
4630
|
-
if (a[propName] !== b[propName]) {
|
|
4631
|
-
return false;
|
|
4632
|
-
}
|
|
4633
|
-
}
|
|
4634
|
-
return true;
|
|
4727
|
+
function isDate(date) {
|
|
4728
|
+
if (date instanceof Date) return true;
|
|
4729
|
+
else if (String(date).endsWith("Z")) return true;
|
|
4730
|
+
return false;
|
|
4635
4731
|
}
|
|
4636
|
-
function
|
|
4637
|
-
|
|
4638
|
-
|
|
4639
|
-
|
|
4732
|
+
function compareFilter(item, filter) {
|
|
4733
|
+
const itemValue = getObjectValue(item)(filter.prop);
|
|
4734
|
+
switch (filter.compareType) {
|
|
4735
|
+
case "equal":
|
|
4736
|
+
return itemValue === filter.value;
|
|
4737
|
+
case "notEqual":
|
|
4738
|
+
return itemValue !== filter.value;
|
|
4739
|
+
case "in":
|
|
4740
|
+
return filter.value.includes(itemValue);
|
|
4741
|
+
case "notIn":
|
|
4742
|
+
return !filter.value.includes(itemValue);
|
|
4743
|
+
case "valueIn":
|
|
4744
|
+
return itemValue.includes(filter.value);
|
|
4745
|
+
case "valueNotIn":
|
|
4746
|
+
return !itemValue.includes(filter.value);
|
|
4747
|
+
case "gte":
|
|
4748
|
+
return isDate(itemValue) ? new Date(String(itemValue)) >= filter.value : itemValue >= filter.value;
|
|
4749
|
+
case "gt":
|
|
4750
|
+
return isDate(itemValue) ? new Date(String(itemValue)) > filter.value : itemValue > filter.value;
|
|
4751
|
+
case "lte":
|
|
4752
|
+
return isDate(itemValue) ? new Date(String(itemValue)) <= filter.value : itemValue <= filter.value;
|
|
4753
|
+
case "lt":
|
|
4754
|
+
return isDate(itemValue) ? new Date(String(itemValue)) < filter.value : itemValue < filter.value;
|
|
4640
4755
|
}
|
|
4641
|
-
return hasSameProperties(
|
|
4642
|
-
{ ...a, sameSite: void 0 },
|
|
4643
|
-
{ ...b, sameSite: void 0 }
|
|
4644
|
-
) && sameSiteSame;
|
|
4645
4756
|
}
|
|
4646
|
-
|
|
4647
|
-
|
|
4648
|
-
|
|
4649
|
-
|
|
4650
|
-
|
|
4651
|
-
|
|
4652
|
-
|
|
4653
|
-
return cookie.parse(document.cookie, options);
|
|
4757
|
+
function createFilter(filters) {
|
|
4758
|
+
function apply(item) {
|
|
4759
|
+
const satisfiedFilters = filters.reduce((acc, filter) => {
|
|
4760
|
+
if (compareFilter(item, filter)) acc += 1;
|
|
4761
|
+
return acc;
|
|
4762
|
+
}, 0);
|
|
4763
|
+
return satisfiedFilters === filters.length;
|
|
4654
4764
|
}
|
|
4655
|
-
return {
|
|
4765
|
+
return {
|
|
4766
|
+
apply
|
|
4767
|
+
};
|
|
4656
4768
|
}
|
|
4657
|
-
|
|
4658
|
-
|
|
4659
|
-
|
|
4660
|
-
|
|
4661
|
-
|
|
4662
|
-
|
|
4663
|
-
|
|
4664
|
-
|
|
4665
|
-
|
|
4666
|
-
|
|
4667
|
-
const parsedCookies = setCookieParser.parse(cookies, {
|
|
4668
|
-
decodeValues: false
|
|
4669
|
-
});
|
|
4670
|
-
const newCookie = createCookie(name, value, options);
|
|
4671
|
-
let cookiesToSet = [];
|
|
4672
|
-
parsedCookies.forEach((parsedCookie) => {
|
|
4673
|
-
if (!areCookiesEqual(parsedCookie, newCookie)) {
|
|
4674
|
-
const serializedCookie = cookie.serialize(
|
|
4675
|
-
parsedCookie.name,
|
|
4676
|
-
parsedCookie.value,
|
|
4677
|
-
{
|
|
4678
|
-
// we prevent reencoding by default, but you might override it
|
|
4679
|
-
encode: (val) => val,
|
|
4680
|
-
...parsedCookie
|
|
4681
|
-
}
|
|
4682
|
-
);
|
|
4683
|
-
cookiesToSet.push(serializedCookie);
|
|
4769
|
+
|
|
4770
|
+
// src/helpers/sortHelper.ts
|
|
4771
|
+
function SortHelper(...fields) {
|
|
4772
|
+
return (a, b) => {
|
|
4773
|
+
for (const field of fields) {
|
|
4774
|
+
let direction = 1;
|
|
4775
|
+
let key = field;
|
|
4776
|
+
if (field.startsWith("-")) {
|
|
4777
|
+
direction = -1;
|
|
4778
|
+
key = field.slice(1);
|
|
4684
4779
|
}
|
|
4685
|
-
|
|
4686
|
-
|
|
4687
|
-
|
|
4688
|
-
|
|
4689
|
-
if (isBrowser()) {
|
|
4690
|
-
if (options && options.httpOnly) {
|
|
4691
|
-
throw new Error("Can not set a httpOnly cookie in the browser.");
|
|
4780
|
+
const aVal = a[key];
|
|
4781
|
+
const bVal = b[key];
|
|
4782
|
+
if (aVal > bVal) return direction;
|
|
4783
|
+
if (aVal < bVal) return -direction;
|
|
4692
4784
|
}
|
|
4693
|
-
|
|
4694
|
-
}
|
|
4695
|
-
return {};
|
|
4696
|
-
}
|
|
4697
|
-
function destroyCookie(ctx, name, options) {
|
|
4698
|
-
return setCookie(ctx, name, "", { ...options || {}, maxAge: -1 });
|
|
4785
|
+
return 0;
|
|
4786
|
+
};
|
|
4699
4787
|
}
|
|
4700
|
-
var nookies = {
|
|
4701
|
-
set: setCookie,
|
|
4702
|
-
get: parseCookies,
|
|
4703
|
-
destroy: destroyCookie
|
|
4704
|
-
};
|
|
4705
4788
|
|
|
4706
|
-
// src/
|
|
4707
|
-
|
|
4708
|
-
|
|
4709
|
-
|
|
4710
|
-
|
|
4711
|
-
|
|
4712
|
-
|
|
4789
|
+
// src/hooks/useGrid.ts
|
|
4790
|
+
function useGrid({
|
|
4791
|
+
columns,
|
|
4792
|
+
filters,
|
|
4793
|
+
search,
|
|
4794
|
+
rowsPerPageOptions = [30, 60, 100],
|
|
4795
|
+
defaultData: externalDefaultData,
|
|
4796
|
+
defaultCurrentPage,
|
|
4797
|
+
defaultSortedBy
|
|
4713
4798
|
}) {
|
|
4714
|
-
const
|
|
4715
|
-
|
|
4716
|
-
|
|
4717
|
-
|
|
4718
|
-
|
|
4719
|
-
const
|
|
4720
|
-
|
|
4721
|
-
|
|
4722
|
-
|
|
4723
|
-
|
|
4724
|
-
|
|
4725
|
-
|
|
4726
|
-
|
|
4727
|
-
|
|
4728
|
-
|
|
4729
|
-
|
|
4730
|
-
|
|
4731
|
-
|
|
4732
|
-
}
|
|
4733
|
-
|
|
4734
|
-
|
|
4735
|
-
|
|
4736
|
-
|
|
4737
|
-
|
|
4738
|
-
|
|
4739
|
-
|
|
4740
|
-
|
|
4741
|
-
|
|
4742
|
-
|
|
4743
|
-
|
|
4744
|
-
|
|
4745
|
-
|
|
4746
|
-
|
|
4747
|
-
|
|
4748
|
-
|
|
4749
|
-
|
|
4750
|
-
|
|
4751
|
-
|
|
4752
|
-
|
|
4753
|
-
|
|
4754
|
-
refreshToken: uniqueToken
|
|
4755
|
-
};
|
|
4756
|
-
};
|
|
4757
|
-
this.invalidateCookies = (res) => {
|
|
4758
|
-
return res.setHeader("Set-Cookie", [
|
|
4759
|
-
serialize2(this.cookies.sessionToken, "", {
|
|
4760
|
-
maxAge: -1,
|
|
4761
|
-
path: "/"
|
|
4762
|
-
}),
|
|
4763
|
-
serialize2(this.cookies.refreshToken, "", {
|
|
4764
|
-
maxAge: -1,
|
|
4765
|
-
path: "/"
|
|
4766
|
-
})
|
|
4767
|
-
]);
|
|
4768
|
-
};
|
|
4769
|
-
this.cookies = cookies;
|
|
4770
|
-
this.oauth = oauth;
|
|
4771
|
-
this.tokenExpTimeInSeconds = tokenExpTimeInSeconds;
|
|
4772
|
-
this.onLogin = onLogin;
|
|
4773
|
-
this.onValidateRefreshToken = onValidateRefreshToken;
|
|
4774
|
-
this.onInvalidateRefreshToken = onInvalidateRefreshToken;
|
|
4775
|
-
this.onCreateRefreshToken = onCreateRefreshToken;
|
|
4776
|
-
this.onGetUserData = onGetUserData;
|
|
4777
|
-
}
|
|
4778
|
-
async handler(req, res) {
|
|
4779
|
-
if (!req.url) return res.status(400).json({ error: "url not sent" });
|
|
4780
|
-
if (req.url.endsWith("/login")) {
|
|
4781
|
-
const loginResult = await this.onLogin(req.body);
|
|
4782
|
-
if (loginResult.status === "success") {
|
|
4783
|
-
const { refreshToken, token } = await this.generateJwtAndRefreshToken(
|
|
4784
|
-
loginResult.userId,
|
|
4785
|
-
{}
|
|
4786
|
-
);
|
|
4787
|
-
setCookie({ res }, this.cookies.sessionToken, token, {
|
|
4788
|
-
secure: true,
|
|
4789
|
-
maxAge: 60 * 60 * 24 * 30,
|
|
4790
|
-
// 30 days
|
|
4791
|
-
path: "/",
|
|
4792
|
-
sameSite: true
|
|
4793
|
-
});
|
|
4794
|
-
setCookie({ res }, this.cookies.refreshToken, refreshToken, {
|
|
4795
|
-
secure: true,
|
|
4796
|
-
maxAge: 60 * 60 * 24 * 30,
|
|
4797
|
-
// 30 days
|
|
4798
|
-
path: "/",
|
|
4799
|
-
sameSite: true,
|
|
4800
|
-
httpOnly: true
|
|
4801
|
-
});
|
|
4802
|
-
return res.json({ token, refreshToken });
|
|
4803
|
-
}
|
|
4804
|
-
throw new HttpError(400, loginResult.response);
|
|
4805
|
-
}
|
|
4806
|
-
if (req.url.endsWith("/logout")) {
|
|
4807
|
-
this.invalidateCookies(res).end();
|
|
4808
|
-
}
|
|
4809
|
-
if (req.url.endsWith("/refresh")) {
|
|
4810
|
-
const error = decodeSessionToken({
|
|
4811
|
-
req,
|
|
4812
|
-
res,
|
|
4813
|
-
sessionTokenName: this.cookies.sessionToken,
|
|
4814
|
-
validate: false
|
|
4815
|
-
});
|
|
4816
|
-
if (error) return;
|
|
4817
|
-
const userId = String(req.user);
|
|
4818
|
-
const refreshToken = parseCookies({ req })[this.cookies.refreshToken];
|
|
4819
|
-
if (!refreshToken) {
|
|
4820
|
-
this.invalidateCookies(res);
|
|
4821
|
-
return res.status(400).json({
|
|
4822
|
-
error: "Refresh Token inv\xE1lido"
|
|
4823
|
-
});
|
|
4824
|
-
}
|
|
4825
|
-
const isValidRefreshToken = await this.onValidateRefreshToken(
|
|
4826
|
-
userId,
|
|
4827
|
-
refreshToken
|
|
4828
|
-
);
|
|
4829
|
-
if (!isValidRefreshToken) {
|
|
4830
|
-
this.invalidateCookies(res);
|
|
4831
|
-
return res.status(400).json({
|
|
4832
|
-
error: "Refresh Token inv\xE1lido"
|
|
4833
|
-
});
|
|
4834
|
-
}
|
|
4835
|
-
await this.onInvalidateRefreshToken(userId, refreshToken);
|
|
4836
|
-
const { token, refreshToken: newRefreshToken } = await this.generateJwtAndRefreshToken(userId, {});
|
|
4837
|
-
setCookie({ res }, this.cookies.sessionToken, token, {
|
|
4838
|
-
secure: true,
|
|
4839
|
-
maxAge: 60 * 60 * 24 * 30,
|
|
4840
|
-
// 30 days
|
|
4841
|
-
path: "/",
|
|
4842
|
-
sameSite: true
|
|
4843
|
-
});
|
|
4844
|
-
setCookie({ res }, this.cookies.refreshToken, newRefreshToken, {
|
|
4845
|
-
secure: true,
|
|
4846
|
-
maxAge: 60 * 60 * 24 * 30,
|
|
4847
|
-
// 30 days
|
|
4848
|
-
path: "/",
|
|
4849
|
-
sameSite: true,
|
|
4850
|
-
httpOnly: true
|
|
4851
|
-
});
|
|
4852
|
-
return res.json({
|
|
4853
|
-
token,
|
|
4854
|
-
refreshToken: newRefreshToken
|
|
4855
|
-
});
|
|
4856
|
-
}
|
|
4857
|
-
if (req.url.endsWith("/me")) {
|
|
4858
|
-
const error = decodeSessionToken({
|
|
4859
|
-
req,
|
|
4860
|
-
res,
|
|
4861
|
-
sessionTokenName: this.cookies.sessionToken,
|
|
4862
|
-
validate: true
|
|
4863
|
-
});
|
|
4864
|
-
if (error) return;
|
|
4865
|
-
if (!req.user)
|
|
4866
|
-
return res.status(400).json({ error: "Usu\xE1rio n\xE3o encontrado" });
|
|
4867
|
-
const userData = await this.onGetUserData(req.user);
|
|
4868
|
-
if (!userData)
|
|
4869
|
-
return res.status(400).json({ error: "Usu\xE1rio n\xE3o encontrado" });
|
|
4870
|
-
return res.json(userData);
|
|
4871
|
-
}
|
|
4872
|
-
if (req.url.endsWith("/oauth-url") && this.oauth) {
|
|
4873
|
-
const params = {
|
|
4874
|
-
client_id: this.oauth.client_id,
|
|
4875
|
-
redirect_uri: this.oauth.redirect_uri,
|
|
4876
|
-
scope: this.oauth.scope,
|
|
4877
|
-
response_type: "code",
|
|
4878
|
-
response_mode: "query"
|
|
4879
|
-
};
|
|
4880
|
-
const url = `https://login.microsoftonline.com/${this.oauth.tenant_id}/oauth2/v2.0/authorize?${new URLSearchParams(params)}`;
|
|
4881
|
-
return res.json({
|
|
4882
|
-
url
|
|
4883
|
-
});
|
|
4884
|
-
}
|
|
4885
|
-
return res.status(404).json({ error: "Route not found" });
|
|
4886
|
-
}
|
|
4887
|
-
async oauthSignInCallback(code) {
|
|
4888
|
-
if (!this.oauth) throw new Error("OAUTH variables is not defined");
|
|
4889
|
-
const body = {
|
|
4890
|
-
client_id: this.oauth.client_id,
|
|
4891
|
-
scope: this.oauth.scope,
|
|
4892
|
-
code,
|
|
4893
|
-
session_state: this.oauth.client_id,
|
|
4894
|
-
redirect_uri: this.oauth.redirect_uri,
|
|
4895
|
-
grant_type: "authorization_code",
|
|
4896
|
-
client_secret: this.oauth.client_secret
|
|
4897
|
-
};
|
|
4898
|
-
const response = await fetch(
|
|
4899
|
-
`https://login.microsoftonline.com/${this.oauth.tenant_id}/oauth2/v2.0/token`,
|
|
4900
|
-
{
|
|
4901
|
-
method: "POST",
|
|
4902
|
-
body: new URLSearchParams(body),
|
|
4903
|
-
headers: { "Content-Type": "application/x-www-form-urlencoded" }
|
|
4904
|
-
}
|
|
4905
|
-
);
|
|
4906
|
-
const data = await response.json();
|
|
4907
|
-
const decodedToken = jwt.decode(data.access_token);
|
|
4908
|
-
const email = decodedToken.upn;
|
|
4909
|
-
const fullName = `${decodedToken?.given_name} ${decodedToken?.family_name}`;
|
|
4910
|
-
return { decodedToken, email, fullName };
|
|
4911
|
-
}
|
|
4912
|
-
createOauthCallbackGetServerSideProps({
|
|
4913
|
-
onSuccessDestination,
|
|
4914
|
-
onFailedDestination
|
|
4915
|
-
}) {
|
|
4916
|
-
return async (ctx) => {
|
|
4917
|
-
if (!this.oauth) throw new Error("Oauth env variables are not defined");
|
|
4918
|
-
const code = ctx.query.code;
|
|
4919
|
-
if (!code)
|
|
4920
|
-
return {
|
|
4921
|
-
redirect: {
|
|
4922
|
-
permanent: false,
|
|
4923
|
-
destination: onFailedDestination || "/"
|
|
4924
|
-
}
|
|
4925
|
-
};
|
|
4926
|
-
try {
|
|
4927
|
-
const { fullName, email } = await this.oauthSignInCallback(code);
|
|
4928
|
-
const userExists = await this.onGetUserData(email);
|
|
4929
|
-
if (!userExists && !this.oauth.onCreateUser)
|
|
4930
|
-
throw new Error("User does not exists");
|
|
4931
|
-
if (!userExists && this.oauth.onCreateUser) {
|
|
4932
|
-
await this.oauth.onCreateUser({ fullname: fullName, email });
|
|
4799
|
+
const [defaultData, setDefaultData] = useState8(externalDefaultData || []);
|
|
4800
|
+
const [sortedBy, setSortedBy] = useState8(
|
|
4801
|
+
defaultSortedBy || []
|
|
4802
|
+
);
|
|
4803
|
+
const [currentPage, setCurrentPage] = useState8(defaultCurrentPage || 0);
|
|
4804
|
+
const [rowsPerPage, setRowsPerPage] = useState8(rowsPerPageOptions[0]);
|
|
4805
|
+
const toggleSortedDirection = useCallback4(
|
|
4806
|
+
(direction) => {
|
|
4807
|
+
if (direction === "asc") return "desc";
|
|
4808
|
+
return "asc";
|
|
4809
|
+
},
|
|
4810
|
+
[]
|
|
4811
|
+
);
|
|
4812
|
+
const clearSort = useCallback4(() => {
|
|
4813
|
+
setSortedBy([]);
|
|
4814
|
+
}, []);
|
|
4815
|
+
const appendSort = useCallback4((prop, direction) => {
|
|
4816
|
+
setSortedBy((prev) => [...prev, { prop, direction }]);
|
|
4817
|
+
}, []);
|
|
4818
|
+
const setSort = useCallback4((prop, direction) => {
|
|
4819
|
+
setSortedBy([{ prop, direction }]);
|
|
4820
|
+
}, []);
|
|
4821
|
+
const onSortBy = useCallback4(
|
|
4822
|
+
(prop) => {
|
|
4823
|
+
if (!prop) return;
|
|
4824
|
+
const currentSorted = sortedBy.find((p) => p.prop === prop);
|
|
4825
|
+
if (currentSorted) {
|
|
4826
|
+
if (currentSorted.direction === "asc") {
|
|
4827
|
+
setSortedBy((prev) => prev.filter((p) => p.prop !== prop));
|
|
4828
|
+
} else {
|
|
4829
|
+
setSortedBy((prev) => {
|
|
4830
|
+
const newArr = prev.map((p) => {
|
|
4831
|
+
if (p.prop !== prop) return p;
|
|
4832
|
+
return {
|
|
4833
|
+
prop: p.prop,
|
|
4834
|
+
direction: toggleSortedDirection(p.direction)
|
|
4835
|
+
};
|
|
4836
|
+
});
|
|
4837
|
+
return [...newArr].slice(0);
|
|
4838
|
+
});
|
|
4933
4839
|
}
|
|
4934
|
-
|
|
4935
|
-
|
|
4936
|
-
{}
|
|
4937
|
-
);
|
|
4938
|
-
setCookie(ctx, this.cookies.sessionToken, token, {
|
|
4939
|
-
secure: true,
|
|
4940
|
-
maxAge: 60 * 60 * 24 * 30,
|
|
4941
|
-
// 30 days
|
|
4942
|
-
path: "/"
|
|
4943
|
-
});
|
|
4944
|
-
setCookie(ctx, this.cookies.refreshToken, refreshToken, {
|
|
4945
|
-
secure: true,
|
|
4946
|
-
maxAge: 60 * 60 * 24 * 30,
|
|
4947
|
-
// 30 days
|
|
4948
|
-
path: "/",
|
|
4949
|
-
httpOnly: true
|
|
4950
|
-
});
|
|
4951
|
-
return {
|
|
4952
|
-
redirect: {
|
|
4953
|
-
destination: onSuccessDestination,
|
|
4954
|
-
permanent: false
|
|
4955
|
-
}
|
|
4956
|
-
};
|
|
4957
|
-
} catch (error) {
|
|
4958
|
-
return {
|
|
4959
|
-
props: {
|
|
4960
|
-
error: JSON.stringify(error)
|
|
4961
|
-
}
|
|
4962
|
-
};
|
|
4840
|
+
} else {
|
|
4841
|
+
setSortedBy((prev) => [...prev, { prop, direction: "desc" }]);
|
|
4963
4842
|
}
|
|
4964
|
-
}
|
|
4965
|
-
|
|
4966
|
-
|
|
4967
|
-
|
|
4968
|
-
|
|
4969
|
-
import { useCallback as useCallback3, useEffect as useEffect4, useMemo as useMemo3, useState as useState7 } from "react";
|
|
4970
|
-
|
|
4971
|
-
// src/hooks/useFilter.ts
|
|
4972
|
-
import { useCallback as useCallback2, useState as useState6 } from "react";
|
|
4973
|
-
|
|
4974
|
-
// src/components/utils/getObjectValue.ts
|
|
4975
|
-
function getObjectValue(obj) {
|
|
4976
|
-
return (prop) => {
|
|
4977
|
-
try {
|
|
4978
|
-
return prop.split(".").reduce((o, k) => o[k], obj);
|
|
4979
|
-
} catch (_) {
|
|
4980
|
-
return void 0;
|
|
4981
|
-
}
|
|
4982
|
-
};
|
|
4983
|
-
}
|
|
4984
|
-
|
|
4985
|
-
// src/hooks/useFilter.ts
|
|
4986
|
-
function useFilter(props = { defaultFilters: [] }) {
|
|
4987
|
-
const [selectedFilters, setSelectedFilters] = useState6(() => {
|
|
4988
|
-
const { defaultFilters } = props;
|
|
4989
|
-
return defaultFilters || [];
|
|
4990
|
-
});
|
|
4991
|
-
const filterBy = useCallback2((newFilter) => {
|
|
4992
|
-
const propToCompare = newFilter?.id ? "id" : "prop";
|
|
4993
|
-
function removeRepeatedFilters(filter) {
|
|
4994
|
-
return filter[propToCompare] !== newFilter[propToCompare];
|
|
4995
|
-
}
|
|
4996
|
-
setSelectedFilters((filters) => [
|
|
4997
|
-
...filters.filter(removeRepeatedFilters),
|
|
4998
|
-
newFilter
|
|
4999
|
-
]);
|
|
4843
|
+
},
|
|
4844
|
+
[toggleSortedDirection, sortedBy]
|
|
4845
|
+
);
|
|
4846
|
+
const set = useCallback4((data) => {
|
|
4847
|
+
setDefaultData(data);
|
|
5000
4848
|
}, []);
|
|
5001
|
-
const
|
|
5002
|
-
(
|
|
5003
|
-
|
|
5004
|
-
|
|
5005
|
-
|
|
5006
|
-
|
|
4849
|
+
const sortData = useCallback4(
|
|
4850
|
+
(data) => {
|
|
4851
|
+
if (sortedBy.length > 0) {
|
|
4852
|
+
const symbolDir = {
|
|
4853
|
+
asc: "",
|
|
4854
|
+
desc: "-"
|
|
4855
|
+
};
|
|
4856
|
+
const formattedKeys = sortedBy.map(
|
|
4857
|
+
({ prop, direction }) => `${symbolDir[direction]}${prop}`
|
|
4858
|
+
);
|
|
4859
|
+
return data.sort(SortHelper(...formattedKeys));
|
|
4860
|
+
} else return data;
|
|
5007
4861
|
},
|
|
5008
|
-
[
|
|
4862
|
+
[sortedBy]
|
|
5009
4863
|
);
|
|
5010
|
-
|
|
5011
|
-
|
|
5012
|
-
|
|
5013
|
-
|
|
5014
|
-
filters: selectedFilters,
|
|
5015
|
-
filterBy,
|
|
5016
|
-
removeFilter,
|
|
5017
|
-
createFilter,
|
|
5018
|
-
clearAllFilters
|
|
4864
|
+
const onPageChange = (pageNumber) => {
|
|
4865
|
+
if (pageNumber < 0) return;
|
|
4866
|
+
if (pageNumber > totalNumberOfPages) return;
|
|
4867
|
+
setCurrentPage(pageNumber);
|
|
5019
4868
|
};
|
|
5020
|
-
|
|
5021
|
-
|
|
5022
|
-
|
|
5023
|
-
|
|
5024
|
-
|
|
5025
|
-
|
|
5026
|
-
|
|
5027
|
-
|
|
5028
|
-
|
|
5029
|
-
|
|
5030
|
-
|
|
5031
|
-
|
|
5032
|
-
|
|
5033
|
-
|
|
5034
|
-
|
|
5035
|
-
|
|
5036
|
-
|
|
5037
|
-
|
|
5038
|
-
|
|
5039
|
-
|
|
5040
|
-
|
|
5041
|
-
|
|
5042
|
-
|
|
5043
|
-
|
|
5044
|
-
|
|
5045
|
-
|
|
5046
|
-
|
|
5047
|
-
|
|
5048
|
-
|
|
5049
|
-
}
|
|
5050
|
-
|
|
5051
|
-
|
|
5052
|
-
|
|
5053
|
-
|
|
5054
|
-
if (compareFilter(item, filter)) acc += 1;
|
|
5055
|
-
return acc;
|
|
5056
|
-
}, 0);
|
|
5057
|
-
return satisfiedFilters === filters.length;
|
|
5058
|
-
}
|
|
4869
|
+
const onChangeRowsPerPage = useCallback4(
|
|
4870
|
+
(rows) => {
|
|
4871
|
+
let totalNumberOfPages2 = Math.round(filteredData.length / rows) - 1;
|
|
4872
|
+
totalNumberOfPages2 = totalNumberOfPages2 <= 0 ? 0 : 1;
|
|
4873
|
+
if (currentPage > totalNumberOfPages2) setCurrentPage(totalNumberOfPages2);
|
|
4874
|
+
setRowsPerPage(rows);
|
|
4875
|
+
},
|
|
4876
|
+
[currentPage]
|
|
4877
|
+
);
|
|
4878
|
+
const orderedData = useMemo3(() => {
|
|
4879
|
+
if (sortedBy.length === 0) return defaultData;
|
|
4880
|
+
const newData = defaultData.slice(0);
|
|
4881
|
+
const sortedData = sortData(newData);
|
|
4882
|
+
return sortedData;
|
|
4883
|
+
}, [defaultData, sortData, sortedBy]);
|
|
4884
|
+
const filteredData = useMemo3(() => {
|
|
4885
|
+
let newData = orderedData.slice(0);
|
|
4886
|
+
if (search && search.value !== "") {
|
|
4887
|
+
const searchBy = createSearch(search);
|
|
4888
|
+
newData = newData.filter(searchBy);
|
|
4889
|
+
}
|
|
4890
|
+
if (!filters) return newData;
|
|
4891
|
+
const newFilter = createFilter(filters);
|
|
4892
|
+
return newData.filter(newFilter.apply);
|
|
4893
|
+
}, [orderedData, search, filters]);
|
|
4894
|
+
const paginatedData = useMemo3(() => {
|
|
4895
|
+
const startPage = currentPage * rowsPerPage;
|
|
4896
|
+
const endPage = startPage + rowsPerPage;
|
|
4897
|
+
return filteredData.slice(startPage, endPage);
|
|
4898
|
+
}, [currentPage, rowsPerPage, filteredData]);
|
|
4899
|
+
const totalNumberOfPages = Math.ceil(filteredData.length / rowsPerPage) - 1;
|
|
4900
|
+
useEffect4(() => {
|
|
4901
|
+
if (externalDefaultData) setDefaultData(externalDefaultData);
|
|
4902
|
+
}, [externalDefaultData]);
|
|
5059
4903
|
return {
|
|
5060
|
-
|
|
4904
|
+
data: paginatedData,
|
|
4905
|
+
orderedData,
|
|
4906
|
+
filteredData,
|
|
4907
|
+
defaultData,
|
|
4908
|
+
sortedBy,
|
|
4909
|
+
columns,
|
|
4910
|
+
currentPage,
|
|
4911
|
+
totalNumberOfPages: totalNumberOfPages < 0 ? 0 : totalNumberOfPages,
|
|
4912
|
+
rowsPerPageOptions,
|
|
4913
|
+
rowsPerPage,
|
|
4914
|
+
set,
|
|
4915
|
+
onSortBy,
|
|
4916
|
+
onPageChange,
|
|
4917
|
+
setRowsPerPage: onChangeRowsPerPage,
|
|
4918
|
+
appendSort,
|
|
4919
|
+
setSort,
|
|
4920
|
+
clearSort
|
|
5061
4921
|
};
|
|
5062
4922
|
}
|
|
5063
|
-
|
|
5064
|
-
|
|
5065
|
-
|
|
5066
|
-
return
|
|
5067
|
-
|
|
5068
|
-
|
|
5069
|
-
|
|
5070
|
-
|
|
5071
|
-
|
|
5072
|
-
|
|
5073
|
-
|
|
5074
|
-
|
|
5075
|
-
|
|
5076
|
-
|
|
5077
|
-
|
|
4923
|
+
var isNumberOrString = (value) => ["number", "string"].includes(typeof value);
|
|
4924
|
+
var concatenateKey = (key, prev) => {
|
|
4925
|
+
if (!prev) return key;
|
|
4926
|
+
return `${prev}.${key}`;
|
|
4927
|
+
};
|
|
4928
|
+
function searchKeysForValue(row, accKey, compare) {
|
|
4929
|
+
if (typeof row === "undefined") return false;
|
|
4930
|
+
const rowKeys = Object.keys(row);
|
|
4931
|
+
let match = false;
|
|
4932
|
+
for (const key of rowKeys) {
|
|
4933
|
+
if (match) break;
|
|
4934
|
+
const objValue = row[key];
|
|
4935
|
+
if (!objValue) continue;
|
|
4936
|
+
const concatenatedKey = concatenateKey(key, accKey);
|
|
4937
|
+
if (Array.isArray(objValue)) {
|
|
4938
|
+
match = objValue.some(
|
|
4939
|
+
(obj) => isNumberOrString(obj) ? compare(concatenatedKey, obj) : searchKeysForValue(obj, concatenatedKey, compare)
|
|
4940
|
+
);
|
|
4941
|
+
continue;
|
|
5078
4942
|
}
|
|
5079
|
-
|
|
4943
|
+
if (typeof objValue === "object") {
|
|
4944
|
+
match = searchKeysForValue(objValue, concatenatedKey, compare);
|
|
4945
|
+
continue;
|
|
4946
|
+
}
|
|
4947
|
+
match = compare(concatenatedKey, row[key]);
|
|
4948
|
+
}
|
|
4949
|
+
return match;
|
|
4950
|
+
}
|
|
4951
|
+
var normalize = (str) => str.normalize("NFD").replace(/[\u0300-\u036f]/g, "");
|
|
4952
|
+
function createSearch(options) {
|
|
4953
|
+
const searchValue = options.caseSensitive ? options.value : String(options.value).toLowerCase();
|
|
4954
|
+
function getValue2(value) {
|
|
4955
|
+
if (options.caseSensitive) return String(value);
|
|
4956
|
+
return String(value).toLowerCase();
|
|
4957
|
+
}
|
|
4958
|
+
function compare(key, objValue) {
|
|
4959
|
+
if (options.ignoredKeys) {
|
|
4960
|
+
const isIgnoredKey = options.ignoredKeys.includes(key);
|
|
4961
|
+
if (isIgnoredKey) return false;
|
|
4962
|
+
}
|
|
4963
|
+
const value = getValue2(objValue);
|
|
4964
|
+
if (options.exact) return value === searchValue;
|
|
4965
|
+
if (options.ignoreAccentMark) return normalize(value).includes(normalize(searchValue));
|
|
4966
|
+
return value.includes(searchValue);
|
|
4967
|
+
}
|
|
4968
|
+
return (row) => {
|
|
4969
|
+
const match = searchKeysForValue(row, "", compare);
|
|
4970
|
+
return match;
|
|
5080
4971
|
};
|
|
5081
4972
|
}
|
|
5082
4973
|
|
|
5083
|
-
// src/hooks/
|
|
5084
|
-
|
|
4974
|
+
// src/hooks/useAsyncGrid.ts
|
|
4975
|
+
import { useCallback as useCallback5, useEffect as useEffect5, useState as useState9 } from "react";
|
|
4976
|
+
function useAsyncGrid({
|
|
5085
4977
|
columns,
|
|
5086
|
-
filters,
|
|
4978
|
+
filters = [],
|
|
5087
4979
|
search,
|
|
5088
4980
|
rowsPerPageOptions = [30, 60, 100],
|
|
4981
|
+
onRequest,
|
|
4982
|
+
axiosInstance,
|
|
4983
|
+
url,
|
|
5089
4984
|
defaultData: externalDefaultData,
|
|
5090
4985
|
defaultCurrentPage,
|
|
5091
4986
|
defaultSortedBy
|
|
5092
4987
|
}) {
|
|
5093
|
-
const [defaultData, setDefaultData] =
|
|
5094
|
-
const [sortedBy, setSortedBy] =
|
|
4988
|
+
const [defaultData, setDefaultData] = useState9(externalDefaultData || []);
|
|
4989
|
+
const [sortedBy, setSortedBy] = useState9(
|
|
5095
4990
|
defaultSortedBy || []
|
|
5096
4991
|
);
|
|
5097
|
-
const [
|
|
5098
|
-
const [
|
|
5099
|
-
const
|
|
5100
|
-
|
|
5101
|
-
|
|
5102
|
-
|
|
4992
|
+
const [totalNumberOfItems, setTotalNumberOfItems] = useState9(0);
|
|
4993
|
+
const [isLoading, setIsLoading] = useState9(false);
|
|
4994
|
+
const [currentPage, setCurrentPage] = useState9(defaultCurrentPage || 0);
|
|
4995
|
+
const [rowsPerPage, setRowsPerPage] = useState9(rowsPerPageOptions[0]);
|
|
4996
|
+
const totalNumberOfPages = Math.ceil(totalNumberOfItems / rowsPerPage) - 1;
|
|
4997
|
+
const toggleSortedDirection = useCallback5(
|
|
4998
|
+
(direction) => {
|
|
4999
|
+
if (direction === "asc") return "desc";
|
|
5000
|
+
return "asc";
|
|
5001
|
+
},
|
|
5002
|
+
[]
|
|
5003
|
+
);
|
|
5004
|
+
const setSort = useCallback5((prop, direction) => {
|
|
5005
|
+
setSortedBy((prev) => [...prev, { prop, direction }]);
|
|
5006
|
+
}, []);
|
|
5007
|
+
const onSortBy = useCallback5(
|
|
5008
|
+
async (prop) => {
|
|
5009
|
+
if (!prop) return;
|
|
5010
|
+
let finalArr = [];
|
|
5011
|
+
const currentSorted = sortedBy.find((p) => p.prop === prop);
|
|
5012
|
+
if (currentSorted) {
|
|
5013
|
+
if (currentSorted.direction === "asc") {
|
|
5014
|
+
finalArr = sortedBy.filter((p) => p.prop !== prop);
|
|
5015
|
+
} else {
|
|
5016
|
+
finalArr = sortedBy.map((p) => {
|
|
5017
|
+
if (p.prop !== prop) return p;
|
|
5018
|
+
return {
|
|
5019
|
+
prop: p.prop,
|
|
5020
|
+
direction: toggleSortedDirection(p.direction)
|
|
5021
|
+
};
|
|
5022
|
+
});
|
|
5023
|
+
}
|
|
5024
|
+
} else {
|
|
5025
|
+
finalArr = [...sortedBy, { prop, direction: "desc" }];
|
|
5026
|
+
}
|
|
5027
|
+
await updateGridContent({
|
|
5028
|
+
page: currentPage,
|
|
5029
|
+
sortedBy: finalArr,
|
|
5030
|
+
rowsPerPage
|
|
5031
|
+
});
|
|
5032
|
+
},
|
|
5033
|
+
[sortedBy, toggleSortedDirection, rowsPerPage, currentPage]
|
|
5034
|
+
);
|
|
5035
|
+
const set = useCallback5((data) => {
|
|
5036
|
+
setDefaultData(data);
|
|
5037
|
+
}, []);
|
|
5038
|
+
const baseRequest = useCallback5(
|
|
5039
|
+
async ({
|
|
5040
|
+
page,
|
|
5041
|
+
search: search2,
|
|
5042
|
+
filters: filters2,
|
|
5043
|
+
sortedBy: sortedBy2,
|
|
5044
|
+
rowsPerPage: rowsPerPage2
|
|
5045
|
+
}) => {
|
|
5046
|
+
if (!axiosInstance) throw new Error("Axios instance not provided");
|
|
5047
|
+
try {
|
|
5048
|
+
const params = new URLSearchParams({
|
|
5049
|
+
page: String(page),
|
|
5050
|
+
rowsPerPage: String(rowsPerPage2),
|
|
5051
|
+
searchText: search2?.value || "",
|
|
5052
|
+
sort: sortedBy2.map(({ prop, direction }) => `${prop}:${direction}`).join(","),
|
|
5053
|
+
filters: filters2.map(
|
|
5054
|
+
(filter) => `${filter.prop}:${filter.compareType}:${filter.value}`
|
|
5055
|
+
).join(",")
|
|
5056
|
+
});
|
|
5057
|
+
const pathWithParams = `${url}?${params.toString()}`;
|
|
5058
|
+
const { data } = await axiosInstance.get(pathWithParams);
|
|
5059
|
+
setTotalNumberOfItems(data.totalNumberOfItems);
|
|
5060
|
+
return data.rows;
|
|
5061
|
+
} catch (_) {
|
|
5062
|
+
return [];
|
|
5063
|
+
}
|
|
5064
|
+
},
|
|
5065
|
+
[axiosInstance, url]
|
|
5066
|
+
);
|
|
5067
|
+
const updateGridContent = useCallback5(
|
|
5068
|
+
async ({
|
|
5069
|
+
page,
|
|
5070
|
+
sortedBy: sortedBy2,
|
|
5071
|
+
rowsPerPage: rowsPerPage2
|
|
5072
|
+
}) => {
|
|
5073
|
+
setIsLoading(true);
|
|
5074
|
+
try {
|
|
5075
|
+
const props = {
|
|
5076
|
+
page,
|
|
5077
|
+
rowsPerPage: rowsPerPage2,
|
|
5078
|
+
sortedBy: sortedBy2,
|
|
5079
|
+
search,
|
|
5080
|
+
filters
|
|
5081
|
+
};
|
|
5082
|
+
const result = !onRequest ? await baseRequest(props) : await onRequest(props);
|
|
5083
|
+
setSortedBy(sortedBy2);
|
|
5084
|
+
setRowsPerPage(rowsPerPage2);
|
|
5085
|
+
set(result);
|
|
5086
|
+
setCurrentPage(page);
|
|
5087
|
+
} finally {
|
|
5088
|
+
setIsLoading(false);
|
|
5089
|
+
}
|
|
5090
|
+
},
|
|
5091
|
+
[set, search, filters, onRequest, baseRequest]
|
|
5092
|
+
);
|
|
5093
|
+
const onPageChange = useCallback5(
|
|
5094
|
+
(pageNumber) => {
|
|
5095
|
+
if (pageNumber < 0) return;
|
|
5096
|
+
if (pageNumber > totalNumberOfPages) return;
|
|
5097
|
+
updateGridContent({ page: pageNumber, sortedBy, rowsPerPage });
|
|
5098
|
+
},
|
|
5099
|
+
[updateGridContent, totalNumberOfPages, sortedBy, rowsPerPage]
|
|
5100
|
+
);
|
|
5101
|
+
const onChangeRowsPerPage = useCallback5(
|
|
5102
|
+
(rows) => {
|
|
5103
|
+
let totalNumberOfPages2 = Math.round(totalNumberOfItems / rows) - 1;
|
|
5104
|
+
totalNumberOfPages2 = totalNumberOfPages2 <= 0 ? 0 : 1;
|
|
5105
|
+
if (currentPage > totalNumberOfPages2)
|
|
5106
|
+
updateGridContent({
|
|
5107
|
+
page: totalNumberOfPages2,
|
|
5108
|
+
sortedBy,
|
|
5109
|
+
rowsPerPage: rows
|
|
5110
|
+
});
|
|
5111
|
+
updateGridContent({
|
|
5112
|
+
page: currentPage,
|
|
5113
|
+
sortedBy,
|
|
5114
|
+
rowsPerPage: rows
|
|
5115
|
+
});
|
|
5116
|
+
},
|
|
5117
|
+
[updateGridContent, totalNumberOfItems, sortedBy, currentPage]
|
|
5118
|
+
);
|
|
5119
|
+
const displayData = defaultData;
|
|
5120
|
+
useEffect5(() => {
|
|
5121
|
+
updateGridContent({ page: 0, sortedBy: [], rowsPerPage });
|
|
5122
|
+
}, [updateGridContent, rowsPerPage]);
|
|
5123
|
+
return {
|
|
5124
|
+
data: displayData,
|
|
5125
|
+
set,
|
|
5126
|
+
onSortBy,
|
|
5127
|
+
sortedBy,
|
|
5128
|
+
defaultData,
|
|
5129
|
+
columns,
|
|
5130
|
+
currentPage,
|
|
5131
|
+
totalNumberOfPages: totalNumberOfPages < 0 ? 0 : totalNumberOfPages,
|
|
5132
|
+
onPageChange,
|
|
5133
|
+
setRowsPerPage: onChangeRowsPerPage,
|
|
5134
|
+
rowsPerPageOptions,
|
|
5135
|
+
rowsPerPage,
|
|
5136
|
+
setSort,
|
|
5137
|
+
isLoading,
|
|
5138
|
+
setIsLoading
|
|
5139
|
+
};
|
|
5140
|
+
}
|
|
5141
|
+
|
|
5142
|
+
// src/hooks/useEvent.ts
|
|
5143
|
+
import { useEffect as useEffect6 } from "react";
|
|
5144
|
+
function useEvent(event, handler, passive = false) {
|
|
5145
|
+
useEffect6(() => {
|
|
5146
|
+
window.addEventListener(event, handler, passive);
|
|
5147
|
+
return function cleanup() {
|
|
5148
|
+
window.removeEventListener(event, handler);
|
|
5149
|
+
};
|
|
5150
|
+
});
|
|
5151
|
+
}
|
|
5152
|
+
|
|
5153
|
+
// src/hooks/useLoading.ts
|
|
5154
|
+
import { useCallback as useCallback6, useState as useState10 } from "react";
|
|
5155
|
+
function useLoading() {
|
|
5156
|
+
const [state, setState] = useState10([]);
|
|
5157
|
+
const isLoading = useCallback6((prop) => state.includes(prop), [state]);
|
|
5158
|
+
const setLoading = useCallback6((prop, remove) => {
|
|
5159
|
+
if (remove)
|
|
5160
|
+
setState((prevState) => prevState.filter((state2) => state2 !== prop));
|
|
5161
|
+
else setState((prevState) => [...prevState, prop]);
|
|
5162
|
+
}, []);
|
|
5163
|
+
return { isLoading, setLoading };
|
|
5164
|
+
}
|
|
5165
|
+
|
|
5166
|
+
// src/hooks/useAlert.ts
|
|
5167
|
+
import { useContext as useContext3 } from "react";
|
|
5168
|
+
var useAlert = () => {
|
|
5169
|
+
return useContext3(AlertContext);
|
|
5170
|
+
};
|
|
5171
|
+
|
|
5172
|
+
// src/hooks/useFormHelper.ts
|
|
5173
|
+
import { useCallback as useCallback7, useContext as useContext4, useEffect as useEffect7, useRef as useRef4 } from "react";
|
|
5174
|
+
function useFormHelper() {
|
|
5175
|
+
const alertProps = useAlert();
|
|
5176
|
+
const loadingProps = useLoading();
|
|
5177
|
+
const { api, formatErrorMessage } = useContext4(FormHelperContext);
|
|
5178
|
+
const { createAlert } = alertProps;
|
|
5179
|
+
const { setLoading } = loadingProps;
|
|
5180
|
+
const sourceRef = useRef4(new AbortController());
|
|
5181
|
+
const onSubmitWrapper = useCallback7(
|
|
5182
|
+
(fn, { name }) => {
|
|
5183
|
+
return async (fields, methods) => {
|
|
5184
|
+
const LOADING_NAME = name;
|
|
5185
|
+
setLoading(LOADING_NAME);
|
|
5186
|
+
try {
|
|
5187
|
+
await fn(fields, methods);
|
|
5188
|
+
} catch (error) {
|
|
5189
|
+
errorHandler(error, methods.setErrors);
|
|
5190
|
+
} finally {
|
|
5191
|
+
setLoading(LOADING_NAME, true);
|
|
5192
|
+
}
|
|
5193
|
+
};
|
|
5194
|
+
},
|
|
5195
|
+
[setLoading]
|
|
5196
|
+
);
|
|
5197
|
+
const onRequestWrapper = useCallback7(
|
|
5198
|
+
(fn, { name }) => {
|
|
5199
|
+
return async (...params) => {
|
|
5200
|
+
const LOADING_NAME = name;
|
|
5201
|
+
setLoading(LOADING_NAME);
|
|
5202
|
+
api.interceptors.request.use(
|
|
5203
|
+
(config) => {
|
|
5204
|
+
if (!config.signal && sourceRef.current && config.method === "get") {
|
|
5205
|
+
config.signal = sourceRef.current.signal;
|
|
5206
|
+
}
|
|
5207
|
+
return config;
|
|
5208
|
+
},
|
|
5209
|
+
(error) => {
|
|
5210
|
+
return Promise.reject(error);
|
|
5211
|
+
}
|
|
5212
|
+
);
|
|
5213
|
+
try {
|
|
5214
|
+
const response = await fn(...params);
|
|
5215
|
+
return response;
|
|
5216
|
+
} catch (error) {
|
|
5217
|
+
errorHandler(error);
|
|
5218
|
+
} finally {
|
|
5219
|
+
setLoading(LOADING_NAME, true);
|
|
5220
|
+
}
|
|
5221
|
+
};
|
|
5103
5222
|
},
|
|
5104
|
-
[]
|
|
5223
|
+
[setLoading, api]
|
|
5105
5224
|
);
|
|
5106
|
-
const
|
|
5107
|
-
|
|
5108
|
-
|
|
5109
|
-
|
|
5110
|
-
|
|
5111
|
-
|
|
5112
|
-
|
|
5113
|
-
|
|
5114
|
-
|
|
5115
|
-
|
|
5116
|
-
|
|
5117
|
-
if (!prop) return;
|
|
5118
|
-
const currentSorted = sortedBy.find((p) => p.prop === prop);
|
|
5119
|
-
if (currentSorted) {
|
|
5120
|
-
if (currentSorted.direction === "asc") {
|
|
5121
|
-
setSortedBy((prev) => prev.filter((p) => p.prop !== prop));
|
|
5122
|
-
} else {
|
|
5123
|
-
setSortedBy((prev) => {
|
|
5124
|
-
const newArr = prev.map((p) => {
|
|
5125
|
-
if (p.prop !== prop) return p;
|
|
5126
|
-
return {
|
|
5127
|
-
prop: p.prop,
|
|
5128
|
-
direction: toggleSortedDirection(p.direction)
|
|
5129
|
-
};
|
|
5130
|
-
});
|
|
5131
|
-
return [...newArr].slice(0);
|
|
5132
|
-
});
|
|
5225
|
+
const errorHandler = useCallback7(
|
|
5226
|
+
(error, callback) => {
|
|
5227
|
+
if (error?.message === "cancel.navigation") return;
|
|
5228
|
+
if (callback) {
|
|
5229
|
+
if (error.response.data.code === "invalid.body") {
|
|
5230
|
+
const errors = error.response.data.details.issues;
|
|
5231
|
+
const currentErrors = errors.reduce((acc, item) => {
|
|
5232
|
+
acc[item.path.join(".")] = item.message;
|
|
5233
|
+
return acc;
|
|
5234
|
+
}, {});
|
|
5235
|
+
callback(currentErrors);
|
|
5133
5236
|
}
|
|
5134
|
-
} else {
|
|
5135
|
-
setSortedBy((prev) => [...prev, { prop, direction: "desc" }]);
|
|
5136
5237
|
}
|
|
5238
|
+
createAlert(formatErrorMessage(error), "error");
|
|
5137
5239
|
},
|
|
5138
|
-
[
|
|
5240
|
+
[formatErrorMessage, createAlert]
|
|
5139
5241
|
);
|
|
5140
|
-
|
|
5141
|
-
|
|
5242
|
+
useEffect7(() => {
|
|
5243
|
+
return () => {
|
|
5244
|
+
sourceRef.current.abort();
|
|
5245
|
+
sourceRef.current = new AbortController();
|
|
5246
|
+
};
|
|
5142
5247
|
}, []);
|
|
5143
|
-
|
|
5144
|
-
|
|
5145
|
-
|
|
5146
|
-
|
|
5147
|
-
|
|
5148
|
-
desc: "-"
|
|
5149
|
-
};
|
|
5150
|
-
const formattedKeys = sortedBy.map(
|
|
5151
|
-
({ prop, direction }) => `${symbolDir[direction]}${prop}`
|
|
5152
|
-
);
|
|
5153
|
-
return data.sort(SortHelper(...formattedKeys));
|
|
5154
|
-
} else return data;
|
|
5155
|
-
},
|
|
5156
|
-
[sortedBy]
|
|
5157
|
-
);
|
|
5158
|
-
const onPageChange = (pageNumber) => {
|
|
5159
|
-
if (pageNumber < 0) return;
|
|
5160
|
-
if (pageNumber > totalNumberOfPages) return;
|
|
5161
|
-
setCurrentPage(pageNumber);
|
|
5248
|
+
return {
|
|
5249
|
+
...alertProps,
|
|
5250
|
+
...loadingProps,
|
|
5251
|
+
onSubmitWrapper,
|
|
5252
|
+
onRequestWrapper
|
|
5162
5253
|
};
|
|
5163
|
-
|
|
5164
|
-
|
|
5165
|
-
|
|
5166
|
-
|
|
5167
|
-
|
|
5168
|
-
|
|
5254
|
+
}
|
|
5255
|
+
|
|
5256
|
+
// src/contexts/AuthContext.tsx
|
|
5257
|
+
function createAuthContext() {
|
|
5258
|
+
return createContext5({});
|
|
5259
|
+
}
|
|
5260
|
+
function CreateAuthProvider({
|
|
5261
|
+
api,
|
|
5262
|
+
children,
|
|
5263
|
+
sessionTokenName,
|
|
5264
|
+
Provider
|
|
5265
|
+
}) {
|
|
5266
|
+
const [user, setUser] = useState11();
|
|
5267
|
+
const [status, setStatus] = useState11("unauthenticated");
|
|
5268
|
+
const { createAlert } = useAlert();
|
|
5269
|
+
const signIn = useCallback8(
|
|
5270
|
+
async ({ email, password }) => {
|
|
5271
|
+
setStatus("loading");
|
|
5272
|
+
try {
|
|
5273
|
+
const response = await api.post("/auth/login", {
|
|
5274
|
+
email,
|
|
5275
|
+
password
|
|
5276
|
+
});
|
|
5277
|
+
const { token } = response.data;
|
|
5278
|
+
api.defaults.headers.common.Authorization = `Bearer ${token}`;
|
|
5279
|
+
const { data } = await api.get("/auth/me");
|
|
5280
|
+
setUser(data);
|
|
5281
|
+
setStatus("autenticated");
|
|
5282
|
+
return true;
|
|
5283
|
+
} catch (error) {
|
|
5284
|
+
createAlert(error?.response?.data?.error, "error");
|
|
5285
|
+
setStatus("unauthenticated");
|
|
5286
|
+
throw error;
|
|
5287
|
+
}
|
|
5169
5288
|
},
|
|
5170
|
-
[
|
|
5289
|
+
[createAlert, api]
|
|
5171
5290
|
);
|
|
5172
|
-
const
|
|
5173
|
-
|
|
5174
|
-
|
|
5175
|
-
|
|
5176
|
-
|
|
5177
|
-
|
|
5178
|
-
|
|
5179
|
-
|
|
5180
|
-
|
|
5181
|
-
|
|
5182
|
-
|
|
5291
|
+
const ClientSignOut = useCallback8(async () => {
|
|
5292
|
+
await api.get("/auth/logout");
|
|
5293
|
+
setUser(void 0);
|
|
5294
|
+
}, [api]);
|
|
5295
|
+
useEffect8(() => {
|
|
5296
|
+
const token = parseCookies()[sessionTokenName];
|
|
5297
|
+
if (token) {
|
|
5298
|
+
setStatus("loading");
|
|
5299
|
+
api.get("/auth/me").then((response) => {
|
|
5300
|
+
setStatus("autenticated");
|
|
5301
|
+
setUser(response.data);
|
|
5302
|
+
}).catch(() => {
|
|
5303
|
+
setStatus("unauthenticated");
|
|
5304
|
+
});
|
|
5183
5305
|
}
|
|
5184
|
-
|
|
5185
|
-
|
|
5186
|
-
|
|
5187
|
-
|
|
5188
|
-
|
|
5189
|
-
|
|
5190
|
-
|
|
5191
|
-
|
|
5192
|
-
|
|
5193
|
-
|
|
5194
|
-
|
|
5195
|
-
|
|
5196
|
-
|
|
5197
|
-
return {
|
|
5198
|
-
data: paginatedData,
|
|
5199
|
-
orderedData,
|
|
5200
|
-
filteredData,
|
|
5201
|
-
defaultData,
|
|
5202
|
-
sortedBy,
|
|
5203
|
-
columns,
|
|
5204
|
-
currentPage,
|
|
5205
|
-
totalNumberOfPages: totalNumberOfPages < 0 ? 0 : totalNumberOfPages,
|
|
5206
|
-
rowsPerPageOptions,
|
|
5207
|
-
rowsPerPage,
|
|
5208
|
-
set,
|
|
5209
|
-
onSortBy,
|
|
5210
|
-
onPageChange,
|
|
5211
|
-
setRowsPerPage: onChangeRowsPerPage,
|
|
5212
|
-
appendSort,
|
|
5213
|
-
setSort,
|
|
5214
|
-
clearSort
|
|
5215
|
-
};
|
|
5306
|
+
}, [api, sessionTokenName]);
|
|
5307
|
+
return /* @__PURE__ */ React33.createElement(
|
|
5308
|
+
Provider,
|
|
5309
|
+
{
|
|
5310
|
+
value: {
|
|
5311
|
+
user,
|
|
5312
|
+
signOut: ClientSignOut,
|
|
5313
|
+
signIn,
|
|
5314
|
+
status
|
|
5315
|
+
}
|
|
5316
|
+
},
|
|
5317
|
+
children
|
|
5318
|
+
);
|
|
5216
5319
|
}
|
|
5217
|
-
|
|
5218
|
-
|
|
5219
|
-
|
|
5220
|
-
|
|
5320
|
+
|
|
5321
|
+
// src/errors/HttpError.ts
|
|
5322
|
+
var HttpError = class extends Error {
|
|
5323
|
+
constructor(status, message) {
|
|
5324
|
+
super(message);
|
|
5325
|
+
this.message = message;
|
|
5326
|
+
this.stack = `HttpError: ${message}`;
|
|
5327
|
+
this.status = status;
|
|
5328
|
+
}
|
|
5329
|
+
};
|
|
5330
|
+
|
|
5331
|
+
// src/errors/DomainError.ts
|
|
5332
|
+
var DomainError = class extends Error {
|
|
5333
|
+
constructor(message) {
|
|
5334
|
+
super(message);
|
|
5335
|
+
this.message = message;
|
|
5336
|
+
this.stack = `DomainError: ${message}`;
|
|
5337
|
+
}
|
|
5221
5338
|
};
|
|
5222
|
-
|
|
5223
|
-
|
|
5224
|
-
|
|
5225
|
-
|
|
5226
|
-
|
|
5227
|
-
|
|
5228
|
-
|
|
5229
|
-
|
|
5230
|
-
|
|
5231
|
-
|
|
5232
|
-
|
|
5233
|
-
|
|
5234
|
-
|
|
5235
|
-
|
|
5236
|
-
|
|
5237
|
-
if (typeof objValue === "object") {
|
|
5238
|
-
match = searchKeysForValue(objValue, concatenatedKey, compare);
|
|
5239
|
-
continue;
|
|
5240
|
-
}
|
|
5241
|
-
match = compare(concatenatedKey, row[key]);
|
|
5339
|
+
|
|
5340
|
+
// src/helpers/apiHelper/index.ts
|
|
5341
|
+
var VALID_METHODS = [
|
|
5342
|
+
"GET",
|
|
5343
|
+
"HEAD",
|
|
5344
|
+
"POST",
|
|
5345
|
+
"PUT",
|
|
5346
|
+
"DELETE",
|
|
5347
|
+
"CONNECT",
|
|
5348
|
+
"OPTIONS",
|
|
5349
|
+
"TRACE",
|
|
5350
|
+
"PATCH"
|
|
5351
|
+
];
|
|
5352
|
+
var _ApiHelper = class _ApiHelper {
|
|
5353
|
+
async onFinally(_req, _res) {
|
|
5242
5354
|
}
|
|
5243
|
-
|
|
5244
|
-
}
|
|
5245
|
-
var normalize = (str) => str.normalize("NFD").replace(/[\u0300-\u036f]/g, "");
|
|
5246
|
-
function createSearch(options) {
|
|
5247
|
-
const searchValue = options.caseSensitive ? options.value : String(options.value).toLowerCase();
|
|
5248
|
-
function getValue2(value) {
|
|
5249
|
-
if (options.caseSensitive) return String(value);
|
|
5250
|
-
return String(value).toLowerCase();
|
|
5355
|
+
async onError(_req, _res, _error) {
|
|
5251
5356
|
}
|
|
5252
|
-
|
|
5253
|
-
|
|
5254
|
-
|
|
5255
|
-
|
|
5357
|
+
constructor(props) {
|
|
5358
|
+
this.public = props?.public ?? false;
|
|
5359
|
+
this.middlewares = (props?.middlewares || []).reverse();
|
|
5360
|
+
this.onFinally = props?.onFinally || (async () => {
|
|
5361
|
+
});
|
|
5362
|
+
this.onError = props?.onError || (async () => {
|
|
5363
|
+
});
|
|
5364
|
+
}
|
|
5365
|
+
createMethods(methods) {
|
|
5366
|
+
return async (req, res) => {
|
|
5367
|
+
const currentMethod = methods[req.method] || methods.ALL;
|
|
5368
|
+
const options = { public: this.public };
|
|
5369
|
+
if (req.method === "OPTIONS") return res.status(200).end();
|
|
5370
|
+
try {
|
|
5371
|
+
if (!VALID_METHODS.includes(req.method))
|
|
5372
|
+
throw new HttpError(405, "M\xE9todo inv\xE1lido");
|
|
5373
|
+
if (!currentMethod) throw new HttpError(500, "M\xE9todo n\xE3o encontrado");
|
|
5374
|
+
const methodWithMiddlewares = this.middlewares.reduce(
|
|
5375
|
+
(acc, fn) => fn(acc, options),
|
|
5376
|
+
currentMethod
|
|
5377
|
+
);
|
|
5378
|
+
return await methodWithMiddlewares(req, res, options);
|
|
5379
|
+
} catch (error) {
|
|
5380
|
+
if (error instanceof DomainError) return res.status(400).json(error.message);
|
|
5381
|
+
if (error instanceof HttpError) return res.status(error.status).json(error.message);
|
|
5382
|
+
this.onError(req, res, error);
|
|
5383
|
+
throw error;
|
|
5384
|
+
} finally {
|
|
5385
|
+
await this.onFinally(req, res);
|
|
5386
|
+
}
|
|
5387
|
+
};
|
|
5388
|
+
}
|
|
5389
|
+
buildFactory(factory) {
|
|
5390
|
+
const options = {
|
|
5391
|
+
public: this.public
|
|
5392
|
+
};
|
|
5393
|
+
return async (req, res) => {
|
|
5394
|
+
const methods = factory(req, res);
|
|
5395
|
+
const handler = methods[req.method];
|
|
5396
|
+
if (!handler) throw new HttpError(405, "M\xE9todo inv\xE1lido");
|
|
5397
|
+
const methodWithMiddlewares = this.middlewares.reduce((acc, fn) => {
|
|
5398
|
+
return fn(acc, options);
|
|
5399
|
+
}, handler);
|
|
5400
|
+
return await methodWithMiddlewares(req, res, options);
|
|
5401
|
+
};
|
|
5402
|
+
}
|
|
5403
|
+
static build(factory, options) {
|
|
5404
|
+
const helper = new _ApiHelper({
|
|
5405
|
+
...options
|
|
5406
|
+
}).buildFactory(factory);
|
|
5407
|
+
return helper;
|
|
5408
|
+
}
|
|
5409
|
+
static parse(body, parser) {
|
|
5410
|
+
try {
|
|
5411
|
+
const object = parser.parse(body);
|
|
5412
|
+
return object;
|
|
5413
|
+
} catch (error) {
|
|
5414
|
+
throw new HttpError(400, {
|
|
5415
|
+
code: "invalid.body",
|
|
5416
|
+
error: "Dados inv\xE1lidos",
|
|
5417
|
+
details: error
|
|
5418
|
+
});
|
|
5256
5419
|
}
|
|
5257
|
-
const value = getValue2(objValue);
|
|
5258
|
-
if (options.exact) return value === searchValue;
|
|
5259
|
-
if (options.ignoreAccentMark) return normalize(value).includes(normalize(searchValue));
|
|
5260
|
-
return value.includes(searchValue);
|
|
5261
5420
|
}
|
|
5262
|
-
|
|
5263
|
-
|
|
5264
|
-
return
|
|
5265
|
-
|
|
5266
|
-
}
|
|
5421
|
+
/** @deprecated Use {@Link ApiHelper.build} instead. */
|
|
5422
|
+
static create({ onFinally }) {
|
|
5423
|
+
return new _ApiHelper({
|
|
5424
|
+
onFinally
|
|
5425
|
+
});
|
|
5426
|
+
}
|
|
5427
|
+
};
|
|
5428
|
+
/** @deprecated Use {@link ApiHelper.parser} instead. */
|
|
5429
|
+
_ApiHelper.parserErrorWrapper = _ApiHelper.parse;
|
|
5430
|
+
var ApiHelper = _ApiHelper;
|
|
5267
5431
|
|
|
5268
|
-
// src/
|
|
5269
|
-
import {
|
|
5270
|
-
|
|
5271
|
-
|
|
5272
|
-
|
|
5273
|
-
|
|
5274
|
-
|
|
5275
|
-
|
|
5276
|
-
|
|
5277
|
-
url,
|
|
5278
|
-
defaultData: externalDefaultData,
|
|
5279
|
-
defaultCurrentPage,
|
|
5280
|
-
defaultSortedBy
|
|
5432
|
+
// src/helpers/authHelper.ts
|
|
5433
|
+
import { serialize as serialize2 } from "cookie";
|
|
5434
|
+
import jwt from "jsonwebtoken";
|
|
5435
|
+
import { randomUUID } from "crypto";
|
|
5436
|
+
function decodeSessionToken({
|
|
5437
|
+
req,
|
|
5438
|
+
res,
|
|
5439
|
+
sessionTokenName,
|
|
5440
|
+
validate
|
|
5281
5441
|
}) {
|
|
5282
|
-
const
|
|
5283
|
-
|
|
5284
|
-
|
|
5285
|
-
|
|
5286
|
-
|
|
5287
|
-
const
|
|
5288
|
-
|
|
5289
|
-
|
|
5290
|
-
|
|
5291
|
-
|
|
5292
|
-
|
|
5293
|
-
|
|
5294
|
-
|
|
5295
|
-
|
|
5296
|
-
|
|
5297
|
-
|
|
5298
|
-
|
|
5299
|
-
|
|
5300
|
-
|
|
5301
|
-
|
|
5302
|
-
|
|
5303
|
-
|
|
5304
|
-
|
|
5305
|
-
|
|
5306
|
-
|
|
5307
|
-
|
|
5308
|
-
|
|
5309
|
-
|
|
5310
|
-
|
|
5311
|
-
|
|
5312
|
-
|
|
5313
|
-
|
|
5314
|
-
|
|
5315
|
-
|
|
5316
|
-
|
|
5317
|
-
|
|
5318
|
-
|
|
5319
|
-
|
|
5442
|
+
const token = req.headers.authorization?.split(" ")[1] || req.cookies[sessionTokenName];
|
|
5443
|
+
if (!token) {
|
|
5444
|
+
res.status(401).json({ error: "Token inv\xE1lido", code: "token.invalid" });
|
|
5445
|
+
return true;
|
|
5446
|
+
}
|
|
5447
|
+
const jwtDecode = (token2) => {
|
|
5448
|
+
if (validate) {
|
|
5449
|
+
return jwt.verify(token2, process.env.JWT_SECRET);
|
|
5450
|
+
}
|
|
5451
|
+
return jwt.decode(token2);
|
|
5452
|
+
};
|
|
5453
|
+
try {
|
|
5454
|
+
const decoded = jwtDecode(token);
|
|
5455
|
+
req.user = decoded.sub;
|
|
5456
|
+
} catch (_) {
|
|
5457
|
+
res.status(401).json({ error: "Token inv\xE1lido", code: "token.expired" });
|
|
5458
|
+
return true;
|
|
5459
|
+
}
|
|
5460
|
+
}
|
|
5461
|
+
var AuthHelper = class {
|
|
5462
|
+
constructor({
|
|
5463
|
+
cookies,
|
|
5464
|
+
oauth,
|
|
5465
|
+
tokenExpTimeInSeconds,
|
|
5466
|
+
onLogin,
|
|
5467
|
+
onValidateRefreshToken,
|
|
5468
|
+
onInvalidateRefreshToken,
|
|
5469
|
+
onCreateRefreshToken,
|
|
5470
|
+
onGetUserData
|
|
5471
|
+
}) {
|
|
5472
|
+
this.generateJwtAndRefreshToken = async (userId, payload = {}) => {
|
|
5473
|
+
const token = jwt.sign(payload, process.env.JWT_SECRET, {
|
|
5474
|
+
subject: String(userId),
|
|
5475
|
+
expiresIn: this.tokenExpTimeInSeconds || 60 * 15
|
|
5476
|
+
// 15 minutos
|
|
5477
|
+
});
|
|
5478
|
+
const uniqueToken = randomUUID();
|
|
5479
|
+
await this.onCreateRefreshToken(userId, uniqueToken);
|
|
5480
|
+
return {
|
|
5481
|
+
token,
|
|
5482
|
+
refreshToken: uniqueToken
|
|
5483
|
+
};
|
|
5484
|
+
};
|
|
5485
|
+
this.invalidateCookies = (res) => {
|
|
5486
|
+
return res.setHeader("Set-Cookie", [
|
|
5487
|
+
serialize2(this.cookies.sessionToken, "", {
|
|
5488
|
+
maxAge: -1,
|
|
5489
|
+
path: "/"
|
|
5490
|
+
}),
|
|
5491
|
+
serialize2(this.cookies.refreshToken, "", {
|
|
5492
|
+
maxAge: -1,
|
|
5493
|
+
path: "/"
|
|
5494
|
+
})
|
|
5495
|
+
]);
|
|
5496
|
+
};
|
|
5497
|
+
this.cookies = cookies;
|
|
5498
|
+
this.oauth = oauth;
|
|
5499
|
+
this.tokenExpTimeInSeconds = tokenExpTimeInSeconds;
|
|
5500
|
+
this.onLogin = onLogin;
|
|
5501
|
+
this.onValidateRefreshToken = onValidateRefreshToken;
|
|
5502
|
+
this.onInvalidateRefreshToken = onInvalidateRefreshToken;
|
|
5503
|
+
this.onCreateRefreshToken = onCreateRefreshToken;
|
|
5504
|
+
this.onGetUserData = onGetUserData;
|
|
5505
|
+
}
|
|
5506
|
+
async handler(req, res) {
|
|
5507
|
+
if (!req.url) return res.status(400).json({ error: "url not sent" });
|
|
5508
|
+
if (req.url.endsWith("/login")) {
|
|
5509
|
+
const loginResult = await this.onLogin(req.body);
|
|
5510
|
+
if (loginResult.status === "success") {
|
|
5511
|
+
const { refreshToken, token } = await this.generateJwtAndRefreshToken(
|
|
5512
|
+
loginResult.userId,
|
|
5513
|
+
{}
|
|
5514
|
+
);
|
|
5515
|
+
setCookie({ res }, this.cookies.sessionToken, token, {
|
|
5516
|
+
secure: true,
|
|
5517
|
+
maxAge: 60 * 60 * 24 * 30,
|
|
5518
|
+
// 30 days
|
|
5519
|
+
path: "/",
|
|
5520
|
+
sameSite: true
|
|
5521
|
+
});
|
|
5522
|
+
setCookie({ res }, this.cookies.refreshToken, refreshToken, {
|
|
5523
|
+
secure: true,
|
|
5524
|
+
maxAge: 60 * 60 * 24 * 30,
|
|
5525
|
+
// 30 days
|
|
5526
|
+
path: "/",
|
|
5527
|
+
sameSite: true,
|
|
5528
|
+
httpOnly: true
|
|
5529
|
+
});
|
|
5530
|
+
return res.json({ token, refreshToken });
|
|
5320
5531
|
}
|
|
5321
|
-
|
|
5322
|
-
|
|
5323
|
-
|
|
5324
|
-
|
|
5532
|
+
throw new HttpError(400, loginResult.response);
|
|
5533
|
+
}
|
|
5534
|
+
if (req.url.endsWith("/logout")) {
|
|
5535
|
+
this.invalidateCookies(res).end();
|
|
5536
|
+
}
|
|
5537
|
+
if (req.url.endsWith("/refresh")) {
|
|
5538
|
+
const error = decodeSessionToken({
|
|
5539
|
+
req,
|
|
5540
|
+
res,
|
|
5541
|
+
sessionTokenName: this.cookies.sessionToken,
|
|
5542
|
+
validate: false
|
|
5325
5543
|
});
|
|
5326
|
-
|
|
5327
|
-
|
|
5328
|
-
|
|
5329
|
-
|
|
5330
|
-
|
|
5331
|
-
|
|
5332
|
-
|
|
5333
|
-
async ({
|
|
5334
|
-
page,
|
|
5335
|
-
search: search2,
|
|
5336
|
-
filters: filters2,
|
|
5337
|
-
sortedBy: sortedBy2,
|
|
5338
|
-
rowsPerPage: rowsPerPage2
|
|
5339
|
-
}) => {
|
|
5340
|
-
if (!axiosInstance) throw new Error("Axios instance not provided");
|
|
5341
|
-
try {
|
|
5342
|
-
const params = new URLSearchParams({
|
|
5343
|
-
page: String(page),
|
|
5344
|
-
rowsPerPage: String(rowsPerPage2),
|
|
5345
|
-
searchText: search2?.value || "",
|
|
5346
|
-
sort: sortedBy2.map(({ prop, direction }) => `${prop}:${direction}`).join(","),
|
|
5347
|
-
filters: filters2.map(
|
|
5348
|
-
(filter) => `${filter.prop}:${filter.compareType}:${filter.value}`
|
|
5349
|
-
).join(",")
|
|
5544
|
+
if (error) return;
|
|
5545
|
+
const userId = String(req.user);
|
|
5546
|
+
const refreshToken = parseCookies({ req })[this.cookies.refreshToken];
|
|
5547
|
+
if (!refreshToken) {
|
|
5548
|
+
this.invalidateCookies(res);
|
|
5549
|
+
return res.status(400).json({
|
|
5550
|
+
error: "Refresh Token inv\xE1lido"
|
|
5350
5551
|
});
|
|
5351
|
-
const pathWithParams = `${url}?${params.toString()}`;
|
|
5352
|
-
const { data } = await axiosInstance.get(pathWithParams);
|
|
5353
|
-
setTotalNumberOfItems(data.totalNumberOfItems);
|
|
5354
|
-
return data.rows;
|
|
5355
|
-
} catch (_) {
|
|
5356
|
-
return [];
|
|
5357
|
-
}
|
|
5358
|
-
},
|
|
5359
|
-
[axiosInstance, url]
|
|
5360
|
-
);
|
|
5361
|
-
const updateGridContent = useCallback4(
|
|
5362
|
-
async ({
|
|
5363
|
-
page,
|
|
5364
|
-
sortedBy: sortedBy2,
|
|
5365
|
-
rowsPerPage: rowsPerPage2
|
|
5366
|
-
}) => {
|
|
5367
|
-
setIsLoading(true);
|
|
5368
|
-
try {
|
|
5369
|
-
const props = {
|
|
5370
|
-
page,
|
|
5371
|
-
rowsPerPage: rowsPerPage2,
|
|
5372
|
-
sortedBy: sortedBy2,
|
|
5373
|
-
search,
|
|
5374
|
-
filters
|
|
5375
|
-
};
|
|
5376
|
-
const result = !onRequest ? await baseRequest(props) : await onRequest(props);
|
|
5377
|
-
setSortedBy(sortedBy2);
|
|
5378
|
-
setRowsPerPage(rowsPerPage2);
|
|
5379
|
-
set(result);
|
|
5380
|
-
setCurrentPage(page);
|
|
5381
|
-
} finally {
|
|
5382
|
-
setIsLoading(false);
|
|
5383
5552
|
}
|
|
5384
|
-
|
|
5385
|
-
|
|
5386
|
-
|
|
5387
|
-
|
|
5388
|
-
|
|
5389
|
-
|
|
5390
|
-
|
|
5391
|
-
|
|
5392
|
-
},
|
|
5393
|
-
[updateGridContent, totalNumberOfPages, sortedBy, rowsPerPage]
|
|
5394
|
-
);
|
|
5395
|
-
const onChangeRowsPerPage = useCallback4(
|
|
5396
|
-
(rows) => {
|
|
5397
|
-
let totalNumberOfPages2 = Math.round(totalNumberOfItems / rows) - 1;
|
|
5398
|
-
totalNumberOfPages2 = totalNumberOfPages2 <= 0 ? 0 : 1;
|
|
5399
|
-
if (currentPage > totalNumberOfPages2)
|
|
5400
|
-
updateGridContent({
|
|
5401
|
-
page: totalNumberOfPages2,
|
|
5402
|
-
sortedBy,
|
|
5403
|
-
rowsPerPage: rows
|
|
5553
|
+
const isValidRefreshToken = await this.onValidateRefreshToken(
|
|
5554
|
+
userId,
|
|
5555
|
+
refreshToken
|
|
5556
|
+
);
|
|
5557
|
+
if (!isValidRefreshToken) {
|
|
5558
|
+
this.invalidateCookies(res);
|
|
5559
|
+
return res.status(400).json({
|
|
5560
|
+
error: "Refresh Token inv\xE1lido"
|
|
5404
5561
|
});
|
|
5405
|
-
|
|
5406
|
-
|
|
5407
|
-
|
|
5408
|
-
|
|
5562
|
+
}
|
|
5563
|
+
await this.onInvalidateRefreshToken(userId, refreshToken);
|
|
5564
|
+
const { token, refreshToken: newRefreshToken } = await this.generateJwtAndRefreshToken(userId, {});
|
|
5565
|
+
setCookie({ res }, this.cookies.sessionToken, token, {
|
|
5566
|
+
secure: true,
|
|
5567
|
+
maxAge: 60 * 60 * 24 * 30,
|
|
5568
|
+
// 30 days
|
|
5569
|
+
path: "/",
|
|
5570
|
+
sameSite: true
|
|
5409
5571
|
});
|
|
5410
|
-
|
|
5411
|
-
|
|
5412
|
-
|
|
5413
|
-
|
|
5414
|
-
|
|
5415
|
-
|
|
5416
|
-
|
|
5417
|
-
|
|
5418
|
-
|
|
5419
|
-
|
|
5420
|
-
|
|
5421
|
-
|
|
5422
|
-
|
|
5423
|
-
|
|
5424
|
-
|
|
5425
|
-
|
|
5426
|
-
|
|
5427
|
-
|
|
5428
|
-
|
|
5429
|
-
|
|
5430
|
-
|
|
5431
|
-
|
|
5432
|
-
|
|
5433
|
-
|
|
5434
|
-
|
|
5435
|
-
|
|
5436
|
-
|
|
5437
|
-
import { useEffect as useEffect6 } from "react";
|
|
5438
|
-
function useEvent(event, handler, passive = false) {
|
|
5439
|
-
useEffect6(() => {
|
|
5440
|
-
window.addEventListener(event, handler, passive);
|
|
5441
|
-
return function cleanup() {
|
|
5442
|
-
window.removeEventListener(event, handler);
|
|
5443
|
-
};
|
|
5444
|
-
});
|
|
5445
|
-
}
|
|
5446
|
-
|
|
5447
|
-
// src/hooks/useLoading.ts
|
|
5448
|
-
import { useCallback as useCallback5, useState as useState9 } from "react";
|
|
5449
|
-
function useLoading() {
|
|
5450
|
-
const [state, setState] = useState9([]);
|
|
5451
|
-
const isLoading = useCallback5((prop) => state.includes(prop), [state]);
|
|
5452
|
-
const setLoading = useCallback5((prop, remove) => {
|
|
5453
|
-
if (remove)
|
|
5454
|
-
setState((prevState) => prevState.filter((state2) => state2 !== prop));
|
|
5455
|
-
else setState((prevState) => [...prevState, prop]);
|
|
5456
|
-
}, []);
|
|
5457
|
-
return { isLoading, setLoading };
|
|
5458
|
-
}
|
|
5459
|
-
|
|
5460
|
-
// src/hooks/useAlert.ts
|
|
5461
|
-
import { useContext as useContext3 } from "react";
|
|
5462
|
-
|
|
5463
|
-
// src/contexts/AlertContext.tsx
|
|
5464
|
-
import React31, { useCallback as useCallback6 } from "react";
|
|
5465
|
-
import { createContext as createContext3, useState as useState10 } from "react";
|
|
5466
|
-
|
|
5467
|
-
// src/components/Toast/index.tsx
|
|
5468
|
-
import React30 from "react";
|
|
5469
|
-
import { Alert, IconButton as IconButton5, Snackbar } from "@mui/material";
|
|
5470
|
-
import { MdClose as MdClose3 } from "react-icons/md";
|
|
5471
|
-
var Toast = ({ open, onClose, severity, message }) => {
|
|
5472
|
-
return /* @__PURE__ */ React30.createElement(React30.Fragment, null, /* @__PURE__ */ React30.createElement(
|
|
5473
|
-
Snackbar,
|
|
5474
|
-
{
|
|
5475
|
-
open,
|
|
5476
|
-
autoHideDuration: 6e3,
|
|
5477
|
-
onClose,
|
|
5478
|
-
anchorOrigin: { vertical: "top", horizontal: "right" },
|
|
5479
|
-
sx: { zIndex: 99999999 }
|
|
5480
|
-
},
|
|
5481
|
-
/* @__PURE__ */ React30.createElement(
|
|
5482
|
-
Alert,
|
|
5483
|
-
{
|
|
5484
|
-
severity,
|
|
5485
|
-
elevation: 2,
|
|
5486
|
-
action: /* @__PURE__ */ React30.createElement(
|
|
5487
|
-
IconButton5,
|
|
5488
|
-
{
|
|
5489
|
-
"aria-label": "close",
|
|
5490
|
-
color: "inherit",
|
|
5491
|
-
size: "small",
|
|
5492
|
-
onClick: onClose
|
|
5493
|
-
},
|
|
5494
|
-
/* @__PURE__ */ React30.createElement(MdClose3, { fontSize: "inherit" })
|
|
5495
|
-
)
|
|
5496
|
-
},
|
|
5497
|
-
message
|
|
5498
|
-
)
|
|
5499
|
-
));
|
|
5500
|
-
};
|
|
5501
|
-
|
|
5502
|
-
// src/contexts/AlertContext.tsx
|
|
5503
|
-
var AlertContext = createContext3({});
|
|
5504
|
-
var AlertProvider = ({ children }) => {
|
|
5505
|
-
const [severity, setSeverity] = useState10("info");
|
|
5506
|
-
const [message, setMessage] = useState10("");
|
|
5507
|
-
const [isVisible, setIsVisible] = useState10(false);
|
|
5508
|
-
const createAlert = useCallback6(
|
|
5509
|
-
(newMessage, severity2) => {
|
|
5510
|
-
setMessage(newMessage);
|
|
5511
|
-
setSeverity(severity2);
|
|
5512
|
-
setIsVisible(true);
|
|
5513
|
-
},
|
|
5514
|
-
[]
|
|
5515
|
-
);
|
|
5516
|
-
const onCloseToast = useCallback6(() => {
|
|
5517
|
-
setIsVisible(false);
|
|
5518
|
-
}, []);
|
|
5519
|
-
return /* @__PURE__ */ React31.createElement(AlertContext.Provider, { value: { createAlert } }, children, /* @__PURE__ */ React31.createElement(
|
|
5520
|
-
Toast,
|
|
5521
|
-
{
|
|
5522
|
-
open: isVisible,
|
|
5523
|
-
onClose: onCloseToast,
|
|
5524
|
-
severity,
|
|
5525
|
-
message
|
|
5572
|
+
setCookie({ res }, this.cookies.refreshToken, newRefreshToken, {
|
|
5573
|
+
secure: true,
|
|
5574
|
+
maxAge: 60 * 60 * 24 * 30,
|
|
5575
|
+
// 30 days
|
|
5576
|
+
path: "/",
|
|
5577
|
+
sameSite: true,
|
|
5578
|
+
httpOnly: true
|
|
5579
|
+
});
|
|
5580
|
+
return res.json({
|
|
5581
|
+
token,
|
|
5582
|
+
refreshToken: newRefreshToken
|
|
5583
|
+
});
|
|
5584
|
+
}
|
|
5585
|
+
if (req.url.endsWith("/me")) {
|
|
5586
|
+
const error = decodeSessionToken({
|
|
5587
|
+
req,
|
|
5588
|
+
res,
|
|
5589
|
+
sessionTokenName: this.cookies.sessionToken,
|
|
5590
|
+
validate: true
|
|
5591
|
+
});
|
|
5592
|
+
if (error) return;
|
|
5593
|
+
if (!req.user)
|
|
5594
|
+
return res.status(400).json({ error: "Usu\xE1rio n\xE3o encontrado" });
|
|
5595
|
+
const userData = await this.onGetUserData(req.user);
|
|
5596
|
+
if (!userData)
|
|
5597
|
+
return res.status(400).json({ error: "Usu\xE1rio n\xE3o encontrado" });
|
|
5598
|
+
return res.json(userData);
|
|
5526
5599
|
}
|
|
5527
|
-
|
|
5528
|
-
|
|
5529
|
-
|
|
5530
|
-
|
|
5531
|
-
|
|
5532
|
-
|
|
5533
|
-
|
|
5534
|
-
|
|
5535
|
-
// src/hooks/useFormHelper.ts
|
|
5536
|
-
import { useCallback as useCallback7, useContext as useContext4, useEffect as useEffect7, useRef as useRef4 } from "react";
|
|
5537
|
-
|
|
5538
|
-
// src/contexts/FormHelperProvider.tsx
|
|
5539
|
-
import React32 from "react";
|
|
5540
|
-
import { createContext as createContext4 } from "react";
|
|
5541
|
-
var FormHelperContext = createContext4({});
|
|
5542
|
-
var FormHelperProvider = ({ formatErrorMessage, api, children }) => {
|
|
5543
|
-
return /* @__PURE__ */ React32.createElement(FormHelperContext.Provider, { value: { formatErrorMessage, api } }, children);
|
|
5544
|
-
};
|
|
5545
|
-
|
|
5546
|
-
// src/hooks/useFormHelper.ts
|
|
5547
|
-
function useFormHelper() {
|
|
5548
|
-
const alertProps = useAlert();
|
|
5549
|
-
const loadingProps = useLoading();
|
|
5550
|
-
const { api, formatErrorMessage } = useContext4(FormHelperContext);
|
|
5551
|
-
const { createAlert } = alertProps;
|
|
5552
|
-
const { setLoading } = loadingProps;
|
|
5553
|
-
const sourceRef = useRef4(new AbortController());
|
|
5554
|
-
const onSubmitWrapper = useCallback7(
|
|
5555
|
-
(fn, { name }) => {
|
|
5556
|
-
return async (fields, methods) => {
|
|
5557
|
-
const LOADING_NAME = name;
|
|
5558
|
-
setLoading(LOADING_NAME);
|
|
5559
|
-
try {
|
|
5560
|
-
await fn(fields, methods);
|
|
5561
|
-
} catch (error) {
|
|
5562
|
-
errorHandler(error, methods.setErrors);
|
|
5563
|
-
} finally {
|
|
5564
|
-
setLoading(LOADING_NAME, true);
|
|
5565
|
-
}
|
|
5566
|
-
};
|
|
5567
|
-
},
|
|
5568
|
-
[setLoading]
|
|
5569
|
-
);
|
|
5570
|
-
const onRequestWrapper = useCallback7(
|
|
5571
|
-
(fn, { name }) => {
|
|
5572
|
-
return async (...params) => {
|
|
5573
|
-
const LOADING_NAME = name;
|
|
5574
|
-
setLoading(LOADING_NAME);
|
|
5575
|
-
api.interceptors.request.use(
|
|
5576
|
-
(config) => {
|
|
5577
|
-
if (!config.signal && sourceRef.current && config.method === "get") {
|
|
5578
|
-
config.signal = sourceRef.current.signal;
|
|
5579
|
-
}
|
|
5580
|
-
return config;
|
|
5581
|
-
},
|
|
5582
|
-
(error) => {
|
|
5583
|
-
return Promise.reject(error);
|
|
5584
|
-
}
|
|
5585
|
-
);
|
|
5586
|
-
try {
|
|
5587
|
-
const response = await fn(...params);
|
|
5588
|
-
return response;
|
|
5589
|
-
} catch (error) {
|
|
5590
|
-
errorHandler(error);
|
|
5591
|
-
} finally {
|
|
5592
|
-
setLoading(LOADING_NAME, true);
|
|
5593
|
-
}
|
|
5600
|
+
if (req.url.endsWith("/oauth-url") && this.oauth) {
|
|
5601
|
+
const params = {
|
|
5602
|
+
client_id: this.oauth.client_id,
|
|
5603
|
+
redirect_uri: this.oauth.redirect_uri,
|
|
5604
|
+
scope: this.oauth.scope,
|
|
5605
|
+
response_type: "code",
|
|
5606
|
+
response_mode: "query"
|
|
5594
5607
|
};
|
|
5595
|
-
|
|
5596
|
-
|
|
5597
|
-
|
|
5598
|
-
|
|
5599
|
-
|
|
5600
|
-
|
|
5601
|
-
|
|
5602
|
-
|
|
5603
|
-
|
|
5604
|
-
|
|
5605
|
-
|
|
5606
|
-
|
|
5607
|
-
|
|
5608
|
-
|
|
5609
|
-
|
|
5610
|
-
|
|
5611
|
-
|
|
5612
|
-
},
|
|
5613
|
-
[formatErrorMessage, createAlert]
|
|
5614
|
-
);
|
|
5615
|
-
useEffect7(() => {
|
|
5616
|
-
return () => {
|
|
5617
|
-
sourceRef.current.abort();
|
|
5618
|
-
sourceRef.current = new AbortController();
|
|
5608
|
+
const url = `https://login.microsoftonline.com/${this.oauth.tenant_id}/oauth2/v2.0/authorize?${new URLSearchParams(params)}`;
|
|
5609
|
+
return res.json({
|
|
5610
|
+
url
|
|
5611
|
+
});
|
|
5612
|
+
}
|
|
5613
|
+
return res.status(404).json({ error: "Route not found" });
|
|
5614
|
+
}
|
|
5615
|
+
async oauthSignInCallback(code) {
|
|
5616
|
+
if (!this.oauth) throw new Error("OAUTH variables is not defined");
|
|
5617
|
+
const body = {
|
|
5618
|
+
client_id: this.oauth.client_id,
|
|
5619
|
+
scope: this.oauth.scope,
|
|
5620
|
+
code,
|
|
5621
|
+
session_state: this.oauth.client_id,
|
|
5622
|
+
redirect_uri: this.oauth.redirect_uri,
|
|
5623
|
+
grant_type: "authorization_code",
|
|
5624
|
+
client_secret: this.oauth.client_secret
|
|
5619
5625
|
};
|
|
5620
|
-
|
|
5621
|
-
|
|
5622
|
-
|
|
5623
|
-
|
|
5624
|
-
|
|
5625
|
-
|
|
5626
|
-
|
|
5627
|
-
|
|
5628
|
-
|
|
5629
|
-
|
|
5630
|
-
|
|
5631
|
-
|
|
5632
|
-
|
|
5633
|
-
|
|
5634
|
-
|
|
5635
|
-
|
|
5636
|
-
|
|
5637
|
-
|
|
5638
|
-
|
|
5639
|
-
|
|
5640
|
-
|
|
5641
|
-
|
|
5642
|
-
|
|
5643
|
-
|
|
5644
|
-
|
|
5645
|
-
|
|
5646
|
-
|
|
5647
|
-
|
|
5648
|
-
const signIn = useCallback8(
|
|
5649
|
-
async ({ email, password }) => {
|
|
5650
|
-
setStatus("loading");
|
|
5626
|
+
const response = await fetch(
|
|
5627
|
+
`https://login.microsoftonline.com/${this.oauth.tenant_id}/oauth2/v2.0/token`,
|
|
5628
|
+
{
|
|
5629
|
+
method: "POST",
|
|
5630
|
+
body: new URLSearchParams(body),
|
|
5631
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" }
|
|
5632
|
+
}
|
|
5633
|
+
);
|
|
5634
|
+
const data = await response.json();
|
|
5635
|
+
const decodedToken = jwt.decode(data.access_token);
|
|
5636
|
+
const email = decodedToken.upn;
|
|
5637
|
+
const fullName = `${decodedToken?.given_name} ${decodedToken?.family_name}`;
|
|
5638
|
+
return { decodedToken, email, fullName };
|
|
5639
|
+
}
|
|
5640
|
+
createOauthCallbackGetServerSideProps({
|
|
5641
|
+
onSuccessDestination,
|
|
5642
|
+
onFailedDestination
|
|
5643
|
+
}) {
|
|
5644
|
+
return async (ctx) => {
|
|
5645
|
+
if (!this.oauth) throw new Error("Oauth env variables are not defined");
|
|
5646
|
+
const code = ctx.query.code;
|
|
5647
|
+
if (!code)
|
|
5648
|
+
return {
|
|
5649
|
+
redirect: {
|
|
5650
|
+
permanent: false,
|
|
5651
|
+
destination: onFailedDestination || "/"
|
|
5652
|
+
}
|
|
5653
|
+
};
|
|
5651
5654
|
try {
|
|
5652
|
-
const
|
|
5655
|
+
const { fullName, email } = await this.oauthSignInCallback(code);
|
|
5656
|
+
const userExists = await this.onGetUserData(email);
|
|
5657
|
+
if (!userExists && !this.oauth.onCreateUser)
|
|
5658
|
+
throw new Error("User does not exists");
|
|
5659
|
+
if (!userExists && this.oauth.onCreateUser) {
|
|
5660
|
+
await this.oauth.onCreateUser({ fullname: fullName, email });
|
|
5661
|
+
}
|
|
5662
|
+
const { token, refreshToken } = await this.generateJwtAndRefreshToken(
|
|
5653
5663
|
email,
|
|
5654
|
-
|
|
5664
|
+
{}
|
|
5665
|
+
);
|
|
5666
|
+
setCookie(ctx, this.cookies.sessionToken, token, {
|
|
5667
|
+
secure: true,
|
|
5668
|
+
maxAge: 60 * 60 * 24 * 30,
|
|
5669
|
+
// 30 days
|
|
5670
|
+
path: "/"
|
|
5655
5671
|
});
|
|
5656
|
-
|
|
5657
|
-
|
|
5658
|
-
|
|
5659
|
-
|
|
5660
|
-
|
|
5661
|
-
|
|
5672
|
+
setCookie(ctx, this.cookies.refreshToken, refreshToken, {
|
|
5673
|
+
secure: true,
|
|
5674
|
+
maxAge: 60 * 60 * 24 * 30,
|
|
5675
|
+
// 30 days
|
|
5676
|
+
path: "/",
|
|
5677
|
+
httpOnly: true
|
|
5678
|
+
});
|
|
5679
|
+
return {
|
|
5680
|
+
redirect: {
|
|
5681
|
+
destination: onSuccessDestination,
|
|
5682
|
+
permanent: false
|
|
5683
|
+
}
|
|
5684
|
+
};
|
|
5662
5685
|
} catch (error) {
|
|
5663
|
-
|
|
5664
|
-
|
|
5665
|
-
|
|
5666
|
-
|
|
5667
|
-
|
|
5668
|
-
[createAlert, api]
|
|
5669
|
-
);
|
|
5670
|
-
const ClientSignOut = useCallback8(async () => {
|
|
5671
|
-
await api.get("/auth/logout");
|
|
5672
|
-
setUser(void 0);
|
|
5673
|
-
}, [api]);
|
|
5674
|
-
useEffect8(() => {
|
|
5675
|
-
const token = parseCookies()[sessionTokenName];
|
|
5676
|
-
if (token) {
|
|
5677
|
-
setStatus("loading");
|
|
5678
|
-
api.get("/auth/me").then((response) => {
|
|
5679
|
-
setStatus("autenticated");
|
|
5680
|
-
setUser(response.data);
|
|
5681
|
-
}).catch(() => {
|
|
5682
|
-
setStatus("unauthenticated");
|
|
5683
|
-
});
|
|
5684
|
-
}
|
|
5685
|
-
}, [api, sessionTokenName]);
|
|
5686
|
-
return /* @__PURE__ */ React33.createElement(
|
|
5687
|
-
Provider,
|
|
5688
|
-
{
|
|
5689
|
-
value: {
|
|
5690
|
-
user,
|
|
5691
|
-
signOut: ClientSignOut,
|
|
5692
|
-
signIn,
|
|
5693
|
-
status
|
|
5686
|
+
return {
|
|
5687
|
+
props: {
|
|
5688
|
+
error: JSON.stringify(error)
|
|
5689
|
+
}
|
|
5690
|
+
};
|
|
5694
5691
|
}
|
|
5695
|
-
}
|
|
5696
|
-
|
|
5697
|
-
|
|
5698
|
-
}
|
|
5692
|
+
};
|
|
5693
|
+
}
|
|
5694
|
+
};
|
|
5699
5695
|
export {
|
|
5700
5696
|
AlertContext,
|
|
5701
5697
|
AlertProvider,
|