@livelike/react-native
Version:
LiveLike React Native package
117 lines (111 loc) • 3.72 kB
text/typescript
import {
IWidgetEarnableReward,
IWidgetInteraction,
getRewardTransactions,
getTargetedWidgetIdAndKind,
} from '@livelike/javascript';
import { useEffect, useRef } from 'react';
import {
getWidgetRewardsFromRewardTransactions,
widgetStoreActions,
} from '../store';
import { useWidgetInteractions } from './useWidgetInteractions';
import { useWidgetKind } from './useWidgetKind';
export type UseLoadWidgetRewardsEffectArg = {
widgetId: string;
};
export function useLoadWidgetRewardsEffect({ widgetId }) {
const widgetInteractions = useWidgetInteractions({ widgetId });
const widgetKind = useWidgetKind({ widgetId });
const interactionsRef = useRef<IWidgetInteraction[] | null>(null);
const rewardRef = useRef<IWidgetEarnableReward[] | null>(null);
const mountRef = useRef(null);
useEffect(() => {
// avoid getting reward transactions on initial mount since we are already loading
// widget details including reward transaction as part of useLoadWidgetEffect
if (!mountRef.current && Array.isArray(widgetInteractions)) {
mountRef.current = true;
return;
}
// avoid loading widget rewards if there are no interactions or
// widget interaction are same as earlier interaction
if (!widgetInteractions?.length) {
return;
}
if (
areWidgetInteractionsSame(
widgetInteractions,
interactionsRef.current ?? []
)
) {
return;
}
interactionsRef.current = widgetInteractions;
const timeout = setTimeout(() => {
getTargetedWidgetIdAndKind({ widgetId, widgetKind })
.then(({ widgetId: targettedWidgetId }) =>
getRewardTransactions({ widgetIds: [targettedWidgetId] })
)
.then((res) => {
const widgetRewards = getWidgetRewardsFromRewardTransactions(
res.results
);
if (
rewardRef.current &&
areWidgetRewardsSame(widgetRewards, rewardRef.current)
) {
return;
}
rewardRef.current = widgetRewards;
// Observed a behaviour where old reward animation overlap with new reward animation
// until old reward animation gets resetted and dereferenced
// To avoid overlapping, we clear the existing rewards from state so that
// there's no residue of existing reward animation
Promise.resolve(
widgetStoreActions.updateWidgetRewardsAction({
widgetId,
widgetRewards: [],
})
).then(() =>
widgetStoreActions.updateWidgetRewardsAction({
widgetId,
widgetRewards,
})
);
});
}, 1000);
return () => {
clearTimeout(timeout);
};
}, [widgetId, widgetKind, widgetInteractions]);
}
function areWidgetRewardsSame(
rewardsA: IWidgetEarnableReward[],
rewardsB: IWidgetEarnableReward[]
) {
if (rewardsA.length !== rewardsB.length) {
return false;
}
return rewardsA.every((rewardA) => {
return !!rewardsB.find(
({ reward_item_id, reward_item_amount }) =>
rewardA.reward_item_id === reward_item_id &&
rewardA.reward_item_amount === reward_item_amount
);
});
}
function areWidgetInteractionsSame(
interactionsA: IWidgetInteraction[],
interactionsB: IWidgetInteraction[]
) {
if (interactionsA.length !== interactionsB.length) {
return false;
}
return interactionsA.every((interactionA) => {
return !!interactionsB.find(
({ option_id, choice_id }) =>
(interactionA.option_id && interactionA.option_id === option_id) ||
(interactionA.choice_id && interactionA.choice_id === choice_id)
);
});
}