New: Rework Movie Details view

movie-details-rework
Qstick 2 years ago
parent 5acd41a7ea
commit 155b8f774b

@ -1,8 +1,8 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Slider from 'react-slick';
import TextTruncate from 'react-text-truncate';
import EditCollectionModalConnector from 'Collection/Edit/EditCollectionModalConnector';
import Carousel from 'Components/Carousel';
import CheckInput from 'Components/Form/CheckInput';
import Icon from 'Components/Icon';
import Label from 'Components/Label';
@ -16,9 +16,6 @@ import translate from 'Utilities/String/translate';
import CollectionMovieConnector from './CollectionMovieConnector';
import styles from './CollectionOverview.css';
import 'slick-carousel/slick/slick.css';
import 'slick-carousel/slick/slick-theme.css';
const columnPadding = parseInt(dimensions.movieIndexColumnPadding);
const columnPaddingSmallScreen = parseInt(dimensions.movieIndexColumnPaddingSmallScreen);
const defaultFontSize = parseInt(fonts.defaultFontSize);
@ -118,15 +115,6 @@ class CollectionOverview extends Component {
const contentHeight = getContentHeight(rowHeight, isSmallScreen);
const overviewHeight = contentHeight - titleRowHeight - posterHeight;
const sliderSettings = {
arrows: false,
dots: false,
infinite: false,
slidesToShow: 1,
slidesToScroll: 1,
variableWidth: true
};
return (
<div className={styles.container}>
<div className={styles.content}>
@ -262,7 +250,7 @@ class CollectionOverview extends Component {
}
<div className={styles.sliderContainer}>
<Slider ref={this.setSliderRef} {...sliderSettings}>
<Carousel setRef={this.setSliderRef}>
{movies.map((movie) => (
<div className={styles.movie} key={movie.tmdbId}>
<CollectionMovieConnector
@ -275,7 +263,7 @@ class CollectionOverview extends Component {
/>
</div>
))}
</Slider>
</Carousel>
</div>
</div>
</div>

@ -0,0 +1,37 @@
import PropTypes from 'prop-types';
import React from 'react';
import Slider from 'react-slick';
import styles from './Alert.css';
import 'slick-carousel/slick/slick.css';
import 'slick-carousel/slick/slick-theme.css';
function Carousel({ className, setRef, children, ...otherProps }) {
const sliderSettings = {
arrows: false,
dots: false,
infinite: false,
slidesToShow: 1,
slidesToScroll: 1,
variableWidth: true
};
return (
<Slider ref={setRef} {...sliderSettings}>
{children}
</Slider>
);
}
Carousel.propTypes = {
className: PropTypes.string.isRequired,
setRef: PropTypes.func.isRequired,
children: PropTypes.node.isRequired
};
Carousel.defaultProps = {
className: styles.alert
};
export default Carousel;

@ -2,12 +2,15 @@ import PropTypes from 'prop-types';
import React from 'react';
import Icon from 'Components/Icon';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import FilterMenu from 'Components/Menu/FilterMenu';
import PageMenuButton from 'Components/Menu/PageMenuButton';
import Table from 'Components/Table/Table';
import TableBody from 'Components/Table/TableBody';
import { icons, sortDirections } from 'Helpers/Props';
import { align, icons, sortDirections } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import InteractiveSearchFilterModalConnector from './InteractiveSearchFilterModalConnector';
import InteractiveSearchRowConnector from './InteractiveSearchRowConnector';
import styles from './InteractiveSearchContent.css';
import styles from './InteractiveSearch.css';
const columns = [
{
@ -22,20 +25,6 @@ const columns = [
isSortable: true,
isVisible: true
},
{
name: 'releaseWeight',
label: React.createElement(Icon, { name: icons.DOWNLOAD }),
isSortable: true,
fixedSortDirection: sortDirections.ASCENDING,
isVisible: true
},
{
name: 'rejections',
label: React.createElement(Icon, { name: icons.DANGER }),
isSortable: true,
fixedSortDirection: sortDirections.ASCENDING,
isVisible: true
},
{
name: 'title',
label: translate('Title'),
@ -99,10 +88,24 @@ const columns = [
label: React.createElement(Icon, { name: icons.FLAG }),
isSortable: true,
isVisible: true
},
{
name: 'rejections',
label: React.createElement(Icon, { name: icons.DANGER }),
isSortable: true,
fixedSortDirection: sortDirections.ASCENDING,
isVisible: true
},
{
name: 'releaseWeight',
label: React.createElement(Icon, { name: icons.DOWNLOAD }),
isSortable: true,
fixedSortDirection: sortDirections.ASCENDING,
isVisible: true
}
];
function InteractiveSearchContent(props) {
function InteractiveSearch(props) {
const {
searchPayload,
isFetching,
@ -110,44 +113,63 @@ function InteractiveSearchContent(props) {
error,
totalReleasesCount,
items,
selectedFilterKey,
filters,
customFilters,
sortKey,
sortDirection,
longDateFormat,
timeFormat,
onSortPress,
onFilterSelect,
onGrabPress
} = props;
return (
<div>
<div className={styles.filterMenuContainer}>
<FilterMenu
alignMenu={align.RIGHT}
selectedFilterKey={selectedFilterKey}
filters={filters}
customFilters={customFilters}
buttonComponent={PageMenuButton}
filterModalConnectorComponent={InteractiveSearchFilterModalConnector}
filterModalConnectorComponentProps={'movies'}
onFilterSelect={onFilterSelect}
/>
</div>
{
isFetching &&
<LoadingIndicator />
isFetching ? <LoadingIndicator /> : null
}
{
!isFetching && !!error &&
!isFetching && error ?
<div>
{translate('UnableToLoadResultsIntSearch')}
</div>
</div> :
null
}
{
!isFetching && isPopulated && !totalReleasesCount &&
!isFetching && isPopulated && !totalReleasesCount ?
<div>
{translate('NoResultsFound')}
</div>
</div> :
null
}
{
!!totalReleasesCount && isPopulated && !items.length &&
!!totalReleasesCount && isPopulated && !items.length ?
<div>
{translate('AllResultsHiddenFilter')}
</div>
</div> :
null
}
{
isPopulated && !!items.length &&
isPopulated && !!items.length ?
<Table
columns={columns}
sortKey={sortKey}
@ -170,32 +192,38 @@ function InteractiveSearchContent(props) {
})
}
</TableBody>
</Table>
</Table> :
null
}
{
totalReleasesCount !== items.length && !!items.length &&
totalReleasesCount !== items.length && !!items.length ?
<div className={styles.filteredMessage}>
{translate('SomeResultsHiddenFilter')}
</div>
</div> :
null
}
</div>
);
}
InteractiveSearchContent.propTypes = {
InteractiveSearch.propTypes = {
searchPayload: PropTypes.object.isRequired,
isFetching: PropTypes.bool.isRequired,
isPopulated: PropTypes.bool.isRequired,
error: PropTypes.object,
totalReleasesCount: PropTypes.number.isRequired,
items: PropTypes.arrayOf(PropTypes.object).isRequired,
selectedFilterKey: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
filters: PropTypes.arrayOf(PropTypes.object).isRequired,
customFilters: PropTypes.arrayOf(PropTypes.object).isRequired,
sortKey: PropTypes.string,
sortDirection: PropTypes.string,
longDateFormat: PropTypes.string.isRequired,
timeFormat: PropTypes.string.isRequired,
onSortPress: PropTypes.func.isRequired,
onFilterSelect: PropTypes.func.isRequired,
onGrabPress: PropTypes.func.isRequired
};
export default InteractiveSearchContent;
export default InteractiveSearch;

@ -5,7 +5,7 @@ import { createSelector } from 'reselect';
import * as releaseActions from 'Store/Actions/releaseActions';
import createClientSideCollectionSelector from 'Store/Selectors/createClientSideCollectionSelector';
import createUISettingsSelector from 'Store/Selectors/createUISettingsSelector';
import InteractiveSearchContent from './InteractiveSearchContent';
import InteractiveSearch from './InteractiveSearch';
function createMapStateToProps(appState) {
return createSelector(
@ -48,7 +48,7 @@ function createMapDispatchToProps(dispatch, props) {
};
}
class InteractiveSearchContentConnector extends Component {
class InteractiveSearchConnector extends Component {
//
// Lifecycle
@ -79,18 +79,18 @@ class InteractiveSearchContentConnector extends Component {
return (
<InteractiveSearchContent
<InteractiveSearch
{...otherProps}
/>
);
}
}
InteractiveSearchContentConnector.propTypes = {
InteractiveSearchConnector.propTypes = {
searchPayload: PropTypes.object.isRequired,
isPopulated: PropTypes.bool.isRequired,
dispatchFetchReleases: PropTypes.func.isRequired,
dispatchClearReleases: PropTypes.func.isRequired
};
export default connect(createMapStateToProps, createMapDispatchToProps)(InteractiveSearchContentConnector);
export default connect(createMapStateToProps, createMapDispatchToProps)(InteractiveSearchConnector);

@ -1,15 +1,20 @@
.cell {
.protocol {
composes: cell from '~Components/Table/Cells/TableRowCell.css';
width: 80px;
}
.protocol {
composes: cell;
.title {
composes: cell from '~Components/Table/Cells/TableRowCell.css';
width: 80px;
display: flex;
align-items: center;
justify-content: space-between;
word-break: break-all;
}
.indexer {
composes: cell;
composes: cell from '~Components/Table/Cells/TableRowCell.css';
width: 85px;
}
@ -17,7 +22,9 @@
.quality,
.customFormat,
.language {
composes: cell;
composes: cell from '~Components/Table/Cells/TableRowCell.css';
text-align: center;
}
.language {
@ -25,7 +32,7 @@
}
.customFormatScore {
composes: cell;
composes: cell from '~Components/Table/Cells/TableRowCell.css';
width: 55px;
font-weight: bold;
@ -35,34 +42,26 @@
.rejected,
.indexerFlags,
.download {
composes: cell;
composes: cell from '~Components/Table/Cells/TableRowCell.css';
width: 50px;
}
.age,
.size {
composes: cell;
composes: cell from '~Components/Table/Cells/TableRowCell.css';
white-space: nowrap;
}
.peers {
composes: cell;
composes: cell from '~Components/Table/Cells/TableRowCell.css';
width: 75px;
}
.title {
composes: cell;
}
.title div {
overflow-wrap: break-word;
}
.history {
composes: cell;
composes: cell from '~Components/Table/Cells/TableRowCell.css';
width: 75px;
}

@ -145,46 +145,6 @@ class InteractiveSearchRow extends Component {
{formatAge(age, ageHours, ageMinutes)}
</TableRowCell>
<TableRowCell className={styles.download}>
<SpinnerIconButton
name={getDownloadIcon(isGrabbing, isGrabbed, grabError)}
kind={grabError ? kinds.DANGER : kinds.DEFAULT}
title={getDownloadTooltip(isGrabbing, isGrabbed, grabError)}
isDisabled={isGrabbed}
isSpinning={isGrabbing}
onPress={downloadAllowed ? this.onGrabPress : this.onConfirmGrabPress}
/>
</TableRowCell>
<TableRowCell className={styles.rejected}>
{
!!rejections.length &&
<Popover
anchor={
<Icon
name={icons.DANGER}
kind={kinds.DANGER}
/>
}
title={translate('ReleaseRejected')}
body={
<ul>
{
rejections.map((rejection, index) => {
return (
<li key={index}>
{rejection}
</li>
);
})
}
</ul>
}
position={tooltipPositions.BOTTOM}
/>
}
</TableRowCell>
<TableRowCell className={styles.title}>
<Link
to={infoUrl}
@ -297,6 +257,46 @@ class InteractiveSearchRow extends Component {
}
</TableRowCell>
<TableRowCell className={styles.rejected}>
{
!!rejections.length &&
<Popover
anchor={
<Icon
name={icons.DANGER}
kind={kinds.DANGER}
/>
}
title={translate('ReleaseRejected')}
body={
<ul>
{
rejections.map((rejection, index) => {
return (
<li key={index}>
{rejection}
</li>
);
})
}
</ul>
}
position={tooltipPositions.LEFT}
/>
}
</TableRowCell>
<TableRowCell className={styles.download}>
<SpinnerIconButton
name={getDownloadIcon(isGrabbing, isGrabbed, grabError)}
kind={grabError ? kinds.DANGER : kinds.DEFAULT}
title={getDownloadTooltip(isGrabbing, isGrabbed, grabError)}
isDisabled={isGrabbed}
isSpinning={isGrabbing}
onPress={downloadAllowed ? this.onGrabPress : this.onConfirmGrabPress}
/>
</TableRowCell>
<ConfirmModal
isOpen={this.state.isConfirmGrabModalOpen}
kind={kinds.WARNING}

@ -1,16 +0,0 @@
import React from 'react';
import InteractiveSearchContentConnector from './InteractiveSearchContentConnector';
function InteractiveSearchTable(props) {
return (
<InteractiveSearchContentConnector
searchPayload={props}
/>
);
}
InteractiveSearchTable.propTypes = {
};
export default InteractiveSearchTable;

@ -69,7 +69,8 @@ class MovieCastPoster extends Component {
const elementStyle = {
width: `${posterWidth}px`,
height: `${posterHeight}px`
height: `${posterHeight}px`,
borderRadius: '5px'
};
const contentStyle = {

@ -69,7 +69,8 @@ class MovieCrewPoster extends Component {
const elementStyle = {
width: `${posterWidth}px`,
height: `${posterHeight}px`
height: `${posterHeight}px`,
borderRadius: '5px'
};
const contentStyle = {

@ -1,6 +1,7 @@
$hoverScale: 1.05;
.content {
border-radius: 5px;
transition: all 200ms ease-in;
&:hover {

@ -2,6 +2,10 @@
flex: 1 0 auto;
}
.movie {
padding: 10px;
}
.container {
padding: 10px;
}

@ -1,7 +1,6 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { Grid, WindowScroller } from 'react-virtualized';
import Measure from 'Components/Measure';
import Carousel from 'Components/Carousel';
import dimensions from 'Styles/Variables/dimensions';
import hasDifferentItemsOrOrder from 'Utilities/Object/hasDifferentItemsOrOrder';
import MovieCreditPosterConnector from './MovieCreditPosterConnector';
@ -169,56 +168,36 @@ class MovieCreditPosters extends Component {
render() {
const {
items
items,
itemComponent
} = this.props;
const {
width,
columnWidth,
columnCount,
rowHeight
posterWidth,
posterHeight
} = this.state;
const rowCount = Math.ceil(items.length / columnCount);
return (
<Measure
whitelist={['width']}
onMeasure={this.onMeasure}
>
<WindowScroller
scrollElement={undefined}
>
{({ height, registerChild, onChildScroll, scrollTop }) => {
if (!height) {
return <div />;
}
return (
<div ref={registerChild}>
<Grid
ref={this.setGridRef}
className={styles.grid}
autoHeight={true}
height={height}
columnCount={columnCount}
columnWidth={columnWidth}
rowCount={rowCount}
rowHeight={rowHeight}
width={width}
onScroll={onChildScroll}
scrollTop={scrollTop}
overscanRowCount={2}
cellRenderer={this.cellRenderer}
scrollToAlignment={'start'}
isScrollingOptOut={true}
/>
</div>
);
}
}
</WindowScroller>
</Measure>
<div className={styles.sliderContainer}>
<Carousel setRef={this.setSliderRef}>
{items.map((movie) => (
<div className={styles.movie} key={movie.tmdbId}>
<MovieCreditPosterConnector
key={movie.order}
component={itemComponent}
posterWidth={posterWidth}
posterHeight={posterHeight}
tmdbId={movie.personTmdbId}
personName={movie.personName}
job={movie.job}
character={movie.character}
images={movie.images}
/>
</div>
))}
</Carousel>
</div>
);
}
}

@ -1,3 +0,0 @@
.alternateTitle {
white-space: nowrap;
}

@ -1,28 +0,0 @@
import PropTypes from 'prop-types';
import React from 'react';
import styles from './MovieAlternateTitles.css';
function MovieAlternateTitles({ alternateTitles }) {
return (
<ul>
{
alternateTitles.filter((x, i, a) => a.indexOf(x) === i).map((alternateTitle) => {
return (
<li
key={alternateTitle}
className={styles.alternateTitle}
>
{alternateTitle}
</li>
);
})
}
</ul>
);
}
MovieAlternateTitles.propTypes = {
alternateTitles: PropTypes.arrayOf(PropTypes.string).isRequired
};
export default MovieAlternateTitles;

@ -5,7 +5,7 @@
.header {
position: relative;
width: 100%;
height: 375px;
height: 425px;
}
.errorMessage {
@ -39,10 +39,11 @@
}
.poster {
z-index: 2;
flex-shrink: 0;
margin-right: 35px;
width: 217px;
height: 319px;
width: 250px;
height: 368px;
}
.info {

@ -1,8 +1,8 @@
import _ from 'lodash';
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { Tab, TabList, TabPanel, Tabs } from 'react-tabs';
import TextTruncate from 'react-text-truncate';
import FieldSet from 'Components/FieldSet';
import Icon from 'Components/Icon';
import ImdbRating from 'Components/ImdbRating';
import InfoLabel from 'Components/InfoLabel';
@ -22,12 +22,11 @@ import Popover from 'Components/Tooltip/Popover';
import Tooltip from 'Components/Tooltip/Tooltip';
import { icons, kinds, sizes, tooltipPositions } from 'Helpers/Props';
import InteractiveImportModal from 'InteractiveImport/InteractiveImportModal';
import InteractiveSearchFilterMenuConnector from 'InteractiveSearch/InteractiveSearchFilterMenuConnector';
import InteractiveSearchTable from 'InteractiveSearch/InteractiveSearchTable';
import DeleteMovieModal from 'Movie/Delete/DeleteMovieModal';
import EditMovieModalConnector from 'Movie/Edit/EditMovieModalConnector';
import MovieHistoryTable from 'Movie/History/MovieHistoryTable';
import MoviePoster from 'Movie/MoviePoster';
import MovieInteractiveSearchModalConnector from 'Movie/Search/MovieInteractiveSearchModalConnector';
import MovieFileEditorTable from 'MovieFile/Editor/MovieFileEditorTable';
import ExtraFileTable from 'MovieFile/Extras/ExtraFileTable';
import OrganizePreviewModalConnector from 'Organize/OrganizePreviewModalConnector';
@ -81,10 +80,10 @@ class MovieDetails extends Component {
isEditMovieModalOpen: false,
isDeleteMovieModalOpen: false,
isInteractiveImportModalOpen: false,
isInteractiveSearchModalOpen: false,
allExpanded: false,
allCollapsed: false,
expandedState: {},
selectedTabIndex: 0,
overviewHeight: 0,
titleWidth: 0
};
@ -137,6 +136,14 @@ class MovieDetails extends Component {
this.setState({ isEditMovieModalOpen: false });
};
onInteractiveSearchPress = () => {
this.setState({ isInteractiveSearchModalOpen: true });
};
onInteractiveSearchModalClose = () => {
this.setState({ isInteractiveSearchModalOpen: false });
};
onDeleteMoviePress = () => {
this.setState({
isEditMovieModalOpen: false,
@ -298,9 +305,9 @@ class MovieDetails extends Component {
isEditMovieModalOpen,
isDeleteMovieModalOpen,
isInteractiveImportModalOpen,
isInteractiveSearchModalOpen,
overviewHeight,
titleWidth,
selectedTabIndex
titleWidth
} = this.state;
const marqueeWidth = isSmallScreen ? titleWidth : (titleWidth - 150);
@ -326,6 +333,14 @@ class MovieDetails extends Component {
onPress={onSearchPress}
/>
<PageToolbarButton
label={translate('InteractiveSearch')}
iconName={icons.INTERACTIVE}
isSpinning={isSearching}
title={undefined}
onPress={this.onInteractiveSearchPress}
/>
<PageToolbarSeparator />
<PageToolbarButton
@ -651,101 +666,39 @@ class MovieDetails extends Component {
</div>
}
<Tabs selectedIndex={this.state.tabIndex} onSelect={this.onTabSelect}>
<TabList
className={styles.tabList}
>
<Tab
className={styles.tab}
selectedClassName={styles.selectedTab}
>
{translate('History')}
</Tab>
<Tab
className={styles.tab}
selectedClassName={styles.selectedTab}
>
{translate('Search')}
</Tab>
<Tab
className={styles.tab}
selectedClassName={styles.selectedTab}
>
{translate('Files')}
</Tab>
<Tab
className={styles.tab}
selectedClassName={styles.selectedTab}
>
{translate('Titles')}
</Tab>
<Tab
className={styles.tab}
selectedClassName={styles.selectedTab}
>
{translate('Cast')}
</Tab>
<Tab
className={styles.tab}
selectedClassName={styles.selectedTab}
>
{translate('Crew')}
</Tab>
{
selectedTabIndex === 1 &&
<div className={styles.filterIcon}>
<InteractiveSearchFilterMenuConnector />
</div>
}
</TabList>
<TabPanel>
<MovieHistoryTable
movieId={id}
/>
</TabPanel>
<TabPanel>
<InteractiveSearchTable
movieId={id}
/>
</TabPanel>
<TabPanel>
<MovieFileEditorTable
movieId={id}
/>
<ExtraFileTable
movieId={id}
/>
</TabPanel>
<TabPanel>
<MovieTitlesTable
movieId={id}
/>
</TabPanel>
<TabPanel>
<MovieCastPostersConnector
isSmallScreen={isSmallScreen}
/>
</TabPanel>
<TabPanel>
<MovieCrewPostersConnector
isSmallScreen={isSmallScreen}
/>
</TabPanel>
</Tabs>
<FieldSet legend={translate('History')}>
<MovieHistoryTable
movieId={id}
/>
</FieldSet>
<FieldSet legend={translate('Files')}>
<MovieFileEditorTable
movieId={id}
/>
<ExtraFileTable
movieId={id}
/>
</FieldSet>
<FieldSet legend={translate('Cast')}>
<MovieCastPostersConnector
isSmallScreen={isSmallScreen}
/>
</FieldSet>
<FieldSet legend={translate('Crew')}>
<MovieCrewPostersConnector
isSmallScreen={isSmallScreen}
/>
</FieldSet>
<FieldSet legend={translate('Titles')}>
<MovieTitlesTable
movieId={id}
/>
</FieldSet>
</div>
<OrganizePreviewModalConnector
@ -777,6 +730,12 @@ class MovieDetails extends Component {
showImportMode={false}
onModalClose={this.onInteractiveImportModalClose}
/>
<MovieInteractiveSearchModalConnector
isOpen={isInteractiveSearchModalOpen}
movieId={id}
onModalClose={this.onInteractiveSearchModalClose}
/>
</PageContentBody>
</PageContent>
);

@ -0,0 +1,9 @@
.container {
border: 1px solid $borderColor;
border-radius: 4px;
background-color: $white;
&:last-of-type {
margin-bottom: 0;
}
}

@ -1,5 +1,6 @@
import React from 'react';
import MovieTitlesTableContentConnector from './MovieTitlesTableContentConnector';
import styles from './MovieTitlesTable.css';
function MovieTitlesTable(props) {
const {
@ -7,9 +8,11 @@ function MovieTitlesTable(props) {
} = props;
return (
<MovieTitlesTableContentConnector
{...otherProps}
/>
<div className={styles.container}>
<MovieTitlesTableContentConnector
{...otherProps}
/>
</div>
);
}

@ -0,0 +1,9 @@
.container {
border: 1px solid $borderColor;
border-radius: 4px;
background-color: $white;
&:last-of-type {
margin-bottom: 0;
}
}

@ -1,5 +1,6 @@
import React from 'react';
import MovieHistoryTableContentConnector from './MovieHistoryTableContentConnector';
import styles from './MovieHistoryTable.css';
function MovieHistoryTable(props) {
const {
@ -7,9 +8,11 @@ function MovieHistoryTable(props) {
} = props;
return (
<MovieHistoryTableContentConnector
{...otherProps}
/>
<div className={styles.container}>
<MovieHistoryTableContentConnector
{...otherProps}
/>
</div>
);
}

@ -0,0 +1,35 @@
import PropTypes from 'prop-types';
import React from 'react';
import Modal from 'Components/Modal/Modal';
import { sizes } from 'Helpers/Props';
import MovieInteractiveSearchModalContent from './MovieInteractiveSearchModalContent';
function MovieInteractiveSearchModal(props) {
const {
isOpen,
movieId,
onModalClose
} = props;
return (
<Modal
isOpen={isOpen}
closeOnBackgroundClick={false}
onModalClose={onModalClose}
size={sizes.EXTRA_LARGE}
>
<MovieInteractiveSearchModalContent
movieId={movieId}
onModalClose={onModalClose}
/>
</Modal>
);
}
MovieInteractiveSearchModal.propTypes = {
isOpen: PropTypes.bool.isRequired,
movieId: PropTypes.number.isRequired,
onModalClose: PropTypes.func.isRequired
};
export default MovieInteractiveSearchModal;

@ -0,0 +1,15 @@
import { connect } from 'react-redux';
import { cancelFetchReleases, clearReleases } from 'Store/Actions/releaseActions';
import MovieInteractiveSearchModal from './MovieInteractiveSearchModal';
function createMapDispatchToProps(dispatch, props) {
return {
onModalClose() {
dispatch(cancelFetchReleases());
dispatch(clearReleases());
props.onModalClose();
}
};
}
export default connect(null, createMapDispatchToProps)(MovieInteractiveSearchModal);

@ -0,0 +1,45 @@
import PropTypes from 'prop-types';
import React from 'react';
import Button from 'Components/Link/Button';
import ModalBody from 'Components/Modal/ModalBody';
import ModalContent from 'Components/Modal/ModalContent';
import ModalFooter from 'Components/Modal/ModalFooter';
import ModalHeader from 'Components/Modal/ModalHeader';
import { scrollDirections } from 'Helpers/Props';
import InteractiveSearchConnector from 'InteractiveSearch/InteractiveSearchConnector';
function MovieInteractiveSearchModalContent(props) {
const {
movieId,
onModalClose
} = props;
return (
<ModalContent onModalClose={onModalClose}>
<ModalHeader>
Interactive Search
</ModalHeader>
<ModalBody scrollDirection={scrollDirections.BOTH}>
<InteractiveSearchConnector
searchPayload={{
movieId
}}
/>
</ModalBody>
<ModalFooter>
<Button onPress={onModalClose}>
Close
</Button>
</ModalFooter>
</ModalContent>
);
}
MovieInteractiveSearchModalContent.propTypes = {
movieId: PropTypes.number.isRequired,
onModalClose: PropTypes.func.isRequired
};
export default MovieInteractiveSearchModalContent;

@ -1,5 +1,4 @@
.container {
margin-top: 20px;
border: 1px solid $borderColor;
border-radius: 4px;
background-color: $white;

Loading…
Cancel
Save