From 91b68db1fe6b4d24b7b402b65cc2e68cddd79ec2 Mon Sep 17 00:00:00 2001
From: catloversg <152669316+catloversg@users.noreply.github.com>
Date: Sat, 1 Mar 2025 03:52:08 +0700
Subject: [PATCH] BUGFIX: Multiple problems with Job tab (#1976)
---
src/Locations/ui/GenericLocation.tsx | 123 ++++++++++++++++-----------
src/Locations/ui/JobRoot.tsx | 16 +++-
src/Sidebar/ui/SidebarRoot.tsx | 7 +-
src/ui/Enums.ts | 2 +-
src/ui/GameRoot.tsx | 2 +-
src/ui/Router.ts | 3 -
src/ui/WorkInProgressRoot.tsx | 4 +-
src/utils/KeyBindingUtils.ts | 4 +-
8 files changed, 92 insertions(+), 69 deletions(-)
diff --git a/src/Locations/ui/GenericLocation.tsx b/src/Locations/ui/GenericLocation.tsx
index 2740188ea..46b8d44d3 100644
--- a/src/Locations/ui/GenericLocation.tsx
+++ b/src/Locations/ui/GenericLocation.tsx
@@ -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();
+ 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();
- }
-
- if (loc.types.includes(LocationType.Hospital)) {
- content.push();
- }
-
- if (loc.types.includes(LocationType.Slums)) {
- content.push();
- }
-
- if (loc.types.includes(LocationType.Special)) {
- content.push();
- }
-
- if (loc.types.includes(LocationType.TechVendor)) {
- content.push();
- }
-
- if (loc.types.includes(LocationType.TravelAgency)) {
- content.push();
- }
-
- if (loc.types.includes(LocationType.University)) {
- content.push();
- }
-
- if (loc.types.includes(LocationType.Casino)) {
- content.push();
- }
-
- return content;
+ content.push();
}
- const locContent: React.ReactNode[] = getLocationSpecificContent();
- const serverMeta = serverMetadata.find((s) => s.specialName === loc.name);
+ if (location.types.includes(LocationType.Gym)) {
+ content.push();
+ }
+
+ if (location.types.includes(LocationType.Hospital)) {
+ content.push();
+ }
+
+ if (location.types.includes(LocationType.Slums)) {
+ content.push();
+ }
+
+ if (location.types.includes(LocationType.Special)) {
+ content.push();
+ }
+
+ if (location.types.includes(LocationType.TechVendor)) {
+ content.push();
+ }
+
+ if (location.types.includes(LocationType.TravelAgency)) {
+ content.push();
+ }
+
+ if (location.types.includes(LocationType.University)) {
+ content.push();
+ }
+
+ if (location.types.includes(LocationType.Casino)) {
+ content.push();
+ }
+
+ return content;
+}
+
+export function GenericLocation({ location, showBackButton }: IProps): React.ReactElement {
+ /**
+ * location can be undefined if GenericLocation is used like this:
+ *
+ *
+ *
+ * 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 ? (
-
+
) : (
- loc.name
+ location.name
)}
- {locContent}
+ {locationContent}
>
);
}
diff --git a/src/Locations/ui/JobRoot.tsx b/src/Locations/ui/JobRoot.tsx
index fecfd2e27..9161a0770 100644
--- a/src/Locations/ui/JobRoot.tsx
+++ b/src/Locations/ui/JobRoot.tsx
@@ -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 (
- ;
+ ;
);
});
+ if (jobs.length === 0) {
+ return (
+
+ No jobs
+
+ );
+ }
+
return {jobs};
}
diff --git a/src/Sidebar/ui/SidebarRoot.tsx b/src/Sidebar/ui/SidebarRoot.tsx
index 50a12a49e..0fa7c766a 100644
--- a/src/Sidebar/ui/SidebarRoot.tsx
+++ b/src/Sidebar/ui/SidebarRoot.tsx
@@ -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;
diff --git a/src/ui/Enums.ts b/src/ui/Enums.ts
index 25fb9630f..c3f510b75 100644
--- a/src/ui/Enums.ts
+++ b/src/ui/Enums.ts
@@ -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",
diff --git a/src/ui/GameRoot.tsx b/src/ui/GameRoot.tsx
index 4cb920d32..74ac4927c 100644
--- a/src/ui/GameRoot.tsx
+++ b/src/ui/GameRoot.tsx
@@ -337,7 +337,7 @@ export function GameRoot(): React.ReactElement {
mainPage = ;
break;
case Page.Location: {
- mainPage = ;
+ mainPage = ;
break;
}
case Page.Options: {
diff --git a/src/ui/Router.ts b/src/ui/Router.ts
index 89ed12f68..2cf895f97 100644
--- a/src/ui/Router.ts
+++ b/src/ui/Router.ts
@@ -14,8 +14,6 @@ export type PageContext = 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 ComplexPage.BitVerse
export type PageWithContext =
| ({ page: ComplexPage.BitVerse } & PageContext)
| ({ page: ComplexPage.Infiltration } & PageContext)
- | ({ page: ComplexPage.Job } & PageContext)
| ({ page: ComplexPage.Faction } & PageContext)
| ({ page: ComplexPage.FactionAugmentations } & PageContext)
| ({ page: ComplexPage.ScriptEditor } & PageContext)
diff --git a/src/ui/WorkInProgressRoot.tsx b/src/ui/WorkInProgressRoot.tsx
index cfa7db910..e16f6a250 100644
--- a/src/ui/WorkInProgressRoot.tsx
+++ b/src/ui/WorkInProgressRoot.tsx
@@ -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: (
diff --git a/src/utils/KeyBindingUtils.ts b/src/utils/KeyBindingUtils.ts
index 750f24d56..4044be4bb 100644
--- a/src/utils/KeyBindingUtils.ts
+++ b/src/utils/KeyBindingUtils.ts
@@ -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