mirror of
https://github.com/Radarr/Radarr
synced 2025-12-06 16:32:36 +01:00
Convert Collection Footer to TypeScript
This commit is contained in:
parent
3a55316ada
commit
1d1aca1a04
6 changed files with 359 additions and 361 deletions
|
|
@ -20,7 +20,7 @@ import toggleSelected from 'Utilities/Table/toggleSelected';
|
|||
import CollectionFooter from './CollectionFooter';
|
||||
import CollectionFilterMenu from './Menus/CollectionFilterMenu';
|
||||
import CollectionSortMenu from './Menus/CollectionSortMenu';
|
||||
import NoCollection from './NoCollection';
|
||||
import NoCollections from './NoCollections';
|
||||
import CollectionOverviewsConnector from './Overview/CollectionOverviewsConnector';
|
||||
import CollectionOverviewOptionsModal from './Overview/Options/CollectionOverviewOptionsModal';
|
||||
|
||||
|
|
@ -341,7 +341,7 @@ class Collection extends Component {
|
|||
|
||||
{
|
||||
!error && isPopulated && !items.length &&
|
||||
<NoCollection totalItems={totalItems} />
|
||||
<NoCollections totalItems={totalItems} />
|
||||
}
|
||||
</PageContentBody>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,300 +0,0 @@
|
|||
import _ from 'lodash';
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import FormInputGroup from 'Components/Form/FormInputGroup';
|
||||
import SpinnerButton from 'Components/Link/SpinnerButton';
|
||||
import PageContentFooter from 'Components/Page/PageContentFooter';
|
||||
import { inputTypes, kinds } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import CollectionFooterLabel from './CollectionFooterLabel';
|
||||
import styles from './CollectionFooter.css';
|
||||
|
||||
const NO_CHANGE = 'noChange';
|
||||
|
||||
const monitoredOptions = [
|
||||
{
|
||||
key: NO_CHANGE,
|
||||
get value() {
|
||||
return translate('NoChange');
|
||||
}
|
||||
},
|
||||
{
|
||||
key: 'monitored',
|
||||
get value() {
|
||||
return translate('Monitored');
|
||||
}
|
||||
},
|
||||
{
|
||||
key: 'unmonitored',
|
||||
get value() {
|
||||
return translate('Unmonitored');
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
const searchOnAddOptions = [
|
||||
{
|
||||
key: NO_CHANGE,
|
||||
get value() {
|
||||
return translate('NoChange');
|
||||
}
|
||||
},
|
||||
{
|
||||
key: 'yes',
|
||||
get value() {
|
||||
return translate('Yes');
|
||||
}
|
||||
},
|
||||
{
|
||||
key: 'no',
|
||||
get value() {
|
||||
return translate('No');
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
class CollectionFooter extends Component {
|
||||
|
||||
//
|
||||
// Lifecycle
|
||||
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
|
||||
this.state = {
|
||||
monitored: NO_CHANGE,
|
||||
monitor: NO_CHANGE,
|
||||
qualityProfileId: NO_CHANGE,
|
||||
minimumAvailability: NO_CHANGE,
|
||||
rootFolderPath: NO_CHANGE,
|
||||
searchOnAdd: NO_CHANGE
|
||||
};
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
const {
|
||||
isSaving,
|
||||
saveError
|
||||
} = this.props;
|
||||
|
||||
const newState = {};
|
||||
if (prevProps.isSaving && !isSaving && !saveError) {
|
||||
this.setState({
|
||||
monitored: NO_CHANGE,
|
||||
monitor: NO_CHANGE,
|
||||
qualityProfileId: NO_CHANGE,
|
||||
minimumAvailability: NO_CHANGE,
|
||||
rootFolderPath: NO_CHANGE,
|
||||
searchOnAdd: NO_CHANGE
|
||||
});
|
||||
}
|
||||
|
||||
if (!_.isEmpty(newState)) {
|
||||
this.setState(newState);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
||||
onInputChange = ({ name, value }) => {
|
||||
this.setState({ [name]: value });
|
||||
};
|
||||
|
||||
onUpdateSelectedPress = () => {
|
||||
const {
|
||||
monitored,
|
||||
monitor,
|
||||
qualityProfileId,
|
||||
minimumAvailability,
|
||||
rootFolderPath,
|
||||
searchOnAdd
|
||||
} = this.state;
|
||||
|
||||
const changes = {};
|
||||
|
||||
if (monitored !== NO_CHANGE) {
|
||||
changes.monitored = monitored === 'monitored';
|
||||
}
|
||||
|
||||
if (monitor !== NO_CHANGE) {
|
||||
changes.monitor = monitor;
|
||||
}
|
||||
|
||||
if (qualityProfileId !== NO_CHANGE) {
|
||||
changes.qualityProfileId = qualityProfileId;
|
||||
}
|
||||
|
||||
if (minimumAvailability !== NO_CHANGE) {
|
||||
changes.minimumAvailability = minimumAvailability;
|
||||
}
|
||||
|
||||
if (rootFolderPath !== NO_CHANGE) {
|
||||
changes.rootFolderPath = rootFolderPath;
|
||||
}
|
||||
|
||||
if (searchOnAdd !== NO_CHANGE) {
|
||||
changes.searchOnAdd = searchOnAdd === 'yes';
|
||||
}
|
||||
|
||||
this.props.onUpdateSelectedPress(changes);
|
||||
};
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
const {
|
||||
selectedIds,
|
||||
isSaving
|
||||
} = this.props;
|
||||
|
||||
const {
|
||||
monitored,
|
||||
monitor,
|
||||
qualityProfileId,
|
||||
minimumAvailability,
|
||||
rootFolderPath,
|
||||
searchOnAdd
|
||||
} = this.state;
|
||||
|
||||
const selectedCount = selectedIds.length;
|
||||
|
||||
return (
|
||||
<PageContentFooter>
|
||||
<div className={styles.inputContainer}>
|
||||
<CollectionFooterLabel
|
||||
label={translate('MonitorCollection')}
|
||||
isSaving={isSaving && monitored !== NO_CHANGE}
|
||||
/>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.SELECT}
|
||||
name="monitored"
|
||||
value={monitored}
|
||||
values={monitoredOptions}
|
||||
isDisabled={!selectedCount}
|
||||
onChange={this.onInputChange}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className={styles.inputContainer}>
|
||||
<CollectionFooterLabel
|
||||
label={translate('MonitorMovies')}
|
||||
isSaving={isSaving && monitor !== NO_CHANGE}
|
||||
/>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.SELECT}
|
||||
name="monitor"
|
||||
value={monitor}
|
||||
values={monitoredOptions}
|
||||
isDisabled={!selectedCount}
|
||||
onChange={this.onInputChange}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className={styles.inputContainer}>
|
||||
<CollectionFooterLabel
|
||||
label={translate('QualityProfile')}
|
||||
isSaving={isSaving && qualityProfileId !== NO_CHANGE}
|
||||
/>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.QUALITY_PROFILE_SELECT}
|
||||
name="qualityProfileId"
|
||||
value={qualityProfileId}
|
||||
includeNoChange={true}
|
||||
includeNoChangeDisabled={false}
|
||||
isDisabled={!selectedCount}
|
||||
onChange={this.onInputChange}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className={styles.inputContainer}>
|
||||
<CollectionFooterLabel
|
||||
label={translate('MinimumAvailability')}
|
||||
isSaving={isSaving && minimumAvailability !== NO_CHANGE}
|
||||
/>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.AVAILABILITY_SELECT}
|
||||
name="minimumAvailability"
|
||||
value={minimumAvailability}
|
||||
includeNoChange={true}
|
||||
includeNoChangeDisabled={false}
|
||||
isDisabled={!selectedCount}
|
||||
onChange={this.onInputChange}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className={styles.inputContainer}>
|
||||
<CollectionFooterLabel
|
||||
label={translate('RootFolder')}
|
||||
isSaving={isSaving && rootFolderPath !== NO_CHANGE}
|
||||
/>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.ROOT_FOLDER_SELECT}
|
||||
name="rootFolderPath"
|
||||
value={rootFolderPath}
|
||||
includeNoChange={true}
|
||||
includeNoChangeDisabled={false}
|
||||
selectedValueOptions={{ includeFreeSpace: false }}
|
||||
isDisabled={!selectedCount}
|
||||
onChange={this.onInputChange}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className={styles.inputContainer}>
|
||||
<CollectionFooterLabel
|
||||
label={translate('SearchMoviesOnAdd')}
|
||||
isSaving={isSaving && searchOnAdd !== NO_CHANGE}
|
||||
/>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.SELECT}
|
||||
name="searchOnAdd"
|
||||
value={searchOnAdd}
|
||||
values={searchOnAddOptions}
|
||||
isDisabled={!selectedCount}
|
||||
onChange={this.onInputChange}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className={styles.buttonContainer}>
|
||||
<div className={styles.buttonContainerContent}>
|
||||
<CollectionFooterLabel
|
||||
label={translate('CountCollectionsSelected', { count: selectedCount })}
|
||||
isSaving={false}
|
||||
/>
|
||||
|
||||
<div className={styles.buttons}>
|
||||
<div>
|
||||
<SpinnerButton
|
||||
className={styles.addSelectedButton}
|
||||
kind={kinds.PRIMARY}
|
||||
isSpinning={isSaving}
|
||||
isDisabled={!selectedCount || isSaving}
|
||||
onPress={this.onUpdateSelectedPress}
|
||||
>
|
||||
{translate('UpdateSelected')}
|
||||
</SpinnerButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</PageContentFooter>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
CollectionFooter.propTypes = {
|
||||
selectedIds: PropTypes.arrayOf(PropTypes.number).isRequired,
|
||||
isAdding: PropTypes.bool.isRequired,
|
||||
isSaving: PropTypes.bool.isRequired,
|
||||
saveError: PropTypes.object,
|
||||
onUpdateSelectedPress: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default CollectionFooter;
|
||||
317
frontend/src/Collection/CollectionFooter.tsx
Normal file
317
frontend/src/Collection/CollectionFooter.tsx
Normal file
|
|
@ -0,0 +1,317 @@
|
|||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import { Error } from 'App/State/AppSectionState';
|
||||
import FormInputGroup from 'Components/Form/FormInputGroup';
|
||||
import { EnhancedSelectInputValue } from 'Components/Form/Select/EnhancedSelectInput';
|
||||
import SpinnerButton from 'Components/Link/SpinnerButton';
|
||||
import PageContentFooter from 'Components/Page/PageContentFooter';
|
||||
import usePrevious from 'Helpers/Hooks/usePrevious';
|
||||
import { inputTypes, kinds } from 'Helpers/Props';
|
||||
import { InputChanged } from 'typings/inputs';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import CollectionFooterLabel from './CollectionFooterLabel';
|
||||
import styles from './CollectionFooter.css';
|
||||
|
||||
interface SavePayload {
|
||||
monitored?: boolean;
|
||||
monitor?: string;
|
||||
qualityProfileId?: number;
|
||||
minimumAvailability?: string;
|
||||
rootFolderPath?: string;
|
||||
searchOnAdd?: boolean;
|
||||
}
|
||||
|
||||
interface CollectionFooterProps {
|
||||
selectedIds: number[];
|
||||
isAdding: boolean;
|
||||
isSaving: boolean;
|
||||
saveError: Error;
|
||||
onUpdateSelectedPress(payload: object): void;
|
||||
}
|
||||
|
||||
const NO_CHANGE = 'noChange';
|
||||
|
||||
const monitoredOptions: EnhancedSelectInputValue<string>[] = [
|
||||
{
|
||||
key: NO_CHANGE,
|
||||
get value() {
|
||||
return translate('NoChange');
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'monitored',
|
||||
get value() {
|
||||
return translate('Monitored');
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'unmonitored',
|
||||
get value() {
|
||||
return translate('Unmonitored');
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const searchOnAddOptions: EnhancedSelectInputValue<string>[] = [
|
||||
{
|
||||
key: NO_CHANGE,
|
||||
get value() {
|
||||
return translate('NoChange');
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'yes',
|
||||
get value() {
|
||||
return translate('Yes');
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'no',
|
||||
get value() {
|
||||
return translate('No');
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
function CollectionFooter({
|
||||
selectedIds,
|
||||
isSaving,
|
||||
saveError,
|
||||
onUpdateSelectedPress,
|
||||
}: CollectionFooterProps) {
|
||||
const [monitored, setMonitored] = useState(NO_CHANGE);
|
||||
const [monitor, setMonitor] = useState(NO_CHANGE);
|
||||
const [qualityProfileId, setQualityProfileId] = useState<string | number>(
|
||||
NO_CHANGE
|
||||
);
|
||||
const [minimumAvailability, setMinimumAvailability] = useState(NO_CHANGE);
|
||||
const [rootFolderPath, setRootFolderPath] = useState(NO_CHANGE);
|
||||
const [searchOnAdd, setSearchOnAdd] = useState(NO_CHANGE);
|
||||
|
||||
const wasSaving = usePrevious(isSaving);
|
||||
|
||||
const handleSavePress = useCallback(() => {
|
||||
let hasChanges = false;
|
||||
const payload: SavePayload = {};
|
||||
|
||||
if (monitored !== NO_CHANGE) {
|
||||
hasChanges = true;
|
||||
payload.monitored = monitored === 'monitored';
|
||||
}
|
||||
|
||||
if (monitor !== NO_CHANGE) {
|
||||
hasChanges = true;
|
||||
payload.monitor = monitor;
|
||||
}
|
||||
|
||||
if (qualityProfileId !== NO_CHANGE) {
|
||||
hasChanges = true;
|
||||
payload.qualityProfileId = qualityProfileId as number;
|
||||
}
|
||||
|
||||
if (minimumAvailability !== NO_CHANGE) {
|
||||
hasChanges = true;
|
||||
payload.minimumAvailability = minimumAvailability as string;
|
||||
}
|
||||
|
||||
if (rootFolderPath !== NO_CHANGE) {
|
||||
hasChanges = true;
|
||||
payload.rootFolderPath = rootFolderPath;
|
||||
}
|
||||
|
||||
if (searchOnAdd !== NO_CHANGE) {
|
||||
hasChanges = true;
|
||||
payload.searchOnAdd = searchOnAdd === 'yes';
|
||||
}
|
||||
|
||||
if (hasChanges) {
|
||||
onUpdateSelectedPress(payload);
|
||||
}
|
||||
}, [
|
||||
monitor,
|
||||
monitored,
|
||||
qualityProfileId,
|
||||
minimumAvailability,
|
||||
rootFolderPath,
|
||||
searchOnAdd,
|
||||
onUpdateSelectedPress,
|
||||
]);
|
||||
|
||||
const handleInputChange = useCallback(({ name, value }: InputChanged) => {
|
||||
switch (name) {
|
||||
case 'monitored':
|
||||
setMonitored(value as string);
|
||||
break;
|
||||
case 'monitor':
|
||||
setMonitor(value as string);
|
||||
break;
|
||||
case 'qualityProfileId':
|
||||
setQualityProfileId(value as string);
|
||||
break;
|
||||
case 'minimumAvailability':
|
||||
setMinimumAvailability(value as string);
|
||||
break;
|
||||
case 'rootFolderPath':
|
||||
setRootFolderPath(value as string);
|
||||
break;
|
||||
case 'searchOnAdd':
|
||||
setSearchOnAdd(value as string);
|
||||
break;
|
||||
default:
|
||||
console.warn(`CollectionFooter Unknown Input: '${name}'`);
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isSaving && wasSaving && !saveError) {
|
||||
setMonitored(NO_CHANGE);
|
||||
setMonitor(NO_CHANGE);
|
||||
setQualityProfileId(NO_CHANGE);
|
||||
setMinimumAvailability(NO_CHANGE);
|
||||
setRootFolderPath(NO_CHANGE);
|
||||
setSearchOnAdd(NO_CHANGE);
|
||||
}
|
||||
}, [
|
||||
isSaving,
|
||||
wasSaving,
|
||||
saveError,
|
||||
setMonitored,
|
||||
setMonitor,
|
||||
setQualityProfileId,
|
||||
setMinimumAvailability,
|
||||
setRootFolderPath,
|
||||
setSearchOnAdd,
|
||||
]);
|
||||
|
||||
const selectedCount = selectedIds.length;
|
||||
|
||||
return (
|
||||
<PageContentFooter>
|
||||
<div className={styles.inputContainer}>
|
||||
<CollectionFooterLabel
|
||||
label={translate('MonitorCollection')}
|
||||
isSaving={isSaving && monitored !== NO_CHANGE}
|
||||
/>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.SELECT}
|
||||
name="monitored"
|
||||
value={monitored}
|
||||
values={monitoredOptions}
|
||||
isDisabled={!selectedCount}
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className={styles.inputContainer}>
|
||||
<CollectionFooterLabel
|
||||
label={translate('MonitorMovies')}
|
||||
isSaving={isSaving && monitor !== NO_CHANGE}
|
||||
/>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.SELECT}
|
||||
name="monitor"
|
||||
value={monitor}
|
||||
values={monitoredOptions}
|
||||
isDisabled={!selectedCount}
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className={styles.inputContainer}>
|
||||
<CollectionFooterLabel
|
||||
label={translate('QualityProfile')}
|
||||
isSaving={isSaving && qualityProfileId !== NO_CHANGE}
|
||||
/>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.QUALITY_PROFILE_SELECT}
|
||||
name="qualityProfileId"
|
||||
value={qualityProfileId}
|
||||
includeNoChange={true}
|
||||
includeNoChangeDisabled={false}
|
||||
isDisabled={!selectedCount}
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className={styles.inputContainer}>
|
||||
<CollectionFooterLabel
|
||||
label={translate('MinimumAvailability')}
|
||||
isSaving={isSaving && minimumAvailability !== NO_CHANGE}
|
||||
/>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.AVAILABILITY_SELECT}
|
||||
name="minimumAvailability"
|
||||
value={minimumAvailability}
|
||||
includeNoChange={true}
|
||||
includeNoChangeDisabled={false}
|
||||
isDisabled={!selectedCount}
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className={styles.inputContainer}>
|
||||
<CollectionFooterLabel
|
||||
label={translate('RootFolder')}
|
||||
isSaving={isSaving && rootFolderPath !== NO_CHANGE}
|
||||
/>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.ROOT_FOLDER_SELECT}
|
||||
name="rootFolderPath"
|
||||
value={rootFolderPath}
|
||||
includeNoChange={true}
|
||||
includeNoChangeDisabled={false}
|
||||
selectedValueOptions={{ includeFreeSpace: false }}
|
||||
isDisabled={!selectedCount}
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className={styles.inputContainer}>
|
||||
<CollectionFooterLabel
|
||||
label={translate('SearchMoviesOnAdd')}
|
||||
isSaving={isSaving && searchOnAdd !== NO_CHANGE}
|
||||
/>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.SELECT}
|
||||
name="searchOnAdd"
|
||||
value={searchOnAdd}
|
||||
values={searchOnAddOptions}
|
||||
isDisabled={!selectedCount}
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className={styles.buttonContainer}>
|
||||
<div className={styles.buttonContainerContent}>
|
||||
<CollectionFooterLabel
|
||||
label={translate('CountCollectionsSelected', {
|
||||
count: selectedCount,
|
||||
})}
|
||||
isSaving={false}
|
||||
/>
|
||||
|
||||
<div className={styles.buttons}>
|
||||
<div>
|
||||
<SpinnerButton
|
||||
className={styles.addSelectedButton}
|
||||
kind={kinds.PRIMARY}
|
||||
isSpinning={isSaving}
|
||||
isDisabled={!selectedCount || isSaving}
|
||||
onPress={handleSavePress}
|
||||
>
|
||||
{translate('UpdateSelected')}
|
||||
</SpinnerButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</PageContentFooter>
|
||||
);
|
||||
}
|
||||
|
||||
export default CollectionFooter;
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import SpinnerIcon from 'Components/SpinnerIcon';
|
||||
import { icons } from 'Helpers/Props';
|
||||
import styles from './CollectionFooterLabel.css';
|
||||
|
||||
function CollectionFooterLabel(props) {
|
||||
const {
|
||||
className,
|
||||
label,
|
||||
isSaving
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
{label}
|
||||
|
||||
{
|
||||
isSaving &&
|
||||
<SpinnerIcon
|
||||
className={styles.savingIcon}
|
||||
name={icons.SPINNER}
|
||||
isSpinning={true}
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
CollectionFooterLabel.propTypes = {
|
||||
className: PropTypes.string.isRequired,
|
||||
label: PropTypes.string.isRequired,
|
||||
isSaving: PropTypes.bool.isRequired
|
||||
};
|
||||
|
||||
CollectionFooterLabel.defaultProps = {
|
||||
className: styles.label
|
||||
};
|
||||
|
||||
export default CollectionFooterLabel;
|
||||
32
frontend/src/Collection/CollectionFooterLabel.tsx
Normal file
32
frontend/src/Collection/CollectionFooterLabel.tsx
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
import React from 'react';
|
||||
import SpinnerIcon from 'Components/SpinnerIcon';
|
||||
import { icons } from 'Helpers/Props';
|
||||
import styles from './CollectionFooterLabel.css';
|
||||
|
||||
interface CollectionFooterLabelProps {
|
||||
className?: string;
|
||||
label: string;
|
||||
isSaving: boolean;
|
||||
}
|
||||
|
||||
function CollectionFooterLabel({
|
||||
className = styles.label,
|
||||
label,
|
||||
isSaving,
|
||||
}: CollectionFooterLabelProps) {
|
||||
return (
|
||||
<div className={className}>
|
||||
{label}
|
||||
|
||||
{isSaving ? (
|
||||
<SpinnerIcon
|
||||
className={styles.savingIcon}
|
||||
name={icons.SPINNER}
|
||||
isSpinning={true}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default CollectionFooterLabel;
|
||||
|
|
@ -1,13 +1,14 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import Button from 'Components/Link/Button';
|
||||
import { kinds } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import styles from './NoCollection.css';
|
||||
|
||||
function NoCollection(props) {
|
||||
const { totalItems } = props;
|
||||
interface NoCollectionsProps {
|
||||
totalItems: number;
|
||||
}
|
||||
|
||||
function NoCollections({ totalItems }: NoCollectionsProps) {
|
||||
if (totalItems > 0) {
|
||||
return (
|
||||
<div>
|
||||
|
|
@ -20,24 +21,16 @@ function NoCollection(props) {
|
|||
|
||||
return (
|
||||
<div>
|
||||
<div className={styles.message}>
|
||||
{translate('NoCollections')}
|
||||
</div>
|
||||
<div className={styles.message}>{translate('NoCollections')}</div>
|
||||
|
||||
<div className={styles.buttonContainer}>
|
||||
<Button
|
||||
to="/add/import"
|
||||
kind={kinds.PRIMARY}
|
||||
>
|
||||
<Button to="/add/import" kind={kinds.PRIMARY}>
|
||||
{translate('ImportExistingMovies')}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className={styles.buttonContainer}>
|
||||
<Button
|
||||
to="/add/new"
|
||||
kind={kinds.PRIMARY}
|
||||
>
|
||||
<Button to="/add/new" kind={kinds.PRIMARY}>
|
||||
{translate('AddNewMovie')}
|
||||
</Button>
|
||||
</div>
|
||||
|
|
@ -45,8 +38,4 @@ function NoCollection(props) {
|
|||
);
|
||||
}
|
||||
|
||||
NoCollection.propTypes = {
|
||||
totalItems: PropTypes.number.isRequired
|
||||
};
|
||||
|
||||
export default NoCollection;
|
||||
export default NoCollections;
|
||||
Loading…
Reference in a new issue