diff --git a/src/Bladeburner/ui/AllPages.tsx b/src/Bladeburner/ui/AllPages.tsx index 8112eda21..383e89900 100644 --- a/src/Bladeburner/ui/AllPages.tsx +++ b/src/Bladeburner/ui/AllPages.tsx @@ -26,7 +26,7 @@ export function AllPages(props: IProps): React.ReactElement { return ( <> - + diff --git a/src/Corporation/ui/BribeFactionModal.tsx b/src/Corporation/ui/BribeFactionModal.tsx new file mode 100644 index 000000000..4844d3368 --- /dev/null +++ b/src/Corporation/ui/BribeFactionModal.tsx @@ -0,0 +1,112 @@ +import React, { useState } from "react"; +import { Factions } from "../../Faction/Factions"; +import { CorporationConstants } from "../data/Constants"; +import { numeralWrapper } from "../../ui/numeralFormat"; +import { dialogBoxCreate } from "../../ui/React/DialogBox"; +import { Modal } from "../../ui/React/Modal"; +import { use } from "../../ui/Context"; +import { useCorporation } from "./Context"; +import Typography from "@mui/material/Typography"; +import Button from "@mui/material/Button"; +import MenuItem from "@mui/material/MenuItem"; +import TextField from "@mui/material/TextField"; +import Box from "@mui/material/Box"; +import Select, { SelectChangeEvent } from "@mui/material/Select"; + +interface IProps { + open: boolean; + onClose: () => void; +} + +export function BribeFactionModal(props: IProps): React.ReactElement { + const player = use.Player(); + const corp = useCorporation(); + const [money, setMoney] = useState(0); + const [stock, setStock] = useState(0); + const [selectedFaction, setSelectedFaction] = useState( + player.factions.length > 0 ? player.factions.filter((faction) => Factions[faction].getInfo().offersWork())[0] : "", + ); + + function onMoneyChange(event: React.ChangeEvent): void { + setMoney(parseFloat(event.target.value)); + } + + function onStockChange(event: React.ChangeEvent): void { + setStock(parseFloat(event.target.value)); + } + + function changeFaction(event: SelectChangeEvent): void { + setSelectedFaction(event.target.value); + } + + function repGain(money: number, stock: number): number { + return (money + stock * corp.sharePrice) / CorporationConstants.BribeToRepRatio; + } + + function getRepText(money: number, stock: number): string { + if (money === 0 && stock === 0) return ""; + if (isNaN(money) || isNaN(stock) || money < 0 || stock < 0) { + return "ERROR: Invalid value(s) entered"; + } else if (corp.funds.lt(money)) { + return "ERROR: You do not have this much money to bribe with"; + } else if (stock > corp.numShares) { + return "ERROR: You do not have this many shares to bribe with"; + } else { + return ( + "You will gain " + + numeralWrapper.formatReputation(repGain(money, stock)) + + " reputation with " + + selectedFaction + + " with this bribe" + ); + } + } + + function bribe(money: number, stock: number): void { + const fac = Factions[selectedFaction]; + if (fac == null) { + dialogBoxCreate("ERROR: You must select a faction to bribe"); + } + if (isNaN(money) || isNaN(stock) || money < 0 || stock < 0) { + } else if (corp.funds.lt(money)) { + } else if (stock > corp.numShares) { + } else { + const rep = repGain(money, stock); + dialogBoxCreate( + "You gained " + numeralWrapper.formatReputation(rep) + " reputation with " + fac.name + " by bribing them.", + ); + fac.playerReputation += rep; + corp.funds = corp.funds.minus(money); + corp.numShares -= stock; + props.onClose(); + } + } + + return ( + + + You can use Corporation funds or stock shares to bribe Faction Leaders in exchange for faction reputation. + + + Faction: + + + {getRepText(money ? money : 0, stock ? stock : 0)} + + + + + ); +} diff --git a/src/Corporation/ui/BribeFactionPopup.tsx b/src/Corporation/ui/BribeFactionPopup.tsx deleted file mode 100644 index 5b85a32d9..000000000 --- a/src/Corporation/ui/BribeFactionPopup.tsx +++ /dev/null @@ -1,109 +0,0 @@ -import React, { useState } from "react"; -import { IPlayer } from "../../PersonObjects/IPlayer"; -import { Factions } from "../../Faction/Factions"; -import { CorporationConstants } from "../data/Constants"; -import { numeralWrapper } from "../../ui/numeralFormat"; -import { removePopup } from "../../ui/React/createPopup"; -import { dialogBoxCreate } from "../../ui/React/DialogBox"; -import { ICorporation } from "../ICorporation"; - -interface IProps { - popupId: string; - corp: ICorporation; - player: IPlayer; -} - -export function BribeFactionPopup(props: IProps): React.ReactElement { - const [money, setMoney] = useState(0); - const [stock, setStock] = useState(0); - const [selectedFaction, setSelectedFaction] = useState( - props.player.factions.length > 0 ? props.player.factions.filter(faction => Factions[faction].getInfo().offersWork())[0] : "" - ); - - function onMoneyChange(event: React.ChangeEvent): void { - setMoney(parseFloat(event.target.value)); - } - - function onStockChange(event: React.ChangeEvent): void { - setStock(parseFloat(event.target.value)); - } - - function changeFaction(event: React.ChangeEvent): void { - setSelectedFaction(event.target.value); - } - - function repGain(money: number, stock: number): number { - return (money + stock * props.corp.sharePrice) / CorporationConstants.BribeToRepRatio; - } - - function getRepText(money: number, stock: number): string { - if (money === 0 && stock === 0) return ""; - if (isNaN(money) || isNaN(stock) || money < 0 || stock < 0) { - return "ERROR: Invalid value(s) entered"; - } else if (props.corp.funds.lt(money)) { - return "ERROR: You do not have this much money to bribe with"; - } else if (stock > props.corp.numShares) { - return "ERROR: You do not have this many shares to bribe with"; - } else { - return ( - "You will gain " + - numeralWrapper.formatReputation(repGain(money, stock)) + - " reputation with " + - selectedFaction + - " with this bribe" - ); - } - } - - function bribe(money: number, stock: number): void { - const fac = Factions[selectedFaction]; - if (fac == null) { - dialogBoxCreate("ERROR: You must select a faction to bribe"); - } - if (isNaN(money) || isNaN(stock) || money < 0 || stock < 0) { - } else if (props.corp.funds.lt(money)) { - } else if (stock > props.corp.numShares) { - } else { - const rep = repGain(money, stock); - dialogBoxCreate( - "You gained " + numeralWrapper.formatReputation(rep) + " reputation with " + fac.name + " by bribing them.", - ); - fac.playerReputation += rep; - props.corp.funds = props.corp.funds.minus(money); - props.corp.numShares -= stock; - removePopup(props.popupId); - } - } - - return ( - <> -

You can use Corporation funds or stock shares to bribe Faction Leaders in exchange for faction reputation.

- -

{getRepText(money ? money : 0, stock ? stock : 0)}

- - - - - ); -} diff --git a/src/Corporation/ui/BuybackSharesPopup.tsx b/src/Corporation/ui/BuybackSharesModal.tsx similarity index 71% rename from src/Corporation/ui/BuybackSharesPopup.tsx rename to src/Corporation/ui/BuybackSharesModal.tsx index 3aaa8a4eb..ae25cb5e7 100644 --- a/src/Corporation/ui/BuybackSharesPopup.tsx +++ b/src/Corporation/ui/BuybackSharesModal.tsx @@ -1,20 +1,21 @@ import React, { useState } from "react"; -import { IPlayer } from "../../PersonObjects/IPlayer"; -import { removePopup } from "../../ui/React/createPopup"; +import { Modal } from "../../ui/React/Modal"; import { numeralWrapper } from "../../ui/numeralFormat"; import { dialogBoxCreate } from "../../ui/React/DialogBox"; -import { ICorporation } from "../ICorporation"; +import { use } from "../../ui/Context"; +import { useCorporation } from "./Context"; interface IProps { - player: IPlayer; - popupId: string; - corp: ICorporation; + open: boolean; + onClose: () => void; rerender: () => void; } // Create a popup that lets the player buyback shares // This is created when the player clicks the "Buyback Shares" button in the overview panel -export function BuybackSharesPopup(props: IProps): React.ReactElement { +export function BuybackSharesModal(props: IProps): React.ReactElement { + const player = use.Player(); + const corp = useCorporation(); const [shares, setShares] = useState(null); function changeShares(event: React.ChangeEvent): void { @@ -22,38 +23,38 @@ export function BuybackSharesPopup(props: IProps): React.ReactElement { else setShares(Math.round(parseFloat(event.target.value))); } - const currentStockPrice = props.corp.sharePrice; + const currentStockPrice = corp.sharePrice; const buybackPrice = currentStockPrice * 1.1; function buy(): void { if (shares === null) return; - const tempStockPrice = props.corp.sharePrice; + const tempStockPrice = corp.sharePrice; const buybackPrice = tempStockPrice * 1.1; if (isNaN(shares) || shares <= 0) { dialogBoxCreate("ERROR: Invalid value for number of shares"); - } else if (shares > props.corp.issuedShares) { + } else if (shares > corp.issuedShares) { dialogBoxCreate("ERROR: There are not this many oustanding shares to buy back"); - } else if (shares * buybackPrice > props.player.money) { + } else if (shares * buybackPrice > player.money) { dialogBoxCreate( "ERROR: You do not have enough money to purchase this many shares (you need " + numeralWrapper.format(shares * buybackPrice, "$0.000a") + ")", ); } else { - props.corp.numShares += shares; - if (isNaN(props.corp.issuedShares)) { - console.warn("Corporation issuedShares is NaN: " + props.corp.issuedShares); + corp.numShares += shares; + if (isNaN(corp.issuedShares)) { + console.warn("Corporation issuedShares is NaN: " + corp.issuedShares); console.warn("Converting to number now"); - const res = props.corp.issuedShares; + const res = corp.issuedShares; if (isNaN(res)) { - props.corp.issuedShares = 0; + corp.issuedShares = 0; } else { - props.corp.issuedShares = res; + corp.issuedShares = res; } } - props.corp.issuedShares -= shares; - props.player.loseMoney(shares * buybackPrice); - removePopup(props.popupId); + corp.issuedShares -= shares; + player.loseMoney(shares * buybackPrice); + props.onClose(); props.rerender(); } } @@ -62,11 +63,11 @@ export function BuybackSharesPopup(props: IProps): React.ReactElement { if (shares === null) return <>; if (isNaN(shares) || shares <= 0) { return <>ERROR: Invalid value entered for number of shares to buyback; - } else if (shares > props.corp.issuedShares) { + } else if (shares > corp.issuedShares) { return ( <> There are not this many shares available to buy back. There are only{" "} - {numeralWrapper.formatBigNumber(props.corp.issuedShares)} outstanding shares. + {numeralWrapper.formatBigNumber(corp.issuedShares)} outstanding shares. ); } else { @@ -83,7 +84,7 @@ export function BuybackSharesPopup(props: IProps): React.ReactElement { } return ( - <> +

Enter the number of outstanding shares you would like to buy back. These shares must be bought at a 10% premium. However, repurchasing shares from the market tends to lead to an increase in stock price. @@ -93,7 +94,7 @@ export function BuybackSharesPopup(props: IProps): React.ReactElement {

The current buyback price of your company's stock is {numeralWrapper.formatMoney(buybackPrice)}. Your company - currently has {numeralWrapper.formatBigNumber(props.corp.issuedShares)} outstanding stock shares. + currently has {numeralWrapper.formatBigNumber(corp.issuedShares)} outstanding stock shares.


@@ -109,6 +110,6 @@ export function BuybackSharesPopup(props: IProps): React.ReactElement { - +
); } diff --git a/src/Corporation/ui/Context.ts b/src/Corporation/ui/Context.ts new file mode 100644 index 000000000..6fe5720be --- /dev/null +++ b/src/Corporation/ui/Context.ts @@ -0,0 +1,10 @@ +import React, { useContext } from "react"; +import { ICorporation } from "../ICorporation"; + +export const Context: { + Corporation: React.Context; +} = { + Corporation: React.createContext({} as ICorporation), +}; + +export const useCorporation = () => useContext(Context.Corporation); diff --git a/src/Corporation/ui/CorporationRoot.tsx b/src/Corporation/ui/CorporationRoot.tsx index 1fa5c647e..c3538ff75 100644 --- a/src/Corporation/ui/CorporationRoot.tsx +++ b/src/Corporation/ui/CorporationRoot.tsx @@ -2,41 +2,16 @@ // These are the tabs at the top of the UI that let you switch to different // divisions, see an overview of your corporation, or create a new industry import React, { useState, useEffect } from "react"; -import { HeaderTab } from "./HeaderTab"; import { IIndustry } from "../IIndustry"; -import { NewIndustryPopup } from "./NewIndustryPopup"; -import { createPopup } from "../../ui/React/createPopup"; -import { ICorporation } from "../ICorporation"; import { MainPanel } from "./MainPanel"; import { Industries } from "../IndustryData"; +import { ExpandIndustryTab } from "./ExpandIndustryTab"; import { use } from "../../ui/Context"; +import { Context } from "./Context"; +import { Overview } from "./Overview"; -interface IExpandButtonProps { - corp: ICorporation; - setDivisionName: (name: string) => void; -} - -function ExpandButton(props: IExpandButtonProps): React.ReactElement { - const allIndustries = Object.keys(Industries).sort(); - const possibleIndustries = allIndustries - .filter( - (industryType: string) => - props.corp.divisions.find((division: IIndustry) => division.type === industryType) === undefined, - ) - .sort(); - if (possibleIndustries.length === 0) return <>; - - function openNewIndustryPopup(): void { - const popupId = "cmpy-mgmt-expand-industry-popup"; - createPopup(popupId, NewIndustryPopup, { - corp: props.corp, - setDivisionName: props.setDivisionName, - popupId: popupId, - }); - } - - return ; -} +import Tabs from "@mui/material/Tabs"; +import Tab from "@mui/material/Tab"; export function CorporationRoot(): React.ReactElement { const player = use.Player(); @@ -46,33 +21,37 @@ export function CorporationRoot(): React.ReactElement { function rerender(): void { setRerender((old) => !old); } - const [divisionName, setDivisionName] = useState("Overview"); - + const [divisionName, setDivisionName] = useState("Overview"); + function handleChange(event: React.SyntheticEvent, tab: string | number): void { + setDivisionName(tab); + } useEffect(() => { - const id = setInterval(rerender, 1000); + const id = setInterval(rerender, 200); return () => clearInterval(id); }, []); + const canExpand = + Object.keys(Industries).filter( + (industryType: string) => + corporation.divisions.find((division: IIndustry) => division.type === industryType) === undefined, + ).length > 0; + return ( -
-
- setDivisionName("Overview")} - text={corporation.name} - /> - {corporation.divisions.map((division: IIndustry) => ( - setDivisionName(division.name)} - text={division.name} - /> - ))} - + +
+ + + {corporation.divisions.map((div) => ( + + ))} + {canExpand && } + + {divisionName === "Overview" && } + {divisionName === -1 && } + {typeof divisionName === "string" && divisionName !== "Overview" && ( + + )}
- -
+ ); } diff --git a/src/Corporation/ui/CreateCorporationModal.tsx b/src/Corporation/ui/CreateCorporationModal.tsx new file mode 100644 index 000000000..272b7d90c --- /dev/null +++ b/src/Corporation/ui/CreateCorporationModal.tsx @@ -0,0 +1,75 @@ +import React, { useState } from "react"; + +import { Money } from "../../ui/React/Money"; +import { Modal } from "../../ui/React/Modal"; +import { use } from "../../ui/Context"; +import Typography from "@mui/material/Typography"; +import Button from "@mui/material/Button"; +import TextField from "@mui/material/TextField"; + +interface IProps { + open: boolean; + onClose: () => void; +} + +export function CreateCorporationModal(props: IProps): React.ReactElement { + const player = use.Player(); + const router = use.Router(); + const canSelfFund = player.canAfford(150e9); + if (!player.canAccessCorporation() || player.hasCorporation()) { + props.onClose(); + return <>; + } + + const [name, setName] = useState(""); + function onChange(event: React.ChangeEvent): void { + setName(event.target.value); + } + + function selfFund(): void { + if (!canSelfFund) { + return; + } + + if (name == "") { + return; + } + + player.startCorporation(name); + player.loseMoney(150e9); + + props.onClose(); + router.toCorporation(); + } + + function seed(): void { + if (name == "") { + return; + } + + player.startCorporation(name, 500e6); + + props.onClose(); + router.toCorporation(); + } + + return ( + + + Would you like to start a corporation? This will require $150b for registration and initial funding. This $150b + can either be self-funded, or you can obtain the seed money from the government in exchange for 500 million + shares +
+
+ If you would like to start one, please enter a name for your corporation below: +
+ + + +
+ ); +} diff --git a/src/Corporation/ui/CreateCorporationPopup.tsx b/src/Corporation/ui/CreateCorporationPopup.tsx deleted file mode 100644 index daeae26df..000000000 --- a/src/Corporation/ui/CreateCorporationPopup.tsx +++ /dev/null @@ -1,83 +0,0 @@ -import React, { useState } from "react"; - -import { IPlayer } from "../../PersonObjects/IPlayer"; -import { removePopup } from "../../ui/React/createPopup"; -import { Money } from "../../ui/React/Money"; -import { dialogBoxCreate } from "../../ui/React/DialogBox"; -import { IRouter } from "../../ui/Router"; - -interface IProps { - player: IPlayer; - popupId: string; - router: IRouter; -} - -export function CreateCorporationPopup(props: IProps): React.ReactElement { - if (!props.player.canAccessCorporation() || props.player.hasCorporation()) { - removePopup(props.popupId); - return <>; - } - - const [name, setName] = useState(""); - function onChange(event: React.ChangeEvent): void { - setName(event.target.value); - } - - function selfFund(): void { - if (!props.player.canAfford(150e9)) { - dialogBoxCreate("You don't have enough money to create a corporation! You need $150b."); - return; - } - - if (name == "") { - dialogBoxCreate("Invalid company name!"); - return; - } - - props.player.startCorporation(name); - props.player.loseMoney(150e9); - - dialogBoxCreate( - "Congratulations! You just self-funded your own corporation. You can visit " + - "and manage your company in the City.", - ); - removePopup(props.popupId); - props.router.toCorporation(); - } - - function seed(): void { - if (name == "") { - dialogBoxCreate("Invalid company name!"); - return; - } - - props.player.startCorporation(name, 500e6); - - dialogBoxCreate( - "Congratulations! You just started your own corporation with government seed money. " + - "You can visit and manage your company in the City.", - ); - removePopup(props.popupId); - props.router.toCorporation(); - } - - return ( - <> -

- Would you like to start a corporation? This will require $150b for registration and initial funding. This $150b - can either be self-funded, or you can obtain the seed money from the government in exchange for 500 million - shares -
-
- If you would like to start one, please enter a name for your corporation below: -

- - - - - ); -} diff --git a/src/Corporation/ui/NewIndustryPopup.tsx b/src/Corporation/ui/ExpandIndustryTab.tsx similarity index 51% rename from src/Corporation/ui/NewIndustryPopup.tsx rename to src/Corporation/ui/ExpandIndustryTab.tsx index c217a7015..2f63a2b3f 100644 --- a/src/Corporation/ui/NewIndustryPopup.tsx +++ b/src/Corporation/ui/ExpandIndustryTab.tsx @@ -1,24 +1,28 @@ import React, { useState } from "react"; import { dialogBoxCreate } from "../../ui/React/DialogBox"; -import { removePopup } from "../../ui/React/createPopup"; import { Industries, IndustryDescriptions } from "../IndustryData"; -import { ICorporation } from "../ICorporation"; +import { useCorporation } from "./Context"; import { IIndustry } from "../IIndustry"; import { NewIndustry } from "../Actions"; +import Typography from "@mui/material/Typography"; +import Button from "@mui/material/Button"; +import TextField from "@mui/material/TextField"; +import MenuItem from "@mui/material/MenuItem"; +import Box from "@mui/material/Box"; +import Select, { SelectChangeEvent } from "@mui/material/Select"; + interface IProps { - corp: ICorporation; - popupId: string; setDivisionName: (name: string) => void; } -// Create a popup that lets the player create a new industry. -// This is created when the player clicks the "Expand into new Industry" header tab -export function NewIndustryPopup(props: IProps): React.ReactElement { + +export function ExpandIndustryTab(props: IProps): React.ReactElement { + const corp = useCorporation(); const allIndustries = Object.keys(Industries).sort(); const possibleIndustries = allIndustries .filter( (industryType: string) => - props.corp.divisions.find((division: IIndustry) => division.type === industryType) === undefined, + corp.divisions.find((division: IIndustry) => division.type === industryType) === undefined, ) .sort(); const [industry, setIndustry] = useState(possibleIndustries.length > 0 ? possibleIndustries[0] : ""); @@ -26,7 +30,7 @@ export function NewIndustryPopup(props: IProps): React.ReactElement { function newIndustry(): void { try { - NewIndustry(props.corp, industry, name); + NewIndustry(corp, industry, name); } catch (err) { dialogBoxCreate(err + ""); return; @@ -34,11 +38,10 @@ export function NewIndustryPopup(props: IProps): React.ReactElement { // Set routing to the new division so that the UI automatically switches to it props.setDivisionName(name); - - removePopup(props.popupId); } function onNameChange(event: React.ChangeEvent): void { + // [a-zA-Z0-9-_] setName(event.target.value); } @@ -46,7 +49,7 @@ export function NewIndustryPopup(props: IProps): React.ReactElement { if (event.keyCode === 13) newIndustry(); } - function onIndustryChange(event: React.ChangeEvent): void { + function onIndustryChange(event: SelectChangeEvent): void { setIndustry(event.target.value); } @@ -55,33 +58,33 @@ export function NewIndustryPopup(props: IProps): React.ReactElement { return ( <> -

Create a new division to expand into a new industry:

- {possibleIndustries.map((industry: string) => ( - + ))} - -

{desc(props.corp)}

+ + {desc(corp)}

-

Division name:

- - - Create Division - + Division name: + + + + + ); } diff --git a/src/Corporation/ui/FindInvestorsPopup.tsx b/src/Corporation/ui/FindInvestorsModal.tsx similarity index 67% rename from src/Corporation/ui/FindInvestorsPopup.tsx rename to src/Corporation/ui/FindInvestorsModal.tsx index 6aa1428f1..62bf50831 100644 --- a/src/Corporation/ui/FindInvestorsPopup.tsx +++ b/src/Corporation/ui/FindInvestorsModal.tsx @@ -1,23 +1,25 @@ import React from "react"; -import { removePopup } from "../../ui/React/createPopup"; import { numeralWrapper } from "../../ui/numeralFormat"; import { CorporationConstants } from "../data/Constants"; -import { ICorporation } from "../ICorporation"; -import { IPlayer } from "../../PersonObjects/IPlayer"; +import { Modal } from "../../ui/React/Modal"; +import { useCorporation } from "./Context"; + +import Typography from "@mui/material/Typography"; +import Button from "@mui/material/Button"; interface IProps { - corp: ICorporation; - popupId: string; - player: IPlayer; + open: boolean; + onClose: () => void; rerender: () => void; } // Create a popup that lets the player manage exports -export function FindInvestorsPopup(props: IProps): React.ReactElement { - const val = props.corp.determineValuation(); +export function FindInvestorsModal(props: IProps): React.ReactElement { + const corp = useCorporation(); + const val = corp.determineValuation(); let percShares = 0; let roundMultiplier = 4; - switch (props.corp.fundingRound) { + switch (corp.fundingRound) { case 0: //Seed percShares = 0.1; roundMultiplier = 4; @@ -41,15 +43,15 @@ export function FindInvestorsPopup(props: IProps): React.ReactElement { const investShares = Math.floor(CorporationConstants.INITIALSHARES * percShares); function findInvestors(): void { - props.corp.fundingRound++; - props.corp.addFunds(funding); - props.corp.numShares -= investShares; + corp.fundingRound++; + corp.addFunds(funding); + corp.numShares -= investShares; props.rerender(); - removePopup(props.popupId); + props.onClose(); } return ( - <> -

+ + An investment firm has offered you {numeralWrapper.formatMoney(funding)} in funding in exchange for a{" "} {numeralWrapper.format(percShares * 100, "0.000a")}% stake in the company ( {numeralWrapper.format(investShares, "0.000a")} shares). @@ -59,10 +61,8 @@ export function FindInvestorsPopup(props: IProps): React.ReactElement {

Hint: Investment firms will offer more money if your corporation is turning a profit -

- - + + + ); } diff --git a/src/Corporation/ui/GoPublicModal.tsx b/src/Corporation/ui/GoPublicModal.tsx new file mode 100644 index 000000000..7ec482ad7 --- /dev/null +++ b/src/Corporation/ui/GoPublicModal.tsx @@ -0,0 +1,81 @@ +import React, { useState } from "react"; +import { dialogBoxCreate } from "../../ui/React/DialogBox"; +import { Modal } from "../../ui/React/Modal"; +import { numeralWrapper } from "../../ui/numeralFormat"; +import { useCorporation } from "./Context"; +import Typography from "@mui/material/Typography"; +import Button from "@mui/material/Button"; +import TextField from "@mui/material/TextField"; +import Box from "@mui/material/Box"; + +interface IProps { + open: boolean; + onClose: () => void; + rerender: () => void; +} + +// Create a popup that lets the player manage exports +export function GoPublicModal(props: IProps): React.ReactElement { + const corp = useCorporation(); + const [shares, setShares] = useState(""); + const initialSharePrice = corp.determineValuation() / corp.totalShares; + + function goPublic(): void { + const numShares = parseFloat(shares); + const initialSharePrice = corp.determineValuation() / corp.totalShares; + if (isNaN(numShares)) { + dialogBoxCreate("Invalid value for number of issued shares"); + return; + } + if (numShares > corp.numShares) { + dialogBoxCreate("Error: You don't have that many shares to issue!"); + return; + } + corp.public = true; + corp.sharePrice = initialSharePrice; + corp.issuedShares = numShares; + corp.numShares -= numShares; + corp.addFunds(numShares * initialSharePrice); + props.rerender(); + dialogBoxCreate( + `You took your ${corp.name} public and earned ` + + `${numeralWrapper.formatMoney(numShares * initialSharePrice)} in your IPO`, + ); + props.onClose(); + } + + function onKeyDown(event: React.KeyboardEvent): void { + if (event.keyCode === 13) goPublic(); + } + + function onChange(event: React.ChangeEvent): void { + setShares(event.target.value); + } + + return ( + + + Enter the number of shares you would like to issue for your IPO. These shares will be publicly sold and you will + no longer own them. Your Corporation will receive {numeralWrapper.formatMoney(initialSharePrice)} per share (the + IPO money will be deposited directly into your Corporation's funds). +
+
+ You have a total of {numeralWrapper.format(corp.numShares, "0.000a")} of shares that you can issue. +
+ + + + +
+ ); +} diff --git a/src/Corporation/ui/GoPublicPopup.tsx b/src/Corporation/ui/GoPublicPopup.tsx deleted file mode 100644 index 9410ba0e0..000000000 --- a/src/Corporation/ui/GoPublicPopup.tsx +++ /dev/null @@ -1,76 +0,0 @@ -import React, { useState } from "react"; -import { dialogBoxCreate } from "../../ui/React/DialogBox"; -import { removePopup } from "../../ui/React/createPopup"; -import { numeralWrapper } from "../../ui/numeralFormat"; -import { ICorporation } from "../ICorporation"; -import { IPlayer } from "../../PersonObjects/IPlayer"; - -interface IProps { - corp: ICorporation; - popupId: string; - player: IPlayer; - rerender: () => void; -} - -// Create a popup that lets the player manage exports -export function GoPublicPopup(props: IProps): React.ReactElement { - const [shares, setShares] = useState(""); - const initialSharePrice = props.corp.determineValuation() / props.corp.totalShares; - - function goPublic(): void { - const numShares = parseFloat(shares); - const initialSharePrice = props.corp.determineValuation() / props.corp.totalShares; - if (isNaN(numShares)) { - dialogBoxCreate("Invalid value for number of issued shares"); - return; - } - if (numShares > props.corp.numShares) { - dialogBoxCreate("Error: You don't have that many shares to issue!"); - return; - } - props.corp.public = true; - props.corp.sharePrice = initialSharePrice; - props.corp.issuedShares = numShares; - props.corp.numShares -= numShares; - props.corp.addFunds(numShares * initialSharePrice); - props.rerender(); - dialogBoxCreate( - `You took your ${props.corp.name} public and earned ` + - `${numeralWrapper.formatMoney(numShares * initialSharePrice)} in your IPO`, - ); - removePopup(props.popupId); - } - - function onKeyDown(event: React.KeyboardEvent): void { - if (event.keyCode === 13) goPublic(); - } - - function onChange(event: React.ChangeEvent): void { - setShares(event.target.value); - } - - return ( - <> -

- Enter the number of shares you would like to issue for your IPO. These shares will be publicly sold and you will - no longer own them. Your Corporation will receive {numeralWrapper.formatMoney(initialSharePrice)} per share (the - IPO money will be deposited directly into your Corporation's funds). -
-
- You have a total of {numeralWrapper.format(props.corp.numShares, "0.000a")} of shares that you can issue. -

- - - - ); -} diff --git a/src/Corporation/ui/IssueDividendsPopup.tsx b/src/Corporation/ui/IssueDividendsModal.tsx similarity index 65% rename from src/Corporation/ui/IssueDividendsPopup.tsx rename to src/Corporation/ui/IssueDividendsModal.tsx index 42aadd432..c5ce67c39 100644 --- a/src/Corporation/ui/IssueDividendsPopup.tsx +++ b/src/Corporation/ui/IssueDividendsModal.tsx @@ -1,29 +1,34 @@ import React, { useState } from "react"; -import { removePopup } from "../../ui/React/createPopup"; import { dialogBoxCreate } from "../../ui/React/DialogBox"; +import { Modal } from "../../ui/React/Modal"; import { CorporationConstants } from "../data/Constants"; -import { ICorporation } from "../ICorporation"; import { IssueDividends } from "../Actions"; - +import { useCorporation } from "./Context"; +import Typography from "@mui/material/Typography"; +import TextField from "@mui/material/TextField"; +import Button from "@mui/material/Button"; interface IProps { - popupId: string; - corp: ICorporation; + open: boolean; + onClose: () => void; } // Create a popup that lets the player issue & manage dividends // This is created when the player clicks the "Issue Dividends" button in the overview panel -export function IssueDividendsPopup(props: IProps): React.ReactElement { - const [percent, setPercent] = useState(null); +export function IssueDividendsModal(props: IProps): React.ReactElement { + const corp = useCorporation(); + const [percent, setPercent] = useState(0); + const canIssue = !isNaN(percent) && percent >= 0 && percent <= CorporationConstants.DividendMaxPercentage * 100; function issueDividends(): void { + if (!canIssue) return; if (percent === null) return; try { - IssueDividends(props.corp, percent / 100); + IssueDividends(corp, percent / 100); } catch (err) { dialogBoxCreate(err + ""); } - removePopup(props.popupId); + props.onClose(); } function onKeyDown(event: React.KeyboardEvent): void { @@ -31,13 +36,17 @@ export function IssueDividendsPopup(props: IProps): React.ReactElement { } function onChange(event: React.ChangeEvent): void { - if (event.target.value === "") setPercent(null); - else setPercent(parseFloat(event.target.value)); + if (event.target.value === "") setPercent(0); + else { + let p = parseFloat(event.target.value); + if (p > 50) p = 50; + setPercent(p); + } } return ( - <> -

+ + Dividends are a distribution of a portion of the corporation's profits to the shareholders. This includes yourself, as well.
@@ -58,19 +67,19 @@ export function IssueDividendsPopup(props: IProps): React.ReactElement { That means your corporation will gain $60m / sec in funds and the remaining $40m / sec will be paid as dividends. Since your corporation starts with 1 billion shares, every shareholder will be paid $0.04 per share per second before taxes. -

- + - - + + ); } diff --git a/src/Corporation/ui/IssueNewSharesPopup.tsx b/src/Corporation/ui/IssueNewSharesModal.tsx similarity index 69% rename from src/Corporation/ui/IssueNewSharesPopup.tsx rename to src/Corporation/ui/IssueNewSharesModal.tsx index 1b1eca398..b006ccf44 100644 --- a/src/Corporation/ui/IssueNewSharesPopup.tsx +++ b/src/Corporation/ui/IssueNewSharesModal.tsx @@ -1,24 +1,27 @@ import React, { useState } from "react"; import { numeralWrapper } from "../../ui/numeralFormat"; import { dialogBoxCreate } from "../../ui/React/DialogBox"; -import { removePopup } from "../../ui/React/createPopup"; +import { Modal } from "../../ui/React/Modal"; import { getRandomInt } from "../../utils/helpers/getRandomInt"; import { CorporationConstants } from "../data/Constants"; -import { ICorporation } from "../ICorporation"; +import { useCorporation } from "./Context"; +import Typography from "@mui/material/Typography"; +import TextField from "@mui/material/TextField"; +import Button from "@mui/material/Button"; interface IEffectTextProps { - corp: ICorporation; shares: number | null; } function EffectText(props: IEffectTextProps): React.ReactElement { + const corp = useCorporation(); if (props.shares === null) return <>; - const newSharePrice = Math.round(props.corp.sharePrice * 0.9); - const maxNewSharesUnrounded = Math.round(props.corp.totalShares * 0.2); + const newSharePrice = Math.round(corp.sharePrice * 0.9); + const maxNewSharesUnrounded = Math.round(corp.totalShares * 0.2); const maxNewShares = maxNewSharesUnrounded - (maxNewSharesUnrounded % 1e6); let newShares = props.shares; if (isNaN(newShares)) { - return

Invalid input

; + return Invalid input; } // Round to nearest ten-millionth @@ -26,36 +29,37 @@ function EffectText(props: IEffectTextProps): React.ReactElement { newShares = Math.round(newShares) * 10e6; if (newShares < 10e6) { - return

Must issue at least 10 million new shares

; + return Must issue at least 10 million new shares; } if (newShares > maxNewShares) { - return

You cannot issue that many shares

; + return You cannot issue that many shares; } return ( -

+ Issue ${numeralWrapper.format(newShares, "0.000a")} new shares for{" "} {numeralWrapper.formatMoney(newShares * newSharePrice)}? -

+ ); } interface IProps { - corp: ICorporation; - popupId: string; + open: boolean; + onClose: () => void; } // Create a popup that lets the player issue new shares // This is created when the player clicks the "Issue New Shares" buttons in the overview panel -export function IssueNewSharesPopup(props: IProps): React.ReactElement { +export function IssueNewSharesModal(props: IProps): React.ReactElement { + const corp = useCorporation(); const [shares, setShares] = useState(null); - const maxNewSharesUnrounded = Math.round(props.corp.totalShares * 0.2); + const maxNewSharesUnrounded = Math.round(corp.totalShares * 0.2); const maxNewShares = maxNewSharesUnrounded - (maxNewSharesUnrounded % 1e6); function issueNewShares(): void { if (shares === null) return; - const newSharePrice = Math.round(props.corp.sharePrice * 0.9); + const newSharePrice = Math.round(corp.sharePrice * 0.9); let newShares = shares; if (isNaN(newShares)) { dialogBoxCreate("Invalid input for number of new shares"); @@ -71,8 +75,8 @@ export function IssueNewSharesPopup(props: IProps): React.ReactElement { } const profit = newShares * newSharePrice; - props.corp.issueNewSharesCooldown = CorporationConstants.IssueNewSharesCooldown; - props.corp.totalShares += newShares; + corp.issueNewSharesCooldown = CorporationConstants.IssueNewSharesCooldown; + corp.totalShares += newShares; // Determine how many are bought by private investors // Private investors get up to 50% at most @@ -80,16 +84,15 @@ export function IssueNewSharesPopup(props: IProps): React.ReactElement { let privateShares = getRandomInt(0, Math.round(newShares / 2)); privateShares = Math.round(privateShares / 1e6) * 1e6; - props.corp.issuedShares += newShares - privateShares; - props.corp.funds = props.corp.funds.plus(profit); - props.corp.immediatelyUpdateSharePrice(); - - removePopup(props.popupId); + corp.issuedShares += newShares - privateShares; + corp.funds = corp.funds.plus(profit); + corp.immediatelyUpdateSharePrice(); + props.onClose(); dialogBoxCreate( `Issued ${numeralWrapper.format(newShares, "0.000a")} and raised ` + `${numeralWrapper.formatMoney(profit)}. ${numeralWrapper.format(privateShares, "0.000a")} ` + `of these shares were bought by private investors.

` + - `Stock price decreased to ${numeralWrapper.formatMoney(props.corp.sharePrice)}`, + `Stock price decreased to ${numeralWrapper.formatMoney(corp.sharePrice)}`, ); } @@ -103,8 +106,8 @@ export function IssueNewSharesPopup(props: IProps): React.ReactElement { } return ( - <> -

+ + You can issue new equity shares (i.e. stocks) in order to raise capital for your corporation.

@@ -122,19 +125,12 @@ export function IssueNewSharesPopup(props: IProps): React.ReactElement { When you choose to issue new equity, private shareholders have first priority for up to 50% of the new shares. If they choose to exercise this option, these newly issued shares become private, restricted shares, which means you cannot buy them back. -

- - - - + + ); } diff --git a/src/Corporation/ui/LevelableUpgrade.tsx b/src/Corporation/ui/LevelableUpgrade.tsx index 6cd8d261f..5fe8781b7 100644 --- a/src/Corporation/ui/LevelableUpgrade.tsx +++ b/src/Corporation/ui/LevelableUpgrade.tsx @@ -2,22 +2,22 @@ import React from "react"; import { dialogBoxCreate } from "../../ui/React/DialogBox"; -import { ICorporation } from "../ICorporation"; -import { IPlayer } from "../../PersonObjects/IPlayer"; import { CorporationUpgrade } from "../data/CorporationUpgrades"; import { LevelUpgrade } from "../Actions"; import { MoneyCost } from "./MoneyCost"; +import { use } from "../../ui/Context"; +import { useCorporation } from "./Context"; interface IProps { upgrade: CorporationUpgrade; - corp: ICorporation; - player: IPlayer; rerender: () => void; } export function LevelableUpgrade(props: IProps): React.ReactElement { + const player = use.Player(); + const corp = useCorporation(); const data = props.upgrade; - const level = props.corp.upgrades[data[0]]; + const level = corp.upgrades[data[0]]; const baseCost = data[1]; const priceMult = data[2]; @@ -25,14 +25,14 @@ export function LevelableUpgrade(props: IProps): React.ReactElement { const text = ( <> - {data[4]} - + {data[4]} - ); const tooltip = data[5]; function onClick(): void { - if (props.corp.funds.lt(cost)) return; + if (corp.funds.lt(cost)) return; try { - LevelUpgrade(props.corp, props.upgrade); + LevelUpgrade(corp, props.upgrade); } catch (err) { dialogBoxCreate(err + ""); } diff --git a/src/Corporation/ui/MainPanel.tsx b/src/Corporation/ui/MainPanel.tsx index 319aacff9..4e548d080 100644 --- a/src/Corporation/ui/MainPanel.tsx +++ b/src/Corporation/ui/MainPanel.tsx @@ -5,42 +5,28 @@ import React from "react"; import { CityTabs } from "./CityTabs"; import { IIndustry } from "../IIndustry"; -import { Overview } from "./Overview"; +import { useCorporation } from "./Context"; +import { use } from "../../ui/Context"; import { CityName } from "../../Locations/data/CityNames"; -import { IPlayer } from "../../PersonObjects/IPlayer"; -import { ICorporation } from "../ICorporation"; interface IProps { - corp: ICorporation; - player: IPlayer; divisionName: string; rerender: () => void; } export function MainPanel(props: IProps): React.ReactElement { + const player = use.Player(); + const corp = useCorporation(); const division = props.divisionName !== "Overview" - ? props.corp.divisions.find((division: IIndustry) => division.name === props.divisionName) + ? corp.divisions.find((division: IIndustry) => division.name === props.divisionName) : undefined; // use undefined because find returns undefined - if (division === undefined) { - return ( -
- -
- ); - } else { - return ( -
- -
- ); - } + if (division === undefined) throw new Error("Cannot find division"); + return ( +
+ +
+ ); } diff --git a/src/Corporation/ui/Overview.tsx b/src/Corporation/ui/Overview.tsx index 4062dd1f1..b8f13be1b 100644 --- a/src/Corporation/ui/Overview.tsx +++ b/src/Corporation/ui/Overview.tsx @@ -1,14 +1,15 @@ // React Component for displaying Corporation Overview info -import React from "react"; +import React, { useState } from "react"; import { LevelableUpgrade } from "./LevelableUpgrade"; import { UnlockUpgrade } from "./UnlockUpgrade"; -import { BribeFactionPopup } from "./BribeFactionPopup"; -import { SellSharesPopup } from "./SellSharesPopup"; -import { BuybackSharesPopup } from "./BuybackSharesPopup"; -import { IssueDividendsPopup } from "./IssueDividendsPopup"; -import { IssueNewSharesPopup } from "./IssueNewSharesPopup"; -import { FindInvestorsPopup } from "./FindInvestorsPopup"; -import { GoPublicPopup } from "./GoPublicPopup"; +import { BribeFactionModal } from "./BribeFactionModal"; +import { SellSharesModal } from "./SellSharesModal"; +import { BuybackSharesModal } from "./BuybackSharesModal"; +import { IssueDividendsModal } from "./IssueDividendsModal"; +import { IssueNewSharesModal } from "./IssueNewSharesModal"; +import { FindInvestorsModal } from "./FindInvestorsModal"; +import { GoPublicModal } from "./GoPublicModal"; +import { Factions } from "../../Faction/Factions"; import { CorporationConstants } from "../data/Constants"; import { CorporationUnlockUpgrade, CorporationUnlockUpgrades } from "../data/CorporationUnlockUpgrades"; @@ -17,44 +18,52 @@ import { CorporationUpgrade, CorporationUpgrades } from "../data/CorporationUpgr import { CONSTANTS } from "../../Constants"; import { numeralWrapper } from "../../ui/numeralFormat"; import { convertTimeMsToTimeElapsedString } from "../../utils/StringHelperFunctions"; -import { createPopup } from "../../ui/React/createPopup"; import { Money } from "../../ui/React/Money"; -import { IPlayer } from "../../PersonObjects/IPlayer"; -import { ICorporation } from "../ICorporation"; +import { use } from "../../ui/Context"; +import { useCorporation } from "./Context"; +import Typography from "@mui/material/Typography"; +import Tooltip from "@mui/material/Tooltip"; +import Button from "@mui/material/Button"; interface IProps { - corp: ICorporation; - player: IPlayer; rerender: () => void; } -export function Overview({ corp, player, rerender }: IProps): React.ReactElement { +export function Overview({ rerender }: IProps): React.ReactElement { + const player = use.Player(); + const corp = useCorporation(); const profit: number = corp.revenue.minus(corp.expenses).toNumber(); return (
-

+ Total Funds:
Total Revenue: / s
Total Expenses: / s
Total Profits: / s
- + Publicly Traded: {corp.public ? "Yes" : "No"}
Owned Stock Shares: {numeralWrapper.format(corp.numShares, "0.000a")}
Stock Price: {corp.public ? : "N/A"}
-

-

- Total Stock Shares: {numeralWrapper.format(corp.totalShares, "0.000a")} - - Outstanding Shares: {numeralWrapper.format(corp.issuedShares, "0.000a")} -
- Private Shares: {numeralWrapper.format(corp.totalShares - corp.issuedShares - corp.numShares, "0.000a")} -
-

+ + + Outstanding Shares: {numeralWrapper.format(corp.issuedShares, "0.000a")} +
+ Private Shares: {numeralWrapper.format(corp.totalShares - corp.issuedShares - corp.numShares, "0.000a")} + + } + > + + Total Stock Shares: {numeralWrapper.format(corp.totalShares, "0.000a")} + +


@@ -67,100 +76,78 @@ export function Overview({ corp, player, rerender }: IProps): React.ReactElement
- +
- + + {corp.public ? : } +

- +
); } interface IPrivateButtonsProps { - corp: ICorporation; - player: IPlayer; rerender: () => void; } // Render the buttons for when your Corporation is still private -function PrivateButtons({ corp, player, rerender }: IPrivateButtonsProps): React.ReactElement { - function openFindInvestorsPopup(): void { - const popupId = "cmpy-mgmt-find-investors-popup"; - createPopup(popupId, FindInvestorsPopup, { - rerender, - player, - popupId, - corp: corp, - }); - } - - function openGoPublicPopup(): void { - const popupId = "cmpy-mgmt-go-public-popup"; - createPopup(popupId, GoPublicPopup, { - rerender, - player, - popupId, - corp: corp, - }); - } +function PrivateButtons({ rerender }: IPrivateButtonsProps): React.ReactElement { + const player = use.Player(); + const corp = useCorporation(); + const [findInvestorsopen, setFindInvestorsopen] = useState(false); + const [goPublicopen, setGoPublicopen] = useState(false); const fundingAvailable = corp.fundingRound < 4; - const findInvestorsClassName = fundingAvailable ? "std-button" : "a-link-button-inactive"; const findInvestorsTooltip = fundingAvailable - ? "Search for private investors who will give you startup funding in exchangefor equity (stock shares) in your company" - : undefined; + ? "Search for private investors who will give you startup funding in exchange for equity (stock shares) in your company" + : ""; return ( <> - + + + Become a publicly traded and owned entity. Going public involves issuing shares for an IPO. Once you are a + public company, your shares will be traded on the stock market. + } - /> + > + + + setFindInvestorsopen(false)} rerender={rerender} /> + setGoPublicopen(false)} rerender={rerender} />
); } interface IUpgradeProps { - corp: ICorporation; - player: IPlayer; rerender: () => void; } // Render the UI for Corporation upgrades -function Upgrades({ corp, player, rerender }: IUpgradeProps): React.ReactElement { +function Upgrades({ rerender }: IUpgradeProps): React.ReactElement { + const corp = useCorporation(); // Don't show upgrades if (corp.divisions.length <= 0) { - return

Upgrades are unlocked once you create an industry.

; + return Upgrades are unlocked once you create an industry.; } return ( @@ -169,29 +156,32 @@ function Upgrades({ corp, player, rerender }: IUpgradeProps): React.ReactElement {Object.values(CorporationUnlockUpgrades) .filter((upgrade: CorporationUnlockUpgrade) => corp.unlockUpgrades[upgrade[0]] === 0) .map((upgrade: CorporationUnlockUpgrade) => ( - + ))}

Upgrades

{corp.upgrades .map((level: number, i: number) => CorporationUpgrades[i]) .map((upgrade: CorporationUpgrade) => ( - + ))}
); } interface IPublicButtonsProps { - corp: ICorporation; - player: IPlayer; rerender: () => void; } // Render the buttons for when your Corporation has gone public -function PublicButtons({ corp, player, rerender }: IPublicButtonsProps): React.ReactElement { +function PublicButtons({ rerender }: IPublicButtonsProps): React.ReactElement { + const corp = useCorporation(); + const [sellSharesOpen, setSellSharesOpen] = useState(false); + const [buybackSharesOpen, setBuybackSharesOpen] = useState(false); + const [issueNewSharesOpen, setIssueNewSharesOpen] = useState(false); + const [issueDividendsOpen, setIssueDividendsOpen] = useState(false); + const sellSharesOnCd = corp.shareSaleCooldown > 0; - const sellSharesClass = sellSharesOnCd ? "a-link-button-inactive" : "std-button"; const sellSharesTooltip = sellSharesOnCd ? "Cannot sell shares for " + corp.convertCooldownToString(corp.shareSaleCooldown) : "Sell your shares in the company. The money earned from selling your " + @@ -199,139 +189,83 @@ function PublicButtons({ corp, player, rerender }: IPublicButtonsProps): React.R "This is one of the only ways to profit from your business venture."; const issueNewSharesOnCd = corp.issueNewSharesCooldown > 0; - const issueNewSharesClass = issueNewSharesOnCd ? "a-link-button-inactive" : "std-button"; const issueNewSharesTooltip = issueNewSharesOnCd ? "Cannot issue new shares for " + corp.convertCooldownToString(corp.issueNewSharesCooldown) : "Issue new equity shares to raise capital."; - function openSellSharesPopup(): void { - const popupId = "cmpy-mgmt-sell-shares-popup"; - createPopup(popupId, SellSharesPopup, { - corp: corp, - player, - popupId, - rerender, - }); - } - - function openBuybackSharesPopup(): void { - const popupId = "corp-buyback-shares-popup"; - createPopup(popupId, BuybackSharesPopup, { - rerender, - player, - popupId, - corp: corp, - }); - } - - function openIssueNewSharesPopup(): void { - const popupId = "cmpy-mgmt-issue-new-shares-popup"; - createPopup(popupId, IssueNewSharesPopup, { - popupId, - corp: corp, - }); - } - - function openIssueDividendsPopup(): void { - const popupId = "cmpy-mgmt-issue-dividends-popup"; - createPopup(popupId, IssueDividendsPopup, { - popupId, - corp: corp, - }); - } - return ( <> - + + setSellSharesOpen(false)} rerender={rerender} /> + Buy back shares you that previously issued or sold at market price.} + > + + + setBuybackSharesOpen(false)} rerender={rerender} />
- + + setIssueNewSharesOpen(false)} /> + Manage the dividends that are paid out to shareholders (including yourself)} + > + + + setIssueDividendsOpen(false)} />
); } -// Generic Function for Creating a button -interface ICreateButtonProps { - text: string; - className?: string; - display?: string; - tooltip?: string; - onClick?: (event: React.MouseEvent) => void; -} +function BribeButton(): React.ReactElement { + const player = use.Player(); + const corp = useCorporation(); + const [open, setOpen] = useState(false); + const canBribe = + corp.determineValuation() >= CorporationConstants.BribeThreshold && + player.factions.filter((f) => Factions[f].getInfo().offersWork()).length > 0; -function Button({ className = "std-button", text, display, tooltip, onClick }: ICreateButtonProps): React.ReactElement { - const hasTooltip = tooltip != null; - if (hasTooltip) className += " tooltip"; - return ( - - ); -} - -interface IBribeButtonProps { - player: IPlayer; - corp: ICorporation; -} -function BribeButton({ player, corp }: IBribeButtonProps): React.ReactElement { - function openBribeFactionPopup(): void { - const popupId = "corp-bribe-popup"; - createPopup(popupId, BribeFactionPopup, { - player, - popupId, - corp: corp, - }); + function openBribe(): void { + if (!canBribe) return; + setOpen(true); } - const canBribe = corp.determineValuation() >= CorporationConstants.BribeThreshold || true; - const bribeFactionsClass = canBribe ? "a-link-button" : "a-link-button-inactive"; return ( - + + + setOpen(false)} /> + ); } interface IDividendsStatsProps { - corp: ICorporation; profit: number; } -function DividendsStats({ corp, profit }: IDividendsStatsProps): React.ReactElement { +function DividendsStats({ profit }: IDividendsStatsProps): React.ReactElement { + const corp = useCorporation(); if (corp.dividendPercentage <= 0 || profit <= 0) return <>; const totalDividends = (corp.dividendPercentage / 100) * profit; const retainedEarnings = profit - totalDividends; @@ -361,26 +295,24 @@ interface IMultProps { function Mult({ name, mult }: IMultProps): React.ReactElement { if (mult <= 1) return <>; return ( -

+ {name} {numeralWrapper.format(mult, "0.000")}
-

+ ); } -interface IBonusTimeProps { - corp: ICorporation; -} // Returns a string with general information about Corporation -function BonusTime({ corp }: IBonusTimeProps): React.ReactElement { +function BonusTime(): React.ReactElement { + const corp = useCorporation(); const storedTime = corp.storedCycles * CONSTANTS.MilliPerCycle; if (storedTime <= 15000) return <>; return ( -

+ Bonus time: {convertTimeMsToTimeElapsedString(storedTime)}

-

+ ); } diff --git a/src/Corporation/ui/SellSharesPopup.tsx b/src/Corporation/ui/SellSharesModal.tsx similarity index 63% rename from src/Corporation/ui/SellSharesPopup.tsx rename to src/Corporation/ui/SellSharesModal.tsx index c3b4d248a..035a0a6f4 100644 --- a/src/Corporation/ui/SellSharesPopup.tsx +++ b/src/Corporation/ui/SellSharesModal.tsx @@ -1,21 +1,26 @@ import React, { useState } from "react"; import { numeralWrapper } from "../../ui/numeralFormat"; import { dialogBoxCreate } from "../../ui/React/DialogBox"; -import { IPlayer } from "../../PersonObjects/IPlayer"; -import { removePopup } from "../../ui/React/createPopup"; +import { Modal } from "../../ui/React/Modal"; +import { use } from "../../ui/Context"; +import { useCorporation } from "./Context"; import { CorporationConstants } from "../data/Constants"; import { ICorporation } from "../ICorporation"; +import Typography from "@mui/material/Typography"; +import TextField from "@mui/material/TextField"; +import Button from "@mui/material/Button"; interface IProps { - corp: ICorporation; - player: IPlayer; - popupId: string; + open: boolean; + onClose: () => void; rerender: () => void; } // Create a popup that lets the player sell Corporation shares // This is created when the player clicks the "Sell Shares" button in the overview panel -export function SellSharesPopup(props: IProps): React.ReactElement { +export function SellSharesModal(props: IProps): React.ReactElement { + const player = use.Player(); + const corp = useCorporation(); const [shares, setShares] = useState(null); function changeShares(event: React.ChangeEvent): void { @@ -27,10 +32,10 @@ export function SellSharesPopup(props: IProps): React.ReactElement { if (props.shares === null) return <>; if (isNaN(props.shares) || props.shares <= 0) { return <>ERROR: Invalid value entered for number of shares to sell; - } else if (props.shares > props.corp.numShares) { + } else if (props.shares > corp.numShares) { return <>You don't have this many shares to sell!; } else { - const stockSaleResults = props.corp.calculateShareSale(props.shares); + const stockSaleResults = corp.calculateShareSale(props.shares); const profit = stockSaleResults[0]; return ( <> @@ -44,35 +49,35 @@ export function SellSharesPopup(props: IProps): React.ReactElement { if (shares === null) return; if (isNaN(shares) || shares <= 0) { dialogBoxCreate("ERROR: Invalid value for number of shares"); - } else if (shares > props.corp.numShares) { + } else if (shares > corp.numShares) { dialogBoxCreate("ERROR: You don't have this many shares to sell"); } else { - const stockSaleResults = props.corp.calculateShareSale(shares); + const stockSaleResults = corp.calculateShareSale(shares); const profit = stockSaleResults[0]; const newSharePrice = stockSaleResults[1]; const newSharesUntilUpdate = stockSaleResults[2]; - props.corp.numShares -= shares; - if (isNaN(props.corp.issuedShares)) { - console.error(`Corporation issuedShares is NaN: ${props.corp.issuedShares}`); - const res = props.corp.issuedShares; + corp.numShares -= shares; + if (isNaN(corp.issuedShares)) { + console.error(`Corporation issuedShares is NaN: ${corp.issuedShares}`); + const res = corp.issuedShares; if (isNaN(res)) { - props.corp.issuedShares = 0; + corp.issuedShares = 0; } else { - props.corp.issuedShares = res; + corp.issuedShares = res; } } - props.corp.issuedShares += shares; - props.corp.sharePrice = newSharePrice; - props.corp.shareSalesUntilPriceUpdate = newSharesUntilUpdate; - props.corp.shareSaleCooldown = CorporationConstants.SellSharesCooldown; - props.player.gainMoney(profit); - props.player.recordMoneySource(profit, "corporation"); - removePopup(props.popupId); + corp.issuedShares += shares; + corp.sharePrice = newSharePrice; + corp.shareSalesUntilPriceUpdate = newSharesUntilUpdate; + corp.shareSaleCooldown = CorporationConstants.SellSharesCooldown; + player.gainMoney(profit); + player.recordMoneySource(profit, "corporation"); + props.onClose(); dialogBoxCreate( `Sold ${numeralWrapper.formatMoney(shares)} shares for ` + `${numeralWrapper.formatMoney(profit)}. ` + - `The corporation's stock price fell to ${numeralWrapper.formatMoney(props.corp.sharePrice)} ` + + `The corporation's stock price fell to ${numeralWrapper.formatMoney(corp.sharePrice)} ` + `as a result of dilution.`, ); @@ -85,8 +90,8 @@ export function SellSharesPopup(props: IProps): React.ReactElement { } return ( - <> -

+ + Enter the number of shares you would like to sell. The money from selling your shares will go directly to you (NOT your Corporation).
@@ -95,22 +100,21 @@ export function SellSharesPopup(props: IProps): React.ReactElement { large number of shares all at once will have an immediate effect in reducing your stock price.

- The current price of your company's stock is {numeralWrapper.formatMoney(props.corp.sharePrice)} -

- + The current price of your company's stock is {numeralWrapper.formatMoney(corp.sharePrice)} + +
- - - + + ); } diff --git a/src/Corporation/ui/UnlockUpgrade.tsx b/src/Corporation/ui/UnlockUpgrade.tsx index 6435a1ea7..5ea775fed 100644 --- a/src/Corporation/ui/UnlockUpgrade.tsx +++ b/src/Corporation/ui/UnlockUpgrade.tsx @@ -3,30 +3,28 @@ import React from "react"; import { dialogBoxCreate } from "../../ui/React/DialogBox"; import { CorporationUnlockUpgrade } from "../data/CorporationUnlockUpgrades"; -import { ICorporation } from "../ICorporation"; -import { IPlayer } from "../../PersonObjects/IPlayer"; +import { useCorporation } from "./Context"; import { UnlockUpgrade as UU } from "../Actions"; import { MoneyCost } from "./MoneyCost"; interface IProps { upgradeData: CorporationUnlockUpgrade; - corp: ICorporation; - player: IPlayer; rerender: () => void; } export function UnlockUpgrade(props: IProps): React.ReactElement { + const corp = useCorporation(); const data = props.upgradeData; const text = ( <> - {data[2]} - + {data[2]} - ); const tooltip = data[3]; function onClick(): void { - if (props.corp.funds.lt(data[1])) return; + if (corp.funds.lt(data[1])) return; try { - UU(props.corp, props.upgradeData); + UU(corp, props.upgradeData); } catch (err) { dialogBoxCreate(err + ""); } diff --git a/src/Locations/ui/SpecialLocation.tsx b/src/Locations/ui/SpecialLocation.tsx index 21fcb7585..b2143d37b 100644 --- a/src/Locations/ui/SpecialLocation.tsx +++ b/src/Locations/ui/SpecialLocation.tsx @@ -15,8 +15,7 @@ import Typography from "@mui/material/Typography"; import Button from "@mui/material/Button"; import { Location } from "../Location"; -import { CreateCorporationPopup } from "../../Corporation/ui/CreateCorporationPopup"; -import { createPopup } from "../../ui/React/createPopup"; +import { CreateCorporationModal } from "../../Corporation/ui/CreateCorporationModal"; import { LocationName } from "../data/LocationNames"; import { use } from "../../ui/Context"; @@ -32,17 +31,6 @@ export function SpecialLocation(props: IProps): React.ReactElement { const router = use.Router(); const setRerender = useState(false)[1]; const inBladeburner = player.inBladeburner(); - /** - * Click handler for "Create Corporation" button at Sector-12 City Hall - */ - function createCorporationPopup(): void { - const popupId = `create-start-corporation-popup`; - createPopup(popupId, CreateCorporationPopup, { - player: player, - popupId: popupId, - router: router, - }); - } /** * Click handler for Bladeburner button at Sector-12 NSA @@ -93,7 +81,8 @@ export function SpecialLocation(props: IProps): React.ReactElement { return ; } - function renderCreateCorporation(): React.ReactElement { + function CreateCorporation(): React.ReactElement { + const [open, setOpen] = useState(false); if (!player.canAccessCorporation()) { return ( <> @@ -104,9 +93,12 @@ export function SpecialLocation(props: IProps): React.ReactElement { ); } return ( - + <> + + setOpen(false)} /> + ); } @@ -122,7 +114,7 @@ export function SpecialLocation(props: IProps): React.ReactElement { return renderResleeving(); } case LocationName.Sector12CityHall: { - return renderCreateCorporation(); + return ; } case LocationName.Sector12NSA: { return renderBladeburner();