WIP pl-api migration

Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
marcin mikołajczak
2024-08-18 15:35:52 +02:00
parent 6addd190f5
commit 5c2dbbd1d6
43 changed files with 72 additions and 69 deletions

View File

@@ -23,6 +23,7 @@ import type { Account as BaseAccount, BackendVersion, CreateStatusParams, Group,
import type { AutoSuggestion } from 'soapbox/components/autosuggest-input';
import type { Emoji } from 'soapbox/features/emoji';
import type { Account, Status } from 'soapbox/normalizers';
import type { ReducerStatus } from 'soapbox/reducers/statuses';
import type { AppDispatch, RootState } from 'soapbox/store';
import type { History } from 'soapbox/types/history';
@@ -110,8 +111,8 @@ const messages = defineMessages({
interface ComposeSetStatusAction {
type: typeof COMPOSE_SET_STATUS;
composeId: string;
status: Pick<BaseStatus, 'id' | 'account' | 'content' | 'group' | 'in_reply_to_id' | 'media_attachments' | 'mentions' | 'quote' | 'spoiler_text' | 'visibility'>;
poll?: Poll;
status: Pick<Status | ReducerStatus, 'id' | 'account' | 'content' | 'group' | 'in_reply_to_id' | 'media_attachments' | 'mentions' | 'quote' | 'spoiler_text' | 'visibility'>;
poll?: Poll | null;
rawText: string;
explicitAddressing: boolean;
spoilerText?: string;
@@ -122,7 +123,7 @@ interface ComposeSetStatusAction {
editorState?: string | null;
}
const setComposeToStatus = (status: ComposeSetStatusAction['status'], poll: Poll, rawText: string, spoilerText?: string, contentType?: string | false, withRedraft?: boolean, draftId?: string, editorState?: string | null) =>
const setComposeToStatus = (status: ComposeSetStatusAction['status'], poll: Poll | null, rawText: string, spoilerText?: string, contentType?: string | false, withRedraft?: boolean, draftId?: string, editorState?: string | null) =>
(dispatch: AppDispatch, getState: () => RootState) => {
const client = getClient(getState);
const { createStatusExplicitAddressing: explicitAddressing, version: v } = client.features;
@@ -154,7 +155,7 @@ const changeCompose = (composeId: string, text: string) => ({
interface ComposeReplyAction {
type: typeof COMPOSE_REPLY;
composeId: string;
status: Pick<Status, 'id' | 'account' | 'group' | 'mentions' | 'spoiler_text' | 'visibility'>;
status: Pick<Status | ReducerStatus, 'id' | 'account' | 'group' | 'mentions' | 'spoiler_text' | 'visibility'>;
account: Pick<Account, 'acct'>;
explicitAddressing: boolean;
preserveSpoilers: boolean;
@@ -196,7 +197,7 @@ const cancelReplyCompose = () => ({
interface ComposeQuoteAction {
type: typeof COMPOSE_QUOTE;
composeId: string;
status: Pick<Status, 'id' | 'account' | 'visibility' | 'group'>;
status: Pick<Status | ReducerStatus, 'id' | 'account' | 'visibility' | 'group'>;
account: Pick<Account, 'acct'> | undefined;
explicitAddressing: boolean;
}

View File

@@ -1,4 +1,4 @@
import { accountSchema, type Account as BaseAccount } from 'pl-api';
import { accountSchema, mutedAccountSchema, type Account as BaseAccount } from 'pl-api';
import { Entities } from 'soapbox/entity-store/entities';
import { useEntities } from 'soapbox/entity-store/hooks';
@@ -17,7 +17,7 @@ const useAccountList = (listKey: string[], entityFn: EntityFn<void>, opts: useAc
const { entities, ...rest } = useEntities<BaseAccount, Account>(
[Entities.ACCOUNTS, ...listKey],
entityFn,
{ schema: accountSchema, enabled: opts.enabled, transform: normalizeAccount },
{ schema: listKey[0] === 'mutes' ? mutedAccountSchema : accountSchema, enabled: opts.enabled, transform: normalizeAccount },
);
const { relationships } = useRelationships(

View File

@@ -1,9 +1,10 @@
import { groupMemberSchema, type Group, type GroupMember, type GroupRole } from 'pl-api';
import { groupMemberSchema, type Group, type GroupMember as GroupMember, type GroupRole } from 'pl-api';
import { z } from 'zod';
import { Entities } from 'soapbox/entity-store/entities';
import { useCreateEntity } from 'soapbox/entity-store/hooks';
import { useClient } from 'soapbox/hooks';
import { normalizeGroupMember } from 'soapbox/normalizers/group-member';
const useDemoteGroupMember = (group: Pick<Group, 'id'>, groupMember: Pick<GroupMember, 'id'>) => {
const client = useClient();
@@ -11,7 +12,7 @@ const useDemoteGroupMember = (group: Pick<Group, 'id'>, groupMember: Pick<GroupM
const { createEntity } = useCreateEntity(
[Entities.GROUP_MEMBERSHIPS, groupMember.id],
({ account_ids, role }: { account_ids: string[]; role: GroupRole }) => client.experimental.groups.demoteGroupUsers(group.id, account_ids, role),
{ schema: z.array(groupMemberSchema).transform((arr) => arr[0]) },
{ schema: z.array(groupMemberSchema).transform((arr) => arr[0]), transform: normalizeGroupMember },
);
return createEntity;

View File

@@ -3,6 +3,7 @@ import { groupMemberSchema, type GroupMember, type GroupRoles } from 'pl-api';
import { Entities } from 'soapbox/entity-store/entities';
import { useEntities } from 'soapbox/entity-store/hooks';
import { useClient } from 'soapbox/hooks';
import { normalizeGroupMember } from 'soapbox/normalizers/group-member';
const useGroupMembers = (groupId: string, role: GroupRoles) => {
const client = useClient();
@@ -10,7 +11,7 @@ const useGroupMembers = (groupId: string, role: GroupRoles) => {
const { entities, ...result } = useEntities<GroupMember>(
[Entities.GROUP_MEMBERSHIPS, groupId, role],
() => client.experimental.groups.getGroupMemberships(groupId, role),
{ schema: groupMemberSchema },
{ schema: groupMemberSchema, transform: normalizeGroupMember },
);
return {

View File

@@ -1,10 +1,10 @@
import { groupSchema, type Group } from 'pl-api';
import { groupSchema, type Group as BaseGroup } from 'pl-api';
import { Entities } from 'soapbox/entity-store/entities';
import { useEntities } from 'soapbox/entity-store/hooks';
import { useClient } from 'soapbox/hooks';
import { useFeatures } from 'soapbox/hooks/useFeatures';
import { normalizeGroup } from 'soapbox/normalizers';
import { normalizeGroup, type Group } from 'soapbox/normalizers';
import { useGroupRelationships } from './useGroupRelationships';
@@ -12,7 +12,7 @@ const useGroups = () => {
const client = useClient();
const features = useFeatures();
const { entities, ...result } = useEntities<Group>(
const { entities, ...result } = useEntities<BaseGroup, Group>(
[Entities.GROUPS, 'search', ''],
() => client.experimental.groups.getGroups(),
{ enabled: features.groups, schema: groupSchema, transform: normalizeGroup },

View File

@@ -4,6 +4,7 @@ import { z } from 'zod';
import { Entities } from 'soapbox/entity-store/entities';
import { useCreateEntity } from 'soapbox/entity-store/hooks';
import { useClient } from 'soapbox/hooks';
import { normalizeGroupMember } from 'soapbox/normalizers/group-member';
import type { Group, GroupMember, GroupRole } from 'pl-api';
@@ -13,7 +14,7 @@ const usePromoteGroupMember = (group: Pick<Group, 'id'>, groupMember: Pick<Group
const { createEntity } = useCreateEntity(
[Entities.GROUP_MEMBERSHIPS, groupMember.id],
({ account_ids, role }: { account_ids: string[]; role: GroupRole }) => client.experimental.groups.promoteGroupUsers(group.id, account_ids, role),
{ schema: z.array(groupMemberSchema).transform((arr) => arr[0]) },
{ schema: z.array(groupMemberSchema).transform((arr) => arr[0]), transform: normalizeGroupMember },
);
return createEntity;

View File

@@ -10,7 +10,7 @@ import Icon from './icon';
import { Button, HStack, Stack, Text } from './ui';
import VerificationBadge from './verification-badge';
import type { Status as StatusEntity } from 'soapbox/types/entities';
import type { Status as StatusEntity } from 'soapbox/normalizers';
const messages = defineMessages({
eventBanner: { id: 'event.banner', defaultMessage: 'Event banner' },

View File

@@ -1,5 +1,5 @@
import clsx from 'clsx';
import { type MediaAttachment, mediaAttachmentSchema } from 'pl-api';
import { type MediaAttachment, type PreviewCard as CardEntity, mediaAttachmentSchema } from 'pl-api';
import React, { useState, useEffect } from 'react';
import Blurhash from 'soapbox/components/blurhash';
@@ -7,8 +7,6 @@ import { HStack, Stack, Text, Icon } from 'soapbox/components/ui';
import { addAutoPlay } from 'soapbox/utils/media';
import { getTextDirection } from 'soapbox/utils/rtl';
import type { Card as CardEntity } from 'soapbox/types/entities';
/** Props for `PreviewCard`. */
interface IPreviewCard {
card: CardEntity;

View File

@@ -14,7 +14,7 @@ import StatusContent from './status-content';
import StatusReplyMentions from './status-reply-mentions';
import SensitiveContentOverlay from './statuses/sensitive-content-overlay';
import type { Status as StatusEntity } from 'soapbox/types/entities';
import type { ReducerStatus as StatusEntity } from 'soapbox/reducers/statuses';
const messages = defineMessages({
cancel: { id: 'reply_indicator.cancel', defaultMessage: 'Cancel' },

View File

@@ -15,7 +15,7 @@ import { useAppDispatch, useAppSelector, useFeatures, useInstance } from 'soapbo
import { makeGetOtherAccounts } from 'soapbox/selectors';
import type { List as ImmutableList } from 'immutable';
import type { Account as AccountEntity } from 'soapbox/types/entities';
import type { Account as AccountEntity } from 'soapbox/normalizers';
const messages = defineMessages({
profile: { id: 'account.profile', defaultMessage: 'Profile' },
@@ -336,7 +336,7 @@ const SidebarMenu: React.FC = (): JSX.Element | null => {
/>
)}
{account.staff && (
{(account.is_admin || account.is_moderator) && (
<SidebarLink
to='/dashboard'
icon={require('@tabler/icons/outline/dashboard.svg')}

View File

@@ -30,8 +30,7 @@ import { getReactForStatus, reduceEmoji } from 'soapbox/utils/emoji-reacts';
import GroupPopover from './groups/popover/group-popover';
import type { Menu } from 'soapbox/components/dropdown-menu';
import type { Account, Group } from 'soapbox/normalizers';
import type { Status } from 'soapbox/types/entities';
import type { Account, Group, Status } from 'soapbox/normalizers';
const messages = defineMessages({
adminAccount: { id: 'status.admin_account', defaultMessage: 'Moderate @{name}' },

View File

@@ -15,7 +15,7 @@ import Markup from './markup';
import Poll from './polls/poll';
import type { Sizes } from 'soapbox/components/ui/text/text';
import type { Status } from 'soapbox/types/entities';
import type { Status } from 'soapbox/normalizers';
const MAX_HEIGHT = 642; // 20px * 32 (+ 2px padding at the top)
const BIG_EMOJI_LIMIT = 10;

View File

@@ -8,7 +8,7 @@ import { useAppDispatch } from 'soapbox/hooks';
import DropdownMenu from './dropdown-menu';
import { HStack, Icon, Text } from './ui';
import type { Status } from 'soapbox/types/entities';
import type { Status } from 'soapbox/normalizers';
const messages = defineMessages({
languageVersions: { id: 'status.language_versions', defaultMessage: 'The post has multiple language versions.' },

View File

@@ -9,7 +9,7 @@ import { useAppDispatch, useSettings } from 'soapbox/hooks';
import { defaultMediaVisibility } from 'soapbox/utils/status';
import type { MediaAttachment } from 'pl-api';
import type { Status } from 'soapbox/types/entities';
import type { Status } from 'soapbox/normalizers';
interface IStatusMedia {
/** Status entity to render media for. */

View File

@@ -24,7 +24,7 @@ import SensitiveContentOverlay from './statuses/sensitive-content-overlay';
import StatusInfo from './statuses/status-info';
import { Card, Icon, Stack, Text } from './ui';
import type { Status as StatusEntity } from 'soapbox/types/entities';
import type { Status as StatusEntity } from 'soapbox/normalizers';
// Defined in components/scrollable-list
type ScrollPosition = { height: number; top: number };
@@ -84,7 +84,7 @@ const Status: React.FC<IStatus> = (props) => {
const [minHeight, setMinHeight] = useState(208);
const actualStatus = getActualStatus(status);
const actualStatus = getActualStatus<StatusEntity>(status);
const isReblog = status.reblog && typeof status.reblog === 'object';
const statusUrl = `/@${actualStatus.account.acct}/posts/${actualStatus.id}`;
const group = actualStatus.group;

View File

@@ -28,7 +28,7 @@ const useCreateEntity = <TEntity extends Entity = Entity, TTransformedEntity ext
const createEntity = async (
data: Data,
callbacks: EntityCallbacks<TEntity | TTransformedEntity, { response?: PlfeResponse }> = {},
callbacks: EntityCallbacks<TTransformedEntity, { response?: PlfeResponse }> = {},
): Promise<void> => {
const result = await setPromise(entityFn(data));
const schema = opts.schema || z.custom<TEntity>();
@@ -39,7 +39,7 @@ const useCreateEntity = <TEntity extends Entity = Entity, TTransformedEntity ext
dispatch(importEntities([entity], entityType, listKey, 'start'));
if (callbacks.onSuccess) {
callbacks.onSuccess(entity);
callbacks.onSuccess(entity as TTransformedEntity);
}
};

View File

@@ -14,8 +14,6 @@ import { type AccountGalleryAttachment, getAccountGallery } from 'soapbox/select
import MediaItem from './components/media-item';
import type { Status } from 'soapbox/types/entities';
interface ILoadMoreMedia {
maxId: string | null;
onLoadMore: (value: string | null) => void;
@@ -68,7 +66,7 @@ const AccountGallery = () => {
if (attachment.type === 'video') {
dispatch(openModal('VIDEO', { media: attachment, status: attachment.status, account: attachment.account }));
} else {
const media = (attachment.status as Status).media_attachments;
const media = attachment.status.media_attachments;
const index = media.findIndex((x) => x.id === attachment.id);
dispatch(openModal('MEDIA', { media, index, status: attachment.status }));

View File

@@ -8,7 +8,8 @@ import StatusMedia from 'soapbox/components/status-media';
import { HStack, Stack } from 'soapbox/components/ui';
import { useAppDispatch } from 'soapbox/hooks';
import type { AdminReport, Status } from 'soapbox/types/entities';
import type { Status } from 'soapbox/normalizers';
import type { AdminReport } from 'soapbox/types/entities';
const messages = defineMessages({
viewStatus: { id: 'admin.reports.actions.view_status', defaultMessage: 'View post' },

View File

@@ -5,7 +5,7 @@ import { openModal } from 'soapbox/actions/modals';
import { useAppDispatch, useAppSelector, useCompose, useFeatures } from 'soapbox/hooks';
import { makeGetStatus } from 'soapbox/selectors';
import type { Status as StatusEntity } from 'soapbox/types/entities';
import type { Status as StatusEntity } from 'soapbox/normalizers';
interface IReplyMentions {
composeId: string;

View File

@@ -46,7 +46,7 @@ const DraftStatusActionBar: React.FC<IDraftStatusActionBar> = ({ source, status
};
const handleEditClick = () => {
dispatch(setComposeToStatus(status, source.text, source.spoiler_text, source.content_type, false, source.draft_id, source.editorState));
dispatch(setComposeToStatus(status, status.poll, source.text, source.spoiler_text, source.content_type, false, source.draft_id, source.editorState));
dispatch(openModal('COMPOSE'));
};

View File

@@ -15,8 +15,8 @@ import { buildStatus } from '../builder';
import DraftStatusActionBar from './draft-status-action-bar';
import type { Status as StatusEntity } from 'soapbox/normalizers';
import type { DraftStatus as DraftStatusType } from 'soapbox/reducers/draft-statuses';
import type { Status as StatusEntity } from 'soapbox/types/entities';
interface IDraftStatus {
draftStatus: DraftStatusType;

View File

@@ -12,7 +12,7 @@ import QuotedStatus from 'soapbox/features/status/containers/quoted-status-conta
import { useAppDispatch, useAppSelector, useSoapboxConfig } from 'soapbox/hooks';
import { makeGetStatus } from 'soapbox/selectors';
import type { Status as StatusEntity } from 'soapbox/types/entities';
import type { Status as StatusEntity } from 'soapbox/normalizers';
type RouteParams = { statusId: string };

View File

@@ -10,8 +10,8 @@ import { useAppDispatch } from 'soapbox/hooks';
import MediaItem from '../account-gallery/components/media-item';
import type { Status } from 'soapbox/normalizers';
import type { AccountGalleryAttachment } from 'soapbox/selectors';
import type { Status } from 'soapbox/types/entities';
interface IGroupGallery {
params: { groupId: string };

View File

@@ -9,6 +9,7 @@ import { useAppDispatch, useAppSelector } from 'soapbox/hooks';
import NewListForm from './components/new-list-form';
import type { List as ListEntity } from 'pl-api';
import type { RootState } from 'soapbox/store';
const messages = defineMessages({
@@ -21,7 +22,7 @@ const getOrderedLists = createSelector([(state: RootState) => state.lists], list
return lists;
}
return lists.toList().filter((item) => !!item).sort((a, b) => a.title.localeCompare(b.title));
return lists.toList().filter((item): item is ListEntity => !!item).sort((a, b) => a.title.localeCompare(b.title));
});
const Lists: React.FC = () => {

View File

@@ -16,11 +16,10 @@ import { useAppDispatch, useAppSelector, useInstance } from 'soapbox/hooks';
import { makeGetNotification } from 'soapbox/selectors';
import { NotificationType } from 'soapbox/utils/notification';
import type { Account, Notification as BaseNotification } from 'pl-api';
import type { Notification as BaseNotification } from 'pl-api';
import type { ScrollPosition } from 'soapbox/components/status';
import type { Notification as NotificationEntity } from 'soapbox/normalizers';
import type { Account, Notification as NotificationEntity, Status as StatusEntity } from 'soapbox/normalizers';
import type { MinifiedNotification } from 'soapbox/reducers/notifications';
import type { Status as StatusEntity } from 'soapbox/types/entities';
const notificationForScreenReader = (intl: IntlShape, message: string, timestamp: string) => {
const output = [message];
@@ -290,7 +289,7 @@ const Notification: React.FC<INotification> = (props) => {
} else if (icons[type]) {
return (
<Icon
src={icons[type]}
src={icons[type]!}
className='flex-none text-primary-600 dark:text-primary-400'
/>
);

View File

@@ -7,7 +7,7 @@ import { getSettings } from 'soapbox/actions/settings';
import { Button, HStack } from 'soapbox/components/ui';
import { useAppDispatch } from 'soapbox/hooks';
import type { Status as StatusEntity } from 'soapbox/types/entities';
import type { Status as StatusEntity } from 'soapbox/normalizers';
const messages = defineMessages({
cancel: { id: 'scheduled_status.cancel', defaultMessage: 'Cancel' },

View File

@@ -34,11 +34,11 @@ const MfaForm: React.FC = () => {
setDisplayOtpForm(true);
};
const mfa = useAppSelector((state) => state.security.get('mfa'));
const mfa = useAppSelector((state) => state.security.mfa);
return (
<Column label={intl.formatMessage(messages.heading)}>
{mfa.getIn(['settings', 'totp']) ? (
{mfa.settings.totp ? (
<DisableOtpForm />
) : (
<Stack space={4}>

View File

@@ -16,7 +16,7 @@ import { getActualStatus } from 'soapbox/utils/status';
import StatusInteractionBar from './status-interaction-bar';
import type { Status as StatusEntity } from 'soapbox/types/entities';
import type { Status as StatusEntity } from 'soapbox/normalizers';
interface IDetailedStatus {
status: StatusEntity;
@@ -81,7 +81,7 @@ const DetailedStatus: React.FC<IDetailedStatus> = ({
}
};
const actualStatus = getActualStatus(status);
const actualStatus = getActualStatus<StatusEntity>(status);
if (!actualStatus) return null;
const { account } = actualStatus;
if (!account || typeof account !== 'object') return null;

View File

@@ -8,7 +8,7 @@ import { HStack, Text, Emoji } from 'soapbox/components/ui';
import { useAppSelector, useSoapboxConfig, useFeatures, useAppDispatch } from 'soapbox/hooks';
import { reduceEmoji } from 'soapbox/utils/emoji-reacts';
import type { Status } from 'soapbox/types/entities';
import type { Status } from 'soapbox/normalizers';
interface IStatusInteractionBar {
status: Status;

View File

@@ -25,7 +25,7 @@ import { textForScreenReader } from 'soapbox/utils/status';
import DetailedStatus from './detailed-status';
import ThreadStatus from './thread-status';
import type { Account, Status } from 'soapbox/types/entities';
import type { Account, Status } from 'soapbox/normalizers';
const getAncestorsIds = createSelector([
(_: RootState, statusId: string | undefined) => statusId,

View File

@@ -5,7 +5,7 @@ import Icon from 'soapbox/components/icon';
import { Modal, Stack, Text } from 'soapbox/components/ui';
import ReplyIndicator from 'soapbox/features/compose/components/reply-indicator';
import type { Status as StatusEntity } from 'soapbox/types/entities';
import type { Status as StatusEntity } from 'soapbox/normalizers';
const messages = defineMessages({
cancel_reblog: { id: 'status.cancel_reblog_private', defaultMessage: 'Un-repost' },
@@ -14,7 +14,7 @@ const messages = defineMessages({
interface IBoostModal {
status: StatusEntity;
onReblog: (status: StatusEntity) => void;
onReblog: (status: Pick<StatusEntity, 'id' | 'reblogged'>) => void;
onClose: () => void;
}

View File

@@ -20,7 +20,7 @@ import { makeGetStatus } from 'soapbox/selectors';
import ImageLoader from '../image-loader';
import type { MediaAttachment } from 'pl-api';
import type { Status } from 'soapbox/types/entities';
import type { Status } from 'soapbox/normalizers';
const messages = defineMessages({
close: { id: 'lightbox.close', defaultMessage: 'Close' },

View File

@@ -9,7 +9,7 @@ import NewFolderForm from 'soapbox/features/bookmark-folders/components/new-fold
import { useAppDispatch, useAppSelector } from 'soapbox/hooks';
import { makeGetStatus } from 'soapbox/selectors';
import type { Status as StatusEntity } from 'soapbox/types/entities';
import type { Status as StatusEntity } from 'soapbox/normalizers';
interface ISelectBookmarkFolderModal {
statusId: string;

View File

@@ -5,7 +5,7 @@ import { useHistory } from 'react-router-dom';
import Video from 'soapbox/features/video';
import type { MediaAttachment } from 'pl-api';
import type { Status, Account } from 'soapbox/types/entities';
import type { Account, Status } from 'soapbox/normalizers';
interface IVideoModal {
media: MediaAttachment;

View File

@@ -14,7 +14,7 @@ import { buildStatus } from '../util/pending-status-builder';
import PollPreview from './poll-preview';
import type { Status as StatusEntity } from 'soapbox/types/entities';
import type { Status as StatusEntity } from 'soapbox/normalizers';
const shouldHaveCard = (pendingStatus: StatusEntity) => Boolean(pendingStatus.content.match(/https?:\/\/\S*/));
@@ -47,7 +47,7 @@ const PendingStatus: React.FC<IPendingStatus> = ({ idempotencyKey, className, mu
const status = useAppSelector((state) => {
const pendingStatus = state.pending_statuses.get(idempotencyKey);
return pendingStatus ? buildStatus(state, pendingStatus, idempotencyKey) : null;
}) as StatusEntity | null;
});
if (!status) return null;
if (!status.account) return null;
@@ -89,7 +89,7 @@ const PendingStatus: React.FC<IPendingStatus> = ({ idempotencyKey, className, mu
{status.poll && <PollPreview poll={status.poll} />}
{status.quote && <QuotedStatus statusId={status.quote as string} />}
{status.quote && <QuotedStatus statusId={status.quote.id} />}
</Stack>
</div>

View File

@@ -13,7 +13,7 @@ import { makeGetAccount } from 'soapbox/selectors';
import ThemeToggle from './theme-toggle';
import type { Account as AccountEntity } from 'soapbox/types/entities';
import type { Account as AccountEntity } from 'soapbox/normalizers';
const messages = defineMessages({
add: { id: 'profile_dropdown.add_account', defaultMessage: 'Add an existing account' },

View File

@@ -6,7 +6,7 @@ import { IconButton } from 'soapbox/components/ui';
import { useFeatures } from 'soapbox/hooks';
import toast from 'soapbox/toast';
import type { Account as AccountEntity } from 'soapbox/types/entities';
import type { Account as AccountEntity } from 'soapbox/normalizers';
const messages = defineMessages({
subscribe: { id: 'account.subscribe', defaultMessage: 'Subscribe to notifications from @{name}' },

View File

@@ -7,7 +7,7 @@ import AccountContainer from 'soapbox/containers/account-container';
import PlaceholderSidebarSuggestions from 'soapbox/features/placeholder/components/placeholder-sidebar-suggestions';
import { useDismissSuggestion, useSuggestions } from 'soapbox/queries/suggestions';
import type { Account as AccountEntity } from 'soapbox/types/entities';
import type { Account as AccountEntity } from 'soapbox/normalizers';
const messages = defineMessages({
dismissSuggestion: { id: 'suggestions.dismiss', defaultMessage: 'Dismiss suggestion' },

View File

@@ -41,7 +41,7 @@ const buildStatus = (state: RootState, pendingStatus: PendingStatus, idempotency
media_attachments: (pendingStatus.media_ids || ImmutableList()).map((id: string) => ({ id })),
mentions: buildMentions(pendingStatus),
poll: buildPoll(pendingStatus),
quote: pendingStatus.quote_id,
quote: pendingStatus.quote_id ? state.statuses.get(pendingStatus.quote_id) : null,
sensitive: pendingStatus.sensitive,
visibility: pendingStatus.visibility,
};

View File

@@ -37,6 +37,7 @@ const normalizeAccount = (account: BaseAccount) => {
const emojiMap = makeEmojiMap(account.emojis);
return {
mute_expires_at: null,
...account,
avatar: account.avatar || account.avatar_static || missingAvatar,
avatar_static: account.avatar_static || account.avatar || missingAvatar,

View File

@@ -9,7 +9,8 @@ import {
fromJS,
} from 'immutable';
import type { Account, EmbeddedEntity } from 'soapbox/types/entities';
import type { Account } from 'soapbox/normalizers';
import type { EmbeddedEntity } from 'soapbox/types/entities';
const AdminAccountRecord = ImmutableRecord({
account: null as EmbeddedEntity<Account>,

View File

@@ -9,7 +9,8 @@ import {
fromJS,
} from 'immutable';
import type { Account, EmbeddedEntity, Status } from 'soapbox/types/entities';
import type { Account, Status } from 'soapbox/normalizers';
import type { EmbeddedEntity } from 'soapbox/types/entities';
const AdminReportRecord = ImmutableRecord({
account: null as EmbeddedEntity<Account>,

View File

@@ -331,7 +331,7 @@ const compose = (state = initialState, action: ComposeAction | EventsAction | Me
? statusToMentionsArray(action.status, action.account, action.rebloggedBy)
: ImmutableOrderedSet<string>();
map.set('group_id', action.status.group?.id as string);
map.set('group_id', typeof action.status.group === 'string' ? action.status.group : action.status.group?.id || null);
map.set('in_reply_to', action.status.id);
map.set('to', to);
map.set('parent_reblogged_by', action.rebloggedBy?.id || null);
@@ -371,7 +371,7 @@ const compose = (state = initialState, action: ComposeAction | EventsAction | Me
map.set('spoiler_text', '');
if (action.status.visibility === 'group') {
map.set('group_id', action.status.group?.id as string);
map.set('group_id', typeof action.status.group === 'string' ? action.status.group : action.status.group?.id || null);
map.set('privacy', 'group');
}
}));
@@ -474,8 +474,8 @@ const compose = (state = initialState, action: ComposeAction | EventsAction | Me
map.set('caretPosition', null);
map.set('idempotencyKey', uuid());
map.set('content_type', action.contentType || 'text/plain');
map.set('quote', action.status.quote?.id as string);
map.set('group_id', action.status.group?.id as string);
map.set('quote', typeof action.status.quote === 'string' ? action.status.quote : action.status.quote?.id || null);
map.set('group_id', typeof action.status.group === 'string' ? action.status.group : action.status.group?.id || null);
if (action.v?.software === PLEROMA && action.withRedraft && hasIntegerMediaIds(action.status)) {
map.set('media_attachments', ImmutableList());