import { ColorContext, SessionContext } from "@/app/context/Context"; import { PI_TYPES_MAP, STORAGE_IDS, STORAGE_CAPACITIES, PI_PRODUCT_VOLUMES, EVE_IMAGE_URL, PI_SCHEMATICS, LAUNCHPAD_IDS } from "@/const"; import { planetCalculations } from "@/planets"; import { AccessToken, PlanetWithInfo } from "@/types"; import { PlanetCalculations, StorageInfo } from "@/types/planet"; import CloseIcon from "@mui/icons-material/Close"; import MoreVertIcon from '@mui/icons-material/MoreVert'; import { Button, Tooltip, Typography, useTheme, Menu, MenuItem, IconButton, Checkbox, FormControlLabel } from "@mui/material"; import AppBar from "@mui/material/AppBar"; import Dialog from "@mui/material/Dialog"; import Slide from "@mui/material/Slide"; import TableCell from "@mui/material/TableCell"; import TableRow from "@mui/material/TableRow"; import Toolbar from "@mui/material/Toolbar"; import { TransitionProps } from "@mui/material/transitions"; import { DateTime } from "luxon"; import Image from "next/image"; import React, { forwardRef, useContext, useState } from "react"; import Countdown from "react-countdown"; import { PlanetConfigDialog } from "../PlanetConfig/PlanetConfigDialog"; import PinsCanvas3D from "./PinsCanvas3D"; import { timeColor } from "./alerts"; import { ExtractionSimulationDisplay } from './ExtractionSimulationDisplay'; import { ExtractionSimulationTooltip } from './ExtractionSimulationTooltip'; import { Collapse, Box, Stack } from "@mui/material"; const Transition = forwardRef(function Transition( props: TransitionProps & { children: React.ReactElement; }, ref: React.Ref, ) { return ; }); interface SchematicInput { type_id: number; quantity: number; } interface SchematicOutput { type_id: number; quantity: number; } export const PlanetTableRow = ({ planet, character, planetDetails, }: { planet: PlanetWithInfo; character: AccessToken; planetDetails: PlanetCalculations; }) => { const theme = useTheme(); const { showProductIcons, extractionTimeMode, alertMode } = useContext(SessionContext); const { colors } = useContext(ColorContext); const [planetRenderOpen, setPlanetRenderOpen] = useState(false); const [planetConfigOpen, setPlanetConfigOpen] = useState(false); const [simulationOpen, setSimulationOpen] = useState(false); const [menuAnchorEl, setMenuAnchorEl] = useState(null); const handleMenuOpen = (event: React.MouseEvent) => { setMenuAnchorEl(event.currentTarget); }; const handleMenuClose = () => { setMenuAnchorEl(null); }; const handle3DrenderOpen = () => { setPlanetRenderOpen(true); }; const handle3DrenderClose = () => { setPlanetRenderOpen(false); }; const handlePlanetConfigOpen = () => { setPlanetConfigOpen(true); }; const handlePlanetConfigClose = () => { setPlanetConfigOpen(false); }; const { piPrices, updatePlanetConfig, readPlanetConfig } = useContext(SessionContext); const planetInfo = planet.info; const planetInfoUniverse = planet.infoUniverse; const planetConfig = readPlanetConfig({ characterId: character.character.characterId, planetId: planet.planet_id, }); const handleExcludeChange = (event: React.ChangeEvent) => { updatePlanetConfig({ ...planetConfig, excludeFromTotals: event.target.checked, }); }; // Check if there are any alerts const hasAlerts = alertMode && ( planetDetails.expired || planetDetails.storageInfo.some(storage => storage.fillRate > 60) || planetDetails.importDepletionTimes.some(depletion => depletion.hoursUntilDepletion < 24) || planetDetails.hasLargeExtractorDifference ); // If in alert mode and no alerts, hide the row if (alertMode && !hasAlerts) { return null; } const renderProductDisplay = (typeId: number, amount?: number) => { if (!typeId || !PI_TYPES_MAP[typeId]) { return (
No product {amount !== undefined && ( {amount} )}
); } if (showProductIcons) { return (
{PI_TYPES_MAP[typeId].name} {amount !== undefined && ( {amount} )}
); } return (
{PI_TYPES_MAP[typeId].name} {amount !== undefined && ( {amount} )}
); }; return ( <> ) => { if (!(e.target as HTMLElement).closest('.clickable-cell')) return; setSimulationOpen(!simulationOpen); }} >
0 ? ( e.extractor_details?.product_type_id && e.extractor_details?.qty_per_cycle) .map(e => ({ typeId: e.extractor_details!.product_type_id!, baseValue: e.extractor_details!.qty_per_cycle!, cycleTime: e.extractor_details!.cycle_time || 3600, installTime: e.install_time ?? "", expiryTime: e.expiry_time ?? "" }))} /> ) : null } componentsProps={{ tooltip: { sx: { bgcolor: 'background.paper', '& .MuiTooltip-arrow': { color: 'background.paper', }, maxWidth: 'none', width: 'fit-content' } } }} > {planetInfoUniverse?.name} {planetDetails.hasLargeExtractorDifference && ( off-balance )}
{planet.upgrade_level}
{planetDetails.extractors.length === 0 &&No extractors} {planetDetails.extractors.map((e, idx) => { return (
{e ? ( extractionTimeMode ? ( DateTime.fromISO(e.expiry_time ?? "").toFormat('yyyy-MM-dd HH:mm:ss') ) : ( ) ) : ( "STOPPED" )} {renderProductDisplay(e.extractor_details?.product_type_id ?? 0)}
); })}
{Array.from(planetDetails.localProduction).map((schematic, idx) => { return (
{renderProductDisplay(schematic[1].outputs[0].type_id)}
); })}
{planetDetails.localImports.map((i) => { const depletionTime = planetDetails.importDepletionTimes.find(d => d.typeId === i.type_id); return (
Will be depleted in {depletionTime?.hoursUntilDepletion.toFixed(1)} hours
Monthly cost: {depletionTime?.monthlyCost.toFixed(2)}M ISK
}>
{renderProductDisplay(i.type_id, i.quantity * i.factoryCount)} {depletionTime && ( ({depletionTime.hoursUntilDepletion.toFixed(1)}h) )}
); })}
{planetDetails.localExports.map((exports) => (
{renderProductDisplay(exports.type_id, exports.quantity * exports.factoryCount)}
))}
{planetDetails.localExports.map((exports) => ( } label="" /> ))}
{planetDetails.localExports.map((exports) => ( {exports.quantity * exports.factoryCount} ))}
{planetDetails.localExports.map((e) => { const valueInMillions = (((piPrices?.appraisal.items.find((a) => a.typeID === e.type_id) ?.prices.sell.min ?? 0) * e.quantity * e.factoryCount) / 1000000) * 24 * 30; const displayValue = valueInMillions >= 1000 ? `${(valueInMillions / 1000).toFixed(2)} B` : `${valueInMillions.toFixed(2)} M`; return ( {displayValue} ); })}
{planetDetails.storageInfo.length === 0 &&No storage} {planetDetails.storageInfo.map((storage: StorageInfo) => { const isLaunchpad = LAUNCHPAD_IDS.includes(storage.type_id); const fillRate = storage.fillRate; const color = fillRate > 90 ? '#ff0000' : fillRate > 80 ? '#ffa500' : fillRate > 60 ? '#ffd700' : 'inherit'; return (
{isLaunchpad ? 'L' : 'S'} {fillRate.toFixed(1)}% {storage.value > 0 && ( ({Math.round(storage.value / 1000000)}M) )}
); })}
{ handlePlanetConfigOpen(); handleMenuClose(); }}> Configure Planet { handle3DrenderOpen(); handleMenuClose(); }}> Show 3D View
e.extractor_details?.product_type_id && e.extractor_details?.qty_per_cycle) .map(e => ({ typeId: e.extractor_details!.product_type_id!, baseValue: e.extractor_details!.qty_per_cycle!, cycleTime: e.extractor_details!.cycle_time || 3600, installTime: e.install_time ?? "", expiryTime: e.expiry_time ?? "" }))} productionNodes={Array.from(planetDetails.localProduction).map(([schematicId, schematic]) => ({ schematicId: schematicId, typeId: schematic.outputs[0].type_id, name: schematic.name, inputs: schematic.inputs.map((input: SchematicInput) => ({ typeId: input.type_id, quantity: input.quantity })), outputs: schematic.outputs.map((output: SchematicOutput) => ({ typeId: output.type_id, quantity: output.quantity })), cycleTime: schematic.cycle_time, factoryCount: schematic.factoryCount || 1 }))} /> {planetInfoUniverse?.name} Planet configuration: {planetInfoUniverse?.name} ); };