mirror of
https://github.com/Sonarr/Sonarr
synced 2024-12-21 23:33:00 +00:00
Convert EpisodeSearch to TypeScript
This commit is contained in:
parent
4e4bf3507f
commit
03b8c4c28e
4 changed files with 82 additions and 151 deletions
|
@ -20,7 +20,7 @@ import {
|
|||
} from 'Store/Actions/releaseActions';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import EpisodeHistoryConnector from './History/EpisodeHistoryConnector';
|
||||
import EpisodeSearchConnector from './Search/EpisodeSearchConnector';
|
||||
import EpisodeSearch from './Search/EpisodeSearch';
|
||||
import SeasonEpisodeNumber from './SeasonEpisodeNumber';
|
||||
import EpisodeSummary from './Summary/EpisodeSummary';
|
||||
import styles from './EpisodeDetailsModalContent.css';
|
||||
|
@ -174,7 +174,7 @@ function EpisodeDetailsModalContent(props: EpisodeDetailsModalContentProps) {
|
|||
|
||||
<TabPanel>
|
||||
{/* Don't wrap in tabContent so we not have a top margin */}
|
||||
<EpisodeSearchConnector
|
||||
<EpisodeSearch
|
||||
episodeId={episodeId}
|
||||
startInteractiveSearch={startInteractiveSearch}
|
||||
onModalClose={onModalClose}
|
||||
|
|
|
@ -1,56 +0,0 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import Icon from 'Components/Icon';
|
||||
import Button from 'Components/Link/Button';
|
||||
import { icons, kinds, sizes } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import styles from './EpisodeSearch.css';
|
||||
|
||||
function EpisodeSearch(props) {
|
||||
const {
|
||||
onQuickSearchPress,
|
||||
onInteractiveSearchPress
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className={styles.buttonContainer}>
|
||||
<Button
|
||||
className={styles.button}
|
||||
size={sizes.LARGE}
|
||||
onPress={onQuickSearchPress}
|
||||
>
|
||||
<Icon
|
||||
className={styles.buttonIcon}
|
||||
name={icons.QUICK}
|
||||
/>
|
||||
|
||||
{translate('QuickSearch')}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className={styles.buttonContainer}>
|
||||
<Button
|
||||
className={styles.button}
|
||||
kind={kinds.PRIMARY}
|
||||
size={sizes.LARGE}
|
||||
onPress={onInteractiveSearchPress}
|
||||
>
|
||||
<Icon
|
||||
className={styles.buttonIcon}
|
||||
name={icons.INTERACTIVE}
|
||||
/>
|
||||
|
||||
{translate('InteractiveSearch')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
EpisodeSearch.propTypes = {
|
||||
onQuickSearchPress: PropTypes.func.isRequired,
|
||||
onInteractiveSearchPress: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default EpisodeSearch;
|
80
frontend/src/Episode/Search/EpisodeSearch.tsx
Normal file
80
frontend/src/Episode/Search/EpisodeSearch.tsx
Normal file
|
@ -0,0 +1,80 @@
|
|||
import React, { useCallback, useState } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import AppState from 'App/State/AppState';
|
||||
import * as commandNames from 'Commands/commandNames';
|
||||
import Icon from 'Components/Icon';
|
||||
import Button from 'Components/Link/Button';
|
||||
import { icons, kinds, sizes } from 'Helpers/Props';
|
||||
import InteractiveSearch from 'InteractiveSearch/InteractiveSearch';
|
||||
import { executeCommand } from 'Store/Actions/commandActions';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import styles from './EpisodeSearch.css';
|
||||
|
||||
interface EpisodeSearchProps {
|
||||
episodeId: number;
|
||||
startInteractiveSearch: boolean;
|
||||
onModalClose: () => void;
|
||||
}
|
||||
|
||||
function EpisodeSearch({
|
||||
episodeId,
|
||||
startInteractiveSearch,
|
||||
onModalClose,
|
||||
}: EpisodeSearchProps) {
|
||||
const dispatch = useDispatch();
|
||||
const { isPopulated } = useSelector((state: AppState) => state.releases);
|
||||
|
||||
const [isInteractiveSearchOpen, setIsInteractiveSearchOpen] = useState(
|
||||
startInteractiveSearch || isPopulated
|
||||
);
|
||||
|
||||
const handleQuickSearchPress = useCallback(() => {
|
||||
dispatch(
|
||||
executeCommand({
|
||||
name: commandNames.EPISODE_SEARCH,
|
||||
episodeIds: [episodeId],
|
||||
})
|
||||
);
|
||||
|
||||
onModalClose();
|
||||
}, [episodeId, dispatch, onModalClose]);
|
||||
|
||||
const handleInteractiveSearchPress = useCallback(() => {
|
||||
setIsInteractiveSearchOpen(true);
|
||||
}, []);
|
||||
|
||||
if (isInteractiveSearchOpen) {
|
||||
return <InteractiveSearch type="episode" searchPayload={{ episodeId }} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className={styles.buttonContainer}>
|
||||
<Button
|
||||
className={styles.button}
|
||||
size={sizes.LARGE}
|
||||
onPress={handleQuickSearchPress}
|
||||
>
|
||||
<Icon className={styles.buttonIcon} name={icons.QUICK} />
|
||||
|
||||
{translate('QuickSearch')}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className={styles.buttonContainer}>
|
||||
<Button
|
||||
className={styles.button}
|
||||
kind={kinds.PRIMARY}
|
||||
size={sizes.LARGE}
|
||||
onPress={handleInteractiveSearchPress}
|
||||
>
|
||||
<Icon className={styles.buttonIcon} name={icons.INTERACTIVE} />
|
||||
|
||||
{translate('InteractiveSearch')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default EpisodeSearch;
|
|
@ -1,93 +0,0 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import * as commandNames from 'Commands/commandNames';
|
||||
import InteractiveSearch from 'InteractiveSearch/InteractiveSearch';
|
||||
import { executeCommand } from 'Store/Actions/commandActions';
|
||||
import EpisodeSearch from './EpisodeSearch';
|
||||
|
||||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
(state) => state.releases,
|
||||
(releases) => {
|
||||
return {
|
||||
isPopulated: releases.isPopulated
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
const mapDispatchToProps = {
|
||||
executeCommand
|
||||
};
|
||||
|
||||
class EpisodeSearchConnector extends Component {
|
||||
|
||||
//
|
||||
// Lifecycle
|
||||
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
|
||||
this.state = {
|
||||
isInteractiveSearchOpen: props.startInteractiveSearch
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
if (this.props.isPopulated) {
|
||||
this.setState({ isInteractiveSearchOpen: true });
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
||||
onQuickSearchPress = () => {
|
||||
this.props.executeCommand({
|
||||
name: commandNames.EPISODE_SEARCH,
|
||||
episodeIds: [this.props.episodeId]
|
||||
});
|
||||
|
||||
this.props.onModalClose();
|
||||
};
|
||||
|
||||
onInteractiveSearchPress = () => {
|
||||
this.setState({ isInteractiveSearchOpen: true });
|
||||
};
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
const { episodeId } = this.props;
|
||||
|
||||
if (this.state.isInteractiveSearchOpen) {
|
||||
return (
|
||||
<InteractiveSearch
|
||||
type="episode"
|
||||
searchPayload={{ episodeId }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<EpisodeSearch
|
||||
{...this.props}
|
||||
onQuickSearchPress={this.onQuickSearchPress}
|
||||
onInteractiveSearchPress={this.onInteractiveSearchPress}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
EpisodeSearchConnector.propTypes = {
|
||||
episodeId: PropTypes.number.isRequired,
|
||||
isPopulated: PropTypes.bool.isRequired,
|
||||
startInteractiveSearch: PropTypes.bool.isRequired,
|
||||
onModalClose: PropTypes.func.isRequired,
|
||||
executeCommand: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default connect(createMapStateToProps, mapDispatchToProps)(EpisodeSearchConnector);
|
Loading…
Reference in a new issue