cspace-ui
Version:
CollectionSpace user interface for browsers
200 lines (168 loc) • 5.43 kB
JSX
import React, { useEffect, useMemo } from 'react';
import PropTypes from 'prop-types';
import Immutable from 'immutable';
import { useSelector, useDispatch } from 'react-redux';
import { defineMessages, FormattedMessage } from 'react-intl';
import { baseComponents as inputBaseComponents, components as inputComponents } from 'cspace-input';
import {
moveFieldValue,
saveRecord,
setFieldValue,
} from '../../actions/record';
import {
getRecordData,
getRecordRelationUpdatedTimestamp,
getSearchResult,
} from '../../reducers';
import { MEDIA_SNAPSHOT_PANEL_SEARCH_NAME } from '../../constants/searchNames';
import { readListItems } from '../search/searchResultHelpers';
import { ConnectedPanel as Panel } from '../../containers/layout/PanelContainer';
import { getSearchDescriptor, mediaPriorityPath } from './MediaSnapshotPanel';
import MediaPriorityRow from './MediaPriorityRow';
import styles from '../../../styles/cspace-ui/MediaPriorityOrderPanel.css';
const { MiniButton } = inputBaseComponents;
const { RepeatingInput } = inputComponents;
const listType = 'common';
const parentDataPath = mediaPriorityPath.slice(0, -1);
const messages = defineMessages({
title: {
id: 'mediaPriorityOrderPanel.title',
defaultMessage: 'Media Priority',
},
titleWithCount: {
id: 'mediaPriorityOrderPanel.titleWithCount',
defaultMessage: '{title}: {count, number}',
},
});
const propTypes = {
color: PropTypes.string,
config: PropTypes.shape({
listTypes: PropTypes.object,
recordTypes: PropTypes.object,
mediaSnapshotSort: PropTypes.string,
}),
csid: PropTypes.string,
recordType: PropTypes.string,
};
const toRefNameArray = (value) => {
if (!value) return [];
if (Immutable.List.isList(value)) return value.toArray();
return [value];
};
export default function MediaPriorityOrderPanel(props) {
const {
color,
config,
csid,
recordType,
} = props;
const dispatch = useDispatch();
const seqID = useSelector(
(state) => getRecordRelationUpdatedTimestamp(state, csid),
);
const searchDescriptor = useMemo(
() => getSearchDescriptor({
csid,
mediaRecordType: 'media',
recordRelationUpdatedTimestamp: seqID,
recordType,
sort: config.mediaSnapshotSort || 'title',
}),
[config.mediaSnapshotSort, csid, recordType, seqID],
);
const storedValue = useSelector(
(state) => getRecordData(state, csid)?.getIn(mediaPriorityPath),
);
const searchResult = useSelector(
(state) => getSearchResult(state, MEDIA_SNAPSHOT_PANEL_SEARCH_NAME, searchDescriptor),
);
const recordTypeConfig = config.recordTypes[recordType];
const onCommit = (path, value) => dispatch(setFieldValue(recordTypeConfig, csid, path, value));
const onMoveInstance = (path, newPosition) => dispatch(
moveFieldValue(recordTypeConfig, csid, path, newPosition),
);
const save = () => dispatch(saveRecord(config, recordTypeConfig, undefined, csid))
.catch(() => {});
const { labelsByRefName, searchLoaded } = useMemo(() => {
const { list, items } = readListItems(config, listType, searchResult);
const labels = new Map();
if (items) {
items.forEach((item) => {
const refName = item.get('refName');
if (refName) {
const label = [item.get('identificationNumber'), item.get('title')]
.filter((part) => !!part)
.join(' – ');
labels.set(refName, label);
}
});
}
return {
labelsByRefName: labels,
searchLoaded: list?.get('totalItems') != null,
};
}, [config, searchResult]);
const mergedValue = useMemo(() => {
if (!searchLoaded) return null;
const orderedRefNames = toRefNameArray(storedValue)
.filter((refName) => labelsByRefName.has(refName));
const orderedSet = new Set(orderedRefNames);
labelsByRefName.forEach((label, refName) => {
if (!orderedSet.has(refName)) orderedRefNames.push(refName);
});
return Immutable.List(orderedRefNames);
}, [labelsByRefName, searchLoaded, storedValue]);
useEffect(() => {
if (mergedValue && !mergedValue.equals(Immutable.List(toRefNameArray(storedValue)))) {
onCommit(mediaPriorityPath, mergedValue);
}
}, [mergedValue]);
if (!mergedValue) return null;
const saveButton = (
<MiniButton
autoWidth
key="save"
name="save"
onClick={save}
>
Save
</MiniButton>
);
const title = <FormattedMessage {...messages.title} />;
const header = (
<h3>
{
mergedValue.size === 0
? <FormattedMessage {...messages.titleWithCount} values={{ title, count: 0 }} />
: title
}
</h3>
);
return (
<Panel
buttons={mergedValue.size > 0 ? [saveButton] : []}
color={color}
collapsible
collapsed
config={config}
header={header}
name="mediaPriorityPanel"
recordType={recordType}
>
<div className={styles.panel}>
{mergedValue.size > 0 && (
<RepeatingInput
name="mediaPriority"
parentPath={parentDataPath}
value={mergedValue}
onCommit={onCommit}
onMoveInstance={onMoveInstance}
>
<MediaPriorityRow labelsByRefName={labelsByRefName} />
</RepeatingInput>
)}
</div>
</Panel>
);
}
MediaPriorityOrderPanel.propTypes = propTypes;