Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 52 additions & 3 deletions src/ui/components/views/account/masterclasses/ResourceNodesTab.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
toInt,
toNum,
useWriteStatus,
writeManyVerified,
writeVerified,
} from "../accountShared.js";

Expand Down Expand Up @@ -162,6 +163,8 @@ const NodeRow = ({ node, gradeState, depletedState }) => {
export const ResourceNodesTab = () => {
const { loading, error, run: runLoad } = useAccountLoad({ label: "Resource Nodes" });
const activeWorld = van.state(1);
const bulkStatus = useWriteStatus();
const bulkMessage = van.state("");
const nodes = van.state([]);
const gradeStates = new Map();
const depletedStates = new Map();
Expand Down Expand Up @@ -212,6 +215,32 @@ export const ResourceNodesTab = () => {
nodes.val = nextNodes;
});

const writeWorldDepleted = async (value) => {
if (loading.val || bulkStatus.status.val === "loading") return;
const world = activeWorld.val;
const targets = nodes.val.filter((node) => node.world === world);
if (!targets.length) return;

bulkMessage.val = "";
await bulkStatus.run(
async () => {
await writeManyVerified(targets.map((node) => ({ path: `RoyalG[4][${node.nodeIndex}]`, value })));
targets.forEach((node) => {
depletedStates.get(node.nodeIndex).val = value;
});
bulkMessage.val = `W${world}: ${targets.length} nodes ${value === 0 ? "refreshed" : "depleted"}.`;
},
{
onError: (error) => {
bulkMessage.val = `W${world} bulk action failed: ${error.message}. Re-reading node state.`;
void load();
},
}
);
};

const bulkDisabled = () => loading.val || !nodes.val.some((node) => node.world === activeWorld.val);

load();

return PersistentAccountListPage({
Expand All @@ -222,7 +251,7 @@ export const ResourceNodesTab = () => {
refresh: {
onClick: load,
tooltip: "Re-read Royal resource nodes from the running game.",
disabled: () => loading.val,
disabled: () => loading.val || bulkStatus.status.val === "loading",
},
}),
state: { loading, error },
Expand All @@ -235,7 +264,7 @@ export const ResourceNodesTab = () => {
title: "NODE WORLDS",
body: [
div(
{ class: "masterclass-category-tabs" },
{ class: "masterclass-category-tabs resource-node-toolbar" },
...Array.from({ length: WORLD_COUNT }, (_, index) => {
const world = index + 1;
return button(
Expand All @@ -245,14 +274,34 @@ export const ResourceNodesTab = () => {
`masterclass-category-tabs__button${
activeWorld.val === world ? " is-active" : ""
}`,
disabled: () => bulkStatus.status.val === "loading",
onclick: () => {
activeWorld.val = world;
},
},
`W${world}`
);
})
}),
div(
{ class: "resource-node-toolbar__actions" },
ActionButton({
label: "REFRESH ALL",
status: bulkStatus.status,
disabled: bulkDisabled,
tooltip: "Set every node in the selected world to fresh (collected = 0).",
onClick: () => void writeWorldDepleted(0),
}),
ActionButton({
label: "DEPLETE ALL",
status: bulkStatus.status,
disabled: bulkDisabled,
variant: "danger",
tooltip: "Deplete every node in the selected world (collected = -1).",
onClick: () => void writeWorldDepleted(-1),
})
)
),
div({ role: "status", "aria-live": "polite" }, () => bulkMessage.val),
bodyContent,
],
}),
Expand Down
12 changes: 12 additions & 0 deletions src/ui/styles/_masterclasses.css
Original file line number Diff line number Diff line change
Expand Up @@ -474,3 +474,15 @@
justify-self: start;
}
}

/* Resource node world actions */
.resource-node-toolbar {
align-items: center;
}

.resource-node-toolbar__actions {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-left: auto;
}