2022-10-26 16:01:19 -04:00

297 lines
7.7 KiB
TypeScript

import { styled } from '@mui/material/styles';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { translate } from 'react-polyglot';
import { connect } from 'react-redux';
import {
changeViewStyle as changeViewStyleAction,
filterByField as filterByFieldAction,
groupByField as groupByFieldAction,
sortByField as sortByFieldAction,
} from '../../actions/entries';
import { components } from '../../components/UI/styles';
import { SortDirection } from '../../interface';
import { getNewEntryUrl } from '../../lib/urlHelper';
import {
selectSortableFields,
selectViewFilters,
selectViewGroups,
} from '../../lib/util/collection.util';
import {
selectEntriesFilter,
selectEntriesGroup,
selectEntriesSort,
selectViewStyle,
} from '../../reducers/entries';
import CollectionControls from './CollectionControls';
import CollectionTop from './CollectionTop';
import EntriesCollection from './Entries/EntriesCollection';
import EntriesSearch from './Entries/EntriesSearch';
import Sidebar from './Sidebar';
import type { ComponentType } from 'react';
import type { ConnectedProps } from 'react-redux';
import type { Collection, TranslatedProps, ViewFilter, ViewGroup } from '../../interface';
import type { RootState } from '../../store';
const CollectionMain = styled('main')`
width: 100%;
`;
const SearchResultContainer = styled('div')`
${components.cardTop};
margin-bottom: 22px;
`;
const SearchResultHeading = styled('h1')`
${components.cardTopHeading};
`;
const CollectionView = ({
collection,
collections,
collectionName,
isSearchEnabled,
isSearchResults,
isSingleSearchResult,
searchTerm,
sortableFields,
sortByField,
sort,
viewFilters,
viewGroups,
filterTerm,
t,
filterByField,
groupByField,
filter,
group,
changeViewStyle,
viewStyle,
}: TranslatedProps<CollectionViewProps>) => {
const [readyToLoad, setReadyToLoad] = useState(false);
const [prevCollection, setPrevCollection] = useState<Collection | null>();
useEffect(() => {
setPrevCollection(collection);
}, [collection]);
const newEntryUrl = useMemo(() => {
let url = collection.create ? getNewEntryUrl(collectionName) : '';
if (url && filterTerm) {
url = getNewEntryUrl(collectionName);
if (filterTerm) {
url = `${newEntryUrl}?path=${filterTerm}`;
}
}
return url;
}, [collection, collectionName, filterTerm]);
const searchResultKey = useMemo(
() => `collection.collectionTop.searchResults${isSingleSearchResult ? 'InCollection' : ''}`,
[isSingleSearchResult],
);
const entries = useMemo(() => {
if (isSearchResults) {
let searchCollections = collections;
if (isSingleSearchResult) {
const searchCollection = Object.values(collections).filter(c => c === collection);
if (searchCollection.length === 1) {
searchCollections = {
[searchCollection[0].name]: searchCollection[0],
};
}
}
return <EntriesSearch collections={searchCollections} searchTerm={searchTerm} />;
}
return (
<EntriesCollection
collection={collection}
viewStyle={viewStyle}
filterTerm={filterTerm}
readyToLoad={readyToLoad && collection === prevCollection}
/>
);
}, [
collection,
collections,
filterTerm,
isSearchResults,
isSingleSearchResult,
prevCollection,
readyToLoad,
searchTerm,
viewStyle,
]);
const onSortClick = useCallback(
async (key: string, direction?: SortDirection) => {
await sortByField(collection, key, direction);
},
[collection, sortByField],
);
const onFilterClick = useCallback(
async (filter: ViewFilter) => {
await filterByField(collection, filter);
},
[collection, filterByField],
);
const onGroupClick = useCallback(
async (group: ViewGroup) => {
await groupByField(collection, group);
},
[collection, groupByField],
);
useEffect(() => {
if (prevCollection === collection) {
if (!readyToLoad) {
setReadyToLoad(true);
}
return;
}
if (sort?.[0]?.key) {
if (!readyToLoad) {
setReadyToLoad(true);
}
return;
}
const defaultSort = collection.sortable_fields.default;
if (!defaultSort || !defaultSort.field) {
if (!readyToLoad) {
setReadyToLoad(true);
}
return;
}
setReadyToLoad(false);
let alive = true;
const sortEntries = () => {
setTimeout(async () => {
await onSortClick(defaultSort.field, defaultSort.direction ?? SortDirection.Ascending);
if (alive) {
setReadyToLoad(true);
}
});
};
sortEntries();
return () => {
alive = false;
};
}, [collection, onSortClick, prevCollection, readyToLoad, sort]);
return (
<>
<Sidebar
collections={collections}
collection={(!isSearchResults || isSingleSearchResult) && collection}
isSearchEnabled={isSearchEnabled}
searchTerm={searchTerm}
filterTerm={filterTerm}
/>
<CollectionMain>
<>
{isSearchResults ? (
<SearchResultContainer>
<SearchResultHeading>
{t(searchResultKey, { searchTerm, collection: collection.label })}
</SearchResultHeading>
</SearchResultContainer>
) : (
<>
<CollectionTop collection={collection} newEntryUrl={newEntryUrl} />
<CollectionControls
viewStyle={viewStyle}
onChangeViewStyle={changeViewStyle}
sortableFields={sortableFields}
onSortClick={onSortClick}
sort={sort}
viewFilters={viewFilters}
viewGroups={viewGroups}
t={t}
onFilterClick={onFilterClick}
onGroupClick={onGroupClick}
filter={filter}
group={group}
/>
</>
)}
{entries}
</>
</CollectionMain>
</>
);
};
interface CollectionViewOwnProps {
isSearchResults?: boolean;
isSingleSearchResult?: boolean;
name: string;
searchTerm?: string;
filterTerm?: string;
}
function mapStateToProps(state: RootState, ownProps: TranslatedProps<CollectionViewOwnProps>) {
const { collections } = state;
const isSearchEnabled = state.config.config && state.config.config.search != false;
const {
isSearchResults,
isSingleSearchResult,
name,
searchTerm = '',
filterTerm = '',
t,
} = ownProps;
const collection: Collection = name ? collections[name] : collections[0];
const sort = selectEntriesSort(state.entries, collection.name);
const sortableFields = selectSortableFields(collection, t);
const viewFilters = selectViewFilters(collection);
const viewGroups = selectViewGroups(collection);
const filter = selectEntriesFilter(state.entries, collection.name);
const group = selectEntriesGroup(state.entries, collection.name);
const viewStyle = selectViewStyle(state.entries);
return {
isSearchResults,
isSingleSearchResult,
name,
searchTerm,
filterTerm,
collection,
collections,
collectionName: name,
isSearchEnabled,
sort,
sortableFields,
viewFilters,
viewGroups,
filter,
group,
viewStyle,
};
}
const mapDispatchToProps = {
sortByField: sortByFieldAction,
filterByField: filterByFieldAction,
changeViewStyle: changeViewStyleAction,
groupByField: groupByFieldAction,
};
const connector = connect(mapStateToProps, mapDispatchToProps);
export type CollectionViewProps = ConnectedProps<typeof connector>;
export default translate()(connector(CollectionView)) as ComponentType<CollectionViewOwnProps>;