@instructure/canvas-rce
Version:
A component wrapping Canvas's usage of Tinymce
115 lines (114 loc) • 3.77 kB
JavaScript
/*
* Copyright (C) 2019 - present Instructure, Inc.
*
* This file is part of Canvas.
*
* Canvas is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3 of the License.
*
* Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React, { useRef } from 'react';
import { func, oneOf, shape, string } from 'prop-types';
import { contentTrayDocumentShape } from '../../shared/fileShape';
import formatMessage from '../../../../format-message';
import { Text } from '@instructure/ui-text';
import { View } from '@instructure/ui-view';
import Link from '../../instructure_documents/components/Link';
import { LoadMoreButton, LoadingIndicator, LoadingStatus, useIncrementalLoading } from '../../../../common/incremental-loading';
const PENDING_MEDIA_ENTRY_ID = 'maybe';
function hasFiles(media) {
return media.files.length > 0;
}
function isEmpty(media) {
return !hasFiles(media) && !media.hasMore && !media.isLoading;
}
function renderLinks(files, handleClick, lastItemRef) {
return files.map((f, index) => {
let focusRef = null;
if (index === files.length - 1) {
focusRef = lastItemRef;
}
return /*#__PURE__*/React.createElement(Link, Object.assign({
key: f.id
}, f, {
onClick: handleClick,
focusRef: focusRef,
disabled: f.media_entry_id === PENDING_MEDIA_ENTRY_ID,
disabledMessage: formatMessage('Media file is processing. Please try again later.')
}));
});
}
function renderLoadingError(_error) {
return /*#__PURE__*/React.createElement(View, {
as: "div",
role: "alert",
margin: "medium"
}, /*#__PURE__*/React.createElement(Text, {
color: "danger"
}, formatMessage('Loading failed.')));
}
export default function MediaPanel(props) {
const {
fetchInitialMedia,
fetchNextMedia,
contextType,
sortBy,
searchString
} = props;
const media = props.media[contextType];
const {
hasMore,
isLoading,
error,
files
} = media;
const lastItemRef = useRef(null);
const loader = useIncrementalLoading({
hasMore,
isLoading,
lastItemRef,
onLoadInitial: fetchInitialMedia,
onLoadMore: fetchNextMedia,
records: files,
contextType,
sortBy,
searchString
});
const handleFileClick = file => {
props.onMediaEmbed(file);
};
return /*#__PURE__*/React.createElement(View, {
as: "div",
"data-testid": "instructure_links-MediaPanel"
}, renderLinks(files, handleFileClick, lastItemRef), loader.isLoading && /*#__PURE__*/React.createElement(LoadingIndicator, {
loader: loader
}), !loader.isLoading && loader.hasMore && /*#__PURE__*/React.createElement(LoadMoreButton, {
loader: loader
}), /*#__PURE__*/React.createElement(LoadingStatus, {
loader: loader
}), error && renderLoadingError(error), isEmpty(media) && /*#__PURE__*/React.createElement(View, {
as: "div",
role: "alert",
padding: "medium"
}, formatMessage('No results.')));
}
MediaPanel.propTypes = {
contextType: string.isRequired,
fetchInitialMedia: func.isRequired,
fetchNextMedia: func.isRequired,
onMediaEmbed: func.isRequired,
media: contentTrayDocumentShape.isRequired,
sortBy: shape({
sort: oneOf(['date_added', 'alphabetical']).isRequired,
order: oneOf(['asc', 'desc']).isRequired
}),
searchString: string
};