mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-11-19 22:23:51 +01:00
Fix GH Issue #616: Stock Market UI throws error for certain locales because the price format length is too high
This commit is contained in:
parent
571ddb109a
commit
8ddf7dfbd4
@ -20,6 +20,7 @@ import { CONSTANTS } from "../Constants";
|
||||
import { WorkerScript } from "../Netscript/WorkerScript";
|
||||
import { Player } from "../Player";
|
||||
import { IMap } from "../types";
|
||||
import { EventEmitter } from "../utils/EventEmitter";
|
||||
|
||||
import { Page, routing } from ".././ui/navigationTracking";
|
||||
import { numeralWrapper } from ".././ui/numeralFormat";
|
||||
@ -290,11 +291,15 @@ function initStockMarketFnForReact() {
|
||||
initSymbolToStockMap();
|
||||
}
|
||||
|
||||
const eventEmitterForUiReset = new EventEmitter();
|
||||
|
||||
export function displayStockMarketContent() {
|
||||
if (!routing.isOn(Page.StockMarket)) {
|
||||
return;
|
||||
}
|
||||
|
||||
eventEmitterForUiReset.emitEvent();
|
||||
|
||||
if (stockMarketContainer instanceof HTMLElement) {
|
||||
const castedStockMarket = StockMarket as IStockMarket;
|
||||
ReactDOM.render(
|
||||
@ -302,6 +307,7 @@ export function displayStockMarketContent() {
|
||||
buyStockLong={buyStock}
|
||||
buyStockShort={shortStock}
|
||||
cancelOrder={cancelOrder}
|
||||
eventEmitterForReset={eventEmitterForUiReset}
|
||||
initStockMarket={initStockMarketFnForReact}
|
||||
p={Player}
|
||||
placeOrder={placeOrder}
|
||||
|
@ -12,6 +12,7 @@ import { OrderTypes } from "../data/OrderTypes";
|
||||
import { PositionTypes } from "../data/PositionTypes";
|
||||
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { EventEmitter } from "../../utils/EventEmitter";
|
||||
|
||||
type txFn = (stock: Stock, shares: number) => boolean;
|
||||
export type placeOrderFn = (stock: Stock, shares: number, price: number, ordType: OrderTypes, posType: PositionTypes) => boolean;
|
||||
@ -20,6 +21,7 @@ type IProps = {
|
||||
buyStockLong: txFn;
|
||||
buyStockShort: txFn;
|
||||
cancelOrder: (params: object) => void;
|
||||
eventEmitterForReset?: EventEmitter;
|
||||
initStockMarket: () => void;
|
||||
p: IPlayer;
|
||||
placeOrder: placeOrderFn;
|
||||
@ -65,6 +67,7 @@ export class StockMarketRoot extends React.Component<IProps, IState> {
|
||||
buyStockLong={this.props.buyStockLong}
|
||||
buyStockShort={this.props.buyStockShort}
|
||||
cancelOrder={this.props.cancelOrder}
|
||||
eventEmitterForReset={this.props.eventEmitterForReset}
|
||||
p={this.props.p}
|
||||
placeOrder={this.props.placeOrder}
|
||||
sellStockLong={this.props.sellStockLong}
|
||||
|
@ -9,6 +9,7 @@ import { Stock } from "../Stock";
|
||||
import { TickerHeaderFormatData } from "../data/TickerHeaderFormatData";
|
||||
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { Settings } from "../../Settings/Settings";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
|
||||
type IProps = {
|
||||
@ -16,12 +17,22 @@ type IProps = {
|
||||
stock: Stock;
|
||||
}
|
||||
|
||||
const localesWithLongPriceFormat = [
|
||||
"cs",
|
||||
"lv",
|
||||
"pl",
|
||||
"ru",
|
||||
];
|
||||
|
||||
export function StockTickerHeaderText(props: IProps): React.ReactElement {
|
||||
const stock = props.stock;
|
||||
|
||||
const stockPriceFormat = numeralWrapper.formatMoney(stock.price);
|
||||
const spacesAllottedForStockPrice = localesWithLongPriceFormat.includes(Settings.Locale) ? 15 : 12;
|
||||
const spacesAfterStockName = " ".repeat(1 + TickerHeaderFormatData.longestName - stock.name.length + (TickerHeaderFormatData.longestSymbol - stock.symbol.length));
|
||||
const spacesBeforePrice = " ".repeat(spacesAllottedForStockPrice - stockPriceFormat.length);
|
||||
|
||||
let hdrText = `${stock.name}${" ".repeat(1 + TickerHeaderFormatData.longestName - stock.name.length + (TickerHeaderFormatData.longestSymbol - stock.symbol.length))}${stock.symbol} -${" ".repeat(10 - stockPriceFormat.length)}${stockPriceFormat}`;
|
||||
let hdrText = `${stock.name}${spacesAfterStockName}${stock.symbol} -${spacesBeforePrice}${stockPriceFormat}`;
|
||||
if (props.p.has4SData) {
|
||||
hdrText += ` - Volatility: ${numeralWrapper.format(stock.mv, '0,0.00')}% - Price Forecast: `;
|
||||
let plusOrMinus = stock.b; // True for "+", false for "-"
|
||||
|
@ -14,6 +14,9 @@ import { OrderTypes } from "../data/OrderTypes";
|
||||
import { PositionTypes } from "../data/PositionTypes";
|
||||
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { EventEmitter } from "../../utils/EventEmitter";
|
||||
|
||||
import { ErrorBoundary } from "../../ui/React/ErrorBoundary";
|
||||
|
||||
export type txFn = (stock: Stock, shares: number) => boolean;
|
||||
export type placeOrderFn = (stock: Stock, shares: number, price: number, ordType: OrderTypes, posType: PositionTypes) => boolean;
|
||||
@ -22,6 +25,7 @@ type IProps = {
|
||||
buyStockLong: txFn;
|
||||
buyStockShort: txFn;
|
||||
cancelOrder: (params: object) => void;
|
||||
eventEmitterForReset?: EventEmitter;
|
||||
p: IPlayer;
|
||||
placeOrder: placeOrderFn;
|
||||
sellStockLong: txFn;
|
||||
@ -169,8 +173,13 @@ export class StockTickers extends React.Component<IProps, IState> {
|
||||
}
|
||||
}
|
||||
|
||||
const errorBoundaryProps = {
|
||||
eventEmitterForReset: this.props.eventEmitterForReset,
|
||||
id: "StockTickersErrorBoundary",
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<ErrorBoundary {...errorBoundaryProps}>
|
||||
<StockTickersConfig
|
||||
changeDisplayMode={this.changeDisplayMode}
|
||||
changeWatchlistFilter={this.changeWatchlistFilter}
|
||||
@ -182,7 +191,7 @@ export class StockTickers extends React.Component<IProps, IState> {
|
||||
<ul id="stock-market-list" ref={this.listRef}>
|
||||
{tickers}
|
||||
</ul>
|
||||
</div>
|
||||
</ErrorBoundary>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
103
src/ui/React/ErrorBoundary.tsx
Normal file
103
src/ui/React/ErrorBoundary.tsx
Normal file
@ -0,0 +1,103 @@
|
||||
/**
|
||||
* React Component for a simple Error Boundary. The fallback UI for
|
||||
* this error boundary is simply a bordered text box
|
||||
*/
|
||||
import * as React from "react";
|
||||
|
||||
import { EventEmitter } from "../../utils/EventEmitter";
|
||||
|
||||
type IProps = {
|
||||
eventEmitterForReset?: EventEmitter;
|
||||
id?: string;
|
||||
};
|
||||
|
||||
type IState = {
|
||||
errorInfo: string;
|
||||
hasError: boolean;
|
||||
}
|
||||
|
||||
type IErrorInfo = {
|
||||
componentStack: string;
|
||||
}
|
||||
|
||||
// TODO: Move this out to a css file
|
||||
const styleMarkup = {
|
||||
border: "1px solid red",
|
||||
display: "inline-block",
|
||||
margin: "4px",
|
||||
padding: "4px",
|
||||
}
|
||||
|
||||
export class ErrorBoundary extends React.Component<IProps, IState> {
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
errorInfo: "",
|
||||
hasError: false,
|
||||
}
|
||||
}
|
||||
|
||||
static getDerivedStateFromError(error: Error) {
|
||||
return {
|
||||
errorInfo: error.message,
|
||||
hasError: true,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidCatch(error: Error, info: IErrorInfo) {
|
||||
console.error(`Caught error in React ErrorBoundary. Component stack:`);
|
||||
console.error(info.componentStack);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const cb = () => {
|
||||
this.setState({
|
||||
hasError: false,
|
||||
});
|
||||
}
|
||||
|
||||
if (this.hasEventEmitter()) {
|
||||
this.props.eventEmitterForReset!.addSubscriber({
|
||||
cb: cb,
|
||||
id: this.props.id!,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this.hasEventEmitter()) {
|
||||
this.props.eventEmitterForReset!.removeSubscriber(this.props.id!);
|
||||
}
|
||||
}
|
||||
|
||||
hasEventEmitter(): boolean {
|
||||
return this.props.eventEmitterForReset instanceof EventEmitter
|
||||
&& typeof this.props.id === "string";
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.state.hasError) {
|
||||
return (
|
||||
<div style={styleMarkup}>
|
||||
<p>
|
||||
{
|
||||
`Error rendering UI. This is (probably) a bug. Please report to game developer.`
|
||||
}
|
||||
</p>
|
||||
<p>
|
||||
{
|
||||
`In the meantime, try refreshing the game WITHOUT saving.`
|
||||
}
|
||||
</p>
|
||||
<p>
|
||||
{
|
||||
`Error info: ${this.state.errorInfo}`
|
||||
}
|
||||
</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return this.props.children;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user