Subscribe notify #1066
10 changed files with 218 additions and 12 deletions
|
@ -15,8 +15,8 @@ class FileList extends React.PureComponent {
|
||||||
this._sortFunctions = {
|
this._sortFunctions = {
|
||||||
dateNew(fileInfos) {
|
dateNew(fileInfos) {
|
||||||
return fileInfos.slice().sort((fileInfo1, fileInfo2) => {
|
return fileInfos.slice().sort((fileInfo1, fileInfo2) => {
|
||||||
const height1 = fileInfo1.height
|
const height1 = fileInfo1.height;
|
||||||
const height2 = fileInfo2.height
|
const height2 = fileInfo2.height;
|
||||||
if (height1 > height2) {
|
if (height1 > height2) {
|
||||||
return -1;
|
return -1;
|
||||||
} else if (height1 < height2) {
|
} else if (height1 < height2) {
|
||||||
|
@ -27,8 +27,8 @@ class FileList extends React.PureComponent {
|
||||||
},
|
},
|
||||||
dateOld(fileInfos) {
|
dateOld(fileInfos) {
|
||||||
return fileInfos.slice().sort((fileInfo1, fileInfo2) => {
|
return fileInfos.slice().sort((fileInfo1, fileInfo2) => {
|
||||||
const height1 = fileInfo1.height
|
const height1 = fileInfo1.height;
|
||||||
const height2 = fileInfo2.height
|
const height2 = fileInfo2.height;
|
||||||
if (height1 < height2) {
|
if (height1 < height2) {
|
||||||
return -1;
|
return -1;
|
||||||
} else if (height1 > height2) {
|
} else if (height1 > height2) {
|
||||||
|
|
|
@ -15,8 +15,8 @@ const RewardSummary = (props: Props) => {
|
||||||
<div className="card__title-primary">
|
<div className="card__title-primary">
|
||||||
<h3>{__('Rewards')}</h3>
|
<h3>{__('Rewards')}</h3>
|
||||||
<p className="help">
|
<p className="help">
|
||||||
{__('Read our')}{' '}
|
{__('Read our')} <Link href="https://lbry.io/faq/rewards">{__('FAQ')}</Link>{' '}
|
||||||
<Link href="https://lbry.io/faq/rewards">{__('FAQ')}</Link>{' '}{__('to learn more about LBRY Rewards')}.
|
{__('to learn more about LBRY Rewards')}.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="card__content">
|
<div className="card__content">
|
||||||
|
|
|
@ -164,6 +164,10 @@ export const CLEAR_SHAPE_SHIFT = 'CLEAR_SHAPE_SHIFT';
|
||||||
export const CHANNEL_SUBSCRIBE = 'CHANNEL_SUBSCRIBE';
|
export const CHANNEL_SUBSCRIBE = 'CHANNEL_SUBSCRIBE';
|
||||||
export const CHANNEL_UNSUBSCRIBE = 'CHANNEL_UNSUBSCRIBE';
|
export const CHANNEL_UNSUBSCRIBE = 'CHANNEL_UNSUBSCRIBE';
|
||||||
export const HAS_FETCHED_SUBSCRIPTIONS = 'HAS_FETCHED_SUBSCRIPTIONS';
|
export const HAS_FETCHED_SUBSCRIPTIONS = 'HAS_FETCHED_SUBSCRIPTIONS';
|
||||||
|
export const SET_SUBSCRIPTION_LATEST = 'SET_SUBSCRIPTION_LATEST';
|
||||||
|
export const CHECK_SUBSCRIPTION_STARTED = 'CHECK_SUBSCRIPTION_STARTED';
|
||||||
|
export const CHECK_SUBSCRIPTION_COMPLETED = 'CHECK_SUBSCRIPTION_COMPLETED';
|
||||||
|
export const CHECK_SUBSCRIPTIONS_SUBSCRIBE = 'CHECK_SUBSCRIPTIONS_SUBSCRIBE';
|
||||||
|
|
||||||
// Video controls
|
// Video controls
|
||||||
export const SET_VIDEO_PAUSE = 'SET_VIDEO_PAUSE';
|
export const SET_VIDEO_PAUSE = 'SET_VIDEO_PAUSE';
|
||||||
|
|
|
@ -63,7 +63,7 @@ ipcRenderer.on('window-is-focused', () => {
|
||||||
|
|
||||||
document.addEventListener('dragover', event => {
|
document.addEventListener('dragover', event => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
})
|
});
|
||||||
document.addEventListener('drop', event => {
|
document.addEventListener('drop', event => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
});
|
});
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { doFetchFileInfo } from 'redux/actions/file_info';
|
||||||
import { makeSelectFileInfoForUri } from 'redux/selectors/file_info';
|
import { makeSelectFileInfoForUri } from 'redux/selectors/file_info';
|
||||||
import { selectRewardContentClaimIds } from 'redux/selectors/content';
|
import { selectRewardContentClaimIds } from 'redux/selectors/content';
|
||||||
import { doFetchCostInfoForUri } from 'redux/actions/cost_info';
|
import { doFetchCostInfoForUri } from 'redux/actions/cost_info';
|
||||||
|
import { checkSubscriptionLatest } from 'redux/actions/subscriptions';
|
||||||
import {
|
import {
|
||||||
makeSelectClaimForUri,
|
makeSelectClaimForUri,
|
||||||
makeSelectContentTypeForUri,
|
makeSelectContentTypeForUri,
|
||||||
|
@ -13,6 +14,7 @@ import { makeSelectCostInfoForUri } from 'redux/selectors/cost_info';
|
||||||
import { selectShowNsfw } from 'redux/selectors/settings';
|
import { selectShowNsfw } from 'redux/selectors/settings';
|
||||||
import FilePage from './view';
|
import FilePage from './view';
|
||||||
import { makeSelectCurrentParam } from 'redux/selectors/navigation';
|
import { makeSelectCurrentParam } from 'redux/selectors/navigation';
|
||||||
|
import { selectSubscriptions } from 'redux/selectors/subscriptions';
|
||||||
|
|
||||||
const select = (state, props) => ({
|
const select = (state, props) => ({
|
||||||
claim: makeSelectClaimForUri(props.uri)(state),
|
claim: makeSelectClaimForUri(props.uri)(state),
|
||||||
|
@ -23,12 +25,15 @@ const select = (state, props) => ({
|
||||||
tab: makeSelectCurrentParam('tab')(state),
|
tab: makeSelectCurrentParam('tab')(state),
|
||||||
fileInfo: makeSelectFileInfoForUri(props.uri)(state),
|
fileInfo: makeSelectFileInfoForUri(props.uri)(state),
|
||||||
rewardedContentClaimIds: selectRewardContentClaimIds(state, props),
|
rewardedContentClaimIds: selectRewardContentClaimIds(state, props),
|
||||||
|
subscriptions: selectSubscriptions(state),
|
||||||
});
|
});
|
||||||
|
|
||||||
const perform = dispatch => ({
|
const perform = dispatch => ({
|
||||||
navigate: (path, params) => dispatch(doNavigate(path, params)),
|
navigate: (path, params) => dispatch(doNavigate(path, params)),
|
||||||
fetchFileInfo: uri => dispatch(doFetchFileInfo(uri)),
|
fetchFileInfo: uri => dispatch(doFetchFileInfo(uri)),
|
||||||
fetchCostInfo: uri => dispatch(doFetchCostInfoForUri(uri)),
|
fetchCostInfo: uri => dispatch(doFetchCostInfoForUri(uri)),
|
||||||
|
checkSubscriptionLatest: (subscription, uri) =>
|
||||||
|
dispatch(checkSubscriptionLatest(subscription, uri)),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(select, perform)(FilePage);
|
export default connect(select, perform)(FilePage);
|
||||||
|
|
|
@ -17,6 +17,7 @@ class FilePage extends React.PureComponent {
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.fetchFileInfo(this.props);
|
this.fetchFileInfo(this.props);
|
||||||
this.fetchCostInfo(this.props);
|
this.fetchCostInfo(this.props);
|
||||||
|
this.checkSubscriptionLatest(this.props);
|
||||||
good call good call
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps) {
|
componentWillReceiveProps(nextProps) {
|
||||||
|
@ -35,6 +36,28 @@ class FilePage extends React.PureComponent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
checkSubscriptionLatest(props) {
|
||||||
|
if (
|
||||||
|
props.subscriptions
|
||||||
|
.map(subscription => subscription.channelName)
|
||||||
|
.indexOf(props.claim.channel_name) !== -1
|
||||||
|
) {
|
||||||
|
props.checkSubscriptionLatest(
|
||||||
|
{
|
||||||
|
channelName: props.claim.channel_name,
|
||||||
|
uri: buildURI(
|
||||||
|
{
|
||||||
|
contentName: props.claim.channel_name,
|
||||||
|
claimId: props.claim.value.publisherSignature.certificateId,
|
||||||
|
},
|
||||||
|
false
|
||||||
|
),
|
||||||
|
},
|
||||||
|
buildURI({ contentName: props.claim.name, claimId: props.claim.claim_id }, false)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
claim,
|
claim,
|
||||||
|
|
|
@ -11,6 +11,8 @@ import { doFetchDaemonSettings } from 'redux/actions/settings';
|
||||||
import { doAuthenticate } from 'redux/actions/user';
|
import { doAuthenticate } from 'redux/actions/user';
|
||||||
import { doBalanceSubscribe } from 'redux/actions/wallet';
|
import { doBalanceSubscribe } from 'redux/actions/wallet';
|
||||||
import { doPause } from 'redux/actions/media';
|
import { doPause } from 'redux/actions/media';
|
||||||
|
import { doCheckSubscriptions } from 'redux/actions/subscriptions';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
selectCurrentModal,
|
selectCurrentModal,
|
||||||
selectIsUpgradeSkipped,
|
selectIsUpgradeSkipped,
|
||||||
|
@ -253,6 +255,7 @@ export function doDaemonReady() {
|
||||||
dispatch(doCheckUpgradeAvailable());
|
dispatch(doCheckUpgradeAvailable());
|
||||||
}
|
}
|
||||||
dispatch(doCheckUpgradeSubscribe());
|
dispatch(doCheckUpgradeSubscribe());
|
||||||
|
dispatch(doCheckSubscriptions());
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ import Lbryio from 'lbryio';
|
||||||
import { normalizeURI, buildURI } from 'lbryURI';
|
import { normalizeURI, buildURI } from 'lbryURI';
|
||||||
import { doAlertError, doOpenModal } from 'redux/actions/app';
|
import { doAlertError, doOpenModal } from 'redux/actions/app';
|
||||||
import { doClaimEligiblePurchaseRewards } from 'redux/actions/rewards';
|
import { doClaimEligiblePurchaseRewards } from 'redux/actions/rewards';
|
||||||
|
import { setSubscriptionLatest } from 'redux/actions/subscriptions';
|
||||||
import { selectBadgeNumber } from 'redux/selectors/app';
|
import { selectBadgeNumber } from 'redux/selectors/app';
|
||||||
import { selectMyClaimsRaw } from 'redux/selectors/claims';
|
import { selectMyClaimsRaw } from 'redux/selectors/claims';
|
||||||
import { selectResolvingUris } from 'redux/selectors/content';
|
import { selectResolvingUris } from 'redux/selectors/content';
|
||||||
|
@ -288,7 +289,7 @@ export function doLoadVideo(uri) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function doPurchaseUri(uri) {
|
export function doPurchaseUri(uri, specificCostInfo) {
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
const balance = selectBalance(state);
|
const balance = selectBalance(state);
|
||||||
|
@ -321,7 +322,7 @@ export function doPurchaseUri(uri) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const costInfo = makeSelectCostInfoForUri(uri)(state);
|
const costInfo = makeSelectCostInfoForUri(uri)(state) || specificCostInfo;
|
||||||
const { cost } = costInfo;
|
const { cost } = costInfo;
|
||||||
|
|
||||||
if (cost > balance) {
|
if (cost > balance) {
|
||||||
|
@ -358,6 +359,25 @@ export function doFetchClaimsByChannel(uri, page) {
|
||||||
const claimResult = result[uri] || {};
|
const claimResult = result[uri] || {};
|
||||||
const { claims_in_channel: claimsInChannel, returned_page: returnedPage } = claimResult;
|
const { claims_in_channel: claimsInChannel, returned_page: returnedPage } = claimResult;
|
||||||
|
|
||||||
|
if (claimsInChannel && claimsInChannel.length) {
|
||||||
|
const latest = claimsInChannel[0];
|
||||||
|
dispatch(
|
||||||
|
setSubscriptionLatest(
|
||||||
|
{
|
||||||
|
channelName: latest.channel_name,
|
||||||
|
uri: buildURI(
|
||||||
|
{
|
||||||
|
contentName: latest.channel_name,
|
||||||
|
claimId: latest.value.publisherSignature.certificateId,
|
||||||
|
},
|
||||||
|
false
|
||||||
|
),
|
||||||
|
},
|
||||||
|
buildURI({ contentName: latest.name, claimId: latest.claim_id }, false)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: ACTIONS.FETCH_CHANNEL_CLAIMS_COMPLETED,
|
type: ACTIONS.FETCH_CHANNEL_CLAIMS_COMPLETED,
|
||||||
data: {
|
data: {
|
||||||
|
|
|
@ -1,6 +1,13 @@
|
||||||
// @flow
|
// @flow
|
||||||
import * as ACTIONS from 'constants/action_types';
|
import * as ACTIONS from 'constants/action_types';
|
||||||
import type { Subscription, Dispatch } from 'redux/reducers/subscriptions';
|
import type { Subscription, Dispatch, SubscriptionState } from 'redux/reducers/subscriptions';
|
||||||
|
import { selectSubscriptions } from 'redux/selectors/subscriptions';
|
||||||
|
import Lbry from 'lbry';
|
||||||
|
import { doPurchaseUri } from 'redux/actions/content';
|
||||||
|
import { doNavigate } from 'redux/actions/navigation';
|
||||||
|
import { buildURI } from 'lbryURI';
|
||||||
|
|
||||||
|
const CHECK_SUBSCRIPTIONS_INTERVAL = 10 * 60 * 1000;
|
||||||
|
|
||||||
export const doChannelSubscribe = (subscription: Subscription) => (dispatch: Dispatch) =>
|
export const doChannelSubscribe = (subscription: Subscription) => (dispatch: Dispatch) =>
|
||||||
dispatch({
|
dispatch({
|
||||||
|
@ -14,5 +21,113 @@ export const doChannelUnsubscribe = (subscription: Subscription) => (dispatch: D
|
||||||
data: subscription,
|
data: subscription,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const doCheckSubscriptions = () => (
|
||||||
|
dispatch: Dispatch,
|
||||||
|
getState: () => SubscriptionState
|
||||||
|
) => {
|
||||||
|
const checkSubscriptionsTimer = setInterval(
|
||||||
|
() =>
|
||||||
|
selectSubscriptions(getState()).map((subscription: Subscription) =>
|
||||||
|
dispatch(doCheckSubscription(subscription))
|
||||||
|
),
|
||||||
|
CHECK_SUBSCRIPTIONS_INTERVAL
|
||||||
|
);
|
||||||
|
dispatch({
|
||||||
|
type: ACTIONS.CHECK_SUBSCRIPTIONS_SUBSCRIBE,
|
||||||
|
data: { checkSubscriptionsTimer },
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const doCheckSubscription = (subscription: Subscription) => (dispatch: Dispatch) => {
|
||||||
|
dispatch({
|
||||||
|
type: ACTIONS.CHECK_SUBSCRIPTION_STARTED,
|
||||||
|
data: subscription,
|
||||||
|
});
|
||||||
|
|
||||||
|
Lbry.claim_list_by_channel({ uri: subscription.uri, page: 1 }).then(result => {
|
||||||
|
const claimResult = result[subscription.uri] || {};
|
||||||
|
const { claims_in_channel: claimsInChannel } = claimResult;
|
||||||
|
|
||||||
|
const count = subscription.latest
|
||||||
|
? claimsInChannel.reduce(
|
||||||
|
(prev, cur, index) =>
|
||||||
|
buildURI({ contentName: cur.name, claimId: cur.claim_id }, false) ===
|
||||||
|
subscription.latest
|
||||||
|
? index
|
||||||
|
: prev,
|
||||||
|
-1
|
||||||
|
)
|
||||||
|
: 1;
|
||||||
|
|
||||||
|
if (count !== 0) {
|
||||||
|
if (!claimsInChannel[0].value.stream.metadata.fee) {
|
||||||
|
dispatch(
|
||||||
|
doPurchaseUri(
|
||||||
|
buildURI(
|
||||||
|
{ contentName: claimsInChannel[0].name, claimId: claimsInChannel[0].claim_id },
|
||||||
|
false
|
||||||
|
),
|
||||||
|
{ cost: 0 }
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const notif = new window.Notification(subscription.channelName, {
|
||||||
|
body: `Posted ${claimsInChannel[0].value.stream.metadata.title}${
|
||||||
|
count > 1 ? ` and ${count - 1} other new items` : ''
|
||||||
|
}${count < 0 ? ' and 9+ other new items' : ''}`,
|
||||||
|
silent: false,
|
||||||
|
});
|
||||||
|
notif.onclick = () => {
|
||||||
|
dispatch(
|
||||||
|
doNavigate('/show', {
|
||||||
|
uri: buildURI(
|
||||||
|
{ contentName: claimsInChannel[0].name, claimId: claimsInChannel[0].claim_id },
|
||||||
|
true
|
||||||
|
),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
//$FlowIssue
|
||||||
I think this should have a case for I think this should have a case for `count === 1`, which is probably the most likely scenario. I think in that case just showing the title would make the most sense.
it does, it just says
instead of, for example,
it does, it just says
```
"Sean"
"Posted myVideo"
```
instead of, for example,
```
"Sean"
"Posted myVideo and 9+ other new items"
```
|
|||||||
|
dispatch({
|
||||||
|
type: ACTIONS.CHECK_SUBSCRIPTION_COMPLETED,
|
||||||
|
data: subscription,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const checkSubscriptionLatest = (channel: Subscription, uri: string) => (
|
||||||
|
dispatch: Dispatch
|
||||||
|
) => {
|
||||||
|
Lbry.claim_list_by_channel({ uri: channel.uri, page: 1 }).then(result => {
|
||||||
|
const claimResult = result[channel.uri] || {};
|
||||||
|
const { claims_in_channel: claimsInChannel } = claimResult;
|
||||||
|
|
||||||
|
if (
|
||||||
|
claimsInChannel &&
|
||||||
|
claimsInChannel.length &&
|
||||||
|
buildURI(
|
||||||
|
{ contentName: claimsInChannel[0].name, claimId: claimsInChannel[0].claim_id },
|
||||||
|
false
|
||||||
|
) === uri
|
||||||
|
) {
|
||||||
|
dispatch(setSubscriptionLatest(channel, uri));
|
||||||
Is this function actually necessary? Could Is this function actually necessary? Could `doCheckSubscription` just call `setSubscriptionLatest`?
check and set are different, set simply sets the value in the redux store. Check does an asynchronous call and sets the value accordingly by dispatching set, if that makes sense. check and set are different, set simply sets the value in the redux store. Check does an asynchronous call and sets the value accordingly by dispatching set, if that makes sense.
I'm asking two things in my question:
I'm asking two things in my question:
1) If we're already fetching the latest subscription data at time interval `n`, is it actually necessary to check for the latest for this same information when accessing a file page?
2) If it is necessary (for staleness reasons, presumably), why can't more of the code be shared between the two? Isn't `doCheckSubscription` a superset of the functionality provided by `checkSubscriptionLatest`? and why wouldn't you want `checkSubscriptionLatest` to also begin downloads? Furthermore, why do _both_ of these call `Lbry.claim_list_by_channel` when they could call `doFetchClaimsByChannel` instead?
@liamcardenas did you see above? @liamcardenas did you see above?
|
|||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const setSubscriptionLatest = (subscription: Subscription, uri: string) => (
|
||||||
|
dispatch: Dispatch
|
||||||
|
) =>
|
||||||
|
dispatch({
|
||||||
|
type: ACTIONS.SET_SUBSCRIPTION_LATEST,
|
||||||
|
data: {
|
||||||
|
subscription,
|
||||||
|
uri,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
export const setHasFetchedSubscriptions = () => (dispatch: Dispatch) =>
|
export const setHasFetchedSubscriptions = () => (dispatch: Dispatch) =>
|
||||||
dispatch({ type: ACTIONS.HAS_FETCHED_SUBSCRIPTIONS });
|
dispatch({ type: ACTIONS.HAS_FETCHED_SUBSCRIPTIONS });
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { handleActions } from 'util/redux-utils';
|
||||||
export type Subscription = {
|
export type Subscription = {
|
||||||
channelName: string,
|
channelName: string,
|
||||||
uri: string,
|
uri: string,
|
||||||
|
latest: ?string,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Subscription redux types
|
// Subscription redux types
|
||||||
|
@ -28,7 +29,30 @@ type HasFetchedSubscriptions = {
|
||||||
type: ACTIONS.HAS_FETCHED_SUBSCRIPTIONS,
|
type: ACTIONS.HAS_FETCHED_SUBSCRIPTIONS,
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Action = doChannelSubscribe | doChannelUnsubscribe | HasFetchedSubscriptions;
|
type setSubscriptionLatest = {
|
||||||
|
type: ACTIONS.SET_SUBSCRIPTION_LATEST,
|
||||||
|
data: {
|
||||||
|
subscription: Subscription,
|
||||||
|
uri: string,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
type CheckSubscriptionStarted = {
|
||||||
|
type: ACTIONS.CHECK_SUBSCRIPTION_STARTED,
|
||||||
|
};
|
||||||
|
|
||||||
|
type CheckSubscriptionCompleted = {
|
||||||
|
type: ACTIONS.CHECK_SUBSCRIPTION_COMPLETED,
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Action =
|
||||||
|
| doChannelSubscribe
|
||||||
|
| doChannelUnsubscribe
|
||||||
|
| HasFetchedSubscriptions
|
||||||
|
| setSubscriptionLatest
|
||||||
|
| CheckSubscriptionStarted
|
||||||
|
| CheckSubscriptionCompleted
|
||||||
|
| Function;
|
||||||
export type Dispatch = (action: Action) => any;
|
export type Dispatch = (action: Action) => any;
|
||||||
|
|
||||||
const defaultState = {
|
const defaultState = {
|
||||||
|
@ -70,6 +94,18 @@ export default handleActions(
|
||||||
...state,
|
...state,
|
||||||
hasFetchedSubscriptions: true,
|
hasFetchedSubscriptions: true,
|
||||||
}),
|
}),
|
||||||
|
[ACTIONS.SET_SUBSCRIPTION_LATEST]: (
|
||||||
|
state: SubscriptionState,
|
||||||
|
action: setSubscriptionLatest
|
||||||
|
): SubscriptionState => ({
|
||||||
|
...state,
|
||||||
|
subscriptions: state.subscriptions.map(
|
||||||
|
subscription =>
|
||||||
|
subscription.channelName === action.data.subscription.channelName
|
||||||
|
? { ...subscription, latest: action.data.uri }
|
||||||
|
: subscription
|
||||||
|
),
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
defaultState
|
defaultState
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in a new issue
You can avoid a lot of unnecessary calls by only calling
checkSubscriptionLatest
if you are subscribed to that channel