Back

0% Statements 0/32
0% Branches 0/22
0% Functions 0/8
0% Lines 0/32

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92                                                                                                                                                                                       
import { useMutation, useQuery } from '@tanstack/react-query';
import { useCallback, useState } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { fetchDownloadStatus, initiateDownload } from '../data/api/download';
import { keys } from '../data/query-client';
import type { RestoreItems } from '../types/restore';
 
type DownloadState =
	| { phase: 'idle' }
	| { phase: 'submitting' }
	| { phase: 'progress'; percent: number }
	| { phase: 'success'; downloadUrl: string }
	| { phase: 'error'; message: string };
 
type Result = {
	state: DownloadState;
	submit: ( items: RestoreItems ) => void;
	reset: () => void;
};
 
const POLL_INTERVAL_MS = 1500;
 
/**
 * Real `useDownload` driving the modernized Download screen via the
 * `/jetpack/v4/backups/download/$rewindId` bridge.
 *
 * Submit kicks off the WPCOM `prepare-download` and stores the download
 * id; a polled status query then advances the state machine
 * idle → submitting → progress → success | error.
 *
 * @param rewindId - The backup's rewind id.
 * @return state + submit + reset.
 */
export function useDownload( rewindId: string ): Result {
	const [ downloadId, setDownloadId ] = useState< number | null >( null );
	const [ errorMessage, setErrorMessage ] = useState< string | null >( null );
 
	const {
		mutate: mutateInitiate,
		reset: resetMutation,
		isPending: isInitiating,
	} = useMutation( {
		mutationFn: ( items: RestoreItems ) => initiateDownload( rewindId, items ),
		onSuccess: result => {
			setDownloadId( result.id );
			setErrorMessage( null );
		},
		onError: ( err: Error ) => {
			setErrorMessage( err.message );
		},
	} );
 
	const effectiveDownloadId = downloadId ?? -1;
	const statusQuery = useQuery( {
		queryKey: keys.downloadStatus( rewindId, effectiveDownloadId ),
		queryFn: () => fetchDownloadStatus( rewindId, effectiveDownloadId ),
		enabled: downloadId !== null,
		refetchInterval: query =>
			query.state.data?.status === 'in-progress' ? POLL_INTERVAL_MS : false,
	} );
 
	const submit = useCallback(
		( items: RestoreItems ) => mutateInitiate( items ),
		[ mutateInitiate ]
	);
	const reset = useCallback( () => {
		setDownloadId( null );
		setErrorMessage( null );
		resetMutation();
	}, [ resetMutation ] );
 
	let state: DownloadState = { phase: 'idle' };
	if ( errorMessage ) {
		state = { phase: 'error', message: errorMessage };
	} else if ( isInitiating ) {
		state = { phase: 'submitting' };
	} else if ( statusQuery.data?.status === 'completed' && statusQuery.data.url ) {
		state = { phase: 'success', downloadUrl: statusQuery.data.url };
	} else if ( statusQuery.data?.status === 'failed' ) {
		state = { phase: 'error', message: __( 'Download failed.', 'jetpack-backup-pkg' ) };
	} else if ( downloadId !== null && statusQuery.data ) {
		state = {
			phase: 'progress',
			percent: Math.round( ( statusQuery.data.progress ?? 0 ) * 100 ),
		};
	} else if ( downloadId !== null ) {
		state = { phase: 'progress', percent: 0 };
	}
 
	return { state, submit, reset };
}