refactor: remove immutable, convert to use plain javascript object

all changes were made to the StatusMedia component and its components, including all subcomponents recursively.
other components that dispatch openModal() of 'MEDIA' still need to be updated
finish-refactor-pure-status-component
P. Reis 2024-12-10 21:20:12 -03:00
rodzic 77e45dea2c
commit 10ff18e76f
22 zmienionych plików z 99 dodań i 100 usunięć

Wyświetl plik

@ -3,12 +3,10 @@ import { Suspense } from 'react';
import { openModal } from 'soapbox/actions/modals.ts'; import { openModal } from 'soapbox/actions/modals.ts';
import { MediaGallery } from 'soapbox/features/ui/util/async-components.ts'; import { MediaGallery } from 'soapbox/features/ui/util/async-components.ts';
import { useAppDispatch } from 'soapbox/hooks/useAppDispatch.ts'; import { useAppDispatch } from 'soapbox/hooks/useAppDispatch.ts';
import { Attachment } from 'soapbox/schemas/index.ts';
import type { List as ImmutableList } from 'immutable';
import type { Attachment } from 'soapbox/types/entities.ts';
interface IAttachmentThumbs { interface IAttachmentThumbs {
media: ImmutableList<Attachment>; media: readonly Attachment[];
onClick?(): void; onClick?(): void;
sensitive?: boolean; sensitive?: boolean;
} }
@ -18,7 +16,7 @@ const AttachmentThumbs = (props: IAttachmentThumbs) => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const fallback = <div className='!h-[50px] bg-transparent' />; const fallback = <div className='!h-[50px] bg-transparent' />;
const onOpenMedia = (media: ImmutableList<Attachment>, index: number) => dispatch(openModal('MEDIA', { media, index })); const onOpenMedia = (media: readonly Attachment[], index: number) => dispatch(openModal('MEDIA', { media, index }));
return ( return (
<div className='relative'> <div className='relative'>

Wyświetl plik

@ -9,13 +9,12 @@ import { closeDropdownMenu as closeDropdownMenuRedux, openDropdownMenu } from 's
import { closeModal, openModal } from 'soapbox/actions/modals.ts'; import { closeModal, openModal } from 'soapbox/actions/modals.ts';
import IconButton from 'soapbox/components/ui/icon-button.tsx'; import IconButton from 'soapbox/components/ui/icon-button.tsx';
import Portal from 'soapbox/components/ui/portal.tsx'; import Portal from 'soapbox/components/ui/portal.tsx';
import { Entities, EntityTypes } from 'soapbox/entity-store/entities.ts';
import { useAppDispatch } from 'soapbox/hooks/useAppDispatch.ts'; import { useAppDispatch } from 'soapbox/hooks/useAppDispatch.ts';
import { userTouching } from 'soapbox/is-mobile.ts'; import { userTouching } from 'soapbox/is-mobile.ts';
import DropdownMenuItem, { MenuItem } from './dropdown-menu-item.tsx'; import DropdownMenuItem, { MenuItem } from './dropdown-menu-item.tsx';
import type { Status } from 'soapbox/types/entities.ts';
export type Menu = Array<MenuItem | null>; export type Menu = Array<MenuItem | null>;
interface IDropdownMenu { interface IDropdownMenu {
@ -28,7 +27,7 @@ interface IDropdownMenu {
onShiftClick?: React.EventHandler<React.MouseEvent | React.KeyboardEvent>; onShiftClick?: React.EventHandler<React.MouseEvent | React.KeyboardEvent>;
placement?: Placement; placement?: Placement;
src?: string; src?: string;
status?: Status; status?: EntityTypes[Entities.STATUSES];
title?: string; title?: string;
} }

Wyświetl plik

@ -8,7 +8,7 @@ import StillImage from 'soapbox/components/still-image.tsx';
import { MIMETYPE_ICONS } from 'soapbox/components/upload.tsx'; import { MIMETYPE_ICONS } from 'soapbox/components/upload.tsx';
import { useSettings } from 'soapbox/hooks/useSettings.ts'; import { useSettings } from 'soapbox/hooks/useSettings.ts';
import { useSoapboxConfig } from 'soapbox/hooks/useSoapboxConfig.ts'; import { useSoapboxConfig } from 'soapbox/hooks/useSoapboxConfig.ts';
import { Attachment } from 'soapbox/types/entities.ts'; import { Attachment } from 'soapbox/schemas/index.ts';
import { truncateFilename } from 'soapbox/utils/media.ts'; import { truncateFilename } from 'soapbox/utils/media.ts';
import { isIOS } from '../is-mobile.ts'; import { isIOS } from '../is-mobile.ts';
@ -16,8 +16,6 @@ import { isPanoramic, isPortrait, isNonConformingRatio, minimumAspectRatio, maxi
import SvgIcon from './ui/svg-icon.tsx'; import SvgIcon from './ui/svg-icon.tsx';
import type { List as ImmutableList } from 'immutable';
// const Gameboy = lazy(() => import('./gameboy')); // const Gameboy = lazy(() => import('./gameboy'));
const ATTACHMENT_LIMIT = 4; const ATTACHMENT_LIMIT = 4;
@ -46,7 +44,8 @@ const withinLimits = (aspectRatio: number) => {
}; };
const shouldLetterbox = (attachment: Attachment): boolean => { const shouldLetterbox = (attachment: Attachment): boolean => {
const aspectRatio = attachment.getIn(['meta', 'original', 'aspect']) as number | undefined; const aspectRatio = 'meta' in attachment && 'original' in attachment.meta && (attachment)?.meta?.original?.aspect;
if (!aspectRatio) return true; if (!aspectRatio) return true;
return !withinLimits(aspectRatio); return !withinLimits(aspectRatio);
@ -159,7 +158,7 @@ const Item: React.FC<IItem> = ({
const attachmentIcon = ( const attachmentIcon = (
<SvgIcon <SvgIcon
className={clsx('size-16 text-gray-800 dark:text-gray-200', { 'size-8': compact })} className={clsx('size-16 text-gray-800 dark:text-gray-200', { 'size-8': compact })}
src={MIMETYPE_ICONS[attachment.getIn(['pleroma', 'mime_type']) as string] || paperclipIcon} src={MIMETYPE_ICONS[attachment?.pleroma?.mime_type as string] || paperclipIcon}
/> />
); );
@ -291,9 +290,9 @@ const Item: React.FC<IItem> = ({
export interface IMediaGallery { export interface IMediaGallery {
sensitive?: boolean; sensitive?: boolean;
media: ImmutableList<Attachment>; media: readonly Attachment[];
height?: number; height?: number;
onOpenMedia: (media: ImmutableList<Attachment>, index: number) => void; onOpenMedia: (media: readonly Attachment[], index: number) => void;
defaultWidth?: number; defaultWidth?: number;
cacheWidth?: (width: number) => void; cacheWidth?: (width: number) => void;
visible?: boolean; visible?: boolean;
@ -323,7 +322,7 @@ const MediaGallery: React.FC<IMediaGallery> = (props) => {
const getSizeDataSingle = (): SizeData => { const getSizeDataSingle = (): SizeData => {
const w = width || defaultWidth; const w = width || defaultWidth;
const aspectRatio = media.getIn([0, 'meta', 'original', 'aspect']) as number | undefined; const aspectRatio = 'meta' in media[0] && 'original' in media[0].meta && (media[0])?.meta?.original?.aspect;
const getHeight = () => { const getHeight = () => {
if (!aspectRatio) return w * 9 / 16; if (!aspectRatio) return w * 9 / 16;
@ -349,7 +348,9 @@ const MediaGallery: React.FC<IMediaGallery> = (props) => {
let itemsDimensions: Dimensions[] = []; let itemsDimensions: Dimensions[] = [];
const ratios = Array(size).fill(null).map((_, i) => const ratios = Array(size).fill(null).map((_, i) =>
media.getIn([i, 'meta', 'original', 'aspect']) as number, 'meta' in media[i] && 'original' in media[i].meta && typeof media[i].meta?.original?.aspect === 'number'
? media[i].meta.original.aspect
: undefined as unknown as number, // NOTE: the old logic returned undefined anyways, and the implementation of the functions below call 'isNaN', such as the 'isPortrait' function
); );
const [ar1, ar2, ar3, ar4] = ratios; const [ar1, ar2, ar3, ar4] = ratios;
@ -547,9 +548,9 @@ const MediaGallery: React.FC<IMediaGallery> = (props) => {
}; };
}; };
const sizeData: SizeData = getSizeData(media.size); const sizeData: SizeData = getSizeData(media.length);
const children = media.take(ATTACHMENT_LIMIT).map((attachment, i) => ( const children = media.slice(0, ATTACHMENT_LIMIT).map((attachment, i) => (
<Item <Item
key={attachment.id} key={attachment.id}
onClick={handleClick} onClick={handleClick}
@ -560,7 +561,7 @@ const MediaGallery: React.FC<IMediaGallery> = (props) => {
visible={!!props.visible} visible={!!props.visible}
dimensions={sizeData.itemsDimensions[i]} dimensions={sizeData.itemsDimensions[i]}
last={i === ATTACHMENT_LIMIT - 1} last={i === ATTACHMENT_LIMIT - 1}
total={media.size} total={media.length}
compact={compact} compact={compact}
/> />
)); ));

Wyświetl plik

@ -3,7 +3,6 @@ import linkIcon from '@tabler/icons/outline/link.svg';
import playerPlayIcon from '@tabler/icons/outline/player-play.svg'; import playerPlayIcon from '@tabler/icons/outline/player-play.svg';
import zoomInIcon from '@tabler/icons/outline/zoom-in.svg'; import zoomInIcon from '@tabler/icons/outline/zoom-in.svg';
import clsx from 'clsx'; import clsx from 'clsx';
import { List as ImmutableList } from 'immutable';
import { useState, useEffect, useRef } from 'react'; import { useState, useEffect, useRef } from 'react';
import Blurhash from 'soapbox/components/blurhash.tsx'; import Blurhash from 'soapbox/components/blurhash.tsx';
@ -12,17 +11,18 @@ import Stack from 'soapbox/components/ui/stack.tsx';
import SvgIcon from 'soapbox/components/ui/svg-icon.tsx'; import SvgIcon from 'soapbox/components/ui/svg-icon.tsx';
import Text from 'soapbox/components/ui/text.tsx'; import Text from 'soapbox/components/ui/text.tsx';
import { normalizeAttachment } from 'soapbox/normalizers/index.ts'; import { normalizeAttachment } from 'soapbox/normalizers/index.ts';
import { Attachment } from 'soapbox/schemas/index.ts';
import { addAutoPlay } from 'soapbox/utils/media.ts'; import { addAutoPlay } from 'soapbox/utils/media.ts';
import { getTextDirection } from 'soapbox/utils/rtl.ts'; import { getTextDirection } from 'soapbox/utils/rtl.ts';
import type { Card as CardEntity, Attachment } from 'soapbox/types/entities.ts'; import type { Card as CardEntity } from 'soapbox/types/entities.ts';
/** Props for `PreviewCard`. */ /** Props for `PreviewCard`. */
interface IPreviewCard { interface IPreviewCard {
card: CardEntity; card: CardEntity;
maxTitle?: number; maxTitle?: number;
maxDescription?: number; maxDescription?: number;
onOpenMedia: (attachments: ImmutableList<Attachment>, index: number) => void; onOpenMedia: (attachments: readonly Attachment[], index: number) => void;
compact?: boolean; compact?: boolean;
defaultWidth?: number; defaultWidth?: number;
cacheWidth?: (width: number) => void; cacheWidth?: (width: number) => void;
@ -73,9 +73,9 @@ const PreviewCard: React.FC<IPreviewCard> = ({
height: card.height, height: card.height,
}, },
}, },
}); }).toJS();
onOpenMedia(ImmutableList([attachment]), 0); onOpenMedia([{ ...attachment, blurhash: attachment.blurhash === undefined ? null : attachment.blurhash } as Attachment], 0);
}; };
const handleEmbedClick: React.MouseEventHandler = (e) => { const handleEmbedClick: React.MouseEventHandler = (e) => {

Wyświetl plik

@ -2,11 +2,10 @@ import circlesIcon from '@tabler/icons/outline/circles.svg';
import pinnedIcon from '@tabler/icons/outline/pinned.svg'; import pinnedIcon from '@tabler/icons/outline/pinned.svg';
import repeatIcon from '@tabler/icons/outline/repeat.svg'; import repeatIcon from '@tabler/icons/outline/repeat.svg';
import clsx from 'clsx'; import clsx from 'clsx';
import { useCallback, useEffect, useRef, useState } from 'react'; import { useEffect, useRef, useState } from 'react';
import { useIntl, FormattedMessage, defineMessages } from 'react-intl'; import { useIntl, FormattedMessage, defineMessages } from 'react-intl';
import { Link, useHistory } from 'react-router-dom'; import { Link, useHistory } from 'react-router-dom';
import { importFetchedStatuses } from 'soapbox/actions/importer/index.ts';
import { openModal } from 'soapbox/actions/modals.ts'; import { openModal } from 'soapbox/actions/modals.ts';
import { unfilterStatus } from 'soapbox/actions/statuses.ts'; import { unfilterStatus } from 'soapbox/actions/statuses.ts';
import PureEventPreview from 'soapbox/components/pure-event-preview.tsx'; import PureEventPreview from 'soapbox/components/pure-event-preview.tsx';
@ -23,14 +22,14 @@ import { EntityTypes, Entities } from 'soapbox/entity-store/entities.ts';
import QuotedStatus from 'soapbox/features/status/containers/quoted-status-container.tsx'; import QuotedStatus from 'soapbox/features/status/containers/quoted-status-container.tsx';
import { HotKeys } from 'soapbox/features/ui/components/hotkeys.tsx'; import { HotKeys } from 'soapbox/features/ui/components/hotkeys.tsx';
import { useAppDispatch } from 'soapbox/hooks/useAppDispatch.ts'; import { useAppDispatch } from 'soapbox/hooks/useAppDispatch.ts';
import { useAppSelector } from 'soapbox/hooks/useAppSelector.ts';
import { useFavourite } from 'soapbox/hooks/useFavourite.ts'; import { useFavourite } from 'soapbox/hooks/useFavourite.ts';
import { useMentionCompose } from 'soapbox/hooks/useMentionCompose.ts'; import { useMentionCompose } from 'soapbox/hooks/useMentionCompose.ts';
import { useReblog } from 'soapbox/hooks/useReblog.ts'; import { useReblog } from 'soapbox/hooks/useReblog.ts';
import { useReplyCompose } from 'soapbox/hooks/useReplyCompose.ts'; import { useReplyCompose } from 'soapbox/hooks/useReplyCompose.ts';
import { useSettings } from 'soapbox/hooks/useSettings.ts'; import { useSettings } from 'soapbox/hooks/useSettings.ts';
import { useStatusHidden } from 'soapbox/hooks/useStatusHidden.ts'; import { useStatusHidden } from 'soapbox/hooks/useStatusHidden.ts';
import { makeGetStatus } from 'soapbox/selectors/index.ts'; import { normalizeStatus } from 'soapbox/normalizers/index.ts';
import { Status } from 'soapbox/types/entities.ts';
import { emojifyText } from 'soapbox/utils/emojify.tsx'; import { emojifyText } from 'soapbox/utils/emojify.tsx';
import { defaultMediaVisibility, textForScreenReader, getActualStatus } from 'soapbox/utils/status.ts'; import { defaultMediaVisibility, textForScreenReader, getActualStatus } from 'soapbox/utils/status.ts';
@ -127,16 +126,7 @@ const PureStatus: React.FC<IPureStatus> = (props) => {
} }
}, [overlay.current]); }, [overlay.current]);
// TODO: remove this code, it will be removed once all components in this file are pure. const statusImmutable = normalizeStatus(status) as Status; // TODO: remove this line, it will be removed once all components in this file are pure.
useEffect(() => {
dispatch(importFetchedStatuses([status]));
}, []);
const getStatus = useCallback(makeGetStatus(), []);
const statusImmutable = useAppSelector(state => getStatus(state, { id: status.id }));
if (!statusImmutable) {
return null;
}
// END TODO
const handleToggleMediaVisibility = (): void => { const handleToggleMediaVisibility = (): void => {
setShowMedia(!showMedia); setShowMedia(!showMedia);
@ -486,7 +476,7 @@ const PureStatus: React.FC<IPureStatus> = (props) => {
{(quote || actualStatus.card || actualStatus.media_attachments.length > 0) && ( {(quote || actualStatus.card || actualStatus.media_attachments.length > 0) && (
<Stack space={4}> <Stack space={4}>
<StatusMedia <StatusMedia
status={statusImmutable} // FIXME: stop using 'statusImmutable' and use 'status' variable directly, for that create a new component called 'PureStatusMedia' status={status}
muted={muted} muted={muted}
onClick={handleClick} onClick={handleClick}
showMedia={showMedia} showMedia={showMedia}

Wyświetl plik

@ -7,6 +7,7 @@ import { useHistory } from 'react-router-dom';
import StatusMedia from 'soapbox/components/status-media.tsx'; import StatusMedia from 'soapbox/components/status-media.tsx';
import Stack from 'soapbox/components/ui/stack.tsx'; import Stack from 'soapbox/components/ui/stack.tsx';
import AccountContainer from 'soapbox/containers/account-container.tsx'; import AccountContainer from 'soapbox/containers/account-container.tsx';
import { Entities, EntityTypes } from 'soapbox/entity-store/entities.ts';
import { useSettings } from 'soapbox/hooks/useSettings.ts'; import { useSettings } from 'soapbox/hooks/useSettings.ts';
import { defaultMediaVisibility } from 'soapbox/utils/status.ts'; import { defaultMediaVisibility } from 'soapbox/utils/status.ts';
@ -138,7 +139,7 @@ const QuotedStatus: React.FC<IQuotedStatus> = ({ status, onCancel, compose }) =>
{status.media_attachments.size > 0 && ( {status.media_attachments.size > 0 && (
<StatusMedia <StatusMedia
status={status} status={status.toJS() as EntityTypes[Entities.STATUSES]}
muted={compose} muted={compose}
showMedia={showMedia} showMedia={showMedia}
onToggleVisibility={handleToggleMediaVisibility} onToggleVisibility={handleToggleMediaVisibility}

Wyświetl plik

@ -49,6 +49,7 @@ import DropdownMenu from 'soapbox/components/dropdown-menu/index.ts';
import StatusActionButton from 'soapbox/components/status-action-button.tsx'; import StatusActionButton from 'soapbox/components/status-action-button.tsx';
import StatusReactionWrapper from 'soapbox/components/status-reaction-wrapper.tsx'; import StatusReactionWrapper from 'soapbox/components/status-reaction-wrapper.tsx';
import HStack from 'soapbox/components/ui/hstack.tsx'; import HStack from 'soapbox/components/ui/hstack.tsx';
import { Entities, EntityTypes } from 'soapbox/entity-store/entities.ts';
import { useAppDispatch } from 'soapbox/hooks/useAppDispatch.ts'; import { useAppDispatch } from 'soapbox/hooks/useAppDispatch.ts';
import { useAppSelector } from 'soapbox/hooks/useAppSelector.ts'; import { useAppSelector } from 'soapbox/hooks/useAppSelector.ts';
import { useFeatures } from 'soapbox/hooks/useFeatures.ts'; import { useFeatures } from 'soapbox/hooks/useFeatures.ts';
@ -826,7 +827,7 @@ const StatusActionBar: React.FC<IStatusActionBar> = ({
/> />
)} )}
<DropdownMenu items={menu} status={status}> <DropdownMenu items={menu} status={status.toJS() as EntityTypes[Entities.STATUSES]}>
<StatusActionButton <StatusActionButton
title={intl.formatMessage(messages.more)} title={intl.formatMessage(messages.more)}
icon={dotsIcon} icon={dotsIcon}

Wyświetl plik

@ -4,17 +4,16 @@ import { Suspense } from 'react';
import { openModal } from 'soapbox/actions/modals.ts'; import { openModal } from 'soapbox/actions/modals.ts';
import AttachmentThumbs from 'soapbox/components/attachment-thumbs.tsx'; import AttachmentThumbs from 'soapbox/components/attachment-thumbs.tsx';
import PreviewCard from 'soapbox/components/preview-card.tsx'; import PreviewCard from 'soapbox/components/preview-card.tsx';
import { Entities, EntityTypes } from 'soapbox/entity-store/entities.ts';
import { GroupLinkPreview } from 'soapbox/features/groups/components/group-link-preview.tsx'; import { GroupLinkPreview } from 'soapbox/features/groups/components/group-link-preview.tsx';
import PlaceholderCard from 'soapbox/features/placeholder/components/placeholder-card.tsx'; import PlaceholderCard from 'soapbox/features/placeholder/components/placeholder-card.tsx';
import { MediaGallery, Video, Audio } from 'soapbox/features/ui/util/async-components.ts'; import { MediaGallery, Video, Audio } from 'soapbox/features/ui/util/async-components.ts';
import { useAppDispatch } from 'soapbox/hooks/useAppDispatch.ts'; import { useAppDispatch } from 'soapbox/hooks/useAppDispatch.ts';
import { Attachment } from 'soapbox/schemas/index.ts';
import type { List as ImmutableList } from 'immutable';
import type { Status, Attachment } from 'soapbox/types/entities.ts';
interface IStatusMedia { interface IStatusMedia {
/** Status entity to render media for. */ /** Status entity to render media for. */
status: Status; status: EntityTypes[Entities.STATUSES];
/** Whether to display compact media. */ /** Whether to display compact media. */
muted?: boolean; muted?: boolean;
/** Callback when compact media is clicked. */ /** Callback when compact media is clicked. */
@ -35,8 +34,8 @@ const StatusMedia: React.FC<IStatusMedia> = ({
}) => { }) => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const size = status.media_attachments.size; const size = status.media_attachments.length;
const firstAttachment = status.media_attachments.first(); const firstAttachment = status.media_attachments[0];
let media: JSX.Element | null = null; let media: JSX.Element | null = null;
@ -52,7 +51,7 @@ const StatusMedia: React.FC<IStatusMedia> = ({
return <div className='relative mt-2 block cursor-pointer border-0 bg-cover bg-center bg-no-repeat' style={{ height: '285px' }} />; return <div className='relative mt-2 block cursor-pointer border-0 bg-cover bg-center bg-no-repeat' style={{ height: '285px' }} />;
}; };
const openMedia = (media: ImmutableList<Attachment>, index: number) => { const openMedia = (media: readonly Attachment[], index: number) => {
dispatch(openModal('MEDIA', { media, status, index })); dispatch(openModal('MEDIA', { media, status, index }));
}; };
@ -72,10 +71,10 @@ const StatusMedia: React.FC<IStatusMedia> = ({
<Suspense fallback={renderLoadingVideoPlayer()}> <Suspense fallback={renderLoadingVideoPlayer()}>
<Video <Video
preview={video.preview_url} preview={video.preview_url}
blurhash={video.blurhash} blurhash={video.blurhash ?? undefined}
src={video.url} src={video.url}
alt={video.description} alt={video.description}
aspectRatio={Number(video.meta.getIn(['original', 'aspect']))} aspectRatio={Number(video.meta?.original?.aspect)}
height={285} height={285}
visible={showMedia} visible={showMedia}
inline inline
@ -90,11 +89,11 @@ const StatusMedia: React.FC<IStatusMedia> = ({
<Audio <Audio
src={attachment.url} src={attachment.url}
alt={attachment.description} alt={attachment.description}
poster={attachment.preview_url !== attachment.url ? attachment.preview_url : status.getIn(['account', 'avatar_static']) as string | undefined} poster={attachment.preview_url !== attachment.url ? attachment.preview_url : status.account.avatar_static}
backgroundColor={attachment.meta.getIn(['colors', 'background']) as string | undefined} backgroundColor={attachment.meta?.colors?.background}
foregroundColor={attachment.meta.getIn(['colors', 'foreground']) as string | undefined} foregroundColor={attachment.meta?.colors?.foreground}
accentColor={attachment.meta.getIn(['colors', 'accent']) as string | undefined} accentColor={attachment.meta?.colors?.accent}
duration={attachment.meta.getIn(['original', 'duration'], 0) as number | undefined} duration={attachment.meta?.duration ?? 0}
height={263} height={263}
/> />
</Suspense> </Suspense>

Wyświetl plik

@ -16,6 +16,7 @@ import Icon from 'soapbox/components/ui/icon.tsx';
import Stack from 'soapbox/components/ui/stack.tsx'; import Stack from 'soapbox/components/ui/stack.tsx';
import Text from 'soapbox/components/ui/text.tsx'; import Text from 'soapbox/components/ui/text.tsx';
import AccountContainer from 'soapbox/containers/account-container.tsx'; import AccountContainer from 'soapbox/containers/account-container.tsx';
import { Entities, EntityTypes } from 'soapbox/entity-store/entities.ts';
import QuotedStatus from 'soapbox/features/status/containers/quoted-status-container.tsx'; import QuotedStatus from 'soapbox/features/status/containers/quoted-status-container.tsx';
import { HotKeys } from 'soapbox/features/ui/components/hotkeys.tsx'; import { HotKeys } from 'soapbox/features/ui/components/hotkeys.tsx';
import { useAppDispatch } from 'soapbox/hooks/useAppDispatch.ts'; import { useAppDispatch } from 'soapbox/hooks/useAppDispatch.ts';
@ -465,7 +466,7 @@ const Status: React.FC<IStatus> = (props) => {
{(quote || actualStatus.card || actualStatus.media_attachments.size > 0) && ( {(quote || actualStatus.card || actualStatus.media_attachments.size > 0) && (
<Stack space={4}> <Stack space={4}>
<StatusMedia <StatusMedia
status={actualStatus} status={actualStatus.toJS() as EntityTypes[Entities.STATUSES]}
muted={muted} muted={muted}
onClick={handleClick} onClick={handleClick}
showMedia={showMedia} showMedia={showMedia}

Wyświetl plik

@ -9,6 +9,7 @@ import StatusContent from 'soapbox/components/status-content.tsx';
import StatusMedia from 'soapbox/components/status-media.tsx'; import StatusMedia from 'soapbox/components/status-media.tsx';
import HStack from 'soapbox/components/ui/hstack.tsx'; import HStack from 'soapbox/components/ui/hstack.tsx';
import Stack from 'soapbox/components/ui/stack.tsx'; import Stack from 'soapbox/components/ui/stack.tsx';
import { Entities, EntityTypes } from 'soapbox/entity-store/entities.ts';
import { useAppDispatch } from 'soapbox/hooks/useAppDispatch.ts'; import { useAppDispatch } from 'soapbox/hooks/useAppDispatch.ts';
import type { AdminReport, Status } from 'soapbox/types/entities.ts'; import type { AdminReport, Status } from 'soapbox/types/entities.ts';
@ -52,7 +53,7 @@ const ReportStatus: React.FC<IReportStatus> = ({ status }) => {
<HStack space={2} alignItems='start'> <HStack space={2} alignItems='start'>
<Stack space={2} className='overflow-hidden' grow> <Stack space={2} className='overflow-hidden' grow>
<StatusContent status={status} /> <StatusContent status={status} />
<StatusMedia status={status} /> <StatusMedia status={status.toJS() as EntityTypes[Entities.STATUSES]} />
</Stack> </Stack>
<div className='flex-none'> <div className='flex-none'>

Wyświetl plik

@ -23,6 +23,7 @@ import { useAppSelector } from 'soapbox/hooks/useAppSelector.ts';
import { useFeatures } from 'soapbox/hooks/useFeatures.ts'; import { useFeatures } from 'soapbox/hooks/useFeatures.ts';
import { ChatKeys, IChat, useChatActions } from 'soapbox/queries/chats.ts'; import { ChatKeys, IChat, useChatActions } from 'soapbox/queries/chats.ts';
import { queryClient } from 'soapbox/queries/client.ts'; import { queryClient } from 'soapbox/queries/client.ts';
import { Attachment } from 'soapbox/schemas/index.ts';
import { htmlToPlaintext } from 'soapbox/utils/html.ts'; import { htmlToPlaintext } from 'soapbox/utils/html.ts';
import { isOnlyEmoji as _isOnlyEmoji } from 'soapbox/utils/only-emoji.ts'; import { isOnlyEmoji as _isOnlyEmoji } from 'soapbox/utils/only-emoji.ts';
@ -112,7 +113,7 @@ const ChatMessage = (props: IChatMessage) => {
'rounded-br-sm': isMyMessage && content, 'rounded-br-sm': isMyMessage && content,
'rounded-bl-sm': !isMyMessage && content, 'rounded-bl-sm': !isMyMessage && content,
})} })}
media={chatMessage.media_attachments} media={chatMessage.media_attachments.toJS() as unknown as Attachment[]}
onOpenMedia={onOpenMedia} onOpenMedia={onOpenMedia}
visible visible
/> />

Wyświetl plik

@ -5,13 +5,12 @@ import AttachmentThumbs from 'soapbox/components/attachment-thumbs.tsx';
import Markup from 'soapbox/components/markup.tsx'; import Markup from 'soapbox/components/markup.tsx';
import Stack from 'soapbox/components/ui/stack.tsx'; import Stack from 'soapbox/components/ui/stack.tsx';
import AccountContainer from 'soapbox/containers/account-container.tsx'; import AccountContainer from 'soapbox/containers/account-container.tsx';
import { Entities, EntityTypes } from 'soapbox/entity-store/entities.ts';
import { getTextDirection } from 'soapbox/utils/rtl.ts'; import { getTextDirection } from 'soapbox/utils/rtl.ts';
import type { Status } from 'soapbox/types/entities.ts';
interface IReplyIndicator { interface IReplyIndicator {
className?: string; className?: string;
status?: Status; status?: EntityTypes[Entities.STATUSES];
onCancel?: () => void; onCancel?: () => void;
hideActions: boolean; hideActions: boolean;
} }
@ -50,12 +49,12 @@ const ReplyIndicator: React.FC<IReplyIndicator> = ({ className, status, hideActi
className='break-words' className='break-words'
size='sm' size='sm'
direction={getTextDirection(status.search_index)} direction={getTextDirection(status.search_index)}
emojis={status?.emojis?.toJS() ?? status.emojis} // Use toJS() if status.emojis is immutable; otherwise, fallback to plain status.emojis emojis={status.emojis}
mentions={status.mentions.toJS()} mentions={status.mentions}
html={{ __html: status.content }} html={{ __html: status.content }}
/> />
{status.media_attachments.size > 0 && ( {status.media_attachments.length > 0 && (
<AttachmentThumbs <AttachmentThumbs
media={status.media_attachments} media={status.media_attachments}
sensitive={status.sensitive} sensitive={status.sensitive}

Wyświetl plik

@ -1,6 +1,7 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { cancelReplyCompose } from 'soapbox/actions/compose.ts'; import { cancelReplyCompose } from 'soapbox/actions/compose.ts';
import { Entities, EntityTypes } from 'soapbox/entity-store/entities.ts';
import { makeGetStatus } from 'soapbox/selectors/index.ts'; import { makeGetStatus } from 'soapbox/selectors/index.ts';
import ReplyIndicator from '../components/reply-indicator.tsx'; import ReplyIndicator from '../components/reply-indicator.tsx';
@ -16,7 +17,7 @@ const makeMapStateToProps = () => {
const editing = !!state.compose.get(composeId)?.id; const editing = !!state.compose.get(composeId)?.id;
return { return {
status: getStatus(state, { id: statusId }) as Status, status: (getStatus(state, { id: statusId }) as Status)?.toJS() as EntityTypes[Entities.STATUSES],
hideActions: editing, hideActions: editing,
}; };
}; };

Wyświetl plik

@ -15,6 +15,7 @@ import HStack from 'soapbox/components/ui/hstack.tsx';
import Icon from 'soapbox/components/ui/icon.tsx'; import Icon from 'soapbox/components/ui/icon.tsx';
import Stack from 'soapbox/components/ui/stack.tsx'; import Stack from 'soapbox/components/ui/stack.tsx';
import Text from 'soapbox/components/ui/text.tsx'; import Text from 'soapbox/components/ui/text.tsx';
import { Entities, EntityTypes } from 'soapbox/entity-store/entities.ts';
import QuotedStatus from 'soapbox/features/status/containers/quoted-status-container.tsx'; import QuotedStatus from 'soapbox/features/status/containers/quoted-status-container.tsx';
import { useAppDispatch } from 'soapbox/hooks/useAppDispatch.ts'; import { useAppDispatch } from 'soapbox/hooks/useAppDispatch.ts';
import { useAppSelector } from 'soapbox/hooks/useAppSelector.ts'; import { useAppSelector } from 'soapbox/hooks/useAppSelector.ts';
@ -208,7 +209,7 @@ const EventInformation: React.FC<IEventInformation> = ({ params }) => {
)} )}
<StatusMedia <StatusMedia
status={status} status={status.toJS() as EntityTypes[Entities.STATUSES]}
showMedia={showMedia} showMedia={showMedia}
onToggleVisibility={handleToggleMediaVisibility} onToggleVisibility={handleToggleMediaVisibility}
/> />

Wyświetl plik

@ -7,6 +7,7 @@ import Toggle from 'soapbox/components/ui/toggle.tsx';
import { MediaGallery, Video, Audio } from 'soapbox/features/ui/util/async-components.ts'; import { MediaGallery, Video, Audio } from 'soapbox/features/ui/util/async-components.ts';
import { useAppDispatch } from 'soapbox/hooks/useAppDispatch.ts'; import { useAppDispatch } from 'soapbox/hooks/useAppDispatch.ts';
import { useAppSelector } from 'soapbox/hooks/useAppSelector.ts'; import { useAppSelector } from 'soapbox/hooks/useAppSelector.ts';
import { Attachment } from 'soapbox/schemas/index.ts';
interface IStatusCheckBox { interface IStatusCheckBox {
id: string; id: string;
@ -62,7 +63,7 @@ const StatusCheckBox: React.FC<IStatusCheckBox> = ({ id, disabled }) => {
} else { } else {
media = ( media = (
<MediaGallery <MediaGallery
media={status.media_attachments} media={status.media_attachments.toJS() as unknown as Attachment[]}
sensitive={status.sensitive} sensitive={status.sensitive}
height={110} height={110}
onOpenMedia={() => {}} onOpenMedia={() => {}}

Wyświetl plik

@ -8,6 +8,7 @@ import HStack from 'soapbox/components/ui/hstack.tsx';
import Stack from 'soapbox/components/ui/stack.tsx'; import Stack from 'soapbox/components/ui/stack.tsx';
import PollPreview from 'soapbox/features/ui/components/poll-preview.tsx'; import PollPreview from 'soapbox/features/ui/components/poll-preview.tsx';
import { useAppSelector } from 'soapbox/hooks/useAppSelector.ts'; import { useAppSelector } from 'soapbox/hooks/useAppSelector.ts';
import { Attachment } from 'soapbox/schemas/index.ts';
import { buildStatus } from '../builder.tsx'; import { buildStatus } from '../builder.tsx';
@ -55,7 +56,7 @@ const ScheduledStatus: React.FC<IScheduledStatus> = ({ statusId, ...other }) =>
{status.media_attachments.size > 0 && ( {status.media_attachments.size > 0 && (
<AttachmentThumbs <AttachmentThumbs
media={status.media_attachments} media={status.media_attachments.toJS() as unknown as Attachment[]}
sensitive={status.sensitive} sensitive={status.sensitive}
/> />
)} )}

Wyświetl plik

@ -16,6 +16,7 @@ import HStack from 'soapbox/components/ui/hstack.tsx';
import Icon from 'soapbox/components/ui/icon.tsx'; import Icon from 'soapbox/components/ui/icon.tsx';
import Stack from 'soapbox/components/ui/stack.tsx'; import Stack from 'soapbox/components/ui/stack.tsx';
import Text from 'soapbox/components/ui/text.tsx'; import Text from 'soapbox/components/ui/text.tsx';
import { Entities, EntityTypes } from 'soapbox/entity-store/entities.ts';
import QuotedStatus from 'soapbox/features/status/containers/quoted-status-container.tsx'; import QuotedStatus from 'soapbox/features/status/containers/quoted-status-container.tsx';
import { getActualStatus } from 'soapbox/utils/status.ts'; import { getActualStatus } from 'soapbox/utils/status.ts';
@ -162,7 +163,7 @@ const DetailedStatus: React.FC<IDetailedStatus> = ({
{(withMedia && (quote || actualStatus.card || actualStatus.media_attachments.size > 0)) && ( {(withMedia && (quote || actualStatus.card || actualStatus.media_attachments.size > 0)) && (
<Stack space={4}> <Stack space={4}>
<StatusMedia <StatusMedia
status={actualStatus} status={actualStatus.toJS() as EntityTypes[Entities.STATUSES]}
showMedia={showMedia} showMedia={showMedia}
onToggleVisibility={onToggleMediaVisibility} onToggleVisibility={onToggleMediaVisibility}
/> />

Wyświetl plik

@ -4,15 +4,15 @@ import { spring } from 'react-motion';
import HStack from 'soapbox/components/ui/hstack.tsx'; import HStack from 'soapbox/components/ui/hstack.tsx';
import SvgIcon from 'soapbox/components/ui/svg-icon.tsx'; import SvgIcon from 'soapbox/components/ui/svg-icon.tsx';
import { Entities, EntityTypes } from 'soapbox/entity-store/entities.ts';
import ReplyIndicator from 'soapbox/features/compose/components/reply-indicator.tsx'; import ReplyIndicator from 'soapbox/features/compose/components/reply-indicator.tsx';
import Motion from '../../util/optional-motion.tsx'; import Motion from '../../util/optional-motion.tsx';
import type { Menu, MenuItem } from 'soapbox/components/dropdown-menu/index.ts'; import type { Menu, MenuItem } from 'soapbox/components/dropdown-menu/index.ts';
import type { Status as StatusEntity } from 'soapbox/types/entities.ts';
interface IActionsModal { interface IActionsModal {
status: StatusEntity; status: EntityTypes[Entities.STATUSES];
actions: Menu; actions: Menu;
onClick: () => void; onClick: () => void;
onClose: () => void; onClose: () => void;

Wyświetl plik

@ -5,6 +5,7 @@ import Icon from 'soapbox/components/icon.tsx';
import Modal from 'soapbox/components/ui/modal.tsx'; import Modal from 'soapbox/components/ui/modal.tsx';
import Stack from 'soapbox/components/ui/stack.tsx'; import Stack from 'soapbox/components/ui/stack.tsx';
import Text from 'soapbox/components/ui/text.tsx'; import Text from 'soapbox/components/ui/text.tsx';
import { Entities, EntityTypes } from 'soapbox/entity-store/entities.ts';
import ReplyIndicator from 'soapbox/features/compose/components/reply-indicator.tsx'; import ReplyIndicator from 'soapbox/features/compose/components/reply-indicator.tsx';
import type { Status as StatusEntity } from 'soapbox/types/entities.ts'; import type { Status as StatusEntity } from 'soapbox/types/entities.ts';
@ -37,7 +38,7 @@ const BoostModal: React.FC<IBoostModal> = ({ status, onReblog, onClose }) => {
confirmationText={intl.formatMessage(buttonText)} confirmationText={intl.formatMessage(buttonText)}
> >
<Stack space={4}> <Stack space={4}>
<ReplyIndicator status={status} hideActions /> <ReplyIndicator status={status.toJS() as EntityTypes[Entities.STATUSES]} hideActions />
<Text> <Text>
{/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */} {/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}

Wyświetl plik

@ -12,6 +12,7 @@ import Stack from 'soapbox/components/ui/stack.tsx';
import Text from 'soapbox/components/ui/text.tsx'; import Text from 'soapbox/components/ui/text.tsx';
import { useAppDispatch } from 'soapbox/hooks/useAppDispatch.ts'; import { useAppDispatch } from 'soapbox/hooks/useAppDispatch.ts';
import { useAppSelector } from 'soapbox/hooks/useAppSelector.ts'; import { useAppSelector } from 'soapbox/hooks/useAppSelector.ts';
import { Attachment } from 'soapbox/schemas/index.ts';
import { emojifyText } from 'soapbox/utils/emojify.tsx'; import { emojifyText } from 'soapbox/utils/emojify.tsx';
import type { StatusEdit as StatusEditEntity } from 'soapbox/types/entities.ts'; import type { StatusEdit as StatusEditEntity } from 'soapbox/types/entities.ts';
@ -81,7 +82,7 @@ const CompareHistoryModal: React.FC<ICompareHistoryModal> = ({ onClose, statusId
)} )}
{version.media_attachments.size > 0 && ( {version.media_attachments.size > 0 && (
<AttachmentThumbs media={version.media_attachments} /> <AttachmentThumbs media={version.media_attachments.toJS() as unknown as Attachment[]} />
)} )}
<Text align='right' tag='span' theme='muted' size='sm'> <Text align='right' tag='span' theme='muted' size='sm'>

Wyświetl plik

@ -19,20 +19,20 @@ import HStack from 'soapbox/components/ui/hstack.tsx';
import IconButton from 'soapbox/components/ui/icon-button.tsx'; import IconButton from 'soapbox/components/ui/icon-button.tsx';
import Icon from 'soapbox/components/ui/icon.tsx'; import Icon from 'soapbox/components/ui/icon.tsx';
import Stack from 'soapbox/components/ui/stack.tsx'; import Stack from 'soapbox/components/ui/stack.tsx';
import { Entities, EntityTypes } from 'soapbox/entity-store/entities.ts';
import Audio from 'soapbox/features/audio/index.tsx'; import Audio from 'soapbox/features/audio/index.tsx';
import PlaceholderStatus from 'soapbox/features/placeholder/components/placeholder-status.tsx'; import PlaceholderStatus from 'soapbox/features/placeholder/components/placeholder-status.tsx';
import Thread from 'soapbox/features/status/components/thread.tsx'; import Thread from 'soapbox/features/status/components/thread.tsx';
import Video from 'soapbox/features/video/index.tsx'; import Video from 'soapbox/features/video/index.tsx';
import { useAppDispatch } from 'soapbox/hooks/useAppDispatch.ts'; import { useAppDispatch } from 'soapbox/hooks/useAppDispatch.ts';
import { useAppSelector } from 'soapbox/hooks/useAppSelector.ts';
import { userTouching } from 'soapbox/is-mobile.ts'; import { userTouching } from 'soapbox/is-mobile.ts';
import { makeGetStatus } from 'soapbox/selectors/index.ts'; import { normalizeStatus } from 'soapbox/normalizers/index.ts';
import { Attachment } from 'soapbox/schemas/index.ts';
import { Status } from 'soapbox/types/entities.ts';
import { getActualStatus } from 'soapbox/utils/status.ts';
import ImageLoader from '../image-loader.tsx'; import ImageLoader from '../image-loader.tsx';
import type { List as ImmutableList } from 'immutable';
import type { Attachment, Status } from 'soapbox/types/entities.ts';
const messages = defineMessages({ const messages = defineMessages({
close: { id: 'lightbox.close', defaultMessage: 'Close' }, close: { id: 'lightbox.close', defaultMessage: 'Close' },
expand: { id: 'lightbox.expand', defaultMessage: 'Expand' }, expand: { id: 'lightbox.expand', defaultMessage: 'Expand' },
@ -55,8 +55,8 @@ const containerStyle: React.CSSProperties = {
}; };
interface IMediaModal { interface IMediaModal {
media: ImmutableList<Attachment>; media: readonly Attachment[];
status?: Status; status?: EntityTypes[Entities.STATUSES];
index: number; index: number;
time?: number; time?: number;
onClose(): void; onClose(): void;
@ -74,8 +74,7 @@ const MediaModal: React.FC<IMediaModal> = (props) => {
const history = useHistory(); const history = useHistory();
const intl = useIntl(); const intl = useIntl();
const getStatus = useCallback(makeGetStatus(), []); const actualStatus = status ? getActualStatus(status) : undefined;
const actualStatus = useAppSelector((state) => getStatus(state, { id: status?.id as string }));
const [isLoaded, setIsLoaded] = useState<boolean>(!!status); const [isLoaded, setIsLoaded] = useState<boolean>(!!status);
const [next, setNext] = useState<string>(); const [next, setNext] = useState<string>();
@ -83,11 +82,11 @@ const MediaModal: React.FC<IMediaModal> = (props) => {
const [navigationHidden, setNavigationHidden] = useState(false); const [navigationHidden, setNavigationHidden] = useState(false);
const [isFullScreen, setIsFullScreen] = useState(!status); const [isFullScreen, setIsFullScreen] = useState(!status);
const hasMultipleImages = media.size > 1; const hasMultipleImages = media.length > 1;
const handleSwipe = (index: number) => setIndex(index % media.size); const handleSwipe = (index: number) => setIndex(index % media.length);
const handleNextClick = () => setIndex((getIndex() + 1) % media.size); const handleNextClick = () => setIndex((getIndex() + 1) % media.length);
const handlePrevClick = () => setIndex((media.size + getIndex() - 1) % media.size); const handlePrevClick = () => setIndex((media.length + getIndex() - 1) % media.length);
const navigationHiddenClassName = navigationHidden ? 'pointer-events-none opacity-0' : ''; const navigationHiddenClassName = navigationHidden ? 'pointer-events-none opacity-0' : '';
@ -107,7 +106,7 @@ const MediaModal: React.FC<IMediaModal> = (props) => {
}; };
const handleDownload = () => { const handleDownload = () => {
const mediaItem = hasMultipleImages ? media.get(index as number) : media.get(0); const mediaItem = hasMultipleImages ? media[index as number] : media[0];
window.open(mediaItem?.url); window.open(mediaItem?.url);
}; };
@ -126,8 +125,8 @@ const MediaModal: React.FC<IMediaModal> = (props) => {
}; };
const content = media.map((attachment, i) => { const content = media.map((attachment, i) => {
const width = (attachment.meta.getIn(['original', 'width']) || undefined) as number | undefined; const width = 'meta' in attachment && 'original' in attachment.meta ? (attachment)?.meta?.original?.width : undefined;
const height = (attachment.meta.getIn(['original', 'height']) || undefined) as number | undefined; const height = 'meta' in attachment && 'original' in attachment.meta ? (attachment)?.meta?.original?.height : undefined;
const link = (status && ( const link = (status && (
<a href={status.url} onClick={handleStatusClick}> <a href={status.url} onClick={handleStatusClick}>
@ -151,7 +150,7 @@ const MediaModal: React.FC<IMediaModal> = (props) => {
return ( return (
<Video <Video
preview={attachment.preview_url} preview={attachment.preview_url}
blurhash={attachment.blurhash} blurhash={attachment.blurhash ?? undefined}
src={attachment.url} src={attachment.url}
width={width} width={width}
height={height} height={height}
@ -169,11 +168,11 @@ const MediaModal: React.FC<IMediaModal> = (props) => {
<Audio <Audio
src={attachment.url} src={attachment.url}
alt={attachment.description} alt={attachment.description}
poster={attachment.preview_url !== attachment.url ? attachment.preview_url : (status?.getIn(['account', 'avatar_static'])) as string | undefined} poster={attachment.preview_url !== attachment.url ? attachment.preview_url : status?.account.avatar_static}
backgroundColor={attachment.meta.getIn(['colors', 'background']) as string | undefined} backgroundColor={attachment.meta?.colors?.background}
foregroundColor={attachment.meta.getIn(['colors', 'foreground']) as string | undefined} foregroundColor={attachment.meta?.colors?.foreground}
accentColor={attachment.meta.getIn(['colors', 'accent']) as string | undefined} accentColor={attachment.meta?.colors?.accent}
duration={attachment.meta.getIn(['original', 'duration'], 0) as number | undefined} duration={attachment?.meta?.duration ?? 0}
key={attachment.url} key={attachment.url}
/> />
); );
@ -193,7 +192,7 @@ const MediaModal: React.FC<IMediaModal> = (props) => {
} }
return null; return null;
}).toArray(); });
const handleLoadMore = useCallback(debounce(() => { const handleLoadMore = useCallback(debounce(() => {
if (next && status) { if (next && status) {
@ -344,7 +343,7 @@ const MediaModal: React.FC<IMediaModal> = (props) => {
className={clsx('absolute bottom-2 flex w-full transition-opacity', navigationHiddenClassName)} className={clsx('absolute bottom-2 flex w-full transition-opacity', navigationHiddenClassName)}
> >
<StatusActionBar <StatusActionBar
status={actualStatus} status={normalizeStatus(actualStatus) as Status}
space='md' space='md'
statusActionButtonTheme='inverse' statusActionButtonTheme='inverse'
/> />
@ -362,7 +361,7 @@ const MediaModal: React.FC<IMediaModal> = (props) => {
} }
> >
<Thread <Thread
status={actualStatus} status={normalizeStatus(actualStatus) as Status}
withMedia={false} withMedia={false}
useWindowScroll={false} useWindowScroll={false}
itemClassName='px-4' itemClassName='px-4'

Wyświetl plik

@ -21,11 +21,13 @@ import AccountContainer from 'soapbox/containers/account-container.tsx';
import { useAppDispatch } from 'soapbox/hooks/useAppDispatch.ts'; import { useAppDispatch } from 'soapbox/hooks/useAppDispatch.ts';
import { useAppSelector } from 'soapbox/hooks/useAppSelector.ts'; import { useAppSelector } from 'soapbox/hooks/useAppSelector.ts';
import { useInstance } from 'soapbox/hooks/useInstance.ts'; import { useInstance } from 'soapbox/hooks/useInstance.ts';
import { Attachment } from 'soapbox/schemas/index.ts';
import ConfirmationStep from './steps/confirmation-step.tsx'; import ConfirmationStep from './steps/confirmation-step.tsx';
import OtherActionsStep from './steps/other-actions-step.tsx'; import OtherActionsStep from './steps/other-actions-step.tsx';
import ReasonStep from './steps/reason-step.tsx'; import ReasonStep from './steps/reason-step.tsx';
const messages = defineMessages({ const messages = defineMessages({
blankslate: { id: 'report.reason.blankslate', defaultMessage: 'You have removed all statuses from being selected.' }, blankslate: { id: 'report.reason.blankslate', defaultMessage: 'You have removed all statuses from being selected.' },
done: { id: 'report.done', defaultMessage: 'Done' }, done: { id: 'report.done', defaultMessage: 'Done' },
@ -91,7 +93,7 @@ const SelectedStatus = ({ statusId }: { statusId: string }) => {
{status.media_attachments.size > 0 && ( {status.media_attachments.size > 0 && (
<AttachmentThumbs <AttachmentThumbs
media={status.media_attachments} media={status.media_attachments.toJS() as unknown as Attachment[]}
sensitive={status.sensitive} sensitive={status.sensitive}
/> />
)} )}