From f83f80c9913db237e6bc30220fbc8d3912faeea9 Mon Sep 17 00:00:00 2001 From: Sainan Date: Sat, 1 Jun 2024 12:57:27 +0200 Subject: [PATCH] feat(webui): add Mods card (#252) --- .../custom/getItemListsController.ts | 11 +- static/webui/index.html | 115 +++++++--- static/webui/script.js | 211 ++++++++++++++++-- static/webui/style.css | 5 +- 4 files changed, 282 insertions(+), 60 deletions(-) diff --git a/src/controllers/custom/getItemListsController.ts b/src/controllers/custom/getItemListsController.ts index 5eeacdc90..c03457169 100644 --- a/src/controllers/custom/getItemListsController.ts +++ b/src/controllers/custom/getItemListsController.ts @@ -1,16 +1,19 @@ import { RequestHandler } from "express"; import { MinItem, warframes, weapons, items } from "@/src/services/itemDataService"; +import badItems from "@/static/json/exclude-mods.json"; interface ListedItem { uniqueName: string; name: string; + fusionLimit?: number; } function reduceItems(items: MinItem[]): ListedItem[] { return items.map((item: MinItem): ListedItem => { return { uniqueName: item.uniqueName, - name: item.name + name: item.name, + fusionLimit: (item as any).fusionLimit }; }); } @@ -19,7 +22,11 @@ const getItemListsController: RequestHandler = (_req, res) => { res.json({ warframes: reduceItems(warframes), weapons: reduceItems(weapons.filter(item => item.productCategory != "OperatorAmps")), - miscitems: reduceItems(items.filter(item => item.category == "Misc" || item.category == "Resources")) + miscitems: reduceItems( + items.filter(item => item.category == "Misc" || item.category == "Resources" || item.category == "Fish") + ), + mods: reduceItems(items.filter(item => item.category == "Mods" || item.category == "Arcanes")), + badItems }); }; diff --git a/static/webui/index.html b/static/webui/index.html index 52efb9676..72cb6ebef 100644 --- a/static/webui/index.html +++ b/static/webui/index.html @@ -45,14 +45,30 @@ >
- +
@@ -117,33 +133,61 @@
-
-
Add Riven
-
- - - - Need help with the fingerprint? -
-
-
-
Rivens
-
- - -
+
+
+
+
Add Riven
+
+ + + + + Need help with the fingerprint? + +
+
+
+
Rivens
+
+ + +
+
+
+
+
+
+
Mods
+
+ + +
+
+ + +
+
+
@@ -152,6 +196,7 @@ + diff --git a/static/webui/script.js b/static/webui/script.js index 83fd77895..6fa3bbeec 100644 --- a/static/webui/script.js +++ b/static/webui/script.js @@ -76,33 +76,47 @@ single.on("route_load", function (event) { } else { $("body").removeClass("logged-in"); } + + $(".nav-link").removeClass("active"); + const navLink = document.querySelector(".nav-link[href='" + event.route.paths[0] + "']"); + if (navLink) { + navLink.classList.add("active"); + } }); window.itemListPromise = new Promise(resolve => { const req = $.get("/custom/getItemLists"); req.done(data => { - const itemMap = {}; + const itemMap = { + // Generics for rivens + "/Lotus/Weapons/Tenno/Archwing/Primary/ArchGun": { name: "Archgun" }, + "/Lotus/Weapons/Tenno/Melee/PlayerMeleeWeapon": { name: "Melee" }, + "/Lotus/Weapons/Tenno/Pistol/LotusPistol": { name: "Pistol" }, + "/Lotus/Weapons/Tenno/Rifle/LotusRifle": { name: "Rifle" }, + "/Lotus/Weapons/Tenno/Shotgun/LotusShotgun": { name: "Shotgun" }, + // Missing in data sources + "/Lotus/Upgrades/CosmeticEnhancers/Peculiars/CyoteMod": { name: "Traumatic Peculiar" }, + "/Lotus/Weapons/Tenno/Grimoire/TnGrimoire": { name: "Grimoire" } + }; for (const [type, items] of Object.entries(data)) { - items.forEach(item => { - const option = document.createElement("option"); - option.setAttribute("data-key", item.uniqueName); - option.value = item.name; - document.getElementById("datalist-" + type).appendChild(option); - itemMap[item.uniqueName] = { ...item, type }; - }); + if (type != "badItems") { + items.forEach(item => { + if (item.uniqueName in data.badItems) { + item.name += " (Imposter)"; + } else if (item.uniqueName.substr(0, 18) != "/Lotus/Types/Game/") { + const option = document.createElement("option"); + option.setAttribute("data-key", item.uniqueName); + option.value = item.name; + document.getElementById("datalist-" + type).appendChild(option); + } + itemMap[item.uniqueName] = { ...item, type }; + }); + } } resolve(itemMap); }); }); -const rivenGenericCompatNames = { - "/Lotus/Weapons/Tenno/Archwing/Primary/ArchGun": "Archgun", - "/Lotus/Weapons/Tenno/Melee/PlayerMeleeWeapon": "Melee", - "/Lotus/Weapons/Tenno/Pistol/LotusPistol": "Pistol", - "/Lotus/Weapons/Tenno/Rifle/LotusRifle": "Rifle", - "/Lotus/Weapons/Tenno/Shotgun/LotusShotgun": "Shotgun" -}; - function updateInventory() { const req = $.get("/api/inventory.php?" + window.authz); req.done(data => { @@ -190,6 +204,7 @@ function updateInventory() { }); document.getElementById("riven-list").innerHTML = ""; + document.getElementById("mods-list").innerHTML = ""; data.Upgrades.forEach(item => { if (item.ItemType.substr(0, 32) == "/Lotus/Upgrades/Mods/Randomized/") { const rivenType = item.ItemType.substr(32); @@ -198,10 +213,7 @@ function updateInventory() { const tr = document.createElement("tr"); { const td = document.createElement("td"); - td.textContent = - itemMap[fingerprint.compat]?.name ?? - rivenGenericCompatNames[fingerprint.compat] ?? - fingerprint.compat; + td.textContent = itemMap[fingerprint.compat]?.name ?? fingerprint.compat; td.textContent += " " + RivenParser.parseRiven(rivenType, fingerprint, 1).name; td.innerHTML += " ▲ " + fingerprint.buffs.length + ""; td.innerHTML += " ▼ " + fingerprint.curses.length + ""; @@ -245,6 +257,92 @@ function updateInventory() { tr.appendChild(td); } document.getElementById("riven-list").appendChild(tr); + } else { + const tr = document.createElement("tr"); + const rank = parseInt(JSON.parse(item.UpgradeFingerprint).lvl); + const maxRank = itemMap[item.ItemType]?.fusionLimit ?? 5; + { + const td = document.createElement("td"); + td.textContent = itemMap[item.ItemType]?.name ?? item.ItemType; + td.innerHTML += " ★ " + rank + "/" + maxRank + ""; + tr.appendChild(td); + } + { + const td = document.createElement("td"); + td.classList = "text-end"; + if (rank < maxRank) { + const a = document.createElement("a"); + a.href = "#"; + a.onclick = function (event) { + event.preventDefault(); + setFingerprint(item.ItemType, item.ItemId, { lvl: maxRank }); + }; + a.textContent = "Max Rank"; + td.appendChild(a); + + const span = document.createElement("span"); + span.innerHTML = " · "; + td.appendChild(span); + } + { + const a = document.createElement("a"); + a.href = "#"; + a.onclick = function (event) { + event.preventDefault(); + disposeOfGear("Upgrades", item.ItemId.$oid); + }; + a.textContent = "Remove"; + td.appendChild(a); + } + tr.appendChild(td); + } + document.getElementById("mods-list").appendChild(tr); + } + }); + data.RawUpgrades.forEach(item => { + if (item.ItemCount > 0) { + const maxRank = itemMap[item.ItemType]?.fusionLimit ?? 5; + const tr = document.createElement("tr"); + { + const td = document.createElement("td"); + td.textContent = itemMap[item.ItemType]?.name ?? item.ItemType; + td.innerHTML += " ★ 0/" + maxRank + ""; + if (item.ItemCount > 1) { + td.innerHTML += " 🗍 " + parseInt(item.ItemCount) + ""; + } + tr.appendChild(td); + } + { + const td = document.createElement("td"); + td.classList = "text-end"; + { + const a = document.createElement("a"); + a.href = "#"; + a.onclick = function (event) { + event.preventDefault(); + setFingerprint(item.ItemType, item.LastAdded, { lvl: maxRank }); + }; + a.textContent = "Max Rank"; + td.appendChild(a); + } + { + const span = document.createElement("span"); + span.innerHTML = " · "; + td.appendChild(span); + } + { + const a = document.createElement("a"); + a.href = "#"; + a.onclick = function (event) { + event.preventDefault(); + disposeOfItems("Upgrades", item.ItemType, item.ItemCount); + }; + a.textContent = "Remove"; + td.appendChild(a); + } + tr.appendChild(td); + } + document.getElementById("mods-list").appendChild(tr); } }); }); @@ -352,6 +450,29 @@ function disposeOfGear(category, oid) { }); } +function disposeOfItems(category, type, count) { + const data = { + SellCurrency: "SC_RegularCredits", + SellPrice: 0, + Items: {} + }; + data.Items[category] = [ + { + String: type, + Count: count + } + ]; + revalidateAuthz(() => { + $.post({ + url: "/api/sell.php?" + window.authz, + contentType: "text/plain", + data: JSON.stringify(data) + }).done(function () { + updateInventory(); + }); + }); +} + function doAcquireMiscItems() { const uniqueName = getKey(document.getElementById("miscitem-type")); if (!uniqueName) { @@ -445,3 +566,53 @@ function doAcquireRiven() { $("#addriven-fingerprint").on("input", () => { $("#addriven-fingerprint").removeClass("is-invalid"); }); + +function setFingerprint(ItemType, ItemId, fingerprint) { + revalidateAuthz(() => { + $.post({ + url: "/api/artifacts.php?" + window.authz, + contentType: "text/plain", + data: JSON.stringify({ + Upgrade: { + ItemType, + ItemId, + UpgradeFingerprint: JSON.stringify(fingerprint) + }, + LevelDiff: 0, + Cost: 0, + FusionPointCost: 0 + }) + }).done(function () { + updateInventory(); + }); + }); +} + +function doAcquireMod() { + const uniqueName = getKey(document.getElementById("mod-to-acquire")); + if (!uniqueName) { + $("#mod-to-acquire").addClass("is-invalid").focus(); + return; + } + revalidateAuthz(() => { + $.post({ + url: "/api/missionInventoryUpdate.php?" + window.authz, + contentType: "text/plain", + data: JSON.stringify({ + RawUpgrades: [ + { + ItemType: uniqueName, + ItemCount: 1 + } + ] + }) + }).done(function () { + document.getElementById("mod-to-acquire").value = ""; + updateInventory(); + }); + }); +} + +$("#mod-to-acquire").on("input", () => { + $("#mod-to-acquire").removeClass("is-invalid"); +}); diff --git a/static/webui/style.css b/static/webui/style.css index 109802b4d..119d4fd23 100644 --- a/static/webui/style.css +++ b/static/webui/style.css @@ -1,14 +1,13 @@ @media (min-width: 992px) { body.logged-in #main-view { - display: grid; - grid-template-columns: 1fr 8fr; - gap: 1.5rem; + display: flex; } body.logged-in #sidebar { position: sticky; top: 5rem; height: 100px; + margin-right: 3rem; } body:not(.logged-in) #sidebar {