feat: cap Amount input max to stored amount and remaining capacity
- Withdraw/Transfer tabs: max = currently stored amount of selected resource - Deposit tab: max = remaining capacity divided by resource massPerUnit - Amount auto-clamps when resource selection changes - Show 'Max: X' hint below each amount input
This commit is contained in:
parent
b719f25ff2
commit
866a470750
1 changed files with 79 additions and 6 deletions
|
|
@ -114,6 +114,8 @@ export function ManageStorageDialog({
|
|||
return total + (resource.massPerUnit ?? 0) * entry.amount;
|
||||
}, 0);
|
||||
|
||||
const remainingMass = maxMass ? maxMass - currentMass : null;
|
||||
|
||||
const findResource = (id: string): Resource | undefined =>
|
||||
allResources.find((r) => r.id === Number(id));
|
||||
|
||||
|
|
@ -130,6 +132,32 @@ export function ManageStorageDialog({
|
|||
return { resource, amount: entry.amount };
|
||||
};
|
||||
|
||||
const getDepositMax = (): number | undefined => {
|
||||
const resource = findResource(depositResourceId);
|
||||
if (!resource) return undefined;
|
||||
if (remainingMass === null) return undefined;
|
||||
const massPerUnit = resource.massPerUnit ?? 0;
|
||||
if (massPerUnit <= 0) return undefined;
|
||||
return Math.floor(remainingMass / massPerUnit);
|
||||
};
|
||||
|
||||
const getWithdrawMax = (): number | undefined => {
|
||||
const stored = findStoredResource(withdrawResourceId);
|
||||
return stored?.amount;
|
||||
};
|
||||
|
||||
const getTransferMax = (): number | undefined => {
|
||||
const stored = findStoredResource(transferResourceId);
|
||||
return stored?.amount;
|
||||
};
|
||||
|
||||
const clampAmount = (value: string, max: number | undefined): string => {
|
||||
const num = Number(value);
|
||||
if (isNaN(num) || num < 1) return "1";
|
||||
if (max !== undefined && num > max) return String(max);
|
||||
return value;
|
||||
};
|
||||
|
||||
const getPreviewMass = (tab: "deposit" | "withdraw" | "transfer"): number | null => {
|
||||
if (!maxMass) return null;
|
||||
|
||||
|
|
@ -331,7 +359,20 @@ export function ManageStorageDialog({
|
|||
<TabsContent value="deposit" className="flex flex-col gap-4 pt-4">
|
||||
<div className="flex flex-col gap-2">
|
||||
<Label>Resource</Label>
|
||||
<Select value={depositResourceId} onValueChange={setDepositResourceId}>
|
||||
<Select
|
||||
value={depositResourceId}
|
||||
onValueChange={(val) => {
|
||||
setDepositResourceId(val);
|
||||
const res = findResource(val);
|
||||
if (res) {
|
||||
const massPerUnit = res.massPerUnit ?? 0;
|
||||
const depositMax = remainingMass !== null && massPerUnit > 0
|
||||
? Math.floor(remainingMass / massPerUnit)
|
||||
: undefined;
|
||||
setDepositAmount(clampAmount(depositAmount, depositMax));
|
||||
}
|
||||
}}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Select a resource..." />
|
||||
</SelectTrigger>
|
||||
|
|
@ -351,9 +392,15 @@ export function ManageStorageDialog({
|
|||
<Input
|
||||
type="number"
|
||||
min="1"
|
||||
max={getDepositMax()}
|
||||
value={depositAmount}
|
||||
onChange={(e) => setDepositAmount(e.target.value)}
|
||||
onChange={(e) => setDepositAmount(clampAmount(e.target.value, getDepositMax()))}
|
||||
/>
|
||||
{getDepositMax() !== undefined && (
|
||||
<span className="text-xs text-muted-foreground">
|
||||
Max: {getDepositMax()!.toLocaleString()} (limited by remaining capacity)
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
{renderCapacityPreview("deposit")}
|
||||
<Button
|
||||
|
|
@ -373,7 +420,14 @@ export function ManageStorageDialog({
|
|||
<TabsContent value="withdraw" className="flex flex-col gap-4 pt-4">
|
||||
<div className="flex flex-col gap-2">
|
||||
<Label>Resource</Label>
|
||||
<Select value={withdrawResourceId} onValueChange={setWithdrawResourceId}>
|
||||
<Select
|
||||
value={withdrawResourceId}
|
||||
onValueChange={(val) => {
|
||||
setWithdrawResourceId(val);
|
||||
const stored = findStoredResource(val);
|
||||
setWithdrawAmount(clampAmount(withdrawAmount, stored?.amount));
|
||||
}}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Select a resource..." />
|
||||
</SelectTrigger>
|
||||
|
|
@ -395,9 +449,15 @@ export function ManageStorageDialog({
|
|||
<Input
|
||||
type="number"
|
||||
min="1"
|
||||
max={getWithdrawMax()}
|
||||
value={withdrawAmount}
|
||||
onChange={(e) => setWithdrawAmount(e.target.value)}
|
||||
onChange={(e) => setWithdrawAmount(clampAmount(e.target.value, getWithdrawMax()))}
|
||||
/>
|
||||
{getWithdrawMax() !== undefined && (
|
||||
<span className="text-xs text-muted-foreground">
|
||||
Max: {getWithdrawMax()!.toLocaleString()} stored
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
{renderCapacityPreview("withdraw")}
|
||||
<Button
|
||||
|
|
@ -433,7 +493,14 @@ export function ManageStorageDialog({
|
|||
</div>
|
||||
<div className="flex flex-col gap-2">
|
||||
<Label>Resource</Label>
|
||||
<Select value={transferResourceId} onValueChange={setTransferResourceId}>
|
||||
<Select
|
||||
value={transferResourceId}
|
||||
onValueChange={(val) => {
|
||||
setTransferResourceId(val);
|
||||
const stored = findStoredResource(val);
|
||||
setTransferAmount(clampAmount(transferAmount, stored?.amount));
|
||||
}}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Select a resource..." />
|
||||
</SelectTrigger>
|
||||
|
|
@ -455,9 +522,15 @@ export function ManageStorageDialog({
|
|||
<Input
|
||||
type="number"
|
||||
min="1"
|
||||
max={getTransferMax()}
|
||||
value={transferAmount}
|
||||
onChange={(e) => setTransferAmount(e.target.value)}
|
||||
onChange={(e) => setTransferAmount(clampAmount(e.target.value, getTransferMax()))}
|
||||
/>
|
||||
{getTransferMax() !== undefined && (
|
||||
<span className="text-xs text-muted-foreground">
|
||||
Max: {getTransferMax()!.toLocaleString()} stored
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
{renderCapacityPreview("transfer")}
|
||||
<Button
|
||||
|
|
|
|||
Loading…
Reference in a new issue