@microbitsclub/paywall-solid
Version:
Solid components for Microbits paywalls
145 lines (142 loc) • 5.46 kB
JSX
import Cookies from 'js-cookie';
import { createContext, createEffect, Show, useContext } from 'solid-js';
import { createStore } from 'solid-js/store';
import { isServer, Portal } from 'solid-js/web';
import { PaywallPopoverContent } from './paywall-popopver-content';
import { stringifyUrl } from './stringify-url';
const createPopoverPaywall = (microbits) => {
const [state, setState] = createStore({ microbits });
return {
state,
// selectPaywallById(paywallId: string) {
// if (state.microbits === undefined) return;
// state.microbits
// .getPaywallById(paywallId)
// .then(x => {
// if ('ok' in x) {
// setState('currentPaywall', {
// id: x.ok.id,
// price: x.ok.price,
// contentUrl: x.ok.url,
// });
// } else {
// setState('currentPaywall', undefined);
// }
// })
// .catch(() => {
// setState('currentPaywall', undefined);
// });
// },
selectPaywallByContentUrl(contentUrl) {
if (state.microbits === undefined)
return;
state.microbits
.getPaywallByContentUrl(contentUrl)
.then(x => {
if ('ok' in x) {
setState('currentPaywall', {
id: x.ok.id,
price: x.ok.price,
contentUrl: x.ok.url,
});
}
else {
setState('currentPaywall', undefined);
}
})
.catch(() => {
setState('currentPaywall', undefined);
});
},
closePaywall() {
setState('currentPaywall', undefined);
},
confirmPaywallPurchase() {
if (state.microbits === undefined)
return;
if (state.currentPaywall === undefined)
return;
const { id, contentUrl } = state.currentPaywall;
const userSessionId = Cookies.get('microbits.user_session');
console.log({ userSessionId, paywallId: id, contentUrl });
if (userSessionId === undefined) {
const userSessionUrl = stringifyUrl({
domain: 'microbits.localhost',
path: ['a', 'merchant-user-session'],
query: {
redirect: contentUrl,
merchant: state.microbits.config.merchantId,
},
});
const signInUrl = stringifyUrl({
domain: 'microbits.localhost',
path: ['a', 'signin'],
query: { redirect: userSessionUrl },
});
window.location.href = signInUrl;
}
/*
if userSessionId is undefined:
redirect to userSessionAcquire with signin bounce
destination is contentUrl
otherwise:
make purchase request through merchant backend
destination is contentUrl
*/
},
};
};
const microbitsContext = createContext();
export const usePopoverPaywall = () => {
const ctx = useContext(microbitsContext);
if (ctx === undefined) {
throw Error('PopoverPaywallProvider not found');
}
const { state, ...rest } = ctx;
return [state, rest];
};
const { Provider } = microbitsContext;
export const PopoverPaywallProvider = (props) => {
const ctx = createPopoverPaywall(props.microbits);
const popoverElement = isServer ? undefined : document.body;
const handleConfirm = () => {
ctx.confirmPaywallPurchase();
};
const handleCancel = () => {
ctx.closePaywall();
};
let preserveBodyStyle;
createEffect(() => {
if (ctx.state.currentPaywall !== undefined) {
preserveBodyStyle = {
height: document.body.style.height,
overflow: document.body.style.overflow,
};
document.body.style.height = '100%';
document.body.style.overflow = 'hidden';
}
else if (preserveBodyStyle !== undefined) {
document.body.style.height = preserveBodyStyle.height;
document.body.style.overflow = preserveBodyStyle.overflow;
preserveBodyStyle = undefined;
}
});
return (<Provider value={ctx}>
{props.children}
<Portal mount={popoverElement}>
<Show when={ctx.state.currentPaywall !== undefined}>
<div style={{
position: 'fixed',
'box-sizing': 'border',
top: 0,
left: 0,
width: '100vw',
height: '100vh',
opacity: 0.5,
'background-color': '#eee',
}}/>
</Show>
<PaywallPopoverContent visible={ctx.state.currentPaywall !== undefined} paywallId={ctx.state.currentPaywall?.id} paywallPrice={ctx.state.currentPaywall?.price} onConfirm={handleConfirm} onCancel={handleCancel}/>
</Portal>
</Provider>);
};