diff --git a/lib/hooks/invite-links.js b/lib/hooks/invite-links.js --- a/lib/hooks/invite-links.js +++ b/lib/hooks/invite-links.js @@ -129,13 +129,15 @@ joinThreadActionTypes, ); +export type LinkStatus = 'invalid' | 'valid' | 'timed_out'; + type AcceptInviteLinkParams = { +verificationResponse: InviteLinkVerificationResponse, +inviteSecret: string, +keyserverOverride: ?KeyserverOverride, +calendarQuery: () => CalendarQuery, +onFinish: () => mixed, - +onInvalidLinkDetected: () => mixed, + +setLinkStatus: SetState, }; function useAcceptInviteLink(params: AcceptInviteLinkParams): { +joinCommunity: () => mixed, @@ -147,7 +149,7 @@ keyserverOverride, calendarQuery, onFinish, - onInvalidLinkDetected, + setLinkStatus, } = params; React.useEffect(() => { @@ -196,7 +198,7 @@ keyserverID !== extractKeyserverIDFromID(communityID) ) { reject(); - onInvalidLinkDetected(); + setLinkStatus('invalid'); setOngoingJoinData(null); return; } @@ -204,7 +206,7 @@ reject(); setOngoingJoinData(oldData => { if (oldData) { - onInvalidLinkDetected(); + setLinkStatus('timed_out'); } return null; }); @@ -224,7 +226,7 @@ communityID, }); }); - }, [communityID, keyserverID, onInvalidLinkDetected]); + }, [communityID, keyserverID, setLinkStatus]); React.useEffect(() => { void (async () => { @@ -233,7 +235,7 @@ } const isValid = await isKeyserverURLValid(); if (!isValid || !keyserverURL) { - onInvalidLinkDetected(); + setLinkStatus('invalid'); ongoingJoinData.reject(); setOngoingJoinData(null); return; @@ -253,7 +255,7 @@ ongoingJoinData, keyserverID, keyserverURL, - onInvalidLinkDetected, + setLinkStatus, ]); React.useEffect(() => { @@ -280,7 +282,7 @@ onFinish(); ongoingJoinData.resolve(result); } catch (e) { - onInvalidLinkDetected(); + setLinkStatus(status => (status === 'valid' ? 'invalid' : status)); ongoingJoinData.reject(); } finally { setOngoingJoinData(null); @@ -294,7 +296,7 @@ isAuthenticated, ongoingJoinData, onFinish, - onInvalidLinkDetected, + setLinkStatus, ]); const dispatchActionPromise = useDispatchActionPromise(); diff --git a/native/navigation/invite-link-modal.react.js b/native/navigation/invite-link-modal.react.js --- a/native/navigation/invite-link-modal.react.js +++ b/native/navigation/invite-link-modal.react.js @@ -4,6 +4,7 @@ import { View, Text, ActivityIndicator } from 'react-native'; import { useAcceptInviteLink } from 'lib/hooks/invite-links.js'; +import type { LinkStatus } from 'lib/hooks/invite-links.js'; import type { KeyserverOverride } from 'lib/shared/invite-links'; import type { InviteLinkVerificationResponse } from 'lib/types/link-types.js'; @@ -30,6 +31,9 @@ function InviteLinkModal(props: Props): React.Node { const styles = useStyles(unboundStyles); const { invitationDetails, secret, keyserverOverride } = props.route.params; + const [linkStatus, setLinkStatus] = React.useState( + invitationDetails.status === 'valid' ? 'valid' : 'invalid', + ); const navContext = React.useContext(NavContext); const calendarQuery = useSelector(state => @@ -38,27 +42,18 @@ navContext, }), ); - const onInvalidLinkDetected = React.useCallback( - () => - props.navigation.setParams({ - invitationDetails: { - status: 'invalid', - }, - secret, - }), - [props.navigation, secret], - ); + const { joinCommunity, joinThreadLoadingStatus } = useAcceptInviteLink({ verificationResponse: invitationDetails, inviteSecret: secret, keyserverOverride, calendarQuery, onFinish: props.navigation.goBack, - onInvalidLinkDetected, + setLinkStatus, }); const header = React.useMemo(() => { - if (invitationDetails.status === 'valid') { + if (invitationDetails.status === 'valid' && linkStatus === 'valid') { return ( <> You have been invited to join @@ -68,13 +63,16 @@ ); } + const headerText = linkStatus === 'invalid' ? 'Invite invalid' : 'Timeout'; + const message = + linkStatus === 'invalid' + ? 'This invite link may be expired. Please try again with another ' + + 'invite link.' + : 'The request has timed out.'; return ( <> - Invite invalid - - This invite link may be expired. Please try again with another invite - link. - + {headerText} + {message} ); }, [ @@ -83,10 +81,11 @@ styles.invalidInviteExplanation, styles.invalidInviteTitle, styles.invitation, + linkStatus, ]); const buttons = React.useMemo(() => { - if (invitationDetails.status === 'valid') { + if (linkStatus === 'valid') { const joinButtonContent = joinThreadLoadingStatus === 'loading' ? ( ); }, [ - invitationDetails.status, + linkStatus, joinCommunity, joinThreadLoadingStatus, props.navigation.goBack, diff --git a/web/invite-links/accept-invite-modal.react.js b/web/invite-links/accept-invite-modal.react.js --- a/web/invite-links/accept-invite-modal.react.js +++ b/web/invite-links/accept-invite-modal.react.js @@ -5,6 +5,7 @@ import ModalOverlay from 'lib/components/modal-overlay.react.js'; import { useModalContext } from 'lib/components/modal-provider.react.js'; import { useAcceptInviteLink } from 'lib/hooks/invite-links.js'; +import type { LinkStatus } from 'lib/hooks/invite-links.js'; import type { KeyserverOverride } from 'lib/shared/invite-links.js'; import { type InviteLinkVerificationResponse } from 'lib/types/link-types.js'; @@ -21,12 +22,8 @@ function AcceptInviteModal(props: Props): React.Node { const { verificationResponse, inviteSecret, keyserverOverride } = props; - const [isLinkValid, setIsLinkValid] = React.useState( - verificationResponse.status === 'valid', - ); - const onInvalidLinkDetected = React.useCallback( - () => setIsLinkValid(false), - [], + const [linkStatus, setLinkStatus] = React.useState( + verificationResponse.status === 'valid' ? 'valid' : 'invalid', ); const { popModal } = useModalContext(); const calendarQuery = useSelector(nonThreadCalendarQuery); @@ -37,11 +34,11 @@ keyserverOverride, calendarQuery, onFinish: popModal, - onInvalidLinkDetected, + setLinkStatus, }); let content; - if (verificationResponse.status === 'valid' && isLinkValid) { + if (verificationResponse.status === 'valid' && linkStatus === 'valid') { const { community } = verificationResponse; content = ( <> @@ -64,14 +61,17 @@ ); } else { + const header = linkStatus === 'invalid' ? 'Invite invalid' : 'Timeout'; + const message = + linkStatus === 'invalid' + ? 'This invite link may be expired. Please try again with another ' + + 'invite link.' + : 'The request has timed out.'; content = ( <>
-
Invite invalid
-
- This invite link may be expired. Please try again with another - invite link. -
+
{header}
+
{message}