Skip to content

Commit b614b89

Browse files
committed
Make DIFM migration cancellation context aware
We now display slightly different context depending on if the site has a migration in progress. If the site doesn't have a migration in progress (no migration-in-progress sticker), the user is allowed to cancel outright. Otherwise they are told they're sending a migration cancellation request.
1 parent 977b217 commit b614b89

File tree

3 files changed

+173
-44
lines changed

3 files changed

+173
-44
lines changed

client/sites/overview/components/migration-overview/components/cancel-difm-migration/index.tsx

Lines changed: 107 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,102 @@ import { Modal, Button } from '@wordpress/components';
33
import { useTranslate } from 'i18n-calypso';
44
import { useState } from 'react';
55
import { useDispatch } from 'react-redux';
6+
import { useBlogStickersQuery } from 'calypso/blocks/blog-stickers/use-blog-stickers-query';
67
import { LoadingBar } from 'calypso/components/loading-bar';
78
import wp from 'calypso/lib/wp';
89
import { successNotice, errorNotice } from 'calypso/state/notices/actions';
10+
import type { ButtonProps } from '@wordpress/components';
11+
12+
type CancelMigrationButtonProps = {
13+
isMigrationInProgress: boolean;
14+
onClick: () => void;
15+
buttonType: 'cta' | 'confirm';
16+
} & Omit< ButtonProps, 'onClick' >;
17+
18+
const CancelMigrationButton = ( {
19+
isMigrationInProgress,
20+
onClick,
21+
buttonType,
22+
...buttonProps
23+
}: CancelMigrationButtonProps ) => {
24+
const translate = useTranslate();
25+
26+
let cancelMigrationButtonText = translate( 'Cancel migration' );
27+
28+
if ( buttonType === 'cta' && isMigrationInProgress ) {
29+
cancelMigrationButtonText = translate( 'Request migration cancellation' );
30+
}
31+
32+
if ( buttonType === 'confirm' && isMigrationInProgress ) {
33+
cancelMigrationButtonText = translate( 'Send request' );
34+
}
35+
36+
return (
37+
<Button
38+
onClick={ ( e: React.MouseEvent< HTMLButtonElement > ) => {
39+
e.preventDefault();
40+
onClick();
41+
} }
42+
{ ...buttonProps }
43+
>
44+
{ cancelMigrationButtonText }
45+
</Button>
46+
);
47+
};
48+
49+
const CancelMigrationModal = ( {
50+
closeModal,
51+
handleCancelMigration,
52+
siteId,
53+
isMigrationInProgress,
54+
}: {
55+
closeModal: () => void;
56+
handleCancelMigration: ( siteId: number ) => void;
57+
siteId: number;
58+
isMigrationInProgress: boolean;
59+
} ) => {
60+
const translate = useTranslate();
61+
62+
const modalTitle = ! isMigrationInProgress
63+
? translate( 'Cancel migration' )
64+
: translate( 'Request migration cancellation' );
65+
66+
const modalContent = ! isMigrationInProgress
67+
? translate(
68+
"If you cancel now, our Happiness Engineers will be notified that you've chosen not to move your site to WordPress.com, and your current site will remain exactly as it is."
69+
)
70+
: translate(
71+
"Since your migration is already underway, you'll need to send us a cancellation request. If you cancel now, you'll lose all your progress."
72+
);
73+
74+
return (
75+
<Modal
76+
className="migration-started-difm__cancel-dialog"
77+
title={ modalTitle }
78+
onRequestClose={ closeModal }
79+
size="medium"
80+
>
81+
<p>{ modalContent }</p>
82+
<div className="migration-started-difm__cancel-dialog-buttons">
83+
<Button key="cancel" variant="secondary" onClick={ () => closeModal() }>
84+
{ translate( "Don't cancel migration" ) }
85+
</Button>
86+
<CancelMigrationButton
87+
key="send"
88+
variant="primary"
89+
isMigrationInProgress={ isMigrationInProgress }
90+
onClick={ () => handleCancelMigration( siteId ) }
91+
buttonType="confirm"
92+
/>
93+
</div>
94+
</Modal>
95+
);
96+
};
997

1098
const CancelDifmMigrationForm = ( { siteId }: { siteId: number } ) => {
1199
const translate = useTranslate();
12100
const dispatch = useDispatch();
101+
const { data: stickers = [] } = useBlogStickersQuery( siteId );
13102
const [ isOpen, setOpen ] = useState( false );
14103
const openModal = () => setOpen( true );
15104
const closeModal = () => setOpen( false );
@@ -21,6 +110,8 @@ const CancelDifmMigrationForm = ( { siteId }: { siteId: number } ) => {
21110
return null;
22111
}
23112

113+
const isMigrationInProgress = stickers.includes( 'migration-in-progress' );
114+
24115
const handleSendCancellationRequest = async ( siteId: number ) => {
25116
try {
26117
return await wp.req.post( {
@@ -50,9 +141,13 @@ const CancelDifmMigrationForm = ( { siteId }: { siteId: number } ) => {
50141
return;
51142
}
52143

144+
const cancellationSuccessMessage = isMigrationInProgress
145+
? translate( 'Migration cancellation request sent.' )
146+
: translate( 'Migration cancelled.' );
147+
53148
setCancellationStatus( 'success' );
54149
dispatch(
55-
successNotice( translate( 'Migration cancellation request sent.' ), {
150+
successNotice( cancellationSuccessMessage, {
56151
duration: 5000,
57152
} )
58153
);
@@ -64,37 +159,20 @@ const CancelDifmMigrationForm = ( { siteId }: { siteId: number } ) => {
64159
<LoadingBar className="migration-started-difm__cancel-loading-bar" progress={ 0.5 } />
65160
) }
66161
{ cancellationStatus === null && (
67-
<Button
162+
<CancelMigrationButton
163+
isMigrationInProgress={ isMigrationInProgress }
164+
onClick={ openModal }
165+
buttonType="cta"
68166
variant="link"
69-
onClick={ ( e: React.MouseEvent< HTMLButtonElement > ) => {
70-
e.preventDefault();
71-
openModal();
72-
} }
73-
>
74-
{ translate( 'Request cancellation' ) }
75-
</Button>
167+
/>
76168
) }
77169
{ isOpen && (
78-
<Modal
79-
className="migration-started-difm__cancel-dialog"
80-
title={ translate( 'Request migration cancellation' ) }
81-
onRequestClose={ closeModal }
82-
size="medium"
83-
>
84-
<p>
85-
{ translate(
86-
"Since your migration is already underway, you'll need to send us a cancellation request. If you cancel now, you'll lose all your progress."
87-
) }
88-
</p>
89-
<div className="migration-started-difm__cancel-dialog-buttons">
90-
<Button key="cancel" variant="secondary" onClick={ () => closeModal() }>
91-
{ translate( "Don't cancel migration" ) }
92-
</Button>
93-
<Button key="send" variant="primary" onClick={ () => handleCancelMigration( siteId ) }>
94-
{ translate( 'Send request' ) }
95-
</Button>
96-
</div>
97-
</Modal>
170+
<CancelMigrationModal
171+
closeModal={ closeModal }
172+
handleCancelMigration={ handleCancelMigration }
173+
siteId={ siteId }
174+
isMigrationInProgress={ isMigrationInProgress }
175+
/>
98176
) }
99177
</div>
100178
);

client/sites/overview/components/migration-overview/components/cancel-difm-migration/test/index.tsx

Lines changed: 52 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,32 +23,77 @@ jest.mock( 'calypso/lib/wp', () => ( {
2323
},
2424
} ) );
2525

26+
jest.mock( 'calypso/blocks/blog-stickers/use-blog-stickers-query', () => ( {
27+
useBlogStickersQuery: jest.fn(),
28+
} ) );
29+
2630
describe( 'CancelDifmMigrationForm', () => {
2731
const siteId = 123;
2832
const isEnabled = jest.requireMock( '@automattic/calypso-config' ).isEnabled;
33+
const useBlogStickersQuery = jest.requireMock(
34+
'calypso/blocks/blog-stickers/use-blog-stickers-query'
35+
).useBlogStickersQuery;
2936

3037
beforeEach( () => {
3138
nock.cleanAll();
3239
jest.clearAllMocks();
3340
isEnabled.mockReturnValue( true );
41+
useBlogStickersQuery.mockReturnValue( { data: [] } );
3442
} );
3543

3644
it( 'renders nothing if feature flag is disabled', () => {
3745
isEnabled.mockReturnValue( false );
3846
renderWithProvider( <CancelDifmMigrationForm siteId={ siteId } /> );
39-
expect( screen.queryByRole( 'button', { name: /request cancellation/i } ) ).toBeNull();
47+
expect( screen.queryByRole( 'button', { name: /cancel migration/i } ) ).toBeNull();
4048
} );
4149

42-
it( 'opens dialog on button click', async () => {
43-
renderWithProvider( <CancelDifmMigrationForm siteId={ siteId } /> );
44-
await userEvent.click( screen.getByRole( 'button', { name: /request cancellation/i } ) );
45-
expect( screen.getByRole( 'dialog' ) ).toBeVisible();
46-
expect( screen.getByText( /request migration cancellation/i ) ).toBeVisible();
50+
describe( 'when migration is not in progress', () => {
51+
beforeEach( () => {
52+
useBlogStickersQuery.mockReturnValue( { data: [] } );
53+
} );
54+
55+
it( 'shows cancel migration button', () => {
56+
renderWithProvider( <CancelDifmMigrationForm siteId={ siteId } /> );
57+
expect( screen.getByRole( 'button', { name: /cancel migration/i } ) ).toBeVisible();
58+
} );
59+
60+
it( 'opens dialog with cancel migration content', async () => {
61+
renderWithProvider( <CancelDifmMigrationForm siteId={ siteId } /> );
62+
await userEvent.click( screen.getByRole( 'button', { name: /cancel migration/i } ) );
63+
expect( screen.getByRole( 'dialog' ) ).toBeVisible();
64+
expect( screen.getByRole( 'heading', { name: /cancel migration/i } ) ).toBeVisible();
65+
expect( screen.getByText( /our Happiness Engineers will be notified/i ) ).toBeVisible();
66+
} );
67+
} );
68+
69+
describe( 'when migration is in progress', () => {
70+
beforeEach( () => {
71+
useBlogStickersQuery.mockReturnValue( { data: [ 'migration-in-progress' ] } );
72+
} );
73+
74+
it( 'shows request cancellation button', () => {
75+
renderWithProvider( <CancelDifmMigrationForm siteId={ siteId } /> );
76+
expect(
77+
screen.getByRole( 'button', { name: /request migration cancellation/i } )
78+
).toBeVisible();
79+
} );
80+
81+
it( 'opens dialog with request cancellation content', async () => {
82+
renderWithProvider( <CancelDifmMigrationForm siteId={ siteId } /> );
83+
await userEvent.click(
84+
screen.getByRole( 'button', { name: /request migration cancellation/i } )
85+
);
86+
expect( screen.getByRole( 'dialog' ) ).toBeVisible();
87+
expect(
88+
screen.getByRole( 'heading', { name: /request migration cancellation/i } )
89+
).toBeVisible();
90+
expect( screen.getByText( /you'll lose all your progress/i ) ).toBeVisible();
91+
} );
4792
} );
4893

4994
it( 'closes dialog on cancel', async () => {
5095
renderWithProvider( <CancelDifmMigrationForm siteId={ siteId } /> );
51-
await userEvent.click( screen.getByRole( 'button', { name: /request cancellation/i } ) );
96+
await userEvent.click( screen.getByRole( 'button', { name: /cancel migration/i } ) );
5297
await userEvent.click( screen.getByRole( 'button', { name: /don't cancel migration/i } ) );
5398
await waitFor( () => {
5499
expect( screen.queryByRole( 'dialog' ) ).toBeNull();

client/sites/overview/components/style.scss

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -133,21 +133,27 @@ $blueberry-color: #3858e9;
133133
}
134134
}
135135

136+
&__navigation-header {
137+
margin-bottom: 24px;
138+
}
139+
140+
&__blog-stickers {
141+
margin: 0 0 24px;
142+
padding: 16px;
143+
background-color: var(--color-surface);
144+
border: 1px solid var(--color-border-subtle);
145+
border-radius: 4px;
146+
font-size: 14px;
147+
color: var(--color-text-subtle);
148+
}
149+
136150
}
137151

138152
.hosting-overview__domain-to-plan-credit-notice {
139153
grid-column: 1 / -1;
140154
text-wrap: pretty;
141155
}
142156

143-
.hosting-overview__navigation-header {
144-
grid-column: 1 / -1;
145-
146-
&.navigation-header {
147-
margin-bottom: 16px;
148-
}
149-
}
150-
151157
.hosting-overview__navigation-header,
152158
.hosting-overview__active-domains {
153159
grid-column: 1 / -1;

0 commit comments

Comments
 (0)