feat: integrate "default characters" into character selection (#30)
This commit is contained in:
@@ -3,6 +3,7 @@ import React from "react";
|
||||
|
||||
import { EsiProvider } from '../EsiProvider';
|
||||
import { EsiCharacterSelection } from './';
|
||||
import { EveDataProvider } from '../EveDataProvider';
|
||||
|
||||
const meta: Meta<typeof EsiCharacterSelection> = {
|
||||
component: EsiCharacterSelection,
|
||||
@@ -15,9 +16,11 @@ type Story = StoryObj<typeof EsiCharacterSelection>;
|
||||
|
||||
const withEsiProvider: Decorator<Record<string, never>> = (Story) => {
|
||||
return (
|
||||
<EsiProvider>
|
||||
<Story />
|
||||
</EsiProvider>
|
||||
<EveDataProvider>
|
||||
<EsiProvider setSkills={console.log}>
|
||||
<Story />
|
||||
</EsiProvider>
|
||||
</EveDataProvider>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -13,17 +13,9 @@ import styles from "./EsiCharacterSelection.module.css";
|
||||
export const EsiCharacterSelection = () => {
|
||||
const esi = React.useContext(EsiContext);
|
||||
|
||||
if (Object.keys(esi.characters ?? {}).length === 0) {
|
||||
return <div className={styles.character}>
|
||||
<button className={styles.noCharacter} onClick={esi.login}>
|
||||
Login to load characters skills and fits
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
|
||||
return <div className={styles.character}>
|
||||
<select onChange={e => esi.changeCharacter(e.target.value)} value={esi.currentCharacter}>
|
||||
{Object.entries(esi.characters).map(([id, name]) => {
|
||||
{Object.entries(esi.characters).sort().map(([id, name]) => {
|
||||
return <option key={id} value={id}>{name.name}</option>
|
||||
})}
|
||||
</select>
|
||||
|
||||
@@ -2,6 +2,7 @@ import type { Meta, StoryObj } from '@storybook/react';
|
||||
import React from "react";
|
||||
|
||||
import { EsiContext, EsiProvider } from './';
|
||||
import { EveDataProvider } from '../EveDataProvider';
|
||||
|
||||
const meta: Meta<typeof EsiProvider> = {
|
||||
component: EsiProvider,
|
||||
@@ -33,10 +34,13 @@ const TestEsi = () => {
|
||||
|
||||
export const Default: Story = {
|
||||
args: {
|
||||
setSkills: (skills: Record<string, number>) => { console.log(skills); }
|
||||
},
|
||||
render: (args) => (
|
||||
<EsiProvider {...args}>
|
||||
<TestEsi />
|
||||
</EsiProvider>
|
||||
<EveDataProvider>
|
||||
<EsiProvider {...args}>
|
||||
<TestEsi />
|
||||
</EsiProvider>
|
||||
</EveDataProvider>
|
||||
),
|
||||
};
|
||||
|
||||
@@ -6,6 +6,7 @@ import { EsiFit } from "../ShipSnapshotProvider";
|
||||
import { getAccessToken } from "./EsiAccessToken";
|
||||
import { getSkills } from "./EsiSkills";
|
||||
import { getCharFittings } from "./EsiFittings";
|
||||
import { EveDataContext } from "../EveDataProvider";
|
||||
|
||||
export interface EsiCharacter {
|
||||
name: string;
|
||||
@@ -41,6 +42,8 @@ export const EsiContext = React.createContext<Esi>({
|
||||
});
|
||||
|
||||
export interface EsiProps {
|
||||
/** Callback to call when skills are changed. */
|
||||
setSkills: (skills: Record<string, number>) => void;
|
||||
/** Children that can use this provider. */
|
||||
children: React.ReactNode;
|
||||
}
|
||||
@@ -75,6 +78,8 @@ const useLocalStorage = function <T>(key: string, initialValue: T) {
|
||||
* Keeps track (in local storage) of ESI characters and their refresh token.
|
||||
*/
|
||||
export const EsiProvider = (props: EsiProps) => {
|
||||
const eveData = React.useContext(EveDataContext);
|
||||
|
||||
const [esi, setEsi] = React.useState<Esi>({
|
||||
loaded: undefined,
|
||||
characters: {},
|
||||
@@ -137,10 +142,43 @@ export const EsiProvider = (props: EsiProps) => {
|
||||
}, [esiPrivate.accessTokens, esiPrivate.refreshTokens]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!eveData.loaded) return;
|
||||
|
||||
const characterId = esi.currentCharacter;
|
||||
if (characterId === undefined) return;
|
||||
/* Skills already fetched? We won't do it again till the user reloads. */
|
||||
if (esi.characters[characterId]?.skills !== undefined) return;
|
||||
const currentSkills = esi.characters[characterId]?.skills;
|
||||
if (currentSkills !== undefined) {
|
||||
props.setSkills(currentSkills);
|
||||
return;
|
||||
}
|
||||
|
||||
if (characterId === '.all-0' || characterId === '.all-5') {
|
||||
const level = characterId === '.all-0' ? 0 : 5;
|
||||
|
||||
const skills: Record<string, number> = {};
|
||||
for (const typeId in eveData.typeIDs) {
|
||||
if (eveData?.typeIDs?.[typeId].categoryID !== 16) continue;
|
||||
skills[typeId] = level;
|
||||
}
|
||||
|
||||
setEsi((oldEsi: Esi) => {
|
||||
return {
|
||||
...oldEsi,
|
||||
characters: {
|
||||
...oldEsi.characters,
|
||||
[characterId]: {
|
||||
...oldEsi.characters[characterId],
|
||||
skills,
|
||||
charFittings: [],
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
props.setSkills(skills);
|
||||
return;
|
||||
}
|
||||
|
||||
ensureAccessToken(characterId).then((accessToken) => {
|
||||
if (accessToken === undefined) return;
|
||||
@@ -148,6 +186,13 @@ export const EsiProvider = (props: EsiProps) => {
|
||||
getSkills(characterId, accessToken).then((skills) => {
|
||||
if (skills === undefined) return;
|
||||
|
||||
/* Ensure all skills are set; also those not learnt. */
|
||||
for (const typeId in eveData.typeIDs) {
|
||||
if (eveData?.typeIDs?.[typeId].categoryID !== 16) continue;
|
||||
if (skills[typeId] !== undefined) continue;
|
||||
skills[typeId] = 0;
|
||||
}
|
||||
|
||||
setEsi((oldEsi: Esi) => {
|
||||
return {
|
||||
...oldEsi,
|
||||
@@ -160,6 +205,8 @@ export const EsiProvider = (props: EsiProps) => {
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
props.setSkills(skills);
|
||||
});
|
||||
|
||||
getCharFittings(characterId, accessToken).then((charFittings) => {
|
||||
@@ -182,7 +229,7 @@ export const EsiProvider = (props: EsiProps) => {
|
||||
|
||||
/* We only update when currentCharacter changes, and ignore all others. */
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [esi.currentCharacter]);
|
||||
}, [esi.currentCharacter, eveData.loaded]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (typeof window === 'undefined') return;
|
||||
@@ -265,9 +312,19 @@ export const EsiProvider = (props: EsiProps) => {
|
||||
}
|
||||
|
||||
async function startup() {
|
||||
const charactersDefault = {
|
||||
'.all-0': {
|
||||
name: 'Default character - All Skills L0',
|
||||
},
|
||||
'.all-5': {
|
||||
name: 'Default character - All Skills L5',
|
||||
},
|
||||
...characters,
|
||||
};
|
||||
|
||||
setEsi({
|
||||
loaded: true,
|
||||
characters,
|
||||
characters: charactersDefault,
|
||||
currentCharacter,
|
||||
changeCharacter,
|
||||
login,
|
||||
|
||||
@@ -21,7 +21,7 @@ type Story = StoryObj<typeof HullListing>;
|
||||
const withEsiProvider: Decorator<{ changeHull: (typeId: number) => void, changeFit: (fit: EsiFit) => void }> = (Story, context) => {
|
||||
return (
|
||||
<EveDataProvider>
|
||||
<EsiProvider>
|
||||
<EsiProvider setSkills={console.log}>
|
||||
<DogmaEngineProvider>
|
||||
<ShipSnapshotProvider {...context.parameters.snapshot}>
|
||||
<div style={{height: "400px"}}>
|
||||
|
||||
Reference in New Issue
Block a user