mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-12-27 00:17:32 +01:00
Finished converting all the popups.
This commit is contained in:
parent
3ba04220e1
commit
cf72d72bb0
@ -47,7 +47,6 @@ import { yesNoBoxCreate,
|
||||
// UI Related Imports
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import { CorporationEventHandler } from "./ui/CorporationUIEventHandler";
|
||||
import { CorporationRoot } from "./ui/Root";
|
||||
import { CorporationRouting } from "./ui/Routing";
|
||||
|
||||
@ -1884,7 +1883,6 @@ Corporation.prototype.getStarterGuide = function() {
|
||||
}
|
||||
|
||||
let corpRouting;
|
||||
let eventHandler;
|
||||
let companyManagementDiv;
|
||||
Corporation.prototype.createUI = function() {
|
||||
companyManagementDiv = createElement("div", {
|
||||
@ -1895,13 +1893,12 @@ Corporation.prototype.createUI = function() {
|
||||
document.getElementById("entire-game-container").appendChild(companyManagementDiv);
|
||||
|
||||
corpRouting = new CorporationRouting(this);
|
||||
eventHandler = new CorporationEventHandler(this, corpRouting);
|
||||
|
||||
this.rerender();
|
||||
}
|
||||
|
||||
Corporation.prototype.rerender = function() {
|
||||
if (companyManagementDiv == null || corpRouting == null || eventHandler == null) {
|
||||
if (companyManagementDiv == null || corpRouting == null) {
|
||||
console.warn(`Corporation.rerender() called when companyManagementDiv, corpRouting, or eventHandler is null`);
|
||||
return;
|
||||
}
|
||||
@ -1910,7 +1907,6 @@ Corporation.prototype.rerender = function() {
|
||||
ReactDOM.render(<CorporationRoot
|
||||
corp={this}
|
||||
routing={corpRouting}
|
||||
eventHandler={eventHandler}
|
||||
player={Player}
|
||||
/>, companyManagementDiv);
|
||||
}
|
||||
|
@ -7,7 +7,6 @@ import { createPopup } from "../../ui/React/createPopup";
|
||||
import { IDivision } from "../IDivision";
|
||||
|
||||
interface IProps {
|
||||
eventHandler: any;
|
||||
routing: any;
|
||||
onClicks: {[key: string]: () => void};
|
||||
city: string; // currentCity
|
||||
|
@ -1,578 +0,0 @@
|
||||
// Creates a class for handling UI events, such as clicks and keyboard events
|
||||
import { CorporationRouting } from "./Routing";
|
||||
import { Corporation,
|
||||
Industry,
|
||||
Warehouse,
|
||||
DividendMaxPercentage,
|
||||
IssueNewSharesCooldown } from "../Corporation";
|
||||
import { OfficeSpace } from "../OfficeSpace";
|
||||
|
||||
import { Industries,
|
||||
IndustryStartingCosts,
|
||||
IndustryDescriptions,
|
||||
} from "../IndustryData";
|
||||
|
||||
import { MaterialSizes } from "../MaterialSizes";
|
||||
|
||||
import { Product } from "../Product";
|
||||
|
||||
import { Cities } from "../../Locations/Cities";
|
||||
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
|
||||
import { dialogBoxCreate } from "../../../utils/DialogBox";
|
||||
|
||||
import { getRandomInt } from "../../../utils/helpers/getRandomInt";
|
||||
import { KEY } from "../../../utils/helpers/keyCodes";
|
||||
|
||||
import { clearSelector } from "../../../utils/uiHelpers/clearSelector";
|
||||
import { createElement } from "../../../utils/uiHelpers/createElement";
|
||||
import { createOptionElement } from "../../../utils/uiHelpers/createOptionElement";
|
||||
import { createPopup } from "../../../utils/uiHelpers/createPopup";
|
||||
import { createPopupCloseButton } from "../../../utils/uiHelpers/createPopupCloseButton";
|
||||
import { getSelectText,
|
||||
getSelectValue } from "../../../utils/uiHelpers/getSelectData";
|
||||
import { removeElementById } from "../../../utils/uiHelpers/removeElementById";
|
||||
|
||||
export class CorporationEventHandler {
|
||||
constructor(corp, routing) {
|
||||
if (!(corp instanceof Corporation)) {
|
||||
throw new Error(`CorporationEventHandler constructed without proper Corporation instance`);
|
||||
}
|
||||
if (!(routing instanceof CorporationRouting)) {
|
||||
throw new Error(`CorporationEventHandler constructed without proper CorporationRouting instance`);
|
||||
}
|
||||
|
||||
this.corp = corp;
|
||||
this.routing = routing;
|
||||
}
|
||||
|
||||
// Create a popup that lets the player use the Market TA research for Products
|
||||
createProductMarketTaPopup(product, industry) {
|
||||
const popupId = "cmpy-mgmt-marketta-popup";
|
||||
const markupLimit = product.rat / product.mku;
|
||||
const ta1 = createElement("p", {
|
||||
innerHTML: "<u><strong>Market-TA.I</strong></u><br>" +
|
||||
"The maximum sale price you can mark this up to is " +
|
||||
numeralWrapper.formatMoney(product.pCost + markupLimit) +
|
||||
". This means that if you set the sale price higher than this, " +
|
||||
"you will begin to experience a loss in number of sales",
|
||||
});
|
||||
|
||||
// Enable using Market-TA1 for automatically setting sale price
|
||||
const useTa1AutoSaleId = "cmpy-mgmt-marketa1-checkbox";
|
||||
const useTa1AutoSaleDiv = createElement("div", { display: "block" });
|
||||
const useTa1AutoSaleLabel = createElement("label", {
|
||||
color: "white",
|
||||
for: useTa1AutoSaleId,
|
||||
innerText: "Use Market-TA.I for Auto-Sale Price",
|
||||
tooltip: "If this is enabled, then this Product will automatically " +
|
||||
"be sold at the price identified by Market-TA.I (i.e. the price shown above)",
|
||||
})
|
||||
const useTa1AutoSaleCheckbox = createElement("input", {
|
||||
checked: product.marketTa1,
|
||||
id: useTa1AutoSaleId,
|
||||
margin: "3px",
|
||||
type: "checkbox",
|
||||
changeListener: (e) => {
|
||||
product.marketTa1 = e.target.checked;
|
||||
},
|
||||
});
|
||||
useTa1AutoSaleDiv.appendChild(useTa1AutoSaleLabel);
|
||||
useTa1AutoSaleDiv.appendChild(useTa1AutoSaleCheckbox);
|
||||
|
||||
const closeBtn = createPopupCloseButton(popupId, {
|
||||
class: "std-button",
|
||||
display: "block",
|
||||
innerText: "Close",
|
||||
});
|
||||
|
||||
if (industry.hasResearch("Market-TA.II")) {
|
||||
let updateTa2Text;
|
||||
const ta2Text = createElement("p");
|
||||
const ta2Input = createElement("input", {
|
||||
marginTop: "4px",
|
||||
onkeyup: (e) => {
|
||||
e.preventDefault();
|
||||
updateTa2Text();
|
||||
},
|
||||
type: "number",
|
||||
value: product.pCost,
|
||||
});
|
||||
|
||||
// Function that updates the text in ta2Text element
|
||||
updateTa2Text = function() {
|
||||
const sCost = parseFloat(ta2Input.value);
|
||||
let markup = 1;
|
||||
if (sCost > product.pCost) {
|
||||
if ((sCost - product.pCost) > markupLimit) {
|
||||
markup = markupLimit / (sCost - product.pCost);
|
||||
}
|
||||
}
|
||||
ta2Text.innerHTML = `<br><u><strong>Market-TA.II</strong></u><br>` +
|
||||
`If you sell at ${numeralWrapper.formatMoney(sCost)}, ` +
|
||||
`then you will sell ${numeralWrapper.format(markup, "0.00000")}x as much compared ` +
|
||||
`to if you sold at market price.`;
|
||||
}
|
||||
updateTa2Text();
|
||||
|
||||
// Enable using Market-TA2 for automatically setting sale price
|
||||
const useTa2AutoSaleId = "cmpy-mgmt-marketa2-checkbox";
|
||||
const useTa2AutoSaleDiv = createElement("div", { display: "block" });
|
||||
const useTa2AutoSaleLabel = createElement("label", {
|
||||
color: "white",
|
||||
for: useTa2AutoSaleId,
|
||||
innerText: "Use Market-TA.II for Auto-Sale Price",
|
||||
tooltip: "If this is enabled, then this Product will automatically " +
|
||||
"be sold at the optimal price such that the amount sold matches the " +
|
||||
"amount produced. (i.e. the highest possible price, while still ensuring " +
|
||||
" that all produced materials will be sold)",
|
||||
})
|
||||
const useTa2AutoSaleCheckbox = createElement("input", {
|
||||
checked: product.marketTa2,
|
||||
id: useTa2AutoSaleId,
|
||||
margin: "3px",
|
||||
type: "checkbox",
|
||||
changeListener: (e) => {
|
||||
product.marketTa2 = e.target.checked;
|
||||
},
|
||||
});
|
||||
useTa2AutoSaleDiv.appendChild(useTa2AutoSaleLabel);
|
||||
useTa2AutoSaleDiv.appendChild(useTa2AutoSaleCheckbox);
|
||||
|
||||
const ta2OverridesTa1 = createElement("p", {
|
||||
innerText: "Note that Market-TA.II overrides Market-TA.I. This means that if " +
|
||||
"both are enabled, then Market-TA.II will take effect, not Market-TA.I",
|
||||
});
|
||||
|
||||
createPopup(popupId, [ta1, useTa1AutoSaleDiv, ta2Text, ta2Input, useTa2AutoSaleDiv, ta2OverridesTa1, closeBtn]);
|
||||
} else {
|
||||
// Market-TA.I only
|
||||
createPopup(popupId, [ta1, useTa1AutoSaleDiv, closeBtn]);
|
||||
}
|
||||
}
|
||||
|
||||
// Create a popup that lets the player purchase a Material
|
||||
createPurchaseMaterialPopup(mat, industry, warehouse) {
|
||||
const corp = this.corp;
|
||||
|
||||
const purchasePopupId = "cmpy-mgmt-material-purchase-popup";
|
||||
const txt = createElement("p", {
|
||||
innerHTML: "Enter the amount of " + mat.name + " you would like " +
|
||||
"to purchase per second. This material's cost changes constantly",
|
||||
});
|
||||
let confirmBtn;
|
||||
let input = createElement("input", {
|
||||
margin: "5px",
|
||||
placeholder: "Purchase amount",
|
||||
type: "number",
|
||||
value: mat.buy ? mat.buy : null,
|
||||
onkeyup: (e) => {
|
||||
e.preventDefault();
|
||||
if (e.keyCode === KEY.ENTER) {confirmBtn.click();}
|
||||
},
|
||||
});
|
||||
confirmBtn = createElement("button", {
|
||||
innerText: "Confirm", class: "std-button",
|
||||
clickListener: () => {
|
||||
if (isNaN(input.value)) {
|
||||
dialogBoxCreate("Invalid amount");
|
||||
} else {
|
||||
mat.buy = parseFloat(input.value);
|
||||
if (isNaN(mat.buy)) {mat.buy = 0;}
|
||||
removeElementById(purchasePopupId);
|
||||
this.rerender();
|
||||
return false;
|
||||
}
|
||||
},
|
||||
});
|
||||
const clearButton = createElement("button", {
|
||||
innerText: "Clear Purchase", class: "std-button",
|
||||
clickListener: () => {
|
||||
mat.buy = 0;
|
||||
removeElementById(purchasePopupId);
|
||||
this.rerender();
|
||||
return false;
|
||||
},
|
||||
});
|
||||
const cancelBtn = createPopupCloseButton(purchasePopupId, {
|
||||
class: "std-button",
|
||||
innerText: "Cancel",
|
||||
});
|
||||
|
||||
const elems = [txt, input, confirmBtn, clearButton, cancelBtn];
|
||||
|
||||
if (industry.hasResearch("Bulk Purchasing")) {
|
||||
const bulkPurchaseInfo = createElement("p", {
|
||||
innerText: "Enter the amount of " + mat.name + " you would like " +
|
||||
"to bulk purchase. This purchases the specified amount instantly " +
|
||||
"(all at once).",
|
||||
});
|
||||
|
||||
let bulkPurchaseCostTxt = createElement("p");
|
||||
function updateBulkPurchaseText(amount) {
|
||||
const parsedAmt = parseFloat(amount);
|
||||
const cost = parsedAmt * mat.bCost;
|
||||
|
||||
const matSize = MaterialSizes[mat.name];
|
||||
const maxAmount = ((warehouse.size - warehouse.sizeUsed) / matSize);
|
||||
|
||||
if (parsedAmt * matSize > maxAmount) {
|
||||
bulkPurchaseCostTxt.innerText = "Not enough warehouse space to purchase this amount";
|
||||
} else if (isNaN(cost)) {
|
||||
bulkPurchaseCostTxt.innerText = "Invalid put for Bulk Purchase amount";
|
||||
} else {
|
||||
bulkPurchaseCostTxt.innerText = `Purchasing ${numeralWrapper.format(parsedAmt, "0,0.00")} of ` +
|
||||
`${mat.name} will cost ${numeralWrapper.formatMoney(cost)}`;
|
||||
}
|
||||
}
|
||||
|
||||
let bulkPurchaseConfirmBtn;
|
||||
const bulkPurchaseInput = createElement("input", {
|
||||
margin: "5px",
|
||||
placeholder: "Bulk Purchase amount",
|
||||
type: "number",
|
||||
onkeyup: (e) => {
|
||||
e.preventDefault();
|
||||
updateBulkPurchaseText(e.target.value);
|
||||
if (e.keyCode === KEY.ENTER) {bulkPurchaseConfirmBtn.click();}
|
||||
},
|
||||
});
|
||||
|
||||
bulkPurchaseConfirmBtn = createElement("button", {
|
||||
class: "std-button",
|
||||
innerText: "Confirm Bulk Purchase",
|
||||
clickListener: () => {
|
||||
const amount = parseFloat(bulkPurchaseInput.value);
|
||||
|
||||
const matSize = MaterialSizes[mat.name];
|
||||
const maxAmount = ((warehouse.size - warehouse.sizeUsed) / matSize);
|
||||
if (amount * matSize > maxAmount) {
|
||||
dialogBoxCreate(`You do not have enough warehouse size to fit this purchase`);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isNaN(amount)) {
|
||||
dialogBoxCreate("Invalid input amount");
|
||||
} else {
|
||||
const cost = amount * mat.bCost;
|
||||
if (corp.funds.gt(cost)) {
|
||||
corp.funds = corp.funds.minus(cost);
|
||||
mat.qty += amount;
|
||||
} else {
|
||||
dialogBoxCreate(`You cannot afford this purchase.`);
|
||||
return false;
|
||||
}
|
||||
|
||||
removeElementById(purchasePopupId);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
elems.push(bulkPurchaseInfo);
|
||||
elems.push(bulkPurchaseCostTxt);
|
||||
elems.push(bulkPurchaseInput);
|
||||
elems.push(bulkPurchaseConfirmBtn);
|
||||
}
|
||||
|
||||
createPopup(purchasePopupId, elems);
|
||||
input.focus();
|
||||
}
|
||||
|
||||
// Create a popup that let the player manage sales of a material
|
||||
createSellMaterialPopup(mat) {
|
||||
const sellPopupId = "cmpy-mgmt-material-sell-popup";
|
||||
const txt = createElement("p", {
|
||||
innerHTML: "Enter the maximum amount of " + mat.name + " you would like " +
|
||||
"to sell per second, as well as the price at which you would " +
|
||||
"like to sell at.<br><br>" +
|
||||
"If the sell amount is set to 0, then the material will not be sold. If the sell price " +
|
||||
"if set to 0, then the material will be discarded<br><br>" +
|
||||
"Setting the sell amount to 'MAX' will result in you always selling the " +
|
||||
"maximum possible amount of the material.<br><br>" +
|
||||
"When setting the sell amount, you can use the 'PROD' variable to designate a dynamically " +
|
||||
"changing amount that depends on your production. For example, if you set the sell amount " +
|
||||
"to 'PROD-5' then you will always sell 5 less of the material than you produce.<br><br>" +
|
||||
"When setting the sell price, you can use the 'MP' variable to designate a dynamically " +
|
||||
"changing price that depends on the market price. For example, if you set the sell price " +
|
||||
"to 'MP+10' then it will always be sold at $10 above the market price.",
|
||||
});
|
||||
const br = createElement("br");
|
||||
let confirmBtn;
|
||||
const inputQty = createElement("input", {
|
||||
type: "text", marginTop: "4px",
|
||||
value: mat.sllman[1] ? mat.sllman[1] : null,
|
||||
placeholder: "Sell amount",
|
||||
onkeyup: (e) => {
|
||||
e.preventDefault();
|
||||
if (e.keyCode === KEY.ENTER) {confirmBtn.click();}
|
||||
},
|
||||
});
|
||||
|
||||
let inputButtonInitValue = mat.sCost ? mat.sCost : null;
|
||||
if (mat.marketTa2) {
|
||||
inputButtonInitValue += " (Market-TA.II)";
|
||||
} else if (mat.marketTa1) {
|
||||
inputButtonInitValue += " (Market-TA.I)";
|
||||
}
|
||||
|
||||
const inputPx = createElement("input", {
|
||||
type: "text", marginTop: "4px",
|
||||
value: inputButtonInitValue,
|
||||
placeholder: "Sell price",
|
||||
onkeyup: (e) => {
|
||||
e.preventDefault();
|
||||
if (e.keyCode === KEY.ENTER) {confirmBtn.click();}
|
||||
},
|
||||
});
|
||||
confirmBtn = createElement("button", {
|
||||
class: "std-button",
|
||||
innerText: "Confirm",
|
||||
clickListener: () => {
|
||||
//Parse price
|
||||
let cost = inputPx.value.replace(/\s+/g, '');
|
||||
cost = cost.replace(/[^-()\d/*+.MP]/g, ''); //Sanitize cost
|
||||
let temp = cost.replace(/MP/g, mat.bCost);
|
||||
try {
|
||||
temp = eval(temp);
|
||||
} catch(e) {
|
||||
dialogBoxCreate("Invalid value or expression for sell price field: " + e);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (temp == null || isNaN(temp)) {
|
||||
dialogBoxCreate("Invalid value or expression for sell price field");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cost.includes("MP")) {
|
||||
mat.sCost = cost; //Dynamically evaluated
|
||||
} else {
|
||||
mat.sCost = temp;
|
||||
}
|
||||
|
||||
//Parse quantity
|
||||
if (inputQty.value.includes("MAX") || inputQty.value.includes("PROD")) {
|
||||
let qty = inputQty.value.replace(/\s+/g, '');
|
||||
qty = qty.replace(/[^-()\d/*+.MAXPROD]/g, '');
|
||||
let tempQty = qty.replace(/MAX/g, 1);
|
||||
tempQty = tempQty.replace(/PROD/g, 1);
|
||||
try {
|
||||
tempQty = eval(tempQty);
|
||||
} catch(e) {
|
||||
dialogBoxCreate("Invalid value or expression for sell price field: " + e);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tempQty == null || isNaN(tempQty)) {
|
||||
dialogBoxCreate("Invalid value or expression for sell price field");
|
||||
return false;
|
||||
}
|
||||
|
||||
mat.sllman[0] = true;
|
||||
mat.sllman[1] = qty; //Use sanitized input
|
||||
} else if (isNaN(inputQty.value)) {
|
||||
dialogBoxCreate("Invalid value for sell quantity field! Must be numeric or 'MAX'");
|
||||
return false;
|
||||
} else {
|
||||
var qty = parseFloat(inputQty.value);
|
||||
if (isNaN(qty)) {qty = 0;}
|
||||
if (qty === 0) {
|
||||
mat.sllman[0] = false;
|
||||
mat.sllman[1] = 0;
|
||||
} else {
|
||||
mat.sllman[0] = true;
|
||||
mat.sllman[1] = qty;
|
||||
}
|
||||
}
|
||||
|
||||
removeElementById(sellPopupId);
|
||||
this.rerender();
|
||||
return false;
|
||||
},
|
||||
});
|
||||
const cancelBtn = createPopupCloseButton(sellPopupId, {
|
||||
class: "std-button",
|
||||
innerText: "Cancel",
|
||||
});
|
||||
|
||||
createPopup(sellPopupId, [txt, br, inputQty, inputPx, confirmBtn, cancelBtn]);
|
||||
inputQty.focus();
|
||||
}
|
||||
|
||||
// Create a popup that lets the player manage sales of the product
|
||||
createSellProductPopup(product, city) {
|
||||
const popupId = "cmpy-mgmt-sell-product-popup";
|
||||
const txt = createElement("p", {
|
||||
innerHTML:"Enter the maximum amount of " + product.name + " you would like " +
|
||||
"to sell per second, as well as the price at which you would like to " +
|
||||
"sell it at.<br><br>" +
|
||||
"If the sell amount is set to 0, then the product will not be sold. If the " +
|
||||
"sell price is set to 0, then the product will be discarded.<br><br>" +
|
||||
"Setting the sell amount to 'MAX' will result in you always selling the " +
|
||||
"maximum possible amount of the material.<br><br>" +
|
||||
"When setting the sell amount, you can use the 'PROD' variable to designate a " +
|
||||
"dynamically changing amount that depends on your production. For example, " +
|
||||
"if you set the sell amount to 'PROD-1' then you will always sell 1 less of " +
|
||||
"the material than you produce.<br><br>" +
|
||||
"When setting the sell price, you can use the 'MP' variable to set a " +
|
||||
"dynamically changing price that depends on the Product's estimated " +
|
||||
"market price. For example, if you set it to 'MP*5' then it " +
|
||||
"will always be sold at five times the estimated market price.",
|
||||
});
|
||||
let confirmBtn;
|
||||
const inputQty = createElement("input", {
|
||||
margin: "5px 0px 5px 0px",
|
||||
placeholder: "Sell amount",
|
||||
type: "text",
|
||||
value: product.sllman[city][1] ? product.sllman[city][1] : null,
|
||||
onkeyup: (e) => {
|
||||
e.preventDefault();
|
||||
if (e.keyCode === KEY.ENTER) {confirmBtn.click();}
|
||||
},
|
||||
});
|
||||
|
||||
let inputButtonInitValue = product.sCost ? product.sCost : null;
|
||||
if (product.marketTa2) {
|
||||
inputButtonInitValue += " (Market-TA.II)";
|
||||
} else if (product.marketTa1) {
|
||||
inputButtonInitValue += " (Market-TA.I)";
|
||||
}
|
||||
|
||||
const inputPx = createElement("input", {
|
||||
margin: "5px 0px 5px 0px",
|
||||
placeholder: "Sell price",
|
||||
type: "text",
|
||||
value: inputButtonInitValue,
|
||||
onkeyup: (e) => {
|
||||
e.preventDefault();
|
||||
if (e.keyCode === KEY.ENTER) {confirmBtn.click();}
|
||||
},
|
||||
});
|
||||
const checkboxDiv = createElement("div", {
|
||||
border: "1px solid white",
|
||||
display: "inline-block",
|
||||
})
|
||||
const checkboxLabel = createElement("label", {
|
||||
for: popupId + "-checkbox",
|
||||
innerText: "Use same 'Sell Amount' for all cities",
|
||||
});
|
||||
const checkbox = createElement("input", {
|
||||
checked: true,
|
||||
id: popupId + "-checkbox",
|
||||
margin: "2px",
|
||||
type: "checkbox",
|
||||
});
|
||||
checkboxDiv.appendChild(checkboxLabel);
|
||||
checkboxDiv.appendChild(checkbox);
|
||||
|
||||
confirmBtn = createElement("button", {
|
||||
class: "std-button",
|
||||
innerText: "Confirm",
|
||||
clickListener: () => {
|
||||
//Parse price
|
||||
if (inputPx.value.includes("MP")) {
|
||||
//Dynamically evaluated quantity. First test to make sure its valid
|
||||
//Sanitize input, then replace dynamic variables with arbitrary numbers
|
||||
var price = inputPx.value.replace(/\s+/g, '');
|
||||
price = price.replace(/[^-()\d/*+.MP]/g, '');
|
||||
var temp = price.replace(/MP/g, 1);
|
||||
try {
|
||||
temp = eval(temp);
|
||||
} catch(e) {
|
||||
dialogBoxCreate("Invalid value or expression for sell quantity field: " + e);
|
||||
return false;
|
||||
}
|
||||
if (temp == null || isNaN(temp)) {
|
||||
dialogBoxCreate("Invalid value or expression for sell quantity field.");
|
||||
return false;
|
||||
}
|
||||
product.sCost = price; //Use sanitized price
|
||||
} else {
|
||||
var cost = parseFloat(inputPx.value);
|
||||
if (isNaN(cost)) {
|
||||
dialogBoxCreate("Invalid value for sell price field");
|
||||
return false;
|
||||
}
|
||||
product.sCost = cost;
|
||||
}
|
||||
|
||||
// Array of all cities. Used later
|
||||
const cities = Object.keys(Cities);
|
||||
|
||||
// Parse quantity
|
||||
if (inputQty.value.includes("MAX") || inputQty.value.includes("PROD")) {
|
||||
//Dynamically evaluated quantity. First test to make sure its valid
|
||||
var qty = inputQty.value.replace(/\s+/g, '');
|
||||
qty = qty.replace(/[^-()\d/*+.MAXPROD]/g, '');
|
||||
var temp = qty.replace(/MAX/g, 1);
|
||||
temp = temp.replace(/PROD/g, 1);
|
||||
try {
|
||||
temp = eval(temp);
|
||||
} catch(e) {
|
||||
dialogBoxCreate("Invalid value or expression for sell price field: " + e);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (temp == null || isNaN(temp)) {
|
||||
dialogBoxCreate("Invalid value or expression for sell price field");
|
||||
return false;
|
||||
}
|
||||
if (checkbox.checked) {
|
||||
for (let i = 0; i < cities.length; ++i) {
|
||||
const tempCity = cities[i];
|
||||
product.sllman[tempCity][0] = true;
|
||||
product.sllman[tempCity][1] = qty; //Use sanitized input
|
||||
}
|
||||
} else {
|
||||
product.sllman[city][0] = true;
|
||||
product.sllman[city][1] = qty; //Use sanitized input
|
||||
}
|
||||
} else if (isNaN(inputQty.value)) {
|
||||
dialogBoxCreate("Invalid value for sell quantity field! Must be numeric");
|
||||
return false;
|
||||
} else {
|
||||
var qty = parseFloat(inputQty.value);
|
||||
if (isNaN(qty)) {qty = 0;}
|
||||
if (qty === 0) {
|
||||
if (checkbox.checked) {
|
||||
for (let i = 0; i < cities.length; ++i) {
|
||||
const tempCity = cities[i];
|
||||
product.sllman[tempCity][0] = false;
|
||||
}
|
||||
} else {
|
||||
product.sllman[city][0] = false;
|
||||
}
|
||||
} else {
|
||||
if (checkbox.checked) {
|
||||
for (let i = 0; i < cities.length; ++i) {
|
||||
const tempCity = cities[i];
|
||||
product.sllman[tempCity][0] = true;
|
||||
product.sllman[tempCity][1] = qty;
|
||||
}
|
||||
} else {
|
||||
product.sllman[city][0] = true;
|
||||
product.sllman[city][1] = qty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
removeElementById(popupId);
|
||||
this.rerender();
|
||||
return false;
|
||||
},
|
||||
});
|
||||
const cancelBtn = createPopupCloseButton(popupId, { class: "std-button" });
|
||||
|
||||
const linebreak1 = createElement("br");
|
||||
|
||||
createPopup(popupId, [txt, inputQty, inputPx, confirmBtn, cancelBtn, linebreak1,
|
||||
checkboxDiv]);
|
||||
inputQty.focus();
|
||||
}
|
||||
|
||||
rerender() {
|
||||
this.corp.rerender();
|
||||
}
|
||||
}
|
@ -9,7 +9,6 @@ import { createPopup } from "../../ui/React/createPopup";
|
||||
|
||||
interface IProps {
|
||||
corp: any;
|
||||
eventHandler: any;
|
||||
routing: any;
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,6 @@ import { IndustryWarehouse } from "./IndustryWarehouse";
|
||||
|
||||
interface IProps {
|
||||
routing: any;
|
||||
eventHandler: any;
|
||||
corp: any;
|
||||
currentCity: string;
|
||||
}
|
||||
@ -19,12 +18,10 @@ export function Industry(props: IProps): React.ReactElement {
|
||||
<div className={"cmpy-mgmt-industry-left-panel"}>
|
||||
<IndustryOverview
|
||||
routing={props.routing}
|
||||
eventHandler={props.eventHandler}
|
||||
corp={props.corp}
|
||||
currentCity={props.currentCity} />
|
||||
<IndustryOffice
|
||||
routing={props.routing}
|
||||
eventHandler={props.eventHandler}
|
||||
corp={props.corp}
|
||||
currentCity={props.currentCity} />
|
||||
</div>
|
||||
@ -32,8 +29,7 @@ export function Industry(props: IProps): React.ReactElement {
|
||||
<IndustryWarehouse
|
||||
corp={props.corp}
|
||||
routing={props.routing}
|
||||
currentCity={props.currentCity}
|
||||
eventHandler={props.eventHandler} />
|
||||
currentCity={props.currentCity} />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
@ -15,7 +15,6 @@ import { ThrowPartyPopup } from "./ThrowPartyPopup";
|
||||
|
||||
interface IProps {
|
||||
routing: any;
|
||||
eventHandler: any;
|
||||
corp: any;
|
||||
currentCity: string;
|
||||
}
|
||||
|
@ -13,7 +13,6 @@ import { createPopup } from "../../ui/React/createPopup";
|
||||
|
||||
interface IProps {
|
||||
routing: any;
|
||||
eventHandler: any;
|
||||
corp: any;
|
||||
currentCity: string;
|
||||
}
|
||||
|
@ -11,6 +11,10 @@ import { DiscontinueProductPopup } from "./DiscontinueProductPopup";
|
||||
import { ExportPopup } from "./ExportPopup";
|
||||
import { LimitProductProductionPopup } from "./LimitProductProductionPopup";
|
||||
import { MaterialMarketTaPopup } from "./MaterialMarketTaPopup";
|
||||
import { SellMaterialPopup } from "./SellMaterialPopup";
|
||||
import { SellProductPopup } from "./SellProductPopup";
|
||||
import { PurchaseMaterialPopup } from "./PurchaseMaterialPopup";
|
||||
import { ProductMarketTaPopup } from "./ProductMarketTaPopup";
|
||||
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
import { dialogBoxCreate } from "../../../utils/DialogBox";
|
||||
@ -23,7 +27,6 @@ interface IProductProps {
|
||||
division: any;
|
||||
city: string;
|
||||
product: any;
|
||||
eventHandler: any;
|
||||
}
|
||||
|
||||
// Creates the UI for a single Product type
|
||||
@ -32,7 +35,6 @@ function ProductComponent(props: IProductProps): React.ReactElement {
|
||||
const division = props.division;
|
||||
const city = props.city;
|
||||
const product = props.product;
|
||||
const eventHandler = props.eventHandler;
|
||||
|
||||
// Numeraljs formatters
|
||||
const nf = "0.000";
|
||||
@ -67,7 +69,15 @@ function ProductComponent(props: IProductProps): React.ReactElement {
|
||||
sellButtonText += (" @ " + numeralWrapper.format(product.sCost, "$0.000a"));
|
||||
}
|
||||
}
|
||||
const sellButtonOnClick = eventHandler.createSellProductPopup.bind(eventHandler, product, city);
|
||||
|
||||
function openSellProductPopup(): void {
|
||||
const popupId = "cmpy-mgmt-limit-product-production-popup";
|
||||
createPopup(popupId, SellProductPopup, {
|
||||
product: product,
|
||||
city: city,
|
||||
popupId: popupId,
|
||||
});
|
||||
}
|
||||
|
||||
// Limit Production button
|
||||
let limitProductionButtonText = "Limit Production";
|
||||
@ -94,8 +104,14 @@ function ProductComponent(props: IProductProps): React.ReactElement {
|
||||
});
|
||||
}
|
||||
|
||||
// Market TA button
|
||||
const marketTaButtonOnClick = eventHandler.createProductMarketTaPopup.bind(eventHandler, product, division);
|
||||
function openProductMarketTaPopup(): void {
|
||||
const popupId = "cmpy-mgmt-marketta-popup";
|
||||
createPopup(popupId, ProductMarketTaPopup, {
|
||||
product: product,
|
||||
industry: division,
|
||||
popupId: popupId,
|
||||
});
|
||||
}
|
||||
|
||||
// Unfinished Product
|
||||
if (!product.fin) {
|
||||
@ -107,7 +123,7 @@ function ProductComponent(props: IProductProps): React.ReactElement {
|
||||
<br />
|
||||
|
||||
<div>
|
||||
<button className={"std-button"} onClick={sellButtonOnClick}>
|
||||
<button className={"std-button"} onClick={openSellProductPopup}>
|
||||
{sellButtonText}
|
||||
</button><br />
|
||||
<button className={"std-button"} onClick={openLimitProductProdutionPopup}>
|
||||
@ -118,7 +134,7 @@ function ProductComponent(props: IProductProps): React.ReactElement {
|
||||
</button>
|
||||
{
|
||||
division.hasResearch("Market-TA.I") &&
|
||||
<button className={"std-button"} onClick={marketTaButtonOnClick}>
|
||||
<button className={"std-button"} onClick={openProductMarketTaPopup}>
|
||||
Market-TA
|
||||
</button>
|
||||
}
|
||||
@ -187,7 +203,7 @@ function ProductComponent(props: IProductProps): React.ReactElement {
|
||||
</p>
|
||||
|
||||
<div>
|
||||
<button className={"std-button"} onClick={sellButtonOnClick}>
|
||||
<button className={"std-button"} onClick={openSellProductPopup}>
|
||||
{sellButtonText}
|
||||
</button><br />
|
||||
<button className={"std-button"} onClick={openLimitProductProdutionPopup}>
|
||||
@ -198,7 +214,7 @@ function ProductComponent(props: IProductProps): React.ReactElement {
|
||||
</button>
|
||||
{
|
||||
division.hasResearch("Market-TA.I") &&
|
||||
<button className={"std-button"} onClick={marketTaButtonOnClick}>
|
||||
<button className={"std-button"} onClick={openProductMarketTaPopup}>
|
||||
Market-TA
|
||||
</button>
|
||||
}
|
||||
@ -213,7 +229,6 @@ interface IMaterialProps {
|
||||
warehouse: any;
|
||||
city: string;
|
||||
mat: any;
|
||||
eventHandler: any;
|
||||
}
|
||||
|
||||
// Creates the UI for a single Material type
|
||||
@ -223,7 +238,6 @@ function MaterialComponent(props: IMaterialProps): React.ReactElement {
|
||||
const warehouse = props.warehouse;
|
||||
const city = props.city;
|
||||
const mat = props.mat;
|
||||
const eventHandler = props.eventHandler;
|
||||
const markupLimit = mat.getMarkupLimit();
|
||||
const office = division.offices[city];
|
||||
if (!(office instanceof OfficeSpace)) {
|
||||
@ -245,7 +259,17 @@ function MaterialComponent(props: IMaterialProps): React.ReactElement {
|
||||
// Purchase material button
|
||||
const purchaseButtonText = `Buy (${numeralWrapper.format(mat.buy, nfB)})`;
|
||||
const purchaseButtonClass = tutorial ? "std-button flashing-button tooltip" : "std-button";
|
||||
const purchaseButtonOnClick = eventHandler.createPurchaseMaterialPopup.bind(eventHandler, mat, division, warehouse);
|
||||
|
||||
function openPurchaseMaterialPopup() {
|
||||
const popupId = "cmpy-mgmt-material-purchase-popup";
|
||||
createPopup(popupId, PurchaseMaterialPopup, {
|
||||
mat: mat,
|
||||
industry: division,
|
||||
warehouse: warehouse,
|
||||
corp: props.corp,
|
||||
popupId: popupId,
|
||||
});
|
||||
}
|
||||
|
||||
function openExportPopup() {
|
||||
const popupId = "cmpy-mgmt-export-popup";
|
||||
@ -280,7 +304,15 @@ function MaterialComponent(props: IMaterialProps): React.ReactElement {
|
||||
} else {
|
||||
sellButtonText = "Sell (0.000/0.000)";
|
||||
}
|
||||
const sellButtonOnClick = eventHandler.createSellMaterialPopup.bind(eventHandler, mat);
|
||||
|
||||
function openSellMaterialPopup(): void {
|
||||
const popupId = "cmpy-mgmt-material-sell-popup";
|
||||
createPopup(popupId, SellMaterialPopup, {
|
||||
mat: mat,
|
||||
corp: props.corp,
|
||||
popupId: popupId,
|
||||
});
|
||||
}
|
||||
|
||||
function openMaterialMarketTaPopup(): void {
|
||||
const popupId = "cmpy-mgmt-export-popup";
|
||||
@ -334,7 +366,7 @@ function MaterialComponent(props: IMaterialProps): React.ReactElement {
|
||||
</div>
|
||||
|
||||
<div style={{display: "inline-block"}}>
|
||||
<button className={purchaseButtonClass} onClick={purchaseButtonOnClick}>
|
||||
<button className={purchaseButtonClass} onClick={openPurchaseMaterialPopup}>
|
||||
{purchaseButtonText}
|
||||
{
|
||||
tutorial &&
|
||||
@ -352,7 +384,7 @@ function MaterialComponent(props: IMaterialProps): React.ReactElement {
|
||||
}
|
||||
<br />
|
||||
|
||||
<button className={"std-button"} onClick={sellButtonOnClick}>
|
||||
<button className={"std-button"} onClick={openSellMaterialPopup}>
|
||||
{sellButtonText}
|
||||
</button>
|
||||
|
||||
@ -372,7 +404,6 @@ interface IProps {
|
||||
corp: any;
|
||||
routing: any;
|
||||
currentCity: string;
|
||||
eventHandler: any;
|
||||
}
|
||||
|
||||
export function IndustryWarehouse(props: IProps): React.ReactElement {
|
||||
@ -485,7 +516,6 @@ export function IndustryWarehouse(props: IProps): React.ReactElement {
|
||||
city={props.currentCity}
|
||||
corp={corp}
|
||||
division={division}
|
||||
eventHandler={props.eventHandler}
|
||||
key={matName}
|
||||
mat={warehouse.materials[matName]}
|
||||
warehouse={warehouse} />);
|
||||
@ -502,7 +532,6 @@ export function IndustryWarehouse(props: IProps): React.ReactElement {
|
||||
city={props.currentCity}
|
||||
corp={corp}
|
||||
division={division}
|
||||
eventHandler={props.eventHandler}
|
||||
key={productName}
|
||||
product={division.products[productName]}
|
||||
/>);
|
||||
|
@ -14,7 +14,6 @@ import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
|
||||
interface IProps {
|
||||
corp: any;
|
||||
eventHandler: any;
|
||||
routing: any;
|
||||
player: IPlayer;
|
||||
}
|
||||
|
@ -20,7 +20,6 @@ import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
|
||||
interface IProps {
|
||||
corp: any;
|
||||
eventHandler: any;
|
||||
player: IPlayer;
|
||||
}
|
||||
|
||||
|
105
src/Corporation/ui/ProductMarketTaPopup.tsx
Normal file
105
src/Corporation/ui/ProductMarketTaPopup.tsx
Normal file
@ -0,0 +1,105 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Warehouse } from "../Warehouse";
|
||||
import { dialogBoxCreate } from "../../../utils/DialogBox";
|
||||
import { createElement } from "../../../utils/uiHelpers/createElement";
|
||||
import { removePopup } from "../../ui/React/createPopup";
|
||||
import { createOptionElement } from "../../../utils/uiHelpers/createOptionElement";
|
||||
import { clearSelector } from "../../../utils/uiHelpers/clearSelector";
|
||||
import { getSelectText,
|
||||
getSelectValue } from "../../../utils/uiHelpers/getSelectData";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
|
||||
interface IProps {
|
||||
product: any;
|
||||
industry: any;
|
||||
popupId: string;
|
||||
}
|
||||
|
||||
function MarketTA2(props: IProps): React.ReactElement {
|
||||
const markupLimit = props.product.rat / props.product.mku;
|
||||
const [value, setValue] = useState(props.product.pCost);
|
||||
const setRerender = useState(false)[1];
|
||||
function rerender(): void {
|
||||
setRerender(old => !old);
|
||||
}
|
||||
|
||||
function onChange(event: React.ChangeEvent<HTMLInputElement>): void {
|
||||
setValue(event.target.value);
|
||||
}
|
||||
|
||||
|
||||
function onCheckedChange(event: React.ChangeEvent<HTMLInputElement>): void {
|
||||
props.product.marketTa2 = event.target.checked;
|
||||
rerender();
|
||||
}
|
||||
|
||||
const sCost = parseFloat(value);
|
||||
let markup = 1;
|
||||
if (sCost > props.product.pCost) {
|
||||
if ((sCost - props.product.pCost) > markupLimit) {
|
||||
markup = markupLimit / (sCost - props.product.pCost);
|
||||
}
|
||||
}
|
||||
|
||||
return (<>
|
||||
<p>
|
||||
<br /><u><strong>Market-TA.II</strong></u><br />
|
||||
If you sell at {numeralWrapper.formatMoney(sCost)},
|
||||
then you will sell {numeralWrapper.format(markup, "0.00000")}x as much compared
|
||||
to if you sold at market price.
|
||||
</p>
|
||||
<input className="text-input" onChange={onChange} value={value} type="number" style={{marginTop: "4px"}} />
|
||||
<div style={{display: 'block'}}>
|
||||
<label className="tooltip" htmlFor="cmpy-mgmt-marketa2-checkbox" style={{color: "white"}}>
|
||||
Use Market-TA.II for Auto-Sale Price
|
||||
<span className="tooltiptext">
|
||||
If this is enabled, then this Product will automatically
|
||||
be sold at the optimal price such that the amount sold matches the
|
||||
amount produced. (i.e. the highest possible price, while still ensuring
|
||||
that all produced materials will be sold).
|
||||
</span>
|
||||
</label>
|
||||
<input className="text-input" onChange={onCheckedChange} id="cmpy-mgmt-marketa2-checkbox" style={{margin: "3px"}} type="checkbox" checked={props.product.marketTa2} />
|
||||
</div>
|
||||
<p>
|
||||
Note that Market-TA.II overrides Market-TA.I. This means that if
|
||||
both are enabled, then Market-TA.II will take effect, not Market-TA.I
|
||||
</p>
|
||||
</>);
|
||||
}
|
||||
|
||||
// Create a popup that lets the player use the Market TA research for Products
|
||||
export function ProductMarketTaPopup(props: IProps): React.ReactElement {
|
||||
const markupLimit = props.product.rat / props.product.mku;
|
||||
const setRerender = useState(false)[1];
|
||||
function rerender(): void {
|
||||
setRerender(old => !old);
|
||||
}
|
||||
|
||||
function onChange(event: React.ChangeEvent<HTMLInputElement>): void {
|
||||
props.product.marketTa1 = event.target.checked;
|
||||
rerender();
|
||||
}
|
||||
|
||||
return (<>
|
||||
<p>
|
||||
<u><strong>Market-TA.I</strong></u><br />
|
||||
The maximum sale price you can mark this up to
|
||||
is {numeralWrapper.formatMoney(props.product.pCost + markupLimit)}.
|
||||
This means that if you set the sale price higher than this,
|
||||
you will begin to experience a loss in number of sales.
|
||||
</p>
|
||||
<div style={{display: 'block'}}>
|
||||
<label className="tooltip" htmlFor="cmpy-mgmt-marketa1-checkbox" style={{color: "white"}}>
|
||||
Use Market-TA.I for Auto-Sale Price
|
||||
<span className="tooltiptext">
|
||||
If this is enabled, then this Product will automatically
|
||||
be sold at the price identified by Market-TA.I
|
||||
(i.e. the price shown above).
|
||||
</span>
|
||||
</label>
|
||||
<input onChange={onChange} className="text-input" id="cmpy-mgmt-marketa1-checkbox" style={{margin: "3px"}} type="checkbox" checked={props.product.marketTa1} />
|
||||
</div>
|
||||
{props.industry.hasResearch("Market-TA.II") && <MarketTA2 product={props.product} industry={props.industry} popupId={props.popupId} />}
|
||||
</>);
|
||||
}
|
130
src/Corporation/ui/PurchaseMaterialPopup.tsx
Normal file
130
src/Corporation/ui/PurchaseMaterialPopup.tsx
Normal file
@ -0,0 +1,130 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Warehouse } from "../Warehouse";
|
||||
import { dialogBoxCreate } from "../../../utils/DialogBox";
|
||||
import { createElement } from "../../../utils/uiHelpers/createElement";
|
||||
import { removePopup } from "../../ui/React/createPopup";
|
||||
import { createOptionElement } from "../../../utils/uiHelpers/createOptionElement";
|
||||
import { clearSelector } from "../../../utils/uiHelpers/clearSelector";
|
||||
import { getSelectText,
|
||||
getSelectValue } from "../../../utils/uiHelpers/getSelectData";
|
||||
import { MaterialSizes } from "../MaterialSizes";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
|
||||
interface IBulkPurchaseTextProps {
|
||||
warehouse: any;
|
||||
mat: any;
|
||||
amount: string;
|
||||
}
|
||||
|
||||
function BulkPurchaseText(props: IBulkPurchaseTextProps): React.ReactElement {
|
||||
const parsedAmt = parseFloat(props.amount);
|
||||
const cost = parsedAmt * props.mat.bCost;
|
||||
|
||||
const matSize = MaterialSizes[props.mat.name];
|
||||
const maxAmount = ((props.warehouse.size - props.warehouse.sizeUsed) / matSize);
|
||||
|
||||
if (parsedAmt * matSize > maxAmount) {
|
||||
return (<>Not enough warehouse space to purchase this amount</>);
|
||||
} else if (isNaN(cost)) {
|
||||
return (<>Invalid put for Bulk Purchase amount</>);
|
||||
} else {
|
||||
return (<>Purchasing {numeralWrapper.format(parsedAmt, "0,0.00")} of
|
||||
{props.mat.name} will cost {numeralWrapper.formatMoney(cost)}</>);
|
||||
}
|
||||
}
|
||||
|
||||
interface IProps {
|
||||
mat: any;
|
||||
industry: any;
|
||||
warehouse: any;
|
||||
corp: any;
|
||||
popupId: string;
|
||||
}
|
||||
|
||||
function BulkPurchase(props: IProps): React.ReactElement {
|
||||
const [buyAmt, setBuyAmt] = useState('');
|
||||
|
||||
function bulkPurchase(): void {
|
||||
const amount = parseFloat(buyAmt);
|
||||
|
||||
const matSize = MaterialSizes[props.mat.name];
|
||||
const maxAmount = ((props.warehouse.size - props.warehouse.sizeUsed) / matSize);
|
||||
if (amount * matSize > maxAmount) {
|
||||
dialogBoxCreate(`You do not have enough warehouse size to fit this purchase`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isNaN(amount)) {
|
||||
dialogBoxCreate("Invalid input amount");
|
||||
} else {
|
||||
const cost = amount * props.mat.bCost;
|
||||
if (props.corp.funds.gt(cost)) {
|
||||
props.corp.funds = props.corp.funds.minus(cost);
|
||||
props.mat.qty += amount;
|
||||
} else {
|
||||
dialogBoxCreate(`You cannot afford this purchase.`);
|
||||
return;
|
||||
}
|
||||
|
||||
removePopup(props.popupId);
|
||||
}
|
||||
}
|
||||
|
||||
function onKeyDown(event: React.KeyboardEvent<HTMLInputElement>): void {
|
||||
if (event.keyCode === 13) bulkPurchase();
|
||||
}
|
||||
|
||||
function onChange(event: React.ChangeEvent<HTMLInputElement>): void {
|
||||
setBuyAmt(event.target.value);
|
||||
}
|
||||
|
||||
return (<>
|
||||
<p>
|
||||
Enter the amount of {props.mat.name} you would like
|
||||
to bulk purchase. This purchases the specified amount instantly
|
||||
(all at once).
|
||||
</p>
|
||||
<BulkPurchaseText warehouse={props.warehouse} mat={props.mat} amount={buyAmt} />
|
||||
<input onChange={onChange} type="number" placeholder="Bulk Purchase amount" style={{margin: "5px"}} />
|
||||
<button className="std-button">Confirm Bulk Purchase</button>
|
||||
</>);
|
||||
}
|
||||
|
||||
// Create a popup that lets the player purchase a Material
|
||||
export function PurchaseMaterialPopup(props: IProps): React.ReactElement {
|
||||
const [buyAmt, setBuyAmt] = useState(props.mat.buy ? props.mat.buy : null);
|
||||
|
||||
function purchaseMaterial(): void {
|
||||
if (isNaN(parseFloat(buyAmt))) {
|
||||
dialogBoxCreate("Invalid amount");
|
||||
} else {
|
||||
props.mat.buy = parseFloat(buyAmt);
|
||||
if (isNaN(props.mat.buy)) props.mat.buy = 0;
|
||||
removePopup(props.popupId);
|
||||
}
|
||||
}
|
||||
|
||||
function clearPurchase(): void {
|
||||
props.mat.buy = 0;
|
||||
removePopup(props.popupId);
|
||||
}
|
||||
|
||||
function onKeyDown(event: React.KeyboardEvent<HTMLInputElement>): void {
|
||||
if (event.keyCode === 13) purchaseMaterial();
|
||||
}
|
||||
|
||||
function onChange(event: React.ChangeEvent<HTMLInputElement>): void {
|
||||
setBuyAmt(event.target.value);
|
||||
}
|
||||
|
||||
return (<>
|
||||
<p>
|
||||
Enter the amount of {props.mat.name} you would like
|
||||
to purchase per second. This material's cost changes constantly.
|
||||
</p>
|
||||
<input onChange={onChange} className="text-input" autoFocus={true} placeholder="Purchase amount" type="number" style={{margin: "5px"}} onKeyDown={onKeyDown} />
|
||||
<button onClick={purchaseMaterial} className="std-button">Confirm</button>
|
||||
<button onClick={clearPurchase} className="std-button">Clear Purchase</button>
|
||||
{props.industry.hasResearch("Bulk Purchasing") && <BulkPurchase corp={props.corp} mat={props.mat} industry={props.industry} warehouse={props.warehouse} popupId={props.popupId} />}
|
||||
</>);
|
||||
}
|
@ -7,7 +7,6 @@ import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
|
||||
interface IProps {
|
||||
corp: any;
|
||||
eventHandler: any;
|
||||
routing: any;
|
||||
player: IPlayer;
|
||||
}
|
||||
@ -15,8 +14,8 @@ interface IProps {
|
||||
export function CorporationRoot(props: IProps): React.ReactElement {
|
||||
return (
|
||||
<div>
|
||||
<HeaderTabs corp={props.corp} eventHandler={props.eventHandler} routing={props.routing} />
|
||||
<MainPanel corp={props.corp} eventHandler={props.eventHandler} routing={props.routing} player={props.player} />
|
||||
<HeaderTabs corp={props.corp} routing={props.routing} />
|
||||
<MainPanel corp={props.corp} routing={props.routing} player={props.player} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
129
src/Corporation/ui/SellMaterialPopup.tsx
Normal file
129
src/Corporation/ui/SellMaterialPopup.tsx
Normal file
@ -0,0 +1,129 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Warehouse } from "../Warehouse";
|
||||
import { dialogBoxCreate } from "../../../utils/DialogBox";
|
||||
import { createElement } from "../../../utils/uiHelpers/createElement";
|
||||
import { removePopup } from "../../ui/React/createPopup";
|
||||
import { createOptionElement } from "../../../utils/uiHelpers/createOptionElement";
|
||||
import { clearSelector } from "../../../utils/uiHelpers/clearSelector";
|
||||
import { getSelectText,
|
||||
getSelectValue } from "../../../utils/uiHelpers/getSelectData";
|
||||
|
||||
function initialPrice(mat: any): string {
|
||||
let val = mat.sCost ? mat.sCost : '';
|
||||
if (mat.marketTa2) {
|
||||
val += " (Market-TA.II)";
|
||||
} else if (mat.marketTa1) {
|
||||
val += " (Market-TA.I)";
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
interface IProps {
|
||||
mat: any;
|
||||
corp: any;
|
||||
popupId: string;
|
||||
}
|
||||
|
||||
// Create a popup that let the player manage sales of a material
|
||||
export function SellMaterialPopup(props: IProps): React.ReactElement {
|
||||
const [amt, setAmt] = useState<string>(props.mat.sllman[1] ? props.mat.sllman[1] : '');
|
||||
const [price, setPrice] = useState<string>(initialPrice(props.mat));
|
||||
|
||||
function sellMaterial(): void {
|
||||
let p = price;
|
||||
let qty = amt;
|
||||
if(p === '') p = '0';
|
||||
if(qty === '') qty = '0';
|
||||
let cost = p.replace(/\s+/g, '');
|
||||
cost = cost.replace(/[^-()\d/*+.MP]/g, ''); //Sanitize cost
|
||||
let temp = cost.replace(/MP/g, props.mat.bCost);
|
||||
try {
|
||||
temp = eval(temp);
|
||||
} catch(e) {
|
||||
dialogBoxCreate("Invalid value or expression for sell price field: " + e);
|
||||
return;
|
||||
}
|
||||
|
||||
if (temp == null || isNaN(parseFloat(temp))) {
|
||||
dialogBoxCreate("Invalid value or expression for sell price field");
|
||||
return;
|
||||
}
|
||||
|
||||
if (cost.includes("MP")) {
|
||||
props.mat.sCost = cost; //Dynamically evaluated
|
||||
} else {
|
||||
props.mat.sCost = temp;
|
||||
}
|
||||
|
||||
//Parse quantity
|
||||
if (qty.includes("MAX") || qty.includes("PROD")) {
|
||||
let q = qty.replace(/\s+/g, '');
|
||||
q = q.replace(/[^-()\d/*+.MAXPROD]/g, '');
|
||||
let tempQty = q.replace(/MAX/g, '1');
|
||||
tempQty = tempQty.replace(/PROD/g, '1');
|
||||
try {
|
||||
tempQty = eval(tempQty);
|
||||
} catch(e) {
|
||||
dialogBoxCreate("Invalid value or expression for sell price field: " + e);
|
||||
return;
|
||||
}
|
||||
|
||||
if (tempQty == null || isNaN(parseFloat(tempQty))) {
|
||||
dialogBoxCreate("Invalid value or expression for sell price field");
|
||||
return;
|
||||
}
|
||||
|
||||
props.mat.sllman[0] = true;
|
||||
props.mat.sllman[1] = q; //Use sanitized input
|
||||
} else if (isNaN(parseFloat(qty))) {
|
||||
dialogBoxCreate("Invalid value for sell quantity field! Must be numeric or 'MAX'");
|
||||
return;
|
||||
} else {
|
||||
let q = parseFloat(qty);
|
||||
if (isNaN(q)) {q = 0;}
|
||||
if (q === 0) {
|
||||
props.mat.sllman[0] = false;
|
||||
props.mat.sllman[1] = 0;
|
||||
} else {
|
||||
props.mat.sllman[0] = true;
|
||||
props.mat.sllman[1] = q;
|
||||
}
|
||||
}
|
||||
|
||||
removePopup(props.popupId);
|
||||
}
|
||||
|
||||
function onAmtChange(event: React.ChangeEvent<HTMLInputElement>): void {
|
||||
setAmt(event.target.value);
|
||||
}
|
||||
|
||||
function onPriceChange(event: React.ChangeEvent<HTMLInputElement>): void {
|
||||
setPrice(event.target.value);
|
||||
}
|
||||
|
||||
function onKeyDown(event: React.KeyboardEvent<HTMLInputElement>): void {
|
||||
if (event.keyCode === 13) sellMaterial();
|
||||
}
|
||||
|
||||
return (<>
|
||||
<p>
|
||||
Enter the maximum amount of {props.mat.name} you would like
|
||||
to sell per second, as well as the price at which you would
|
||||
like to sell at.<br /><br />
|
||||
If the sell amount is set to 0, then the material will not be sold. If the sell price
|
||||
if set to 0, then the material will be discarded<br /><br />
|
||||
Setting the sell amount to 'MAX' will result in you always selling the
|
||||
maximum possible amount of the material.<br /><br />
|
||||
When setting the sell amount, you can use the 'PROD' variable to designate a dynamically
|
||||
changing amount that depends on your production. For example, if you set the sell amount
|
||||
to 'PROD-5' then you will always sell 5 less of the material than you produce.<br /><br />
|
||||
When setting the sell price, you can use the 'MP' variable to designate a dynamically
|
||||
changing price that depends on the market price. For example, if you set the sell price
|
||||
to 'MP+10' then it will always be sold at $10 above the market price.
|
||||
</p>
|
||||
<br />
|
||||
<input className="text-input" value={amt} autoFocus={true} type="text" placeholder="Sell amount" style={{marginTop: "4px"}} onChange={onAmtChange} onKeyDown={onKeyDown} />
|
||||
<input className="text-input" value={price} type="text" placeholder="Sell price" style={{marginTop: "4px"}} onChange={onPriceChange} onKeyDown={onKeyDown} />
|
||||
<button className="std-button" onClick={sellMaterial}>Confirm</button>
|
||||
</>);
|
||||
}
|
170
src/Corporation/ui/SellProductPopup.tsx
Normal file
170
src/Corporation/ui/SellProductPopup.tsx
Normal file
@ -0,0 +1,170 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Warehouse } from "../Warehouse";
|
||||
import { dialogBoxCreate } from "../../../utils/DialogBox";
|
||||
import { createElement } from "../../../utils/uiHelpers/createElement";
|
||||
import { removePopup } from "../../ui/React/createPopup";
|
||||
import { createOptionElement } from "../../../utils/uiHelpers/createOptionElement";
|
||||
import { clearSelector } from "../../../utils/uiHelpers/clearSelector";
|
||||
import { getSelectText,
|
||||
getSelectValue } from "../../../utils/uiHelpers/getSelectData";
|
||||
import { Cities } from "../../Locations/Cities";
|
||||
|
||||
function initialPrice(product: any): string {
|
||||
let val = product.sCost ? product.sCost : '';
|
||||
if (product.marketTa2) {
|
||||
val += " (Market-TA.II)";
|
||||
} else if (product.marketTa1) {
|
||||
val += " (Market-TA.I)";
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
interface IProps {
|
||||
product: any;
|
||||
city: string;
|
||||
popupId: string;
|
||||
}
|
||||
|
||||
// Create a popup that let the player manage sales of a material
|
||||
export function SellProductPopup(props: IProps): React.ReactElement {
|
||||
const [checked, setChecked] = useState(true);
|
||||
const [iQty, setQty] = useState<string>(props.product.sllman[props.city][1] ? props.product.sllman[props.city][1] : '');
|
||||
const [px, setPx] = useState<string>(initialPrice(props.product));
|
||||
|
||||
function onCheckedChange(event: React.ChangeEvent<HTMLInputElement>): void {
|
||||
setChecked(event.target.checked);
|
||||
}
|
||||
|
||||
function sellProduct(): void {
|
||||
//Parse price
|
||||
if (px.includes("MP")) {
|
||||
//Dynamically evaluated quantity. First test to make sure its valid
|
||||
//Sanitize input, then replace dynamic variables with arbitrary numbers
|
||||
var price = px.replace(/\s+/g, '');
|
||||
price = price.replace(/[^-()\d/*+.MP]/g, '');
|
||||
var temp = price.replace(/MP/g, '1');
|
||||
try {
|
||||
temp = eval(temp);
|
||||
} catch(e) {
|
||||
dialogBoxCreate("Invalid value or expression for sell quantity field: " + e);
|
||||
return;
|
||||
}
|
||||
if (temp == null || isNaN(parseFloat(temp))) {
|
||||
dialogBoxCreate("Invalid value or expression for sell quantity field.");
|
||||
return;
|
||||
}
|
||||
props.product.sCost = price; //Use sanitized price
|
||||
} else {
|
||||
var cost = parseFloat(px);
|
||||
if (isNaN(cost)) {
|
||||
dialogBoxCreate("Invalid value for sell price field");
|
||||
return;
|
||||
}
|
||||
props.product.sCost = cost;
|
||||
}
|
||||
|
||||
// Array of all cities. Used later
|
||||
const cities = Object.keys(Cities);
|
||||
|
||||
// Parse quantity
|
||||
if (iQty.includes("MAX") || iQty.includes("PROD")) {
|
||||
//Dynamically evaluated quantity. First test to make sure its valid
|
||||
var qty = iQty.replace(/\s+/g, '');
|
||||
qty = qty.replace(/[^-()\d/*+.MAXPROD]/g, '');
|
||||
var temp = qty.replace(/MAX/g, '1');
|
||||
temp = temp.replace(/PROD/g, '1');
|
||||
try {
|
||||
temp = eval(temp);
|
||||
} catch(e) {
|
||||
dialogBoxCreate("Invalid value or expression for sell price field: " + e);
|
||||
return;
|
||||
}
|
||||
|
||||
if (temp == null || isNaN(parseFloat(temp))) {
|
||||
dialogBoxCreate("Invalid value or expression for sell price field");
|
||||
return;
|
||||
}
|
||||
if (checked) {
|
||||
for (let i = 0; i < cities.length; ++i) {
|
||||
const tempCity = cities[i];
|
||||
props.product.sllman[tempCity][0] = true;
|
||||
props.product.sllman[tempCity][1] = qty; //Use sanitized input
|
||||
}
|
||||
} else {
|
||||
props.product.sllman[props.city][0] = true;
|
||||
props.product.sllman[props.city][1] = qty; //Use sanitized input
|
||||
}
|
||||
} else if (isNaN(parseFloat(iQty))) {
|
||||
dialogBoxCreate("Invalid value for sell quantity field! Must be numeric");
|
||||
return;
|
||||
} else {
|
||||
let qty = parseFloat(iQty);
|
||||
if (isNaN(qty)) {qty = 0;}
|
||||
if (qty === 0) {
|
||||
if (checked) {
|
||||
for (let i = 0; i < cities.length; ++i) {
|
||||
const tempCity = cities[i];
|
||||
props.product.sllman[tempCity][0] = false;
|
||||
props.product.sllman[tempCity][1] = '';
|
||||
}
|
||||
} else {
|
||||
props.product.sllman[props.city][0] = false;
|
||||
props.product.sllman[props.city][1] = '';
|
||||
}
|
||||
} else {
|
||||
if (checked) {
|
||||
for (let i = 0; i < cities.length; ++i) {
|
||||
const tempCity = cities[i];
|
||||
props.product.sllman[tempCity][0] = true;
|
||||
props.product.sllman[tempCity][1] = qty;
|
||||
}
|
||||
} else {
|
||||
props.product.sllman[props.city][0] = true;
|
||||
props.product.sllman[props.city][1] = qty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
removePopup(props.popupId);
|
||||
}
|
||||
|
||||
function onAmtChange(event: React.ChangeEvent<HTMLInputElement>): void {
|
||||
setQty(event.target.value);
|
||||
}
|
||||
|
||||
function onPriceChange(event: React.ChangeEvent<HTMLInputElement>): void {
|
||||
setPx(event.target.value);
|
||||
}
|
||||
|
||||
function onKeyDown(event: React.KeyboardEvent<HTMLInputElement>): void {
|
||||
if (event.keyCode === 13) sellProduct();
|
||||
}
|
||||
|
||||
return (<>
|
||||
<p>
|
||||
Enter the maximum amount of {props.product.name} you would like
|
||||
to sell per second, as well as the price at which you would like to
|
||||
sell it at.<br /><br />
|
||||
If the sell amount is set to 0, then the product will not be sold. If the
|
||||
sell price is set to 0, then the product will be discarded.<br /><br />
|
||||
Setting the sell amount to 'MAX' will result in you always selling the
|
||||
maximum possible amount of the material.<br /><br />
|
||||
When setting the sell amount, you can use the 'PROD' variable to designate a
|
||||
dynamically changing amount that depends on your production. For example,
|
||||
if you set the sell amount to 'PROD-1' then you will always sell 1 less of
|
||||
the material than you produce.<br /><br />
|
||||
When setting the sell price, you can use the 'MP' variable to set a
|
||||
dynamically changing price that depends on the Product's estimated
|
||||
market price. For example, if you set it to 'MP*5' then it
|
||||
will always be sold at five times the estimated market price.
|
||||
</p>
|
||||
<br />
|
||||
<input className="text-input" value={iQty} autoFocus={true} type="text" placeholder="Sell amount" style={{marginTop: "4px"}} onChange={onAmtChange} onKeyDown={onKeyDown} />
|
||||
<input className="text-input" value={px} type="text" placeholder="Sell price" style={{marginTop: "4px"}} onChange={onPriceChange} onKeyDown={onKeyDown} />
|
||||
<button className="std-button" onClick={sellProduct}>Confirm</button>
|
||||
<div style={{border: "1px solid white", display: "inline-block"}}>
|
||||
<label htmlFor={props.popupId+'-checkbox'}>Use same 'Sell Amount' for all cities</label>
|
||||
<input checked={checked} onChange={onCheckedChange} id={props.popupId + "-checkbox"} style={{margin:"2px"}} type="checkbox" />
|
||||
</div>
|
||||
</>);
|
||||
}
|
Loading…
Reference in New Issue
Block a user