mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2026-04-16 06:18:42 +02:00
BUGFIX: Multiple problems with Job tab (#1976)
This commit is contained in:
@@ -30,64 +30,83 @@ import { Page } from "../../ui/Router";
|
||||
import { serverMetadata } from "../../Server/data/servers";
|
||||
import { Tooltip } from "@mui/material";
|
||||
import { getEnumHelper } from "../../utils/EnumHelper";
|
||||
import { exceptionAlert } from "../../utils/helpers/exceptionAlert";
|
||||
|
||||
interface IProps {
|
||||
loc: Location;
|
||||
location: Location;
|
||||
showBackButton: boolean;
|
||||
}
|
||||
|
||||
export function GenericLocation({ loc, showBackButton }: IProps): React.ReactElement {
|
||||
/**
|
||||
* Determine what needs to be rendered for this location based on the locations
|
||||
* type. Returns an array of React components that should be rendered
|
||||
*/
|
||||
function getLocationSpecificContent(): React.ReactNode[] {
|
||||
const content: React.ReactNode[] = [];
|
||||
/**
|
||||
* Determine what needs to be rendered for this location based on the locations
|
||||
* type. Returns an array of React components that should be rendered
|
||||
*/
|
||||
function getLocationSpecificContent(location: Location): React.ReactNode[] {
|
||||
const content: React.ReactNode[] = [];
|
||||
|
||||
if (loc.types.includes(LocationType.Company)) {
|
||||
if (!getEnumHelper("CompanyName").isMember(loc.name)) {
|
||||
throw new Error(`Location name ${loc.name} is for a company but is not a company name.`);
|
||||
}
|
||||
content.push(<CompanyLocation key="CompanyLocation" companyName={loc.name} />);
|
||||
if (location.types.includes(LocationType.Company)) {
|
||||
if (!getEnumHelper("CompanyName").isMember(location.name)) {
|
||||
throw new Error(`Location name ${location.name} is for a company but is not a company name.`);
|
||||
}
|
||||
|
||||
if (loc.types.includes(LocationType.Gym)) {
|
||||
content.push(<GymLocation key="GymLocation" loc={loc} />);
|
||||
}
|
||||
|
||||
if (loc.types.includes(LocationType.Hospital)) {
|
||||
content.push(<HospitalLocation key="HospitalLocation" />);
|
||||
}
|
||||
|
||||
if (loc.types.includes(LocationType.Slums)) {
|
||||
content.push(<SlumsLocation key="SlumsLocation" />);
|
||||
}
|
||||
|
||||
if (loc.types.includes(LocationType.Special)) {
|
||||
content.push(<SpecialLocation key="SpecialLocation" loc={loc} />);
|
||||
}
|
||||
|
||||
if (loc.types.includes(LocationType.TechVendor)) {
|
||||
content.push(<TechVendorLocation key="TechVendorLocation" loc={loc} />);
|
||||
}
|
||||
|
||||
if (loc.types.includes(LocationType.TravelAgency)) {
|
||||
content.push(<TravelAgencyRoot key="TravelAgencyRoot" />);
|
||||
}
|
||||
|
||||
if (loc.types.includes(LocationType.University)) {
|
||||
content.push(<UniversityLocation key="UniversityLocation" loc={loc} />);
|
||||
}
|
||||
|
||||
if (loc.types.includes(LocationType.Casino)) {
|
||||
content.push(<CasinoLocation key="CasinoLocation" />);
|
||||
}
|
||||
|
||||
return content;
|
||||
content.push(<CompanyLocation key="CompanyLocation" companyName={location.name} />);
|
||||
}
|
||||
|
||||
const locContent: React.ReactNode[] = getLocationSpecificContent();
|
||||
const serverMeta = serverMetadata.find((s) => s.specialName === loc.name);
|
||||
if (location.types.includes(LocationType.Gym)) {
|
||||
content.push(<GymLocation key="GymLocation" loc={location} />);
|
||||
}
|
||||
|
||||
if (location.types.includes(LocationType.Hospital)) {
|
||||
content.push(<HospitalLocation key="HospitalLocation" />);
|
||||
}
|
||||
|
||||
if (location.types.includes(LocationType.Slums)) {
|
||||
content.push(<SlumsLocation key="SlumsLocation" />);
|
||||
}
|
||||
|
||||
if (location.types.includes(LocationType.Special)) {
|
||||
content.push(<SpecialLocation key="SpecialLocation" loc={location} />);
|
||||
}
|
||||
|
||||
if (location.types.includes(LocationType.TechVendor)) {
|
||||
content.push(<TechVendorLocation key="TechVendorLocation" loc={location} />);
|
||||
}
|
||||
|
||||
if (location.types.includes(LocationType.TravelAgency)) {
|
||||
content.push(<TravelAgencyRoot key="TravelAgencyRoot" />);
|
||||
}
|
||||
|
||||
if (location.types.includes(LocationType.University)) {
|
||||
content.push(<UniversityLocation key="UniversityLocation" loc={location} />);
|
||||
}
|
||||
|
||||
if (location.types.includes(LocationType.Casino)) {
|
||||
content.push(<CasinoLocation key="CasinoLocation" />);
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
export function GenericLocation({ location, showBackButton }: IProps): React.ReactElement {
|
||||
/**
|
||||
* location can be undefined if GenericLocation is used like this:
|
||||
*
|
||||
* <GenericLocation location={Locations["unknown"]} showBackButton={true} />
|
||||
*
|
||||
* We need to check it before using.
|
||||
*/
|
||||
if (location == null) {
|
||||
exceptionAlert(new Error(`GenericLocation is used with invalid location.`), true);
|
||||
/**
|
||||
* Return to the Terminal tab. We put the call of Router.toPage() inside setTimeout to avoid updating GameRoot while
|
||||
* rendering this component.
|
||||
*/
|
||||
setTimeout(() => {
|
||||
Router.toPage(Page.Terminal);
|
||||
}, 100);
|
||||
return <></>;
|
||||
}
|
||||
const locationContent: React.ReactNode[] = getLocationSpecificContent(location);
|
||||
const serverMeta = serverMetadata.find((s) => s.specialName === location.name);
|
||||
const server = GetServer(serverMeta ? serverMeta.hostname : "");
|
||||
|
||||
const backdoorInstalled = server !== null && isBackdoorInstalled(server);
|
||||
@@ -99,14 +118,14 @@ export function GenericLocation({ loc, showBackButton }: IProps): React.ReactEle
|
||||
{backdoorInstalled && serverMeta ? (
|
||||
<Tooltip title={`Backdoor installed on ${serverMeta.hostname}.`}>
|
||||
<span>
|
||||
<CorruptableText content={loc.name} spoiler={false} />
|
||||
<CorruptableText content={location.name} spoiler={false} />
|
||||
</span>
|
||||
</Tooltip>
|
||||
) : (
|
||||
loc.name
|
||||
location.name
|
||||
)}
|
||||
</Typography>
|
||||
{locContent}
|
||||
{locationContent}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import React from "react";
|
||||
import { Box } from "@mui/material";
|
||||
import { Box, Typography } from "@mui/material";
|
||||
|
||||
import { Player } from "@player";
|
||||
import { getRecordKeys } from "../../Types/Record";
|
||||
import { useCycleRerender } from "../../ui/React/hooks";
|
||||
import { Locations } from "../Locations";
|
||||
import { GenericLocation } from "./GenericLocation";
|
||||
import { exceptionAlert } from "../../utils/helpers/exceptionAlert";
|
||||
|
||||
export function JobRoot(): React.ReactElement {
|
||||
useCycleRerender();
|
||||
@@ -13,14 +14,23 @@ export function JobRoot(): React.ReactElement {
|
||||
const jobs = getRecordKeys(Player.jobs).map((companyName) => {
|
||||
const location = Locations[companyName];
|
||||
if (location == null) {
|
||||
throw new Error(`Invalid company name: ${companyName}`);
|
||||
exceptionAlert(new Error(`Player.jobs contains invalid data. companyName: ${companyName}.`), true);
|
||||
return <></>;
|
||||
}
|
||||
return (
|
||||
<Box key={companyName} sx={{ marginBottom: "20px" }}>
|
||||
<GenericLocation loc={location} showBackButton={false} />;
|
||||
<GenericLocation location={location} showBackButton={false} />;
|
||||
</Box>
|
||||
);
|
||||
});
|
||||
|
||||
if (jobs.length === 0) {
|
||||
return (
|
||||
<Typography sx={{ height: "100%", display: "flex", justifyContent: "center", alignItems: "center" }}>
|
||||
No jobs
|
||||
</Typography>
|
||||
);
|
||||
}
|
||||
|
||||
return <Box sx={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, 28em)" }}>{jobs}</Box>;
|
||||
}
|
||||
|
||||
@@ -54,7 +54,6 @@ import { AugmentationName, CityName } from "@enums";
|
||||
import { ProgramsSeen } from "../../Programs/ui/ProgramsRoot";
|
||||
import { InvitationsSeen } from "../../Faction/ui/FactionsRoot";
|
||||
import { commitHash } from "../../utils/helpers/commitHash";
|
||||
import { Locations } from "../../Locations/Locations";
|
||||
import { useCycleRerender } from "../../ui/React/hooks";
|
||||
import { playerHasDiscoveredGo } from "../../Go/effects/effect";
|
||||
import { knowAboutBitverse } from "../../BitNode/BitNodeUtils";
|
||||
@@ -176,9 +175,7 @@ export function SidebarRoot(props: { page: Page }): React.ReactElement {
|
||||
|
||||
const clickPage = useCallback(
|
||||
(page: Page) => {
|
||||
if (page === Page.Job) {
|
||||
Router.toPage(page, { location: Locations[Object.keys(Player.jobs)[0]] });
|
||||
} else if (page == Page.ScriptEditor || page == Page.Documentation) {
|
||||
if (page == Page.ScriptEditor || page == Page.Documentation) {
|
||||
Router.toPage(page, {});
|
||||
} else if (isSimplePage(page)) {
|
||||
Router.toPage(page);
|
||||
@@ -221,7 +218,7 @@ export function SidebarRoot(props: { page: Page }): React.ReactElement {
|
||||
return canOpenSleeves;
|
||||
case SimplePage.Grafting:
|
||||
return canOpenGrafting;
|
||||
case ComplexPage.Job:
|
||||
case SimplePage.Job:
|
||||
return canJob;
|
||||
case SimplePage.StockMarket:
|
||||
return canStockMarket;
|
||||
|
||||
@@ -31,6 +31,7 @@ export enum SimplePage {
|
||||
StockMarket = "Stock Market",
|
||||
Terminal = "Terminal",
|
||||
Travel = "Travel",
|
||||
Job = "Job",
|
||||
Work = "Work",
|
||||
BladeburnerCinematic = "Bladeburner Cinematic",
|
||||
Loading = "Loading",
|
||||
@@ -43,7 +44,6 @@ export enum SimplePage {
|
||||
export enum ComplexPage {
|
||||
BitVerse = "BitVerse",
|
||||
Infiltration = "Infiltration",
|
||||
Job = "Job",
|
||||
Faction = "Faction",
|
||||
FactionAugmentations = "Faction Augmentations",
|
||||
ScriptEditor = "Script Editor",
|
||||
|
||||
@@ -337,7 +337,7 @@ export function GameRoot(): React.ReactElement {
|
||||
mainPage = <JobRoot />;
|
||||
break;
|
||||
case Page.Location: {
|
||||
mainPage = <GenericLocation loc={pageWithContext.location} showBackButton={true} />;
|
||||
mainPage = <GenericLocation location={pageWithContext.location} showBackButton={true} />;
|
||||
break;
|
||||
}
|
||||
case Page.Options: {
|
||||
|
||||
@@ -14,8 +14,6 @@ export type PageContext<T extends Page> = T extends ComplexPage.BitVerse
|
||||
? { flume: boolean; quick: boolean }
|
||||
: T extends ComplexPage.Infiltration
|
||||
? { location: Location }
|
||||
: T extends ComplexPage.Job
|
||||
? { location: Location }
|
||||
: T extends ComplexPage.Faction
|
||||
? { faction: Faction }
|
||||
: T extends ComplexPage.FactionAugmentations
|
||||
@@ -33,7 +31,6 @@ export type PageContext<T extends Page> = T extends ComplexPage.BitVerse
|
||||
export type PageWithContext =
|
||||
| ({ page: ComplexPage.BitVerse } & PageContext<ComplexPage.BitVerse>)
|
||||
| ({ page: ComplexPage.Infiltration } & PageContext<ComplexPage.Infiltration>)
|
||||
| ({ page: ComplexPage.Job } & PageContext<ComplexPage.Job>)
|
||||
| ({ page: ComplexPage.Faction } & PageContext<ComplexPage.Faction>)
|
||||
| ({ page: ComplexPage.FactionAugmentations } & PageContext<ComplexPage.FactionAugmentations>)
|
||||
| ({ page: ComplexPage.ScriptEditor } & PageContext<ComplexPage.ScriptEditor>)
|
||||
|
||||
@@ -428,11 +428,11 @@ export function WorkInProgressRoot(): React.ReactElement {
|
||||
buttons: {
|
||||
cancel: () => {
|
||||
Player.finishWork(true);
|
||||
Router.toPage(Page.Job, { location: Locations[comp.name] });
|
||||
Router.toPage(Page.Job);
|
||||
},
|
||||
unfocus: () => {
|
||||
Player.stopFocusing();
|
||||
Router.toPage(Page.Job, { location: Locations[comp.name] });
|
||||
Router.toPage(Page.Job);
|
||||
},
|
||||
},
|
||||
title: (
|
||||
|
||||
@@ -28,7 +28,7 @@ export const GoToPageKeyBindingTypes = [
|
||||
SimplePage.Hacknet,
|
||||
SimplePage.City,
|
||||
SimplePage.Travel,
|
||||
ComplexPage.Job,
|
||||
SimplePage.Job,
|
||||
SimplePage.StockMarket,
|
||||
SimplePage.Go,
|
||||
SimplePage.Milestones,
|
||||
@@ -165,7 +165,7 @@ export const DefaultKeyBindings: Record<KeyBindingType, [KeyCombination | null,
|
||||
},
|
||||
null,
|
||||
],
|
||||
[ComplexPage.Job]: [
|
||||
[SimplePage.Job]: [
|
||||
{
|
||||
control: false,
|
||||
alt: true,
|
||||
|
||||
Reference in New Issue
Block a user