UNPKG

@microbitsclub/paywall-solid

Version:
128 lines (127 loc) 5.2 kB
import { DEFAULTS } from '@microbitsclub/microbits-client'; import crossFetch from 'cross-fetch'; import Cookies from 'js-cookie'; import { createStore } from 'solid-js/store'; import { createUrlPath, stringifyUrl } from './url'; export const createPaywallPopoverStore = (config) => { const fetch = config.fetchFunction ?? crossFetch; const getServerUrl = config.getServerUrl ?? ((path, query) => stringifyUrl({ ...path, query })); // We need the full URL for when we redirect back to the content const getContentUrl = config.getContentUrl ?? ((path, query) => stringifyUrl({ proto: window.location.protocol.replace(':', ''), hostname: window.location.hostname, ...path, query, })); const [state, setState] = createStore({ userSessionId: undefined, responseCache: { paywall: {}, contentAuthorized: {}, }, popover: undefined, get hasUserSessionId() { if (this.userSessionId === undefined) { const cookie = Cookies.get()[DEFAULTS.USER_SESSION_COOKIE]; if (cookie) { setState('userSessionId', cookie); return true; } } return this.userSessionId !== undefined; }, async getPaywall(contentUrl) { const cacheEntry = this.responseCache.paywall[contentUrl]; if (cacheEntry?.type === 'ok') { return cacheEntry.ok ?? undefined; } const url = getServerUrl(createUrlPath(`${DEFAULTS.MERCHANT_ROUTE_PREFIX}/get-paywall`), { contentUrl }); return fetch(url) .then(resp => resp.json()) .then((x) => { setState('responseCache', 'paywall', contentUrl, x); return x.type === 'ok' ? x.ok ?? undefined : undefined; }); }, async isContentAuthorized(contentUrl) { const cacheEntry = this.responseCache.contentAuthorized[contentUrl]; if (cacheEntry?.type === 'ok') { return cacheEntry.ok; } const url = getServerUrl(createUrlPath(`${DEFAULTS.MERCHANT_ROUTE_PREFIX}/is-content-authorized`), { contentUrl }); return fetch(url) .then(resp => resp.json()) .then((x) => { setState('responseCache', 'contentAuthorized', contentUrl, x); return x.type === 'ok'; }); }, async attempNavigateToContent(contentUrl) { if (!this.hasUserSessionId) { await this.showPopoverPaywall(contentUrl, 'no-session'); } else if (await this.isContentAuthorized(contentUrl)) { await this.showPopoverPaywall(contentUrl, 'not-authorized'); } else { this.navigateToContent(contentUrl); } }, async handleContentLinkClick(e, contentUrl) { if (!this.hasUserSessionId) { e.preventDefault(); await this.showPopoverPaywall(contentUrl, 'no-session'); } else if (await this.isContentAuthorized(contentUrl)) { e.preventDefault(); await this.showPopoverPaywall(contentUrl, 'not-authorized'); } }, getContentLinkClickHandler(contentUrl) { return e => state.handleContentLinkClick(e, contentUrl); }, navigateToGetUserSession(contentUrl, shouldPurchase) { const getUserSessionIdUrl = stringifyUrl({ ...DEFAULTS.MICROBITS_URL, path: ['a', 'merchant-user-session'], query: { merchantId: config.merchantId, contentUrl: getContentUrl(createUrlPath(contentUrl)), shouldPurchase: shouldPurchase ? '1' : undefined, }, }); const signInUrl = stringifyUrl({ ...DEFAULTS.MICROBITS_URL, path: ['a', 'signin'], query: { redirect: getUserSessionIdUrl, }, }); window.location.href = signInUrl; }, navigateToPurchaseThenViewContent(contentUrl) { const url = getContentUrl(createUrlPath(contentUrl), { shouldPurchase: '1' }); window.location.href = url; }, navigateToContent(contentUrl) { const url = getContentUrl(createUrlPath(contentUrl)); window.location.href = url; }, async showPopoverPaywall(contentUrl, mode) { return this.getPaywall(contentUrl).then(paywall => { if (paywall !== undefined) { setState('popover', { mode, contentUrl, paywall }); } else { // TODO(logging) console.log(`Paywall not found: ${contentUrl}`); } }); }, hidePopoverPaywall() { setState('popover', undefined); }, }); return state; };