diff --git a/lib/index.js b/lib/index.js index a0c1ca8..918106d 100644 --- a/lib/index.js +++ b/lib/index.js @@ -12,197 +12,240 @@ TODO: - readme how to use and debug */ -const createPricesContainer = () => { - const pricingActionContainers = document.querySelectorAll(".pricing-details"); - - l("all pricing containers", pricingActionContainers); - - let visible; - for (const node of pricingActionContainers) { - if (node.checkVisibility()) { - l("found visible pricing container", node); - visible = node; - break; - } - } - - return visible.parentNode.insertBefore( - document.createElement("div"), - visible, - ); -}; - -const isInLibrary = () => document.querySelectorAll(".read-now").length; +const isInLibrary = () => + // Old layout + document.querySelectorAll(".read-now").length > 0 || + // New layout + document.querySelectorAll('[data-testid="buypad-readnow"]').length > 0; const formatPrice = (countryPrice, convertedPrice, isSelected) => { - if (!isSelected) return "SKIP"; + if (!isSelected) return "SKIP"; - if (countryPrice == undefined) { - return "NOT LOADED"; - } + if (countryPrice == undefined) { + return "NOT LOADED"; + } - if (convertedPrice) { - return `${countryPrice} => ${convertedPrice?.formatted}`; - } + if (convertedPrice) { + return `${countryPrice} => ${convertedPrice?.formatted}`; + } - return "NOT FOUND"; + return "NOT FOUND"; }; const Price = ({ price, toggleCountry, isSelected }) => { - const { convertedPrice, countryCode, countryPrice } = price; - const [isHovered, setHover] = useState(false); + const { convertedPrice, countryCode, countryPrice } = price; + const [isHovered, setHover] = useState(false); - const hover = useCallback(() => setHover(true)); - const leave = useCallback(() => setHover(false)); + const hover = useCallback(() => setHover(true)); + const leave = useCallback(() => setHover(false)); - const style = { - display: "flex", - flexDirection: "row", - justifyContent: "space-between", - alignItems: "center", - backgroundColor: isHovered ? "#d7d7d7" : "", - padding: "0 10px", - }; + const style = { + display: "flex", + flexDirection: "row", + justifyContent: "space-between", + alignItems: "center", + backgroundColor: isHovered ? "#d7d7d7" : "", + padding: "0 10px", + }; - const link = h( - "a", - { - style: { textDecoration: "underline" }, - href: bookUrl(countryCode), - target: "_blank", - }, - countryCode.toUpperCase(), - ); + const link = h( + "a", + { + style: { textDecoration: "underline" }, + href: bookUrl(countryCode), + target: "_blank", + }, + countryCode.toUpperCase(), + ); - const checkbox = h("input", { - type: "checkbox", - checked: isSelected, - onChange: () => toggleCountry(), - }); + const checkbox = h("input", { + type: "checkbox", + checked: isSelected, + onChange: () => toggleCountry(), + }); - const priceLabel = h( - "p", - { style: { fontWeight: "bold" } }, - formatPrice(countryPrice, convertedPrice, isSelected), - ); + const priceLabel = h( + "p", + { style: { fontWeight: "bold" } }, + formatPrice(countryPrice, convertedPrice, isSelected), + ); - return h( - "label", - { style, onMouseEnter: hover, onMouseLeave: leave }, - h("div", { style: { display: "flex" } }, checkbox, link), - priceLabel, - ); + return h( + "label", + { style, onMouseEnter: hover, onMouseLeave: leave }, + h("div", { style: { display: "flex" } }, checkbox, link), + priceLabel, + ); }; const InLibrary = () => - h( - "div", - { - style: { - display: "flex", - flexDirection: "column", - border: "1px solid black", - textAlign: "center", - }, - }, - h("h2", null, "Already in Library!"), - ); + h( + "div", + { + style: { + padding: "10px", + textAlign: "center", + }, + }, + h("h2", null, "Already in Library!"), + ); const Percent = (percent) => { - const spinner = useRef(); + const spinner = useRef(); - useEffect(() => { - spinner.current.animate( - [{ transform: "rotate(0deg)" }, { transform: "rotate(360deg)" }], - { iterations: Infinity, duration: 1000 }, - ); - }, []); + useEffect(() => { + spinner.current.animate( + [{ transform: "rotate(0deg)" }, { transform: "rotate(360deg)" }], + { iterations: Infinity, duration: 1000 }, + ); + }, []); - const style = { padding: "10px 10px 0 10px", textAlign: "center" }; + const style = { padding: "10px 10px 0 10px", textAlign: "center" }; - if (percent == 100) return h("h2", { style }, "all prices are loaded!"); + if (percent == 100) return h("h2", { style }, "all prices are loaded!"); - return h( - "h2", - { style }, - `${percent}%`, - h("span", { - ref: spinner, - style: { - width: "16px", - height: "16px", - borderRadius: "50%", - display: "inline-block", - borderTop: "3px solid black", - borderRight: "3px solid transparent", - boxSizing: "border-box", - marginLeft: "15px", - }, - }), - ); + return h( + "h2", + { style }, + `${percent}%`, + h("span", { + ref: spinner, + style: { + width: "16px", + height: "16px", + borderRadius: "50%", + display: "inline-block", + borderTop: "3px solid black", + borderRight: "3px solid transparent", + boxSizing: "border-box", + marginLeft: "15px", + }, + }), + ); }; const Header = (state, percentChecked) => { - if (state === "loading") return Percent(percentChecked); + if (state === "loading") return Percent(percentChecked); - if (state === "done") - return h( - "h2", - { style: { textAlign: "center" } }, - "All prices are loaded!", - ); + if (state === "done") + return h( + "h2", + { style: { textAlign: "center" } }, + "All prices are loaded!", + ); - return h( - "h2", - { style: { textAlign: "center" } }, - 'Select countries or leave as is and press "load"', - ); + return h( + "h2", + { style: { textAlign: "center" } }, + 'Select countries or leave as is and press "Load prices"', + ); }; const Load = (state, load) => { - return h( - "button", - { - disabled: state === "loading", - onClick: load, - type: "button", - style: { backgroundColor: "#91ff91" }, - }, - state === "loading" ? "Loading..." : "Load prices", - ); + return h( + "button", + { + disabled: state === "loading", + onClick: load, + type: "button", + style: { backgroundColor: "#91ff91" }, + }, + state === "loading" ? "Loading..." : "Load prices", + ); }; const App = () => { - const { isSelected, toggleCountry, selected } = useSelectedCountries(); - const { prices, percentChecked, state, load } = usePrices(selected); + const { isSelected, toggleCountry, selected } = useSelectedCountries(); + const { prices, percentChecked, state, load } = usePrices(selected); + const [expanded, setExpanded] = useState(false); - l(selected); - const style = { - display: "flex", - flexDirection: "column", - border: "1px solid black", - }; + l(selected); - if (isInLibrary()) { - return InLibrary(); - } + const toggle = useCallback(() => setExpanded((v) => !v)); - return h( - "div", - { style }, - Header(state, percentChecked), - ...prices.map((price) => - h(Price, { - price, - toggleCountry: () => toggleCountry(price.countryCode), - isSelected: isSelected(price.countryCode), - isLoading: state, - }), - ), - Load(state, load), - ); + if (isInLibrary()) { + return h( + "div", + { + style: { + position: "fixed", + top: "10px", + left: "10px", + zIndex: 99999, + background: "white", + border: "1px solid black", + fontFamily: "sans-serif", + fontSize: "14px", + }, + }, + InLibrary(), + ); + } + + const panelStyle = { + position: "fixed", + bottom: "0", + left: "0", + zIndex: 99999, + background: "white", + border: "1px solid black", + fontFamily: "sans-serif", + fontSize: "14px", + maxHeight: expanded ? "100vh" : "auto", + overflowY: expanded ? "auto" : "hidden", + minWidth: "100%", + }; + + const buttonStyle = { + height: "2.25rem", + background: "white", + border: "1px solid black", + // padding: "6px 12px", + cursor: "pointer", + fontSize: "14px", + fontWeight: "bold", + width: "100%", + }; + + if (!expanded) { + return h( + "div", + { style: panelStyle }, + h("button", { style: buttonStyle, onClick: toggle }, "PRICES"), + ); + } + + const listStyle = { + display: "flex", + flexDirection: "column", + }; + + return h( + "div", + { style: panelStyle }, + h("button", { style: buttonStyle, onClick: toggle }, "CLOSE"), + h( + "div", + { style: listStyle }, + ...[ + Header(state, percentChecked), + Load(state, load), + ...prices.map((price) => + h(Price, { + price, + toggleCountry: () => toggleCountry(price.countryCode), + isSelected: isSelected(price.countryCode), + isLoading: state, + }), + ), + ], + ), + ); }; l("starting..."); initCache(); -render(createElement(App), createPricesContainer()); + +const container = document.createElement("div"); +document.body.appendChild(container); +render(createElement(App), container);