diff --git a/package.json b/package.json
index 3ef9bce45..fd29adda9 100644
--- a/package.json
+++ b/package.json
@@ -119,7 +119,7 @@
"html-react-parser": "^5.0.0",
"http-link-header": "^1.0.2",
"immer": "^10.0.0",
- "immutable": "^4.2.1",
+ "immutable": "^4.3.7",
"intersection-observer": "^0.12.2",
"intl-messageformat": "10.5.11",
"intl-pluralrules": "^2.0.0",
diff --git a/src/actions/compose.ts b/src/actions/compose.ts
index e7d431589..1f6dea9ba 100644
--- a/src/actions/compose.ts
+++ b/src/actions/compose.ts
@@ -20,7 +20,7 @@ import { getSettings } from './settings';
import { createStatus } from './statuses';
import type { EditorState } from 'lexical';
-import type { Tag } from 'pl-api';
+import type { CreateStatusParams, Tag } from 'pl-api';
import type { AutoSuggestion } from 'soapbox/components/autosuggest-input';
import type { Emoji } from 'soapbox/features/emoji';
import type { Account, Group } from 'soapbox/schemas';
@@ -373,22 +373,31 @@ const submitCompose = (composeId: string, opts: SubmitComposeOpts = {}) =>
const idempotencyKey = compose.idempotencyKey;
const contentType = compose.content_type === 'wysiwyg' ? 'text/markdown' : compose.content_type;
- const params: Record = {
+ const params: CreateStatusParams = {
status,
- in_reply_to_id: compose.in_reply_to,
- quote_id: compose.quote,
- media_ids: media.map(item => item.id),
+ in_reply_to_id: compose.in_reply_to || undefined,
+ quote_id: compose.quote || undefined,
+ media_ids: media.map(item => item.id).toArray(),
sensitive: compose.sensitive,
spoiler_text: compose.spoiler_text,
visibility: compose.privacy,
content_type: contentType,
- poll: compose.poll,
- scheduled_at: compose.schedule,
- language: compose.language || compose.suggested_language,
- to,
+ scheduled_at: compose.schedule?.toISOString(),
+ language: compose.language || compose.suggested_language || undefined,
+ to: to.size ? to.toArray() : undefined,
federated: compose.federated,
};
+ if (compose.poll) {
+ params.poll = {
+ options: compose.poll.options.toArray(),
+ expires_in: compose.poll.expires_in,
+ multiple: compose.poll.multiple,
+ hide_totals: compose.poll.hide_totals,
+ options_map: compose.poll.options_map.toJS(),
+ };
+ }
+
if (compose.language && compose.textMap.size) {
params.status_map = compose.textMap.toJS();
params.status_map[compose.language] = status;
@@ -398,14 +407,13 @@ const submitCompose = (composeId: string, opts: SubmitComposeOpts = {}) =>
params.spoiler_text_map[compose.language] = compose.spoiler_text;
}
- if (params.poll) {
- const poll = params.poll.toJS();
- poll.options.forEach((option: any, index: number) => poll.options_map[index][compose.language!] = option);
- params.poll = poll;
+ const poll = params.poll;
+ if (poll?.options_map) {
+ poll.options.forEach((option: any, index: number) => poll.options_map![index][compose.language!] = option);
}
}
- if (compose.privacy === 'group') {
+ if (compose.privacy === 'group' && compose.group_id) {
params.group_id = compose.group_id;
}
diff --git a/src/actions/notifications.ts b/src/actions/notifications.ts
index a87cdab88..53fc79fcb 100644
--- a/src/actions/notifications.ts
+++ b/src/actions/notifications.ts
@@ -283,7 +283,10 @@ const expandNotifications = ({ maxId }: Record = {}, done: () => an
acc.accounts[item.target.id] = item.target;
}
+ // TODO actually check for type
+ // @ts-ignore
if (item.status?.id) {
+ // @ts-ignore
acc.statuses[item.status.id] = item.status;
}
diff --git a/src/actions/statuses.ts b/src/actions/statuses.ts
index b7b9ea2cd..e7c1e65bb 100644
--- a/src/actions/statuses.ts
+++ b/src/actions/statuses.ts
@@ -64,16 +64,14 @@ const createStatus = (params: CreateStatusParams, idempotencyKey: string, status
return (statusId === null ? getClient(getState()).statuses.createStatus(params) : getClient(getState()).statuses.editStatus(statusId, params))
.then((status) => {
- // The backend might still be processing the rich media attachment
- if (!status.card && shouldHaveCard(status)) {
- status.expectsCard = true;
- }
+ // The backend might still be processing the rich media attachment
+ const expectsCard = !status.card && shouldHaveCard(status);
- dispatch(importFetchedStatus(status, idempotencyKey));
+ dispatch(importFetchedStatus({ ...status, expectsCard }, idempotencyKey));
dispatch({ type: STATUS_CREATE_SUCCESS, status, params, idempotencyKey, editing: !!statusId });
// Poll the backend for the updated card
- if (status.expectsCard) {
+ if (expectsCard) {
const delay = 1000;
const poll = (retries = 5) => {
diff --git a/src/api/hooks/accounts/useAccountLookup.ts b/src/api/hooks/accounts/useAccountLookup.ts
index a16f4e0d1..b9adda5c3 100644
--- a/src/api/hooks/accounts/useAccountLookup.ts
+++ b/src/api/hooks/accounts/useAccountLookup.ts
@@ -22,7 +22,7 @@ const useAccountLookup = (acct: string | undefined, opts: UseAccountLookupOpts =
const { entity: account, isUnauthorized, ...result } = useEntityLookup(
Entities.ACCOUNTS,
(account) => account.acct.toLowerCase() === acct?.toLowerCase(),
- () => client.accounts.lookupAccount(acct),
+ () => client.accounts.lookupAccount(acct!),
{ schema: accountSchema, enabled: !!acct },
);
diff --git a/src/api/hooks/announcements/useAnnouncements.ts b/src/api/hooks/announcements/useAnnouncements.ts
index fa91865d0..06cf52d90 100644
--- a/src/api/hooks/announcements/useAnnouncements.ts
+++ b/src/api/hooks/announcements/useAnnouncements.ts
@@ -1,8 +1,25 @@
import { useMutation, useQuery } from '@tanstack/react-query';
-import { announcementReactionSchema, announcementSchema, type Announcement, type AnnouncementReaction } from 'pl-api';
+import { announcementReactionSchema, type Announcement as BaseAnnouncement, type AnnouncementReaction } from 'pl-api';
+import emojify from 'soapbox/features/emoji';
import { useClient } from 'soapbox/hooks';
import { queryClient } from 'soapbox/queries/client';
+import { makeCustomEmojiMap } from 'soapbox/schemas/utils';
+
+interface Announcement extends BaseAnnouncement {
+ contentHtml: string;
+}
+
+const transformAnnouncement = (announcement: BaseAnnouncement) => {
+ const emojiMap = makeCustomEmojiMap(announcement.emojis);
+
+ const contentHtml = emojify(announcement.content, emojiMap);
+
+ return {
+ ...announcement,
+ contentHtml,
+ };
+};
const updateReaction = (reaction: AnnouncementReaction, count: number, me?: boolean, overwrite?: boolean) => announcementReactionSchema.parse({
...reaction,
@@ -25,7 +42,7 @@ const useAnnouncements = () => {
const getAnnouncements = async () => {
const data = await client.announcements.getAnnouncements();
- return data;
+ return data.map(transformAnnouncement);
};
const { data, ...result } = useQuery>({
@@ -42,18 +59,18 @@ const useAnnouncements = () => {
retry: false,
onMutate: ({ announcementId: id, name }) => {
queryClient.setQueryData(['announcements'], (prevResult: Announcement[]) =>
- prevResult.map(value => value.id !== id ? value : announcementSchema.parse({
+ prevResult.map(value => value.id !== id ? value : {
...value,
reactions: updateReactions(value.reactions, name, 1, true),
- })),
+ }),
);
},
onError: (_, { announcementId: id, name }) => {
queryClient.setQueryData(['announcements'], (prevResult: Announcement[]) =>
- prevResult.map(value => value.id !== id ? value : announcementSchema.parse({
+ prevResult.map(value => value.id !== id ? value : {
...value,
reactions: updateReactions(value.reactions, name, -1, false),
- })),
+ }),
);
},
});
@@ -66,18 +83,18 @@ const useAnnouncements = () => {
retry: false,
onMutate: ({ announcementId: id, name }) => {
queryClient.setQueryData(['announcements'], (prevResult: Announcement[]) =>
- prevResult.map(value => value.id !== id ? value : announcementSchema.parse({
+ prevResult.map(value => value.id !== id ? value : {
...value,
reactions: updateReactions(value.reactions, name, -1, false),
- })),
+ }),
);
},
onError: (_, { announcementId: id, name }) => {
queryClient.setQueryData(['announcements'], (prevResult: Announcement[]) =>
- prevResult.map(value => value.id !== id ? value : announcementSchema.parse({
+ prevResult.map(value => value.id !== id ? value : {
...value,
reactions: updateReactions(value.reactions, name, 1, true),
- })),
+ }),
);
},
});
@@ -93,4 +110,4 @@ const useAnnouncements = () => {
const compareAnnouncements = (a: Announcement, b: Announcement): number =>
new Date(a.starts_at || a.published_at).getDate() - new Date(b.starts_at || b.published_at).getDate();
-export { updateReactions, useAnnouncements };
+export { updateReactions, useAnnouncements, type Announcement };
diff --git a/src/api/hooks/groups/useCreateGroup.ts b/src/api/hooks/groups/useCreateGroup.ts
index 2217ec800..981df176e 100644
--- a/src/api/hooks/groups/useCreateGroup.ts
+++ b/src/api/hooks/groups/useCreateGroup.ts
@@ -4,7 +4,7 @@ import { useClient } from 'soapbox/hooks';
import { groupSchema } from 'soapbox/schemas';
interface CreateGroupParams {
- display_name?: string;
+ display_name: string;
note?: string;
avatar?: File;
header?: File;
diff --git a/src/api/hooks/statuses/useBookmarkFolders.ts b/src/api/hooks/statuses/useBookmarkFolders.ts
index 07d398b97..32ebc49c2 100644
--- a/src/api/hooks/statuses/useBookmarkFolders.ts
+++ b/src/api/hooks/statuses/useBookmarkFolders.ts
@@ -10,7 +10,7 @@ const useBookmarkFolders = () => {
const { entities, ...result } = useEntities(
[Entities.BOOKMARK_FOLDERS],
- () => client.myAccount.getBookmarkFolders,
+ () => client.myAccount.getBookmarkFolders(),
{ enabled: features.bookmarkFolders, schema: bookmarkFolderSchema },
);
diff --git a/src/api/hooks/statuses/useDeleteBookmarkFolder.ts b/src/api/hooks/statuses/useDeleteBookmarkFolder.ts
index 2ec9d36d7..f5058438b 100644
--- a/src/api/hooks/statuses/useDeleteBookmarkFolder.ts
+++ b/src/api/hooks/statuses/useDeleteBookmarkFolder.ts
@@ -2,12 +2,12 @@ import { Entities } from 'soapbox/entity-store/entities';
import { useDeleteEntity } from 'soapbox/entity-store/hooks';
import { useClient } from 'soapbox/hooks';
-const useDeleteBookmarkFolder = (folderId: string) => {
+const useDeleteBookmarkFolder = () => {
const client = useClient();
const { deleteEntity, isSubmitting } = useDeleteEntity(
Entities.BOOKMARK_FOLDERS,
- () => client.myAccount.deleteBookmarkFolder(folderId),
+ (folderId: string) => client.myAccount.deleteBookmarkFolder(folderId),
);
return {
diff --git a/src/components/announcements/announcement-content.tsx b/src/components/announcements/announcement-content.tsx
index 108b06452..c65325d2f 100644
--- a/src/components/announcements/announcement-content.tsx
+++ b/src/components/announcements/announcement-content.tsx
@@ -3,10 +3,11 @@ import { useHistory } from 'react-router-dom';
import { getTextDirection } from 'soapbox/utils/rtl';
-import type { Announcement as AnnouncementEntity, Mention as MentionEntity } from 'soapbox/schemas';
+import type { Announcement } from 'soapbox/api/hooks/announcements/useAnnouncements';
+import type { Mention as MentionEntity } from 'soapbox/schemas';
interface IAnnouncementContent {
- announcement: AnnouncementEntity;
+ announcement: Announcement;
}
const AnnouncementContent: React.FC = ({ announcement }) => {
diff --git a/src/components/announcements/announcement.tsx b/src/components/announcements/announcement.tsx
index b1467a9cf..759c0bffd 100644
--- a/src/components/announcements/announcement.tsx
+++ b/src/components/announcements/announcement.tsx
@@ -9,7 +9,7 @@ import AnnouncementContent from './announcement-content';
import ReactionsBar from './reactions-bar';
import type { Map as ImmutableMap } from 'immutable';
-import type { Announcement as AnnouncementEntity } from 'soapbox/schemas';
+import type { Announcement as AnnouncementEntity } from 'soapbox/api/hooks/announcements/useAnnouncements';
interface IAnnouncement {
announcement: AnnouncementEntity;
diff --git a/src/components/announcements/announcements-panel.tsx b/src/components/announcements/announcements-panel.tsx
index cc3676330..2e3619e62 100644
--- a/src/components/announcements/announcements-panel.tsx
+++ b/src/components/announcements/announcements-panel.tsx
@@ -31,7 +31,7 @@ const AnnouncementsPanel = () => {
}>
- {announcements!.map((announcement) => (
+ {announcements.map((announcement) => (
({
isOpen: false,
@@ -69,7 +71,7 @@ const ChatProvider: React.FC = ({ children }) => {
};
interface IChatContext {
- chat: IChat | null;
+ chat: Chat | null;
isOpen: boolean;
isUsingMainChatPage?: boolean;
toggleChatPane(): void;
diff --git a/src/entity-store/hooks/useBatchedEntities.ts b/src/entity-store/hooks/useBatchedEntities.ts
index 7c4889989..3ba102e80 100644
--- a/src/entity-store/hooks/useBatchedEntities.ts
+++ b/src/entity-store/hooks/useBatchedEntities.ts
@@ -23,7 +23,7 @@ interface UseBatchedEntitiesOpts {
const useBatchedEntities = (
expandedPath: ExpandedEntitiesPath,
ids: string[],
- entityFn: EntityFn,
+ entityFn: EntityFn,
opts: UseBatchedEntitiesOpts = {},
) => {
const getState = useGetState();
diff --git a/src/entity-store/hooks/useEntity.ts b/src/entity-store/hooks/useEntity.ts
index 1c03a0ab8..4e6a1ed72 100644
--- a/src/entity-store/hooks/useEntity.ts
+++ b/src/entity-store/hooks/useEntity.ts
@@ -24,7 +24,7 @@ interface UseEntityOpts {
const useEntity = (
path: EntityPath,
- entityFn: EntityFn,
+ entityFn: EntityFn,
opts: UseEntityOpts = {},
) => {
const [isFetching, setPromise] = useLoading(true);
diff --git a/src/entity-store/utils.ts b/src/entity-store/utils.ts
index 2aac06a17..9167a40f4 100644
--- a/src/entity-store/utils.ts
+++ b/src/entity-store/utils.ts
@@ -37,8 +37,8 @@ const createList = (): EntityList => ({
/** Create an empty entity list state. */
const createListState = (): EntityListState => ({
- next: undefined,
- prev: undefined,
+ next: null,
+ prev: null,
totalCount: 0,
error: null,
fetched: false,
diff --git a/src/features/auth-login/components/registration-form.tsx b/src/features/auth-login/components/registration-form.tsx
index 3795b3175..aaf30cb22 100644
--- a/src/features/auth-login/components/registration-form.tsx
+++ b/src/features/auth-login/components/registration-form.tsx
@@ -13,6 +13,8 @@ import { Checkbox, Form, FormGroup, FormActions, Button, Input, Textarea, Select
import CaptchaField from 'soapbox/features/auth-login/components/captcha';
import { useAppDispatch, useSettings, useFeatures, useInstance } from 'soapbox/hooks';
+import type { CreateAccountParams } from 'pl-api';
+
const messages = defineMessages({
username: { id: 'registration.fields.username_placeholder', defaultMessage: 'Username' },
username_hint: { id: 'registration.fields.username_hint', defaultMessage: 'Only letters, numbers, and underscores are allowed.' },
@@ -53,7 +55,13 @@ const RegistrationForm: React.FC = ({ inviteToken }) => {
const [captchaLoading, setCaptchaLoading] = useState(true);
const [submissionLoading, setSubmissionLoading] = useState(false);
- const [params, setParams] = useState(ImmutableMap());
+ const [params, setParams] = useState({
+ username: '',
+ email: '',
+ password: '',
+ agreement: false,
+ locale: '',
+ });
const [captchaIdempotencyKey, setCaptchaIdempotencyKey] = useState(uuidv4());
const [usernameUnavailable, setUsernameUnavailable] = useState(false);
const [passwordConfirmation, setPasswordConfirmation] = useState('');
@@ -61,39 +69,35 @@ const RegistrationForm: React.FC = ({ inviteToken }) => {
const controller = useRef(new AbortController());
- const updateParams = (map: any) => {
- setParams(params.merge(ImmutableMap(map)));
- };
-
const onInputChange: React.ChangeEventHandler = e => {
- updateParams({ [e.target.name]: e.target.value });
+ setParams(params => ({ ...params, [e.target.name]: e.target.value }));
};
const onUsernameChange: React.ChangeEventHandler = e => {
- updateParams({ username: e.target.value });
+ setParams(params => ({ ...params, username: e.target.value }));
setUsernameUnavailable(false);
controller.current.abort();
controller.current = new AbortController();
- const domain = params.get('domain');
+ const domain = params.domain;
usernameAvailable(e.target.value, domain ? domains!.find(({ id }) => id === domain)?.domain : undefined);
};
const onDomainChange: React.ChangeEventHandler = e => {
- updateParams({ domain: e.target.value || null });
+ setParams(params => ({ ...params, domain: e.target.value || undefined }));
setUsernameUnavailable(false);
controller.current.abort();
controller.current = new AbortController();
- const username = params.get('username');
+ const username = params.username;
if (username) {
usernameAvailable(username, domains!.find(({ id }) => id === e.target.value)?.domain);
}
};
const onCheckboxChange: React.ChangeEventHandler = e => {
- updateParams({ [e.target.name]: e.target.checked });
+ setParams(params => ({ ...params, [e.target.name]: e.target.checked }));
};
const onPasswordChange: React.ChangeEventHandler = e => {
@@ -106,7 +110,7 @@ const RegistrationForm: React.FC = ({ inviteToken }) => {
};
const onPasswordConfirmChange: React.ChangeEventHandler = e => {
- const password = params.get('password', '');
+ const password = params.password || '';
const passwordConfirmation = e.target.value;
setPasswordConfirmation(passwordConfirmation);
@@ -120,7 +124,7 @@ const RegistrationForm: React.FC = ({ inviteToken }) => {
};
const onBirthdayChange = (birthday: string) => {
- updateParams({ birthday });
+ setParams(params => ({ ...params, birthday }));
};
const launchModal = () => {
@@ -129,7 +133,7 @@ const RegistrationForm: React.FC = ({ inviteToken }) => {
{params.get('email')} }}
+ values={{ email: {params.email} }}
/>
}
{needsApproval &&
= ({ inviteToken }) => {
}
};
- const passwordsMatch = () => params.get('password', '') === passwordConfirmation;
+ const passwordsMatch = () => params.password === passwordConfirmation;
const usernameAvailable = useCallback(debounce((username, domain?: string) => {
if (!supportsAccountLookup) return;
@@ -186,19 +190,18 @@ const RegistrationForm: React.FC = ({ inviteToken }) => {
return;
}
- const normalParams = params.withMutations(params => {
- // Locale for confirmation email
- params.set('locale', locale);
+ const normalParams = {
+ ...params,
+ locale,
+ };
- // Pleroma invites
- if (inviteToken) {
- params.set('token', inviteToken);
- }
- });
+ if (inviteToken) {
+ params.token = inviteToken;
+ }
setSubmissionLoading(true);
- dispatch(register(normalParams.toJS()))
+ dispatch(register(normalParams))
.then(postRegisterAction)
.catch(() => {
setSubmissionLoading(false);
@@ -212,10 +215,11 @@ const RegistrationForm: React.FC = ({ inviteToken }) => {
const onFetchCaptcha = (captcha: ImmutableMap) => {
setCaptchaLoading(false);
- updateParams({
+ setParams(params => ({
+ ...params,
captcha_token: captcha.get('token'),
captcha_answer_data: captcha.get('answer_data'),
- });
+ }));
};
const onFetchCaptchaFail = () => {
@@ -224,7 +228,7 @@ const RegistrationForm: React.FC = ({ inviteToken }) => {
const refreshCaptcha = () => {
setCaptchaIdempotencyKey(uuidv4());
- updateParams({ captcha_solution: '' });
+ setParams(params => ({ ...params, captcha_solution: '' }));
};
const isLoading = captchaLoading || submissionLoading;
@@ -247,7 +251,7 @@ const RegistrationForm: React.FC = ({ inviteToken }) => {
pattern='^[a-zA-Z\d_-]+'
icon={require('@tabler/icons/outline/at.svg')}
onChange={onUsernameChange}
- value={params.get('username', '')}
+ value={params.username}
required
/>
@@ -256,7 +260,7 @@ const RegistrationForm: React.FC = ({ inviteToken }) => {
)}
diff --git a/src/features/chats/components/chat-list-item.tsx b/src/features/chats/components/chat-list-item.tsx
index 19a90dcb5..a320443b6 100644
--- a/src/features/chats/components/chat-list-item.tsx
+++ b/src/features/chats/components/chat-list-item.tsx
@@ -9,8 +9,9 @@ import { Avatar, HStack, IconButton, Stack, Text } from 'soapbox/components/ui';
import VerificationBadge from 'soapbox/components/verification-badge';
import { useChatContext } from 'soapbox/contexts/chat-context';
import { useAppDispatch, useAppSelector, useFeatures } from 'soapbox/hooks';
-import { IChat, useChatActions } from 'soapbox/queries/chats';
+import { useChatActions } from 'soapbox/queries/chats';
+import type { Chat } from 'pl-api';
import type { Menu } from 'soapbox/components/dropdown-menu';
const messages = defineMessages({
@@ -23,7 +24,7 @@ const messages = defineMessages({
});
interface IChatListItemInterface {
- chat: IChat;
+ chat: Chat;
onClick: (chat: any) => void;
}
diff --git a/src/features/chats/components/chat-message-list.tsx b/src/features/chats/components/chat-message-list.tsx
index 3f46ba1c6..4eefc81d3 100644
--- a/src/features/chats/components/chat-message-list.tsx
+++ b/src/features/chats/components/chat-message-list.tsx
@@ -5,10 +5,11 @@ import { Components, Virtuoso, VirtuosoHandle } from 'react-virtuoso';
import { Avatar, Button, Divider, Spinner, Stack, Text } from 'soapbox/components/ui';
import PlaceholderChatMessage from 'soapbox/features/placeholder/components/placeholder-chat-message';
import { useAppSelector } from 'soapbox/hooks';
-import { IChat, useChatActions, useChatMessages } from 'soapbox/queries/chats';
+import { useChatActions, useChatMessages } from 'soapbox/queries/chats';
import ChatMessage from './chat-message';
+import type { Chat } from 'pl-api';
import type { ChatMessage as ChatMessageEntity } from 'soapbox/types/entities';
const messages = defineMessages({
@@ -21,7 +22,7 @@ const messages = defineMessages({
type TimeFormat = 'today' | 'date';
-const timeChange = (prev: ChatMessageEntity, curr: ChatMessageEntity): TimeFormat | null => {
+const timeChange = (prev: Pick, curr: Pick): TimeFormat | null => {
const prevDate = new Date(prev.created_at).getDate();
const currDate = new Date(curr.created_at).getDate();
const nowDate = new Date().getDate();
@@ -57,7 +58,7 @@ const Scroller: Components['Scroller'] = React.forwardRef((props, ref) => {
interface IChatMessageList {
/** Chat the messages are being rendered from. */
- chat: IChat;
+ chat: Chat;
}
/** Scrollable list of chat messages. */
diff --git a/src/features/chats/components/chat-message.tsx b/src/features/chats/components/chat-message.tsx
index bf712941d..1e631369e 100644
--- a/src/features/chats/components/chat-message.tsx
+++ b/src/features/chats/components/chat-message.tsx
@@ -11,11 +11,12 @@ import { HStack, Icon, Stack, Text } from 'soapbox/components/ui';
import emojify from 'soapbox/features/emoji';
import { MediaGallery } from 'soapbox/features/ui/util/async-components';
import { useAppDispatch, useAppSelector } from 'soapbox/hooks';
-import { ChatKeys, IChat, useChatActions } from 'soapbox/queries/chats';
+import { ChatKeys, useChatActions } from 'soapbox/queries/chats';
import { queryClient } from 'soapbox/queries/client';
import { stripHTML } from 'soapbox/utils/html';
import { onlyEmoji } from 'soapbox/utils/rich-content';
+import type { Chat } from 'pl-api';
import type { Menu as IMenu } from 'soapbox/components/dropdown-menu';
import type { ChatMessage as ChatMessageEntity } from 'soapbox/types/entities';
@@ -43,7 +44,7 @@ const parseContent = (chatMessage: ChatMessageEntity) => {
};
interface IChatMessage {
- chat: IChat;
+ chat: Chat;
chatMessage: ChatMessageEntity;
}
diff --git a/src/features/chats/components/chat-page/components/chat-page-sidebar.tsx b/src/features/chats/components/chat-page/components/chat-page-sidebar.tsx
index 0f9e81ff3..fc33248e9 100644
--- a/src/features/chats/components/chat-page/components/chat-page-sidebar.tsx
+++ b/src/features/chats/components/chat-page/components/chat-page-sidebar.tsx
@@ -3,10 +3,11 @@ import { defineMessages, useIntl } from 'react-intl';
import { useHistory } from 'react-router-dom';
import { CardTitle, HStack, IconButton, Stack } from 'soapbox/components/ui';
-import { IChat } from 'soapbox/queries/chats';
import ChatList from '../../chat-list';
+import type { Chat } from 'pl-api';
+
const messages = defineMessages({
title: { id: 'column.chats', defaultMessage: 'Chats' },
});
@@ -15,7 +16,7 @@ const ChatPageSidebar = () => {
const intl = useIntl();
const history = useHistory();
- const handleClickChat = (chat: IChat) => {
+ const handleClickChat = (chat: Chat) => {
history.push(`/chats/${chat.id}`);
};
diff --git a/src/features/chats/components/chat-pane/chat-pane.tsx b/src/features/chats/components/chat-pane/chat-pane.tsx
index fc3f82e4a..8f859a50a 100644
--- a/src/features/chats/components/chat-pane/chat-pane.tsx
+++ b/src/features/chats/components/chat-pane/chat-pane.tsx
@@ -4,7 +4,7 @@ import { FormattedMessage } from 'react-intl';
import { Stack } from 'soapbox/components/ui';
import { ChatWidgetScreens, useChatContext } from 'soapbox/contexts/chat-context';
import { useStatContext } from 'soapbox/contexts/stat-context';
-import { IChat, useChats } from 'soapbox/queries/chats';
+import { useChats } from 'soapbox/queries/chats';
import ChatList from '../chat-list';
import ChatSearch from '../chat-search/chat-search';
@@ -16,13 +16,15 @@ import { Pane } from '../ui';
import Blankslate from './blankslate';
+import type { Chat } from 'pl-api';
+
const ChatPane = () => {
const { unreadChatsCount } = useStatContext();
const { screen, changeScreen, isOpen, toggleChatPane } = useChatContext();
const { chatsQuery: { data: chats, isLoading } } = useChats();
- const handleClickChat = (nextChat: IChat) => {
+ const handleClickChat = (nextChat: Chat) => {
changeScreen(ChatWidgetScreens.CHAT, nextChat.id);
};
diff --git a/src/features/chats/components/chat-search/results.tsx b/src/features/chats/components/chat-search/results.tsx
index c3ea7e67b..ed44538da 100644
--- a/src/features/chats/components/chat-search/results.tsx
+++ b/src/features/chats/components/chat-search/results.tsx
@@ -6,7 +6,7 @@ import { Avatar, HStack, Stack, Text } from 'soapbox/components/ui';
import VerificationBadge from 'soapbox/components/verification-badge';
import useAccountSearch from 'soapbox/queries/search';
-import type { Account } from 'soapbox/types/entities';
+import type { Account } from 'pl-api';
interface IResults {
accountSearchResult: ReturnType;
diff --git a/src/features/chats/components/chat.tsx b/src/features/chats/components/chat.tsx
index 6d4dd7d24..4e0fe8ca4 100644
--- a/src/features/chats/components/chat.tsx
+++ b/src/features/chats/components/chat.tsx
@@ -6,12 +6,13 @@ import { uploadMedia } from 'soapbox/actions/media';
import { Stack } from 'soapbox/components/ui';
import { useAppDispatch } from 'soapbox/hooks';
import { normalizeAttachment } from 'soapbox/normalizers';
-import { IChat, useChatActions } from 'soapbox/queries/chats';
+import { useChatActions } from 'soapbox/queries/chats';
import toast from 'soapbox/toast';
import ChatComposer from './chat-composer';
import ChatMessageList from './chat-message-list';
+import type { Chat as ChatEntity } from 'pl-api';
import type { PlfeResponse } from 'soapbox/api';
import type { Attachment } from 'soapbox/types/entities';
@@ -23,7 +24,7 @@ const messages = defineMessages({
});
interface ChatInterface {
- chat: IChat;
+ chat: ChatEntity;
inputRef?: MutableRefObject;
className?: string;
}
diff --git a/src/features/compose/components/compose-form.tsx b/src/features/compose/components/compose-form.tsx
index 0129cfe5f..ce20d080b 100644
--- a/src/features/compose/components/compose-form.tsx
+++ b/src/features/compose/components/compose-form.tsx
@@ -196,7 +196,7 @@ const ComposeForm = ({ id, shouldCondense, autoFocus, clickab
const renderButtons = useCallback(() => (
- {features.media && }
+
{features.polls && }
{features.scheduledStatuses && }
diff --git a/src/features/compose/components/reply-mentions.tsx b/src/features/compose/components/reply-mentions.tsx
index b54b17df7..6efddace2 100644
--- a/src/features/compose/components/reply-mentions.tsx
+++ b/src/features/compose/components/reply-mentions.tsx
@@ -20,7 +20,7 @@ const ReplyMentions: React.FC = ({ composeId }) => {
const status = useAppSelector(state => getStatus(state, { id: compose.in_reply_to! }));
const to = compose.to;
- if (!features.explicitAddressing || !status || !to) {
+ if (!features.createStatusExplicitAddressing || !status || !to) {
return null;
}
diff --git a/src/features/settings/index.tsx b/src/features/settings/index.tsx
index 243291838..7395fc37a 100644
--- a/src/features/settings/index.tsx
+++ b/src/features/settings/index.tsx
@@ -132,7 +132,7 @@ const Settings = () => {
- {(features.security || features.accountAliases) && (
+ {(features.security || features.manageAccountAliases) && (
<>
diff --git a/src/features/ui/components/modals/manage-group-modal/create-group-modal.tsx b/src/features/ui/components/modals/manage-group-modal/create-group-modal.tsx
index 92b7e173b..43d1f3f3e 100644
--- a/src/features/ui/components/modals/manage-group-modal/create-group-modal.tsx
+++ b/src/features/ui/components/modals/manage-group-modal/create-group-modal.tsx
@@ -2,15 +2,15 @@ import React, { useMemo, useState } from 'react';
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import { z } from 'zod';
-import { useCreateGroup, type CreateGroupParams } from 'soapbox/api/hooks';
+import { useCreateGroup } from 'soapbox/api/hooks';
import { Modal, Stack } from 'soapbox/components/ui';
import { type Group } from 'soapbox/schemas';
import toast from 'soapbox/toast';
import ConfirmationStep from './steps/confirmation-step';
import DetailsStep from './steps/details-step';
-import PrivacyStep from './steps/privacy-step';
+import type { CreateGroupParams } from 'pl-api';
import type { PlfeResponse } from 'soapbox/api';
const messages = defineMessages({
@@ -22,7 +22,6 @@ const messages = defineMessages({
enum Steps {
ONE = 'ONE',
TWO = 'TWO',
- THREE = 'THREE',
}
interface ICreateGroupModal {
@@ -34,7 +33,7 @@ const CreateGroupModal: React.FC = ({ onClose }) => {
const [group, setGroup] = useState(null);
const [params, setParams] = useState({
- group_visibility: 'everyone',
+ display_name: '',
});
const [currentStep, setCurrentStep] = useState(Steps.ONE);
@@ -46,24 +45,19 @@ const CreateGroupModal: React.FC = ({ onClose }) => {
const confirmationText = useMemo(() => {
switch (currentStep) {
- case Steps.THREE:
- return intl.formatMessage(messages.done);
case Steps.TWO:
- return intl.formatMessage(messages.create);
+ return intl.formatMessage(messages.done);
default:
- return intl.formatMessage(messages.next);
+ return intl.formatMessage(messages.create);
}
}, [currentStep]);
const handleNextStep = () => {
switch (currentStep) {
case Steps.ONE:
- setCurrentStep(Steps.TWO);
- break;
- case Steps.TWO:
createGroup(params, {
onSuccess(group) {
- setCurrentStep(Steps.THREE);
+ setCurrentStep(Steps.TWO);
setGroup(group);
},
onError(error: { response?: PlfeResponse }) {
@@ -74,7 +68,7 @@ const CreateGroupModal: React.FC = ({ onClose }) => {
},
});
break;
- case Steps.THREE:
+ case Steps.TWO:
handleClose();
break;
default:
@@ -85,26 +79,13 @@ const CreateGroupModal: React.FC = ({ onClose }) => {
const renderStep = () => {
switch (currentStep) {
case Steps.ONE:
- return ;
- case Steps.TWO:
return ;
- case Steps.THREE:
+ case Steps.TWO:
return ;
}
};
- const renderModalTitle = () => {
- switch (currentStep) {
- case Steps.ONE:
- return ;
- default:
- if (params.group_visibility === 'everyone') {
- return ;
- } else {
- return ;
- }
- }
- };
+ const renderModalTitle = () => ;
return (
void;
}
const DetailsStep: React.FC = ({ params, onChange }) => {
@@ -52,7 +53,10 @@ const DetailsStep: React.FC = ({ params, onChange }) => {
}
};
- const handleImageClear = (property: keyof CreateGroupParams) => () => onChange({ [property]: undefined });
+ const handleImageClear = (property: keyof CreateGroupParams) => () => onChange({
+ ...params,
+ [property]: undefined,
+ });
return (