import config from "@/utils/config.json";
import * as apiTypes from "@/utils/api/types";
import { getAPI } from "@/utils/api";
/**
* Adds a row to the user statistics card on the profile page allowing the user to quickly view & copy another user's ID.
* @param userId The ID of the user.
*/
export async function displayId(userId: number) {
const statsCard = document.getElementById("user-stats-card");
if (!statsCard) return; // ? Incase the user is blocked, which means the stats card won't be present
const row = document.createElement("div");
row.classList.add("mb-1");
row.innerHTML = `
Player ID
${userId}
`;
const copyBtn = row.getElementsByTagName("a")[0];
copyBtn.addEventListener("click", () => {
navigator.clipboard.writeText(userId as unknown as string)
.then(() => {
const icon: HTMLElement = copyBtn.children[0] as HTMLElement;
copyBtn.classList.add("text-success");
icon.setAttribute("class", "fa-duotone fa-circle-check");
icon.style.marginLeft = "3px";
setTimeout(() => {
copyBtn.classList.remove("text-success");
icon.setAttribute("class", "fad fa-copy");
icon.style.marginLeft = "5px";
}, 1500);
})
.catch(() => {
alert("Failure to copy user ID to clipboard.");
});
});
statsCard.children[0].insertBefore(
row,
statsCard.querySelector(".mb-1:has(.fa-calendar)")!,
);
}
/**
* Adds a button next to the "Avatar" card heading, which, on click, adds up all the items the user who owns this profile is wearing.
* @param userId The ID of the user.
*/
export async function outfitCost(userId: number) {
const publicAPI = getAPI("public");
const calculateBtn = document.createElement("small");
calculateBtn.classList.add("fw-normal");
calculateBtn.style.letterSpacing = "0px";
const calculate = async function () {
const outfit = {
cost: 0,
collectibles: 0,
offsale: 0,
timed: 0,
};
const avatar: apiTypes.avatarApiSchema | "disabled" = await pullKVCache(
"avatars",
userId.toString(),
async () => {
if (!publicAPI.enabled) return "disabled";
return (await (await fetch(
publicAPI.url + "users/" + userId + "/avatar",
)).json());
},
30000, // 30 seconds
false,
);
if (avatar == "disabled") {
calculateBtn.innerHTML =
'Outfit cost unavailable, please try again later';
throw new Error(
"[Poly+] API is disabled, cancelling avatar cost loading..",
);
}
if (avatar.isDefault) {
calculateBtn.innerHTML =
'Default avatar';
console.warn(
"[Poly+] User has default avatar, cancelling avatar cost loading..",
);
return;
}
for (
const asset of avatar.assets.filter((asset) =>
asset.type != "profileTheme"
)
) {
// ? API won't be disabled at this step, since there was already an API check previously
const item: apiTypes.itemApiSchema = await pullKVCache(
"items",
asset.id.toString(),
async () => {
return (await (await fetch(
publicAPI.url + "store/" + asset.id,
)).json());
},
600000,
false,
);
if (item.isLimited) {
outfit.collectibles++;
outfit.cost += item.averagePrice!;
} else if (!item.price) {
outfit.offsale++;
} else if (item.onSaleUntil != null) {
outfit.timed++;
} else {
outfit.cost += item.price!;
}
}
console.log("[Poly+] Outfit breakdown: ", outfit);
calculateBtn.innerHTML =
` approx. ${outfit.cost.toLocaleString()} brick(s)`;
};
if (publicAPI.enabled) {
calculateBtn.innerHTML =
'$ calculate avatar cost';
calculateBtn.children[0].addEventListener("click", calculate);
} else {
calculateBtn.innerHTML =
'Outfit cost unavailable, please try again later';
console.error(
"[Poly+] API is disabled, outfit cost calculation is unavailable.",
);
}
document.querySelector(".section-title:first-child")!.appendChild(
calculateBtn,
);
}