@livelike/react-native
Version:
LiveLike React Native package
251 lines (245 loc) • 8.33 kB
JavaScript
import { getRewardTransactions, getTargetedWidgetIdAndKind, addProgramListener, removeProgramListener, WidgetCreatedEvent, getPostedWidgets, getWidgetsInteractions, PREDICTION_FOLLOW_UP_WIDGET_KIND, PREDICTION_WIDGET_ID_PROP, getWidgetInteractions } from '@livelike/javascript';
import { useCallback, useEffect, useRef, useState } from 'react';
import { getSelectedOptionIndex, getWidgeUIPhase, getWidgetResultState, getWidgetRewardsFromRewardTransactions, widgetStoreActions, timelineWidgetStoreActions } from '../store';
import { useApi } from './useApi';
import { WidgetMode } from '../types';
export function useLoadTimelineWidgetEffect(_ref) {
let {
programId,
mode
} = _ref;
const [moreWidgets, setMoreWidgets] = useState(false);
const nextIteratorRef = useRef();
const {
onApi,
isLoading,
error,
data
} = useApi(() => getPostedWidgets({
programId
}).then(widgetsPayload => {
if (!widgetsPayload.done) {
setMoreWidgets(true);
nextIteratorRef.current = widgetsPayload.next;
}
return widgetsPayload;
}).then(getWidgetsDetails));
useEffect(() => {
if (mode === WidgetMode.POPUP) {
timelineWidgetStoreActions.updateTimelineWidgetStateAction({
programId,
widgetTimelineState: {
widgets: []
}
});
return;
}
onApi().then(apiData => updateWidgetsState(apiData, programId));
}, [programId, mode]);
useEffect(() => {
if (!data && mode === WidgetMode.INTERACTIVE_TIMELINE) {
return;
}
function onProgramListener(_ref2) {
let {
event,
message
} = _ref2;
if (Object.values(WidgetCreatedEvent).includes(event)) {
const {
id: widgetId,
kind: widgetKind
} = message;
const widgetPayload = message;
(PREDICTION_FOLLOW_UP_WIDGET_KIND.includes(widgetKind) ? getWidgetInteractions({
widgetId,
widgetKind,
interactionUrl: widgetPayload.widget_interactions_url_template
}) : Promise.resolve([])).then(widgetInteractions => {
widgetStoreActions.updateWidgetStateAction({
widgetId,
widgetState: {
widgetPayload,
widgetInteractions,
widgetResultState: getWidgetResultState({
widgetPayload,
widgetInteractions
}),
widgetUIPhase: getWidgeUIPhase({
widgetPayload,
widgetInteractions
}),
selectedOptionIndex: getSelectedOptionIndex({
widgetPayload,
widgetInteractions
}),
isTimelineWidget: true
}
});
timelineWidgetStoreActions.updateTimelineWidgetsAction({
programId,
widgets: [{
widgetId,
widgetKind
}],
prepend: true
});
});
}
}
addProgramListener({
programId
}, onProgramListener);
return () => {
removeProgramListener({
programId
}, onProgramListener);
};
}, [data, programId, mode]);
const onLoadMore = useCallback(() => {
if (nextIteratorRef.current) {
return nextIteratorRef.current().then(res => {
if (res.done) {
setMoreWidgets(false);
nextIteratorRef.current = null;
}
return res.value;
}).then(getWidgetsDetails).then(widgetsData => updateWidgetsState(widgetsData, programId));
}
}, [nextIteratorRef.current, programId]);
return {
onApi,
isLoading,
error,
data,
onLoadMore: moreWidgets ? onLoadMore : null
};
}
const getWidgetsDetails = widgetsPayload => {
return Promise.all([getWidgetsInteractions({
interactionUrl: widgetsPayload.widget_interactions_url_template
}), Promise.all(widgetsPayload.widgets.map(widget => getTargetedWidgetIdAndKind({
widget
}))).then(widgetIdsAndKinds => getAllRewardTransasctions(widgetIdsAndKinds.map(_ref3 => {
let {
widgetId
} = _ref3;
return widgetId;
})))]).then(_ref4 => {
let [widgetInteractions, widgetRewards] = _ref4;
return [widgetsPayload.widgets, widgetInteractions, widgetRewards];
});
};
const updateWidgetsState = (_ref5, programId) => {
let [widgets, widgetInteractions, widgetRewards] = _ref5;
const {
widgetRecords: widgetsPayloadRecord,
followUpWidgetRecords
} = getWidgetPayloadRecord(widgets);
const widgetsInteractionsRecord = getWidgetsInteractionsRecord(widgetInteractions, followUpWidgetRecords);
const widgetsRewardsRecord = getWidgetsRewardsRecord(widgetRewards, followUpWidgetRecords);
// set individual widget state so that widget details are not reloaded
// This is done to avoid sending multiple widget details request for every widget rendered
// that would give same response.
Object.keys(widgetsPayloadRecord).forEach(widgetId => {
const widgetPayload = widgetsPayloadRecord[widgetId];
const widgetInteractions = widgetsInteractionsRecord[widgetId] ?? [];
widgetStoreActions.updateWidgetStateAction({
widgetId,
widgetState: {
widgetPayload,
widgetInteractions,
widgetRewards: widgetsRewardsRecord[widgetId],
widgetResultState: getWidgetResultState({
widgetPayload,
widgetInteractions
}),
widgetUIPhase: getWidgeUIPhase({
widgetPayload,
widgetInteractions
}),
selectedOptionIndex: getSelectedOptionIndex({
widgetPayload,
widgetInteractions
}),
isTimelineWidget: true
}
});
});
timelineWidgetStoreActions.updateTimelineWidgetsAction({
programId,
widgets: widgets.map(_ref6 => {
let {
id: widgetId,
kind: widgetKind
} = _ref6;
return {
widgetId,
widgetKind
};
})
});
};
// get all reward transactions incase there are multiple pages of
// reward transactions
const getAllRewardTransasctions = async widgetIds => {
const response = await getRewardTransactions({
widgetIds
});
let results = response.results;
let done = response.done;
while (!done) {
const res = await response.next();
results = results.concat(res.value.results);
done = res.done;
}
return results;
};
// create a record of widgetId vs widgetpayload
function getWidgetPayloadRecord(widgets) {
const followUpWidgetRecords = {};
const widgetRecords = widgets.reduce((record, widgetPayload) => {
record[widgetPayload.id] = widgetPayload;
if (PREDICTION_FOLLOW_UP_WIDGET_KIND.includes(widgetPayload.kind)) {
followUpWidgetRecords[widgetPayload.id] = widgetPayload;
}
return record;
}, {});
return {
widgetRecords,
followUpWidgetRecords
};
}
// create a record of widgetId vs widgetInteractions
function getWidgetsInteractionsRecord(widgetsInteractions, followUpWidgetRecords) {
const record = {};
for (const interactions of Object.values(widgetsInteractions)) {
for (const interaction of interactions) {
record[interaction.widget_id] = [...(record[interaction.widget_id] ?? []), interaction];
}
}
// set followup widget interaction using its corresponding prediction widget id
for (const predictionWidget of Object.values(followUpWidgetRecords)) {
const widgetId = predictionWidget[PREDICTION_WIDGET_ID_PROP[predictionWidget.kind]];
if (widgetId && record[widgetId]) {
record[predictionWidget.id] = record[widgetId];
}
}
return record;
}
// create a record of widgetId vs widgetRewards
function getWidgetsRewardsRecord(widgetsRewards, followUpWidgetRecords) {
const record = {};
for (const reward of widgetsRewards) {
record[reward.widget_id] = [...(record[reward.widget_id] ?? []), ...getWidgetRewardsFromRewardTransactions([reward])];
}
// set followup widget rewards using its corresponding prediction widget id
for (const predictionWidget of Object.values(followUpWidgetRecords)) {
const widgetId = predictionWidget[PREDICTION_WIDGET_ID_PROP[predictionWidget.kind]];
if (widgetId && record[widgetId]) {
record[predictionWidget.id] = record[widgetId];
}
}
return record;
}
//# sourceMappingURL=useLoadTimelineWidgetEffect.js.map