mirror of
https://github.com/lux-tel/session-desktop.git
synced 2026-10-30 20:33:24 +00:00
382 lines
13 KiB
TypeScript
382 lines
13 KiB
TypeScript
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
|
|
import { SessionDataTestId } from 'react';
|
|
import { BlockOrUnblockModalState } from '../../components/dialog/blockOrUnblock/BlockOrUnblockModalState';
|
|
import { EnterPasswordModalProps } from '../../components/dialog/EnterPasswordModal';
|
|
import { HideRecoveryPasswordDialogProps } from '../../components/dialog/HideRecoveryPasswordDialog';
|
|
import { SessionConfirmDialogProps } from '../../components/dialog/SessionConfirm';
|
|
import { MediaItemType } from '../../components/lightbox/LightboxGallery';
|
|
import { AttachmentTypeWithPath } from '../../types/Attachment';
|
|
import type {
|
|
EditProfilePictureModalProps,
|
|
PasswordAction,
|
|
ProNonOriginatingPageVariant,
|
|
} from '../../types/ReduxTypes';
|
|
import { WithConvoId } from '../../session/types/with';
|
|
import type { TrArgs } from '../../localization/localeTools';
|
|
import { SessionButtonType } from '../../components/basic/SessionButton';
|
|
import type { CTAVariant } from '../../components/dialog/cta/types';
|
|
|
|
export type BanType = 'ban' | 'unban';
|
|
|
|
export type UserSettingsPage =
|
|
| 'default'
|
|
| 'privacy'
|
|
| 'notifications'
|
|
| 'conversations'
|
|
| 'message-requests'
|
|
| 'appearance'
|
|
| 'recovery-password'
|
|
| 'help'
|
|
| 'blocked-contacts'
|
|
| 'clear-data'
|
|
| 'password'
|
|
| 'preferences'
|
|
| 'network'
|
|
| 'pro'
|
|
| 'proNonOriginating';
|
|
|
|
export type WithUserSettingsPage = {
|
|
overrideBackAction?: () => void;
|
|
afterCloseAction?: () => void;
|
|
} & (
|
|
| { userSettingsPage: Exclude<UserSettingsPage, 'password' | 'pro' | 'proNonOriginating'> }
|
|
| {
|
|
userSettingsPage: 'password';
|
|
passwordAction: PasswordAction;
|
|
}
|
|
| {
|
|
userSettingsPage: 'pro';
|
|
hideBackButton?: boolean;
|
|
fromCTA?: boolean;
|
|
centerAlign?: boolean;
|
|
}
|
|
| {
|
|
userSettingsPage: 'proNonOriginating';
|
|
nonOriginatingVariant: ProNonOriginatingPageVariant;
|
|
hideBackButton?: boolean;
|
|
centerAlign?: boolean;
|
|
}
|
|
);
|
|
|
|
export type ConfirmModalState = SessionConfirmDialogProps | null;
|
|
|
|
export type InviteContactModalState = WithConvoId | null;
|
|
export type BanOrUnbanUserModalState =
|
|
| (WithConvoId & {
|
|
banType: BanType;
|
|
pubkey?: string;
|
|
})
|
|
| null;
|
|
export type AddModeratorsModalState = InviteContactModalState;
|
|
export type RemoveModeratorsModalState = InviteContactModalState;
|
|
export type UpdateGroupMembersModalState = InviteContactModalState;
|
|
type UpdateConversationDetailsModalState = WithConvoId | null;
|
|
export type ChangeNickNameModalState = InviteContactModalState;
|
|
export type UserSettingsModalState = WithUserSettingsPage | null;
|
|
export type OnionPathModalState = object | null;
|
|
export type EnterPasswordModalState = EnterPasswordModalProps | null;
|
|
export type DeleteAccountModalState = object | null;
|
|
export type OpenUrlModalState = { urlToOpen: string } | null;
|
|
|
|
export type LocalizedPopupDialogButtonOptions = {
|
|
label: TrArgs;
|
|
buttonType?: SessionButtonType;
|
|
dataTestId: SessionDataTestId;
|
|
onClick?: () => Promise<void> | void;
|
|
closeAfterClick?: boolean;
|
|
};
|
|
export type LocalizedPopupDialogState = {
|
|
title: TrArgs;
|
|
description: TrArgs;
|
|
overrideButtons?: Array<LocalizedPopupDialogButtonOptions>;
|
|
} | null;
|
|
|
|
export type SessionCTAState = {
|
|
variant: CTAVariant;
|
|
afterActionButtonCallback?: () => void;
|
|
// If the action button opens another modal, this callback is called after that next modal is closed.
|
|
// For example: If "SessionCTA" is opened from the "EditProfilePictureModal", and "SessionCTA"'s
|
|
// action button opens the "ProSettingsModal", we want to re-open "EditProfilePictureModal"
|
|
// when "ProSettingsModal" closes.
|
|
actionButtonNextModalAfterCloseCallback?: () => void;
|
|
} | null;
|
|
|
|
export type UserProfileModalState = {
|
|
/** this can be blinded or not */
|
|
conversationId: string;
|
|
/** if conversationId is blinded, and we know the real corresponding sessionID, this is it. */
|
|
realSessionId: string | null;
|
|
} | null;
|
|
|
|
export type ReactModalsState = {
|
|
reaction: string;
|
|
messageId: string;
|
|
} | null;
|
|
|
|
export type EditProfilePictureModalState = EditProfilePictureModalProps | null;
|
|
|
|
export type HideRecoveryPasswordModalState = HideRecoveryPasswordDialogProps | null;
|
|
|
|
export type LightBoxOptions = {
|
|
media: Array<MediaItemType>;
|
|
attachment: AttachmentTypeWithPath;
|
|
selectedIndex?: number;
|
|
onClose?: () => void;
|
|
} | null;
|
|
|
|
export type DebugMenuModalState = object | null;
|
|
|
|
export type ConversationSettingsModalPage = 'default' | 'disappearing_message' | 'notifications';
|
|
type SettingsPageThatCannotBeStandalone = Extract<ConversationSettingsModalPage, 'default'>;
|
|
type SettingsPageThatCanBeStandalone = Exclude<ConversationSettingsModalPage, 'default'>;
|
|
|
|
export type ConversationSettingsPage =
|
|
| { settingsModalPage: SettingsPageThatCannotBeStandalone }
|
|
| {
|
|
settingsModalPage: SettingsPageThatCanBeStandalone;
|
|
standalonePage: boolean;
|
|
};
|
|
export type ConversationSettingsModalState = (WithConvoId & ConversationSettingsPage) | null;
|
|
|
|
export type ModalId =
|
|
| 'confirmModal'
|
|
| 'inviteContactModal'
|
|
| 'banOrUnbanUserModal'
|
|
| 'blockOrUnblockModal'
|
|
| 'removeModeratorsModal'
|
|
| 'addModeratorsModal'
|
|
| 'updateConversationDetailsModal'
|
|
| 'groupMembersModal'
|
|
| 'userProfileModal'
|
|
| 'nickNameModal'
|
|
| 'userSettingsModal'
|
|
| 'onionPathModal'
|
|
| 'enterPasswordModal'
|
|
| 'deleteAccountModal'
|
|
| 'reactListModal'
|
|
| 'reactClearAllModal'
|
|
| 'editProfilePictureModal'
|
|
| 'hideRecoveryPasswordModal'
|
|
| 'openUrlModal'
|
|
| 'localizedPopupDialog'
|
|
| 'sessionProInfoModal'
|
|
| 'lightBoxOptions'
|
|
| 'debugMenuModal'
|
|
| 'conversationSettingsModal';
|
|
|
|
export type ModalState = {
|
|
confirmModal: ConfirmModalState;
|
|
inviteContactModal: InviteContactModalState;
|
|
banOrUnbanUserModal: BanOrUnbanUserModalState;
|
|
blockOrUnblockModal: BlockOrUnblockModalState;
|
|
removeModeratorsModal: RemoveModeratorsModalState;
|
|
addModeratorsModal: AddModeratorsModalState;
|
|
updateConversationDetailsModal: UpdateConversationDetailsModalState;
|
|
groupMembersModal: UpdateGroupMembersModalState;
|
|
userProfileModal: UserProfileModalState;
|
|
nickNameModal: ChangeNickNameModalState;
|
|
userSettingsModal: UserSettingsModalState;
|
|
onionPathModal: OnionPathModalState;
|
|
enterPasswordModal: EnterPasswordModalState;
|
|
deleteAccountModal: DeleteAccountModalState;
|
|
reactListModal: ReactModalsState;
|
|
reactClearAllModal: ReactModalsState;
|
|
editProfilePictureModal: EditProfilePictureModalState;
|
|
hideRecoveryPasswordModal: HideRecoveryPasswordModalState;
|
|
openUrlModal: OpenUrlModalState;
|
|
localizedPopupDialog: LocalizedPopupDialogState;
|
|
sessionProInfoModal: SessionCTAState;
|
|
lightBoxOptions: LightBoxOptions;
|
|
debugMenuModal: DebugMenuModalState;
|
|
conversationSettingsModal: ConversationSettingsModalState;
|
|
modalStack: Array<ModalId>;
|
|
};
|
|
|
|
export const initialModalState: ModalState = {
|
|
modalStack: [],
|
|
confirmModal: null,
|
|
inviteContactModal: null,
|
|
addModeratorsModal: null,
|
|
removeModeratorsModal: null,
|
|
banOrUnbanUserModal: null,
|
|
blockOrUnblockModal: null,
|
|
updateConversationDetailsModal: null,
|
|
groupMembersModal: null,
|
|
userProfileModal: null,
|
|
nickNameModal: null,
|
|
userSettingsModal: null,
|
|
onionPathModal: null,
|
|
enterPasswordModal: null,
|
|
deleteAccountModal: null,
|
|
reactListModal: null,
|
|
reactClearAllModal: null,
|
|
editProfilePictureModal: null,
|
|
hideRecoveryPasswordModal: null,
|
|
openUrlModal: null,
|
|
localizedPopupDialog: null,
|
|
sessionProInfoModal: null,
|
|
lightBoxOptions: null,
|
|
debugMenuModal: null,
|
|
conversationSettingsModal: null,
|
|
};
|
|
|
|
function pushModal<T extends ModalId>(
|
|
state: ModalState,
|
|
modalId: T,
|
|
thatModalState: ModalState[T]
|
|
) {
|
|
state[modalId] = thatModalState;
|
|
state.modalStack.push(modalId);
|
|
|
|
return state;
|
|
}
|
|
|
|
function popModal(state: ModalState, modalId: ModalId) {
|
|
state[modalId] = null;
|
|
state.modalStack = state.modalStack.filter(m => m !== modalId);
|
|
|
|
return state;
|
|
}
|
|
|
|
function pushOrPopModal<T extends ModalId>(
|
|
state: ModalState,
|
|
modalId: T,
|
|
thatModalState: ModalState[T]
|
|
) {
|
|
const modalStack = state.modalStack;
|
|
if (thatModalState === null) {
|
|
// consider that this is a pop of that corresponding modal id
|
|
return popModal(state, modalId);
|
|
}
|
|
// if the modal is already on the stack, do nothing
|
|
if (modalStack.includes(modalId)) {
|
|
state[modalId] = thatModalState;
|
|
return state;
|
|
}
|
|
return pushModal(state, modalId, thatModalState);
|
|
}
|
|
|
|
const ModalSlice = createSlice({
|
|
name: 'modals',
|
|
initialState: initialModalState,
|
|
reducers: {
|
|
updateConfirmModal(state, action: PayloadAction<ConfirmModalState | null>) {
|
|
return pushOrPopModal(state, 'confirmModal', action.payload);
|
|
},
|
|
updateInviteContactModal(state, action: PayloadAction<InviteContactModalState | null>) {
|
|
return pushOrPopModal(state, 'inviteContactModal', action.payload);
|
|
},
|
|
updateBanOrUnbanUserModal(state, action: PayloadAction<BanOrUnbanUserModalState | null>) {
|
|
return pushOrPopModal(state, 'banOrUnbanUserModal', action.payload);
|
|
},
|
|
updateBlockOrUnblockModal(state, action: PayloadAction<BlockOrUnblockModalState | null>) {
|
|
return pushOrPopModal(state, 'blockOrUnblockModal', action.payload);
|
|
},
|
|
updateAddModeratorsModal(state, action: PayloadAction<AddModeratorsModalState | null>) {
|
|
return pushOrPopModal(state, 'addModeratorsModal', action.payload);
|
|
},
|
|
updateRemoveModeratorsModal(state, action: PayloadAction<RemoveModeratorsModalState | null>) {
|
|
return pushOrPopModal(state, 'removeModeratorsModal', action.payload);
|
|
},
|
|
updateConversationDetailsModal(
|
|
state,
|
|
action: PayloadAction<UpdateConversationDetailsModalState | null>
|
|
) {
|
|
return pushOrPopModal(state, 'updateConversationDetailsModal', action.payload);
|
|
},
|
|
updateGroupMembersModal(state, action: PayloadAction<UpdateGroupMembersModalState | null>) {
|
|
return pushOrPopModal(state, 'groupMembersModal', action.payload);
|
|
},
|
|
updateUserProfileModal(state, action: PayloadAction<UserProfileModalState | null>) {
|
|
return pushOrPopModal(state, 'userProfileModal', action.payload);
|
|
},
|
|
changeNickNameModal(state, action: PayloadAction<ChangeNickNameModalState | null>) {
|
|
return pushOrPopModal(state, 'nickNameModal', action.payload);
|
|
},
|
|
userSettingsModal(state, action: PayloadAction<UserSettingsModalState | null>) {
|
|
return pushOrPopModal(state, 'userSettingsModal', action.payload);
|
|
},
|
|
onionPathModal(state, action: PayloadAction<OnionPathModalState | null>) {
|
|
return pushOrPopModal(state, 'onionPathModal', action.payload);
|
|
},
|
|
updateEnterPasswordModal(state, action: PayloadAction<EnterPasswordModalState | null>) {
|
|
return pushOrPopModal(state, 'enterPasswordModal', action.payload);
|
|
},
|
|
updateDeleteAccountModal(state, action: PayloadAction<DeleteAccountModalState>) {
|
|
return pushOrPopModal(state, 'deleteAccountModal', action.payload);
|
|
},
|
|
updateReactListModal(state, action: PayloadAction<ReactModalsState>) {
|
|
return pushOrPopModal(state, 'reactListModal', action.payload);
|
|
},
|
|
updateReactClearAllModal(state, action: PayloadAction<ReactModalsState>) {
|
|
return pushOrPopModal(state, 'reactClearAllModal', action.payload);
|
|
},
|
|
updateEditProfilePictureModal(state, action: PayloadAction<EditProfilePictureModalState>) {
|
|
return pushOrPopModal(state, 'editProfilePictureModal', action.payload);
|
|
},
|
|
updateHideRecoveryPasswordModal(state, action: PayloadAction<HideRecoveryPasswordModalState>) {
|
|
return pushOrPopModal(state, 'hideRecoveryPasswordModal', action.payload);
|
|
},
|
|
updateOpenUrlModal(state, action: PayloadAction<OpenUrlModalState>) {
|
|
return pushOrPopModal(state, 'openUrlModal', action.payload);
|
|
},
|
|
updateLocalizedPopupDialog(state, action: PayloadAction<LocalizedPopupDialogState>) {
|
|
return pushOrPopModal(state, 'localizedPopupDialog', action.payload);
|
|
},
|
|
updateSessionCTA(state, action: PayloadAction<SessionCTAState>) {
|
|
return pushOrPopModal(state, 'sessionProInfoModal', action.payload);
|
|
},
|
|
updateLightBoxOptions(state, action: PayloadAction<LightBoxOptions>) {
|
|
const lightBoxOptions = action.payload;
|
|
|
|
if (lightBoxOptions) {
|
|
const { media, attachment } = lightBoxOptions;
|
|
|
|
if (attachment && media) {
|
|
const selectedIndex =
|
|
media.length > 1
|
|
? media.findIndex(mediaMessage => mediaMessage.attachment.path === attachment.path)
|
|
: 0;
|
|
lightBoxOptions.selectedIndex = selectedIndex;
|
|
}
|
|
}
|
|
return pushOrPopModal(state, 'lightBoxOptions', lightBoxOptions);
|
|
},
|
|
updateDebugMenuModal(state, action: PayloadAction<DebugMenuModalState>) {
|
|
return pushOrPopModal(state, 'debugMenuModal', action.payload);
|
|
},
|
|
updateConversationSettingsModal(state, action: PayloadAction<ConversationSettingsModalState>) {
|
|
return pushOrPopModal(state, 'conversationSettingsModal', action.payload);
|
|
},
|
|
},
|
|
});
|
|
|
|
export const { actions, reducer } = ModalSlice;
|
|
export const {
|
|
updateConfirmModal,
|
|
updateInviteContactModal,
|
|
updateAddModeratorsModal,
|
|
updateRemoveModeratorsModal,
|
|
updateConversationDetailsModal,
|
|
updateGroupMembersModal,
|
|
updateUserProfileModal,
|
|
changeNickNameModal,
|
|
userSettingsModal,
|
|
onionPathModal,
|
|
updateEnterPasswordModal,
|
|
updateDeleteAccountModal,
|
|
updateBanOrUnbanUserModal,
|
|
updateBlockOrUnblockModal,
|
|
updateReactListModal,
|
|
updateReactClearAllModal,
|
|
updateEditProfilePictureModal,
|
|
updateHideRecoveryPasswordModal,
|
|
updateOpenUrlModal,
|
|
updateLocalizedPopupDialog,
|
|
updateSessionCTA,
|
|
updateLightBoxOptions,
|
|
updateDebugMenuModal,
|
|
updateConversationSettingsModal,
|
|
} = actions;
|
|
export const modalReducer = reducer;
|