diff --git a/projects/packages/videopress/changelog/fix-videopress-delete-last-video b/projects/packages/videopress/changelog/fix-videopress-delete-last-video new file mode 100644 index 0000000000000..d11d43fbd4bb8 --- /dev/null +++ b/projects/packages/videopress/changelog/fix-videopress-delete-last-video @@ -0,0 +1,4 @@ +Significance: patch +Type: changed + +VideoPress: Fix exception when deleting last video of page diff --git a/projects/packages/videopress/src/client/admin/components/admin-page/index.tsx b/projects/packages/videopress/src/client/admin/components/admin-page/index.tsx index 368a22ef3f064..f54c729c842f0 100644 --- a/projects/packages/videopress/src/client/admin/components/admin-page/index.tsx +++ b/projects/packages/videopress/src/client/admin/components/admin-page/index.tsx @@ -22,7 +22,7 @@ import { FormFileUpload } from '@wordpress/components'; import { useDispatch } from '@wordpress/data'; import { __ } from '@wordpress/i18n'; import classnames from 'classnames'; -import { useEffect, useState } from 'react'; +import { useEffect, useRef, useState } from 'react'; /** * Internal dependencies */ @@ -58,11 +58,15 @@ const useDashboardVideos = () => { const { items: localVideos, uploadedLocalVideoCount } = useLocalVideos(); const { hasVideoPressPurchase } = usePlan(); + // Use a tempPage to catch changes in page from store and not URL + const tempPage = useRef( page ); + /** Get the page number from the search parameters and set it to the state when the state is outdated */ const searchParams = useSearchParams(); const pageFromSearchParam = parseInt( searchParams.getParam( 'page', '1' ) ); const searchFromSearchParam = searchParams.getParam( 'q', '' ); const totalOfPages = Math.ceil( total / itemsPerPage ); + useEffect( () => { // when there are no search results, ensure that the current page number is 1 if ( total === 0 && pageFromSearchParam !== 1 ) { @@ -82,9 +86,18 @@ const useDashboardVideos = () => { // react to a page param change if ( page !== pageFromSearchParam ) { - setVideosQuery( { - page: pageFromSearchParam, - } ); + // store changed and not url + // update url to match store update + if ( page !== tempPage.current ) { + tempPage.current = page; + searchParams.setParam( 'page', page ); + searchParams.update(); + } else { + tempPage.current = pageFromSearchParam; + setVideosQuery( { + page: pageFromSearchParam, + } ); + } return; } @@ -97,7 +110,7 @@ const useDashboardVideos = () => { return; } - }, [ totalOfPages, page, pageFromSearchParam, search, searchFromSearchParam ] ); + }, [ totalOfPages, page, pageFromSearchParam, search, searchFromSearchParam, tempPage.current ] ); // Do not show uploading videos if not in the first page or searching let videos = page > 1 || Boolean( search ) ? items : [ ...uploading, ...items ]; diff --git a/projects/packages/videopress/src/client/state/actions.js b/projects/packages/videopress/src/client/state/actions.js index 90f627ab6ad92..2d219a97d7237 100644 --- a/projects/packages/videopress/src/client/state/actions.js +++ b/projects/packages/videopress/src/client/state/actions.js @@ -50,6 +50,7 @@ import { SET_VIDEO_UPLOAD_PROGRESS, SET_VIDEOPRESS_SETTINGS, WP_REST_API_VIDEOPRESS_SETTINGS_ENDPOINT, + UPDATE_PAGINATION_AFTER_DELETE, } from './constants'; import { mapVideoFromWPV2MediaEndpoint } from './utils/map-videos'; @@ -220,9 +221,11 @@ const deleteVideo = id => async ( { dispatch } ) => { // dispach action to invalidate the cache if ( ! resp?.deleted ) { - return dispatch( { type: DELETE_VIDEO, id, hasBeenDeleted: false, video: {} } ); + dispatch( { type: DELETE_VIDEO, id, hasBeenDeleted: false, video: {} } ); + } else { + dispatch( { type: UPDATE_PAGINATION_AFTER_DELETE } ); + dispatch( { type: DELETE_VIDEO, id, hasBeenDeleted: true, video: resp?.previous } ); } - dispatch( { type: DELETE_VIDEO, id, hasBeenDeleted: true, video: resp?.previous } ); } catch ( error ) { // @todo: implement error handling / UI console.error( error ); // eslint-disable-line no-console diff --git a/projects/packages/videopress/src/client/state/constants.js b/projects/packages/videopress/src/client/state/constants.js index f339886e3afa1..194f75dc98536 100644 --- a/projects/packages/videopress/src/client/state/constants.js +++ b/projects/packages/videopress/src/client/state/constants.js @@ -40,6 +40,7 @@ export const SET_VIDEO_PRIVACY = 'SET_VIDEO_PRIVACY'; export const UPDATE_VIDEO_PRIVACY = 'UPDATE_VIDEO_PRIVACY'; export const DELETE_VIDEO = 'DELETE_VIDEO'; export const REMOVE_VIDEO = 'REMOVE_VIDEO'; +export const UPDATE_PAGINATION_AFTER_DELETE = 'UPDATE_PAGINATION_AFTER_DELETE'; export const SET_VIDEO_UPLOADING = 'SET_VIDEO_UPLOADING'; export const SET_VIDEO_PROCESSING = 'SET_VIDEO_PROCESSING'; diff --git a/projects/packages/videopress/src/client/state/reducers.js b/projects/packages/videopress/src/client/state/reducers.js index 167fd5d0441bd..8353bd55a8440 100644 --- a/projects/packages/videopress/src/client/state/reducers.js +++ b/projects/packages/videopress/src/client/state/reducers.js @@ -41,6 +41,7 @@ import { EXPIRE_PLAYBACK_TOKEN, SET_VIDEOPRESS_SETTINGS, DISMISS_FIRST_VIDEO_POPOVER, + UPDATE_PAGINATION_AFTER_DELETE, } from './constants'; /** @@ -294,6 +295,38 @@ const videos = ( state, action ) => { }; } + /* + * Check if query and pagination should change + * after deleting video + */ + case UPDATE_PAGINATION_AFTER_DELETE: { + const { items = [], query = {}, pagination = {} } = state; + + // If is the last video, reduce the page per 1 + // Being optimistic here + const isLastVideo = items?.length === 1; + const currentPage = query?.page ?? 1; + const currentTotalPage = pagination?.totalPages ?? 1; + const currentTotal = pagination?.total; + + const page = isLastVideo && currentPage > 1 ? currentPage - 1 : currentPage; + const totalPages = + isLastVideo && currentTotalPage > 1 ? currentTotalPage - 1 : currentTotalPage; + + return { + ...state, + query: { + ...query, + page, + }, + pagination: { + ...pagination, + total: currentTotal - 1, + totalPages, + }, + }; + } + case SET_VIDEOS_STORAGE_USED: { return { ...state,