@bluemarble/bm-components 2.4.2 → 2.4.4
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 +1097 -1101
- 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,639 +4588,237 @@ 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
|
-
res.status(401).json({ error: "Token inv\xE1lido", code: "token.invalid" });
|
|
4717
|
-
return true;
|
|
4718
|
-
}
|
|
4719
|
-
const jwtDecode = (token2) => {
|
|
4720
|
-
if (validate) {
|
|
4721
|
-
return jwt.verify(token2, process.env.JWT_SECRET);
|
|
4722
|
-
}
|
|
4723
|
-
return jwt.decode(token2);
|
|
4724
|
-
};
|
|
4725
|
-
try {
|
|
4726
|
-
const decoded = jwtDecode(token);
|
|
4727
|
-
req.user = decoded.sub;
|
|
4728
|
-
} catch (_) {
|
|
4729
|
-
res.status(401).json({ error: "Token inv\xE1lido", code: "token.expired" });
|
|
4730
|
-
return true;
|
|
4731
|
-
}
|
|
4732
|
-
}
|
|
4733
|
-
var AuthHelper = class {
|
|
4734
|
-
constructor({
|
|
4735
|
-
cookies,
|
|
4736
|
-
oauth,
|
|
4737
|
-
tokenExpTimeInSeconds,
|
|
4738
|
-
onLogin,
|
|
4739
|
-
onValidateRefreshToken,
|
|
4740
|
-
onInvalidateRefreshToken,
|
|
4741
|
-
onCreateRefreshToken,
|
|
4742
|
-
onGetUserData
|
|
4743
|
-
}) {
|
|
4744
|
-
this.generateJwtAndRefreshToken = async (userId, payload = {}) => {
|
|
4745
|
-
const token = jwt.sign(payload, process.env.JWT_SECRET, {
|
|
4746
|
-
subject: String(userId),
|
|
4747
|
-
expiresIn: this.tokenExpTimeInSeconds || 60 * 15
|
|
4748
|
-
// 15 minutos
|
|
4749
|
-
});
|
|
4750
|
-
const uniqueToken = randomUUID();
|
|
4751
|
-
await this.onCreateRefreshToken(userId, uniqueToken);
|
|
4752
|
-
return {
|
|
4753
|
-
token,
|
|
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 });
|
|
4933
|
-
}
|
|
4934
|
-
const { token, refreshToken } = await this.generateJwtAndRefreshToken(
|
|
4935
|
-
email,
|
|
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
|
-
};
|
|
4963
|
-
}
|
|
4964
|
-
};
|
|
4965
|
-
}
|
|
4966
|
-
};
|
|
4967
|
-
|
|
4968
|
-
// src/hooks/useGrid.ts
|
|
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
|
-
]);
|
|
5000
|
-
}, []);
|
|
5001
|
-
const removeFilter = useCallback2(
|
|
5002
|
-
(prop, isId) => {
|
|
5003
|
-
const propToCompare = isId ? "id" : "prop";
|
|
5004
|
-
setSelectedFilters(
|
|
5005
|
-
selectedFilters.filter((filter) => filter[propToCompare] !== prop)
|
|
5006
|
-
);
|
|
5007
|
-
},
|
|
5008
|
-
[selectedFilters]
|
|
5009
|
-
);
|
|
5010
|
-
function clearAllFilters() {
|
|
5011
|
-
setSelectedFilters([]);
|
|
5012
|
-
}
|
|
5013
|
-
return {
|
|
5014
|
-
filters: selectedFilters,
|
|
5015
|
-
filterBy,
|
|
5016
|
-
removeFilter,
|
|
5017
|
-
createFilter,
|
|
5018
|
-
clearAllFilters
|
|
5019
|
-
};
|
|
5020
|
-
}
|
|
5021
|
-
function isDate(date) {
|
|
5022
|
-
if (date instanceof Date) return true;
|
|
5023
|
-
else if (String(date).endsWith("Z")) return true;
|
|
5024
|
-
return false;
|
|
5025
|
-
}
|
|
5026
|
-
function compareFilter(item, filter) {
|
|
5027
|
-
const itemValue = getObjectValue(item)(filter.prop);
|
|
5028
|
-
switch (filter.compareType) {
|
|
5029
|
-
case "equal":
|
|
5030
|
-
return itemValue === filter.value;
|
|
5031
|
-
case "notEqual":
|
|
5032
|
-
return itemValue !== filter.value;
|
|
5033
|
-
case "in":
|
|
5034
|
-
return filter.value.includes(itemValue);
|
|
5035
|
-
case "notIn":
|
|
5036
|
-
return !filter.value.includes(itemValue);
|
|
5037
|
-
case "valueIn":
|
|
5038
|
-
return itemValue.includes(filter.value);
|
|
5039
|
-
case "valueNotIn":
|
|
5040
|
-
return !itemValue.includes(filter.value);
|
|
5041
|
-
case "gte":
|
|
5042
|
-
return isDate(itemValue) ? new Date(String(itemValue)) >= filter.value : itemValue >= filter.value;
|
|
5043
|
-
case "gt":
|
|
5044
|
-
return isDate(itemValue) ? new Date(String(itemValue)) > filter.value : itemValue > filter.value;
|
|
5045
|
-
case "lte":
|
|
5046
|
-
return isDate(itemValue) ? new Date(String(itemValue)) <= filter.value : itemValue <= filter.value;
|
|
5047
|
-
case "lt":
|
|
5048
|
-
return isDate(itemValue) ? new Date(String(itemValue)) < filter.value : itemValue < filter.value;
|
|
5049
|
-
}
|
|
5050
|
-
}
|
|
5051
|
-
function createFilter(filters) {
|
|
5052
|
-
function apply(item) {
|
|
5053
|
-
const satisfiedFilters = filters.reduce((acc, filter) => {
|
|
5054
|
-
if (compareFilter(item, filter)) acc += 1;
|
|
5055
|
-
return acc;
|
|
5056
|
-
}, 0);
|
|
5057
|
-
return satisfiedFilters === filters.length;
|
|
5058
|
-
}
|
|
5059
|
-
return {
|
|
5060
|
-
apply
|
|
5061
|
-
};
|
|
5062
|
-
}
|
|
5063
|
-
|
|
5064
|
-
// src/helpers/sortHelper.ts
|
|
5065
|
-
function SortHelper(...fields) {
|
|
5066
|
-
return (a, b) => {
|
|
5067
|
-
for (const field of fields) {
|
|
5068
|
-
let direction = 1;
|
|
5069
|
-
let key = field;
|
|
5070
|
-
if (field.startsWith("-")) {
|
|
5071
|
-
direction = -1;
|
|
5072
|
-
key = field.slice(1);
|
|
5073
|
-
}
|
|
5074
|
-
const aVal = a[key];
|
|
5075
|
-
const bVal = b[key];
|
|
5076
|
-
if (aVal > bVal) return direction;
|
|
5077
|
-
if (aVal < bVal) return -direction;
|
|
5078
|
-
}
|
|
5079
|
-
return 0;
|
|
5080
|
-
};
|
|
5081
|
-
}
|
|
5082
|
-
|
|
5083
|
-
// src/hooks/useGrid.ts
|
|
5084
|
-
function useGrid({
|
|
5085
|
-
columns,
|
|
5086
|
-
filters,
|
|
5087
|
-
search,
|
|
5088
|
-
rowsPerPageOptions = [30, 60, 100],
|
|
5089
|
-
defaultData: externalDefaultData,
|
|
5090
|
-
defaultCurrentPage,
|
|
5091
|
-
defaultSortedBy
|
|
5092
|
-
}) {
|
|
5093
|
-
const [defaultData, setDefaultData] = useState7(externalDefaultData || []);
|
|
5094
|
-
const [sortedBy, setSortedBy] = useState7(
|
|
4799
|
+
const [defaultData, setDefaultData] = useState8(externalDefaultData || []);
|
|
4800
|
+
const [sortedBy, setSortedBy] = useState8(
|
|
5095
4801
|
defaultSortedBy || []
|
|
5096
4802
|
);
|
|
5097
|
-
const [currentPage, setCurrentPage] =
|
|
5098
|
-
const [rowsPerPage, setRowsPerPage] =
|
|
5099
|
-
const toggleSortedDirection =
|
|
4803
|
+
const [currentPage, setCurrentPage] = useState8(defaultCurrentPage || 0);
|
|
4804
|
+
const [rowsPerPage, setRowsPerPage] = useState8(rowsPerPageOptions[0]);
|
|
4805
|
+
const toggleSortedDirection = useCallback4(
|
|
5100
4806
|
(direction) => {
|
|
5101
4807
|
if (direction === "asc") return "desc";
|
|
5102
4808
|
return "asc";
|
|
5103
4809
|
},
|
|
5104
4810
|
[]
|
|
5105
4811
|
);
|
|
5106
|
-
const clearSort =
|
|
4812
|
+
const clearSort = useCallback4(() => {
|
|
5107
4813
|
setSortedBy([]);
|
|
5108
4814
|
}, []);
|
|
5109
|
-
const appendSort =
|
|
4815
|
+
const appendSort = useCallback4((prop, direction) => {
|
|
5110
4816
|
setSortedBy((prev) => [...prev, { prop, direction }]);
|
|
5111
4817
|
}, []);
|
|
5112
|
-
const setSort =
|
|
4818
|
+
const setSort = useCallback4((prop, direction) => {
|
|
5113
4819
|
setSortedBy([{ prop, direction }]);
|
|
5114
4820
|
}, []);
|
|
5115
|
-
const onSortBy =
|
|
4821
|
+
const onSortBy = useCallback4(
|
|
5116
4822
|
(prop) => {
|
|
5117
4823
|
if (!prop) return;
|
|
5118
4824
|
const currentSorted = sortedBy.find((p) => p.prop === prop);
|
|
@@ -5137,10 +4843,10 @@ function useGrid({
|
|
|
5137
4843
|
},
|
|
5138
4844
|
[toggleSortedDirection, sortedBy]
|
|
5139
4845
|
);
|
|
5140
|
-
const set =
|
|
4846
|
+
const set = useCallback4((data) => {
|
|
5141
4847
|
setDefaultData(data);
|
|
5142
4848
|
}, []);
|
|
5143
|
-
const sortData =
|
|
4849
|
+
const sortData = useCallback4(
|
|
5144
4850
|
(data) => {
|
|
5145
4851
|
if (sortedBy.length > 0) {
|
|
5146
4852
|
const symbolDir = {
|
|
@@ -5160,542 +4866,832 @@ function useGrid({
|
|
|
5160
4866
|
if (pageNumber > totalNumberOfPages) return;
|
|
5161
4867
|
setCurrentPage(pageNumber);
|
|
5162
4868
|
};
|
|
5163
|
-
const onChangeRowsPerPage =
|
|
4869
|
+
const onChangeRowsPerPage = useCallback4(
|
|
5164
4870
|
(rows) => {
|
|
5165
4871
|
let totalNumberOfPages2 = Math.round(filteredData.length / rows) - 1;
|
|
5166
4872
|
totalNumberOfPages2 = totalNumberOfPages2 <= 0 ? 0 : 1;
|
|
5167
|
-
if (currentPage > totalNumberOfPages2) setCurrentPage(totalNumberOfPages2);
|
|
5168
|
-
setRowsPerPage(rows);
|
|
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]);
|
|
4903
|
+
return {
|
|
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
|
|
4921
|
+
};
|
|
4922
|
+
}
|
|
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;
|
|
4942
|
+
}
|
|
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;
|
|
4971
|
+
};
|
|
4972
|
+
}
|
|
4973
|
+
|
|
4974
|
+
// src/hooks/useAsyncGrid.ts
|
|
4975
|
+
import { useCallback as useCallback5, useEffect as useEffect5, useState as useState9 } from "react";
|
|
4976
|
+
function useAsyncGrid({
|
|
4977
|
+
columns,
|
|
4978
|
+
filters = [],
|
|
4979
|
+
search,
|
|
4980
|
+
rowsPerPageOptions = [30, 60, 100],
|
|
4981
|
+
onRequest,
|
|
4982
|
+
axiosInstance,
|
|
4983
|
+
url,
|
|
4984
|
+
defaultData: externalDefaultData,
|
|
4985
|
+
defaultCurrentPage,
|
|
4986
|
+
defaultSortedBy
|
|
4987
|
+
}) {
|
|
4988
|
+
const [defaultData, setDefaultData] = useState9(externalDefaultData || []);
|
|
4989
|
+
const [sortedBy, setSortedBy] = useState9(
|
|
4990
|
+
defaultSortedBy || []
|
|
4991
|
+
);
|
|
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
|
+
});
|
|
5169
5116
|
},
|
|
5170
|
-
[currentPage]
|
|
5117
|
+
[updateGridContent, totalNumberOfItems, sortedBy, currentPage]
|
|
5171
5118
|
);
|
|
5172
|
-
const
|
|
5173
|
-
|
|
5174
|
-
|
|
5175
|
-
|
|
5176
|
-
return sortedData;
|
|
5177
|
-
}, [defaultData, sortData, sortedBy]);
|
|
5178
|
-
const filteredData = useMemo3(() => {
|
|
5179
|
-
let newData = orderedData.slice(0);
|
|
5180
|
-
if (search && search.value !== "") {
|
|
5181
|
-
const searchBy = createSearch(search);
|
|
5182
|
-
newData = newData.filter(searchBy);
|
|
5183
|
-
}
|
|
5184
|
-
if (!filters) return newData;
|
|
5185
|
-
const newFilter = createFilter(filters);
|
|
5186
|
-
return newData.filter(newFilter.apply);
|
|
5187
|
-
}, [orderedData, search, filters]);
|
|
5188
|
-
const paginatedData = useMemo3(() => {
|
|
5189
|
-
const startPage = currentPage * rowsPerPage;
|
|
5190
|
-
const endPage = startPage + rowsPerPage;
|
|
5191
|
-
return filteredData.slice(startPage, endPage);
|
|
5192
|
-
}, [currentPage, rowsPerPage, filteredData]);
|
|
5193
|
-
const totalNumberOfPages = Math.ceil(filteredData.length / rowsPerPage) - 1;
|
|
5194
|
-
useEffect4(() => {
|
|
5195
|
-
if (externalDefaultData) setDefaultData(externalDefaultData);
|
|
5196
|
-
}, [externalDefaultData]);
|
|
5119
|
+
const displayData = defaultData;
|
|
5120
|
+
useEffect5(() => {
|
|
5121
|
+
updateGridContent({ page: 0, sortedBy: [], rowsPerPage });
|
|
5122
|
+
}, [updateGridContent, rowsPerPage]);
|
|
5197
5123
|
return {
|
|
5198
|
-
data:
|
|
5199
|
-
|
|
5200
|
-
|
|
5201
|
-
defaultData,
|
|
5124
|
+
data: displayData,
|
|
5125
|
+
set,
|
|
5126
|
+
onSortBy,
|
|
5202
5127
|
sortedBy,
|
|
5128
|
+
defaultData,
|
|
5203
5129
|
columns,
|
|
5204
5130
|
currentPage,
|
|
5205
5131
|
totalNumberOfPages: totalNumberOfPages < 0 ? 0 : totalNumberOfPages,
|
|
5206
|
-
rowsPerPageOptions,
|
|
5207
|
-
rowsPerPage,
|
|
5208
|
-
set,
|
|
5209
|
-
onSortBy,
|
|
5210
5132
|
onPageChange,
|
|
5211
5133
|
setRowsPerPage: onChangeRowsPerPage,
|
|
5212
|
-
|
|
5134
|
+
rowsPerPageOptions,
|
|
5135
|
+
rowsPerPage,
|
|
5213
5136
|
setSort,
|
|
5214
|
-
|
|
5137
|
+
isLoading,
|
|
5138
|
+
setIsLoading
|
|
5215
5139
|
};
|
|
5216
5140
|
}
|
|
5217
|
-
|
|
5218
|
-
|
|
5219
|
-
|
|
5220
|
-
|
|
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
|
+
};
|
|
5222
|
+
},
|
|
5223
|
+
[setLoading, api]
|
|
5224
|
+
);
|
|
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);
|
|
5236
|
+
}
|
|
5237
|
+
}
|
|
5238
|
+
createAlert(formatErrorMessage(error), "error");
|
|
5239
|
+
},
|
|
5240
|
+
[formatErrorMessage, createAlert]
|
|
5241
|
+
);
|
|
5242
|
+
useEffect7(() => {
|
|
5243
|
+
return () => {
|
|
5244
|
+
sourceRef.current.abort();
|
|
5245
|
+
sourceRef.current = new AbortController();
|
|
5246
|
+
};
|
|
5247
|
+
}, []);
|
|
5248
|
+
return {
|
|
5249
|
+
...alertProps,
|
|
5250
|
+
...loadingProps,
|
|
5251
|
+
onSubmitWrapper,
|
|
5252
|
+
onRequestWrapper
|
|
5253
|
+
};
|
|
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
|
+
}
|
|
5288
|
+
},
|
|
5289
|
+
[createAlert, api]
|
|
5290
|
+
);
|
|
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
|
+
});
|
|
5305
|
+
}
|
|
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
|
+
);
|
|
5319
|
+
}
|
|
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) return res.status(405).json({ error: "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,
|