Fix stuck in-call close dialog overlay when cancelling

Co-authored-by: ayumi-signal <143036029+ayumi-signal@users.noreply.github.com>
This commit is contained in:
automated-signal
2025-09-02 17:23:09 -05:00
committed by GitHub
parent e2c36f1031
commit 24fd5e6a95
3 changed files with 32 additions and 33 deletions

View File

@@ -1,8 +1,7 @@
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { unmountComponentAtNode } from 'react-dom';
import { createRoot } from 'react-dom/client';
import { createRoot, type Root } from 'react-dom/client';
import type { ConversationAttributesType } from '../model-types.d';
import type { ConversationModel } from '../models/conversations';
@@ -211,9 +210,9 @@ export async function joinViaLink(value: string): Promise<void> {
const closeDialog = async () => {
try {
if (groupV2InfoNode) {
unmountComponentAtNode(groupV2InfoNode);
groupV2InfoNode = undefined;
if (groupV2InfoRoot) {
groupV2InfoRoot.unmount();
groupV2InfoRoot = undefined;
}
window.reduxActions.conversations.setPreJoinConversation(undefined);
@@ -234,9 +233,9 @@ export async function joinViaLink(value: string): Promise<void> {
const join = async () => {
try {
if (groupV2InfoNode) {
unmountComponentAtNode(groupV2InfoNode);
groupV2InfoNode = undefined;
if (groupV2InfoRoot) {
groupV2InfoRoot.unmount();
groupV2InfoRoot = undefined;
}
window.reduxActions.conversations.setPreJoinConversation(undefined);
@@ -387,10 +386,11 @@ export async function joinViaLink(value: string): Promise<void> {
log.info(`${logId}: Showing modal`);
let groupV2InfoNode: HTMLDivElement | undefined =
document.createElement('div');
const groupV2InfoNode = document.createElement('div');
let groupV2InfoRoot: Root | undefined;
createRoot(groupV2InfoNode).render(
groupV2InfoRoot = createRoot(groupV2InfoNode);
groupV2InfoRoot.render(
createGroupV2JoinModal(window.reduxStore, { join, onClose: closeDialog })
);
@@ -426,7 +426,7 @@ export async function joinViaLink(value: string): Promise<void> {
};
// Dialog has been dismissed; we'll delete the unneeeded avatar
if (!groupV2InfoNode) {
if (!groupV2InfoRoot) {
await window.Signal.Migrations.deleteAttachmentData(
attributes.avatar.path
);

View File

@@ -2,8 +2,7 @@
// SPDX-License-Identifier: AGPL-3.0-only
import React, { StrictMode } from 'react';
import { unmountComponentAtNode } from 'react-dom';
import { createRoot } from 'react-dom/client';
import { createRoot, type Root } from 'react-dom/client';
import * as Errors from '../types/errors';
import { createLogger } from '../logging/log';
@@ -29,13 +28,14 @@ export async function longRunningTaskWrapper<T>({
const ONE_SECOND = 1000;
const TWO_SECONDS = 2000;
let progressNode: HTMLDivElement | undefined;
let progressRoot: Root | undefined;
let spinnerStart;
let progressTimeout: NodeJS.Timeout | undefined = setTimeout(() => {
progressNode = document.createElement('div');
const progressNode = document.createElement('div');
log.info(`${idLog}: Creating spinner`);
createRoot(progressNode).render(
progressRoot = createRoot(progressNode);
progressRoot.render(
<StrictMode>
<FunDefaultEnglishEmojiLocalizationProvider>
<ProgressModal i18n={window.i18n} />
@@ -54,7 +54,7 @@ export async function longRunningTaskWrapper<T>({
clearTimeoutIfNecessary(progressTimeout);
progressTimeout = undefined;
if (progressNode) {
if (progressRoot) {
const now = Date.now();
if (spinnerStart && now - spinnerStart < ONE_SECOND) {
log.info(
@@ -62,8 +62,8 @@ export async function longRunningTaskWrapper<T>({
);
await sleep(ONE_SECOND);
}
unmountComponentAtNode(progressNode);
progressNode = undefined;
progressRoot.unmount();
progressRoot = undefined;
}
return result;
@@ -72,9 +72,9 @@ export async function longRunningTaskWrapper<T>({
clearTimeoutIfNecessary(progressTimeout);
progressTimeout = undefined;
if (progressNode) {
unmountComponentAtNode(progressNode);
progressNode = undefined;
if (progressRoot) {
progressRoot.unmount();
progressRoot = undefined;
}
if (!suppressErrorDialog) {

View File

@@ -2,8 +2,7 @@
// SPDX-License-Identifier: AGPL-3.0-only
import React, { StrictMode } from 'react';
import { unmountComponentAtNode } from 'react-dom';
import { createRoot } from 'react-dom/client';
import { createRoot, type Root } from 'react-dom/client';
import { ConfirmationDialog } from '../components/ConfirmationDialog';
import { FunDefaultEnglishEmojiLocalizationProvider } from '../components/fun/FunEmojiLocalizationProvider';
@@ -20,18 +19,17 @@ type ConfirmationDialogViewProps = {
resolve: () => void;
};
let confirmationDialogViewNode: HTMLElement | undefined;
let confirmationDialogRoot: Root | undefined;
let confirmationDialogPreviousFocus: HTMLElement | undefined;
function removeConfirmationDialog() {
if (!confirmationDialogViewNode) {
if (!confirmationDialogRoot) {
return;
}
window.reduxActions?.globalModals.toggleConfirmationModal(false);
unmountComponentAtNode(confirmationDialogViewNode);
document.body.removeChild(confirmationDialogViewNode);
confirmationDialogRoot.unmount();
if (
confirmationDialogPreviousFocus &&
@@ -39,24 +37,25 @@ function removeConfirmationDialog() {
) {
confirmationDialogPreviousFocus.focus();
}
confirmationDialogViewNode = undefined;
confirmationDialogRoot = undefined;
}
export function showConfirmationDialog(
options: ConfirmationDialogViewProps
): void {
if (confirmationDialogViewNode) {
if (confirmationDialogRoot) {
removeConfirmationDialog();
}
window.reduxActions?.globalModals.toggleConfirmationModal(true);
confirmationDialogViewNode = document.createElement('div');
const confirmationDialogViewNode = document.createElement('div');
document.body.appendChild(confirmationDialogViewNode);
confirmationDialogPreviousFocus = document.activeElement as HTMLElement;
createRoot(confirmationDialogViewNode).render(
confirmationDialogRoot = createRoot(confirmationDialogViewNode);
confirmationDialogRoot.render(
<StrictMode>
<FunDefaultEnglishEmojiLocalizationProvider>
<ConfirmationDialog