Refactor confirm modal to redux.

This commit is contained in:
Warrick Corfe-Tan 2021-06-09 10:06:23 +10:00
parent 1bfdbc5c93
commit e55cae697d
24 changed files with 737 additions and 295 deletions

View file

@ -39,7 +39,6 @@ export class MessageView extends React.Component {
async function createClosedGroup(
groupName: string,
groupMembers: Array<ContactType>,
setModal: () => void
): Promise<boolean> {
// Validate groupName and groupMembers length
if (groupName.length === 0) {
@ -64,7 +63,7 @@ async function createClosedGroup(
const groupMemberIds = groupMembers.map(m => m.id);
await createClosedGroupV2(groupName, groupMemberIds, setModal);
await createClosedGroupV2(groupName, groupMemberIds);
return true;
}

View file

@ -34,6 +34,8 @@ export type StatusLightType = {
const OnionPathModalInner = (props: any) => {
const onionNodes = useSelector((state: StateType) => state.onionPaths.snodePath);
const confirmModalState = useSelector((state: StateType) => state);
console.log('onion path: ', confirmModalState);
const onionPath = onionNodes.path;
// including the device and destination in calculation
const glowDuration = onionPath.length + 2;

View file

@ -2,52 +2,53 @@ import React from 'react';
import { SessionModal } from '../session/SessionModal';
import { SessionButton, SessionButtonColor } from '../session/SessionButton';
import { DefaultTheme } from 'styled-components';
import { DefaultTheme, useTheme } from 'styled-components';
import { SessionWrapperModal } from '../session/SessionWrapperModal';
interface Props {
groupName: string;
onSubmit: any;
onSubmit: () => any;
onClose: any;
theme: DefaultTheme;
}
class AdminLeaveClosedGroupDialogInner extends React.Component<Props> {
constructor(props: any) {
super(props);
const AdminLeaveClosedGroupDialogInner = (props: Props) => {
this.closeDialog = this.closeDialog.bind(this);
this.onClickOK = this.onClickOK.bind(this);
const { groupName, theme, onSubmit, onClose } = props;
const titleText = `${window.i18n('leaveGroup')} ${groupName}`;
const warningAsAdmin = `${window.i18n('leaveGroupConfirmationAdmin')}`;
const okText = window.i18n('leaveAndRemoveForEveryone');
const cancelText = window.i18n('cancel');
const onClickOK = () => {
void onSubmit();
closeDialog();
}
public render() {
const titleText = `${window.i18n('leaveGroup')} ${this.props.groupName}`;
const warningAsAdmin = `${window.i18n('leaveGroupConfirmationAdmin')}`;
const okText = window.i18n('leaveAndRemoveForEveryone');
return (
<SessionModal title={titleText} onClose={this.closeDialog} theme={this.props.theme}>
<div className="spacer-lg" />
<p>{warningAsAdmin}</p>
<div className="session-modal__button-group">
<SessionButton
text={okText}
onClick={this.onClickOK}
buttonColor={SessionButtonColor.Danger}
/>
</div>
</SessionModal>
);
const closeDialog = () => {
onClose();
}
private onClickOK() {
this.props.onSubmit();
this.closeDialog();
}
return (
<SessionWrapperModal title={titleText} onClose={closeDialog} theme={theme}>
private closeDialog() {
this.props.onClose();
}
<div className="spacer-lg" />
<p>{warningAsAdmin}</p>
<div className="session-modal__button-group">
<SessionButton
text={okText}
onClick={onClickOK}
buttonColor={SessionButtonColor.Danger}
/>
<SessionButton
text={cancelText}
onClick={closeDialog}
/>
</div>
</SessionWrapperModal>
);
}
export const AdminLeaveClosedGroupDialog = AdminLeaveClosedGroupDialogInner;

View file

@ -1,4 +1,4 @@
import React from 'react';
import React, { useEffect, useState } from 'react';
import { SessionButton, SessionButtonColor, SessionButtonType } from '../session/SessionButton';
import { PubKey } from '../../session/types';
import { ToastUtils } from '../../session/utils';
@ -8,6 +8,7 @@ import { SessionSpinner } from '../session/SessionSpinner';
import { Flex } from '../basic/Flex';
import { ConversationModel } from '../../models/conversation';
import { ApiV2 } from '../../opengroup/opengroupV2';
import { processDecrypted } from '../../receiver/dataMessage';
interface Props {
convo: ConversationModel;
onClose: any;
@ -20,33 +21,144 @@ interface State {
firstLoading: boolean;
}
export class AddModeratorsDialog extends React.Component<Props, State> {
private channelAPI: any;
// export class AddModeratorsDialog extends React.Component<Props, State> {
// private channelAPI: any;
constructor(props: Props) {
super(props);
// constructor(props: Props) {
// super(props);
this.addAsModerator = this.addAsModerator.bind(this);
this.onPubkeyBoxChanges = this.onPubkeyBoxChanges.bind(this);
// this.addAsModerator = this.addAsModerator.bind(this);
// this.onPubkeyBoxChanges = this.onPubkeyBoxChanges.bind(this);
this.state = {
inputBoxValue: '',
addingInProgress: false,
firstLoading: true,
};
}
// this.state = {
// inputBoxValue: '',
// addingInProgress: false,
// firstLoading: true,
// };
// }
public async componentDidMount() {
if (this.props.convo.isOpenGroupV1()) {
this.channelAPI = await this.props.convo.getPublicSendData();
// public async componentDidMount() {
// if (this.props.convo.isOpenGroupV1()) {
// this.channelAPI = await this.props.convo.getPublicSendData();
// }
// this.setState({ firstLoading: false });
// }
// public async addAsModerator() {
// // if we don't have valid data entered by the user
// const pubkey = PubKey.from(this.state.inputBoxValue);
// if (!pubkey) {
// window.log.info('invalid pubkey for adding as moderator:', this.state.inputBoxValue);
// ToastUtils.pushInvalidPubKey();
// return;
// }
// window.log.info(`asked to add moderator: ${pubkey.key}`);
// try {
// this.setState({
// addingInProgress: true,
// });
// let isAdded: any;
// if (this.props.convo.isOpenGroupV1()) {
// isAdded = await this.channelAPI.serverAPI.addModerator([pubkey.key]);
// } else {
// // this is a v2 opengroup
// const roomInfos = this.props.convo.toOpenGroupV2();
// isAdded = await ApiV2.addModerator(pubkey, roomInfos);
// }
// if (!isAdded) {
// window.log.warn('failed to add moderators:', isAdded);
// ToastUtils.pushUserNeedsToHaveJoined();
// } else {
// window.log.info(`${pubkey.key} added as moderator...`);
// ToastUtils.pushUserAddedToModerators();
// // clear input box
// this.setState({
// inputBoxValue: '',
// });
// }
// } catch (e) {
// window.log.error('Got error while adding moderator:', e);
// } finally {
// this.setState({
// addingInProgress: false,
// });
// }
// }
// public render() {
// const { i18n } = window;
// const { addingInProgress, inputBoxValue, firstLoading } = this.state;
// const chatName = this.props.convo.get('name');
// const title = `${i18n('addModerators')}: ${chatName}`;
// const renderContent = !firstLoading;
// return (
// <SessionModal title={title} onClose={() => this.props.onClose()} theme={this.props.theme}>
// <Flex container={true} flexDirection="column" alignItems="center">
// {renderContent && (
// <>
// <p>Add Moderator:</p>
// <input
// type="text"
// className="module-main-header__search__input"
// placeholder={i18n('enterSessionID')}
// dir="auto"
// onChange={this.onPubkeyBoxChanges}
// disabled={addingInProgress}
// value={inputBoxValue}
// />
// <SessionButton
// buttonType={SessionButtonType.Brand}
// buttonColor={SessionButtonColor.Primary}
// onClick={this.addAsModerator}
// text={i18n('add')}
// disabled={addingInProgress}
// />
// </>
// )}
// <SessionSpinner loading={addingInProgress || firstLoading} />
// </Flex>
// </SessionModal>
// );
// }
// private onPubkeyBoxChanges(e: any) {
// const val = e.target.value;
// this.setState({ inputBoxValue: val });
// }
// }
export const AddModeratorsDialog = (props: any) => {
const { convo, onClose, theme } = props;
const [inputBoxValue, setInputBoxValue] = useState('');
const [addingInProgress, setAddingInProgress] = useState(false);
const [firstLoading, setFirstLoading] = useState(true);
let channelAPI: any;
useEffect(() => {
async function getPublicSendData {
if (props.convo.isOpenGroupV1()) {
channelAPI = await convo.getPublicSendData();
}
setFirstLoading(false);
}
}, [])
this.setState({ firstLoading: false });
}
public async addAsModerator() {
const addAsModerator = async () => {
// if we don't have valid data entered by the user
const pubkey = PubKey.from(this.state.inputBoxValue);
const pubkey = PubKey.from(inputBoxValue);
if (!pubkey) {
window.log.info('invalid pubkey for adding as moderator:', this.state.inputBoxValue);
ToastUtils.pushInvalidPubKey();
@ -56,15 +168,13 @@ export class AddModeratorsDialog extends React.Component<Props, State> {
window.log.info(`asked to add moderator: ${pubkey.key}`);
try {
this.setState({
addingInProgress: true,
});
setAddingInProgress(true);
let isAdded: any;
if (this.props.convo.isOpenGroupV1()) {
isAdded = await this.channelAPI.serverAPI.addModerator([pubkey.key]);
if (convo.isOpenGroupV1()) {
isAdded = await channelAPI.serverAPI.addModerator([pubkey.key]);
} else {
// this is a v2 opengroup
const roomInfos = this.props.convo.toOpenGroupV2();
const roomInfos = props.convo.toOpenGroupV2();
isAdded = await ApiV2.addModerator(pubkey, roomInfos);
}
if (!isAdded) {
@ -76,60 +186,57 @@ export class AddModeratorsDialog extends React.Component<Props, State> {
ToastUtils.pushUserAddedToModerators();
// clear input box
this.setState({
inputBoxValue: '',
});
setInputBoxValue('');
}
} catch (e) {
window.log.error('Got error while adding moderator:', e);
} finally {
this.setState({
addingInProgress: false,
});
setAddingInProgress(false);
}
}
public render() {
const { i18n } = window;
const { addingInProgress, inputBoxValue, firstLoading } = this.state;
const chatName = this.props.convo.get('name');
const { i18n } = window;
// const { addingInProgress, inputBoxValue, firstLoading } = this.state;
const chatName = props.convo.get('name');
const title = `${i18n('addModerators')}: ${chatName}`;
const title = `${i18n('addModerators')}: ${chatName}`;
const renderContent = !firstLoading;
const renderContent = !firstLoading;
return (
<SessionModal title={title} onClose={() => this.props.onClose()} theme={this.props.theme}>
<Flex container={true} flexDirection="column" alignItems="center">
{renderContent && (
<>
<p>Add Moderator:</p>
<input
type="text"
className="module-main-header__search__input"
placeholder={i18n('enterSessionID')}
dir="auto"
onChange={this.onPubkeyBoxChanges}
disabled={addingInProgress}
value={inputBoxValue}
/>
<SessionButton
buttonType={SessionButtonType.Brand}
buttonColor={SessionButtonColor.Primary}
onClick={this.addAsModerator}
text={i18n('add')}
disabled={addingInProgress}
/>
</>
)}
<SessionSpinner loading={addingInProgress || firstLoading} />
</Flex>
</SessionModal>
);
}
private onPubkeyBoxChanges(e: any) {
const onPubkeyBoxChanges = (e: any) => {
const val = e.target.value;
this.setState({ inputBoxValue: val });
setInputBoxValue(val);
}
return (
<SessionModal title={title} onClose={() => onClose()} theme={theme}>
<Flex container={true} flexDirection="column" alignItems="center">
{renderContent && (
<>
<p>Add Moderator:</p>
<input
type="text"
className="module-main-header__search__input"
placeholder={i18n('enterSessionID')}
dir="auto"
onChange={onPubkeyBoxChanges}
disabled={addingInProgress}
value={inputBoxValue}
/>
<SessionButton
buttonType={SessionButtonType.Brand}
buttonColor={SessionButtonColor.Primary}
onClick={addAsModerator}
text={i18n('add')}
disabled={addingInProgress}
/>
</>
)}
<SessionSpinner loading={addingInProgress || firstLoading} />
</Flex>
</SessionModal>
);
}

View file

@ -33,9 +33,13 @@ import { OpenGroupManagerV2 } from '../../opengroup/opengroupV2/OpenGroupManager
import { loadDefaultRooms } from '../../opengroup/opengroupV2/ApiUtil';
import { forceRefreshRandomSnodePool } from '../../session/snode_api/snodePool';
import { SwarmPolling } from '../../session/snode_api/swarmPolling';
import _ from 'lodash';
import _, { divide } from 'lodash';
import { ActionPanelOnionStatusLight, OnionPathModal } from '../OnionStatusDialog';
import { EditProfileDialog } from '../EditProfileDialog';
import { StateType } from '../../state/reducer';
import { updateConfirmModal } from "../../state/ducks/modalDialog";
import { useInView } from 'react-intersection-observer';
import { SessionConfirm } from './SessionConfirm';
// tslint:disable-next-line: no-import-side-effect no-submodule-imports
@ -72,6 +76,11 @@ const Section = (props: {
/* tslint:disable:no-void-expression */
if (type === SectionType.Profile) {
// window.showEditProfileDialog();
console.log("edit profile");
// window.inboxStore?.dispatch(updateConfirmModal({ title: "title test" }));
// dispatch(updateConfirmModal({ title: "title test" }));
// setModal(<EditProfileDialog2 onClose={() => setModal(null)}></EditProfileDialog2>);
setModal(<EditProfileDialog onClose={handleModalClose} theme={theme} ></EditProfileDialog>);
@ -134,21 +143,21 @@ const Section = (props: {
return (
<>
{type === SectionType.PathIndicator ?
<ActionPanelOnionStatusLight
handleClick={handleClick}
isSelected={isSelected}
/>
:
<SessionIconButton
iconSize={SessionIconSize.Medium}
iconType={iconType}
iconColor={iconColor}
notificationCount={unreadToShow}
onClick={handleClick}
isSelected={isSelected}
theme={theme}
/>
}
<ActionPanelOnionStatusLight
handleClick={handleClick}
isSelected={isSelected}
/>
:
<SessionIconButton
iconSize={SessionIconSize.Medium}
iconType={iconType}
iconColor={iconColor}
notificationCount={unreadToShow}
onClick={handleClick}
isSelected={isSelected}
theme={theme}
/>
}
</>
);
};
@ -260,24 +269,45 @@ export const ActionsPanel = () => {
void forceRefreshRandomSnodePool();
}, DAYS * 1);
const formatLog = (s: any ) => {
console.log("@@@@:: ", s);
}
// const confirmModalState = useSelector((state: StateType) => state);
const confirmModalState = useSelector((state: StateType) => state.confirmModal);
console.log('@@@ confirm modal state', confirmModalState);
// formatLog(confirmModalState.modalState.title);
formatLog(confirmModalState);
// formatLog(confirmModalState2);
return (
<>
{modal ? modal : null}
<div className="module-left-pane__sections-container">
<Section
setModal={setModal}
type={SectionType.Profile}
avatarPath={ourPrimaryConversation.avatarPath}
/>
<Section type={SectionType.Message} />
<Section type={SectionType.Contact} />
<Section type={SectionType.Settings} />
{/* { confirmModalState && confirmModalState.title ? <div>{confirmModalState.title}</div> : null} */}
{ confirmModalState ? <SessionConfirm {...confirmModalState} />: null}
<div className="module-left-pane__sections-container">
<Section
setModal={setModal}
type={SectionType.Profile}
avatarPath={ourPrimaryConversation.avatarPath}
/>
<Section type={SectionType.Message} />
<Section type={SectionType.Contact} />
<Section type={SectionType.Settings} />
<SessionToastContainer />
<SessionToastContainer />
<Section setModal={setModal} type={SectionType.PathIndicator} />
<Section type={SectionType.Moon} />
</div>
<Section
setModal={setModal}
type={SectionType.PathIndicator} />
<Section type={SectionType.Moon} />
</div>
</>
);
};

View file

@ -447,7 +447,7 @@ export class LeftPaneMessageSection extends React.Component<Props, State> {
return;
}
this.setState({ loading: true }, async () => {
const groupCreated = await MainViewController.createClosedGroup(groupName, groupMembers, setModal);
const groupCreated = await MainViewController.createClosedGroup(groupName, groupMembers);
if (groupCreated) {
this.handleToggleOverlay(undefined);

View file

@ -1,16 +1,13 @@
import React from 'react';
import { SessionIconButton, SessionIconSize, SessionIconType } from './icon';
import { SessionToggle } from './SessionToggle';
import { SessionIdEditable } from './SessionIdEditable';
import { UserSearchDropdown } from './UserSearchDropdown';
import { ContactType, SessionMemberListItem } from './SessionMemberListItem';
import { ConversationType } from '../../state/ducks/conversations';
import { SessionButton, SessionButtonColor, SessionButtonType } from './SessionButton';
import { SessionSpinner } from './SessionSpinner';
import { PillDivider } from './PillDivider';
import { DefaultTheme } from 'styled-components';
import { UserUtils } from '../../session/utils';
import { ConversationTypeEnum } from '../../models/conversation';
import { SessionJoinableRooms } from './SessionJoinableDefaultRooms';

View file

@ -5,15 +5,18 @@ import { SessionHtmlRenderer } from './SessionHTMLRenderer';
import { SessionIcon, SessionIconSize, SessionIconType } from './icon';
import { DefaultTheme, useTheme, withTheme } from 'styled-components';
import { SessionWrapperModal } from './SessionWrapperModal';
import { useDispatch } from 'react-redux';
import { updateConfirmModal } from '../../state/ducks/modalDialog';
import { update } from 'lodash';
type Props = {
message: string;
export interface SessionConfirmDialogProps {
message?: string;
messageSub?: string;
title: string;
title?: string;
onOk?: any;
onClose?: any;
onClickOk?: any;
onClickClose?: any;
onClickOk?: () => any;
onClickClose?: () => any;
okText?: string;
cancelText?: string;
hideCancel?: boolean;
@ -22,20 +25,25 @@ type Props = {
sessionIcon?: SessionIconType;
iconSize?: SessionIconSize;
theme?: DefaultTheme;
closeAfterClickOk?: boolean;
shouldShowConfirm?: () => boolean | undefined;
};
const SessionConfirmInner = (props: Props) => {
const SessionConfirmInner = (props: SessionConfirmDialogProps) => {
const {
title = '',
message,
message = '',
messageSub = '',
okTheme = SessionButtonColor.Primary,
closeTheme = SessionButtonColor.Primary,
onClickOk,
onClickClose,
closeAfterClickOk = true,
hideCancel = false,
sessionIcon,
iconSize,
shouldShowConfirm,
// updateConfirmModal
} = props;
const okText = props.okText || window.i18n('ok');
@ -46,8 +54,43 @@ const SessionConfirmInner = (props: Props) => {
const messageSubText = messageSub ? 'session-confirm-main-message' : 'subtle';
return (
/**
* Calls close function after the ok button is clicked. If no close method specified, closes the modal
*/
const onClickOkWithClose = () => {
if (onClickOk) {
onClickOk();
}
if (onClickClose) {
onClickClose();
}
}
const onClickOkHandler = () => {
if (onClickOk) {
onClickOk();
}
window.inboxStore?.dispatch(updateConfirmModal(null));
}
if (shouldShowConfirm && !shouldShowConfirm()) {
return null;
}
const onClickCancelHandler = () => {
if (onClickClose) {
onClickClose();
}
window.inboxStore?.dispatch(updateConfirmModal(null));
}
return (
<SessionWrapperModal
title={title}
onClose={onClickClose}
@ -75,10 +118,12 @@ const SessionConfirmInner = (props: Props) => {
</div>
<div className="session-modal__button-group">
<SessionButton text={okText} buttonColor={okTheme} onClick={onClickOk} />
{/* <SessionButton text={okText} buttonColor={okTheme} onClick={closeAfterClickOk ? onClickOk : onClickOkWithClose} /> */}
<SessionButton text={okText} buttonColor={okTheme} onClick={onClickOkHandler} />
{!hideCancel && (
<SessionButton text={cancelText} buttonColor={closeTheme} onClick={onClickClose} />
// <SessionButton text={cancelText} buttonColor={closeTheme} onClick={onClickClose} />
<SessionButton text={cancelText} buttonColor={closeTheme} onClick={onClickCancelHandler} />
)}
</div>

View file

@ -1,5 +1,6 @@
import React from 'react';
import classNames from 'classnames';
import { updateConfirmModal } from '../../state/ducks/modalDialog';
interface Props {
active: boolean;
@ -14,6 +15,8 @@ interface Props {
// okTheme: 'danger',
// }
confirmationDialogParams?: any | undefined;
updateConfirmModal?: any;
}
interface State {
@ -62,15 +65,25 @@ export class SessionToggle extends React.PureComponent<Props, State> {
if (
this.props.confirmationDialogParams &&
this.props.updateConfirmModal &&
this.props.confirmationDialogParams.shouldShowConfirm()
) {
// If item needs a confirmation dialog to turn ON, render it
window.confirmationDialog({
resolve: () => {
const closeConfirmModal = () => {
this.props.updateConfirmModal(null);
}
this.props.updateConfirmModal({
onClickOk: () => {
stateManager(event);
closeConfirmModal();
},
onClickClose: () => {
this.props.updateConfirmModal(null);
},
...this.props.confirmationDialogParams,
});
updateConfirmModal,
})
return;
}

View file

@ -1,6 +1,8 @@
// tslint:disable: no-backbone-get-set-outside-model
import React from 'react';
import { useDispatch } from "react-redux";
import { updateConfirmModal } from '../../../state/ducks/modalDialog';
import classNames from 'classnames';
@ -12,7 +14,7 @@ import { AttachmentUtil, GoogleChrome } from '../../../util';
import { ConversationHeaderWithDetails } from '../../conversation/ConversationHeader';
import { SessionRightPanelWithDetails } from './SessionRightPanel';
import { SessionTheme } from '../../../state/ducks/SessionTheme';
import { DefaultTheme } from 'styled-components';
import { DefaultTheme, useTheme } from 'styled-components';
import { SessionMessagesList } from './SessionMessagesList';
import { LightboxGallery, MediaItemType } from '../../LightboxGallery';
import { Message } from '../../conversation/media-gallery/types/Message';
@ -31,6 +33,9 @@ import autoBind from 'auto-bind';
import { getDecryptedMediaUrl } from '../../../session/crypto/DecryptedAttachmentsManager';
import { deleteOpenGroupMessages } from '../../../interactions/conversation';
import { ConversationTypeEnum } from '../../../models/conversation';
import { SessionButtonColor } from '../SessionButton';
interface State {
// Message sending progress
@ -359,12 +364,10 @@ export class SessionConversation extends React.Component<Props, State> {
onSetDisappearingMessages: conversation.updateExpirationTimer,
onDeleteMessages: conversation.deleteMessages,
onDeleteSelectedMessages: this.deleteSelectedMessages,
onChangeNickname: conversation.changeNickname,
onClearNickname: conversation.clearNickname,
onCloseOverlay: () => {
this.setState({ selectedMessages: [] });
},
onDeleteContact: conversation.deleteContact,
onGoBack: () => {
this.setState({
@ -451,8 +454,8 @@ export class SessionConversation extends React.Component<Props, State> {
const isAdmin = conversation.isMediumGroup()
? true
: conversation.isPublic()
? conversation.isAdmin(ourPrimary)
: false;
? conversation.isAdmin(ourPrimary)
: false;
return {
id: conversation.id,
@ -507,7 +510,6 @@ export class SessionConversation extends React.Component<Props, State> {
onInviteContacts: () => {
window.Whisper.events.trigger('inviteContacts', conversation);
},
onDeleteContact: conversation.deleteContact,
onLeaveGroup: () => {
window.Whisper.events.trigger('leaveClosedGroup', conversation);
},
@ -661,14 +663,22 @@ export class SessionConversation extends React.Component<Props, State> {
}
const okText = window.i18n(isServerDeletable ? 'deleteForEveryone' : 'delete');
if (askUserForConfirmation) {
window.confirmationDialog({
const onClickClose = () => {
this.props.actions.updateConfirmModal(null);
}
this.props.actions.updateConfirmModal({
title,
message: warningMessage,
okText,
okTheme: 'danger',
resolve: doDelete,
});
okTheme: SessionButtonColor.Danger,
onClickOk: doDelete,
onClickClose,
closeAfterClick: true
})
} else {
void doDelete();
}
@ -684,7 +694,7 @@ export class SessionConversation extends React.Component<Props, State> {
public selectMessage(messageId: string) {
const selectedMessages = this.state.selectedMessages.includes(messageId)
? // Add to array if not selected. Else remove.
this.state.selectedMessages.filter(id => id !== messageId)
this.state.selectedMessages.filter(id => id !== messageId)
: [...this.state.selectedMessages, messageId];
this.setState({ selectedMessages });

View file

@ -29,6 +29,7 @@ export type PropsConversationHeaderMenu = {
timerOptions: Array<TimerOption>;
isPrivate: boolean;
isBlocked: boolean;
theme: any;
hasNickname?: boolean;
onDeleteMessages?: () => void;
@ -62,6 +63,7 @@ export const ConversationHeaderMenu = (props: PropsConversationHeaderMenu) => {
isPrivate,
left,
hasNickname,
theme,
onClearNickname,
onChangeNickname,
@ -104,11 +106,11 @@ export const ConversationHeaderMenu = (props: PropsConversationHeaderMenu) => {
{getMarkAllReadMenuItem(onMarkAllRead, window.i18n)}
{getChangeNicknameMenuItem(isMe, onChangeNickname, isGroup, window.i18n, id, setModal)}
{getClearNicknameMenuItem(isMe, hasNickname, onClearNickname, isGroup, window.i18n)}
{getDeleteMessagesMenuItem(isPublic, onDeleteMessages, window.i18n)}
{getDeleteMessagesMenuItem(isPublic, onDeleteMessages, window.i18n, id)}
{getAddModeratorsMenuItem(isAdmin, isKickedFromGroup, onAddModerators, window.i18n)}
{getRemoveModeratorsMenuItem(isAdmin, isKickedFromGroup, onRemoveModerators, window.i18n)}
{getUpdateGroupNameMenuItem(isAdmin, isKickedFromGroup, left, onUpdateGroupName, window.i18n)}
{getLeaveGroupMenuItem(isKickedFromGroup, left, isGroup, isPublic, onLeaveGroup, window.i18n)}
{getLeaveGroupMenuItem(isKickedFromGroup, left, isGroup, isPublic, onLeaveGroup, window.i18n, id, setModal, theme)}
{/* TODO: add delete group */}
{getInviteContactMenuItem(isGroup, isPublic, onInviteContacts, window.i18n)}
{getDeleteContactMenuItem(
@ -118,7 +120,8 @@ export const ConversationHeaderMenu = (props: PropsConversationHeaderMenu) => {
left,
isKickedFromGroup,
onDeleteContact,
window.i18n
window.i18n,
id
)}
</Menu>
</>

View file

@ -24,6 +24,7 @@ export type PropsContextConversationItem = {
hasNickname?: boolean;
isKickedFromGroup?: boolean;
left?: boolean;
theme?: any
onDeleteMessages?: () => void;
onDeleteContact?: () => void;
@ -58,6 +59,7 @@ export const ConversationListItemContextMenu = (props: PropsContextConversationI
onInviteContacts,
onLeaveGroup,
onChangeNickname,
theme
} = props;
const isGroup = type === 'group';
@ -82,7 +84,7 @@ export const ConversationListItemContextMenu = (props: PropsContextConversationI
{getChangeNicknameMenuItem(isMe, onChangeNickname, isGroup, window.i18n, id, setModal)}
{getClearNicknameMenuItem(isMe, hasNickname, onClearNickname, isGroup, window.i18n)}
{getDeleteMessagesMenuItem(isPublic, onDeleteMessages, window.i18n)}
{getDeleteMessagesMenuItem(isPublic, onDeleteMessages, window.i18n, id)}
{getInviteContactMenuItem(isGroup, isPublic, onInviteContacts, window.i18n)}
{getDeleteContactMenuItem(
isMe,
@ -91,9 +93,10 @@ export const ConversationListItemContextMenu = (props: PropsContextConversationI
left,
isKickedFromGroup,
onDeleteContact,
window.i18n
window.i18n,
id
)}
{getLeaveGroupMenuItem(isKickedFromGroup, left, isGroup, isPublic, onLeaveGroup, window.i18n)}
{getLeaveGroupMenuItem(isKickedFromGroup, left, isGroup, isPublic, onLeaveGroup, window.i18n, id, setModal, theme)}
</Menu>
</>
);

View file

@ -3,6 +3,13 @@ import { LocalizerType } from '../../../types/Util';
import { TimerOption } from '../../conversation/ConversationHeader';
import { Item, Submenu } from 'react-contexify';
import { SessionNicknameDialog } from '../SessionNicknameDialog';
import { useDispatch, useSelector } from 'react-redux';
import { updateConfirmModal } from '../../../state/ducks/modalDialog';
import { ConversationController } from '../../../session/conversations';
import { useTheme } from 'styled-components';
import { UserUtils } from '../../../session/utils';
import { AdminLeaveClosedGroupDialog } from '../../conversation/AdminLeaveClosedGroupDialog';
import { getTheme } from '../../../state/selectors/theme';
function showTimerOptions(
isPublic: boolean,
@ -95,7 +102,8 @@ export function getDeleteContactMenuItem(
isLeft: boolean | undefined,
isKickedFromGroup: boolean | undefined,
action: any,
i18n: LocalizerType
i18n: LocalizerType,
id: string
): JSX.Element | null {
if (
showDeleteContact(
@ -106,10 +114,31 @@ export function getDeleteContactMenuItem(
Boolean(isKickedFromGroup)
)
) {
let menuItemText: string;
if (isPublic) {
return <Item onClick={action}>{i18n('leaveGroup')}</Item>;
menuItemText = i18n('leaveGroup');
} else {
menuItemText = i18n('delete');
}
return <Item onClick={action}>{i18n('delete')}</Item>;
const dispatch = useDispatch();
const onClickClose = () => {
dispatch(updateConfirmModal(null));
}
const showConfirmationModal = () => {
dispatch(updateConfirmModal({
title: menuItemText,
message: isGroup ? i18n('leaveGroupConfirmation'): i18n('deleteContactConfirmation'),
onClickClose,
onClickOk: () => {
void ConversationController.getInstance().deleteContact(id);
onClickClose();
}
}))
}
return <Item onClick={showConfirmationModal}>{menuItemText}</Item>;
}
return null;
}
@ -120,12 +149,57 @@ export function getLeaveGroupMenuItem(
isGroup: boolean | undefined,
isPublic: boolean | undefined,
action: any,
i18n: LocalizerType
i18n: LocalizerType,
id: string,
setModal: any,
theme: any
): JSX.Element | null {
if (
showLeaveGroup(Boolean(isKickedFromGroup), Boolean(left), Boolean(isGroup), Boolean(isPublic))
) {
return <Item onClick={action}>{i18n('leaveGroup')}</Item>;
const dispatch = useDispatch();
const conversation = ConversationController.getInstance().get(id);
const onClickClose = () => {
dispatch(updateConfirmModal(null));
}
const openConfirmationModal = () => {
if (!conversation.isGroup()) {
throw new Error('showLeaveGroupDialog() called with a non group convo.');
}
const title = window.i18n('leaveGroup');
const message = window.i18n('leaveGroupConfirmation');
const ourPK = UserUtils.getOurPubKeyStrFromCache();
const isAdmin = (conversation.get('groupAdmins') || []).includes(ourPK);
const isClosedGroup = conversation.get('is_medium_group') || false;
// if this is not a closed group, or we are not admin, we can just show a confirmation dialog
if (!isClosedGroup || (isClosedGroup && !isAdmin)) {
dispatch(updateConfirmModal({
title,
message,
onClickOk: () => {
conversation.leaveClosedGroup();
onClickClose();
},
onClickClose
}));
} else {
setModal(
<AdminLeaveClosedGroupDialog
groupName={conversation.getName()}
onSubmit={conversation.leaveClosedGroup}
onClose={() => {setModal(null)}}
theme={theme}
></AdminLeaveClosedGroupDialog>
)
}
}
return <Item onClick={openConfirmationModal}>{i18n('leaveGroup')}</Item>;
}
return null;
}
@ -283,19 +357,13 @@ export function getChangeNicknameMenuItem(
setModal(null);
}
// const onClickOk = () => {
// console.log("@@ onclickok clicked");
// }
const onClickCustom = () => {
setModal(<SessionNicknameDialog onClickClose={clearModal} conversationId={conversationId}></SessionNicknameDialog>);
// setModal(null);
}
return (
<>
<Item onClick={onClickCustom}>{i18n('changeNickname')}</Item>
{/* <Item onClick={action}>{i18n('changeNickname')}</Item> */}
</>
);
}
@ -305,10 +373,33 @@ export function getChangeNicknameMenuItem(
export function getDeleteMessagesMenuItem(
isPublic: boolean | undefined,
action: any,
i18n: LocalizerType
i18n: LocalizerType,
id: string
): JSX.Element | null {
if (showDeleteMessages(Boolean(isPublic))) {
return <Item onClick={action}>{i18n('deleteMessages')}</Item>;
const dispatch = useDispatch();
const conversation = ConversationController.getInstance().get(id);
const onClickClose = () => {
dispatch(updateConfirmModal(null));
}
const onClickOk = () => {
conversation.destroyMessages();
onClickClose();
}
const openConfirmationModal = () => {
dispatch(updateConfirmModal({
title: window.i18n('deleteMessages'),
message: window.i18n('deleteConversationConfirmation'),
onClickOk,
onClickClose,
}))
}
return <Item onClick={openConfirmationModal}>{i18n('deleteMessages')}</Item>;
}
return null;
}

View file

@ -7,6 +7,7 @@ import { SessionToggle } from '../SessionToggle';
import { SessionButton } from '../SessionButton';
import { SessionSettingType } from './SessionSettings';
import { SessionRadioGroup } from '../SessionRadioGroup';
import { SessionConfirmDialogProps } from '../SessionConfirm';
interface Props {
title?: string;
@ -17,7 +18,10 @@ interface Props {
onClick?: any;
onSliderChange?: any;
content: any;
confirmationDialogParams?: any;
confirmationDialogParams?: SessionConfirmDialogProps;
// for updating modal in redux
updateConfirmModal?: any
}
interface State {
@ -61,6 +65,7 @@ export class SessionSettingListItem extends React.Component<Props, State> {
active={Boolean(value)}
onClick={this.handleClick}
confirmationDialogParams={this.props.confirmationDialogParams}
updateConfirmModal={this.props.updateConfirmModal}
/>
</div>
)}

View file

@ -12,6 +12,8 @@ import { getConversationLookup, getConversations } from '../../../state/selector
import { connect } from 'react-redux';
import { getPasswordHash } from '../../../../ts/data/data';
import { PasswordAction, SessionPasswordModal } from '../SessionPasswordModal';
import { SessionConfirmDialogProps } from '../SessionConfirm';
import { mapDispatchToProps } from '../../../state/actions';
export enum SessionSettingCategory {
Appearance = 'appearance',
@ -34,6 +36,7 @@ export interface SettingsViewProps {
// pass the conversation as props, so our render is called everytime they change.
// we have to do this to make the list refresh on unblock()
conversations?: ConversationLookupType;
updateConfirmModal?: any;
}
interface State {
@ -44,6 +47,10 @@ interface State {
modal: JSX.Element | null;
}
interface ConfirmationDialogParams extends SessionConfirmDialogProps {
shouldShowConfirm: () => boolean | undefined;
}
interface LocalSettingType {
category: SessionSettingCategory;
description: string | undefined;
@ -56,7 +63,7 @@ interface LocalSettingType {
type: SessionSettingType | undefined;
setFn: any;
onClick: any;
confirmationDialogParams: any | undefined;
confirmationDialogParams: ConfirmationDialogParams | undefined;
}
class SettingsViewInner extends React.Component<SettingsViewProps, State> {
@ -147,6 +154,7 @@ class SettingsViewInner extends React.Component<SettingsViewProps, State> {
onSliderChange={sliderFn}
content={content}
confirmationDialogParams={setting.confirmationDialogParams}
updateConfirmModal={this.props.updateConfirmModal}
/>
)}
</div>
@ -345,7 +353,7 @@ class SettingsViewInner extends React.Component<SettingsViewProps, State> {
shouldShowConfirm: () => !window.getSettingValue('link-preview-setting'),
title: window.i18n('linkPreviewsTitle'),
message: window.i18n('linkPreviewsConfirmMessage'),
okTheme: 'danger',
okTheme: SessionButtonColor.Danger,
},
},
{
@ -614,11 +622,13 @@ class SettingsViewInner extends React.Component<SettingsViewProps, State> {
}
}
const mapStateToProps = (state: StateType) => {
return {
conversations: getConversationLookup(state),
};
};
const smart = connect(mapStateToProps);
const smart = connect(mapStateToProps, mapDispatchToProps);
export const SmartSettingsView = smart(SettingsViewInner);

View file

@ -10,6 +10,9 @@ import { PubKey } from '../session/types';
import { ToastUtils } from '../session/utils';
import { openConversationExternal } from '../state/ducks/conversations';
import { useDispatch } from 'react-redux';
import { updateConfirmModal } from '../state/ducks/modalDialog';
export function banUser(userToBan: string, conversation?: ConversationModel) {
let pubKeyToBan: PubKey;
try {
@ -19,37 +22,46 @@ export function banUser(userToBan: string, conversation?: ConversationModel) {
ToastUtils.pushUserBanFailure();
return;
}
window.confirmationDialog({
title: window.i18n('banUser'),
message: window.i18n('banUserConfirm'),
resolve: async () => {
if (!conversation) {
window.log.info('cannot ban user, the corresponding conversation was not found.');
return;
}
let success = false;
if (isOpenGroupV2(conversation.id)) {
const roomInfos = await getV2OpenGroupRoom(conversation.id);
if (!roomInfos) {
window.log.warn('banUser room not found');
} else {
success = await ApiV2.banUser(pubKeyToBan, _.pick(roomInfos, 'serverUrl', 'roomId'));
}
} else {
const channelAPI = await conversation.getPublicSendData();
if (!channelAPI) {
window.log.info('cannot ban user, the corresponding channelAPI was not found.');
return;
}
success = await channelAPI.banUser(userToBan);
}
if (success) {
ToastUtils.pushUserBanSuccess();
} else {
ToastUtils.pushUserBanFailure();
}
},
});
const dispatch = useDispatch();
const onClickClose = () => {
dispatch(updateConfirmModal(null))
};
// const confirmationModalProps = {
// title: window.i18n('banUser'),
// message: window.i18n('banUserConfirm'),
// onClickClose,
// // onClickOk: async () => {
// // if (!conversation) {
// // window.log.info('cannot ban user, the corresponding conversation was not found.');
// // return;
// // }
// // let success = false;
// // if (isOpenGroupV2(conversation.id)) {
// // const roomInfos = await getV2OpenGroupRoom(conversation.id);
// // if (!roomInfos) {
// // window.log.warn('banUser room not found');
// // } else {
// // success = await ApiV2.banUser(pubKeyToBan, _.pick(roomInfos, 'serverUrl', 'roomId'));
// // }
// // } else {
// // const channelAPI = await conversation.getPublicSendData();
// // if (!channelAPI) {
// // window.log.info('cannot ban user, the corresponding channelAPI was not found.');
// // return;
// // }
// // success = await channelAPI.banUser(userToBan);
// // }
// // if (success) {
// // ToastUtils.pushUserBanSuccess();
// // } else {
// // ToastUtils.pushUserBanFailure();
// // }
// // },
// }
// dispatch(updateConfirmModal(confirmationModalProps));
}
/**
@ -70,31 +82,65 @@ export function unbanUser(userToUnBan: string, conversation?: ConversationModel)
ToastUtils.pushUserBanFailure();
return;
}
window.confirmationDialog({
const dispatch = useDispatch();
const onClickClose = () => dispatch(updateConfirmModal(null));
const onClickOk = async () => {
if (!conversation) {
// double check here. the convo might have been removed since the dialog was opened
window.log.info('cannot unban user, the corresponding conversation was not found.');
return;
}
let success = false;
if (isOpenGroupV2(conversation.id)) {
const roomInfos = await getV2OpenGroupRoom(conversation.id);
if (!roomInfos) {
window.log.warn('unbanUser room not found');
} else {
success = await ApiV2.unbanUser(pubKeyToUnban, _.pick(roomInfos, 'serverUrl', 'roomId'));
}
}
if (success) {
ToastUtils.pushUserUnbanSuccess();
} else {
ToastUtils.pushUserUnbanFailure();
}
}
dispatch(updateConfirmModal({
title: window.i18n('unbanUser'),
message: window.i18n('unbanUserConfirm'),
resolve: async () => {
if (!conversation) {
// double check here. the convo might have been removed since the dialog was opened
window.log.info('cannot unban user, the corresponding conversation was not found.');
return;
}
let success = false;
if (isOpenGroupV2(conversation.id)) {
const roomInfos = await getV2OpenGroupRoom(conversation.id);
if (!roomInfos) {
window.log.warn('unbanUser room not found');
} else {
success = await ApiV2.unbanUser(pubKeyToUnban, _.pick(roomInfos, 'serverUrl', 'roomId'));
}
}
if (success) {
ToastUtils.pushUserUnbanSuccess();
} else {
ToastUtils.pushUserUnbanFailure();
}
},
});
onClickOk,
onClickClose,
}));
// window.confirmationDialog({
// title: window.i18n('unbanUser'),
// message: window.i18n('unbanUserConfirm'),
// resolve: async () => {
// if (!conversation) {
// // double check here. the convo might have been removed since the dialog was opened
// window.log.info('cannot unban user, the corresponding conversation was not found.');
// return;
// }
// let success = false;
// if (isOpenGroupV2(conversation.id)) {
// const roomInfos = await getV2OpenGroupRoom(conversation.id);
// if (!roomInfos) {
// window.log.warn('unbanUser room not found');
// } else {
// success = await ApiV2.unbanUser(pubKeyToUnban, _.pick(roomInfos, 'serverUrl', 'roomId'));
// }
// }
// if (success) {
// ToastUtils.pushUserUnbanSuccess();
// } else {
// ToastUtils.pushUserUnbanFailure();
// }
// },
// });
}
export function copyBodyToClipboard(body?: string) {
@ -242,11 +288,27 @@ async function acceptOpenGroupInvitationV1(serverAddress: string) {
}
const acceptOpenGroupInvitationV2 = (completeUrl: string, roomName?: string) => {
window.confirmationDialog({
const dispatch = useDispatch();
const onClickClose = () => {
dispatch(updateConfirmModal(null))
};
dispatch(updateConfirmModal({
title: window.i18n('joinOpenGroupAfterInvitationConfirmationTitle', roomName),
message: window.i18n('joinOpenGroupAfterInvitationConfirmationDesc', roomName),
resolve: () => joinOpenGroupV2WithUIEvents(completeUrl, true),
});
onClickOk: () => joinOpenGroupV2WithUIEvents(completeUrl, true),
onClickClose
}))
// window.confirmationDialog({
// title: window.i18n('joinOpenGroupAfterInvitationConfirmationTitle', roomName),
// message: window.i18n('joinOpenGroupAfterInvitationConfirmationDesc', roomName),
// resolve: () => joinOpenGroupV2WithUIEvents(completeUrl, true),
// });
// this function does not throw, and will showToasts if anything happens
};

View file

@ -42,6 +42,8 @@ import { ConversationInteraction } from '../interactions';
import { OpenGroupVisibleMessage } from '../session/messages/outgoing/visibleMessage/OpenGroupVisibleMessage';
import { OpenGroupRequestCommonType } from '../opengroup/opengroupV2/ApiUtil';
import { getOpenGroupV2FromConversationId } from '../opengroup/utils/OpenGroupUtils';
import { useDispatch } from 'react-redux';
import { updateConfirmModal } from '../state/ducks/modalDialog';
export enum ConversationTypeEnum {
GROUP = 'group',
@ -421,7 +423,6 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
onBlockContact: this.block,
onUnblockContact: this.unblock,
onCopyPublicKey: this.copyPublicKey,
onDeleteContact: this.deleteContact,
onClearNickname: this.clearNickname,
onDeleteMessages: this.deleteMessages,
onLeaveGroup: () => {
@ -1309,23 +1310,23 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
void this.setNickname('');
};
public deleteContact() {
let title = window.i18n('delete');
let message = window.i18n('deleteContactConfirmation');
// public deleteContact() {
// let title = window.i18n('delete');
// let message = window.i18n('deleteContactConfirmation');
if (this.isGroup()) {
title = window.i18n('leaveGroup');
message = window.i18n('leaveGroupConfirmation');
}
// if (this.isGroup()) {
// title = window.i18n('leaveGroup');
// message = window.i18n('leaveGroupConfirmation');
// }
window.confirmationDialog({
title,
message,
resolve: () => {
void ConversationController.getInstance().deleteContact(this.id);
},
});
}
// window.confirmationDialog({
// title,
// message,
// resolve: () => {
// void ConversationController.getInstance().deleteContact(this.id);
// },
// });
// }
public async removeMessage(messageId: any) {
await dataRemoveMessage(messageId);
@ -1351,7 +1352,14 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
};
}
window.confirmationDialog(params);
// window.confirmationDialog(params);
const dispatch = useDispatch()
dispatch(updateConfirmModal({
title: window.i18n('deleteMessages'),
message: window.i18n('deleteConversationConfirmation'),
onClickOk: () => this.destroyMessages(),
}))
}
public async destroyMessages() {

View file

@ -1,4 +1,3 @@
import React from 'react';
import { SignalService } from '../protobuf';
import { removeFromCache } from './cache';
import { EnvelopePlus } from './types';
@ -36,7 +35,10 @@ import { queueAllCachedFromSource } from './receiver';
import { actions as conversationActions } from '../state/ducks/conversations';
import { SwarmPolling } from '../session/snode_api/swarmPolling';
import { MessageModel } from '../models/message';
import { SessionConfirm } from '../components/session/SessionConfirm';
import { useSelector, useDispatch } from "react-redux";
import { updateConfirmModal } from "../state/ducks/modalDialog";
export const distributingClosedGroupEncryptionKeyPairs = new Map<string, ECKeyPair>();
@ -838,7 +840,7 @@ async function handleClosedGroupEncryptionKeyPairRequest(
return removeFromCache(envelope);
}
export async function createClosedGroup(groupName: string, members: Array<string>, setModal: any) {
export async function createClosedGroup(groupName: string, members: Array<string>) {
const setOfMembers = new Set(members);
const ourNumber = UserUtils.getOurPubKeyFromCache();
@ -894,7 +896,6 @@ export async function createClosedGroup(groupName: string, members: Array<string
admins,
encryptionKeyPair,
dbMessage,
setModal
);
if (allInvitesSent) {
@ -929,7 +930,6 @@ async function sendToGroupMembers(
admins: Array<string>,
encryptionKeyPair: ECKeyPair,
dbMessage: MessageModel,
setModal: any,
isRetry: boolean = false,
): Promise<any> {
const promises = createInvitePromises(
@ -945,35 +945,34 @@ async function sendToGroupMembers(
const inviteResults = await Promise.all(promises);
const allInvitesSent = _.every(inviteResults, Boolean);
// const dispatch = useDispatch();
// window.inboxStore?.dispatch(updateConfirmModal({
// title: 'hi'
// }))
console.log('@@@@', inviteResults);
if (allInvitesSent) {
// if (true) {
if (isRetry) {
const invitesTitle =
inviteResults.length > 1
? window.i18n('closedGroupInviteSuccessTitlePlural')
: window.i18n('closedGroupInviteSuccessTitle');
// setModal(<SessionConfirm message={'hi'} title={invitesTitle} />)
setModal(
<SessionConfirm
title={title}
message={message}
onClickOk={deleteAccount}
okTheme={SessionButtonColor.Danger}
onClickClose={clearModal}
/>)
)
// window.confirmationDialog({
// title: invitesTitle,
// message: window.i18n('closedGroupInviteSuccessMessage'),
// });
window.inboxStore?.dispatch(updateConfirmModal({
title: invitesTitle,
message: window.i18n('closedGroupInviteSuccessMessage'),
hideCancel: true
}));
}
return allInvitesSent;
} else {
// Confirmation dialog that recursively calls sendToGroupMembers on resolve
window.confirmationDialog({
window.inboxStore?.dispatch(updateConfirmModal({
title:
inviteResults.length > 1
? window.i18n('closedGroupInviteFailTitlePlural')
@ -983,7 +982,7 @@ async function sendToGroupMembers(
? window.i18n('closedGroupInviteFailMessagePlural')
: window.i18n('closedGroupInviteFailMessage'),
okText: window.i18n('closedGroupInviteOkText'),
resolve: async () => {
onClickOk: async () => {
const membersToResend: Array<string> = new Array<string>();
inviteResults.forEach((result, index) => {
const member = listOfMembers[index];
@ -1001,12 +1000,45 @@ async function sendToGroupMembers(
admins,
encryptionKeyPair,
dbMessage,
setModal,
isRetrySend
);
}
},
});
}));
// window.confirmationDialog({
// title:
// inviteResults.length > 1
// ? window.i18n('closedGroupInviteFailTitlePlural')
// : window.i18n('closedGroupInviteFailTitle'),
// message:
// inviteResults.length > 1
// ? window.i18n('closedGroupInviteFailMessagePlural')
// : window.i18n('closedGroupInviteFailMessage'),
// okText: window.i18n('closedGroupInviteOkText'),
// resolve: async () => {
// const membersToResend: Array<string> = new Array<string>();
// inviteResults.forEach((result, index) => {
// const member = listOfMembers[index];
// // group invite must always contain the admin member.
// if (result !== true || admins.includes(member)) {
// membersToResend.push(member);
// }
// });
// if (membersToResend.length > 0) {
// const isRetrySend = true;
// await sendToGroupMembers(
// membersToResend,
// groupPublicKey,
// groupName,
// admins,
// encryptionKeyPair,
// dbMessage,
// isRetrySend
// );
// }
// },
// });
}
return allInvitesSent;
}

View file

@ -5,6 +5,7 @@ import { actions as conversations } from './ducks/conversations';
import { actions as user } from './ducks/user';
import { actions as sections } from './ducks/section';
import { actions as theme } from './ducks/theme';
import { actions as modalDialog } from './ducks/modalDialog';
export function mapDispatchToProps(dispatch: Dispatch): Object {
return {
@ -15,6 +16,7 @@ export function mapDispatchToProps(dispatch: Dispatch): Object {
...user,
...theme,
...sections,
...modalDialog
},
dispatch
),

View file

@ -0,0 +1,21 @@
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
import { SessionConfirmDialogProps } from '../../components/session/SessionConfirm';
export type ConfirmModalState = SessionConfirmDialogProps | null;
const initialState: ConfirmModalState = null as ConfirmModalState;
const confirmModalSlice = createSlice({
name: 'confirmModal',
initialState,
reducers: {
updateConfirmModal(state, action: PayloadAction<ConfirmModalState | null>) {
state = action.payload;
return action.payload;
}
}
})
export const { actions, reducer } = confirmModalSlice;
export const { updateConfirmModal } = actions;
export const confirmModalReducer = reducer;

View file

@ -1,17 +1,10 @@
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
import _, { forEach } from 'underscore';
import { SnodePath, Snode } from '../../session/onions/index';
export type OnionState = {
// nodes: Array<OnionPathNodeType>;
// path: SnodePath;
snodePath: SnodePath;
};
// const initialState: OnionState = {
// // nodes: new Array<OnionPathNodeType>(),
// nodes: new Array<Snode>(),
// };
const initialState = {
snodePath: {
@ -32,8 +25,6 @@ const onionSlice = createSlice({
let isEqual = JSON.stringify(state, null, 2) == JSON.stringify(newPayload, null, 2);
return isEqual ? state : newPayload;
return newPayload;
},
},
});

View file

@ -6,8 +6,8 @@ import { reducer as user, UserStateType } from './ducks/user';
import { reducer as theme, ThemeStateType } from './ducks/theme';
import { reducer as section, SectionStateType } from './ducks/section';
import { defaultRoomReducer as defaultRooms, DefaultRoomsState } from './ducks/defaultRooms';
import { defaultOnionReducer as onionPaths, OnionState } from './ducks/onion';
import { confirmModalReducer as confirmModal, ConfirmModalState } from "./ducks/modalDialog";
export type StateType = {
search: SearchStateType;
@ -19,6 +19,9 @@ export type StateType = {
defaultRooms: DefaultRoomsState;
onionPaths: OnionState;
confirmModal: ConfirmModalState
// modalState: ConfirmModalState
};
export const reducers = {
@ -31,8 +34,8 @@ export const reducers = {
theme,
section,
defaultRooms,
onionPaths,
confirmModal
};
// Making this work would require that our reducer signature supported AnyAction, not

View file

@ -17,6 +17,7 @@ const mapStateToProps = (state: StateType) => {
theme: getTheme(state),
messages: getMessagesOfSelectedConversation(state),
ourNumber: getOurNumber(state),
confirmModal: (state: StateType) => {state.confirmModal}
};
};

6
ts/window.d.ts vendored
View file

@ -96,5 +96,11 @@ declare global {
darkTheme: DefaultTheme;
LokiPushNotificationServer: any;
LokiPushNotificationServerApi: any;
confirmationDialog: any;
}
// window.confirmationDialog = () => {
// console.log("confirmation dialog stub called");
// }
}