@campxdev/campx-web-utils 0.1.9 → 0.1.11

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/craco.config.js CHANGED
@@ -1,7 +1,4 @@
1
- const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
2
-
3
1
  const path = require("path");
4
- const deps = require("./package.json").dependencies;
5
2
  const { getLoader, loaderByName } = require("@craco/craco");
6
3
  const packages = [];
7
4
  packages.push(path.dirname(require.resolve("@campxdev/react-blueprint")));
package/exports.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  export * from "./src/config/axios";
2
+ export * from "./src/context/SnackbarProvider";
2
3
  export * from "./src/ErrorBoundary/export";
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "@campxdev/campx-web-utils",
3
- "version": "0.1.9",
3
+ "version": "0.1.11",
4
4
  "main": "./exports.ts",
5
5
  "private": false,
6
6
  "dependencies": {
7
- "@campxdev/react-blueprint": "^1.0.14",
7
+ "@campxdev/react-blueprint": "^1.1.2",
8
+ "@hookform/resolvers": "^3.9.0",
8
9
  "@mui/x-date-pickers": "^7.11.0",
9
10
  "@testing-library/jest-dom": "^5.14.1",
10
11
  "@testing-library/react": "^13.0.0",
@@ -15,14 +16,17 @@
15
16
  "@types/react-dom": "^18.0.0",
16
17
  "axios": "^1.7.2",
17
18
  "cookie-js": "^0.0.1",
19
+ "device-detector-js": "^3.0.3",
18
20
  "pullstate": "^1.25.0",
19
21
  "react": "^18.3.1",
20
22
  "react-dom": "^18.3.1",
23
+ "react-hook-form": "^7.52.1",
21
24
  "react-query": "^3.39.3",
22
25
  "react-scripts": "5.0.1",
23
26
  "react-toastify": "^9.0.1",
24
27
  "typescript": "^4.4.2",
25
- "web-vitals": "^2.1.0"
28
+ "web-vitals": "^2.1.0",
29
+ "yup": "^1.4.0"
26
30
  },
27
31
  "devDependencies": {
28
32
  "@babel/plugin-proposal-private-property-in-object": "^7.21.11",
@@ -1,14 +1,19 @@
1
- import { InternalServerError } from "@campxdev/react-blueprint/src/components/Assets/ErrorPages/InternalServerError";
2
- import { NoInterneConnection } from "@campxdev/react-blueprint/src/components/Assets/ErrorPages/NoInternetConnection";
3
- import { UnAuthorized } from "@campxdev/react-blueprint/src/components/Assets/ErrorPages/UnAuthorized";
4
- import { Button } from "@campxdev/react-blueprint/src/components/Input/Button/Button";
1
+ import {
2
+ Button,
3
+ CustomDialog,
4
+ InternalServerError,
5
+ NoInterneConnection,
6
+ PageNotFound,
7
+ UnAuthorized,
8
+ } from "@campxdev/react-blueprint";
5
9
  import { Alert, Box, styled } from "@mui/material";
6
10
  import Cookies from "js-cookie";
7
- import { ReactNode } from "react";
11
+ import { ReactNode, useState } from "react";
8
12
  import { ErrorBoundary as ReactErrorBoundary } from "react-error-boundary";
9
13
  import { QueryErrorResetBoundary } from "react-query";
10
14
  import { useLocation, useNavigate } from "react-router-dom";
11
15
  import { axios } from "../config/axios";
16
+ import { Login } from "./Login";
12
17
 
13
18
  export type ErrorBoundaryProps = {
14
19
  children: ReactNode;
@@ -53,14 +58,15 @@ export const ErrorBoundary = (props: ErrorBoundaryProps) => {
53
58
  };
54
59
 
55
60
  export const ErrorFallback = ({ error, resetErrorBoundary }: any) => {
56
- console.log(error, "llll");
57
61
  if (error?.response?.status) {
58
62
  switch (error?.response?.status) {
59
63
  case 401:
60
- return <UnAuth resetErrorBoundary={resetErrorBoundary} />;
64
+ return <UnAuth />;
61
65
 
62
66
  case 500:
63
67
  return <InternalServerError resetBoundary={resetErrorBoundary} />;
68
+ case 404:
69
+ return <PageNotFound />;
64
70
  }
65
71
  }
66
72
 
@@ -86,8 +92,9 @@ export const ErrorFallback = ({ error, resetErrorBoundary }: any) => {
86
92
  );
87
93
  };
88
94
 
89
- const UnAuth = ({ resetBoundary }: any) => {
95
+ const UnAuth = () => {
90
96
  const navigate = useNavigate();
97
+ const [isModalOpen, setModalOpen] = useState(false);
91
98
 
92
99
  const sessionCookie = Cookies.get("campx_session_key");
93
100
 
@@ -98,10 +105,14 @@ const UnAuth = ({ resetBoundary }: any) => {
98
105
  };
99
106
 
100
107
  const handleLoginClick = () => {
101
- if (!sessionCookie) {
102
- navigate("/auth/login");
108
+ if (window.location.hostname == "localhost") {
109
+ setModalOpen(true);
103
110
  } else {
104
- appinit();
111
+ if (!sessionCookie) {
112
+ navigate("/auth/login");
113
+ } else {
114
+ appinit();
115
+ }
105
116
  }
106
117
  };
107
118
 
@@ -118,6 +129,11 @@ const UnAuth = ({ resetBoundary }: any) => {
118
129
  >
119
130
  Click Here To Login
120
131
  </Button>
132
+ <CustomDialog
133
+ open={isModalOpen}
134
+ onClose={() => setModalOpen(false)}
135
+ content={({ close }) => <Login close={close} />}
136
+ />
121
137
  </>
122
138
  }
123
139
  />
@@ -0,0 +1,194 @@
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
+
11
+ import * as Yup from "yup";
12
+
13
+ type DeviceInformation = {
14
+ deviceType: string;
15
+ clientName: string;
16
+ os: string;
17
+ osVersion: string;
18
+ latitude: number | null;
19
+ longitude: number | null;
20
+ tokenType: string;
21
+ };
22
+
23
+ export type DeviceState = {
24
+ deviceInformation: DeviceInformation;
25
+ isLocationAllowed: boolean;
26
+ };
27
+
28
+ const performLogin = async (body: any) => {
29
+ if (!body.latitude || !body.longitude) {
30
+ const response = await fetch(
31
+ "https://www.googleapis.com/geolocation/v1/geolocate?key=AIzaSyB2YCpo1yi107RYj1LdZu2DCcpcO93reFY",
32
+ {
33
+ method: "POST",
34
+ headers: {
35
+ "Content-Type": "application/json",
36
+ },
37
+ body: JSON.stringify({
38
+ considerIp: "true",
39
+ }),
40
+ }
41
+ );
42
+ const data = await response.json();
43
+ body.latitude = data.location.lat;
44
+ body.longitude = data.location.lng;
45
+ }
46
+ return axios.post(`/auth-server/auth/login`, body).then((res) => res.data);
47
+ };
48
+
49
+ const validationSchema = Yup.object().shape({
50
+ username: Yup.string().required("Username is required"),
51
+ password: Yup.string().required("Password is required"),
52
+ });
53
+
54
+ export const Login = ({ close }: { close: () => void }) => {
55
+ const [deviceState, setDeviceState] = useState<DeviceState>({
56
+ deviceInformation: {
57
+ deviceType: "browser",
58
+ clientName: "unknown",
59
+ os: "unknown",
60
+ osVersion: "unknown",
61
+ latitude: null,
62
+ longitude: null,
63
+ tokenType: "WEB",
64
+ },
65
+ isLocationAllowed: true,
66
+ });
67
+
68
+ useEffect(() => {
69
+ navigator.geolocation.getCurrentPosition((position) => {
70
+ setDeviceState((s) => ({
71
+ ...s,
72
+ deviceInformation: {
73
+ ...s.deviceInformation,
74
+ latitude: position.coords.latitude,
75
+ longitude: position.coords.longitude,
76
+ },
77
+ }));
78
+ });
79
+ navigator.permissions
80
+ .query({ name: "geolocation" })
81
+ .then((permissionStatus) => {
82
+ if (permissionStatus.state === "denied") {
83
+ setDeviceState((s) => ({
84
+ ...s,
85
+ isLocationAllowed: false,
86
+ }));
87
+ }
88
+ });
89
+
90
+ const detector = new DeviceDetector();
91
+ const deviceInfo = detector.parse(navigator.userAgent);
92
+ setDeviceState((s) => ({
93
+ ...s,
94
+ deviceInformation: {
95
+ ...s.deviceInformation,
96
+ clientName: deviceInfo.client?.name || s.deviceInformation.clientName,
97
+ os: deviceInfo.os?.name || s.deviceInformation.os,
98
+ osVersion: deviceInfo.os?.version || s.deviceInformation.osVersion,
99
+ },
100
+ }));
101
+ }, []);
102
+
103
+ const {
104
+ handleSubmit,
105
+ control,
106
+ formState: { errors },
107
+ } = useForm({ resolver: yupResolver(validationSchema) });
108
+
109
+ const { mutate, isLoading } = useMutation(performLogin, {
110
+ onSuccess(data) {
111
+ if (data.loginSuccessful) {
112
+ Cookies.remove("campx_session_key");
113
+ Cookies.remove("campx_tenant");
114
+ Cookies.remove("campx_institution");
115
+ Cookies.set("campx_session_key", data?.token);
116
+ Cookies.set("campx_tenant", data?.subDomain);
117
+ Cookies.set("campx_institution", data?.institutionCode);
118
+ close();
119
+ window.location.reload();
120
+ }
121
+ },
122
+ });
123
+ const onSubmit = async (body: any) => {
124
+ mutate({ ...body, ...deviceState.deviceInformation });
125
+ };
126
+
127
+ return (
128
+ <>
129
+ <Stack gap="16px" justifyContent="space-between" alignItems="center">
130
+ <Box height="36px" width="194.8px">
131
+ <Icons.CampxFullLogoIcon />
132
+ </Box>
133
+ <Stack gap="10px" justifyContent="center" alignItems="center">
134
+ <Controller
135
+ control={control}
136
+ render={({ field }: { field: any }) => {
137
+ return (
138
+ <TextField
139
+ size="medium"
140
+ name="username"
141
+ sx={{
142
+ width: "400px",
143
+ }}
144
+ placeholder="Enter Username or Email"
145
+ containerProps={{ my: "0" }}
146
+ onChange={field.onChange}
147
+ label="Username or Email"
148
+ error={!!errors.username}
149
+ required
150
+ />
151
+ );
152
+ }}
153
+ name="username"
154
+ />
155
+ <Controller
156
+ control={control}
157
+ render={({ field }: { field: any }) => {
158
+ return (
159
+ <TextField
160
+ size="medium"
161
+ name="password"
162
+ sx={{
163
+ width: "400px",
164
+ }}
165
+ placeholder="Enter password"
166
+ onChange={field.onChange}
167
+ containerProps={{ my: "0" }}
168
+ label="Password"
169
+ type="password"
170
+ error={!!errors.password}
171
+ required
172
+ />
173
+ );
174
+ }}
175
+ name="password"
176
+ />
177
+ <Button
178
+ type="submit"
179
+ color="primary"
180
+ variant="contained"
181
+ sx={{
182
+ width: "400px",
183
+ }}
184
+ onClick={handleSubmit(onSubmit)}
185
+ disabled={isLoading}
186
+ loading={isLoading}
187
+ >
188
+ Login
189
+ </Button>
190
+ </Stack>
191
+ </Stack>
192
+ </>
193
+ );
194
+ };
@@ -63,7 +63,7 @@ axios.interceptors.response.use(
63
63
  SnackbarStore.update((s) => {
64
64
  s.open = true;
65
65
  s.message = response.data.message;
66
- s.variant = "success";
66
+ s.severity = "success";
67
67
  });
68
68
  }
69
69
 
@@ -74,7 +74,7 @@ axios.interceptors.response.use(
74
74
  SnackbarStore.update((s) => {
75
75
  s.open = true;
76
76
  s.message = err.response.data.message || "Bad Request";
77
- s.variant = "alert";
77
+ s.severity = "error";
78
78
  });
79
79
  }
80
80
 
@@ -1,11 +1,9 @@
1
- import { Snackbar } from "@campxdev/react-blueprint";
1
+ import { Severity, Snackbar } from "@campxdev/react-blueprint";
2
2
  import { Store } from "pullstate";
3
3
  import { createContext, ReactNode } from "react";
4
4
 
5
- type Variant = "success" | "info" | "warning" | "alert";
6
-
7
5
  interface SnackbarContextProps {
8
- showSnackbar: (message: string, variant?: Variant) => void;
6
+ showSnackbar: (message: string, severity?: Severity) => void;
9
7
  }
10
8
 
11
9
  const SnackbarContext = createContext<SnackbarContextProps | undefined>(
@@ -18,16 +16,16 @@ interface SnackbarProviderProps {
18
16
  export const SnackbarStore = new Store({
19
17
  open: false,
20
18
  message: "",
21
- variant: "success" as Variant,
19
+ severity: "success" as Severity,
22
20
  });
23
21
 
24
22
  export const SnackbarProvider = ({ children }: SnackbarProviderProps) => {
25
23
  const snackbar = SnackbarStore.useState((s) => s);
26
- const showSnackbar = (message: string, variant: Variant = "info") => {
24
+ const showSnackbar = (message: string, severity: Severity = "info") => {
27
25
  SnackbarStore.update((s) => {
28
26
  s.open = true;
29
27
  s.message = message;
30
- s.variant = variant;
28
+ s.severity = severity;
31
29
  });
32
30
  };
33
31
  return (
@@ -36,7 +34,7 @@ export const SnackbarProvider = ({ children }: SnackbarProviderProps) => {
36
34
  <Snackbar
37
35
  open={snackbar.open}
38
36
  message={snackbar.message}
39
- variant={snackbar.variant}
37
+ severity={snackbar.severity}
40
38
  autoHideDuration={1500}
41
39
  onClose={() => {
42
40
  SnackbarStore.update((s) => {