nicolium: types

Signed-off-by: nicole mikołajczyk <git@mkljczk.pl>
This commit is contained in:
nicole mikołajczyk
2026-02-27 00:02:43 +01:00
parent ea06d6c61e
commit 7150879186
24 changed files with 106 additions and 112 deletions

View File

@ -185,7 +185,8 @@ const toggleStatusSensitivityModal =
(intl: IntlShape, statusId: string, sensitive: boolean, afterConfirm = () => {}) =>
(dispatch: AppDispatch, getState: () => RootState) => {
const state = getState();
const acct = state.statuses[statusId].account.acct;
const statusAccount = selectAccount(state.statuses[statusId].account_id);
const acct = statusAccount?.acct;
useModalsStore.getState().actions.openModal('CONFIRM', {
heading: intl.formatMessage(
@ -217,7 +218,8 @@ const deleteStatusModal =
(intl: IntlShape, statusId: string, afterConfirm = () => {}) =>
(dispatch: AppDispatch, getState: () => RootState) => {
const state = getState();
const acct = state.statuses[statusId].account.acct;
const statusAccount = selectAccount(state.statuses[statusId].account_id);
const acct = statusAccount?.acct;
useModalsStore.getState().actions.openModal('CONFIRM', {
heading: intl.formatMessage(messages.deleteStatusHeading),

View File

@ -127,7 +127,7 @@ interface TimelineDeleteAction {
const deleteFromTimelines =
(statusId: string) => (dispatch: AppDispatch, getState: () => RootState) => {
const accountId = getState().statuses[statusId]?.account?.id;
const accountId = getState().statuses[statusId]?.account_id;
const references: Array<[string, string]> = Object.entries(getState().statuses)
.filter(([key, status]) => [key, status.reblog_id === statusId])
.map(([key, status]) => [key, status.account_id]);

View File

@ -12,6 +12,7 @@ import Emojify from '@/features/emoji/emojify';
import EventActionButton from '@/features/event/components/event-action-button';
import EventDate from '@/features/event/components/event-date';
import { useAppSelector } from '@/hooks/use-app-selector';
import { useAccount } from '@/queries/accounts/use-account';
import type { NormalizedStatus as StatusEntity } from '@/reducers/statuses';
@ -26,7 +27,7 @@ const messages = defineMessages({
});
interface IEventPreview {
status: Pick<StatusEntity, 'id' | 'account' | 'event' | 'url'>;
status: Pick<StatusEntity, 'id' | 'account_id' | 'event' | 'url'>;
className?: string;
hideAction?: boolean;
floatingAction?: boolean;
@ -41,10 +42,12 @@ const EventPreview: React.FC<IEventPreview> = ({
const intl = useIntl();
const me = useAppSelector((state) => state.me);
const { data: account } = useAccount(status.account_id);
const account = status.account;
const event = status.event!;
if (!account) return null;
const banner = event.banner;
const action =

View File

@ -7,6 +7,7 @@ import Stack from '@/components/ui/stack';
import Emojify from '@/features/emoji/emojify';
import QuotedStatus from '@/features/status/containers/quoted-status-container';
import { useFrontendConfig } from '@/hooks/use-frontend-config';
import { useAccount } from '@/queries/accounts/use-account';
import { useLocalStatusTranslation } from '@/queries/statuses/use-local-status-translation';
import { useStatusTranslation } from '@/queries/statuses/use-status-translation';
import { useSettings } from '@/stores/settings';
@ -79,6 +80,7 @@ const StatusContent: React.FC<IStatusContent> = React.memo(
}) => {
const { urlPrivacy, displaySpoilers, renderMfm } = useSettings();
const { greentext } = useFrontendConfig();
const { data: account } = useAccount(status.account_id);
const [collapsed, setCollapsed] = useState<boolean | null>(null);
const [onlyEmoji, setOnlyEmoji] = useState(false);
@ -172,11 +174,11 @@ const StatusContent: React.FC<IStatusContent> = React.memo(
redirectUrls: urlPrivacy.redirectLinksMode !== 'off',
displayTargetHost: urlPrivacy.displayTargetHost,
greentext,
speakAsCat: status.account.speak_as_cat,
speakAsCat: account?.speak_as_cat,
},
true,
);
}, [content, renderMfm]);
}, [content, renderMfm, account?.speak_as_cat]);
const spoilerText =
status.spoiler_text_map && statusMeta.currentLanguage

View File

@ -4,6 +4,7 @@ import AttachmentThumbs from '@/components/attachment-thumbs';
import PreviewCard from '@/components/preview-card';
import PlaceholderCard from '@/features/placeholder/components/placeholder-card';
import { MediaGallery, Video, Audio } from '@/features/ui/util/async-components';
import { useAccount } from '@/queries/accounts/use-account';
import { useModalsActions } from '@/stores/modals';
import { useSettings } from '@/stores/settings';
@ -17,7 +18,7 @@ interface IStatusMedia {
status: Pick<
Status,
| 'id'
| 'account'
| 'account_id'
| 'card'
| 'expectsCard'
| 'filtered'
@ -36,6 +37,7 @@ interface IStatusMedia {
const StatusMedia: React.FC<IStatusMedia> = ({ status, muted = false, onClick }) => {
const { openModal } = useModalsActions();
const { displayMedia } = useSettings();
const { data: account } = useAccount(status.account_id);
const [visible] = useMediaVisible(status, displayMedia);
@ -97,7 +99,7 @@ const StatusMedia: React.FC<IStatusMedia> = ({ status, muted = false, onClick })
poster={
attachment.preview_url !== attachment.url
? attachment.preview_url
: status.account.avatar_static
: account?.avatar_static
}
backgroundColor={attachment.meta.colors?.background}
foregroundColor={attachment.meta.colors?.foreground}
@ -128,13 +130,7 @@ const StatusMedia: React.FC<IStatusMedia> = ({ status, muted = false, onClick })
if (media) {
return (
// eslint-disable-next-line jsx-a11y/no-static-element-interactions
<div
onClick={(e) => {
e.stopPropagation();
}}
>
{media}
</div>
<div onClick={(e) => e.stopPropagation()}>{media}</div>
);
} else {
return null;

View File

@ -7,6 +7,7 @@ import Text from '@/components/ui/text';
import { useAppSelector } from '@/hooks/use-app-selector';
import { useFeatures } from '@/hooks/use-features';
import { useInstance } from '@/hooks/use-instance';
import { selectAccount } from '@/queries/accounts/selectors';
import { useTranslationLanguages } from '@/queries/instance/use-translation-languages';
import { useLocalStatusTranslation } from '@/queries/statuses/use-local-status-translation';
import { useStatusTranslation } from '@/queries/statuses/use-status-translation';
@ -40,7 +41,8 @@ const canRemoteTranslate = (
if (!isLoggedIn && !allowUnauthenticated) return false;
if (!status.account.local && !allowRemote) return false;
const statusAccount = selectAccount(status.account_id);
if (statusAccount && !statusAccount.local && !allowRemote) return false;
if (!supportedLanguages[status.language]?.includes(locale)) return false;
@ -68,7 +70,7 @@ const localTranslationAvailability = async (
};
interface ITranslateButton {
status: Pick<Status, 'id' | 'account' | 'content' | 'content_map' | 'language' | 'visibility'>;
status: Pick<Status, 'id' | 'account_id' | 'content' | 'content_map' | 'language' | 'visibility'>;
}
const TranslateButton: React.FC<ITranslateButton> = ({ status }) => {

View File

@ -1,4 +1,4 @@
import React, { useMemo } from 'react';
import React from 'react';
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import EventPreview from '@/components/event-preview';
@ -14,7 +14,6 @@ import IconButton from '@/components/ui/icon-button';
import Stack from '@/components/ui/stack';
import Text from '@/components/ui/text';
import AccountContainer from '@/containers/account-container';
import { useOwnAccount } from '@/hooks/use-own-account';
import { useCompose, useComposeActions } from '@/stores/compose';
import type { NormalizedStatus as Status } from '@/reducers/statuses';
@ -34,7 +33,6 @@ interface IQuotedStatusContainer {
const PreviewComposeContainer: React.FC<IQuotedStatusContainer> = ({ composeId }) => {
const { updateCompose } = useComposeActions();
const intl = useIntl();
const { data: ownAccount } = useOwnAccount();
const previewedStatus = useCompose(composeId).preview as unknown as Status;
@ -44,16 +42,7 @@ const PreviewComposeContainer: React.FC<IQuotedStatusContainer> = ({ composeId }
});
};
const status = useMemo(
() =>
previewedStatus
? {
...previewedStatus,
account: previewedStatus.account || ownAccount,
}
: null,
[previewedStatus, ownAccount],
);
const status = previewedStatus ?? null;
if (!status) {
return null;
@ -80,7 +69,7 @@ const PreviewComposeContainer: React.FC<IQuotedStatusContainer> = ({ composeId }
/>
</HStack>
<AccountContainer
id={status.account.id}
id={status.account_id}
timestamp={status.created_at}
withRelationship={false}
showAccountHoverCard={false}

View File

@ -1,17 +1,17 @@
import { statusSchema, type Account } from 'pl-api';
import { pollSchema, statusSchema, type Account } from 'pl-api';
import * as v from 'valibot';
import { normalizeStatus } from '@/reducers/statuses';
import type { DraftStatus } from '@/queries/statuses/use-draft-statuses';
const buildPoll = (draftStatus: DraftStatus) => {
if (draftStatus.poll?.options) {
return {
...draftStatus.poll,
id: `${draftStatus.draft_id}-poll`,
options: draftStatus.poll.options.map((title: string) => ({ title })).toArray(),
};
const buildPoll = (draftPoll: DraftStatus['poll']) => {
if (draftPoll?.options) {
return v.parse(pollSchema, {
...draftPoll,
id: 'poll',
options: draftPoll.options.map((title: string) => ({ title })).toArray(),
});
} else {
return null;
}
@ -29,7 +29,6 @@ const buildStatus = (account: Account, draftStatus: DraftStatus) => {
group: draftStatus.group_id,
in_reply_to_id: draftStatus.in_reply_to,
media_attachments: draftStatus.media_attachments,
poll: buildPoll(draftStatus),
quote_id: draftStatus.quote,
sensitive: draftStatus.sensitive,
spoiler_text: draftStatus.spoiler_text,
@ -41,4 +40,4 @@ const buildStatus = (account: Account, draftStatus: DraftStatus) => {
return normalizeStatus(status);
};
export { buildStatus };
export { buildStatus, buildPoll };

View File

@ -5,6 +5,8 @@ import { fetchStatus } from '@/actions/statuses';
import Button from '@/components/ui/button';
import HStack from '@/components/ui/hstack';
import { useAppDispatch } from '@/hooks/use-app-dispatch';
import { queryClient } from '@/queries/client';
import { queryKeys } from '@/queries/keys';
import { useCancelDraftStatus } from '@/queries/statuses/use-draft-statuses';
import { useComposeActions } from '@/stores/compose';
import { useModalsActions } from '@/stores/modals';
@ -55,7 +57,10 @@ const DraftStatusActionBar: React.FC<IDraftStatusActionBar> = ({ source, status
const handleEditClick = () => {
if (status.in_reply_to_id) dispatch(fetchStatus(status.in_reply_to_id));
setComposeToStatus(status, status.poll, source, false, source.draft_id, source.editorState);
const poll = status.poll_id
? queryClient.getQueryData(queryKeys.statuses.polls.show(status.poll_id))
: undefined;
setComposeToStatus(status, poll, source, false, source.draft_id, source.editorState);
openModal('COMPOSE');
};

View File

@ -13,7 +13,7 @@ import QuotedStatus from '@/features/status/containers/quoted-status-container';
import PollPreview from '@/features/ui/components/poll-preview';
import { useOwnAccount } from '@/hooks/use-own-account';
import { buildStatus } from '../builder';
import { buildPoll, buildStatus } from '../builder';
import DraftStatusActionBar from './draft-status-action-bar';
@ -29,10 +29,11 @@ const DraftStatus: React.FC<IDraftStatus> = ({ draftStatus, ...other }) => {
if (!ownAccount || !draftStatus) return null;
const status = buildStatus(ownAccount, draftStatus);
const poll = draftStatus.poll ? buildPoll(draftStatus.poll) : null;
if (!status) return null;
const account = status.account;
const account = ownAccount;
let quote;
@ -82,7 +83,7 @@ const DraftStatus: React.FC<IDraftStatus> = ({ draftStatus, ...other }) => {
{quote}
{status.poll && <PollPreview poll={status.poll} />}
{poll && <PollPreview poll={poll} />}
</Stack>
</div>
</div>

View File

@ -19,6 +19,7 @@ import Emojify from '@/features/emoji/emojify';
import { useAppDispatch } from '@/hooks/use-app-dispatch';
import { useFeatures } from '@/hooks/use-features';
import { useOwnAccount } from '@/hooks/use-own-account';
import { useAccount } from '@/queries/accounts/use-account';
import { useChats } from '@/queries/chats';
import {
useBookmarkStatus,
@ -94,7 +95,7 @@ interface IEventHeader {
status?: Pick<
Status,
| 'id'
| 'account'
| 'account_id'
| 'bookmarked'
| 'event'
| 'group_id'
@ -121,6 +122,7 @@ const EventHeader: React.FC<IEventHeader> = ({ status }) => {
const features = useFeatures();
const { boostModal } = useSettings();
const { data: ownAccount } = useOwnAccount();
const { data: account } = useAccount(status?.account_id!);
const isStaff = ownAccount ? (ownAccount.is_admin ?? ownAccount.is_moderator) : false;
const isAdmin = ownAccount ? ownAccount.is_admin : false;
@ -131,7 +133,7 @@ const EventHeader: React.FC<IEventHeader> = ({ status }) => {
const { mutate: pinStatus } = usePinStatus(status?.id!);
const { mutate: unpinStatus } = useUnpinStatus(status?.id!);
if (!status || !status.event) {
if (!status || !status.event || !account) {
return (
<>
<div className='-mx-4 -mt-4'>
@ -142,11 +144,11 @@ const EventHeader: React.FC<IEventHeader> = ({ status }) => {
</>
);
}
const account = status.account;
const event = status.event;
const banner = event.banner;
if (!account) return null;
const username = account.username;
const handleHeaderClick: React.MouseEventHandler<HTMLAnchorElement> = (e) => {
@ -365,7 +367,7 @@ const EventHeader: React.FC<IEventHeader> = ({ status }) => {
icon: require('@phosphor-icons/core/regular/at.svg'),
});
if (status.account.accepts_chat_messages === true) {
if (account.accepts_chat_messages === true) {
menu.push({
text: intl.formatMessage(messages.chat, { name: username }),
action: handleChatClick,

View File

@ -7,6 +7,7 @@ import StatusContent from '@/components/status-content';
import StatusReplyMentions from '@/components/status-reply-mentions';
import HStack from '@/components/ui/hstack';
import Stack from '@/components/ui/stack';
import { buildPoll } from '@/features/draft-statuses/builder';
import PollPreview from '@/features/ui/components/poll-preview';
import { useOwnAccount } from '@/hooks/use-own-account';
@ -26,11 +27,10 @@ const ScheduledStatus: React.FC<IScheduledStatus> = ({ scheduledStatus, ...other
if (!ownAccount) return null;
const status = buildStatus(ownAccount, scheduledStatus);
const poll = scheduledStatus.params.poll ? buildPoll(scheduledStatus.params.poll) : null;
if (!status) return null;
const account = status.account;
return (
<div
className={clsx('status__wrapper py-4', `status__wrapper-${status.visibility}`, {
@ -47,8 +47,8 @@ const ScheduledStatus: React.FC<IScheduledStatus> = ({ scheduledStatus, ...other
<div className='mb-4'>
<HStack justifyContent='between' alignItems='start'>
<Account
key={account.id}
account={account}
key={ownAccount.id}
account={ownAccount}
timestamp={status.created_at}
futureTimestamp
action={<ScheduledStatusActionBar status={status} {...other} />}
@ -63,7 +63,7 @@ const ScheduledStatus: React.FC<IScheduledStatus> = ({ scheduledStatus, ...other
{status.media_attachments.length > 0 && <AttachmentThumbs status={status} />}
{status.poll && <PollPreview poll={status.poll} />}
{poll && <PollPreview poll={poll} />}
</Stack>
</div>
</div>

View File

@ -14,6 +14,7 @@ import Icon from '@/components/ui/icon';
import Stack from '@/components/ui/stack';
import Text from '@/components/ui/text';
import Emojify from '@/features/emoji/emojify';
import { useAccount } from '@/queries/accounts/use-account';
import { useGroupQuery } from '@/queries/groups/use-group';
import StatusInteractionBar from './status-interaction-bar';
@ -41,6 +42,7 @@ const DetailedStatus: React.FC<IDetailedStatus> = ({
const node = useRef<HTMLDivElement>(null);
const { data: group } = useGroupQuery(status.group_id ?? undefined);
const { data: account } = useAccount(status.account_id);
const handleOpenCompareHistoryModal = () => {
onOpenCompareHistoryModal(status);
@ -93,8 +95,7 @@ const DetailedStatus: React.FC<IDetailedStatus> = ({
const actualStatus = status?.reblog || status;
if (!actualStatus) return null;
const { account } = actualStatus;
if (!account || typeof account !== 'object') return null;
if (!account) return null;
return (
<div className='border-box'>

View File

@ -7,6 +7,7 @@ import AnimatedNumber from '@/components/animated-number';
import HStack from '@/components/ui/hstack';
import Text from '@/components/ui/text';
import { useFeatures } from '@/hooks/use-features';
import { useAccount } from '@/queries/accounts/use-account';
import { useModalsActions } from '@/stores/modals';
import type { NormalizedStatus as Status } from '@/reducers/statuses';
@ -15,7 +16,7 @@ interface IStatusInteractionBar {
status: Pick<
Status,
| 'id'
| 'account'
| 'account_id'
| 'dislikes_count'
| 'favourited'
| 'favourites_count'
@ -29,7 +30,7 @@ const StatusInteractionBar: React.FC<IStatusInteractionBar> = ({
}): React.JSX.Element | null => {
const { openModal } = useModalsActions();
const features = useFeatures();
const { account } = status;
const { data: account } = useAccount(status.account_id);
if (!account || typeof account !== 'object') return null;
@ -74,7 +75,7 @@ const StatusInteractionBar: React.FC<IStatusInteractionBar> = ({
<InteractionCounter
count={status.quotes_count}
to='/@{$username}/posts/$statusId/quotes'
params={{ username: status.account.acct, statusId: status.id }}
params={{ username: account?.acct ?? '', statusId: status.id }}
>
<FormattedMessage
id='status.interactions.quotes'

View File

@ -12,6 +12,7 @@ import PlaceholderMediaGallery from '@/features/placeholder/components/placehold
import QuotedStatus from '@/features/status/containers/quoted-status-container';
import { useAppSelector } from '@/hooks/use-app-selector';
import { useOwnAccount } from '@/hooks/use-own-account';
import { usePollQuery } from '@/queries/statuses/use-poll';
import { usePendingStatus } from '@/stores/pending-statuses';
import { buildStatus } from '../util/pending-status-builder';
@ -36,7 +37,7 @@ interface IPendingStatusMedia {
const PendingStatusMedia: React.FC<IPendingStatusMedia> = ({ status }) => {
if (status.media_attachments && status.media_attachments.length) {
return <PlaceholderMediaGallery media={status.media_attachments} />;
} else if (!status.quote && shouldHaveCard(status)) {
} else if (!status.quote_id && shouldHaveCard(status)) {
return <PlaceholderCard />;
} else {
return null;
@ -57,10 +58,10 @@ const PendingStatus: React.FC<IPendingStatus> = ({
: null;
});
if (!status) return null;
if (!status.account) return null;
const { data: poll } = usePollQuery(status?.poll_id ?? '');
const account = status.account;
if (!status) return null;
if (!ownAccount) return null;
return (
<div className={clsx('opacity-50', className)}>
@ -75,8 +76,8 @@ const PendingStatus: React.FC<IPendingStatus> = ({
<div className='mb-4'>
<HStack justifyContent='between' alignItems='start'>
<Account
key={account.id}
account={account}
key={ownAccount.id}
account={ownAccount}
timestamp={status.created_at}
hideActions
withLinkToProfile={false}
@ -92,7 +93,7 @@ const PendingStatus: React.FC<IPendingStatus> = ({
<PendingStatusMedia status={status} />
{status.poll && <PollPreview poll={status.poll} />}
{poll && <PollPreview poll={poll} />}
{status.quote_id && <QuotedStatus statusId={status.quote_id} />}
</Stack>

View File

@ -1,4 +1,3 @@
import { create } from 'mutative';
import { statusSchema, type Account } from 'pl-api';
import * as v from 'valibot';
@ -15,17 +14,6 @@ const buildMentions = (pendingStatus: PendingStatus) => {
}
};
const buildPoll = (pendingStatus: PendingStatus) => {
if (pendingStatus.poll?.options) {
return create(pendingStatus.poll, (draft) => {
// @ts-expect-error
draft.options = draft.options.map((title) => ({ title }));
});
} else {
return null;
}
};
const buildStatus = (
account: Account,
state: RootState,
@ -42,7 +30,6 @@ const buildStatus = (
in_reply_to_id: inReplyToId,
media_attachments: (pendingStatus.media_ids ?? []).map((id: string) => ({ id })),
mentions: buildMentions(pendingStatus),
poll: buildPoll(pendingStatus),
quote: pendingStatus.quote_id ? state.statuses[pendingStatus.quote_id] : null,
sensitive: pendingStatus.sensitive,
visibility: pendingStatus.visibility,

View File

@ -33,7 +33,7 @@ const getGallery = createSelector(
sensitive: status.sensitive,
visibility: status.visibility,
status_id: statusId,
account_id: status.account.id,
account_id: status.account_id,
})),
);
}, []),

View File

@ -10,6 +10,7 @@ import Stack from '@/components/ui/stack';
import Text from '@/components/ui/text';
import Emojify from '@/features/emoji/emojify';
import { useAppSelector } from '@/hooks/use-app-selector';
import { useAccount } from '@/queries/accounts/use-account';
import { useStatusHistory } from '@/queries/statuses/use-status-history';
import type { BaseModalProps } from '@/features/ui/components/modal-root';
@ -25,6 +26,7 @@ const CompareHistoryModal: React.FC<BaseModalProps & CompareHistoryModalProps> =
const { data: versions, isLoading } = useStatusHistory(statusId);
const status = useAppSelector((state) => state.statuses[statusId]);
const { data: statusAccount } = useAccount(status?.account_id ?? '');
const onClickClose = () => {
onClose('COMPARE_HISTORY');
@ -44,7 +46,7 @@ const CompareHistoryModal: React.FC<BaseModalProps & CompareHistoryModalProps> =
mentions={status?.mentions}
hasQuote={!!status?.quote_id}
emojis={version.emojis}
speakAsCat={status.account.speak_as_cat}
speakAsCat={statusAccount?.speak_as_cat}
/>
);
@ -81,7 +83,7 @@ const CompareHistoryModal: React.FC<BaseModalProps & CompareHistoryModalProps> =
<ParsedContent
html={option.title}
emojis={version.emojis}
speakAsCat={status.account.speak_as_cat}
speakAsCat={statusAccount?.speak_as_cat}
/>
</span>
</HStack>

View File

@ -5,10 +5,7 @@ import { useCallback, useEffect } from 'react';
import { useIntl } from 'react-intl';
import { importEntities } from '@/actions/importer';
import {
getNotificationStatus,
notificationMessages,
} from '@/features/notifications/components/notification';
import { notificationMessages } from '@/features/notifications/components/notification';
import { useAppDispatch } from '@/hooks/use-app-dispatch';
import { useAppSelector } from '@/hooks/use-app-selector';
import { useClient } from '@/hooks/use-client';
@ -150,7 +147,7 @@ const useProcessStreamNotification = () => {
if (notification.type === 'chat_mention') return;
const playSound = sounds[notification.type];
const status = getNotificationStatus(notification);
const status = 'status' in notification ? notification.status : null;
let filtered: boolean | null = false;
@ -166,7 +163,7 @@ const useProcessStreamNotification = () => {
if (!filtered && isNotificationsEnabled) {
const targetName = notification.type === 'move' ? notification.target.acct : '';
const isReblog = status?.reblog_id ? 1 : 0;
const isReblog = status?.reblog ? 1 : 0;
const title = intl.formatMessage(notificationMessages[notification.type], {
name: notification.account.display_name,

View File

@ -4,14 +4,13 @@ import { useClient } from '@/hooks/use-client';
import { queryKeys } from '../keys';
import type { Poll } from 'pl-api';
const usePollQuery = (pollId: string) => {
const client = useClient();
return useQuery<Poll>({
return useQuery({
queryKey: queryKeys.statuses.polls.show(pollId),
queryFn: () => client.polls.getPoll(pollId),
enabled: !!pollId,
});
};

View File

@ -223,7 +223,7 @@ const isReblogOf = (reblog: Pick<Status, 'reblog_id'>, status: Pick<Status, 'id'
reblog.reblog_id === status.id;
const buildReferencesTo = (
statuses: Record<string, Pick<Status, 'id' | 'account' | 'reblog_id'>>,
statuses: Record<string, Pick<Status, 'id' | 'account_id' | 'reblog_id'>>,
status: Pick<Status, 'id'>,
): Array<[string]> =>
Object.values(statuses)
@ -239,7 +239,7 @@ const buildReferencesTo = (
const filterTimelines = (
state: State,
relationship: Relationship,
statuses: Record<string, Pick<Status, 'id' | 'account' | 'account_id' | 'reblog_id'>>,
statuses: Record<string, Pick<Status, 'id' | 'account_id' | 'reblog_id'>>,
) => {
for (const statusId in statuses) {
const status = statuses[statusId];

View File

@ -209,36 +209,38 @@ const newPoll = (params: Partial<ComposePoll> = {}): ComposePoll => ({
});
const statusToTextMentions = (
status: Pick<Status, 'account' | 'mentions'>,
status: Pick<Status, 'account_id' | 'mentions'>,
account: Pick<Account, 'acct'>,
) => {
const author = status.account.acct;
const statusAccount = selectAccount(status.account_id);
const author = statusAccount?.acct;
const mentions = status.mentions.map((m) => m.acct);
return [...new Set([author, ...mentions].filter((acct) => acct !== account.acct))]
return [...new Set([author, ...mentions].filter((acct) => acct && acct !== account.acct))]
.map((m) => `@${m} `)
.join('');
};
const statusToMentionsArray = (
status: Pick<Status, 'account' | 'mentions'>,
status: Pick<Status, 'account_id' | 'mentions'>,
account: Pick<Account, 'acct'>,
rebloggedBy?: Pick<Account, 'acct'>,
) => {
const author = status.account.acct;
const statusAccount = selectAccount(status.account_id);
const author = statusAccount?.acct;
const mentions = status.mentions.map((m) => m.acct);
return [
...new Set(
[author, ...(rebloggedBy ? [rebloggedBy.acct] : []), ...mentions].filter(
(acct) => acct !== account.acct,
(acct): acct is string => !!acct && acct !== account.acct,
),
),
];
};
const statusToMentionsAccountIdsArray = (
status: Pick<Status, 'mentions' | 'account'>,
status: Pick<Status, 'mentions' | 'account_id'>,
account: Pick<Account, 'id'>,
parentRebloggedBy?: string | null,
) => {
@ -246,7 +248,7 @@ const statusToMentionsAccountIdsArray = (
return [
...new Set(
[status.account.id, ...(parentRebloggedBy ? [parentRebloggedBy] : []), ...mentions].filter(
[status.account_id, ...(parentRebloggedBy ? [parentRebloggedBy] : []), ...mentions].filter(
(id) => id !== account.id,
),
),
@ -307,7 +309,7 @@ interface ComposeActions {
status: Pick<
Status,
| 'id'
| 'account'
| 'account_id'
| 'content'
| 'group_id'
| 'in_reply_to_id'
@ -330,7 +332,7 @@ interface ComposeActions {
status: Pick<
Status,
| 'id'
| 'account'
| 'account_id'
| 'group_id'
| 'list_id'
| 'local_only'
@ -342,7 +344,7 @@ interface ComposeActions {
approvalRequired?: boolean,
) => void;
quoteCompose: (
status: Pick<Status, 'id' | 'account' | 'visibility' | 'group_id' | 'list_id'>,
status: Pick<Status, 'id' | 'account_id' | 'visibility' | 'group_id' | 'list_id'>,
approvalRequired?: boolean,
) => void;
mentionCompose: (account: Pick<Account, 'acct'>) => void;
@ -351,7 +353,7 @@ interface ComposeActions {
openComposeWithText: (composeId: string, text?: string) => void;
eventDiscussionCompose: (
composeId: string,
status: Pick<Status, 'id' | 'account' | 'mentions'>,
status: Pick<Status, 'id' | 'account_id' | 'mentions'>,
) => void;
resetCompose: (composeId?: string) => void;
selectComposeSuggestion: (
@ -423,7 +425,7 @@ const useComposeStore = create<ComposeStore>()(
const compose = state.composers['compose-modal'];
const mentions = explicitAddressing
? getExplicitMentions(status.account.id, status)
? getExplicitMentions(status.account_id, status)
: [];
if (!withRedraft && !draftId) {
compose.editedId = status.id;
@ -526,7 +528,8 @@ const useComposeStore = create<ComposeStore>()(
}
const compose = draft.composers['compose-modal'];
const author = status.account.acct;
const statusAccount = selectAccount(status.account_id);
const author = statusAccount?.acct ?? '';
compose.quoteId = status.id;
compose.to = [author];

View File

@ -7,4 +7,4 @@
@include mixins.text($theme: success);
line-height: 1;
}
}
}

View File

@ -1,3 +1,5 @@
import { selectAccount } from '@/queries/accounts/selectors';
import type { NormalizedStatus as Status } from '@/reducers/statuses';
import type { IntlShape } from 'react-intl';
@ -21,10 +23,10 @@ const shouldHaveCard = (status: Pick<Status, 'content'>): boolean =>
/** Sanitize status text for use with screen readers. */
const textForScreenReader = (
intl: IntlShape,
status: Pick<Status, 'account' | 'spoiler_text' | 'search_index' | 'created_at'>,
status: Pick<Status, 'account_id' | 'spoiler_text' | 'search_index' | 'created_at'>,
rebloggedByText?: string,
): string => {
const { account } = status;
const account = selectAccount(status.account_id);
if (!account || typeof account !== 'object') return '';
const displayName = account.display_name;