@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.
Files changed (53) hide show
  1. package/.gitattributes +12 -0
  2. package/CHANGELOG.md +622 -0
  3. package/LICENSE.txt +357 -0
  4. package/README.md +284 -0
  5. package/SECURITY.md +38 -0
  6. package/components/connect-button/index.jsx +70 -0
  7. package/components/connect-screen/basic/index.jsx +104 -0
  8. package/components/connect-screen/basic/style.scss +46 -0
  9. package/components/connect-screen/basic/visual.jsx +109 -0
  10. package/components/connect-screen/layout/image-slider.jsx +37 -0
  11. package/components/connect-screen/layout/index.jsx +65 -0
  12. package/components/connect-screen/layout/style.scss +238 -0
  13. package/components/connect-screen/required-plan/index.jsx +127 -0
  14. package/components/connect-screen/required-plan/style.scss +109 -0
  15. package/components/connect-screen/required-plan/visual.jsx +151 -0
  16. package/components/connect-user/index.jsx +64 -0
  17. package/components/connected-plugins/index.jsx +67 -0
  18. package/components/connection-error-notice/index.jsx +110 -0
  19. package/components/connection-error-notice/styles.module.scss +97 -0
  20. package/components/disconnect-card/index.jsx +40 -0
  21. package/components/disconnect-card/style.scss +85 -0
  22. package/components/disconnect-dialog/images/disconnect-confirm.jpg +0 -0
  23. package/components/disconnect-dialog/images/disconnect-thanks.jpg +0 -0
  24. package/components/disconnect-dialog/index.jsx +409 -0
  25. package/components/disconnect-dialog/steps/step-disconnect-confirm.jsx +87 -0
  26. package/components/disconnect-dialog/steps/step-disconnect.jsx +206 -0
  27. package/components/disconnect-dialog/steps/step-survey.jsx +48 -0
  28. package/components/disconnect-dialog/steps/step-thank-you.jsx +54 -0
  29. package/components/disconnect-dialog/style.scss +218 -0
  30. package/components/disconnect-survey/_jp-connect_disconnect-survey-card.scss +60 -0
  31. package/components/disconnect-survey/index.jsx +181 -0
  32. package/components/disconnect-survey/survey-choice.jsx +43 -0
  33. package/components/in-place-connection/index.jsx +140 -0
  34. package/components/in-place-connection/style.scss +35 -0
  35. package/components/manage-connection-dialog/index.jsx +219 -0
  36. package/components/manage-connection-dialog/style.scss +106 -0
  37. package/components/use-connection/index.jsx +112 -0
  38. package/helpers/third-party-cookies-fallback.jsx +10 -0
  39. package/hooks/use-connection-error-notice/index.jsx +38 -0
  40. package/hooks/use-product-checkout-workflow/Readme.md +61 -0
  41. package/hooks/use-product-checkout-workflow/index.jsx +103 -0
  42. package/hooks/use-restore-connection/index.jsx +64 -0
  43. package/index.jsx +48 -0
  44. package/index.native.js +1 -0
  45. package/package.json +62 -0
  46. package/state/actions.jsx +166 -0
  47. package/state/controls.jsx +40 -0
  48. package/state/reducers.jsx +121 -0
  49. package/state/resolvers.jsx +32 -0
  50. package/state/selectors.jsx +35 -0
  51. package/state/store-holder.jsx +14 -0
  52. package/state/store-id.jsx +3 -0
  53. package/state/store.jsx +29 -0
@@ -0,0 +1,166 @@
1
+ import restApi from '@automattic/jetpack-api';
2
+
3
+ const SET_CONNECTION_STATUS = 'SET_CONNECTION_STATUS';
4
+ const SET_CONNECTION_STATUS_IS_FETCHING = 'SET_CONNECTION_STATUS_IS_FETCHING';
5
+ const FETCH_CONNECTION_STATUS = 'FETCH_CONNECTION_STATUS';
6
+ const SET_SITE_IS_REGISTERING = 'SET_SITE_IS_REGISTERING';
7
+ const SET_USER_IS_CONNECTING = 'SET_USER_IS_CONNECTING';
8
+ const SET_REGISTRATION_ERROR = 'SET_REGISTRATION_ERROR';
9
+ const CLEAR_REGISTRATION_ERROR = 'CLEAR_REGISTRATION_ERROR';
10
+ const REGISTER_SITE = 'REGISTER_SITE';
11
+ const SET_AUTHORIZATION_URL = 'SET_AUTHORIZATION_URL';
12
+ const CONNECT_USER = 'CONNECT_USER';
13
+ const DISCONNECT_USER_SUCCESS = 'DISCONNECT_USER_SUCCESS';
14
+ const FETCH_AUTHORIZATION_URL = 'FETCH_AUTHORIZATION_URL';
15
+ const SET_CONNECTED_PLUGINS = 'SET_CONNECTED_PLUGINS';
16
+ const REFRESH_CONNECTED_PLUGINS = 'REFRESH_CONNECTED_PLUGINS';
17
+ const SET_CONNECTION_ERRORS = 'SET_CONNECTION_ERRORS';
18
+ const SET_IS_OFFLINE_MODE = 'SET_IS_OFFLINE_MODE';
19
+
20
+ const setConnectionStatus = connectionStatus => {
21
+ return { type: SET_CONNECTION_STATUS, connectionStatus };
22
+ };
23
+
24
+ const setConnectionStatusIsFetching = isFetching => {
25
+ return { type: SET_CONNECTION_STATUS_IS_FETCHING, isFetching };
26
+ };
27
+
28
+ const fetchConnectionStatus = () => {
29
+ return { type: FETCH_CONNECTION_STATUS };
30
+ };
31
+
32
+ const setSiteIsRegistering = isRegistering => {
33
+ return { type: SET_SITE_IS_REGISTERING, isRegistering };
34
+ };
35
+
36
+ const setUserIsConnecting = isConnecting => {
37
+ return { type: SET_USER_IS_CONNECTING, isConnecting };
38
+ };
39
+
40
+ const disconnectUserSuccess = () => {
41
+ return { type: DISCONNECT_USER_SUCCESS };
42
+ };
43
+
44
+ const setRegistrationError = registrationError => {
45
+ return { type: SET_REGISTRATION_ERROR, registrationError };
46
+ };
47
+
48
+ const clearRegistrationError = () => {
49
+ return { type: CLEAR_REGISTRATION_ERROR };
50
+ };
51
+
52
+ const setAuthorizationUrl = authorizationUrl => {
53
+ return { type: SET_AUTHORIZATION_URL, authorizationUrl };
54
+ };
55
+
56
+ const fetchAuthorizationUrl = redirectUri => {
57
+ return { type: FETCH_AUTHORIZATION_URL, redirectUri };
58
+ };
59
+
60
+ const setConnectedPlugins = connectedPlugins => {
61
+ return { type: SET_CONNECTED_PLUGINS, connectedPlugins };
62
+ };
63
+
64
+ const setConnectionErrors = connectionErrors => {
65
+ return { type: SET_CONNECTION_ERRORS, connectionErrors };
66
+ };
67
+
68
+ const setIsOfflineMode = isOfflineMode => {
69
+ return { type: SET_IS_OFFLINE_MODE, isOfflineMode };
70
+ };
71
+
72
+ /**
73
+ * Connect site with wp.com user
74
+ *
75
+ * @param {object} Object - contains from and redirectFunc
76
+ * @param {string} Object.from - Value that represents the redirect origin
77
+ * @param {Function} Object.redirectFunc - A function to handle the redirect, defaults to location.assign
78
+ * @param {string} [Object.redirectUri] - A URI that the user will be redirected to
79
+ * @yields {object} Action object that will be yielded
80
+ */
81
+ function* connectUser( { from, redirectFunc, redirectUri } = {} ) {
82
+ yield setUserIsConnecting( true );
83
+ yield { type: CONNECT_USER, from, redirectFunc, redirectUri };
84
+ }
85
+
86
+ /**
87
+ *
88
+ * Register an site into jetpack
89
+ *
90
+ * @param {object} Object - contains registrationNonce and redirectUri
91
+ * @param {string} Object.registrationNonce - Registration nonce
92
+ * @param {string} Object.redirectUri - URI that user will be redirected
93
+ * @yields {object} Action object that will be yielded
94
+ * @returns {Promise} Resolved or rejected value of registerSite
95
+ */
96
+ function* registerSite( { registrationNonce, redirectUri } ) {
97
+ yield clearRegistrationError();
98
+ yield setSiteIsRegistering( true );
99
+
100
+ try {
101
+ const response = yield { type: REGISTER_SITE, registrationNonce, redirectUri };
102
+ yield setConnectionStatus( { isRegistered: true } );
103
+ yield setAuthorizationUrl( response.authorizeUrl );
104
+ yield setSiteIsRegistering( false );
105
+ return Promise.resolve( response );
106
+ } catch ( error ) {
107
+ yield setRegistrationError( error );
108
+ yield setSiteIsRegistering( false );
109
+ return Promise.reject( error );
110
+ }
111
+ }
112
+
113
+ /**
114
+ * Side effect action which will fetch a new list of connectedPlugins from the server
115
+ *
116
+ * @returns {Promise} - Promise which resolves when the product status is activated.
117
+ */
118
+ const refreshConnectedPlugins =
119
+ () =>
120
+ async ( { dispatch } ) => {
121
+ return await new Promise( resolve => {
122
+ return restApi.fetchConnectedPlugins().then( data => {
123
+ dispatch( setConnectedPlugins( data ) );
124
+ resolve( data );
125
+ } );
126
+ } );
127
+ };
128
+
129
+ const actions = {
130
+ setConnectionStatus,
131
+ setConnectionStatusIsFetching,
132
+ fetchConnectionStatus,
133
+ fetchAuthorizationUrl,
134
+ setSiteIsRegistering,
135
+ setUserIsConnecting,
136
+ setRegistrationError,
137
+ clearRegistrationError,
138
+ setAuthorizationUrl,
139
+ registerSite,
140
+ connectUser,
141
+ disconnectUserSuccess,
142
+ setConnectedPlugins,
143
+ refreshConnectedPlugins,
144
+ setConnectionErrors,
145
+ setIsOfflineMode,
146
+ };
147
+
148
+ export {
149
+ SET_CONNECTION_STATUS,
150
+ SET_CONNECTION_STATUS_IS_FETCHING,
151
+ FETCH_CONNECTION_STATUS,
152
+ FETCH_AUTHORIZATION_URL,
153
+ SET_SITE_IS_REGISTERING,
154
+ SET_USER_IS_CONNECTING,
155
+ SET_REGISTRATION_ERROR,
156
+ CLEAR_REGISTRATION_ERROR,
157
+ REGISTER_SITE,
158
+ SET_AUTHORIZATION_URL,
159
+ CONNECT_USER,
160
+ DISCONNECT_USER_SUCCESS,
161
+ SET_CONNECTED_PLUGINS,
162
+ REFRESH_CONNECTED_PLUGINS,
163
+ SET_CONNECTION_ERRORS,
164
+ SET_IS_OFFLINE_MODE,
165
+ actions as default,
166
+ };
@@ -0,0 +1,40 @@
1
+ import restApi from '@automattic/jetpack-api';
2
+ import { createRegistryControl } from '@wordpress/data';
3
+ import STORE_ID from './store-id';
4
+
5
+ const REGISTER_SITE = ( { registrationNonce, redirectUri } ) =>
6
+ restApi.registerSite( registrationNonce, redirectUri );
7
+
8
+ const CONNECT_USER = createRegistryControl(
9
+ ( { resolveSelect } ) =>
10
+ ( { from, redirectFunc, redirectUri } = {} ) => {
11
+ return new Promise( ( resolve, reject ) => {
12
+ resolveSelect( STORE_ID )
13
+ .getAuthorizationUrl( redirectUri )
14
+ .then( authorizationUrl => {
15
+ const redirect = redirectFunc || ( url => window.location.assign( url ) );
16
+
17
+ const url = new URL( authorizationUrl );
18
+
19
+ if ( from ) {
20
+ url.searchParams.set( 'from', encodeURIComponent( from ) );
21
+ }
22
+
23
+ const finalUrl = url.toString();
24
+ redirect( finalUrl );
25
+ resolve( finalUrl );
26
+ } )
27
+ .catch( error => {
28
+ reject( error );
29
+ } );
30
+ } );
31
+ }
32
+ );
33
+
34
+ const FETCH_AUTHORIZATION_URL = ( { redirectUri } ) => restApi.fetchAuthorizationUrl( redirectUri );
35
+
36
+ export default {
37
+ FETCH_AUTHORIZATION_URL,
38
+ REGISTER_SITE,
39
+ CONNECT_USER,
40
+ };
@@ -0,0 +1,121 @@
1
+ import { combineReducers } from '@wordpress/data';
2
+ import {
3
+ SET_CONNECTION_STATUS,
4
+ SET_CONNECTION_STATUS_IS_FETCHING,
5
+ SET_SITE_IS_REGISTERING,
6
+ SET_USER_IS_CONNECTING,
7
+ DISCONNECT_USER_SUCCESS,
8
+ CLEAR_REGISTRATION_ERROR,
9
+ SET_REGISTRATION_ERROR,
10
+ SET_AUTHORIZATION_URL,
11
+ SET_CONNECTED_PLUGINS,
12
+ SET_CONNECTION_ERRORS,
13
+ SET_IS_OFFLINE_MODE,
14
+ } from './actions';
15
+
16
+ const connectionStatus = ( state = {}, action ) => {
17
+ switch ( action.type ) {
18
+ case SET_CONNECTION_STATUS:
19
+ return { ...state, ...action.connectionStatus };
20
+ case DISCONNECT_USER_SUCCESS:
21
+ return { ...state, isUserConnected: false };
22
+ }
23
+
24
+ return state;
25
+ };
26
+
27
+ const connectedPlugins = ( state = {}, action ) => {
28
+ switch ( action.type ) {
29
+ case SET_CONNECTED_PLUGINS:
30
+ return action.connectedPlugins;
31
+ }
32
+
33
+ return state;
34
+ };
35
+
36
+ const connectionStatusIsFetching = ( state = false, action ) => {
37
+ switch ( action.type ) {
38
+ case SET_CONNECTION_STATUS_IS_FETCHING:
39
+ return action.isFetching;
40
+ }
41
+
42
+ return state;
43
+ };
44
+
45
+ const siteIsRegistering = ( state = false, action ) => {
46
+ switch ( action.type ) {
47
+ case SET_SITE_IS_REGISTERING:
48
+ return action.isRegistering;
49
+ }
50
+
51
+ return state;
52
+ };
53
+
54
+ const userIsConnecting = ( state = false, action ) => {
55
+ switch ( action.type ) {
56
+ case SET_USER_IS_CONNECTING:
57
+ return action.isConnecting;
58
+ }
59
+
60
+ return state;
61
+ };
62
+
63
+ const registrationError = ( state, action ) => {
64
+ switch ( action.type ) {
65
+ case CLEAR_REGISTRATION_ERROR:
66
+ return false;
67
+ case SET_REGISTRATION_ERROR:
68
+ return action.registrationError;
69
+ default:
70
+ return state;
71
+ }
72
+ };
73
+
74
+ const authorizationUrl = ( state, action ) => {
75
+ switch ( action.type ) {
76
+ case SET_AUTHORIZATION_URL:
77
+ return action.authorizationUrl;
78
+ default:
79
+ return state;
80
+ }
81
+ };
82
+
83
+ const userConnectionData = ( state, action ) => {
84
+ switch ( action.type ) {
85
+ default:
86
+ return state;
87
+ }
88
+ };
89
+
90
+ const connectionErrors = ( state = {}, action ) => {
91
+ switch ( action.type ) {
92
+ case SET_CONNECTION_ERRORS:
93
+ return action.connectionErrors;
94
+ }
95
+
96
+ return state;
97
+ };
98
+
99
+ const isOfflineMode = ( state = false, action ) => {
100
+ switch ( action.type ) {
101
+ case SET_IS_OFFLINE_MODE:
102
+ return action.isConnecting;
103
+ }
104
+
105
+ return state;
106
+ };
107
+
108
+ const reducers = combineReducers( {
109
+ connectionStatus,
110
+ connectionStatusIsFetching,
111
+ siteIsRegistering,
112
+ userIsConnecting,
113
+ registrationError,
114
+ authorizationUrl,
115
+ userConnectionData,
116
+ connectedPlugins,
117
+ connectionErrors,
118
+ isOfflineMode,
119
+ } );
120
+
121
+ export default reducers;
@@ -0,0 +1,32 @@
1
+ import { dispatch, select } from '@wordpress/data';
2
+ import actions from './actions';
3
+ import STORE_ID from './store-id';
4
+
5
+ const connectionResolvers = {
6
+ getAuthorizationUrl: {
7
+ isFulfilled: ( state, ...args ) => {
8
+ const hasAuthorization = Boolean( state.authorizationUrl );
9
+ const hasFinishedResolution = select( STORE_ID ).hasFinishedResolution(
10
+ 'getAuthorizationUrl',
11
+ args
12
+ );
13
+
14
+ // we need to set finish resolution to fix a problem when using resolveSelect,
15
+ // since it looks for finishResolution to return the value
16
+ // ref: https://github.com/WordPress/gutenberg/blob/5dbf7ca8a285f5cab65ebf7ab87dafeb6118b6aa/packages/data/src/redux-store/index.js#L342
17
+ if ( hasAuthorization && ! hasFinishedResolution ) {
18
+ dispatch( STORE_ID ).finishResolution( 'getAuthorizationUrl', args );
19
+ }
20
+
21
+ return hasAuthorization;
22
+ },
23
+ *fulfill( redirectUri ) {
24
+ const response = yield actions.fetchAuthorizationUrl( redirectUri );
25
+ yield actions.setAuthorizationUrl( response.authorizeUrl );
26
+ },
27
+ },
28
+ };
29
+
30
+ export default {
31
+ ...connectionResolvers,
32
+ };
@@ -0,0 +1,35 @@
1
+ const getWpcomUser = state => {
2
+ return state?.userConnectionData?.currentUser?.wpcomUser;
3
+ };
4
+
5
+ const getBlogId = state => {
6
+ return state?.userConnectionData?.currentUser?.blogId;
7
+ };
8
+
9
+ const connectionSelectors = {
10
+ getConnectionStatus: state => state.connectionStatus || {},
11
+ /**
12
+ * Checks whether the store is fetching the connection status from the server
13
+ *
14
+ * @deprecated since 0.14.0
15
+ * @returns {boolean} Is the store is fetching the connection status from the server?
16
+ */
17
+ getConnectionStatusIsFetching: () => false,
18
+ getSiteIsRegistering: state => state.siteIsRegistering || false,
19
+ getUserIsConnecting: state => state.userIsConnecting || false,
20
+ getRegistrationError: state => state.registrationError || false,
21
+ getAuthorizationUrl: state => state.authorizationUrl || false,
22
+ getUserConnectionData: state => state.userConnectionData || false,
23
+ getConnectedPlugins: state => state.connectedPlugins || [],
24
+ getConnectionErrors: state => state.connectionErrors || [],
25
+ getIsOfflineMode: state => state.isOfflineMode || false,
26
+
27
+ getWpcomUser,
28
+ getBlogId,
29
+ };
30
+
31
+ const selectors = {
32
+ ...connectionSelectors,
33
+ };
34
+
35
+ export default selectors;
@@ -0,0 +1,14 @@
1
+ import { createReduxStore, register } from '@wordpress/data';
2
+
3
+ class storeHolder {
4
+ static store = null;
5
+
6
+ static mayBeInit( storeId, storeConfig ) {
7
+ if ( null === storeHolder.store ) {
8
+ storeHolder.store = createReduxStore( storeId, storeConfig );
9
+ register( storeHolder.store );
10
+ }
11
+ }
12
+ }
13
+
14
+ export default storeHolder;
@@ -0,0 +1,3 @@
1
+ const STORE_ID = 'jetpack-connection';
2
+
3
+ export default STORE_ID;
@@ -0,0 +1,29 @@
1
+ /* eslint-disable no-console */
2
+
3
+ import actions from './actions';
4
+ import controls from './controls';
5
+ import reducer from './reducers';
6
+ import resolvers from './resolvers';
7
+ import selectors from './selectors';
8
+ import storeHolder from './store-holder';
9
+ import STORE_ID from './store-id';
10
+
11
+ const initialState = window.JP_CONNECTION_INITIAL_STATE;
12
+
13
+ if ( ! initialState ) {
14
+ console.error(
15
+ 'Jetpack Connection package: Initial state is missing. Check documentation to see how to use the Connection composer package to set up the initial state.'
16
+ );
17
+ }
18
+
19
+ storeHolder.mayBeInit( STORE_ID, {
20
+ __experimentalUseThunks: true,
21
+ reducer,
22
+ actions,
23
+ selectors,
24
+ resolvers,
25
+ controls,
26
+ initialState: initialState || {},
27
+ } );
28
+
29
+ export { STORE_ID };