Page MenuHomePhorge

D14920.1765013213.diff
No OneTemporary

Size
8 KB
Referenced Files
None
Subscribers
None

D14920.1765013213.diff

diff --git a/web/account/log-in-form.css b/web/account/log-in-form.css
--- a/web/account/log-in-form.css
+++ b/web/account/log-in-form.css
@@ -134,6 +134,15 @@
height: 195px;
}
+div.new_modal_body .restorationSpinner {
+ padding: 5px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 195px;
+ height: 195px;
+}
+
div.new_modal_body .buttons {
display: flex;
flex-direction: column;
@@ -155,3 +164,129 @@
width: 320px;
min-width: auto;
}
+
+/* Data Restoration Progress Styles */
+div.restoration_header {
+ text-align: center;
+ margin-bottom: 8px;
+}
+
+div.restoration_subtitle {
+ color: #8c889a;
+ font-size: var(--xs-font-12);
+ margin-top: 4px;
+ font-weight: var(--normal);
+}
+
+div.restoration_progress {
+ margin: 20px 0;
+}
+
+div.progress_steps {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 8px;
+}
+
+div.step_item {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 8px;
+ min-width: 70px;
+}
+
+div.step_item span {
+ font-size: var(--xs-font-12);
+ color: #8c889a;
+ text-align: center;
+}
+
+div.step_icon_completed {
+ width: 24px;
+ height: 24px;
+ border-radius: 50%;
+ background: #4caf50;
+ color: white;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: var(--xs-font-12);
+ font-weight: bold;
+}
+
+div.step_icon_active {
+ width: 24px;
+ height: 24px;
+ border-radius: 50%;
+ background: #6a20e3;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ animation: pulse 2s infinite;
+}
+
+div.step_icon_pending {
+ width: 24px;
+ height: 24px;
+ border-radius: 50%;
+ background: #3a3a3a;
+ color: #8c889a;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: var(--xs-font-12);
+}
+
+div.step_connector {
+ width: 30px;
+ height: 2px;
+ background: #3a3a3a;
+ margin: 0 4px;
+}
+
+div.restoration_status {
+ text-align: center;
+ margin: 20px 0;
+}
+
+div.status_message {
+ color: white;
+ font-size: var(--s-font-14);
+ font-weight: var(--medium);
+ margin-bottom: 8px;
+}
+
+div.status_detail {
+ color: #8c889a;
+ font-size: var(--xs-font-12);
+}
+
+div.restoration_spinner_container {
+ display: flex;
+ justify-content: center;
+ margin: 20px 0;
+}
+
+div.restoration_spinner_wrapper {
+ padding: 20px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ border-radius: 12px;
+ background: rgba(106, 32, 227, 0.1);
+ border: 1px solid rgba(106, 32, 227, 0.2);
+}
+
+@keyframes pulse {
+ 0% {
+ box-shadow: 0 0 0 0 rgba(106, 32, 227, 0.7);
+ }
+ 70% {
+ box-shadow: 0 0 0 8px rgba(106, 32, 227, 0);
+ }
+ 100% {
+ box-shadow: 0 0 0 0 rgba(106, 32, 227, 0);
+ }
+}
diff --git a/web/account/log-in-form.react.js b/web/account/log-in-form.react.js
--- a/web/account/log-in-form.react.js
+++ b/web/account/log-in-form.react.js
@@ -8,10 +8,17 @@
import ModalOverlay from 'lib/components/modal-overlay.react.js';
import { useModalContext } from 'lib/components/modal-provider.react.js';
-import { useSecondaryDeviceQRAuthURL } from 'lib/components/secondary-device-qr-auth-context-provider.react.js';
+import {
+ useSecondaryDeviceQRAuthURL,
+ useSecondaryDeviceQRAuthContext,
+} from 'lib/components/secondary-device-qr-auth-context-provider.react.js';
import stores from 'lib/facts/stores.js';
+import { isDev } from 'lib/utils/dev-utils.js';
import { useDispatch } from 'lib/utils/redux-utils.js';
-import { useIsRestoreFlowEnabled } from 'lib/utils/services-utils.js';
+import {
+ useIsRestoreFlowEnabled,
+ fullBackupSupport,
+} from 'lib/utils/services-utils.js';
import HeaderSeparator from './header-separator.react.js';
import css from './log-in-form.css';
@@ -22,6 +29,7 @@
import OrBreak from '../components/or-break.react.js';
import LoadingIndicator from '../loading-indicator.react.js';
import { updateNavInfoActionType } from '../redux/action-types.js';
+import { useSelector } from '../redux/redux-utils.js';
function LegacyLoginForm() {
const { openConnectModal } = useConnectModal();
@@ -82,8 +90,111 @@
);
}
+type BackupRestorationProgressProps = {
+ +qrAuthInProgress: boolean,
+ +userDataRestoreStarted: boolean,
+};
+function BackupRestorationProgress(props: BackupRestorationProgressProps) {
+ const { qrAuthInProgress, userDataRestoreStarted } = props;
+
+ const step: 'authenticating' | 'restoring' =
+ qrAuthInProgress && !userDataRestoreStarted
+ ? 'authenticating'
+ : 'restoring';
+
+ const [title, subtitle, statusMessage, statusDetail] = React.useMemo(() => {
+ if (step === 'authenticating') {
+ return [
+ 'Authenticating device',
+ 'Registering you device to Comm',
+ 'Authenticating your device...',
+ "Please wait while we register your device's cryptographic keys",
+ ];
+ } else {
+ return [
+ 'Restoring your data',
+ 'Device authenticated successfully',
+ 'Restoring your messages and settings...',
+ 'Please wait while we complete this process',
+ ];
+ }
+ }, [step]);
+
+ const restoreState = useSelector(state => state.restoreBackupState.status);
+ let debugInfo;
+ if (isDev) {
+ debugInfo = (
+ <div className={css.buttons}>
+ <button>
+ Step: {step} ({restoreState})
+ </button>
+ </div>
+ );
+ }
+
+ const stepLoadingIndicator = React.useMemo(
+ () => <LoadingIndicator status="loading" size="small" />,
+ [],
+ );
+ const [authProgressStepClasName, authProgressStep] = React.useMemo(() => {
+ return step === 'authenticating'
+ ? [css.step_icon_active, stepLoadingIndicator]
+ : [css.step_icon_completed, '✓'];
+ }, [step, stepLoadingIndicator]);
+
+ const [restoreProgressStepClassName, restoreProgressStep] =
+ React.useMemo(() => {
+ return step === 'restoring'
+ ? [css.step_icon_active, stepLoadingIndicator]
+ : [css.step_icon_pending, '2'];
+ }, [step, stepLoadingIndicator]);
+
+ return (
+ <div className={css.new_modal_body}>
+ <div className={css.restoration_header}>
+ <h1>{title}</h1>
+ <div className={css.restoration_subtitle}>{subtitle}</div>
+ </div>
+ <HeaderSeparator />
+ <div className={css.content}>
+ <div className={css.restoration_progress}>
+ <div className={css.progress_steps}>
+ <div className={css.step_item}>
+ <div className={authProgressStepClasName}>{authProgressStep}</div>
+ <span>Authentication</span>
+ </div>
+ <div className={css.step_connector}></div>
+ <div className={css.step_item}>
+ <div className={restoreProgressStepClassName}>
+ {restoreProgressStep}
+ </div>
+ <span>Data Restoration</span>
+ </div>
+ <div className={css.step_connector}></div>
+ <div className={css.step_item}>
+ <div className={css.step_icon_pending}>3</div>
+ <span>Complete</span>
+ </div>
+ </div>
+ </div>
+ <div className={css.restoration_status}>
+ <div className={css.status_message}>{statusMessage}</div>
+ <div className={css.status_detail}>{statusDetail}</div>
+ </div>
+ <div className={css.restoration_spinner_container}>
+ <div className={css.restoration_spinner_wrapper}>
+ <LoadingIndicator status="loading" size="large" />
+ </div>
+ </div>
+ {debugInfo}
+ </div>
+ </div>
+ );
+}
+
function LoginForm() {
const qrCodeURL = useSecondaryDeviceQRAuthURL();
+ const { qrAuthInProgress } = useSecondaryDeviceQRAuthContext();
const { pushModal, clearModals, popModal } = useModalContext();
@@ -154,6 +265,19 @@
return <LoadingIndicator status="loading" size="large" color="black" />;
}, [qrCodeURL]);
+ const userDataRestoreStarted = useSelector(
+ state => state.restoreBackupState.status !== 'no_backup',
+ );
+
+ if (fullBackupSupport && (qrAuthInProgress || userDataRestoreStarted)) {
+ return (
+ <BackupRestorationProgress
+ qrAuthInProgress={qrAuthInProgress}
+ userDataRestoreStarted={userDataRestoreStarted}
+ />
+ );
+ }
+
return (
<div className={css.new_modal_body}>
<h1>Log in to Comm</h1>

File Metadata

Mime Type
text/plain
Expires
Sat, Dec 6, 9:26 AM (7 h, 29 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5835850
Default Alt Text
D14920.1765013213.diff (8 KB)

Event Timeline