Skip to content

Commit 8158d84

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 8158d84

File tree

3 files changed

+174
-44
lines changed

3 files changed

+174
-44
lines changed

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

Lines changed: 108 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,103 @@ 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';
910

11+
type CancelMigrationButtonProps = {
12+
isMigrationInProgress: boolean;
13+
onClick: () => void;
14+
buttonType: 'cta' | 'confirm';
15+
variant?: string;
16+
key?: string;
17+
};
18+
19+
const CancelMigrationButton = ( {
20+
isMigrationInProgress,
21+
onClick,
22+
buttonType,
23+
...buttonProps
24+
}: CancelMigrationButtonProps ) => {
25+
const translate = useTranslate();
26+
27+
let cancelMigrationButtonText = translate( 'Cancel migration' );
28+
29+
if ( buttonType === 'cta' && isMigrationInProgress ) {
30+
cancelMigrationButtonText = translate( 'Request migration cancellation' );
31+
}
32+
33+
if ( buttonType === 'confirm' && isMigrationInProgress ) {
34+
cancelMigrationButtonText = translate( 'Send request' );
35+
}
36+
37+
return (
38+
<Button
39+
onClick={ ( e: React.MouseEvent< HTMLButtonElement > ) => {
40+
e.preventDefault();
41+
onClick();
42+
} }
43+
{ ...buttonProps }
44+
>
45+
{ cancelMigrationButtonText }
46+
</Button>
47+
);
48+
};
49+
50+
const CancelMigrationModal = ( {
51+
closeModal,
52+
handleCancelMigration,
53+
siteId,
54+
isMigrationInProgress,
55+
}: {
56+
closeModal: () => void;
57+
handleCancelMigration: ( siteId: number ) => void;
58+
siteId: number;
59+
isMigrationInProgress: boolean;
60+
} ) => {
61+
const translate = useTranslate();
62+
63+
const modalTitle = ! isMigrationInProgress
64+
? translate( 'Cancel migration' )
65+
: translate( 'Request migration cancellation' );
66+
67+
const modalContent = ! isMigrationInProgress
68+
? translate(
69+
"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."
70+
)
71+
: translate(
72+
"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."
73+
);
74+
75+
return (
76+
<Modal
77+
className="migration-started-difm__cancel-dialog"
78+
title={ modalTitle }
79+
onRequestClose={ closeModal }
80+
size="medium"
81+
>
82+
<p>{ modalContent }</p>
83+
<div className="migration-started-difm__cancel-dialog-buttons">
84+
<Button key="cancel" variant="secondary" onClick={ () => closeModal() }>
85+
{ translate( "Don't cancel migration" ) }
86+
</Button>
87+
<CancelMigrationButton
88+
key="send"
89+
variant="primary"
90+
isMigrationInProgress={ isMigrationInProgress }
91+
onClick={ () => handleCancelMigration( siteId ) }
92+
buttonType="confirm"
93+
/>
94+
</div>
95+
</Modal>
96+
);
97+
};
98+
1099
const CancelDifmMigrationForm = ( { siteId }: { siteId: number } ) => {
11100
const translate = useTranslate();
12101
const dispatch = useDispatch();
102+
const { data: stickers = [] } = useBlogStickersQuery( siteId );
13103
const [ isOpen, setOpen ] = useState( false );
14104
const openModal = () => setOpen( true );
15105
const closeModal = () => setOpen( false );
@@ -21,6 +111,8 @@ const CancelDifmMigrationForm = ( { siteId }: { siteId: number } ) => {
21111
return null;
22112
}
23113

114+
const isMigrationInProgress = stickers.includes( 'migration-in-progress' );
115+
24116
const handleSendCancellationRequest = async ( siteId: number ) => {
25117
try {
26118
return await wp.req.post( {
@@ -50,9 +142,13 @@ const CancelDifmMigrationForm = ( { siteId }: { siteId: number } ) => {
50142
return;
51143
}
52144

145+
const cancellationSuccessMessage = isMigrationInProgress
146+
? translate( 'Migration cancellation request sent.' )
147+
: translate( 'Migration cancelled.' );
148+
53149
setCancellationStatus( 'success' );
54150
dispatch(
55-
successNotice( translate( 'Migration cancellation request sent.' ), {
151+
successNotice( cancellationSuccessMessage, {
56152
duration: 5000,
57153
} )
58154
);
@@ -64,37 +160,20 @@ const CancelDifmMigrationForm = ( { siteId }: { siteId: number } ) => {
64160
<LoadingBar className="migration-started-difm__cancel-loading-bar" progress={ 0.5 } />
65161
) }
66162
{ cancellationStatus === null && (
67-
<Button
163+
<CancelMigrationButton
164+
isMigrationInProgress={ isMigrationInProgress }
165+
onClick={ openModal }
166+
buttonType="cta"
68167
variant="link"
69-
onClick={ ( e: React.MouseEvent< HTMLButtonElement > ) => {
70-
e.preventDefault();
71-
openModal();
72-
} }
73-
>
74-
{ translate( 'Request cancellation' ) }
75-
</Button>
168+
/>
76169
) }
77170
{ 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>
171+
<CancelMigrationModal
172+
closeModal={ closeModal }
173+
handleCancelMigration={ handleCancelMigration }
174+
siteId={ siteId }
175+
isMigrationInProgress={ isMigrationInProgress }
176+
/>
98177
) }
99178
</div>
100179
);

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)