da691f286e
## Issue If the reward-list fetch is slow, the selector assumes the weekly_watch hasn't been claimed yet, causing an unnecessary claim. ## Change The selector now tells the caller if there is no data -- up to caller on what to do (in this case, don't claim the reward). It should be harmless if the claim action was missed, since the user can still manually claim it.
187 lines
5.4 KiB
JavaScript
187 lines
5.4 KiB
JavaScript
import { Lbryio } from 'lbryinc';
|
|
import { doUpdateBalance } from 'redux/actions/wallet';
|
|
import { doToast } from 'redux/actions/notifications';
|
|
import * as ACTIONS from 'constants/action_types';
|
|
import { selectUnclaimedRewards, selectWeeklyWatchClaimedThisWeek } from 'redux/selectors/rewards';
|
|
import { selectUserIsRewardApproved } from 'redux/selectors/user';
|
|
import { doFetchInviteStatus } from 'redux/actions/user';
|
|
import rewards from 'rewards';
|
|
import { resolveApiMessage } from 'util/api-message';
|
|
|
|
export function doRewardList() {
|
|
return (dispatch) => {
|
|
dispatch({
|
|
type: ACTIONS.FETCH_REWARDS_STARTED,
|
|
});
|
|
|
|
Lbryio.call('reward', 'list', { multiple_rewards_per_type: true })
|
|
.then((userRewards) => {
|
|
dispatch({
|
|
type: ACTIONS.FETCH_REWARDS_COMPLETED,
|
|
data: { userRewards },
|
|
});
|
|
})
|
|
.catch(() => {
|
|
dispatch({
|
|
type: ACTIONS.FETCH_REWARDS_COMPLETED,
|
|
data: { userRewards: [] },
|
|
});
|
|
});
|
|
};
|
|
}
|
|
|
|
export function doClaimRewardType(rewardType, options = {}) {
|
|
return (dispatch, getState) => {
|
|
const state = getState();
|
|
const userIsRewardApproved = selectUserIsRewardApproved(state);
|
|
const unclaimedRewards = selectUnclaimedRewards(state);
|
|
const reward =
|
|
rewardType === rewards.TYPE_REWARD_CODE || rewardType === rewards.TYPE_NEW_ANDROID
|
|
? { reward_type: rewards.TYPE_REWARD_CODE }
|
|
: unclaimedRewards.find((ur) => ur.reward_type === rewardType);
|
|
|
|
// Try to claim the email reward right away, even if we haven't called reward_list yet
|
|
if (
|
|
rewardType !== rewards.TYPE_REWARD_CODE &&
|
|
rewardType !== rewards.TYPE_CONFIRM_EMAIL &&
|
|
rewardType !== rewards.TYPE_WEEKLY_WATCH &&
|
|
rewardType !== rewards.TYPE_NEW_ANDROID
|
|
) {
|
|
if (!reward || reward.transaction_id) {
|
|
// already claimed or doesn't exist, do nothing
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (
|
|
!userIsRewardApproved &&
|
|
rewardType !== rewards.TYPE_CONFIRM_EMAIL &&
|
|
rewardType !== rewards.TYPE_REWARD_CODE &&
|
|
rewardType !== rewards.TYPE_NEW_ANDROID
|
|
) {
|
|
if (!options || (!options.failSilently && rewards.callbacks.rewardApprovalRequested)) {
|
|
rewards.callbacks.rewardApprovalRequested();
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
// Set `claim_code` so the api knows which reward to give if there are multiple of the same type
|
|
const params = options.params || {};
|
|
if (!params.claim_code && reward) {
|
|
params.claim_code = reward.claim_code;
|
|
}
|
|
|
|
dispatch({
|
|
type: ACTIONS.CLAIM_REWARD_STARTED,
|
|
data: { reward },
|
|
});
|
|
|
|
const success = (successReward) => {
|
|
// Temporary timeout to ensure the sdk has the correct balance after claiming a reward
|
|
setTimeout(() => {
|
|
dispatch(doUpdateBalance()).then(() => {
|
|
dispatch({
|
|
type: ACTIONS.CLAIM_REWARD_SUCCESS,
|
|
data: {
|
|
reward: successReward,
|
|
},
|
|
});
|
|
if (successReward.reward_type === rewards.TYPE_NEW_USER && rewards.callbacks.claimFirstRewardSuccess) {
|
|
rewards.callbacks.claimFirstRewardSuccess();
|
|
} else if (successReward.reward_type === rewards.TYPE_REFERRAL) {
|
|
dispatch(doFetchInviteStatus());
|
|
}
|
|
|
|
dispatch(doRewardList());
|
|
|
|
if (options.callback) {
|
|
options.callback();
|
|
}
|
|
});
|
|
}, 2000);
|
|
};
|
|
|
|
const failure = (error) => {
|
|
dispatch({
|
|
type: ACTIONS.CLAIM_REWARD_FAILURE,
|
|
data: {
|
|
reward,
|
|
error: !options || !options.failSilently ? error : undefined,
|
|
},
|
|
});
|
|
|
|
if (options.notifyError) {
|
|
dispatch(doToast({ message: resolveApiMessage(error.message), isError: true }));
|
|
}
|
|
|
|
if (options.callback) {
|
|
options.callback(error);
|
|
}
|
|
};
|
|
|
|
return rewards.claimReward(rewardType, params).then(success, failure);
|
|
};
|
|
}
|
|
|
|
export function doClaimInitialRewards() {
|
|
return (dispatch) => {
|
|
dispatch(doClaimRewardType(rewards.TYPE_NEW_USER));
|
|
dispatch(doClaimRewardType(rewards.TYPE_CONFIRM_EMAIL));
|
|
};
|
|
}
|
|
|
|
export function doClaimEligiblePurchaseRewards() {
|
|
return (dispatch, getState) => {
|
|
const state = getState();
|
|
const unclaimedRewards = selectUnclaimedRewards(state);
|
|
const userIsRewardApproved = selectUserIsRewardApproved(state);
|
|
|
|
if (!userIsRewardApproved || !Lbryio.enabled) {
|
|
return;
|
|
}
|
|
|
|
if (unclaimedRewards.find((ur) => ur.reward_type === rewards.TYPE_FIRST_STREAM)) {
|
|
dispatch(doClaimRewardType(rewards.TYPE_FIRST_STREAM));
|
|
} else {
|
|
if (selectWeeklyWatchClaimedThisWeek(state) === false) {
|
|
dispatch(doClaimRewardType(rewards.TYPE_WEEKLY_WATCH, { failSilently: true }));
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
export function doClaimRewardClearError(reward) {
|
|
return (dispatch) => {
|
|
dispatch({
|
|
type: ACTIONS.CLAIM_REWARD_CLEAR_ERROR,
|
|
data: { reward },
|
|
});
|
|
};
|
|
}
|
|
|
|
export function doFetchRewardedContent() {
|
|
return (dispatch) => {
|
|
const success = (nameToClaimId) => {
|
|
dispatch({
|
|
type: ACTIONS.FETCH_REWARD_CONTENT_COMPLETED,
|
|
data: {
|
|
claimIds: Object.values(nameToClaimId),
|
|
success: true,
|
|
},
|
|
});
|
|
};
|
|
|
|
const failure = () => {
|
|
dispatch({
|
|
type: ACTIONS.FETCH_REWARD_CONTENT_COMPLETED,
|
|
data: {
|
|
claimIds: [],
|
|
success: false,
|
|
},
|
|
});
|
|
};
|
|
|
|
Lbryio.call('reward', 'list_featured').then(success, failure);
|
|
};
|
|
}
|