[Glitch] Allow hiding featured tab from empty state
Port 19ef4e5c40818278156f9be9a4fd76d18cd44822 to glitch-soc Signed-off-by: Claire <claire.github-309c@sitedethib.com>
This commit is contained in:
parent
f84df36bd1
commit
c2fe62be6c
@ -1,13 +1,18 @@
|
|||||||
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
import { useParams } from 'react-router';
|
import { useParams } from 'react-router';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
|
import { openModal } from '@/flavours/glitch/actions/modal';
|
||||||
|
import { Button } from '@/flavours/glitch/components/button';
|
||||||
import { EmptyState } from '@/flavours/glitch/components/empty_state';
|
import { EmptyState } from '@/flavours/glitch/components/empty_state';
|
||||||
import { LimitedAccountHint } from '@/flavours/glitch/features/account_timeline/components/limited_account_hint';
|
import { LimitedAccountHint } from '@/flavours/glitch/features/account_timeline/components/limited_account_hint';
|
||||||
import { areCollectionsEnabled } from '@/flavours/glitch/features/collections/utils';
|
import { areCollectionsEnabled } from '@/flavours/glitch/features/collections/utils';
|
||||||
import { useCurrentAccountId } from '@/flavours/glitch/hooks/useAccountId';
|
import { useCurrentAccountId } from '@/flavours/glitch/hooks/useAccountId';
|
||||||
import { useTheme } from '@/flavours/glitch/hooks/useTheme';
|
import { useTheme } from '@/flavours/glitch/hooks/useTheme';
|
||||||
|
import { useAppDispatch } from '@/flavours/glitch/store';
|
||||||
import ElephantDarkImage from '@/images/elephant_ui_dark.svg?react';
|
import ElephantDarkImage from '@/images/elephant_ui_dark.svg?react';
|
||||||
import ElephantLightImage from '@/images/elephant_ui_light.svg?react';
|
import ElephantLightImage from '@/images/elephant_ui_light.svg?react';
|
||||||
|
|
||||||
@ -16,6 +21,7 @@ interface EmptyMessageProps {
|
|||||||
hidden: boolean;
|
hidden: boolean;
|
||||||
blockedBy: boolean;
|
blockedBy: boolean;
|
||||||
accountId?: string;
|
accountId?: string;
|
||||||
|
withImage?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const EmptyMessage: React.FC<EmptyMessageProps> = ({
|
export const EmptyMessage: React.FC<EmptyMessageProps> = ({
|
||||||
@ -23,6 +29,7 @@ export const EmptyMessage: React.FC<EmptyMessageProps> = ({
|
|||||||
suspended,
|
suspended,
|
||||||
hidden,
|
hidden,
|
||||||
blockedBy,
|
blockedBy,
|
||||||
|
withImage = true,
|
||||||
}) => {
|
}) => {
|
||||||
const { acct } = useParams<{ acct?: string }>();
|
const { acct } = useParams<{ acct?: string }>();
|
||||||
const me = useCurrentAccountId();
|
const me = useCurrentAccountId();
|
||||||
@ -30,6 +37,17 @@ export const EmptyMessage: React.FC<EmptyMessageProps> = ({
|
|||||||
const ElephantImage =
|
const ElephantImage =
|
||||||
theme === 'dark' ? ElephantDarkImage : ElephantLightImage;
|
theme === 'dark' ? ElephantDarkImage : ElephantLightImage;
|
||||||
|
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
|
const confirmHideFeaturedTab = useCallback(() => {
|
||||||
|
void dispatch(
|
||||||
|
openModal({
|
||||||
|
modalType: 'ACCOUNT_HIDE_FEATURED_TAB',
|
||||||
|
modalProps: {},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}, [dispatch]);
|
||||||
|
|
||||||
if (!accountId) {
|
if (!accountId) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -39,7 +57,7 @@ export const EmptyMessage: React.FC<EmptyMessageProps> = ({
|
|||||||
|
|
||||||
const hasCollections = areCollectionsEnabled();
|
const hasCollections = areCollectionsEnabled();
|
||||||
|
|
||||||
const image = <ElephantImage />;
|
const image = withImage && <ElephantImage />;
|
||||||
|
|
||||||
if (me === accountId) {
|
if (me === accountId) {
|
||||||
if (hasCollections) {
|
if (hasCollections) {
|
||||||
@ -66,6 +84,12 @@ export const EmptyMessage: React.FC<EmptyMessageProps> = ({
|
|||||||
defaultMessage='Create a collection'
|
defaultMessage='Create a collection'
|
||||||
/>
|
/>
|
||||||
</Link>
|
</Link>
|
||||||
|
<Button secondary onClick={confirmHideFeaturedTab}>
|
||||||
|
<FormattedMessage
|
||||||
|
id='empty_column.account_featured_self.no_collections_hide_tab'
|
||||||
|
defaultMessage='Hide this tab instead'
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
</EmptyState>
|
</EmptyState>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -35,6 +35,8 @@ import { areCollectionsEnabled } from '../collections/utils';
|
|||||||
import { EmptyMessage } from './components/empty_message';
|
import { EmptyMessage } from './components/empty_message';
|
||||||
import { Subheading, SubheadingLink } from './components/subheading';
|
import { Subheading, SubheadingLink } from './components/subheading';
|
||||||
|
|
||||||
|
const collectionsEnabled = areCollectionsEnabled();
|
||||||
|
|
||||||
const AccountFeatured: React.FC<{ multiColumn: boolean }> = ({
|
const AccountFeatured: React.FC<{ multiColumn: boolean }> = ({
|
||||||
multiColumn,
|
multiColumn,
|
||||||
}) => {
|
}) => {
|
||||||
@ -56,13 +58,12 @@ const AccountFeatured: React.FC<{ multiColumn: boolean }> = ({
|
|||||||
if (accountId) {
|
if (accountId) {
|
||||||
void dispatch(fetchEndorsedAccounts({ accountId }));
|
void dispatch(fetchEndorsedAccounts({ accountId }));
|
||||||
|
|
||||||
if (areCollectionsEnabled()) {
|
if (collectionsEnabled) {
|
||||||
void dispatch(fetchAccountCollections({ accountId }));
|
void dispatch(fetchAccountCollections({ accountId }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [accountId, dispatch]);
|
}, [accountId, dispatch]);
|
||||||
|
|
||||||
const isLoading = !accountId;
|
|
||||||
const featuredAccountIds = useAppSelector(
|
const featuredAccountIds = useAppSelector(
|
||||||
(state) =>
|
(state) =>
|
||||||
state.user_lists.getIn(
|
state.user_lists.getIn(
|
||||||
@ -70,8 +71,8 @@ const AccountFeatured: React.FC<{ multiColumn: boolean }> = ({
|
|||||||
ImmutableList(),
|
ImmutableList(),
|
||||||
) as ImmutableList<string>,
|
) as ImmutableList<string>,
|
||||||
);
|
);
|
||||||
const { collections, status } = useAppSelector((state) =>
|
const { collections, status: collectionsLoadStatus } = useAppSelector(
|
||||||
selectAccountCollections(state, accountId ?? null),
|
(state) => selectAccountCollections(state, accountId ?? null),
|
||||||
);
|
);
|
||||||
const listedCollections = collections.filter(
|
const listedCollections = collections.filter(
|
||||||
// Hide unlisted and empty collections to avoid confusion
|
// Hide unlisted and empty collections to avoid confusion
|
||||||
@ -80,6 +81,15 @@ const AccountFeatured: React.FC<{ multiColumn: boolean }> = ({
|
|||||||
(item) => item.discoverable && !!item.item_count,
|
(item) => item.discoverable && !!item.item_count,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const hasCollections =
|
||||||
|
collectionsEnabled &&
|
||||||
|
collectionsLoadStatus === 'idle' &&
|
||||||
|
listedCollections.length > 0;
|
||||||
|
|
||||||
|
const hasFeaturedAccounts = !featuredAccountIds.isEmpty();
|
||||||
|
|
||||||
|
const isLoading = !accountId || collectionsLoadStatus !== 'idle';
|
||||||
|
|
||||||
if (accountId === null) {
|
if (accountId === null) {
|
||||||
return <BundleColumnError multiColumn={multiColumn} errorType='routing' />;
|
return <BundleColumnError multiColumn={multiColumn} errorType='routing' />;
|
||||||
}
|
}
|
||||||
@ -94,7 +104,7 @@ const AccountFeatured: React.FC<{ multiColumn: boolean }> = ({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (featuredAccountIds.isEmpty() && listedCollections.length === 0) {
|
if (!hasFeaturedAccounts && !hasCollections) {
|
||||||
return (
|
return (
|
||||||
<AccountFeaturedWrapper accountId={accountId}>
|
<AccountFeaturedWrapper accountId={accountId}>
|
||||||
<EmptyMessage
|
<EmptyMessage
|
||||||
@ -138,7 +148,7 @@ const AccountFeatured: React.FC<{ multiColumn: boolean }> = ({
|
|||||||
</ItemList>
|
</ItemList>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{listedCollections.length > 0 && status === 'idle' && (
|
{collectionsEnabled && (
|
||||||
<>
|
<>
|
||||||
<Subheading as='header'>
|
<Subheading as='header'>
|
||||||
<h2>
|
<h2>
|
||||||
@ -154,18 +164,28 @@ const AccountFeatured: React.FC<{ multiColumn: boolean }> = ({
|
|||||||
/>
|
/>
|
||||||
</SubheadingLink>
|
</SubheadingLink>
|
||||||
</Subheading>
|
</Subheading>
|
||||||
<ItemList>
|
{hasCollections ? (
|
||||||
{listedCollections.map((item, index) => (
|
<ItemList>
|
||||||
<CollectionListItem
|
{listedCollections.map((item, index) => (
|
||||||
key={item.id}
|
<CollectionListItem
|
||||||
collection={item}
|
key={item.id}
|
||||||
withoutBorder={index === listedCollections.length - 1}
|
collection={item}
|
||||||
withAuthorHandle={false}
|
withoutBorder={index === listedCollections.length - 1}
|
||||||
positionInList={index + 1}
|
withAuthorHandle={false}
|
||||||
listSize={listedCollections.length}
|
positionInList={index + 1}
|
||||||
/>
|
listSize={listedCollections.length}
|
||||||
))}
|
/>
|
||||||
</ItemList>
|
))}
|
||||||
|
</ItemList>
|
||||||
|
) : (
|
||||||
|
<EmptyMessage
|
||||||
|
withImage={false}
|
||||||
|
blockedBy={blockedBy}
|
||||||
|
hidden={hidden}
|
||||||
|
suspended={suspended}
|
||||||
|
accountId={accountId}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<RemoteHint accountId={accountId} />
|
<RemoteHint accountId={accountId} />
|
||||||
|
|||||||
@ -0,0 +1,73 @@
|
|||||||
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
|
import { defineMessages, useIntl } from 'react-intl';
|
||||||
|
|
||||||
|
import { useHistory } from 'react-router';
|
||||||
|
|
||||||
|
import { useAccount } from '@/flavours/glitch/hooks/useAccount';
|
||||||
|
import { useCurrentAccountId } from '@/flavours/glitch/hooks/useAccountId';
|
||||||
|
import { domain } from '@/flavours/glitch/initial_state';
|
||||||
|
import { patchProfile } from '@/flavours/glitch/reducers/slices/profile_edit';
|
||||||
|
import { useAppDispatch } from 'flavours/glitch/store';
|
||||||
|
|
||||||
|
import type { BaseConfirmationModalProps } from './confirmation_modal';
|
||||||
|
import { ConfirmationModal } from './confirmation_modal';
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
title: {
|
||||||
|
id: 'confirmations.hide_featured_tab.title',
|
||||||
|
defaultMessage: 'Hide "Featured" tab?',
|
||||||
|
},
|
||||||
|
intro: {
|
||||||
|
id: 'confirmations.hide_featured_tab.intro',
|
||||||
|
defaultMessage:
|
||||||
|
'You can change this at any time under <i>Edit profile > Profile tab settings</i>.',
|
||||||
|
},
|
||||||
|
message: {
|
||||||
|
id: 'confirmations.hide_featured_tab.message',
|
||||||
|
defaultMessage:
|
||||||
|
'This will hide the tab for users on {serverName} and other servers running the latest version of Mastodon. Other displays may vary.',
|
||||||
|
},
|
||||||
|
confirm: {
|
||||||
|
id: 'confirmations.hide_featured_tab.confirm',
|
||||||
|
defaultMessage: 'Hide tab',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const ConfirmHideFeaturedTabModal: React.FC<
|
||||||
|
BaseConfirmationModalProps
|
||||||
|
> = ({ onClose }) => {
|
||||||
|
const intl = useIntl();
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
const history = useHistory();
|
||||||
|
const currentAccountId = useCurrentAccountId();
|
||||||
|
const { acct: currentUserName } = useAccount(currentAccountId) ?? {};
|
||||||
|
|
||||||
|
const onConfirm = useCallback(() => {
|
||||||
|
void dispatch(patchProfile({ show_featured: false }));
|
||||||
|
history.push(`/@${currentUserName}`);
|
||||||
|
}, [currentUserName, dispatch, history]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ConfirmationModal
|
||||||
|
title={intl.formatMessage(messages.title)}
|
||||||
|
extraContent={
|
||||||
|
<div className='prose'>
|
||||||
|
<p>
|
||||||
|
{intl.formatMessage(messages.intro, {
|
||||||
|
i: (words) => <i>{words}</i>,
|
||||||
|
})}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
{intl.formatMessage(messages.message, {
|
||||||
|
serverName: domain,
|
||||||
|
})}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
confirm={intl.formatMessage(messages.confirm)}
|
||||||
|
onConfirm={onConfirm}
|
||||||
|
onClose={onClose}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -113,6 +113,7 @@ export const MODAL_COMPONENTS = {
|
|||||||
'ACCOUNT_EDIT_IMAGE_ALT': accountEditModal('ImageAltModal'),
|
'ACCOUNT_EDIT_IMAGE_ALT': accountEditModal('ImageAltModal'),
|
||||||
'ACCOUNT_EDIT_IMAGE_DELETE': accountEditModal('ImageDeleteModal'),
|
'ACCOUNT_EDIT_IMAGE_DELETE': accountEditModal('ImageDeleteModal'),
|
||||||
'ACCOUNT_EDIT_IMAGE_UPLOAD': accountEditModal('ImageUploadModal'),
|
'ACCOUNT_EDIT_IMAGE_UPLOAD': accountEditModal('ImageUploadModal'),
|
||||||
|
'ACCOUNT_HIDE_FEATURED_TAB': () => import('@/flavours/glitch/features/ui/components/confirmation_modals/hide_featured_tab').then(module => ({ default: module.ConfirmHideFeaturedTabModal })),
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @arg {keyof import('@/flavours/glitch/features/account_edit/modals')} type */
|
/** @arg {keyof import('@/flavours/glitch/features/account_edit/modals')} type */
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user