A rewrite of Poly+, my quality-of-life browser extension for Polytoria. Built entirely fresh using the WXT extension framework, Typescript, and with added better overall code quality.
extension
1import config from "@/utils/config.json";
2import { _favoritedPlaces } from "@/utils/storage";
3import { expireCache } from "@/utils/utilities";
4import * as apiTypes from "@/utils/api/types";
5import { getAPI } from "@/utils/api";
6const placeID = window.location.pathname.split("/")[2];
7
8/**
9 * Displays a row of user-selected places at the top of the user's dashboard.
10 */
11export async function favoritedPlaces() {
12 let placeIDs = await _favoritedPlaces.getValue();
13
14 const button = document.createElement("button");
15 button.classList.add("btn", "btn-primary", "btn-sm");
16 button.style.position = "absolute";
17 button.style.top = "0";
18 button.style.right = "0";
19 button.style.margin = "4px";
20 button.style.fontSize = "1.3em";
21 button.innerHTML = `
22 <i class="fa-regular fa-star"></i>
23 `;
24
25 const update = function () {
26 button.classList.value = "btn btn-primary btn-sm";
27 button.disabled = false;
28 if (placeIDs.indexOf(placeID) == -1) {
29 // Not Pinned
30 if (placeIDs.length >= config.limits.favoritedPlaces) {
31 button.disabled = true;
32 }
33 button.children[0].classList.value = "fa-regular fa-star";
34 } else {
35 // Pinned
36 button.children[0].classList.value = "fa-duotone fa-star";
37 }
38 };
39
40 button.addEventListener("mouseenter", function () {
41 if (placeIDs.indexOf(placeID) != -1) {
42 button.classList.add("btn-danger");
43 button.classList.remove("btn-primary");
44 button.children[0].classList.add("fa-star-half-stroke");
45 button.children[0].classList.remove("fa-star");
46 }
47 });
48
49 button.addEventListener("mouseleave", function () {
50 if (placeIDs.indexOf(placeID) != -1) {
51 button.classList.add("btn-primary");
52 button.classList.remove("btn-danger");
53 button.children[0].classList.add("fa-star");
54 button.children[0].classList.remove("fa-star-half-stroke");
55 }
56 });
57
58 update();
59 document.querySelector("h1.my-0")!.parentElement!.appendChild(button);
60
61 button.addEventListener("click", function () {
62 if (placeIDs.indexOf(placeID) == -1) {
63 placeIDs.push(placeID);
64 } else {
65 placeIDs.splice(placeIDs.indexOf(placeID), 1);
66 }
67
68 expireCache("favoritedPlaces");
69 _favoritedPlaces.setValue(placeIDs);
70 update();
71 });
72
73 storage.watch<Array<string>>("sync:favoritedPlaces", (value, previous) => {
74 placeIDs = value!;
75 });
76}
77
78/**
79 * Displays the approximated amount of revenue generated from a certain place, based off the unique visits & any gamepass sales (taking into account the creator's current membership tax)
80 */
81export async function approxPlaceRevenue() {
82 const publicAPI = getAPI("public");
83
84 const round = (number: number) =>
85 Math.round(number / config.economy.visitsPerBrick) *
86 config.economy.visitsPerBrick;
87 const infoCard = document.querySelector(".card-body .row:has(.fa-calendar)")!;
88
89 const key = document.createElement("li");
90 const value = document.createElement("li");
91
92 key.innerHTML = "Revenue:";
93 value.innerHTML = "...";
94 value.classList.add(publicAPI.enabled ? "text-success" : "text-muted");
95
96 infoCard.children[0].appendChild(key);
97 infoCard.children[1].appendChild(value);
98
99 const revenue = await pullKVCache(
100 "placeRevenue",
101 placeID,
102 async () => {
103 if (!publicAPI.enabled) return "disabled";
104
105 const place: apiTypes.placeApiSchema =
106 await (await fetch(publicAPI.url + "places/" + placeID))
107 .json();
108 const store: apiTypes.gamepassesApiSchema = await (await fetch(
109 publicAPI.url + "places/" + placeID + "/gamepasses",
110 )).json();
111 const creator: apiTypes.userApiSchema = await (await fetch(
112 publicAPI.url + "users/" + place.creator.id,
113 )).json();
114
115 const visitorPayout = round(place.uniqueVisits) /
116 config.economy.visitsPerBrick;
117 let gamepassRevenue = 0;
118
119 for (const gamepass of store.gamepasses) {
120 const price = Math.floor(
121 gamepass.asset.price -
122 (gamepass.asset.price *
123 config.economy.membershipTax[creator.membershipType]),
124 );
125 gamepassRevenue += price * gamepass.asset.sales;
126 }
127
128 return visitorPayout + gamepassRevenue;
129 },
130 300000,
131 false,
132 );
133
134 if (revenue == "disabled") {
135 value.innerText =
136 "Sorry, this feature is currently unavailable! Check back later!";
137 throw new Error(
138 "[Poly+] API is disabled, cancelling approx. place revenue loading..",
139 );
140 }
141
142 value.innerHTML = '<i class="pi pi-brick me-2"></i> ~' +
143 revenue.toLocaleString();
144}