Merge branch 'dev' into add-ns-getRecentScripts

This commit is contained in:
hydroflame
2022-04-12 14:21:18 -04:00
committed by GitHub
518 changed files with 15410 additions and 160938 deletions
+6 -6
View File
@@ -1,9 +1,9 @@
import React, { useState, useEffect } from "react";
import { EventEmitter } from "../../utils/EventEmitter";
import { Modal } from "../../ui/React/Modal";
import { Modal } from "./Modal";
import Typography from "@mui/material/Typography";
import Box from "@mui/material/Box";
import {sha256} from "js-sha256";
import { sha256 } from "js-sha256";
export const AlertEvents = new EventEmitter<[string | JSX.Element]>();
@@ -23,8 +23,8 @@ export function AlertManager(): React.ReactElement {
i++;
setAlerts((old) => {
const hash = getMessageHash(text);
if (old.some(a => a.hash === hash)) {
console.log('Duplicate message');
if (old.some((a) => a.hash === hash)) {
console.log("Duplicate message");
return old;
}
return [
@@ -51,7 +51,7 @@ export function AlertManager(): React.ReactElement {
}, []);
function getMessageHash(text: string | JSX.Element): string {
if (typeof text === 'string') return sha256(text);
if (typeof text === "string") return sha256(text);
return sha256(JSON.stringify(text.props));
}
@@ -66,7 +66,7 @@ export function AlertManager(): React.ReactElement {
{alerts.length > 0 && (
<Modal open={true} onClose={close}>
<Box overflow="scroll" sx={{ overflowWrap: "break-word", whiteSpace: "pre-line" }}>
<Typography>{alerts[0].text}</Typography>
<Typography component={"span"}>{alerts[0].text}</Typography>
</Box>
</Modal>
)}
+86 -60
View File
@@ -4,7 +4,7 @@ import React, { useState, useEffect } from "react";
import { Theme, useTheme } from "@mui/material/styles";
import makeStyles from "@mui/styles/makeStyles";
import createStyles from "@mui/styles/createStyles";
import { numeralWrapper } from "../../ui/numeralFormat";
import { numeralWrapper } from "../numeralFormat";
import { Reputation } from "./Reputation";
import { KillScriptsModal } from "./KillScriptsModal";
import { convertTimeMsToTimeElapsedString } from "../../utils/StringHelperFunctions";
@@ -33,23 +33,34 @@ interface IProps {
}
function Intelligence(): React.ReactElement {
const theme = useTheme();
const player = use.Player();
const classes = useStyles();
if (player.intelligence === 0) return <></>;
const progress = player.calculateSkillProgress(player.intelligence_exp);
return (
<TableRow>
<TableCell component="th" scope="row" classes={{ root: classes.cell }}>
<Typography classes={{ root: classes.int }}>Int&nbsp;</Typography>
</TableCell>
<TableCell align="right" classes={{ root: classes.cell }}>
<Typography classes={{ root: classes.int }}>{numeralWrapper.formatSkill(player.intelligence)}</Typography>
</TableCell>
<TableCell align="right" classes={{ root: classes.cell }}>
<Typography id="overview-int-hook" classes={{ root: classes.int }}>
{/*Hook for player scripts*/}
</Typography>
</TableCell>
</TableRow>
<>
<TableRow>
<TableCell component="th" scope="row" classes={{ root: classes.cell }}>
<Typography classes={{ root: classes.int }}>Int&nbsp;</Typography>
</TableCell>
<TableCell align="right" classes={{ root: classes.cell }}>
<Typography classes={{ root: classes.int }}>{numeralWrapper.formatSkill(player.intelligence)}</Typography>
</TableCell>
<TableCell align="right" classes={{ root: classes.cell }}>
<Typography id="overview-int-hook" classes={{ root: classes.int }}>
{/*Hook for player scripts*/}
</Typography>
</TableCell>
</TableRow>
<TableRow>
{!Settings.DisableOverviewProgressBars && (
<StatsProgressOverviewCell progress={progress} color={theme.colors.int} />
)}
</TableRow>
</>
);
}
@@ -132,51 +143,66 @@ function Work(): React.ReactElement {
let details = <></>;
let header = <></>;
let innerText = <></>;
if (player.workType === CONSTANTS.WorkTypeCompanyPartTime || player.workType === CONSTANTS.WorkTypeCompany) {
details = (
<>
{player.jobs[player.companyName]} at <strong>{player.companyName}</strong>
</>
);
header = (
<>
Working at <strong>{player.companyName}</strong>
</>
);
innerText = (
<>
+<Reputation reputation={player.workRepGained} /> rep
</>
);
} else if (player.workType === CONSTANTS.WorkTypeFaction) {
details = (
<>
{player.factionWorkType} for <strong>{player.currentWorkFactionName}</strong>
</>
);
header = (
<>
Working for <strong>{player.currentWorkFactionName}</strong>
</>
);
innerText = (
<>
+<Reputation reputation={player.workRepGained} /> rep
</>
);
} else if (player.workType === CONSTANTS.WorkTypeStudyClass) {
details = <>{player.workType}</>;
header = <>You are {player.className}</>;
innerText = <>{convertTimeMsToTimeElapsedString(player.timeWorked)}</>;
} else if (player.workType === CONSTANTS.WorkTypeCreateProgram) {
details = <>Coding {player.createProgramName}</>;
header = <>Creating a program</>;
innerText = (
<>
{player.createProgramName}{" "}
{((player.timeWorkedCreateProgram / player.timeNeededToCompleteWork) * 100).toFixed(2)}%
</>
);
switch (player.workType) {
case CONSTANTS.WorkTypeCompanyPartTime:
case CONSTANTS.WorkTypeCompany:
details = (
<>
{player.jobs[player.companyName]} at <strong>{player.companyName}</strong>
</>
);
header = (
<>
Working at <strong>{player.companyName}</strong>
</>
);
innerText = (
<>
+<Reputation reputation={player.workRepGained} /> rep
</>
);
break;
case CONSTANTS.WorkTypeFaction:
details = (
<>
{player.factionWorkType} for <strong>{player.currentWorkFactionName}</strong>
</>
);
header = (
<>
Working for <strong>{player.currentWorkFactionName}</strong>
</>
);
innerText = (
<>
+<Reputation reputation={player.workRepGained} /> rep
</>
);
break;
case CONSTANTS.WorkTypeStudyClass:
details = <>{player.workType}</>;
header = <>You are {player.className}</>;
innerText = <>{convertTimeMsToTimeElapsedString(player.timeWorked)}</>;
break;
case CONSTANTS.WorkTypeCreateProgram:
details = <>Coding {player.createProgramName}</>;
header = <>Creating a program</>;
innerText = (
<>
{player.createProgramName}{" "}
{((player.timeWorkedCreateProgram / player.timeNeededToCompleteWork) * 100).toFixed(2)}%
</>
);
break;
case CONSTANTS.WorkTypeGraftAugmentation:
details = <>Grafting {player.graftAugmentationName}</>;
header = <>Grafting an Augmentation</>;
innerText = (
<>
<strong>{((player.timeWorkedGraftAugmentation / player.timeNeededToCompleteWork) * 100).toFixed(2)}%</strong>{" "}
done
</>
);
}
return (
@@ -454,7 +480,7 @@ export function CharacterOverview({ save, killScripts }: IProps): React.ReactEle
<Box sx={{ display: "flex", borderTop: `1px solid ${Settings.theme.welllight}` }}>
<Box sx={{ display: "flex", flex: 1, justifyContent: "flex-start", alignItems: "center" }}>
<IconButton aria-label="save game" onClick={save}>
<Tooltip title="Save game">
<Tooltip title={Settings.AutosaveInterval !== 0 ? "Save game" : "Save game (auto-saves are disabled!)"}>
<SaveIcon color={Settings.AutosaveInterval !== 0 ? "primary" : "error"} />
</Tooltip>
</IconButton>
+1 -1
View File
@@ -37,7 +37,7 @@ export function CodingContractModal(): React.ReactElement {
// whatever ...
const value = (event.target as any).value;
if (event.keyCode === KEY.ENTER && value !== "") {
if (event.key === KEY.ENTER && value !== "") {
event.preventDefault();
props.onAttempt(answer);
setAnswer("");
+5 -3
View File
@@ -33,9 +33,11 @@ export function CorruptableText(props: IProps): JSX.Element {
const index = Math.random() * content.length;
const letter = content.charAt(index);
setContent((content) => replace(content, index, randomize(letter)));
timers.push(window.setTimeout(() => {
setContent((content) => replace(content, index, letter));
}, 500));
timers.push(
window.setTimeout(() => {
setContent((content) => replace(content, index, letter));
}, 500),
);
}, 20);
return () => {
+27 -23
View File
@@ -1,11 +1,11 @@
import React, { useState } from 'react';
import React, { useState } from "react";
import { deleteGame } from "../../db";
import { ConfirmationModal } from "./ConfirmationModal";
import Button from "@mui/material/Button";
import { Tooltip } from '@mui/material';
import { Tooltip } from "@mui/material";
import DeleteIcon from '@mui/icons-material/Delete';
import { pushDisableRestore } from '../../Electron';
import DeleteIcon from "@mui/icons-material/Delete";
import { pushDisableRestore } from "../../Electron";
interface IProps {
color?: "primary" | "warning" | "error";
@@ -14,23 +14,27 @@ interface IProps {
export function DeleteGameButton({ color = "primary" }: IProps): React.ReactElement {
const [modalOpened, setModalOpened] = useState(false);
return (<>
<Tooltip title="This will permanently delete your local save game. Did you export it before?">
<Button startIcon={<DeleteIcon />} color={color} onClick={() => setModalOpened(true)}>Delete Save</Button>
</Tooltip>
<ConfirmationModal
onConfirm={() => {
setModalOpened(false);
deleteGame()
.then(() => {
pushDisableRestore();
setTimeout(() => location.reload(), 1000);
})
.catch((r) => console.error(`Could not delete game: ${r}`));
}}
open={modalOpened}
onClose={() => setModalOpened(false)}
confirmationText={"Really delete your game? (It's permanent!)"}
/>
</>)
return (
<>
<Tooltip title="This will permanently delete your local save game. Did you export it before?">
<Button startIcon={<DeleteIcon />} color={color} onClick={() => setModalOpened(true)}>
Delete Save
</Button>
</Tooltip>
<ConfirmationModal
onConfirm={() => {
setModalOpened(false);
deleteGame()
.then(() => {
pushDisableRestore();
setTimeout(() => location.reload(), 1000);
})
.catch((r) => console.error(`Could not delete game: ${r}`));
}}
open={modalOpened}
onClose={() => setModalOpened(false)}
confirmationText={"Really delete your game? (It's permanent!)"}
/>
</>
);
}
+1 -1
View File
@@ -1,5 +1,5 @@
import * as React from "react";
import { numeralWrapper } from "../../ui/numeralFormat";
import { numeralWrapper } from "../numeralFormat";
import { Theme } from "@mui/material/styles";
import makeStyles from "@mui/styles/makeStyles";
import createStyles from "@mui/styles/createStyles";
+8
View File
@@ -352,6 +352,14 @@ export function GameOptionsRoot(props: IProps): React.ReactElement {
tooltip={<>If this is set, there will be no "Game Saved!" toast appearing after an auto-save.</>}
/>
</ListItem>
<ListItem>
<OptionSwitch
checked={Settings.SuppressAutosaveDisabledWarnings}
onChange={(newValue) => (Settings.SuppressAutosaveDisabledWarnings = newValue)}
text="Suppress Auto-Save Disabled Warning"
tooltip={<>If this is set, there will be no warning triggered when auto-save is disabled (at 0).</>}
/>
</ListItem>
<ListItem>
<OptionSwitch
checked={Settings.DisableHotkeys}
+2 -2
View File
@@ -1,6 +1,6 @@
import React from "react";
import { numeralWrapper } from "../../ui/numeralFormat";
import { Hashes } from "../../ui/React/Hashes";
import { numeralWrapper } from "../numeralFormat";
import { Hashes } from "./Hashes";
export function HashRate({ hashes }: { hashes: number }): React.ReactElement {
return <Hashes hashes={`${numeralWrapper.formatHashes(hashes)} h / s`} />;
+1 -1
View File
@@ -1,5 +1,5 @@
import * as React from "react";
import { numeralWrapper } from "../../ui/numeralFormat";
import { numeralWrapper } from "../numeralFormat";
import { Theme } from "@mui/material/styles";
import makeStyles from "@mui/styles/makeStyles";
import createStyles from "@mui/styles/createStyles";
+7 -5
View File
@@ -121,7 +121,7 @@ export function ImportSaveRoot(props: IProps): JSX.Element {
Settings.AutosaveInterval = initialAutosave;
pushImportResult(false);
props.router.allowRouting(true);
setHeadback(true)
setHeadback(true);
}
async function handleImport(): Promise<void> {
@@ -211,12 +211,14 @@ export function ImportSaveRoot(props: IProps): JSX.Element {
<TableRow>
<TableCell>Saved On</TableCell>
<TableCell>
{(currentData.playerData?.lastSave ?? 0) > 0 ?
new Date(currentData.playerData?.lastSave ?? 0).toLocaleString() : 'n/a'}
{(currentData.playerData?.lastSave ?? 0) > 0
? new Date(currentData.playerData?.lastSave ?? 0).toLocaleString()
: "n/a"}
</TableCell>
<TableCell>
{(importData.playerData?.lastSave ?? 0) > 0 ?
new Date(importData.playerData?.lastSave ?? 0).toLocaleString() : 'n/a'}
{(importData.playerData?.lastSave ?? 0) > 0
? new Date(importData.playerData?.lastSave ?? 0).toLocaleString()
: "n/a"}
</TableCell>
<TableCell>
{importData.playerData?.lastSave !== currentData.playerData?.lastSave && (
+26 -15
View File
@@ -118,7 +118,7 @@ export const logBoxBaseZIndex = 1500;
function LogWindow(props: IProps): React.ReactElement {
const draggableRef = useRef<HTMLDivElement>(null);
const rootRef = useRef<Draggable>(null)
const rootRef = useRef<Draggable>(null);
const [script, setScript] = useState(props.script);
const classes = useStyles();
const container = useRef<HTMLDivElement>(null);
@@ -128,6 +128,23 @@ function LogWindow(props: IProps): React.ReactElement {
setRerender((old) => !old);
}
// useEffect(
// () =>
// WorkerScriptStartStopEventEmitter.subscribe(() => {
// setTimeout(() => {
// const server = GetServer(script.server);
// if (server === null) return;
// const exisitingScript = findRunningScript(script.filename, script.args, server);
// if (exisitingScript) {
// exisitingScript.logs = script.logs.concat(exisitingScript.logs)
// setScript(exisitingScript)
// }
// rerender();
// }, 100)
// }),
// [],
// );
useEffect(() => {
updateLayer();
const id = setInterval(rerender, 1000);
@@ -198,7 +215,7 @@ function LogWindow(props: IProps): React.ReactElement {
const node = draggableRef?.current;
if (!node) return;
if(!isOnScreen(node)) {
if (!isOnScreen(node)) {
resetPosition();
}
}, 100);
@@ -206,27 +223,21 @@ function LogWindow(props: IProps): React.ReactElement {
const isOnScreen = (node: HTMLDivElement): boolean => {
const bounds = node.getBoundingClientRect();
return !(bounds.right < 0 ||
bounds.bottom < 0 ||
bounds.left > innerWidth ||
bounds.top > outerWidth);
}
return !(bounds.right < 0 || bounds.bottom < 0 || bounds.left > innerWidth || bounds.top > outerWidth);
};
const resetPosition = (): void => {
const node = rootRef?.current;
if (!node) return;
const state = node.state as {x: number; y: number};
const state = node.state as { x: number; y: number };
state.x = 0;
state.y = 0;
node.setState(state);
}
};
const boundToBody = (e: any): void | false => {
if(e.clientX < 0 ||
e.clientY < 0 ||
e.clientX > innerWidth ||
e.clientY > innerHeight) return false;
}
if (e.clientX < 0 || e.clientY < 0 || e.clientX > innerWidth || e.clientY > innerHeight) return false;
};
return (
<Draggable handle=".drag" onDrag={boundToBody} ref={rootRef}>
@@ -288,4 +299,4 @@ function LogWindow(props: IProps): React.ReactElement {
</Paper>
</Draggable>
);
}
}
+1 -1
View File
@@ -1,5 +1,5 @@
import * as React from "react";
import { numeralWrapper } from "../../ui/numeralFormat";
import { numeralWrapper } from "../numeralFormat";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { Theme } from "@mui/material/styles";
import makeStyles from "@mui/styles/makeStyles";
+2 -2
View File
@@ -1,6 +1,6 @@
import React from "react";
import { numeralWrapper } from "../../ui/numeralFormat";
import { Money } from "../../ui/React/Money";
import { numeralWrapper } from "../numeralFormat";
import { Money } from "./Money";
export function MoneyRate({ money }: { money: number }): JSX.Element {
return <Money money={`${numeralWrapper.formatMoney(money)} / sec`} />;
+129 -28
View File
@@ -1,54 +1,155 @@
import React, { useState, useEffect } from "react";
import { EventEmitter } from "../../utils/EventEmitter";
import { Modal } from "../../ui/React/Modal";
import { Modal } from "./Modal";
import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button";
import Select, { SelectChangeEvent } from "@mui/material/Select";
import TextField from "@mui/material/TextField";
import MenuItem from "@mui/material/MenuItem";
import { KEY } from "../../utils/helpers/keyCodes";
export const PromptEvent = new EventEmitter<[Prompt]>();
interface Prompt {
txt: string;
resolve: (result: boolean) => void;
options?: { type?: string; choices?: string[] };
resolve: (result: boolean | string) => void;
}
export function PromptManager(): React.ReactElement {
const [prompt, setPrompt] = useState<Prompt | null>(null);
useEffect(
() =>
PromptEvent.subscribe((p: Prompt) => {
setPrompt(p);
}),
[],
);
useEffect(() => {
return PromptEvent.subscribe((p: Prompt) => {
setPrompt(p);
});
}, []);
if (prompt === null) {
return <></>;
}
function close(): void {
if (prompt === null) return;
prompt.resolve(false);
if (["text", "select"].includes(prompt?.options?.type ?? "")) {
prompt.resolve("");
} else {
prompt.resolve(false);
}
setPrompt(null);
}
function yes(): void {
if (prompt === null) return;
prompt.resolve(true);
const types: { [key: string]: any } = {
text: PromptMenuText,
select: PromptMenuSelect,
};
let PromptContent = PromptMenuBoolean;
if (prompt?.options?.type && ["text", "select"].includes(prompt?.options?.type))
PromptContent = types[prompt?.options?.type];
const resolve = (value: boolean | string): void => {
prompt.resolve(value);
setPrompt(null);
}
function no(): void {
if (prompt === null) return;
prompt.resolve(false);
setPrompt(null);
}
};
return (
<Modal open={true} onClose={close}>
<pre>
<Typography>{prompt.txt}</Typography>
</pre>
<PromptContent prompt={prompt} resolve={resolve} />
</Modal>
);
}
interface IContentProps {
prompt: Prompt;
resolve: (value: boolean | string) => void;
}
function PromptMenuBoolean({ resolve }: IContentProps): React.ReactElement {
const yes = (): void => resolve(true);
const no = (): void => resolve(false);
return (
<>
{prompt != null && (
<Modal open={true} onClose={close}>
<Typography>{prompt.txt}</Typography>
<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', paddingTop: '10px' }}>
<Button style={{ marginRight: 'auto' }} onClick={yes}>Yes</Button>
<Button onClick={no}>No</Button>
</div>
</Modal>
)}
<div style={{ display: "flex", justifyContent: "center", alignItems: "center", paddingTop: "10px" }}>
<Button style={{ marginRight: "auto" }} onClick={yes}>
Yes
</Button>
<Button onClick={no}>No</Button>
</div>
</>
);
}
function PromptMenuText({ resolve }: IContentProps): React.ReactElement {
const [value, setValue] = useState("");
const submit = (): void => resolve(value);
const onInput = (event: React.ChangeEvent<HTMLInputElement>): void => {
setValue(event.target.value);
};
const onKeyDown = (event: React.KeyboardEvent<HTMLInputElement>): void => {
event.stopPropagation();
if (event.key === KEY.ENTER) {
event.preventDefault();
submit();
}
};
return (
<>
<div style={{ display: "flex", alignItems: "center", paddingTop: "10px" }}>
<TextField
autoFocus
value={value}
onInput={onInput}
onKeyDown={onKeyDown}
style={{ flex: "1 0 auto" }}
InputProps={{
endAdornment: <Button onClick={submit}>Confirm</Button>,
}}
/>
</div>
</>
);
}
function PromptMenuSelect({ prompt, resolve }: IContentProps): React.ReactElement {
const [value, setValue] = useState("");
const submit = (): void => resolve(value);
const onChange = (event: SelectChangeEvent<string>): void => {
setValue(event.target.value);
};
const getItems = (choices: string[]): React.ReactElement[] => {
const content = [];
for (const i of choices) {
// @ts-ignore
content.push(
<MenuItem key={i} value={i}>
{i}
</MenuItem>,
);
}
return content;
};
return (
<>
<div style={{ display: "flex", alignItems: "center", paddingTop: "10px" }}>
<Select onChange={onChange} value={value} style={{ flex: "1 0 auto" }}>
{getItems(prompt?.options?.choices || [])}
</Select>
<Button onClick={submit} disabled={value === ""}>
Confirm
</Button>
</div>
</>
);
}
+28 -15
View File
@@ -9,7 +9,7 @@ import { IErrorData, newIssueUrl } from "../../utils/ErrorHelper";
import { DeleteGameButton } from "./DeleteGameButton";
import { SoftResetButton } from "./SoftResetButton";
import DirectionsRunIcon from '@mui/icons-material/DirectionsRun';
import DirectionsRunIcon from "@mui/icons-material/DirectionsRun";
import GitHubIcon from "@mui/icons-material/GitHub";
export let RecoveryMode = false;
@@ -42,21 +42,27 @@ export function RecoveryRoot({ router, softReset, errorData, resetError }: IProp
}, []);
return (
<Box sx={{ padding: "8px 16px", minHeight: "100vh", maxWidth: '1200px', boxSizing: "border-box",}}>
<Box sx={{ padding: "8px 16px", minHeight: "100vh", maxWidth: "1200px", boxSizing: "border-box" }}>
<Typography variant="h3">RECOVERY MODE ACTIVATED</Typography>
<Typography>
There was an error with your save file and the game went into recovery mode. In this mode saving is disabled
and the game will automatically export your save file (to prevent corruption).
There was an error with your save file and the game went into recovery mode. In this mode saving is disabled and
the game will automatically export your save file (to prevent corruption).
</Typography>
<Typography>At this point it is recommended to alert a developer.</Typography>
<Typography>
<Link href={errorData?.issueUrl ?? newIssueUrl} target="_blank">File an issue on github</Link>
<Link href={errorData?.issueUrl ?? newIssueUrl} target="_blank">
File an issue on github
</Link>
</Typography>
<Typography>
<Link href="https://www.reddit.com/r/Bitburner/" target="_blank">Make a reddit post</Link>
<Link href="https://www.reddit.com/r/Bitburner/" target="_blank">
Make a reddit post
</Link>
</Typography>
<Typography>
<Link href="https://discord.gg/TFc3hKD" target="_blank">Post in the #bug-report channel on Discord.</Link>
<Link href="https://discord.gg/TFc3hKD" target="_blank">
Post in the #bug-report channel on Discord.
</Link>
</Typography>
<Typography>Please include your save file.</Typography>
<br />
@@ -64,17 +70,17 @@ export function RecoveryRoot({ router, softReset, errorData, resetError }: IProp
<Typography>You can disable recovery mode now. But chances are the game will not work correctly.</Typography>
<ButtonGroup sx={{ my: 2 }}>
<Tooltip title="Disables the recovery mode & attempt to head back to the terminal page. This may or may not work. Ensure you have saved the recovery file.">
<Button onClick={recover} startIcon={<DirectionsRunIcon />}>Disable Recovery Mode</Button>
<Button onClick={recover} startIcon={<DirectionsRunIcon />}>
Disable Recovery Mode
</Button>
</Tooltip>
<SoftResetButton color="warning" onTriggered={softReset} />
<DeleteGameButton color="error" />
</ButtonGroup>
{errorData && (
<Paper sx={{ px: 2, pt: 1, pb: 2, mt: 2}}>
<Typography variant="h5">
{errorData.title}
</Typography>
<Paper sx={{ px: 2, pt: 1, pb: 2, mt: 2 }}>
<Typography variant="h5">{errorData.title}</Typography>
<Box sx={{ my: 2 }}>
<TextField
label="Bug Report Text"
@@ -84,11 +90,18 @@ export function RecoveryRoot({ router, softReset, errorData, resetError }: IProp
multiline
fullWidth
rows={12}
sx={{ "& .MuiOutlinedInput-root": { color: Settings.theme.secondary }}} />
sx={{ "& .MuiOutlinedInput-root": { color: Settings.theme.secondary } }}
/>
</Box>
<Tooltip title="Submitting an issue to GitHub really help us improve the game!">
<Button component={Link} startIcon={<GitHubIcon />} color="info" sx={{ px: 2 }}
href={errorData.issueUrl ?? newIssueUrl} target={"_blank"} >
<Button
component={Link}
startIcon={<GitHubIcon />}
color="info"
sx={{ px: 2 }}
href={errorData.issueUrl ?? newIssueUrl}
target={"_blank"}
>
Submit Issue to GitHub
</Button>
</Tooltip>
+1 -1
View File
@@ -1,5 +1,5 @@
import * as React from "react";
import { numeralWrapper } from "../../ui/numeralFormat";
import { numeralWrapper } from "../numeralFormat";
import { Theme } from "@mui/material/styles";
import makeStyles from "@mui/styles/makeStyles";
import createStyles from "@mui/styles/createStyles";
+2 -2
View File
@@ -1,6 +1,6 @@
import React from "react";
import { numeralWrapper } from "../../ui/numeralFormat";
import { Reputation } from "../../ui/React/Reputation";
import { numeralWrapper } from "../numeralFormat";
import { Reputation } from "./Reputation";
export function ReputationRate({ reputation }: { reputation: number }): React.ReactElement {
return <Reputation reputation={`${numeralWrapper.formatReputation(reputation)} / sec`} />;
+13 -6
View File
@@ -16,22 +16,29 @@ const useStyles = makeStyles(() => ({
zIndex: `${logBoxBaseZIndex + 1000} !important` as any,
"& .MuiAlert-icon": {
alignSelf: 'center',
alignSelf: "center",
},
}
},
}));
export function SnackbarProvider(props: IProps): React.ReactElement {
const classes = useStyles();
return (
<SB dense maxSnack={9} anchorOrigin={{ horizontal: "right", vertical: "bottom" }} autoHideDuration={2000}
classes={{ containerRoot: classes.snackbar }}>
<SB
dense
maxSnack={9}
anchorOrigin={{ horizontal: "right", vertical: "bottom" }}
autoHideDuration={2000}
classes={{ containerRoot: classes.snackbar }}
>
{props.children}
</SB>
);
}
export const SnackbarEvents = new EventEmitter<[string | React.ReactNode, "success" | "warning" | "error" | "info", number]>();
export const SnackbarEvents = new EventEmitter<
[string | React.ReactNode, "success" | "warning" | "error" | "info", number]
>();
export function Snackbar(): React.ReactElement {
const { enqueueSnackbar, closeSnackbar } = useSnackbar();
@@ -43,7 +50,7 @@ export function Snackbar(): React.ReactElement {
variant: variant,
autoHideDuration: duration,
onClick: () => closeSnackbar(id),
})
});
}),
);
return <></>;
+23 -15
View File
@@ -1,9 +1,9 @@
import React, { useState } from 'react';
import React, { useState } from "react";
import { ConfirmationModal } from "./ConfirmationModal";
import Button from "@mui/material/Button";
import { Tooltip } from '@mui/material';
import RestartAltIcon from '@mui/icons-material/RestartAlt';
import { Tooltip } from "@mui/material";
import RestartAltIcon from "@mui/icons-material/RestartAlt";
interface IProps {
color?: "primary" | "warning" | "error";
@@ -11,7 +11,11 @@ interface IProps {
onTriggered: () => void;
}
export function SoftResetButton({ color = "primary", noConfirmation = false, onTriggered }: IProps): React.ReactElement {
export function SoftResetButton({
color = "primary",
noConfirmation = false,
onTriggered,
}: IProps): React.ReactElement {
const [modalOpened, setModalOpened] = useState(false);
function handleButtonClick(): void {
@@ -22,15 +26,19 @@ export function SoftResetButton({ color = "primary", noConfirmation = false, onT
}
}
return (<>
<Tooltip title="Perform a soft reset. Resets everything as if you had just purchased an Augmentation.">
<Button startIcon={<RestartAltIcon />} color={color} onClick={handleButtonClick}>Soft Reset</Button>
</Tooltip>
<ConfirmationModal
onConfirm={onTriggered}
open={modalOpened}
onClose={() => setModalOpened(false)}
confirmationText={"This will perform the same action as installing Augmentations, are you sure?"}
/>
</>)
return (
<>
<Tooltip title="Perform a soft reset. Resets everything as if you had just purchased an Augmentation.">
<Button startIcon={<RestartAltIcon />} color={color} onClick={handleButtonClick}>
Soft Reset
</Button>
</Tooltip>
<ConfirmationModal
onConfirm={onTriggered}
open={modalOpened}
onClose={() => setModalOpened(false)}
confirmationText={"This will perform the same action as installing Augmentations, are you sure?"}
/>
</>
);
}
+9 -2
View File
@@ -19,9 +19,16 @@ interface IStatsOverviewCellProps {
color?: React.CSSProperties["color"];
}
export function StatsProgressBar({ min, max, current, remaining, progress, color }: IProgressProps): React.ReactElement {
export function StatsProgressBar({
min,
max,
current,
remaining,
progress,
color,
}: IProgressProps): React.ReactElement {
const tooltip = (
<Typography sx={{ textAlign: 'right' }}>
<Typography sx={{ textAlign: "right" }}>
<strong>Progress:</strong>&nbsp;
{numeralWrapper.formatExp(current)} / {numeralWrapper.formatExp(max - min)}
<br />
+45
View File
@@ -0,0 +1,45 @@
import React from "react";
import { Typography, TableCell, TableRow } from "@mui/material";
import { numeralWrapper } from "../numeralFormat";
import { formatNumber } from "../../utils/StringHelperFunctions";
import { characterOverviewStyles as useStyles } from "./CharacterOverview";
interface ITableRowData {
content?: string;
level?: number;
exp?: number;
}
interface IProps {
name: string;
color: string;
classes?: any;
data: ITableRowData;
children?: React.ReactElement;
}
export const StatsRow = ({ name, color, classes = useStyles(), children, data }: IProps): React.ReactElement => {
let content;
if (data.content !== undefined) {
content = data.content;
} else if (data.level !== undefined && data.exp !== undefined) {
content = `${formatNumber(data.level, 0)} (${numeralWrapper.formatExp(data.exp)} exp)`;
} else if (data.level !== undefined && data.exp === undefined) {
content = `${formatNumber(data.level, 0)}`;
}
return (
<TableRow>
<TableCell classes={{ root: classes.cellNone }}>
<Typography style={{ color: color }}>{name}</Typography>
</TableCell>
<TableCell align="right" classes={{ root: classes.cellNone }}>
{content ? <Typography style={{ color: color }}>{content}</Typography> : <></>}
{children}
</TableCell>
</TableRow>
);
};
+8 -11
View File
@@ -14,13 +14,13 @@ interface ICityProps {
const useStyles = makeStyles((theme: Theme) =>
createStyles({
travel: {
color: theme.colors.white,
lineHeight: "1em",
whiteSpace: "pre",
cursor: "pointer"
},
})
travel: {
color: theme.colors.white,
lineHeight: "1em",
whiteSpace: "pre",
cursor: "pointer",
},
}),
);
function City(props: ICityProps): React.ReactElement {
@@ -28,10 +28,7 @@ function City(props: ICityProps): React.ReactElement {
if (props.city !== props.currentCity) {
return (
<Tooltip title={<Typography>{props.city}</Typography>}>
<span
onClick={() => props.onTravel(props.city)}
className={classes.travel}
>
<span onClick={() => props.onTravel(props.city)} className={classes.travel}>
{props.city[0]}
</span>
</Tooltip>