[Glitch] Mark pending accounts on the collection detail page

Port b193913f462702981d20d4a58249a1bceaf3b974 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
This commit is contained in:
diondiondion 2026-04-28 18:31:18 +02:00 committed by Claire
parent 57ed939d00
commit 1e7c8912d6
3 changed files with 52 additions and 16 deletions

View File

@ -87,7 +87,7 @@
} }
.variantSubtle { .variantSubtle {
border: 1px solid var(--color-bg-brand-softest); border: 1px solid var(--color-border-brand-soft);
background-color: var(--color-bg-primary); background-color: var(--color-bg-primary);
.icon { .icon {

View File

@ -2,8 +2,12 @@ import { useCallback, useMemo, useRef, useState } from 'react';
import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import { PendingBadge } from '@/flavours/glitch/components/badge';
import VisibilityOffIcon from '@/material-icons/400-24px/visibility_off.svg?react'; import VisibilityOffIcon from '@/material-icons/400-24px/visibility_off.svg?react';
import type { ApiCollectionJSON } from 'flavours/glitch/api_types/collections'; import type {
ApiCollectionJSON,
CollectionAccountItem,
} from 'flavours/glitch/api_types/collections';
import type { RenderButtonOptions } from 'flavours/glitch/components/account_list_item'; import type { RenderButtonOptions } from 'flavours/glitch/components/account_list_item';
import { import {
AccountListItem, AccountListItem,
@ -75,15 +79,22 @@ const SensitiveScreen: React.FC<{
); );
}; };
const getCollectionAccounts = createAppSelector( type CollectionItemWithAccount = CollectionAccountItem & {
account?: Account | null;
};
const getCollectionItems = createAppSelector(
[ [
(state) => state.accounts, (state) => state.accounts,
(state, collectionId?: string) => (state, collectionId?: string) =>
state.collections.collections[collectionId ?? '']?.items, state.collections.collections[collectionId ?? '']?.items,
], ],
(accounts, collectionAccountItems) => (accounts, collectionAccountItems) =>
(collectionAccountItems ?? []).map(({ account_id }) => (collectionAccountItems ?? []).map(
account_id ? accounts.get(account_id) : null, (item): CollectionItemWithAccount => ({
...item,
account: item.account_id ? accounts.get(item.account_id) : null,
}),
), ),
); );
@ -100,22 +111,22 @@ export const CollectionAccountsList: React.FC<{
const relationships = useAppSelector((state) => state.relationships); const relationships = useAppSelector((state) => state.relationships);
const collectionAccounts = useAppSelector((state) => const collectionAccounts = useAppSelector((state) =>
getCollectionAccounts(state, id), getCollectionItems(state, id),
); );
const { visibleAccounts, hiddenAccounts } = useMemo(() => { const { visibleAccounts, hiddenAccounts } = useMemo(() => {
const visibleAccounts: Account[] = []; const visibleAccounts: CollectionItemWithAccount[] = [];
const hiddenAccounts: Account[] = []; const hiddenAccounts: CollectionItemWithAccount[] = [];
collectionAccounts.forEach((item) => { collectionAccounts.forEach((item) => {
if (!item) { const { account, account_id } = item;
// We currently simply hide unavailable accounts, this includes
// accounts that are pending inclusion; at least for the collection if (!isOwnCollection && !account) {
// owner we should display an indication of pending users // Hide unavailable accounts unless you own this collection
return; return;
} }
const relationship = relationships.get(item.id); const relationship = account_id ? relationships.get(account_id) : null;
if (relationship?.blocking || relationship?.muting) { if (relationship?.blocking || relationship?.muting) {
hiddenAccounts.push(item); hiddenAccounts.push(item);
} else { } else {
@ -124,7 +135,7 @@ export const CollectionAccountsList: React.FC<{
}); });
return { visibleAccounts, hiddenAccounts }; return { visibleAccounts, hiddenAccounts };
}, [collectionAccounts, relationships]); }, [collectionAccounts, isOwnCollection, relationships]);
const renderAccountItemButton = useCallback( const renderAccountItemButton = useCallback(
({ relationship, accountId }: RenderButtonOptions) => { ({ relationship, accountId }: RenderButtonOptions) => {
@ -159,15 +170,16 @@ export const CollectionAccountsList: React.FC<{
index, index,
totalListLength, totalListLength,
isLastElement, isLastElement,
}: TruncatedListItemInfo<Account>) => ( }: TruncatedListItemInfo<CollectionItemWithAccount>) => (
<Article <Article
key={item.id} key={item.id}
aria-posinset={index + 1} aria-posinset={index + 1}
aria-setsize={totalListLength} aria-setsize={totalListLength}
> >
<AccountListItem <AccountListItem
accountId={item.id} accountId={item.account_id}
withBorder={!isLastElement} withBorder={!isLastElement}
badge={item.state === 'pending' ? <PendingBadge /> : null}
renderButton={renderAccountItemButton} renderButton={renderAccountItemButton}
/> />
</Article> </Article>

View File

@ -8,6 +8,7 @@ import { Link } from 'react-router-dom';
import { openModal } from '@/flavours/glitch/actions/modal'; import { openModal } from '@/flavours/glitch/actions/modal';
import { useAccountHandle } from '@/flavours/glitch/components/display_name/default'; import { useAccountHandle } from '@/flavours/glitch/components/display_name/default';
import HelpIcon from '@/material-icons/400-24px/help.svg?react';
import ListAltIcon from '@/material-icons/400-24px/list_alt.svg?react'; import ListAltIcon from '@/material-icons/400-24px/list_alt.svg?react';
import ShareIcon from '@/material-icons/400-24px/share.svg?react'; import ShareIcon from '@/material-icons/400-24px/share.svg?react';
import type { ApiCollectionJSON } from 'flavours/glitch/api_types/collections'; import type { ApiCollectionJSON } from 'flavours/glitch/api_types/collections';
@ -101,6 +102,26 @@ const RevokeControls: React.FC<{
); );
}; };
const PendingNote: React.FC = () => {
return (
<Callout
variant='subtle'
icon={HelpIcon}
title={
<FormattedMessage
id='collections.pending_accounts.title'
defaultMessage='Why am I seeing pending accounts?'
/>
}
>
<FormattedMessage
id='collections.pending_accounts.message'
defaultMessage='Accounts may appear as pending when were awaiting a response from the user or their server. Only you can see pending accounts.'
/>
</Callout>
);
};
const CollectionHeader: React.FC<{ collection: ApiCollectionJSON }> = ({ const CollectionHeader: React.FC<{ collection: ApiCollectionJSON }> = ({
collection, collection,
}) => { }) => {
@ -136,6 +157,8 @@ const CollectionHeader: React.FC<{ collection: ApiCollectionJSON }> = ({
} }
}, [history, openShareModal, isNewCollection, location.pathname]); }, [history, openShareModal, isNewCollection, location.pathname]);
const hasPendingAccounts = items.some((item) => item.state === 'pending');
return ( return (
<header className={classes.header}> <header className={classes.header}>
<div className={classes.titleWithMenu}> <div className={classes.titleWithMenu}>
@ -160,6 +183,7 @@ const CollectionHeader: React.FC<{ collection: ApiCollectionJSON }> = ({
</div> </div>
</div> </div>
{description && <p className={classes.description}>{description}</p>} {description && <p className={classes.description}>{description}</p>}
{hasPendingAccounts && <PendingNote />}
{isCurrentUserInCollection && <RevokeControls collection={collection} />} {isCurrentUserInCollection && <RevokeControls collection={collection} />}
</header> </header>
); );