mirror of
https://github.com/mediacms-io/mediacms.git
synced 2026-03-11 07:27:22 -04:00
a
This commit is contained in:
@@ -9,14 +9,15 @@ interface BulkActionsDropdownProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const BULK_ACTIONS = [
|
const BULK_ACTIONS = [
|
||||||
{ value: 'add-remove-coviewers', label: translateString('Add / Remove Co-Viewers'), enabled: true },
|
{ value: 'add-remove-coviewers', label: inEmbeddedApp() ? translateString('Share with Co-Viewers') : translateString('Add / Remove Co-Viewers'), enabled: true },
|
||||||
{ value: 'add-remove-coeditors', label: translateString('Add / Remove Co-Editors'), enabled: true },
|
{ value: 'add-remove-coeditors', label: inEmbeddedApp() ? translateString('Share with Co-Editors') : translateString('Add / Remove Co-Editors'), enabled: true },
|
||||||
{ value: 'add-remove-coowners', label: translateString('Add / Remove Co-Owners'), enabled: true },
|
{ value: 'add-remove-coowners', label: inEmbeddedApp() ? translateString('Share with Co-Owners') : translateString('Add / Remove Co-Owners'), enabled: true },
|
||||||
{ value: 'add-remove-playlist', label: translateString('Add to / Remove from Playlist'), enabled: true },
|
{ value: 'add-remove-playlist', label: translateString('Add to / Remove from Playlist'), enabled: true },
|
||||||
{ value: 'add-remove-category', label: inEmbeddedApp() ? translateString('Share with Course') : translateString('Add to / Remove from Category'), enabled: true },
|
{ value: 'add-remove-category', label: inEmbeddedApp() ? translateString('Share with Course Members') : translateString('Add to / Remove from Category'), enabled: true },
|
||||||
{ value: 'add-remove-tags', label: translateString('Add / Remove Tags'), enabled: true },
|
{ value: 'add-remove-tags', label: translateString('Add / Remove Tags'), enabled: true },
|
||||||
{ value: 'enable-comments', label: translateString('Enable Comments'), enabled: true },
|
{ value: 'enable-comments', label: translateString('Enable Comments'), enabled: true },
|
||||||
{ value: 'disable-comments', label: translateString('Disable Comments'), enabled: true },
|
{ value: 'disable-comments', label: translateString('Disable Comments'), enabled: true },
|
||||||
|
{ value: 'delete-comments', label: translateString('Delete Comments'), enabled: true },
|
||||||
{ value: 'enable-download', label: translateString('Enable Download'), enabled: true },
|
{ value: 'enable-download', label: translateString('Enable Download'), enabled: true },
|
||||||
{ value: 'disable-download', label: translateString('Disable Download'), enabled: true },
|
{ value: 'disable-download', label: translateString('Disable Download'), enabled: true },
|
||||||
{ value: 'publish-state', label: translateString('Publish State'), enabled: true },
|
{ value: 'publish-state', label: translateString('Publish State'), enabled: true },
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { PageStore, ProfilePageStore } from '../utils/stores/';
|
|||||||
import ProfilePagesHeader from '../components/profile-page/ProfilePagesHeader';
|
import ProfilePagesHeader from '../components/profile-page/ProfilePagesHeader';
|
||||||
import ProfilePagesContent from '../components/profile-page/ProfilePagesContent';
|
import ProfilePagesContent from '../components/profile-page/ProfilePagesContent';
|
||||||
import { MediaListRow } from '../components/MediaListRow';
|
import { MediaListRow } from '../components/MediaListRow';
|
||||||
import { ProfileMediaPage } from './ProfileMediaPage';
|
import { ProfileMediaPageBase } from './ProfileMediaPage';
|
||||||
|
|
||||||
class ChannelContactForm extends React.PureComponent {
|
class ChannelContactForm extends React.PureComponent {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
@@ -149,7 +149,7 @@ class ChannelContactForm extends React.PureComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ProfileAboutPage extends ProfileMediaPage {
|
export class ProfileAboutPage extends ProfileMediaPageBase {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props, 'author-about');
|
super(props, 'author-about');
|
||||||
|
|
||||||
|
|||||||
@@ -7,9 +7,9 @@ import { MediaListWrapper } from '../components/MediaListWrapper';
|
|||||||
import ProfilePagesHeader from '../components/profile-page/ProfilePagesHeader';
|
import ProfilePagesHeader from '../components/profile-page/ProfilePagesHeader';
|
||||||
import ProfilePagesContent from '../components/profile-page/ProfilePagesContent';
|
import ProfilePagesContent from '../components/profile-page/ProfilePagesContent';
|
||||||
import { LazyLoadItemListAsync } from '../components/item-list/LazyLoadItemListAsync.jsx';
|
import { LazyLoadItemListAsync } from '../components/item-list/LazyLoadItemListAsync.jsx';
|
||||||
import { ProfileMediaPage } from './ProfileMediaPage';
|
import { ProfileMediaPageBase } from './ProfileMediaPage';
|
||||||
|
|
||||||
export class ProfileHistoryPage extends ProfileMediaPage {
|
export class ProfileHistoryPage extends ProfileMediaPageBase {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props, 'author-history');
|
super(props, 'author-history');
|
||||||
|
|
||||||
|
|||||||
@@ -7,9 +7,9 @@ import { MediaListWrapper } from '../components/MediaListWrapper';
|
|||||||
import ProfilePagesHeader from '../components/profile-page/ProfilePagesHeader';
|
import ProfilePagesHeader from '../components/profile-page/ProfilePagesHeader';
|
||||||
import ProfilePagesContent from '../components/profile-page/ProfilePagesContent';
|
import ProfilePagesContent from '../components/profile-page/ProfilePagesContent';
|
||||||
import { LazyLoadItemListAsync } from '../components/item-list/LazyLoadItemListAsync';
|
import { LazyLoadItemListAsync } from '../components/item-list/LazyLoadItemListAsync';
|
||||||
import { ProfileMediaPage } from './ProfileMediaPage';
|
import { ProfileMediaPageBase } from './ProfileMediaPage';
|
||||||
|
|
||||||
export class ProfileLikedPage extends ProfileMediaPage {
|
export class ProfileLikedPage extends ProfileMediaPageBase {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props, 'author-liked');
|
super(props, 'author-liked');
|
||||||
|
|
||||||
|
|||||||
@@ -8,22 +8,17 @@ import { MediaListWrapper } from '../components/MediaListWrapper';
|
|||||||
import ProfilePagesHeader from '../components/profile-page/ProfilePagesHeader';
|
import ProfilePagesHeader from '../components/profile-page/ProfilePagesHeader';
|
||||||
import ProfilePagesContent from '../components/profile-page/ProfilePagesContent';
|
import ProfilePagesContent from '../components/profile-page/ProfilePagesContent';
|
||||||
import { LazyLoadItemListAsync } from '../components/item-list/LazyLoadItemListAsync';
|
import { LazyLoadItemListAsync } from '../components/item-list/LazyLoadItemListAsync';
|
||||||
import { BulkActionConfirmModal } from '../components/BulkActionConfirmModal';
|
import { BulkActionsModals } from '../components/BulkActionsModals';
|
||||||
import { BulkActionPermissionModal } from '../components/BulkActionPermissionModal';
|
|
||||||
import { BulkActionPlaylistModal } from '../components/BulkActionPlaylistModal';
|
|
||||||
import { BulkActionChangeOwnerModal } from '../components/BulkActionChangeOwnerModal';
|
|
||||||
import { BulkActionPublishStateModal } from '../components/BulkActionPublishStateModal';
|
|
||||||
import { BulkActionCategoryModal } from '../components/BulkActionCategoryModal';
|
|
||||||
import { BulkActionTagModal } from '../components/BulkActionTagModal';
|
|
||||||
import { ProfileMediaFilters } from '../components/search-filters/ProfileMediaFilters';
|
import { ProfileMediaFilters } from '../components/search-filters/ProfileMediaFilters';
|
||||||
import { ProfileMediaTags } from '../components/search-filters/ProfileMediaTags';
|
import { ProfileMediaTags } from '../components/search-filters/ProfileMediaTags';
|
||||||
import { ProfileMediaSorting } from '../components/search-filters/ProfileMediaSorting';
|
import { ProfileMediaSorting } from '../components/search-filters/ProfileMediaSorting';
|
||||||
|
import { withBulkActions } from '../utils/hoc/withBulkActions';
|
||||||
|
|
||||||
import { Page } from './_Page';
|
import { Page } from './_Page';
|
||||||
|
|
||||||
import '../components/profile-page/ProfilePage.scss';
|
import '../components/profile-page/ProfilePage.scss';
|
||||||
|
|
||||||
export class ProfileMediaPage extends Page {
|
class ProfileMediaPage extends Page {
|
||||||
constructor(props, pageSlug) {
|
constructor(props, pageSlug) {
|
||||||
super(props, 'string' === typeof pageSlug ? pageSlug : 'author-home');
|
super(props, 'string' === typeof pageSlug ? pageSlug : 'author-home');
|
||||||
|
|
||||||
@@ -36,15 +31,7 @@ export class ProfileMediaPage extends Page {
|
|||||||
title: this.props.title,
|
title: this.props.title,
|
||||||
query: ProfilePageStore.get('author-query'),
|
query: ProfilePageStore.get('author-query'),
|
||||||
requestUrl: null,
|
requestUrl: null,
|
||||||
selectedMedia: new Set(),
|
selectedMedia: new Set(), // For select media embed mode only
|
||||||
availableMediaIds: [],
|
|
||||||
showConfirmModal: false,
|
|
||||||
pendingAction: null,
|
|
||||||
confirmMessage: '',
|
|
||||||
listKey: 0,
|
|
||||||
notificationMessage: '',
|
|
||||||
showNotification: false,
|
|
||||||
notificationType: 'success',
|
|
||||||
hiddenFilters: true,
|
hiddenFilters: true,
|
||||||
hiddenTags: true,
|
hiddenTags: true,
|
||||||
hiddenSorting: true,
|
hiddenSorting: true,
|
||||||
@@ -52,13 +39,6 @@ export class ProfileMediaPage extends Page {
|
|||||||
availableTags: [],
|
availableTags: [],
|
||||||
selectedTag: 'all',
|
selectedTag: 'all',
|
||||||
selectedSort: 'date_added_desc',
|
selectedSort: 'date_added_desc',
|
||||||
showPermissionModal: false,
|
|
||||||
permissionType: null,
|
|
||||||
showPlaylistModal: false,
|
|
||||||
showChangeOwnerModal: false,
|
|
||||||
showPublishStateModal: false,
|
|
||||||
showCategoryModal: false,
|
|
||||||
showTagModal: false,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
this.authorDataLoad = this.authorDataLoad.bind(this);
|
this.authorDataLoad = this.authorDataLoad.bind(this);
|
||||||
@@ -66,20 +46,6 @@ export class ProfileMediaPage extends Page {
|
|||||||
this.getCountFunc = this.getCountFunc.bind(this);
|
this.getCountFunc = this.getCountFunc.bind(this);
|
||||||
this.changeRequestQuery = this.changeRequestQuery.bind(this);
|
this.changeRequestQuery = this.changeRequestQuery.bind(this);
|
||||||
this.handleMediaSelection = this.handleMediaSelection.bind(this);
|
this.handleMediaSelection = this.handleMediaSelection.bind(this);
|
||||||
this.handleBulkAction = this.handleBulkAction.bind(this);
|
|
||||||
this.handleConfirmCancel = this.handleConfirmCancel.bind(this);
|
|
||||||
this.handleConfirmProceed = this.handleConfirmProceed.bind(this);
|
|
||||||
this.clearSelectionAndRefresh = this.clearSelectionAndRefresh.bind(this);
|
|
||||||
this.clearSelection = this.clearSelection.bind(this);
|
|
||||||
this.executeEnableComments = this.executeEnableComments.bind(this);
|
|
||||||
this.executeDisableComments = this.executeDisableComments.bind(this);
|
|
||||||
this.executeEnableDownload = this.executeEnableDownload.bind(this);
|
|
||||||
this.executeDisableDownload = this.executeDisableDownload.bind(this);
|
|
||||||
this.executeCopyMedia = this.executeCopyMedia.bind(this);
|
|
||||||
this.showNotification = this.showNotification.bind(this);
|
|
||||||
this.handleSelectAll = this.handleSelectAll.bind(this);
|
|
||||||
this.handleDeselectAll = this.handleDeselectAll.bind(this);
|
|
||||||
this.handleItemsUpdate = this.handleItemsUpdate.bind(this);
|
|
||||||
this.onToggleFiltersClick = this.onToggleFiltersClick.bind(this);
|
this.onToggleFiltersClick = this.onToggleFiltersClick.bind(this);
|
||||||
this.onToggleTagsClick = this.onToggleTagsClick.bind(this);
|
this.onToggleTagsClick = this.onToggleTagsClick.bind(this);
|
||||||
this.onToggleSortingClick = this.onToggleSortingClick.bind(this);
|
this.onToggleSortingClick = this.onToggleSortingClick.bind(this);
|
||||||
@@ -87,24 +53,6 @@ export class ProfileMediaPage extends Page {
|
|||||||
this.onTagSelect = this.onTagSelect.bind(this);
|
this.onTagSelect = this.onTagSelect.bind(this);
|
||||||
this.onSortSelect = this.onSortSelect.bind(this);
|
this.onSortSelect = this.onSortSelect.bind(this);
|
||||||
this.onResponseDataLoaded = this.onResponseDataLoaded.bind(this);
|
this.onResponseDataLoaded = this.onResponseDataLoaded.bind(this);
|
||||||
this.handlePermissionModalCancel = this.handlePermissionModalCancel.bind(this);
|
|
||||||
this.handlePermissionModalSuccess = this.handlePermissionModalSuccess.bind(this);
|
|
||||||
this.handlePermissionModalError = this.handlePermissionModalError.bind(this);
|
|
||||||
this.handlePlaylistModalCancel = this.handlePlaylistModalCancel.bind(this);
|
|
||||||
this.handlePlaylistModalSuccess = this.handlePlaylistModalSuccess.bind(this);
|
|
||||||
this.handlePlaylistModalError = this.handlePlaylistModalError.bind(this);
|
|
||||||
this.handleChangeOwnerModalCancel = this.handleChangeOwnerModalCancel.bind(this);
|
|
||||||
this.handleChangeOwnerModalSuccess = this.handleChangeOwnerModalSuccess.bind(this);
|
|
||||||
this.handleChangeOwnerModalError = this.handleChangeOwnerModalError.bind(this);
|
|
||||||
this.handlePublishStateModalCancel = this.handlePublishStateModalCancel.bind(this);
|
|
||||||
this.handlePublishStateModalSuccess = this.handlePublishStateModalSuccess.bind(this);
|
|
||||||
this.handlePublishStateModalError = this.handlePublishStateModalError.bind(this);
|
|
||||||
this.handleCategoryModalCancel = this.handleCategoryModalCancel.bind(this);
|
|
||||||
this.handleCategoryModalSuccess = this.handleCategoryModalSuccess.bind(this);
|
|
||||||
this.handleCategoryModalError = this.handleCategoryModalError.bind(this);
|
|
||||||
this.handleTagModalCancel = this.handleTagModalCancel.bind(this);
|
|
||||||
this.handleTagModalSuccess = this.handleTagModalSuccess.bind(this);
|
|
||||||
this.handleTagModalError = this.handleTagModalError.bind(this);
|
|
||||||
|
|
||||||
ProfilePageStore.on('load-author-data', this.authorDataLoad);
|
ProfilePageStore.on('load-author-data', this.authorDataLoad);
|
||||||
}
|
}
|
||||||
@@ -202,42 +150,22 @@ export class ProfileMediaPage extends Page {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleMediaSelection(mediaId, isSelected) {
|
handleMediaSelection(mediaId, isSelected) {
|
||||||
const isSelectMediaMode = inSelectMediaEmbedMode();
|
// Only used in select media embed mode; normal mode is handled by bulkActions
|
||||||
|
|
||||||
this.setState((prevState) => {
|
this.setState((prevState) => {
|
||||||
const newSelectedMedia = new Set();
|
const newSelectedMedia = new Set();
|
||||||
|
|
||||||
// In select media mode, only allow single selection
|
if (isSelected) {
|
||||||
if (isSelectMediaMode) {
|
newSelectedMedia.add(mediaId);
|
||||||
if (isSelected) {
|
|
||||||
newSelectedMedia.add(mediaId);
|
|
||||||
console.log('Selected media item:', mediaId);
|
|
||||||
|
|
||||||
// Send postMessage to parent window (Moodle TinyMCE plugin)
|
if (window.parent !== window) {
|
||||||
if (window.parent !== window) {
|
const baseUrl = window.location.origin;
|
||||||
// Construct the embed URL
|
const embedUrl = `${baseUrl}/embed?m=${mediaId}`;
|
||||||
const baseUrl = window.location.origin;
|
|
||||||
const embedUrl = `${baseUrl}/embed?m=${mediaId}`;
|
|
||||||
|
|
||||||
// Send message in the format expected by the Moodle plugin
|
window.parent.postMessage({
|
||||||
window.parent.postMessage({
|
type: 'videoSelected',
|
||||||
type: 'videoSelected',
|
embedUrl: embedUrl,
|
||||||
embedUrl: embedUrl,
|
videoId: mediaId
|
||||||
videoId: mediaId
|
}, '*');
|
||||||
}, '*');
|
|
||||||
|
|
||||||
console.log('Sent postMessage to parent:', { embedUrl, videoId: mediaId });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Normal mode: allow multiple selection
|
|
||||||
newSelectedMedia.clear();
|
|
||||||
prevState.selectedMedia.forEach((id) => newSelectedMedia.add(id));
|
|
||||||
|
|
||||||
if (isSelected) {
|
|
||||||
newSelectedMedia.add(mediaId);
|
|
||||||
} else {
|
|
||||||
newSelectedMedia.delete(mediaId);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -245,386 +173,6 @@ export class ProfileMediaPage extends Page {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
handleBulkAction(action) {
|
|
||||||
const selectedCount = this.state.selectedMedia.size;
|
|
||||||
|
|
||||||
if (selectedCount === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (action === 'delete-media') {
|
|
||||||
this.setState({
|
|
||||||
showConfirmModal: true,
|
|
||||||
pendingAction: action,
|
|
||||||
confirmMessage:
|
|
||||||
translateString('You are going to delete') +
|
|
||||||
` ${selectedCount} ` +
|
|
||||||
translateString('media, are you sure?'),
|
|
||||||
});
|
|
||||||
} else if (action === 'enable-comments') {
|
|
||||||
this.setState({
|
|
||||||
showConfirmModal: true,
|
|
||||||
pendingAction: action,
|
|
||||||
confirmMessage:
|
|
||||||
translateString('You are going to enable comments to') +
|
|
||||||
` ${selectedCount} ` +
|
|
||||||
translateString('media, are you sure?'),
|
|
||||||
});
|
|
||||||
} else if (action === 'disable-comments') {
|
|
||||||
this.setState({
|
|
||||||
showConfirmModal: true,
|
|
||||||
pendingAction: action,
|
|
||||||
confirmMessage:
|
|
||||||
translateString('You are going to disable comments to') +
|
|
||||||
` ${selectedCount} ` +
|
|
||||||
translateString('media, are you sure?'),
|
|
||||||
});
|
|
||||||
} else if (action === 'enable-download') {
|
|
||||||
this.setState({
|
|
||||||
showConfirmModal: true,
|
|
||||||
pendingAction: action,
|
|
||||||
confirmMessage:
|
|
||||||
translateString('You are going to enable download for') +
|
|
||||||
` ${selectedCount} ` +
|
|
||||||
translateString('media, are you sure?'),
|
|
||||||
});
|
|
||||||
} else if (action === 'disable-download') {
|
|
||||||
this.setState({
|
|
||||||
showConfirmModal: true,
|
|
||||||
pendingAction: action,
|
|
||||||
confirmMessage:
|
|
||||||
translateString('You are going to disable download for') +
|
|
||||||
` ${selectedCount} ` +
|
|
||||||
translateString('media, are you sure?'),
|
|
||||||
});
|
|
||||||
} else if (action === 'copy-media') {
|
|
||||||
this.setState({
|
|
||||||
showConfirmModal: true,
|
|
||||||
pendingAction: action,
|
|
||||||
confirmMessage:
|
|
||||||
translateString('You are going to copy') +
|
|
||||||
` ${selectedCount} ` +
|
|
||||||
translateString('media, are you sure?'),
|
|
||||||
});
|
|
||||||
} else if (action === 'add-remove-coviewers') {
|
|
||||||
this.setState({
|
|
||||||
showPermissionModal: true,
|
|
||||||
permissionType: 'viewer',
|
|
||||||
});
|
|
||||||
} else if (action === 'add-remove-coeditors') {
|
|
||||||
this.setState({
|
|
||||||
showPermissionModal: true,
|
|
||||||
permissionType: 'editor',
|
|
||||||
});
|
|
||||||
} else if (action === 'add-remove-coowners') {
|
|
||||||
this.setState({
|
|
||||||
showPermissionModal: true,
|
|
||||||
permissionType: 'owner',
|
|
||||||
});
|
|
||||||
} else if (action === 'add-remove-playlist') {
|
|
||||||
this.setState({
|
|
||||||
showPlaylistModal: true,
|
|
||||||
});
|
|
||||||
} else if (action === 'change-owner') {
|
|
||||||
this.setState({
|
|
||||||
showChangeOwnerModal: true,
|
|
||||||
});
|
|
||||||
} else if (action === 'publish-state') {
|
|
||||||
this.setState({
|
|
||||||
showPublishStateModal: true,
|
|
||||||
});
|
|
||||||
} else if (action === 'add-remove-category') {
|
|
||||||
this.setState({
|
|
||||||
showCategoryModal: true,
|
|
||||||
});
|
|
||||||
} else if (action === 'add-remove-tags') {
|
|
||||||
this.setState({
|
|
||||||
showTagModal: true,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// Other actions can be implemented later
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleConfirmCancel() {
|
|
||||||
this.setState({
|
|
||||||
showConfirmModal: false,
|
|
||||||
pendingAction: null,
|
|
||||||
confirmMessage: '',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
handleConfirmProceed() {
|
|
||||||
const action = this.state.pendingAction;
|
|
||||||
this.setState({
|
|
||||||
showConfirmModal: false,
|
|
||||||
pendingAction: null,
|
|
||||||
confirmMessage: '',
|
|
||||||
});
|
|
||||||
|
|
||||||
if (action === 'delete-media') {
|
|
||||||
this.executeDeleteMedia();
|
|
||||||
} else if (action === 'enable-comments') {
|
|
||||||
this.executeEnableComments();
|
|
||||||
} else if (action === 'disable-comments') {
|
|
||||||
this.executeDisableComments();
|
|
||||||
} else if (action === 'enable-download') {
|
|
||||||
this.executeEnableDownload();
|
|
||||||
} else if (action === 'disable-download') {
|
|
||||||
this.executeDisableDownload();
|
|
||||||
} else if (action === 'copy-media') {
|
|
||||||
this.executeCopyMedia();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
executeDeleteMedia() {
|
|
||||||
const selectedIds = Array.from(this.state.selectedMedia);
|
|
||||||
const selectedCount = selectedIds.length;
|
|
||||||
|
|
||||||
fetch('/api/v1/media/user/bulk_actions', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'X-CSRFToken': this.getCsrfToken(),
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
action: 'delete_media',
|
|
||||||
media_ids: selectedIds,
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
.then((response) => {
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error('Failed to delete media');
|
|
||||||
}
|
|
||||||
return response.json();
|
|
||||||
})
|
|
||||||
.then((data) => {
|
|
||||||
const message =
|
|
||||||
selectedCount === 1
|
|
||||||
? translateString('The media was deleted successfully.')
|
|
||||||
: translateString('Successfully deleted') + ` ${selectedCount} ` + translateString('media.');
|
|
||||||
this.showNotification(message);
|
|
||||||
this.clearSelectionAndRefresh();
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
this.showNotification(translateString('Failed to delete media. Please try again.'), 'error');
|
|
||||||
this.clearSelectionAndRefresh();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getCsrfToken() {
|
|
||||||
const name = 'csrftoken';
|
|
||||||
let cookieValue = null;
|
|
||||||
if (document.cookie && document.cookie !== '') {
|
|
||||||
const cookies = document.cookie.split(';');
|
|
||||||
for (let i = 0; i < cookies.length; i++) {
|
|
||||||
const cookie = cookies[i].trim();
|
|
||||||
if (cookie.substring(0, name.length + 1) === name + '=') {
|
|
||||||
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return cookieValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
clearSelectionAndRefresh() {
|
|
||||||
// Clear selected media and increment listKey to force re-render
|
|
||||||
this.setState((prevState) => ({
|
|
||||||
selectedMedia: new Set(),
|
|
||||||
listKey: prevState.listKey + 1,
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
clearSelection() {
|
|
||||||
// Clear selected media without refreshing
|
|
||||||
this.setState({
|
|
||||||
selectedMedia: new Set(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
executeEnableComments() {
|
|
||||||
const selectedIds = Array.from(this.state.selectedMedia);
|
|
||||||
|
|
||||||
fetch('/api/v1/media/user/bulk_actions', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'X-CSRFToken': this.getCsrfToken(),
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
action: 'enable_comments',
|
|
||||||
media_ids: selectedIds,
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
.then((response) => {
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error('Failed to enable comments');
|
|
||||||
}
|
|
||||||
return response.json();
|
|
||||||
})
|
|
||||||
.then((data) => {
|
|
||||||
this.showNotification(translateString('Successfully Enabled comments'));
|
|
||||||
this.clearSelection();
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
this.showNotification(translateString('Failed to enable comments.'), 'error');
|
|
||||||
this.clearSelection();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
executeDisableComments() {
|
|
||||||
const selectedIds = Array.from(this.state.selectedMedia);
|
|
||||||
|
|
||||||
fetch('/api/v1/media/user/bulk_actions', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'X-CSRFToken': this.getCsrfToken(),
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
action: 'disable_comments',
|
|
||||||
media_ids: selectedIds,
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
.then((response) => {
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error('Failed to disable comments');
|
|
||||||
}
|
|
||||||
return response.json();
|
|
||||||
})
|
|
||||||
.then((data) => {
|
|
||||||
this.showNotification(translateString('Successfully Disabled comments'));
|
|
||||||
this.clearSelection();
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
this.showNotification(translateString('Failed to disable comments.'), 'error');
|
|
||||||
this.clearSelection();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
executeEnableDownload() {
|
|
||||||
const selectedIds = Array.from(this.state.selectedMedia);
|
|
||||||
|
|
||||||
fetch('/api/v1/media/user/bulk_actions', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'X-CSRFToken': this.getCsrfToken(),
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
action: 'enable_download',
|
|
||||||
media_ids: selectedIds,
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
.then((response) => {
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error('Failed to enable download');
|
|
||||||
}
|
|
||||||
return response.json();
|
|
||||||
})
|
|
||||||
.then((data) => {
|
|
||||||
this.showNotification(translateString('Successfully Enabled Download'));
|
|
||||||
this.clearSelection();
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
this.showNotification(translateString('Failed to enable download.'), 'error');
|
|
||||||
this.clearSelection();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
executeDisableDownload() {
|
|
||||||
const selectedIds = Array.from(this.state.selectedMedia);
|
|
||||||
|
|
||||||
fetch('/api/v1/media/user/bulk_actions', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'X-CSRFToken': this.getCsrfToken(),
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
action: 'disable_download',
|
|
||||||
media_ids: selectedIds,
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
.then((response) => {
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error('Failed to disable download');
|
|
||||||
}
|
|
||||||
return response.json();
|
|
||||||
})
|
|
||||||
.then((data) => {
|
|
||||||
this.showNotification(translateString('Successfully Disabled Download'));
|
|
||||||
this.clearSelection();
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
this.showNotification(translateString('Failed to disable download.'), 'error');
|
|
||||||
this.clearSelection();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
executeCopyMedia() {
|
|
||||||
const selectedIds = Array.from(this.state.selectedMedia);
|
|
||||||
|
|
||||||
fetch('/api/v1/media/user/bulk_actions', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'X-CSRFToken': this.getCsrfToken(),
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
action: 'copy_media',
|
|
||||||
media_ids: selectedIds,
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
.then((response) => {
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error('Failed to copy media');
|
|
||||||
}
|
|
||||||
return response.json();
|
|
||||||
})
|
|
||||||
.then((data) => {
|
|
||||||
this.showNotification(translateString('Successfully Copied'));
|
|
||||||
this.clearSelectionAndRefresh();
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
this.showNotification(translateString('Failed to copy media.'), 'error');
|
|
||||||
this.clearSelection();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
showNotification(message, type = 'success') {
|
|
||||||
this.setState({
|
|
||||||
notificationMessage: message,
|
|
||||||
showNotification: true,
|
|
||||||
notificationType: type,
|
|
||||||
});
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
this.setState({ showNotification: false });
|
|
||||||
}, 5000);
|
|
||||||
}
|
|
||||||
|
|
||||||
handleItemsUpdate(items) {
|
|
||||||
// Extract media IDs from loaded items
|
|
||||||
const mediaIds = items.map((item) => item.friendly_token || item.uid || item.id);
|
|
||||||
this.setState({ availableMediaIds: mediaIds });
|
|
||||||
}
|
|
||||||
|
|
||||||
handleSelectAll() {
|
|
||||||
// Select all available media
|
|
||||||
this.setState({
|
|
||||||
selectedMedia: new Set(this.state.availableMediaIds),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
handleDeselectAll() {
|
|
||||||
// Clear all selections
|
|
||||||
this.setState({
|
|
||||||
selectedMedia: new Set(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onToggleFiltersClick() {
|
onToggleFiltersClick() {
|
||||||
this.setState({
|
this.setState({
|
||||||
hiddenFilters: !this.state.hiddenFilters,
|
hiddenFilters: !this.state.hiddenFilters,
|
||||||
@@ -651,7 +199,6 @@ export class ProfileMediaPage extends Page {
|
|||||||
|
|
||||||
onTagSelect(tag) {
|
onTagSelect(tag) {
|
||||||
this.setState({ selectedTag: tag }, () => {
|
this.setState({ selectedTag: tag }, () => {
|
||||||
// Apply tag filter
|
|
||||||
this.onFiltersUpdate({
|
this.onFiltersUpdate({
|
||||||
media_type: this.state.filterArgs.includes('media_type')
|
media_type: this.state.filterArgs.includes('media_type')
|
||||||
? this.state.filterArgs.match(/media_type=([^&]*)/)?.[1]
|
? this.state.filterArgs.match(/media_type=([^&]*)/)?.[1]
|
||||||
@@ -673,7 +220,6 @@ export class ProfileMediaPage extends Page {
|
|||||||
|
|
||||||
onSortSelect(sortOption) {
|
onSortSelect(sortOption) {
|
||||||
this.setState({ selectedSort: sortOption }, () => {
|
this.setState({ selectedSort: sortOption }, () => {
|
||||||
// Apply sort filter
|
|
||||||
this.onFiltersUpdate({
|
this.onFiltersUpdate({
|
||||||
media_type: this.state.filterArgs.includes('media_type')
|
media_type: this.state.filterArgs.includes('media_type')
|
||||||
? this.state.filterArgs.match(/media_type=([^&]*)/)?.[1]
|
? this.state.filterArgs.match(/media_type=([^&]*)/)?.[1]
|
||||||
@@ -722,19 +268,16 @@ export class ProfileMediaPage extends Page {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle duration filter
|
|
||||||
if (updatedArgs.duration && updatedArgs.duration !== 'all') {
|
if (updatedArgs.duration && updatedArgs.duration !== 'all') {
|
||||||
args.duration = updatedArgs.duration;
|
args.duration = updatedArgs.duration;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle publish state filter
|
|
||||||
if (updatedArgs.publish_state && updatedArgs.publish_state !== 'all') {
|
if (updatedArgs.publish_state && updatedArgs.publish_state !== 'all') {
|
||||||
args.publish_state = updatedArgs.publish_state;
|
args.publish_state = updatedArgs.publish_state;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (updatedArgs.sort_by) {
|
switch (updatedArgs.sort_by) {
|
||||||
case 'date_added_desc':
|
case 'date_added_desc':
|
||||||
// Default sorting, no need to add parameters
|
|
||||||
break;
|
break;
|
||||||
case 'date_added_asc':
|
case 'date_added_asc':
|
||||||
args.ordering = 'asc';
|
args.ordering = 'asc';
|
||||||
@@ -759,7 +302,6 @@ export class ProfileMediaPage extends Page {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle tag filter
|
|
||||||
if (updatedArgs.tag && updatedArgs.tag !== 'all') {
|
if (updatedArgs.tag && updatedArgs.tag !== 'all') {
|
||||||
args.t = updatedArgs.tag;
|
args.t = updatedArgs.tag;
|
||||||
}
|
}
|
||||||
@@ -775,10 +317,8 @@ export class ProfileMediaPage extends Page {
|
|||||||
this.setState(
|
this.setState(
|
||||||
{
|
{
|
||||||
filterArgs: newArgs.length ? '&' + newArgs.join('&') : '',
|
filterArgs: newArgs.length ? '&' + newArgs.join('&') : '',
|
||||||
selectedMedia: new Set(), // Clear selected items when filter changes
|
|
||||||
},
|
},
|
||||||
function () {
|
function () {
|
||||||
// Update the request URL with new filter args
|
|
||||||
if (!this.state.author) {
|
if (!this.state.author) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -805,137 +345,7 @@ export class ProfileMediaPage extends Page {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
handlePermissionModalCancel() {
|
|
||||||
this.setState({
|
|
||||||
showPermissionModal: false,
|
|
||||||
permissionType: null,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
handlePermissionModalSuccess(message) {
|
|
||||||
this.showNotification(message);
|
|
||||||
this.clearSelection();
|
|
||||||
this.setState({
|
|
||||||
showPermissionModal: false,
|
|
||||||
permissionType: null,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
handlePermissionModalError(message) {
|
|
||||||
this.showNotification(message, 'error');
|
|
||||||
this.setState({
|
|
||||||
showPermissionModal: false,
|
|
||||||
permissionType: null,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
handlePlaylistModalCancel() {
|
|
||||||
this.setState({
|
|
||||||
showPlaylistModal: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
handlePlaylistModalSuccess(message) {
|
|
||||||
this.showNotification(message);
|
|
||||||
this.clearSelection();
|
|
||||||
this.setState({
|
|
||||||
showPlaylistModal: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
handlePlaylistModalError(message) {
|
|
||||||
this.showNotification(message, 'error');
|
|
||||||
this.setState({
|
|
||||||
showPlaylistModal: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
handleChangeOwnerModalCancel() {
|
|
||||||
this.setState({
|
|
||||||
showChangeOwnerModal: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
handleChangeOwnerModalSuccess(message) {
|
|
||||||
this.showNotification(message);
|
|
||||||
this.clearSelectionAndRefresh();
|
|
||||||
this.setState({
|
|
||||||
showChangeOwnerModal: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
handleChangeOwnerModalError(message) {
|
|
||||||
this.showNotification(message, 'error');
|
|
||||||
this.setState({
|
|
||||||
showChangeOwnerModal: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
handlePublishStateModalCancel() {
|
|
||||||
this.setState({
|
|
||||||
showPublishStateModal: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
handlePublishStateModalSuccess(message) {
|
|
||||||
this.showNotification(message);
|
|
||||||
this.clearSelectionAndRefresh();
|
|
||||||
this.setState({
|
|
||||||
showPublishStateModal: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
handlePublishStateModalError(message) {
|
|
||||||
this.showNotification(message, 'error');
|
|
||||||
this.setState({
|
|
||||||
showPublishStateModal: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
handleCategoryModalCancel() {
|
|
||||||
this.setState({
|
|
||||||
showCategoryModal: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
handleCategoryModalSuccess(message) {
|
|
||||||
this.showNotification(message);
|
|
||||||
this.clearSelection();
|
|
||||||
this.setState({
|
|
||||||
showCategoryModal: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
handleCategoryModalError(message) {
|
|
||||||
this.showNotification(message, 'error');
|
|
||||||
this.setState({
|
|
||||||
showCategoryModal: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
handleTagModalCancel() {
|
|
||||||
this.setState({
|
|
||||||
showTagModal: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
handleTagModalSuccess(message) {
|
|
||||||
this.showNotification(message);
|
|
||||||
this.clearSelection();
|
|
||||||
this.setState({
|
|
||||||
showTagModal: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
handleTagModalError(message) {
|
|
||||||
this.showNotification(message, 'error');
|
|
||||||
this.setState({
|
|
||||||
showTagModal: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onResponseDataLoaded(responseData) {
|
onResponseDataLoaded(responseData) {
|
||||||
// Extract tags from response
|
|
||||||
if (responseData && responseData.tags) {
|
if (responseData && responseData.tags) {
|
||||||
const tags = responseData.tags
|
const tags = responseData.tags
|
||||||
.split(',')
|
.split(',')
|
||||||
@@ -951,7 +361,6 @@ export class ProfileMediaPage extends Page {
|
|||||||
const isMediaAuthor = authorData && authorData.username === MemberContext._currentValue.username;
|
const isMediaAuthor = authorData && authorData.username === MemberContext._currentValue.username;
|
||||||
const isSelectMediaMode = inSelectMediaEmbedMode();
|
const isSelectMediaMode = inSelectMediaEmbedMode();
|
||||||
|
|
||||||
// Check if any filters are active (excluding default sort and tags)
|
|
||||||
const hasActiveFilters =
|
const hasActiveFilters =
|
||||||
this.state.filterArgs &&
|
this.state.filterArgs &&
|
||||||
(this.state.filterArgs.includes('media_type=') ||
|
(this.state.filterArgs.includes('media_type=') ||
|
||||||
@@ -985,11 +394,11 @@ export class ProfileMediaPage extends Page {
|
|||||||
className="items-list-ver"
|
className="items-list-ver"
|
||||||
style={inEmbeddedApp() ? { marginTop: '24px' } : undefined}
|
style={inEmbeddedApp() ? { marginTop: '24px' } : undefined}
|
||||||
showBulkActions={!isSelectMediaMode && isMediaAuthor}
|
showBulkActions={!isSelectMediaMode && isMediaAuthor}
|
||||||
selectedCount={this.state.selectedMedia.size}
|
selectedCount={isSelectMediaMode ? this.state.selectedMedia.size : this.props.bulkActions.selectedMedia.size}
|
||||||
totalCount={this.state.availableMediaIds.length}
|
totalCount={isSelectMediaMode ? 0 : this.props.bulkActions.availableMediaIds.length}
|
||||||
onBulkAction={this.handleBulkAction}
|
onBulkAction={this.props.bulkActions.handleBulkAction}
|
||||||
onSelectAll={this.handleSelectAll}
|
onSelectAll={this.props.bulkActions.handleSelectAll}
|
||||||
onDeselectAll={this.handleDeselectAll}
|
onDeselectAll={this.props.bulkActions.handleDeselectAll}
|
||||||
showAddMediaButton={!isSelectMediaMode && isMediaAuthor}
|
showAddMediaButton={!isSelectMediaMode && isMediaAuthor}
|
||||||
>
|
>
|
||||||
<ProfileMediaFilters
|
<ProfileMediaFilters
|
||||||
@@ -1006,7 +415,7 @@ export class ProfileMediaPage extends Page {
|
|||||||
/>
|
/>
|
||||||
<ProfileMediaSorting hidden={this.state.hiddenSorting} onSortSelect={this.onSortSelect} />
|
<ProfileMediaSorting hidden={this.state.hiddenSorting} onSortSelect={this.onSortSelect} />
|
||||||
<LazyLoadItemListAsync
|
<LazyLoadItemListAsync
|
||||||
key={`${this.state.requestUrl}-${this.state.listKey}`}
|
key={`${this.state.requestUrl}-${this.props.bulkActions.listKey}`}
|
||||||
requestUrl={this.state.requestUrl}
|
requestUrl={this.state.requestUrl}
|
||||||
hideAuthor={true}
|
hideAuthor={true}
|
||||||
itemsCountCallback={this.state.requestUrl ? this.getCountFunc : null}
|
itemsCountCallback={this.state.requestUrl ? this.getCountFunc : null}
|
||||||
@@ -1014,97 +423,43 @@ export class ProfileMediaPage extends Page {
|
|||||||
hideDate={!PageStore.get('config-media-item').displayPublishDate}
|
hideDate={!PageStore.get('config-media-item').displayPublishDate}
|
||||||
canEdit={isMediaAuthor}
|
canEdit={isMediaAuthor}
|
||||||
showSelection={isMediaAuthor || isSelectMediaMode}
|
showSelection={isMediaAuthor || isSelectMediaMode}
|
||||||
hasAnySelection={this.state.selectedMedia.size > 0}
|
hasAnySelection={isSelectMediaMode ? this.state.selectedMedia.size > 0 : this.props.bulkActions.selectedMedia.size > 0}
|
||||||
selectedMedia={this.state.selectedMedia}
|
selectedMedia={isSelectMediaMode ? this.state.selectedMedia : this.props.bulkActions.selectedMedia}
|
||||||
onMediaSelection={this.handleMediaSelection}
|
onMediaSelection={isSelectMediaMode ? this.handleMediaSelection : this.props.bulkActions.handleMediaSelection}
|
||||||
onItemsUpdate={this.handleItemsUpdate}
|
onItemsUpdate={!isSelectMediaMode ? this.props.bulkActions.handleItemsUpdate : undefined}
|
||||||
onResponseDataLoaded={this.onResponseDataLoaded}
|
onResponseDataLoaded={this.onResponseDataLoaded}
|
||||||
/>
|
/>
|
||||||
</MediaListWrapper>
|
</MediaListWrapper>
|
||||||
</ProfilePagesContent>
|
</ProfilePagesContent>
|
||||||
) : null,
|
) : null,
|
||||||
<BulkActionConfirmModal
|
this.state.author && isMediaAuthor && !isSelectMediaMode ? (
|
||||||
key="BulkActionConfirmModal"
|
<BulkActionsModals
|
||||||
isOpen={this.state.showConfirmModal}
|
key="BulkActionsModals"
|
||||||
message={this.state.confirmMessage}
|
{...this.props.bulkActions}
|
||||||
onCancel={this.handleConfirmCancel}
|
selectedMediaIds={Array.from(this.props.bulkActions.selectedMedia)}
|
||||||
onProceed={this.handleConfirmProceed}
|
csrfToken={this.props.bulkActions.getCsrfToken()}
|
||||||
/>,
|
username={this.state.author.username}
|
||||||
<BulkActionPermissionModal
|
onConfirmCancel={this.props.bulkActions.handleConfirmCancel}
|
||||||
key="BulkActionPermissionModal"
|
onConfirmProceed={this.props.bulkActions.handleConfirmProceed}
|
||||||
isOpen={this.state.showPermissionModal}
|
onPermissionModalCancel={this.props.bulkActions.handlePermissionModalCancel}
|
||||||
permissionType={this.state.permissionType}
|
onPermissionModalSuccess={this.props.bulkActions.handlePermissionModalSuccess}
|
||||||
selectedMediaIds={Array.from(this.state.selectedMedia)}
|
onPermissionModalError={this.props.bulkActions.handlePermissionModalError}
|
||||||
onCancel={this.handlePermissionModalCancel}
|
onPlaylistModalCancel={this.props.bulkActions.handlePlaylistModalCancel}
|
||||||
onSuccess={this.handlePermissionModalSuccess}
|
onPlaylistModalSuccess={this.props.bulkActions.handlePlaylistModalSuccess}
|
||||||
onError={this.handlePermissionModalError}
|
onPlaylistModalError={this.props.bulkActions.handlePlaylistModalError}
|
||||||
csrfToken={this.getCsrfToken()}
|
onChangeOwnerModalCancel={this.props.bulkActions.handleChangeOwnerModalCancel}
|
||||||
/>,
|
onChangeOwnerModalSuccess={this.props.bulkActions.handleChangeOwnerModalSuccess}
|
||||||
<BulkActionPlaylistModal
|
onChangeOwnerModalError={this.props.bulkActions.handleChangeOwnerModalError}
|
||||||
key="BulkActionPlaylistModal"
|
onPublishStateModalCancel={this.props.bulkActions.handlePublishStateModalCancel}
|
||||||
isOpen={this.state.showPlaylistModal}
|
onPublishStateModalSuccess={this.props.bulkActions.handlePublishStateModalSuccess}
|
||||||
selectedMediaIds={Array.from(this.state.selectedMedia)}
|
onPublishStateModalError={this.props.bulkActions.handlePublishStateModalError}
|
||||||
onCancel={this.handlePlaylistModalCancel}
|
onCategoryModalCancel={this.props.bulkActions.handleCategoryModalCancel}
|
||||||
onSuccess={this.handlePlaylistModalSuccess}
|
onCategoryModalSuccess={this.props.bulkActions.handleCategoryModalSuccess}
|
||||||
onError={this.handlePlaylistModalError}
|
onCategoryModalError={this.props.bulkActions.handleCategoryModalError}
|
||||||
csrfToken={this.getCsrfToken()}
|
onTagModalCancel={this.props.bulkActions.handleTagModalCancel}
|
||||||
username={this.state.author ? this.state.author.username : ''}
|
onTagModalSuccess={this.props.bulkActions.handleTagModalSuccess}
|
||||||
/>,
|
onTagModalError={this.props.bulkActions.handleTagModalError}
|
||||||
<BulkActionChangeOwnerModal
|
/>
|
||||||
key="BulkActionChangeOwnerModal"
|
|
||||||
isOpen={this.state.showChangeOwnerModal}
|
|
||||||
selectedMediaIds={Array.from(this.state.selectedMedia)}
|
|
||||||
onCancel={this.handleChangeOwnerModalCancel}
|
|
||||||
onSuccess={this.handleChangeOwnerModalSuccess}
|
|
||||||
onError={this.handleChangeOwnerModalError}
|
|
||||||
csrfToken={this.getCsrfToken()}
|
|
||||||
/>,
|
|
||||||
<BulkActionPublishStateModal
|
|
||||||
key="BulkActionPublishStateModal"
|
|
||||||
isOpen={this.state.showPublishStateModal}
|
|
||||||
selectedMediaIds={Array.from(this.state.selectedMedia)}
|
|
||||||
onCancel={this.handlePublishStateModalCancel}
|
|
||||||
onSuccess={this.handlePublishStateModalSuccess}
|
|
||||||
onError={this.handlePublishStateModalError}
|
|
||||||
csrfToken={this.getCsrfToken()}
|
|
||||||
/>,
|
|
||||||
<BulkActionCategoryModal
|
|
||||||
key="BulkActionCategoryModal"
|
|
||||||
isOpen={this.state.showCategoryModal}
|
|
||||||
selectedMediaIds={Array.from(this.state.selectedMedia)}
|
|
||||||
onCancel={this.handleCategoryModalCancel}
|
|
||||||
onSuccess={this.handleCategoryModalSuccess}
|
|
||||||
onError={this.handleCategoryModalError}
|
|
||||||
csrfToken={this.getCsrfToken()}
|
|
||||||
/>,
|
|
||||||
<BulkActionTagModal
|
|
||||||
key="BulkActionTagModal"
|
|
||||||
isOpen={this.state.showTagModal}
|
|
||||||
selectedMediaIds={Array.from(this.state.selectedMedia)}
|
|
||||||
onCancel={this.handleTagModalCancel}
|
|
||||||
onSuccess={this.handleTagModalSuccess}
|
|
||||||
onError={this.handleTagModalError}
|
|
||||||
csrfToken={this.getCsrfToken()}
|
|
||||||
/>,
|
|
||||||
this.state.showNotification ? (
|
|
||||||
<div
|
|
||||||
key="SimpleNotification"
|
|
||||||
style={{
|
|
||||||
position: 'fixed',
|
|
||||||
bottom: '20px',
|
|
||||||
left: '260px',
|
|
||||||
backgroundColor: this.state.notificationType === 'error' ? '#f44336' : '#4CAF50',
|
|
||||||
color: 'white',
|
|
||||||
padding: '16px 24px',
|
|
||||||
borderRadius: '4px',
|
|
||||||
boxShadow: '0 4px 6px rgba(0, 0, 0, 0.1)',
|
|
||||||
zIndex: 1000,
|
|
||||||
fontSize: '14px',
|
|
||||||
fontWeight: '500',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{this.state.notificationMessage}
|
|
||||||
</div>
|
|
||||||
) : null,
|
) : null,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -1112,8 +467,17 @@ export class ProfileMediaPage extends Page {
|
|||||||
|
|
||||||
ProfileMediaPage.propTypes = {
|
ProfileMediaPage.propTypes = {
|
||||||
title: PropTypes.string.isRequired,
|
title: PropTypes.string.isRequired,
|
||||||
|
bulkActions: PropTypes.object.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
ProfileMediaPage.defaultProps = {
|
ProfileMediaPage.defaultProps = {
|
||||||
title: 'Uploads',
|
title: 'Uploads',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Export the raw class for subclasses to extend
|
||||||
|
export { ProfileMediaPage as ProfileMediaPageBase };
|
||||||
|
|
||||||
|
// Export the HOC-wrapped version as the renderable component
|
||||||
|
const WrappedProfileMediaPage = withBulkActions(ProfileMediaPage);
|
||||||
|
export { WrappedProfileMediaPage as ProfileMediaPage };
|
||||||
|
export default WrappedProfileMediaPage;
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ import { MediaListWrapper } from '../components/MediaListWrapper';
|
|||||||
import ProfilePagesHeader from '../components/profile-page/ProfilePagesHeader';
|
import ProfilePagesHeader from '../components/profile-page/ProfilePagesHeader';
|
||||||
import ProfilePagesContent from '../components/profile-page/ProfilePagesContent';
|
import ProfilePagesContent from '../components/profile-page/ProfilePagesContent';
|
||||||
import { LazyLoadItemListAsync } from '../components/item-list/LazyLoadItemListAsync.jsx';
|
import { LazyLoadItemListAsync } from '../components/item-list/LazyLoadItemListAsync.jsx';
|
||||||
import { ProfileMediaPage } from './ProfileMediaPage';
|
import { ProfileMediaPageBase } from './ProfileMediaPage';
|
||||||
|
|
||||||
export class ProfilePlaylistsPage extends ProfileMediaPage {
|
export class ProfilePlaylistsPage extends ProfileMediaPageBase {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props, 'author-playlists');
|
super(props, 'author-playlists');
|
||||||
|
|
||||||
|
|||||||
@@ -111,6 +111,10 @@ export function useBulkActions() {
|
|||||||
setShowConfirmModal(true);
|
setShowConfirmModal(true);
|
||||||
setPendingAction(action);
|
setPendingAction(action);
|
||||||
setConfirmMessage(translateString('You are going to disable comments to') + ` ${selectedCount} ` + translateString('media, are you sure?'));
|
setConfirmMessage(translateString('You are going to disable comments to') + ` ${selectedCount} ` + translateString('media, are you sure?'));
|
||||||
|
} else if (action === 'delete-comments') {
|
||||||
|
setShowConfirmModal(true);
|
||||||
|
setPendingAction(action);
|
||||||
|
setConfirmMessage(translateString('You are going to delete all comments from') + ` ${selectedCount} ` + translateString('media, are you sure?'));
|
||||||
} else if (action === 'enable-download') {
|
} else if (action === 'enable-download') {
|
||||||
setShowConfirmModal(true);
|
setShowConfirmModal(true);
|
||||||
setPendingAction(action);
|
setPendingAction(action);
|
||||||
@@ -165,6 +169,8 @@ export function useBulkActions() {
|
|||||||
executeEnableComments();
|
executeEnableComments();
|
||||||
} else if (action === 'disable-comments') {
|
} else if (action === 'disable-comments') {
|
||||||
executeDisableComments();
|
executeDisableComments();
|
||||||
|
} else if (action === 'delete-comments') {
|
||||||
|
executeDeleteComments();
|
||||||
} else if (action === 'enable-download') {
|
} else if (action === 'enable-download') {
|
||||||
executeEnableDownload();
|
executeEnableDownload();
|
||||||
} else if (action === 'disable-download') {
|
} else if (action === 'disable-download') {
|
||||||
@@ -271,6 +277,37 @@ export function useBulkActions() {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Execute delete comments
|
||||||
|
const executeDeleteComments = () => {
|
||||||
|
const selectedIds = Array.from(selectedMedia);
|
||||||
|
|
||||||
|
fetch('/api/v1/media/user/bulk_actions', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-CSRFToken': getCsrfToken(),
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
action: 'delete_comments',
|
||||||
|
media_ids: selectedIds,
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('Failed to delete comments');
|
||||||
|
}
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
|
.then((data) => {
|
||||||
|
showNotificationMessage(translateString('Successfully deleted comments'));
|
||||||
|
clearSelection();
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
showNotificationMessage(translateString('Failed to delete comments.'), 'error');
|
||||||
|
clearSelection();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
// Execute enable download
|
// Execute enable download
|
||||||
const executeEnableDownload = () => {
|
const executeEnableDownload = () => {
|
||||||
const selectedIds = Array.from(selectedMedia);
|
const selectedIds = Array.from(selectedMedia);
|
||||||
|
|||||||
Reference in New Issue
Block a user