@automattic/jetpack-connection 0.29.8
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/.gitattributes +12 -0
- package/CHANGELOG.md +622 -0
- package/LICENSE.txt +357 -0
- package/README.md +284 -0
- package/SECURITY.md +38 -0
- package/components/connect-button/index.jsx +70 -0
- package/components/connect-screen/basic/index.jsx +104 -0
- package/components/connect-screen/basic/style.scss +46 -0
- package/components/connect-screen/basic/visual.jsx +109 -0
- package/components/connect-screen/layout/image-slider.jsx +37 -0
- package/components/connect-screen/layout/index.jsx +65 -0
- package/components/connect-screen/layout/style.scss +238 -0
- package/components/connect-screen/required-plan/index.jsx +127 -0
- package/components/connect-screen/required-plan/style.scss +109 -0
- package/components/connect-screen/required-plan/visual.jsx +151 -0
- package/components/connect-user/index.jsx +64 -0
- package/components/connected-plugins/index.jsx +67 -0
- package/components/connection-error-notice/index.jsx +110 -0
- package/components/connection-error-notice/styles.module.scss +97 -0
- package/components/disconnect-card/index.jsx +40 -0
- package/components/disconnect-card/style.scss +85 -0
- package/components/disconnect-dialog/images/disconnect-confirm.jpg +0 -0
- package/components/disconnect-dialog/images/disconnect-thanks.jpg +0 -0
- package/components/disconnect-dialog/index.jsx +409 -0
- package/components/disconnect-dialog/steps/step-disconnect-confirm.jsx +87 -0
- package/components/disconnect-dialog/steps/step-disconnect.jsx +206 -0
- package/components/disconnect-dialog/steps/step-survey.jsx +48 -0
- package/components/disconnect-dialog/steps/step-thank-you.jsx +54 -0
- package/components/disconnect-dialog/style.scss +218 -0
- package/components/disconnect-survey/_jp-connect_disconnect-survey-card.scss +60 -0
- package/components/disconnect-survey/index.jsx +181 -0
- package/components/disconnect-survey/survey-choice.jsx +43 -0
- package/components/in-place-connection/index.jsx +140 -0
- package/components/in-place-connection/style.scss +35 -0
- package/components/manage-connection-dialog/index.jsx +219 -0
- package/components/manage-connection-dialog/style.scss +106 -0
- package/components/use-connection/index.jsx +112 -0
- package/helpers/third-party-cookies-fallback.jsx +10 -0
- package/hooks/use-connection-error-notice/index.jsx +38 -0
- package/hooks/use-product-checkout-workflow/Readme.md +61 -0
- package/hooks/use-product-checkout-workflow/index.jsx +103 -0
- package/hooks/use-restore-connection/index.jsx +64 -0
- package/index.jsx +48 -0
- package/index.native.js +1 -0
- package/package.json +62 -0
- package/state/actions.jsx +166 -0
- package/state/controls.jsx +40 -0
- package/state/reducers.jsx +121 -0
- package/state/resolvers.jsx +32 -0
- package/state/selectors.jsx +35 -0
- package/state/store-holder.jsx +14 -0
- package/state/store-id.jsx +3 -0
- package/state/store.jsx +29 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
@import '@automattic/jetpack-base-styles/style';
|
|
2
|
+
|
|
3
|
+
.jp-connection__manage-dialog {
|
|
4
|
+
--spacing-base: 8px;
|
|
5
|
+
margin: auto;
|
|
6
|
+
width: 1200px;
|
|
7
|
+
border-radius: 3px;
|
|
8
|
+
|
|
9
|
+
&__content{
|
|
10
|
+
background: var( --jp-white-off );
|
|
11
|
+
padding: 80px;
|
|
12
|
+
text-align: center;
|
|
13
|
+
display: flex;
|
|
14
|
+
flex-direction: column;
|
|
15
|
+
justify-content: center;
|
|
16
|
+
align-items: center;
|
|
17
|
+
|
|
18
|
+
h1 {
|
|
19
|
+
margin: 0;
|
|
20
|
+
font-size: var( --font-title-large );
|
|
21
|
+
font-weight: bold;
|
|
22
|
+
line-height: 1.2;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
&__large-text {
|
|
27
|
+
margin-top: calc( var( --spacing-base ) * 3 );
|
|
28
|
+
margin-bottom: calc( var( --spacing-base ) * 4 );
|
|
29
|
+
max-width: 60%;
|
|
30
|
+
font-weight: 600;
|
|
31
|
+
font-size: 1.25rem;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
&__actions{
|
|
35
|
+
background: var( --jp-white );
|
|
36
|
+
margin:0px !important;
|
|
37
|
+
border-top: 1px solid var( --jp-gray );
|
|
38
|
+
max-width: 1200px !important;
|
|
39
|
+
padding: calc( var( --spacing-base ) * 4 ) calc( var( --spacing-base ) * 5 );
|
|
40
|
+
align-items:center;
|
|
41
|
+
position: sticky;
|
|
42
|
+
bottom: 0;
|
|
43
|
+
box-sizing: border-box;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
&__link {
|
|
47
|
+
color: var( --jp-black );
|
|
48
|
+
|
|
49
|
+
&:hover {
|
|
50
|
+
color: var( --jp-black );
|
|
51
|
+
text-decoration-thickness: var( --jp-underline-thickness );
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
&:focus {
|
|
55
|
+
color: var( --jp-black );
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
&__button-wrap button{
|
|
60
|
+
float:right;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
&__action-card {
|
|
64
|
+
background-color: var( --jp-white );
|
|
65
|
+
width: 750px;
|
|
66
|
+
max-width: 100%;
|
|
67
|
+
padding: 1rem 2rem;
|
|
68
|
+
border-radius: 3px;
|
|
69
|
+
box-shadow: 0 0 15px var( --jp-gray-off );
|
|
70
|
+
margin: var( --spacing-base ) auto;
|
|
71
|
+
text-align: left;
|
|
72
|
+
border: none;
|
|
73
|
+
|
|
74
|
+
&__card-headline {
|
|
75
|
+
font-size: var( --font-body );
|
|
76
|
+
font-weight: 600;
|
|
77
|
+
text-decoration: none;
|
|
78
|
+
line-height: calc( var(--spacing-base) * 3 );
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
&__icon {
|
|
82
|
+
float:right;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.transfer {
|
|
86
|
+
color:var( --jp-black );
|
|
87
|
+
fill: var( --jp-black );
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.disconnect {
|
|
91
|
+
color: var( --jp-red );
|
|
92
|
+
fill: var( --jp-red );
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.components-modal {
|
|
97
|
+
&__header {
|
|
98
|
+
display: none;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
&__content {
|
|
102
|
+
margin: 0;
|
|
103
|
+
padding:0;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import restApi from '@automattic/jetpack-api';
|
|
2
|
+
import { useSelect, useDispatch } from '@wordpress/data';
|
|
3
|
+
import { useEffect } from 'react';
|
|
4
|
+
import { STORE_ID } from '../../state/store';
|
|
5
|
+
|
|
6
|
+
const initialState = window?.JP_CONNECTION_INITIAL_STATE ? window.JP_CONNECTION_INITIAL_STATE : {};
|
|
7
|
+
|
|
8
|
+
export default ( {
|
|
9
|
+
registrationNonce = initialState.registrationNonce,
|
|
10
|
+
apiRoot = initialState.apiRoot,
|
|
11
|
+
apiNonce = initialState.apiNonce,
|
|
12
|
+
redirectUri,
|
|
13
|
+
autoTrigger,
|
|
14
|
+
from,
|
|
15
|
+
skipUserConnection,
|
|
16
|
+
} = {} ) => {
|
|
17
|
+
const { registerSite, connectUser, refreshConnectedPlugins } = useDispatch( STORE_ID );
|
|
18
|
+
|
|
19
|
+
const registrationError = useSelect( select => select( STORE_ID ).getRegistrationError() );
|
|
20
|
+
const {
|
|
21
|
+
siteIsRegistering,
|
|
22
|
+
userIsConnecting,
|
|
23
|
+
userConnectionData,
|
|
24
|
+
connectedPlugins,
|
|
25
|
+
connectionErrors,
|
|
26
|
+
isRegistered,
|
|
27
|
+
isUserConnected,
|
|
28
|
+
hasConnectedOwner,
|
|
29
|
+
isOfflineMode,
|
|
30
|
+
} = useSelect( select => ( {
|
|
31
|
+
siteIsRegistering: select( STORE_ID ).getSiteIsRegistering(),
|
|
32
|
+
userIsConnecting: select( STORE_ID ).getUserIsConnecting(),
|
|
33
|
+
userConnectionData: select( STORE_ID ).getUserConnectionData(),
|
|
34
|
+
connectedPlugins: select( STORE_ID ).getConnectedPlugins(),
|
|
35
|
+
connectionErrors: select( STORE_ID ).getConnectionErrors(),
|
|
36
|
+
isOfflineMode: select( STORE_ID ).getIsOfflineMode(),
|
|
37
|
+
...select( STORE_ID ).getConnectionStatus(),
|
|
38
|
+
} ) );
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* User register process handler.
|
|
42
|
+
*
|
|
43
|
+
* @returns {Promise} - Promise which resolves when the product status is activated.
|
|
44
|
+
*/
|
|
45
|
+
const handleConnectUser = () => {
|
|
46
|
+
if ( ! skipUserConnection ) {
|
|
47
|
+
return connectUser( { from, redirectUri } );
|
|
48
|
+
} else if ( redirectUri ) {
|
|
49
|
+
window.location = redirectUri;
|
|
50
|
+
return Promise.resolve( redirectUri );
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return Promise.resolve();
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Site register process handler.
|
|
58
|
+
*
|
|
59
|
+
* It handles the process to register the site,
|
|
60
|
+
* considering also the user registration status.
|
|
61
|
+
* When they are registered, it will try to only register the site.
|
|
62
|
+
* Otherwise, will try to register the user right after
|
|
63
|
+
* the site was successfully registered.
|
|
64
|
+
*
|
|
65
|
+
* @param {Event} [e] - Event that dispatched handleRegisterSite
|
|
66
|
+
* @returns {Promise} Promise when running the registration process. Otherwise, nothing.
|
|
67
|
+
*/
|
|
68
|
+
const handleRegisterSite = e => {
|
|
69
|
+
e && e.preventDefault();
|
|
70
|
+
|
|
71
|
+
if ( isRegistered ) {
|
|
72
|
+
return handleConnectUser();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return registerSite( { registrationNonce, redirectUri } ).then( () => {
|
|
76
|
+
return handleConnectUser();
|
|
77
|
+
} );
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Initialize/Setup the REST API.
|
|
82
|
+
*/
|
|
83
|
+
useEffect( () => {
|
|
84
|
+
restApi.setApiRoot( apiRoot );
|
|
85
|
+
restApi.setApiNonce( apiNonce );
|
|
86
|
+
}, [ apiRoot, apiNonce ] );
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Auto-trigger the flow, only do it once.
|
|
90
|
+
*/
|
|
91
|
+
useEffect( () => {
|
|
92
|
+
if ( autoTrigger && ! siteIsRegistering && ! userIsConnecting ) {
|
|
93
|
+
handleRegisterSite();
|
|
94
|
+
}
|
|
95
|
+
}, [] ); // eslint-disable-line react-hooks/exhaustive-deps
|
|
96
|
+
|
|
97
|
+
return {
|
|
98
|
+
handleRegisterSite,
|
|
99
|
+
handleConnectUser,
|
|
100
|
+
refreshConnectedPlugins,
|
|
101
|
+
isRegistered,
|
|
102
|
+
isUserConnected,
|
|
103
|
+
siteIsRegistering,
|
|
104
|
+
userIsConnecting,
|
|
105
|
+
registrationError,
|
|
106
|
+
userConnectionData,
|
|
107
|
+
hasConnectedOwner,
|
|
108
|
+
connectedPlugins,
|
|
109
|
+
connectionErrors,
|
|
110
|
+
isOfflineMode,
|
|
111
|
+
};
|
|
112
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Performs the fallback redirect if third-party cookies are not available.
|
|
3
|
+
*
|
|
4
|
+
* @param {string} fallbackURL -- The fallback URL.
|
|
5
|
+
*/
|
|
6
|
+
const thirdPartyCookiesFallback = fallbackURL => {
|
|
7
|
+
window.location.replace( fallbackURL );
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export default thirdPartyCookiesFallback;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import ConnectionErrorNotice from '../../components/connection-error-notice';
|
|
2
|
+
import useConnection from '../../components/use-connection';
|
|
3
|
+
import useRestoreConnection from '../../hooks/use-restore-connection/index.jsx';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Connection error notice hook.
|
|
7
|
+
* Returns a ConnectionErrorNotice component and the conditional flag on whether
|
|
8
|
+
* to render the component or not.
|
|
9
|
+
*
|
|
10
|
+
* @returns {object} - The hook data.
|
|
11
|
+
*/
|
|
12
|
+
export default function useConnectionErrorNotice() {
|
|
13
|
+
const { connectionErrors } = useConnection( {} );
|
|
14
|
+
const connectionErrorList = Object.values( connectionErrors ).shift();
|
|
15
|
+
const connectionErrorMessage =
|
|
16
|
+
connectionErrorList &&
|
|
17
|
+
Object.values( connectionErrorList ).length &&
|
|
18
|
+
Object.values( connectionErrorList ).shift().error_message;
|
|
19
|
+
|
|
20
|
+
const hasConnectionError = Boolean( connectionErrorMessage );
|
|
21
|
+
|
|
22
|
+
return { hasConnectionError, connectionErrorMessage };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const ConnectionError = () => {
|
|
26
|
+
const { hasConnectionError, connectionErrorMessage } = useConnectionErrorNotice();
|
|
27
|
+
const { restoreConnection, isRestoringConnection, restoreConnectionError } =
|
|
28
|
+
useRestoreConnection();
|
|
29
|
+
|
|
30
|
+
return hasConnectionError ? (
|
|
31
|
+
<ConnectionErrorNotice
|
|
32
|
+
isRestoringConnection={ isRestoringConnection }
|
|
33
|
+
restoreConnectionError={ restoreConnectionError }
|
|
34
|
+
restoreConnectionCallback={ restoreConnection }
|
|
35
|
+
message={ connectionErrorMessage }
|
|
36
|
+
/>
|
|
37
|
+
) : null;
|
|
38
|
+
};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# useProductCheckoutWorkflow
|
|
2
|
+
|
|
3
|
+
Custom hook that performs the needed steps to concrete the checkout workflow.
|
|
4
|
+
For this, it'll try to regiter the site in case it's disconnected, and then it'll redirect to the Calypso checkout page.
|
|
5
|
+
The hook delegates the task to connect the user when it's disconnected, adding a `unlinked=1` to the checkout URL.
|
|
6
|
+
|
|
7
|
+
## API
|
|
8
|
+
|
|
9
|
+
### Arguments
|
|
10
|
+
The hook expects a `props` object argument with the following specs:
|
|
11
|
+
|
|
12
|
+
#### productSlug
|
|
13
|
+
this is the WordPress.com product slug.
|
|
14
|
+
#### redirectUrl
|
|
15
|
+
The URL to redirect to after checkout.
|
|
16
|
+
For instance, for security bundle it's usually defined with `jetpack_security_t1_yearly`.
|
|
17
|
+
#### siteSuffix (optional)
|
|
18
|
+
Site slug suffix to be used as part of Calypso URLs. As default, tt's defined by the [get_site_suffix()](../../../../packages/status/src/class-status.php#L327) backend helper.
|
|
19
|
+
|
|
20
|
+
And it returns also an object with the following keys:
|
|
21
|
+
|
|
22
|
+
#### run
|
|
23
|
+
helper function to run the checkout process. Usually, you'd like to asign this function as to an event callback.
|
|
24
|
+
|
|
25
|
+
```jsx
|
|
26
|
+
import { useProductCheckoutWorkflow } from '@automattic/jetpack-connection';
|
|
27
|
+
|
|
28
|
+
function MyComponent() {
|
|
29
|
+
const { run } = useProductCheckoutWorkflow( {
|
|
30
|
+
productSlug: 'jetpack_security_t1_yearly',
|
|
31
|
+
siteSuffix: 'poweredsite.wordpress.com'
|
|
32
|
+
redirectUrl: 'https://poweredsite.wordpress.com/wp-admin/admin.php?page=jetpack-protect',
|
|
33
|
+
} );
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<Button onClick={ run }>Add Security plan!</Button>
|
|
37
|
+
)
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
#### isRegisterd
|
|
42
|
+
determine if the site is registered, or not. It's shortcut to the [getSiteIsRegistering](../../state/selectors.jsx#L10) selector.
|
|
43
|
+
|
|
44
|
+
#### hasCheckoutStarted*
|
|
45
|
+
True right after the checkout process starts. Take advantage of this prop to deal with the delay that happens when the browser starts to redirect to the checkout page.
|
|
46
|
+
|
|
47
|
+
```jsx
|
|
48
|
+
import { useProductCheckoutWorkflow } from '@automattic/jetpack-connection';
|
|
49
|
+
|
|
50
|
+
function MyComponent() {
|
|
51
|
+
const { run, hasCheckoutStarted } = useProductCheckoutWorkflow( { ... } );
|
|
52
|
+
|
|
53
|
+
if ( hasCheckoutStarted ) {
|
|
54
|
+
return <div>Going to checkout page.</div>;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<Button onClick={ run }>Add Security plan!</Button>
|
|
59
|
+
)
|
|
60
|
+
}
|
|
61
|
+
```
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import restApi from '@automattic/jetpack-api';
|
|
2
|
+
import { getProductCheckoutUrl } from '@automattic/jetpack-components';
|
|
3
|
+
import { useDispatch } from '@wordpress/data';
|
|
4
|
+
import debugFactory from 'debug';
|
|
5
|
+
import { useEffect, useState } from 'react';
|
|
6
|
+
import useConnection from '../../components/use-connection';
|
|
7
|
+
import { STORE_ID } from '../../state/store.jsx';
|
|
8
|
+
|
|
9
|
+
const debug = debugFactory( 'jetpack:connection:useProductCheckoutWorkflow' );
|
|
10
|
+
|
|
11
|
+
const {
|
|
12
|
+
registrationNonce,
|
|
13
|
+
apiRoot,
|
|
14
|
+
apiNonce,
|
|
15
|
+
siteSuffix: defaultSiteSuffix,
|
|
16
|
+
} = window?.JP_CONNECTION_INITIAL_STATE ? window.JP_CONNECTION_INITIAL_STATE : {};
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Custom hook that performs the needed steps
|
|
20
|
+
* to concrete the checkout workflow.
|
|
21
|
+
*
|
|
22
|
+
* @param {object} props - The props passed to the hook.
|
|
23
|
+
* @param {string} props.productSlug - The WordPress product slug.
|
|
24
|
+
* @param {string} props.redirectUrl - The URI to redirect to after checkout.
|
|
25
|
+
* @param {string} [props.siteSuffix] - The site suffix.
|
|
26
|
+
* @param {Function} props.siteProductAvailabilityHandler - The function used to check whether the site already has the requested product. This will be checked after registration and the checkout page will be skipped if the promise returned resloves true.
|
|
27
|
+
* @param {Function} props.from - The plugin slug initiated the flow.
|
|
28
|
+
* @returns {Function} - The useEffect hook.
|
|
29
|
+
*/
|
|
30
|
+
export default function useProductCheckoutWorkflow( {
|
|
31
|
+
productSlug,
|
|
32
|
+
redirectUrl,
|
|
33
|
+
siteSuffix = defaultSiteSuffix,
|
|
34
|
+
siteProductAvailabilityHandler = null,
|
|
35
|
+
from,
|
|
36
|
+
} = {} ) {
|
|
37
|
+
debug( 'productSlug is %s', productSlug );
|
|
38
|
+
debug( 'redirectUrl is %s', redirectUrl );
|
|
39
|
+
debug( 'siteSuffix is %s', siteSuffix );
|
|
40
|
+
debug( 'from is %s', from );
|
|
41
|
+
const [ hasCheckoutStarted, setCheckoutStarted ] = useState( false );
|
|
42
|
+
const { registerSite } = useDispatch( STORE_ID );
|
|
43
|
+
|
|
44
|
+
const { isUserConnected, isRegistered, handleConnectUser } = useConnection( {
|
|
45
|
+
redirectUri: redirectUrl,
|
|
46
|
+
from,
|
|
47
|
+
} );
|
|
48
|
+
|
|
49
|
+
// Build the checkout URL.
|
|
50
|
+
const checkoutProductUrl = getProductCheckoutUrl(
|
|
51
|
+
productSlug,
|
|
52
|
+
siteSuffix,
|
|
53
|
+
redirectUrl,
|
|
54
|
+
isUserConnected
|
|
55
|
+
);
|
|
56
|
+
debug( 'checkoutProductUrl is %s', checkoutProductUrl );
|
|
57
|
+
debug( 'isUserConnected is %s', isUserConnected );
|
|
58
|
+
|
|
59
|
+
const handleAfterRegistration = () => {
|
|
60
|
+
return Promise.resolve(
|
|
61
|
+
siteProductAvailabilityHandler && siteProductAvailabilityHandler()
|
|
62
|
+
).then( siteHasWpcomProduct => {
|
|
63
|
+
if ( siteHasWpcomProduct ) {
|
|
64
|
+
debug( 'handleAfterRegistration: Site has a product associated' );
|
|
65
|
+
return handleConnectUser();
|
|
66
|
+
}
|
|
67
|
+
debug(
|
|
68
|
+
'handleAfterRegistration: Site does not have a product associated. Redirecting to checkout %s',
|
|
69
|
+
checkoutProductUrl
|
|
70
|
+
);
|
|
71
|
+
window.location.href = checkoutProductUrl;
|
|
72
|
+
} );
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Handler to run the checkout workflow.
|
|
77
|
+
*
|
|
78
|
+
* @param {Event} [event] - Event that dispatched run
|
|
79
|
+
* @returns {void} Nothing.
|
|
80
|
+
*/
|
|
81
|
+
const run = event => {
|
|
82
|
+
event && event.preventDefault();
|
|
83
|
+
setCheckoutStarted( true );
|
|
84
|
+
|
|
85
|
+
if ( isRegistered ) {
|
|
86
|
+
return handleAfterRegistration();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
registerSite( { registrationNonce, redirectUri: redirectUrl } ).then( handleAfterRegistration );
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
// Initialize/Setup the REST API.
|
|
93
|
+
useEffect( () => {
|
|
94
|
+
restApi.setApiRoot( apiRoot );
|
|
95
|
+
restApi.setApiNonce( apiNonce );
|
|
96
|
+
}, [] );
|
|
97
|
+
|
|
98
|
+
return {
|
|
99
|
+
run,
|
|
100
|
+
isRegistered,
|
|
101
|
+
hasCheckoutStarted,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import restApi from '@automattic/jetpack-api';
|
|
2
|
+
import { useDispatch } from '@wordpress/data';
|
|
3
|
+
import { useEffect, useState } from 'react';
|
|
4
|
+
import { STORE_ID } from '../../state/store';
|
|
5
|
+
|
|
6
|
+
const { apiRoot, apiNonce } = window?.JP_CONNECTION_INITIAL_STATE
|
|
7
|
+
? window.JP_CONNECTION_INITIAL_STATE
|
|
8
|
+
: {};
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Restore connection hook.
|
|
12
|
+
* It will initiate an API request attempting to restore the connection, or reconnect if it cannot be restored.
|
|
13
|
+
*
|
|
14
|
+
* @returns {object} - The hook data.
|
|
15
|
+
*/
|
|
16
|
+
export default function useRestoreConnection() {
|
|
17
|
+
const [ isRestoringConnection, setIsRestoringConnection ] = useState( false );
|
|
18
|
+
const [ restoreConnectionError, setRestoreConnectionError ] = useState( null );
|
|
19
|
+
|
|
20
|
+
const { disconnectUserSuccess, setConnectionErrors } = useDispatch( STORE_ID );
|
|
21
|
+
|
|
22
|
+
const USER_CONNECTION_URL = '/wp-admin/admin.php?page=my-jetpack#/connection';
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Initiate connection restore.
|
|
26
|
+
*
|
|
27
|
+
* @param {boolean} autoReconnectUser - If user connection needs to be reestablished, automatically initiate the flow.
|
|
28
|
+
* @returns {Promise<object>} - The API request promise.
|
|
29
|
+
*/
|
|
30
|
+
const restoreConnection = ( autoReconnectUser = true ) => {
|
|
31
|
+
setIsRestoringConnection( true );
|
|
32
|
+
setRestoreConnectionError( null );
|
|
33
|
+
|
|
34
|
+
return restApi
|
|
35
|
+
.reconnect()
|
|
36
|
+
.then( connectionStatusData => {
|
|
37
|
+
// status 'in_progress' means the user needs to re-connect their WP.com account.
|
|
38
|
+
if ( 'in_progress' === connectionStatusData.status ) {
|
|
39
|
+
disconnectUserSuccess();
|
|
40
|
+
setConnectionErrors( {} );
|
|
41
|
+
if ( autoReconnectUser ) {
|
|
42
|
+
window.location.href = USER_CONNECTION_URL;
|
|
43
|
+
}
|
|
44
|
+
} else {
|
|
45
|
+
window.location.reload();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return connectionStatusData;
|
|
49
|
+
} )
|
|
50
|
+
.catch( error => {
|
|
51
|
+
setRestoreConnectionError( error );
|
|
52
|
+
setIsRestoringConnection( false );
|
|
53
|
+
|
|
54
|
+
throw error;
|
|
55
|
+
} );
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
useEffect( () => {
|
|
59
|
+
restApi.setApiRoot( apiRoot );
|
|
60
|
+
restApi.setApiNonce( apiNonce );
|
|
61
|
+
}, [] );
|
|
62
|
+
|
|
63
|
+
return { restoreConnection, isRestoringConnection, restoreConnectionError };
|
|
64
|
+
}
|
package/index.jsx
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/*
|
|
2
|
+
This program is free software; you can redistribute it and/or
|
|
3
|
+
modify it under the terms of the GNU General Public License
|
|
4
|
+
as published by the Free Software Foundation; either version 2
|
|
5
|
+
of the License, or (at your option) any later version.
|
|
6
|
+
|
|
7
|
+
This program is distributed in the hope that it will be useful,
|
|
8
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
9
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
10
|
+
GNU General Public License for more details.
|
|
11
|
+
|
|
12
|
+
You should have received a copy of the GNU General Public License
|
|
13
|
+
along with this program; if not, write to the Free Software
|
|
14
|
+
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Components.
|
|
19
|
+
*/
|
|
20
|
+
export { default as ConnectScreen } from './components/connect-screen/basic';
|
|
21
|
+
export { default as ConnectScreenLayout } from './components/connect-screen/layout';
|
|
22
|
+
export { default as ConnectScreenRequiredPlan } from './components/connect-screen/required-plan';
|
|
23
|
+
export { default as ConnectButton } from './components/connect-button';
|
|
24
|
+
export { default as InPlaceConnection } from './components/in-place-connection';
|
|
25
|
+
export { default as ConnectUser } from './components/connect-user';
|
|
26
|
+
export { default as ConnectionErrorNotice } from './components/connection-error-notice';
|
|
27
|
+
export { ConnectionError } from './hooks/use-connection-error-notice';
|
|
28
|
+
export { default as DisconnectDialog } from './components/disconnect-dialog';
|
|
29
|
+
export { default as DisconnectCard } from './components/disconnect-card';
|
|
30
|
+
export { default as useConnection } from './components/use-connection';
|
|
31
|
+
export { default as ManageConnectionDialog } from './components/manage-connection-dialog';
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Helpers.
|
|
35
|
+
*/
|
|
36
|
+
export { default as thirdPartyCookiesFallbackHelper } from './helpers/third-party-cookies-fallback';
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Store
|
|
40
|
+
*/
|
|
41
|
+
export { STORE_ID as CONNECTION_STORE_ID } from './state/store';
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Hooks
|
|
45
|
+
*/
|
|
46
|
+
export { default as useProductCheckoutWorkflow } from './hooks/use-product-checkout-workflow';
|
|
47
|
+
export { default as useRestoreConnection } from './hooks/use-restore-connection';
|
|
48
|
+
export { default as useConnectionErrorNotice } from './hooks/use-connection-error-notice';
|
package/index.native.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as useConnection } from './components/use-connection';
|
package/package.json
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@automattic/jetpack-connection",
|
|
3
|
+
"version": "0.29.8",
|
|
4
|
+
"description": "Jetpack Connection Component",
|
|
5
|
+
"homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/js-packages/connection/#readme",
|
|
6
|
+
"bugs": {
|
|
7
|
+
"url": "https://github.com/Automattic/jetpack/labels/[JS Package] Connection"
|
|
8
|
+
},
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "https://github.com/Automattic/jetpack.git",
|
|
12
|
+
"directory": "projects/js-packages/connection"
|
|
13
|
+
},
|
|
14
|
+
"author": "Automattic",
|
|
15
|
+
"license": "GPL-2.0-or-later",
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"@automattic/jetpack-analytics": "^0.1.26",
|
|
18
|
+
"@automattic/jetpack-api": "^0.16.1",
|
|
19
|
+
"@automattic/jetpack-components": "^0.41.1",
|
|
20
|
+
"@automattic/jetpack-config": "^0.1.21",
|
|
21
|
+
"@wordpress/base-styles": "4.29.0",
|
|
22
|
+
"@wordpress/browserslist-config": "5.21.0",
|
|
23
|
+
"@wordpress/components": "25.4.0",
|
|
24
|
+
"@wordpress/data": "9.8.0",
|
|
25
|
+
"@wordpress/element": "5.15.0",
|
|
26
|
+
"@wordpress/i18n": "4.38.0",
|
|
27
|
+
"@wordpress/icons": "9.29.0",
|
|
28
|
+
"classnames": "2.3.2",
|
|
29
|
+
"debug": "4.3.4",
|
|
30
|
+
"prop-types": "^15.7.2"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@automattic/jetpack-base-styles": "^0.6.5",
|
|
34
|
+
"@babel/core": "7.22.9",
|
|
35
|
+
"@babel/preset-react": "7.22.5",
|
|
36
|
+
"@storybook/addon-actions": "7.1.0",
|
|
37
|
+
"@testing-library/dom": "8.19.1",
|
|
38
|
+
"@testing-library/react": "13.4.0",
|
|
39
|
+
"@testing-library/user-event": "14.4.3",
|
|
40
|
+
"jest": "29.4.3",
|
|
41
|
+
"jest-environment-jsdom": "29.4.3",
|
|
42
|
+
"react": "18.2.0",
|
|
43
|
+
"react-dom": "18.2.0",
|
|
44
|
+
"react-test-renderer": "18.2.0"
|
|
45
|
+
},
|
|
46
|
+
"peerDependencies": {
|
|
47
|
+
"react": "^18.0.0",
|
|
48
|
+
"react-dom": "^18.0.0"
|
|
49
|
+
},
|
|
50
|
+
"type": "module",
|
|
51
|
+
"exports": {
|
|
52
|
+
".": "./index.jsx"
|
|
53
|
+
},
|
|
54
|
+
"sideEffects": [
|
|
55
|
+
"./state/store.jsx",
|
|
56
|
+
"*.css",
|
|
57
|
+
"*.scss"
|
|
58
|
+
],
|
|
59
|
+
"scripts": {
|
|
60
|
+
"test": "NODE_OPTIONS=--experimental-vm-modules jest"
|
|
61
|
+
}
|
|
62
|
+
}
|