feat(calls): EC iframe load watchdog + recovery UI; avatar decorations on call tiles
- CallEmbed: 25s load watchdog that fails fast on iframe error / preparing-error / timeout instead of hanging on a permanent spinner; additive onLoadError API, cleared on ready/capabilities/joined. - CallView: user-visible "call failed to load" overlay with Retry/Leave (folds + tokens) via a new useCallLoadError hook. - CallMemberCard: wrap the participant avatar in AvatarDecoration so decorations render in the call roster (the tile rendered UserAvatar bare while member lists already wrapped it). Addresses LOTUS_BUGS item 3 (avatar decorations in calls) and EC iframe failure monitoring. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,13 @@
|
||||
import React, { RefObject, useRef } from 'react';
|
||||
import { Badge, Box, color, Header, Scroll, Text, toRem } from 'folds';
|
||||
import { useCallEmbed, useCallJoined, useCallEmbedPlacementSync } from '../../hooks/useCallEmbed';
|
||||
import { useSetAtom } from 'jotai';
|
||||
import { Badge, Box, Button, color, Header, Icon, Icons, Scroll, Text, toRem } from 'folds';
|
||||
import {
|
||||
useCallEmbed,
|
||||
useCallJoined,
|
||||
useCallEmbedPlacementSync,
|
||||
useCallLoadError,
|
||||
} from '../../hooks/useCallEmbed';
|
||||
import { callEmbedAtom } from '../../state/callEmbed';
|
||||
import { ContainerColor } from '../../styles/ContainerColor.css';
|
||||
import { PrescreenControls } from './PrescreenControls';
|
||||
import { usePowerLevelsContext } from '../../hooks/usePowerLevels';
|
||||
@@ -153,6 +160,37 @@ function CallPrescreen() {
|
||||
);
|
||||
}
|
||||
|
||||
function CallLoadErrorMessage() {
|
||||
const setCallEmbed = useSetAtom(callEmbedAtom);
|
||||
|
||||
// Disposing the embed tears down the hung iframe and returns the user to the
|
||||
// prescreen, from which they can join again ("Retry") or simply walk away.
|
||||
const dismiss = () => setCallEmbed(undefined);
|
||||
|
||||
return (
|
||||
<Box
|
||||
className={css.CallViewContent}
|
||||
direction="Column"
|
||||
alignItems="Center"
|
||||
justifyContent="Center"
|
||||
gap="300"
|
||||
>
|
||||
<Icon src={Icons.Warning} size="400" style={{ color: color.Critical.Main }} />
|
||||
<Text style={{ color: color.Critical.Main }} size="L400" align="Center">
|
||||
The call failed to load. Check your connection and try again.
|
||||
</Text>
|
||||
<Box gap="200" alignItems="Center">
|
||||
<Button variant="Primary" size="300" radii="400" onClick={dismiss}>
|
||||
<Text size="B400">Retry</Text>
|
||||
</Button>
|
||||
<Button variant="Secondary" fill="Soft" size="300" radii="400" onClick={dismiss}>
|
||||
<Text size="B400">Leave</Text>
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
type CallJoinedProps = {
|
||||
containerRef: RefObject<HTMLDivElement>;
|
||||
joined: boolean;
|
||||
@@ -175,8 +213,13 @@ export function CallView() {
|
||||
|
||||
const callEmbed = useCallEmbed();
|
||||
const callJoined = useCallJoined(callEmbed);
|
||||
const loadError = useCallLoadError(callEmbed);
|
||||
|
||||
const currentJoined = callEmbed?.roomId === room.roomId && callJoined;
|
||||
const isCurrentRoom = callEmbed?.roomId === room.roomId;
|
||||
const currentJoined = isCurrentRoom && callJoined;
|
||||
// Show the recovery UI when this room's embed failed to load and we never
|
||||
// made it into the call (a hung iframe / blank spinner otherwise).
|
||||
const showLoadError = isCurrentRoom && !currentJoined && Boolean(loadError);
|
||||
|
||||
return (
|
||||
<Box
|
||||
@@ -184,8 +227,9 @@ export function CallView() {
|
||||
style={{ minWidth: toRem(280) }}
|
||||
grow="Yes"
|
||||
>
|
||||
{!currentJoined && <CallPrescreen />}
|
||||
<CallJoined joined={currentJoined} containerRef={callContainerRef} />
|
||||
{showLoadError && <CallLoadErrorMessage />}
|
||||
{!currentJoined && !showLoadError && <CallPrescreen />}
|
||||
{!showLoadError && <CallJoined joined={currentJoined} containerRef={callContainerRef} />}
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user