logbox manager, alert manager and fix bitverse colors

This commit is contained in:
Olivier Gagnon 2021-10-01 10:39:09 -04:00
parent 62cd8ffcc6
commit 97c04a1037
18 changed files with 18 additions and 447 deletions

@ -51,7 +51,6 @@ interface IPortalProps {
function BitNodePortal(props: IPortalProps): React.ReactElement {
const [portalOpen, setPortalOpen] = useState(false);
const classes = useStyles();
const router = use.Router();
const bitNode = BitNodes[`BitNode${props.n}`];
if (bitNode == null) {
return <>O</>;
@ -63,9 +62,12 @@ function BitNodePortal(props: IPortalProps): React.ReactElement {
cssClass = classes.level2;
} else if (props.level === 1) {
cssClass = classes.level1;
} else {
} else if (props.level === 3) {
cssClass = classes.level3;
}
if (props.level === 2) {
cssClass = classes.level2;
}
return (
<>

@ -17,7 +17,7 @@ export function determineCrimeSuccess(p: IPlayer, type: string): boolean {
}
if (!found) {
dialogBoxCreate(`ERR: Unrecognized crime type: ${type} This is probably a bug please contact the developer`, false);
dialogBoxCreate(`ERR: Unrecognized crime type: ${type} This is probably a bug please contact the developer`);
return false;
}

@ -107,7 +107,7 @@ export class HacknetNode implements IHacknetNode {
this.moneyGainRatePerSecond = calculateMoneyGainRate(this.level, this.ram, this.cores, prodMult);
if (isNaN(this.moneyGainRatePerSecond)) {
this.moneyGainRatePerSecond = 0;
dialogBoxCreate("Error in calculating Hacknet Node production. Please report to game developer", false);
dialogBoxCreate("Error in calculating Hacknet Node production. Please report to game developer");
}
}

@ -9,7 +9,6 @@ import Button from "@mui/material/Button";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { getHospitalizationCost } from "../../Hospital/Hospital";
import { AutoupdatingStdButton } from "../../ui/React/AutoupdatingStdButton";
import { Money } from "../../ui/React/Money";
import { dialogBoxCreate } from "../../ui/React/DialogBox";

@ -58,7 +58,7 @@ export function CovenantPurchasesRoot(props: IProps): React.ReactElement {
player.sleeves.push(new Sleeve(player));
rerender();
} else {
dialogBoxCreate(`You cannot afford to purchase a Duplicate Sleeve`, false);
dialogBoxCreate(`You cannot afford to purchase a Duplicate Sleeve`);
}
}

@ -46,7 +46,7 @@ export function getPurchaseServerMaxRam(): number {
export function purchaseServer(hostname: string, ram: number, cost: number, p: IPlayer): void {
//Check if player has enough money
if (!p.canAfford(cost)) {
dialogBoxCreate("You don't have enough money to purchase this server!", false);
dialogBoxCreate("You don't have enough money to purchase this server!");
return;
}

@ -104,11 +104,11 @@ export function StockTickerPositionText(props: IProps): React.ReactElement {
return (
<>
<Typography>Max Shares: {numeralWrapper.formatShares(stock.maxShares)}</Typography>
<Typography className={"tooltip"}>
<Typography>
Ask Price: <Money money={stock.getAskPrice()} />
</Typography>
<br />
<Typography className={"tooltip"}>
<Typography>
Bid Price: <Money money={stock.getBidPrice()} />
</Typography>
<LongPosition {...props} />

@ -65,7 +65,7 @@ export class TextFile {
* Shows the content to the user via the game's dialog box.
*/
show(): void {
dialogBoxCreate(`${this.fn}<br /><br />${this.text}`, true);
dialogBoxCreate(`${this.fn}<br /><br />${this.text}`);
}
/**

@ -1,46 +0,0 @@
/**
* Basic stateless button that uses the 'accordion-button' css class.
* This class has a black background so that it does not clash with the default
* accordion coloring
*/
import * as React from "react";
interface IProps {
addClasses?: string;
disabled?: boolean;
id?: string;
onClick?: (e: React.MouseEvent<HTMLElement>) => any;
style?: any;
text: string;
tooltip?: string;
}
type IInnerHTMLMarkup = {
__html: string;
};
export function AccordionButton(props: IProps): React.ReactElement {
const hasTooltip = props.tooltip != null && props.tooltip !== "";
// TODO Add a disabled class for accordion buttons?
let className = "accordion-button";
if (hasTooltip) {
className += " tooltip";
}
if (typeof props.addClasses === "string") {
className += ` ${props.addClasses}`;
}
// Tooltip will be set using inner HTML
const tooltipMarkup: IInnerHTMLMarkup = {
__html: props.tooltip ? props.tooltip : "",
};
return (
<button className={className} id={props.id} onClick={props.onClick} style={props.style}>
{props.text}
{hasTooltip && <span className={"tooltiptext"} dangerouslySetInnerHTML={tooltipMarkup}></span>}
</button>
);
}

@ -32,9 +32,8 @@ export function AlertManager(): React.ReactElement {
);
function close(): void {
console.log("close");
setAlerts((old) => {
return old.slice(0, -1);
return old.slice(1, 1e99);
});
}

@ -1,67 +0,0 @@
/**
* Basic paragraph (p Element) that automatically re-renders itself every X seconds
*
* NOT recommended for usage - only if you really have to
*/
import * as React from "react";
interface IProps {
intervalTime?: number;
style?: any;
getContent: () => JSX.Element;
getTooltip?: () => JSX.Element;
}
interface IState {
i: number;
}
export class AutoupdatingParagraph extends React.Component<IProps, IState> {
/**
* Timer ID for auto-updating implementation (returned value from setInterval())
*/
interval = 0;
constructor(props: IProps) {
super(props);
this.state = {
i: 0,
};
}
componentDidMount(): void {
const time = this.props.intervalTime ? this.props.intervalTime : 1000;
this.interval = window.setInterval(() => this.tick(), time);
}
componentWillUnmount(): void {
clearInterval(this.interval);
}
tick(): void {
this.setState((prevState) => ({
i: prevState.i + 1,
}));
}
hasTooltip(): boolean {
if (this.props.getTooltip != null) {
return !!this.props.getTooltip();
}
return true;
}
tooltip(): JSX.Element {
if (!this.props.getTooltip) return <></>;
return this.props.getTooltip();
}
render(): React.ReactNode {
return (
<div className="tooltip" style={this.props.style}>
<p>{this.props.getContent()}</p>
{this.hasTooltip() && <span className={"tooltiptext"}>{this.tooltip()}</span>}
</div>
);
}
}

@ -1,80 +0,0 @@
/**
* Basic stateless button that automatically re-renders itself every X seconds
* Uses the 'std-button' css class
*
* NOT recommended for usage - only if you really have to
*/
import * as React from "react";
interface IProps {
label?: string;
disabled?: boolean;
intervalTime?: number;
onClick?: (e: React.MouseEvent<HTMLElement>) => any;
style?: any;
text: string | JSX.Element;
tooltip?: string;
}
interface IState {
i: number;
}
type IInnerHTMLMarkup = {
__html: string;
};
export class AutoupdatingStdButton extends React.Component<IProps, IState> {
/**
* Timer ID for auto-updating implementation (returned value from setInterval())
*/
interval = 0;
constructor(props: IProps) {
super(props);
this.state = {
i: 0,
};
}
componentDidMount(): void {
const time = this.props.intervalTime ? this.props.intervalTime : 1000;
this.interval = window.setInterval(() => this.tick(), time);
}
componentWillUnmount(): void {
clearInterval(this.interval);
}
tick(): void {
this.setState((prevState) => ({
i: prevState.i + 1,
}));
}
render(): React.ReactNode {
const hasTooltip = this.props.tooltip != null && this.props.tooltip !== "";
let className = this.props.disabled ? "std-button-disabled" : "std-button";
if (hasTooltip) {
className += " tooltip";
}
// Tooltip will eb set using inner HTML
const tooltipMarkup: IInnerHTMLMarkup = {
__html: this.props.tooltip ? this.props.tooltip : "",
};
return (
<button
aria-label={this.props.label || ""}
className={className}
onClick={this.props.onClick}
style={this.props.style}
>
{this.props.text}
{hasTooltip && <span className={"tooltiptext"} dangerouslySetInnerHTML={tooltipMarkup}></span>}
</button>
);
}
}

@ -1,43 +1,12 @@
import { createPopup } from "./createPopup";
import { getRandomInt } from "../../utils/helpers/getRandomInt";
import { AlertEvents } from "./AlertManager";
import React from "react";
import { jsx } from "@emotion/react";
interface IProps {
content: JSX.Element;
}
function MessagePopup(props: IProps): React.ReactElement {
return <>{props.content}</>;
}
export function dialogBoxCreate(txt: string | JSX.Element, preformatted = false): void {
const popupId =
`popup-` +
Array.from(Array(16))
.map(() => `${getRandomInt(0, 9)}`)
.join("");
if (typeof txt === "string") {
if (preformatted) {
// For text files as they are often computed data that
// shouldn't be wrapped and should retain tabstops.
createPopup(popupId, MessagePopup, {
content: <pre dangerouslySetInnerHTML={{ __html: txt }} />,
});
} else {
createPopup(popupId, MessagePopup, {
content: (
<p
dangerouslySetInnerHTML={{
__html: txt.replace(/(?:\r\n|\r|\n)/g, "<br />"),
}}
/>
),
});
}
export function dialogBoxCreate(txt: string | JSX.Element): void {
if (typeof txt !== "string") {
AlertEvents.emit(txt);
} else {
createPopup(popupId, MessagePopup, {
content: txt,
});
AlertEvents.emit(<pre dangerouslySetInnerHTML={{ __html: txt }} />);
}
}

@ -1,21 +0,0 @@
/**
* Text (p Element) with Tooltip
*/
import * as React from "react";
export interface IParagraphWithTooltipProps {
style?: any;
content: JSX.Element;
tooltip: string | React.ReactElement | JSX.Element;
}
export class ParagraphWithTooltip extends React.Component<IParagraphWithTooltipProps, any> {
render(): React.ReactNode {
return (
<div className={"tooltip"} style={this.props.style}>
<p>{this.props.content}</p>
<span className={"tooltiptext"}>{this.props.tooltip}</span>
</div>
);
}
}

@ -1,71 +0,0 @@
/**
* Basic button for popup dialog boxes
* It creates an event handler such that pressing Esc will perform the click handler.
*
* Should only be used in other React components, otherwise it may not be properly
* unmounted
*/
import * as React from "react";
import * as ReactDOM from "react-dom";
import { KEY } from "../../utils/helpers/keyCodes";
import { removeElement } from "../uiHelpers/removeElement";
export interface IPopupButtonProps {
class?: string;
popup: HTMLElement | string;
style?: any;
text: string;
onClose?: () => void;
}
export class PopupButton extends React.Component<IPopupButtonProps, any> {
constructor(props: IPopupButtonProps) {
super(props);
this.handleClick = this.handleClick.bind(this);
this.keyListener = this.keyListener.bind(this);
}
componentDidMount(): void {
document.addEventListener("keydown", this.keyListener);
}
componentWillUnmount(): void {
document.removeEventListener("keydown", this.keyListener);
}
handleClick(): void {
if (this.props.onClose) this.props.onClose();
//We might be able to remove this?
//Clickhandler from the props will override this anyhow.
let popup: HTMLElement | null;
if (typeof this.props.popup === "string") {
popup = document.getElementById(this.props.popup);
} else {
popup = this.props.popup;
}
// TODO Check if this is okay? This is essentially calling to unmount a parent component
if (popup instanceof HTMLElement) {
ReactDOM.unmountComponentAtNode(popup); // Removes everything inside the wrapper container
removeElement(popup); // Removes the wrapper container
}
}
keyListener(e: KeyboardEvent): void {
//This doesn't really make sense, a button doesnt have to listen to escape IMO
//Too affraid to remove it since im not sure what it will break.. But yuck..
if (e.keyCode === KEY.ESC) {
this.handleClick();
}
}
render(): React.ReactNode {
const className = this.props.class ? this.props.class : "std-button";
return (
<button className={className} onClick={this.handleClick} style={this.props.style}>
{this.props.text}
</button>
);
}
}

@ -1,56 +0,0 @@
/**
* Close button for popup dialog boxes
* It creates an event handler such that pressing Esc will close the binded popup
*
* Should only be used in other React components, otherwise it may not be properly
* unmounted
*/
import * as React from "react";
import * as ReactDOM from "react-dom";
import { removeElement } from "../uiHelpers/removeElement";
import { IPopupButtonProps, PopupButton } from "./PopupButton";
export interface IPopupCloseButtonProps extends IPopupButtonProps {
class?: string;
popup: HTMLElement | string;
style?: any;
text: string;
onClose: () => void;
}
export class PopupCloseButton extends PopupButton {
constructor(props: IPopupCloseButtonProps) {
super(props);
this.closePopup = this.closePopup.bind(this);
}
closePopup(): void {
if (this.props.onClose) this.props.onClose();
let popup: HTMLElement | null;
if (typeof this.props.popup === "string") {
popup = document.getElementById(this.props.popup);
} else {
popup = this.props.popup;
}
// TODO Check if this is okay? This is essentially calling to unmount a
// parent component
if (popup instanceof HTMLElement) {
// Removes everything inside the wrapper container
ReactDOM.unmountComponentAtNode(popup);
removeElement(popup); // Removes the wrapper container
}
}
render(): React.ReactNode {
const className = this.props.class ? this.props.class : "std-button";
return (
<button className={className} onClick={this.closePopup} style={this.props.style}>
{this.props.text}
</button>
);
}
}

@ -1,56 +0,0 @@
/**
* Stateless button that represents something that has been purchased.
*/
import * as React from "react";
interface IStdButtonPurchasedProps {
onClick?: (e: React.MouseEvent<HTMLElement>) => any;
style?: any;
text: string;
tooltip?: string;
}
type IInnerHTMLMarkup = {
__html: string;
};
export class StdButtonPurchased extends React.Component<IStdButtonPurchasedProps, any> {
constructor(props: IStdButtonPurchasedProps) {
super(props);
this.hasTooltip = this.hasTooltip.bind(this);
this.tooltip = this.tooltip.bind(this);
}
hasTooltip(): boolean {
return this.props.tooltip != null && this.props.tooltip !== "";
}
tooltip(): string {
if (!this.props.tooltip) return "";
return this.props.tooltip;
}
render(): React.ReactNode {
let className = "std-button-bought";
if (this.hasTooltip()) {
className += " tooltip";
}
// Tooltip will be set using inner HTML
let tooltipMarkup: IInnerHTMLMarkup = {
__html: "",
};
if (this.hasTooltip()) {
tooltipMarkup = {
__html: this.tooltip(),
};
}
return (
<button className={className} onClick={this.props.onClick} style={this.props.style}>
{this.props.text}
{this.hasTooltip() && <span className={"tooltiptext"} dangerouslySetInnerHTML={tooltipMarkup}></span>}
</button>
);
}
}

@ -21,6 +21,5 @@ export function exceptionAlert(e: IError | string): void {
"message as well as details about how to reproduce the bug.<br><br>" +
"If you want to be safe, I suggest refreshing the game WITHOUT saving so that your " +
"safe doesn't get corrupted",
false,
);
}