diff --git a/app/javascript/flavours/glitch/actions/importer/index.js b/app/javascript/flavours/glitch/actions/importer/index.js index c1db557115..f1aabe2747 100644 --- a/app/javascript/flavours/glitch/actions/importer/index.js +++ b/app/javascript/flavours/glitch/actions/importer/index.js @@ -69,6 +69,10 @@ export function importFetchedStatuses(statuses) { processStatus(status.reblog); } + if (status.quote?.quoted_status) { + processStatus(status.quote.quoted_status); + } + if (status.poll?.id) { pushUnique(polls, createPollFromServerJSON(status.poll, getState().polls[status.poll.id])); } diff --git a/app/javascript/flavours/glitch/actions/importer/normalizer.js b/app/javascript/flavours/glitch/actions/importer/normalizer.js index 69c755d06f..ece72dd1e4 100644 --- a/app/javascript/flavours/glitch/actions/importer/normalizer.js +++ b/app/javascript/flavours/glitch/actions/importer/normalizer.js @@ -23,12 +23,20 @@ export function normalizeFilterResult(result) { export function normalizeStatus(status, normalOldStatus, settings) { const normalStatus = { ...status }; + normalStatus.account = status.account.id; if (status.reblog && status.reblog.id) { normalStatus.reblog = status.reblog.id; } + if (status.quote?.quoted_status ?? status.quote?.quoted_status_id) { + normalStatus.quote = { + ...status.quote, + quoted_status: status.quote.quoted_status?.id ?? status.quote?.quoted_status_id, + }; + } + if (status.poll && status.poll.id) { normalStatus.poll = status.poll.id; } diff --git a/app/javascript/flavours/glitch/components/status.jsx b/app/javascript/flavours/glitch/components/status.jsx index fb62be9b87..1ded07261d 100644 --- a/app/javascript/flavours/glitch/components/status.jsx +++ b/app/javascript/flavours/glitch/components/status.jsx @@ -82,6 +82,7 @@ class Status extends ImmutablePureComponent { id: PropTypes.string, status: ImmutablePropTypes.map, account: ImmutablePropTypes.record, + children: PropTypes.node, previousId: PropTypes.string, nextInReplyToId: PropTypes.string, rootId: PropTypes.string, @@ -111,6 +112,7 @@ class Status extends ImmutablePureComponent { withDismiss: PropTypes.bool, onMoveUp: PropTypes.func, onMoveDown: PropTypes.func, + isQuotedPost: PropTypes.bool, getScrollPosition: PropTypes.func, updateScrollBottom: PropTypes.func, expanded: PropTypes.bool, @@ -440,7 +442,7 @@ class Status extends ImmutablePureComponent { } render () { - const { intl, hidden, featured, unfocusable, unread, pictureInPicture, previousId, nextInReplyToId, rootId, skipPrepend, avatarSize = 46 } = this.props; + const { intl, hidden, featured, unfocusable, unread, pictureInPicture, previousId, nextInReplyToId, rootId, skipPrepend, avatarSize = 46, children } = this.props; const { status, @@ -452,6 +454,7 @@ class Status extends ImmutablePureComponent { onOpenMedia, notification, history, + isQuotedPost, ...other } = this.props; let attachments = null; @@ -684,7 +687,7 @@ class Status extends ImmutablePureComponent { {!skipPrepend && prepend}
{(connectReply || connectUp || connectToRoot) &&
} @@ -722,6 +725,8 @@ class Status extends ImmutablePureComponent { {...statusContentProps} /> + {children} + {media} {hashtagBar} @@ -730,13 +735,15 @@ class Status extends ImmutablePureComponent { {/* This is a glitch-soc addition to have a placeholder */} {!expanded && } - + {!isQuotedPost && + + }
diff --git a/app/javascript/flavours/glitch/components/status_list.jsx b/app/javascript/flavours/glitch/components/status_list.jsx index 09061f9dc0..95ff8f45e5 100644 --- a/app/javascript/flavours/glitch/components/status_list.jsx +++ b/app/javascript/flavours/glitch/components/status_list.jsx @@ -9,7 +9,7 @@ import { TIMELINE_GAP, TIMELINE_SUGGESTIONS } from 'flavours/glitch/actions/time import { RegenerationIndicator } from 'flavours/glitch/components/regeneration_indicator'; import { InlineFollowSuggestions } from 'flavours/glitch/features/home_timeline/components/inline_follow_suggestions'; -import StatusContainer from '../containers/status_container'; +import { StatusQuoteManager } from '../components/status_quoted'; import { LoadGap } from './load_gap'; import ScrollableList from './scrollable_list'; @@ -114,7 +114,7 @@ export default class StatusList extends ImmutablePureComponent { ); default: return ( - ( - = ({ isError, children }) => { + return ( +
+ + {children} +
+ ); +}; + +type QuoteMap = ImmutableMap<'state' | 'quoted_status', string | null>; + +export const QuotedStatus: React.FC<{ quote: QuoteMap }> = ({ quote }) => { + const quotedStatusId = quote.get('quoted_status'); + const state = quote.get('state'); + const status = useAppSelector((state) => + quotedStatusId ? state.statuses.get(quotedStatusId) : undefined, + ); + + let quoteError: React.ReactNode | null = null; + + if (state === 'deleted') { + quoteError = ( + + ); + } else if (state === 'unauthorized') { + quoteError = ( + + ); + } else if (state === 'pending') { + quoteError = ( + + ); + } else if (state === 'rejected' || state === 'revoked') { + quoteError = ( + + ); + } else if (!status || !quotedStatusId) { + quoteError = ( + + ); + } + + if (quoteError) { + return {quoteError}; + } + + return ( + + + + ); +}; + +interface StatusQuoteManagerProps { + id: string; + [key: string]: unknown; +} + +/** + * This wrapper component takes a status ID and, if the associated status + * is a quote post, it renders the quote into `StatusContainer` as a child. + * It passes all other props through to `StatusContainer`. + */ + +export const StatusQuoteManager = (props: StatusQuoteManagerProps) => { + const status = useAppSelector((state) => state.statuses.get(props.id)); + const quote = status?.get('quote') as QuoteMap | undefined; + + if (quote) { + return ( + /* @ts-expect-error Status is not yet typed */ + + + + ); + } + + /* @ts-expect-error Status is not yet typed */ + return ; +}; diff --git a/app/javascript/flavours/glitch/features/account_featured/index.tsx b/app/javascript/flavours/glitch/features/account_featured/index.tsx index 1efa7bdd6c..ea1bac2e9d 100644 --- a/app/javascript/flavours/glitch/features/account_featured/index.tsx +++ b/app/javascript/flavours/glitch/features/account_featured/index.tsx @@ -14,7 +14,7 @@ import { Account } from 'flavours/glitch/components/account'; import { ColumnBackButton } from 'flavours/glitch/components/column_back_button'; import { LoadingIndicator } from 'flavours/glitch/components/loading_indicator'; import { RemoteHint } from 'flavours/glitch/components/remote_hint'; -import StatusContainer from 'flavours/glitch/containers/status_container'; +import { StatusQuoteManager } from 'flavours/glitch/components/status_quoted'; import { AccountHeader } from 'flavours/glitch/features/account_timeline/components/account_header'; import BundleColumnError from 'flavours/glitch/features/ui/components/bundle_column_error'; import Column from 'flavours/glitch/features/ui/components/column'; @@ -142,9 +142,8 @@ const AccountFeatured: React.FC<{ multiColumn: boolean }> = ({ /> {featuredStatusIds.map((statusId) => ( - diff --git a/app/javascript/flavours/glitch/features/notifications/components/notification.jsx b/app/javascript/flavours/glitch/features/notifications/components/notification.jsx index 6ec613e209..a2ed584135 100644 --- a/app/javascript/flavours/glitch/features/notifications/components/notification.jsx +++ b/app/javascript/flavours/glitch/features/notifications/components/notification.jsx @@ -16,7 +16,7 @@ import PersonAddIcon from '@/material-icons/400-24px/person_add-fill.svg?react'; import { Account } from 'flavours/glitch/components/account'; import { Icon } from 'flavours/glitch/components/icon'; import { Permalink } from 'flavours/glitch/components/permalink'; -import StatusContainer from 'flavours/glitch/containers/status_container'; +import { StatusQuoteManager } from 'flavours/glitch/components/status_quoted'; import { WithRouterPropTypes } from 'flavours/glitch/utils/react_router'; import FollowRequestContainer from '../containers/follow_request_container'; @@ -159,7 +159,7 @@ class Notification extends ImmutablePureComponent { renderMention (notification) { return ( -