diff --git a/native/navigation/invite-link-modal.react.js b/native/navigation/invite-link-modal.react.js
index 5d3c3866e..49a74c35b 100644
--- a/native/navigation/invite-link-modal.react.js
+++ b/native/navigation/invite-link-modal.react.js
@@ -1,222 +1,244 @@
// @flow
import invariant from 'invariant';
import * as React from 'react';
-import { View, Text } from 'react-native';
+import { View, Text, ActivityIndicator } from 'react-native';
import {
joinThread,
joinThreadActionTypes,
} from 'lib/actions/thread-actions.js';
+import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors.js';
import type { InviteLinkVerificationResponse } from 'lib/types/link-types.js';
import {
useDispatchActionPromise,
useServerCall,
} from 'lib/utils/action-utils.js';
import { nonThreadCalendarQuery } from './nav-selectors.js';
import { NavContext } from './navigation-context.js';
import type { RootNavigationProp } from './root-navigator.react.js';
import type { NavigationRoute } from './route-names.js';
import Button from '../components/button.react.js';
import Modal from '../components/modal.react.js';
import { useSelector } from '../redux/redux-utils.js';
import { useStyles } from '../themes/colors.js';
export type InviteLinkModalParams = {
+invitationDetails: InviteLinkVerificationResponse,
+secret: string,
};
type Props = {
+navigation: RootNavigationProp<'InviteLinkModal'>,
+route: NavigationRoute<'InviteLinkModal'>,
};
function InviteLinkModal(props: Props): React.Node {
const styles = useStyles(unboundStyles);
const { invitationDetails, secret } = props.route.params;
React.useEffect(() => {
if (invitationDetails.status === 'already_joined') {
props.navigation.goBack();
}
}, [invitationDetails.status, props.navigation]);
const header = React.useMemo(() => {
if (invitationDetails.status === 'valid') {
return (
<>
You have been invited to join
{invitationDetails.community.name}
>
);
}
return (
<>
Invite invalid
This invite link may be expired, please try again with another invite
link
>
);
}, [
invitationDetails,
styles.communityName,
styles.invalidInviteExplanation,
styles.invalidInviteTitle,
styles.invitation,
]);
const callJoinThread = useServerCall(joinThread);
const navContext = React.useContext(NavContext);
const calendarQuery = useSelector(state =>
nonThreadCalendarQuery({
redux: state,
navContext,
}),
);
const communityID = invitationDetails.community?.id;
const createJoinCommunityAction = React.useCallback(async () => {
invariant(
communityID,
'CommunityID should be present while calling this function',
);
const query = calendarQuery();
const result = await callJoinThread({
threadID: communityID,
calendarQuery: {
startDate: query.startDate,
endDate: query.endDate,
filters: [
...query.filters,
{ type: 'threads', threadIDs: [communityID] },
],
},
inviteLinkSecret: secret,
});
props.navigation.goBack();
return result;
}, [calendarQuery, callJoinThread, communityID, props.navigation, secret]);
const dispatchActionPromise = useDispatchActionPromise();
const joinCommunity = React.useCallback(() => {
dispatchActionPromise(joinThreadActionTypes, createJoinCommunityAction());
}, [createJoinCommunityAction, dispatchActionPromise]);
+ const joinThreadLoadingStatus = useSelector(joinThreadLoadingStatusSelector);
const buttons = React.useMemo(() => {
if (invitationDetails.status === 'valid') {
+ const joinButtonContent =
+ joinThreadLoadingStatus === 'loading' ? (
+
+ ) : (
+ Accept Invite
+ );
return (
<>
>
);
}
return (
);
}, [
invitationDetails.status,
joinCommunity,
+ joinThreadLoadingStatus,
props.navigation.goBack,
+ styles.activityIndicatorStyle,
styles.button,
styles.buttonPrimary,
styles.buttonSecondary,
styles.buttonText,
styles.gap,
]);
return (
{header}
{buttons}
);
}
+const joinThreadLoadingStatusSelector = createLoadingStatusSelector(
+ joinThreadActionTypes,
+);
+
const unboundStyles = {
modal: {
backgroundColor: 'modalForeground',
paddingVertical: 24,
paddingHorizontal: 16,
flex: 0,
},
invitation: {
color: 'whiteText',
textAlign: 'center',
fontSize: 14,
fontWeight: '400',
lineHeight: 22,
marginBottom: 24,
},
communityName: {
color: 'whiteText',
textAlign: 'center',
fontSize: 18,
fontWeight: '500',
lineHeight: 24,
},
invalidInviteTitle: {
color: 'whiteText',
textAlign: 'center',
fontSize: 22,
fontWeight: '500',
lineHeight: 28,
marginBottom: 24,
},
invalidInviteExplanation: {
color: 'whiteText',
textAlign: 'center',
fontSize: 14,
fontWeight: '400',
lineHeight: 22,
},
separator: {
height: 1,
backgroundColor: 'modalSeparator',
marginVertical: 24,
},
gap: {
marginBottom: 16,
},
button: {
borderRadius: 8,
paddingVertical: 12,
paddingHorizontal: 24,
},
buttonPrimary: {
backgroundColor: 'purpleButton',
},
buttonSecondary: {
borderColor: 'secondaryButtonBorder',
borderWidth: 1,
},
buttonText: {
color: 'whiteText',
textAlign: 'center',
fontSize: 16,
fontWeight: '500',
lineHeight: 24,
},
+ activityIndicatorStyle: {
+ paddingVertical: 2,
+ },
};
export default InviteLinkModal;