Skip to content

Commit

Permalink
VideoPress: Enhance behavior when deleting multiple videos (#28302)
Browse files Browse the repository at this point in the history
* refactor delete action adding FLUSH_DELETED_VIDEOS

* changelog

* fix removedVideoCount processing order

* enhancements from code review

* remove videosBeingRemovedCount
  • Loading branch information
dhasilva authored Jan 12, 2023
1 parent 394ee81 commit a000af6
Show file tree
Hide file tree
Showing 7 changed files with 78 additions and 20 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: patch
Type: fixed

VideoPress: Enhance behavior when deleting multiple videos
3 changes: 2 additions & 1 deletion projects/packages/videopress/src/class-data.php
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,8 @@ function ( $video ) {
),
'query' => $videopress_data['query'],
'_meta' => array(
'relyOnInitialState' => true,
'processedAllVideosBeingRemoved' => true,
'relyOnInitialState' => true,
),
),
'localVideos' => array(
Expand Down
21 changes: 15 additions & 6 deletions projects/packages/videopress/src/client/state/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ import {
SET_VIDEOPRESS_SETTINGS,
WP_REST_API_VIDEOPRESS_SETTINGS_ENDPOINT,
UPDATE_PAGINATION_AFTER_DELETE,
FLUSH_DELETED_VIDEOS,
} from './constants';
import { mapVideoFromWPV2MediaEndpoint } from './utils/map-videos';

Expand Down Expand Up @@ -204,11 +205,13 @@ const removeVideo = id => {
* @param {string|number} id - Video post ID
* @returns {Function} Thunk action
*/
const deleteVideo = id => async ( { dispatch } ) => {
const deleteVideo = id => async ( { dispatch, select } ) => {
// Let's be optimistic and update the UI right away.
// @todo: Add a loading state to the state/UI.
dispatch.removeVideo( id );

let deleteAction = { type: DELETE_VIDEO, id, hasBeenDeleted: false, video: {} };

try {
const resp = await apiFetch( {
path: `${ WP_REST_API_MEDIA_ENDPOINT }/${ id }`,
Expand All @@ -220,15 +223,21 @@ const deleteVideo = id => async ( { dispatch } ) => {
} );

// dispach action to invalidate the cache
if ( ! resp?.deleted ) {
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 } );
if ( resp?.deleted ) {
deleteAction = { ...deleteAction, hasBeenDeleted: true, video: resp?.previous };
}
} catch ( error ) {
// @todo: implement error handling / UI
console.error( error ); // eslint-disable-line no-console
} finally {
dispatch( deleteAction );
}

const processedAllVideosBeingRemoved = select.getProcessedAllVideosBeingRemoved();

if ( processedAllVideosBeingRemoved ) {
dispatch( { type: UPDATE_PAGINATION_AFTER_DELETE } );
dispatch( { type: FLUSH_DELETED_VIDEOS } );
}
};

Expand Down
1 change: 1 addition & 0 deletions projects/packages/videopress/src/client/state/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 FLUSH_DELETED_VIDEOS = 'FLUSH_DELETED_VIDEOS';
export const UPDATE_PAGINATION_AFTER_DELETE = 'UPDATE_PAGINATION_AFTER_DELETE';

export const SET_VIDEO_UPLOADING = 'SET_VIDEO_UPLOADING';
Expand Down
52 changes: 42 additions & 10 deletions projects/packages/videopress/src/client/state/reducers.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import {
EXPIRE_PLAYBACK_TOKEN,
SET_VIDEOPRESS_SETTINGS,
DISMISS_FIRST_VIDEO_POPOVER,
FLUSH_DELETED_VIDEOS,
UPDATE_PAGINATION_AFTER_DELETE,
} from './constants';

Expand Down Expand Up @@ -247,10 +248,14 @@ const videos = ( state, action ) => {
return {
...state,
// Do not remove the video from the list, just update the meta data.
// Keep here in caswe we want to do it in the future.
// Keep here in case we want to do it in the future.
// items: [ ...state.items.slice( 0, videoIndex ), ...state.items.slice( videoIndex + 1 ) ],
_meta: {
...state._meta,
videosBeingRemoved: [
{ id, processed: false, deleted: false },
...( state._meta.videosBeingRemoved ?? [] ),
],
items: {
..._metaItems,
[ id ]: {
Expand All @@ -270,23 +275,37 @@ const videos = ( state, action ) => {
const { id, hasBeenDeleted, video: deletedVideo } = action;
const _metaItems = state?._meta?.items || [];
const _metaVideo = _metaItems[ id ] || {};
const uploadedVideoCount = state.uploadedVideoCount - 1;
const videosBeingRemoved = [ ...( state._meta.videosBeingRemoved ?? [] ) ];
const removedVideoIndex = videosBeingRemoved.findIndex( item => item.id === id );

if ( ! _metaVideo ) {
if ( ! _metaVideo || removedVideoIndex < 0 ) {
return state;
}

videosBeingRemoved[ removedVideoIndex ].processed = true;
videosBeingRemoved[ removedVideoIndex ].deleted = hasBeenDeleted;

const processedAllVideosBeingRemoved =
videosBeingRemoved.filter( item => ! item.processed ).length === 0;

let uploadedVideoCount = state.uploadedVideoCount ?? 0;

if ( processedAllVideosBeingRemoved ) {
const videosBeingRemovedCount = videosBeingRemoved.filter( item => item.deleted ).length;
uploadedVideoCount = uploadedVideoCount - videosBeingRemovedCount;
}

return {
...state,
uploadedVideoCount,
_meta: {
...state._meta,
relyOnInitialState: false,
videosBeingRemoved,
processedAllVideosBeingRemoved,
items: {
..._metaItems,
[ id ]: {
..._metaVideo,
isDeleting: false,
hasBeenDeleted,
deletedVideo,
},
Expand All @@ -295,23 +314,36 @@ const videos = ( state, action ) => {
};
}

case FLUSH_DELETED_VIDEOS: {
return {
...state,
_meta: {
...state._meta,
videosBeingRemoved: [],
relyOnInitialState: false,
},
};
}

/*
* Check if query and pagination should change
* after deleting video
*/
case UPDATE_PAGINATION_AFTER_DELETE: {
const { items = [], query = {}, pagination = {} } = state;
const { items = [], query = {}, pagination = {}, _meta = {} } = state;
const { videosBeingRemoved = [] } = _meta;
const videosBeingRemovedCount = videosBeingRemoved.filter( item => item.deleted ).length;

// If is the last video, reduce the page per 1
// If the last videos of the page are deleted, reduce the page by 1
// Being optimistic here
const isLastVideo = items?.length === 1;
const areLastVideos = items?.length === videosBeingRemovedCount;
const currentPage = query?.page ?? 1;
const currentTotalPage = pagination?.totalPages ?? 1;
const currentTotal = pagination?.total;

const page = isLastVideo && currentPage > 1 ? currentPage - 1 : currentPage;
const page = areLastVideos && currentPage > 1 ? currentPage - 1 : currentPage;
const totalPages =
isLastVideo && currentTotalPage > 1 ? currentTotalPage - 1 : currentTotalPage;
areLastVideos && currentTotalPage > 1 ? currentTotalPage - 1 : currentTotalPage;

return {
...state,
Expand Down
12 changes: 9 additions & 3 deletions projects/packages/videopress/src/client/state/resolvers.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
SET_VIDEOS_QUERY,
SET_VIDEOS_FILTER,
WP_REST_API_MEDIA_ENDPOINT,
DELETE_VIDEO,
FLUSH_DELETED_VIDEOS,
REST_API_SITE_INFO_ENDPOINT,
SET_VIDEO_PROCESSING,
SET_LOCAL_VIDEOS_QUERY,
Expand Down Expand Up @@ -164,8 +164,9 @@ const getVideos = {
console.error( error ); // eslint-disable-line no-console
}
},

shouldInvalidate: ( { type } ) => {
return type === SET_VIDEOS_QUERY || type === DELETE_VIDEO || type === SET_VIDEOS_FILTER;
return type === SET_VIDEOS_QUERY || type === FLUSH_DELETED_VIDEOS || type === SET_VIDEOS_FILTER;
},
};

Expand All @@ -189,6 +190,7 @@ const getVideo = {

return video;
},

fulfill: id => async ( { dispatch, resolveSelect } ) => {
dispatch.setIsFetchingVideos( true );

Expand Down Expand Up @@ -241,7 +243,7 @@ const getUploadedVideoCount = {
},

shouldInvalidate: action => {
return action.type === SET_VIDEO_PROCESSING || action.type === DELETE_VIDEO;
return action.type === SET_VIDEO_PROCESSING || action.type === FLUSH_DELETED_VIDEOS;
},
};

Expand Down Expand Up @@ -323,6 +325,7 @@ const getLocalVideos = {
console.error( error ); // eslint-disable-line no-console
}
},

shouldInvalidate: action => {
return action.type === SET_LOCAL_VIDEOS_QUERY;
},
Expand Down Expand Up @@ -371,6 +374,7 @@ const getPlaybackToken = {
const playbackTokens = state?.playbackTokens?.items ?? [];
return playbackTokens?.some( token => token?.guid === guid );
},

fulfill: guid => async ( { dispatch } ) => {
dispatch.setIsFetchingPlaybackToken( true );

Expand All @@ -393,6 +397,7 @@ const getPlaybackToken = {
console.error( error ); // eslint-disable-line no-console
}
},

shouldInvalidate: ( action, guid ) => {
return action.type === EXPIRE_PLAYBACK_TOKEN && action.guid === guid;
},
Expand All @@ -402,6 +407,7 @@ const getVideoPressSettings = {
isFulfilled: state => {
return state?.siteSettings !== undefined;
},

fulfill: () => async ( { dispatch } ) => {
try {
const { videopress_videos_private_for_site: videoPressVideosPrivateForSite } = await apiFetch(
Expand Down
5 changes: 5 additions & 0 deletions projects/packages/videopress/src/client/state/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ export const getDismissedFirstVideoPopover = state => {
return state?.videos?.dismissedFirstVideoPopover;
};

export const getProcessedAllVideosBeingRemoved = state => {
return state?.videos?._meta?.processedAllVideosBeingRemoved;
};

// Single Video stuff
export const getVideo = ( state, id ) => {
const videos = getVideos( state );
Expand Down Expand Up @@ -128,6 +132,7 @@ const selectors = {
getFirstUploadedVideoId,
getFirstVideoProcessed,
getDismissedFirstVideoPopover,
getProcessedAllVideosBeingRemoved,

// Local videos
getLocalVideos,
Expand Down

0 comments on commit a000af6

Please sign in to comment.