@told.club/sdk-rn
Version:
Told React Native SDK
216 lines (206 loc) • 11.2 kB
JavaScript
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
import * as React from 'react';
import { Platform } from 'react-native';
import { ApolloClient, InMemoryCache, ApolloProvider } from '@apollo/client';
import { SafeAreaProvider } from 'react-native-safe-area-context';
import { getBundleId } from 'react-native-device-info';
import ToldContext from './ToldContext';
import { GET_EVERY_SURVEY_AVAILABLE_TO_BE_TRIGGERED, CHECK_CAN_USE_SURVEY } from './utils/graphql';
import NavigationListener from './NavigationListener';
import { isCustomEventTriggerConditionTrue, isScreenTriggerConditionTrue } from './utils/triggerConditions';
import ToldWidget from './ToldWidget';
import { isReplied, isSeen, loadSurveyData } from './ToldStorage';
const SERVER_API_URL = 'https://api.told.club';
const WIDGET_URL = 'https://widget.told.club';
export default function ToldProvider({
sourceID,
appVersion,
defaultParams,
defaultHiddenFields,
language,
servers,
children
}) {
const [loaded, setLoaded] = React.useState(false);
const [triggers, setTriggers] = React.useState([]);
const [currentScreenName, setCurrentScreenName] = React.useState('');
const [currentSurvey, setCurrentSurvey] = React.useState(null);
const [hiddenFields, setHiddenFields] = React.useState(defaultHiddenFields || {});
const [lastLoadVars, setLastLoadVars] = React.useState(null);
const {
apiUrl,
widgetUrl
} = React.useMemo(() => ({
apiUrl: (servers === null || servers === void 0 ? void 0 : servers.apiUrl) || SERVER_API_URL,
widgetUrl: (servers === null || servers === void 0 ? void 0 : servers.widgetUrl) || WIDGET_URL
}), [servers]);
const client = React.useMemo(() => new ApolloClient({
uri: `${apiUrl}/graphql`,
cache: new InMemoryCache()
}), [apiUrl]);
const timeoutsRef = React.useRef([]);
// INIT: Load triggers
React.useEffect(() => {
const loadVars = {
folderID: sourceID,
type: 'IN_APP_MOBILE',
os: Platform.OS.toUpperCase(),
mobileApp: getBundleId(),
language: language || 'fr',
version: appVersion || '1.0.0',
listReplied: [],
preview: defaultParams !== null && defaultParams !== void 0 && defaultParams.includes('preview') ? true : false
};
if (lastLoadVars && JSON.stringify(lastLoadVars) === JSON.stringify(loadVars)) return;
loadSurveyData().then(() => {
client.query({
query: GET_EVERY_SURVEY_AVAILABLE_TO_BE_TRIGGERED,
variables: loadVars
}).then(data => {
const {
getEverySurveyAvailableToBeTriggered
} = data.data;
if (defaultParams !== null && defaultParams !== void 0 && defaultParams.includes('debug')) console.log(`Initializing ${getEverySurveyAvailableToBeTriggered === null || getEverySurveyAvailableToBeTriggered === void 0 ? void 0 : getEverySurveyAvailableToBeTriggered.length} survey triggers.`);
setLastLoadVars(loadVars);
setTriggers(getEverySurveyAvailableToBeTriggered);
setLoaded(true);
}).catch(error => {
console.error(`Told SDK not loaded correctly : ${(error === null || error === void 0 ? void 0 : error.message) ?? '(unknown)'}`);
});
});
}, [lastLoadVars, appVersion, defaultParams, language, sourceID, client]);
// Method: Start survey
const start = React.useCallback(surveyId => {
if (defaultParams !== null && defaultParams !== void 0 && defaultParams.includes('seeItOnlyOnce') && isSeen(surveyId)) return;
client.query({
query: CHECK_CAN_USE_SURVEY,
variables: {
surveyID: surveyId,
preview: defaultParams !== null && defaultParams !== void 0 && defaultParams.includes('preview') ? true : false,
os: Platform.OS.toUpperCase(),
mobileApp: getBundleId()
}
}).then(data => {
var _data$data;
const canUse = (data === null || data === void 0 || (_data$data = data.data) === null || _data$data === void 0 || (_data$data = _data$data.checkIfCanUseWidgetWithSurvey) === null || _data$data === void 0 ? void 0 : _data$data.canUse) ?? false;
if (canUse) {
if (defaultParams !== null && defaultParams !== void 0 && defaultParams.includes('debug')) console.log(`Starting survey: ${surveyId}`);
// Start survey
setCurrentSurvey({
surveyId,
sourceID,
params: defaultParams || []
});
} else {
console.log(`Cannot display survey ${surveyId}. Check if survey is correctly configured and enabled on website. Or already seen ?`);
}
}).catch(error => {
console.error(`Told SDK Error while checking if can use widget : ${(error === null || error === void 0 ? void 0 : error.message) ?? '(unknown)'}`);
});
}, [client, defaultParams, sourceID]);
// EVENT: On screen change
React.useEffect(() => {
if (!currentScreenName) return;
if (!loaded) return;
if (defaultParams !== null && defaultParams !== void 0 && defaultParams.includes('debug')) console.log(`Screen changed to ${currentScreenName}`);
checkScreenTriggers(currentScreenName);
}, [currentScreenName, loaded, defaultParams]); // eslint-disable-line react-hooks/exhaustive-deps
const checkScreenTriggers = React.useCallback((screenName, enableDelayCheck = true) => {
const screenTriggers = (triggers === null || triggers === void 0 ? void 0 : triggers.filter(el => (el === null || el === void 0 ? void 0 : el.__typename) === 'SurveyTriggerScreen')) || [];
// Clear previously set timeouts
for (const timeoutId of timeoutsRef.current) clearTimeout(timeoutId);
for (const trigger of screenTriggers) {
var _trigger$whenData, _trigger$whenData2;
if ((_trigger$whenData = trigger.whenData) !== null && _trigger$whenData !== void 0 && _trigger$whenData.seeItOnlyOnce && isSeen(trigger.survey)) {
if (defaultParams !== null && defaultParams !== void 0 && defaultParams.includes('debug')) console.log(`Survey ${trigger.survey} already seen, not triggering again.`);
continue;
}
if ((_trigger$whenData2 = trigger.whenData) !== null && _trigger$whenData2 !== void 0 && _trigger$whenData2.replyOnlyOnce && isReplied(trigger.survey)) {
if (defaultParams !== null && defaultParams !== void 0 && defaultParams.includes('debug')) console.log(`Survey ${trigger.survey} already replied, not triggering again.`);
continue;
}
if ((trigger.onAllScreen ?? false) || isScreenTriggerConditionTrue(trigger.condition, screenName)) {
var _trigger$delay, _trigger$delay2;
const delayEnabled = enableDelayCheck ? ((_trigger$delay = trigger.delay) === null || _trigger$delay === void 0 ? void 0 : _trigger$delay.active) ?? false : false;
const delayValue = delayEnabled ? ((_trigger$delay2 = trigger.delay) === null || _trigger$delay2 === void 0 ? void 0 : _trigger$delay2.value) ?? 0 : 0;
if (delayEnabled) {
const timeoutId = setTimeout(() => {
// Because of js closure, we're using a function to get the current screen name
setCurrentScreenName(_screenName => {
checkScreenTriggers(_screenName, false);
return _screenName;
});
}, delayValue * 1000);
timeoutsRef.current.push(timeoutId);
} else {
if (defaultParams !== null && defaultParams !== void 0 && defaultParams.includes('debug')) console.log(`Triggered survey: ${trigger.survey} on screen ${screenName}`);
start(trigger.survey);
// Start survey
}
}
}
}, [start, triggers, defaultParams]);
const onScreenChange = React.useCallback(screenName => {
setCurrentScreenName(screenName);
}, []);
// EVENT: On custom event
const checkCustomEvent = React.useCallback((eventName, eventProperties) => {
var _customEventTrigger$w, _customEventTrigger$w2;
const customEventTrigger = triggers === null || triggers === void 0 ? void 0 : triggers.find(el => (el === null || el === void 0 ? void 0 : el.__typename) === 'SurveyTriggerCustomEvent' && el.eventName === eventName);
if (!customEventTrigger) return;
// Check whenData conditions
if ((_customEventTrigger$w = customEventTrigger.whenData) !== null && _customEventTrigger$w !== void 0 && _customEventTrigger$w.seeItOnlyOnce && isSeen(customEventTrigger.survey)) {
if (defaultParams !== null && defaultParams !== void 0 && defaultParams.includes('debug')) console.log(`Survey ${customEventTrigger.survey} already seen, not triggering again.`);
return;
}
if ((_customEventTrigger$w2 = customEventTrigger.whenData) !== null && _customEventTrigger$w2 !== void 0 && _customEventTrigger$w2.replyOnlyOnce && isReplied(customEventTrigger.survey)) {
if (defaultParams !== null && defaultParams !== void 0 && defaultParams.includes('debug')) console.log(`Survey ${customEventTrigger.survey} already replied, not triggering again.`);
return;
}
const conditions = customEventTrigger.conditions || [];
let conditionsMet = true;
// Check if all conditions are met
for (const condition of conditions) {
if (condition && condition.key) {
if (!(eventProperties !== null && eventProperties !== void 0 && eventProperties[condition.key]) || !isCustomEventTriggerConditionTrue(condition, (eventProperties === null || eventProperties === void 0 ? void 0 : eventProperties[condition.key]) ?? '')) conditionsMet = false;
}
}
if (conditionsMet) {
if (defaultParams !== null && defaultParams !== void 0 && defaultParams.includes('debug')) console.log(`Triggered survey: ${customEventTrigger.survey} on custom event ${eventName}`);
start(customEventTrigger.survey);
}
}, [defaultParams, start, triggers]);
// EVENT: On survey close callback
const onClose = React.useCallback(() => {
setCurrentSurvey(null);
}, []);
// EVENT: Add hidden field
const addHiddenFields = React.useCallback((newHiddenFields, setData) => {
if (setData) {
// If we want to set the hidden fields, we clear the previous ones
setHiddenFields(newHiddenFields || {});
} else {
// If we want to add hidden fields, we merge them
setHiddenFields(prevHiddenFields => ({
...prevHiddenFields,
...newHiddenFields
}));
}
}, []);
return /*#__PURE__*/React.createElement(SafeAreaProvider, null, /*#__PURE__*/React.createElement(ApolloProvider, {
client: client
}, /*#__PURE__*/React.createElement(NavigationListener, {
onScreenChange: onScreenChange
}, /*#__PURE__*/React.createElement(ToldContext.Provider, {
value: {
hiddenFields,
trackScreen: onScreenChange,
sendCustomEvent: checkCustomEvent,
close: onClose,
addHiddenFields
}
}, children, currentSurvey && /*#__PURE__*/React.createElement(ToldWidget, _extends({}, currentSurvey, {
widgetUrl: widgetUrl
}))))));
}
//# sourceMappingURL=ToldProvider.js.map