@applicaster/quick-brick-core
Version:
Core package for Applicaster's Quick Brick App
222 lines (181 loc) • 6.21 kB
text/typescript
import { useActions } from "@applicaster/zapp-react-native-redux/hooks";
import * as R from "ramda";
import * as React from "react";
import axios from "axios";
import { useDispatch } from "react-redux";
import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks";
import { useFeedLoader } from "@applicaster/zapp-react-native-utils/reactHooks/feed/useFeedLoader";
import { sessionStorage } from "@applicaster/zapp-react-native-bridge/ZappStorage/SessionStorage";
import { loadAppContextData } from "@applicaster/zapp-react-native-redux";
import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
import {
setAppNotReady,
setAppReady,
} from "@applicaster/zapp-react-native-redux/appState";
import {
findRiver,
getKeyFromStorage,
handlePresentNavigation,
isInternalUrl,
} from "../../helpers";
import { log_error, log_info } from "../../logger";
import { useRivers } from "@applicaster/zapp-react-native-utils/reactHooks/state";
const getFeed = (query) => ({
content: { src: query.data_source },
screen_type: query.screen_id,
});
export function usePresentSchemeHandler({
query,
url,
onFinish,
}: UrlSchemeHandlerArgs) {
const {
screen_id,
data_source,
entry_id,
rivers_configuration_id,
resumeTime,
link_url,
show_nav_bar,
content_type,
} = query;
React.useEffect(() => {
log_info(`Handling present url ${url}`, { query });
}, []);
const navigator = useNavigation();
const { data: feedData } = useFeedLoader({
feedUrl: data_source,
});
const rivers = useRivers();
const screenRiver = findRiver({ screen_id, rivers });
const dispatch = useDispatch();
const actions = useActions({
setAppReady,
setAppNotReady,
});
const navigateTo = React.useCallback(
(data) => {
onFinish((done) => {
handlePresentNavigation({
data,
navigator,
pushScreen: isInternalUrl(url) || link_url,
});
done?.();
});
},
[onFinish, navigator, rivers, url]
);
const setCustomLayout = React.useCallback(
async ({ rivers_configuration_id }) => {
let sessionData: Partial<SessionStorageKeys> = {};
try {
sessionData = await sessionStorage.getAllItems("applicaster.v2");
// ios returns accountsAccountID, while android has accountsAccountId
// until this is aligned, we're pulling both values and use the one that
// isn't undefined
const accountKey = sessionData.accountsAccountId
? "accountsAccountId"
: "zapp_account_id";
// @ts-ignore - to be fixed on iOS side
// key accountsAccountID should be accountsAccountId
const accountId = getKeyFromStorage<string>(accountKey, sessionData);
const appBundleIdentifier = getKeyFromStorage<string>(
"bundleIdentifier",
sessionData
);
const versionName = getKeyFromStorage<string>(
"version_name",
sessionData
);
const familyId = getKeyFromStorage<string>(
"app_family_id",
sessionData
);
const storeKey = getKeyFromStorage<string>("store", sessionData);
const riversUrl = `https://assets-secure.applicaster.com/zapp/accounts/${accountId}/apps/${appBundleIdentifier}/${storeKey}/${versionName}/layouts/${rivers_configuration_id}.json`;
const cellStylesUrl = `https://assets-secure.applicaster.com/zapp/accounts/${accountId}/app_families/${familyId}/layouts/${rivers_configuration_id}/cell_styles.json`;
const presetsMappingUrl = `https://assets-secure.applicaster.com/zapp/accounts/${accountId}/app_families/${familyId}/layouts/${rivers_configuration_id}/presets_mapping.json`;
actions?.setAppNotReady();
const { data: newRivers } = await axios.get(riversUrl);
const { data: cellStyles } = await axios.get(cellStylesUrl);
const presetsMapping = await axios
.get(presetsMappingUrl)
.then(({ data }) => data)
.catch(noop);
loadAppContextData(dispatch, {
cellStyles,
rivers: newRivers,
contentTypes: newRivers.content_types,
presetsMapping,
});
const homeRiver = R.compose(
R.find(R.propEq("home", true)),
R.ifElse(R.has("screens"), R.prop("screens"), R.values)
)(newRivers);
await sessionStorage.setItem(
"rivers_configuration_id",
rivers_configuration_id
);
onFinish((done) => {
actions?.setAppReady();
navigator.replace(homeRiver);
done?.();
});
} catch (error) {
log_error(`Cannot handle present url ${url}`, {
query,
error: error.message,
sessionData,
});
onFinish((done) => {
actions?.setAppReady();
navigator.goHome();
done?.();
});
}
},
[]
);
const getFeedEntry = React.useCallback(
() =>
query.entry_id
? R.compose(
R.when(
() => resumeTime,
R.assocPath(["extensions", "resumeTime"], resumeTime)
),
R.find(R.propEq("id", entry_id))
)(feedData?.entry || [])
: getFeed(query),
[feedData, query]
);
const getLinkEntry = React.useCallback(() => {
const linkEntry: ZappEntry = {
id: "url_scheme_entry",
type: { value: content_type || "link" },
link: {
type: "text/html",
href: decodeURIComponent(link_url),
},
extensions: {
showNavBar: show_nav_bar === "true",
},
};
if (screenRiver) {
linkEntry.screen_type = screenRiver.id;
}
return linkEntry;
}, [show_nav_bar, link_url]);
if (link_url) {
navigateTo(getLinkEntry());
} else if (rivers_configuration_id) {
setCustomLayout({ rivers_configuration_id });
} else if ((data_source || entry_id) && feedData) {
navigateTo(getFeedEntry());
} else if (screenRiver) {
navigateTo(screenRiver);
} else if (!!screen_id && !screenRiver) {
throw new Error("сan not proceed this URL");
}
}