mirror of
https://github.com/calli-eve/eve-pi.git
synced 2026-02-15 20:19:51 +01:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
741b2480b9 | ||
|
|
b185e5d044 | ||
|
|
f0d4708b43 | ||
|
|
0f33a7ff0c | ||
|
|
bbdcece163 | ||
|
|
2a1e74ca79 |
@@ -43,11 +43,6 @@ module.exports = withSentryConfig(
|
|||||||
// Transpiles SDK to be compatible with IE11 (increases bundle size)
|
// Transpiles SDK to be compatible with IE11 (increases bundle size)
|
||||||
transpileClientSDK: true,
|
transpileClientSDK: true,
|
||||||
|
|
||||||
// Route browser requests to Sentry through a Next.js rewrite to circumvent ad-blockers.
|
|
||||||
// This can increase your server load as well as your hosting bill.
|
|
||||||
// Note: Check that the configured route will not match with your Next.js middleware, otherwise reporting of client-
|
|
||||||
// side errors will fail.
|
|
||||||
tunnelRoute: "/monitoring",
|
|
||||||
|
|
||||||
// Hides source maps from generated client bundles
|
// Hides source maps from generated client bundles
|
||||||
hideSourceMaps: true,
|
hideSourceMaps: true,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { AccessToken } from "@/types";
|
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 { CharacterRow } from "../Characters/CharacterRow";
|
||||||
import { PlanetaryInteractionRow } from "../PlanetaryInteraction/PlanetaryInteractionRow";
|
import { PlanetaryInteractionRow } from "../PlanetaryInteraction/PlanetaryInteractionRow";
|
||||||
import { SessionContext } from "@/app/context/Context";
|
import { SessionContext } from "@/app/context/Context";
|
||||||
@@ -14,17 +14,36 @@ import { STORAGE_IDS } from "@/const";
|
|||||||
interface AccountTotals {
|
interface AccountTotals {
|
||||||
monthlyEstimate: number;
|
monthlyEstimate: number;
|
||||||
storageValue: number;
|
storageValue: number;
|
||||||
|
planetCount: number;
|
||||||
|
characterCount: number;
|
||||||
|
runningExtractors: number;
|
||||||
|
totalExtractors: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
const calculateAccountTotals = (characters: AccessToken[], piPrices: EvePraisalResult | undefined): AccountTotals => {
|
const calculateAccountTotals = (characters: AccessToken[], piPrices: EvePraisalResult | undefined): AccountTotals => {
|
||||||
let totalMonthlyEstimate = 0;
|
let totalMonthlyEstimate = 0;
|
||||||
let totalStorageValue = 0;
|
let totalStorageValue = 0;
|
||||||
|
let totalPlanetCount = 0;
|
||||||
|
let totalCharacterCount = characters.length;
|
||||||
|
let runningExtractors = 0;
|
||||||
|
let totalExtractors = 0;
|
||||||
|
|
||||||
characters.forEach((character) => {
|
characters.forEach((character) => {
|
||||||
|
totalPlanetCount += character.planets.length;
|
||||||
character.planets.forEach((planet) => {
|
character.planets.forEach((planet) => {
|
||||||
const { localExports } = planetCalculations(planet);
|
const { localExports, extractors } = planetCalculations(planet);
|
||||||
const planetConfig = character.planetConfig.find(p => p.planetId === planet.planet_id);
|
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
|
// Calculate monthly estimate
|
||||||
if (!planetConfig?.excludeFromTotals) {
|
if (!planetConfig?.excludeFromTotals) {
|
||||||
localExports.forEach((exportItem) => {
|
localExports.forEach((exportItem) => {
|
||||||
@@ -56,7 +75,11 @@ const calculateAccountTotals = (characters: AccessToken[], piPrices: EvePraisalR
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
monthlyEstimate: totalMonthlyEstimate,
|
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 theme = useTheme();
|
||||||
const [localIsCollapsed, setLocalIsCollapsed] = useState(false);
|
const [localIsCollapsed, setLocalIsCollapsed] = useState(false);
|
||||||
const { planMode, piPrices } = useContext(SessionContext);
|
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
|
// Update local collapse state when prop changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -116,26 +139,62 @@ export const AccountCard = ({ characters, isCollapsed: propIsCollapsed }: { char
|
|||||||
? `Account: ${characters[0].account}`
|
? `Account: ${characters[0].account}`
|
||||||
: "No account name"}
|
: "No account name"}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography
|
<Box sx={{
|
||||||
sx={{
|
display: 'flex',
|
||||||
fontSize: "0.8rem",
|
gap: 2,
|
||||||
color: theme.palette.text.secondary,
|
flexWrap: 'wrap',
|
||||||
}}
|
mt: 1,
|
||||||
>
|
alignItems: 'center'
|
||||||
Monthly Estimate: {monthlyEstimate >= 1000
|
}}>
|
||||||
? `${(monthlyEstimate / 1000).toFixed(2)} B`
|
<Typography
|
||||||
: `${monthlyEstimate.toFixed(2)} M`} ISK
|
sx={{
|
||||||
</Typography>
|
fontSize: "0.8rem",
|
||||||
<Typography
|
color: theme.palette.text.secondary,
|
||||||
sx={{
|
}}
|
||||||
fontSize: "0.8rem",
|
>
|
||||||
color: theme.palette.text.secondary,
|
Monthly: {monthlyEstimate >= 1000
|
||||||
}}
|
? `${(monthlyEstimate / 1000).toFixed(2)} B`
|
||||||
>
|
: `${monthlyEstimate.toFixed(2)} M`} ISK
|
||||||
Storage Value: {storageValue >= 1000
|
</Typography>
|
||||||
? `${(storageValue / 1000).toFixed(2)} B`
|
<Divider orientation="vertical" flexItem sx={{ height: 16, borderColor: theme.palette.divider }} />
|
||||||
: `${storageValue.toFixed(2)} M`} ISK
|
<Typography
|
||||||
</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>
|
</Box>
|
||||||
<IconButton
|
<IconButton
|
||||||
size="small"
|
size="small"
|
||||||
|
|||||||
@@ -170,7 +170,7 @@ export const ExtractionSimulationDisplay: React.FC<ExtractionSimulationDisplayPr
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
<Paper sx={{ p: 2 }}>
|
{extractors.length > 0 ? <Paper sx={{ p: 2 }}>
|
||||||
<Typography variant="h6" gutterBottom>
|
<Typography variant="h6" gutterBottom>
|
||||||
Extraction Simulation
|
Extraction Simulation
|
||||||
</Typography>
|
</Typography>
|
||||||
@@ -210,7 +210,7 @@ export const ExtractionSimulationDisplay: React.FC<ExtractionSimulationDisplayPr
|
|||||||
<div style={{ height: '300px' }}>
|
<div style={{ height: '300px' }}>
|
||||||
<Line data={chartData} options={chartOptions} />
|
<Line data={chartData} options={chartOptions} />
|
||||||
</div>
|
</div>
|
||||||
</Paper>
|
</Paper> : null}
|
||||||
|
|
||||||
<ProductionChainVisualization
|
<ProductionChainVisualization
|
||||||
extractedTypeIds={extractedTypeIds}
|
extractedTypeIds={extractedTypeIds}
|
||||||
|
|||||||
@@ -102,9 +102,11 @@ export const PlanetCard = ({
|
|||||||
return (
|
return (
|
||||||
<Tooltip
|
<Tooltip
|
||||||
title={
|
title={
|
||||||
<ExtractionSimulationTooltip
|
extractors.length > 0 ? (
|
||||||
extractors={extractors}
|
<ExtractionSimulationTooltip
|
||||||
/>
|
extractors={extractors}
|
||||||
|
/>
|
||||||
|
) : null
|
||||||
}
|
}
|
||||||
componentsProps={{
|
componentsProps={{
|
||||||
tooltip: {
|
tooltip: {
|
||||||
|
|||||||
@@ -165,11 +165,8 @@ export const PlanetTableRow = ({
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
// Only trigger if clicking a cell with the clickable-cell class
|
|
||||||
if (!(e.target as HTMLElement).closest('.clickable-cell')) return;
|
if (!(e.target as HTMLElement).closest('.clickable-cell')) return;
|
||||||
if (extractors.length > 0) {
|
setSimulationOpen(!simulationOpen);
|
||||||
setSimulationOpen(!simulationOpen);
|
|
||||||
}
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<TableCell component="th" scope="row" className="clickable-cell">
|
<TableCell component="th" scope="row" className="clickable-cell">
|
||||||
@@ -190,17 +187,19 @@ export const PlanetTableRow = ({
|
|||||||
<Tooltip
|
<Tooltip
|
||||||
placement="right"
|
placement="right"
|
||||||
title={
|
title={
|
||||||
<ExtractionSimulationTooltip
|
extractors.length > 0 ? (
|
||||||
extractors={extractors
|
<ExtractionSimulationTooltip
|
||||||
.filter(e => e.extractor_details?.product_type_id && e.extractor_details?.qty_per_cycle)
|
extractors={extractors
|
||||||
.map(e => ({
|
.filter(e => e.extractor_details?.product_type_id && e.extractor_details?.qty_per_cycle)
|
||||||
typeId: e.extractor_details!.product_type_id!,
|
.map(e => ({
|
||||||
baseValue: e.extractor_details!.qty_per_cycle!,
|
typeId: e.extractor_details!.product_type_id!,
|
||||||
cycleTime: e.extractor_details!.cycle_time || 3600,
|
baseValue: e.extractor_details!.qty_per_cycle!,
|
||||||
installTime: e.install_time ?? "",
|
cycleTime: e.extractor_details!.cycle_time || 3600,
|
||||||
expiryTime: e.expiry_time ?? ""
|
installTime: e.install_time ?? "",
|
||||||
}))}
|
expiryTime: e.expiry_time ?? ""
|
||||||
/>
|
}))}
|
||||||
|
/>
|
||||||
|
) : null
|
||||||
}
|
}
|
||||||
componentsProps={{
|
componentsProps={{
|
||||||
tooltip: {
|
tooltip: {
|
||||||
@@ -291,7 +290,7 @@ export const PlanetTableRow = ({
|
|||||||
key={`import-${character.character.characterId}-${planet.planet_id}-${i.type_id}`}
|
key={`import-${character.character.characterId}-${planet.planet_id}-${i.type_id}`}
|
||||||
fontSize={theme.custom.smallText}
|
fontSize={theme.custom.smallText}
|
||||||
>
|
>
|
||||||
{PI_TYPES_MAP[i.type_id].name} ({i.quantity}/h)
|
{PI_TYPES_MAP[i.type_id].name} ({i.quantity * i.factoryCount}/h)
|
||||||
</Typography>
|
</Typography>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -51,18 +51,22 @@ export const Summary = ({ characters }: { characters: AccessToken[] }) => {
|
|||||||
const [sortDirection, setSortDirection] = useState<SortDirection>("asc");
|
const [sortDirection, setSortDirection] = useState<SortDirection>("asc");
|
||||||
const [sortBy, setSortBy] = useState<SortBy>("name");
|
const [sortBy, setSortBy] = useState<SortBy>("name");
|
||||||
const [startDate, setStartDate] = useState<string>(DateTime.now().startOf('day').toISO());
|
const [startDate, setStartDate] = useState<string>(DateTime.now().startOf('day').toISO());
|
||||||
const [activityPercentage, setActivityPercentage] = useState<number>(() => {
|
const [activityPercentage, setActivityPercentage] = useState<number>(100);
|
||||||
const saved = localStorage.getItem('activityPercentage');
|
|
||||||
return saved ? parseFloat(saved) : 100;
|
|
||||||
});
|
|
||||||
|
|
||||||
|
// Load saved values from localStorage on mount
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const savedDate = localStorage.getItem('productionStartDate');
|
const savedDate = localStorage.getItem('productionStartDate');
|
||||||
if (savedDate) {
|
if (savedDate) {
|
||||||
setStartDate(savedDate);
|
setStartDate(savedDate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const savedActivity = localStorage.getItem('activityPercentage');
|
||||||
|
if (savedActivity) {
|
||||||
|
setActivityPercentage(parseFloat(savedActivity));
|
||||||
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
// Save values to localStorage when they change
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
localStorage.setItem('productionStartDate', startDate);
|
localStorage.setItem('productionStartDate', startDate);
|
||||||
}, [startDate]);
|
}, [startDate]);
|
||||||
|
|||||||
@@ -94,7 +94,13 @@ export const planetCalculations = (planet: PlanetWithInfo) => {
|
|||||||
![...locallyProduced, ...locallyExcavated].some(
|
![...locallyProduced, ...locallyExcavated].some(
|
||||||
(lp) => lp === p.type_id,
|
(lp) => lp === p.type_id,
|
||||||
),
|
),
|
||||||
);
|
).map((p) => ({
|
||||||
|
...p,
|
||||||
|
factoryCount: planetInfo.pins
|
||||||
|
.filter((f) => f.schematic_id === p.schematic_id)
|
||||||
|
.length,
|
||||||
|
}));
|
||||||
|
|
||||||
|
|
||||||
const localExports = locallyProduced
|
const localExports = locallyProduced
|
||||||
.filter((p) => !locallyConsumed.some((lp) => lp === p))
|
.filter((p) => !locallyConsumed.some((lp) => lp === p))
|
||||||
|
|||||||
Reference in New Issue
Block a user