- );
+ );
}
function EditMediaButton(props) {
- let link = props.link;
+ let link = props.link;
- if (window.MediaCMS.site.devEnv) {
- link = '/edit-media.html';
- }
+ if (window.MediaCMS.site.devEnv) {
+ link = '/edit-media.html';
+ }
- return (
-
+ );
}
export default function ViewerInfoContent(props) {
- const { userCan } = useUser();
+ const { userCan } = useUser();
- const description = props.description.trim();
- const tagsContent =
- !PageStore.get('config-enabled').taxonomies.tags || PageStore.get('config-enabled').taxonomies.tags.enabled
- ? metafield(MediaPageStore.get('media-tags'))
- : [];
- const categoriesContent = PageStore.get('config-options').pages.media.categoriesWithTitle
- ? []
- : !PageStore.get('config-enabled').taxonomies.categories ||
- PageStore.get('config-enabled').taxonomies.categories.enabled
- ? metafield(MediaPageStore.get('media-categories'))
- : [];
+ const description = props.description.trim();
+ const tagsContent =
+ !PageStore.get('config-enabled').taxonomies.tags || PageStore.get('config-enabled').taxonomies.tags.enabled
+ ? metafield(MediaPageStore.get('media-tags'))
+ : [];
+ const categoriesContent = PageStore.get('config-options').pages.media.categoriesWithTitle
+ ? []
+ : !PageStore.get('config-enabled').taxonomies.categories ||
+ PageStore.get('config-enabled').taxonomies.categories.enabled
+ ? metafield(MediaPageStore.get('media-categories'))
+ : [];
- let summary = MediaPageStore.get('media-summary');
+ let summary = MediaPageStore.get('media-summary');
- summary = summary ? summary.trim() : '';
+ summary = summary ? summary.trim() : '';
- const [popupContentRef, PopupContent, PopupTrigger] = usePopup();
+ const [popupContentRef, PopupContent, PopupTrigger] = usePopup();
- const [hasSummary, setHasSummary] = useState('' !== summary);
- const [isContentVisible, setIsContentVisible] = useState('' == summary);
+ const [hasSummary, setHasSummary] = useState('' !== summary);
+ const [isContentVisible, setIsContentVisible] = useState('' == summary);
- function proceedMediaRemoval() {
- MediaPageActions.removeMedia();
- popupContentRef.current.toggle();
- }
-
- function cancelMediaRemoval() {
- popupContentRef.current.toggle();
- }
-
- function onMediaDelete(mediaId) {
- // FIXME: Without delay creates conflict [ Uncaught Error: Dispatch.dispatch(...): Cannot dispatch in the middle of a dispatch. ].
- setTimeout(function () {
- PageActions.addNotification('Media removed. Redirecting...', 'mediaDelete');
- setTimeout(function () {
- window.location.href =
- SiteContext._currentValue.url + '/' + MediaPageStore.get('media-data').author_profile.replace(/^\//g, '');
- }, 2000);
- }, 100);
-
- if (void 0 !== mediaId) {
- console.info("Removed media '" + mediaId + '"');
- }
- }
-
- function onMediaDeleteFail(mediaId) {
- // FIXME: Without delay creates conflict [ Uncaught Error: Dispatch.dispatch(...): Cannot dispatch in the middle of a dispatch. ].
- setTimeout(function () {
- PageActions.addNotification('Media removal failed', 'mediaDeleteFail');
- }, 100);
-
- if (void 0 !== mediaId) {
- console.info('Media "' + mediaId + '"' + ' removal failed');
- }
- }
-
- function onClickLoadMore() {
- setIsContentVisible(!isContentVisible);
- }
-
- useEffect(() => {
- MediaPageStore.on('media_delete', onMediaDelete);
- MediaPageStore.on('media_delete_fail', onMediaDeleteFail);
- return () => {
- MediaPageStore.removeListener('media_delete', onMediaDelete);
- MediaPageStore.removeListener('media_delete_fail', onMediaDeleteFail);
- };
- }, []);
-
- const authorLink = formatInnerLink(props.author.url, SiteContext._currentValue.url);
- const authorThumb = formatInnerLink(props.author.thumb, SiteContext._currentValue.url);
-
- function setTimestampAnchors(text) {
- function wrapTimestampWithAnchor(match, string) {
- let split = match.split(':'),
- s = 0,
- m = 1;
-
- while (split.length > 0) {
- s += m * parseInt(split.pop(), 10);
- m *= 60;
- }
-
- const wrapped = `
`;
- return wrapped;
+ function proceedMediaRemoval() {
+ MediaPageActions.removeMedia();
+ popupContentRef.current.toggle();
}
- const timeRegex = new RegExp('((\\d)?\\d:)?(\\d)?\\d:\\d\\d', 'g');
- return text.replace(timeRegex, wrapTimestampWithAnchor);
- }
+ function cancelMediaRemoval() {
+ popupContentRef.current.toggle();
+ }
- return (
-
- {void 0 === PageStore.get('config-media-item').displayAuthor ||
- null === PageStore.get('config-media-item').displayAuthor ||
- !!PageStore.get('config-media-item').displayAuthor ? (
-
- ) : null}
+ function onMediaDelete(mediaId) {
+ // FIXME: Without delay creates conflict [ Uncaught Error: Dispatch.dispatch(...): Cannot dispatch in the middle of a dispatch. ].
+ setTimeout(function () {
+ PageActions.addNotification('Media removed. Redirecting...', 'mediaDelete');
+ setTimeout(function () {
+ window.location.href =
+ SiteContext._currentValue.url +
+ '/' +
+ MediaPageStore.get('media-data').author_profile.replace(/^\//g, '');
+ }, 2000);
+ }, 100);
-
-
- {hasSummary ?
{summary}
: null}
- {(!hasSummary || isContentVisible) && description ? (
-
- ) : null}
- {hasSummary ? (
-
- ) : null}
- {tagsContent.length ? (
-
- ) : null}
- {categoriesContent.length ? (
-
- ) : null}
+ if (void 0 !== mediaId) {
+ console.info("Removed media '" + mediaId + '"');
+ }
+ }
- {userCan.editMedia ? (
-
- {userCan.editMedia ?
: null}
+ function onMediaDeleteFail(mediaId) {
+ // FIXME: Without delay creates conflict [ Uncaught Error: Dispatch.dispatch(...): Cannot dispatch in the middle of a dispatch. ].
+ setTimeout(function () {
+ PageActions.addNotification('Media removal failed', 'mediaDeleteFail');
+ }, 100);
- {userCan.deleteMedia ? (
-
-
-
- ) : null}
+ if (void 0 !== mediaId) {
+ console.info('Media "' + mediaId + '"' + ' removal failed');
+ }
+ }
- {userCan.deleteMedia ? (
-
-
-
- Media removal
- You're willing to remove media permanently?
-
-
-
-
-
-
-
-
- ) : null}
+ function onClickLoadMore() {
+ setIsContentVisible(!isContentVisible);
+ }
+
+ useEffect(() => {
+ MediaPageStore.on('media_delete', onMediaDelete);
+ MediaPageStore.on('media_delete_fail', onMediaDeleteFail);
+ return () => {
+ MediaPageStore.removeListener('media_delete', onMediaDelete);
+ MediaPageStore.removeListener('media_delete_fail', onMediaDeleteFail);
+ };
+ }, []);
+
+ const authorLink = formatInnerLink(props.author.url, SiteContext._currentValue.url);
+ const authorThumb = formatInnerLink(props.author.thumb, SiteContext._currentValue.url);
+
+ function setTimestampAnchors(text) {
+ function wrapTimestampWithAnchor(match, string) {
+ let split = match.split(':'),
+ s = 0,
+ m = 1;
+
+ while (split.length > 0) {
+ s += m * parseInt(split.pop(), 10);
+ m *= 60;
+ }
+
+ const wrapped = `
${match}`;
+ return wrapped;
+ }
+
+ const timeRegex = new RegExp('((\\d)?\\d:)?(\\d)?\\d:\\d\\d', 'g');
+ return text.replace(timeRegex, wrapTimestampWithAnchor);
+ }
+
+ return (
+
+ {void 0 === PageStore.get('config-media-item').displayAuthor ||
+ null === PageStore.get('config-media-item').displayAuthor ||
+ !!PageStore.get('config-media-item').displayAuthor ? (
+
+ ) : null}
+
+
+
+ {hasSummary ?
{summary}
: null}
+ {(!hasSummary || isContentVisible) && description ? (
+
+ ) : null}
+ {hasSummary ? (
+
+ ) : null}
+ {tagsContent.length ? (
+
+ ) : null}
+ {categoriesContent.length ? (
+
+ ) : null}
+
+ {userCan.editMedia ? (
+
+ {userCan.editMedia ? (
+
+ ) : null}
+
+ {userCan.deleteMedia ? (
+
+
+
+ ) : null}
+
+ {userCan.deleteMedia ? (
+
+
+
+ Media removal
+
+ You're willing to remove media permanently?
+
+
+
+
+
+
+
+
+
+ ) : null}
+
+ ) : null}
+
- ) : null}
-
-
-
-
- );
+ {!inEmbeddedApp() &&
}
+
+ );
}
diff --git a/frontend/src/static/js/components/page-layout/PageMain.scss b/frontend/src/static/js/components/page-layout/PageMain.scss
index 55c258c8..3e81c203 100755
--- a/frontend/src/static/js/components/page-layout/PageMain.scss
+++ b/frontend/src/static/js/components/page-layout/PageMain.scss
@@ -1,28 +1,33 @@
.page-main-wrap {
- padding-top: var(--header-height);
- will-change: padding-left;
+ padding-top: var(--header-height);
+ will-change: padding-left;
+
+ @media (min-width: 768px) {
+ .visible-sidebar & {
+ padding-left: var(--sidebar-width);
+ opacity: 1;
+ }
+ }
+
+ .visible-sidebar #page-media & {
+ padding-left: 0;
+ }
- @media (min-width: 768px) {
.visible-sidebar & {
- padding-left: var(--sidebar-width);
- opacity: 1;
+ #page-media {
+ padding-left: 0;
+ }
}
- }
- .visible-sidebar #page-media & {
- padding-left: 0;
- }
-
- .visible-sidebar & {
- #page-media {
- padding-left: 0;
+ body.sliding-sidebar & {
+ transition-property: padding-left;
+ transition-duration: 0.2s;
}
- }
- body.sliding-sidebar & {
- transition-property: padding-left;
- transition-duration: 0.2s;
- }
+ .embedded-app & {
+ padding-top: 0;
+ padding-left: 0;
+ }
}
#page-profile-media,
@@ -30,20 +35,20 @@
#page-profile-about,
#page-liked.profile-page-liked,
#page-history.profile-page-history {
- .page-main {
- min-height: calc(100vh - var(--header-height));
- }
+ .page-main {
+ min-height: calc(100vh - var(--header-height));
+ }
}
.page-main {
- position: relative;
- width: 100%;
- padding-bottom: 16px;
+ position: relative;
+ width: 100%;
+ padding-bottom: 16px;
}
.page-main-inner {
- display: block;
- margin: 1em 1em 0 1em;
+ display: block;
+ margin: 1em 1em 0 1em;
}
#page-profile-media,
@@ -51,7 +56,7 @@
#page-profile-about,
#page-liked.profile-page-liked,
#page-history.profile-page-history {
- .page-main-wrap {
- background-color: var(--body-bg-color);
- }
+ .page-main-wrap {
+ background-color: var(--body-bg-color);
+ }
}
diff --git a/frontend/src/static/js/components/profile-page/ProfilePagesHeader.js b/frontend/src/static/js/components/profile-page/ProfilePagesHeader.js
index d114c2d5..be5fce04 100644
--- a/frontend/src/static/js/components/profile-page/ProfilePagesHeader.js
+++ b/frontend/src/static/js/components/profile-page/ProfilePagesHeader.js
@@ -8,78 +8,78 @@ import { CircleIconButton, PopupMain } from '../_shared';
import { translateString } from '../../utils/helpers/';
class ProfileSearchBar extends React.PureComponent {
- constructor(props) {
- super(props);
+ constructor(props) {
+ super(props);
- this.state = {
- visibleForm: false,
- queryVal: ProfilePageStore.get('author-query') || '',
- };
+ this.state = {
+ visibleForm: false,
+ queryVal: ProfilePageStore.get('author-query') || '',
+ };
- this.onChange = this.onChange.bind(this);
- this.onInputFocus = this.onInputFocus.bind(this);
- this.onInputBlur = this.onInputBlur.bind(this);
- this.showForm = this.showForm.bind(this);
- this.hideForm = this.hideForm.bind(this);
- this.onFormSubmit = this.onFormSubmit.bind(this);
+ this.onChange = this.onChange.bind(this);
+ this.onInputFocus = this.onInputFocus.bind(this);
+ this.onInputBlur = this.onInputBlur.bind(this);
+ this.showForm = this.showForm.bind(this);
+ this.hideForm = this.hideForm.bind(this);
+ this.onFormSubmit = this.onFormSubmit.bind(this);
- this.updateTimeout = null;
- this.pendingUpdate = false;
- this.justShown = false;
- }
+ this.updateTimeout = null;
+ this.pendingUpdate = false;
+ this.justShown = false;
+ }
- updateQuery(value) {
- this.pendingUpdateValue = null;
+ updateQuery(value) {
+ this.pendingUpdateValue = null;
- this.setState(
- {
- queryVal: value,
- },
- function () {
- if ('function' === typeof this.props.onQueryChange) {
- this.props.onQueryChange(this.state.queryVal);
- }
- }
- );
- }
-
- onChange(ev) {
- this.pendingEvent = ev;
- const newValue = ev.target.value || '';
-
- this.setState(
- {
- queryVal: newValue,
- },
- function () {
- if (this.updateTimeout) {
- return;
- }
-
- this.pendingEvent = null;
-
- // Only trigger search if 3+ characters or empty (to reset)
- if ('function' === typeof this.props.onQueryChange) {
- if (newValue.length >= 3 || newValue.length === 0) {
- this.props.onQueryChange(newValue);
- }
- }
-
- this.updateTimeout = setTimeout(
- function () {
- this.updateTimeout = null;
-
- if (this.pendingEvent) {
- this.onChange(this.pendingEvent);
+ this.setState(
+ {
+ queryVal: value,
+ },
+ function () {
+ if ('function' === typeof this.props.onQueryChange) {
+ this.props.onQueryChange(this.state.queryVal);
+ }
}
- }.bind(this),
- 100
);
- }
- );
- }
+ }
- /*onKeydown(e){
+ onChange(ev) {
+ this.pendingEvent = ev;
+ const newValue = ev.target.value || '';
+
+ this.setState(
+ {
+ queryVal: newValue,
+ },
+ function () {
+ if (this.updateTimeout) {
+ return;
+ }
+
+ this.pendingEvent = null;
+
+ // Only trigger search if 3+ characters or empty (to reset)
+ if ('function' === typeof this.props.onQueryChange) {
+ if (newValue.length >= 3 || newValue.length === 0) {
+ this.props.onQueryChange(newValue);
+ }
+ }
+
+ this.updateTimeout = setTimeout(
+ function () {
+ this.updateTimeout = null;
+
+ if (this.pendingEvent) {
+ this.onChange(this.pendingEvent);
+ }
+ }.bind(this),
+ 100
+ );
+ }
+ );
+ }
+
+ /*onKeydown(e){
let found = false, key = e.keyCode || e.charCode;
switch( key ){
case 38: // Arrow Up.
@@ -96,665 +96,726 @@ class ProfileSearchBar extends React.PureComponent {
}
}*/
- onInputFocus() {
- // console.log('FOCUS');
- /*if( this.state.predictionItems.length ){
+ onInputFocus() {
+ // console.log('FOCUS');
+ /*if( this.state.predictionItems.length ){
this.refs.SearchInput.onkeydown = this.refs.SearchInput.onkeydown || this.onKeydown;
}*/
- }
-
- onInputBlur() {
- // Don't hide immediately after showing to prevent race condition
- if (this.justShown) {
- return;
}
- this.hideForm();
- }
- showForm() {
- this.justShown = true;
- this.setState(
- {
- visibleForm: true,
- },
- function () {
- if ('function' === typeof this.props.toggleSearchField) {
- this.props.toggleSearchField();
+ onInputBlur() {
+ // Don't hide immediately after showing to prevent race condition
+ if (this.justShown) {
+ return;
}
- // Reset the flag after a short delay
- setTimeout(() => {
- this.justShown = false;
- }, 200);
- }
- );
- }
+ this.hideForm();
+ }
- hideForm() {
- this.setState(
- {
- visibleForm: false,
- },
- function () {
- if ('function' === typeof this.props.toggleSearchField) {
- this.props.toggleSearchField();
+ showForm() {
+ this.justShown = true;
+ this.setState(
+ {
+ visibleForm: true,
+ },
+ function () {
+ if ('function' === typeof this.props.toggleSearchField) {
+ this.props.toggleSearchField();
+ }
+ // Reset the flag after a short delay
+ setTimeout(() => {
+ this.justShown = false;
+ }, 200);
+ }
+ );
+ }
+
+ hideForm() {
+ this.setState(
+ {
+ visibleForm: false,
+ },
+ function () {
+ if ('function' === typeof this.props.toggleSearchField) {
+ this.props.toggleSearchField();
+ }
+ }
+ );
+ }
+
+ onFormSubmit(ev) {
+ if ('' === this.refs.SearchInput.value.trim()) {
+ ev.preventDefault();
+ ev.stopPropagation();
}
- }
- );
- }
-
- onFormSubmit(ev) {
- if ('' === this.refs.SearchInput.value.trim()) {
- ev.preventDefault();
- ev.stopPropagation();
- }
- }
-
- render() {
- const hasSearchText = this.state.queryVal && this.state.queryVal.length > 0;
-
- // Determine the correct action URL based on page type
- let actionUrl = LinksContext._currentValue.profile.media;
- if (this.props.type === 'shared_by_me') {
- actionUrl = LinksContext._currentValue.profile.shared_by_me;
- } else if (this.props.type === 'shared_with_me') {
- actionUrl = LinksContext._currentValue.profile.shared_with_me;
}
- if (!this.state.visibleForm) {
- return (
-
-
- search
-
- {hasSearchText ? (
-
- ) : null}
-
- );
- }
+ render() {
+ const hasSearchText = this.state.queryVal && this.state.queryVal.length > 0;
- return (
-
- );
- }
+ // Determine the correct action URL based on page type
+ let actionUrl = LinksContext._currentValue.profile.media;
+ if (this.props.type === 'shared_by_me') {
+ actionUrl = LinksContext._currentValue.profile.shared_by_me;
+ } else if (this.props.type === 'shared_with_me') {
+ actionUrl = LinksContext._currentValue.profile.shared_with_me;
+ }
+
+ if (!this.state.visibleForm) {
+ return (
+
+
+ search
+
+ {hasSearchText ? (
+
+ ) : null}
+
+ );
+ }
+
+ return (
+
+ );
+ }
}
ProfileSearchBar.propTypes = {
- onQueryChange: PropTypes.func,
- type: PropTypes.string,
+ onQueryChange: PropTypes.func,
+ type: PropTypes.string,
};
ProfileSearchBar.defaultProps = {};
function InlineTab(props) {
- return (
-
-
- {props.label}
-
-
- );
+ return (
+
+
+ {props.label}
+
+
+ );
}
InlineTab.propTypes = {
- id: PropTypes.string.isRequired,
- label: PropTypes.string.isRequired,
- link: PropTypes.string.isRequired,
- isActive: PropTypes.bool.isRequired,
+ id: PropTypes.string.isRequired,
+ label: PropTypes.string.isRequired,
+ link: PropTypes.string.isRequired,
+ isActive: PropTypes.bool.isRequired,
};
class NavMenuInlineTabs extends React.PureComponent {
- constructor(props) {
- super(props);
+ constructor(props) {
+ super(props);
- this.state = {
- displayNext: false,
- displayPrev: false,
- };
+ this.state = {
+ displayNext: false,
+ displayPrev: false,
+ };
- this.nextSlide = this.nextSlide.bind(this);
- this.prevSlide = this.prevSlide.bind(this);
+ this.nextSlide = this.nextSlide.bind(this);
+ this.prevSlide = this.prevSlide.bind(this);
- this.updateSlider = this.updateSlider.bind(this);
- this.updateSliderButtonsView = this.updateSliderButtonsView.bind(this);
+ this.updateSlider = this.updateSlider.bind(this);
+ this.updateSliderButtonsView = this.updateSliderButtonsView.bind(this);
- this.onToggleSearchField = this.onToggleSearchField.bind(this);
+ this.onToggleSearchField = this.onToggleSearchField.bind(this);
- PageStore.on('window_resize', this.updateSlider);
+ PageStore.on('window_resize', this.updateSlider);
- this.sliderRecalTimeout = null;
+ this.sliderRecalTimeout = null;
- PageStore.on(
- 'changed_page_sidebar_visibility',
- function () {
- clearTimeout(this.sliderRecalTimeout);
+ PageStore.on(
+ 'changed_page_sidebar_visibility',
+ function () {
+ clearTimeout(this.sliderRecalTimeout);
- // NOTE: 200ms is transition duration, set in CSS.
- this.sliderRecalTimeout = setTimeout(
- function () {
- this.updateSliderButtonsView();
+ // NOTE: 200ms is transition duration, set in CSS.
+ this.sliderRecalTimeout = setTimeout(
+ function () {
+ this.updateSliderButtonsView();
- this.sliderRecalTimeout = setTimeout(
- function () {
- this.sliderRecalTimeout = null;
+ this.sliderRecalTimeout = setTimeout(
+ function () {
+ this.sliderRecalTimeout = null;
- this.updateSlider();
- }.bind(this),
- 50
- );
- }.bind(this),
- 150
+ this.updateSlider();
+ }.bind(this),
+ 50
+ );
+ }.bind(this),
+ 150
+ );
+ }.bind(this)
);
- }.bind(this)
- );
- this.previousBtn = (
-
-
- keyboard_arrow_left
-
-
- );
- this.nextBtn = (
-
-
- keyboard_arrow_right
-
-
- );
+ this.previousBtn = (
+
+
+ keyboard_arrow_left
+
+
+ );
+ this.nextBtn = (
+
+
+ keyboard_arrow_right
+
+
+ );
- this.userIsAuthor =
- !MemberContext._currentValue.is.anonymous &&
- ProfilePageStore.get('author-data').username === MemberContext._currentValue.username;
- }
-
- componentDidMount() {
- this.updateSlider();
- if (this.refs.itemsListWrap) {
- this.refs.itemsListWrap.addEventListener('scroll', this.updateSliderButtonsView.bind(this));
+ this.userIsAuthor =
+ !MemberContext._currentValue.is.anonymous &&
+ ProfilePageStore.get('author-data').username === MemberContext._currentValue.username;
}
- }
- componentWillUnmount() {
- if (this.refs.itemsListWrap) {
- this.refs.itemsListWrap.removeEventListener('scroll', this.updateSliderButtonsView.bind(this));
+ componentDidMount() {
+ this.updateSlider();
+ if (this.refs.itemsListWrap) {
+ this.refs.itemsListWrap.addEventListener('scroll', this.updateSliderButtonsView.bind(this));
+ }
}
- }
- nextSlide() {
- if (!this.refs.itemsListWrap) return;
- const scrollAmount = this.refs.itemsListWrap.offsetWidth * 0.7; // Scroll 70% of visible width
- this.refs.itemsListWrap.scrollLeft += scrollAmount;
- setTimeout(() => this.updateSliderButtonsView(), 50);
- }
+ componentWillUnmount() {
+ if (this.refs.itemsListWrap) {
+ this.refs.itemsListWrap.removeEventListener('scroll', this.updateSliderButtonsView.bind(this));
+ }
+ }
- prevSlide() {
- if (!this.refs.itemsListWrap) return;
- const scrollAmount = this.refs.itemsListWrap.offsetWidth * 0.7; // Scroll 70% of visible width
- this.refs.itemsListWrap.scrollLeft -= scrollAmount;
- setTimeout(() => this.updateSliderButtonsView(), 50);
- }
+ nextSlide() {
+ if (!this.refs.itemsListWrap) return;
+ const scrollAmount = this.refs.itemsListWrap.offsetWidth * 0.7; // Scroll 70% of visible width
+ this.refs.itemsListWrap.scrollLeft += scrollAmount;
+ setTimeout(() => this.updateSliderButtonsView(), 50);
+ }
- updateSlider(afterItemsUpdate) {
- this.updateSliderButtonsView();
- }
+ prevSlide() {
+ if (!this.refs.itemsListWrap) return;
+ const scrollAmount = this.refs.itemsListWrap.offsetWidth * 0.7; // Scroll 70% of visible width
+ this.refs.itemsListWrap.scrollLeft -= scrollAmount;
+ setTimeout(() => this.updateSliderButtonsView(), 50);
+ }
- updateSliderButtonsView() {
- if (!this.refs.itemsListWrap) return;
+ updateSlider(afterItemsUpdate) {
+ this.updateSliderButtonsView();
+ }
- const container = this.refs.itemsListWrap;
- const scrollLeft = container.scrollLeft;
- const scrollWidth = container.scrollWidth;
- const clientWidth = container.clientWidth;
+ updateSliderButtonsView() {
+ if (!this.refs.itemsListWrap) return;
- // Show prev arrow if we can scroll left
- const canScrollLeft = scrollLeft > 1;
+ const container = this.refs.itemsListWrap;
+ const scrollLeft = container.scrollLeft;
+ const scrollWidth = container.scrollWidth;
+ const clientWidth = container.clientWidth;
- // Show next arrow if we can scroll right
- const canScrollRight = scrollLeft < scrollWidth - clientWidth - 1;
+ // Show prev arrow if we can scroll left
+ const canScrollLeft = scrollLeft > 1;
- this.setState({
- displayPrev: canScrollLeft,
- displayNext: canScrollRight,
- });
- }
+ // Show next arrow if we can scroll right
+ const canScrollRight = scrollLeft < scrollWidth - clientWidth - 1;
- onToggleSearchField() {
- setTimeout(() => this.updateSlider(), 100);
- }
+ this.setState({
+ displayPrev: canScrollLeft,
+ displayNext: canScrollRight,
+ });
+ }
- render() {
- return (
-
+ );
+ }
}
NavMenuInlineTabs.propTypes = {
- type: PropTypes.string.isRequired,
- onQueryChange: PropTypes.func,
- onToggleFiltersClick: PropTypes.func,
- onToggleTagsClick: PropTypes.func,
- onToggleSortingClick: PropTypes.func,
- hasActiveFilters: PropTypes.bool,
- hasActiveTags: PropTypes.bool,
- hasActiveSort: PropTypes.bool,
+ type: PropTypes.string.isRequired,
+ onQueryChange: PropTypes.func,
+ onToggleFiltersClick: PropTypes.func,
+ onToggleTagsClick: PropTypes.func,
+ onToggleSortingClick: PropTypes.func,
+ hasActiveFilters: PropTypes.bool,
+ hasActiveTags: PropTypes.bool,
+ hasActiveSort: PropTypes.bool,
};
function AddBannerButton(props) {
- let link = props.link;
+ let link = props.link;
- if (window.MediaCMS.site.devEnv) {
- link = '/edit-channel.html';
- }
- return (
-
- add_photo_alternate
-
- );
+ if (window.MediaCMS.site.devEnv) {
+ link = '/edit-channel.html';
+ }
+ return (
+
+ add_photo_alternate
+
+ );
}
function EditBannerButton(props) {
- let link = props.link;
+ let link = props.link;
- if (window.MediaCMS.site.devEnv) {
- link = '/edit-channel.html';
- }
- return (
-
- edit
-
- );
+ if (window.MediaCMS.site.devEnv) {
+ link = '/edit-channel.html';
+ }
+ return (
+
+ edit
+
+ );
}
function EditProfileButton(props) {
- let link = props.link;
+ let link = props.link;
- if (window.MediaCMS.site.devEnv) {
- link = '/edit-profile.html';
- }
+ if (window.MediaCMS.site.devEnv) {
+ link = '/edit-profile.html';
+ }
- return (
-
- edit
-
- );
+ return (
+
+ edit
+
+ );
}
export default function ProfilePagesHeader(props) {
- const [popupContentRef, PopupContent, PopupTrigger] = usePopup();
+ const [popupContentRef, PopupContent, PopupTrigger] = usePopup();
- const profilePageHeaderRef = useRef(null);
- const profileNavRef = useRef(null);
+ const profilePageHeaderRef = useRef(null);
+ const profileNavRef = useRef(null);
- const [fixedNav, setFixedNav] = useState(false);
+ const [fixedNav, setFixedNav] = useState(false);
- const positions = {
- profileNavTop: 0,
- };
-
- const userIsAdmin = !MemberContext._currentValue.is.anonymous && MemberContext._currentValue.is.admin;
- const userIsAuthor =
- !MemberContext._currentValue.is.anonymous &&
- ProfilePageStore.get('author-data').username === MemberContext._currentValue.username;
- const userCanEditProfile =
- userIsAuthor || (!MemberContext._currentValue.is.anonymous && MemberContext._currentValue.can.editProfile);
- const userCanDeleteProfile =
- userIsAdmin ||
- userIsAuthor ||
- (!MemberContext._currentValue.is.anonymous && MemberContext._currentValue.can.deleteProfile);
-
- function updateProfileNavTopPosition() {
- positions.profileHeaderTop = profilePageHeaderRef.current.offsetTop;
- positions.profileNavTop =
- positions.profileHeaderTop +
- profilePageHeaderRef.current.offsetHeight -
- profileNavRef.current.refs.tabsNav.offsetHeight;
- }
-
- function updateFixedNavPosition() {
- setFixedNav(positions.profileHeaderTop + window.scrollY > positions.profileNavTop);
- }
-
- function cancelProfileRemoval() {
- popupContentRef.current.toggle();
- }
-
- function proceedMediaRemoval() {
- ProfilePageActions.remove_profile();
- popupContentRef.current.toggle();
- }
-
- function onProfileDelete(username) {
- // FIXME: Without delay creates conflict [ Uncaught Error: Dispatch.dispatch(...): Cannot dispatch in the middle of a dispatch. ].
- setTimeout(function () {
- PageActions.addNotification('Profile removed. Redirecting...', 'profileDelete');
- setTimeout(function () {
- window.location.href = SiteContext._currentValue.url;
- }, 2000);
- }, 100);
-
- if (void 0 !== username) {
- console.info("Removed user's profile '" + username + '"');
- }
- }
-
- function onProfileDeleteFail(username) {
- // FIXME: Without delay creates conflict [ Uncaught Error: Dispatch.dispatch(...): Cannot dispatch in the middle of a dispatch. ].
- setTimeout(function () {
- PageActions.addNotification('Profile removal failed', 'profileDeleteFail');
- }, 100);
-
- if (void 0 !== username) {
- console.info('Profile "' + username + '"' + ' removal failed');
- }
- }
-
- function onWindowResize() {
- updateProfileNavTopPosition();
- updateFixedNavPosition();
- }
-
- function onWindowScroll() {
- updateFixedNavPosition();
- }
-
- useEffect(() => {
- if (userCanDeleteProfile) {
- ProfilePageStore.on('profile_delete', onProfileDelete);
- ProfilePageStore.on('profile_delete_fail', onProfileDeleteFail);
- }
-
- PageStore.on('resize', onWindowResize);
- PageStore.on('changed_page_sidebar_visibility', onWindowResize);
- PageStore.on('window_scroll', onWindowScroll);
-
- updateProfileNavTopPosition();
- updateFixedNavPosition();
-
- return () => {
- if (userCanDeleteProfile) {
- ProfilePageStore.removeListener('profile_delete', onProfileDelete);
- ProfilePageStore.removeListener('profile_delete_fail', onProfileDeleteFail);
- }
-
- PageStore.removeListener('resize', onWindowResize);
- PageStore.removeListener('changed_page_sidebar_visibility', onWindowResize);
- PageStore.removeListener('window_scroll', onWindowScroll);
+ const positions = {
+ profileNavTop: 0,
};
- }, []);
- return (
-
-
- {props.author.banner_thumbnail_url ? (
-
- ) : null}
+ const userIsAdmin = !MemberContext._currentValue.is.anonymous && MemberContext._currentValue.is.admin;
+ const userIsAuthor =
+ !MemberContext._currentValue.is.anonymous &&
+ ProfilePageStore.get('author-data').username === MemberContext._currentValue.username;
+ const userCanEditProfile =
+ userIsAuthor || (!MemberContext._currentValue.is.anonymous && MemberContext._currentValue.can.editProfile);
+ const userCanDeleteProfile =
+ userIsAdmin ||
+ userIsAuthor ||
+ (!MemberContext._currentValue.is.anonymous && MemberContext._currentValue.can.deleteProfile);
- {userCanDeleteProfile && !userIsAuthor ? (
-
-
-
-
+ function updateProfileNavTopPosition() {
+ positions.profileHeaderTop = profilePageHeaderRef.current.offsetTop;
+ positions.profileNavTop =
+ positions.profileHeaderTop +
+ profilePageHeaderRef.current.offsetHeight -
+ profileNavRef.current.refs.tabsNav.offsetHeight;
+ }
-
-
-
- Profile removal
- You're willing to remove profile permanently?
-
-
-
-
-
+ function updateFixedNavPosition() {
+ setFixedNav(positions.profileHeaderTop + window.scrollY > positions.profileNavTop);
+ }
+
+ function cancelProfileRemoval() {
+ popupContentRef.current.toggle();
+ }
+
+ function proceedMediaRemoval() {
+ ProfilePageActions.remove_profile();
+ popupContentRef.current.toggle();
+ }
+
+ function onProfileDelete(username) {
+ // FIXME: Without delay creates conflict [ Uncaught Error: Dispatch.dispatch(...): Cannot dispatch in the middle of a dispatch. ].
+ setTimeout(function () {
+ PageActions.addNotification('Profile removed. Redirecting...', 'profileDelete');
+ setTimeout(function () {
+ window.location.href = SiteContext._currentValue.url;
+ }, 2000);
+ }, 100);
+
+ if (void 0 !== username) {
+ console.info("Removed user's profile '" + username + '"');
+ }
+ }
+
+ function onProfileDeleteFail(username) {
+ // FIXME: Without delay creates conflict [ Uncaught Error: Dispatch.dispatch(...): Cannot dispatch in the middle of a dispatch. ].
+ setTimeout(function () {
+ PageActions.addNotification('Profile removal failed', 'profileDeleteFail');
+ }, 100);
+
+ if (void 0 !== username) {
+ console.info('Profile "' + username + '"' + ' removal failed');
+ }
+ }
+
+ function onWindowResize() {
+ updateProfileNavTopPosition();
+ updateFixedNavPosition();
+ }
+
+ function onWindowScroll() {
+ updateFixedNavPosition();
+ }
+
+ useEffect(() => {
+ if (userCanDeleteProfile) {
+ ProfilePageStore.on('profile_delete', onProfileDelete);
+ ProfilePageStore.on('profile_delete_fail', onProfileDeleteFail);
+ }
+
+ PageStore.on('resize', onWindowResize);
+ PageStore.on('changed_page_sidebar_visibility', onWindowResize);
+ PageStore.on('window_scroll', onWindowScroll);
+
+ updateProfileNavTopPosition();
+ updateFixedNavPosition();
+
+ return () => {
+ if (userCanDeleteProfile) {
+ ProfilePageStore.removeListener('profile_delete', onProfileDelete);
+ ProfilePageStore.removeListener('profile_delete_fail', onProfileDeleteFail);
+ }
+
+ PageStore.removeListener('resize', onWindowResize);
+ PageStore.removeListener('changed_page_sidebar_visibility', onWindowResize);
+ PageStore.removeListener('window_scroll', onWindowScroll);
+ };
+ }, []);
+
+ return (
+
+ {!props.hideChannelBanner && (
+
+ {props.author.banner_thumbnail_url ? (
+
+ ) : null}
+
+ {userCanDeleteProfile && !userIsAuthor ? (
+
+
+
+
+
+
+
+
+ Profile removal
+
+ You're willing to remove profile permanently?
+
+
+
+
+
+
+
+
+
+
+ ) : null}
+
+ {userCanEditProfile && userIsAuthor ? (
+ props.author.banner_thumbnail_url ? (
+
+ ) : (
+
+ )
+ ) : null}
-
-
-
- ) : null}
+ )}
- {userCanEditProfile && userIsAuthor ? (
- props.author.banner_thumbnail_url ? (
-
- ) : (
-
- )
- ) : null}
-
-
-
- {props.author.thumbnail_url || props.author.name ? (
-
-
-
{props.author.thumbnail_url ?

: null}
-
- {props.author.name ? (
-
-
{props.author.name}
- {userCanEditProfile && !userIsAuthor ? : null}
-
+
+ {props.author.thumbnail_url || props.author.name ? (
+
+
+
+ {props.author.thumbnail_url ?

: null}
+
+
+ {props.author.name ? (
+
+
{props.author.name}
+ {userCanEditProfile && !userIsAuthor ? (
+
+ ) : null}
+
+ ) : null}
+
+
+
) : null}
-
-
-
- ) : null}
-
-
-
- );
+
+
+
+ );
}
ProfilePagesHeader.propTypes = {
- author: PropTypes.object.isRequired,
- type: PropTypes.string.isRequired,
- onQueryChange: PropTypes.func,
- onToggleFiltersClick: PropTypes.func,
- onToggleTagsClick: PropTypes.func,
- onToggleSortingClick: PropTypes.func,
- hasActiveFilters: PropTypes.bool,
- hasActiveTags: PropTypes.bool,
- hasActiveSort: PropTypes.bool,
+ author: PropTypes.object.isRequired,
+ type: PropTypes.string.isRequired,
+ onQueryChange: PropTypes.func,
+ onToggleFiltersClick: PropTypes.func,
+ onToggleTagsClick: PropTypes.func,
+ onToggleSortingClick: PropTypes.func,
+ hasActiveFilters: PropTypes.bool,
+ hasActiveTags: PropTypes.bool,
+ hasActiveSort: PropTypes.bool,
};
ProfilePagesHeader.defaultProps = {
- type: 'media',
+ type: 'media',
};
diff --git a/frontend/src/static/js/pages/ProfileMediaPage.js b/frontend/src/static/js/pages/ProfileMediaPage.js
index eabe8d6b..7a8797b6 100755
--- a/frontend/src/static/js/pages/ProfileMediaPage.js
+++ b/frontend/src/static/js/pages/ProfileMediaPage.js
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import { ApiUrlContext, LinksConsumer, MemberContext } from '../utils/contexts';
import { PageStore, ProfilePageStore } from '../utils/stores';
import { ProfilePageActions, PageActions } from '../utils/actions';
-import { translateString } from '../utils/helpers/';
+import { inEmbeddedApp, translateString } from '../utils/helpers/';
import { MediaListWrapper } from '../components/MediaListWrapper';
import ProfilePagesHeader from '../components/profile-page/ProfilePagesHeader';
import ProfilePagesContent from '../components/profile-page/ProfilePagesContent';
@@ -24,994 +24,1062 @@ import { Page } from './_Page';
import '../components/profile-page/ProfilePage.scss';
export class ProfileMediaPage extends Page {
- constructor(props, pageSlug) {
- super(props, 'string' === typeof pageSlug ? pageSlug : 'author-home');
+ constructor(props, pageSlug) {
+ super(props, 'string' === typeof pageSlug ? pageSlug : 'author-home');
- this.profilePageSlug = 'string' === typeof pageSlug ? pageSlug : 'author-home';
+ this.profilePageSlug = 'string' === typeof pageSlug ? pageSlug : 'author-home';
- this.state = {
- channelMediaCount: -1,
- author: ProfilePageStore.get('author-data'),
- uploadsPreviewItemsCount: 0,
- title: this.props.title,
- query: ProfilePageStore.get('author-query'),
- requestUrl: null,
- selectedMedia: new Set(),
- availableMediaIds: [],
- showConfirmModal: false,
- pendingAction: null,
- confirmMessage: '',
- listKey: 0,
- notificationMessage: '',
- showNotification: false,
- notificationType: 'success',
- hiddenFilters: true,
- hiddenTags: true,
- hiddenSorting: true,
- filterArgs: '',
- availableTags: [],
- selectedTag: 'all',
- selectedSort: 'date_added_desc',
- showPermissionModal: false,
- permissionType: null,
- showPlaylistModal: false,
- showChangeOwnerModal: false,
- showPublishStateModal: false,
- showCategoryModal: false,
- showTagModal: false,
- };
+ this.state = {
+ channelMediaCount: -1,
+ author: ProfilePageStore.get('author-data'),
+ uploadsPreviewItemsCount: 0,
+ title: this.props.title,
+ query: ProfilePageStore.get('author-query'),
+ requestUrl: null,
+ selectedMedia: new Set(),
+ availableMediaIds: [],
+ showConfirmModal: false,
+ pendingAction: null,
+ confirmMessage: '',
+ listKey: 0,
+ notificationMessage: '',
+ showNotification: false,
+ notificationType: 'success',
+ hiddenFilters: true,
+ hiddenTags: true,
+ hiddenSorting: true,
+ filterArgs: '',
+ availableTags: [],
+ selectedTag: 'all',
+ 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.onAuthorPreviewItemsCountCallback = this.onAuthorPreviewItemsCountCallback.bind(this);
- this.getCountFunc = this.getCountFunc.bind(this);
- this.changeRequestQuery = this.changeRequestQuery.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.onToggleTagsClick = this.onToggleTagsClick.bind(this);
- this.onToggleSortingClick = this.onToggleSortingClick.bind(this);
- this.onFiltersUpdate = this.onFiltersUpdate.bind(this);
- this.onTagSelect = this.onTagSelect.bind(this);
- this.onSortSelect = this.onSortSelect.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);
+ this.authorDataLoad = this.authorDataLoad.bind(this);
+ this.onAuthorPreviewItemsCountCallback = this.onAuthorPreviewItemsCountCallback.bind(this);
+ this.getCountFunc = this.getCountFunc.bind(this);
+ this.changeRequestQuery = this.changeRequestQuery.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.onToggleTagsClick = this.onToggleTagsClick.bind(this);
+ this.onToggleSortingClick = this.onToggleSortingClick.bind(this);
+ this.onFiltersUpdate = this.onFiltersUpdate.bind(this);
+ this.onTagSelect = this.onTagSelect.bind(this);
+ this.onSortSelect = this.onSortSelect.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);
- }
-
- componentDidMount() {
- ProfilePageActions.load_author_data();
- }
-
- authorDataLoad() {
- const author = ProfilePageStore.get('author-data');
-
- let requestUrl = this.state.requestUrl;
-
- if (author) {
- if (this.state.query) {
- requestUrl = ApiUrlContext._currentValue.media + '?author=' + author.id + '&q=' + encodeURIComponent(this.state.query) + this.state.filterArgs;
- } else {
- requestUrl = ApiUrlContext._currentValue.media + '?author=' + author.id + this.state.filterArgs;
- }
+ ProfilePageStore.on('load-author-data', this.authorDataLoad);
}
- this.setState({
- author: author,
- requestUrl: requestUrl,
- });
- }
+ componentDidMount() {
+ ProfilePageActions.load_author_data();
+ }
- onAuthorPreviewItemsCountCallback(totalAuthorPreviewItems) {
- this.setState({
- uploadsPreviewItemsCount: totalAuthorPreviewItems,
- });
- }
+ authorDataLoad() {
+ const author = ProfilePageStore.get('author-data');
- getCountFunc(count) {
- this.setState(
- {
- channelMediaCount: count,
- },
- () => {
- if (this.state.query) {
- let title = '';
+ let requestUrl = this.state.requestUrl;
- if (!count) {
- title = translateString('No results for') + ' "' + this.state.query + '"';
- } else if (1 === count) {
- title = translateString('1 result for') + ' "' + this.state.query + '"';
- } else {
- title = count + ' ' + translateString('results for') + ' "' + this.state.query + '"';
- }
-
- this.setState({
- title: title,
- });
+ if (author) {
+ if (this.state.query) {
+ requestUrl =
+ ApiUrlContext._currentValue.media +
+ '?author=' +
+ author.id +
+ '&q=' +
+ encodeURIComponent(this.state.query) +
+ this.state.filterArgs;
+ } else {
+ requestUrl = ApiUrlContext._currentValue.media + '?author=' + author.id + this.state.filterArgs;
+ }
}
- }
- );
- }
- changeRequestQuery(newQuery) {
- if (!this.state.author) {
- return;
+ this.setState({
+ author: author,
+ requestUrl: requestUrl,
+ });
}
- let requestUrl;
-
- if (newQuery) {
- requestUrl = ApiUrlContext._currentValue.media + '?author=' + this.state.author.id + '&q=' + encodeURIComponent(newQuery) + this.state.filterArgs;
- } else {
- requestUrl = ApiUrlContext._currentValue.media + '?author=' + this.state.author.id + this.state.filterArgs;
+ onAuthorPreviewItemsCountCallback(totalAuthorPreviewItems) {
+ this.setState({
+ uploadsPreviewItemsCount: totalAuthorPreviewItems,
+ });
}
- let title = this.state.title;
+ getCountFunc(count) {
+ this.setState(
+ {
+ channelMediaCount: count,
+ },
+ () => {
+ if (this.state.query) {
+ let title = '';
- if ('' === newQuery) {
- title = this.props.title;
+ if (!count) {
+ title = translateString('No results for') + ' "' + this.state.query + '"';
+ } else if (1 === count) {
+ title = translateString('1 result for') + ' "' + this.state.query + '"';
+ } else {
+ title = count + ' ' + translateString('results for') + ' "' + this.state.query + '"';
+ }
+
+ this.setState({
+ title: title,
+ });
+ }
+ }
+ );
}
- this.setState({
- requestUrl: requestUrl,
- query: newQuery,
- title: title,
- });
- }
-
- handleMediaSelection(mediaId, isSelected) {
- this.setState((prevState) => {
- const newSelectedMedia = new Set(prevState.selectedMedia);
- if (isSelected) {
- newSelectedMedia.add(mediaId);
- } else {
- newSelectedMedia.delete(mediaId);
- }
- return { selectedMedia: newSelectedMedia };
- });
- }
-
- 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() {
- this.setState({
- hiddenFilters: !this.state.hiddenFilters,
- hiddenTags: true,
- hiddenSorting: true,
- });
- }
-
- onToggleTagsClick() {
- this.setState({
- hiddenFilters: true,
- hiddenTags: !this.state.hiddenTags,
- hiddenSorting: true,
- });
- }
-
- onToggleSortingClick() {
- this.setState({
- hiddenFilters: true,
- hiddenTags: true,
- hiddenSorting: !this.state.hiddenSorting,
- });
- }
-
- onTagSelect(tag) {
- this.setState({ selectedTag: tag }, () => {
- // Apply tag filter
- this.onFiltersUpdate({
- media_type: this.state.filterArgs.includes('media_type') ? this.state.filterArgs.match(/media_type=([^&]*)/)?.[1] : null,
- upload_date: this.state.filterArgs.includes('upload_date') ? this.state.filterArgs.match(/upload_date=([^&]*)/)?.[1] : null,
- duration: this.state.filterArgs.includes('duration') ? this.state.filterArgs.match(/duration=([^&]*)/)?.[1] : null,
- publish_state: this.state.filterArgs.includes('publish_state') ? this.state.filterArgs.match(/publish_state=([^&]*)/)?.[1] : null,
- sort_by: this.state.selectedSort,
- tag: tag,
- });
- });
- }
-
- onSortSelect(sortOption) {
- this.setState({ selectedSort: sortOption }, () => {
- // Apply sort filter
- this.onFiltersUpdate({
- media_type: this.state.filterArgs.includes('media_type') ? this.state.filterArgs.match(/media_type=([^&]*)/)?.[1] : null,
- upload_date: this.state.filterArgs.includes('upload_date') ? this.state.filterArgs.match(/upload_date=([^&]*)/)?.[1] : null,
- duration: this.state.filterArgs.includes('duration') ? this.state.filterArgs.match(/duration=([^&]*)/)?.[1] : null,
- publish_state: this.state.filterArgs.includes('publish_state') ? this.state.filterArgs.match(/publish_state=([^&]*)/)?.[1] : null,
- sort_by: sortOption,
- tag: this.state.selectedTag,
- });
- });
- }
-
- onFiltersUpdate(updatedArgs) {
- const args = {
- media_type: null,
- upload_date: null,
- duration: null,
- publish_state: null,
- sort_by: null,
- ordering: null,
- t: null,
- };
-
- switch (updatedArgs.media_type) {
- case 'video':
- case 'audio':
- case 'image':
- case 'pdf':
- args.media_type = updatedArgs.media_type;
- break;
- }
-
- switch (updatedArgs.upload_date) {
- case 'today':
- case 'this_week':
- case 'this_month':
- case 'this_year':
- args.upload_date = updatedArgs.upload_date;
- break;
- }
-
- // Handle duration filter
- if (updatedArgs.duration && updatedArgs.duration !== 'all') {
- args.duration = updatedArgs.duration;
- }
-
- // Handle publish state filter
- if (updatedArgs.publish_state && updatedArgs.publish_state !== 'all') {
- args.publish_state = updatedArgs.publish_state;
- }
-
- switch (updatedArgs.sort_by) {
- case 'date_added_desc':
- // Default sorting, no need to add parameters
- break;
- case 'date_added_asc':
- args.ordering = 'asc';
- break;
- case 'alphabetically_asc':
- args.sort_by = 'title_asc';
- break;
- case 'alphabetically_desc':
- args.sort_by = 'title_desc';
- break;
- case 'plays_least':
- args.sort_by = 'views_asc';
- break;
- case 'plays_most':
- args.sort_by = 'views_desc';
- break;
- case 'likes_least':
- args.sort_by = 'likes_asc';
- break;
- case 'likes_most':
- args.sort_by = 'likes_desc';
- break;
- }
-
- // Handle tag filter
- if (updatedArgs.tag && updatedArgs.tag !== 'all') {
- args.t = updatedArgs.tag;
- }
-
- const newArgs = [];
-
- for (let arg in args) {
- if (null !== args[arg]) {
- newArgs.push(arg + '=' + args[arg]);
- }
- }
-
- this.setState(
- {
- filterArgs: newArgs.length ? '&' + newArgs.join('&') : '',
- selectedMedia: new Set(), // Clear selected items when filter changes
- },
- function () {
- // Update the request URL with new filter args
+ changeRequestQuery(newQuery) {
if (!this.state.author) {
- return;
+ return;
}
let requestUrl;
- if (this.state.query) {
- requestUrl = ApiUrlContext._currentValue.media + '?author=' + this.state.author.id + '&q=' + encodeURIComponent(this.state.query) + this.state.filterArgs;
+ if (newQuery) {
+ requestUrl =
+ ApiUrlContext._currentValue.media +
+ '?author=' +
+ this.state.author.id +
+ '&q=' +
+ encodeURIComponent(newQuery) +
+ this.state.filterArgs;
} else {
- requestUrl = ApiUrlContext._currentValue.media + '?author=' + this.state.author.id + this.state.filterArgs;
+ requestUrl = ApiUrlContext._currentValue.media + '?author=' + this.state.author.id + this.state.filterArgs;
+ }
+
+ let title = this.state.title;
+
+ if ('' === newQuery) {
+ title = this.props.title;
}
this.setState({
- requestUrl: requestUrl,
+ requestUrl: requestUrl,
+ query: newQuery,
+ title: title,
});
- }
- );
- }
-
- 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) {
- // Extract tags from response
- if (responseData && responseData.tags) {
- const tags = responseData.tags.split(',').map((tag) => tag.trim()).filter((tag) => tag);
- this.setState({ availableTags: tags });
}
- }
- pageContent() {
- const authorData = ProfilePageStore.get('author-data');
+ handleMediaSelection(mediaId, isSelected) {
+ this.setState((prevState) => {
+ const newSelectedMedia = new Set(prevState.selectedMedia);
+ if (isSelected) {
+ newSelectedMedia.add(mediaId);
+ } else {
+ newSelectedMedia.delete(mediaId);
+ }
+ return { selectedMedia: newSelectedMedia };
+ });
+ }
- const isMediaAuthor = authorData && authorData.username === MemberContext._currentValue.username;
+ handleBulkAction(action) {
+ const selectedCount = this.state.selectedMedia.size;
- // Check if any filters are active (excluding default sort and tags)
- const hasActiveFilters = this.state.filterArgs && (
- this.state.filterArgs.includes('media_type=') ||
- this.state.filterArgs.includes('upload_date=') ||
- this.state.filterArgs.includes('duration=') ||
- this.state.filterArgs.includes('publish_state=')
- );
+ if (selectedCount === 0) {
+ return;
+ }
- const hasActiveTags = this.state.selectedTag && this.state.selectedTag !== 'all';
- const hasActiveSort = this.state.selectedSort && this.state.selectedSort !== 'date_added_desc';
+ 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
+ }
+ }
- return [
- this.state.author ? (
-
- ) : null,
- this.state.author ? (
-
-
-
-
-
- 0}
- selectedMedia={this.state.selectedMedia}
- onMediaSelection={this.handleMediaSelection}
- onItemsUpdate={this.handleItemsUpdate}
- onResponseDataLoaded={this.onResponseDataLoaded}
- />
-
-
- ) : null,
-
,
-
,
-
,
-
,
-
,
-
,
-
,
- this.state.showNotification ? (
-
- {this.state.notificationMessage}
-
- ) : null,
- ];
- }
+ 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() {
+ this.setState({
+ hiddenFilters: !this.state.hiddenFilters,
+ hiddenTags: true,
+ hiddenSorting: true,
+ });
+ }
+
+ onToggleTagsClick() {
+ this.setState({
+ hiddenFilters: true,
+ hiddenTags: !this.state.hiddenTags,
+ hiddenSorting: true,
+ });
+ }
+
+ onToggleSortingClick() {
+ this.setState({
+ hiddenFilters: true,
+ hiddenTags: true,
+ hiddenSorting: !this.state.hiddenSorting,
+ });
+ }
+
+ onTagSelect(tag) {
+ this.setState({ selectedTag: tag }, () => {
+ // Apply tag filter
+ this.onFiltersUpdate({
+ media_type: this.state.filterArgs.includes('media_type')
+ ? this.state.filterArgs.match(/media_type=([^&]*)/)?.[1]
+ : null,
+ upload_date: this.state.filterArgs.includes('upload_date')
+ ? this.state.filterArgs.match(/upload_date=([^&]*)/)?.[1]
+ : null,
+ duration: this.state.filterArgs.includes('duration')
+ ? this.state.filterArgs.match(/duration=([^&]*)/)?.[1]
+ : null,
+ publish_state: this.state.filterArgs.includes('publish_state')
+ ? this.state.filterArgs.match(/publish_state=([^&]*)/)?.[1]
+ : null,
+ sort_by: this.state.selectedSort,
+ tag: tag,
+ });
+ });
+ }
+
+ onSortSelect(sortOption) {
+ this.setState({ selectedSort: sortOption }, () => {
+ // Apply sort filter
+ this.onFiltersUpdate({
+ media_type: this.state.filterArgs.includes('media_type')
+ ? this.state.filterArgs.match(/media_type=([^&]*)/)?.[1]
+ : null,
+ upload_date: this.state.filterArgs.includes('upload_date')
+ ? this.state.filterArgs.match(/upload_date=([^&]*)/)?.[1]
+ : null,
+ duration: this.state.filterArgs.includes('duration')
+ ? this.state.filterArgs.match(/duration=([^&]*)/)?.[1]
+ : null,
+ publish_state: this.state.filterArgs.includes('publish_state')
+ ? this.state.filterArgs.match(/publish_state=([^&]*)/)?.[1]
+ : null,
+ sort_by: sortOption,
+ tag: this.state.selectedTag,
+ });
+ });
+ }
+
+ onFiltersUpdate(updatedArgs) {
+ const args = {
+ media_type: null,
+ upload_date: null,
+ duration: null,
+ publish_state: null,
+ sort_by: null,
+ ordering: null,
+ t: null,
+ };
+
+ switch (updatedArgs.media_type) {
+ case 'video':
+ case 'audio':
+ case 'image':
+ case 'pdf':
+ args.media_type = updatedArgs.media_type;
+ break;
+ }
+
+ switch (updatedArgs.upload_date) {
+ case 'today':
+ case 'this_week':
+ case 'this_month':
+ case 'this_year':
+ args.upload_date = updatedArgs.upload_date;
+ break;
+ }
+
+ // Handle duration filter
+ if (updatedArgs.duration && updatedArgs.duration !== 'all') {
+ args.duration = updatedArgs.duration;
+ }
+
+ // Handle publish state filter
+ if (updatedArgs.publish_state && updatedArgs.publish_state !== 'all') {
+ args.publish_state = updatedArgs.publish_state;
+ }
+
+ switch (updatedArgs.sort_by) {
+ case 'date_added_desc':
+ // Default sorting, no need to add parameters
+ break;
+ case 'date_added_asc':
+ args.ordering = 'asc';
+ break;
+ case 'alphabetically_asc':
+ args.sort_by = 'title_asc';
+ break;
+ case 'alphabetically_desc':
+ args.sort_by = 'title_desc';
+ break;
+ case 'plays_least':
+ args.sort_by = 'views_asc';
+ break;
+ case 'plays_most':
+ args.sort_by = 'views_desc';
+ break;
+ case 'likes_least':
+ args.sort_by = 'likes_asc';
+ break;
+ case 'likes_most':
+ args.sort_by = 'likes_desc';
+ break;
+ }
+
+ // Handle tag filter
+ if (updatedArgs.tag && updatedArgs.tag !== 'all') {
+ args.t = updatedArgs.tag;
+ }
+
+ const newArgs = [];
+
+ for (let arg in args) {
+ if (null !== args[arg]) {
+ newArgs.push(arg + '=' + args[arg]);
+ }
+ }
+
+ this.setState(
+ {
+ filterArgs: newArgs.length ? '&' + newArgs.join('&') : '',
+ selectedMedia: new Set(), // Clear selected items when filter changes
+ },
+ function () {
+ // Update the request URL with new filter args
+ if (!this.state.author) {
+ return;
+ }
+
+ let requestUrl;
+
+ if (this.state.query) {
+ requestUrl =
+ ApiUrlContext._currentValue.media +
+ '?author=' +
+ this.state.author.id +
+ '&q=' +
+ encodeURIComponent(this.state.query) +
+ this.state.filterArgs;
+ } else {
+ requestUrl =
+ ApiUrlContext._currentValue.media + '?author=' + this.state.author.id + this.state.filterArgs;
+ }
+
+ this.setState({
+ requestUrl: requestUrl,
+ });
+ }
+ );
+ }
+
+ 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) {
+ // Extract tags from response
+ if (responseData && responseData.tags) {
+ const tags = responseData.tags
+ .split(',')
+ .map((tag) => tag.trim())
+ .filter((tag) => tag);
+ this.setState({ availableTags: tags });
+ }
+ }
+
+ pageContent() {
+ const authorData = ProfilePageStore.get('author-data');
+
+ const isMediaAuthor = authorData && authorData.username === MemberContext._currentValue.username;
+
+ // Check if any filters are active (excluding default sort and tags)
+ const hasActiveFilters =
+ this.state.filterArgs &&
+ (this.state.filterArgs.includes('media_type=') ||
+ this.state.filterArgs.includes('upload_date=') ||
+ this.state.filterArgs.includes('duration=') ||
+ this.state.filterArgs.includes('publish_state='));
+
+ const hasActiveTags = this.state.selectedTag && this.state.selectedTag !== 'all';
+ const hasActiveSort = this.state.selectedSort && this.state.selectedSort !== 'date_added_desc';
+
+ return [
+ this.state.author ? (
+
+ ) : null,
+ this.state.author ? (
+
+
+
+
+
+ 0}
+ selectedMedia={this.state.selectedMedia}
+ onMediaSelection={this.handleMediaSelection}
+ onItemsUpdate={this.handleItemsUpdate}
+ onResponseDataLoaded={this.onResponseDataLoaded}
+ />
+
+
+ ) : null,
+
,
+
,
+
,
+
,
+
,
+
,
+
,
+ this.state.showNotification ? (
+
+ {this.state.notificationMessage}
+
+ ) : null,
+ ];
+ }
}
ProfileMediaPage.propTypes = {
- title: PropTypes.string.isRequired,
+ title: PropTypes.string.isRequired,
};
ProfileMediaPage.defaultProps = {
- title: 'Uploads',
+ title: 'Uploads',
};
diff --git a/frontend/src/static/js/pages/ProfileSharedByMePage.js b/frontend/src/static/js/pages/ProfileSharedByMePage.js
index a026e9b3..a0f9a14f 100644
--- a/frontend/src/static/js/pages/ProfileSharedByMePage.js
+++ b/frontend/src/static/js/pages/ProfileSharedByMePage.js
@@ -11,7 +11,7 @@ import { ProfileMediaFilters } from '../components/search-filters/ProfileMediaFi
import { ProfileMediaTags } from '../components/search-filters/ProfileMediaTags';
import { ProfileMediaSorting } from '../components/search-filters/ProfileMediaSorting';
import { BulkActionsModals } from '../components/BulkActionsModals';
-import { translateString } from '../utils/helpers';
+import { inEmbeddedApp, translateString } from '../utils/helpers';
import { withBulkActions } from '../utils/hoc/withBulkActions';
import { Page } from './_Page';
@@ -19,400 +19,443 @@ import { Page } from './_Page';
import '../components/profile-page/ProfilePage.scss';
function EmptySharedByMe(props) {
- return (
-
- {(links) => (
-
-
No shared media
-
- Media that you have shared with others will show up here.
-
-
- )}
-
- );
+ return (
+
+ {(links) => (
+
+
No shared media
+
Media that you have shared with others will show up here.
+
+ )}
+
+ );
}
class ProfileSharedByMePage extends Page {
- constructor(props, pageSlug) {
- super(props, 'string' === typeof pageSlug ? pageSlug : 'author-shared-by-me');
+ constructor(props, pageSlug) {
+ super(props, 'string' === typeof pageSlug ? pageSlug : 'author-shared-by-me');
- this.profilePageSlug = 'string' === typeof pageSlug ? pageSlug : 'author-shared-by-me';
+ this.profilePageSlug = 'string' === typeof pageSlug ? pageSlug : 'author-shared-by-me';
- this.state = {
- channelMediaCount: -1,
- author: ProfilePageStore.get('author-data'),
- uploadsPreviewItemsCount: 0,
- title: this.props.title,
- query: ProfilePageStore.get('author-query'),
- requestUrl: null,
- hiddenFilters: true,
- hiddenTags: true,
- hiddenSorting: true,
- filterArgs: '',
- availableTags: [],
- selectedTag: 'all',
- selectedSort: 'date_added_desc',
- };
+ this.state = {
+ channelMediaCount: -1,
+ author: ProfilePageStore.get('author-data'),
+ uploadsPreviewItemsCount: 0,
+ title: this.props.title,
+ query: ProfilePageStore.get('author-query'),
+ requestUrl: null,
+ hiddenFilters: true,
+ hiddenTags: true,
+ hiddenSorting: true,
+ filterArgs: '',
+ availableTags: [],
+ selectedTag: 'all',
+ selectedSort: 'date_added_desc',
+ };
- this.authorDataLoad = this.authorDataLoad.bind(this);
- this.onAuthorPreviewItemsCountCallback = this.onAuthorPreviewItemsCountCallback.bind(this);
- this.getCountFunc = this.getCountFunc.bind(this);
- this.changeRequestQuery = this.changeRequestQuery.bind(this);
- this.onToggleFiltersClick = this.onToggleFiltersClick.bind(this);
- this.onToggleTagsClick = this.onToggleTagsClick.bind(this);
- this.onToggleSortingClick = this.onToggleSortingClick.bind(this);
- this.onFiltersUpdate = this.onFiltersUpdate.bind(this);
- this.onTagSelect = this.onTagSelect.bind(this);
- this.onSortSelect = this.onSortSelect.bind(this);
- this.onResponseDataLoaded = this.onResponseDataLoaded.bind(this);
+ this.authorDataLoad = this.authorDataLoad.bind(this);
+ this.onAuthorPreviewItemsCountCallback = this.onAuthorPreviewItemsCountCallback.bind(this);
+ this.getCountFunc = this.getCountFunc.bind(this);
+ this.changeRequestQuery = this.changeRequestQuery.bind(this);
+ this.onToggleFiltersClick = this.onToggleFiltersClick.bind(this);
+ this.onToggleTagsClick = this.onToggleTagsClick.bind(this);
+ this.onToggleSortingClick = this.onToggleSortingClick.bind(this);
+ this.onFiltersUpdate = this.onFiltersUpdate.bind(this);
+ this.onTagSelect = this.onTagSelect.bind(this);
+ this.onSortSelect = this.onSortSelect.bind(this);
+ this.onResponseDataLoaded = this.onResponseDataLoaded.bind(this);
- ProfilePageStore.on('load-author-data', this.authorDataLoad);
- }
-
- componentDidMount() {
- ProfilePageActions.load_author_data();
- }
-
- authorDataLoad() {
- const author = ProfilePageStore.get('author-data');
-
- let requestUrl = this.state.requestUrl;
-
- if (author) {
- if (this.state.query) {
- requestUrl = ApiUrlContext._currentValue.media + '?author=' + author.id + '&show=shared_by_me&q=' + encodeURIComponent(this.state.query) + this.state.filterArgs;
- } else {
- requestUrl = ApiUrlContext._currentValue.media + '?author=' + author.id + '&show=shared_by_me' + this.state.filterArgs;
- }
+ ProfilePageStore.on('load-author-data', this.authorDataLoad);
}
- this.setState({
- author: author,
- requestUrl: requestUrl,
- });
- }
+ componentDidMount() {
+ ProfilePageActions.load_author_data();
+ }
- onAuthorPreviewItemsCountCallback(totalAuthorPreviewItems) {
- this.setState({
- uploadsPreviewItemsCount: totalAuthorPreviewItems,
- });
- }
+ authorDataLoad() {
+ const author = ProfilePageStore.get('author-data');
- getCountFunc(count) {
- this.setState(
- {
- channelMediaCount: count,
- },
- () => {
- if (this.state.query) {
- let title = '';
+ let requestUrl = this.state.requestUrl;
- if (!count) {
- title = 'No results for "' + this.state.query + '"';
- } else if (1 === count) {
- title = '1 result for "' + this.state.query + '"';
- } else {
- title = count + ' results for "' + this.state.query + '"';
- }
-
- this.setState({
- title: title,
- });
+ if (author) {
+ if (this.state.query) {
+ requestUrl =
+ ApiUrlContext._currentValue.media +
+ '?author=' +
+ author.id +
+ '&show=shared_by_me&q=' +
+ encodeURIComponent(this.state.query) +
+ this.state.filterArgs;
+ } else {
+ requestUrl =
+ ApiUrlContext._currentValue.media +
+ '?author=' +
+ author.id +
+ '&show=shared_by_me' +
+ this.state.filterArgs;
+ }
}
- }
- );
- }
- changeRequestQuery(newQuery) {
- if (!this.state.author) {
- return;
+ this.setState({
+ author: author,
+ requestUrl: requestUrl,
+ });
}
- let requestUrl;
-
- if (newQuery) {
- requestUrl = ApiUrlContext._currentValue.media + '?author=' + this.state.author.id + '&show=shared_by_me&q=' + encodeURIComponent(newQuery) + this.state.filterArgs;
- } else {
- requestUrl = ApiUrlContext._currentValue.media + '?author=' + this.state.author.id + '&show=shared_by_me' + this.state.filterArgs;
+ onAuthorPreviewItemsCountCallback(totalAuthorPreviewItems) {
+ this.setState({
+ uploadsPreviewItemsCount: totalAuthorPreviewItems,
+ });
}
- let title = this.state.title;
+ getCountFunc(count) {
+ this.setState(
+ {
+ channelMediaCount: count,
+ },
+ () => {
+ if (this.state.query) {
+ let title = '';
- if ('' === newQuery) {
- title = this.props.title;
+ if (!count) {
+ title = 'No results for "' + this.state.query + '"';
+ } else if (1 === count) {
+ title = '1 result for "' + this.state.query + '"';
+ } else {
+ title = count + ' results for "' + this.state.query + '"';
+ }
+
+ this.setState({
+ title: title,
+ });
+ }
+ }
+ );
}
- this.setState({
- requestUrl: requestUrl,
- query: newQuery,
- title: title,
- });
- }
-
- onToggleFiltersClick() {
- this.setState({
- hiddenFilters: !this.state.hiddenFilters,
- hiddenTags: true,
- hiddenSorting: true,
- });
- }
-
- onToggleTagsClick() {
- this.setState({
- hiddenFilters: true,
- hiddenTags: !this.state.hiddenTags,
- hiddenSorting: true,
- });
- }
-
- onToggleSortingClick() {
- this.setState({
- hiddenFilters: true,
- hiddenTags: true,
- hiddenSorting: !this.state.hiddenSorting,
- });
- }
-
- onTagSelect(tag) {
- this.setState({ selectedTag: tag }, () => {
- this.onFiltersUpdate({
- media_type: this.state.filterArgs.match(/media_type=([^&]+)/)?.[1],
- upload_date: this.state.filterArgs.match(/upload_date=([^&]+)/)?.[1],
- duration: this.state.filterArgs.match(/duration=([^&]+)/)?.[1],
- publish_state: this.state.filterArgs.match(/publish_state=([^&]+)/)?.[1],
- sort_by: this.state.selectedSort,
- tag: tag,
- });
- });
- }
-
- onSortSelect(sortBy) {
- this.setState({ selectedSort: sortBy }, () => {
- this.onFiltersUpdate({
- media_type: this.state.filterArgs.match(/media_type=([^&]+)/)?.[1],
- upload_date: this.state.filterArgs.match(/upload_date=([^&]+)/)?.[1],
- duration: this.state.filterArgs.match(/duration=([^&]+)/)?.[1],
- publish_state: this.state.filterArgs.match(/publish_state=([^&]+)/)?.[1],
- sort_by: sortBy,
- tag: this.state.selectedTag,
- });
- });
- }
-
- onFiltersUpdate(updatedArgs) {
- const args = {
- media_type: null,
- upload_date: null,
- duration: null,
- publish_state: null,
- sort_by: null,
- ordering: null,
- t: null,
- };
-
- switch (updatedArgs.media_type) {
- case 'video':
- case 'audio':
- case 'image':
- case 'pdf':
- args.media_type = updatedArgs.media_type;
- break;
- }
-
- switch (updatedArgs.upload_date) {
- case 'today':
- case 'this_week':
- case 'this_month':
- case 'this_year':
- args.upload_date = updatedArgs.upload_date;
- break;
- }
-
- // Handle duration filter
- if (updatedArgs.duration && updatedArgs.duration !== 'all') {
- args.duration = updatedArgs.duration;
- }
-
- // Handle publish state filter
- if (updatedArgs.publish_state && updatedArgs.publish_state !== 'all') {
- args.publish_state = updatedArgs.publish_state;
- }
-
- switch (updatedArgs.sort_by) {
- case 'date_added_desc':
- // Default sorting, no need to add parameters
- break;
- case 'date_added_asc':
- args.ordering = 'asc';
- break;
- case 'alphabetically_asc':
- args.sort_by = 'title_asc';
- break;
- case 'alphabetically_desc':
- args.sort_by = 'title_desc';
- break;
- case 'plays_least':
- args.sort_by = 'views_asc';
- break;
- case 'plays_most':
- args.sort_by = 'views_desc';
- break;
- case 'likes_least':
- args.sort_by = 'likes_asc';
- break;
- case 'likes_most':
- args.sort_by = 'likes_desc';
- break;
- }
-
- if (updatedArgs.tag && updatedArgs.tag !== 'all') {
- args.t = updatedArgs.tag;
- }
-
- const newArgs = [];
-
- for (let arg in args) {
- if (null !== args[arg]) {
- newArgs.push(arg + '=' + args[arg]);
- }
- }
-
- this.setState(
- {
- filterArgs: newArgs.length ? '&' + newArgs.join('&') : '',
- },
- function () {
+ changeRequestQuery(newQuery) {
if (!this.state.author) {
- return;
+ return;
}
let requestUrl;
- if (this.state.query) {
- requestUrl = ApiUrlContext._currentValue.media + '?author=' + this.state.author.id + '&show=shared_by_me&q=' + encodeURIComponent(this.state.query) + this.state.filterArgs;
+ if (newQuery) {
+ requestUrl =
+ ApiUrlContext._currentValue.media +
+ '?author=' +
+ this.state.author.id +
+ '&show=shared_by_me&q=' +
+ encodeURIComponent(newQuery) +
+ this.state.filterArgs;
} else {
- requestUrl = ApiUrlContext._currentValue.media + '?author=' + this.state.author.id + '&show=shared_by_me' + this.state.filterArgs;
+ requestUrl =
+ ApiUrlContext._currentValue.media +
+ '?author=' +
+ this.state.author.id +
+ '&show=shared_by_me' +
+ this.state.filterArgs;
+ }
+
+ let title = this.state.title;
+
+ if ('' === newQuery) {
+ title = this.props.title;
}
this.setState({
- requestUrl: requestUrl,
+ requestUrl: requestUrl,
+ query: newQuery,
+ title: title,
});
- }
- );
- }
-
- onResponseDataLoaded(responseData) {
- if (responseData && responseData.tags) {
- const tags = responseData.tags.split(',').map((tag) => tag.trim()).filter((tag) => tag);
- this.setState({ availableTags: tags });
}
- }
- pageContent() {
- const authorData = ProfilePageStore.get('author-data');
+ onToggleFiltersClick() {
+ this.setState({
+ hiddenFilters: !this.state.hiddenFilters,
+ hiddenTags: true,
+ hiddenSorting: true,
+ });
+ }
- const isMediaAuthor = authorData && authorData.username === MemberContext._currentValue.username;
+ onToggleTagsClick() {
+ this.setState({
+ hiddenFilters: true,
+ hiddenTags: !this.state.hiddenTags,
+ hiddenSorting: true,
+ });
+ }
- // Check if any filters are active
- const hasActiveFilters = this.state.filterArgs && (
- this.state.filterArgs.includes('media_type=') ||
- this.state.filterArgs.includes('upload_date=') ||
- this.state.filterArgs.includes('duration=') ||
- this.state.filterArgs.includes('publish_state=')
- );
+ onToggleSortingClick() {
+ this.setState({
+ hiddenFilters: true,
+ hiddenTags: true,
+ hiddenSorting: !this.state.hiddenSorting,
+ });
+ }
- return [
- this.state.author ? (
-
- ) : null,
- this.state.author ? (
-
-
-
-
-
- 0}
- selectedMedia={this.props.bulkActions.selectedMedia}
- onMediaSelection={this.props.bulkActions.handleMediaSelection}
- onItemsUpdate={this.props.bulkActions.handleItemsUpdate}
- />
- {isMediaAuthor && 0 === this.state.channelMediaCount && !this.state.query ? (
-
- ) : null}
-
-
- ) : null,
- this.state.author && isMediaAuthor ? (
-
- ) : null,
- ];
- }
+ onTagSelect(tag) {
+ this.setState({ selectedTag: tag }, () => {
+ this.onFiltersUpdate({
+ media_type: this.state.filterArgs.match(/media_type=([^&]+)/)?.[1],
+ upload_date: this.state.filterArgs.match(/upload_date=([^&]+)/)?.[1],
+ duration: this.state.filterArgs.match(/duration=([^&]+)/)?.[1],
+ publish_state: this.state.filterArgs.match(/publish_state=([^&]+)/)?.[1],
+ sort_by: this.state.selectedSort,
+ tag: tag,
+ });
+ });
+ }
+
+ onSortSelect(sortBy) {
+ this.setState({ selectedSort: sortBy }, () => {
+ this.onFiltersUpdate({
+ media_type: this.state.filterArgs.match(/media_type=([^&]+)/)?.[1],
+ upload_date: this.state.filterArgs.match(/upload_date=([^&]+)/)?.[1],
+ duration: this.state.filterArgs.match(/duration=([^&]+)/)?.[1],
+ publish_state: this.state.filterArgs.match(/publish_state=([^&]+)/)?.[1],
+ sort_by: sortBy,
+ tag: this.state.selectedTag,
+ });
+ });
+ }
+
+ onFiltersUpdate(updatedArgs) {
+ const args = {
+ media_type: null,
+ upload_date: null,
+ duration: null,
+ publish_state: null,
+ sort_by: null,
+ ordering: null,
+ t: null,
+ };
+
+ switch (updatedArgs.media_type) {
+ case 'video':
+ case 'audio':
+ case 'image':
+ case 'pdf':
+ args.media_type = updatedArgs.media_type;
+ break;
+ }
+
+ switch (updatedArgs.upload_date) {
+ case 'today':
+ case 'this_week':
+ case 'this_month':
+ case 'this_year':
+ args.upload_date = updatedArgs.upload_date;
+ break;
+ }
+
+ // Handle duration filter
+ if (updatedArgs.duration && updatedArgs.duration !== 'all') {
+ args.duration = updatedArgs.duration;
+ }
+
+ // Handle publish state filter
+ if (updatedArgs.publish_state && updatedArgs.publish_state !== 'all') {
+ args.publish_state = updatedArgs.publish_state;
+ }
+
+ switch (updatedArgs.sort_by) {
+ case 'date_added_desc':
+ // Default sorting, no need to add parameters
+ break;
+ case 'date_added_asc':
+ args.ordering = 'asc';
+ break;
+ case 'alphabetically_asc':
+ args.sort_by = 'title_asc';
+ break;
+ case 'alphabetically_desc':
+ args.sort_by = 'title_desc';
+ break;
+ case 'plays_least':
+ args.sort_by = 'views_asc';
+ break;
+ case 'plays_most':
+ args.sort_by = 'views_desc';
+ break;
+ case 'likes_least':
+ args.sort_by = 'likes_asc';
+ break;
+ case 'likes_most':
+ args.sort_by = 'likes_desc';
+ break;
+ }
+
+ if (updatedArgs.tag && updatedArgs.tag !== 'all') {
+ args.t = updatedArgs.tag;
+ }
+
+ const newArgs = [];
+
+ for (let arg in args) {
+ if (null !== args[arg]) {
+ newArgs.push(arg + '=' + args[arg]);
+ }
+ }
+
+ this.setState(
+ {
+ filterArgs: newArgs.length ? '&' + newArgs.join('&') : '',
+ },
+ function () {
+ if (!this.state.author) {
+ return;
+ }
+
+ let requestUrl;
+
+ if (this.state.query) {
+ requestUrl =
+ ApiUrlContext._currentValue.media +
+ '?author=' +
+ this.state.author.id +
+ '&show=shared_by_me&q=' +
+ encodeURIComponent(this.state.query) +
+ this.state.filterArgs;
+ } else {
+ requestUrl =
+ ApiUrlContext._currentValue.media +
+ '?author=' +
+ this.state.author.id +
+ '&show=shared_by_me' +
+ this.state.filterArgs;
+ }
+
+ this.setState({
+ requestUrl: requestUrl,
+ });
+ }
+ );
+ }
+
+ onResponseDataLoaded(responseData) {
+ if (responseData && responseData.tags) {
+ const tags = responseData.tags
+ .split(',')
+ .map((tag) => tag.trim())
+ .filter((tag) => tag);
+ this.setState({ availableTags: tags });
+ }
+ }
+
+ pageContent() {
+ const authorData = ProfilePageStore.get('author-data');
+
+ const isMediaAuthor = authorData && authorData.username === MemberContext._currentValue.username;
+
+ // Check if any filters are active
+ const hasActiveFilters =
+ this.state.filterArgs &&
+ (this.state.filterArgs.includes('media_type=') ||
+ this.state.filterArgs.includes('upload_date=') ||
+ this.state.filterArgs.includes('duration=') ||
+ this.state.filterArgs.includes('publish_state='));
+
+ return [
+ this.state.author ? (
+
+ ) : null,
+ this.state.author ? (
+
+
+
+
+
+ 0}
+ selectedMedia={this.props.bulkActions.selectedMedia}
+ onMediaSelection={this.props.bulkActions.handleMediaSelection}
+ onItemsUpdate={this.props.bulkActions.handleItemsUpdate}
+ />
+ {isMediaAuthor && 0 === this.state.channelMediaCount && !this.state.query ? (
+
+ ) : null}
+
+
+ ) : null,
+ this.state.author && isMediaAuthor ? (
+
+ ) : null,
+ ];
+ }
}
ProfileSharedByMePage.propTypes = {
- title: PropTypes.string.isRequired,
- bulkActions: PropTypes.object.isRequired,
+ title: PropTypes.string.isRequired,
+ bulkActions: PropTypes.object.isRequired,
};
ProfileSharedByMePage.defaultProps = {
- title: 'Shared by me',
+ title: 'Shared by me',
};
// Wrap with HOC and export as named export for compatibility
diff --git a/frontend/src/static/js/pages/ProfileSharedWithMePage.js b/frontend/src/static/js/pages/ProfileSharedWithMePage.js
index 9376f262..08c1f0e8 100644
--- a/frontend/src/static/js/pages/ProfileSharedWithMePage.js
+++ b/frontend/src/static/js/pages/ProfileSharedWithMePage.js
@@ -10,364 +10,404 @@ import { LazyLoadItemListAsync } from '../components/item-list/LazyLoadItemListA
import { ProfileMediaFilters } from '../components/search-filters/ProfileMediaFilters';
import { ProfileMediaTags } from '../components/search-filters/ProfileMediaTags';
import { ProfileMediaSorting } from '../components/search-filters/ProfileMediaSorting';
-import { translateString } from '../utils/helpers';
+import { inEmbeddedApp, translateString } from '../utils/helpers';
import { Page } from './_Page';
import '../components/profile-page/ProfilePage.scss';
function EmptySharedWithMe(props) {
- return (
-
- {(links) => (
-
-
No shared media
-
- Media that others have shared with you will show up here.
-
-
- )}
-
- );
+ return (
+
+ {(links) => (
+
+
No shared media
+
Media that others have shared with you will show up here.
+
+ )}
+
+ );
}
export class ProfileSharedWithMePage extends Page {
- constructor(props, pageSlug) {
- super(props, 'string' === typeof pageSlug ? pageSlug : 'author-shared-with-me');
+ constructor(props, pageSlug) {
+ super(props, 'string' === typeof pageSlug ? pageSlug : 'author-shared-with-me');
- this.profilePageSlug = 'string' === typeof pageSlug ? pageSlug : 'author-shared-with-me';
+ this.profilePageSlug = 'string' === typeof pageSlug ? pageSlug : 'author-shared-with-me';
- this.state = {
- channelMediaCount: -1,
- author: ProfilePageStore.get('author-data'),
- uploadsPreviewItemsCount: 0,
- title: this.props.title,
- query: ProfilePageStore.get('author-query'),
- requestUrl: null,
- hiddenFilters: true,
- hiddenTags: true,
- hiddenSorting: true,
- filterArgs: '',
- availableTags: [],
- selectedTag: 'all',
- selectedSort: 'date_added_desc',
- };
+ this.state = {
+ channelMediaCount: -1,
+ author: ProfilePageStore.get('author-data'),
+ uploadsPreviewItemsCount: 0,
+ title: this.props.title,
+ query: ProfilePageStore.get('author-query'),
+ requestUrl: null,
+ hiddenFilters: true,
+ hiddenTags: true,
+ hiddenSorting: true,
+ filterArgs: '',
+ availableTags: [],
+ selectedTag: 'all',
+ selectedSort: 'date_added_desc',
+ };
- this.authorDataLoad = this.authorDataLoad.bind(this);
- this.onAuthorPreviewItemsCountCallback = this.onAuthorPreviewItemsCountCallback.bind(this);
- this.getCountFunc = this.getCountFunc.bind(this);
- this.changeRequestQuery = this.changeRequestQuery.bind(this);
- this.onToggleFiltersClick = this.onToggleFiltersClick.bind(this);
- this.onToggleTagsClick = this.onToggleTagsClick.bind(this);
- this.onToggleSortingClick = this.onToggleSortingClick.bind(this);
- this.onFiltersUpdate = this.onFiltersUpdate.bind(this);
- this.onTagSelect = this.onTagSelect.bind(this);
- this.onSortSelect = this.onSortSelect.bind(this);
- this.onResponseDataLoaded = this.onResponseDataLoaded.bind(this);
+ this.authorDataLoad = this.authorDataLoad.bind(this);
+ this.onAuthorPreviewItemsCountCallback = this.onAuthorPreviewItemsCountCallback.bind(this);
+ this.getCountFunc = this.getCountFunc.bind(this);
+ this.changeRequestQuery = this.changeRequestQuery.bind(this);
+ this.onToggleFiltersClick = this.onToggleFiltersClick.bind(this);
+ this.onToggleTagsClick = this.onToggleTagsClick.bind(this);
+ this.onToggleSortingClick = this.onToggleSortingClick.bind(this);
+ this.onFiltersUpdate = this.onFiltersUpdate.bind(this);
+ this.onTagSelect = this.onTagSelect.bind(this);
+ this.onSortSelect = this.onSortSelect.bind(this);
+ this.onResponseDataLoaded = this.onResponseDataLoaded.bind(this);
- ProfilePageStore.on('load-author-data', this.authorDataLoad);
- }
-
- componentDidMount() {
- ProfilePageActions.load_author_data();
- }
-
- authorDataLoad() {
- const author = ProfilePageStore.get('author-data');
-
- let requestUrl = this.state.requestUrl;
-
- if (author) {
- if (this.state.query) {
- requestUrl = ApiUrlContext._currentValue.media + '?author=' + author.id + '&show=shared_with_me&q=' + encodeURIComponent(this.state.query) + this.state.filterArgs;
- } else {
- requestUrl = ApiUrlContext._currentValue.media + '?author=' + author.id + '&show=shared_with_me' + this.state.filterArgs;
- }
+ ProfilePageStore.on('load-author-data', this.authorDataLoad);
}
- this.setState({
- author: author,
- requestUrl: requestUrl,
- });
- }
+ componentDidMount() {
+ ProfilePageActions.load_author_data();
+ }
- onAuthorPreviewItemsCountCallback(totalAuthorPreviewItems) {
- this.setState({
- uploadsPreviewItemsCount: totalAuthorPreviewItems,
- });
- }
+ authorDataLoad() {
+ const author = ProfilePageStore.get('author-data');
- getCountFunc(count) {
- this.setState(
- {
- channelMediaCount: count,
- },
- () => {
- if (this.state.query) {
- let title = '';
+ let requestUrl = this.state.requestUrl;
- if (!count) {
- title = 'No results for "' + this.state.query + '"';
- } else if (1 === count) {
- title = '1 result for "' + this.state.query + '"';
- } else {
- title = count + ' results for "' + this.state.query + '"';
- }
-
- this.setState({
- title: title,
- });
+ if (author) {
+ if (this.state.query) {
+ requestUrl =
+ ApiUrlContext._currentValue.media +
+ '?author=' +
+ author.id +
+ '&show=shared_with_me&q=' +
+ encodeURIComponent(this.state.query) +
+ this.state.filterArgs;
+ } else {
+ requestUrl =
+ ApiUrlContext._currentValue.media +
+ '?author=' +
+ author.id +
+ '&show=shared_with_me' +
+ this.state.filterArgs;
+ }
}
- }
- );
- }
- changeRequestQuery(newQuery) {
- if (!this.state.author) {
- return;
+ this.setState({
+ author: author,
+ requestUrl: requestUrl,
+ });
}
- let requestUrl;
-
- if (newQuery) {
- requestUrl = ApiUrlContext._currentValue.media + '?author=' + this.state.author.id + '&show=shared_with_me&q=' + encodeURIComponent(newQuery) + this.state.filterArgs;
- } else {
- requestUrl = ApiUrlContext._currentValue.media + '?author=' + this.state.author.id + '&show=shared_with_me' + this.state.filterArgs;
+ onAuthorPreviewItemsCountCallback(totalAuthorPreviewItems) {
+ this.setState({
+ uploadsPreviewItemsCount: totalAuthorPreviewItems,
+ });
}
- let title = this.state.title;
+ getCountFunc(count) {
+ this.setState(
+ {
+ channelMediaCount: count,
+ },
+ () => {
+ if (this.state.query) {
+ let title = '';
- if ('' === newQuery) {
- title = this.props.title;
+ if (!count) {
+ title = 'No results for "' + this.state.query + '"';
+ } else if (1 === count) {
+ title = '1 result for "' + this.state.query + '"';
+ } else {
+ title = count + ' results for "' + this.state.query + '"';
+ }
+
+ this.setState({
+ title: title,
+ });
+ }
+ }
+ );
}
- this.setState({
- requestUrl: requestUrl,
- query: newQuery,
- title: title,
- });
- }
-
- onToggleFiltersClick() {
- this.setState({
- hiddenFilters: !this.state.hiddenFilters,
- hiddenTags: true,
- hiddenSorting: true,
- });
- }
-
- onToggleTagsClick() {
- this.setState({
- hiddenFilters: true,
- hiddenTags: !this.state.hiddenTags,
- hiddenSorting: true,
- });
- }
-
- onToggleSortingClick() {
- this.setState({
- hiddenFilters: true,
- hiddenTags: true,
- hiddenSorting: !this.state.hiddenSorting,
- });
- }
-
- onTagSelect(tag) {
- this.setState({ selectedTag: tag }, () => {
- this.onFiltersUpdate({
- media_type: this.state.filterArgs.match(/media_type=([^&]+)/)?.[1],
- upload_date: this.state.filterArgs.match(/upload_date=([^&]+)/)?.[1],
- duration: this.state.filterArgs.match(/duration=([^&]+)/)?.[1],
- publish_state: this.state.filterArgs.match(/publish_state=([^&]+)/)?.[1],
- sort_by: this.state.selectedSort,
- tag: tag,
- });
- });
- }
-
- onSortSelect(sortBy) {
- this.setState({ selectedSort: sortBy }, () => {
- this.onFiltersUpdate({
- media_type: this.state.filterArgs.match(/media_type=([^&]+)/)?.[1],
- upload_date: this.state.filterArgs.match(/upload_date=([^&]+)/)?.[1],
- duration: this.state.filterArgs.match(/duration=([^&]+)/)?.[1],
- publish_state: this.state.filterArgs.match(/publish_state=([^&]+)/)?.[1],
- sort_by: sortBy,
- tag: this.state.selectedTag,
- });
- });
- }
-
- onFiltersUpdate(updatedArgs) {
- const args = {
- media_type: null,
- upload_date: null,
- duration: null,
- publish_state: null,
- sort_by: null,
- ordering: null,
- t: null,
- };
-
- switch (updatedArgs.media_type) {
- case 'video':
- case 'audio':
- case 'image':
- case 'pdf':
- args.media_type = updatedArgs.media_type;
- break;
- }
-
- switch (updatedArgs.upload_date) {
- case 'today':
- case 'this_week':
- case 'this_month':
- case 'this_year':
- args.upload_date = updatedArgs.upload_date;
- break;
- }
-
- // Handle duration filter
- if (updatedArgs.duration && updatedArgs.duration !== 'all') {
- args.duration = updatedArgs.duration;
- }
-
- // Handle publish state filter
- if (updatedArgs.publish_state && updatedArgs.publish_state !== 'all') {
- args.publish_state = updatedArgs.publish_state;
- }
-
- switch (updatedArgs.sort_by) {
- case 'date_added_desc':
- // Default sorting, no need to add parameters
- break;
- case 'date_added_asc':
- args.ordering = 'asc';
- break;
- case 'alphabetically_asc':
- args.sort_by = 'title_asc';
- break;
- case 'alphabetically_desc':
- args.sort_by = 'title_desc';
- break;
- case 'plays_least':
- args.sort_by = 'views_asc';
- break;
- case 'plays_most':
- args.sort_by = 'views_desc';
- break;
- case 'likes_least':
- args.sort_by = 'likes_asc';
- break;
- case 'likes_most':
- args.sort_by = 'likes_desc';
- break;
- }
-
- if (updatedArgs.tag && updatedArgs.tag !== 'all') {
- args.t = updatedArgs.tag;
- }
-
- const newArgs = [];
-
- for (let arg in args) {
- if (null !== args[arg]) {
- newArgs.push(arg + '=' + args[arg]);
- }
- }
-
- this.setState(
- {
- filterArgs: newArgs.length ? '&' + newArgs.join('&') : '',
- },
- function () {
+ changeRequestQuery(newQuery) {
if (!this.state.author) {
- return;
+ return;
}
let requestUrl;
- if (this.state.query) {
- requestUrl = ApiUrlContext._currentValue.media + '?author=' + this.state.author.id + '&show=shared_with_me&q=' + encodeURIComponent(this.state.query) + this.state.filterArgs;
+ if (newQuery) {
+ requestUrl =
+ ApiUrlContext._currentValue.media +
+ '?author=' +
+ this.state.author.id +
+ '&show=shared_with_me&q=' +
+ encodeURIComponent(newQuery) +
+ this.state.filterArgs;
} else {
- requestUrl = ApiUrlContext._currentValue.media + '?author=' + this.state.author.id + '&show=shared_with_me' + this.state.filterArgs;
+ requestUrl =
+ ApiUrlContext._currentValue.media +
+ '?author=' +
+ this.state.author.id +
+ '&show=shared_with_me' +
+ this.state.filterArgs;
+ }
+
+ let title = this.state.title;
+
+ if ('' === newQuery) {
+ title = this.props.title;
}
this.setState({
- requestUrl: requestUrl,
+ requestUrl: requestUrl,
+ query: newQuery,
+ title: title,
});
- }
- );
- }
-
- onResponseDataLoaded(responseData) {
- if (responseData && responseData.tags) {
- const tags = responseData.tags.split(',').map((tag) => tag.trim()).filter((tag) => tag);
- this.setState({ availableTags: tags });
}
- }
- pageContent() {
- const authorData = ProfilePageStore.get('author-data');
+ onToggleFiltersClick() {
+ this.setState({
+ hiddenFilters: !this.state.hiddenFilters,
+ hiddenTags: true,
+ hiddenSorting: true,
+ });
+ }
- const isMediaAuthor = authorData && authorData.username === MemberContext._currentValue.username;
+ onToggleTagsClick() {
+ this.setState({
+ hiddenFilters: true,
+ hiddenTags: !this.state.hiddenTags,
+ hiddenSorting: true,
+ });
+ }
- // Check if any filters are active
- const hasActiveFilters = this.state.filterArgs && (
- this.state.filterArgs.includes('media_type=') ||
- this.state.filterArgs.includes('upload_date=') ||
- this.state.filterArgs.includes('duration=') ||
- this.state.filterArgs.includes('publish_state=')
- );
+ onToggleSortingClick() {
+ this.setState({
+ hiddenFilters: true,
+ hiddenTags: true,
+ hiddenSorting: !this.state.hiddenSorting,
+ });
+ }
- return [
- this.state.author ? (
-
- ) : null,
- this.state.author ? (
-
-
-
-
-
-
- {isMediaAuthor && 0 === this.state.channelMediaCount && !this.state.query ? (
-
- ) : null}
-
-
- ) : null,
- ];
- }
+ onTagSelect(tag) {
+ this.setState({ selectedTag: tag }, () => {
+ this.onFiltersUpdate({
+ media_type: this.state.filterArgs.match(/media_type=([^&]+)/)?.[1],
+ upload_date: this.state.filterArgs.match(/upload_date=([^&]+)/)?.[1],
+ duration: this.state.filterArgs.match(/duration=([^&]+)/)?.[1],
+ publish_state: this.state.filterArgs.match(/publish_state=([^&]+)/)?.[1],
+ sort_by: this.state.selectedSort,
+ tag: tag,
+ });
+ });
+ }
+
+ onSortSelect(sortBy) {
+ this.setState({ selectedSort: sortBy }, () => {
+ this.onFiltersUpdate({
+ media_type: this.state.filterArgs.match(/media_type=([^&]+)/)?.[1],
+ upload_date: this.state.filterArgs.match(/upload_date=([^&]+)/)?.[1],
+ duration: this.state.filterArgs.match(/duration=([^&]+)/)?.[1],
+ publish_state: this.state.filterArgs.match(/publish_state=([^&]+)/)?.[1],
+ sort_by: sortBy,
+ tag: this.state.selectedTag,
+ });
+ });
+ }
+
+ onFiltersUpdate(updatedArgs) {
+ const args = {
+ media_type: null,
+ upload_date: null,
+ duration: null,
+ publish_state: null,
+ sort_by: null,
+ ordering: null,
+ t: null,
+ };
+
+ switch (updatedArgs.media_type) {
+ case 'video':
+ case 'audio':
+ case 'image':
+ case 'pdf':
+ args.media_type = updatedArgs.media_type;
+ break;
+ }
+
+ switch (updatedArgs.upload_date) {
+ case 'today':
+ case 'this_week':
+ case 'this_month':
+ case 'this_year':
+ args.upload_date = updatedArgs.upload_date;
+ break;
+ }
+
+ // Handle duration filter
+ if (updatedArgs.duration && updatedArgs.duration !== 'all') {
+ args.duration = updatedArgs.duration;
+ }
+
+ // Handle publish state filter
+ if (updatedArgs.publish_state && updatedArgs.publish_state !== 'all') {
+ args.publish_state = updatedArgs.publish_state;
+ }
+
+ switch (updatedArgs.sort_by) {
+ case 'date_added_desc':
+ // Default sorting, no need to add parameters
+ break;
+ case 'date_added_asc':
+ args.ordering = 'asc';
+ break;
+ case 'alphabetically_asc':
+ args.sort_by = 'title_asc';
+ break;
+ case 'alphabetically_desc':
+ args.sort_by = 'title_desc';
+ break;
+ case 'plays_least':
+ args.sort_by = 'views_asc';
+ break;
+ case 'plays_most':
+ args.sort_by = 'views_desc';
+ break;
+ case 'likes_least':
+ args.sort_by = 'likes_asc';
+ break;
+ case 'likes_most':
+ args.sort_by = 'likes_desc';
+ break;
+ }
+
+ if (updatedArgs.tag && updatedArgs.tag !== 'all') {
+ args.t = updatedArgs.tag;
+ }
+
+ const newArgs = [];
+
+ for (let arg in args) {
+ if (null !== args[arg]) {
+ newArgs.push(arg + '=' + args[arg]);
+ }
+ }
+
+ this.setState(
+ {
+ filterArgs: newArgs.length ? '&' + newArgs.join('&') : '',
+ },
+ function () {
+ if (!this.state.author) {
+ return;
+ }
+
+ let requestUrl;
+
+ if (this.state.query) {
+ requestUrl =
+ ApiUrlContext._currentValue.media +
+ '?author=' +
+ this.state.author.id +
+ '&show=shared_with_me&q=' +
+ encodeURIComponent(this.state.query) +
+ this.state.filterArgs;
+ } else {
+ requestUrl =
+ ApiUrlContext._currentValue.media +
+ '?author=' +
+ this.state.author.id +
+ '&show=shared_with_me' +
+ this.state.filterArgs;
+ }
+
+ this.setState({
+ requestUrl: requestUrl,
+ });
+ }
+ );
+ }
+
+ onResponseDataLoaded(responseData) {
+ if (responseData && responseData.tags) {
+ const tags = responseData.tags
+ .split(',')
+ .map((tag) => tag.trim())
+ .filter((tag) => tag);
+ this.setState({ availableTags: tags });
+ }
+ }
+
+ pageContent() {
+ const authorData = ProfilePageStore.get('author-data');
+
+ const isMediaAuthor = authorData && authorData.username === MemberContext._currentValue.username;
+
+ // Check if any filters are active
+ const hasActiveFilters =
+ this.state.filterArgs &&
+ (this.state.filterArgs.includes('media_type=') ||
+ this.state.filterArgs.includes('upload_date=') ||
+ this.state.filterArgs.includes('duration=') ||
+ this.state.filterArgs.includes('publish_state='));
+
+ return [
+ this.state.author ? (
+
+ ) : null,
+ this.state.author ? (
+
+
+
+
+
+
+ {isMediaAuthor && 0 === this.state.channelMediaCount && !this.state.query ? (
+
+ ) : null}
+
+
+ ) : null,
+ ];
+ }
}
ProfileSharedWithMePage.propTypes = {
- title: PropTypes.string.isRequired,
+ title: PropTypes.string.isRequired,
};
ProfileSharedWithMePage.defaultProps = {
- title: 'Shared with me',
+ title: 'Shared with me',
};
diff --git a/frontend/src/static/js/pages/_MediaPage.js b/frontend/src/static/js/pages/_MediaPage.js
index c5e4a4ed..0ed50174 100755
--- a/frontend/src/static/js/pages/_MediaPage.js
+++ b/frontend/src/static/js/pages/_MediaPage.js
@@ -1,6 +1,7 @@
import React from 'react';
import { PageStore, MediaPageStore } from '../utils/stores/';
import { MediaPageActions } from '../utils/actions/';
+import { inEmbeddedApp } from '../utils/helpers/';
import ViewerError from '../components/media-page/ViewerError';
import ViewerInfo from '../components/media-page/ViewerInfo';
import ViewerSidebar from '../components/media-page/ViewerSidebar';
@@ -10,102 +11,102 @@ import '../components/media-page/MediaPage.scss';
const wideLayoutBreakpoint = 1216;
export class _MediaPage extends Page {
- constructor(props) {
- super(props, 'media');
+ constructor(props) {
+ super(props, 'media');
- const isWideLayout = wideLayoutBreakpoint <= window.innerWidth;
+ const isWideLayout = wideLayoutBreakpoint <= window.innerWidth;
- this.state = {
- mediaLoaded: false,
- mediaLoadFailed: false,
- wideLayout: isWideLayout,
- infoAndSidebarViewType: !isWideLayout ? 0 : 1,
- viewerClassname: 'cf viewer-section viewer-wide',
- viewerNestedClassname: 'viewer-section-nested',
- pagePlaylistLoaded: false,
- };
+ this.state = {
+ mediaLoaded: false,
+ mediaLoadFailed: false,
+ wideLayout: isWideLayout,
+ infoAndSidebarViewType: !isWideLayout ? 0 : 1,
+ viewerClassname: 'cf viewer-section viewer-wide',
+ viewerNestedClassname: 'viewer-section-nested',
+ pagePlaylistLoaded: false,
+ };
- this.onWindowResize = this.onWindowResize.bind(this);
- this.onMediaLoad = this.onMediaLoad.bind(this);
- this.onMediaLoadError = this.onMediaLoadError.bind(this);
- this.onPagePlaylistLoad = this.onPagePlaylistLoad.bind(this);
+ this.onWindowResize = this.onWindowResize.bind(this);
+ this.onMediaLoad = this.onMediaLoad.bind(this);
+ this.onMediaLoadError = this.onMediaLoadError.bind(this);
+ this.onPagePlaylistLoad = this.onPagePlaylistLoad.bind(this);
- MediaPageStore.on('loaded_media_data', this.onMediaLoad);
- MediaPageStore.on('loaded_media_error', this.onMediaLoadError);
- MediaPageStore.on('loaded_page_playlist_data', this.onPagePlaylistLoad);
- }
+ MediaPageStore.on('loaded_media_data', this.onMediaLoad);
+ MediaPageStore.on('loaded_media_error', this.onMediaLoadError);
+ MediaPageStore.on('loaded_page_playlist_data', this.onPagePlaylistLoad);
+ }
- componentDidMount() {
- MediaPageActions.loadMediaData();
- // FIXME: Is not neccessary to check on every window dimension for changes...
- PageStore.on('window_resize', this.onWindowResize);
- }
+ componentDidMount() {
+ MediaPageActions.loadMediaData();
+ // FIXME: Is not neccessary to check on every window dimension for changes...
+ PageStore.on('window_resize', this.onWindowResize);
+ }
- onPagePlaylistLoad() {
- this.setState({
- pagePlaylistLoaded: true,
- });
- }
+ onPagePlaylistLoad() {
+ this.setState({
+ pagePlaylistLoaded: true,
+ });
+ }
- onWindowResize() {
- const isWideLayout = wideLayoutBreakpoint <= window.innerWidth;
+ onWindowResize() {
+ const isWideLayout = wideLayoutBreakpoint <= window.innerWidth;
- this.setState({
- wideLayout: isWideLayout,
- infoAndSidebarViewType: !isWideLayout || (MediaPageStore.isVideo() && this.state.theaterMode) ? 0 : 1,
- });
- }
+ this.setState({
+ wideLayout: isWideLayout,
+ infoAndSidebarViewType: !isWideLayout || (MediaPageStore.isVideo() && this.state.theaterMode) ? 0 : 1,
+ });
+ }
- onMediaLoad() {
- this.setState({ mediaLoaded: true });
- }
+ onMediaLoad() {
+ this.setState({ mediaLoaded: true });
+ }
- onMediaLoadError() {
- this.setState({ mediaLoadFailed: true });
- }
+ onMediaLoadError() {
+ this.setState({ mediaLoadFailed: true });
+ }
- viewerContainerContent() {
- return null;
- }
+ viewerContainerContent() {
+ return null;
+ }
- mediaType() {
- return null;
- }
+ mediaType() {
+ return null;
+ }
- pageContent() {
- return this.state.mediaLoadFailed ? (
-
-
-
- ) : (
-
-
- {this.state.mediaLoaded ? this.viewerContainerContent() : null}
-
-
- {!this.state.infoAndSidebarViewType
- ? [
- ,
- this.state.pagePlaylistLoaded ? (
-
- ) : null,
- ]
- : [
- this.state.pagePlaylistLoaded ? (
-
- ) : null,
- ,
- ]}
-
-
- );
- }
+ pageContent() {
+ return this.state.mediaLoadFailed ? (
+
+
+
+ ) : (
+
+
+ {this.state.mediaLoaded ? this.viewerContainerContent() : null}
+
+
+ {!this.state.infoAndSidebarViewType
+ ? [
+ ,
+ !inEmbeddedApp() && this.state.pagePlaylistLoaded ? (
+
+ ) : null,
+ ]
+ : [
+ !inEmbeddedApp() && this.state.pagePlaylistLoaded ? (
+
+ ) : null,
+ ,
+ ]}
+
+
+ );
+ }
}
diff --git a/frontend/src/static/js/pages/_VideoMediaPage.js b/frontend/src/static/js/pages/_VideoMediaPage.js
index eed1be70..6c052145 100644
--- a/frontend/src/static/js/pages/_VideoMediaPage.js
+++ b/frontend/src/static/js/pages/_VideoMediaPage.js
@@ -2,6 +2,7 @@ import React from 'react';
// FIXME: 'VideoViewerStore' is used only in case of video media, but is included in every media page code.
import { PageStore, MediaPageStore, VideoViewerStore } from '../utils/stores/';
import { MediaPageActions } from '../utils/actions/';
+import { inEmbeddedApp } from '../utils/helpers/';
import ViewerInfoVideo from '../components/media-page/ViewerInfoVideo';
import ViewerError from '../components/media-page/ViewerError';
import ViewerSidebar from '../components/media-page/ViewerSidebar';
@@ -11,118 +12,119 @@ import _MediaPage from './_MediaPage';
const wideLayoutBreakpoint = 1216;
export class _VideoMediaPage extends Page {
- constructor(props) {
- super(props, 'media');
+ constructor(props) {
+ super(props, 'media');
- this.state = {
- wideLayout: wideLayoutBreakpoint <= window.innerWidth,
- mediaLoaded: false,
- mediaLoadFailed: false,
- isVideoMedia: false,
- theaterMode: false, // FIXME: Used only in case of video media, but is included in every media page code.
- pagePlaylistLoaded: false,
- pagePlaylistData: MediaPageStore.get('playlist-data'),
- };
+ this.state = {
+ wideLayout: wideLayoutBreakpoint <= window.innerWidth,
+ mediaLoaded: false,
+ mediaLoadFailed: false,
+ isVideoMedia: false,
+ theaterMode: false, // FIXME: Used only in case of video media, but is included in every media page code.
+ pagePlaylistLoaded: false,
+ pagePlaylistData: MediaPageStore.get('playlist-data'),
+ };
- this.onWindowResize = this.onWindowResize.bind(this);
- this.onMediaLoad = this.onMediaLoad.bind(this);
- this.onMediaLoadError = this.onMediaLoadError.bind(this);
- this.onPagePlaylistLoad = this.onPagePlaylistLoad.bind(this);
+ this.onWindowResize = this.onWindowResize.bind(this);
+ this.onMediaLoad = this.onMediaLoad.bind(this);
+ this.onMediaLoadError = this.onMediaLoadError.bind(this);
+ this.onPagePlaylistLoad = this.onPagePlaylistLoad.bind(this);
- MediaPageStore.on('loaded_media_data', this.onMediaLoad);
- MediaPageStore.on('loaded_media_error', this.onMediaLoadError);
- MediaPageStore.on('loaded_page_playlist_data', this.onPagePlaylistLoad);
- }
-
- componentDidMount() {
- MediaPageActions.loadMediaData();
- // FIXME: Is not neccessary to check on every window dimension for changes...
- PageStore.on('window_resize', this.onWindowResize);
- }
-
- onWindowResize() {
- this.setState({
- wideLayout: wideLayoutBreakpoint <= window.innerWidth,
- });
- }
-
- onPagePlaylistLoad() {
- this.setState({
- pagePlaylistLoaded: true,
- pagePlaylistData: MediaPageStore.get('playlist-data'),
- });
- }
-
- onMediaLoad() {
- const isVideoMedia = 'video' === MediaPageStore.get('media-type') || 'audio' === MediaPageStore.get('media-type');
-
- if (isVideoMedia) {
- this.onViewerModeChange = this.onViewerModeChange.bind(this);
-
- VideoViewerStore.on('changed_viewer_mode', this.onViewerModeChange);
-
- this.setState({
- mediaLoaded: true,
- isVideoMedia: isVideoMedia,
- theaterMode: VideoViewerStore.get('in-theater-mode'),
- });
- } else {
- this.setState({
- mediaLoaded: true,
- isVideoMedia: isVideoMedia,
- });
+ MediaPageStore.on('loaded_media_data', this.onMediaLoad);
+ MediaPageStore.on('loaded_media_error', this.onMediaLoadError);
+ MediaPageStore.on('loaded_page_playlist_data', this.onPagePlaylistLoad);
}
- }
- onViewerModeChange() {
- this.setState({ theaterMode: VideoViewerStore.get('in-theater-mode') });
- }
+ componentDidMount() {
+ MediaPageActions.loadMediaData();
+ // FIXME: Is not neccessary to check on every window dimension for changes...
+ PageStore.on('window_resize', this.onWindowResize);
+ }
- onMediaLoadError(a) {
- this.setState({ mediaLoadFailed: true });
- }
+ onWindowResize() {
+ this.setState({
+ wideLayout: wideLayoutBreakpoint <= window.innerWidth,
+ });
+ }
- pageContent() {
- const viewerClassname = 'cf viewer-section' + (this.state.theaterMode ? ' theater-mode' : ' viewer-wide');
- const viewerNestedClassname = 'viewer-section-nested' + (this.state.theaterMode ? ' viewer-section' : '');
+ onPagePlaylistLoad() {
+ this.setState({
+ pagePlaylistLoaded: true,
+ pagePlaylistData: MediaPageStore.get('playlist-data'),
+ });
+ }
- return this.state.mediaLoadFailed ? (
-
-
-
- ) : (
-
- {[
-
- {this.state.mediaLoaded && this.state.pagePlaylistLoaded
- ? this.viewerContainerContent(MediaPageStore.get('media-data'))
- : null}
-
,
-
- {!this.state.wideLayout || (this.state.isVideoMedia && this.state.theaterMode)
- ? [
-
,
- this.state.pagePlaylistLoaded ? (
-
- ) : null,
- ]
- : [
- this.state.pagePlaylistLoaded ? (
-
- ) : null,
-
,
+ onMediaLoad() {
+ const isVideoMedia =
+ 'video' === MediaPageStore.get('media-type') || 'audio' === MediaPageStore.get('media-type');
+
+ if (isVideoMedia) {
+ this.onViewerModeChange = this.onViewerModeChange.bind(this);
+
+ VideoViewerStore.on('changed_viewer_mode', this.onViewerModeChange);
+
+ this.setState({
+ mediaLoaded: true,
+ isVideoMedia: isVideoMedia,
+ theaterMode: VideoViewerStore.get('in-theater-mode'),
+ });
+ } else {
+ this.setState({
+ mediaLoaded: true,
+ isVideoMedia: isVideoMedia,
+ });
+ }
+ }
+
+ onViewerModeChange() {
+ this.setState({ theaterMode: VideoViewerStore.get('in-theater-mode') });
+ }
+
+ onMediaLoadError(a) {
+ this.setState({ mediaLoadFailed: true });
+ }
+
+ pageContent() {
+ const viewerClassname = 'cf viewer-section' + (this.state.theaterMode ? ' theater-mode' : ' viewer-wide');
+ const viewerNestedClassname = 'viewer-section-nested' + (this.state.theaterMode ? ' viewer-section' : '');
+
+ return this.state.mediaLoadFailed ? (
+
+
+
+ ) : (
+
+ {[
+
+ {this.state.mediaLoaded && this.state.pagePlaylistLoaded
+ ? this.viewerContainerContent(MediaPageStore.get('media-data'))
+ : null}
+
,
+
+ {!this.state.wideLayout || (this.state.isVideoMedia && this.state.theaterMode)
+ ? [
+ ,
+ !inEmbeddedApp() && this.state.pagePlaylistLoaded ? (
+
+ ) : null,
+ ]
+ : [
+ !inEmbeddedApp() && this.state.pagePlaylistLoaded ? (
+
+ ) : null,
+ ,
+ ]}
+
,
]}
-
,
- ]}
-
- );
- }
+
+ );
+ }
}
diff --git a/frontend/src/static/js/utils/contexts/LayoutContext.js b/frontend/src/static/js/utils/contexts/LayoutContext.js
index 52f59b5f..813fc80b 100644
--- a/frontend/src/static/js/utils/contexts/LayoutContext.js
+++ b/frontend/src/static/js/utils/contexts/LayoutContext.js
@@ -1,101 +1,103 @@
-import React, { createContext, useContext, useEffect, useState } from 'react';
+import React, { createContext, useContext, useEffect, useMemo, useState } from 'react';
import { BrowserCache } from '../classes/';
import { PageStore } from '../stores/';
-import { addClassname, removeClassname } from '../helpers/';
+import { addClassname, removeClassname, inEmbeddedApp } from '../helpers/';
import SiteContext from './SiteContext';
let slidingSidebarTimeout;
function onSidebarVisibilityChange(visibleSidebar) {
- clearTimeout(slidingSidebarTimeout);
+ clearTimeout(slidingSidebarTimeout);
- addClassname(document.body, 'sliding-sidebar');
-
- slidingSidebarTimeout = setTimeout(function () {
- if ('media' === PageStore.get('current-page')) {
- if (visibleSidebar) {
- addClassname(document.body, 'overflow-hidden');
- } else {
- removeClassname(document.body, 'overflow-hidden');
- }
- } else {
- if (!visibleSidebar || 767 < window.innerWidth) {
- removeClassname(document.body, 'overflow-hidden');
- } else {
- addClassname(document.body, 'overflow-hidden');
- }
- }
-
- if (visibleSidebar) {
- addClassname(document.body, 'visible-sidebar');
- } else {
- removeClassname(document.body, 'visible-sidebar');
- }
+ addClassname(document.body, 'sliding-sidebar');
slidingSidebarTimeout = setTimeout(function () {
- slidingSidebarTimeout = null;
- removeClassname(document.body, 'sliding-sidebar');
- }, 220);
- }, 20);
+ if ('media' === PageStore.get('current-page')) {
+ if (visibleSidebar) {
+ addClassname(document.body, 'overflow-hidden');
+ } else {
+ removeClassname(document.body, 'overflow-hidden');
+ }
+ } else {
+ if (!visibleSidebar || 767 < window.innerWidth) {
+ removeClassname(document.body, 'overflow-hidden');
+ } else {
+ addClassname(document.body, 'overflow-hidden');
+ }
+ }
+
+ if (visibleSidebar) {
+ addClassname(document.body, 'visible-sidebar');
+ } else {
+ removeClassname(document.body, 'visible-sidebar');
+ }
+
+ slidingSidebarTimeout = setTimeout(function () {
+ slidingSidebarTimeout = null;
+ removeClassname(document.body, 'sliding-sidebar');
+ }, 220);
+ }, 20);
}
export const LayoutContext = createContext();
export const LayoutProvider = ({ children }) => {
- const site = useContext(SiteContext);
- const cache = new BrowserCache('MediaCMS[' + site.id + '][layout]', 86400);
+ const site = useContext(SiteContext);
+ const cache = new BrowserCache('MediaCMS[' + site.id + '][layout]', 86400);
- const enabledSidebar = !!(document.getElementById('app-sidebar') || document.querySelector('.page-sidebar'));
+ const isMediaPage = useMemo(() => PageStore.get('current-page') === 'media', []);
+ const isEmbeddedApp = useMemo(() => inEmbeddedApp(), []);
- const [visibleSidebar, setVisibleSidebar] = useState(cache.get('visible-sidebar'));
- const [visibleMobileSearch, setVisibleMobileSearch] = useState(false);
+ const enabledSidebar = Boolean(document.getElementById('app-sidebar') || document.querySelector('.page-sidebar'));
- const toggleMobileSearch = () => {
- setVisibleMobileSearch(!visibleMobileSearch);
- };
+ const [visibleSidebar, setVisibleSidebar] = useState(cache.get('visible-sidebar'));
+ const [visibleMobileSearch, setVisibleMobileSearch] = useState(false);
- const toggleSidebar = () => {
- const newval = !visibleSidebar;
- onSidebarVisibilityChange(newval);
- setVisibleSidebar(newval);
- };
+ const toggleMobileSearch = () => {
+ setVisibleMobileSearch(!visibleMobileSearch);
+ };
- useEffect(() => {
- if (visibleSidebar) {
- addClassname(document.body, 'visible-sidebar');
- } else {
- removeClassname(document.body, 'visible-sidebar');
- }
- if ('media' !== PageStore.get('current-page') && 1023 < window.innerWidth) {
- cache.set('visible-sidebar', visibleSidebar);
- }
- }, [visibleSidebar]);
+ const toggleSidebar = () => {
+ const newval = !visibleSidebar;
+ onSidebarVisibilityChange(newval);
+ setVisibleSidebar(newval);
+ };
- useEffect(() => {
- PageStore.once('page_init', () => {
- if ('media' === PageStore.get('current-page')) {
- setVisibleSidebar(false);
- removeClassname(document.body, 'visible-sidebar');
- }
- });
+ useEffect(() => {
+ if (!isEmbeddedApp && visibleSidebar) {
+ addClassname(document.body, 'visible-sidebar');
+ } else {
+ removeClassname(document.body, 'visible-sidebar');
+ }
- setVisibleSidebar(
- 'media' !== PageStore.get('current-page') &&
- 1023 < window.innerWidth &&
- (null === visibleSidebar || visibleSidebar)
- );
- }, []);
+ if (!isEmbeddedApp && !isMediaPage && 1023 < window.innerWidth) {
+ cache.set('visible-sidebar', visibleSidebar);
+ }
+ }, [isEmbeddedApp, isMediaPage, visibleSidebar]);
- const value = {
- enabledSidebar,
- visibleSidebar,
- setVisibleSidebar,
- visibleMobileSearch,
- toggleMobileSearch,
- toggleSidebar,
- };
+ useEffect(() => {
+ PageStore.once('page_init', () => {
+ if (isEmbeddedApp || isMediaPage) {
+ setVisibleSidebar(false);
+ removeClassname(document.body, 'visible-sidebar');
+ }
+ });
- return
{children};
+ setVisibleSidebar(
+ !isEmbeddedApp && !isMediaPage && 1023 < window.innerWidth && (null === visibleSidebar || visibleSidebar)
+ );
+ }, []);
+
+ const value = {
+ enabledSidebar,
+ visibleSidebar,
+ setVisibleSidebar,
+ visibleMobileSearch,
+ toggleMobileSearch,
+ toggleSidebar,
+ };
+
+ return
{children};
};
export const LayoutConsumer = LayoutContext.Consumer;
diff --git a/frontend/src/static/js/utils/helpers/embeddedApp.ts b/frontend/src/static/js/utils/helpers/embeddedApp.ts
new file mode 100644
index 00000000..7c859f77
--- /dev/null
+++ b/frontend/src/static/js/utils/helpers/embeddedApp.ts
@@ -0,0 +1,4 @@
+export function inEmbeddedApp() {
+ const url = new URL(globalThis.location.href);
+ return url.searchParams.get('mode') === 'embed_mode';
+}
diff --git a/frontend/src/static/js/utils/helpers/index.js b/frontend/src/static/js/utils/helpers/index.js
index 3b69683f..0376b929 100644
--- a/frontend/src/static/js/utils/helpers/index.js
+++ b/frontend/src/static/js/utils/helpers/index.js
@@ -14,3 +14,4 @@ export * from './quickSort';
export * from './requests';
export { translateString } from './translate';
export { replaceString } from './replacementStrings';
+export * from './embeddedApp';
diff --git a/frontend/src/static/js/utils/renderer.js b/frontend/src/static/js/utils/renderer.js
index 7e663b6a..1eeaa484 100755
--- a/frontend/src/static/js/utils/renderer.js
+++ b/frontend/src/static/js/utils/renderer.js
@@ -3,64 +3,82 @@ import ReactDOM from 'react-dom';
import { ThemeProvider } from './contexts/ThemeContext';
import { LayoutProvider } from './contexts/LayoutContext';
import { UserProvider } from './contexts/UserContext';
+import { inEmbeddedApp } from './helpers';
const AppProviders = ({ children }) => (
-
-
- {children}
-
-
+
+
+ {children}
+
+
);
import { PageHeader, PageSidebar } from '../components/page-layout';
export function renderPage(idSelector, PageComponent) {
- const appHeader = document.getElementById('app-header');
- const appSidebar = document.getElementById('app-sidebar');
- const appContent = idSelector ? document.getElementById(idSelector) : undefined;
+ const appContent = idSelector ? document.getElementById(idSelector) : undefined;
- if (appContent && PageComponent) {
- ReactDOM.render(
-
- {appHeader ? ReactDOM.createPortal(, appHeader) : null}
- {appSidebar ? ReactDOM.createPortal(, appSidebar) : null}
-
- ,
- appContent
- );
- } else if (appHeader && appSidebar) {
- ReactDOM.render(
-
- {ReactDOM.createPortal(, appHeader)}
-
- ,
- appSidebar
- );
- } else if (appHeader) {
- ReactDOM.render(
-
-
-
-
-
-
- ,
- appSidebar
- );
- } else if (appSidebar) {
- ReactDOM.render(
-
-
- ,
- appSidebar
- );
- }
+ if (inEmbeddedApp() && appContent) {
+ globalThis.document.body.classList.add('embedded-app');
+ globalThis.document.body.classList.remove('visible-sidebar');
+
+ if (PageComponent) {
+ ReactDOM.render(
+
+
+ ,
+ appContent
+ );
+ }
+
+ return;
+ }
+
+ const appHeader = document.getElementById('app-header');
+ const appSidebar = document.getElementById('app-sidebar');
+
+ if (appContent && PageComponent) {
+ ReactDOM.render(
+
+ {appHeader ? ReactDOM.createPortal(, appHeader) : null}
+ {appSidebar ? ReactDOM.createPortal(, appSidebar) : null}
+
+ ,
+ appContent
+ );
+ } else if (appHeader && appSidebar) {
+ ReactDOM.render(
+
+ {ReactDOM.createPortal(, appHeader)}
+
+ ,
+ appSidebar
+ );
+ } else if (appHeader) {
+ ReactDOM.render(
+
+
+
+
+
+
+ ,
+ appSidebar
+ );
+ } else if (appSidebar) {
+ ReactDOM.render(
+
+
+ ,
+ appSidebar
+ );
+ }
}
export function renderEmbedPage(idSelector, PageComponent) {
- const appContent = idSelector ? document.getElementById(idSelector) : undefined;
+ const appContent = idSelector ? document.getElementById(idSelector) : undefined;
- if (appContent && PageComponent) {
- ReactDOM.render(
, appContent);
- }
+ if (appContent && PageComponent) {
+ ReactDOM.render(
, appContent);
+ }
}