pl-fe: more reducer migrations

Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
marcin mikołajczak 2024-11-14 12:03:17 +01:00
parent 06113f2610
commit 95a8c63591
8 changed files with 76 additions and 79 deletions

View file

@ -375,7 +375,7 @@ const submitCompose = (composeId: string, opts: SubmitComposeOpts = {}) =>
const mentions: string[] | null = status.match(/(?:^|\s)@([a-z\d_-]+(?:@(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]+)?)/gi); const mentions: string[] | null = status.match(/(?:^|\s)@([a-z\d_-]+(?:@(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]+)?)/gi);
if (mentions) { if (mentions) {
to = to.union(mentions.map(mention => mention.replace(/&#x20;/g, '').trim().slice(1))); to = [...new Set([...to, ...mentions.map(mention => mention.replace(/&#x20;/g, '').trim().slice(1))])];
} }
dispatch(submitComposeRequest(composeId)); dispatch(submitComposeRequest(composeId));
@ -399,26 +399,26 @@ const submitCompose = (composeId: string, opts: SubmitComposeOpts = {}) =>
content_type: contentType, content_type: contentType,
scheduled_at: compose.schedule?.toISOString(), scheduled_at: compose.schedule?.toISOString(),
language: compose.language || compose.suggested_language || undefined, language: compose.language || compose.suggested_language || undefined,
to: to.size ? to.toArray() : undefined, to: to.length ? to : undefined,
local_only: !compose.federated, local_only: !compose.federated,
}; };
if (compose.poll) { if (compose.poll) {
params.poll = { params.poll = {
options: compose.poll.options.toArray(), options: compose.poll.options,
expires_in: compose.poll.expires_in, expires_in: compose.poll.expires_in,
multiple: compose.poll.multiple, multiple: compose.poll.multiple,
hide_totals: compose.poll.hide_totals, hide_totals: compose.poll.hide_totals,
options_map: compose.poll.options_map.toJS(), options_map: compose.poll.options_map,
}; };
} }
if (compose.language && compose.textMap.size) { if (compose.language && Object.keys(compose.textMap).length) {
params.status_map = compose.textMap.toJS(); params.status_map = compose.textMap;
params.status_map[compose.language] = status; params.status_map[compose.language] = status;
if (params.spoiler_text) { if (params.spoiler_text) {
params.spoiler_text_map = compose.spoilerTextMap.toJS(); params.spoiler_text_map = compose.spoilerTextMap;
params.spoiler_text_map[compose.language] = compose.spoiler_text; params.spoiler_text_map[compose.language] = compose.spoiler_text;
} }

View file

@ -189,7 +189,7 @@ const ComposeForm = <ID extends string>({ id, shouldCondense, autoFocus, clickab
</HStack> </HStack>
), [features, id, anyMedia]); ), [features, id, anyMedia]);
const showModifiers = !condensed && (compose.media_attachments.size || compose.is_uploading || compose.poll?.options.size || compose.schedule); const showModifiers = !condensed && (compose.media_attachments.size || compose.is_uploading || compose.poll?.options.length || compose.schedule);
const composeModifiers = showModifiers && ( const composeModifiers = showModifiers && (
<Stack space={4} className='font-[inherit] text-sm text-gray-900'> <Stack space={4} className='font-[inherit] text-sm text-gray-900'>

View file

@ -53,11 +53,13 @@ const getLanguageDropdown = (composeId: string): React.FC<ILanguageDropdown> =>
textMap, textMap,
} = useCompose(composeId); } = useCompose(composeId);
const hasMultipleLanguages = !!Object.keys(textMap).length;
const handleOptionClick: React.EventHandler<any> = (e: MouseEvent | KeyboardEvent) => { const handleOptionClick: React.EventHandler<any> = (e: MouseEvent | KeyboardEvent) => {
const value = (e.currentTarget as HTMLElement)?.getAttribute('data-index') as Language; const value = (e.currentTarget as HTMLElement)?.getAttribute('data-index') as Language;
if (textMap.size) { if (Object.keys(textMap).length) {
if (!(textMap.has(value) || language === value)) return; if (!(value in textMap || language === value)) return;
dispatch(changeComposeModifiedLanguage(composeId, value)); dispatch(changeComposeModifiedLanguage(composeId, value));
} else { } else {
@ -99,11 +101,11 @@ const getLanguageDropdown = (composeId: string): React.FC<ILanguageDropdown> =>
return [...languages].sort((a, b) => { return [...languages].sort((a, b) => {
// Push current selection to the top of the list // Push current selection to the top of the list
if (textMap.has(a[0])) { if (a[0] in textMap) {
if (b[0] === language) return 1; if (b[0] === language) return 1;
return -1; return -1;
} }
if (textMap.has(b[0])) { if (b[0] in textMap) {
if (a[0] === language) return -1; if (a[0] === language) return -1;
return 1; return 1;
} }
@ -180,9 +182,9 @@ const getLanguageDropdown = (composeId: string): React.FC<ILanguageDropdown> =>
'flex w-full gap-2 p-2.5 text-left text-sm text-gray-700 dark:text-gray-400', 'flex w-full gap-2 p-2.5 text-left text-sm text-gray-700 dark:text-gray-400',
{ {
'bg-gray-100 dark:bg-gray-800 black:bg-gray-900 cursor-pointer hover:bg-gray-200 dark:hover:bg-gray-700': modified, 'bg-gray-100 dark:bg-gray-800 black:bg-gray-900 cursor-pointer hover:bg-gray-200 dark:hover:bg-gray-700': modified,
'cursor-pointer hover:bg-gray-100 black:hover:bg-gray-900 dark:hover:bg-gray-800': !textMap.size || textMap.has(code), 'cursor-pointer hover:bg-gray-100 black:hover:bg-gray-900 dark:hover:bg-gray-800': !hasMultipleLanguages || code in textMap,
'cursor-pointer': active, 'cursor-pointer': active,
'cursor-default': !active && !(!textMap.size || textMap.has(code)), 'cursor-default': !active && !(!hasMultipleLanguages || code in textMap),
}, },
)} )}
aria-selected={active} aria-selected={active}
@ -196,7 +198,7 @@ const getLanguageDropdown = (composeId: string): React.FC<ILanguageDropdown> =>
{name} {name}
</div> </div>
{features.multiLanguage && !!language && !active && ( {features.multiLanguage && !!language && !active && (
textMap.has(code) ? ( code in textMap ? (
<button title={intl.formatMessage(messages.deleteLanguage)} onClick={handleDeleteLanguageClick}> <button title={intl.formatMessage(messages.deleteLanguage)} onClick={handleDeleteLanguageClick}>
<Icon className='size-4' src={require('@tabler/icons/outline/minus.svg')} /> <Icon className='size-4' src={require('@tabler/icons/outline/minus.svg')} />
</button> </button>
@ -228,11 +230,13 @@ const LanguageDropdownButton: React.FC<ILanguageDropdownButton> = ({ composeId }
textMap, textMap,
} = useCompose(composeId); } = useCompose(composeId);
const languagesCount = Object.keys(textMap).length;
let buttonLabel = intl.formatMessage(messages.languagePrompt); let buttonLabel = intl.formatMessage(messages.languagePrompt);
if (language) { if (language) {
const list: string[] = [languagesObject[modifiedLanguage || language]]; const list: string[] = [languagesObject[modifiedLanguage || language]];
if (textMap.size) list.push(intl.formatMessage(messages.multipleLanguages, { if (languagesCount) list.push(intl.formatMessage(messages.multipleLanguages, {
count: textMap.size, count: languagesCount,
})); }));
buttonLabel = intl.formatList(list); buttonLabel = intl.formatList(list);
} else if (suggestedLanguage) buttonLabel = intl.formatMessage(messages.languageSuggestion, { } else if (suggestedLanguage) buttonLabel = intl.formatMessage(messages.languageSuggestion, {

View file

@ -122,7 +122,7 @@ const PollForm: React.FC<IPollForm> = ({ composeId }) => {
const { poll, language, modified_language: modifiedLanguage } = useCompose(composeId); const { poll, language, modified_language: modifiedLanguage } = useCompose(composeId);
const options = !modifiedLanguage || modifiedLanguage === language ? poll?.options : poll?.options_map.map((option, key) => option.get(modifiedLanguage, poll.options.get(key)!)); const options = !modifiedLanguage || modifiedLanguage === language ? poll?.options : poll?.options_map.map((option, key) => option[modifiedLanguage] || poll.options[key]);
const expiresIn = poll?.expires_in; const expiresIn = poll?.expires_in;
const isMultiple = poll?.multiple; const isMultiple = poll?.multiple;
@ -156,7 +156,7 @@ const PollForm: React.FC<IPollForm> = ({ composeId }) => {
onChange={onChangeOption} onChange={onChangeOption}
onRemove={onRemoveOption} onRemove={onRemoveOption}
maxChars={maxOptionChars} maxChars={maxOptionChars}
numOptions={options.size} numOptions={options.length}
onRemovePoll={onRemovePoll} onRemovePoll={onRemovePoll}
/> />
))} ))}
@ -164,7 +164,7 @@ const PollForm: React.FC<IPollForm> = ({ composeId }) => {
<HStack space={2}> <HStack space={2}>
<div className='w-6' /> <div className='w-6' />
{options.size < maxOptions && ( {options.length < maxOptions && (
<Button <Button
theme='secondary' theme='secondary'
onClick={handleAddOption} onClick={handleAddOption}

View file

@ -13,7 +13,7 @@ const ReplyMentions: React.FC<IReplyMentions> = ({ composeId }) => {
const { openModal } = useModalsStore(); const { openModal } = useModalsStore();
const features = useFeatures(); const features = useFeatures();
const compose = useCompose(composeId); const compose = useCompose(composeId);
const to = compose.to.toArray(); const to = compose.to;
if (!features.createStatusExplicitAddressing || !compose.in_reply_to || !to) { if (!features.createStatusExplicitAddressing || !compose.in_reply_to || !to) {
return null; return null;

View file

@ -30,7 +30,7 @@ const SpoilerInput: React.FC<ISpoilerInput> = ({
dispatch(changeComposeSpoilerText(composeId, e.target.value)); dispatch(changeComposeSpoilerText(composeId, e.target.value));
}; };
const value = !modified_language || modified_language === language ? spoilerText : spoilerTextMap.get(modified_language, ''); const value = !modified_language || modified_language === language ? spoilerText : spoilerTextMap[modified_language] || '';
return ( return (
<AutosuggestInput <AutosuggestInput

View file

@ -119,7 +119,7 @@ const ComposeEditor = React.forwardRef<LexicalEditor, IComposeEditor>(({
const editorState = !compose.modified_language || compose.modified_language === compose.language const editorState = !compose.modified_language || compose.modified_language === compose.language
? compose.editorState ? compose.editorState
: compose.editorStateMap.get(compose.modified_language, ''); : compose.editorStateMap[compose.modified_language] || '';
if (editorState) { if (editorState) {
return editorState; return editorState;
@ -128,7 +128,7 @@ const ComposeEditor = React.forwardRef<LexicalEditor, IComposeEditor>(({
return () => { return () => {
const text = !compose.modified_language || compose.modified_language === compose.language const text = !compose.modified_language || compose.modified_language === compose.language
? compose.text ? compose.text
: compose.textMap.get(compose.modified_language, ''); : compose.textMap[compose.modified_language] || '';
if (!text && navigator.userAgent.includes('Ladybird/')) { if (!text && navigator.userAgent.includes('Ladybird/')) {
const paragraph = $createParagraphNode(); const paragraph = $createParagraphNode();

View file

@ -1,4 +1,4 @@
import { Map as ImmutableMap, List as ImmutableList, OrderedSet as ImmutableOrderedSet } from 'immutable'; import { List as ImmutableList } from 'immutable';
import { create } from 'mutative'; import { create } from 'mutative';
import { Instance, PLEROMA, type CredentialAccount, type MediaAttachment, type Tag } from 'pl-api'; import { Instance, PLEROMA, type CredentialAccount, type MediaAttachment, type Tag } from 'pl-api';
@ -78,16 +78,16 @@ import type { APIEntity } from 'pl-fe/types/entities';
const getResetFileKey = () => Math.floor((Math.random() * 0x10000)); const getResetFileKey = () => Math.floor((Math.random() * 0x10000));
interface ComposePoll { interface ComposePoll {
options: ImmutableList<string>; options: Array<string>;
options_map: ImmutableList<ImmutableMap<Language, string>>; options_map: Array<Partial<Record<Language, string>>>;
expires_in: number; expires_in: number;
multiple: boolean; multiple: boolean;
hide_totals: boolean; hide_totals: boolean;
} }
const newPoll = (params: Partial<ComposePoll> = {}): ComposePoll => ({ const newPoll = (params: Partial<ComposePoll> = {}): ComposePoll => ({
options: ImmutableList(['', '']), options: ['', ''],
options_map: ImmutableList([ImmutableMap(), ImmutableMap()]), options_map: [{}, {}],
expires_in: 24 * 3600, expires_in: 24 * 3600,
multiple: false, multiple: false,
hide_totals: false, hide_totals: false,
@ -99,7 +99,7 @@ interface Compose {
content_type: string; content_type: string;
draft_id: string | null; draft_id: string | null;
editorState: string | null; editorState: string | null;
editorStateMap: ImmutableMap<Language, string | null>; editorStateMap: Partial<Record<Language, string | null>>;
focusDate: Date | null; focusDate: Date | null;
group_id: string | null; group_id: string | null;
idempotencyKey: string; idempotencyKey: string;
@ -118,15 +118,15 @@ interface Compose {
schedule: Date | null; schedule: Date | null;
sensitive: boolean; sensitive: boolean;
spoiler_text: string; spoiler_text: string;
spoilerTextMap: ImmutableMap<Language, string>; spoilerTextMap: Partial<Record<Language, string>>;
suggestions: ImmutableList<string>; suggestions: ImmutableList<string>;
suggestion_token: string | null; suggestion_token: string | null;
tagHistory: ImmutableList<string>; tagHistory: ImmutableList<string>;
text: string; text: string;
textMap: ImmutableMap<Language, string>; textMap: Partial<Record<Language, string>>;
to: ImmutableOrderedSet<string>; to: Array<string>;
parent_reblogged_by: string | null; parent_reblogged_by: string | null;
dismissed_quotes: ImmutableOrderedSet<string>; dismissed_quotes: Array<string>;
language: Language | null; language: Language | null;
modified_language: Language | null; modified_language: Language | null;
suggested_language: string | null; suggested_language: string | null;
@ -139,7 +139,7 @@ const newCompose = (params: Partial<Compose> = {}): Compose => ({
content_type: 'text/plain', content_type: 'text/plain',
draft_id: null, draft_id: null,
editorState: null, editorState: null,
editorStateMap: ImmutableMap<Language, string | null>(), editorStateMap: {},
focusDate: null, focusDate: null,
group_id: null, group_id: null,
idempotencyKey: '', idempotencyKey: '',
@ -158,15 +158,15 @@ const newCompose = (params: Partial<Compose> = {}): Compose => ({
schedule: null, schedule: null,
sensitive: false, sensitive: false,
spoiler_text: '', spoiler_text: '',
spoilerTextMap: ImmutableMap<Language, string>(), spoilerTextMap: {},
suggestions: ImmutableList<string>(), suggestions: ImmutableList<string>(),
suggestion_token: null, suggestion_token: null,
tagHistory: ImmutableList<string>(), tagHistory: ImmutableList<string>(),
text: '', text: '',
textMap: ImmutableMap<Language, string>(), textMap: {},
to: ImmutableOrderedSet<string>(), to: [],
parent_reblogged_by: null, parent_reblogged_by: null,
dismissed_quotes: ImmutableOrderedSet<string>(), dismissed_quotes: [],
language: null, language: null,
modified_language: null, modified_language: null,
suggested_language: null, suggested_language: null,
@ -184,9 +184,8 @@ const statusToTextMentions = (status: Pick<Status, 'account' | 'mentions'>, acco
const author = status.account.acct; const author = status.account.acct;
const mentions = status.mentions.map((m) => m.acct) || []; const mentions = status.mentions.map((m) => m.acct) || [];
return ImmutableOrderedSet([author]) return [...new Set([author, ...mentions]
.concat(mentions) .filter(acct => acct !== account.acct))]
.delete(account.acct)
.map(m => `@${m} `) .map(m => `@${m} `)
.join(''); .join('');
}; };
@ -195,19 +194,13 @@ const statusToMentionsArray = (status: Pick<Status, 'account' | 'mentions'>, acc
const author = status.account.acct; const author = status.account.acct;
const mentions = status.mentions.map((m) => m.acct) || []; const mentions = status.mentions.map((m) => m.acct) || [];
return ImmutableOrderedSet<string>([author]) return [...new Set([author, ...(rebloggedBy ? [rebloggedBy.acct] : []), ...mentions].filter(acct => acct !== account.acct))];
.concat(rebloggedBy ? [rebloggedBy.acct] : [])
.concat(mentions)
.delete(account.acct);
}; };
const statusToMentionsAccountIdsArray = (status: Pick<Status, 'mentions' | 'account'>, account: Pick<Account, 'id'>, parentRebloggedBy?: string | null) => { const statusToMentionsAccountIdsArray = (status: Pick<Status, 'mentions' | 'account'>, account: Pick<Account, 'id'>, parentRebloggedBy?: string | null) => {
const mentions = status.mentions.map((m) => m.id); const mentions = status.mentions.map((m) => m.id);
return ImmutableOrderedSet<string>([status.account.id]) return [...new Set([status.account.id, ...(parentRebloggedBy ? [parentRebloggedBy] : []), ...mentions].filter((id) => id !== account.id))];
.concat(parentRebloggedBy ? [parentRebloggedBy] : [])
.concat(mentions)
.delete(account.id);
}; };
const appendMedia = (compose: Compose, media: MediaAttachment, defaultSensitive?: boolean) => { const appendMedia = (compose: Compose, media: MediaAttachment, defaultSensitive?: boolean) => {
@ -239,7 +232,7 @@ const insertSuggestion = (compose: Compose, position: number, token: string | nu
if (path[0] === 'spoiler_text') { if (path[0] === 'spoiler_text') {
compose.spoiler_text = updateText(compose.spoiler_text); compose.spoiler_text = updateText(compose.spoiler_text);
} else if (compose.poll) { } else if (compose.poll) {
compose.poll.options = compose.poll.options.update(path[2], updateText); compose.poll.options[path[2]] = updateText(compose.poll.options[path[2]]);
} }
compose.suggestion_token = null; compose.suggestion_token = null;
compose.suggestions = ImmutableList(); compose.suggestions = ImmutableList();
@ -296,7 +289,7 @@ const getExplicitMentions = (me: string, status: Pick<Status, 'content' | 'menti
.filter((mention) => !(fragment.querySelector(`a[href="${mention.url}"]`) || mention.id === me)) .filter((mention) => !(fragment.querySelector(`a[href="${mention.url}"]`) || mention.id === me))
.map((m) => m.acct); .map((m) => m.acct);
return ImmutableOrderedSet<string>(mentions); return [...new Set(mentions)];
}; };
const importAccount = (compose: Compose, account: CredentialAccount) => { const importAccount = (compose: Compose, account: CredentialAccount) => {
@ -352,10 +345,10 @@ const compose = (state = initialState, action: ComposeAction | EventsAction | In
}); });
case COMPOSE_SPOILER_TEXT_CHANGE: case COMPOSE_SPOILER_TEXT_CHANGE:
return updateCompose(state, action.composeId, compose => { return updateCompose(state, action.composeId, compose => {
if (compose.modified_language === compose.language) { if (!compose.modified_language || compose.modified_language === compose.language) {
compose.spoiler_text = action.text; compose.spoiler_text = action.text;
} else { } else if (compose.modified_language) {
compose.spoilerTextMap = compose.spoilerTextMap.set(compose.modified_language!, action.text); compose.spoilerTextMap[compose.modified_language] = action.text;
} }
}); });
case COMPOSE_VISIBILITY_CHANGE: case COMPOSE_VISIBILITY_CHANGE:
@ -385,7 +378,7 @@ const compose = (state = initialState, action: ComposeAction | EventsAction | In
const to = action.explicitAddressing const to = action.explicitAddressing
? statusToMentionsArray(action.status, action.account, action.rebloggedBy) ? statusToMentionsArray(action.status, action.account, action.rebloggedBy)
: ImmutableOrderedSet<string>(); : [];
compose.group_id = action.status.group_id; compose.group_id = action.status.group_id;
compose.in_reply_to = action.status.id; compose.in_reply_to = action.status.id;
@ -415,7 +408,7 @@ const compose = (state = initialState, action: ComposeAction | EventsAction | In
const defaultCompose = state.default; const defaultCompose = state.default;
compose.quote = action.status.id; compose.quote = action.status.id;
compose.to = ImmutableOrderedSet<string>([author]); compose.to = [author];
compose.parent_reblogged_by = null; compose.parent_reblogged_by = null;
compose.text = ''; compose.text = '';
compose.privacy = privacyPreference(action.status.visibility, defaultCompose.privacy); compose.privacy = privacyPreference(action.status.visibility, defaultCompose.privacy);
@ -540,7 +533,7 @@ const compose = (state = initialState, action: ComposeAction | EventsAction | In
}); });
case COMPOSE_SET_STATUS: case COMPOSE_SET_STATUS:
return updateCompose(state, 'compose-modal', compose => { return updateCompose(state, 'compose-modal', compose => {
const to = action.explicitAddressing ? getExplicitMentions(action.status.account.id, action.status) : ImmutableOrderedSet<string>(); const to = action.explicitAddressing ? getExplicitMentions(action.status.account.id, action.status) : [];
if (!action.withRedraft && !action.draftId) { if (!action.withRedraft && !action.draftId) {
compose.id = action.status.id; compose.id = action.status.id;
} }
@ -570,7 +563,7 @@ const compose = (state = initialState, action: ComposeAction | EventsAction | In
if (action.poll) { if (action.poll) {
compose.poll = newPoll({ compose.poll = newPoll({
options: ImmutableList(action.poll.options.map(({ title }) => title)), options: action.poll.options.map(({ title }) => title),
multiple: action.poll.multiple, multiple: action.poll.multiple,
expires_in: 24 * 3600, expires_in: 24 * 3600,
}); });
@ -607,22 +600,22 @@ const compose = (state = initialState, action: ComposeAction | EventsAction | In
case COMPOSE_POLL_OPTION_ADD: case COMPOSE_POLL_OPTION_ADD:
return updateCompose(state, action.composeId, compose => { return updateCompose(state, action.composeId, compose => {
if (!compose.poll) return; if (!compose.poll) return;
compose.poll.options = compose.poll.options.push(action.title); compose.poll.options.push(action.title);
compose.poll.options_map = compose.poll.options_map.push(ImmutableMap(compose.textMap.map(_ => action.title))); compose.poll.options_map.push(Object.fromEntries(Object.entries(compose.textMap).map((key) => [key, action.title])));
}); });
case COMPOSE_POLL_OPTION_CHANGE: case COMPOSE_POLL_OPTION_CHANGE:
return updateCompose(state, action.composeId, compose => { return updateCompose(state, action.composeId, compose => {
if (!compose.poll) return; if (!compose.poll) return;
if (!compose.modified_language || compose.modified_language === compose.language) { if (!compose.modified_language || compose.modified_language === compose.language) {
compose.poll.options = compose.poll.options.set(action.index, action.title); compose.poll.options[action.index] = action.title;
compose.poll.options_map = compose.poll.options_map.setIn([action.index, compose.modified_language], action.title); if (compose.modified_language) compose.poll.options_map[action.index][compose.modified_language] = action.title;
} }
}); });
case COMPOSE_POLL_OPTION_REMOVE: case COMPOSE_POLL_OPTION_REMOVE:
return updateCompose(state, action.composeId, compose => { return updateCompose(state, action.composeId, compose => {
if (!compose.poll) return; if (!compose.poll) return;
compose.poll.options = compose.poll.options.delete(action.index); compose.poll.options = compose.poll.options.filter((_, index) => index !== action.index);
compose.poll.options_map = compose.poll.options_map.delete(action.index); compose.poll.options_map = compose.poll.options_map.filter((_, index) => index !== action.index);
}); });
case COMPOSE_POLL_SETTINGS_CHANGE: case COMPOSE_POLL_SETTINGS_CHANGE:
return updateCompose(state, action.composeId, compose => { return updateCompose(state, action.composeId, compose => {
@ -636,11 +629,11 @@ const compose = (state = initialState, action: ComposeAction | EventsAction | In
}); });
case COMPOSE_ADD_TO_MENTIONS: case COMPOSE_ADD_TO_MENTIONS:
return updateCompose(state, action.composeId, compose => { return updateCompose(state, action.composeId, compose => {
compose.to = compose.to.add(action.account); compose.to = [...new Set([...compose.to, action.account])];
}); });
case COMPOSE_REMOVE_FROM_MENTIONS: case COMPOSE_REMOVE_FROM_MENTIONS:
return updateCompose(state, action.composeId, compose => { return updateCompose(state, action.composeId, compose => {
compose.to = compose.to.delete(action.account); compose.to = compose.to.filter(acct => acct !== action.account);
}); });
case ME_FETCH_SUCCESS: case ME_FETCH_SUCCESS:
case ME_PATCH_SUCCESS: case ME_PATCH_SUCCESS:
@ -649,12 +642,12 @@ const compose = (state = initialState, action: ComposeAction | EventsAction | In
// return updateCompose(state, 'default', compose => updateSetting(compose, action.path, action.value)); // return updateCompose(state, 'default', compose => updateSetting(compose, action.path, action.value));
case COMPOSE_EDITOR_STATE_SET: case COMPOSE_EDITOR_STATE_SET:
return updateCompose(state, action.composeId, compose => { return updateCompose(state, action.composeId, compose => {
if (!compose.modified_language || compose.modified_language) { if (!compose.modified_language || compose.modified_language === compose.language) {
compose.editorState = action.editorState as string; compose.editorState = action.editorState as string;
compose.text = action.text as string; compose.text = action.text as string;
} else { } else if (compose.modified_language) {
compose.editorStateMap = compose.editorStateMap.set(compose.modified_language, action.editorState as string); compose.editorStateMap[compose.modified_language] = action.editorState as string;
compose.textMap = compose.textMap.set(compose.modified_language, action.text as string); compose.textMap[compose.modified_language] = action.text as string;
} }
}); });
case EVENT_COMPOSE_CANCEL: case EVENT_COMPOSE_CANCEL:
@ -683,20 +676,20 @@ const compose = (state = initialState, action: ComposeAction | EventsAction | In
}); });
case COMPOSE_LANGUAGE_ADD: case COMPOSE_LANGUAGE_ADD:
return updateCompose(state, action.composeId, compose => { return updateCompose(state, action.composeId, compose => {
compose.editorStateMap = compose.editorStateMap.set(action.value, compose.editorState); compose.editorStateMap[action.value] = compose.editorState;
compose.textMap = compose.textMap.set(action.value, compose.text); compose.textMap[action.value] = compose.text;
compose.spoilerTextMap = compose.spoilerTextMap.set(action.value, compose.spoiler_text); compose.spoilerTextMap[action.value] = compose.spoiler_text;
if (compose.poll) compose.poll.options_map = compose.poll.options_map.map((option, key) => option.set(action.value, compose.poll!.options.get(key)!)); if (compose.poll) compose.poll.options_map.forEach((option, key) => option[action.value] = compose.poll!.options[key]);
}); });
case COMPOSE_LANGUAGE_DELETE: case COMPOSE_LANGUAGE_DELETE:
return updateCompose(state, action.composeId, compose => { return updateCompose(state, action.composeId, compose => {
compose.editorStateMap = compose.editorStateMap.delete(action.value); delete compose.editorStateMap[action.value];
compose.textMap = compose.textMap.delete(action.value); delete compose.textMap[action.value];
compose.spoilerTextMap = compose.spoilerTextMap.delete(action.value); delete compose.spoilerTextMap[action.value];
}); });
case COMPOSE_QUOTE_CANCEL: case COMPOSE_QUOTE_CANCEL:
return updateCompose(state, action.composeId, (compose) => { return updateCompose(state, action.composeId, (compose) => {
if (compose.quote) compose.dismissed_quotes = compose.dismissed_quotes.add(compose.quote); if (compose.quote) compose.dismissed_quotes.push(compose.quote);
compose.quote = null; compose.quote = null;
}); });
case COMPOSE_FEDERATED_CHANGE: case COMPOSE_FEDERATED_CHANGE: