@velocitycareerlabs/velocity-registrar-app 1.25.0-dev-build.1253d0f86 → 1.25.0-dev-build.1540aaa8e
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/.env.dev +4 -4
- package/package.json +2 -2
- package/src/App.jsx +8 -8
- package/src/pages/invitations/CreateOrganisationFromInvitation.jsx +6 -0
- package/src/pages/organizations/OrganizationAddService.jsx +6 -0
- package/src/pages/organizations/OrganizationCreate.jsx +12 -0
- package/src/pages/organizations/components/MockOrganization.jsx +44 -0
- package/src/pages/organizations/utils/mockOrganization.js +21 -0
- package/src/pages/services/ServiceCreateForm.jsx +6 -0
- package/src/pages/services/ServiceList.jsx +6 -0
- package/src/pages/services/components/SecureIntegrationPopup/index.jsx +70 -0
- package/src/pages/services/components/SecureMessageUrl/SaveButton/index.jsx +23 -0
- package/src/pages/services/components/SecureMessageUrl/TestButton/index.jsx +44 -0
- package/src/pages/services/components/SecureMessageUrl/TestSecureMessageWarning/index.jsx +73 -0
- package/src/pages/services/components/SecureMessageUrl/TrackTestStatus/index.jsx +27 -0
- package/src/pages/services/components/SecureMessageUrl/index.jsx +157 -0
- package/src/pages/services/components/SecureTransfer/ConsentLabel/index.jsx +13 -0
- package/src/pages/services/components/SecureTransfer/SaveButton/index.jsx +20 -0
- package/src/pages/services/components/SecureTransfer/index.jsx +102 -0
- package/src/pages/services/hooks/useSecureMessageTest.js +86 -0
- package/src/pages/services/utils/index.jsx +49 -0
- package/src/utils/remoteDataProvider.js +54 -0
package/.env.dev
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
VITE_REGISTRAR_AUTH0_DOMAIN=
|
|
2
|
-
VITE_REGISTRAR_AUTH0_CLIENT_ID=
|
|
3
|
-
VITE_REGISTRAR_AUTH0_REDIRECT_URI=
|
|
1
|
+
VITE_REGISTRAR_AUTH0_DOMAIN=devauth.velocitynetwork.foundation
|
|
2
|
+
VITE_REGISTRAR_AUTH0_CLIENT_ID=RkHjVKfdzpdemtZeJ7lFxDMMAe4CfyYa
|
|
3
|
+
VITE_REGISTRAR_AUTH0_REDIRECT_URI=https://devregistrarapp.velocitynetwork.foundation
|
|
4
4
|
VITE_REGISTRAR_AUDIENCE=https://registrar.velocitynetwork.foundation
|
|
5
|
-
VITE_REGISTRAR_CONNECTION=vnf-
|
|
5
|
+
VITE_REGISTRAR_CONNECTION=vnf-dev-users-connection
|
|
6
6
|
VITE_REGISTRAR_API=https://devregistrar.velocitynetwork.foundation/api/v0.6
|
|
7
7
|
VITE_X_AUTO_ACTIVATE=true
|
|
8
8
|
VITE_CHAIN_NAME=Devnet
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@velocitycareerlabs/velocity-registrar-app",
|
|
3
|
-
"version": "1.25.0-dev-build.
|
|
3
|
+
"version": "1.25.0-dev-build.1540aaa8e",
|
|
4
4
|
"description": "Velocity Registrar",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"publishConfig": {
|
|
@@ -60,5 +60,5 @@
|
|
|
60
60
|
"not ie <= 11",
|
|
61
61
|
"not op_mini all"
|
|
62
62
|
],
|
|
63
|
-
"gitHead": "
|
|
63
|
+
"gitHead": "bff19461f623080a5fb849529152fb4eb0956515"
|
|
64
64
|
}
|
package/src/App.jsx
CHANGED
|
@@ -15,26 +15,21 @@
|
|
|
15
15
|
*
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
+
import React from 'react';
|
|
18
19
|
import { Route, useLocation, useNavigate } from 'react-router-dom';
|
|
19
20
|
import { CustomRoutes, Resource } from 'react-admin';
|
|
20
|
-
import React from 'react';
|
|
21
21
|
import { Auth0Provider } from '@auth0/auth0-react';
|
|
22
22
|
import OrganizationIcon from '@mui/icons-material/Business';
|
|
23
23
|
import {
|
|
24
24
|
OrganizationShow,
|
|
25
25
|
OrganizationEdit,
|
|
26
|
-
OrganizationCreate,
|
|
27
26
|
} from '@velocitycareerlabs/components-organizations-registrar/pages/organizations';
|
|
28
27
|
import {
|
|
29
28
|
IndividualsDashboard,
|
|
30
29
|
IndividualsShow,
|
|
31
30
|
IndividualsEdit,
|
|
32
31
|
} from '@velocitycareerlabs/components-organizations-registrar/pages/individuals';
|
|
33
|
-
import {
|
|
34
|
-
import {
|
|
35
|
-
CreateOrganisationFromInvitation,
|
|
36
|
-
InvitationsList,
|
|
37
|
-
} from '@velocitycareerlabs/components-organizations-registrar/pages/invitations';
|
|
32
|
+
import { InvitationsList } from '@velocitycareerlabs/components-organizations-registrar/pages/invitations';
|
|
38
33
|
import {
|
|
39
34
|
PrivacyPolicy,
|
|
40
35
|
TermsAndConditions,
|
|
@@ -48,7 +43,12 @@ import {
|
|
|
48
43
|
PrivateAppRoot,
|
|
49
44
|
useConfig,
|
|
50
45
|
} from '@velocitycareerlabs/components-organizations-registrar';
|
|
46
|
+
|
|
51
47
|
import { AuthProviderBridge } from './AuthProviderBridge.jsx';
|
|
48
|
+
import { ServicesList } from './pages/services/ServiceList.jsx';
|
|
49
|
+
import { OrganizationCreate } from './pages/organizations/OrganizationCreate.jsx';
|
|
50
|
+
import { CreateOrganisationFromInvitation } from './pages/invitations/CreateOrganisationFromInvitation.jsx';
|
|
51
|
+
import { extendedRemoteDataProvider } from './utils/remoteDataProvider';
|
|
52
52
|
|
|
53
53
|
const PublicRoutes = ['/privacy-policy', '/terms-and-conditions', /^\/signatories\/[^/]+$/];
|
|
54
54
|
|
|
@@ -94,7 +94,7 @@ const PrivateRegistrarApp = () => {
|
|
|
94
94
|
}}
|
|
95
95
|
>
|
|
96
96
|
<AuthProviderBridge config={config}>
|
|
97
|
-
<PrivateAppRoot>
|
|
97
|
+
<PrivateAppRoot extendedRemoteDataProvider={extendedRemoteDataProvider()}>
|
|
98
98
|
<Resource
|
|
99
99
|
name="organizations"
|
|
100
100
|
icon={OrganizationIcon}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { CreateOrganisationFromInvitation as CreateOrganization } from '@velocitycareerlabs/components-organizations-registrar/pages/invitations';
|
|
2
|
+
import { SecureIntegrationPopup } from '../services/components/SecureIntegrationPopup/index.jsx';
|
|
3
|
+
|
|
4
|
+
export const CreateOrganisationFromInvitation = () => {
|
|
5
|
+
return <CreateOrganization InterceptOnCreate={SecureIntegrationPopup} />;
|
|
6
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { OrganizationAddService as OrganizationAddServiceBase } from '@velocitycareerlabs/components-organizations-registrar/pages/organizations';
|
|
2
|
+
import { SecureIntegrationPopup } from '../services/components/SecureIntegrationPopup/index.jsx';
|
|
3
|
+
|
|
4
|
+
export const OrganizationAddService = (props) => {
|
|
5
|
+
return <OrganizationAddServiceBase {...props} InterceptOnCreate={SecureIntegrationPopup} />;
|
|
6
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { OrganizationCreate as OrganizationCreateBase } from '@velocitycareerlabs/components-organizations-registrar/pages/organizations';
|
|
2
|
+
import { OrganizationAddService } from './OrganizationAddService.jsx';
|
|
3
|
+
import { MockOrganization } from './components/MockOrganization.jsx';
|
|
4
|
+
|
|
5
|
+
export const OrganizationCreate = () => {
|
|
6
|
+
return (
|
|
7
|
+
<OrganizationCreateBase
|
|
8
|
+
CreateServiceComponent={OrganizationAddService}
|
|
9
|
+
MockOrganization={MockOrganization}
|
|
10
|
+
/>
|
|
11
|
+
);
|
|
12
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { useCallback } from 'react';
|
|
2
|
+
import { Button } from 'react-admin';
|
|
3
|
+
import { Box } from '@mui/material';
|
|
4
|
+
import PropTypes from 'prop-types';
|
|
5
|
+
|
|
6
|
+
import { useConfig, chainNames } from '@velocitycareerlabs/components-organizations-registrar';
|
|
7
|
+
import { initialRecordMock } from '../utils/mockOrganization';
|
|
8
|
+
|
|
9
|
+
export const MockOrganization = ({ setInitialRecord }) => {
|
|
10
|
+
const config = useConfig();
|
|
11
|
+
const isMockDataAllowed = [chainNames.localnet, chainNames.devnet, chainNames.qanet].includes(
|
|
12
|
+
config.chainName,
|
|
13
|
+
);
|
|
14
|
+
const mockOrganization = useCallback(() => {
|
|
15
|
+
setInitialRecord(initialRecordMock);
|
|
16
|
+
}, [setInitialRecord]);
|
|
17
|
+
|
|
18
|
+
return isMockDataAllowed ? (
|
|
19
|
+
<Box display="flex" alignSelf="flex-end">
|
|
20
|
+
<Button
|
|
21
|
+
variant="text"
|
|
22
|
+
color="secondary"
|
|
23
|
+
size="large"
|
|
24
|
+
sx={sx.mockButton}
|
|
25
|
+
onClick={mockOrganization}
|
|
26
|
+
>
|
|
27
|
+
Mock Organization
|
|
28
|
+
</Button>
|
|
29
|
+
</Box>
|
|
30
|
+
) : null;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const sx = {
|
|
34
|
+
mockButton: {
|
|
35
|
+
color: 'primary.main',
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// eslint-disable-next-line better-mutation/no-mutation
|
|
40
|
+
MockOrganization.propTypes = {
|
|
41
|
+
setInitialRecord: PropTypes.func.isRequired,
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export default MockOrganization;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export const initialRecordMock = {
|
|
2
|
+
profile: {
|
|
3
|
+
name: `Mock Organization, Inc. ${new Date().getTime()}`,
|
|
4
|
+
website: `https://mockcompany${new Date().getTime()}.com`,
|
|
5
|
+
linkedInProfile: 'https://www.linkedin.com/company/mockcompanyid',
|
|
6
|
+
physicalAddress: { line1: '123 Mock Street' },
|
|
7
|
+
location: { countryCode: 'US' },
|
|
8
|
+
contactEmail: 'support@mockcompany.com',
|
|
9
|
+
technicalEmail: 'tech@mockcompany.com',
|
|
10
|
+
description: 'This is a mock description for local development.',
|
|
11
|
+
registrationNumbers: [{ authority: 'DunnAndBradstreet', number: '12345' }],
|
|
12
|
+
adminGivenName: 'AdminFirst',
|
|
13
|
+
adminFamilyName: 'AdminLast',
|
|
14
|
+
adminTitle: 'Administrator',
|
|
15
|
+
adminEmail: 'admin@mockcompany.com',
|
|
16
|
+
signatoryGivenName: 'SignerFirst',
|
|
17
|
+
signatoryFamilyName: 'SignerLast',
|
|
18
|
+
signatoryTitle: 'Signatory Officer',
|
|
19
|
+
signatoryEmail: 'sign@mockcompany.com',
|
|
20
|
+
},
|
|
21
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { ServiceCreateForm as ServiceCreateFormBase } from '@velocitycareerlabs/components-organizations-registrar/pages/services';
|
|
2
|
+
import { SecureIntegrationPopup } from './components/SecureIntegrationPopup/index.jsx';
|
|
3
|
+
|
|
4
|
+
export const ServiceCreateForm = (props) => {
|
|
5
|
+
return <ServiceCreateFormBase {...props} InterceptOnCreate={SecureIntegrationPopup} />;
|
|
6
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { ServicesList as ServicesListBase } from '@velocitycareerlabs/components-organizations-registrar/pages/services';
|
|
2
|
+
import { ServiceCreateForm } from './ServiceCreateForm.jsx';
|
|
3
|
+
|
|
4
|
+
export const ServicesList = () => {
|
|
5
|
+
return <ServicesListBase CreateComponent={ServiceCreateForm} />;
|
|
6
|
+
};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import React, { useEffect } from 'react';
|
|
2
|
+
import { useGetOne } from 'react-admin';
|
|
3
|
+
import PropTypes from 'prop-types';
|
|
4
|
+
import { useSelectedOrganization } from '@velocitycareerlabs/components-organizations-registrar';
|
|
5
|
+
import { Popup } from '@velocitycareerlabs/components-organizations-registrar/components/common';
|
|
6
|
+
import { Loading } from '@velocitycareerlabs/components-organizations-registrar/components';
|
|
7
|
+
|
|
8
|
+
import { SecureMessageURL } from '../SecureMessageUrl/index.jsx';
|
|
9
|
+
import { SecureTransfer } from '../SecureTransfer/index.jsx';
|
|
10
|
+
import { dataResources } from '../../../../utils/remoteDataProvider';
|
|
11
|
+
|
|
12
|
+
export const SecureIntegrationPopup = ({
|
|
13
|
+
isInterceptOnCreateOpen,
|
|
14
|
+
serviceId,
|
|
15
|
+
onNext,
|
|
16
|
+
onClose,
|
|
17
|
+
isIssueOrInspection,
|
|
18
|
+
selectedCAO,
|
|
19
|
+
}) => {
|
|
20
|
+
const [did] = useSelectedOrganization();
|
|
21
|
+
|
|
22
|
+
const { data: secureMessageTransfer, isLoading: isCheckingCAOSecureTranferSupport } = useGetOne(
|
|
23
|
+
dataResources.SECURE_MESSAGE_SUPPORTED,
|
|
24
|
+
{
|
|
25
|
+
id: selectedCAO,
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
enabled: !!selectedCAO && isIssueOrInspection,
|
|
29
|
+
},
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
if (secureMessageTransfer && !secureMessageTransfer?.supported) {
|
|
34
|
+
onClose();
|
|
35
|
+
}
|
|
36
|
+
}, [secureMessageTransfer, onClose]);
|
|
37
|
+
|
|
38
|
+
return isIssueOrInspection && isCheckingCAOSecureTranferSupport ? (
|
|
39
|
+
<Loading sx={styles.loading} />
|
|
40
|
+
) : (
|
|
41
|
+
<Popup
|
|
42
|
+
onClose={() => {}}
|
|
43
|
+
title=""
|
|
44
|
+
isOpen={isInterceptOnCreateOpen}
|
|
45
|
+
mainContainerStyles={styles.mainContainer}
|
|
46
|
+
disableCloseButton={true}
|
|
47
|
+
>
|
|
48
|
+
{isIssueOrInspection ? (
|
|
49
|
+
<SecureTransfer serviceId={serviceId} did={did} onClose={onClose} />
|
|
50
|
+
) : (
|
|
51
|
+
<SecureMessageURL did={did} onSave={() => onNext(true)} onSkip={() => onNext(true)} />
|
|
52
|
+
)}
|
|
53
|
+
</Popup>
|
|
54
|
+
);
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const styles = {
|
|
58
|
+
mainContainer: { pt: 2 },
|
|
59
|
+
loading: { pt: '60px' },
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
// eslint-disable-next-line better-mutation/no-mutation
|
|
63
|
+
SecureIntegrationPopup.propTypes = {
|
|
64
|
+
isInterceptOnCreateOpen: PropTypes.bool.isRequired,
|
|
65
|
+
serviceId: PropTypes.string.isRequired,
|
|
66
|
+
onNext: PropTypes.func.isRequired,
|
|
67
|
+
onClose: PropTypes.func.isRequired,
|
|
68
|
+
isIssueOrInspection: PropTypes.bool.isRequired,
|
|
69
|
+
selectedCAO: PropTypes.string,
|
|
70
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { useFormContext } from 'react-hook-form';
|
|
3
|
+
import PropTypes from 'prop-types';
|
|
4
|
+
import { Save } from '@velocitycareerlabs/components-organizations-registrar/components/common';
|
|
5
|
+
|
|
6
|
+
const SaveButtonComponent = ({ saveInProgress, disabled }) => {
|
|
7
|
+
const {
|
|
8
|
+
formState: { errors },
|
|
9
|
+
} = useFormContext();
|
|
10
|
+
|
|
11
|
+
const hasValidationError = Boolean(errors?.secureMessagesUrl);
|
|
12
|
+
const isDisabled = saveInProgress || hasValidationError || disabled;
|
|
13
|
+
|
|
14
|
+
return <Save saveInProgress={saveInProgress} isDisabled={isDisabled} />;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
// eslint-disable-next-line better-mutation/no-mutation
|
|
18
|
+
SaveButtonComponent.propTypes = {
|
|
19
|
+
saveInProgress: PropTypes.bool.isRequired,
|
|
20
|
+
disabled: PropTypes.bool.isRequired,
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export const SaveButton = React.memo(SaveButtonComponent);
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { useFormContext } from 'react-hook-form';
|
|
3
|
+
import { Button } from '@mui/material';
|
|
4
|
+
import { Loading } from '@velocitycareerlabs/components-organizations-registrar/components';
|
|
5
|
+
import PropTypes from 'prop-types';
|
|
6
|
+
|
|
7
|
+
const TestButtonComponent = ({ onTest, testInProgress }) => {
|
|
8
|
+
const {
|
|
9
|
+
watch,
|
|
10
|
+
formState: { errors },
|
|
11
|
+
} = useFormContext();
|
|
12
|
+
const secureMessagesUrl = watch('secureMessagesUrl');
|
|
13
|
+
const hasValidationError = Boolean(errors?.secureMessagesUrl);
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<Button
|
|
17
|
+
variant="outlined"
|
|
18
|
+
sx={styles.testButton}
|
|
19
|
+
onClick={() => onTest(secureMessagesUrl)}
|
|
20
|
+
endIcon={testInProgress ? <Loading color="error" sx={styles.loader} size={26} /> : null}
|
|
21
|
+
disabled={testInProgress || !secureMessagesUrl || hasValidationError}
|
|
22
|
+
>
|
|
23
|
+
TEST
|
|
24
|
+
</Button>
|
|
25
|
+
);
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const styles = {
|
|
29
|
+
button: { px: 4, py: 1, fontSize: '16px', width: '160px', fontWeight: '600' },
|
|
30
|
+
testButton: {
|
|
31
|
+
borderColor: 'primary.main',
|
|
32
|
+
color: 'text.main',
|
|
33
|
+
padding: '12.5px',
|
|
34
|
+
fontWeight: '600',
|
|
35
|
+
fontSize: '16px',
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
// eslint-disable-next-line better-mutation/no-mutation
|
|
39
|
+
TestButtonComponent.propTypes = {
|
|
40
|
+
onTest: PropTypes.func.isRequired,
|
|
41
|
+
testInProgress: PropTypes.bool.isRequired,
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export const TestButton = React.memo(TestButtonComponent);
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Box, Typography, Button, useTheme } from '@mui/material';
|
|
3
|
+
import InfoIcon from '@mui/icons-material/Info';
|
|
4
|
+
import { Popup } from '@velocitycareerlabs/components-organizations-registrar/components/common';
|
|
5
|
+
import PropTypes from 'prop-types';
|
|
6
|
+
|
|
7
|
+
const TestSecureMessageWarningComponent = ({ isModalOpened, onClose, onContinue }) => {
|
|
8
|
+
const theme = useTheme();
|
|
9
|
+
|
|
10
|
+
return (
|
|
11
|
+
<Popup
|
|
12
|
+
onClose={onClose}
|
|
13
|
+
title=""
|
|
14
|
+
isOpen={isModalOpened}
|
|
15
|
+
mainContainerStyles={styles.mainContainer}
|
|
16
|
+
isBackBoxVisible
|
|
17
|
+
backBoxColor={theme.palette.warning.main}
|
|
18
|
+
>
|
|
19
|
+
<InfoIcon color="warning" sx={styles.icon} />
|
|
20
|
+
<Typography sx={styles.title}>Secure message URL should be tested before saving</Typography>
|
|
21
|
+
<Typography textAlign="center">
|
|
22
|
+
They will not be available again and are critical for managing your organization data.
|
|
23
|
+
</Typography>
|
|
24
|
+
<Box sx={styles.buttonBlock}>
|
|
25
|
+
<Button variant="outlined" sx={styles.button} onClick={onClose}>
|
|
26
|
+
BACK TO TEST
|
|
27
|
+
</Button>
|
|
28
|
+
<Button variant="text" sx={[styles.button, styles.continueButton]} onClick={onContinue}>
|
|
29
|
+
CONTINUE ANYWAY
|
|
30
|
+
</Button>
|
|
31
|
+
</Box>
|
|
32
|
+
</Popup>
|
|
33
|
+
);
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const styles = {
|
|
37
|
+
mainContainer: {
|
|
38
|
+
display: 'flex',
|
|
39
|
+
flexDirection: 'column',
|
|
40
|
+
alignItems: 'center',
|
|
41
|
+
pt: '19px',
|
|
42
|
+
maxWidth: '620px',
|
|
43
|
+
},
|
|
44
|
+
title: {
|
|
45
|
+
fontWeight: 600,
|
|
46
|
+
fontSize: '32px',
|
|
47
|
+
lineHeight: '39px',
|
|
48
|
+
textAlign: 'center',
|
|
49
|
+
mb: '32px',
|
|
50
|
+
mt: '35px',
|
|
51
|
+
},
|
|
52
|
+
button: { px: 4, py: 1, fontSize: '16px' },
|
|
53
|
+
continueButton: {
|
|
54
|
+
color: 'text.disabled',
|
|
55
|
+
},
|
|
56
|
+
buttonBlock: {
|
|
57
|
+
marginTop: '52px',
|
|
58
|
+
display: 'flex',
|
|
59
|
+
flexDirection: 'column',
|
|
60
|
+
gap: '10px',
|
|
61
|
+
},
|
|
62
|
+
icon: { width: '50px', height: '50px' },
|
|
63
|
+
loader: { pl: '10px' },
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
// eslint-disable-next-line better-mutation/no-mutation
|
|
67
|
+
TestSecureMessageWarningComponent.propTypes = {
|
|
68
|
+
isModalOpened: PropTypes.bool.isRequired,
|
|
69
|
+
onClose: PropTypes.func.isRequired,
|
|
70
|
+
onContinue: PropTypes.func.isRequired,
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export const TestSecureMessageWarning = React.memo(TestSecureMessageWarningComponent);
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import React, { useEffect, useRef } from 'react';
|
|
2
|
+
import { useFormContext } from 'react-hook-form';
|
|
3
|
+
import PropTypes from 'prop-types';
|
|
4
|
+
|
|
5
|
+
const TrackTestStatusComponent = ({ tested, reset }) => {
|
|
6
|
+
const { watch } = useFormContext();
|
|
7
|
+
const secureMessagesUrl = watch('secureMessagesUrl');
|
|
8
|
+
const prevUrlRef = useRef(secureMessagesUrl);
|
|
9
|
+
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
if (tested && secureMessagesUrl !== prevUrlRef.current) {
|
|
12
|
+
reset();
|
|
13
|
+
}
|
|
14
|
+
// eslint-disable-next-line better-mutation/no-mutation
|
|
15
|
+
prevUrlRef.current = secureMessagesUrl;
|
|
16
|
+
}, [secureMessagesUrl, tested, reset]);
|
|
17
|
+
|
|
18
|
+
return null;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
// eslint-disable-next-line better-mutation/no-mutation
|
|
22
|
+
TrackTestStatusComponent.propTypes = {
|
|
23
|
+
tested: PropTypes.bool,
|
|
24
|
+
reset: PropTypes.func.isRequired,
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export const TrackTestStatus = React.memo(TrackTestStatusComponent);
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import React, { useState, useCallback } from 'react';
|
|
2
|
+
import { Form, FormDataConsumer, TextInput } from 'react-admin';
|
|
3
|
+
import { Box, Button, Stack, Typography } from '@mui/material';
|
|
4
|
+
import CheckCircleIcon from '@mui/icons-material/CheckCircle';
|
|
5
|
+
import CancelIcon from '@mui/icons-material/Cancel';
|
|
6
|
+
import PropTypes from 'prop-types';
|
|
7
|
+
|
|
8
|
+
import { validateUrlOptional } from '../../utils/index.jsx';
|
|
9
|
+
import { useSecureMessageTest } from '../../hooks/useSecureMessageTest';
|
|
10
|
+
import { TestSecureMessageWarning } from './TestSecureMessageWarning/index.jsx';
|
|
11
|
+
import { SaveButton } from './SaveButton/index.jsx';
|
|
12
|
+
import { TestButton } from './TestButton/index.jsx';
|
|
13
|
+
import { TrackTestStatus } from './TrackTestStatus/index.jsx';
|
|
14
|
+
|
|
15
|
+
export const SecureMessageURL = ({ did, onSave: onSaveCallback, onSkip }) => {
|
|
16
|
+
const [isWarningModalOpen, setIsWarningModalOpen] = useState(false);
|
|
17
|
+
|
|
18
|
+
const { onTest, testPassed, testError, testInProgress, tested, reset, onSave, saveInProgress } =
|
|
19
|
+
useSecureMessageTest({
|
|
20
|
+
did,
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const handleSave = useCallback(
|
|
24
|
+
async (data) => {
|
|
25
|
+
const { secureMessagesUrl } = data;
|
|
26
|
+
if (secureMessagesUrl && !testPassed) {
|
|
27
|
+
setIsWarningModalOpen(true);
|
|
28
|
+
} else {
|
|
29
|
+
await onSave(secureMessagesUrl, onSaveCallback);
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
[testPassed, onSave, onSaveCallback],
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<>
|
|
37
|
+
<Typography sx={styles.title} mb={2}>
|
|
38
|
+
Set a Secure Messages URL
|
|
39
|
+
</Typography>
|
|
40
|
+
<Typography>
|
|
41
|
+
Ease your client's efforts by using a Secure Messages endpoint at which a Credential
|
|
42
|
+
Agent Operator. The Secure Messages endpoint is used to securely receive clients. Ensure
|
|
43
|
+
that the webhook is active and responding before setting this value otherwise the profile
|
|
44
|
+
cannot be saved.
|
|
45
|
+
</Typography>
|
|
46
|
+
<Form onSubmit={handleSave} mode="onChange" defaultValues={{ secureMessagesUrl: '' }}>
|
|
47
|
+
<TrackTestStatus tested={tested} reset={reset} />
|
|
48
|
+
<FormDataConsumer>
|
|
49
|
+
{({ formData }) => (
|
|
50
|
+
<Stack>
|
|
51
|
+
<Box sx={styles.fields}>
|
|
52
|
+
{testPassed && (
|
|
53
|
+
<Box sx={[styles.statusBlock, styles.successBlock]}>
|
|
54
|
+
<CheckCircleIcon sx={[styles.statusIcon, styles.iconSuccess]} />
|
|
55
|
+
<Typography>Secure message URL tested successfully!</Typography>
|
|
56
|
+
</Box>
|
|
57
|
+
)}
|
|
58
|
+
{testError && (
|
|
59
|
+
<Box sx={[styles.statusBlock, styles.errorBlock]}>
|
|
60
|
+
<CancelIcon sx={[styles.statusIcon, styles.iconError]} />
|
|
61
|
+
<Typography>Failed to test the secure message URL.</Typography>
|
|
62
|
+
</Box>
|
|
63
|
+
)}
|
|
64
|
+
<TextInput
|
|
65
|
+
source="secureMessagesUrl"
|
|
66
|
+
label="Secure message URL"
|
|
67
|
+
validate={[...validateUrlOptional]}
|
|
68
|
+
parse={(value) => value?.trim() ?? ''}
|
|
69
|
+
/>
|
|
70
|
+
<TestButton onTest={onTest} testInProgress={testInProgress} />
|
|
71
|
+
</Box>
|
|
72
|
+
|
|
73
|
+
<Box sx={styles.buttonBlock}>
|
|
74
|
+
<Button
|
|
75
|
+
variant="outlined"
|
|
76
|
+
sx={[styles.button, styles.secondaryButton]}
|
|
77
|
+
onClick={onSkip}
|
|
78
|
+
>
|
|
79
|
+
Skip
|
|
80
|
+
</Button>
|
|
81
|
+
<SaveButton
|
|
82
|
+
saveInProgress={saveInProgress || testInProgress}
|
|
83
|
+
disabled={testError}
|
|
84
|
+
/>
|
|
85
|
+
</Box>
|
|
86
|
+
<TestSecureMessageWarning
|
|
87
|
+
isModalOpened={isWarningModalOpen}
|
|
88
|
+
onClose={() => setIsWarningModalOpen(false)}
|
|
89
|
+
onContinue={() => {
|
|
90
|
+
onSave(formData.secureMessagesUrl, onSaveCallback);
|
|
91
|
+
}}
|
|
92
|
+
/>
|
|
93
|
+
</Stack>
|
|
94
|
+
)}
|
|
95
|
+
</FormDataConsumer>
|
|
96
|
+
</Form>
|
|
97
|
+
</>
|
|
98
|
+
);
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
const styles = {
|
|
102
|
+
step: { color: (theme) => theme.palette.primary.main, pb: '20px', display: 'block' },
|
|
103
|
+
title: {
|
|
104
|
+
fontSize: '32px',
|
|
105
|
+
fontWeight: '600',
|
|
106
|
+
lineHeight: '38px',
|
|
107
|
+
},
|
|
108
|
+
statusBlock: {
|
|
109
|
+
display: 'flex',
|
|
110
|
+
gap: '20px',
|
|
111
|
+
alignItems: 'center',
|
|
112
|
+
padding: '11px 15px',
|
|
113
|
+
borderRadius: '4px',
|
|
114
|
+
border: '1px solid',
|
|
115
|
+
marginBottom: '32px',
|
|
116
|
+
},
|
|
117
|
+
successBlock: {
|
|
118
|
+
backgroundColor: 'success.light',
|
|
119
|
+
borderColor: 'success.main',
|
|
120
|
+
},
|
|
121
|
+
errorBlock: {
|
|
122
|
+
backgroundColor: 'error.light',
|
|
123
|
+
borderColor: 'primary.main',
|
|
124
|
+
},
|
|
125
|
+
statusIcon: {
|
|
126
|
+
fontSize: '32px',
|
|
127
|
+
padding: '2.5px',
|
|
128
|
+
},
|
|
129
|
+
iconSuccess: {
|
|
130
|
+
color: 'success.main',
|
|
131
|
+
},
|
|
132
|
+
iconError: {
|
|
133
|
+
color: 'error.main',
|
|
134
|
+
},
|
|
135
|
+
fields: {
|
|
136
|
+
padding: '32px 0 40px',
|
|
137
|
+
display: 'flex',
|
|
138
|
+
flexDirection: 'column',
|
|
139
|
+
gap: '0px',
|
|
140
|
+
},
|
|
141
|
+
buttonBlock: {
|
|
142
|
+
display: 'flex',
|
|
143
|
+
justifyContent: 'center',
|
|
144
|
+
gap: '24px',
|
|
145
|
+
},
|
|
146
|
+
button: { px: 4, py: 1, fontSize: '16px', width: '160px', fontWeight: '600' },
|
|
147
|
+
secondaryButton: {
|
|
148
|
+
borderColor: 'secondary.light',
|
|
149
|
+
color: 'text.primary',
|
|
150
|
+
},
|
|
151
|
+
};
|
|
152
|
+
// eslint-disable-next-line better-mutation/no-mutation
|
|
153
|
+
SecureMessageURL.propTypes = {
|
|
154
|
+
did: PropTypes.string.isRequired,
|
|
155
|
+
onSave: PropTypes.func.isRequired,
|
|
156
|
+
onSkip: PropTypes.func.isRequired,
|
|
157
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Typography, Link } from '@mui/material';
|
|
3
|
+
|
|
4
|
+
const ConsentLabelComponent = () => (
|
|
5
|
+
<Typography>
|
|
6
|
+
Confirm that you consent to the secure transfer of your keys to your Credential Agent Operator.{' '}
|
|
7
|
+
<Link href="./" target="_blank">
|
|
8
|
+
Click here for more information
|
|
9
|
+
</Link>
|
|
10
|
+
</Typography>
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
export const ConsentLabel = React.memo(ConsentLabelComponent);
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
3
|
+
import { useFormContext } from 'react-hook-form';
|
|
4
|
+
import PropTypes from 'prop-types';
|
|
5
|
+
import { Save } from '@velocitycareerlabs/components-organizations-registrar/components/common';
|
|
6
|
+
|
|
7
|
+
export const SaveButton = ({ saveInProgress }) => {
|
|
8
|
+
const {
|
|
9
|
+
formState: { errors },
|
|
10
|
+
watch,
|
|
11
|
+
} = useFormContext();
|
|
12
|
+
const consent = watch('consent');
|
|
13
|
+
const hasValidationError = Boolean(Object.keys(errors).length);
|
|
14
|
+
const isDisabled = saveInProgress || hasValidationError || !consent;
|
|
15
|
+
return <Save saveInProgress={saveInProgress} isDisabled={isDisabled} label="Confirm" />;
|
|
16
|
+
};
|
|
17
|
+
// eslint-disable-next-line better-mutation/no-mutation
|
|
18
|
+
SaveButton.propTypes = {
|
|
19
|
+
saveInProgress: PropTypes.bool.isRequired,
|
|
20
|
+
};
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import { useCreate, Form, useNotify } from 'react-admin';
|
|
3
|
+
import { Box, Button, Stack, Typography } from '@mui/material';
|
|
4
|
+
import { CustomBooleanInput } from '@velocitycareerlabs/components-organizations-registrar/components/common';
|
|
5
|
+
import PropTypes from 'prop-types';
|
|
6
|
+
import { dataResources } from '../../../../utils/remoteDataProvider';
|
|
7
|
+
import { SaveButton } from './SaveButton/index.jsx';
|
|
8
|
+
import { ConsentLabel } from './ConsentLabel/index.jsx';
|
|
9
|
+
|
|
10
|
+
const MESSAGE_CODES = {
|
|
11
|
+
keys_sent: 'keys_sent',
|
|
12
|
+
keys_not_sent: 'keys_not_sent',
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export const SecureTransfer = ({ did, serviceId, onClose }) => {
|
|
16
|
+
const [transferKeys] = useCreate();
|
|
17
|
+
const notify = useNotify();
|
|
18
|
+
|
|
19
|
+
const [saveInProgress, setSaveInProgress] = useState(false);
|
|
20
|
+
|
|
21
|
+
const onTransfer = async () => {
|
|
22
|
+
setSaveInProgress(true);
|
|
23
|
+
try {
|
|
24
|
+
const result = await transferKeys(
|
|
25
|
+
dataResources.SECURE_MESSAGE_TRANSFER,
|
|
26
|
+
{
|
|
27
|
+
data: { serviceIds: [serviceId] },
|
|
28
|
+
meta: { organizationId: did },
|
|
29
|
+
},
|
|
30
|
+
{ returnPromise: true },
|
|
31
|
+
);
|
|
32
|
+
if (result.messageCode === MESSAGE_CODES.keys_sent) {
|
|
33
|
+
notify('Succeded', { type: 'success' }, { autoHideDuration: 500 });
|
|
34
|
+
onClose(true);
|
|
35
|
+
} else {
|
|
36
|
+
notify('Error transferring keys', { type: 'warning' }, { autoHideDuration: 500 });
|
|
37
|
+
}
|
|
38
|
+
} catch (error) {
|
|
39
|
+
notify('Error transferring keys', { type: 'warning' }, { autoHideDuration: 500 });
|
|
40
|
+
} finally {
|
|
41
|
+
setSaveInProgress(false);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<>
|
|
47
|
+
<Typography sx={styles.title} mb={2}>
|
|
48
|
+
Automatically setup your network integration
|
|
49
|
+
</Typography>
|
|
50
|
+
<Typography>This Credential Agent Operator supports the secure transfer of keys.</Typography>
|
|
51
|
+
<Form onSubmit={onTransfer} mode="onChange" defaultValues={{ secureMessagesUrl: '' }}>
|
|
52
|
+
<Stack>
|
|
53
|
+
<Box sx={styles.fields}>
|
|
54
|
+
<CustomBooleanInput source="consent" label={<ConsentLabel />} defaultValue={false} />
|
|
55
|
+
</Box>
|
|
56
|
+
<Box sx={styles.buttonBlock}>
|
|
57
|
+
<Button variant="outlined" sx={[styles.button, styles.backButton]} onClick={onClose}>
|
|
58
|
+
Skip
|
|
59
|
+
</Button>
|
|
60
|
+
<SaveButton saveInProgress={saveInProgress} />
|
|
61
|
+
</Box>
|
|
62
|
+
</Stack>
|
|
63
|
+
</Form>
|
|
64
|
+
</>
|
|
65
|
+
);
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const styles = {
|
|
69
|
+
step: { color: (theme) => theme.palette.primary.main, pb: '20px', display: 'block' },
|
|
70
|
+
title: {
|
|
71
|
+
fontSize: '32px',
|
|
72
|
+
fontWeight: '600',
|
|
73
|
+
lineHeight: '38px',
|
|
74
|
+
},
|
|
75
|
+
fields: {
|
|
76
|
+
padding: '32px 0 40px',
|
|
77
|
+
display: 'flex',
|
|
78
|
+
flexDirection: 'column',
|
|
79
|
+
gap: '0px',
|
|
80
|
+
},
|
|
81
|
+
buttonBlock: {
|
|
82
|
+
display: 'flex',
|
|
83
|
+
justifyContent: 'center',
|
|
84
|
+
gap: '24px',
|
|
85
|
+
},
|
|
86
|
+
button: { px: 4, py: 1, fontSize: '16px', width: '160px', fontWeight: '600' },
|
|
87
|
+
backButton: {
|
|
88
|
+
borderColor: 'secondary.light',
|
|
89
|
+
color: 'text.primary',
|
|
90
|
+
},
|
|
91
|
+
skipButton: {
|
|
92
|
+
color: 'text.disabled',
|
|
93
|
+
marginTop: '16px',
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
// eslint-disable-next-line better-mutation/no-mutation
|
|
98
|
+
SecureTransfer.propTypes = {
|
|
99
|
+
did: PropTypes.string.isRequired,
|
|
100
|
+
serviceId: PropTypes.string.isRequired,
|
|
101
|
+
onClose: PropTypes.func.isRequired,
|
|
102
|
+
};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { useState, useCallback } from 'react';
|
|
2
|
+
import { useCreate } from 'react-admin';
|
|
3
|
+
import { dataResources } from '../../../utils/remoteDataProvider';
|
|
4
|
+
|
|
5
|
+
export const useSecureMessageTest = ({ did }) => {
|
|
6
|
+
const [testSecureMessage] = useCreate();
|
|
7
|
+
const [testPassed, setTestPassed] = useState(false);
|
|
8
|
+
const [testError, setTestError] = useState(null);
|
|
9
|
+
const [testInProgress, setTestInProgress] = useState(false);
|
|
10
|
+
const [tested, setTested] = useState(false);
|
|
11
|
+
|
|
12
|
+
const [saveInProgress, setSaveInProgress] = useState(false);
|
|
13
|
+
|
|
14
|
+
const reset = useCallback(() => {
|
|
15
|
+
setTestPassed(false);
|
|
16
|
+
setTestError(null);
|
|
17
|
+
setTested(false);
|
|
18
|
+
}, []);
|
|
19
|
+
|
|
20
|
+
const onTest = useCallback(
|
|
21
|
+
async (secureMessagesUrl) => {
|
|
22
|
+
setTestInProgress(true);
|
|
23
|
+
setTestPassed(false);
|
|
24
|
+
setTestError(null);
|
|
25
|
+
try {
|
|
26
|
+
const result = await testSecureMessage(
|
|
27
|
+
dataResources.SECURE_MESSAGE_TEST,
|
|
28
|
+
{
|
|
29
|
+
data: { secureMessagesUrl },
|
|
30
|
+
meta: { organizationId: did },
|
|
31
|
+
},
|
|
32
|
+
{ returnPromise: true },
|
|
33
|
+
);
|
|
34
|
+
if (result.status === 204) {
|
|
35
|
+
setTestPassed(true);
|
|
36
|
+
} else {
|
|
37
|
+
setTestError(true);
|
|
38
|
+
}
|
|
39
|
+
} catch (error) {
|
|
40
|
+
setTestError(error);
|
|
41
|
+
} finally {
|
|
42
|
+
setTestInProgress(false);
|
|
43
|
+
setTested(true);
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
[did, testSecureMessage],
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
const onSave = useCallback(
|
|
50
|
+
async (secureMessagesUrl, callback) => {
|
|
51
|
+
setSaveInProgress(true);
|
|
52
|
+
try {
|
|
53
|
+
const result = await testSecureMessage(
|
|
54
|
+
dataResources.SECURE_MESSAGE_SAVE,
|
|
55
|
+
{
|
|
56
|
+
data: { secureMessagesUrl },
|
|
57
|
+
meta: { organizationId: did },
|
|
58
|
+
},
|
|
59
|
+
{ returnPromise: true },
|
|
60
|
+
);
|
|
61
|
+
if (result.status !== 204) {
|
|
62
|
+
throw new Error('Error testing secure message URL');
|
|
63
|
+
}
|
|
64
|
+
if (callback) {
|
|
65
|
+
callback(result);
|
|
66
|
+
}
|
|
67
|
+
} catch (error) {
|
|
68
|
+
setTestError(error);
|
|
69
|
+
} finally {
|
|
70
|
+
setSaveInProgress(false);
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
[did, testSecureMessage],
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
onTest,
|
|
78
|
+
testPassed,
|
|
79
|
+
testError,
|
|
80
|
+
testInProgress,
|
|
81
|
+
tested,
|
|
82
|
+
reset,
|
|
83
|
+
onSave,
|
|
84
|
+
saveInProgress,
|
|
85
|
+
};
|
|
86
|
+
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { maxLength } from 'react-admin';
|
|
2
|
+
|
|
3
|
+
export const REGEXP_VALID_URL = new RegExp(
|
|
4
|
+
'^' +
|
|
5
|
+
// protocol
|
|
6
|
+
'((https?):\\/\\/)' +
|
|
7
|
+
// authentication
|
|
8
|
+
'((([a-z\\d]([a-z\\d-]*[a-z\\d])*)@)?' +
|
|
9
|
+
// hostname or IP
|
|
10
|
+
'((\\d{1,3}\\.){3}\\d{1,3}' + // IPv4
|
|
11
|
+
'|(([a-z\\d]([a-z\\d-]*[a-z\\d])*\\.)+[a-z]{2,}))' +
|
|
12
|
+
// optional port
|
|
13
|
+
'(\\:\\d+)?' +
|
|
14
|
+
// path
|
|
15
|
+
'(\\/[-a-z\\d%_.~+]*)*' +
|
|
16
|
+
// query string
|
|
17
|
+
'(\\?[;&a-z\\d%_.~+=-]*)?' +
|
|
18
|
+
// fragment
|
|
19
|
+
'(\\#[-a-z\\d_]*)?' +
|
|
20
|
+
')$',
|
|
21
|
+
'i',
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
export const REGEXP_HTTPS_URL = new RegExp(
|
|
25
|
+
'^https:\\/\\/' +
|
|
26
|
+
'((([a-z\\d]([a-z\\d-]*[a-z\\d])*)@)?' +
|
|
27
|
+
'((\\d{1,3}\\.){3}\\d{1,3}' + // IPv4
|
|
28
|
+
'|(([a-z\\d]([a-z\\d-]*[a-z\\d])*\\.)+[a-z]{2,}))' +
|
|
29
|
+
'(\\:\\d+)?' +
|
|
30
|
+
'(\\/[-a-z\\d%_.~+]*)*' +
|
|
31
|
+
'(\\?[;&a-z\\d%_.~+=-]*)?' +
|
|
32
|
+
'(\\#[-a-z\\d_]*)?)$',
|
|
33
|
+
'i',
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
const optionalUrlValidation = (value) => {
|
|
37
|
+
if (!value) {
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
if (!REGEXP_VALID_URL.test(value.trim())) {
|
|
41
|
+
return 'Please type in a valid URL';
|
|
42
|
+
}
|
|
43
|
+
if (!REGEXP_HTTPS_URL.test(value.trim())) {
|
|
44
|
+
return 'Https is required';
|
|
45
|
+
}
|
|
46
|
+
return undefined;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export const validateUrlOptional = [optionalUrlValidation, maxLength(1024)];
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
export const dataResources = {
|
|
2
|
+
SECURE_MESSAGE_TEST: 'test-url',
|
|
3
|
+
SECURE_MESSAGE_SAVE: 'set-url',
|
|
4
|
+
SECURE_MESSAGE_SUPPORTED: 'are-supported',
|
|
5
|
+
SECURE_MESSAGE_TRANSFER: 'transfer-keys',
|
|
6
|
+
};
|
|
7
|
+
export const extendedRemoteDataProvider = () => {
|
|
8
|
+
return (client, apiUrl, baseDataProvider, dataResourcesBase) => ({
|
|
9
|
+
getOne: (resource, params) => {
|
|
10
|
+
switch (resource) {
|
|
11
|
+
case dataResources.SECURE_MESSAGE_SUPPORTED: {
|
|
12
|
+
return client(
|
|
13
|
+
`${apiUrl}/${dataResourcesBase.ORGANIZATIONS}/${params.id}/secure-cao-messages/${resource}`,
|
|
14
|
+
).then(({ json }) => {
|
|
15
|
+
return {
|
|
16
|
+
data: { ...json, id: new Date().getTime() },
|
|
17
|
+
};
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
default: {
|
|
21
|
+
return baseDataProvider.getOne(resource, params);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
create: (resource, params) => {
|
|
26
|
+
switch (resource) {
|
|
27
|
+
case dataResources.SECURE_MESSAGE_TEST: {
|
|
28
|
+
const url = `${apiUrl}/${dataResourcesBase.ORGANIZATIONS}/${params.meta.organizationId}/secure-cao-messages/${resource}`;
|
|
29
|
+
return client(url, {
|
|
30
|
+
method: 'POST',
|
|
31
|
+
body: JSON.stringify(params.data),
|
|
32
|
+
}).then((res) => ({ data: { ...res, status: res.status, id: Date.now() } }));
|
|
33
|
+
}
|
|
34
|
+
case dataResources.SECURE_MESSAGE_SAVE: {
|
|
35
|
+
const url = `${apiUrl}/${dataResourcesBase.ORGANIZATIONS}/${params.meta.organizationId}/secure-cao-messages/${resource}`;
|
|
36
|
+
return client(url, {
|
|
37
|
+
method: 'POST',
|
|
38
|
+
body: JSON.stringify(params.data),
|
|
39
|
+
}).then((res) => ({ data: { ...res, status: res.status, id: Date.now() } }));
|
|
40
|
+
}
|
|
41
|
+
case dataResources.SECURE_MESSAGE_TRANSFER: {
|
|
42
|
+
const url = `${apiUrl}/${dataResourcesBase.ORGANIZATIONS}/${params.meta.organizationId}/secure-cao-messages/${resource}`;
|
|
43
|
+
return client(url, {
|
|
44
|
+
method: 'POST',
|
|
45
|
+
body: JSON.stringify(params.data),
|
|
46
|
+
}).then(({ json }) => ({ data: { ...json, id: Date.now() } }));
|
|
47
|
+
}
|
|
48
|
+
default: {
|
|
49
|
+
return baseDataProvider.create(resource, params);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
};
|