parent
32ce09648c
commit
a2fd23c84d
@ -0,0 +1,15 @@
|
||||
import ModelBase from 'App/ModelBase';
|
||||
import AppSectionState from 'App/State/AppSectionState';
|
||||
|
||||
export interface OrganizePreviewModel extends ModelBase {
|
||||
seriesId: number;
|
||||
seasonNumber: number;
|
||||
episodeNumbers: number[];
|
||||
episodeFileId: number;
|
||||
existingPath: string;
|
||||
newPath: string;
|
||||
}
|
||||
|
||||
type OrganizePreviewAppState = AppSectionState<OrganizePreviewModel>;
|
||||
|
||||
export default OrganizePreviewAppState;
|
@ -1,34 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import Modal from 'Components/Modal/Modal';
|
||||
import OrganizePreviewModalContentConnector from './OrganizePreviewModalContentConnector';
|
||||
|
||||
function OrganizePreviewModal(props) {
|
||||
const {
|
||||
isOpen,
|
||||
onModalClose,
|
||||
...otherProps
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<Modal
|
||||
isOpen={isOpen}
|
||||
onModalClose={onModalClose}
|
||||
>
|
||||
{
|
||||
isOpen &&
|
||||
<OrganizePreviewModalContentConnector
|
||||
{...otherProps}
|
||||
onModalClose={onModalClose}
|
||||
/>
|
||||
}
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
OrganizePreviewModal.propTypes = {
|
||||
isOpen: PropTypes.bool.isRequired,
|
||||
onModalClose: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default OrganizePreviewModal;
|
@ -0,0 +1,37 @@
|
||||
import React, { useCallback } from 'react';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import Modal from 'Components/Modal/Modal';
|
||||
import { clearOrganizePreview } from 'Store/Actions/organizePreviewActions';
|
||||
import OrganizePreviewModalContent, {
|
||||
OrganizePreviewModalContentProps,
|
||||
} from './OrganizePreviewModalContent';
|
||||
|
||||
interface OrganizePreviewModalProps extends OrganizePreviewModalContentProps {
|
||||
isOpen: boolean;
|
||||
onModalClose: () => void;
|
||||
}
|
||||
|
||||
function OrganizePreviewModal({
|
||||
isOpen,
|
||||
onModalClose,
|
||||
...otherProps
|
||||
}: OrganizePreviewModalProps) {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const handleOnModalClose = useCallback(() => {
|
||||
dispatch(clearOrganizePreview());
|
||||
onModalClose();
|
||||
}, [dispatch, onModalClose]);
|
||||
|
||||
return (
|
||||
<Modal isOpen={isOpen} onModalClose={handleOnModalClose}>
|
||||
{isOpen ? (
|
||||
<OrganizePreviewModalContent
|
||||
{...otherProps}
|
||||
onModalClose={handleOnModalClose}
|
||||
/>
|
||||
) : null}
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
export default OrganizePreviewModal;
|
@ -1,39 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { clearOrganizePreview } from 'Store/Actions/organizePreviewActions';
|
||||
import OrganizePreviewModal from './OrganizePreviewModal';
|
||||
|
||||
const mapDispatchToProps = {
|
||||
clearOrganizePreview
|
||||
};
|
||||
|
||||
class OrganizePreviewModalConnector extends Component {
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
||||
onModalClose = () => {
|
||||
this.props.clearOrganizePreview();
|
||||
this.props.onModalClose();
|
||||
};
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
return (
|
||||
<OrganizePreviewModal
|
||||
{...this.props}
|
||||
onModalClose={this.onModalClose}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
OrganizePreviewModalConnector.propTypes = {
|
||||
clearOrganizePreview: PropTypes.func.isRequired,
|
||||
onModalClose: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default connect(undefined, mapDispatchToProps)(OrganizePreviewModalConnector);
|
@ -1,202 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import Alert from 'Components/Alert';
|
||||
import CheckInput from 'Components/Form/CheckInput';
|
||||
import Button from 'Components/Link/Button';
|
||||
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
||||
import InlineMarkdown from 'Components/Markdown/InlineMarkdown';
|
||||
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 { kinds } from 'Helpers/Props';
|
||||
import formatSeason from 'Season/formatSeason';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import getSelectedIds from 'Utilities/Table/getSelectedIds';
|
||||
import selectAll from 'Utilities/Table/selectAll';
|
||||
import toggleSelected from 'Utilities/Table/toggleSelected';
|
||||
import OrganizePreviewRow from './OrganizePreviewRow';
|
||||
import styles from './OrganizePreviewModalContent.css';
|
||||
|
||||
function getValue(allSelected, allUnselected) {
|
||||
if (allSelected) {
|
||||
return true;
|
||||
} else if (allUnselected) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
class OrganizePreviewModalContent extends Component {
|
||||
|
||||
//
|
||||
// Lifecycle
|
||||
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
|
||||
this.state = {
|
||||
allSelected: false,
|
||||
allUnselected: false,
|
||||
lastToggled: null,
|
||||
selectedState: {}
|
||||
};
|
||||
}
|
||||
|
||||
//
|
||||
// Control
|
||||
|
||||
getSelectedIds = () => {
|
||||
return getSelectedIds(this.state.selectedState);
|
||||
};
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
||||
onSelectAllChange = ({ value }) => {
|
||||
this.setState(selectAll(this.state.selectedState, value));
|
||||
};
|
||||
|
||||
onSelectedChange = ({ id, value, shiftKey = false }) => {
|
||||
this.setState((state) => {
|
||||
return toggleSelected(state, this.props.items, id, value, shiftKey);
|
||||
});
|
||||
};
|
||||
|
||||
onOrganizePress = () => {
|
||||
this.props.onOrganizePress(this.getSelectedIds());
|
||||
};
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
const {
|
||||
isFetching,
|
||||
isPopulated,
|
||||
error,
|
||||
items,
|
||||
seasonNumber,
|
||||
renameEpisodes,
|
||||
episodeFormat,
|
||||
path,
|
||||
onModalClose
|
||||
} = this.props;
|
||||
|
||||
const {
|
||||
allSelected,
|
||||
allUnselected,
|
||||
selectedState
|
||||
} = this.state;
|
||||
|
||||
const selectAllValue = getValue(allSelected, allUnselected);
|
||||
|
||||
return (
|
||||
<ModalContent onModalClose={onModalClose}>
|
||||
<ModalHeader>
|
||||
{ seasonNumber == null ?
|
||||
translate('OrganizeModalHeader') :
|
||||
translate('OrganizeModalHeaderSeason', { season: formatSeason(seasonNumber) })
|
||||
}
|
||||
</ModalHeader>
|
||||
|
||||
<ModalBody>
|
||||
{
|
||||
isFetching &&
|
||||
<LoadingIndicator />
|
||||
}
|
||||
|
||||
{
|
||||
!isFetching && error &&
|
||||
<Alert kind={kinds.DANGER}>{translate('OrganizeLoadError')}</Alert>
|
||||
}
|
||||
|
||||
{
|
||||
!isFetching && isPopulated && !items.length &&
|
||||
<div>
|
||||
{
|
||||
renameEpisodes ?
|
||||
<div>{translate('OrganizeNothingToRename')}</div> :
|
||||
<div>{translate('OrganizeRenamingDisabled')}</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
{
|
||||
!isFetching && isPopulated && !!items.length &&
|
||||
<div>
|
||||
<Alert>
|
||||
<div>
|
||||
<InlineMarkdown data={translate('OrganizeRelativePaths', { path })} blockClassName={styles.path} />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<InlineMarkdown data={translate('OrganizeNamingPattern', { episodeFormat })} blockClassName={styles.episodeFormat} />
|
||||
</div>
|
||||
</Alert>
|
||||
|
||||
<div className={styles.previews}>
|
||||
{
|
||||
items.map((item) => {
|
||||
return (
|
||||
<OrganizePreviewRow
|
||||
key={item.episodeFileId}
|
||||
id={item.episodeFileId}
|
||||
existingPath={item.existingPath}
|
||||
newPath={item.newPath}
|
||||
isSelected={selectedState[item.episodeFileId]}
|
||||
onSelectedChange={this.onSelectedChange}
|
||||
/>
|
||||
);
|
||||
})
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</ModalBody>
|
||||
|
||||
<ModalFooter>
|
||||
{
|
||||
isPopulated && !!items.length &&
|
||||
<CheckInput
|
||||
className={styles.selectAllInput}
|
||||
containerClassName={styles.selectAllInputContainer}
|
||||
name="selectAll"
|
||||
value={selectAllValue}
|
||||
onChange={this.onSelectAllChange}
|
||||
/>
|
||||
}
|
||||
|
||||
<Button
|
||||
onPress={onModalClose}
|
||||
>
|
||||
{translate('Cancel')}
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
kind={kinds.PRIMARY}
|
||||
onPress={this.onOrganizePress}
|
||||
>
|
||||
{translate('Organize')}
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
OrganizePreviewModalContent.propTypes = {
|
||||
isFetching: PropTypes.bool.isRequired,
|
||||
isPopulated: PropTypes.bool.isRequired,
|
||||
error: PropTypes.object,
|
||||
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
seasonNumber: PropTypes.number,
|
||||
path: PropTypes.string.isRequired,
|
||||
renameEpisodes: PropTypes.bool,
|
||||
episodeFormat: PropTypes.string,
|
||||
onOrganizePress: PropTypes.func.isRequired,
|
||||
onModalClose: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default OrganizePreviewModalContent;
|
@ -0,0 +1,201 @@
|
||||
import React, { useCallback, useEffect } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import AppState from 'App/State/AppState';
|
||||
import * as commandNames from 'Commands/commandNames';
|
||||
import Alert from 'Components/Alert';
|
||||
import CheckInput from 'Components/Form/CheckInput';
|
||||
import Button from 'Components/Link/Button';
|
||||
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
||||
import InlineMarkdown from 'Components/Markdown/InlineMarkdown';
|
||||
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 useSelectState from 'Helpers/Hooks/useSelectState';
|
||||
import { kinds } from 'Helpers/Props';
|
||||
import formatSeason from 'Season/formatSeason';
|
||||
import useSeries from 'Series/useSeries';
|
||||
import { executeCommand } from 'Store/Actions/commandActions';
|
||||
import { fetchOrganizePreview } from 'Store/Actions/organizePreviewActions';
|
||||
import { fetchNamingSettings } from 'Store/Actions/settingsActions';
|
||||
import { CheckInputChanged } from 'typings/inputs';
|
||||
import { SelectStateInputProps } from 'typings/props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import getSelectedIds from 'Utilities/Table/getSelectedIds';
|
||||
import OrganizePreviewRow from './OrganizePreviewRow';
|
||||
import styles from './OrganizePreviewModalContent.css';
|
||||
|
||||
function getValue(allSelected: boolean, allUnselected: boolean) {
|
||||
if (allSelected) {
|
||||
return true;
|
||||
} else if (allUnselected) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export interface OrganizePreviewModalContentProps {
|
||||
seriesId: number;
|
||||
seasonNumber?: number;
|
||||
onModalClose: () => void;
|
||||
}
|
||||
|
||||
function OrganizePreviewModalContent({
|
||||
seriesId,
|
||||
seasonNumber,
|
||||
onModalClose,
|
||||
}: OrganizePreviewModalContentProps) {
|
||||
const dispatch = useDispatch();
|
||||
const {
|
||||
items,
|
||||
isFetching: isPreviewFetching,
|
||||
isPopulated: isPreviewPopulated,
|
||||
error: previewError,
|
||||
} = useSelector((state: AppState) => state.organizePreview);
|
||||
|
||||
const {
|
||||
isFetching: isNamingFetching,
|
||||
isPopulated: isNamingPopulated,
|
||||
error: namingError,
|
||||
item: naming,
|
||||
} = useSelector((state: AppState) => state.settings.naming);
|
||||
|
||||
const series = useSeries(seriesId)!;
|
||||
const [selectState, setSelectState] = useSelectState();
|
||||
|
||||
const { allSelected, allUnselected, selectedState } = selectState;
|
||||
const isFetching = isPreviewFetching || isNamingFetching;
|
||||
const isPopulated = isPreviewPopulated && isNamingPopulated;
|
||||
const error = previewError || namingError;
|
||||
const { renameEpisodes } = naming;
|
||||
const episodeFormat = naming[`${series.seriesType}EpisodeFormat`];
|
||||
|
||||
const selectAllValue = getValue(allSelected, allUnselected);
|
||||
|
||||
const handleSelectAllChange = useCallback(
|
||||
({ value }: CheckInputChanged) => {
|
||||
setSelectState({ type: value ? 'selectAll' : 'unselectAll', items });
|
||||
},
|
||||
[items, setSelectState]
|
||||
);
|
||||
|
||||
const handleSelectedChange = useCallback(
|
||||
({ id, value, shiftKey = false }: SelectStateInputProps) => {
|
||||
setSelectState({
|
||||
type: 'toggleSelected',
|
||||
items,
|
||||
id,
|
||||
isSelected: value,
|
||||
shiftKey,
|
||||
});
|
||||
},
|
||||
[items, setSelectState]
|
||||
);
|
||||
|
||||
const handleOrganizePress = useCallback(() => {
|
||||
const files = getSelectedIds(selectedState);
|
||||
|
||||
dispatch(
|
||||
executeCommand({
|
||||
name: commandNames.RENAME_FILES,
|
||||
files,
|
||||
seriesId,
|
||||
})
|
||||
);
|
||||
|
||||
onModalClose();
|
||||
}, [seriesId, selectedState, dispatch, onModalClose]);
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(fetchOrganizePreview({ seriesId, seasonNumber }));
|
||||
dispatch(fetchNamingSettings());
|
||||
}, [seriesId, seasonNumber, dispatch]);
|
||||
|
||||
return (
|
||||
<ModalContent onModalClose={onModalClose}>
|
||||
<ModalHeader>
|
||||
{seasonNumber == null
|
||||
? translate('OrganizeModalHeader')
|
||||
: translate('OrganizeModalHeaderSeason', {
|
||||
season: formatSeason(seasonNumber) ?? '',
|
||||
})}
|
||||
</ModalHeader>
|
||||
|
||||
<ModalBody>
|
||||
{isFetching ? <LoadingIndicator /> : null}
|
||||
|
||||
{!isFetching && error ? (
|
||||
<Alert kind={kinds.DANGER}>{translate('OrganizeLoadError')}</Alert>
|
||||
) : null}
|
||||
|
||||
{!isFetching && isPopulated && !items.length ? (
|
||||
<div>
|
||||
{renameEpisodes ? (
|
||||
<div>{translate('OrganizeNothingToRename')}</div>
|
||||
) : (
|
||||
<div>{translate('OrganizeRenamingDisabled')}</div>
|
||||
)}
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{!isFetching && isPopulated && items.length ? (
|
||||
<div>
|
||||
<Alert>
|
||||
<div>
|
||||
<InlineMarkdown
|
||||
data={translate('OrganizeRelativePaths', {
|
||||
path: series.path,
|
||||
})}
|
||||
blockClassName={styles.path}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<InlineMarkdown
|
||||
data={translate('OrganizeNamingPattern', { episodeFormat })}
|
||||
blockClassName={styles.episodeFormat}
|
||||
/>
|
||||
</div>
|
||||
</Alert>
|
||||
|
||||
<div className={styles.previews}>
|
||||
{items.map((item) => {
|
||||
return (
|
||||
<OrganizePreviewRow
|
||||
key={item.episodeFileId}
|
||||
id={item.episodeFileId}
|
||||
existingPath={item.existingPath}
|
||||
newPath={item.newPath}
|
||||
isSelected={selectedState[item.episodeFileId]}
|
||||
onSelectedChange={handleSelectedChange}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
</ModalBody>
|
||||
|
||||
<ModalFooter>
|
||||
{isPopulated && items.length ? (
|
||||
<CheckInput
|
||||
className={styles.selectAllInput}
|
||||
containerClassName={styles.selectAllInputContainer}
|
||||
name="selectAll"
|
||||
value={selectAllValue}
|
||||
onChange={handleSelectAllChange}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
<Button onPress={onModalClose}>{translate('Cancel')}</Button>
|
||||
|
||||
<Button kind={kinds.PRIMARY} onPress={handleOrganizePress}>
|
||||
{translate('Organize')}
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
);
|
||||
}
|
||||
|
||||
export default OrganizePreviewModalContent;
|
@ -1,91 +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 { executeCommand } from 'Store/Actions/commandActions';
|
||||
import { fetchOrganizePreview } from 'Store/Actions/organizePreviewActions';
|
||||
import { fetchNamingSettings } from 'Store/Actions/settingsActions';
|
||||
import createSeriesSelector from 'Store/Selectors/createSeriesSelector';
|
||||
import OrganizePreviewModalContent from './OrganizePreviewModalContent';
|
||||
|
||||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
(state) => state.organizePreview,
|
||||
(state) => state.settings.naming,
|
||||
createSeriesSelector(),
|
||||
(organizePreview, naming, series) => {
|
||||
const props = { ...organizePreview };
|
||||
props.isFetching = organizePreview.isFetching || naming.isFetching;
|
||||
props.isPopulated = organizePreview.isPopulated && naming.isPopulated;
|
||||
props.error = organizePreview.error || naming.error;
|
||||
props.renameEpisodes = naming.item.renameEpisodes;
|
||||
props.episodeFormat = naming.item[`${series.seriesType}EpisodeFormat`];
|
||||
props.path = series.path;
|
||||
|
||||
return props;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
const mapDispatchToProps = {
|
||||
fetchOrganizePreview,
|
||||
fetchNamingSettings,
|
||||
executeCommand
|
||||
};
|
||||
|
||||
class OrganizePreviewModalContentConnector extends Component {
|
||||
|
||||
//
|
||||
// Lifecycle
|
||||
|
||||
componentDidMount() {
|
||||
const {
|
||||
seriesId,
|
||||
seasonNumber
|
||||
} = this.props;
|
||||
|
||||
this.props.fetchOrganizePreview({
|
||||
seriesId,
|
||||
seasonNumber
|
||||
});
|
||||
|
||||
this.props.fetchNamingSettings();
|
||||
}
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
||||
onOrganizePress = (files) => {
|
||||
this.props.executeCommand({
|
||||
name: commandNames.RENAME_FILES,
|
||||
seriesId: this.props.seriesId,
|
||||
files
|
||||
});
|
||||
|
||||
this.props.onModalClose();
|
||||
};
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
return (
|
||||
<OrganizePreviewModalContent
|
||||
{...this.props}
|
||||
onOrganizePress={this.onOrganizePress}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
OrganizePreviewModalContentConnector.propTypes = {
|
||||
seriesId: PropTypes.number.isRequired,
|
||||
seasonNumber: PropTypes.number,
|
||||
fetchOrganizePreview: PropTypes.func.isRequired,
|
||||
fetchNamingSettings: PropTypes.func.isRequired,
|
||||
executeCommand: PropTypes.func.isRequired,
|
||||
onModalClose: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default connect(createMapStateToProps, mapDispatchToProps)(OrganizePreviewModalContentConnector);
|
@ -1,90 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import CheckInput from 'Components/Form/CheckInput';
|
||||
import Icon from 'Components/Icon';
|
||||
import { icons, kinds } from 'Helpers/Props';
|
||||
import styles from './OrganizePreviewRow.css';
|
||||
|
||||
class OrganizePreviewRow extends Component {
|
||||
|
||||
//
|
||||
// Lifecycle
|
||||
|
||||
componentDidMount() {
|
||||
const {
|
||||
id,
|
||||
onSelectedChange
|
||||
} = this.props;
|
||||
|
||||
onSelectedChange({ id, value: true });
|
||||
}
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
||||
onSelectedChange = ({ value, shiftKey }) => {
|
||||
const {
|
||||
id,
|
||||
onSelectedChange
|
||||
} = this.props;
|
||||
|
||||
onSelectedChange({ id, value, shiftKey });
|
||||
};
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
const {
|
||||
id,
|
||||
existingPath,
|
||||
newPath,
|
||||
isSelected
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<div className={styles.row}>
|
||||
<CheckInput
|
||||
containerClassName={styles.selectedContainer}
|
||||
name={id.toString()}
|
||||
value={isSelected}
|
||||
onChange={this.onSelectedChange}
|
||||
/>
|
||||
|
||||
<div>
|
||||
<div>
|
||||
<Icon
|
||||
name={icons.SUBTRACT}
|
||||
kind={kinds.DANGER}
|
||||
/>
|
||||
|
||||
<span className={styles.path}>
|
||||
{existingPath}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Icon
|
||||
name={icons.ADD}
|
||||
kind={kinds.SUCCESS}
|
||||
/>
|
||||
|
||||
<span className={styles.path}>
|
||||
{newPath}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
OrganizePreviewRow.propTypes = {
|
||||
id: PropTypes.number.isRequired,
|
||||
existingPath: PropTypes.string.isRequired,
|
||||
newPath: PropTypes.string.isRequired,
|
||||
isSelected: PropTypes.bool,
|
||||
onSelectedChange: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default OrganizePreviewRow;
|
@ -0,0 +1,61 @@
|
||||
import React, { useCallback, useEffect } from 'react';
|
||||
import CheckInput from 'Components/Form/CheckInput';
|
||||
import Icon from 'Components/Icon';
|
||||
import { icons, kinds } from 'Helpers/Props';
|
||||
import { CheckInputChanged } from 'typings/inputs';
|
||||
import { SelectStateInputProps } from 'typings/props';
|
||||
import styles from './OrganizePreviewRow.css';
|
||||
|
||||
interface OrganizePreviewRowProps {
|
||||
id: number;
|
||||
existingPath: string;
|
||||
newPath: string;
|
||||
isSelected?: boolean;
|
||||
onSelectedChange: (props: SelectStateInputProps) => void;
|
||||
}
|
||||
|
||||
function OrganizePreviewRow({
|
||||
id,
|
||||
existingPath,
|
||||
newPath,
|
||||
isSelected,
|
||||
onSelectedChange,
|
||||
}: OrganizePreviewRowProps) {
|
||||
const handleSelectedChange = useCallback(
|
||||
({ value, shiftKey }: CheckInputChanged) => {
|
||||
onSelectedChange({ id, value, shiftKey });
|
||||
},
|
||||
[id, onSelectedChange]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
onSelectedChange({ id, value: true, shiftKey: false });
|
||||
}, [id, onSelectedChange]);
|
||||
|
||||
return (
|
||||
<div className={styles.row}>
|
||||
<CheckInput
|
||||
containerClassName={styles.selectedContainer}
|
||||
name={id.toString()}
|
||||
value={isSelected}
|
||||
onChange={handleSelectedChange}
|
||||
/>
|
||||
|
||||
<div>
|
||||
<div>
|
||||
<Icon name={icons.SUBTRACT} kind={kinds.DANGER} />
|
||||
|
||||
<span className={styles.path}>{existingPath}</span>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Icon name={icons.ADD} kind={kinds.SUCCESS} />
|
||||
|
||||
<span className={styles.path}>{newPath}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default OrganizePreviewRow;
|
Loading…
Reference in new issue