inject container to the root of a page
This commit is contained in:
parent
60930c4f1a
commit
6d61a34503
1 changed files with 196 additions and 153 deletions
349
lib/index.js
349
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);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue