Defer user/invite_status from startup

## Issue
Closes 385

## Approach
As mentioned in the ticket, the current places where that info is needed is in the Invites Page and Social Share Component.

1. Invites Page: it is already doing the fetch on mount, so no issue there.
2. Social Share: show spinner until the data is fetched.
This commit is contained in:
infinite-persistence 2022-01-21 18:11:42 +08:00 committed by Thomas Zarebczan
parent 2340138ab5
commit 7fc66aecb6
6 changed files with 47 additions and 7 deletions

View file

@ -1,15 +1,21 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { doFetchInviteStatus } from 'redux/actions/user';
import { makeSelectClaimForUri, selectTitleForUri } from 'redux/selectors/claims'; import { makeSelectClaimForUri, selectTitleForUri } from 'redux/selectors/claims';
import SocialShare from './view'; import SocialShare from './view';
import { selectUserInviteReferralCode, selectUser } from 'redux/selectors/user'; import { selectUserInviteReferralCode, selectUser, selectUserInviteStatusFetched } from 'redux/selectors/user';
import { makeSelectContentPositionForUri } from 'redux/selectors/content'; import { makeSelectContentPositionForUri } from 'redux/selectors/content';
const select = (state, props) => ({ const select = (state, props) => ({
claim: makeSelectClaimForUri(props.uri)(state), claim: makeSelectClaimForUri(props.uri)(state),
inviteStatusFetched: selectUserInviteStatusFetched(state),
referralCode: selectUserInviteReferralCode(state), referralCode: selectUserInviteReferralCode(state),
user: selectUser(state), user: selectUser(state),
title: selectTitleForUri(state, props.uri), title: selectTitleForUri(state, props.uri),
position: makeSelectContentPositionForUri(props.uri)(state), position: makeSelectContentPositionForUri(props.uri)(state),
}); });
export default connect(select)(SocialShare); const perform = {
doFetchInviteStatus,
};
export default connect(select, perform)(SocialShare);

View file

@ -4,6 +4,7 @@ import React from 'react';
import Button from 'component/button'; import Button from 'component/button';
import CopyableText from 'component/copyableText'; import CopyableText from 'component/copyableText';
import EmbedTextArea from 'component/embedTextArea'; import EmbedTextArea from 'component/embedTextArea';
import Spinner from 'component/spinner';
import { generateDownloadUrl } from 'util/web'; import { generateDownloadUrl } from 'util/web';
import { useIsMobile } from 'effects/use-screensize'; import { useIsMobile } from 'effects/use-screensize';
import { FormField } from 'component/common/form'; import { FormField } from 'component/common/form';
@ -22,14 +23,26 @@ type Props = {
claim: StreamClaim, claim: StreamClaim,
title: ?string, title: ?string,
webShareable: boolean, webShareable: boolean,
inviteStatusFetched: boolean,
referralCode: string, referralCode: string,
user: any, user: any,
position: number, position: number,
collectionId?: number, collectionId?: number,
doFetchInviteStatus: (boolean) => void,
}; };
function SocialShare(props: Props) { function SocialShare(props: Props) {
const { claim, title, referralCode, user, webShareable, position, collectionId } = props; const {
claim,
title,
inviteStatusFetched,
referralCode,
user,
webShareable,
position,
collectionId,
doFetchInviteStatus,
} = props;
const [showEmbed, setShowEmbed] = React.useState(false); const [showEmbed, setShowEmbed] = React.useState(false);
const [includeCollectionId, setIncludeCollectionId] = React.useState(Boolean(collectionId)); // unless it *is* a collection? const [includeCollectionId, setIncludeCollectionId] = React.useState(Boolean(collectionId)); // unless it *is* a collection?
const [showClaimLinks, setShowClaimLinks] = React.useState(false); const [showClaimLinks, setShowClaimLinks] = React.useState(false);
@ -38,8 +51,20 @@ function SocialShare(props: Props) {
const startTimeSeconds: number = hmsToSeconds(startTime); const startTimeSeconds: number = hmsToSeconds(startTime);
const isMobile = useIsMobile(); const isMobile = useIsMobile();
React.useEffect(() => {
if (!inviteStatusFetched) {
doFetchInviteStatus(false);
}
}, [inviteStatusFetched, doFetchInviteStatus]);
if (!claim) { if (!claim) {
return null; return null;
} else if (!inviteStatusFetched) {
return (
<div className="main--empty">
<Spinner />
</div>
);
} }
const { canonical_url: canonicalUrl, permanent_url: permanentUrl, name, claim_id: claimId } = claim; const { canonical_url: canonicalUrl, permanent_url: permanentUrl, name, claim_id: claimId } = claim;

View file

@ -18,7 +18,7 @@ const select = (state) => ({
}); });
const perform = (dispatch) => ({ const perform = (dispatch) => ({
fetchInviteStatus: () => dispatch(doFetchInviteStatus()), fetchInviteStatus: (callRewardList) => dispatch(doFetchInviteStatus(callRewardList)),
acknowledgeInivte: () => dispatch(doSetClientSetting(SETTINGS.INVITE_ACKNOWLEDGED, true)), acknowledgeInivte: () => dispatch(doSetClientSetting(SETTINGS.INVITE_ACKNOWLEDGED, true)),
}); });

View file

@ -13,13 +13,13 @@ type Props = {
inviteAcknowledged: boolean, inviteAcknowledged: boolean,
authenticated: boolean, authenticated: boolean,
acknowledgeInivte: () => void, acknowledgeInivte: () => void,
fetchInviteStatus: () => void, fetchInviteStatus: (boolean) => void,
}; };
class InvitePage extends React.PureComponent<Props> { class InvitePage extends React.PureComponent<Props> {
componentDidMount() { componentDidMount() {
const { fetchInviteStatus, inviteAcknowledged, acknowledgeInivte } = this.props; const { fetchInviteStatus, inviteAcknowledged, acknowledgeInivte } = this.props;
fetchInviteStatus(); fetchInviteStatus(false);
if (!inviteAcknowledged) { if (!inviteAcknowledged) {
acknowledgeInivte(); acknowledgeInivte();

View file

@ -126,7 +126,7 @@ export function doAuthenticate(
if (shareUsageData) { if (shareUsageData) {
dispatch(doRewardList()); dispatch(doRewardList());
dispatch(doFetchInviteStatus(false));
if (callInstall && !user?.device_types?.includes('web')) { if (callInstall && !user?.device_types?.includes('web')) {
doInstallNew(appVersion, callbackForUsersWhoAreSharingData, DOMAIN); doInstallNew(appVersion, callbackForUsersWhoAreSharingData, DOMAIN);
} }

View file

@ -82,10 +82,19 @@ export const selectUserInviteStatusFailed = createSelector(
() => selectUserInvitesRemaining === null () => selectUserInvitesRemaining === null
); );
export const selectUserInviteStatusFetched = (state) => {
// A successful fetch produces something; a failed fetch sets it to 'null'.
return selectUserInvitees(state) !== undefined;
};
export const selectUserInviteNewIsPending = (state) => selectState(state).inviteNewIsPending; export const selectUserInviteNewIsPending = (state) => selectState(state).inviteNewIsPending;
export const selectUserInviteNewErrorMessage = (state) => selectState(state).inviteNewErrorMessage; export const selectUserInviteNewErrorMessage = (state) => selectState(state).inviteNewErrorMessage;
export const selectUserInviteReferralLink = (state) => selectState(state).referralLink; export const selectUserInviteReferralLink = (state) => selectState(state).referralLink;
/**
* Returns the invitation referral code.
* Clients should use selectUserInviteStatusFetched to check if the info has been fetched.
*/
export const selectUserInviteReferralCode = createSelector(selectState, (state) => export const selectUserInviteReferralCode = createSelector(selectState, (state) =>
state.referralCode ? state.referralCode[0] : '' state.referralCode ? state.referralCode[0] : ''
); );