Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion stylesheets/components/InstallScreenProfileNameStep.scss
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
background: variables.$color-white;
border-radius: 16px;
padding: 48px;
max-width: 420px;
max-width: 520px;
width: 100%;
box-shadow: 0 4px 24px rgba(0, 0, 0, 0.15);
text-align: center;
Expand Down
45 changes: 37 additions & 8 deletions ts/components/installScreen/InstallScreenCaptchaStep.dom.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// SPDX-License-Identifier: AGPL-3.0-only

import React, { type ReactElement, useState, useCallback } from 'react';
import copyText from 'copy-text-to-clipboard';

import { Button, ButtonVariant } from '../Button.dom.js';
import { TitlebarDragArea } from '../TitlebarDragArea.dom.js';
Expand Down Expand Up @@ -30,15 +31,18 @@ export function InstallScreenCaptchaStep({
}: Props): ReactElement {
const [isWaitingForCaptcha, setIsWaitingForCaptcha] = useState(false);
const [captchaError, setCaptchaError] = useState<string | null>(null);
const [isCopied, setIsCopied] = useState(false);

// Shared function to start waiting for captcha and register handler
const startWaitingForCaptcha = useCallback(async () => {
if (isWaitingForCaptcha) {
// Already waiting, don't start another handler
return;
}

const handleOpenCaptcha = useCallback(async () => {
setIsWaitingForCaptcha(true);
setCaptchaError(null);

// Open the captcha URL in external browser
// This will be intercepted by Electron's will-navigate handler
document.location.href = CAPTCHA_URL;

try {
// Wait for the captcha token to come back via the signalcaptcha:// URL
const token = await requestCaptcha();
Expand All @@ -47,7 +51,25 @@ export function InstallScreenCaptchaStep({
setCaptchaError('Failed to complete captcha. Please try again.');
setIsWaitingForCaptcha(false);
}
}, [requestCaptcha, onCaptchaComplete]);
}, [isWaitingForCaptcha, requestCaptcha, onCaptchaComplete]);

const handleOpenCaptcha = useCallback(async () => {
// Open the captcha URL in external browser
// This will be intercepted by Electron's will-navigate handler
document.location.href = CAPTCHA_URL;

// Start waiting for the captcha response
await startWaitingForCaptcha();
}, [startWaitingForCaptcha]);

const handleCopyUrl = useCallback(async () => {
copyText(CAPTCHA_URL);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);

// Also start waiting for the captcha response
await startWaitingForCaptcha();
}, [startWaitingForCaptcha]);

return (
<div className="module-InstallScreenCaptchaStep">
Expand All @@ -74,7 +96,7 @@ export function InstallScreenCaptchaStep({
<div className="module-InstallScreenCaptchaStep__waiting">
<Spinner size="36px" svgSize="normal" />
<span className="module-InstallScreenCaptchaStep__waiting-text">
Complete the captcha in your browser, then click &quot;Open
Complete the CAPTCHA in your browser, then click &quot;Open
Signal&quot;
</span>
</div>
Expand All @@ -86,7 +108,14 @@ export function InstallScreenCaptchaStep({
variant={ButtonVariant.Primary}
disabled={isSubmitting || isWaitingForCaptcha}
>
{isWaitingForCaptcha ? 'Waiting for captcha...' : 'Open Captcha'}
{isWaitingForCaptcha ? 'Waiting for CAPTCHA...' : 'Open CAPTCHA'}
</Button>
<Button
onClick={handleCopyUrl}
variant={ButtonVariant.Details}
disabled={isSubmitting}
>
{isCopied ? 'Copied!' : 'Copy URL'}
</Button>
<Button
onClick={onBack}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,12 @@ export function InstallScreenProfileNameStep({

<div className="module-InstallScreenProfileNameStep__card">
<h1 className="module-InstallScreenProfileNameStep__title">
Set up your profile
Set up your Observer Vault profile
</h1>
<p className="module-InstallScreenProfileNameStep__description">
Enter your name to complete registration. This is how you&apos;ll
appear to others.
Enter a name for your Observer Vault&apos;s Signal account. If
you&apos;re not sure what to use, just set the first name to
&quot;Observer Vault&quot;.
</p>

<form
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ export function InstallScreenVerificationCodeStep({
Enter verification code
</h1>
<p className="module-InstallScreenVerificationCodeStep__description">
We sent a code to <strong>{phoneNumber}</strong>
Signal sent a code to <strong>{phoneNumber}</strong>
</p>

{error && (
Expand Down
14 changes: 12 additions & 2 deletions ts/util/stories.preload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,18 @@ export const getStoriesDisabled = (): boolean =>

export const setStoriesDisabled = async (value: boolean): Promise<void> => {
await itemStorage.put('hasStoriesDisabled', value);
const account = window.ConversationController.getOurConversationOrThrow();
account.captureChange('hasStoriesDisabled');

// Only update the conversation if it exists and the controller is ready
try {
const account = window.ConversationController.getOurConversation();
if (account) {
account.captureChange('hasStoriesDisabled');
}
} catch (error) {
// ConversationController may not be ready yet (e.g., during app startup)
// The setting is still saved to storage, so it will be applied when ready
}

onHasStoriesDisabledChange(value);
};

Expand Down