182 lines
5.2 KiB
TypeScript

import { useEffect } from 'react';
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import {
Switch,
Route,
useParams,
useRouteMatch,
matchPath,
useLocation,
} from 'react-router-dom';
import { Helmet } from '@unhead/react/helmet';
import ListAltIcon from '@/material-icons/400-24px/list_alt.svg?react';
import { Callout } from 'mastodon/components/callout';
import { Column } from 'mastodon/components/column';
import { ColumnHeader } from 'mastodon/components/column_header';
import { LoadingIndicator } from 'mastodon/components/loading_indicator';
import { NotSignedInIndicator } from 'mastodon/components/not_signed_in_indicator';
import { useIdentity } from 'mastodon/identity_context';
import { initialState } from 'mastodon/initial_state';
import {
collectionEditorActions,
fetchCollection,
} from 'mastodon/reducers/slices/collections';
import { useAppDispatch, useAppSelector } from 'mastodon/store';
import { useCollectionsCreatedBy } from '../overview/created_by_account';
import { CollectionAccounts } from './accounts';
import { CollectionDetails } from './details';
import classes from './styles.module.scss';
export const messages = defineMessages({
create: {
id: 'collections.create_collection',
defaultMessage: 'Create collection',
},
newCollection: {
id: 'collections.new_collection',
defaultMessage: 'New collection',
},
editDetails: {
id: 'collections.edit_details',
defaultMessage: 'Edit details',
},
manageAccounts: {
id: 'collections.manage_accounts',
defaultMessage: 'Manage accounts',
},
});
function usePageTitle(id: string | null) {
const { path } = useRouteMatch();
const location = useLocation();
if (!id) {
return messages.newCollection;
}
if (matchPath(location.pathname, { path, exact: true })) {
return messages.manageAccounts;
} else if (matchPath(location.pathname, { path: `${path}/details` })) {
return messages.editDetails;
} else {
throw new Error('No page title defined for route');
}
}
export const userCollectionLimit = initialState?.role?.collection_limit ?? 0;
export const CollectionEditorPage: React.FC<{
multiColumn?: boolean;
}> = ({ multiColumn }) => {
const intl = useIntl();
const dispatch = useAppDispatch();
const { accountId, signedIn } = useIdentity();
const { id = null } = useParams<{ id?: string }>();
const { path } = useRouteMatch();
const collection = useAppSelector((state) =>
id ? state.collections.collections[id] : undefined,
);
const editorStateId = useAppSelector((state) => state.collections.editor.id);
const isEditMode = !!id;
// When creating a new collection, we load the current account's collections
// to determine if they're allowed to create more.
const { collections: collectionList, status: collectionListStatus } =
useCollectionsCreatedBy(isEditMode ? null : accountId);
const isLoading =
(isEditMode && !collection) ||
(!isEditMode && collectionListStatus === 'loading');
const canCreateMoreCollections =
signedIn && (isEditMode || collectionList.length < userCollectionLimit);
useEffect(() => {
if (id && signedIn) {
void dispatch(fetchCollection({ collectionId: id }));
}
}, [dispatch, id, signedIn]);
useEffect(() => {
if (id !== editorStateId) {
void dispatch(collectionEditorActions.reset());
}
}, [dispatch, editorStateId, id]);
useEffect(() => {
if (collection) {
void dispatch(collectionEditorActions.init(collection));
}
}, [dispatch, collection]);
const pageTitle = intl.formatMessage(usePageTitle(id));
return (
<Column bindToDocument={!multiColumn} label={pageTitle}>
<ColumnHeader
title={pageTitle}
icon='list-ul'
iconComponent={ListAltIcon}
multiColumn={multiColumn}
showBackButton
/>
<div className='scrollable'>
{isLoading ? (
<LoadingIndicator />
) : !signedIn ? (
<NotSignedInIndicator />
) : canCreateMoreCollections ? (
<Switch>
<Route
exact
path={path}
// eslint-disable-next-line react/jsx-no-bind
render={() => <CollectionAccounts collection={collection} />}
/>
<Route
exact
path={`${path}/details`}
// eslint-disable-next-line react/jsx-no-bind
render={() => <CollectionDetails />}
/>
</Switch>
) : (
<MaxCollectionsCallout className={classes.maxCollectionsError} />
)}
</div>
<Helmet>
<title>{pageTitle}</title>
<meta name='robots' content='noindex' />
</Helmet>
</Column>
);
};
export const MaxCollectionsCallout: React.FC<{ className?: string }> = ({
className,
}) => (
<Callout
className={className}
title={
<FormattedMessage
id='collections.maximum_collection_count_reached'
defaultMessage='You have created the maximum number of collections'
/>
}
>
<FormattedMessage
id='collections.maximum_collection_count_description'
defaultMessage='Your server allows creation of up to {count} collections.'
values={{ count: userCollectionLimit }}
/>
</Callout>
);