Skip to content

Commit

Permalink
Backup: render BackupRealtimeMessage component for displaying backup …
Browse files Browse the repository at this point in the history
…real-time info in restore page (#94218)

* feat: Add BackupRealtimeMessage component for displaying backup realtime information

* Render `BackupRealtimeMessage` on successful backup view

* Add unit tests for BackupRealtimeMessage component

* feat: Update BackupRealtimeMessage component to use baseBackupDate instead of backupDate

The BackupRealtimeMessage component has been updated to use the baseBackupDate prop instead of the backupDate prop. This change ensures that the correct backup date is displayed in the message. Also we are adding `selectedBackupDate` to use instead of `today` date.

* Refactor BackupSuccessful component to pass selectedBackupDate to BackupRealtimeMessage

* Remove redundant message scenario

* Replace `today` with `selectedBackupDate`

* Refactor BackupRealtimeMessage component to receive baseBackupDate as a Moment object

* Refactor BackupRealtimeMessage unit tests to consider latest changes

* Update test descriptions

* Improve unit test description grammar

* Improve showRealTimeMessage validation

* Remove `baseBackupDate` comment

* Refactor `BackupRealtimeMessage` conditions to improve readability and clarity

* Add real-time message on restore page

* Adjust CSS spacing on restore backup to properly fit realtime message

* BackupRealtimeMessage: add `Learn more` link

* BackupRealtimeMessage: update unit tests to consider the new Learn more link

* BackupRealtimeMessage: update unit tests comments

* Restore page: render real-time message under a feature flag
  • Loading branch information
Initsogar authored Sep 6, 2024
1 parent 2d532e4 commit c393d88
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 11 deletions.
Original file line number Diff line number Diff line change
@@ -1,21 +1,31 @@
import { useCallback } from '@wordpress/element';
import { useTranslate } from 'i18n-calypso';
import { FunctionComponent } from 'react';
import { useLocalizedMoment } from 'calypso/components/localized-moment';
import { useDispatch } from 'calypso/state';
import { recordTracksEvent } from 'calypso/state/analytics/actions/record';
import type { Moment } from 'moment';

type Props = {
baseBackupDate: Moment;
eventsCount: number;
selectedBackupDate: Moment;
learnMoreUrl?: string;
};

export const BackupRealtimeMessage: FunctionComponent< Props > = ( {
baseBackupDate,
eventsCount,
selectedBackupDate,
learnMoreUrl,
} ) => {
const translate = useTranslate();
const moment = useLocalizedMoment();
const dispatch = useDispatch();

const onLearnMoreClick = useCallback( () => {
dispatch( recordTracksEvent( 'calypso_jetpack_backup_realtime_message_learn_more_click' ) );
}, [ dispatch ] );

if (
! moment.isMoment( baseBackupDate ) ||
Expand Down Expand Up @@ -76,5 +86,17 @@ export const BackupRealtimeMessage: FunctionComponent< Props > = ( {
);
}

return <>{ message }</>;
return (
<p>
{ message }
{ learnMoreUrl && (
<>
{ ' ' }
<a href={ learnMoreUrl } onClick={ onLearnMoreClick }>
{ translate( 'Learn more' ) }
</a>
</>
) }
</p>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,33 +4,40 @@
import { render } from '@testing-library/react';
import { useTranslate } from 'i18n-calypso';
import moment from 'moment';
import { useDispatch } from 'calypso/state';
import { BackupRealtimeMessage } from '../status-card/backup-realtime-message';

// Mock the useTranslate function
jest.mock( 'i18n-calypso' );
jest.mock( 'i18n-calypso' ); // Mock the useTranslate hook
jest.mock( 'calypso/state' ); // Mock the useDispatch hook

describe( 'BackupRealtimeMessage', () => {
const renderMessage = ( baseBackupDate, eventsCount, selectedDate ) => {
const renderMessage = ( baseBackupDate, eventsCount, selectedDate, learnMoreUrl ) => {
return render(
<BackupRealtimeMessage
baseBackupDate={ baseBackupDate }
eventsCount={ eventsCount }
selectedBackupDate={ selectedDate }
learnMoreUrl={ learnMoreUrl } // Optional `Learn more` link
/>
);
};

const translateMock = jest.fn( ( singular, plural, { count, args } ) => {
const translatedText = count === 1 ? singular : plural;
const translateMock = jest.fn( ( singular, plural, options ) => {
if ( options === undefined ) {
return singular;
}

const translatedText = options.count === 1 ? singular : plural;
return translatedText
.replace( '%(baseBackupDate)s', args.baseBackupDate )
.replace( '%(eventsCount)d', args.eventsCount )
.replace( '%(daysAgo)d', args.daysAgo );
.replace( '%(baseBackupDate)s', options.args.baseBackupDate )
.replace( '%(eventsCount)d', options.args.eventsCount )
.replace( '%(daysAgo)d', options.args.daysAgo );
} );

beforeEach( () => {
jest.clearAllMocks();
useTranslate.mockImplementation( () => translateMock );
useDispatch.mockImplementation( () => jest.fn() );
} );

test( 'renders the correct message when the base backup date is the same as the selected backup date', () => {
Expand Down Expand Up @@ -77,4 +84,24 @@ describe( 'BackupRealtimeMessage', () => {
`We are using a full backup from this day (2024-08-26 12:00 PM) with 2 changes you have made since then until now.`
);
} );

test( 'renders the correct message and the "Learn more" link when learnMoreUrl is provided', () => {
useTranslate.mockImplementation( () => translateMock );

const selectedDate = moment( '2024-08-26T12:00:00Z' );
const baseBackupDate = moment( '2024-08-26T12:00:00Z' );
const learnMoreUrl = '/learn-more';

const { container, getByText } = renderMessage( baseBackupDate, 3, selectedDate, learnMoreUrl );

// Verify the message content
expect( container.textContent ).toContain(
'We are using a full backup from this day (2024-08-26 12:00 PM) with 3 changes you have made since then until now.'
);

// Verify the `Learn more` link is rendered
const learnMoreLink = getByText( 'Learn more' );
expect( learnMoreLink ).toBeInTheDocument();
expect( learnMoreLink.getAttribute( 'href' ) ).toBe( learnMoreUrl );
} );
} );
1 change: 1 addition & 0 deletions client/my-sites/backup/rewind-flow/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ const BackupRewindFlow: FunctionComponent< Props > = ( { rewindId, purpose } ) =
if ( purpose === RewindFlowPurpose.RESTORE ) {
return (
<BackupRestoreFlow
backup={ activityQuery.data }
backupDisplayDate={ backupDisplayDate }
rewindId={ rewindId }
siteId={ siteId }
Expand Down
16 changes: 16 additions & 0 deletions client/my-sites/backup/rewind-flow/restore.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import QueryJetpackCredentialsStatus from 'calypso/components/data/query-jetpack
import QueryRewindBackups from 'calypso/components/data/query-rewind-backups';
import QueryRewindRestoreStatus from 'calypso/components/data/query-rewind-restore-status';
import QueryRewindState from 'calypso/components/data/query-rewind-state';
import { BackupRealtimeMessage } from 'calypso/components/jetpack/daily-backup-status/status-card/backup-realtime-message';
import { useLocalizedMoment } from 'calypso/components/localized-moment';
import { Interval, EVERY_FIVE_SECONDS } from 'calypso/lib/interval';
import { backupPath, settingsPath } from 'calypso/lib/jetpack/paths';
import { useDispatch, useSelector } from 'calypso/state';
Expand Down Expand Up @@ -48,20 +50,23 @@ import type { RestoreProgress } from 'calypso/state/data-layer/wpcom/activity-lo
import type { RewindState } from 'calypso/state/data-layer/wpcom/sites/rewind/type';

interface Props {
backup: any;
backupDisplayDate: string;
rewindId: string;
siteId: number;
siteUrl: string;
}

const BackupRestoreFlow: FunctionComponent< Props > = ( {
backup,
backupDisplayDate,
rewindId,
siteId,
siteUrl,
} ) => {
const dispatch = useDispatch();
const translate = useTranslate();
const moment = useLocalizedMoment();

const [ rewindConfig, setRewindConfig ] = useState< RewindConfig >( defaultRewindConfig );

Expand Down Expand Up @@ -223,6 +228,10 @@ const BackupRestoreFlow: FunctionComponent< Props > = ( {
( ! isAtomic && areCredentialsInvalid ) ||
Object.values( rewindConfig ).every( ( setting ) => ! setting );

const selectedDate = moment( rewindId, 'X' );
const baseBackupDate = backup.baseRewindId ? moment.unix( backup.baseRewindId ) : null;
const showRealTimeMessage = backup.baseRewindId && baseBackupDate && backup.rewindStepCount > 0;

const renderConfirm = () => (
<>
{ ! isAtomic && <QueryJetpackCredentialsStatus siteId={ siteId } role="main" /> }
Expand All @@ -240,6 +249,13 @@ const BackupRestoreFlow: FunctionComponent< Props > = ( {
},
} ) }
</p>
{ config.isEnabled( 'jetpack/backup-realtime-message' ) && showRealTimeMessage && (
<BackupRealtimeMessage
baseBackupDate={ baseBackupDate }
eventsCount={ backup.rewindStepCount }
selectedBackupDate={ selectedDate }
/>
) }
<h4 className="rewind-flow__cta">{ translate( 'Choose the items you wish to restore:' ) }</h4>
<RewindConfigEditor currentConfig={ rewindConfig } onConfigChange={ setRewindConfig } />
<RewindFlowNotice
Expand Down
6 changes: 4 additions & 2 deletions client/my-sites/backup/rewind-flow/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
.rewind-flow__title {
font-size: 2.25rem;
line-height: 36px;
padding-bottom: 48px;
padding-bottom: 12px;
text-align: left;

&.error {
Expand Down Expand Up @@ -203,8 +203,10 @@ a.rewind-flow-notice__title-warning:visited {

.rewind-flow__info,
.rewind-flow__cta,
.rewind-flow-notice__title-warning h4 {
.rewind-flow-notice__title-warning h4,
.rewind-flow__content p {
font-size: 0.875rem;
margin-bottom: 1em;
}

.rewind-flow__cta {
Expand Down

0 comments on commit c393d88

Please sign in to comment.