From 651921590c40a4a4ceee83c918ccfb31ce37e1ad Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Fri, 18 Jun 2021 16:41:35 +1000 Subject: [PATCH] reduxify remaining dialogs --- js/modules/signal.js | 4 -- ts/components/EditProfileDialog.tsx | 45 +++++++----------- ts/components/LeftPane.tsx | 10 ++-- ts/components/UserDetailsDialog.tsx | 3 +- .../AdminLeaveClosedGroupDialog.tsx | 25 +++++----- ts/components/session/ActionsPanel.tsx | 47 ++++++++++++------- .../session/LeftPaneMessageSection.tsx | 9 ---- .../session/LeftPaneSettingSection.tsx | 45 ++++++++---------- .../session/SessionNicknameDialog.tsx | 33 ++++--------- ts/components/session/SessionSeedModal.tsx | 22 ++++----- ts/components/session/icon/SessionIcon.tsx | 8 ++-- .../session/icon/SessionIconButton.tsx | 8 ++-- .../session/menu/ConversationHeaderMenu.tsx | 15 +----- .../menu/ConversationListItemContextMenu.tsx | 15 +----- ts/components/session/menu/Menu.tsx | 45 ++++++++---------- ts/interactions/conversationInteractions.ts | 5 ++ ts/state/ducks/modalDialog.tsx | 44 +++++++++++++++-- ts/state/selectors/modal.ts | 30 ++++++++++++ 18 files changed, 207 insertions(+), 206 deletions(-) diff --git a/js/modules/signal.js b/js/modules/signal.js index 1e8aa1404..b9f6407c1 100644 --- a/js/modules/signal.js +++ b/js/modules/signal.js @@ -12,12 +12,10 @@ const LinkPreviews = require('./link_previews'); const { Message } = require('../../ts/components/conversation/Message'); // Components -const { SessionSeedModal } = require('../../ts/components/session/SessionSeedModal'); const { SessionIDResetDialog } = require('../../ts/components/session/SessionIDResetDialog'); const { SessionRegistrationView } = require('../../ts/components/session/SessionRegistrationView'); const { SessionInboxView } = require('../../ts/components/session/SessionInboxView'); -const { SessionPasswordModal } = require('../../ts/components/session/SessionPasswordModal'); // Types const AttachmentType = require('./types/attachment'); @@ -123,9 +121,7 @@ exports.setup = (options = {}) => { const Components = { SessionInboxView, - SessionSeedModal, SessionIDResetDialog, - SessionPasswordModal, SessionRegistrationView, Message, }; diff --git a/ts/components/EditProfileDialog.tsx b/ts/components/EditProfileDialog.tsx index 7f44a1d81..32120a42e 100644 --- a/ts/components/EditProfileDialog.tsx +++ b/ts/components/EditProfileDialog.tsx @@ -9,24 +9,16 @@ import { SessionButton, SessionButtonColor, SessionButtonType } from './session/ import { SessionIconButton, SessionIconSize, SessionIconType } from './session/icon'; import { PillDivider } from './session/PillDivider'; import { SyncUtils, ToastUtils, UserUtils } from '../session/utils'; -import { DefaultTheme } from 'styled-components'; import { MAX_USERNAME_LENGTH } from './session/registration/RegistrationTabs'; import { SessionSpinner } from './session/SessionSpinner'; -import { ConversationTypeEnum } from '../models/conversation'; +import { ConversationModel, ConversationTypeEnum } from '../models/conversation'; import { SessionWrapperModal } from './session/SessionWrapperModal'; import { AttachmentUtil } from '../util'; import { ConversationController } from '../session/conversations'; import { SpacerLG, SpacerMD } from './basic/Text'; - -interface Props { - profileName?: string; - avatarPath?: string; - pubkey?: string; - onClose?: any; - onOk?: any; - theme: DefaultTheme; -} +import autoBind from 'auto-bind'; +import { editProfileModal } from '../state/ducks/modalDialog'; interface State { profileName: string; @@ -36,23 +28,21 @@ interface State { loading: boolean; } -export class EditProfileDialog extends React.Component { +export class EditProfileDialog extends React.Component<{}, State> { private readonly inputEl: any; + private readonly convo: ConversationModel; constructor(props: any) { super(props); - this.onNameEdited = this.onNameEdited.bind(this); - this.closeDialog = this.closeDialog.bind(this); - this.onClickOK = this.onClickOK.bind(this); - this.onKeyUp = this.onKeyUp.bind(this); - this.onFileSelected = this.onFileSelected.bind(this); - this.fireInputEvent = this.fireInputEvent.bind(this); + autoBind(this); + + this.convo = ConversationController.getInstance().get(UserUtils.getOurPubKeyStrFromCache()); this.state = { - profileName: this.props.profileName || '', - setProfileName: this.props.profileName || '', - avatar: this.props.avatarPath || '', + profileName: this.convo.getProfileName() || '', + setProfileName: this.convo.getProfileName() || '', + avatar: this.convo.getAvatarPath() || '', mode: 'default', loading: false, }; @@ -98,7 +88,6 @@ export class EditProfileDialog extends React.Component { } public render() { - // const i18n = this.props.i18n; const i18n = window.i18n; const viewDefault = this.state.mode === 'default'; @@ -194,7 +183,6 @@ export class EditProfileDialog extends React.Component { onClick={() => { this.setState({ mode: 'qr' }); }} - theme={this.props.theme} /> @@ -226,7 +214,6 @@ export class EditProfileDialog extends React.Component { onClick={() => { this.setState({ mode: 'edit' }); }} - theme={this.props.theme} /> @@ -278,10 +265,11 @@ export class EditProfileDialog extends React.Component { private renderAvatar() { const { avatar, profileName } = this.state; - const { pubkey } = this.props; - const userName = profileName || pubkey; + const userName = profileName || this.convo.id; - return ; + return ( + + ); } private onNameEdited(event: any) { @@ -299,7 +287,6 @@ export class EditProfileDialog extends React.Component { switch (event.key) { case 'Enter': if (this.state.mode === 'edit') { - // this.onClickOK(); this.onClickOK(); } break; @@ -353,7 +340,7 @@ export class EditProfileDialog extends React.Component { private closeDialog() { window.removeEventListener('keyup', this.onKeyUp); - this.props.onClose(); + window.inboxStore?.dispatch(editProfileModal(null)); } private async commitProfileEdits(newName: string, avatar: any) { diff --git a/ts/components/LeftPane.tsx b/ts/components/LeftPane.tsx index 485eb3d68..4b5e4cfb0 100644 --- a/ts/components/LeftPane.tsx +++ b/ts/components/LeftPane.tsx @@ -86,9 +86,8 @@ const InnerLeftPaneContactSection = () => { ); }; -const LeftPaneSection = (props: { isExpired: boolean; setModal: any }) => { +const LeftPaneSection = (props: { isExpired: boolean }) => { const focusedSection = useSelector(getFocusedSection); - const { setModal } = props; if (focusedSection === SectionType.Message) { return ; @@ -98,7 +97,7 @@ const LeftPaneSection = (props: { isExpired: boolean; setModal: any }) => { return ; } if (focusedSection === SectionType.Settings) { - return ; + return ; } return <>; }; @@ -106,17 +105,14 @@ const LeftPaneSection = (props: { isExpired: boolean; setModal: any }) => { export const LeftPane = (props: Props) => { const theme = useSelector(getTheme); - const [modal, setModal] = useState(null); - return ( <> - {modal ? modal : null}
- +
diff --git a/ts/components/UserDetailsDialog.tsx b/ts/components/UserDetailsDialog.tsx index ba4685963..0f7d0737e 100644 --- a/ts/components/UserDetailsDialog.tsx +++ b/ts/components/UserDetailsDialog.tsx @@ -9,6 +9,7 @@ import { SessionWrapperModal } from './session/SessionWrapperModal'; import { SpacerMD } from './basic/Text'; import autoBind from 'auto-bind'; import { updateUserDetailsModal } from '../state/ducks/modalDialog'; +import { openConversationExternal } from '../state/ducks/conversations'; type Props = { conversationId: string; @@ -99,7 +100,7 @@ export class UserDetailsDialog extends React.Component { ConversationTypeEnum.PRIVATE ); - window.inboxStore?.dispatch(window.actionsCreators.openConversationExternal(conversation.id)); + window.inboxStore?.dispatch(openConversationExternal(conversation.id)); this.closeDialog(); } diff --git a/ts/components/conversation/AdminLeaveClosedGroupDialog.tsx b/ts/components/conversation/AdminLeaveClosedGroupDialog.tsx index 109c9bf1f..f78877baa 100644 --- a/ts/components/conversation/AdminLeaveClosedGroupDialog.tsx +++ b/ts/components/conversation/AdminLeaveClosedGroupDialog.tsx @@ -1,32 +1,31 @@ import React from 'react'; import { SessionButton, SessionButtonColor } from '../session/SessionButton'; -import { DefaultTheme } from 'styled-components'; import { SessionWrapperModal } from '../session/SessionWrapperModal'; import { SpacerLG } from '../basic/Text'; +import { ConversationController } from '../../session/conversations'; +import { adminLeaveClosedGroup } from '../../state/ducks/modalDialog'; type Props = { - groupName: string; - onSubmit: () => any; - onClose: any; - theme: DefaultTheme; + conversationId: string; }; -const AdminLeaveClosedGroupDialogInner = (props: Props) => { - const { groupName, theme, onSubmit, onClose } = props; - - const titleText = `${window.i18n('leaveGroup')} ${groupName}`; +export const AdminLeaveClosedGroupDialog = (props: Props) => { + const convo = ConversationController.getInstance().get(props.conversationId); + const titleText = `${window.i18n('leaveGroup')} ${convo.getName()}`; const warningAsAdmin = `${window.i18n('leaveGroupConfirmationAdmin')}`; const okText = window.i18n('leaveAndRemoveForEveryone'); const cancelText = window.i18n('cancel'); - const onClickOK = () => { - void onSubmit(); + const onClickOK = async () => { + await ConversationController.getInstance() + .get(props.conversationId) + .leaveClosedGroup(); closeDialog(); }; const closeDialog = () => { - onClose(); + window.inboxStore?.dispatch(adminLeaveClosedGroup(null)); }; return ( @@ -41,5 +40,3 @@ const AdminLeaveClosedGroupDialogInner = (props: Props) => { ); }; - -export const AdminLeaveClosedGroupDialog = AdminLeaveClosedGroupDialogInner; diff --git a/ts/components/session/ActionsPanel.tsx b/ts/components/session/ActionsPanel.tsx index 41d986a5f..270762464 100644 --- a/ts/components/session/ActionsPanel.tsx +++ b/ts/components/session/ActionsPanel.tsx @@ -50,8 +50,13 @@ import { EditProfileDialog } from '../EditProfileDialog'; import { SessionConfirm } from './SessionConfirm'; import { getAddModeratorsModal, + getAdminLeaveClosedGroupDialog, + getChangeNickNameDialog, getConfirmModal, + getEditProfileDialog, getInviteContactModal, + getOnionPathDialog, + getRecoveryPhraseDialog, getRemoveModeratorsModal, getUpdateGroupMembersModal, getUpdateGroupNameModal, @@ -63,6 +68,10 @@ import { RemoveModeratorsDialog } from '../conversation/ModeratorsRemoveDialog'; import { UpdateGroupNameDialog } from '../conversation/UpdateGroupNameDialog'; import { UpdateGroupMembersDialog } from '../conversation/UpdateGroupMembersDialog'; import { UserDetailsDialog } from '../UserDetailsDialog'; +import { SessionNicknameDialog } from './SessionNicknameDialog'; +import { editProfileModal, onionPathModal } from '../../state/ducks/modalDialog'; +import { SessionSeedModal } from './SessionSeedModal'; +import { AdminLeaveClosedGroupDialog } from '../conversation/AdminLeaveClosedGroupDialog'; // tslint:disable-next-line: no-import-side-effect no-submodule-imports @@ -76,24 +85,20 @@ export enum SectionType { PathIndicator, } -const Section = (props: { setModal?: any; type: SectionType; avatarPath?: string }) => { +const Section = (props: { type: SectionType; avatarPath?: string }) => { const ourNumber = useSelector(getOurNumber); const unreadMessageCount = useSelector(getUnreadMessageCount); const theme = useSelector(getTheme); const dispatch = useDispatch(); - const { setModal, type, avatarPath } = props; + const { type, avatarPath } = props; const focusedSection = useSelector(getFocusedSection); const isSelected = focusedSection === props.type; - const handleModalClose = () => { - setModal(null); - }; - const handleClick = () => { /* tslint:disable:no-void-expression */ if (type === SectionType.Profile) { - setModal(); + dispatch(editProfileModal({})); } else if (type === SectionType.Moon) { const themeFromSettings = window.Events.getThemeSetting(); const updatedTheme = themeFromSettings === 'dark' ? 'light' : 'dark'; @@ -103,7 +108,7 @@ const Section = (props: { setModal?: any; type: SectionType; avatarPath?: string dispatch(applyTheme(newThemeObject)); } else if (type === SectionType.PathIndicator) { // Show Path Indicator Modal - setModal(); + dispatch(onionPathModal({})); } else { dispatch(clearSearch()); dispatch(showLeftPaneSection(type)); @@ -346,9 +351,14 @@ const ModalContainer = () => { const updateGroupMembersModalState = useSelector(getUpdateGroupMembersModal); const updateGroupNameModalState = useSelector(getUpdateGroupNameModal); const userDetailsModalState = useSelector(getUserDetailsModal); + const changeNicknameModal = useSelector(getChangeNickNameDialog); + const editProfileModalState = useSelector(getEditProfileDialog); + const onionPathModalState = useSelector(getOnionPathDialog); + const recoveryPhraseModalState = useSelector(getRecoveryPhraseDialog); + const adminLeaveClosedGroupModalState = useSelector(getAdminLeaveClosedGroupDialog); return ( - + <> {confirmModalState && } {inviteModalState && } {addModeratorsModalState && } @@ -358,7 +368,14 @@ const ModalContainer = () => { )} {updateGroupNameModalState && } {userDetailsModalState && } - + {changeNicknameModal && } + {editProfileModalState && } + {onionPathModalState && } + {recoveryPhraseModalState && } + {adminLeaveClosedGroupModalState && ( + + )} + ); }; @@ -369,7 +386,6 @@ const ModalContainer = () => { export const ActionsPanel = () => { const [startCleanUpMedia, setStartCleanUpMedia] = useState(false); const ourPrimaryConversation = useSelector(getOurPrimaryConversation); - const [modal, setModal] = useState(null); // this maxi useEffect is called only once: when the component is mounted. // For the action panel, it means this is called only one per app start/with a user loggedin @@ -412,21 +428,16 @@ export const ActionsPanel = () => { return ( <> - {modal && modal}
-
+
-
+
diff --git a/ts/components/session/LeftPaneMessageSection.tsx b/ts/components/session/LeftPaneMessageSection.tsx index 87099faf0..42f7ef118 100644 --- a/ts/components/session/LeftPaneMessageSection.tsx +++ b/ts/components/session/LeftPaneMessageSection.tsx @@ -62,7 +62,6 @@ interface State { loading: boolean; overlay: false | SessionComposeToType; valuePasted: string; - modal: null | JSX.Element; } export class LeftPaneMessageSection extends React.Component { @@ -75,7 +74,6 @@ export class LeftPaneMessageSection extends React.Component { loading: false, overlay: false, valuePasted: '', - modal: null, }; autoBind(this); @@ -169,18 +167,11 @@ export class LeftPaneMessageSection extends React.Component { return (
{this.renderHeader()} - {this.state.modal ? this.state.modal : null} {overlay ? this.renderClosableOverlay(overlay) : this.renderConversations()}
); } - public setModal(modal: null | JSX.Element) { - this.setState({ - modal, - }); - } - public renderConversations() { return (
diff --git a/ts/components/session/LeftPaneSettingSection.tsx b/ts/components/session/LeftPaneSettingSection.tsx index 9e3799e0c..6778e8f03 100644 --- a/ts/components/session/LeftPaneSettingSection.tsx +++ b/ts/components/session/LeftPaneSettingSection.tsx @@ -14,6 +14,7 @@ import { getFocusedSettingsSection } from '../../state/selectors/section'; import { getTheme } from '../../state/selectors/theme'; import { SessionConfirm } from './SessionConfirm'; import { SessionSeedModal } from './SessionSeedModal'; +import { recoveryPhraseModal, updateConfirmModal } from '../../state/ducks/modalDialog'; type Props = { settingsCategory: SessionSettingCategory; @@ -104,37 +105,33 @@ const LeftPaneSettingsCategories = () => { ); }; -const onDeleteAccount = (setModal: any) => { +const onDeleteAccount = () => { const title = window.i18n('clearAllData'); const message = window.i18n('deleteAccountWarning'); - const clearModal = () => { - setModal(null); + const onClickClose = () => { + window.inboxStore?.dispatch(updateConfirmModal(null)); }; - setModal( - + window.inboxStore?.dispatch( + updateConfirmModal({ + title, + message, + okTheme: SessionButtonColor.Danger, + onClickOk: deleteAccount, + onClickClose, + closeAfterClickOk: true, + }) ); }; -const onShowRecoverPhrase = (setModal: any) => { - const clearModal = () => { - setModal(null); - }; - - setModal(); +const onShowRecoveryPhrase = () => { + window.inboxStore?.dispatch(recoveryPhraseModal({})); }; -const LeftPaneBottomButtons = (props: { setModal: any }) => { +const LeftPaneBottomButtons = () => { const dangerButtonText = window.i18n('clearAllData'); const showRecoveryPhrase = window.i18n('showRecoveryPhrase'); - const { setModal } = props; return (
@@ -143,7 +140,7 @@ const LeftPaneBottomButtons = (props: { setModal: any }) => { buttonType={SessionButtonType.SquareOutline} buttonColor={SessionButtonColor.Danger} onClick={() => { - onDeleteAccount(setModal); + onDeleteAccount(); }} /> @@ -152,23 +149,21 @@ const LeftPaneBottomButtons = (props: { setModal: any }) => { buttonType={SessionButtonType.SquareOutline} buttonColor={SessionButtonColor.White} onClick={() => { - onShowRecoverPhrase(setModal); + onShowRecoveryPhrase(); }} />
); }; -export const LeftPaneSettingSection = (props: { setModal: any }) => { +export const LeftPaneSettingSection = () => { const theme = useSelector(getTheme); - const { setModal } = props; - return (
- +
); diff --git a/ts/components/session/SessionNicknameDialog.tsx b/ts/components/session/SessionNicknameDialog.tsx index 210a02b3f..b22ac3737 100644 --- a/ts/components/session/SessionNicknameDialog.tsx +++ b/ts/components/session/SessionNicknameDialog.tsx @@ -1,25 +1,22 @@ import React, { useState } from 'react'; import { ConversationController } from '../../session/conversations/ConversationController'; import { SessionButton } from './SessionButton'; -import { DefaultTheme, useTheme, withTheme } from 'styled-components'; import _ from 'lodash'; import { SessionWrapperModal } from './SessionWrapperModal'; import { SpacerLG } from '../basic/Text'; +import { useDispatch } from 'react-redux'; +import { changeNickNameModal } from '../../state/ducks/modalDialog'; type Props = { - onClickOk?: any; - onClickClose?: any; - theme?: DefaultTheme; - conversationId?: string; + conversationId: string; }; -const SessionNicknameInner = (props: Props) => { - const { onClickOk, onClickClose, conversationId } = props; - let { theme } = props; +export const SessionNicknameDialog = (props: Props) => { + const { conversationId } = props; const [nickname, setNickname] = useState(''); - theme = theme ? theme : useTheme(); + const dispatch = useDispatch(); /** * Changes the state of nickname variable. If enter is pressed, saves the current @@ -34,6 +31,10 @@ const SessionNicknameInner = (props: Props) => { } }; + const onClickClose = () => { + dispatch(changeNickNameModal(null)); + }; + /** * Saves the currently entered nickname. */ @@ -42,23 +43,11 @@ const SessionNicknameInner = (props: Props) => { throw new Error('Cant save without conversation id'); } const conversation = ConversationController.getInstance().get(conversationId); - if (onClickOk) { - onClickOk(nickname); - } await conversation.setNickname(nickname); onClickClose(); }; return ( - // - - // TODO: Implement showHeader option for modal { ); }; - -export const SessionNicknameDialog = withTheme(SessionNicknameInner); diff --git a/ts/components/session/SessionSeedModal.tsx b/ts/components/session/SessionSeedModal.tsx index 925c343bb..0f4875a36 100644 --- a/ts/components/session/SessionSeedModal.tsx +++ b/ts/components/session/SessionSeedModal.tsx @@ -10,11 +10,8 @@ import { QRCode } from 'react-qr-svg'; import { mn_decode } from '../../session/crypto/mnemonic'; import { SessionWrapperModal } from './SessionWrapperModal'; import { SpacerLG, SpacerSM, SpacerXS } from '../basic/Text'; - -interface Props { - onClose: any; - theme: DefaultTheme; -} +import autoBind from 'auto-bind'; +import { recoveryPhraseModal } from '../../state/ducks/modalDialog'; interface State { error: string; @@ -26,7 +23,7 @@ interface State { passwordValid: boolean; } -class SessionSeedModalInner extends React.Component { +class SessionSeedModalInner extends React.Component<{}, State> { constructor(props: any) { super(props); @@ -40,11 +37,7 @@ class SessionSeedModalInner extends React.Component { passwordValid: false, }; - this.copyRecoveryPhrase = this.copyRecoveryPhrase.bind(this); - this.getRecoveryPhrase = this.getRecoveryPhrase.bind(this); - this.confirmPassword = this.confirmPassword.bind(this); - this.checkHasPassword = this.checkHasPassword.bind(this); - this.onEnter = this.onEnter.bind(this); + autoBind(this); } public componentDidMount() { @@ -57,9 +50,9 @@ class SessionSeedModalInner extends React.Component { void this.checkHasPassword(); void this.getRecoveryPhrase(); - const { onClose } = this.props; const { hasPassword, passwordValid } = this.state; const loading = this.state.loadingPassword || this.state.loadingSeed; + const onClose = () => window.inboxStore?.dispatch(recoveryPhraseModal(null)); return ( <> @@ -81,7 +74,8 @@ class SessionSeedModalInner extends React.Component { private renderPasswordView() { const error = this.state.error; const i18n = window.i18n; - const { onClose } = this.props; + + const onClose = () => window.inboxStore?.dispatch(recoveryPhraseModal(null)); return ( <> @@ -206,7 +200,7 @@ class SessionSeedModalInner extends React.Component { window.clipboard.writeText(recoveryPhrase); ToastUtils.pushCopiedToClipBoard(); - this.props.onClose(); + window.inboxStore?.dispatch(recoveryPhraseModal(null)); } private onEnter(event: any) { diff --git a/ts/components/session/icon/SessionIcon.tsx b/ts/components/session/icon/SessionIcon.tsx index bdda810a6..5bdcb0317 100644 --- a/ts/components/session/icon/SessionIcon.tsx +++ b/ts/components/session/icon/SessionIcon.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { icons, SessionIconSize, SessionIconType } from '../icon'; -import styled, { css, DefaultTheme, keyframes } from 'styled-components'; +import styled, { css, DefaultTheme, keyframes, useTheme } from 'styled-components'; import _ from 'lodash'; export type SessionIconProps = { @@ -12,7 +12,7 @@ export type SessionIconProps = { glowDuration?: number; borderRadius?: number; glowStartDelay?: number; - theme: DefaultTheme; + theme?: DefaultTheme; }; const getIconDimensionFromIconSize = (iconSize: SessionIconSize | number) => { @@ -163,6 +163,8 @@ export const SessionIcon = (props: SessionIconProps) => { iconSize = iconSize || SessionIconSize.Medium; iconRotation = iconRotation || 0; + const themeToUse = theme || useTheme(); + const iconDimensions = getIconDimensionFromIconSize(iconSize); const iconDef = icons[iconType]; const ratio = iconDef?.ratio || 1; @@ -182,7 +184,7 @@ export const SessionIcon = (props: SessionIconProps) => { borderRadius={borderRadius} iconRotation={iconRotation} iconColor={iconColor} - theme={theme} + theme={themeToUse} /> ); }; diff --git a/ts/components/session/icon/SessionIconButton.tsx b/ts/components/session/icon/SessionIconButton.tsx index 121e0fb05..fe4c410e8 100644 --- a/ts/components/session/icon/SessionIconButton.tsx +++ b/ts/components/session/icon/SessionIconButton.tsx @@ -2,13 +2,13 @@ import React from 'react'; import classNames from 'classnames'; import { SessionIcon, SessionIconProps } from '../icon'; import { SessionNotificationCount } from '../SessionNotificationCount'; -import { DefaultTheme } from 'styled-components'; +import { DefaultTheme, useTheme } from 'styled-components'; interface SProps extends SessionIconProps { onClick?: any; notificationCount?: number; isSelected?: boolean; - theme: DefaultTheme; + theme?: DefaultTheme; } export const SessionIconButton = (props: SProps) => { @@ -28,6 +28,8 @@ export const SessionIconButton = (props: SProps) => { } }; + const themeToUSe = theme || useTheme(); + return (
{ iconSize={iconSize} iconColor={iconColor} iconRotation={iconRotation} - theme={theme} + theme={themeToUSe} /> {Boolean(notificationCount) && }
diff --git a/ts/components/session/menu/ConversationHeaderMenu.tsx b/ts/components/session/menu/ConversationHeaderMenu.tsx index 01b1d9dce..40b9f97c8 100644 --- a/ts/components/session/menu/ConversationHeaderMenu.tsx +++ b/ts/components/session/menu/ConversationHeaderMenu.tsx @@ -55,12 +55,8 @@ export const ConversationHeaderMenu = (props: PropsConversationHeaderMenu) => { currentNotificationSetting, } = props; - const [modal, setModal] = useState(null); - return ( <> - {modal ? modal : null} - {getDisappearingMenuItem( isPublic, @@ -82,20 +78,13 @@ export const ConversationHeaderMenu = (props: PropsConversationHeaderMenu) => { {getCopyMenuItem(isPublic, isGroup, conversationId)} {getMarkAllReadMenuItem(conversationId)} - {getChangeNicknameMenuItem(isMe, isGroup, conversationId, setModal)} + {getChangeNicknameMenuItem(isMe, isGroup, conversationId)} {getClearNicknameMenuItem(isMe, hasNickname, isGroup, conversationId)} {getDeleteMessagesMenuItem(isPublic, conversationId)} {getAddModeratorsMenuItem(isAdmin, isKickedFromGroup, conversationId)} {getRemoveModeratorsMenuItem(isAdmin, isKickedFromGroup, conversationId)} {getUpdateGroupNameMenuItem(isAdmin, isKickedFromGroup, left, conversationId)} - {getLeaveGroupMenuItem( - isKickedFromGroup, - left, - isGroup, - isPublic, - conversationId, - setModal - )} + {getLeaveGroupMenuItem(isKickedFromGroup, left, isGroup, isPublic, conversationId)} {/* TODO: add delete group */} {getInviteContactMenuItem(isGroup, isPublic, conversationId)} {getDeleteContactMenuItem(isMe, isGroup, isPublic, left, isKickedFromGroup, conversationId)} diff --git a/ts/components/session/menu/ConversationListItemContextMenu.tsx b/ts/components/session/menu/ConversationListItemContextMenu.tsx index d773c2e84..b00546fdb 100644 --- a/ts/components/session/menu/ConversationListItemContextMenu.tsx +++ b/ts/components/session/menu/ConversationListItemContextMenu.tsx @@ -43,30 +43,19 @@ export const ConversationListItemContextMenu = (props: PropsContextConversationI const isGroup = type === 'group'; - const [modal, setModal] = useState(null); - return ( <> - {modal ? modal : null} - {getBlockMenuItem(isMe, type === ConversationTypeEnum.PRIVATE, isBlocked, conversationId)} {getCopyMenuItem(isPublic, isGroup, conversationId)} {getMarkAllReadMenuItem(conversationId)} - {getChangeNicknameMenuItem(isMe, isGroup, conversationId, setModal)} + {getChangeNicknameMenuItem(isMe, isGroup, conversationId)} {getClearNicknameMenuItem(isMe, hasNickname, isGroup, conversationId)} {getDeleteMessagesMenuItem(isPublic, conversationId)} {getInviteContactMenuItem(isGroup, isPublic, conversationId)} {getDeleteContactMenuItem(isMe, isGroup, isPublic, left, isKickedFromGroup, conversationId)} - {getLeaveGroupMenuItem( - isKickedFromGroup, - left, - isGroup, - isPublic, - conversationId, - setModal - )} + {getLeaveGroupMenuItem(isKickedFromGroup, left, isGroup, isPublic, conversationId)} ); diff --git a/ts/components/session/menu/Menu.tsx b/ts/components/session/menu/Menu.tsx index c61f6508a..18e222924 100644 --- a/ts/components/session/menu/Menu.tsx +++ b/ts/components/session/menu/Menu.tsx @@ -3,9 +3,12 @@ import React from 'react'; import { NotificationForConvoOption, TimerOption } from '../../conversation/ConversationHeader'; import { Item, Submenu } from 'react-contexify'; import { ConversationNotificationSettingType } from '../../../models/conversation'; -import { SessionNicknameDialog } from '../SessionNicknameDialog'; import { useDispatch } from 'react-redux'; -import { updateConfirmModal } from '../../../state/ducks/modalDialog'; +import { + adminLeaveClosedGroup, + changeNickNameModal, + updateConfirmModal, +} from '../../../state/ducks/modalDialog'; import { ConversationController } from '../../../session/conversations'; import { UserUtils } from '../../../session/utils'; import { AdminLeaveClosedGroupDialog } from '../../conversation/AdminLeaveClosedGroupDialog'; @@ -179,8 +182,7 @@ export function getLeaveGroupMenuItem( left: boolean | undefined, isGroup: boolean | undefined, isPublic: boolean | undefined, - conversationId: string, - setModal: any + conversationId: string ): JSX.Element | null { if ( showLeaveGroup(Boolean(isKickedFromGroup), Boolean(left), Boolean(isGroup), Boolean(isPublic)) @@ -218,15 +220,10 @@ export function getLeaveGroupMenuItem( }) ); } else { - setModal( - { - setModal(null); - }} - theme={theme} - /> + dispatch( + adminLeaveClosedGroup({ + conversationId, + }) ); } }; @@ -429,22 +426,18 @@ export function getClearNicknameMenuItem( export function getChangeNicknameMenuItem( isMe: boolean | undefined, isGroup: boolean | undefined, - conversationId?: string, - setModal?: any + conversationId: string ): JSX.Element | null { + const dispatch = useDispatch(); if (showChangeNickname(Boolean(isMe), Boolean(isGroup))) { - const clearModal = () => { - setModal(null); - }; - - const onClickCustom = () => { - setModal(); - }; - return ( - <> - {window.i18n('changeNickname')} - + { + dispatch(changeNickNameModal({ conversationId })); + }} + > + {window.i18n('changeNickname')} + ); } return null; diff --git a/ts/interactions/conversationInteractions.ts b/ts/interactions/conversationInteractions.ts index 0e8b3a718..19bb60fb7 100644 --- a/ts/interactions/conversationInteractions.ts +++ b/ts/interactions/conversationInteractions.ts @@ -17,6 +17,7 @@ import _ from 'lodash'; import { ConversationController } from '../session/conversations'; import { BlockedNumberController } from '../util/blockedNumberController'; import { + changeNickNameModal, updateAddModeratorsModal, updateConfirmModal, updateGroupMembersModal, @@ -235,6 +236,10 @@ export async function clearNickNameByConvoId(conversationId: string) { await conversation.setNickname(''); } +export function showChangeNickNameByConvoId(conversationId: string) { + window.inboxStore?.dispatch(changeNickNameModal({ conversationId })); +} + export async function deleteMessagesByConvoIdNoConfirmation(conversationId: string) { const conversation = ConversationController.getInstance().get(conversationId); await removeAllMessagesInConversation(conversationId); diff --git a/ts/state/ducks/modalDialog.tsx b/ts/state/ducks/modalDialog.tsx index 8b1632cdd..a7279afcf 100644 --- a/ts/state/ducks/modalDialog.tsx +++ b/ts/state/ducks/modalDialog.tsx @@ -3,10 +3,16 @@ import { SessionConfirmDialogProps } from '../../components/session/SessionConfi export type ConfirmModalState = SessionConfirmDialogProps | null; export type InviteContactModalState = { conversationId: string } | null; -export type AddModeratorsModalState = { conversationId: string } | null; -export type RemoveModeratorsModalState = { conversationId: string } | null; -export type UpdateGroupMembersModalState = { conversationId: string } | null; -export type UpdateGroupNameModalState = { conversationId: string } | null; +export type AddModeratorsModalState = InviteContactModalState; +export type RemoveModeratorsModalState = InviteContactModalState; +export type UpdateGroupMembersModalState = InviteContactModalState; +export type UpdateGroupNameModalState = InviteContactModalState; +export type ChangeNickNameModalState = InviteContactModalState; +export type AdminLeaveClosedGroupModalState = InviteContactModalState; +export type EditProfileModalState = {} | null; +export type OnionPathModalState = EditProfileModalState; +export type RecoveryPhraseModalState = EditProfileModalState; + export type UserDetailsModalState = { conversationId: string; authorAvatarPath?: string; @@ -21,6 +27,11 @@ export type ModalState = { groupNameModal: UpdateGroupNameModalState; groupMembersModal: UpdateGroupMembersModalState; userDetailsModal: UserDetailsModalState; + nickNameModal: ChangeNickNameModalState; + editProfileModal: EditProfileModalState; + onionPathModal: OnionPathModalState; + recoveryPhraseModal: RecoveryPhraseModalState; + adminLeaveClosedGroup: AdminLeaveClosedGroupModalState; }; export const initialModalState: ModalState = { @@ -31,6 +42,11 @@ export const initialModalState: ModalState = { groupNameModal: null, groupMembersModal: null, userDetailsModal: null, + nickNameModal: null, + editProfileModal: null, + onionPathModal: null, + recoveryPhraseModal: null, + adminLeaveClosedGroup: null, }; const ModalSlice = createSlice({ @@ -58,6 +74,21 @@ const ModalSlice = createSlice({ updateUserDetailsModal(state, action: PayloadAction) { return { ...state, userDetailsModal: action.payload }; }, + changeNickNameModal(state, action: PayloadAction) { + return { ...state, nickNameModal: action.payload }; + }, + editProfileModal(state, action: PayloadAction) { + return { ...state, editProfileModal: action.payload }; + }, + onionPathModal(state, action: PayloadAction) { + return { ...state, onionPathModal: action.payload }; + }, + recoveryPhraseModal(state, action: PayloadAction) { + return { ...state, onionPathModal: action.payload }; + }, + adminLeaveClosedGroup(state, action: PayloadAction) { + return { ...state, adminLeaveClosedGroup: action.payload }; + }, }, }); @@ -70,5 +101,10 @@ export const { updateGroupNameModal, updateGroupMembersModal, updateUserDetailsModal, + changeNickNameModal, + editProfileModal, + onionPathModal, + recoveryPhraseModal, + adminLeaveClosedGroup, } = actions; export const modalReducer = reducer; diff --git a/ts/state/selectors/modal.ts b/ts/state/selectors/modal.ts index f70f64fd0..769b18e23 100644 --- a/ts/state/selectors/modal.ts +++ b/ts/state/selectors/modal.ts @@ -3,9 +3,14 @@ import { createSelector } from 'reselect'; import { StateType } from '../reducer'; import { AddModeratorsModalState, + AdminLeaveClosedGroupModalState, + ChangeNickNameModalState, ConfirmModalState, + EditProfileModalState, InviteContactModalState, ModalState, + OnionPathModalState, + RecoveryPhraseModalState, RemoveModeratorsModalState, UpdateGroupMembersModalState, UpdateGroupNameModalState, @@ -50,3 +55,28 @@ export const getUserDetailsModal = createSelector( getModal, (state: ModalState): UserDetailsModalState => state.userDetailsModal ); + +export const getChangeNickNameDialog = createSelector( + getModal, + (state: ModalState): ChangeNickNameModalState => state.nickNameModal +); + +export const getEditProfileDialog = createSelector( + getModal, + (state: ModalState): EditProfileModalState => state.editProfileModal +); + +export const getOnionPathDialog = createSelector( + getModal, + (state: ModalState): OnionPathModalState => state.onionPathModal +); + +export const getRecoveryPhraseDialog = createSelector( + getModal, + (state: ModalState): RecoveryPhraseModalState => state.recoveryPhraseModal +); + +export const getAdminLeaveClosedGroupDialog = createSelector( + getModal, + (state: ModalState): AdminLeaveClosedGroupModalState => state.adminLeaveClosedGroup +);