125 lines
3.6 KiB
TypeScript
125 lines
3.6 KiB
TypeScript
import { useApi } from "@/api";
|
|
import { EPlacementKeys, IPaywall } from "@/api/resources/Paywall";
|
|
import { actions, selectors } from "@/store";
|
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
import { useDispatch, useSelector } from "react-redux";
|
|
import parse from "html-react-parser";
|
|
import { defaultPaywalls } from "./defaultPaywalls";
|
|
|
|
interface IUsePaywallProps {
|
|
placementKey: EPlacementKeys;
|
|
}
|
|
|
|
interface IGetTextProps {
|
|
replacementSelector?: string;
|
|
color?: string;
|
|
replacement?: {
|
|
target: string;
|
|
replacement: string;
|
|
};
|
|
}
|
|
|
|
export function usePaywall({ placementKey }: IUsePaywallProps) {
|
|
const api = useApi();
|
|
const dispatch = useDispatch();
|
|
const token = useSelector(selectors.selectToken);
|
|
const [paywall, setPaywall] = useState<IPaywall>();
|
|
const [isLoading, setIsLoading] = useState(false);
|
|
const [error, setError] = useState(false);
|
|
const products = useMemo(() => paywall?.products || [], [paywall?.products]);
|
|
const properties = useMemo(
|
|
() => paywall?.properties || [],
|
|
[paywall?.properties]
|
|
);
|
|
const isMustUpdate = useSelector(selectors.selectPaywallsIsMustUpdate);
|
|
const paywalls = useSelector(selectors.selectPaywalls);
|
|
|
|
const getPaywallByPlacementKey = useCallback(
|
|
async (placementKey: EPlacementKeys) => {
|
|
try {
|
|
setIsLoading(true);
|
|
setError(false);
|
|
const paywall = await api.getPaywallByPlacementKey({
|
|
placementKey,
|
|
token,
|
|
});
|
|
if ("paywall" in paywall && paywall.paywall) {
|
|
setPaywall(paywall.paywall);
|
|
dispatch(
|
|
actions.paywalls.updatePaywall({
|
|
[placementKey]: paywall.paywall,
|
|
})
|
|
);
|
|
dispatch(
|
|
actions.paywalls.updateIsMustUpdate({
|
|
[placementKey]: false,
|
|
})
|
|
);
|
|
}
|
|
} catch (error) {
|
|
console.error(error);
|
|
setError(true);
|
|
setPaywall(defaultPaywalls[placementKey]);
|
|
} finally {
|
|
setIsLoading(false);
|
|
}
|
|
},
|
|
[api, dispatch, token]
|
|
);
|
|
|
|
useEffect(() => {
|
|
if (isMustUpdate[placementKey] || !paywalls[placementKey]) {
|
|
getPaywallByPlacementKey(placementKey);
|
|
} else {
|
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
setPaywall(paywalls[placementKey]!);
|
|
}
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, [getPaywallByPlacementKey, placementKey, isMustUpdate]);
|
|
|
|
const getText = useCallback(
|
|
(
|
|
key: string,
|
|
{
|
|
replacementSelector = "span",
|
|
color = "inherit",
|
|
replacement,
|
|
}: IGetTextProps
|
|
) => {
|
|
const property = properties.find((property) => property.key === key);
|
|
if (!property) return "";
|
|
const text = property.value;
|
|
const colorElements = properties.filter((property) =>
|
|
property.key.includes(`${key}.color`)
|
|
);
|
|
if (text && colorElements.length) {
|
|
let element = text;
|
|
for (const colorElement of colorElements) {
|
|
element = element.replace(
|
|
colorElement.value,
|
|
`<${replacementSelector} class="${property.key}" style="color: ${color}">${colorElement.value}</${replacementSelector}>`
|
|
);
|
|
}
|
|
return parse(element);
|
|
}
|
|
if (text && replacement) {
|
|
return text.replace(replacement.target, replacement.replacement);
|
|
}
|
|
return text;
|
|
},
|
|
[properties]
|
|
);
|
|
|
|
return useMemo(
|
|
() => ({
|
|
paywall,
|
|
isLoading,
|
|
error,
|
|
products,
|
|
properties,
|
|
getText,
|
|
}),
|
|
[error, isLoading, paywall, products, properties, getText]
|
|
);
|
|
}
|