From 542b51220a8fcb2dd71bafb88a2cb22d0f1a5674 Mon Sep 17 00:00:00 2001 From: Ian Macdonald Date: Wed, 22 Feb 2023 19:14:24 +0100 Subject: [PATCH] Add a modal dialogue to allow confirmation when marking all convos read. --- ts/components/dialog/MarkAllAsReadDialog.tsx | 53 ++++++++++++++++++++ ts/components/dialog/ModalContainer.tsx | 4 ++ ts/components/leftpane/ActionsPanel.tsx | 14 ++---- ts/state/ducks/modalDialog.tsx | 7 +++ ts/state/selectors/modal.ts | 5 ++ 5 files changed, 74 insertions(+), 9 deletions(-) create mode 100644 ts/components/dialog/MarkAllAsReadDialog.tsx diff --git a/ts/components/dialog/MarkAllAsReadDialog.tsx b/ts/components/dialog/MarkAllAsReadDialog.tsx new file mode 100644 index 0000000000..b6cf1e16d7 --- /dev/null +++ b/ts/components/dialog/MarkAllAsReadDialog.tsx @@ -0,0 +1,53 @@ +import React, { useState } from 'react'; +import { SpacerLG } from '../basic/Text'; +import { getConversationController } from '../../session/conversations'; +import { markAllAsReadModal } from '../../state/ducks/modalDialog'; +import { SessionButton, SessionButtonType } from '../basic/SessionButton'; +import { SessionWrapperModal } from '../SessionWrapperModal'; +import { ToastUtils } from '../../session/utils'; + +export const MarkAllAsReadDialog = () => { + const titleText = window.i18n('markAllAsRead'); + const okText = window.i18n('markAllAsRead'); + const cancelText = window.i18n('cancel'); + const [_isLoading, setIsLoading] = useState(false); + + const onClickOK = async () => { + setIsLoading(true); + + const controller = getConversationController(); + const convos = controller.getConversations().filter(conversation => { + return conversation.isApproved(); + }); + for (const convo of convos) { + await controller.get(convo.id).markAllAsRead(); + } + ToastUtils.pushToastSuccess( 'allMarkedRead', window.i18n('allMarkedAsRead')); + + setIsLoading(false); + closeDialog(); + }; + + const closeDialog = () => { + window.inboxStore?.dispatch(markAllAsReadModal(null)); + }; + + return ( + + + +
+ + +
+
+ ); +}; diff --git a/ts/components/dialog/ModalContainer.tsx b/ts/components/dialog/ModalContainer.tsx index d54bbe7e81..abb65b9927 100644 --- a/ts/components/dialog/ModalContainer.tsx +++ b/ts/components/dialog/ModalContainer.tsx @@ -9,6 +9,7 @@ import { getDeleteAccountModalState, getEditProfileDialog, getInviteContactModal, + getMarkAllAsReadDialog, getOnionPathDialog, getReactClearAllDialog, getReactListDialog, @@ -36,6 +37,7 @@ import { SessionNicknameDialog } from './SessionNicknameDialog'; import { BanOrUnBanUserDialog } from './BanOrUnbanUserDialog'; import { ReactListModal } from './ReactListModal'; import { ReactClearAllModal } from './ReactClearAllModal'; +import { MarkAllAsReadDialog } from './MarkAllAsReadDialog'; export const ModalContainer = () => { const confirmModalState = useSelector(getConfirmModal); @@ -55,6 +57,7 @@ export const ModalContainer = () => { const banOrUnbanUserModalState = useSelector(getBanOrUnbanUserModalState); const reactListModalState = useSelector(getReactListDialog); const reactClearAllModalState = useSelector(getReactClearAllDialog); + const markAllAsReadModalState = useSelector(getMarkAllAsReadDialog); return ( <> @@ -79,6 +82,7 @@ export const ModalContainer = () => { {confirmModalState && } {reactListModalState && } {reactClearAllModalState && } + {markAllAsReadModalState && } ); }; diff --git a/ts/components/leftpane/ActionsPanel.tsx b/ts/components/leftpane/ActionsPanel.tsx index bc15ccff72..a69fba04b0 100644 --- a/ts/components/leftpane/ActionsPanel.tsx +++ b/ts/components/leftpane/ActionsPanel.tsx @@ -26,7 +26,10 @@ import { cleanUpOldDecryptedMedias } from '../../session/crypto/DecryptedAttachm import { DURATION } from '../../session/constants'; -import { editProfileModal, onionPathModal } from '../../state/ducks/modalDialog'; +import { editProfileModal, + markAllAsReadModal, + onionPathModal +} from '../../state/ducks/modalDialog'; import { uploadOurAvatar } from '../../interactions/conversationInteractions'; import { debounce, isEmpty, isString } from 'lodash'; @@ -79,14 +82,7 @@ const Section = (props: { type: SectionType }) => { // Show Path Indicator Modal dispatch(onionPathModal({})); } else if (type === SectionType.MarkAllAsRead) { - const controller = getConversationController(); - const convos = controller.getConversations().filter(conversation => { - return conversation.isApproved(); - }); - for (const convo of convos) { - await controller.get(convo.id).markAllAsRead(); - } - ToastUtils.pushToastSuccess('allMarkedRead', window.i18n('allMarkedAsRead')); + dispatch(markAllAsReadModal({})); } else { // message section dispatch(clearSearch()); diff --git a/ts/state/ducks/modalDialog.tsx b/ts/state/ducks/modalDialog.tsx index ea8428b703..90b1610c41 100644 --- a/ts/state/ducks/modalDialog.tsx +++ b/ts/state/ducks/modalDialog.tsx @@ -20,6 +20,7 @@ export type EditProfileModalState = {} | null; export type OnionPathModalState = EditProfileModalState; export type RecoveryPhraseModalState = EditProfileModalState; export type DeleteAccountModalState = EditProfileModalState; +export type MarkAllAsReadModalState = EditProfileModalState; export type SessionPasswordModalState = { passwordAction: PasswordAction; onOk: () => void } | null; @@ -50,6 +51,7 @@ export type ModalState = { adminLeaveClosedGroup: AdminLeaveClosedGroupModalState; sessionPasswordModal: SessionPasswordModalState; deleteAccountModal: DeleteAccountModalState; + markAllAsReadModal: MarkAllAsReadModalState; reactListModalState: ReactModalsState; reactClearAllModalState: ReactModalsState; }; @@ -70,6 +72,7 @@ export const initialModalState: ModalState = { adminLeaveClosedGroup: null, sessionPasswordModal: null, deleteAccountModal: null, + markAllAsReadModal: null, reactListModalState: null, reactClearAllModalState: null, }; @@ -123,6 +126,9 @@ const ModalSlice = createSlice({ updateDeleteAccountModal(state, action: PayloadAction) { return { ...state, deleteAccountModal: action.payload }; }, + markAllAsReadModal(state, action: PayloadAction) { + return { ...state, markAllAsReadModal: action.payload }; + }, updateReactListModal(state, action: PayloadAction) { return { ...state, reactListModalState: action.payload }; }, @@ -147,6 +153,7 @@ export const { recoveryPhraseModal, adminLeaveClosedGroup, sessionPassword, + markAllAsReadModal, updateDeleteAccountModal, updateBanOrUnbanUserModal, updateReactListModal, diff --git a/ts/state/selectors/modal.ts b/ts/state/selectors/modal.ts index f959bc243c..7740da59ba 100644 --- a/ts/state/selectors/modal.ts +++ b/ts/state/selectors/modal.ts @@ -10,6 +10,7 @@ import { DeleteAccountModalState, EditProfileModalState, InviteContactModalState, + MarkAllAsReadModalState, ModalState, OnionPathModalState, ReactModalsState, @@ -109,3 +110,7 @@ export const getReactClearAllDialog = createSelector( getModal, (state: ModalState): ReactModalsState => state.reactClearAllModalState ); + +export const getMarkAllAsReadDialog = createSelector( + getModal, + (state: ModalState): MarkAllAsReadModalState => state.markAllAsReadModal);