mirror of
https://github.com/calli-eve/eve-pi.git
synced 2026-02-11 18:28:49 +01:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
67acea9be4 | ||
|
|
98b450fcc7 | ||
|
|
eb15696241 | ||
|
|
741b2480b9 |
@@ -1,5 +1,5 @@
|
||||
import { AccessToken } from "@/types";
|
||||
import { Box, Stack, Typography, useTheme, Paper, IconButton } from "@mui/material";
|
||||
import { Box, Stack, Typography, useTheme, Paper, IconButton, Divider } from "@mui/material";
|
||||
import { CharacterRow } from "../Characters/CharacterRow";
|
||||
import { PlanetaryInteractionRow } from "../PlanetaryInteraction/PlanetaryInteractionRow";
|
||||
import { SessionContext } from "@/app/context/Context";
|
||||
@@ -14,17 +14,36 @@ import { STORAGE_IDS } from "@/const";
|
||||
interface AccountTotals {
|
||||
monthlyEstimate: number;
|
||||
storageValue: number;
|
||||
planetCount: number;
|
||||
characterCount: number;
|
||||
runningExtractors: number;
|
||||
totalExtractors: number;
|
||||
}
|
||||
|
||||
const calculateAccountTotals = (characters: AccessToken[], piPrices: EvePraisalResult | undefined): AccountTotals => {
|
||||
let totalMonthlyEstimate = 0;
|
||||
let totalStorageValue = 0;
|
||||
let totalPlanetCount = 0;
|
||||
let totalCharacterCount = characters.length;
|
||||
let runningExtractors = 0;
|
||||
let totalExtractors = 0;
|
||||
|
||||
characters.forEach((character) => {
|
||||
totalPlanetCount += character.planets.length;
|
||||
character.planets.forEach((planet) => {
|
||||
const { localExports } = planetCalculations(planet);
|
||||
const { localExports, extractors } = planetCalculations(planet);
|
||||
const planetConfig = character.planetConfig.find(p => p.planetId === planet.planet_id);
|
||||
|
||||
// Count running and total extractors
|
||||
if (!planetConfig?.excludeFromTotals) {
|
||||
extractors.forEach(extractor => {
|
||||
totalExtractors++;
|
||||
if (extractor.expiry_time && new Date(extractor.expiry_time) > new Date()) {
|
||||
runningExtractors++;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Calculate monthly estimate
|
||||
if (!planetConfig?.excludeFromTotals) {
|
||||
localExports.forEach((exportItem) => {
|
||||
@@ -56,7 +75,11 @@ const calculateAccountTotals = (characters: AccessToken[], piPrices: EvePraisalR
|
||||
|
||||
return {
|
||||
monthlyEstimate: totalMonthlyEstimate,
|
||||
storageValue: totalStorageValue
|
||||
storageValue: totalStorageValue,
|
||||
planetCount: totalPlanetCount,
|
||||
characterCount: totalCharacterCount,
|
||||
runningExtractors,
|
||||
totalExtractors
|
||||
};
|
||||
};
|
||||
|
||||
@@ -64,7 +87,7 @@ export const AccountCard = ({ characters, isCollapsed: propIsCollapsed }: { char
|
||||
const theme = useTheme();
|
||||
const [localIsCollapsed, setLocalIsCollapsed] = useState(false);
|
||||
const { planMode, piPrices } = useContext(SessionContext);
|
||||
const { monthlyEstimate, storageValue } = calculateAccountTotals(characters, piPrices);
|
||||
const { monthlyEstimate, storageValue, planetCount, characterCount, runningExtractors, totalExtractors } = calculateAccountTotals(characters, piPrices);
|
||||
|
||||
// Update local collapse state when prop changes
|
||||
useEffect(() => {
|
||||
@@ -102,7 +125,12 @@ export const AccountCard = ({ characters, isCollapsed: propIsCollapsed }: { char
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
cursor: 'pointer',
|
||||
'&:hover': {
|
||||
backgroundColor: theme.palette.action.hover,
|
||||
},
|
||||
}}
|
||||
onClick={() => setLocalIsCollapsed(!localIsCollapsed)}
|
||||
>
|
||||
<Box>
|
||||
<Typography
|
||||
@@ -116,30 +144,65 @@ export const AccountCard = ({ characters, isCollapsed: propIsCollapsed }: { char
|
||||
? `Account: ${characters[0].account}`
|
||||
: "No account name"}
|
||||
</Typography>
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: "0.8rem",
|
||||
color: theme.palette.text.secondary,
|
||||
}}
|
||||
>
|
||||
Monthly Estimate: {monthlyEstimate >= 1000
|
||||
? `${(monthlyEstimate / 1000).toFixed(2)} B`
|
||||
: `${monthlyEstimate.toFixed(2)} M`} ISK
|
||||
</Typography>
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: "0.8rem",
|
||||
color: theme.palette.text.secondary,
|
||||
}}
|
||||
>
|
||||
Storage Value: {storageValue >= 1000
|
||||
? `${(storageValue / 1000).toFixed(2)} B`
|
||||
: `${storageValue.toFixed(2)} M`} ISK
|
||||
</Typography>
|
||||
<Box sx={{
|
||||
display: 'flex',
|
||||
gap: 2,
|
||||
flexWrap: 'wrap',
|
||||
mt: 1,
|
||||
alignItems: 'center'
|
||||
}}>
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: "0.8rem",
|
||||
color: theme.palette.text.secondary,
|
||||
}}
|
||||
>
|
||||
Monthly: {monthlyEstimate >= 1000
|
||||
? `${(monthlyEstimate / 1000).toFixed(2)} B`
|
||||
: `${monthlyEstimate.toFixed(2)} M`} ISK
|
||||
</Typography>
|
||||
<Divider orientation="vertical" flexItem sx={{ height: 16, borderColor: theme.palette.divider }} />
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: "0.8rem",
|
||||
color: theme.palette.text.secondary,
|
||||
}}
|
||||
>
|
||||
Storage: {storageValue >= 1000
|
||||
? `${(storageValue / 1000).toFixed(2)} B`
|
||||
: `${storageValue.toFixed(2)} M`} ISK
|
||||
</Typography>
|
||||
<Divider orientation="vertical" flexItem sx={{ height: 16, borderColor: theme.palette.divider }} />
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: "0.8rem",
|
||||
color: theme.palette.text.secondary,
|
||||
}}
|
||||
>
|
||||
Planets: {planetCount}
|
||||
</Typography>
|
||||
<Divider orientation="vertical" flexItem sx={{ height: 16, borderColor: theme.palette.divider }} />
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: "0.8rem",
|
||||
color: theme.palette.text.secondary,
|
||||
}}
|
||||
>
|
||||
Characters: {characterCount}
|
||||
</Typography>
|
||||
<Divider orientation="vertical" flexItem sx={{ height: 16, borderColor: theme.palette.divider }} />
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: "0.8rem",
|
||||
color: runningExtractors < totalExtractors ? theme.palette.error.main : theme.palette.text.secondary,
|
||||
}}
|
||||
>
|
||||
Extractors: {runningExtractors}/{totalExtractors}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
<IconButton
|
||||
size="small"
|
||||
onClick={() => setLocalIsCollapsed(!localIsCollapsed)}
|
||||
sx={{
|
||||
transform: localIsCollapsed ? 'rotate(-90deg)' : 'rotate(0deg)',
|
||||
transition: 'transform 0.2s ease-in-out'
|
||||
|
||||
@@ -7,16 +7,18 @@ import { styled, useTheme } from "@mui/material/styles";
|
||||
import React from "react";
|
||||
import { CharacterDialog } from "./CharacterDialog";
|
||||
import { AccessToken } from "@/types";
|
||||
import { Box, Button, Tooltip } from "@mui/material";
|
||||
import { Box, Tooltip, IconButton, Typography } from "@mui/material";
|
||||
import SettingsIcon from "@mui/icons-material/Settings";
|
||||
import { EVE_IMAGE_URL } from "@/const";
|
||||
import { CharacterContext } from "@/app/context/Context";
|
||||
|
||||
const StackItem = styled(Stack)(({ theme }) => ({
|
||||
...theme.typography.body2,
|
||||
padding: theme.custom.compactMode ? theme.spacing(1) : theme.spacing(2),
|
||||
display: "flex",
|
||||
textAlign: "left",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
justifyContent: "flex-start",
|
||||
alignItems: "flex-start",
|
||||
}));
|
||||
|
||||
export const CharacterRow = ({ character }: { character: AccessToken }) => {
|
||||
@@ -29,8 +31,6 @@ export const CharacterRow = ({ character }: { character: AccessToken }) => {
|
||||
return (
|
||||
<StackItem
|
||||
key={character.character.characterId}
|
||||
alignItems="flex-start"
|
||||
justifyContent="flex-start"
|
||||
>
|
||||
<CharacterDialog
|
||||
character={selectedCharacter}
|
||||
@@ -38,13 +38,49 @@ export const CharacterRow = ({ character }: { character: AccessToken }) => {
|
||||
updateCharacter={updateCharacter}
|
||||
closeDialog={() => setSelectedCharacter(undefined)}
|
||||
/>
|
||||
<Typography
|
||||
sx={{
|
||||
whiteSpace: "nowrap",
|
||||
fontSize: theme.custom.smallText,
|
||||
textAlign: "left",
|
||||
lineHeight: 1.2,
|
||||
marginBottom: "0.4rem",
|
||||
marginLeft: "0.2rem",
|
||||
overflow: "visible",
|
||||
textOverflow: "clip",
|
||||
width: "1rem"
|
||||
}}
|
||||
>
|
||||
{character.character.name}
|
||||
</Typography>
|
||||
<Tooltip title={character.comment}>
|
||||
<Box
|
||||
display="flex"
|
||||
flexDirection="column"
|
||||
maxWidth={120}
|
||||
onClick={() => setSelectedCharacter(character)}
|
||||
position="relative"
|
||||
sx={{ cursor: "pointer" }}
|
||||
>
|
||||
<IconButton
|
||||
size="small"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setSelectedCharacter(character);
|
||||
}}
|
||||
sx={{
|
||||
p: 0,
|
||||
position: "absolute",
|
||||
top: 4,
|
||||
left: 4,
|
||||
backgroundColor: "rgba(0, 0, 0, 0.5)",
|
||||
"&:hover": {
|
||||
backgroundColor: "rgba(0, 0, 0, 0.7)",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<SettingsIcon fontSize="small" sx={{ color: "white" }} />
|
||||
</IconButton>
|
||||
<Image
|
||||
unoptimized
|
||||
src={`${EVE_IMAGE_URL}/characters/${character.character.characterId}/portrait?size=128`}
|
||||
@@ -53,16 +89,6 @@ export const CharacterRow = ({ character }: { character: AccessToken }) => {
|
||||
height={theme.custom.cardImageSize}
|
||||
style={{ marginBottom: "0.2rem", borderRadius: 8 }}
|
||||
/>
|
||||
<Button
|
||||
style={{
|
||||
padding: 6,
|
||||
fontSize: theme.custom.smallText,
|
||||
lineHeight: 1,
|
||||
}}
|
||||
variant="outlined"
|
||||
>
|
||||
{character.character.name}
|
||||
</Button>
|
||||
</Box>
|
||||
</Tooltip>
|
||||
</StackItem>
|
||||
|
||||
@@ -159,8 +159,8 @@ export const PlanetaryInteractionRow = ({
|
||||
const theme = useTheme();
|
||||
|
||||
return theme.custom.compactMode ? (
|
||||
<PlanetaryInteractionIconsRow character={character} />
|
||||
<div style={{ marginTop: "1.2rem" }}><PlanetaryInteractionIconsRow character={character} /></div>
|
||||
) : (
|
||||
<PlanetaryIteractionTable character={character} />
|
||||
<div style={{ marginTop: "1.4rem" }}><PlanetaryIteractionTable character={character} /></div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -248,7 +248,7 @@ const Home = () => {
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const ESI_CACHE_TIME_MS = 600000;
|
||||
const ESI_CACHE_TIME_MS = 3000000;
|
||||
const interval = setInterval(() => {
|
||||
const characters = initializeCharacters();
|
||||
refreshSession(characters)
|
||||
|
||||
Reference in New Issue
Block a user