import React, { forwardRef, useCallback, useEffect, useState } from 'react'; import { Dialog, Header, config, Box, Text, Button, Spinner, color } from 'folds'; import { useAtom } from 'jotai'; import { AsyncStatus, useAsyncCallback } from '../hooks/useAsyncCallback'; import { logoutClient } from '../../client/initMatrix'; import { callEmbedAtom } from '../state/callEmbed'; import { hangupCallAndWait } from '../plugins/call/hangup'; import { useMatrixClient } from '../hooks/useMatrixClient'; import { useModalStyle } from '../hooks/useModalStyle'; import { useCrossSigningActive } from '../hooks/useCrossSigning'; import { InfoCard } from './info-card'; import { ScheduledMessage } from '../state/scheduledMessages'; import { cancelScheduledMessage, fetchScheduledMessages } from '../utils/scheduledMessages'; import { useDeviceVerificationStatus, VerificationStatus, } from '../hooks/useDeviceVerificationStatus'; /** * Ask Element Call to hang up and wait (bounded) until our own MatrixRTC * membership has actually been removed from the room, so the leave reaches * the homeserver before the client is stopped and the token is revoked. */ type LogoutDialogProps = { handleClose: () => void; }; export const LogoutDialog = forwardRef( ({ handleClose }, ref) => { const mx = useMatrixClient(); const modalStyle = useModalStyle(480); const hasEncryptedRoom = !!mx.getRooms().find((room) => room.hasEncryptionStateEvent()); const crossSigningActive = useCrossSigningActive(); const verificationStatus = useDeviceVerificationStatus( mx.getCrypto(), mx.getSafeUserId(), mx.getDeviceId() ?? undefined, ); const [callEmbed, setCallEmbed] = useAtom(callEmbedAtom); // [Gitea #322] Scheduled messages live on the server and still send after // logout, where no client would show them. Say so, and offer to cancel. const [scheduled, setScheduled] = useState([]); useEffect(() => { let alive = true; fetchScheduledMessages(mx) .then((list) => alive && setScheduled(list)) .catch(() => undefined); return () => { alive = false; }; }, [mx]); const [logoutState, logout] = useAsyncCallback( useCallback( async (cancelScheduled?: boolean) => { if (cancelScheduled) { await Promise.all(scheduled.map((m) => cancelScheduledMessage(mx, m.delayId))); } // [Gitea #29] Logging out mid-call must hang up first, or the MatrixRTC // membership (expires: 4 h) stays behind as a ghost participant and // everyone else sees you "in call" until it times out. if (callEmbed && callEmbed.joined && !callEmbed.disposed) { await hangupCallAndWait(mx, callEmbed); setCallEmbed(undefined); } await logoutClient(mx); }, [mx, callEmbed, setCallEmbed, scheduled], ), ); const ongoingLogout = logoutState.status === AsyncStatus.Loading; return (
Logout
{hasEncryptedRoom && (crossSigningActive ? ( verificationStatus === VerificationStatus.Unverified && ( ) ) : ( ))} {scheduled.length > 0 && ( )} You’re about to log out. Are you sure? {logoutState.status === AsyncStatus.Error && ( Failed to logout! {logoutState.error.message} )} {scheduled.length > 0 && ( )}
); }, );