@bluemarble/bm-components 2.4.1 → 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.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,
@@ -3155,7 +3263,7 @@ import React10, { useState as useState2 } from "react";
3155
3263
  // src/components/Grid/EditableTableCell/DefaultInput.tsx
3156
3264
  import React8 from "react";
3157
3265
  import { TextField as TextField2 } from "@mui/material";
3158
- import moment from "moment";
3266
+ import dayjs from "dayjs";
3159
3267
  var DefaultInput = (allProps) => {
3160
3268
  const {
3161
3269
  TextFieldProps: TextFieldProps3,
@@ -3174,9 +3282,9 @@ var DefaultInput = (allProps) => {
3174
3282
  if (formatInputDefautvalue) return formatInputDefautvalue(value);
3175
3283
  switch (type) {
3176
3284
  case "date":
3177
- return moment(value).format("YYYY-MM-DD");
3285
+ return dayjs(value).format("YYYY-MM-DD");
3178
3286
  case "datetime-local":
3179
- return moment(value).format("YYYY-MM-DDTHH:mm:ss");
3287
+ return dayjs(value).format("YYYY-MM-DDTHH:mm:ss");
3180
3288
  default:
3181
3289
  return String(value);
3182
3290
  }
@@ -3246,9 +3354,7 @@ var InputMask = (allProps) => {
3246
3354
  handleCancelEditing,
3247
3355
  setIsEditing
3248
3356
  } = allProps;
3249
- const { ref, unmaskedValue, setValue } = useIMask(
3250
- mask
3251
- );
3357
+ const { ref, unmaskedValue, setValue } = useIMask(mask);
3252
3358
  const handleSave = (event) => {
3253
3359
  setIsEditing(false);
3254
3360
  setValue(String(event.target?.value));
@@ -3484,8 +3590,8 @@ import {
3484
3590
  } from "@mui/material";
3485
3591
  import { useField } from "formik";
3486
3592
  var CustomInputLabel = InputLabel;
3487
- function Select({ withFormik = true, ...rest }) {
3488
- if (withFormik) return /* @__PURE__ */ React13.createElement(FormikSelect, { ...rest });
3593
+ function Select({ withFormik = true, helperText, ...rest }) {
3594
+ if (withFormik) return /* @__PURE__ */ React13.createElement(FormikSelect, { helperText, ...rest });
3489
3595
  else return /* @__PURE__ */ React13.createElement(BaseSelect, { ...rest });
3490
3596
  }
3491
3597
  function BaseSelect({
@@ -3703,7 +3809,9 @@ function FormikAutocomplete({
3703
3809
  import React15 from "react";
3704
3810
  import {
3705
3811
  Checkbox as MuiCheckbox,
3706
- FormControlLabel
3812
+ FormControl as FormControl2,
3813
+ FormControlLabel,
3814
+ FormHelperText as FormHelperText2
3707
3815
  } from "@mui/material";
3708
3816
  import { useField as useField3 } from "formik";
3709
3817
  var Checkbox = ({
@@ -3716,47 +3824,49 @@ var Checkbox = ({
3716
3824
  };
3717
3825
  var BaseCheckbox = ({
3718
3826
  label,
3827
+ helperText,
3719
3828
  FormControlLabelProps: FormControlLabelProps3,
3720
3829
  ...props
3721
3830
  }) => {
3722
- return /* @__PURE__ */ React15.createElement(
3831
+ return /* @__PURE__ */ React15.createElement(FormControl2, null, /* @__PURE__ */ React15.createElement(
3723
3832
  FormControlLabel,
3724
3833
  {
3725
3834
  label,
3726
3835
  control: /* @__PURE__ */ React15.createElement(MuiCheckbox, { ...props }),
3727
3836
  ...FormControlLabelProps3
3728
3837
  }
3729
- );
3838
+ ), helperText && /* @__PURE__ */ React15.createElement(FormHelperText2, null, helperText));
3730
3839
  };
3731
3840
  var FormikCheckbox = ({
3732
3841
  label,
3733
3842
  name,
3843
+ helperText,
3734
3844
  FormControlLabelProps: FormControlLabelProps3,
3735
3845
  ...props
3736
3846
  }) => {
3737
- const [{ value, ...field }, , { setValue }] = useField3({
3738
- name
3739
- });
3847
+ const [{ value, ...field }, { error }, { setValue }] = useField3({ name });
3740
3848
  const onChange = (_, value2) => {
3741
3849
  setValue(value2);
3742
3850
  };
3743
- return /* @__PURE__ */ React15.createElement(
3851
+ return /* @__PURE__ */ React15.createElement(FormControl2, { error: Boolean(error) }, /* @__PURE__ */ React15.createElement(
3744
3852
  FormControlLabel,
3745
3853
  {
3746
3854
  label,
3747
- control: /* @__PURE__ */ React15.createElement(MuiCheckbox, { ...props, defaultChecked: Boolean(value) }),
3855
+ control: /* @__PURE__ */ React15.createElement(MuiCheckbox, { ...props, checked: Boolean(value) }),
3748
3856
  ...field,
3749
3857
  onChange,
3750
3858
  ...FormControlLabelProps3
3751
3859
  }
3752
- );
3860
+ ), (error || helperText) && /* @__PURE__ */ React15.createElement(FormHelperText2, null, error ?? helperText));
3753
3861
  };
3754
3862
 
3755
3863
  // src/components/Switch/index.tsx
3756
3864
  import React16 from "react";
3757
3865
  import {
3758
3866
  Switch as MuiSwitch,
3759
- FormControlLabel as FormControlLabel2
3867
+ FormControl as FormControl3,
3868
+ FormControlLabel as FormControlLabel2,
3869
+ FormHelperText as FormHelperText3
3760
3870
  } from "@mui/material";
3761
3871
  import { useField as useField4 } from "formik";
3762
3872
  var Switch = ({ withFormik = true, name, ...props }) => {
@@ -3765,52 +3875,53 @@ var Switch = ({ withFormik = true, name, ...props }) => {
3765
3875
  };
3766
3876
  var BaseSwitch = ({
3767
3877
  label,
3878
+ helperText,
3768
3879
  FormControlLabelProps: FormControlLabelProps3,
3769
3880
  ...props
3770
3881
  }) => {
3771
- return /* @__PURE__ */ React16.createElement(
3882
+ return /* @__PURE__ */ React16.createElement(FormControl3, null, /* @__PURE__ */ React16.createElement(
3772
3883
  FormControlLabel2,
3773
3884
  {
3774
3885
  label,
3775
3886
  control: /* @__PURE__ */ React16.createElement(MuiSwitch, { ...props }),
3776
3887
  ...FormControlLabelProps3
3777
3888
  }
3778
- );
3889
+ ), helperText && /* @__PURE__ */ React16.createElement(FormHelperText3, null, helperText));
3779
3890
  };
3780
3891
  var FormikSwitch = ({
3781
3892
  label,
3782
3893
  name,
3894
+ helperText,
3783
3895
  FormControlLabelProps: FormControlLabelProps3,
3784
3896
  ...props
3785
3897
  }) => {
3786
- const [{ value, onChange: unused, ...field }, , { setValue }] = useField4({
3787
- name
3788
- });
3898
+ const [{ value, onChange: unused, ...field }, { error }, { setValue }] = useField4({ name });
3789
3899
  const onChange = (_, value2) => {
3790
3900
  setValue(value2);
3791
3901
  };
3792
- return /* @__PURE__ */ React16.createElement(
3902
+ return /* @__PURE__ */ React16.createElement(FormControl3, { error: Boolean(error) }, /* @__PURE__ */ React16.createElement(
3793
3903
  FormControlLabel2,
3794
3904
  {
3795
3905
  label,
3796
3906
  onChange,
3797
- control: /* @__PURE__ */ React16.createElement(MuiSwitch, { defaultChecked: value, ...props }),
3907
+ control: /* @__PURE__ */ React16.createElement(MuiSwitch, { checked: value, ...props }),
3798
3908
  ...field,
3799
3909
  ...FormControlLabelProps3
3800
3910
  }
3801
- );
3911
+ ), (error || helperText) && /* @__PURE__ */ React16.createElement(FormHelperText3, null, error ?? helperText));
3802
3912
  };
3803
3913
 
3804
3914
  // src/components/Radio/index.tsx
3805
3915
  import React17 from "react";
3806
3916
  import {
3807
- FormControl as FormControl2,
3917
+ FormControl as FormControl4,
3808
3918
  FormControlLabel as FormControlLabel3,
3919
+ FormHelperText as FormHelperText4,
3809
3920
  FormLabel,
3810
3921
  Radio as MuiRadio,
3811
3922
  RadioGroup
3812
3923
  } from "@mui/material";
3813
- import { Field as Field3 } from "formik";
3924
+ import { useField as useField5 } from "formik";
3814
3925
  var Radio = ({
3815
3926
  name,
3816
3927
  withFormik = true,
@@ -3822,9 +3933,10 @@ var Radio = ({
3822
3933
  var BaseRadio = ({
3823
3934
  label,
3824
3935
  options,
3936
+ helperText,
3825
3937
  ...rest
3826
3938
  }) => {
3827
- return /* @__PURE__ */ React17.createElement(FormControl2, null, label && /* @__PURE__ */ React17.createElement(FormLabel, null, label), /* @__PURE__ */ React17.createElement(RadioGroup, { ...rest }, options.map((option) => /* @__PURE__ */ React17.createElement(
3939
+ return /* @__PURE__ */ React17.createElement(FormControl4, null, label && /* @__PURE__ */ React17.createElement(FormLabel, null, label), /* @__PURE__ */ React17.createElement(RadioGroup, { ...rest }, options.map((option) => /* @__PURE__ */ React17.createElement(
3828
3940
  FormControlLabel3,
3829
3941
  {
3830
3942
  key: String(option.value),
@@ -3832,22 +3944,21 @@ var BaseRadio = ({
3832
3944
  label: option.label,
3833
3945
  control: /* @__PURE__ */ React17.createElement(MuiRadio, null)
3834
3946
  }
3835
- ))));
3947
+ ))), helperText && /* @__PURE__ */ React17.createElement(FormHelperText4, null, helperText));
3836
3948
  };
3837
3949
  var FormikRadio = ({
3838
3950
  label,
3839
3951
  name,
3840
3952
  options,
3953
+ helperText,
3841
3954
  ...rest
3842
3955
  }) => {
3843
- const onChange = (setFieldValue, value) => {
3844
- setFieldValue(name, value);
3845
- };
3846
- return /* @__PURE__ */ React17.createElement(Field3, null, ({ field: { value }, form: { setFieldValue } }) => /* @__PURE__ */ React17.createElement(FormControl2, null, label && /* @__PURE__ */ React17.createElement(FormLabel, null, label), /* @__PURE__ */ React17.createElement(
3956
+ const [{ value }, meta, { setValue }] = useField5(name);
3957
+ return /* @__PURE__ */ React17.createElement(FormControl4, { error: Boolean(meta.error) }, label && /* @__PURE__ */ React17.createElement(FormLabel, null, label), /* @__PURE__ */ React17.createElement(
3847
3958
  RadioGroup,
3848
3959
  {
3849
- defaultValue: value,
3850
- onChange: (_, value2) => onChange(setFieldValue, value2),
3960
+ value: value ?? "",
3961
+ onChange: (_, val) => setValue(val),
3851
3962
  ...rest
3852
3963
  },
3853
3964
  options.map((option) => /* @__PURE__ */ React17.createElement(
@@ -3859,7 +3970,7 @@ var FormikRadio = ({
3859
3970
  control: /* @__PURE__ */ React17.createElement(MuiRadio, null)
3860
3971
  }
3861
3972
  ))
3862
- )));
3973
+ ), /* @__PURE__ */ React17.createElement(FormHelperText4, null, helperText || meta.error));
3863
3974
  };
3864
3975
 
3865
3976
  // src/components/LargeButton/index.tsx
@@ -4153,6 +4264,11 @@ import {
4153
4264
  Modal as MuiModal
4154
4265
  } from "@mui/material";
4155
4266
  var Modal = ({ open, onClose, BoxProps: BoxProps3, ...rest }) => {
4267
+ if (process.env.NODE_ENV !== "production") {
4268
+ console.warn(
4269
+ "[Modal] is deprecated. Use `BaseDialog` instead. `Modal` will be removed in a future release."
4270
+ );
4271
+ }
4156
4272
  return /* @__PURE__ */ React23.createElement(MuiModal, { open, onClose, ...rest }, /* @__PURE__ */ React23.createElement(
4157
4273
  Box5,
4158
4274
  {
@@ -4472,132 +4588,24 @@ var BaseDialog = {
4472
4588
  Body: BaseDialogBody
4473
4589
  };
4474
4590
 
4475
- // src/errors/HttpError.ts
4476
- var HttpError = class extends Error {
4477
- constructor(status, message) {
4478
- super(message);
4479
- this.message = message;
4480
- this.stack = `HttpError: ${message}`;
4481
- this.status = status;
4482
- }
4483
- };
4484
-
4485
- // src/errors/DomainError.ts
4486
- var DomainError = class extends Error {
4487
- constructor(message) {
4488
- super(message);
4489
- this.message = message;
4490
- this.stack = `DomainError: ${message}`;
4491
- }
4492
- };
4493
-
4494
- // src/helpers/apiHelper/index.ts
4495
- var VALID_METHODS = [
4496
- "GET",
4497
- "HEAD",
4498
- "POST",
4499
- "PUT",
4500
- "DELETE",
4501
- "CONNECT",
4502
- "OPTIONS",
4503
- "TRACE",
4504
- "PATCH"
4505
- ];
4506
- var _ApiHelper = class _ApiHelper {
4507
- async onFinally(_req, _res) {
4508
- }
4509
- async onError(_req, _res, _error) {
4510
- }
4511
- constructor(props) {
4512
- this.public = props?.public ?? false;
4513
- this.middlewares = (props?.middlewares || []).reverse();
4514
- this.onFinally = props?.onFinally || (async () => {
4515
- });
4516
- this.onError = props?.onError || (async () => {
4517
- });
4518
- }
4519
- createMethods(methods) {
4520
- return async (req, res) => {
4521
- const currentMethod = methods[req.method] || methods.ALL;
4522
- const options = { public: this.public };
4523
- if (req.method === "OPTIONS") return res.status(200).end();
4524
- try {
4525
- if (!VALID_METHODS.includes(req.method))
4526
- throw new HttpError(405, "M\xE9todo inv\xE1lido");
4527
- if (!currentMethod) throw new HttpError(500, "M\xE9todo n\xE3o encontrado");
4528
- const methodWithMiddlewares = this.middlewares.reduce(
4529
- (acc, fn) => fn(acc, options),
4530
- currentMethod
4531
- );
4532
- return await methodWithMiddlewares(req, res, options);
4533
- } catch (error) {
4534
- if (error instanceof DomainError) return res.status(400).json(error.message);
4535
- if (error instanceof HttpError) return res.status(error.status).json(error.message);
4536
- this.onError(req, res, error);
4537
- throw error;
4538
- } finally {
4539
- await this.onFinally(req, res);
4540
- }
4541
- };
4542
- }
4543
- buildFactory(factory) {
4544
- const options = {
4545
- public: this.public
4546
- };
4547
- return async (req, res) => {
4548
- const methods = factory(req, res);
4549
- const handler = methods[req.method];
4550
- const methodWithMiddlewares = this.middlewares.reduce((acc, fn) => {
4551
- return fn(acc, options);
4552
- }, handler);
4553
- return await methodWithMiddlewares(req, res, options);
4554
- };
4555
- }
4556
- static build(factory, options) {
4557
- const helper = new _ApiHelper({
4558
- ...options
4559
- }).buildFactory(factory);
4560
- return helper;
4561
- }
4562
- static parse(body, parser) {
4563
- try {
4564
- const object = parser.parse(body);
4565
- return object;
4566
- } catch (error) {
4567
- throw new HttpError(400, {
4568
- code: "invalid.body",
4569
- error: "Dados inv\xE1lidos",
4570
- details: error
4571
- });
4572
- }
4573
- }
4574
- /** @deprecated Use {@Link ApiHelper.build} instead. */
4575
- static create({ onFinally }) {
4576
- return new _ApiHelper({
4577
- onFinally
4578
- });
4579
- }
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);
4580
4597
  };
4581
- /** @deprecated Use {@link ApiHelper.parser} instead. */
4582
- _ApiHelper.parserErrorWrapper = _ApiHelper.parse;
4583
- var ApiHelper = _ApiHelper;
4584
-
4585
- // src/hooks/useFormHelper.ts
4586
- import { useCallback as useCallback4, useContext as useContext4, useEffect as useEffect4, useRef as useRef4 } from "react";
4587
-
4588
- // src/hooks/useAlert.ts
4589
- import { useContext as useContext3 } from "react";
4590
4598
 
4591
4599
  // src/contexts/AlertContext.tsx
4592
- import React31, { useCallback as useCallback2 } from "react";
4593
- import { createContext as createContext3, useState as useState6 } from "react";
4600
+ import React32, { useCallback as useCallback2 } from "react";
4601
+ import { createContext as createContext4, useState as useState6 } from "react";
4594
4602
 
4595
4603
  // src/components/Toast/index.tsx
4596
- import React30 from "react";
4604
+ import React31 from "react";
4597
4605
  import { Alert, IconButton as IconButton5, Snackbar } from "@mui/material";
4598
4606
  import { MdClose as MdClose3 } from "react-icons/md";
4599
4607
  var Toast = ({ open, onClose, severity, message }) => {
4600
- return /* @__PURE__ */ React30.createElement(React30.Fragment, null, /* @__PURE__ */ React30.createElement(
4608
+ return /* @__PURE__ */ React31.createElement(React31.Fragment, null, /* @__PURE__ */ React31.createElement(
4601
4609
  Snackbar,
4602
4610
  {
4603
4611
  open,
@@ -4606,12 +4614,12 @@ var Toast = ({ open, onClose, severity, message }) => {
4606
4614
  anchorOrigin: { vertical: "top", horizontal: "right" },
4607
4615
  sx: { zIndex: 99999999 }
4608
4616
  },
4609
- /* @__PURE__ */ React30.createElement(
4617
+ /* @__PURE__ */ React31.createElement(
4610
4618
  Alert,
4611
4619
  {
4612
4620
  severity,
4613
4621
  elevation: 2,
4614
- action: /* @__PURE__ */ React30.createElement(
4622
+ action: /* @__PURE__ */ React31.createElement(
4615
4623
  IconButton5,
4616
4624
  {
4617
4625
  "aria-label": "close",
@@ -4619,7 +4627,7 @@ var Toast = ({ open, onClose, severity, message }) => {
4619
4627
  size: "small",
4620
4628
  onClick: onClose
4621
4629
  },
4622
- /* @__PURE__ */ React30.createElement(MdClose3, { fontSize: "inherit" })
4630
+ /* @__PURE__ */ React31.createElement(MdClose3, { fontSize: "inherit" })
4623
4631
  )
4624
4632
  },
4625
4633
  message
@@ -4628,7 +4636,7 @@ var Toast = ({ open, onClose, severity, message }) => {
4628
4636
  };
4629
4637
 
4630
4638
  // src/contexts/AlertContext.tsx
4631
- var AlertContext = createContext3({});
4639
+ var AlertContext = createContext4({});
4632
4640
  var AlertProvider = ({ children }) => {
4633
4641
  const [severity, setSeverity] = useState6("info");
4634
4642
  const [message, setMessage] = useState6("");
@@ -4644,7 +4652,7 @@ var AlertProvider = ({ children }) => {
4644
4652
  const onCloseToast = useCallback2(() => {
4645
4653
  setIsVisible(false);
4646
4654
  }, []);
4647
- return /* @__PURE__ */ React31.createElement(AlertContext.Provider, { value: { createAlert } }, children, /* @__PURE__ */ React31.createElement(
4655
+ return /* @__PURE__ */ React32.createElement(AlertContext.Provider, { value: { createAlert } }, children, /* @__PURE__ */ React32.createElement(
4648
4656
  Toast,
4649
4657
  {
4650
4658
  open: isVisible,
@@ -4655,611 +4663,324 @@ var AlertProvider = ({ children }) => {
4655
4663
  ));
4656
4664
  };
4657
4665
 
4658
- // src/hooks/useAlert.ts
4659
- var useAlert = () => {
4660
- return useContext3(AlertContext);
4661
- };
4662
-
4663
- // src/hooks/useLoading.ts
4664
- import { useCallback as useCallback3, useState as useState7 } from "react";
4665
- function useLoading() {
4666
- const [state, setState] = useState7([]);
4667
- const isLoading = useCallback3((prop) => state.includes(prop), [state]);
4668
- const setLoading = useCallback3((prop, remove) => {
4669
- if (remove)
4670
- setState((prevState) => prevState.filter((state2) => state2 !== prop));
4671
- else setState((prevState) => [...prevState, prop]);
4672
- }, []);
4673
- return { isLoading, setLoading };
4674
- }
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";
4675
4673
 
4676
- // src/contexts/FormHelperProvider.tsx
4677
- import React32 from "react";
4678
- import { createContext as createContext4 } from "react";
4679
- var FormHelperContext = createContext4({});
4680
- var FormHelperProvider = ({ formatErrorMessage, api, children }) => {
4681
- return /* @__PURE__ */ React32.createElement(FormHelperContext.Provider, { value: { formatErrorMessage, api } }, children);
4682
- };
4674
+ // src/hooks/useGrid.ts
4675
+ import { useCallback as useCallback4, useEffect as useEffect4, useMemo as useMemo3, useState as useState8 } from "react";
4683
4676
 
4684
- // src/hooks/useFormHelper.ts
4685
- function useFormHelper() {
4686
- const alertProps = useAlert();
4687
- const loadingProps = useLoading();
4688
- const { api, formatErrorMessage } = useContext4(FormHelperContext);
4689
- const { createAlert } = alertProps;
4690
- const { setLoading } = loadingProps;
4691
- const sourceRef = useRef4(new AbortController());
4692
- const onSubmitWrapper = useCallback4(
4693
- (fn, { name }) => {
4694
- return async (fields, methods) => {
4695
- const LOADING_NAME = name;
4696
- setLoading(LOADING_NAME);
4697
- try {
4698
- await fn(fields, methods);
4699
- } catch (error) {
4700
- errorHandler(error, methods.setErrors);
4701
- } finally {
4702
- setLoading(LOADING_NAME, true);
4703
- }
4704
- };
4705
- },
4706
- [setLoading]
4707
- );
4708
- const onRequestWrapper = useCallback4(
4709
- (fn, { name }) => {
4710
- return async (...params) => {
4711
- const LOADING_NAME = name;
4712
- setLoading(LOADING_NAME);
4713
- api.interceptors.request.use(
4714
- (config) => {
4715
- if (!config.signal && sourceRef.current && config.method === "get") {
4716
- config.signal = sourceRef.current.signal;
4717
- }
4718
- return config;
4719
- },
4720
- (error) => {
4721
- return Promise.reject(error);
4722
- }
4723
- );
4724
- try {
4725
- const response = await fn(...params);
4726
- return response;
4727
- } catch (error) {
4728
- errorHandler(error);
4729
- } finally {
4730
- setLoading(LOADING_NAME, true);
4731
- }
4732
- };
4733
- },
4734
- [setLoading, api]
4735
- );
4736
- const errorHandler = useCallback4(
4737
- (error, callback) => {
4738
- if (error?.message === "cancel.navigation") return;
4739
- if (callback) {
4740
- if (error.response.data.code === "invalid.body") {
4741
- const errors = error.response.data.details.issues;
4742
- const currentErrors = errors.reduce((acc, item) => {
4743
- acc[item.path.join(".")] = item.message;
4744
- return acc;
4745
- }, {});
4746
- callback(currentErrors);
4747
- }
4748
- }
4749
- createAlert(formatErrorMessage(error), "error");
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
+ };
4689
+ }
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
+ );
4750
4713
  },
4751
- [formatErrorMessage, createAlert]
4714
+ [selectedFilters]
4752
4715
  );
4753
- useEffect4(() => {
4754
- return () => {
4755
- sourceRef.current.abort();
4756
- sourceRef.current = new AbortController();
4757
- };
4758
- }, []);
4716
+ function clearAllFilters() {
4717
+ setSelectedFilters([]);
4718
+ }
4759
4719
  return {
4760
- ...alertProps,
4761
- ...loadingProps,
4762
- onSubmitWrapper,
4763
- onRequestWrapper
4720
+ filters: selectedFilters,
4721
+ filterBy,
4722
+ removeFilter,
4723
+ createFilter,
4724
+ clearAllFilters
4764
4725
  };
4765
4726
  }
4766
-
4767
- // src/helpers/authHelper.ts
4768
- import { serialize as serialize2 } from "cookie";
4769
- import { v4 as uuid } from "uuid";
4770
- import jwt from "jsonwebtoken";
4771
-
4772
- // packages/nookies/index.ts
4773
- import * as cookie from "cookie";
4774
- import * as setCookieParser from "set-cookie-parser";
4775
-
4776
- // packages/nookies/util.ts
4777
- function isBrowser() {
4778
- return typeof window !== "undefined";
4727
+ function isDate(date) {
4728
+ if (date instanceof Date) return true;
4729
+ else if (String(date).endsWith("Z")) return true;
4730
+ return false;
4779
4731
  }
4780
- function createCookie(name, value, options) {
4781
- let sameSite = options.sameSite;
4782
- if (sameSite === true) {
4783
- sameSite = "strict";
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;
4784
4755
  }
4785
- if (sameSite === void 0 || sameSite === false) {
4786
- sameSite = "lax";
4756
+ }
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;
4787
4764
  }
4788
- const cookieToSet = { ...options, sameSite };
4789
- delete cookieToSet.encode;
4790
4765
  return {
4791
- name,
4792
- value,
4793
- ...cookieToSet
4766
+ apply
4794
4767
  };
4795
4768
  }
4796
- function hasSameProperties(a, b) {
4797
- const aProps = Object.getOwnPropertyNames(a);
4798
- const bProps = Object.getOwnPropertyNames(b);
4799
- if (aProps.length !== bProps.length) {
4800
- return false;
4801
- }
4802
- for (let i = 0; i < aProps.length; i++) {
4803
- const propName = aProps[i];
4804
- if (a[propName] !== b[propName]) {
4805
- return false;
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);
4779
+ }
4780
+ const aVal = a[key];
4781
+ const bVal = b[key];
4782
+ if (aVal > bVal) return direction;
4783
+ if (aVal < bVal) return -direction;
4806
4784
  }
4807
- }
4808
- return true;
4809
- }
4810
- function areCookiesEqual(a, b) {
4811
- let sameSiteSame = a.sameSite === b.sameSite;
4812
- if (typeof a.sameSite === "string" && typeof b.sameSite === "string") {
4813
- sameSiteSame = a.sameSite.toLowerCase() === b.sameSite.toLowerCase();
4814
- }
4815
- return hasSameProperties(
4816
- { ...a, sameSite: void 0 },
4817
- { ...b, sameSite: void 0 }
4818
- ) && sameSiteSame;
4785
+ return 0;
4786
+ };
4819
4787
  }
4820
4788
 
4821
- // packages/nookies/index.ts
4822
- function parseCookies(ctx, options) {
4823
- if (ctx?.req?.headers?.cookie) {
4824
- return cookie.parse(ctx.req.headers.cookie, options);
4825
- }
4826
- if (isBrowser()) {
4827
- return cookie.parse(document.cookie, options);
4828
- }
4829
- return {};
4830
- }
4831
- function setCookie(ctx, name, value, options = {}) {
4832
- if (ctx?.res?.getHeader && ctx.res.setHeader) {
4833
- if (ctx?.res?.finished) {
4834
- console.warn(`Not setting "${name}" cookie. Response has finished.`);
4835
- console.warn(`You should set cookie before res.send()`);
4836
- return {};
4837
- }
4838
- let cookies = ctx.res.getHeader("Set-Cookie") || [];
4839
- if (typeof cookies === "string") cookies = [cookies];
4840
- if (typeof cookies === "number") cookies = [];
4841
- const parsedCookies = setCookieParser.parse(cookies, {
4842
- decodeValues: false
4843
- });
4844
- const newCookie = createCookie(name, value, options);
4845
- let cookiesToSet = [];
4846
- parsedCookies.forEach((parsedCookie) => {
4847
- if (!areCookiesEqual(parsedCookie, newCookie)) {
4848
- const serializedCookie = cookie.serialize(
4849
- parsedCookie.name,
4850
- parsedCookie.value,
4851
- {
4852
- // we prevent reencoding by default, but you might override it
4853
- encode: (val) => val,
4854
- ...parsedCookie
4855
- }
4856
- );
4857
- cookiesToSet.push(serializedCookie);
4858
- }
4859
- });
4860
- cookiesToSet.push(cookie.serialize(name, value, options));
4861
- ctx.res.setHeader("Set-Cookie", cookiesToSet);
4862
- }
4863
- if (isBrowser()) {
4864
- if (options && options.httpOnly) {
4865
- throw new Error("Can not set a httpOnly cookie in the browser.");
4866
- }
4867
- document.cookie = cookie.serialize(name, value, options);
4868
- }
4869
- return {};
4870
- }
4871
- function destroyCookie(ctx, name, options) {
4872
- return setCookie(ctx, name, "", { ...options || {}, maxAge: -1 });
4873
- }
4874
- var nookies = {
4875
- set: setCookie,
4876
- get: parseCookies,
4877
- destroy: destroyCookie
4878
- };
4879
-
4880
- // src/helpers/authHelper.ts
4881
- function decodeSessionToken({
4882
- req,
4883
- res,
4884
- sessionTokenName,
4885
- validate
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
4886
4798
  }) {
4887
- const token = req.headers.authorization?.split(" ")[1] || req.cookies[sessionTokenName];
4888
- if (!token) {
4889
- res.status(401).json({ error: "Token inv\xE1lido", code: "token.invalid" });
4890
- return true;
4891
- }
4892
- const jwtDecode = (token2) => {
4893
- if (validate) {
4894
- return jwt.verify(token2, process.env.JWT_SECRET);
4895
- }
4896
- return jwt.decode(token2);
4897
- };
4898
- try {
4899
- const decoded = jwtDecode(token);
4900
- req.user = decoded.sub;
4901
- } catch (_) {
4902
- res.status(401).json({ error: "Token inv\xE1lido", code: "token.expired" });
4903
- return true;
4904
- }
4905
- }
4906
- var AuthHelper = class {
4907
- constructor({
4908
- cookies,
4909
- oauth,
4910
- tokenExpTimeInSeconds,
4911
- onLogin,
4912
- onValidateRefreshToken,
4913
- onInvalidateRefreshToken,
4914
- onCreateRefreshToken,
4915
- onGetUserData
4916
- }) {
4917
- this.generateJwtAndRefreshToken = async (userId, payload = {}) => {
4918
- const token = jwt.sign(payload, process.env.JWT_SECRET, {
4919
- subject: String(userId),
4920
- expiresIn: this.tokenExpTimeInSeconds || 60 * 15
4921
- // 15 minutos
4922
- });
4923
- const uniqueToken = uuid();
4924
- await this.onCreateRefreshToken(userId, uniqueToken);
4925
- return {
4926
- token,
4927
- refreshToken: uniqueToken
4928
- };
4929
- };
4930
- this.invalidateCookies = (res) => {
4931
- return res.setHeader("Set-Cookie", [
4932
- serialize2(this.cookies.sessionToken, "", {
4933
- maxAge: -1,
4934
- path: "/"
4935
- }),
4936
- serialize2(this.cookies.refreshToken, "", {
4937
- maxAge: -1,
4938
- path: "/"
4939
- })
4940
- ]);
4941
- };
4942
- this.cookies = cookies;
4943
- this.oauth = oauth;
4944
- this.tokenExpTimeInSeconds = tokenExpTimeInSeconds;
4945
- this.onLogin = onLogin;
4946
- this.onValidateRefreshToken = onValidateRefreshToken;
4947
- this.onInvalidateRefreshToken = onInvalidateRefreshToken;
4948
- this.onCreateRefreshToken = onCreateRefreshToken;
4949
- this.onGetUserData = onGetUserData;
4950
- }
4951
- async handler(req, res) {
4952
- if (!req.url) return res.status(400).json({ error: "url not sent" });
4953
- if (req.url.endsWith("/login")) {
4954
- const loginResult = await this.onLogin(req.body);
4955
- if (loginResult.status === "sucess") {
4956
- const { refreshToken, token } = await this.generateJwtAndRefreshToken(
4957
- loginResult.userId,
4958
- {}
4959
- );
4960
- setCookie({ res }, this.cookies.sessionToken, token, {
4961
- secure: true,
4962
- maxAge: 60 * 60 * 24 * 30,
4963
- // 30 days
4964
- path: "/",
4965
- sameSite: true
4966
- });
4967
- setCookie({ res }, this.cookies.refreshToken, refreshToken, {
4968
- secure: true,
4969
- maxAge: 60 * 60 * 24 * 30,
4970
- // 30 days
4971
- path: "/",
4972
- sameSite: true,
4973
- httpOnly: true
4974
- });
4975
- return res.json({ token, refreshToken });
4976
- }
4977
- throw new HttpError(400, loginResult.response);
4978
- }
4979
- if (req.url.endsWith("/logout")) {
4980
- this.invalidateCookies(res).end();
4981
- }
4982
- if (req.url.endsWith("/refresh")) {
4983
- const error = decodeSessionToken({
4984
- req,
4985
- res,
4986
- sessionTokenName: this.cookies.sessionToken,
4987
- validate: false
4988
- });
4989
- if (error) return;
4990
- const userId = String(req.user);
4991
- const refreshToken = parseCookies({ req })[this.cookies.refreshToken];
4992
- if (!refreshToken) {
4993
- this.invalidateCookies(res);
4994
- return res.status(400).json({
4995
- error: "Refresh Token inv\xE1lido"
4996
- });
4997
- }
4998
- const isValidRefreshToken = await this.onValidateRefreshToken(
4999
- userId,
5000
- refreshToken
5001
- );
5002
- if (!isValidRefreshToken) {
5003
- this.invalidateCookies(res);
5004
- return res.status(400).json({
5005
- error: "Refresh Token inv\xE1lido"
5006
- });
5007
- }
5008
- await this.onInvalidateRefreshToken(userId, refreshToken);
5009
- const { token, refreshToken: newRefreshToken } = await this.generateJwtAndRefreshToken(userId, {});
5010
- setCookie({ res }, this.cookies.sessionToken, token, {
5011
- secure: true,
5012
- maxAge: 60 * 60 * 24 * 30,
5013
- // 30 days
5014
- path: "/",
5015
- sameSite: true
5016
- });
5017
- setCookie({ res }, this.cookies.refreshToken, newRefreshToken, {
5018
- secure: true,
5019
- maxAge: 60 * 60 * 24 * 30,
5020
- // 30 days
5021
- path: "/",
5022
- sameSite: true,
5023
- httpOnly: true
5024
- });
5025
- return res.json({
5026
- token,
5027
- refreshToken: newRefreshToken
5028
- });
5029
- }
5030
- if (req.url.endsWith("/me")) {
5031
- const error = decodeSessionToken({
5032
- req,
5033
- res,
5034
- sessionTokenName: this.cookies.sessionToken,
5035
- validate: true
5036
- });
5037
- if (error) return;
5038
- if (!req.user)
5039
- return res.status(400).json({ error: "Usu\xE1rio n\xE3o encontrado" });
5040
- const userData = await this.onGetUserData(req.user);
5041
- if (!userData)
5042
- return res.status(400).json({ error: "Usu\xE1rio n\xE3o encontrado" });
5043
- return res.json(userData);
5044
- }
5045
- if (req.url.endsWith("/oauth-url") && this.oauth) {
5046
- const params = {
5047
- client_id: this.oauth.client_id,
5048
- redirect_uri: this.oauth.redirect_uri,
5049
- scope: this.oauth.scope,
5050
- response_type: "code",
5051
- response_mode: "query"
5052
- };
5053
- const url = `https://login.microsoftonline.com/${this.oauth.tenant_id}/oauth2/v2.0/authorize?${new URLSearchParams(params)}`;
5054
- return res.json({
5055
- url
5056
- });
5057
- }
5058
- return res.status(404).json({ error: "Route not found" });
5059
- }
5060
- async oauthSignInCallback(code) {
5061
- if (!this.oauth) throw new Error("OAUTH variables is not defined");
5062
- const body = {
5063
- client_id: this.oauth.client_id,
5064
- scope: this.oauth.scope,
5065
- code,
5066
- session_state: this.oauth.client_id,
5067
- redirect_uri: this.oauth.redirect_uri,
5068
- grant_type: "authorization_code",
5069
- client_secret: this.oauth.client_secret
5070
- };
5071
- const response = await fetch(
5072
- `https://login.microsoftonline.com/${this.oauth.tenant_id}/oauth2/v2.0/token`,
5073
- {
5074
- method: "POST",
5075
- body: new URLSearchParams(body),
5076
- headers: { "Content-Type": "application/x-www-form-urlencoded" }
5077
- }
5078
- );
5079
- const data = await response.json();
5080
- const decodedToken = jwt.decode(data.access_token);
5081
- const email = decodedToken.upn;
5082
- const fullName = `${decodedToken?.given_name} ${decodedToken?.family_name}`;
5083
- return { decodedToken, email, fullName };
5084
- }
5085
- createOauthCallbackGetServerSideProps({
5086
- onSuccessDestination,
5087
- onFailedDestination
5088
- }) {
5089
- return async (ctx) => {
5090
- if (!this.oauth) throw new Error("Oauth env variables are not defined");
5091
- const code = ctx.query.code;
5092
- if (!code)
5093
- return {
5094
- redirect: {
5095
- permanent: false,
5096
- destination: onFailedDestination || "/"
5097
- }
5098
- };
5099
- try {
5100
- const { fullName, email } = await this.oauthSignInCallback(code);
5101
- const userExists = await this.onGetUserData(email);
5102
- if (!userExists && !this.oauth.onCreateUser)
5103
- throw new Error("User does not exists");
5104
- if (!userExists && this.oauth.onCreateUser) {
5105
- 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
+ });
5106
4839
  }
5107
- const { token, refreshToken } = await this.generateJwtAndRefreshToken(
5108
- email,
5109
- {}
5110
- );
5111
- setCookie(ctx, this.cookies.sessionToken, token, {
5112
- secure: true,
5113
- maxAge: 60 * 60 * 24 * 30,
5114
- // 30 days
5115
- path: "/"
5116
- });
5117
- setCookie(ctx, this.cookies.refreshToken, refreshToken, {
5118
- secure: true,
5119
- maxAge: 60 * 60 * 24 * 30,
5120
- // 30 days
5121
- path: "/",
5122
- httpOnly: true
5123
- });
5124
- return {
5125
- redirect: {
5126
- destination: onSuccessDestination,
5127
- permanent: false
5128
- }
5129
- };
5130
- } catch (error) {
5131
- return {
5132
- props: {
5133
- error: JSON.stringify(error)
5134
- }
5135
- };
4840
+ } else {
4841
+ setSortedBy((prev) => [...prev, { prop, direction: "desc" }]);
5136
4842
  }
5137
- };
5138
- }
5139
- };
5140
-
5141
- // src/hooks/useGrid.ts
5142
- import { useCallback as useCallback6, useEffect as useEffect5, useMemo as useMemo3, useState as useState9 } from "react";
5143
-
5144
- // src/hooks/useFilter.ts
5145
- import moment2 from "moment";
5146
- import { useCallback as useCallback5, useState as useState8 } from "react";
5147
-
5148
- // src/components/utils/getObjectValue.ts
5149
- function getObjectValue(obj) {
5150
- return (prop) => {
5151
- try {
5152
- return prop.split(".").reduce((o, k) => o[k], obj);
5153
- } catch (_) {
5154
- return void 0;
5155
- }
5156
- };
5157
- }
5158
-
5159
- // src/hooks/useFilter.ts
5160
- function useFilter(props = { defaultFilters: [] }) {
5161
- const [selectedFilters, setSelectedFilters] = useState8(() => {
5162
- const { defaultFilters } = props;
5163
- return defaultFilters || [];
5164
- });
5165
- const filterBy = useCallback5((newFilter) => {
5166
- const propToCompare = newFilter?.id ? "id" : "prop";
5167
- function removeRepeatedFilters(filter) {
5168
- return filter[propToCompare] !== newFilter[propToCompare];
5169
- }
5170
- setSelectedFilters((filters) => [
5171
- ...filters.filter(removeRepeatedFilters),
5172
- newFilter
5173
- ]);
4843
+ },
4844
+ [toggleSortedDirection, sortedBy]
4845
+ );
4846
+ const set = useCallback4((data) => {
4847
+ setDefaultData(data);
5174
4848
  }, []);
5175
- const removeFilter = useCallback5(
5176
- (prop, isId) => {
5177
- const propToCompare = isId ? "id" : "prop";
5178
- setSelectedFilters(
5179
- selectedFilters.filter((filter) => filter[propToCompare] !== prop)
5180
- );
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;
5181
4861
  },
5182
- [selectedFilters]
4862
+ [sortedBy]
5183
4863
  );
5184
- function clearAllFilters() {
5185
- setSelectedFilters([]);
5186
- }
5187
- return {
5188
- filters: selectedFilters,
5189
- filterBy,
5190
- removeFilter,
5191
- createFilter,
5192
- clearAllFilters
4864
+ const onPageChange = (pageNumber) => {
4865
+ if (pageNumber < 0) return;
4866
+ if (pageNumber > totalNumberOfPages) return;
4867
+ setCurrentPage(pageNumber);
5193
4868
  };
5194
- }
5195
- function isDate(date) {
5196
- if (date instanceof Date) return true;
5197
- else if (String(date).endsWith("Z")) return true;
5198
- return false;
5199
- }
5200
- function compareFilter(item, filter) {
5201
- const itemValue = getObjectValue(item)(filter.prop);
5202
- switch (filter.compareType) {
5203
- case "equal":
5204
- return itemValue === filter.value;
5205
- case "notEqual":
5206
- return itemValue !== filter.value;
5207
- case "in":
5208
- return filter.value.includes(itemValue);
5209
- case "notIn":
5210
- return !filter.value.includes(itemValue);
5211
- case "valueIn":
5212
- return itemValue.includes(filter.value);
5213
- case "valueNotIn":
5214
- return !itemValue.includes(filter.value);
5215
- case "gte":
5216
- return isDate(itemValue) ? moment2(String(itemValue)).isSameOrAfter(filter.value) : itemValue >= filter.value;
5217
- case "gt":
5218
- return isDate(itemValue) ? moment2(String(itemValue)).isAfter(filter.value) : itemValue > filter.value;
5219
- case "lte":
5220
- return isDate(itemValue) ? moment2(String(itemValue)).isSameOrBefore(filter.value) : itemValue <= filter.value;
5221
- case "lt":
5222
- return isDate(itemValue) ? moment2(String(itemValue)).isBefore(filter.value) : itemValue < filter.value;
5223
- }
5224
- }
5225
- function createFilter(filters) {
5226
- function apply(item) {
5227
- const satisfiedFilters = filters.reduce((acc, filter) => {
5228
- if (compareFilter(item, filter)) acc += 1;
5229
- return acc;
5230
- }, 0);
5231
- return satisfiedFilters === filters.length;
5232
- }
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]);
5233
4903
  return {
5234
- apply
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
5235
4921
  };
5236
4922
  }
5237
-
5238
- // src/helpers/sortHelper.ts
5239
- function SortHelper(...fields) {
5240
- return (a, b) => {
5241
- for (const field of fields) {
5242
- let direction = 1;
5243
- let key = field;
5244
- if (field.startsWith("-")) {
5245
- direction = -1;
5246
- key = field.slice(1);
5247
- }
5248
- const aVal = a[key];
5249
- const bVal = b[key];
5250
- if (aVal > bVal) return direction;
5251
- if (aVal < bVal) return -direction;
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;
5252
4942
  }
5253
- return 0;
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;
5254
4971
  };
5255
4972
  }
5256
4973
 
5257
- // src/hooks/useGrid.ts
5258
- function useGrid({
4974
+ // src/hooks/useAsyncGrid.ts
4975
+ import { useCallback as useCallback5, useEffect as useEffect5, useState as useState9 } from "react";
4976
+ function useAsyncGrid({
5259
4977
  columns,
5260
- filters,
4978
+ filters = [],
5261
4979
  search,
5262
4980
  rowsPerPageOptions = [30, 60, 100],
4981
+ onRequest,
4982
+ axiosInstance,
4983
+ url,
5263
4984
  defaultData: externalDefaultData,
5264
4985
  defaultCurrentPage,
5265
4986
  defaultSortedBy
@@ -5268,426 +4989,709 @@ function useGrid({
5268
4989
  const [sortedBy, setSortedBy] = useState9(
5269
4990
  defaultSortedBy || []
5270
4991
  );
4992
+ const [totalNumberOfItems, setTotalNumberOfItems] = useState9(0);
4993
+ const [isLoading, setIsLoading] = useState9(false);
5271
4994
  const [currentPage, setCurrentPage] = useState9(defaultCurrentPage || 0);
5272
4995
  const [rowsPerPage, setRowsPerPage] = useState9(rowsPerPageOptions[0]);
5273
- const toggleSortedDirection = useCallback6(
4996
+ const totalNumberOfPages = Math.ceil(totalNumberOfItems / rowsPerPage) - 1;
4997
+ const toggleSortedDirection = useCallback5(
5274
4998
  (direction) => {
5275
4999
  if (direction === "asc") return "desc";
5276
5000
  return "asc";
5277
5001
  },
5278
5002
  []
5279
5003
  );
5280
- const clearSort = useCallback6(() => {
5281
- setSortedBy([]);
5282
- }, []);
5283
- const appendSort = useCallback6((prop, direction) => {
5004
+ const setSort = useCallback5((prop, direction) => {
5284
5005
  setSortedBy((prev) => [...prev, { prop, direction }]);
5285
5006
  }, []);
5286
- const setSort = useCallback6((prop, direction) => {
5287
- setSortedBy([{ prop, direction }]);
5288
- }, []);
5289
- const onSortBy = useCallback6(
5290
- (prop) => {
5007
+ const onSortBy = useCallback5(
5008
+ async (prop) => {
5291
5009
  if (!prop) return;
5010
+ let finalArr = [];
5292
5011
  const currentSorted = sortedBy.find((p) => p.prop === prop);
5293
5012
  if (currentSorted) {
5294
5013
  if (currentSorted.direction === "asc") {
5295
- setSortedBy((prev) => prev.filter((p) => p.prop !== prop));
5014
+ finalArr = sortedBy.filter((p) => p.prop !== prop);
5296
5015
  } else {
5297
- setSortedBy((prev) => {
5298
- const newArr = prev.map((p) => {
5299
- if (p.prop !== prop) return p;
5300
- return {
5301
- prop: p.prop,
5302
- direction: toggleSortedDirection(p.direction)
5303
- };
5304
- });
5305
- return [...newArr].slice(0);
5016
+ finalArr = sortedBy.map((p) => {
5017
+ if (p.prop !== prop) return p;
5018
+ return {
5019
+ prop: p.prop,
5020
+ direction: toggleSortedDirection(p.direction)
5021
+ };
5306
5022
  });
5307
5023
  }
5308
- } else {
5309
- setSortedBy((prev) => [...prev, { prop, direction: "desc" }]);
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
+ };
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
+ }
5310
5237
  }
5238
+ createAlert(formatErrorMessage(error), "error");
5311
5239
  },
5312
- [toggleSortedDirection, sortedBy]
5240
+ [formatErrorMessage, createAlert]
5313
5241
  );
5314
- const set = useCallback6((data) => {
5315
- setDefaultData(data);
5242
+ useEffect7(() => {
5243
+ return () => {
5244
+ sourceRef.current.abort();
5245
+ sourceRef.current = new AbortController();
5246
+ };
5316
5247
  }, []);
5317
- const sortData = useCallback6(
5318
- (data) => {
5319
- if (sortedBy.length > 0) {
5320
- const symbolDir = {
5321
- asc: "",
5322
- desc: "-"
5323
- };
5324
- const formattedKeys = sortedBy.map(
5325
- ({ prop, direction }) => `${symbolDir[direction]}${prop}`
5326
- );
5327
- return data.sort(SortHelper(...formattedKeys));
5328
- } else return data;
5329
- },
5330
- [sortedBy]
5331
- );
5332
- const onPageChange = (pageNumber) => {
5333
- if (pageNumber < 0) return;
5334
- if (pageNumber > totalNumberOfPages) return;
5335
- setCurrentPage(pageNumber);
5248
+ return {
5249
+ ...alertProps,
5250
+ ...loadingProps,
5251
+ onSubmitWrapper,
5252
+ onRequestWrapper
5336
5253
  };
5337
- const onChangeRowsPerPage = useCallback6(
5338
- (rows) => {
5339
- let totalNumberOfPages2 = Math.round(filteredData.length / rows) - 1;
5340
- totalNumberOfPages2 = totalNumberOfPages2 <= 0 ? 0 : 1;
5341
- if (currentPage > totalNumberOfPages2) setCurrentPage(totalNumberOfPages2);
5342
- setRowsPerPage(rows);
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
+ }
5343
5288
  },
5344
- [currentPage]
5289
+ [createAlert, api]
5345
5290
  );
5346
- const orderedData = useMemo3(() => {
5347
- if (sortedBy.length === 0) return defaultData;
5348
- const newData = defaultData.slice(0);
5349
- const sortedData = sortData(newData);
5350
- return sortedData;
5351
- }, [defaultData, sortData, sortedBy]);
5352
- const filteredData = useMemo3(() => {
5353
- let newData = orderedData.slice(0);
5354
- if (search && search.value !== "") {
5355
- const searchBy = createSearch(search);
5356
- newData = newData.filter(searchBy);
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
+ });
5357
5305
  }
5358
- if (!filters) return newData;
5359
- const newFilter = createFilter(filters);
5360
- return newData.filter(newFilter.apply);
5361
- }, [orderedData, search, filters]);
5362
- const paginatedData = useMemo3(() => {
5363
- const startPage = currentPage * rowsPerPage;
5364
- const endPage = startPage + rowsPerPage;
5365
- return filteredData.slice(startPage, endPage);
5366
- }, [currentPage, rowsPerPage, filteredData]);
5367
- const totalNumberOfPages = Math.ceil(filteredData.length / rowsPerPage) - 1;
5368
- useEffect5(() => {
5369
- if (externalDefaultData) setDefaultData(externalDefaultData);
5370
- }, [externalDefaultData]);
5371
- return {
5372
- data: paginatedData,
5373
- orderedData,
5374
- filteredData,
5375
- defaultData,
5376
- sortedBy,
5377
- columns,
5378
- currentPage,
5379
- totalNumberOfPages: totalNumberOfPages < 0 ? 0 : totalNumberOfPages,
5380
- rowsPerPageOptions,
5381
- rowsPerPage,
5382
- set,
5383
- onSortBy,
5384
- onPageChange,
5385
- setRowsPerPage: onChangeRowsPerPage,
5386
- appendSort,
5387
- setSort,
5388
- clearSort
5389
- };
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
+ );
5390
5319
  }
5391
- var isNumberOrString = (value) => ["number", "string"].includes(typeof value);
5392
- var concatenateKey = (key, prev) => {
5393
- if (!prev) return key;
5394
- return `${prev}.${key}`;
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
+ }
5395
5329
  };
5396
- function searchKeysForValue(row, accKey, compare) {
5397
- if (typeof row === "undefined") return false;
5398
- const rowKeys = Object.keys(row);
5399
- let match = false;
5400
- for (const key of rowKeys) {
5401
- if (match) break;
5402
- const objValue = row[key];
5403
- if (!objValue) continue;
5404
- const concatenatedKey = concatenateKey(key, accKey);
5405
- if (Array.isArray(objValue)) {
5406
- match = objValue.some(
5407
- (obj) => isNumberOrString(obj) ? compare(concatenatedKey, obj) : searchKeysForValue(obj, concatenatedKey, compare)
5408
- );
5409
- continue;
5410
- }
5411
- if (typeof objValue === "object") {
5412
- match = searchKeysForValue(objValue, concatenatedKey, compare);
5413
- continue;
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
+ }
5338
+ };
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) {
5354
+ }
5355
+ async onError(_req, _res, _error) {
5356
+ }
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
+ });
5414
5419
  }
5415
- match = compare(concatenatedKey, row[key]);
5416
5420
  }
5417
- return match;
5418
- }
5419
- var normalize = (str) => str.normalize("NFD").replace(/[\u0300-\u036f]/g, "");
5420
- function createSearch(options) {
5421
- const searchValue = options.caseSensitive ? options.value : String(options.value).toLowerCase();
5422
- function getValue2(value) {
5423
- if (options.caseSensitive) return String(value);
5424
- return String(value).toLowerCase();
5421
+ /** @deprecated Use {@Link ApiHelper.build} instead. */
5422
+ static create({ onFinally }) {
5423
+ return new _ApiHelper({
5424
+ onFinally
5425
+ });
5425
5426
  }
5426
- function compare(key, objValue) {
5427
- if (options.ignoredKeys) {
5428
- const isIgnoredKey = options.ignoredKeys.includes(key);
5429
- if (isIgnoredKey) return false;
5430
- }
5431
- const value = getValue2(objValue);
5432
- if (options.exact) return value === searchValue;
5433
- if (options.ignoreAccentMark) return normalize(value).includes(normalize(searchValue));
5434
- return value.includes(searchValue);
5427
+ };
5428
+ /** @deprecated Use {@link ApiHelper.parser} instead. */
5429
+ _ApiHelper.parserErrorWrapper = _ApiHelper.parse;
5430
+ var ApiHelper = _ApiHelper;
5431
+
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
5441
+ }) {
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;
5435
5446
  }
5436
- return (row) => {
5437
- const match = searchKeysForValue(row, "", compare);
5438
- return match;
5447
+ const jwtDecode = (token2) => {
5448
+ if (validate) {
5449
+ return jwt.verify(token2, process.env.JWT_SECRET);
5450
+ }
5451
+ return jwt.decode(token2);
5439
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
+ }
5440
5460
  }
5441
-
5442
- // src/hooks/useAsyncGrid.ts
5443
- import { useCallback as useCallback7, useEffect as useEffect6, useState as useState10 } from "react";
5444
- function useAsyncGrid({
5445
- columns,
5446
- filters = [],
5447
- search,
5448
- rowsPerPageOptions = [30, 60, 100],
5449
- onRequest,
5450
- axiosInstance,
5451
- url,
5452
- defaultData: externalDefaultData,
5453
- defaultCurrentPage,
5454
- defaultSortedBy
5455
- }) {
5456
- const [defaultData, setDefaultData] = useState10(externalDefaultData || []);
5457
- const [sortedBy, setSortedBy] = useState10(
5458
- defaultSortedBy || []
5459
- );
5460
- const [totalNumberOfItems, setTotalNumberOfItems] = useState10(0);
5461
- const [isLoading, setIsLoading] = useState10(false);
5462
- const [currentPage, setCurrentPage] = useState10(defaultCurrentPage || 0);
5463
- const [rowsPerPage, setRowsPerPage] = useState10(rowsPerPageOptions[0]);
5464
- const totalNumberOfPages = Math.ceil(totalNumberOfItems / rowsPerPage) - 1;
5465
- const toggleSortedDirection = useCallback7(
5466
- (direction) => {
5467
- if (direction === "asc") return "desc";
5468
- return "asc";
5469
- },
5470
- []
5471
- );
5472
- const setSort = useCallback7((prop, direction) => {
5473
- setSortedBy((prev) => [...prev, { prop, direction }]);
5474
- }, []);
5475
- const onSortBy = useCallback7(
5476
- async (prop) => {
5477
- if (!prop) return;
5478
- let finalArr = [];
5479
- const currentSorted = sortedBy.find((p) => p.prop === prop);
5480
- if (currentSorted) {
5481
- if (currentSorted.direction === "asc") {
5482
- finalArr = sortedBy.filter((p) => p.prop !== prop);
5483
- } else {
5484
- finalArr = sortedBy.map((p) => {
5485
- if (p.prop !== prop) return p;
5486
- return {
5487
- prop: p.prop,
5488
- direction: toggleSortedDirection(p.direction)
5489
- };
5490
- });
5491
- }
5492
- } else {
5493
- finalArr = [...sortedBy, { prop, direction: "desc" }];
5494
- }
5495
- await updateGridContent({
5496
- page: currentPage,
5497
- sortedBy: finalArr,
5498
- rowsPerPage
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
5499
5477
  });
5500
- },
5501
- [sortedBy, toggleSortedDirection, rowsPerPage, currentPage]
5502
- );
5503
- const set = useCallback7((data) => {
5504
- setDefaultData(data);
5505
- }, []);
5506
- const baseRequest = useCallback7(
5507
- async ({
5508
- page,
5509
- search: search2,
5510
- filters: filters2,
5511
- sortedBy: sortedBy2,
5512
- rowsPerPage: rowsPerPage2
5513
- }) => {
5514
- if (!axiosInstance) throw new Error("Axios instance not provided");
5515
- try {
5516
- const params = new URLSearchParams({
5517
- page: String(page),
5518
- rowsPerPage: String(rowsPerPage2),
5519
- searchText: search2?.value || "",
5520
- sort: sortedBy2.map(({ prop, direction }) => `${prop}:${direction}`).join(","),
5521
- filters: filters2.map(
5522
- (filter) => `${filter.prop}:${filter.compareType}:${filter.value}`
5523
- ).join(",")
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
5524
5521
  });
5525
- const pathWithParams = `${url}?${params.toString()}`;
5526
- const { data } = await axiosInstance.get(pathWithParams);
5527
- setTotalNumberOfItems(data.totalNumberOfItems);
5528
- return data.rows;
5529
- } catch (_) {
5530
- return [];
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 });
5531
5531
  }
5532
- },
5533
- [axiosInstance, url]
5534
- );
5535
- const updateGridContent = useCallback7(
5536
- async ({
5537
- page,
5538
- sortedBy: sortedBy2,
5539
- rowsPerPage: rowsPerPage2
5540
- }) => {
5541
- setIsLoading(true);
5542
- try {
5543
- const props = {
5544
- page,
5545
- rowsPerPage: rowsPerPage2,
5546
- sortedBy: sortedBy2,
5547
- search,
5548
- filters
5549
- };
5550
- const result = !onRequest ? await baseRequest(props) : await onRequest(props);
5551
- setSortedBy(sortedBy2);
5552
- setRowsPerPage(rowsPerPage2);
5553
- set(result);
5554
- setCurrentPage(page);
5555
- } finally {
5556
- setIsLoading(false);
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
5543
+ });
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"
5551
+ });
5557
5552
  }
5558
- },
5559
- [set, search, filters, onRequest, baseRequest]
5560
- );
5561
- const onPageChange = useCallback7(
5562
- (pageNumber) => {
5563
- if (pageNumber < 0) return;
5564
- if (pageNumber > totalNumberOfPages) return;
5565
- updateGridContent({ page: pageNumber, sortedBy, rowsPerPage });
5566
- },
5567
- [updateGridContent, totalNumberOfPages, sortedBy, rowsPerPage]
5568
- );
5569
- const onChangeRowsPerPage = useCallback7(
5570
- (rows) => {
5571
- let totalNumberOfPages2 = Math.round(totalNumberOfItems / rows) - 1;
5572
- totalNumberOfPages2 = totalNumberOfPages2 <= 0 ? 0 : 1;
5573
- if (currentPage > totalNumberOfPages2)
5574
- updateGridContent({
5575
- page: totalNumberOfPages2,
5576
- sortedBy,
5577
- 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"
5578
5561
  });
5579
- updateGridContent({
5580
- page: currentPage,
5581
- sortedBy,
5582
- rowsPerPage: rows
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
5583
5571
  });
5584
- },
5585
- [updateGridContent, totalNumberOfItems, sortedBy, currentPage]
5586
- );
5587
- const displayData = defaultData;
5588
- useEffect6(() => {
5589
- updateGridContent({ page: 0, sortedBy: [], rowsPerPage });
5590
- }, [updateGridContent, rowsPerPage]);
5591
- return {
5592
- data: displayData,
5593
- set,
5594
- onSortBy,
5595
- sortedBy,
5596
- defaultData,
5597
- columns,
5598
- currentPage,
5599
- totalNumberOfPages: totalNumberOfPages < 0 ? 0 : totalNumberOfPages,
5600
- onPageChange,
5601
- setRowsPerPage: onChangeRowsPerPage,
5602
- rowsPerPageOptions,
5603
- rowsPerPage,
5604
- setSort,
5605
- isLoading,
5606
- setIsLoading
5607
- };
5608
- }
5609
-
5610
- // src/hooks/useEvent.ts
5611
- import { useEffect as useEffect7 } from "react";
5612
- function useEvent(event, handler, passive = false) {
5613
- useEffect7(() => {
5614
- window.addEventListener(event, handler, passive);
5615
- return function cleanup() {
5616
- window.removeEventListener(event, handler);
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);
5599
+ }
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"
5607
+ };
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
5617
5625
  };
5618
- });
5619
- }
5620
-
5621
- // src/contexts/AuthContext.tsx
5622
- import React33, { useCallback as useCallback8 } from "react";
5623
- import {
5624
- createContext as createContext5,
5625
- useEffect as useEffect8,
5626
- useState as useState11
5627
- } from "react";
5628
- function createAuthContext() {
5629
- return createContext5({});
5630
- }
5631
- function CreateAuthProvider({
5632
- api,
5633
- children,
5634
- sessionTokenName,
5635
- Provider
5636
- }) {
5637
- const [user, setUser] = useState11();
5638
- const [status, setStatus] = useState11("unauthenticated");
5639
- const { createAlert } = useAlert();
5640
- const signIn = useCallback8(
5641
- async ({ email, password }) => {
5642
- 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
+ };
5643
5654
  try {
5644
- const response = await api.post("/auth/login", {
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(
5645
5663
  email,
5646
- password
5664
+ {}
5665
+ );
5666
+ setCookie(ctx, this.cookies.sessionToken, token, {
5667
+ secure: true,
5668
+ maxAge: 60 * 60 * 24 * 30,
5669
+ // 30 days
5670
+ path: "/"
5647
5671
  });
5648
- const { token } = response.data;
5649
- api.defaults.headers.common.Authorization = `Bearer ${token}`;
5650
- const { data } = await api.get("/auth/me");
5651
- setUser(data);
5652
- setStatus("autenticated");
5653
- return true;
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
+ };
5654
5685
  } catch (error) {
5655
- createAlert(error?.response?.data?.error, "error");
5656
- setStatus("unauthenticated");
5657
- throw error;
5658
- }
5659
- },
5660
- [createAlert, api]
5661
- );
5662
- const ClientSignOut = useCallback8(async () => {
5663
- await api.get("/auth/logout");
5664
- setUser(void 0);
5665
- }, [api]);
5666
- useEffect8(() => {
5667
- const token = parseCookies()[sessionTokenName];
5668
- if (token) {
5669
- setStatus("loading");
5670
- api.get("/auth/me").then((response) => {
5671
- setStatus("autenticated");
5672
- setUser(response.data);
5673
- }).catch(() => {
5674
- setStatus("unauthenticated");
5675
- });
5676
- }
5677
- }, [api, sessionTokenName]);
5678
- return /* @__PURE__ */ React33.createElement(
5679
- Provider,
5680
- {
5681
- value: {
5682
- user,
5683
- signOut: ClientSignOut,
5684
- signIn,
5685
- status
5686
+ return {
5687
+ props: {
5688
+ error: JSON.stringify(error)
5689
+ }
5690
+ };
5686
5691
  }
5687
- },
5688
- children
5689
- );
5690
- }
5692
+ };
5693
+ }
5694
+ };
5691
5695
  export {
5692
5696
  AlertContext,
5693
5697
  AlertProvider,