nicolium: migrate compose

Signed-off-by: nicole mikołajczyk <git@mkljczk.pl>
This commit is contained in:
nicole mikołajczyk
2026-02-25 22:41:45 +01:00
parent 8ac76b43e3
commit c577a182f1
63 changed files with 1739 additions and 2904 deletions

View File

@@ -300,4 +300,4 @@ const AutosuggestInput: React.FC<IAutosuggestInput> = ({
];
};
export { type AutoSuggestion, type IAutosuggestInput, AutosuggestInput as default };
export { type AutoSuggestion, AutosuggestInput as default };

View File

@@ -4,14 +4,13 @@ import range from 'lodash/range';
import React, { useCallback, useEffect, useRef, useState } from 'react';
import { FormattedMessage, defineMessages, useIntl } from 'react-intl';
import { cancelReplyCompose } from '@/actions/compose';
import { useAppDispatch } from '@/hooks/use-app-dispatch';
import { usePrevious } from '@/hooks/use-previous';
import { usePersistDraftStatus } from '@/queries/statuses/use-draft-statuses';
import { useComposeStore } from '@/stores/compose';
import { useModalsActions } from '@/stores/modals';
import type { ModalType } from '@/features/ui/components/modal-root';
import type { Compose } from '@/reducers/compose';
import type { Compose } from '@/stores/compose';
const messages = defineMessages({
confirm: { id: 'confirmations.cancel.confirm', defaultMessage: 'Discard' },
@@ -40,8 +39,6 @@ const ModalRoot: React.FC<IModalRoot> = ({ children, onCancel, onClose, type, mo
const intl = useIntl();
const router = useRouter();
const navigate = useNavigate();
const dispatch = useAppDispatch();
const persistDraftStatus = usePersistDraftStatus();
const { openModal } = useModalsActions();
@@ -64,65 +61,64 @@ const ModalRoot: React.FC<IModalRoot> = ({ children, onCancel, onClose, type, mo
};
const handleOnClose = () => {
dispatch((_, getState) => {
const compose = getState().compose['compose-modal'];
const hasComposeContent = checkComposeContent(compose);
const { actions } = useComposeStore.getState();
const compose = actions.getCompose('compose-modal');
const hasComposeContent = checkComposeContent(compose);
if (hasComposeContent && type === 'COMPOSE') {
const isEditing = compose.editedId !== null;
openModal('CONFIRM', {
heading: isEditing ? (
<FormattedMessage
id='confirmations.cancel_editing.heading'
defaultMessage='Cancel post editing'
/>
) : compose.draftId ? (
<FormattedMessage
id='confirmations.cancel_draft.heading'
defaultMessage='Discard draft changes'
/>
) : (
<FormattedMessage id='confirmations.cancel.heading' defaultMessage='Discard post' />
),
message: isEditing ? (
<FormattedMessage
id='confirmations.cancel_editing.message'
defaultMessage='Are you sure you want to discard the changes to this post? All changes will be lost.'
/>
) : compose.draftId ? (
<FormattedMessage
id='confirmations.cancel_draft_editing.message'
defaultMessage='Are you sure you want to discard the changes to this draft post? All changes will be lost.'
/>
) : (
<FormattedMessage
id='confirmations.cancel.message'
defaultMessage='Are you sure you want to discard the currently composed post?'
/>
),
confirm: intl.formatMessage(messages.confirm),
onConfirm: () => {
onClose('COMPOSE');
dispatch(cancelReplyCompose());
},
onCancel: () => {
onClose('CONFIRM');
},
secondary: intl.formatMessage(messages.saveDraft),
onSecondary: isEditing
? undefined
: () => {
persistDraftStatus('compose-modal');
onClose('COMPOSE');
dispatch(cancelReplyCompose());
},
});
} else if (hasComposeContent && type === 'CONFIRM') {
onClose('CONFIRM');
} else {
onClose();
}
});
if (hasComposeContent && type === 'COMPOSE') {
const isEditing = compose.editedId !== null;
openModal('CONFIRM', {
heading: isEditing ? (
<FormattedMessage
id='confirmations.cancel_editing.heading'
defaultMessage='Cancel post editing'
/>
) : compose.draftId ? (
<FormattedMessage
id='confirmations.cancel_draft.heading'
defaultMessage='Discard draft changes'
/>
) : (
<FormattedMessage id='confirmations.cancel.heading' defaultMessage='Discard post' />
),
message: isEditing ? (
<FormattedMessage
id='confirmations.cancel_editing.message'
defaultMessage='Are you sure you want to discard the changes to this post? All changes will be lost.'
/>
) : compose.draftId ? (
<FormattedMessage
id='confirmations.cancel_draft_editing.message'
defaultMessage='Are you sure you want to discard the changes to this draft post? All changes will be lost.'
/>
) : (
<FormattedMessage
id='confirmations.cancel.message'
defaultMessage='Are you sure you want to discard the currently composed post?'
/>
),
confirm: intl.formatMessage(messages.confirm),
onConfirm: () => {
onClose('COMPOSE');
actions.resetCompose('compose-modal');
},
onCancel: () => {
onClose('CONFIRM');
},
secondary: intl.formatMessage(messages.saveDraft),
onSecondary: isEditing
? undefined
: () => {
persistDraftStatus('compose-modal');
onClose('COMPOSE');
actions.resetCompose('compose-modal');
},
});
} else if (hasComposeContent && type === 'CONFIRM') {
onClose('CONFIRM');
} else {
onClose();
}
};
const handleKeyDown = useCallback((e: KeyboardEvent) => {

View File

@@ -4,12 +4,16 @@ import React, { useCallback, useMemo } from 'react';
import { defineMessages, useIntl } from 'react-intl';
import { redactStatus } from '@/actions/admin';
import { directCompose, mentionCompose, quoteCompose, replyCompose } from '@/actions/compose';
import { emojiReact, unEmojiReact } from '@/actions/emoji-reacts';
import { deleteStatusModal, toggleStatusSensitivityModal } from '@/actions/moderation';
import { initReport, ReportableEntities } from '@/actions/reports';
import { changeSetting } from '@/actions/settings';
import { deleteStatus, editStatus, toggleMuteStatus } from '@/actions/statuses';
import {
deleteStatus,
deleteStatusFromGroup,
editStatus,
toggleMuteStatus,
} from '@/actions/statuses';
import DropdownMenu from '@/components/dropdown-menu';
import StatusActionButton from '@/components/status-action-button';
import EmojiPickerDropdown from '@/features/emoji/containers/emoji-picker-dropdown-container';
@@ -40,6 +44,7 @@ import {
useUnpinStatus,
useUnreblogStatus,
} from '@/queries/statuses/use-status-interactions';
import { useComposeActions } from '@/stores/compose';
import { useModalsActions } from '@/stores/modals';
import { useSettings } from '@/stores/settings';
import { useStatusMeta, useStatusMetaActions } from '@/stores/status-meta';
@@ -332,7 +337,7 @@ const ReplyButton: React.FC<IReplyButton> = ({
onOpenUnauthorizedModal,
rebloggedBy,
}) => {
const dispatch = useAppDispatch();
const { replyCompose } = useComposeActions();
const intl = useIntl();
const canReply = useCanInteract(status, 'can_reply');
@@ -354,7 +359,7 @@ const ReplyButton: React.FC<IReplyButton> = ({
const handleReplyClick: React.MouseEventHandler = (e) => {
if (me) {
dispatch(replyCompose(status, rebloggedBy, canReply.approvalRequired ?? false));
replyCompose(status, rebloggedBy, canReply.approvalRequired ?? false);
} else {
onOpenUnauthorizedModal('REPLY');
}
@@ -405,7 +410,7 @@ const ReblogButton: React.FC<IReblogButton> = ({
onOpenUnauthorizedModal,
publicStatus,
}) => {
const dispatch = useAppDispatch();
const { quoteCompose } = useComposeActions();
const features = useFeatures();
const intl = useIntl();
@@ -486,7 +491,7 @@ const ReblogButton: React.FC<IReblogButton> = ({
const handleQuoteClick: React.EventHandler<React.MouseEvent> = (e) => {
if (me) {
dispatch(quoteCompose(status, canQuote.approvalRequired || false));
quoteCompose(status, canQuote.approvalRequired || false);
} else {
onOpenUnauthorizedModal('REBLOG');
}
@@ -723,6 +728,7 @@ const MenuButton: React.FC<IMenuButton> = ({
const intl = useIntl();
const navigate = useNavigate();
const dispatch = useAppDispatch();
const { mentionCompose, directCompose } = useComposeActions();
const match = useMatch({ from: layouts.group.id, shouldThrow: false });
const { boostModal } = useSettings();
const client = useClient();
@@ -788,7 +794,7 @@ const MenuButton: React.FC<IMenuButton> = ({
const doDeleteStatus = (withRedraft = false) => {
if (!deleteModal) {
dispatch(deleteStatus(status.id, undefined, withRedraft));
dispatch(deleteStatus(status.id, withRedraft));
} else {
openModal('CONFIRM', {
heading: intl.formatMessage(
@@ -800,7 +806,7 @@ const MenuButton: React.FC<IMenuButton> = ({
confirm: intl.formatMessage(
withRedraft ? messages.redraftConfirm : messages.deleteConfirm,
),
onConfirm: () => dispatch(deleteStatus(status.id, undefined, withRedraft)),
onConfirm: () => dispatch(deleteStatus(status.id, withRedraft)),
});
}
};
@@ -840,11 +846,11 @@ const MenuButton: React.FC<IMenuButton> = ({
};
const handleMentionClick: React.EventHandler<React.MouseEvent> = (e) => {
dispatch(mentionCompose(status.account));
mentionCompose(status.account);
};
const handleDirectClick: React.EventHandler<React.MouseEvent> = (e) => {
dispatch(directCompose(status.account));
directCompose(status.account);
};
const handleChatClick: React.EventHandler<React.MouseEvent> = (e) => {
@@ -936,7 +942,7 @@ const MenuButton: React.FC<IMenuButton> = ({
}),
confirm: intl.formatMessage(messages.deleteConfirm),
onConfirm: () => {
dispatch(deleteStatus(status.id, group?.id));
dispatch(deleteStatusFromGroup(status.id, group!.id));
},
});
};

View File

@@ -3,7 +3,6 @@ import clsx from 'clsx';
import React, { useEffect, useMemo, useRef } from 'react';
import { defineMessages, useIntl, FormattedList, FormattedMessage } from 'react-intl';
import { mentionCompose, replyCompose } from '@/actions/compose';
import { unfilterStatus } from '@/actions/statuses';
import Card from '@/components/ui/card';
import Icon from '@/components/ui/icon';
@@ -23,6 +22,7 @@ import {
useUnreblogStatus,
} from '@/queries/statuses/use-status-interactions';
import { makeGetStatus, type SelectedStatus } from '@/selectors';
import { useComposeActions } from '@/stores/compose';
import { useModalsActions } from '@/stores/modals';
import { useSettings } from '@/stores/settings';
import { useStatusMetaActions } from '@/stores/status-meta';
@@ -197,6 +197,7 @@ const Status: React.FC<IStatus> = (props) => {
const { toggleStatusesMediaHidden } = useStatusMetaActions();
const { openModal } = useModalsActions();
const { replyCompose, mentionCompose } = useComposeActions();
const { boostModal } = useSettings();
const didShowCard = useRef(false);
const node = useRef<HTMLDivElement>(null);
@@ -276,7 +277,7 @@ const Status: React.FC<IStatus> = (props) => {
if (status.rss_feed) return;
e?.preventDefault();
dispatch(replyCompose(actualStatus, status.reblog_id ? status.account : undefined));
replyCompose(actualStatus, status.reblog_id ? status.account : undefined);
};
const handleHotkeyFavourite = (e?: KeyboardEvent) => {
@@ -305,7 +306,7 @@ const Status: React.FC<IStatus> = (props) => {
if (status.rss_feed) return;
e?.preventDefault();
dispatch(mentionCompose(actualStatus.account));
mentionCompose(actualStatus.account);
};
const handleHotkeyOpen = () => {

View File

@@ -3,16 +3,15 @@ import { useMatch } from '@tanstack/react-router';
import React from 'react';
import { defineMessages, useIntl } from 'react-intl';
import { groupComposeModal } from '@/actions/compose';
import ThumbNavigationLink from '@/components/thumb-navigation-link';
import Icon from '@/components/ui/icon';
import { useStatContext } from '@/contexts/stat-context';
import { layouts } from '@/features/ui/router';
import { useAppDispatch } from '@/hooks/use-app-dispatch';
import { useAppSelector } from '@/hooks/use-app-selector';
import { useFeatures } from '@/hooks/use-features';
import { useOwnAccount } from '@/hooks/use-own-account';
import { useNotificationsUnreadCount } from '@/queries/notifications/use-notifications';
import { useComposeActions } from '@/stores/compose';
import { useModalsActions } from '@/stores/modals';
import { useIsSidebarOpen, useUiStoreActions } from '@/stores/ui';
import { isStandalone } from '@/utils/state';
@@ -31,7 +30,6 @@ const messages = defineMessages({
const ThumbNavigation: React.FC = React.memo((): React.JSX.Element => {
const intl = useIntl();
const dispatch = useAppDispatch();
const { data: account } = useOwnAccount();
const features = useFeatures();
const queryClient = useQueryClient();
@@ -41,6 +39,7 @@ const ThumbNavigation: React.FC = React.memo((): React.JSX.Element => {
const isSidebarOpen = useIsSidebarOpen();
const { openSidebar, closeSidebar } = useUiStoreActions();
const { openModal } = useModalsActions();
const { groupComposeModal } = useComposeActions();
const { unreadChatsCount } = useStatContext();
const standalone = useAppSelector(isStandalone);
@@ -48,10 +47,8 @@ const ThumbNavigation: React.FC = React.memo((): React.JSX.Element => {
const handleOpenComposeModal = () => {
if (match?.params.groupId) {
dispatch((_, getState) => {
const group = queryClient.getQueryData<Group>(['groups', match.params.groupId]);
if (group) dispatch(groupComposeModal(group));
});
const group = queryClient.getQueryData<Group>(['groups', match.params.groupId]);
if (group) groupComposeModal(group);
} else {
openModal('COMPOSE');
}