Donations: Show toasts when resuming after startup
Co-authored-by: ayumi-signal <143036029+ayumi-signal@users.noreply.github.com>
This commit is contained in:
parent
ea3a7f70b6
commit
e17bcb2409
36 changed files with 496 additions and 314 deletions
|
@ -8886,6 +8886,14 @@
|
|||
"messageformat": "Thank you for supporting Signal. Your contribution helps fuel the mission of protecting free expression and enabling secure global communication for millions around the world, through open source privacy technology. If you’re a resident of the United States, please retain this receipt for your tax records. Signal Technology Foundation is a tax-exempt nonprofit organization in the United States under section 501c3 of the Internal Revenue Code. Our Federal Tax ID is 82-4506840.",
|
||||
"description": "Footer text shown on donation receipts explaining tax deductibility and Signal's mission"
|
||||
},
|
||||
"icu:Donations__Toast__Completed": {
|
||||
"messageformat": "Donation completed",
|
||||
"description": "Toast shown when a donation started processing after resuming on startup, and it completed successfully when the user is not on the Preferences/Donations screen"
|
||||
},
|
||||
"icu:Donations__Toast__Processing": {
|
||||
"messageformat": "Processing donation",
|
||||
"description": "Toast shown when a donation starts processing again after resuming on startup"
|
||||
},
|
||||
"icu:Donations__PaymentMethodDeclined": {
|
||||
"messageformat": "Payment method declined",
|
||||
"description": "Title of the dialog shown with the user's provided payment method has not worked"
|
||||
|
|
|
@ -216,10 +216,8 @@ import { waitForEvent } from './shims/events';
|
|||
import { sendSyncRequests } from './textsecure/syncRequests';
|
||||
import { handleServerAlerts } from './util/handleServerAlerts';
|
||||
import { isLocalBackupsEnabled } from './util/isLocalBackupsEnabled';
|
||||
import { NavTab } from './state/ducks/nav';
|
||||
import { Page } from './components/Preferences';
|
||||
import { EditState } from './components/ProfileEditor';
|
||||
import { runDonationWorkflow } from './services/donations';
|
||||
import { NavTab, SettingsPage, ProfileEditorPage } from './types/Nav';
|
||||
import { initialize as initializeDonationService } from './services/donations';
|
||||
import { MessageRequestResponseSource } from './types/MessageRequestResponseEvent';
|
||||
|
||||
const log = createLogger('background');
|
||||
|
@ -1373,8 +1371,8 @@ export async function startApp(): Promise<void> {
|
|||
window.reduxActions.nav.changeLocation({
|
||||
tab: NavTab.Settings,
|
||||
details: {
|
||||
page: Page.Profile,
|
||||
state: EditState.None,
|
||||
page: SettingsPage.Profile,
|
||||
state: ProfileEditorPage.None,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
@ -2198,7 +2196,7 @@ export async function startApp(): Promise<void> {
|
|||
|
||||
drop(ReleaseNotesFetcher.init(window.Whisper.events, newVersion));
|
||||
|
||||
drop(runDonationWorkflow());
|
||||
drop(initializeDonationService());
|
||||
|
||||
if (isFromMessageReceiver) {
|
||||
drop(
|
||||
|
|
|
@ -151,12 +151,15 @@ export function DebugLogWindow({
|
|||
<Button onClick={copyLog}>{i18n('icu:debugLogCopy')}</Button>
|
||||
</div>
|
||||
<ToastManager
|
||||
changeLocation={shouldNeverBeCalled}
|
||||
clearDonation={shouldNeverBeCalled}
|
||||
OS="unused"
|
||||
hideToast={closeToast}
|
||||
i18n={i18n}
|
||||
onShowDebugLog={shouldNeverBeCalled}
|
||||
onUndoArchive={shouldNeverBeCalled}
|
||||
openFileInFolder={shouldNeverBeCalled}
|
||||
setDidResumeDonation={shouldNeverBeCalled}
|
||||
showAttachmentNotAvailableModal={shouldNeverBeCalled}
|
||||
toast={toast}
|
||||
containerWidthBreakpoint={null}
|
||||
|
@ -209,12 +212,15 @@ export function DebugLogWindow({
|
|||
</Button>
|
||||
</div>
|
||||
<ToastManager
|
||||
changeLocation={shouldNeverBeCalled}
|
||||
clearDonation={shouldNeverBeCalled}
|
||||
OS="unused"
|
||||
hideToast={closeToast}
|
||||
i18n={i18n}
|
||||
onShowDebugLog={shouldNeverBeCalled}
|
||||
onUndoArchive={shouldNeverBeCalled}
|
||||
openFileInFolder={shouldNeverBeCalled}
|
||||
setDidResumeDonation={shouldNeverBeCalled}
|
||||
showAttachmentNotAvailableModal={shouldNeverBeCalled}
|
||||
toast={toast}
|
||||
containerWidthBreakpoint={null}
|
||||
|
|
|
@ -284,12 +284,15 @@ const useProps = (overrideProps: OverridePropsType = {}): PropsType => {
|
|||
),
|
||||
renderToastManager: ({ containerWidthBreakpoint }) => (
|
||||
<ToastManager
|
||||
changeLocation={action('changeLocation')}
|
||||
clearDonation={action('clearDonation')}
|
||||
OS="unused"
|
||||
hideToast={action('hideToast')}
|
||||
i18n={i18n}
|
||||
onShowDebugLog={action('onShowDebugLog')}
|
||||
onUndoArchive={action('onUndoArchive')}
|
||||
openFileInFolder={action('openFileInFolder')}
|
||||
setDidResumeDonation={action('setDidResumeDonation')}
|
||||
showAttachmentNotAvailableModal={action(
|
||||
'showAttachmentNotAvailableModal'
|
||||
)}
|
||||
|
|
|
@ -58,10 +58,8 @@ import type { UnreadStats } from '../util/countUnreadStats';
|
|||
import { BackupMediaDownloadProgress } from './BackupMediaDownloadProgress';
|
||||
import type { ServerAlertsType } from '../util/handleServerAlerts';
|
||||
import { getServerAlertDialog } from './ServerAlerts';
|
||||
import { NavTab } from '../state/ducks/nav';
|
||||
import type { Location } from '../state/ducks/nav';
|
||||
import { Page } from './Preferences';
|
||||
import { EditState } from './ProfileEditor';
|
||||
import { NavTab, SettingsPage, ProfileEditorPage } from '../types/Nav';
|
||||
import type { Location } from '../types/Nav';
|
||||
|
||||
export type PropsType = {
|
||||
backupMediaDownloadProgress: {
|
||||
|
@ -674,8 +672,8 @@ export function LeftPane({
|
|||
changeLocation({
|
||||
tab: NavTab.Settings,
|
||||
details: {
|
||||
page: Page.Profile,
|
||||
state: EditState.Username,
|
||||
page: SettingsPage.Profile,
|
||||
state: ProfileEditorPage.Username,
|
||||
},
|
||||
});
|
||||
}}
|
||||
|
@ -691,8 +689,8 @@ export function LeftPane({
|
|||
changeLocation({
|
||||
tab: NavTab.Settings,
|
||||
details: {
|
||||
page: Page.Profile,
|
||||
state: EditState.UsernameLink,
|
||||
page: SettingsPage.Profile,
|
||||
state: ProfileEditorPage.UsernameLink,
|
||||
},
|
||||
});
|
||||
}}
|
||||
|
|
|
@ -7,7 +7,7 @@ import { action } from '@storybook/addon-actions';
|
|||
import type { Meta } from '@storybook/react';
|
||||
import type { NavTabsProps } from './NavTabs';
|
||||
import { NavTabs } from './NavTabs';
|
||||
import { NavTab } from '../state/ducks/nav';
|
||||
import { NavTab } from '../types/Nav';
|
||||
import { getDefaultConversation } from '../test-helpers/getDefaultConversation';
|
||||
import { ThemeType } from '../types/Util';
|
||||
|
||||
|
|
|
@ -9,13 +9,11 @@ import { Avatar, AvatarSize } from './Avatar';
|
|||
import type { LocalizerType, ThemeType } from '../types/Util';
|
||||
import type { ConversationType } from '../state/ducks/conversations';
|
||||
import type { BadgeType } from '../badges/types';
|
||||
import { NavTab } from '../state/ducks/nav';
|
||||
import type { Location } from '../state/ducks/nav';
|
||||
import { NavTab, ProfileEditorPage, SettingsPage } from '../types/Nav';
|
||||
import type { Location } from '../types/Nav';
|
||||
import { Tooltip, TooltipPlacement } from './Tooltip';
|
||||
import { Theme } from '../util/theme';
|
||||
import type { UnreadStats } from '../util/countUnreadStats';
|
||||
import { Page } from './Preferences';
|
||||
import { EditState } from './ProfileEditor';
|
||||
import { ProfileMovedModal } from './ProfileMovedModal';
|
||||
|
||||
type NavTabsItemBadgesProps = Readonly<{
|
||||
|
@ -248,8 +246,8 @@ export function NavTabs({
|
|||
onChangeLocation({
|
||||
tab: NavTab.Settings,
|
||||
details: {
|
||||
page: Page.Profile,
|
||||
state: EditState.None,
|
||||
page: SettingsPage.Profile,
|
||||
state: ProfileEditorPage.None,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
|
|
|
@ -6,7 +6,7 @@ import React, { useRef, useState } from 'react';
|
|||
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import { shuffle } from 'lodash';
|
||||
import { Page, Preferences } from './Preferences';
|
||||
import { Preferences } from './Preferences';
|
||||
import { DEFAULT_CONVERSATION_COLOR } from '../types/Colors';
|
||||
import { PhoneNumberSharingMode } from '../util/phoneNumberSharingMode';
|
||||
import { PhoneNumberDiscoverability } from '../util/phoneNumberDiscoverability';
|
||||
|
@ -15,22 +15,23 @@ import { DAY, DurationInSeconds, WEEK } from '../util/durations';
|
|||
import { DialogUpdate } from './DialogUpdate';
|
||||
import { DialogType } from '../types/Dialogs';
|
||||
import { ThemeType } from '../types/Util';
|
||||
import type { LocalizerType } from '../types/Util';
|
||||
import {
|
||||
getDefaultConversation,
|
||||
getDefaultGroup,
|
||||
} from '../test-helpers/getDefaultConversation';
|
||||
import { EditState, ProfileEditor } from './ProfileEditor';
|
||||
import { ProfileEditor } from './ProfileEditor';
|
||||
import {
|
||||
UsernameEditState,
|
||||
UsernameLinkState,
|
||||
} from '../state/ducks/usernameEnums';
|
||||
import { ProfileEditorPage, SettingsPage } from '../types/Nav';
|
||||
import { PreferencesDonations } from './PreferencesDonations';
|
||||
import { strictAssert } from '../util/assert';
|
||||
|
||||
import type { LocalizerType } from '../types/Util';
|
||||
import type { PropsType } from './Preferences';
|
||||
import type { WidthBreakpoint } from './_util';
|
||||
import type { MessageAttributesType } from '../model-types';
|
||||
import { PreferencesDonations } from './PreferencesDonations';
|
||||
import { strictAssert } from '../util/assert';
|
||||
import type {
|
||||
DonationReceipt,
|
||||
OneTimeDonationHumanAmounts,
|
||||
|
@ -160,7 +161,7 @@ function RenderProfileEditor(): JSX.Element {
|
|||
firstName={me.firstName ?? ''}
|
||||
hasCompletedUsernameLinkOnboarding={false}
|
||||
i18n={i18n}
|
||||
editState={EditState.None}
|
||||
editState={ProfileEditorPage.None}
|
||||
markCompletedUsernameLinkOnboarding={action(
|
||||
'markCompletedUsernameLinkOnboarding'
|
||||
)}
|
||||
|
@ -212,7 +213,7 @@ function RenderDonationsPane(props: {
|
|||
contentsRef={contentsRef}
|
||||
clearWorkflow={action('clearWorkflow')}
|
||||
isStaging={false}
|
||||
page={Page.Donations}
|
||||
page={SettingsPage.Donations}
|
||||
setPage={action('setPage')}
|
||||
submitDonation={action('submitDonation')}
|
||||
workflow={undefined}
|
||||
|
@ -331,7 +332,7 @@ export default {
|
|||
unreadMentionsCount: 0,
|
||||
markedUnread: false,
|
||||
},
|
||||
page: Page.Profile,
|
||||
page: SettingsPage.Profile,
|
||||
preferredSystemLocales: ['en'],
|
||||
preferredWidthFromStorage: 300,
|
||||
resolvedLocale: 'en',
|
||||
|
@ -476,86 +477,86 @@ export const _Preferences = Template.bind({});
|
|||
|
||||
export const General = Template.bind({});
|
||||
General.args = {
|
||||
page: Page.General,
|
||||
page: SettingsPage.General,
|
||||
};
|
||||
export const Appearance = Template.bind({});
|
||||
Appearance.args = {
|
||||
page: Page.Appearance,
|
||||
page: SettingsPage.Appearance,
|
||||
};
|
||||
export const Chats = Template.bind({});
|
||||
Chats.args = {
|
||||
page: Page.Chats,
|
||||
page: SettingsPage.Chats,
|
||||
};
|
||||
export const ChatFolders = Template.bind({});
|
||||
ChatFolders.args = {
|
||||
page: Page.ChatFolders,
|
||||
page: SettingsPage.ChatFolders,
|
||||
};
|
||||
export const EditChatFolder = Template.bind({});
|
||||
EditChatFolder.args = {
|
||||
page: Page.EditChatFolder,
|
||||
page: SettingsPage.EditChatFolder,
|
||||
};
|
||||
export const Calls = Template.bind({});
|
||||
Calls.args = {
|
||||
page: Page.Calls,
|
||||
page: SettingsPage.Calls,
|
||||
};
|
||||
export const Notifications = Template.bind({});
|
||||
Notifications.args = {
|
||||
page: Page.Notifications,
|
||||
page: SettingsPage.Notifications,
|
||||
};
|
||||
export const Privacy = Template.bind({});
|
||||
Privacy.args = {
|
||||
page: Page.Privacy,
|
||||
page: SettingsPage.Privacy,
|
||||
};
|
||||
export const DataUsage = Template.bind({});
|
||||
DataUsage.args = {
|
||||
page: Page.DataUsage,
|
||||
page: SettingsPage.DataUsage,
|
||||
};
|
||||
export const Donations = Template.bind({});
|
||||
Donations.args = {
|
||||
donationsFeatureEnabled: true,
|
||||
page: Page.Donations,
|
||||
page: SettingsPage.Donations,
|
||||
};
|
||||
export const Internal = Template.bind({});
|
||||
Internal.args = {
|
||||
page: Page.Internal,
|
||||
page: SettingsPage.Internal,
|
||||
isInternalUser: true,
|
||||
};
|
||||
|
||||
export const Blocked1 = Template.bind({});
|
||||
Blocked1.args = {
|
||||
blockedCount: 1,
|
||||
page: Page.Privacy,
|
||||
page: SettingsPage.Privacy,
|
||||
};
|
||||
|
||||
export const BlockedMany = Template.bind({});
|
||||
BlockedMany.args = {
|
||||
blockedCount: 55,
|
||||
page: Page.Privacy,
|
||||
page: SettingsPage.Privacy,
|
||||
};
|
||||
|
||||
export const CustomUniversalExpireTimer = Template.bind({});
|
||||
CustomUniversalExpireTimer.args = {
|
||||
universalExpireTimer: DurationInSeconds.fromSeconds(9000),
|
||||
page: Page.Privacy,
|
||||
page: SettingsPage.Privacy,
|
||||
};
|
||||
|
||||
export const PNPSharingDisabled = Template.bind({});
|
||||
PNPSharingDisabled.args = {
|
||||
whoCanSeeMe: PhoneNumberSharingMode.Nobody,
|
||||
whoCanFindMe: PhoneNumberDiscoverability.Discoverable,
|
||||
page: Page.PNP,
|
||||
page: SettingsPage.PNP,
|
||||
};
|
||||
|
||||
export const PNPDiscoverabilityDisabled = Template.bind({});
|
||||
PNPDiscoverabilityDisabled.args = {
|
||||
whoCanSeeMe: PhoneNumberSharingMode.Nobody,
|
||||
whoCanFindMe: PhoneNumberDiscoverability.NotDiscoverable,
|
||||
page: Page.PNP,
|
||||
page: SettingsPage.PNP,
|
||||
};
|
||||
|
||||
export const BackupsMediaDownloadActive = Template.bind({});
|
||||
BackupsMediaDownloadActive.args = {
|
||||
page: Page.BackupsDetails,
|
||||
page: SettingsPage.BackupsDetails,
|
||||
backupFeatureEnabled: true,
|
||||
backupLocalBackupsEnabled: true,
|
||||
cloudBackupStatus: {
|
||||
|
@ -579,7 +580,7 @@ BackupsMediaDownloadActive.args = {
|
|||
};
|
||||
export const BackupsMediaDownloadPaused = Template.bind({});
|
||||
BackupsMediaDownloadPaused.args = {
|
||||
page: Page.BackupsDetails,
|
||||
page: SettingsPage.BackupsDetails,
|
||||
backupFeatureEnabled: true,
|
||||
backupLocalBackupsEnabled: true,
|
||||
cloudBackupStatus: {
|
||||
|
@ -604,7 +605,7 @@ BackupsMediaDownloadPaused.args = {
|
|||
|
||||
export const BackupsPaidActive = Template.bind({});
|
||||
BackupsPaidActive.args = {
|
||||
page: Page.Backups,
|
||||
page: SettingsPage.Backups,
|
||||
backupFeatureEnabled: true,
|
||||
backupLocalBackupsEnabled: true,
|
||||
cloudBackupStatus: {
|
||||
|
@ -623,7 +624,7 @@ BackupsPaidActive.args = {
|
|||
|
||||
export const BackupsPaidCancelled = Template.bind({});
|
||||
BackupsPaidCancelled.args = {
|
||||
page: Page.Backups,
|
||||
page: SettingsPage.Backups,
|
||||
backupFeatureEnabled: true,
|
||||
backupLocalBackupsEnabled: true,
|
||||
cloudBackupStatus: {
|
||||
|
@ -642,7 +643,7 @@ BackupsPaidCancelled.args = {
|
|||
|
||||
export const BackupsFree = Template.bind({});
|
||||
BackupsFree.args = {
|
||||
page: Page.Backups,
|
||||
page: SettingsPage.Backups,
|
||||
backupFeatureEnabled: true,
|
||||
backupLocalBackupsEnabled: true,
|
||||
backupSubscriptionStatus: {
|
||||
|
@ -653,21 +654,21 @@ BackupsFree.args = {
|
|||
|
||||
export const BackupsOff = Template.bind({});
|
||||
BackupsOff.args = {
|
||||
page: Page.Backups,
|
||||
page: SettingsPage.Backups,
|
||||
backupFeatureEnabled: true,
|
||||
backupLocalBackupsEnabled: true,
|
||||
};
|
||||
|
||||
export const BackupsLocalBackups = Template.bind({});
|
||||
BackupsLocalBackups.args = {
|
||||
page: Page.Backups,
|
||||
page: SettingsPage.Backups,
|
||||
backupFeatureEnabled: true,
|
||||
backupLocalBackupsEnabled: true,
|
||||
};
|
||||
|
||||
export const BackupsSubscriptionNotFound = Template.bind({});
|
||||
BackupsSubscriptionNotFound.args = {
|
||||
page: Page.Backups,
|
||||
page: SettingsPage.Backups,
|
||||
backupFeatureEnabled: true,
|
||||
backupLocalBackupsEnabled: true,
|
||||
backupSubscriptionStatus: {
|
||||
|
@ -681,7 +682,7 @@ BackupsSubscriptionNotFound.args = {
|
|||
|
||||
export const BackupsSubscriptionExpired = Template.bind({});
|
||||
BackupsSubscriptionExpired.args = {
|
||||
page: Page.Backups,
|
||||
page: SettingsPage.Backups,
|
||||
backupFeatureEnabled: true,
|
||||
backupLocalBackupsEnabled: true,
|
||||
backupSubscriptionStatus: {
|
||||
|
@ -691,7 +692,7 @@ BackupsSubscriptionExpired.args = {
|
|||
|
||||
export const LocalBackups = Template.bind({});
|
||||
LocalBackups.args = {
|
||||
page: Page.LocalBackups,
|
||||
page: SettingsPage.LocalBackups,
|
||||
backupFeatureEnabled: true,
|
||||
backupLocalBackupsEnabled: true,
|
||||
backupKeyViewed: true,
|
||||
|
@ -700,14 +701,14 @@ LocalBackups.args = {
|
|||
|
||||
export const LocalBackupsSetupChooseFolder = Template.bind({});
|
||||
LocalBackupsSetupChooseFolder.args = {
|
||||
page: Page.LocalBackupsSetupFolder,
|
||||
page: SettingsPage.LocalBackupsSetupFolder,
|
||||
backupFeatureEnabled: true,
|
||||
backupLocalBackupsEnabled: true,
|
||||
};
|
||||
|
||||
export const LocalBackupsSetupViewBackupKey = Template.bind({});
|
||||
LocalBackupsSetupViewBackupKey.args = {
|
||||
page: Page.LocalBackupsSetupKey,
|
||||
page: SettingsPage.LocalBackupsSetupKey,
|
||||
backupFeatureEnabled: true,
|
||||
backupLocalBackupsEnabled: true,
|
||||
localBackupFolder: '/home/signaluser/Signal Backups/',
|
||||
|
|
|
@ -50,6 +50,7 @@ import { PreferencesInternal } from './PreferencesInternal';
|
|||
import { FunEmojiLocalizationProvider } from './fun/FunEmojiLocalizationProvider';
|
||||
import { Avatar, AvatarSize } from './Avatar';
|
||||
import { NavSidebar } from './NavSidebar';
|
||||
import { SettingsPage } from '../types/Nav';
|
||||
|
||||
import type { MediaDeviceSettings } from '../types/Calling';
|
||||
import type { ValidationResultType as BackupValidationResultType } from '../services/backups';
|
||||
|
@ -153,7 +154,7 @@ export type PropsDataType = {
|
|||
hasStoriesDisabled: boolean;
|
||||
hasTextFormatting: boolean;
|
||||
hasTypingIndicators: boolean;
|
||||
page: Page;
|
||||
page: SettingsPage;
|
||||
lastSyncTime?: number;
|
||||
notificationContent: NotificationSettingType;
|
||||
phoneNumber: string | undefined;
|
||||
|
@ -208,8 +209,8 @@ type PropsFunctionType = {
|
|||
// Render props
|
||||
renderDonationsPane: (options: {
|
||||
contentsRef: MutableRefObject<HTMLDivElement | null>;
|
||||
page: Page;
|
||||
setPage: (page: Page) => void;
|
||||
page: SettingsPage;
|
||||
setPage: (page: SettingsPage) => void;
|
||||
}) => JSX.Element;
|
||||
renderProfileEditor: (options: {
|
||||
contentsRef: MutableRefObject<HTMLDivElement | null>;
|
||||
|
@ -254,7 +255,7 @@ type PropsFunctionType = {
|
|||
value: CustomColorType;
|
||||
}
|
||||
) => unknown;
|
||||
setPage: (page: Page) => unknown;
|
||||
setPage: (page: SettingsPage) => unknown;
|
||||
showToast: (toast: AnyToast) => unknown;
|
||||
validateBackup: () => Promise<BackupValidationResultType>;
|
||||
|
||||
|
@ -318,39 +319,11 @@ export type PropsType = PropsDataType & PropsFunctionType;
|
|||
|
||||
export type PropsPreloadType = Omit<PropsType, 'i18n'>;
|
||||
|
||||
export enum Page {
|
||||
// Accessible through left nav
|
||||
Profile = 'Profile',
|
||||
General = 'General',
|
||||
Donations = 'Donations',
|
||||
Appearance = 'Appearance',
|
||||
Chats = 'Chats',
|
||||
Calls = 'Calls',
|
||||
Notifications = 'Notifications',
|
||||
Privacy = 'Privacy',
|
||||
DataUsage = 'DataUsage',
|
||||
Backups = 'Backups',
|
||||
Internal = 'Internal',
|
||||
|
||||
// Sub pages
|
||||
ChatColor = 'ChatColor',
|
||||
ChatFolders = 'ChatFolders',
|
||||
DonationsDonateFlow = 'DonationsDonateFlow',
|
||||
DonationsReceiptList = 'DonationsReceiptList',
|
||||
EditChatFolder = 'EditChatFolder',
|
||||
PNP = 'PNP',
|
||||
BackupsDetails = 'BackupsDetails',
|
||||
LocalBackups = 'LocalBackups',
|
||||
LocalBackupsSetupFolder = 'LocalBackupsSetupFolder',
|
||||
LocalBackupsSetupKey = 'LocalBackupsSetupKey',
|
||||
LocalBackupsKeyReference = 'LocalBackupsKeyReference',
|
||||
}
|
||||
|
||||
function isDonationsPage(page: Page): boolean {
|
||||
function isDonationsPage(page: SettingsPage): boolean {
|
||||
return (
|
||||
page === Page.Donations ||
|
||||
page === Page.DonationsDonateFlow ||
|
||||
page === Page.DonationsReceiptList
|
||||
page === SettingsPage.Donations ||
|
||||
page === SettingsPage.DonationsDonateFlow ||
|
||||
page === SettingsPage.DonationsReceiptList
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -567,14 +540,14 @@ export function Preferences({
|
|||
|
||||
const handleOpenEditChatFoldersPage = useCallback(
|
||||
(chatFolderId: ChatFolderId | null) => {
|
||||
setPage(Page.EditChatFolder);
|
||||
setPage(SettingsPage.EditChatFolder);
|
||||
setEditChatFolderPageId(chatFolderId);
|
||||
},
|
||||
[setPage]
|
||||
);
|
||||
|
||||
const handleCloseEditChatFoldersPage = useCallback(() => {
|
||||
setPage(Page.ChatFolders);
|
||||
setPage(SettingsPage.ChatFolders);
|
||||
setEditChatFolderPageId(null);
|
||||
}, [setPage]);
|
||||
|
||||
|
@ -613,14 +586,14 @@ export function Preferences({
|
|||
const shouldShowBackupsPage =
|
||||
backupFeatureEnabled || backupLocalBackupsEnabled;
|
||||
|
||||
if (page === Page.Backups && !shouldShowBackupsPage) {
|
||||
setPage(Page.General);
|
||||
if (page === SettingsPage.Backups && !shouldShowBackupsPage) {
|
||||
setPage(SettingsPage.General);
|
||||
}
|
||||
if (isDonationsPage(page) && !donationsFeatureEnabled) {
|
||||
setPage(Page.General);
|
||||
setPage(SettingsPage.General);
|
||||
}
|
||||
if (page === Page.Internal && !isInternalUser) {
|
||||
setPage(Page.General);
|
||||
if (page === SettingsPage.Internal && !isInternalUser) {
|
||||
setPage(SettingsPage.General);
|
||||
}
|
||||
|
||||
let maybeUpdateDialog: JSX.Element | undefined;
|
||||
|
@ -782,11 +755,11 @@ export function Preferences({
|
|||
|
||||
let content: JSX.Element | undefined;
|
||||
|
||||
if (page === Page.Profile) {
|
||||
if (page === SettingsPage.Profile) {
|
||||
content = renderProfileEditor({
|
||||
contentsRef: settingsPaneRef,
|
||||
});
|
||||
} else if (page === Page.General) {
|
||||
} else if (page === SettingsPage.General) {
|
||||
const pageContents = (
|
||||
<>
|
||||
<SettingsRow>
|
||||
|
@ -920,7 +893,7 @@ export function Preferences({
|
|||
page,
|
||||
setPage,
|
||||
});
|
||||
} else if (page === Page.Appearance) {
|
||||
} else if (page === SettingsPage.Appearance) {
|
||||
let zoomFactors = DEFAULT_ZOOM_FACTORS;
|
||||
|
||||
if (
|
||||
|
@ -1101,7 +1074,7 @@ export function Preferences({
|
|||
icon
|
||||
left={i18n('icu:showChatColorEditor')}
|
||||
onClick={() => {
|
||||
setPage(Page.ChatColor);
|
||||
setPage(SettingsPage.ChatColor);
|
||||
}}
|
||||
right={
|
||||
<div
|
||||
|
@ -1140,7 +1113,7 @@ export function Preferences({
|
|||
title={i18n('icu:Preferences__button--appearance')}
|
||||
/>
|
||||
);
|
||||
} else if (page === Page.Chats) {
|
||||
} else if (page === SettingsPage.Chats) {
|
||||
let spellCheckDirtyText: string | undefined;
|
||||
if (
|
||||
hasSpellCheck !== undefined &&
|
||||
|
@ -1231,7 +1204,7 @@ export function Preferences({
|
|||
</>
|
||||
}
|
||||
right={null}
|
||||
onClick={() => setPage(Page.ChatFolders)}
|
||||
onClick={() => setPage(SettingsPage.ChatFolders)}
|
||||
/>
|
||||
</SettingsRow>
|
||||
)}
|
||||
|
@ -1298,7 +1271,7 @@ export function Preferences({
|
|||
title={i18n('icu:Preferences__button--chats')}
|
||||
/>
|
||||
);
|
||||
} else if (page === Page.Calls) {
|
||||
} else if (page === SettingsPage.Calls) {
|
||||
const pageContents = (
|
||||
<>
|
||||
<SettingsRow title={i18n('icu:calling')}>
|
||||
|
@ -1447,7 +1420,7 @@ export function Preferences({
|
|||
title={i18n('icu:Preferences__button--calls')}
|
||||
/>
|
||||
);
|
||||
} else if (page === Page.Notifications) {
|
||||
} else if (page === SettingsPage.Notifications) {
|
||||
const pageContents = (
|
||||
<>
|
||||
<SettingsRow>
|
||||
|
@ -1535,7 +1508,7 @@ export function Preferences({
|
|||
title={i18n('icu:Preferences__button--notifications')}
|
||||
/>
|
||||
);
|
||||
} else if (page === Page.Privacy) {
|
||||
} else if (page === SettingsPage.Privacy) {
|
||||
const isCustomDisappearingMessageValue =
|
||||
!DEFAULT_DURATIONS_SET.has(universalExpireTimer);
|
||||
const pageContents = (
|
||||
|
@ -1562,7 +1535,7 @@ export function Preferences({
|
|||
)}
|
||||
>
|
||||
<Button
|
||||
onClick={() => setPage(Page.PNP)}
|
||||
onClick={() => setPage(SettingsPage.PNP)}
|
||||
variant={ButtonVariant.Secondary}
|
||||
>
|
||||
{i18n('icu:Preferences__pnp__row--button')}
|
||||
|
@ -1813,7 +1786,7 @@ export function Preferences({
|
|||
title={i18n('icu:Preferences__button--privacy')}
|
||||
/>
|
||||
);
|
||||
} else if (page === Page.DataUsage) {
|
||||
} else if (page === SettingsPage.DataUsage) {
|
||||
const pageContents = (
|
||||
<>
|
||||
<SettingsRow title={i18n('icu:Preferences__media-auto-download')}>
|
||||
|
@ -1925,12 +1898,12 @@ export function Preferences({
|
|||
title={i18n('icu:Preferences__button--data-usage')}
|
||||
/>
|
||||
);
|
||||
} else if (page === Page.ChatColor) {
|
||||
} else if (page === SettingsPage.ChatColor) {
|
||||
const backButton = (
|
||||
<button
|
||||
aria-label={i18n('icu:goBack')}
|
||||
className="Preferences__back-icon"
|
||||
onClick={() => setPage(Page.Appearance)}
|
||||
onClick={() => setPage(SettingsPage.Appearance)}
|
||||
type="button"
|
||||
/>
|
||||
);
|
||||
|
@ -1961,18 +1934,18 @@ export function Preferences({
|
|||
title={i18n('icu:ChatColorPicker__menu-title')}
|
||||
/>
|
||||
);
|
||||
} else if (page === Page.ChatFolders) {
|
||||
} else if (page === SettingsPage.ChatFolders) {
|
||||
content = (
|
||||
<ChatFoldersPage
|
||||
i18n={i18n}
|
||||
settingsPaneRef={settingsPaneRef}
|
||||
onBack={() => setPage(Page.Chats)}
|
||||
onBack={() => setPage(SettingsPage.Chats)}
|
||||
onOpenEditChatFoldersPage={handleOpenEditChatFoldersPage}
|
||||
chatFolders={chatFolders}
|
||||
onCreateChatFolder={handleCreateChatFolder}
|
||||
/>
|
||||
);
|
||||
} else if (page === Page.EditChatFolder) {
|
||||
} else if (page === SettingsPage.EditChatFolder) {
|
||||
let initChatFolderParam: ChatFolderParams;
|
||||
if (editChatFolderPageId != null) {
|
||||
const found = chatFolders.find(chatFolder => {
|
||||
|
@ -1999,7 +1972,7 @@ export function Preferences({
|
|||
onDeleteChatFolder={handleDeleteChatFolder}
|
||||
/>
|
||||
);
|
||||
} else if (page === Page.PNP) {
|
||||
} else if (page === SettingsPage.PNP) {
|
||||
let sharingDescription: string;
|
||||
|
||||
if (whoCanSeeMe === PhoneNumberSharingMode.Everybody) {
|
||||
|
@ -2020,7 +1993,7 @@ export function Preferences({
|
|||
<button
|
||||
aria-label={i18n('icu:goBack')}
|
||||
className="Preferences__back-icon"
|
||||
onClick={() => setPage(Page.Privacy)}
|
||||
onClick={() => setPage(SettingsPage.Privacy)}
|
||||
type="button"
|
||||
/>
|
||||
);
|
||||
|
@ -2142,18 +2115,18 @@ export function Preferences({
|
|||
);
|
||||
} else if (isBackupPage(page)) {
|
||||
let pageTitle: string | undefined;
|
||||
if (page === Page.Backups || page === Page.BackupsDetails) {
|
||||
if (page === SettingsPage.Backups || page === SettingsPage.BackupsDetails) {
|
||||
pageTitle = i18n('icu:Preferences__button--backups');
|
||||
} else if (page === Page.LocalBackups) {
|
||||
} else if (page === SettingsPage.LocalBackups) {
|
||||
pageTitle = i18n('icu:Preferences__local-backups');
|
||||
}
|
||||
// Local backups setup page titles intentionally left blank
|
||||
|
||||
let backPage: PreferencesBackupPage | undefined;
|
||||
if (page === Page.LocalBackupsKeyReference) {
|
||||
backPage = Page.LocalBackups;
|
||||
} else if (page !== Page.Backups) {
|
||||
backPage = Page.Backups;
|
||||
if (page === SettingsPage.LocalBackupsKeyReference) {
|
||||
backPage = SettingsPage.LocalBackups;
|
||||
} else if (page !== SettingsPage.Backups) {
|
||||
backPage = SettingsPage.Backups;
|
||||
}
|
||||
let backButton: JSX.Element | undefined;
|
||||
if (backPage) {
|
||||
|
@ -2197,7 +2170,7 @@ export function Preferences({
|
|||
title={pageTitle}
|
||||
/>
|
||||
);
|
||||
} else if (page === Page.Internal) {
|
||||
} else if (page === SettingsPage.Internal) {
|
||||
content = (
|
||||
<PreferencesContent
|
||||
contents={
|
||||
|
@ -2249,9 +2222,10 @@ export function Preferences({
|
|||
type="button"
|
||||
className={classNames({
|
||||
'Preferences__profile-chip': true,
|
||||
'Preferences__profile-chip--selected': page === Page.Profile,
|
||||
'Preferences__profile-chip--selected':
|
||||
page === SettingsPage.Profile,
|
||||
})}
|
||||
onClick={() => setPage(Page.Profile)}
|
||||
onClick={() => setPage(SettingsPage.Profile)}
|
||||
>
|
||||
<div className="Preferences__profile-chip__avatar">
|
||||
<Avatar
|
||||
|
@ -2293,9 +2267,10 @@ export function Preferences({
|
|||
className={classNames({
|
||||
Preferences__button: true,
|
||||
'Preferences__button--general': true,
|
||||
'Preferences__button--selected': page === Page.General,
|
||||
'Preferences__button--selected':
|
||||
page === SettingsPage.General,
|
||||
})}
|
||||
onClick={() => setPage(Page.General)}
|
||||
onClick={() => setPage(SettingsPage.General)}
|
||||
>
|
||||
{i18n('icu:Preferences__button--general')}
|
||||
</button>
|
||||
|
@ -2305,9 +2280,10 @@ export function Preferences({
|
|||
Preferences__button: true,
|
||||
'Preferences__button--appearance': true,
|
||||
'Preferences__button--selected':
|
||||
page === Page.Appearance || page === Page.ChatColor,
|
||||
page === SettingsPage.Appearance ||
|
||||
page === SettingsPage.ChatColor,
|
||||
})}
|
||||
onClick={() => setPage(Page.Appearance)}
|
||||
onClick={() => setPage(SettingsPage.Appearance)}
|
||||
>
|
||||
{i18n('icu:Preferences__button--appearance')}
|
||||
</button>
|
||||
|
@ -2316,9 +2292,9 @@ export function Preferences({
|
|||
className={classNames({
|
||||
Preferences__button: true,
|
||||
'Preferences__button--chats': true,
|
||||
'Preferences__button--selected': page === Page.Chats,
|
||||
'Preferences__button--selected': page === SettingsPage.Chats,
|
||||
})}
|
||||
onClick={() => setPage(Page.Chats)}
|
||||
onClick={() => setPage(SettingsPage.Chats)}
|
||||
>
|
||||
{i18n('icu:Preferences__button--chats')}
|
||||
</button>
|
||||
|
@ -2327,9 +2303,9 @@ export function Preferences({
|
|||
className={classNames({
|
||||
Preferences__button: true,
|
||||
'Preferences__button--calls': true,
|
||||
'Preferences__button--selected': page === Page.Calls,
|
||||
'Preferences__button--selected': page === SettingsPage.Calls,
|
||||
})}
|
||||
onClick={() => setPage(Page.Calls)}
|
||||
onClick={() => setPage(SettingsPage.Calls)}
|
||||
>
|
||||
{i18n('icu:Preferences__button--calls')}
|
||||
</button>
|
||||
|
@ -2338,9 +2314,10 @@ export function Preferences({
|
|||
className={classNames({
|
||||
Preferences__button: true,
|
||||
'Preferences__button--notifications': true,
|
||||
'Preferences__button--selected': page === Page.Notifications,
|
||||
'Preferences__button--selected':
|
||||
page === SettingsPage.Notifications,
|
||||
})}
|
||||
onClick={() => setPage(Page.Notifications)}
|
||||
onClick={() => setPage(SettingsPage.Notifications)}
|
||||
>
|
||||
{i18n('icu:Preferences__button--notifications')}
|
||||
</button>
|
||||
|
@ -2350,9 +2327,9 @@ export function Preferences({
|
|||
Preferences__button: true,
|
||||
'Preferences__button--privacy': true,
|
||||
'Preferences__button--selected':
|
||||
page === Page.Privacy || page === Page.PNP,
|
||||
page === SettingsPage.Privacy || page === SettingsPage.PNP,
|
||||
})}
|
||||
onClick={() => setPage(Page.Privacy)}
|
||||
onClick={() => setPage(SettingsPage.Privacy)}
|
||||
>
|
||||
{i18n('icu:Preferences__button--privacy')}
|
||||
</button>
|
||||
|
@ -2361,9 +2338,10 @@ export function Preferences({
|
|||
className={classNames({
|
||||
Preferences__button: true,
|
||||
'Preferences__button--data-usage': true,
|
||||
'Preferences__button--selected': page === Page.DataUsage,
|
||||
'Preferences__button--selected':
|
||||
page === SettingsPage.DataUsage,
|
||||
})}
|
||||
onClick={() => setPage(Page.DataUsage)}
|
||||
onClick={() => setPage(SettingsPage.DataUsage)}
|
||||
>
|
||||
{i18n('icu:Preferences__button--data-usage')}
|
||||
</button>
|
||||
|
@ -2375,7 +2353,7 @@ export function Preferences({
|
|||
'Preferences__button--backups': true,
|
||||
'Preferences__button--selected': isBackupPage(page),
|
||||
})}
|
||||
onClick={() => setPage(Page.Backups)}
|
||||
onClick={() => setPage(SettingsPage.Backups)}
|
||||
>
|
||||
{i18n('icu:Preferences__button--backups')}
|
||||
</button>
|
||||
|
@ -2388,7 +2366,7 @@ export function Preferences({
|
|||
'Preferences__button--appearance': true,
|
||||
'Preferences__button--selected': isDonationsPage(page),
|
||||
})}
|
||||
onClick={() => setPage(Page.Donations)}
|
||||
onClick={() => setPage(SettingsPage.Donations)}
|
||||
>
|
||||
{i18n('icu:Preferences__button--donate')}
|
||||
</button>
|
||||
|
@ -2399,9 +2377,10 @@ export function Preferences({
|
|||
className={classNames({
|
||||
Preferences__button: true,
|
||||
'Preferences__button--internal': true,
|
||||
'Preferences__button--selected': page === Page.Internal,
|
||||
'Preferences__button--selected':
|
||||
page === SettingsPage.Internal,
|
||||
})}
|
||||
onClick={() => setPage(Page.Internal)}
|
||||
onClick={() => setPage(SettingsPage.Internal)}
|
||||
>
|
||||
{i18n('icu:Preferences__button--internal')}
|
||||
</button>
|
||||
|
|
|
@ -20,7 +20,7 @@ import {
|
|||
import { missingCaseError } from '../util/missingCaseError';
|
||||
import { Button, ButtonVariant } from './Button';
|
||||
import type { PreferencesBackupPage } from '../types/PreferencesBackupPage';
|
||||
import { Page } from './Preferences';
|
||||
import { SettingsPage } from '../types/Nav';
|
||||
import { I18n } from './I18n';
|
||||
import { PreferencesLocalBackups } from './PreferencesLocalBackups';
|
||||
import type { ShowToastAction } from '../state/ducks/toast';
|
||||
|
@ -82,17 +82,17 @@ export function PreferencesBackups({
|
|||
const [isAuthPending, setIsAuthPending] = useState<boolean>(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (page === Page.Backups) {
|
||||
if (page === SettingsPage.Backups) {
|
||||
refreshBackupSubscriptionStatus();
|
||||
} else if (page === Page.BackupsDetails) {
|
||||
} else if (page === SettingsPage.BackupsDetails) {
|
||||
refreshBackupSubscriptionStatus();
|
||||
refreshCloudBackupStatus();
|
||||
}
|
||||
}, [page, refreshBackupSubscriptionStatus, refreshCloudBackupStatus]);
|
||||
|
||||
if (page === Page.BackupsDetails) {
|
||||
if (page === SettingsPage.BackupsDetails) {
|
||||
if (backupSubscriptionStatus.status === 'off') {
|
||||
setPage(Page.Backups);
|
||||
setPage(SettingsPage.Backups);
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
|
@ -110,10 +110,10 @@ export function PreferencesBackups({
|
|||
}
|
||||
|
||||
if (
|
||||
page === Page.LocalBackups ||
|
||||
page === Page.LocalBackupsKeyReference ||
|
||||
page === Page.LocalBackupsSetupFolder ||
|
||||
page === Page.LocalBackupsSetupKey
|
||||
page === SettingsPage.LocalBackups ||
|
||||
page === SettingsPage.LocalBackupsKeyReference ||
|
||||
page === SettingsPage.LocalBackupsSetupFolder ||
|
||||
page === SettingsPage.LocalBackupsSetupKey
|
||||
) {
|
||||
return (
|
||||
<PreferencesLocalBackups
|
||||
|
@ -193,7 +193,7 @@ export function PreferencesBackups({
|
|||
)}
|
||||
>
|
||||
<Button
|
||||
onClick={() => setPage(Page.BackupsDetails)}
|
||||
onClick={() => setPage(SettingsPage.BackupsDetails)}
|
||||
variant={ButtonVariant.Secondary}
|
||||
>
|
||||
{i18n('icu:Preferences__button--manage')}
|
||||
|
@ -246,7 +246,7 @@ export function PreferencesBackups({
|
|||
}
|
||||
}
|
||||
|
||||
setPage(Page.LocalBackups);
|
||||
setPage(SettingsPage.LocalBackups);
|
||||
}}
|
||||
variant={ButtonVariant.Secondary}
|
||||
>
|
||||
|
|
|
@ -9,7 +9,8 @@ import { ListBox, ListBoxItem } from 'react-aria-components';
|
|||
import { getDateTimeFormatter } from '../util/formatTimestamp';
|
||||
|
||||
import type { LocalizerType } from '../types/Util';
|
||||
import { Page, PreferencesContent } from './Preferences';
|
||||
import { PreferencesContent } from './Preferences';
|
||||
import { SettingsPage } from '../types/Nav';
|
||||
import { PreferencesDonateFlow } from './PreferencesDonateFlow';
|
||||
import type {
|
||||
DonationWorkflow,
|
||||
|
@ -39,7 +40,7 @@ type PropsExternalType = {
|
|||
export type PropsDataType = {
|
||||
i18n: LocalizerType;
|
||||
isStaging: boolean;
|
||||
page: Page;
|
||||
page: SettingsPage;
|
||||
workflow: DonationWorkflow | undefined;
|
||||
userAvatarData: ReadonlyArray<AvatarDataType>;
|
||||
color?: AvatarColorType;
|
||||
|
@ -62,26 +63,26 @@ export type PropsDataType = {
|
|||
|
||||
type PropsActionType = {
|
||||
clearWorkflow: () => void;
|
||||
setPage: (page: Page) => void;
|
||||
setPage: (page: SettingsPage) => void;
|
||||
submitDonation: (payload: SubmitDonationType) => void;
|
||||
};
|
||||
|
||||
export type PropsType = PropsDataType & PropsActionType & PropsExternalType;
|
||||
|
||||
type DonationPage =
|
||||
| Page.Donations
|
||||
| Page.DonationsDonateFlow
|
||||
| Page.DonationsReceiptList;
|
||||
| SettingsPage.Donations
|
||||
| SettingsPage.DonationsDonateFlow
|
||||
| SettingsPage.DonationsReceiptList;
|
||||
|
||||
type PreferencesHomeProps = PropsType & {
|
||||
navigateToPage: (newPage: Page) => void;
|
||||
navigateToPage: (newPage: SettingsPage) => void;
|
||||
};
|
||||
|
||||
function isDonationPage(page: Page): page is DonationPage {
|
||||
function isDonationPage(page: SettingsPage): page is DonationPage {
|
||||
return (
|
||||
page === Page.Donations ||
|
||||
page === Page.DonationsDonateFlow ||
|
||||
page === Page.DonationsReceiptList
|
||||
page === SettingsPage.Donations ||
|
||||
page === SettingsPage.DonationsDonateFlow ||
|
||||
page === SettingsPage.DonationsReceiptList
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -147,7 +148,7 @@ function DonationsHome({
|
|||
variant={ButtonVariant.Primary}
|
||||
size={ButtonSize.Medium}
|
||||
onClick={() => {
|
||||
setPage(Page.DonationsDonateFlow);
|
||||
setPage(SettingsPage.DonationsDonateFlow);
|
||||
}}
|
||||
>
|
||||
{i18n('icu:PreferencesDonations__donate-button')}
|
||||
|
@ -161,7 +162,7 @@ function DonationsHome({
|
|||
<ListBoxItem
|
||||
className="PreferencesDonations__list-item"
|
||||
onAction={() => {
|
||||
navigateToPage(Page.DonationsReceiptList);
|
||||
navigateToPage(SettingsPage.DonationsReceiptList);
|
||||
}}
|
||||
>
|
||||
<span className="PreferencesDonations__list-item__icon PreferencesDonations__list-item__icon--receipts" />
|
||||
|
@ -418,7 +419,7 @@ export function PreferencesDonations({
|
|||
showToast,
|
||||
}: PropsType): JSX.Element | null {
|
||||
const navigateToPage = useCallback(
|
||||
(newPage: Page) => {
|
||||
(newPage: SettingsPage) => {
|
||||
setPage(newPage);
|
||||
},
|
||||
[setPage]
|
||||
|
@ -429,7 +430,7 @@ export function PreferencesDonations({
|
|||
}
|
||||
|
||||
let content;
|
||||
if (page === Page.DonationsDonateFlow) {
|
||||
if (page === SettingsPage.DonationsDonateFlow) {
|
||||
// DonateFlow has to control Back button to switch between CC form and Amount picker
|
||||
return (
|
||||
<PreferencesDonateFlow
|
||||
|
@ -440,11 +441,11 @@ export function PreferencesDonations({
|
|||
workflow={workflow}
|
||||
clearWorkflow={clearWorkflow}
|
||||
submitDonation={submitDonation}
|
||||
onBack={() => setPage(Page.Donations)}
|
||||
onBack={() => setPage(SettingsPage.Donations)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
if (page === Page.Donations) {
|
||||
if (page === SettingsPage.Donations) {
|
||||
content = (
|
||||
<DonationsHome
|
||||
contentsRef={contentsRef}
|
||||
|
@ -468,7 +469,7 @@ export function PreferencesDonations({
|
|||
submitDonation={submitDonation}
|
||||
/>
|
||||
);
|
||||
} else if (page === Page.DonationsReceiptList) {
|
||||
} else if (page === SettingsPage.DonationsReceiptList) {
|
||||
content = (
|
||||
<PreferencesReceiptList
|
||||
i18n={i18n}
|
||||
|
@ -482,15 +483,15 @@ export function PreferencesDonations({
|
|||
|
||||
let title: string | undefined;
|
||||
let backButton: JSX.Element | undefined;
|
||||
if (page === Page.Donations) {
|
||||
if (page === SettingsPage.Donations) {
|
||||
title = i18n('icu:Preferences__DonateTitle');
|
||||
} else if (page === Page.DonationsReceiptList) {
|
||||
} else if (page === SettingsPage.DonationsReceiptList) {
|
||||
title = i18n('icu:PreferencesDonations__receipts');
|
||||
backButton = (
|
||||
<button
|
||||
aria-label={i18n('icu:goBack')}
|
||||
className="Preferences__back-icon"
|
||||
onClick={() => setPage(Page.Donations)}
|
||||
onClick={() => setPage(SettingsPage.Donations)}
|
||||
type="button"
|
||||
/>
|
||||
);
|
||||
|
|
|
@ -24,7 +24,7 @@ import {
|
|||
} from './PreferencesBackups';
|
||||
import { I18n } from './I18n';
|
||||
import type { PreferencesBackupPage } from '../types/PreferencesBackupPage';
|
||||
import { Page } from './Preferences';
|
||||
import { SettingsPage } from '../types/Nav';
|
||||
import { ToastType } from '../types/Toast';
|
||||
import type { ShowToastAction } from '../state/ducks/toast';
|
||||
import { Modal } from './Modal';
|
||||
|
@ -73,7 +73,7 @@ export function PreferencesLocalBackups({
|
|||
);
|
||||
}
|
||||
|
||||
const isReferencingBackupKey = page === Page.LocalBackupsKeyReference;
|
||||
const isReferencingBackupKey = page === SettingsPage.LocalBackupsKeyReference;
|
||||
if (!backupKeyViewed || isReferencingBackupKey) {
|
||||
strictAssert(accountEntropyPool, 'AEP is required for backup key viewer');
|
||||
|
||||
|
@ -84,7 +84,7 @@ export function PreferencesLocalBackups({
|
|||
isReferencing={isReferencingBackupKey}
|
||||
onBackupKeyViewed={() => {
|
||||
if (backupKeyViewed) {
|
||||
setPage(Page.LocalBackups);
|
||||
setPage(SettingsPage.LocalBackups);
|
||||
} else {
|
||||
onBackupKeyViewedChange(true);
|
||||
}
|
||||
|
@ -158,7 +158,7 @@ export function PreferencesLocalBackups({
|
|||
setIsAuthPending(true);
|
||||
const result = await promptOSAuth('view-aep');
|
||||
if (result === 'success' || result === 'unsupported') {
|
||||
setPage(Page.LocalBackupsKeyReference);
|
||||
setPage(SettingsPage.LocalBackupsKeyReference);
|
||||
} else {
|
||||
setAuthError(result);
|
||||
}
|
||||
|
|
|
@ -8,7 +8,9 @@ import casual from 'casual';
|
|||
import { v4 as generateUuid } from 'uuid';
|
||||
|
||||
import type { PropsType } from './ProfileEditor';
|
||||
import { EditState, ProfileEditor } from './ProfileEditor';
|
||||
|
||||
import { ProfileEditorPage } from '../types/Nav';
|
||||
import { ProfileEditor } from './ProfileEditor';
|
||||
import { UsernameEditor } from './UsernameEditor';
|
||||
import {
|
||||
UsernameEditState,
|
||||
|
@ -51,7 +53,7 @@ export default {
|
|||
conversationId: generateUuid(),
|
||||
color: getRandomColor(),
|
||||
deleteAvatarFromDisk: action('deleteAvatarFromDisk'),
|
||||
editState: EditState.None,
|
||||
editState: ProfileEditorPage.None,
|
||||
familyName: casual.last_name,
|
||||
firstName: casual.first_name,
|
||||
i18n,
|
||||
|
|
|
@ -51,6 +51,7 @@ import { FunEmojiPickerButton } from './fun/FunButton';
|
|||
import { isFunPickerEnabled } from './fun/isFunPickerEnabled';
|
||||
import { useFunEmojiLocalizer } from './fun/useFunEmojiLocalizer';
|
||||
import { PreferencesContent } from './Preferences';
|
||||
import { ProfileEditorPage } from '../types/Nav';
|
||||
|
||||
import type { AvatarColorType } from '../types/Colors';
|
||||
import type {
|
||||
|
@ -73,15 +74,6 @@ import type { EmojiVariantKey } from './fun/data/emojis';
|
|||
import type { FunEmojiSelection } from './fun/panels/FunPanelEmojis';
|
||||
import { useConfirmDiscard } from '../hooks/useConfirmDiscard';
|
||||
|
||||
export enum EditState {
|
||||
None = 'None',
|
||||
BetterAvatar = 'BetterAvatar',
|
||||
ProfileName = 'ProfileName',
|
||||
Bio = 'Bio',
|
||||
Username = 'Username',
|
||||
UsernameLink = 'UsernameLink',
|
||||
}
|
||||
|
||||
type PropsExternalType = {
|
||||
onProfileChanged: (
|
||||
profileData: ProfileDataType,
|
||||
|
@ -100,7 +92,7 @@ export type PropsDataType = {
|
|||
firstName: string;
|
||||
hasCompletedUsernameLinkOnboarding: boolean;
|
||||
i18n: LocalizerType;
|
||||
editState: EditState;
|
||||
editState: ProfileEditorPage;
|
||||
profileAvatarUrl?: string;
|
||||
userAvatarData: ReadonlyArray<AvatarDataType>;
|
||||
username?: string;
|
||||
|
@ -123,7 +115,7 @@ type PropsActionType = {
|
|||
setUsernameLinkColor: (color: number) => void;
|
||||
resetUsernameLink: () => void;
|
||||
deleteUsername: () => void;
|
||||
setEditState: (editState: EditState) => void;
|
||||
setEditState: (editState: ProfileEditorPage) => void;
|
||||
showToast: ShowToastAction;
|
||||
openUsernameReservationModal: () => void;
|
||||
};
|
||||
|
@ -219,13 +211,13 @@ export function ProfileEditor({
|
|||
tryClose,
|
||||
});
|
||||
|
||||
const TITLES_BY_EDIT_STATE: Record<EditState, string | undefined> = {
|
||||
[EditState.BetterAvatar]: i18n('icu:ProfileEditorModal--avatar'),
|
||||
[EditState.Bio]: i18n('icu:ProfileEditorModal--about'),
|
||||
[EditState.None]: i18n('icu:ProfileEditorModal--profile'),
|
||||
[EditState.ProfileName]: i18n('icu:ProfileEditorModal--name'),
|
||||
[EditState.Username]: i18n('icu:ProfileEditorModal--username'),
|
||||
[EditState.UsernameLink]: i18n('icu:ProfileEditorModal--sharing'),
|
||||
const TITLES_BY_EDIT_STATE: Record<ProfileEditorPage, string | undefined> = {
|
||||
[ProfileEditorPage.BetterAvatar]: i18n('icu:ProfileEditorModal--avatar'),
|
||||
[ProfileEditorPage.Bio]: i18n('icu:ProfileEditorModal--about'),
|
||||
[ProfileEditorPage.None]: i18n('icu:ProfileEditorModal--profile'),
|
||||
[ProfileEditorPage.ProfileName]: i18n('icu:ProfileEditorModal--name'),
|
||||
[ProfileEditorPage.Username]: i18n('icu:ProfileEditorModal--username'),
|
||||
[ProfileEditorPage.UsernameLink]: i18n('icu:ProfileEditorModal--sharing'),
|
||||
};
|
||||
|
||||
// This is here to avoid component re-render jitters in the time it takes
|
||||
|
@ -275,7 +267,7 @@ export function ProfileEditor({
|
|||
|
||||
// To make AvatarEditor re-render less often
|
||||
const handleBack = useCallback(() => {
|
||||
setEditState(EditState.None);
|
||||
setEditState(ProfileEditorPage.None);
|
||||
}, [setEditState]);
|
||||
|
||||
const handleEmojiPickerOpenChange = useCallback((open: boolean) => {
|
||||
|
@ -379,7 +371,7 @@ export function ProfileEditor({
|
|||
|
||||
let content: JSX.Element;
|
||||
|
||||
if (editState === EditState.BetterAvatar) {
|
||||
if (editState === ProfileEditorPage.BetterAvatar) {
|
||||
content = (
|
||||
<AvatarEditor
|
||||
avatarColor={color || AvatarColors[0]}
|
||||
|
@ -396,7 +388,7 @@ export function ProfileEditor({
|
|||
saveAvatarToDisk={saveAvatarToDisk}
|
||||
/>
|
||||
);
|
||||
} else if (editState === EditState.ProfileName) {
|
||||
} else if (editState === ProfileEditorPage.ProfileName) {
|
||||
const shouldDisableSave =
|
||||
!stagedProfile.firstName ||
|
||||
(stagedProfile.firstName === fullName.firstName &&
|
||||
|
@ -458,7 +450,7 @@ export function ProfileEditor({
|
|||
</div>
|
||||
</>
|
||||
);
|
||||
} else if (editState === EditState.Bio) {
|
||||
} else if (editState === ProfileEditorPage.Bio) {
|
||||
const shouldDisableSave =
|
||||
stagedProfile.aboutText === fullBio.aboutText &&
|
||||
stagedProfile.aboutEmoji === fullBio.aboutEmoji;
|
||||
|
@ -587,11 +579,11 @@ export function ProfileEditor({
|
|||
</div>
|
||||
</>
|
||||
);
|
||||
} else if (editState === EditState.Username) {
|
||||
} else if (editState === ProfileEditorPage.Username) {
|
||||
content = renderUsernameEditor({
|
||||
onClose: handleBack,
|
||||
});
|
||||
} else if (editState === EditState.UsernameLink) {
|
||||
} else if (editState === ProfileEditorPage.UsernameLink) {
|
||||
content = (
|
||||
<UsernameLinkEditor
|
||||
i18n={i18n}
|
||||
|
@ -604,10 +596,10 @@ export function ProfileEditor({
|
|||
resetUsernameLink={resetUsernameLink}
|
||||
saveAttachment={saveAttachment}
|
||||
showToast={showToast}
|
||||
onBack={() => setEditState(EditState.None)}
|
||||
onBack={() => setEditState(ProfileEditorPage.None)}
|
||||
/>
|
||||
);
|
||||
} else if (editState === EditState.None) {
|
||||
} else if (editState === ProfileEditorPage.None) {
|
||||
let actions: JSX.Element | undefined;
|
||||
let alwaysShowActions = false;
|
||||
|
||||
|
@ -696,7 +688,7 @@ export function ProfileEditor({
|
|||
return;
|
||||
}
|
||||
|
||||
setEditState(EditState.UsernameLink);
|
||||
setEditState(ProfileEditorPage.UsernameLink);
|
||||
}}
|
||||
alwaysShowActions
|
||||
actions={linkActions}
|
||||
|
@ -734,7 +726,7 @@ export function ProfileEditor({
|
|||
}
|
||||
|
||||
openUsernameReservationModal();
|
||||
setEditState(EditState.Username);
|
||||
setEditState(ProfileEditorPage.Username);
|
||||
}}
|
||||
alwaysShowActions={alwaysShowActions}
|
||||
actions={actions}
|
||||
|
@ -758,7 +750,7 @@ export function ProfileEditor({
|
|||
i18n={i18n}
|
||||
onAvatarLoaded={handleAvatarLoaded}
|
||||
onClick={() => {
|
||||
setEditState(EditState.BetterAvatar);
|
||||
setEditState(ProfileEditorPage.BetterAvatar);
|
||||
}}
|
||||
style={{
|
||||
height: 80,
|
||||
|
@ -768,7 +760,7 @@ export function ProfileEditor({
|
|||
<div className="ProfileEditor__EditPhotoContainer">
|
||||
<Button
|
||||
onClick={() => {
|
||||
setEditState(EditState.BetterAvatar);
|
||||
setEditState(ProfileEditorPage.BetterAvatar);
|
||||
}}
|
||||
variant={ButtonVariant.Secondary}
|
||||
className="ProfileEditor__EditPhoto"
|
||||
|
@ -783,7 +775,7 @@ export function ProfileEditor({
|
|||
}
|
||||
label={<UserText text={getFullNameText()} />}
|
||||
onClick={() => {
|
||||
setEditState(EditState.ProfileName);
|
||||
setEditState(ProfileEditorPage.ProfileName);
|
||||
}}
|
||||
/>
|
||||
<PanelRow
|
||||
|
@ -805,7 +797,7 @@ export function ProfileEditor({
|
|||
/>
|
||||
}
|
||||
onClick={() => {
|
||||
setEditState(EditState.Bio);
|
||||
setEditState(ProfileEditorPage.Bio);
|
||||
}}
|
||||
/>
|
||||
<div className="ProfileEditor__info">
|
||||
|
@ -819,7 +811,7 @@ export function ProfileEditor({
|
|||
}
|
||||
|
||||
const backButton =
|
||||
editState !== EditState.None ? (
|
||||
editState !== ProfileEditorPage.None ? (
|
||||
<button
|
||||
aria-label={i18n('icu:goBack')}
|
||||
className="Preferences__back-icon"
|
||||
|
@ -862,7 +854,7 @@ export function ProfileEditor({
|
|||
{
|
||||
action: () => {
|
||||
setIsResettingUsernameLink(false);
|
||||
setEditState(EditState.UsernameLink);
|
||||
setEditState(ProfileEditorPage.UsernameLink);
|
||||
},
|
||||
style: 'affirmative',
|
||||
text: i18n('icu:UsernameLinkModalBody__error__fix-now'),
|
||||
|
@ -885,7 +877,7 @@ export function ProfileEditor({
|
|||
style: 'affirmative',
|
||||
action: () => {
|
||||
openUsernameReservationModal();
|
||||
setEditState(EditState.Username);
|
||||
setEditState(ProfileEditorPage.Username);
|
||||
},
|
||||
},
|
||||
]}
|
||||
|
|
|
@ -100,6 +100,10 @@ function getToast(toastType: ToastType): AnyToast {
|
|||
};
|
||||
case ToastType.DeleteForEveryoneFailed:
|
||||
return { toastType: ToastType.DeleteForEveryoneFailed };
|
||||
case ToastType.DonationCompleted:
|
||||
return { toastType: ToastType.DonationCompleted };
|
||||
case ToastType.DonationProcessing:
|
||||
return { toastType: ToastType.DonationProcessing };
|
||||
case ToastType.Error:
|
||||
return { toastType: ToastType.Error };
|
||||
case ToastType.Expired:
|
||||
|
@ -252,6 +256,8 @@ export default {
|
|||
},
|
||||
},
|
||||
args: {
|
||||
changeLocation: action('changeLocation'),
|
||||
clearDonation: action('clearDonation'),
|
||||
hideToast: action('hideToast'),
|
||||
openFileInFolder: action('openFileInFolder'),
|
||||
onShowDebugLog: action('onShowDebugLog'),
|
||||
|
|
|
@ -5,20 +5,25 @@ import classNames from 'classnames';
|
|||
import React from 'react';
|
||||
import { createPortal } from 'react-dom';
|
||||
|
||||
import type { LocalizerType } from '../types/Util';
|
||||
import { SECOND } from '../util/durations';
|
||||
import { Toast } from './Toast';
|
||||
import { WidthBreakpoint } from './_util';
|
||||
import { UsernameMegaphone } from './UsernameMegaphone';
|
||||
import { assertDev } from '../util/assert';
|
||||
import { missingCaseError } from '../util/missingCaseError';
|
||||
import type { AnyToast } from '../types/Toast';
|
||||
import { ToastType } from '../types/Toast';
|
||||
import type { AnyActionableMegaphone } from '../types/Megaphone';
|
||||
import { MegaphoneType } from '../types/Megaphone';
|
||||
import { AttachmentNotAvailableModalType } from './AttachmentNotAvailableModal';
|
||||
import { NavTab, SettingsPage } from '../types/Nav';
|
||||
|
||||
import type { LocalizerType } from '../types/Util';
|
||||
import type { AnyToast } from '../types/Toast';
|
||||
import type { AnyActionableMegaphone } from '../types/Megaphone';
|
||||
import type { Location } from '../types/Nav';
|
||||
|
||||
export type PropsType = {
|
||||
changeLocation: (newLocation: Location) => unknown;
|
||||
clearDonation: () => unknown;
|
||||
hideToast: () => unknown;
|
||||
i18n: LocalizerType;
|
||||
openFileInFolder: (target: string) => unknown;
|
||||
|
@ -28,6 +33,7 @@ export type PropsType = {
|
|||
conversationId: string,
|
||||
options?: { wasPinned?: boolean }
|
||||
) => unknown;
|
||||
setDidResumeDonation: (didResume: boolean) => unknown;
|
||||
showAttachmentNotAvailableModal: (
|
||||
type: AttachmentNotAvailableModalType
|
||||
) => void;
|
||||
|
@ -42,11 +48,14 @@ export type PropsType = {
|
|||
const SHORT_TIMEOUT = 3 * SECOND;
|
||||
|
||||
export function renderToast({
|
||||
changeLocation,
|
||||
clearDonation,
|
||||
hideToast,
|
||||
i18n,
|
||||
openFileInFolder,
|
||||
onShowDebugLog,
|
||||
onUndoArchive,
|
||||
setDidResumeDonation,
|
||||
showAttachmentNotAvailableModal,
|
||||
OS,
|
||||
toast,
|
||||
|
@ -271,6 +280,54 @@ export function renderToast({
|
|||
);
|
||||
}
|
||||
|
||||
if (toastType === ToastType.DonationCompleted) {
|
||||
return (
|
||||
<Toast
|
||||
autoDismissDisabled
|
||||
onClose={() => {
|
||||
clearDonation();
|
||||
hideToast();
|
||||
}}
|
||||
toastAction={{
|
||||
label: i18n('icu:view'),
|
||||
onClick: () =>
|
||||
changeLocation({
|
||||
tab: NavTab.Settings,
|
||||
details: {
|
||||
page: SettingsPage.Donations,
|
||||
},
|
||||
}),
|
||||
}}
|
||||
>
|
||||
{i18n('icu:Donations__Toast__Completed')}
|
||||
</Toast>
|
||||
);
|
||||
}
|
||||
|
||||
if (toastType === ToastType.DonationProcessing) {
|
||||
return (
|
||||
<Toast
|
||||
onClose={() => {
|
||||
setDidResumeDonation(false);
|
||||
hideToast();
|
||||
}}
|
||||
toastAction={{
|
||||
label: i18n('icu:view'),
|
||||
onClick: () => {
|
||||
changeLocation({
|
||||
tab: NavTab.Settings,
|
||||
details: {
|
||||
page: SettingsPage.DonationsDonateFlow,
|
||||
},
|
||||
});
|
||||
},
|
||||
}}
|
||||
>
|
||||
{i18n('icu:Donations__Toast__Processing')}
|
||||
</Toast>
|
||||
);
|
||||
}
|
||||
|
||||
if (toastType === ToastType.Error) {
|
||||
return (
|
||||
<Toast
|
||||
|
|
|
@ -16,7 +16,7 @@ import { getDefaultConversation } from '../../../test-helpers/getDefaultConversa
|
|||
import { makeFakeLookupConversationWithoutServiceId } from '../../../test-helpers/fakeLookupConversationWithoutServiceId';
|
||||
import { ThemeType } from '../../../types/Util';
|
||||
import { DurationInSeconds } from '../../../util/durations';
|
||||
import { NavTab } from '../../../state/ducks/nav';
|
||||
import { NavTab } from '../../../types/Nav';
|
||||
import { getFakeCallHistoryGroup } from '../../../test-helpers/getFakeCallHistoryGroup';
|
||||
|
||||
const { i18n } = window.SignalContext;
|
||||
|
|
|
@ -53,7 +53,7 @@ import { isConversationMuted } from '../../../util/isConversationMuted';
|
|||
import { ConversationDetailsGroups } from './ConversationDetailsGroups';
|
||||
import { PanelType } from '../../../types/Panels';
|
||||
import { type CallHistoryGroup } from '../../../types/CallDisposition';
|
||||
import { NavTab } from '../../../state/ducks/nav';
|
||||
import { NavTab } from '../../../types/Nav';
|
||||
import { ContextMenu } from '../../ContextMenu';
|
||||
import { canHaveNicknameAndNote } from '../../../util/nicknames';
|
||||
import { CallHistoryGroupPanelSection } from './CallHistoryGroupPanelSection';
|
||||
|
|
|
@ -3,10 +3,11 @@
|
|||
|
||||
import { createLogger } from '../logging/log';
|
||||
|
||||
import type { Location } from '../state/ducks/nav';
|
||||
import { SECOND } from '../util/durations';
|
||||
import { sleep } from '../util/sleep';
|
||||
|
||||
import type { Location } from '../types/Nav';
|
||||
|
||||
const log = createLogger('BeforeNavigate');
|
||||
|
||||
export enum BeforeNavigateResponse {
|
||||
|
|
|
@ -13,10 +13,7 @@ import {
|
|||
getDistributionListsForRedux,
|
||||
loadDistributionLists,
|
||||
} from './distributionListLoader';
|
||||
import {
|
||||
getDonationReceiptsForRedux,
|
||||
loadDonationReceipts,
|
||||
} from './donationReceiptsLoader';
|
||||
import { getDonationsForRedux, loadDonationReceipts } from './donationsLoader';
|
||||
import { getStoriesForRedux, loadStories } from './storyLoader';
|
||||
import { getUserDataForRedux, loadUserData } from './userLoader';
|
||||
import {
|
||||
|
@ -67,7 +64,7 @@ export function getParametersForRedux(): ReduxInitData {
|
|||
callHistory: getCallsHistoryForRedux(),
|
||||
callHistoryUnreadCount: getCallsHistoryUnreadCountForRedux(),
|
||||
callLinks: getCallLinksForRedux(),
|
||||
donations: getDonationReceiptsForRedux(),
|
||||
donations: getDonationsForRedux(),
|
||||
gifs: getGifsStateForRedux(),
|
||||
mainWindowStats,
|
||||
menuOptions,
|
||||
|
|
|
@ -40,6 +40,8 @@ import type {
|
|||
ReceiptContext,
|
||||
StripeDonationAmount,
|
||||
} from '../types/Donations';
|
||||
import { ToastType } from '../types/Toast';
|
||||
import { NavTab, SettingsPage } from '../types/Nav';
|
||||
|
||||
const { createDonationReceipt } = DataWriter;
|
||||
|
||||
|
@ -63,9 +65,36 @@ const MAX_CREDENTIAL_EXPIRATION_IN_DAYS = 90;
|
|||
let runDonationAbortController: AbortController | undefined;
|
||||
let isInternalDonationInProgress = false;
|
||||
let isDonationInProgress = false;
|
||||
let isInitialized = false;
|
||||
|
||||
// Public API
|
||||
|
||||
// Starting everything up
|
||||
|
||||
export async function initialize(): Promise<void> {
|
||||
if (isInitialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
isInitialized = true;
|
||||
|
||||
const workflow = _getWorkflowFromRedux();
|
||||
if (!workflow) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (didResumeWorkflowAtStartup() && !isDonationPageVisible()) {
|
||||
log.info(
|
||||
'initialize: We resumed at startup and donation page not visible. Showing processing toast.'
|
||||
);
|
||||
window.reduxActions.toast.showToast({
|
||||
toastType: ToastType.DonationProcessing,
|
||||
});
|
||||
}
|
||||
|
||||
await _runDonationWorkflow();
|
||||
}
|
||||
|
||||
// These are the four moments the user provides input to the donation workflow. So,
|
||||
// UI calls these methods directly; everything else happens automatically.
|
||||
|
||||
|
@ -190,13 +219,11 @@ export async function _saveAndRunWorkflow(
|
|||
log.info(`${logId}: No need to start workflow; it's been cleared`);
|
||||
}
|
||||
|
||||
await runDonationWorkflow();
|
||||
await _runDonationWorkflow();
|
||||
}
|
||||
|
||||
// There's one place where this is called outside this file - when starting up, in the
|
||||
// onEmpty handler in background.ts.
|
||||
export async function runDonationWorkflow(): Promise<void> {
|
||||
let logId = 'runDonationWorkflow';
|
||||
export async function _runDonationWorkflow(): Promise<void> {
|
||||
let logId = '_runDonationWorkflow';
|
||||
|
||||
let totalCount = 0;
|
||||
let backoffCount = 0;
|
||||
|
@ -283,6 +310,15 @@ export async function runDonationWorkflow(): Promise<void> {
|
|||
updated = await _redeemReceipt(existing);
|
||||
// continuing
|
||||
} else if (type === donationStateSchema.Enum.DONE) {
|
||||
if (!isDonationPageVisible()) {
|
||||
log.info(
|
||||
`${logId}: Donation page not visible. Showing complete toast.`
|
||||
);
|
||||
window.reduxActions.toast.showToast({
|
||||
toastType: ToastType.DonationCompleted,
|
||||
});
|
||||
}
|
||||
|
||||
log.info(`${logId}: Workflow is complete. Returning.`);
|
||||
return;
|
||||
} else {
|
||||
|
@ -789,6 +825,19 @@ async function saveReceipt(workflow: DonationWorkflow, logId: string) {
|
|||
log.info(`${logId}: Successfully saved receipt`);
|
||||
}
|
||||
|
||||
function didResumeWorkflowAtStartup() {
|
||||
return window.reduxStore.getState().donations.didResumeWorkflowAtStartup;
|
||||
}
|
||||
|
||||
function isDonationPageVisible() {
|
||||
const { selectedLocation } = window.reduxStore.getState().nav;
|
||||
return (
|
||||
selectedLocation.tab === NavTab.Settings &&
|
||||
(selectedLocation.details.page === SettingsPage.DonationsDonateFlow ||
|
||||
selectedLocation.details.page === SettingsPage.DonationsReceiptList)
|
||||
);
|
||||
}
|
||||
|
||||
// Working with zkgroup receipts
|
||||
|
||||
function getServerPublicParams(): ServerPublicParams {
|
||||
|
|
|
@ -15,13 +15,16 @@ export async function loadDonationReceipts(): Promise<void> {
|
|||
donationReceipts = await DataReader.getAllDonationReceipts();
|
||||
}
|
||||
|
||||
export function getDonationReceiptsForRedux(): DonationsStateType {
|
||||
export function getDonationsForRedux(): DonationsStateType {
|
||||
strictAssert(
|
||||
donationReceipts != null,
|
||||
'donation receipts have not been loaded'
|
||||
);
|
||||
const currentWorkflow = _getWorkflowFromStorage();
|
||||
|
||||
return {
|
||||
currentWorkflow: _getWorkflowFromStorage(),
|
||||
currentWorkflow,
|
||||
didResumeWorkflowAtStartup: Boolean(currentWorkflow),
|
||||
lastError: undefined,
|
||||
receipts: donationReceipts,
|
||||
};
|
|
@ -180,12 +180,8 @@ import {
|
|||
MESSAGE_MAX_EDIT_COUNT,
|
||||
} from '../../util/canEditMessage';
|
||||
import type { ChangeLocationAction } from './nav';
|
||||
import {
|
||||
CHANGE_LOCATION,
|
||||
NavTab,
|
||||
changeLocation,
|
||||
actions as navActions,
|
||||
} from './nav';
|
||||
import { CHANGE_LOCATION, changeLocation, actions as navActions } from './nav';
|
||||
import { NavTab, ProfileEditorPage, SettingsPage } from '../../types/Nav';
|
||||
import { sortByMessageOrder } from '../../types/ForwardDraft';
|
||||
import { getAddedByForOurPendingInvitation } from '../../util/getAddedByForOurPendingInvitation';
|
||||
import {
|
||||
|
@ -221,8 +217,6 @@ import { markFailed } from '../../test-node/util/messageFailures';
|
|||
import { cleanupMessages } from '../../util/cleanup';
|
||||
import { MessageModel } from '../../models/messages';
|
||||
import type { ConversationModel } from '../../models/conversations';
|
||||
import { EditState } from '../../components/ProfileEditor';
|
||||
import { Page } from '../../components/Preferences';
|
||||
import { MessageRequestResponseSource } from '../../types/MessageRequestResponseEvent';
|
||||
|
||||
const log = createLogger('conversations');
|
||||
|
@ -2268,8 +2262,8 @@ function myProfileChanged(
|
|||
changeLocation({
|
||||
tab: NavTab.Settings,
|
||||
details: {
|
||||
page: Page.Profile,
|
||||
state: EditState.None,
|
||||
page: SettingsPage.Profile,
|
||||
state: ProfileEditorPage.None,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
@ -8,6 +8,8 @@ import { useBoundActions } from '../../hooks/useBoundActions';
|
|||
import { createLogger } from '../../logging/log';
|
||||
import * as Errors from '../../types/errors';
|
||||
import { isStagingServer } from '../../util/isStagingServer';
|
||||
import { DataWriter } from '../../sql/Client';
|
||||
import * as donations from '../../services/donations';
|
||||
|
||||
import type { BoundActionCreatorsMapObject } from '../../hooks/useBoundActions';
|
||||
import type {
|
||||
|
@ -18,8 +20,7 @@ import type {
|
|||
StripeDonationAmount,
|
||||
} from '../../types/Donations';
|
||||
import type { StateType as RootStateType } from '../reducer';
|
||||
import { DataWriter } from '../../sql/Client';
|
||||
import * as donations from '../../services/donations';
|
||||
import { drop } from '../../util/drop';
|
||||
|
||||
const log = createLogger('donations');
|
||||
|
||||
|
@ -29,6 +30,7 @@ export type DonationsStateType = ReadonlyDeep<{
|
|||
currentWorkflow: DonationWorkflow | undefined;
|
||||
lastError: DonationErrorType | undefined;
|
||||
receipts: Array<DonationReceipt>;
|
||||
didResumeWorkflowAtStartup: boolean;
|
||||
}>;
|
||||
|
||||
// Actions
|
||||
|
@ -37,12 +39,18 @@ export const ADD_RECEIPT = 'donations/ADD_RECEIPT';
|
|||
export const SUBMIT_DONATION = 'donations/SUBMIT_DONATION';
|
||||
export const UPDATE_WORKFLOW = 'donations/UPDATE_WORKFLOW';
|
||||
export const UPDATE_LAST_ERROR = 'donations/UPDATE_LAST_ERROR';
|
||||
export const SET_DID_RESUME = 'donations/SET_DID_RESUME';
|
||||
|
||||
export type AddReceiptAction = ReadonlyDeep<{
|
||||
type: typeof ADD_RECEIPT;
|
||||
payload: { receipt: DonationReceipt };
|
||||
}>;
|
||||
|
||||
export type SetDidResumeAction = ReadonlyDeep<{
|
||||
type: typeof SET_DID_RESUME;
|
||||
payload: boolean;
|
||||
}>;
|
||||
|
||||
export type SubmitDonationAction = ReadonlyDeep<{
|
||||
type: typeof SUBMIT_DONATION;
|
||||
payload: SubmitDonationType;
|
||||
|
@ -60,6 +68,7 @@ export type UpdateWorkflowAction = ReadonlyDeep<{
|
|||
|
||||
export type DonationsActionType = ReadonlyDeep<
|
||||
| AddReceiptAction
|
||||
| SetDidResumeAction
|
||||
| SubmitDonationAction
|
||||
| UpdateLastErrorAction
|
||||
| UpdateWorkflowAction
|
||||
|
@ -97,6 +106,13 @@ function internalAddDonationReceipt(
|
|||
};
|
||||
}
|
||||
|
||||
function setDidResume(didResume: boolean): SetDidResumeAction {
|
||||
return {
|
||||
type: SET_DID_RESUME,
|
||||
payload: didResume,
|
||||
};
|
||||
}
|
||||
|
||||
export type SubmitDonationType = ReadonlyDeep<{
|
||||
currencyType: string;
|
||||
paymentAmount: StripeDonationAmount;
|
||||
|
@ -132,6 +148,8 @@ function submitDonation({
|
|||
}
|
||||
|
||||
function clearWorkflow(): UpdateWorkflowAction {
|
||||
drop(donations.clearDonation());
|
||||
|
||||
return {
|
||||
type: UPDATE_WORKFLOW,
|
||||
payload: { nextWorkflow: undefined },
|
||||
|
@ -160,6 +178,7 @@ export const actions = {
|
|||
addReceipt,
|
||||
clearWorkflow,
|
||||
internalAddDonationReceipt,
|
||||
setDidResume,
|
||||
submitDonation,
|
||||
updateLastError,
|
||||
updateWorkflow,
|
||||
|
@ -174,6 +193,7 @@ export const useDonationsActions = (): BoundActionCreatorsMapObject<
|
|||
export function getEmptyState(): DonationsStateType {
|
||||
return {
|
||||
currentWorkflow: undefined,
|
||||
didResumeWorkflowAtStartup: false,
|
||||
lastError: undefined,
|
||||
receipts: [],
|
||||
};
|
||||
|
@ -190,6 +210,13 @@ export function reducer(
|
|||
};
|
||||
}
|
||||
|
||||
if (action.type === SET_DID_RESUME) {
|
||||
return {
|
||||
...state,
|
||||
didResumeWorkflowAtStartup: action.payload,
|
||||
};
|
||||
}
|
||||
|
||||
if (action.type === UPDATE_LAST_ERROR) {
|
||||
return {
|
||||
...state,
|
||||
|
@ -198,9 +225,11 @@ export function reducer(
|
|||
}
|
||||
|
||||
if (action.type === UPDATE_WORKFLOW) {
|
||||
const { nextWorkflow } = action.payload;
|
||||
|
||||
return {
|
||||
...state,
|
||||
currentWorkflow: action.payload.nextWorkflow,
|
||||
currentWorkflow: nextWorkflow,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -6,38 +6,19 @@ import type { ThunkAction } from 'redux-thunk';
|
|||
|
||||
import { createLogger } from '../../logging/log';
|
||||
import { useBoundActions } from '../../hooks/useBoundActions';
|
||||
import { Page } from '../../components/Preferences';
|
||||
import { NavTab, SettingsPage } from '../../types/Nav';
|
||||
|
||||
import type { BoundActionCreatorsMapObject } from '../../hooks/useBoundActions';
|
||||
import type { StateType as RootStateType } from '../reducer';
|
||||
import type { EditState } from '../../components/ProfileEditor';
|
||||
import type { Location } from '../../types/Nav';
|
||||
|
||||
const log = createLogger('nav');
|
||||
|
||||
// Types
|
||||
|
||||
export enum NavTab {
|
||||
Chats = 'Chats',
|
||||
Calls = 'Calls',
|
||||
Stories = 'Stories',
|
||||
Settings = 'Settings',
|
||||
}
|
||||
export type Location = ReadonlyDeep<
|
||||
| {
|
||||
tab: NavTab.Settings;
|
||||
details:
|
||||
| {
|
||||
page: Page.Profile;
|
||||
state: EditState;
|
||||
}
|
||||
| { page: Exclude<Page, Page.Profile> };
|
||||
}
|
||||
| { tab: Exclude<NavTab, NavTab.Settings> }
|
||||
>;
|
||||
|
||||
function printLocation(location: Location): string {
|
||||
if (location.tab === NavTab.Settings) {
|
||||
if (location.details.page === Page.Profile) {
|
||||
if (location.details.page === SettingsPage.Profile) {
|
||||
return `${location.tab}/${location.details.page}/${location.details.state}`;
|
||||
}
|
||||
return `${location.tab}/${location.details.page}`;
|
||||
|
|
|
@ -2,12 +2,14 @@
|
|||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import { createSelector } from 'reselect';
|
||||
import type { StateType } from '../reducer';
|
||||
import { NavTab, type NavStateType } from '../ducks/nav';
|
||||
import { getAllConversationsUnreadStats } from './conversations';
|
||||
import { getStoriesNotificationCount } from './stories';
|
||||
import type { UnreadStats } from '../../util/countUnreadStats';
|
||||
import { getCallHistoryUnreadCount } from './callHistory';
|
||||
import { NavTab } from '../../types/Nav';
|
||||
|
||||
import type { StateType } from '../reducer';
|
||||
import type { NavStateType } from '../ducks/nav';
|
||||
import type { UnreadStats } from '../../util/countUnreadStats';
|
||||
|
||||
function getNav(state: StateType): NavStateType {
|
||||
return state.nav;
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
// Copyright 2023 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import type { ReactNode } from 'react';
|
||||
import React, { memo, useCallback } from 'react';
|
||||
|
||||
import type { ReactNode } from 'react';
|
||||
|
||||
import { useSelector } from 'react-redux';
|
||||
import { NavTabs } from '../../components/NavTabs';
|
||||
import { getIntl, getTheme, getIsNightly } from '../selectors/user';
|
||||
|
@ -20,13 +22,14 @@ import {
|
|||
getStoriesEnabled,
|
||||
} from '../selectors/items';
|
||||
import { getSelectedNavTab } from '../selectors/nav';
|
||||
import type { Location } from '../ducks/nav';
|
||||
import { useNavActions } from '../ducks/nav';
|
||||
import { getHasPendingUpdate } from '../selectors/updates';
|
||||
import { getCallHistoryUnreadCount } from '../selectors/callHistory';
|
||||
import { Environment } from '../../environment';
|
||||
import { useItemsActions } from '../ducks/items';
|
||||
|
||||
import type { Location } from '../../types/Nav';
|
||||
|
||||
export type SmartNavTabsProps = Readonly<{
|
||||
navTabsCollapsed: boolean;
|
||||
onToggleNavTabsCollapse: (navTabsCollapsed: boolean) => void;
|
||||
|
|
|
@ -55,15 +55,15 @@ import { waitForEvent } from '../../shims/events';
|
|||
import { MINUTE } from '../../util/durations';
|
||||
import { sendSyncRequests } from '../../textsecure/syncRequests';
|
||||
import { SmartUpdateDialog } from './UpdateDialog';
|
||||
import { Page, Preferences } from '../../components/Preferences';
|
||||
import { Preferences } from '../../components/Preferences';
|
||||
import { useUpdatesActions } from '../ducks/updates';
|
||||
import { getUpdateDialogType } from '../selectors/updates';
|
||||
import { getHasAnyFailedStorySends } from '../selectors/stories';
|
||||
import { getOtherTabsUnreadStats, getSelectedLocation } from '../selectors/nav';
|
||||
import { getPreferredBadgeSelector } from '../selectors/badges';
|
||||
import { SmartProfileEditor } from './ProfileEditor';
|
||||
import { NavTab, useNavActions } from '../ducks/nav';
|
||||
import { EditState } from '../../components/ProfileEditor';
|
||||
import { useNavActions } from '../ducks/nav';
|
||||
import { NavTab, ProfileEditorPage, SettingsPage } from '../../types/Nav';
|
||||
import { SmartToastManager } from './ToastManager';
|
||||
import { useToastActions } from '../ducks/toast';
|
||||
import { DataReader } from '../../sql/Client';
|
||||
|
@ -111,8 +111,8 @@ function renderDonationsPane({
|
|||
setPage,
|
||||
}: {
|
||||
contentsRef: MutableRefObject<HTMLDivElement | null>;
|
||||
page: Page;
|
||||
setPage: (page: Page) => void;
|
||||
page: SettingsPage;
|
||||
setPage: (page: SettingsPage) => void;
|
||||
}): JSX.Element {
|
||||
return (
|
||||
<SmartPreferencesDonations
|
||||
|
@ -687,13 +687,13 @@ export function SmartPreferences(): JSX.Element | null {
|
|||
}
|
||||
|
||||
const { page } = currentLocation.details;
|
||||
const setPage = (newPage: Page, editState?: EditState) => {
|
||||
if (newPage === Page.Profile) {
|
||||
const setPage = (newPage: SettingsPage, editState?: ProfileEditorPage) => {
|
||||
if (newPage === SettingsPage.Profile) {
|
||||
changeLocation({
|
||||
tab: NavTab.Settings,
|
||||
details: {
|
||||
page: newPage,
|
||||
state: editState || EditState.None,
|
||||
state: editState || ProfileEditorPage.None,
|
||||
},
|
||||
});
|
||||
return;
|
||||
|
|
|
@ -9,7 +9,7 @@ import type { MutableRefObject } from 'react';
|
|||
import { getIntl } from '../selectors/user';
|
||||
import { getMe } from '../selectors/conversations';
|
||||
import { PreferencesDonations } from '../../components/PreferencesDonations';
|
||||
import type { Page } from '../../components/Preferences';
|
||||
import type { SettingsPage } from '../../types/Nav';
|
||||
import { useDonationsActions } from '../ducks/donations';
|
||||
import type { StateType } from '../reducer';
|
||||
import { isStagingServer } from '../../util/isStagingServer';
|
||||
|
@ -26,8 +26,8 @@ export const SmartPreferencesDonations = memo(
|
|||
setPage,
|
||||
}: {
|
||||
contentsRef: MutableRefObject<HTMLDivElement | null>;
|
||||
page: Page;
|
||||
setPage: (page: Page) => void;
|
||||
page: SettingsPage;
|
||||
setPage: (page: SettingsPage) => void;
|
||||
}) {
|
||||
const [validCurrencies, setValidCurrencies] = useState<
|
||||
ReadonlyArray<string>
|
||||
|
|
|
@ -27,10 +27,10 @@ import {
|
|||
} from '../selectors/username';
|
||||
import { SmartUsernameEditor } from './UsernameEditor';
|
||||
import { getSelectedLocation } from '../selectors/nav';
|
||||
import { NavTab, useNavActions } from '../ducks/nav';
|
||||
import { Page } from '../../components/Preferences';
|
||||
import { useNavActions } from '../ducks/nav';
|
||||
import { NavTab, SettingsPage } from '../../types/Nav';
|
||||
|
||||
import type { EditState } from '../../components/ProfileEditor';
|
||||
import type { ProfileEditorPage } from '../../types/Nav';
|
||||
import type { SmartUsernameEditorProps } from './UsernameEditor';
|
||||
import { ConfirmationDialog } from '../../components/ConfirmationDialog';
|
||||
|
||||
|
@ -103,17 +103,17 @@ export const SmartProfileEditor = memo(function SmartProfileEditor(props: {
|
|||
|
||||
if (
|
||||
selectedLocation.tab !== NavTab.Settings ||
|
||||
selectedLocation.details.page !== Page.Profile
|
||||
selectedLocation.details.page !== SettingsPage.Profile
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const editState = selectedLocation.details.state;
|
||||
const setEditState = (newState: EditState) => {
|
||||
const setEditState = (newState: ProfileEditorPage) => {
|
||||
changeLocation({
|
||||
tab: NavTab.Settings,
|
||||
details: {
|
||||
page: Page.Profile,
|
||||
page: SettingsPage.Profile,
|
||||
state: newState,
|
||||
},
|
||||
});
|
||||
|
|
|
@ -21,11 +21,13 @@ import { getMe, getSelectedConversationId } from '../selectors/conversations';
|
|||
import { useConversationsActions } from '../ducks/conversations';
|
||||
import { useToastActions } from '../ducks/toast';
|
||||
import { useGlobalModalActions } from '../ducks/globalModals';
|
||||
import { NavTab } from '../ducks/nav';
|
||||
import { useNavActions } from '../ducks/nav';
|
||||
import { NavTab } from '../../types/Nav';
|
||||
import { getHasCompletedUsernameOnboarding } from '../selectors/items';
|
||||
import { ToastManager } from '../../components/ToastManager';
|
||||
import type { WidthBreakpoint } from '../../components/_util';
|
||||
import { getToast } from '../selectors/toast';
|
||||
import { useDonationsActions } from '../ducks/donations';
|
||||
|
||||
export type SmartPropsType = Readonly<{
|
||||
disableMegaphone?: boolean;
|
||||
|
@ -53,6 +55,8 @@ export const SmartToastManager = memo(function SmartToastManager({
|
|||
const { username } = useSelector(getMe);
|
||||
const selectedNavTab = useSelector(getSelectedNavTab);
|
||||
const selectedConversationId = useSelector(getSelectedConversationId);
|
||||
const { changeLocation } = useNavActions();
|
||||
const { clearWorkflow, setDidResume } = useDonationsActions();
|
||||
|
||||
const { onUndoArchive } = useConversationsActions();
|
||||
const { openFileInFolder, hideToast } = useToastActions();
|
||||
|
@ -86,6 +90,8 @@ export const SmartToastManager = memo(function SmartToastManager({
|
|||
|
||||
return (
|
||||
<ToastManager
|
||||
changeLocation={changeLocation}
|
||||
clearDonation={clearWorkflow}
|
||||
i18n={i18n}
|
||||
OS={OS.getName()}
|
||||
toast={toast}
|
||||
|
@ -94,6 +100,7 @@ export const SmartToastManager = memo(function SmartToastManager({
|
|||
onUndoArchive={onUndoArchive}
|
||||
openFileInFolder={openFileInFolder}
|
||||
hideToast={hideToast}
|
||||
setDidResumeDonation={setDidResume}
|
||||
showAttachmentNotAvailableModal={showAttachmentNotAvailableModal}
|
||||
centerToast={centerToast}
|
||||
containerWidthBreakpoint={containerWidthBreakpoint}
|
||||
|
|
|
@ -8,9 +8,8 @@ import { UsernameOnboardingModal } from '../../components/UsernameOnboardingModa
|
|||
import { getIntl } from '../selectors/user';
|
||||
import { useGlobalModalActions } from '../ducks/globalModals';
|
||||
import { useUsernameActions } from '../ducks/username';
|
||||
import { NavTab, useNavActions } from '../ducks/nav';
|
||||
import { Page } from '../../components/Preferences';
|
||||
import { EditState } from '../../components/ProfileEditor';
|
||||
import { useNavActions } from '../ducks/nav';
|
||||
import { NavTab, SettingsPage, ProfileEditorPage } from '../../types/Nav';
|
||||
|
||||
export const SmartUsernameOnboardingModal = memo(
|
||||
function SmartUsernameOnboardingModal(): JSX.Element {
|
||||
|
@ -25,8 +24,8 @@ export const SmartUsernameOnboardingModal = memo(
|
|||
changeLocation({
|
||||
tab: NavTab.Settings,
|
||||
details: {
|
||||
page: Page.Profile,
|
||||
state: EditState.Username,
|
||||
page: SettingsPage.Profile,
|
||||
state: ProfileEditorPage.Username,
|
||||
},
|
||||
});
|
||||
toggleUsernameOnboarding();
|
||||
|
|
61
ts/types/Nav.ts
Normal file
61
ts/types/Nav.ts
Normal file
|
@ -0,0 +1,61 @@
|
|||
// Copyright 2020 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import type { ReadonlyDeep } from 'type-fest';
|
||||
|
||||
export type Location = ReadonlyDeep<
|
||||
| {
|
||||
tab: NavTab.Settings;
|
||||
details:
|
||||
| {
|
||||
page: SettingsPage.Profile;
|
||||
state: ProfileEditorPage;
|
||||
}
|
||||
| { page: Exclude<SettingsPage, SettingsPage.Profile> };
|
||||
}
|
||||
| { tab: Exclude<NavTab, NavTab.Settings> }
|
||||
>;
|
||||
|
||||
export enum NavTab {
|
||||
Chats = 'Chats',
|
||||
Calls = 'Calls',
|
||||
Stories = 'Stories',
|
||||
Settings = 'Settings',
|
||||
}
|
||||
|
||||
export enum SettingsPage {
|
||||
// Accessible through left nav
|
||||
Profile = 'Profile',
|
||||
General = 'General',
|
||||
Donations = 'Donations',
|
||||
Appearance = 'Appearance',
|
||||
Chats = 'Chats',
|
||||
Calls = 'Calls',
|
||||
Notifications = 'Notifications',
|
||||
Privacy = 'Privacy',
|
||||
DataUsage = 'DataUsage',
|
||||
Backups = 'Backups',
|
||||
Internal = 'Internal',
|
||||
|
||||
// Sub pages
|
||||
ChatColor = 'ChatColor',
|
||||
ChatFolders = 'ChatFolders',
|
||||
DonationsDonateFlow = 'DonationsDonateFlow',
|
||||
DonationsReceiptList = 'DonationsReceiptList',
|
||||
EditChatFolder = 'EditChatFolder',
|
||||
PNP = 'PNP',
|
||||
BackupsDetails = 'BackupsDetails',
|
||||
LocalBackups = 'LocalBackups',
|
||||
LocalBackupsSetupFolder = 'LocalBackupsSetupFolder',
|
||||
LocalBackupsSetupKey = 'LocalBackupsSetupKey',
|
||||
LocalBackupsKeyReference = 'LocalBackupsKeyReference',
|
||||
}
|
||||
|
||||
export enum ProfileEditorPage {
|
||||
None = 'None',
|
||||
BetterAvatar = 'BetterAvatar',
|
||||
ProfileName = 'ProfileName',
|
||||
Bio = 'Bio',
|
||||
Username = 'Username',
|
||||
UsernameLink = 'UsernameLink',
|
||||
}
|
|
@ -1,25 +1,27 @@
|
|||
// Copyright 2025 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import { Page } from '../components/Preferences';
|
||||
import { SettingsPage } from './Nav';
|
||||
|
||||
// Should be in sync with isBackupPage()
|
||||
export type PreferencesBackupPage =
|
||||
| Page.Backups
|
||||
| Page.BackupsDetails
|
||||
| Page.LocalBackups
|
||||
| Page.LocalBackupsKeyReference
|
||||
| Page.LocalBackupsSetupFolder
|
||||
| Page.LocalBackupsSetupKey;
|
||||
| SettingsPage.Backups
|
||||
| SettingsPage.BackupsDetails
|
||||
| SettingsPage.LocalBackups
|
||||
| SettingsPage.LocalBackupsKeyReference
|
||||
| SettingsPage.LocalBackupsSetupFolder
|
||||
| SettingsPage.LocalBackupsSetupKey;
|
||||
|
||||
// Should be in sync with PreferencesBackupPage
|
||||
export function isBackupPage(page: Page): page is PreferencesBackupPage {
|
||||
export function isBackupPage(
|
||||
page: SettingsPage
|
||||
): page is PreferencesBackupPage {
|
||||
return (
|
||||
page === Page.Backups ||
|
||||
page === Page.BackupsDetails ||
|
||||
page === Page.LocalBackups ||
|
||||
page === Page.LocalBackupsSetupFolder ||
|
||||
page === Page.LocalBackupsSetupKey ||
|
||||
page === Page.LocalBackupsKeyReference
|
||||
page === SettingsPage.Backups ||
|
||||
page === SettingsPage.BackupsDetails ||
|
||||
page === SettingsPage.LocalBackups ||
|
||||
page === SettingsPage.LocalBackupsSetupFolder ||
|
||||
page === SettingsPage.LocalBackupsSetupKey ||
|
||||
page === SettingsPage.LocalBackupsKeyReference
|
||||
);
|
||||
}
|
||||
|
|
|
@ -31,6 +31,8 @@ export enum ToastType {
|
|||
DecryptionError = 'DecryptionError',
|
||||
DebugLogError = 'DebugLogError',
|
||||
DeleteForEveryoneFailed = 'DeleteForEveryoneFailed',
|
||||
DonationCompleted = 'DonationCompleted',
|
||||
DonationProcessing = 'DonationProcessing',
|
||||
Error = 'Error',
|
||||
Expired = 'Expired',
|
||||
FailedToDeleteUsername = 'FailedToDeleteUsername',
|
||||
|
@ -120,6 +122,8 @@ export type AnyToast =
|
|||
| { toastType: ToastType.DangerousFileType }
|
||||
| { toastType: ToastType.DebugLogError }
|
||||
| { toastType: ToastType.DeleteForEveryoneFailed }
|
||||
| { toastType: ToastType.DonationCompleted }
|
||||
| { toastType: ToastType.DonationProcessing }
|
||||
| { toastType: ToastType.Error }
|
||||
| { toastType: ToastType.Expired }
|
||||
| { toastType: ToastType.FailedToDeleteUsername }
|
||||
|
|
|
@ -126,6 +126,7 @@ window.testUtilities = {
|
|||
stories: [],
|
||||
storyDistributionLists: [],
|
||||
donations: {
|
||||
didResumeWorkflowAtStartup: false,
|
||||
currentWorkflow: undefined,
|
||||
lastError: undefined,
|
||||
receipts: [],
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue