1
0
Fork 0
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:
Mark McDowall 2024-12-07 19:28:58 -08:00
parent 4e4bf3507f
commit 03b8c4c28e
4 changed files with 82 additions and 151 deletions

View file

@ -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}

View file

@ -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;

View 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;

View file

@ -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);