@campxdev/campx-web-utils 0.1.18 → 0.1.20

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/.prettierrc ADDED
@@ -0,0 +1,7 @@
1
+ {
2
+ "bracketSpacing": true,
3
+ "singleQuote": true,
4
+ "trailingComma": "all",
5
+ "useTabs": false,
6
+ "bracketSameLine": false
7
+ }
package/craco.config.js CHANGED
@@ -1,18 +1,14 @@
1
- const path = require("path");
2
- const { getLoader, loaderByName } = require("@craco/craco");
1
+ const path = require('path');
2
+ const { getLoader, loaderByName } = require('@craco/craco');
3
3
  const packages = [];
4
- packages.push(path.dirname(require.resolve("@campxdev/react-blueprint")));
4
+ packages.push(path.dirname(require.resolve('@campxdev/react-blueprint')));
5
+ packages.push(path.dirname(require.resolve('@campxdev/campx-web-utils')));
5
6
  module.exports = {
6
7
  webpack: {
7
8
  configure: (webpackConfig) => {
8
- const { isFound, match } = getLoader(
9
- webpackConfig,
10
- loaderByName("babel-loader")
11
- );
9
+ const { isFound, match } = getLoader(webpackConfig, loaderByName('babel-loader'));
12
10
  if (isFound) {
13
- const include = Array.isArray(match.loader.include)
14
- ? match.loader.include
15
- : [match.loader.include];
11
+ const include = Array.isArray(match.loader.include) ? match.loader.include : [match.loader.include];
16
12
  match.loader.include = include.concat(packages);
17
13
  }
18
14
 
package/export.ts ADDED
@@ -0,0 +1,3 @@
1
+ export * from './src/config/axios';
2
+ export * from './src/context/export';
3
+ export * from './src/hooks/export';
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@campxdev/campx-web-utils",
3
- "version": "0.1.18",
4
- "main": "./exports.ts",
3
+ "version": "0.1.20",
4
+ "main": "./export.ts",
5
5
  "private": false,
6
6
  "dependencies": {
7
- "@campxdev/react-blueprint": "^1.1.6",
7
+ "@campxdev/react-blueprint": "1.1.8",
8
8
  "@hookform/resolvers": "^3.9.0",
9
9
  "@mui/x-date-pickers": "^7.12.1",
10
10
  "@testing-library/jest-dom": "^5.14.1",
package/src/App.tsx CHANGED
@@ -1,7 +1,7 @@
1
- import { useRoutes } from "react-router-dom";
1
+ import { useRoutes } from 'react-router-dom';
2
2
 
3
- import { mainRoutes } from "./Pages/main";
4
- import { Providers } from "./context/export";
3
+ import { mainRoutes } from './Pages/main';
4
+ import { Providers } from './context/export';
5
5
 
6
6
  export default function App() {
7
7
  return (
@@ -1,37 +1,26 @@
1
- import { useQuery } from "react-query";
2
- import { axios } from "./config/axios";
3
-
4
- const fetchClubRequests = () => {
5
- return axios
6
- .get(`/hrms/departments`, {
7
- headers: {
8
- "x-tenant-id": "aupulse",
9
- "X-Institution-Code": "aupulse",
10
- campx_session_key: "66a36c752e28b1200876b034",
11
- },
12
- })
13
- .then((res) => res.data);
14
- };
1
+ import { Button } from '@campxdev/react-blueprint';
2
+ import useConfirm from './hooks/useConfirm';
15
3
 
16
4
  function AppContent() {
17
- const {
18
- data: requests,
19
- isLoading,
20
- error,
21
- refetch,
22
- } = useQuery("club-requests", () => fetchClubRequests());
5
+ const isConfirm = useConfirm();
23
6
 
24
- if (isLoading) {
25
- return <div>Loading...</div>;
26
- }
7
+ const handleConfirm = async () => {
8
+ const confirm = await isConfirm({
9
+ type: 'delete',
10
+ title: 'Are you sure?',
11
+ message: 'Please confirm before submission to action description',
12
+ });
27
13
 
28
- // if (error) {
29
- // // No need to handle the error locally, it will be caught by ErrorBoundary
30
- // console.error("Error fetching club requests:", error);
31
- // throw error; // Re-throw the error to be caught by the ErrorBoundary
32
- // }
14
+ // If user cancel the action
15
+ if (!confirm) {
16
+ console.log('User cancelled the action');
17
+ return;
18
+ }
19
+ // If user confirm the action
20
+ console.log('User confirmed the action');
21
+ };
33
22
 
34
- return <></>;
23
+ return <Button onClick={handleConfirm}>Confirm</Button>;
35
24
  }
36
25
 
37
26
  export default AppContent;
@@ -1,4 +1,4 @@
1
- import { Outlet } from "react-router-dom";
1
+ import { Outlet } from 'react-router-dom';
2
2
 
3
3
  const AppLayout = () => {
4
4
  return (
@@ -1,18 +1,18 @@
1
- import { Navigate } from "react-router-dom";
2
- import AppContent from "../AppContent";
3
- import AppLayout from "../Layout/AppLayout";
1
+ import { Navigate } from 'react-router-dom';
2
+ import AppContent from '../AppContent';
3
+ import AppLayout from '../Layout/AppLayout';
4
4
 
5
5
  export const mainRoutes = [
6
6
  {
7
- path: "/",
7
+ path: '/',
8
8
  element: <AppLayout />,
9
9
  children: [
10
10
  {
11
11
  index: true,
12
- element: <Navigate to={"app-content"} />,
12
+ element: <Navigate to={'app-content'} />,
13
13
  },
14
14
  {
15
- path: "app-content",
15
+ path: 'app-content',
16
16
  element: <AppContent />,
17
17
  },
18
18
  ],
@@ -1,37 +1,46 @@
1
- import Axios, { InternalAxiosRequestConfig } from "axios";
2
- import Cookies from "js-cookie";
3
- import { SnackbarStore } from "../context/SnackbarProvider";
1
+ import Axios, { InternalAxiosRequestConfig } from 'axios';
2
+ import Cookies from 'js-cookie';
3
+ import { ApplicationStore } from '../context/application-store';
4
4
 
5
- const isDevelopment = process.env.NODE_ENV == "development";
5
+ const isDevelopment = process.env.NODE_ENV == 'development';
6
6
 
7
7
  const tenantCode =
8
- window.location.hostname === "localhost"
9
- ? Cookies.get("campx_tenant")
10
- : window.location.hostname.split(".")[0];
11
- const institutionCode = window.location.pathname.split("/")[1];
8
+ window.location.hostname === 'localhost'
9
+ ? Cookies.get('campx_tenant')
10
+ : window.location.hostname.split('.')[0];
11
+ const institutionCode = window.location.pathname.split('/')[1];
12
+
13
+ export const formatParams = (params: any) => {
14
+ return Object.fromEntries(
15
+ Object.entries(params ?? {})?.map((i) => [
16
+ i[0],
17
+ i[1] === '__empty__' ? '' : i[1],
18
+ ]),
19
+ );
20
+ };
12
21
 
13
22
  export const axios = Axios.create({
14
23
  baseURL: process.env.REACT_APP_API_HOST,
15
24
  withCredentials: true,
16
25
  headers: {
17
- "x-tenant-id": tenantCode,
18
- "x-institution-code": institutionCode,
26
+ 'x-tenant-id': tenantCode,
27
+ 'x-institution-code': institutionCode,
19
28
  },
20
29
  });
21
30
 
22
31
  axios.interceptors.request.use(
23
32
  function (config: InternalAxiosRequestConfig) {
24
- const params = config?.params;
33
+ const params = formatParams(config?.params);
25
34
 
26
- const sessionKey = Cookies.get("campx_session_key");
27
- const openPaymentsKey = Cookies.get("campx_open_payments_key");
35
+ const sessionKey = Cookies.get('campx_session_key');
36
+ const openPaymentsKey = Cookies.get('campx_open_payments_key');
28
37
 
29
38
  if (isDevelopment && sessionKey) {
30
- config.headers.set("campx_session_key", sessionKey);
39
+ config.headers.set('campx_session_key', sessionKey);
31
40
  }
32
41
 
33
42
  if (openPaymentsKey) {
34
- config.headers.set("campx_open_payments_key", openPaymentsKey);
43
+ config.headers.set('campx_open_payments_key', openPaymentsKey);
35
44
  }
36
45
 
37
46
  return {
@@ -41,7 +50,7 @@ axios.interceptors.request.use(
41
50
  },
42
51
  function (error) {
43
52
  return Promise.reject(error);
44
- }
53
+ },
45
54
  );
46
55
 
47
56
  axios.interceptors.response.use(
@@ -49,13 +58,13 @@ axios.interceptors.response.use(
49
58
  console.log(response);
50
59
  if (
51
60
  response.config.method &&
52
- ["put", "post", "delete", "patch"].includes(response.config.method) &&
61
+ ['put', 'post', 'delete', 'patch'].includes(response.config.method) &&
53
62
  [200, 201, 202].includes(response.status)
54
63
  ) {
55
- SnackbarStore.update((s) => {
56
- s.open = true;
57
- s.message = response.data.message;
58
- s.severity = "success";
64
+ ApplicationStore.update((s) => {
65
+ s.snackbar.open = true;
66
+ s.snackbar.message = response.data.message;
67
+ s.snackbar.severity = 'success';
59
68
  });
60
69
  }
61
70
 
@@ -63,24 +72,24 @@ axios.interceptors.response.use(
63
72
  },
64
73
  function (err) {
65
74
  if ([400, 422].includes(err.response.status)) {
66
- SnackbarStore.update((s) => {
67
- s.open = true;
68
- s.message = err.response.data.message || "Bad Request";
69
- s.severity = "error";
75
+ ApplicationStore.update((s) => {
76
+ s.snackbar.open = true;
77
+ s.snackbar.message = err.response.data.message || 'Bad Request';
78
+ s.snackbar.severity = 'error';
70
79
  });
71
80
  }
72
81
  if (
73
82
  err.response.config.method &&
74
- ["put", "post", "delete", "patch"].includes(err.response.config.method) &&
83
+ ['put', 'post', 'delete', 'patch'].includes(err.response.config.method) &&
75
84
  [404].includes(err.response.status)
76
85
  ) {
77
- SnackbarStore.update((s) => {
78
- s.open = true;
79
- s.message = err.response.data.message;
80
- s.severity = "error";
86
+ ApplicationStore.update((s) => {
87
+ s.snackbar.open = true;
88
+ s.snackbar.message = err.response.data.message;
89
+ s.snackbar.severity = 'error';
81
90
  });
82
91
  }
83
92
 
84
93
  return Promise.reject(err);
85
- }
94
+ },
86
95
  );
@@ -0,0 +1,70 @@
1
+ import { ConfirmDialog, ConfirmDialogType } from '@campxdev/react-blueprint';
2
+ import { createContext, ReactNode } from 'react';
3
+ import { ApplicationStore } from './application-store';
4
+
5
+ interface ConfirmStateProps {
6
+ showConfirmDialog: (
7
+ title: string,
8
+ message: string,
9
+ onConfirm: () => void,
10
+ onCancel: () => void,
11
+ type?: ConfirmDialogType,
12
+ ) => void;
13
+ }
14
+
15
+ const ConfirmContext = createContext<ConfirmStateProps>({
16
+ showConfirmDialog: () => {},
17
+ });
18
+
19
+ export const ConfirmDialogProvider = ({
20
+ children,
21
+ }: {
22
+ children: ReactNode;
23
+ }) => {
24
+ const confirmDialog = ApplicationStore.useState((s) => s.confirmDialog);
25
+
26
+ const showConfirmDialog = (
27
+ title: string,
28
+ message: string,
29
+ onConfirm: () => void,
30
+ onCancel: () => void,
31
+ type: ConfirmDialogType = 'confirm',
32
+ ) => {
33
+ ApplicationStore.update((s) => {
34
+ s.confirmDialog = {
35
+ isOpen: true,
36
+ title,
37
+ message,
38
+ onConfirm,
39
+ onCancel,
40
+ type,
41
+ };
42
+ });
43
+ };
44
+
45
+ const handleCloseDialog = () => {
46
+ ApplicationStore.update((s) => {
47
+ s.confirmDialog.isOpen = false;
48
+ });
49
+ };
50
+
51
+ return (
52
+ <ConfirmContext.Provider value={{ showConfirmDialog }}>
53
+ {children}
54
+ <ConfirmDialog
55
+ isOpen={confirmDialog.isOpen}
56
+ title={confirmDialog.title}
57
+ message={confirmDialog.message}
58
+ type={confirmDialog.type}
59
+ onConfirm={() => {
60
+ confirmDialog.onConfirm();
61
+ handleCloseDialog();
62
+ }}
63
+ onCancel={() => {
64
+ confirmDialog.onCancel();
65
+ handleCloseDialog();
66
+ }}
67
+ />
68
+ </ConfirmContext.Provider>
69
+ );
70
+ };
@@ -5,34 +5,34 @@ import {
5
5
  NoInterneConnection,
6
6
  PageNotFound,
7
7
  UnAuthorized,
8
- } from "@campxdev/react-blueprint";
9
- import { Alert, Box, styled } from "@mui/material";
10
- import Cookies from "js-cookie";
11
- import { ReactNode, useState } from "react";
12
- import { ErrorBoundary as ReactErrorBoundary } from "react-error-boundary";
13
- import { QueryErrorResetBoundary } from "react-query";
14
- import { useLocation, useNavigate } from "react-router-dom";
15
- import { Login } from "./Login";
8
+ } from '@campxdev/react-blueprint';
9
+ import { Alert, Box, styled } from '@mui/material';
10
+ import Cookies from 'js-cookie';
11
+ import { ReactNode, useState } from 'react';
12
+ import { ErrorBoundary as ReactErrorBoundary } from 'react-error-boundary';
13
+ import { QueryErrorResetBoundary } from 'react-query';
14
+ import { useLocation, useNavigate } from 'react-router-dom';
15
+ import { Login } from './Login';
16
16
 
17
17
  export type ErrorBoundaryProps = {
18
18
  children: ReactNode;
19
19
  };
20
20
 
21
21
  const StyledAlert = styled(Alert)(({ theme }) => ({
22
- height: "60px",
22
+ height: '60px',
23
23
  border: `1px solid ${theme.palette.error.main}`,
24
- display: "flex",
25
- alignItems: "center",
26
- "& .MuiAlert-message": {
24
+ display: 'flex',
25
+ alignItems: 'center',
26
+ '& .MuiAlert-message': {
27
27
  padding: 0,
28
28
  },
29
- "& .MuiTypography-root": {
29
+ '& .MuiTypography-root': {
30
30
  margin: 0,
31
31
  },
32
- position: "relative",
33
- "& .retryBtn": {
34
- color: "#661B2A",
35
- position: "absolute",
32
+ position: 'relative',
33
+ '& .retryBtn': {
34
+ color: '#661B2A',
35
+ position: 'absolute',
36
36
  right: 8,
37
37
  top: 8,
38
38
  },
@@ -68,12 +68,12 @@ const ErrorFallback = ({ error, resetErrorBoundary }: any) => {
68
68
  }
69
69
  }
70
70
 
71
- if (error?.code === "ERR_NETWORK") {
71
+ if (error?.code === 'ERR_NETWORK') {
72
72
  return <NoInterneConnection resetBoundary={resetErrorBoundary} />;
73
73
  }
74
74
 
75
75
  return (
76
- <Box sx={{ marginTop: "16px", padding: "20px" }}>
76
+ <Box sx={{ marginTop: '16px', padding: '20px' }}>
77
77
  <StyledAlert severity="error">
78
78
  {error?.response?.data?.message ?? error?.message}
79
79
  <Button
@@ -94,14 +94,14 @@ const UnAuth = () => {
94
94
  const navigate = useNavigate();
95
95
  const [isModalOpen, setModalOpen] = useState(false);
96
96
 
97
- const sessionCookie = Cookies.get("campx_session_key");
97
+ const sessionCookie = Cookies.get('campx_session_key');
98
98
 
99
99
  const handleLoginClick = () => {
100
- if (window.location.hostname == "localhost") {
100
+ if (window.location.hostname === 'localhost') {
101
101
  setModalOpen(true);
102
102
  } else {
103
103
  if (!sessionCookie) {
104
- navigate("/auth/login");
104
+ navigate('/auth/login');
105
105
  }
106
106
  }
107
107
  };
@@ -112,7 +112,7 @@ const UnAuth = () => {
112
112
  <>
113
113
  <Button
114
114
  sx={{
115
- marginTop: "20px",
115
+ marginTop: '20px',
116
116
  }}
117
117
  variant="contained"
118
118
  onClick={handleLoginClick}
@@ -1,14 +1,14 @@
1
- import { axios } from "@campxdev/campx-web-utils";
2
- import { Button, Icons, TextField } from "@campxdev/react-blueprint";
3
- import { yupResolver } from "@hookform/resolvers/yup";
4
- import { Box, Stack } from "@mui/material";
5
- import DeviceDetector from "device-detector-js";
6
- import Cookies from "js-cookie";
7
- import { useEffect, useState } from "react";
8
- import { Controller, useForm } from "react-hook-form";
9
- import { useMutation } from "react-query";
1
+ import { axios } from '@campxdev/campx-web-utils';
2
+ import { Button, Icons, TextField } from '@campxdev/react-blueprint';
3
+ import { yupResolver } from '@hookform/resolvers/yup';
4
+ import { Box, Stack } from '@mui/material';
5
+ import DeviceDetector from 'device-detector-js';
6
+ import Cookies from 'js-cookie';
7
+ import { useEffect, useState } from 'react';
8
+ import { Controller, useForm } from 'react-hook-form';
9
+ import { useMutation } from 'react-query';
10
10
 
11
- import * as Yup from "yup";
11
+ import * as Yup from 'yup';
12
12
 
13
13
  type DeviceInformation = {
14
14
  deviceType: string;
@@ -33,16 +33,16 @@ type LoginDetails = {
33
33
  const performLogin = async (body: any) => {
34
34
  if (!body.latitude || !body.longitude) {
35
35
  const response = await fetch(
36
- "https://www.googleapis.com/geolocation/v1/geolocate?key=AIzaSyB2YCpo1yi107RYj1LdZu2DCcpcO93reFY",
36
+ 'https://www.googleapis.com/geolocation/v1/geolocate?key=AIzaSyB2YCpo1yi107RYj1LdZu2DCcpcO93reFY',
37
37
  {
38
- method: "POST",
38
+ method: 'POST',
39
39
  headers: {
40
- "Content-Type": "application/json",
40
+ 'Content-Type': 'application/json',
41
41
  },
42
42
  body: JSON.stringify({
43
- considerIp: "true",
43
+ considerIp: 'true',
44
44
  }),
45
- }
45
+ },
46
46
  );
47
47
  const data = await response.json();
48
48
  body.latitude = data.location.lat;
@@ -52,20 +52,20 @@ const performLogin = async (body: any) => {
52
52
  };
53
53
 
54
54
  const validationSchema = Yup.object().shape({
55
- username: Yup.string().required("Username is required"),
56
- password: Yup.string().required("Password is required"),
55
+ username: Yup.string().required('Username is required'),
56
+ password: Yup.string().required('Password is required'),
57
57
  });
58
58
 
59
59
  export const Login = ({ close }: { close: () => void }) => {
60
60
  const [deviceState, setDeviceState] = useState<DeviceState>({
61
61
  deviceInformation: {
62
- deviceType: "browser",
63
- clientName: "unknown",
64
- os: "unknown",
65
- osVersion: "unknown",
62
+ deviceType: 'browser',
63
+ clientName: 'unknown',
64
+ os: 'unknown',
65
+ osVersion: 'unknown',
66
66
  latitude: null,
67
67
  longitude: null,
68
- tokenType: "WEB",
68
+ tokenType: 'WEB',
69
69
  },
70
70
  isLocationAllowed: true,
71
71
  });
@@ -82,9 +82,9 @@ export const Login = ({ close }: { close: () => void }) => {
82
82
  }));
83
83
  });
84
84
  navigator.permissions
85
- .query({ name: "geolocation" })
85
+ .query({ name: 'geolocation' })
86
86
  .then((permissionStatus) => {
87
- if (permissionStatus.state === "denied") {
87
+ if (permissionStatus.state === 'denied') {
88
88
  setDeviceState((s) => ({
89
89
  ...s,
90
90
  isLocationAllowed: false,
@@ -109,17 +109,19 @@ export const Login = ({ close }: { close: () => void }) => {
109
109
  handleSubmit,
110
110
  control,
111
111
  formState: { errors },
112
- } = useForm<LoginDetails>({ resolver: yupResolver(validationSchema) });
112
+ } = useForm<LoginDetails>({
113
+ resolver: yupResolver<LoginDetails>(validationSchema),
114
+ });
113
115
 
114
116
  const { mutate, isLoading } = useMutation(performLogin, {
115
117
  onSuccess(data) {
116
118
  if (data.loginSuccessful) {
117
- Cookies.remove("campx_session_key");
118
- Cookies.remove("campx_tenant");
119
- Cookies.remove("campx_institution");
120
- Cookies.set("campx_session_key", data?.token);
121
- Cookies.set("campx_tenant", data?.subDomain);
122
- Cookies.set("campx_institution", data?.institutionCode);
119
+ Cookies.remove('campx_session_key');
120
+ Cookies.remove('campx_tenant');
121
+ Cookies.remove('campx_institution');
122
+ Cookies.set('campx_session_key', data?.token);
123
+ Cookies.set('campx_tenant', data?.subDomain);
124
+ Cookies.set('campx_institution', data?.institutionCode);
123
125
  close();
124
126
  window.location.reload();
125
127
  }
@@ -145,10 +147,10 @@ export const Login = ({ close }: { close: () => void }) => {
145
147
  size="medium"
146
148
  name="username"
147
149
  sx={{
148
- width: "400px",
150
+ width: '400px',
149
151
  }}
150
152
  placeholder="Enter Username or Email"
151
- containerProps={{ my: "0" }}
153
+ containerProps={{ my: '0' }}
152
154
  onChange={field.onChange}
153
155
  label="Username or Email"
154
156
  error={!!errors.username}
@@ -166,11 +168,11 @@ export const Login = ({ close }: { close: () => void }) => {
166
168
  size="medium"
167
169
  name="password"
168
170
  sx={{
169
- width: "400px",
171
+ width: '400px',
170
172
  }}
171
173
  placeholder="Enter password"
172
174
  onChange={field.onChange}
173
- containerProps={{ my: "0" }}
175
+ containerProps={{ my: '0' }}
174
176
  label="Password"
175
177
  type="password"
176
178
  error={!!errors.password}
@@ -185,7 +187,7 @@ export const Login = ({ close }: { close: () => void }) => {
185
187
  color="primary"
186
188
  variant="contained"
187
189
  sx={{
188
- width: "400px",
190
+ width: '400px',
189
191
  }}
190
192
  onClick={handleSubmit(onSubmit)}
191
193
  disabled={isLoading}
@@ -1,12 +1,11 @@
1
- import { lightTheme, MuiThemeProvider } from "@campxdev/react-blueprint";
2
- import { LocalizationProvider } from "@mui/x-date-pickers";
3
- import { AdapterDateFns } from "@mui/x-date-pickers/AdapterDateFnsV3";
4
- import Cookies from "js-cookie";
5
- import { ReactNode, useEffect } from "react";
6
- import { QueryClient, QueryClientProvider } from "react-query";
7
- import { BrowserRouter } from "react-router-dom";
8
- import { ErrorBoundary } from "./export";
9
- import { SnackbarProvider } from "./SnackbarProvider";
1
+ import { lightTheme, MuiThemeProvider } from '@campxdev/react-blueprint';
2
+ import Cookies from 'js-cookie';
3
+ import { ReactNode, useEffect } from 'react';
4
+ import { QueryClient, QueryClientProvider } from 'react-query';
5
+ import { BrowserRouter } from 'react-router-dom';
6
+ import { ConfirmDialogProvider } from './ConfirmDialogProvider';
7
+ import { ErrorBoundary } from './export';
8
+ import { SnackbarProvider } from './SnackbarProvider';
10
9
 
11
10
  export const Providers = ({
12
11
  children,
@@ -28,28 +27,28 @@ export const Providers = ({
28
27
  });
29
28
 
30
29
  var tenantCode =
31
- window.location.hostname === "localhost"
32
- ? Cookies.get("campx_tenant")
33
- : window.location.hostname.split(".")[0];
30
+ window.location.hostname === 'localhost'
31
+ ? Cookies.get('campx_tenant')
32
+ : window.location.hostname.split('.')[0];
34
33
  var institutionCode =
35
- window.location.pathname.split("/")[1] !== ""
36
- ? window.location.pathname.split("/")[1]
37
- : Cookies.get("campx_institution");
38
- var baseName = tenantCode && institutionCode ? `/${institutionCode}` : "/";
34
+ window.location.pathname.split('/')[1] !== ''
35
+ ? window.location.pathname.split('/')[1]
36
+ : Cookies.get('campx_institution');
37
+ var baseName = tenantCode && institutionCode ? `/${institutionCode}` : '/';
39
38
  useEffect(() => {
40
- if (window.location.pathname === "/" && institutionCode && tenantCode) {
39
+ if (window.location.pathname === '/' && institutionCode && tenantCode) {
41
40
  window.location.replace(window.location.origin + `/${institutionCode}`);
42
41
  }
43
- }, []);
42
+ }, [institutionCode, tenantCode]);
44
43
 
45
44
  return (
46
45
  <BrowserRouter basename={basename ?? baseName}>
47
46
  <QueryClientProvider client={queryClient}>
48
47
  <MuiThemeProvider theme={theme}>
49
48
  <SnackbarProvider>
50
- <LocalizationProvider dateAdapter={AdapterDateFns}>
49
+ <ConfirmDialogProvider>
51
50
  <ErrorBoundary>{children}</ErrorBoundary>
52
- </LocalizationProvider>
51
+ </ConfirmDialogProvider>
53
52
  </SnackbarProvider>
54
53
  </MuiThemeProvider>
55
54
  </QueryClientProvider>
@@ -1,31 +1,26 @@
1
- import { Severity, Snackbar } from "@campxdev/react-blueprint";
2
- import { Store } from "pullstate";
3
- import { createContext, ReactNode } from "react";
1
+ import { Severity, Snackbar } from '@campxdev/react-blueprint';
2
+ import { createContext, ReactNode } from 'react';
3
+ import { ApplicationStore } from './application-store';
4
4
 
5
5
  interface SnackbarContextProps {
6
6
  showSnackbar: (message: string, severity?: Severity) => void;
7
7
  }
8
8
 
9
9
  const SnackbarContext = createContext<SnackbarContextProps | undefined>(
10
- undefined
10
+ undefined,
11
11
  );
12
12
 
13
13
  interface SnackbarProviderProps {
14
14
  children: ReactNode;
15
15
  }
16
- export const SnackbarStore = new Store({
17
- open: false,
18
- message: "",
19
- severity: "success" as Severity,
20
- });
21
16
 
22
17
  export const SnackbarProvider = ({ children }: SnackbarProviderProps) => {
23
- const snackbar = SnackbarStore.useState((s) => s);
24
- const showSnackbar = (message: string, severity: Severity = "info") => {
25
- SnackbarStore.update((s) => {
26
- s.open = true;
27
- s.message = message;
28
- s.severity = severity;
18
+ const snackbar = ApplicationStore.useState((s) => s.snackbar);
19
+ const showSnackbar = (message: string, severity: Severity = 'info') => {
20
+ ApplicationStore.update((s) => {
21
+ s.snackbar.open = true;
22
+ s.snackbar.message = message;
23
+ s.snackbar.severity = severity;
29
24
  });
30
25
  };
31
26
  return (
@@ -37,8 +32,8 @@ export const SnackbarProvider = ({ children }: SnackbarProviderProps) => {
37
32
  severity={snackbar.severity}
38
33
  autoHideDuration={1500}
39
34
  onClose={() => {
40
- SnackbarStore.update((s) => {
41
- s.open = false;
35
+ ApplicationStore.update((s) => {
36
+ s.snackbar.open = false;
42
37
  });
43
38
  }}
44
39
  />
@@ -1,12 +1,39 @@
1
- import { Store } from "pullstate";
1
+ import { ConfirmDialogType, Severity } from '@campxdev/react-blueprint';
2
+ import { Store } from 'pullstate';
2
3
 
3
4
  export type ApplicationStoreType = {
4
5
  isLoginDialogOpen: boolean;
6
+ snackbar: {
7
+ open: boolean;
8
+ message: string;
9
+ severity: Severity;
10
+ };
11
+ confirmDialog: {
12
+ isOpen: boolean;
13
+ title: string;
14
+ message: string;
15
+ onConfirm: () => void;
16
+ onCancel: () => void;
17
+ type: ConfirmDialogType;
18
+ };
5
19
  };
6
20
 
7
21
  export const initialApplicationState: ApplicationStoreType = {
8
22
  isLoginDialogOpen: false,
23
+ snackbar: {
24
+ open: false,
25
+ message: '',
26
+ severity: 'success',
27
+ },
28
+ confirmDialog: {
29
+ isOpen: false,
30
+ title: '',
31
+ message: '',
32
+ onConfirm: () => {},
33
+ onCancel: () => {},
34
+ type: 'confirm',
35
+ },
9
36
  };
10
37
  export const ApplicationStore = new Store<ApplicationStoreType>(
11
- initialApplicationState
38
+ initialApplicationState,
12
39
  );
@@ -1,4 +1,4 @@
1
- export * from "./application-store";
2
- export * from "./ErrorBoundary/ErrorBoundary";
3
- export * from "./Providers";
4
- export * from "./SnackbarProvider";
1
+ export * from './application-store';
2
+ export * from './ErrorBoundary/ErrorBoundary';
3
+ export * from './Providers';
4
+ export * from './SnackbarProvider';
@@ -0,0 +1 @@
1
+ export * from './useConfirm';
@@ -0,0 +1,51 @@
1
+ import { ConfirmDialogType } from '@campxdev/react-blueprint';
2
+ import { ApplicationStore } from '../context/application-store';
3
+
4
+ const defaultConfirmDialogState = {
5
+ isOpen: false,
6
+ title: '',
7
+ message: '',
8
+ type: 'confirm' as ConfirmDialogType,
9
+ onConfirm: () => {},
10
+ onCancel: () => {},
11
+ };
12
+
13
+ const useConfirm = () => {
14
+ const isConfirmed = ({
15
+ title,
16
+ message,
17
+ type = 'confirm',
18
+ }: {
19
+ title: string;
20
+ message: string;
21
+ type?: ConfirmDialogType;
22
+ }): Promise<boolean> =>
23
+ new Promise((resolve) => {
24
+ ApplicationStore.update((s) => {
25
+ s.confirmDialog = {
26
+ isOpen: true,
27
+ title,
28
+ message,
29
+ type,
30
+ onConfirm: () => {
31
+ resolve(true);
32
+ resetDialog();
33
+ },
34
+ onCancel: () => {
35
+ resolve(false);
36
+ resetDialog();
37
+ },
38
+ };
39
+ });
40
+ });
41
+
42
+ const resetDialog = () => {
43
+ ApplicationStore.update((s) => {
44
+ s.confirmDialog = defaultConfirmDialogState;
45
+ });
46
+ };
47
+
48
+ return isConfirmed;
49
+ };
50
+
51
+ export default useConfirm;
package/src/index.tsx CHANGED
@@ -5,12 +5,12 @@ import App from './App';
5
5
  import reportWebVitals from './reportWebVitals';
6
6
 
7
7
  const root = ReactDOM.createRoot(
8
- document.getElementById('root') as HTMLElement
8
+ document.getElementById('root') as HTMLElement,
9
9
  );
10
10
  root.render(
11
11
  <React.StrictMode>
12
12
  <App />
13
- </React.StrictMode>
13
+ </React.StrictMode>,
14
14
  );
15
15
 
16
16
  // If you want to start measuring performance in your app, pass a function
@@ -0,0 +1,23 @@
1
+ export const getBreadcrumbsCharacter = () => {
2
+ const unicodeChar = String.fromCharCode(0x21e5);
3
+ const testElement = document.createElement('span');
4
+ testElement.innerHTML = unicodeChar;
5
+ document.body.appendChild(testElement);
6
+ const isRendered = testElement.offsetWidth > 0;
7
+ document.body.removeChild(testElement);
8
+
9
+ console.log(isRendered);
10
+
11
+ const fallbackChar = '~~';
12
+ const s = isRendered ? unicodeChar : fallbackChar;
13
+
14
+ return s;
15
+ };
16
+
17
+ interface GetUrlSegment {
18
+ name: string;
19
+ id: string | number;
20
+ }
21
+ export const getUrlSegment = ({ name, id }: GetUrlSegment) => {
22
+ return `${name}${getBreadcrumbsCharacter()}${id}`;
23
+ };
@@ -0,0 +1 @@
1
+ export * from './breadcrumbs';
package/tsconfig.json CHANGED
@@ -1,11 +1,7 @@
1
1
  {
2
2
  "compilerOptions": {
3
3
  "target": "es5",
4
- "lib": [
5
- "dom",
6
- "dom.iterable",
7
- "esnext"
8
- ],
4
+ "lib": ["dom", "dom.iterable", "esnext"],
9
5
  "allowJs": true,
10
6
  "skipLibCheck": true,
11
7
  "esModuleInterop": true,
@@ -18,13 +14,9 @@
18
14
  "resolveJsonModule": true,
19
15
  "isolatedModules": true,
20
16
  "noEmit": true,
21
- "jsx": "react-jsx"
17
+ "jsx": "react-jsx",
18
+ "types": ["node"]
22
19
  },
23
- "include": [
24
- "src",
25
- "./types"
26
- ],
27
- "exclude": [
28
- "node_modules"
29
- ]
20
+ "include": ["src", "./types"],
21
+ "exclude": ["node_modules", ".yalc"]
30
22
  }
package/exports.ts DELETED
@@ -1,2 +0,0 @@
1
- export * from "./src/config/axios";
2
- export * from "./src/context/export";