@ -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),
|
||||
|
||||
@ -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]);
|
||||
|
||||
@ -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 =
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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 }) => {
|
||||
|
||||
@ -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}
|
||||
|
||||
@ -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 };
|
||||
|
||||
@ -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');
|
||||
};
|
||||
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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'>
|
||||
|
||||
@ -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'
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
})),
|
||||
);
|
||||
}, []),
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@ -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];
|
||||
|
||||
@ -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];
|
||||
|
||||
@ -7,4 +7,4 @@
|
||||
@include mixins.text($theme: success);
|
||||
line-height: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
Reference in New Issue
Block a user