authscape 1.0.0 → 1.0.2

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.
@@ -0,0 +1,118 @@
1
+ import React, { Component } from 'react';
2
+ import apiService from '../services/apiService';
3
+ import DataTable, {createTheme} from "react-data-table-component";
4
+
5
+ export default class Datatable extends Component {
6
+
7
+ static defaultProps = {
8
+ options: {}
9
+ }
10
+
11
+ constructor(props) {
12
+ super(props);
13
+
14
+ this.state = {
15
+ pageNumber : 1,
16
+ pageLength : props.pageLength ? props.pageLength : 10,
17
+ data: [],
18
+ loading: false,
19
+ totalRows: 0
20
+ };
21
+ }
22
+
23
+ componentDidMount = async () => {
24
+ await this.GetDataFromUrl(this.state.pageNumber, this.state.pageLength, this.props.params);
25
+ createTheme('dataTable', {
26
+ text:{
27
+
28
+ }
29
+ })
30
+ }
31
+
32
+ reload = async (reset = false) => {
33
+
34
+ if (reset === true)
35
+ {
36
+ this.setState({pageNumber: 1}, async () => {
37
+ await this.GetDataFromUrl(this.state.pageNumber, this.state.pageLength, this.props.params);
38
+ })
39
+ }
40
+ else
41
+ {
42
+ await this.GetDataFromUrl(this.state.pageNumber, this.state.pageLength, this.props.params);
43
+ }
44
+
45
+
46
+ }
47
+
48
+ GetDataFromUrl = (page, length, postData = {}) => {
49
+
50
+ this.setState({
51
+ loading: true
52
+ }, async function () {
53
+
54
+ let data = postData;
55
+
56
+ data.offset = page;
57
+ data.length = length;
58
+
59
+ let response = null;
60
+ if (this.props.methodType == "get")
61
+ {
62
+ response = await apiService().get(this.props.url);
63
+ }
64
+ else
65
+ {
66
+ response = await apiService().post(this.props.url, postData);
67
+ }
68
+
69
+ if (response != null && response.status === 200)
70
+ {
71
+ if (this.props.returnResult != null)
72
+ {
73
+ this.props.returnResult(response.data.data);
74
+ }
75
+
76
+ this.setState({
77
+ totalRows: response.data.recordsTotal,
78
+ data: response.data.data,
79
+ loading: false
80
+ });
81
+ }
82
+ else
83
+ {
84
+ //console.error(response.status + " - " + response.data);
85
+ }
86
+
87
+ });
88
+
89
+ }
90
+
91
+ handlePageChange = async page => {
92
+ const { pageLength } = this.state;
93
+ this.setState({pageNumber: page});
94
+ await this.GetDataFromUrl(page, pageLength, this.props.params);
95
+ };
96
+
97
+ render() {
98
+
99
+ return (
100
+ <div>
101
+ <DataTable
102
+ title={this.props.title}
103
+ columns={this.props.columns}
104
+ data={this.state.data}
105
+ paginationRowsPerPageOptions={this.props.pageLength ? [this.props.pageLength] : [10]}
106
+ progressPending={this.state.loading}
107
+ customStyles={this.props.customStyles}
108
+ paginationPerPage={this.props.pageLength ? this.props.pageLength : 10}
109
+ paginationServer
110
+ pagination
111
+ paginationTotalRows={this.state.totalRows}
112
+ // onChangeRowsPerPage={this.handlePerRowsChange}
113
+ onChangePage={this.handlePageChange}
114
+ noDataComponent={this.props.noDataComponent}
115
+ />
116
+ </div>);
117
+ }
118
+ }
@@ -0,0 +1,32 @@
1
+ import React from 'react';
2
+ import Button from '@mui/material/Button';
3
+ import Dialog from '@mui/material/Dialog';
4
+ import DialogActions from '@mui/material/DialogActions';
5
+ import DialogContent from '@mui/material/DialogContent';
6
+ import DialogContentText from '@mui/material/DialogContentText';
7
+ import DialogTitle from '@mui/material/DialogTitle';
8
+
9
+ export default function confirmationModal({title, description, cancelClicked, okClicked, open = false, cancelTitle = "Cancel", okTitle = "OK"}) {
10
+ return (
11
+ <Dialog
12
+ open={open}
13
+ onClose={cancelClicked}
14
+ aria-labelledby="alert-dialog-title"
15
+ aria-describedby="alert-dialog-description">
16
+ <DialogTitle id="alert-dialog-title">
17
+ {title}
18
+ </DialogTitle>
19
+ <DialogContent>
20
+ <DialogContentText id="alert-dialog-description">
21
+ {description}
22
+ </DialogContentText>
23
+ </DialogContent>
24
+ <DialogActions>
25
+ <Button onClick={cancelClicked}>{cancelTitle}</Button>
26
+ <Button onClick={okClicked}>
27
+ {okTitle}
28
+ </Button>
29
+ </DialogActions>
30
+ </Dialog>
31
+ );
32
+ }
@@ -0,0 +1,254 @@
1
+ import React, {useEffect, useState} from 'react';
2
+ import {Elements} from '@stripe/react-stripe-js';
3
+ import {loadStripe} from '@stripe/stripe-js';
4
+ import Box from '@material-ui/core/Box';
5
+ import Dialog from '@mui/material/Dialog';
6
+ import DialogActions from '@mui/material/DialogActions';
7
+ import DialogContent from '@mui/material/DialogContent';
8
+ import DialogTitle from '@mui/material/DialogTitle';
9
+ import CheckoutForm from '../pricing/CheckoutForm';
10
+ import ApiService from '../../services/apiService';
11
+ import IconButton from '@mui/material/IconButton';
12
+ import CloseIcon from '@mui/icons-material/Close';
13
+ import Tabs from '@mui/material/Tabs';
14
+ import Tab from '@mui/material/Tab';
15
+ import Typography from '@mui/material/Typography';
16
+ import Select from '@mui/material/Select';
17
+ import MenuItem from '@mui/material/MenuItem';
18
+ import Stack from '@mui/material/Stack';
19
+ import Button from '@mui/material/Button';
20
+ import PaymentRoundedIcon from '@mui/icons-material/PaymentRounded';
21
+ import apiService from '../../services/apiService';
22
+ import Grid from '@mui/material/Grid';
23
+
24
+ export default function PaymentModal({title, description, amount, priceId, setIsLoading, isOpen, invoiceId, onModalClose}) {
25
+
26
+ const stripePromise = loadStripe(process.env.stripePublicKey);
27
+ const [options, setOptions] = useState(null);
28
+ const [value, setValue] = React.useState(0);
29
+ const [paymentMethods, setPaymentMethods] = React.useState([]);
30
+ const [paymentMethod, setPaymentMethod] = React.useState(null);
31
+
32
+ useEffect(async () => {
33
+
34
+ if (isOpen)
35
+ {
36
+ let response = await ApiService().post("/StripePayment/ConnectCustomer", {
37
+ paymentRequestType: 3,
38
+ amount: amount,
39
+ priceId: priceId
40
+ });
41
+
42
+ setOptions({
43
+ clientSecret: response.data,
44
+ });
45
+
46
+ let responsePayments = await ApiService().get("/NCAInvoices/GetPaymentMethods");
47
+ if (responsePayments != null && responsePayments.status == 200)
48
+ {
49
+ setPaymentMethods(responsePayments.data);
50
+ }
51
+ }
52
+
53
+ }, [isOpen]);
54
+
55
+ const handleChange = (event, newValue) => {
56
+ setValue(newValue);
57
+ };
58
+
59
+ function a11yProps(index) {
60
+ return {
61
+ id: `simple-tab-${index}`,
62
+ 'aria-controls': `simple-tabpanel-${index}`,
63
+ };
64
+ }
65
+
66
+ const PaymentMethod = ({id, last4, clicked}) => {
67
+ return (
68
+ <>
69
+ <Box fullWidth={true} sx={{height: 160, width:"100%", marginTop:2, backgroundColor:"#2196F3", position:"relative", border: "1px solid #2196F3", borderRadius: 1, display:"flex", flexDirection:"column", justifyContent:"center", textAlign:"center", cursor:"pointer"}}
70
+ onClick={() => {
71
+ clicked(id);
72
+ }}>
73
+ <Typography gutterBottom variant="body" component="div" sx={{fontSize:14, position:"absolute", left:15, top:10, color:"white"}}>
74
+ Visa
75
+ </Typography>
76
+ {/* <Box sx={{position:"absolute", top:10, right:10, color:"#e9e9e9"}}>
77
+ <DeleteRoundedIcon onClick={deleteClicked} />
78
+ </Box> */}
79
+ <Typography gutterBottom variant="body" component="div" sx={{verticalAlign:"middle", fontSize:18, color:"white"}}>
80
+ * * * * &nbsp; * * * * &nbsp; * * * * &nbsp; {last4}
81
+ </Typography>
82
+
83
+ <Grid container spacing={1} sx={{position:"absolute", bottom:8, marginLeft:0, width: "100%"}}>
84
+ <Grid item xs={6} sx={{paddingLeft:2}}>
85
+ <Typography gutterBottom variant="body" component="div" sx={{textAlign:"left", fontSize:12, marginTop:1, paddingLeft:1, color:"#e9e9e9"}}>
86
+ CARD HOLDER
87
+ </Typography>
88
+
89
+ <Typography gutterBottom variant="body" component="div" sx={{textAlign:"left", fontSize:12, marginTop:"-9px", paddingLeft:1, color:"white" }}>
90
+ Brandon Zuech
91
+ </Typography>
92
+ </Grid>
93
+ <Grid item xs={6} sx={{textAlign:"right", paddingRight:2}}>
94
+ <Typography gutterBottom variant="body" component="div" sx={{fontSize:12, marginLeft:2, marginTop:1, color:"#e9e9e9"}}>
95
+ EXPIRES
96
+ </Typography>
97
+
98
+ <Typography gutterBottom variant="body" component="div" sx={{fontSize:12, marginLeft:2, marginTop:"-9px", color:"white"}}>
99
+ 08/21
100
+ </Typography>
101
+ </Grid>
102
+ </Grid>
103
+ </Box>
104
+ </>
105
+ );
106
+ };
107
+
108
+ function TabPanel(props) {
109
+ const { children, value, index, ...other } = props;
110
+
111
+ return (
112
+ <div
113
+ role="tabpanel"
114
+ hidden={value !== index}
115
+ id={`simple-tabpanel-${index}`}
116
+ aria-labelledby={`simple-tab-${index}`}
117
+ {...other}
118
+ >
119
+ {value === index && (
120
+ <Box sx={{ p: 3 }}>
121
+ <Typography>{children}</Typography>
122
+ </Box>
123
+ )}
124
+ </div>
125
+ );
126
+ }
127
+
128
+ return (
129
+ <>
130
+ <Dialog
131
+ fullWidth={true}
132
+ maxWidth={"sm"}
133
+ open={isOpen}
134
+ onClose={() => onModalClose()}>
135
+ <DialogTitle>{title}
136
+
137
+ <IconButton
138
+ aria-label="close"
139
+ onClick={() => {
140
+
141
+ onModalClose();
142
+ }}
143
+ sx={{
144
+ position: 'absolute',
145
+ right: 8,
146
+ top: 8,
147
+ color: (theme) => theme.palette.grey[500],
148
+ }}>
149
+ <CloseIcon />
150
+ </IconButton>
151
+ </DialogTitle>
152
+ <DialogContent>
153
+ {description}
154
+
155
+ <Box sx={{ width: '100%' }}>
156
+ <Box sx={{ borderBottom: 1, borderColor: 'divider' }}>
157
+ <Tabs value={value} onChange={handleChange} aria-label="basic tabs example">
158
+ <Tab label="Existing Payment Method" {...a11yProps(0)} />
159
+ <Tab label="Add Payment Method" {...a11yProps(1)} />
160
+ </Tabs>
161
+ </Box>
162
+ <TabPanel value={value} index={0}>
163
+
164
+ <Select
165
+ sx={{marginTop:4}}
166
+ fullWidth={true}
167
+ //placeholder={"Select a payment type"}
168
+ //labelId="demo-simple-select-label"
169
+ id="demo-simple-select"
170
+ value={paymentMethod}
171
+ //label="Payment Type"
172
+ onChange={(val) => {
173
+ setPaymentMethod(val.target.value);
174
+ }}>
175
+ {paymentMethods != null && paymentMethods.map((paymentMethod) => {
176
+ return (
177
+ <MenuItem value={paymentMethod.id} fullWidth={true} sx={{width:"100%"}}>
178
+
179
+
180
+
181
+ <PaymentMethod id={paymentMethod.id} last4={paymentMethod.last4} clicked={() => {
182
+
183
+ }} />
184
+
185
+
186
+ {/* <Box elevation={0} sx={{backgroundColor:"white"}}>
187
+ <Stack direction="row" spacing={2}>
188
+ <Box sx={{paddingTop:2}}>
189
+ <img
190
+ style={{marginTop:"9px"}}
191
+ loading="lazy"
192
+ width="50"
193
+ src={'/images/cardType/' + paymentMethod.brand + ".png"}
194
+ srcSet={'/images/cardType/' + paymentMethod.brand + ".png"}
195
+ />
196
+ </Box>
197
+ <Box>
198
+ <Box>
199
+ {paymentMethod.funding.toUpperCase()}
200
+ </Box>
201
+ <Box>
202
+ **** **** <small>{paymentMethod.last4}</small> &nbsp; <small>Expire: ({paymentMethod.expMonth}/{paymentMethod.expYear})</small>
203
+ </Box>
204
+ </Box>
205
+ </Stack>
206
+ </Box> */}
207
+
208
+ </MenuItem>)
209
+ })}
210
+ </Select>
211
+
212
+ <Button startIcon={<PaymentRoundedIcon/>} type="submit" variant="contained" disabled={paymentMethod == null} sx={{marginTop:2}} onClick={async () => {
213
+
214
+ setIsLoading(true);
215
+ let response = await apiService().post("/NCAInvoices/PayInvoice", {
216
+ InvoiceId: invoiceId,
217
+ WalletId: paymentMethod
218
+ });
219
+ setIsLoading(false);
220
+
221
+ if (response != null && response.status == 200)
222
+ {
223
+ window.location.reload();
224
+ }
225
+ else
226
+ {
227
+ alert("We had an issue with the payment method");
228
+ }
229
+
230
+
231
+ }}>Pay Now</Button>
232
+
233
+ </TabPanel>
234
+ <TabPanel value={value} index={1}>
235
+ <div>
236
+ <Box mt={4} mb={2}>
237
+ {options != null &&
238
+ <Elements stripe={stripePromise} options={options}>
239
+ <CheckoutForm />
240
+ </Elements>
241
+ }
242
+ </Box>
243
+ </div>
244
+ </TabPanel>
245
+ </Box>
246
+
247
+ </DialogContent>
248
+ <DialogActions>
249
+ {/* <Button onClick={handleClose}>Close</Button> */}
250
+ </DialogActions>
251
+ </Dialog>
252
+ </>
253
+ )
254
+ }
@@ -0,0 +1,55 @@
1
+ import React, {useState} from 'react';
2
+ import Button from '@mui/material/Button';
3
+ import {useStripe, useElements, PaymentElement} from '@stripe/react-stripe-js';
4
+ import PaymentRoundedIcon from '@mui/icons-material/PaymentRounded';
5
+
6
+ const CheckoutForm = () => {
7
+ const stripe = useStripe();
8
+ const elements = useElements();
9
+
10
+ const [errorMessage, setErrorMessage] = useState(null);
11
+
12
+ const handleSubmit = async (event) => {
13
+
14
+ // We don't want to let default form submission happen here,
15
+ // which would refresh the page.
16
+ event.preventDefault();
17
+
18
+ if (!stripe || !elements) {
19
+ // Stripe.js has not yet loaded.
20
+ // Make sure to disable form submission until Stripe.js has loaded.
21
+ return;
22
+ }
23
+
24
+ const {error} = await stripe.confirmPayment({
25
+ //`Elements` instance that was used to create the Payment Element
26
+ elements,
27
+ confirmParams: {
28
+ return_url: process.env.WebsiteBaseUri + '/confirmPayment?redirectUrl=' + encodeURIComponent(window.location.href),
29
+ },
30
+ });
31
+
32
+ if (error) {
33
+ // This point will only be reached if there is an immediate error when
34
+ // confirming the payment. Show error to your customer (for example, payment
35
+ // details incomplete)
36
+ setErrorMessage(error.message);
37
+ } else {
38
+ // Your customer will be redirected to your `return_url`. For some payment
39
+ // methods like iDEAL, your customer will be redirected to an intermediate
40
+ // site first to authorize the payment, then redirected to the `return_url`.
41
+
42
+ }
43
+ };
44
+
45
+ return (
46
+ <form onSubmit={handleSubmit}>
47
+ <PaymentElement />
48
+ <Button startIcon={<PaymentRoundedIcon/>} type="submit" variant="contained" disabled={!stripe} sx={{marginTop:2}}>Pay Now</Button>
49
+ {/* Show error message to your customers */}
50
+ {errorMessage && <div>{errorMessage}</div>}
51
+ </form>
52
+ )
53
+ };
54
+
55
+ export default CheckoutForm;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "authscape",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -10,10 +10,13 @@
10
10
  "license": "ISC",
11
11
  "dependencies": {
12
12
  "axios": "^0.27.2",
13
+ "js-file-download": "^0.4.12",
13
14
  "next": "^12.1.6",
15
+ "next-cookies": "^2.0.3",
14
16
  "nookies": "^2.5.2",
15
17
  "querystring": "^0.2.1",
16
18
  "react": "^18.2.0",
19
+ "react-data-table-component": "^7.5.2",
17
20
  "react-dom": "^18.2.0"
18
21
  }
19
22
  }
@@ -0,0 +1,3 @@
1
+ export function GetEnvironment() {
2
+ return process.env.STAGE;
3
+ }
@@ -0,0 +1,304 @@
1
+ import axios from 'axios'
2
+ import querystring from 'querystring';
3
+ import fileDownload from 'js-file-download';
4
+ import cookies from 'next-cookies';
5
+ import { parseCookies, setCookie, destroyCookie } from 'nookies';
6
+ import { GetEnvironment } from "./BaseUri";
7
+
8
+ const setupDefaultOptions = async (ctx = null) => {
9
+
10
+ let defaultOptions = {};
11
+
12
+ if (ctx == null)
13
+ {
14
+ let accessToken = cookies(ctx).access_token || '';
15
+
16
+ // let accessToken = window.localStorage.getItem("access_token");
17
+
18
+ if (accessToken !== null && accessToken !== undefined && accessToken != "") {
19
+ defaultOptions = {
20
+ headers: {
21
+ Authorization: "Bearer " + accessToken
22
+ }
23
+ };
24
+ }
25
+ else {
26
+ defaultOptions = {
27
+ headers: {
28
+ },
29
+ };
30
+ }
31
+ }
32
+ else
33
+ {
34
+ defaultOptions = {
35
+ headers: {
36
+ },
37
+ };
38
+ }
39
+
40
+ return defaultOptions;
41
+ }
42
+
43
+ const RefreshToken = async (originalRequest, instance) => {
44
+
45
+ let accessToken = cookies(null).access_token || '';
46
+ let refreshToken = cookies(null).refresh_token || '';
47
+
48
+ let response = await instance.post(process.env.AUTHORITYURI + "/connect/token",
49
+ querystring.stringify({
50
+ grant_type: 'refresh_token',
51
+ client_id: process.env.client_id,
52
+ client_secret: process.env.client_secret,
53
+ refresh_token: refreshToken
54
+ }), {
55
+ headers: {
56
+ "Content-Type": "application/x-www-form-urlencoded",
57
+ "Authorization": "Bearer " + accessToken
58
+ }
59
+ });
60
+
61
+ if (response != null && response.status == 200)
62
+ {
63
+ originalRequest.headers['Authorization'] = 'Bearer ' + response.data.access_token;
64
+
65
+ let domain = getCookieDomain();
66
+
67
+ await setCookie(null, "access_token", response.data.access_token,
68
+ {
69
+ maxAge: 2147483647,
70
+ path: '/',
71
+ domain: domain,
72
+ secure: true
73
+ });
74
+
75
+ await setCookie(null, "expires_in", response.data.expires_in,
76
+ {
77
+ maxAge: 2147483647,
78
+ path: '/',
79
+ domain: domain,
80
+ secure: true
81
+ });
82
+
83
+ await setCookie(null, "refresh_token", response.data.refresh_token,
84
+ {
85
+ maxAge: 2147483647,
86
+ path: '/',
87
+ domain: domain,
88
+ secure: true
89
+ });
90
+ }
91
+ }
92
+
93
+ const apiService = (ctx = null) => {
94
+
95
+ let env = GetEnvironment();
96
+ if (env == "development")
97
+ {
98
+ process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
99
+ }
100
+
101
+ let baseUri = process.env.APIURI + "/api";
102
+ let AuthUri = process.env.AUTHORITYURI;
103
+
104
+ const instance = axios.create({
105
+ baseURL: baseUri,
106
+ //timeout: 10000,
107
+ params: {} // do not remove this, its added to add params later in the config
108
+ });
109
+
110
+ instance.interceptors.response.use(
111
+ (response) => {
112
+
113
+ return response;
114
+ },
115
+ async (error) => {
116
+ const originalConfig = error.config;
117
+ if (error.response) {
118
+
119
+ if (error.response.status === 401 && !originalConfig._retry) {
120
+ originalConfig._retry = true;
121
+
122
+ // Do something, call refreshToken() request for example;
123
+ await RefreshToken(originalConfig, instance);
124
+
125
+ // return a request
126
+ return instance.request(originalConfig);
127
+ }
128
+
129
+ if (error.response.status === 400) {
130
+ // Do something
131
+
132
+ if (error.response.config.url.includes("/connect/token")) // remove the access and refresh if invalid
133
+ {
134
+ destroyCookie(ctx, "access_token", {
135
+ maxAge: 2147483647,
136
+ path: '/',
137
+ domain: process.env.cookieDomain
138
+ });
139
+
140
+ destroyCookie(ctx, "refresh_token", {
141
+ maxAge: 2147483647,
142
+ path: '/',
143
+ domain: process.env.cookieDomain
144
+ });
145
+
146
+ destroyCookie(ctx, "expires_in", {
147
+ maxAge: 2147483647,
148
+ path: '/',
149
+ domain: process.env.cookieDomain
150
+ });
151
+ }
152
+
153
+ return Promise.reject(error);
154
+ }
155
+ }
156
+
157
+ return Promise.reject(error);
158
+ }
159
+ );
160
+
161
+ return {
162
+
163
+ get: async (url, options= {}) => {
164
+
165
+ try
166
+ {
167
+ let defaultOptions = await setupDefaultOptions(ctx);
168
+ return await instance.get(url, { ...defaultOptions, ...options });
169
+ }
170
+ catch(error)
171
+ {
172
+ return error.response;
173
+ }
174
+ },
175
+ post: async (url, data, options = {}) => {
176
+
177
+ try
178
+ {
179
+ let defaultOptions = await setupDefaultOptions(ctx);
180
+ return await instance.post(url, data, { ...defaultOptions, ...options });
181
+ }
182
+ catch(error)
183
+ {
184
+ return error.response;
185
+ }
186
+ },
187
+ put: async (url, data, options = {}) => {
188
+
189
+ try
190
+ {
191
+ let defaultOptions = await setupDefaultOptions(ctx);
192
+ return await instance.put(url, data, { ...defaultOptions, ...options });
193
+ }
194
+ catch(error)
195
+ {
196
+ return error.response;
197
+ }
198
+ },
199
+ delete: async (url, options = {}) => {
200
+
201
+ try
202
+ {
203
+ let defaultOptions = await setupDefaultOptions(ctx);
204
+ return await instance.delete(url, { ...defaultOptions, ...options });
205
+ }
206
+ catch(error)
207
+ {
208
+ return error.response;
209
+ }
210
+ },
211
+ login: async () => {
212
+
213
+ await signinRedirect(ctx);
214
+ },
215
+ logout: async () => {
216
+
217
+ let cookieDomain = process.env.cookieDomain;
218
+
219
+ destroyCookie(ctx, "access_token", {
220
+ maxAge: 2147483647,
221
+ path: '/',
222
+ domain: cookieDomain
223
+ });
224
+
225
+ destroyCookie(ctx, "refresh_token", {
226
+ maxAge: 2147483647,
227
+ path: '/',
228
+ domain: cookieDomain
229
+ });
230
+
231
+ destroyCookie(ctx, "expires_in", {
232
+ maxAge: 2147483647,
233
+ path: '/',
234
+ domain: cookieDomain
235
+ });
236
+
237
+ setTimeout(() => {
238
+ window.location.href = AuthUri + "/connect/logout?redirect=" + window.location.href;
239
+ }, 500);
240
+
241
+ },
242
+ signUp: (redirectUrl = null) => {
243
+
244
+ let url = "";
245
+ if (redirectUrl == null)
246
+ {
247
+ url = AuthUri + "/Account/Register?redirectUrl=" + window.location.href;
248
+ localStorage.setItem("redirectUri", window.location.href);
249
+ }
250
+ else
251
+ {
252
+ url = AuthUri + "/Account/Register?redirectUrl=" + redirectUrl;
253
+ localStorage.setItem("redirectUri", redirectUrl);
254
+ }
255
+
256
+ window.location.href = url;
257
+ },
258
+ GetCurrentUser: async () => {
259
+
260
+ try
261
+ {
262
+ let accessToken = cookies(ctx).access_token || null;
263
+ if (accessToken)
264
+ {
265
+ let defaultOptions = await setupDefaultOptions(ctx);
266
+ const response = await instance.get('/UserManagement', defaultOptions);
267
+ if (response != null && response.status == 200)
268
+ {
269
+ return response.data;
270
+ }
271
+ }
272
+
273
+ } catch(exp) {
274
+ //return -1;
275
+ }
276
+ return null;
277
+ },
278
+ DownloadFile: async (url, fileName, completed) => {
279
+
280
+ try
281
+ {
282
+ //let defaultOptions = await setupDefaultOptions();
283
+ let defaultOptions = {};
284
+ let options = { responseType: "blob" };
285
+ let response = await instance.get(url, { ...defaultOptions, ...options });
286
+ if (response.status === 200) {
287
+ fileDownload(response.data, fileName);
288
+ if (completed !== undefined) {
289
+ completed();
290
+ }
291
+ }
292
+ }
293
+ catch(error)
294
+ {
295
+ console.error(error);
296
+ if (completed !== undefined) {
297
+ completed();
298
+ }
299
+ }
300
+ }
301
+ }
302
+ }
303
+
304
+ export default apiService;
@@ -0,0 +1,65 @@
1
+ import React from 'react';
2
+ import axios from 'axios';
3
+ import querystring from 'querystring';
4
+
5
+ const authService = () => {
6
+
7
+ return {
8
+
9
+ dec2hex: (dec) => {
10
+ return ('0' + dec.toString(16)).substr(-2)
11
+ },
12
+ generateRandomString: () => {
13
+ var array = new Uint32Array(56/2);
14
+ window.crypto.getRandomValues(array);
15
+ return Array.from(array, authService().dec2hex).join('');
16
+ },
17
+ sha256: (plain) => {
18
+ const encoder = new TextEncoder();
19
+ const data = encoder.encode(plain);
20
+ return window.crypto.subtle.digest('SHA-256', data);
21
+ },
22
+ base64urlencode: (a) => {
23
+ var str = "";
24
+ var bytes = new Uint8Array(a);
25
+ var len = bytes.byteLength;
26
+ for (var i = 0; i < len; i++) {
27
+ str += String.fromCharCode(bytes[i]);
28
+ }
29
+ return btoa(str)
30
+ .replace(/\+/g, "-")
31
+ .replace(/\//g, "_")
32
+ .replace(/=+$/, "");
33
+ },
34
+ challenge_from_verifier: async (v) => {
35
+ let hashed = await authService().sha256(v);
36
+ let base64encoded = authService().base64urlencode(hashed);
37
+ return base64encoded;
38
+ },
39
+ login: async (redirectUserUri = null, dnsRecord = null, deviceId = null) => {
40
+
41
+ let state = "1234";
42
+ if (redirectUserUri != null)
43
+ {
44
+ localStorage.setItem("redirectUri", redirectUserUri);
45
+ }
46
+
47
+ let verifier = authService().generateRandomString();
48
+ var challenge = await authService().challenge_from_verifier(verifier);
49
+
50
+ window.localStorage.setItem("verifier", verifier);
51
+
52
+ let redirectUri = window.location.origin + "/signin-oidc";
53
+ let loginUri = process.env.AUTHORITYURI + "/connect/authorize?response_type=code&state=" + state + "&client_id=" + process.env.client_id + "&scope=email%20openid%20offline_access%20profile%20api1&redirect_uri=" + redirectUri + "&code_challenge=" + challenge + "&code_challenge_method=S256";
54
+
55
+ if (deviceId)
56
+ {
57
+ loginUri += "&deviceId=" + deviceId; // will be for chrome extention and mobile apps later
58
+ }
59
+
60
+ window.location.href = loginUri;
61
+ }
62
+ }
63
+ }
64
+
65
+ export default authService;
@@ -0,0 +1,37 @@
1
+ import React, { useEffect, useState, useRef } from 'react';
2
+ import apiService from '../services/apiService';
3
+
4
+ export default function AuthorizationComponent({children, setCurrentUser, userLoaded}) {
5
+
6
+ const [loaded, setLoaded] = useState(false);
7
+
8
+ useEffect(async () => {
9
+
10
+ if (!loaded)
11
+ {
12
+ setLoaded(true);
13
+
14
+ let usr = await apiService().GetCurrentUser();
15
+ if (usr != null)
16
+ {
17
+ setCurrentUser(usr);
18
+ }
19
+ else
20
+ {
21
+ setCurrentUser(null);
22
+ }
23
+
24
+ userLoaded();
25
+ }
26
+
27
+ }, [loaded]);
28
+
29
+ return (
30
+ <>
31
+ <div>
32
+ {children}
33
+ </div>
34
+
35
+ </>
36
+ )
37
+ }
@@ -0,0 +1,13 @@
1
+ const Slug = (slug) => {
2
+
3
+ let index = slug.lastIndexOf("-") + 1;
4
+ if (slug.length > index)
5
+ {
6
+ slug = slug.substr(index);
7
+ return slug;
8
+ }
9
+
10
+ return null;
11
+ };
12
+
13
+ export default Slug;
@@ -0,0 +1,30 @@
1
+ const storeWithExpiry = () => {
2
+
3
+ return {
4
+ set: (key, value, ttl) => {
5
+
6
+ const now = new Date()
7
+ const item = {
8
+ value: value,
9
+ expiry: now.getTime() + ttl,
10
+ }
11
+ localStorage.setItem(key, JSON.stringify(item))
12
+ },
13
+ get: (key) => {
14
+
15
+ const itemStr = localStorage.getItem(key)
16
+ if (!itemStr) {
17
+ return null
18
+ }
19
+ const item = JSON.parse(itemStr)
20
+ const now = new Date()
21
+ if (now.getTime() > item.expiry) {
22
+ localStorage.removeItem(key)
23
+ return null
24
+ }
25
+ return item.value
26
+ }
27
+ }
28
+ }
29
+
30
+ export default storeWithExpiry;