Skip to content

Commit

Permalink
refactor: reworked all providers, so they are more well defined in th…
Browse files Browse the repository at this point in the history
…eir actions

This basically touches every file in this repository; so while at it, also
reworked how the storybooks work (you can now select different fits to test
with), and did a bunch of cleanup where I saw it.

There should be no functional difference, just mostly providers (and hooks)
that are named differently.
  • Loading branch information
TrueBrain committed May 20, 2024
1 parent 6627e68 commit 15c52ad
Show file tree
Hide file tree
Showing 113 changed files with 3,093 additions and 2,605 deletions.
2 changes: 1 addition & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ module.exports = {
{
// The files listed below are part of the build process, so they will be using packages that are listed
// under devDependences and/or peerDependencies, so we need to be lenient with the import/no-extraneous-dependencies
files: [".storybook/**/*.ts", ".eslintrc.js", "rollup.config.mjs"],
files: [".storybook/**/*.ts", ".storybook/**/*.tsx", ".eslintrc.js", "rollup.config.mjs", "**/*.stories.tsx"],
rules: {
"import/no-extraneous-dependencies": ["error", { peerDependencies: true, devDependencies: true }],
},
Expand Down
26 changes: 21 additions & 5 deletions .storybook/fits.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
export const eftFit = `[Loki,Loki basic PVE]
import { EsfFit } from "@/providers";
import { InputType } from "@storybook/types";

export const eftFits = {
Loki: `[Loki,Loki basic PVE]
Caldari Navy Ballistic Control System
Caldari Navy Ballistic Control System
Caldari Navy Ballistic Control System
Expand Down Expand Up @@ -28,12 +32,15 @@ Loki Offensive - Launcher Efficiency Configuration
Loki Propulsion - Wake Limiter
Hammerhead II x1
`;
`,
};

export const hashFit =
"fit:v2:H4sIAAAAAAAACmWQMZJDMQhD+38WChBgwx32Ijtb5P5d4ONkdpLOTwhbFjKT6efx90uXk+pmJqE+I9YKEueblC0WyXpDvABrZy2OTTR8UTIPwtp4UIQApNz3C/5DkiRYbwA3RA70TowLINl+8qHMJoYBIxPgTLwnHAOb4FtKOlkuxJeSn0p95lORLwVVQ+i6n9FKI77nTbXqbntPpqgrKoWVEDXN2pNtY01tWBM8rcAjTj9OtaJ6aBV5+qHdM345owlT0hPutE6T0AEAAA==";
export const hashFits = {
Loki: "fit:v2:H4sIAAAAAAAACmWQMZJDMQhD+38WChBgwx32Ijtb5P5d4ONkdpLOTwhbFjKT6efx90uXk+pmJqE+I9YKEueblC0WyXpDvABrZy2OTTR8UTIPwtp4UIQApNz3C/5DkiRYbwA3RA70TowLINl+8qHMJoYBIxPgTLwnHAOb4FtKOlkuxJeSn0p95lORLwVVQ+i6n9FKI77nTbXqbntPpqgrKoWVEDXN2pNtY01tWBM8rcAjTj9OtaJ6aBV5+qHdM345owlT0hPutE6T0AEAAA==",
};

export const fullFits = [
null,
{
name: "Tengu",
ship_type_id: 29984,
Expand Down Expand Up @@ -148,8 +155,8 @@ export const fullFits = [
],
},
{
ship_type_id: 35833,
name: "Killmail 117621358",
ship_type_id: 35833,
description: "",
items: [
{ flag: 5, type_id: 37821, quantity: 6 },
Expand Down Expand Up @@ -195,3 +202,12 @@ export const fullFits = [
];

export const fullFit = fullFits[2];

export const fitArgType: InputType = {
control: "select",
options: fullFits.map((fit: EsfFit | null) => fit?.name ?? "(empty)"),
mapping: fullFits.reduce((acc: Record<string, EsfFit | null>, fit: EsfFit | null) => {
acc[fit?.name ?? "(empty)"] = fit;
return acc;
}, {}),
};
44 changes: 44 additions & 0 deletions .storybook/helpers.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import React from "react";
import { StoryFn } from "@storybook/react";

import { ModalDialogAnchor } from "@/components/ModalDialog";
import { EveDataProvider } from "@/providers/EveDataProvider";
import { DogmaEngineProvider } from "@/providers/DogmaEngineProvider";
import { CurrentFitProvider, EsfFit, useCurrentFit } from "@/providers/CurrentFitProvider";
import { LocalFitsProvider } from "@/providers/LocalFitsProvider";
import { DefaultCharactersProvider, EsiCharactersProvider } from "@/providers/Characters";
import { CurrentCharacterProvider } from "@/providers/CurrentCharacterProvider";
import { StatisticsProvider } from "@/providers/StatisticsProvider";
import { FitManagerProvider } from "@/providers/FitManagerProvider";

export const withDecoratorFull = (Story: StoryFn) => (
<EveDataProvider>
<DogmaEngineProvider>
<CurrentFitProvider>
<LocalFitsProvider>
<DefaultCharactersProvider>
<EsiCharactersProvider>
<CurrentCharacterProvider>
<StatisticsProvider>
<FitManagerProvider>
<ModalDialogAnchor />
<Story />
</FitManagerProvider>
</StatisticsProvider>
</CurrentCharacterProvider>
</EsiCharactersProvider>
</DefaultCharactersProvider>
</LocalFitsProvider>
</CurrentFitProvider>
</DogmaEngineProvider>
</EveDataProvider>
);

export const useFitSelection = (fit: EsfFit | null) => {
const currentFit = useCurrentFit();
const setFit = currentFit.setFit;

React.useEffect(() => {
setFit(fit);
}, [setFit, fit]);
};
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,11 @@
"@storybook/addon-links": "^8",
"@storybook/addon-webpack5-compiler-babel": "^3",
"@storybook/blocks": "^8",
"@storybook/preview-api": "^8",
"@storybook/react": "^8",
"@storybook/react-webpack5": "^8",
"@storybook/test": "^8",
"@storybook/types": "^8",
"@types/react": "^18",
"@types/react-dom": "^18",
"@typescript-eslint/eslint-plugin": "^7",
Expand Down
48 changes: 18 additions & 30 deletions src/components/CalculationDetail/CalculationDetail.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,47 +1,35 @@
import type { Decorator, Meta, StoryObj } from "@storybook/react";
import type { Meta, StoryObj } from "@storybook/react";
import React from "react";

import { fullFit } from "../../../.storybook/fits";
import { fitArgType } from "../../../.storybook/fits";
import { useFitSelection, withDecoratorFull } from "../../../.storybook/helpers";

import { EsfFit } from "@/providers/CurrentFitProvider";

import { DogmaEngineProvider } from "@/providers/DogmaEngineProvider";
import { EsiProvider } from "@/providers/EsiProvider";
import { EveDataProvider } from "@/providers/EveDataProvider";
import { ShipSnapshotProvider } from "@/providers/ShipSnapshotProvider";
import { CalculationDetail } from "./";

const meta: Meta<typeof CalculationDetail> = {
type StoryProps = React.ComponentProps<typeof CalculationDetail> & { fit: EsfFit | null };

const meta: Meta<StoryProps> = {
component: CalculationDetail,
tags: ["autodocs"],
title: "Component/CalculationDetail",
};

export default meta;
type Story = StoryObj<typeof CalculationDetail>;

const useShipSnapshotProvider: Decorator<{
source: "Ship" | "Char" | "Structure" | "Target" | { Item?: number; Cargo?: number };
}> = (Story, context) => {
return (
<EveDataProvider>
<DogmaEngineProvider>
<ShipSnapshotProvider {...context.parameters.snapshot}>
<EsiProvider>
<Story {...context.args} />
</EsiProvider>
</ShipSnapshotProvider>
</DogmaEngineProvider>
</EveDataProvider>
);
};
type Story = StoryObj<StoryProps>;

export const Default: Story = {
argTypes: {
fit: fitArgType,
},
args: {
fit: null,
source: "Ship",
},
decorators: [useShipSnapshotProvider],
parameters: {
snapshot: {
initialFit: fullFit,
},
decorators: [withDecoratorFull],
render: ({ fit, ...args }) => {
useFitSelection(fit);

return <CalculationDetail {...args} />;
},
};
57 changes: 29 additions & 28 deletions src/components/CalculationDetail/CalculationDetail.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
import clsx from "clsx";
import React from "react";

import { EveDataContext } from "@/providers/EveDataProvider";
import {
ShipSnapshotContext,
ShipSnapshotItemAttribute,
ShipSnapshotItemAttributeEffect,
} from "@/providers/ShipSnapshotProvider";
import { Icon } from "@/components/Icon";
import { useEveData } from "@/providers/EveDataProvider";
import { StatisticsItemAttribute, StatisticsItemAttributeEffect, useStatistics } from "@/providers/StatisticsProvider";

import styles from "./CalculationDetail.module.css";

Expand Down Expand Up @@ -46,11 +42,13 @@ function stateToInteger(state: string): number {
}
}

const Effect = (props: { effect: ShipSnapshotItemAttributeEffect }) => {
const eveData = React.useContext(EveDataContext);
const shipSnapshot = React.useContext(ShipSnapshotContext);
const Effect = (props: { effect: StatisticsItemAttributeEffect }) => {
const eveData = useEveData();
const statistics = useStatistics();

const eveAttribute = eveData.dogmaAttributes?.[props.effect.source_attribute_id];
if (eveData === null || statistics === null) return <></>;

const eveAttribute = eveData.dogmaAttributes[props.effect.source_attribute_id];

let sourceName = "Unknown";
let attribute = undefined;
Expand All @@ -59,22 +57,22 @@ const Effect = (props: { effect: ShipSnapshotItemAttributeEffect }) => {
switch (props.effect.source) {
case "Ship":
sourceName = "Ship";
attribute = shipSnapshot.hull?.attributes.get(props.effect.source_attribute_id);
attribute = statistics.hull.attributes.get(props.effect.source_attribute_id);
break;

case "Char":
sourceName = "Character";
attribute = shipSnapshot.char?.attributes.get(props.effect.source_attribute_id);
attribute = statistics.char.attributes.get(props.effect.source_attribute_id);
break;

case "Structure":
sourceName = "Structure";
attribute = shipSnapshot.structure?.attributes.get(props.effect.source_attribute_id);
attribute = statistics.structure.attributes.get(props.effect.source_attribute_id);
break;

case "Target":
sourceName = "Target";
attribute = shipSnapshot.target?.attributes.get(props.effect.source_attribute_id);
attribute = statistics.target.attributes.get(props.effect.source_attribute_id);
break;

default:
Expand All @@ -83,13 +81,13 @@ const Effect = (props: { effect: ShipSnapshotItemAttributeEffect }) => {

/* Lookup the source of the effect. */
if (props.effect.source.Item !== undefined) {
item = shipSnapshot.items?.[props.effect.source.Item];
item = statistics.items[props.effect.source.Item];
sourceType = "Item";
} else if (props.effect.source.Skill !== undefined) {
item = shipSnapshot.skills?.[props.effect.source.Skill];
item = statistics.skills[props.effect.source.Skill];
sourceType = "Skill";
} else if (props.effect.source.Charge !== undefined) {
item = shipSnapshot.items?.[props.effect.source.Charge].charge;
item = statistics.items[props.effect.source.Charge].charge;
sourceType = "Charge";
}

Expand Down Expand Up @@ -125,11 +123,13 @@ const Effect = (props: { effect: ShipSnapshotItemAttributeEffect }) => {
);
};

const CalculationDetailMeta = (props: { attributeId: number; attribute: ShipSnapshotItemAttribute }) => {
const CalculationDetailMeta = (props: { attributeId: number; attribute: StatisticsItemAttribute }) => {
const [expanded, setExpanded] = React.useState(false);
const eveData = React.useContext(EveDataContext);
const eveData = useEveData();

if (eveData === null) return <></>;

const eveAttribute = eveData.dogmaAttributes?.[props.attributeId];
const eveAttribute = eveData.dogmaAttributes[props.attributeId];
const sortedEffects = Object.values(props.attribute.effects).sort((a, b) => {
const aIndex = Object.keys(EffectOperatorOrder).indexOf(a.operator);
const bIndex = Object.keys(EffectOperatorOrder).indexOf(b.operator);
Expand Down Expand Up @@ -172,25 +172,26 @@ const CalculationDetailMeta = (props: { attributeId: number; attribute: ShipSnap
export const CalculationDetail = (props: {
source: "Ship" | "Char" | "Structure" | "Target" | { Item?: number; Charge?: number };
}) => {
const shipSnapshot = React.useContext(ShipSnapshotContext);
const statistics = useStatistics();
if (statistics === null) return <></>;

let attributes: [number, ShipSnapshotItemAttribute][] = [];
let attributes: [number, StatisticsItemAttribute][] = [];

if (props.source === "Ship") {
attributes = [...(shipSnapshot.hull?.attributes.entries() || [])];
attributes = [...(statistics.hull.attributes.entries() ?? [])];
} else if (props.source === "Char") {
attributes = [...(shipSnapshot.char?.attributes.entries() || [])];
attributes = [...(statistics.char.attributes.entries() ?? [])];
} else if (props.source === "Structure") {
attributes = [...(shipSnapshot.structure?.attributes.entries() || [])];
attributes = [...(statistics.structure.attributes.entries() ?? [])];
} else if (props.source === "Target") {
attributes = [...(shipSnapshot.target?.attributes.entries() || [])];
attributes = [...(statistics.target.attributes.entries() ?? [])];
} else if (props.source.Item !== undefined) {
const item = shipSnapshot.items?.[props.source.Item];
const item = statistics.items[props.source.Item];
if (item !== undefined) {
attributes = [...item.attributes.entries()];
}
} else if (props.source.Charge !== undefined) {
const item = shipSnapshot.items?.[props.source.Charge].charge;
const item = statistics.items[props.source.Charge].charge;
if (item !== undefined) {
attributes = [...item.attributes.entries()];
}
Expand Down
30 changes: 30 additions & 0 deletions src/components/CharacterSelection/CharacterSelection.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import type { Meta, StoryObj } from "@storybook/react";
import React from "react";

import { EveDataProvider } from "@/providers/EveDataProvider";
import { DefaultCharactersProvider, EsiCharactersProvider } from "@/providers/Characters";
import { CurrentCharacterProvider } from "@/providers/CurrentCharacterProvider";

import { CharacterSelection } from "./";

const meta: Meta<typeof CharacterSelection> = {
component: CharacterSelection,
tags: ["autodocs"],
};

export default meta;
type Story = StoryObj<typeof CharacterSelection>;

export const Default: Story = {
render: () => (
<EveDataProvider>
<DefaultCharactersProvider>
<EsiCharactersProvider>
<CurrentCharacterProvider>
<CharacterSelection />
</CurrentCharacterProvider>
</EsiCharactersProvider>
</DefaultCharactersProvider>
</EveDataProvider>
),
};
46 changes: 46 additions & 0 deletions src/components/CharacterSelection/CharacterSelection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import React from "react";

import { useCharacters, useEsiCharacters } from "@/providers/Characters";
import { useCurrentCharacter } from "@/providers/CurrentCharacterProvider";

import styles from "./CharacterSelection.module.css";

/**
* Character selection for EsiProvider.
*
* It shows both a dropdown for all the characters that the EsiProvider knows,
* and a button to add another character.
*/
export const CharacterSelection = () => {
const characters = useCharacters();
const currentCharacter = useCurrentCharacter();
const esiCharactersProvider = useEsiCharacters();

const isExpired = currentCharacter.character?.expired ?? false;

return (
<div className={styles.character}>
<select onChange={(e) => currentCharacter.setCharacterId(e.target.value)} value={currentCharacter.characterId}>
{Object.entries(characters)
.sort()
.map(([id, name]) => {
return (
<option key={id} value={id}>
{name.name} {name.expired ? "(access expired)" : ""}
</option>
);
})}
</select>
{isExpired && (
<button onClick={esiCharactersProvider.refresh} title="Refresh access">
R
</button>
)}
{!isExpired && (
<button onClick={esiCharactersProvider.login} title="Add another character">
+
</button>
)}
</div>
);
};
1 change: 1 addition & 0 deletions src/components/CharacterSelection/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { CharacterSelection } from "./CharacterSelection";
Loading

0 comments on commit 15c52ad

Please sign in to comment.