rewards refactor to support types, add list
This commit is contained in:
parent
31fb723d87
commit
2b8296fcc3
18 changed files with 240 additions and 131 deletions
|
@ -2,7 +2,7 @@ import * as types from "constants/action_types";
|
||||||
import * as modals from "constants/modal_types";
|
import * as modals from "constants/modal_types";
|
||||||
import lbryio from "lbryio";
|
import lbryio from "lbryio";
|
||||||
import rewards from "rewards";
|
import rewards from "rewards";
|
||||||
import { selectRewardsByType } from "selectors/rewards";
|
import { selectUnclaimedRewardsByType } from "selectors/rewards";
|
||||||
|
|
||||||
export function doRewardList() {
|
export function doRewardList() {
|
||||||
return function(dispatch, getState) {
|
return function(dispatch, getState) {
|
||||||
|
@ -13,7 +13,7 @@ export function doRewardList() {
|
||||||
});
|
});
|
||||||
|
|
||||||
lbryio
|
lbryio
|
||||||
.call("reward", "list", {})
|
.call("reward", "list", { multiple_rewards_per_type: true })
|
||||||
.then(userRewards => {
|
.then(userRewards => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: types.FETCH_REWARDS_COMPLETED,
|
type: types.FETCH_REWARDS_COMPLETED,
|
||||||
|
@ -31,17 +31,9 @@ export function doRewardList() {
|
||||||
|
|
||||||
export function doClaimRewardType(rewardType) {
|
export function doClaimRewardType(rewardType) {
|
||||||
return function(dispatch, getState) {
|
return function(dispatch, getState) {
|
||||||
const rewardsByType = selectRewardsByType(getState()),
|
const rewardsByType = selectUnclaimedRewardsByType(getState()),
|
||||||
reward = rewardsByType[rewardType];
|
reward = rewardsByType[rewardType];
|
||||||
|
|
||||||
if (reward) {
|
|
||||||
dispatch(doClaimReward(reward));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function doClaimReward(reward, saveError = false) {
|
|
||||||
return function(dispatch, getState) {
|
|
||||||
if (reward.transaction_id) {
|
if (reward.transaction_id) {
|
||||||
//already claimed, do nothing
|
//already claimed, do nothing
|
||||||
return;
|
return;
|
||||||
|
@ -72,7 +64,7 @@ export function doClaimReward(reward, saveError = false) {
|
||||||
type: types.CLAIM_REWARD_FAILURE,
|
type: types.CLAIM_REWARD_FAILURE,
|
||||||
data: {
|
data: {
|
||||||
reward,
|
reward,
|
||||||
error: saveError ? error : null,
|
error: error ? error : null,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -87,26 +79,18 @@ export function doClaimEligiblePurchaseRewards() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const rewardsByType = selectRewardsByType(getState());
|
const rewardsByType = selectUnclaimedRewardsByType(getState());
|
||||||
|
|
||||||
let types = {};
|
if (rewardsByType[rewards.TYPE_FIRST_STREAM]) {
|
||||||
|
dispatch(doClaimRewardType(rewards.TYPE_FIRST_STREAM));
|
||||||
types[rewards.TYPE_FIRST_STREAM] = false;
|
} else {
|
||||||
types[rewards.TYPE_FEATURED_DOWNLOAD] = false;
|
[
|
||||||
types[rewards.TYPE_MANY_DOWNLOADS] = false;
|
rewards.TYPE_MANY_DOWNLOADS,
|
||||||
Object.values(rewardsByType).forEach(reward => {
|
rewards.TYPE_FEATURED_DOWNLOAD,
|
||||||
if (types[reward.reward_type] === false && reward.transaction_id) {
|
].forEach(type => {
|
||||||
types[reward.reward_type] = true;
|
dispatch(doClaimRewardType(type));
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let unclaimedType = Object.keys(types).find(type => {
|
|
||||||
return types[type] === false && type !== rewards.TYPE_FEATURED_DOWNLOAD; //handled below
|
|
||||||
});
|
|
||||||
if (unclaimedType) {
|
|
||||||
dispatch(doClaimRewardType(unclaimedType));
|
|
||||||
}
|
}
|
||||||
dispatch(doClaimRewardType(rewards.TYPE_FEATURED_DOWNLOAD));
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
5
ui/js/component/linkTransaction/index.js
Normal file
5
ui/js/component/linkTransaction/index.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import React from "react";
|
||||||
|
import { connect } from "react-redux";
|
||||||
|
import Link from "./view";
|
||||||
|
|
||||||
|
export default connect(null, null)(Link);
|
14
ui/js/component/linkTransaction/view.jsx
Normal file
14
ui/js/component/linkTransaction/view.jsx
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
import React from "react";
|
||||||
|
import Link from "component/link";
|
||||||
|
|
||||||
|
const LinkTransaction = props => {
|
||||||
|
const { id } = props;
|
||||||
|
const linkProps = Object.assign({}, props);
|
||||||
|
|
||||||
|
linkProps.href = "https://explorer.lbry.io/#!/transaction/" + id;
|
||||||
|
linkProps.label = id.substr(0, 7);
|
||||||
|
|
||||||
|
return <Link {...linkProps} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default LinkTransaction;
|
|
@ -6,7 +6,7 @@ import {
|
||||||
makeSelectIsRewardClaimPending,
|
makeSelectIsRewardClaimPending,
|
||||||
} from "selectors/rewards";
|
} from "selectors/rewards";
|
||||||
import { doNavigate } from "actions/app";
|
import { doNavigate } from "actions/app";
|
||||||
import { doClaimReward, doClaimRewardClearError } from "actions/rewards";
|
import { doClaimRewardType, doClaimRewardClearError } from "actions/rewards";
|
||||||
import RewardLink from "./view";
|
import RewardLink from "./view";
|
||||||
|
|
||||||
const makeSelect = () => {
|
const makeSelect = () => {
|
||||||
|
@ -24,7 +24,7 @@ const makeSelect = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const perform = dispatch => ({
|
const perform = dispatch => ({
|
||||||
claimReward: reward => dispatch(doClaimReward(reward, true)),
|
claimReward: reward => dispatch(doClaimRewardType(reward.reward_type, true)),
|
||||||
clearError: reward => dispatch(doClaimRewardClearError(reward)),
|
clearError: reward => dispatch(doClaimRewardClearError(reward)),
|
||||||
navigate: path => dispatch(doNavigate(path)),
|
navigate: path => dispatch(doNavigate(path)),
|
||||||
});
|
});
|
||||||
|
|
10
ui/js/component/rewardListClaimed/index.js
Normal file
10
ui/js/component/rewardListClaimed/index.js
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
import React from "react";
|
||||||
|
import { connect } from "react-redux";
|
||||||
|
import { selectClaimedRewards } from "selectors/rewards";
|
||||||
|
import RewardListClaimed from "./view";
|
||||||
|
|
||||||
|
const select = state => ({
|
||||||
|
rewards: selectClaimedRewards(state),
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(select, null)(RewardListClaimed);
|
44
ui/js/component/rewardListClaimed/view.jsx
Normal file
44
ui/js/component/rewardListClaimed/view.jsx
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
import React from "react";
|
||||||
|
import LinkTransaction from "component/linkTransaction";
|
||||||
|
|
||||||
|
const RewardListClaimed = props => {
|
||||||
|
const { rewards } = props;
|
||||||
|
|
||||||
|
if (!rewards || !rewards.length) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section className="card">
|
||||||
|
<div className="card__title-identity"><h3>Claimed Rewards</h3></div>
|
||||||
|
<div className="card__content">
|
||||||
|
<table className="table-standard table-stretch">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>{__("Title")}</th>
|
||||||
|
<th>{__("Amount")}</th>
|
||||||
|
<th>{__("Transaction")}</th>
|
||||||
|
<th>{__("Date")}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{rewards.map(reward => {
|
||||||
|
return (
|
||||||
|
<tr key={reward.id}>
|
||||||
|
<td>{reward.reward_title}</td>
|
||||||
|
<td>{reward.reward_amount}</td>
|
||||||
|
<td><LinkTransaction id={reward.transaction_id} /></td>
|
||||||
|
<td>
|
||||||
|
{reward.created_at.replace("Z", " ").replace("T", " ")}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default RewardListClaimed;
|
5
ui/js/component/rewardTile/index.js
Normal file
5
ui/js/component/rewardTile/index.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import React from "react";
|
||||||
|
import { connect } from "react-redux";
|
||||||
|
import RewardTile from "./view";
|
||||||
|
|
||||||
|
export default connect(null, null)(RewardTile);
|
28
ui/js/component/rewardTile/view.jsx
Normal file
28
ui/js/component/rewardTile/view.jsx
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
import React from "react";
|
||||||
|
import { CreditAmount, Icon } from "component/common";
|
||||||
|
import RewardLink from "component/rewardLink";
|
||||||
|
|
||||||
|
const RewardTile = props => {
|
||||||
|
const { reward } = props;
|
||||||
|
|
||||||
|
const claimed = !!reward.transaction_id;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section className="card">
|
||||||
|
<div className="card__inner">
|
||||||
|
<div className="card__title-primary">
|
||||||
|
<CreditAmount amount={reward.reward_amount} />
|
||||||
|
<h3>{reward.reward_title}</h3>
|
||||||
|
</div>
|
||||||
|
<div className="card__actions">
|
||||||
|
{claimed
|
||||||
|
? <span><Icon icon="icon-check" /> {__("Reward claimed.")}</span>
|
||||||
|
: <RewardLink reward_type={reward.reward_type} />}
|
||||||
|
</div>
|
||||||
|
<div className="card__content">{reward.reward_description}</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default RewardTile;
|
|
@ -13,6 +13,7 @@ import DeveloperPage from "page/developer.js";
|
||||||
import RewardsPage from "page/rewards";
|
import RewardsPage from "page/rewards";
|
||||||
import FileListDownloaded from "page/fileListDownloaded";
|
import FileListDownloaded from "page/fileListDownloaded";
|
||||||
import FileListPublished from "page/fileListPublished";
|
import FileListPublished from "page/fileListPublished";
|
||||||
|
import TransactionHistoryPage from "page/transactionHistory";
|
||||||
import ChannelPage from "page/channel";
|
import ChannelPage from "page/channel";
|
||||||
import SearchPage from "page/search";
|
import SearchPage from "page/search";
|
||||||
import AuthPage from "page/auth";
|
import AuthPage from "page/auth";
|
||||||
|
@ -36,6 +37,7 @@ const Router = props => {
|
||||||
discover: <DiscoverPage params={params} />,
|
discover: <DiscoverPage params={params} />,
|
||||||
downloaded: <FileListDownloaded params={params} />,
|
downloaded: <FileListDownloaded params={params} />,
|
||||||
help: <HelpPage params={params} />,
|
help: <HelpPage params={params} />,
|
||||||
|
history: <TransactionHistoryPage params={params} />,
|
||||||
invite: <InvitePage params={params} />,
|
invite: <InvitePage params={params} />,
|
||||||
publish: <PublishPage params={params} />,
|
publish: <PublishPage params={params} />,
|
||||||
published: <FileListPublished params={params} />,
|
published: <FileListPublished params={params} />,
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Address, BusyMessage, CreditAmount } from "component/common";
|
import { BusyMessage } from "component/common";
|
||||||
|
import LinkTransaction from "component/linkTransaction";
|
||||||
|
|
||||||
class TransactionList extends React.PureComponent {
|
class TransactionList extends React.PureComponent {
|
||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
|
@ -26,12 +27,7 @@ class TransactionList extends React.PureComponent {
|
||||||
: <span className="empty">{__("(Transaction pending)")}</span>}
|
: <span className="empty">{__("(Transaction pending)")}</span>}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<a
|
<LinkTransaction id={item.id} />
|
||||||
className="button-text"
|
|
||||||
href={"https://explorer.lbry.io/#!/transaction/" + item.id}
|
|
||||||
>
|
|
||||||
{item.id.substr(0, 7)}
|
|
||||||
</a>
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
);
|
);
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { selectUserIsRewardApproved } from "selectors/user";
|
||||||
import {
|
import {
|
||||||
makeSelectHasClaimedReward,
|
makeSelectHasClaimedReward,
|
||||||
makeSelectRewardByType,
|
makeSelectRewardByType,
|
||||||
selectTotalRewardValue,
|
selectUnclaimedRewardValue,
|
||||||
} from "selectors/rewards";
|
} from "selectors/rewards";
|
||||||
import * as settings from "constants/settings";
|
import * as settings from "constants/settings";
|
||||||
import ModalCreditIntro from "./view";
|
import ModalCreditIntro from "./view";
|
||||||
|
@ -19,7 +19,7 @@ const select = (state, props) => {
|
||||||
return {
|
return {
|
||||||
isRewardApproved: selectUserIsRewardApproved(state),
|
isRewardApproved: selectUserIsRewardApproved(state),
|
||||||
reward: selectReward(state, { reward_type: rewards.TYPE_NEW_USER }),
|
reward: selectReward(state, { reward_type: rewards.TYPE_NEW_USER }),
|
||||||
totalRewardValue: selectTotalRewardValue(state),
|
totalRewardValue: selectUnclaimedRewardValue(state),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,23 +1,18 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import {
|
import {
|
||||||
makeSelectRewardByType,
|
|
||||||
selectFetchingRewards,
|
selectFetchingRewards,
|
||||||
selectRewards,
|
selectUnclaimedRewards,
|
||||||
} from "selectors/rewards";
|
} from "selectors/rewards";
|
||||||
import { selectUser } from "selectors/user";
|
import { selectUser } from "selectors/user";
|
||||||
import { doAuthNavigate, doNavigate } from "actions/app";
|
import { doAuthNavigate, doNavigate } from "actions/app";
|
||||||
import { doRewardList } from "actions/rewards";
|
import { doRewardList } from "actions/rewards";
|
||||||
import rewards from "rewards";
|
|
||||||
import RewardsPage from "./view";
|
import RewardsPage from "./view";
|
||||||
|
|
||||||
const select = (state, props) => {
|
const select = (state, props) => {
|
||||||
const selectReward = makeSelectRewardByType();
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
fetching: selectFetchingRewards(state),
|
fetching: selectFetchingRewards(state),
|
||||||
rewards: selectRewards(state),
|
rewards: selectUnclaimedRewards(state),
|
||||||
newUserReward: selectReward(state, { reward_type: rewards.TYPE_NEW_USER }),
|
|
||||||
user: selectUser(state),
|
user: selectUser(state),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,31 +1,9 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { BusyMessage, CreditAmount, Icon } from "component/common";
|
import { BusyMessage } from "component/common";
|
||||||
|
import RewardListClaimed from "component/rewardListClaimed";
|
||||||
|
import RewardTile from "component/rewardTile";
|
||||||
import SubHeader from "component/subHeader";
|
import SubHeader from "component/subHeader";
|
||||||
import Link from "component/link";
|
import Link from "component/link";
|
||||||
import RewardLink from "component/rewardLink";
|
|
||||||
|
|
||||||
const RewardTile = props => {
|
|
||||||
const { reward } = props;
|
|
||||||
|
|
||||||
const claimed = !!reward.transaction_id;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<section className="card">
|
|
||||||
<div className="card__inner">
|
|
||||||
<div className="card__title-primary">
|
|
||||||
<CreditAmount amount={reward.reward_amount} />
|
|
||||||
<h3>{reward.reward_title}</h3>
|
|
||||||
</div>
|
|
||||||
<div className="card__actions">
|
|
||||||
{claimed
|
|
||||||
? <span><Icon icon="icon-check" /> {__("Reward claimed.")}</span>
|
|
||||||
: <RewardLink reward_type={reward.reward_type} />}
|
|
||||||
</div>
|
|
||||||
<div className="card__content">{reward.reward_description}</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
class RewardsPage extends React.PureComponent {
|
class RewardsPage extends React.PureComponent {
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
|
@ -44,32 +22,8 @@ class RewardsPage extends React.PureComponent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
renderPageHeader() {
|
||||||
const { doAuth, fetching, navigate, rewards, user } = this.props;
|
const { doAuth, navigate, user } = this.props;
|
||||||
|
|
||||||
let content, cardHeader;
|
|
||||||
|
|
||||||
if (fetching) {
|
|
||||||
content = (
|
|
||||||
<div className="card__content">
|
|
||||||
<BusyMessage message={__("Fetching rewards")} />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
} else if (rewards.length > 0) {
|
|
||||||
content = (
|
|
||||||
<div>
|
|
||||||
{rewards.map(reward =>
|
|
||||||
<RewardTile key={reward.reward_type} reward={reward} />
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
content = (
|
|
||||||
<div className="card__content empty">
|
|
||||||
{__("Failed to load rewards.")}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (user && !user.is_reward_approved) {
|
if (user && !user.is_reward_approved) {
|
||||||
if (
|
if (
|
||||||
|
@ -77,7 +31,7 @@ class RewardsPage extends React.PureComponent {
|
||||||
!user.has_verified_email ||
|
!user.has_verified_email ||
|
||||||
!user.is_identity_verified
|
!user.is_identity_verified
|
||||||
) {
|
) {
|
||||||
cardHeader = (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="card__content empty">
|
<div className="card__content empty">
|
||||||
<p>
|
<p>
|
||||||
|
@ -90,7 +44,7 @@ class RewardsPage extends React.PureComponent {
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
cardHeader = (
|
return (
|
||||||
<div className="card__content">
|
<div className="card__content">
|
||||||
<p>
|
<p>
|
||||||
{__(
|
{__(
|
||||||
|
@ -122,9 +76,21 @@ class RewardsPage extends React.PureComponent {
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
renderUnclaimedRewards() {
|
||||||
|
const { fetching, rewards, user } = this.props;
|
||||||
|
|
||||||
|
if (fetching) {
|
||||||
|
return (
|
||||||
|
<div className="card__content">
|
||||||
|
<BusyMessage message={__("Fetching rewards")} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
} else if (user === null) {
|
} else if (user === null) {
|
||||||
cardHeader = (
|
|
||||||
<div>
|
return (
|
||||||
<div className="card__content empty">
|
<div className="card__content empty">
|
||||||
<p>
|
<p>
|
||||||
{__(
|
{__(
|
||||||
|
@ -132,15 +98,27 @@ class RewardsPage extends React.PureComponent {
|
||||||
)}
|
)}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
);
|
||||||
|
} else if (!rewards || rewards.length <= 0) {
|
||||||
|
return (
|
||||||
|
<div className="card__content empty">
|
||||||
|
{__("Failed to load rewards.")}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
return rewards.map(reward =>
|
||||||
|
<RewardTile key={reward.reward_type} reward={reward} />
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
return (
|
return (
|
||||||
<main className="main--single-column">
|
<main className="main--single-column">
|
||||||
<SubHeader />
|
<SubHeader />
|
||||||
{cardHeader && <section className="card">{cardHeader}</section>}
|
{this.renderPageHeader()}
|
||||||
{content}
|
{this.renderUnclaimedRewards()}
|
||||||
|
{<RewardListClaimed />}
|
||||||
</main>
|
</main>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
5
ui/js/page/transactionHistory/index.js
Normal file
5
ui/js/page/transactionHistory/index.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import React from "react";
|
||||||
|
import { connect } from "react-redux";
|
||||||
|
import WalletPage from "./view";
|
||||||
|
|
||||||
|
export default connect(null, null)(WalletPage);
|
14
ui/js/page/transactionHistory/view.jsx
Normal file
14
ui/js/page/transactionHistory/view.jsx
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
import React from "react";
|
||||||
|
import SubHeader from "component/subHeader";
|
||||||
|
import TransactionList from "component/transactionList";
|
||||||
|
|
||||||
|
const TransactionHistoryPage = props => {
|
||||||
|
return (
|
||||||
|
<main className="main--single-column">
|
||||||
|
<SubHeader />
|
||||||
|
<TransactionList />
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TransactionHistoryPage;
|
|
@ -3,7 +3,8 @@ import * as types from "constants/action_types";
|
||||||
const reducers = {};
|
const reducers = {};
|
||||||
const defaultState = {
|
const defaultState = {
|
||||||
fetching: false,
|
fetching: false,
|
||||||
rewardsByType: {},
|
claimedRewardsById: {}, //id => reward
|
||||||
|
unclaimedRewardsByType: {},
|
||||||
claimPendingByType: {},
|
claimPendingByType: {},
|
||||||
claimErrorsByType: {},
|
claimErrorsByType: {},
|
||||||
};
|
};
|
||||||
|
@ -17,11 +18,19 @@ reducers[types.FETCH_REWARDS_STARTED] = function(state, action) {
|
||||||
reducers[types.FETCH_REWARDS_COMPLETED] = function(state, action) {
|
reducers[types.FETCH_REWARDS_COMPLETED] = function(state, action) {
|
||||||
const { userRewards } = action.data;
|
const { userRewards } = action.data;
|
||||||
|
|
||||||
const rewardsByType = {};
|
let unclaimedRewards = {},
|
||||||
userRewards.forEach(reward => (rewardsByType[reward.reward_type] = reward));
|
claimedRewards = {};
|
||||||
|
userRewards.forEach(reward => {
|
||||||
|
if (reward.transaction_id) {
|
||||||
|
claimedRewards[reward.id] = reward;
|
||||||
|
} else {
|
||||||
|
unclaimedRewards[reward.reward_type] = reward;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return Object.assign({}, state, {
|
return Object.assign({}, state, {
|
||||||
rewardsByType: rewardsByType,
|
claimedRewardsById: claimedRewards,
|
||||||
|
unclaimedRewardsByType: unclaimedRewards,
|
||||||
fetching: false,
|
fetching: false,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -55,16 +64,22 @@ reducers[types.CLAIM_REWARD_STARTED] = function(state, action) {
|
||||||
reducers[types.CLAIM_REWARD_SUCCESS] = function(state, action) {
|
reducers[types.CLAIM_REWARD_SUCCESS] = function(state, action) {
|
||||||
const { reward } = action.data;
|
const { reward } = action.data;
|
||||||
|
|
||||||
const existingReward = state.rewardsByType[reward.reward_type];
|
let unclaimedRewardsByType = Object.assign({}, state.unclaimedRewardsByType);
|
||||||
|
const existingReward = unclaimedRewardsByType[reward.reward_type];
|
||||||
|
delete state.unclaimedRewardsByType[reward.reward_type];
|
||||||
|
|
||||||
const newReward = Object.assign({}, reward, {
|
const newReward = Object.assign({}, reward, {
|
||||||
reward_title: existingReward.reward_title,
|
reward_title: existingReward.reward_title,
|
||||||
reward_description: existingReward.reward_description,
|
reward_description: existingReward.reward_description,
|
||||||
});
|
});
|
||||||
const rewardsByType = Object.assign({}, state.rewardsByType);
|
|
||||||
|
|
||||||
rewardsByType[reward.reward_type] = newReward;
|
let claimedRewardsById = Object.assign({}, state.claimedRewardsById);
|
||||||
|
claimedRewardsById[reward.id] = newReward;
|
||||||
|
|
||||||
const newState = Object.assign({}, state, { rewardsByType });
|
const newState = Object.assign({}, state, {
|
||||||
|
unclaimedRewardsByType,
|
||||||
|
claimedRewardsById,
|
||||||
|
});
|
||||||
|
|
||||||
return setClaimRewardState(newState, newReward, false, "");
|
return setClaimRewardState(newState, newReward, false, "");
|
||||||
};
|
};
|
||||||
|
|
|
@ -136,6 +136,7 @@ export const selectHeaderLinks = createSelector(selectCurrentPage, page => {
|
||||||
// This contains intentional fall throughs
|
// This contains intentional fall throughs
|
||||||
switch (page) {
|
switch (page) {
|
||||||
case "wallet":
|
case "wallet":
|
||||||
|
case "history":
|
||||||
case "send":
|
case "send":
|
||||||
case "receive":
|
case "receive":
|
||||||
case "invite":
|
case "invite":
|
||||||
|
@ -143,6 +144,7 @@ export const selectHeaderLinks = createSelector(selectCurrentPage, page => {
|
||||||
case "backup":
|
case "backup":
|
||||||
return {
|
return {
|
||||||
wallet: __("Overview"),
|
wallet: __("Overview"),
|
||||||
|
history: __("History"),
|
||||||
send: __("Send"),
|
send: __("Send"),
|
||||||
receive: __("Receive"),
|
receive: __("Receive"),
|
||||||
invite: __("Invites"),
|
invite: __("Invites"),
|
||||||
|
|
|
@ -3,13 +3,23 @@ import { selectUser } from "selectors/user";
|
||||||
|
|
||||||
const _selectState = state => state.rewards || {};
|
const _selectState = state => state.rewards || {};
|
||||||
|
|
||||||
export const selectRewardsByType = createSelector(
|
export const selectUnclaimedRewardsByType = createSelector(
|
||||||
_selectState,
|
_selectState,
|
||||||
state => state.rewardsByType || {}
|
state => state.unclaimedRewardsByType
|
||||||
);
|
);
|
||||||
|
|
||||||
export const selectRewards = createSelector(
|
export const selectClaimedRewardsById = createSelector(
|
||||||
selectRewardsByType,
|
_selectState,
|
||||||
|
state => state.claimedRewardsById
|
||||||
|
);
|
||||||
|
|
||||||
|
export const selectClaimedRewards = createSelector(
|
||||||
|
selectClaimedRewardsById,
|
||||||
|
byId => Object.values(byId) || []
|
||||||
|
);
|
||||||
|
|
||||||
|
export const selectUnclaimedRewards = createSelector(
|
||||||
|
selectUnclaimedRewardsByType,
|
||||||
byType => Object.values(byType) || []
|
byType => Object.values(byType) || []
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -23,7 +33,9 @@ export const selectFetchingRewards = createSelector(
|
||||||
state => !!state.fetching
|
state => !!state.fetching
|
||||||
);
|
);
|
||||||
|
|
||||||
export const selectTotalRewardValue = createSelector(selectRewards, rewards =>
|
export const selectUnclaimedRewardValue = createSelector(
|
||||||
|
selectUnclaimedRewards,
|
||||||
|
rewards =>
|
||||||
rewards.reduce((sum, reward) => {
|
rewards.reduce((sum, reward) => {
|
||||||
return sum + reward.reward_amount;
|
return sum + reward.reward_amount;
|
||||||
}, 0)
|
}, 0)
|
||||||
|
@ -65,7 +77,7 @@ export const makeSelectClaimRewardError = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const selectRewardByType = (state, props) => {
|
const selectRewardByType = (state, props) => {
|
||||||
return selectRewardsByType(state)[props.reward_type];
|
return selectUnclaimedRewardsByType(state)[props.reward_type];
|
||||||
};
|
};
|
||||||
|
|
||||||
export const makeSelectRewardByType = () => {
|
export const makeSelectRewardByType = () => {
|
||||||
|
|
Loading…
Add table
Reference in a new issue