Skip to content

Commit 4dc2c0d

Browse files
authored
My Jetpack: Move the product card's status action into a hook (#53944)
1 parent de9f8ab commit 4dc2c0d

3 files changed

Lines changed: 316 additions & 296 deletions

File tree

‎projects/packages/my-jetpack/_inc/components/action-button/index.tsx‎

Lines changed: 10 additions & 296 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,13 @@
1-
import { getUserConnectionUrl } from '@automattic/jetpack-connection';
21
import { __ } from '@wordpress/i18n';
32
import { Icon, chevronDown, external, check } from '@wordpress/icons';
43
import { Badge } from '@wordpress/ui';
54
import clsx from 'clsx';
65
import { useCallback, useState, useEffect, useMemo, useRef } from 'react';
7-
import { PRODUCT_STATUSES, MyJetpackRoutes } from '../../constants';
8-
import useActivatePlugins from '../../data/products/use-activate-plugins';
9-
import useInstallPlugins from '../../data/products/use-install-plugins';
10-
import useProduct from '../../data/products/use-product';
11-
import useProductsByOwnership from '../../data/products/use-products-by-ownership';
126
import useAnalytics from '../../hooks/use-analytics';
13-
import useForcedOffReason from '../../hooks/use-forced-off-reason';
14-
import useMyJetpackConnection from '../../hooks/use-my-jetpack-connection';
15-
import useMyJetpackNavigate from '../../hooks/use-my-jetpack-navigate';
167
import useOutsideAlerter from '../../hooks/use-outside-alerter';
178
import SecondaryButton, { type SecondaryButtonProps } from './secondary-button';
189
import styles from './style.module.scss';
10+
import useProductStatusAction from './use-product-status-action';
1911
import type { AdditionalAction } from './types';
2012
import type { FC, MouseEvent, SetStateAction } from 'react';
2113

@@ -42,47 +34,18 @@ const ActionButton: FC< ActionButtonProps > = ( {
4234
tracksIdentifier,
4335
labelSuffixId,
4436
} ) => {
45-
const {
46-
data: { ownedProducts },
47-
} = useProductsByOwnership();
48-
4937
const [ isDropdownOpen, setIsDropdownOpen ] = useState( false );
5038
const [ currentAction, setCurrentAction ] = useState< SecondaryButtonProps >( {} );
51-
const { detail, isLoading: isProductDataLoading, isRefetching } = useProduct( slug );
52-
53-
const {
54-
manageUrl,
55-
purchaseUrl,
56-
managePaidPlanPurchaseUrl,
57-
renewPaidPlanPurchaseUrl,
58-
status,
59-
requiresUserConnection,
60-
} = detail;
61-
const { siteIsRegistering, isRegistered, isUserConnected } = useMyJetpackConnection();
62-
const isManageDisabled = ! manageUrl;
6339
const dropdownRef = useRef( null );
6440
const chevronRef = useRef( null );
6541
const { recordEvent } = useAnalytics();
66-
const navigateToConnectionPage = useMyJetpackNavigate( MyJetpackRoutes.ConnectionSkipPricing );
67-
const { activate, isPending: isActivating } = useActivatePlugins( slug );
68-
const { install: installStandalonePlugin, isPending: isInstalling } = useInstallPlugins( slug );
69-
70-
const { reason: forcedOffReason, isPending: isForcedOffPending } = useForcedOffReason(
71-
slug,
72-
status
73-
);
42+
const { action, isBusy, forcedOffReason } = useProductStatusAction( slug, {
43+
primaryActionOverride,
44+
fixSiteConnectionHandler,
45+
tracksIdentifier,
46+
} );
7447

75-
const isBusy =
76-
isActivating ||
77-
isForcedOffPending ||
78-
isProductDataLoading ||
79-
isRefetching ||
80-
isInstalling ||
81-
( siteIsRegistering && status === PRODUCT_STATUSES.SITE_CONNECTION_ERROR );
8248
const hasAdditionalActions = additionalActions?.length > 0;
83-
const isOwned = ownedProducts?.includes( slug );
84-
const troubleshootBackupsUrl =
85-
'https://jetpack.com/support/backup/troubleshooting-jetpack-backup/';
8649
const labelledBy = `${ getActionButtonId( slug ) } ${ labelSuffixId || '' }`.trim();
8750

8851
const buttonState = useMemo< Partial< SecondaryButtonProps > >( () => {
@@ -95,259 +58,10 @@ const ActionButton: FC< ActionButtonProps > = ( {
9558
};
9659
}, [ isBusy, className ] );
9760

98-
/*
99-
* Redirect only if connected
100-
*/
101-
const handleActivate = useCallback( () => {
102-
if ( ( ! isRegistered || ! isUserConnected ) && requiresUserConnection ) {
103-
navigateToConnectionPage();
104-
return;
105-
}
106-
107-
recordEvent( `jetpack_myjetpack_${ tracksIdentifier }_activate_click`, {
108-
product: slug,
109-
} );
110-
111-
activate();
112-
}, [
113-
activate,
114-
isRegistered,
115-
isUserConnected,
116-
requiresUserConnection,
117-
navigateToConnectionPage,
118-
recordEvent,
119-
slug,
120-
tracksIdentifier,
121-
] );
122-
123-
const learnMoreHandler = useCallback( () => {
124-
recordEvent( `jetpack_myjetpack_${ tracksIdentifier }_learnmore_click`, {
125-
product: slug,
126-
} );
127-
}, [ slug, recordEvent, tracksIdentifier ] );
128-
129-
const fixUserConnectionHandler = useCallback( () => {
130-
recordEvent( `jetpack_myjetpack_${ tracksIdentifier }_fixconnection_click`, {
131-
product: slug,
132-
} );
133-
}, [ slug, recordEvent, tracksIdentifier ] );
134-
135-
const addHandler = useCallback( () => {
136-
recordEvent( `jetpack_myjetpack_${ tracksIdentifier }_add_click`, {
137-
product: slug,
138-
} );
139-
}, [ slug, recordEvent, tracksIdentifier ] );
140-
141-
const manageHandler = useCallback( () => {
142-
recordEvent( `jetpack_myjetpack_${ tracksIdentifier }_manage_click`, {
143-
product: slug,
144-
} );
145-
}, [ slug, recordEvent, tracksIdentifier ] );
146-
147-
const installStandaloneHandler = useCallback( () => {
148-
recordEvent( `jetpack_myjetpack_${ tracksIdentifier }_install_standalone_plugin_click`, {
149-
product: slug,
150-
} );
151-
installStandalonePlugin();
152-
}, [ slug, installStandalonePlugin, recordEvent, tracksIdentifier ] );
153-
154-
const statusAction: SecondaryButtonProps = useMemo( () => {
155-
switch ( status ) {
156-
case PRODUCT_STATUSES.ABSENT: {
157-
const buttonText = __( 'Learn more', 'jetpack-my-jetpack' );
158-
return {
159-
...buttonState,
160-
href: `#/add-${ slug }`,
161-
variant: 'primary',
162-
label: buttonText,
163-
onClick: learnMoreHandler,
164-
'aria-labelledby': labelledBy,
165-
...( primaryActionOverride?.[ PRODUCT_STATUSES.ABSENT ] ?? {} ),
166-
};
167-
}
168-
case PRODUCT_STATUSES.ABSENT_WITH_PLAN: {
169-
const buttonText = __( 'Install Plugin', 'jetpack-my-jetpack' );
170-
return {
171-
...buttonState,
172-
variant: 'primary',
173-
label: buttonText,
174-
onClick: installStandaloneHandler,
175-
'aria-labelledby': labelledBy,
176-
...( primaryActionOverride?.[ PRODUCT_STATUSES.ABSENT_WITH_PLAN ] ?? {} ),
177-
};
178-
}
179-
// The site or user have never been connected before and the connection is required
180-
case PRODUCT_STATUSES.NEEDS_FIRST_SITE_CONNECTION:
181-
return {
182-
...buttonState,
183-
href: purchaseUrl || `#/add-${ slug }`,
184-
variant: 'primary',
185-
label: __( 'Learn more', 'jetpack-my-jetpack' ),
186-
onClick: addHandler,
187-
'aria-labelledby': labelledBy,
188-
...( primaryActionOverride?.[ PRODUCT_STATUSES.NEEDS_FIRST_SITE_CONNECTION ] ?? {} ),
189-
};
190-
case PRODUCT_STATUSES.NEEDS_PLAN: {
191-
const getPlanText = __( 'Get plan', 'jetpack-my-jetpack' );
192-
const learnMoreText = __( 'Learn more', 'jetpack-my-jetpack' );
193-
const buttonText = isOwned ? getPlanText : learnMoreText;
194-
195-
return {
196-
...buttonState,
197-
href: purchaseUrl || `#/add-${ slug }`,
198-
variant: 'primary',
199-
label: buttonText,
200-
onClick: addHandler,
201-
'aria-labelledby': labelledBy,
202-
...( primaryActionOverride?.[ PRODUCT_STATUSES.NEEDS_PLAN ] ?? {} ),
203-
};
204-
}
205-
case PRODUCT_STATUSES.CAN_UPGRADE: {
206-
return {
207-
...buttonState,
208-
href: purchaseUrl || `#/add-${ slug }`,
209-
variant: 'primary',
210-
label: __( 'Upgrade', 'jetpack-my-jetpack' ),
211-
onClick: addHandler,
212-
'aria-labelledby': labelledBy,
213-
...( primaryActionOverride?.[ PRODUCT_STATUSES.CAN_UPGRADE ] ?? {} ),
214-
};
215-
}
216-
case PRODUCT_STATUSES.ACTIVE: {
217-
const buttonText = __( 'View', 'jetpack-my-jetpack' );
218-
219-
return {
220-
...buttonState,
221-
disabled: isManageDisabled,
222-
href: manageUrl,
223-
variant: 'secondary',
224-
label: buttonText,
225-
onClick: manageHandler,
226-
'aria-labelledby': labelledBy,
227-
...( primaryActionOverride?.[ PRODUCT_STATUSES.ACTIVE ] ?? {} ),
228-
};
229-
}
230-
case PRODUCT_STATUSES.SITE_CONNECTION_ERROR:
231-
return {
232-
...buttonState,
233-
variant: 'primary',
234-
label: __( 'Connect', 'jetpack-my-jetpack' ),
235-
onClick: fixSiteConnectionHandler,
236-
'aria-labelledby': labelledBy,
237-
...( primaryActionOverride?.[ PRODUCT_STATUSES.SITE_CONNECTION_ERROR ] ?? {} ),
238-
};
239-
case PRODUCT_STATUSES.USER_CONNECTION_ERROR:
240-
return {
241-
href: getUserConnectionUrl(),
242-
variant: 'primary',
243-
label: __( 'Connect', 'jetpack-my-jetpack' ),
244-
onClick: fixUserConnectionHandler,
245-
'aria-labelledby': labelledBy,
246-
...( primaryActionOverride?.[ PRODUCT_STATUSES.USER_CONNECTION_ERROR ] ?? {} ),
247-
};
248-
case PRODUCT_STATUSES.INACTIVE:
249-
case PRODUCT_STATUSES.MODULE_DISABLED:
250-
case PRODUCT_STATUSES.NEEDS_ACTIVATION:
251-
return {
252-
...buttonState,
253-
variant: 'secondary',
254-
label: __( 'Activate', 'jetpack-my-jetpack' ),
255-
onClick: handleActivate,
256-
'aria-labelledby': labelledBy,
257-
...( primaryActionOverride?.[ PRODUCT_STATUSES.INACTIVE ] ?? {} ),
258-
};
259-
case PRODUCT_STATUSES.EXPIRING_SOON:
260-
return {
261-
...buttonState,
262-
href: renewPaidPlanPurchaseUrl,
263-
variant: 'primary',
264-
label: __( 'Renew my plan', 'jetpack-my-jetpack' ),
265-
'aria-labelledby': labelledBy,
266-
...( primaryActionOverride?.[ PRODUCT_STATUSES.EXPIRING_SOON ] ?? {} ),
267-
};
268-
case PRODUCT_STATUSES.EXPIRED:
269-
return {
270-
...buttonState,
271-
href: managePaidPlanPurchaseUrl,
272-
variant: 'primary',
273-
label: __( 'Resume my plan', 'jetpack-my-jetpack' ),
274-
'aria-labelledby': labelledBy,
275-
...( primaryActionOverride?.[ PRODUCT_STATUSES.EXPIRED ] ?? {} ),
276-
};
277-
case PRODUCT_STATUSES.NEEDS_ATTENTION__ERROR: {
278-
const defaultButton: Partial< SecondaryButtonProps > = {
279-
...buttonState,
280-
href: manageUrl,
281-
variant: 'primary',
282-
label: __( 'Troubleshoot', 'jetpack-my-jetpack' ),
283-
'aria-labelledby': labelledBy,
284-
...( primaryActionOverride?.[ PRODUCT_STATUSES.NEEDS_ATTENTION__ERROR ] ?? {} ),
285-
};
286-
switch ( slug ) {
287-
case 'backup':
288-
return {
289-
...defaultButton,
290-
href: troubleshootBackupsUrl,
291-
};
292-
case 'protect':
293-
return {
294-
...defaultButton,
295-
label: __( 'Fix threats', 'jetpack-my-jetpack' ),
296-
};
297-
default:
298-
return defaultButton;
299-
}
300-
}
301-
case PRODUCT_STATUSES.NEEDS_ATTENTION__WARNING: {
302-
const defaultButton: Partial< SecondaryButtonProps > = {
303-
...buttonState,
304-
href: manageUrl,
305-
variant: 'primary',
306-
label: __( 'Troubleshoot', 'jetpack-my-jetpack' ),
307-
'aria-labelledby': labelledBy,
308-
...( primaryActionOverride?.[ PRODUCT_STATUSES.NEEDS_ATTENTION__WARNING ] ?? {} ),
309-
};
310-
switch ( slug ) {
311-
case 'protect':
312-
return {
313-
...defaultButton,
314-
label: __( 'Fix threats', 'jetpack-my-jetpack' ),
315-
};
316-
default:
317-
return {
318-
...defaultButton,
319-
};
320-
}
321-
}
322-
default:
323-
return {
324-
...buttonState,
325-
href: purchaseUrl || `#/add-${ slug }`,
326-
label: __( 'Learn more', 'jetpack-my-jetpack' ),
327-
onClick: addHandler,
328-
'aria-labelledby': labelledBy,
329-
};
330-
}
331-
}, [
332-
status,
333-
buttonState,
334-
slug,
335-
purchaseUrl,
336-
isManageDisabled,
337-
manageUrl,
338-
primaryActionOverride,
339-
isOwned,
340-
managePaidPlanPurchaseUrl,
341-
renewPaidPlanPurchaseUrl,
342-
addHandler,
343-
fixSiteConnectionHandler,
344-
fixUserConnectionHandler,
345-
handleActivate,
346-
installStandaloneHandler,
347-
learnMoreHandler,
348-
manageHandler,
349-
labelledBy,
350-
] );
61+
const statusAction: SecondaryButtonProps = useMemo(
62+
() => ( { ...buttonState, 'aria-labelledby': labelledBy, ...action } ),
63+
[ buttonState, labelledBy, action ]
64+
);
35165

35266
const allActions = useMemo(
35367
() => ( hasAdditionalActions ? [ ...additionalActions, statusAction ] : [ statusAction ] ),

0 commit comments

Comments
 (0)