5 Commits

14 changed files with 364 additions and 174 deletions

View File

@@ -125,7 +125,12 @@ export const AccountCard = ({ characters, isCollapsed: propIsCollapsed }: { char
display: 'flex', display: 'flex',
alignItems: 'center', alignItems: 'center',
justifyContent: 'space-between', justifyContent: 'space-between',
cursor: 'pointer',
'&:hover': {
backgroundColor: theme.palette.action.hover,
},
}} }}
onClick={() => setLocalIsCollapsed(!localIsCollapsed)}
> >
<Box> <Box>
<Typography <Typography
@@ -198,7 +203,6 @@ export const AccountCard = ({ characters, isCollapsed: propIsCollapsed }: { char
</Box> </Box>
<IconButton <IconButton
size="small" size="small"
onClick={() => setLocalIsCollapsed(!localIsCollapsed)}
sx={{ sx={{
transform: localIsCollapsed ? 'rotate(-90deg)' : 'rotate(0deg)', transform: localIsCollapsed ? 'rotate(-90deg)' : 'rotate(0deg)',
transition: 'transform 0.2s ease-in-out' transition: 'transform 0.2s ease-in-out'

View File

@@ -1,21 +0,0 @@
import { SessionContext } from "@/app/context/Context";
import { Button, Tooltip } from "@mui/material";
import { useContext } from "react";
export const AlertModeButton = () => {
const { alertMode, toggleAlertMode } = useContext(SessionContext);
return (
<Tooltip title="Toggle alert mode to show only accounts and planets that need action.">
<Button
style={{
backgroundColor: alertMode
? "rgba(144, 202, 249, 0.08)"
: "inherit",
}}
onClick={toggleAlertMode}
>
Alert mode
</Button>
</Tooltip>
);
};

View File

@@ -12,20 +12,25 @@ import * as React from "react";
import { DowloadButton } from "../Backup/DowloadButton"; import { DowloadButton } from "../Backup/DowloadButton";
import { UploadButton } from "../Backup/UploadButton"; import { UploadButton } from "../Backup/UploadButton";
import { CCPButton } from "../CCP/CCPButton"; import { CCPButton } from "../CCP/CCPButton";
import { CompactModeButton } from "../CompactModeButton/CompactModeButton";
import { DiscordButton } from "../Discord/DiscordButton"; import { DiscordButton } from "../Discord/DiscordButton";
import { GitHubButton } from "../Github/GitHubButton"; import { GitHubButton } from "../Github/GitHubButton";
import { LoginButton } from "../Login/LoginButton"; import { LoginButton } from "../Login/LoginButton";
import { PlanModeButton } from "../PlanModeButton/PlanModeButton";
import { SettingsButton } from "../Settings/SettingsButtons"; import { SettingsButton } from "../Settings/SettingsButtons";
import { AlertModeButton } from "../AlertModeButton/AlertModeButton"; import {
import { SupportButton } from "../SupportButton/SupportButton"; Button,
Dialog,
DialogTitle,
DialogContent,
DialogContentText,
DialogActions,
} from "@mui/material";
import { useState } from "react";
function ResponsiveAppBar() { function ResponsiveAppBar() {
const [anchorElNav, setAnchorElNav] = React.useState<null | HTMLElement>( const [anchorElNav, setAnchorElNav] = React.useState<null | HTMLElement>(
null, null,
); );
const [faqOpen, setFaqOpen] = useState(false);
const handleOpenNavMenu = (event: React.MouseEvent<HTMLElement>) => { const handleOpenNavMenu = (event: React.MouseEvent<HTMLElement>) => {
setAnchorElNav(event.currentTarget); setAnchorElNav(event.currentTarget);
@@ -102,23 +107,26 @@ function ResponsiveAppBar() {
<MenuItem onClick={handleCloseNavMenu}> <MenuItem onClick={handleCloseNavMenu}>
<GitHubButton /> <GitHubButton />
</MenuItem> </MenuItem>
<MenuItem onClick={handleCloseNavMenu}>
<CCPButton />
</MenuItem>
<MenuItem onClick={handleCloseNavMenu}>
<SupportButton />
</MenuItem>
<MenuItem onClick={handleCloseNavMenu}> <MenuItem onClick={handleCloseNavMenu}>
<SettingsButton /> <SettingsButton />
</MenuItem> </MenuItem>
<MenuItem onClick={handleCloseNavMenu}> <MenuItem
<CompactModeButton /> onClick={() => {
handleCloseNavMenu();
setFaqOpen(true);
}}
>
<Button
href=""
style={{ width: "100%" }}
sx={{ color: "white", display: "flex", justifyContent: "flex-start" }}
>
FAQ
</Button>
</MenuItem> </MenuItem>
<MenuItem onClick={handleCloseNavMenu}> <MenuItem onClick={handleCloseNavMenu}>
<PlanModeButton /> <CCPButton />
</MenuItem>
<MenuItem onClick={handleCloseNavMenu}>
<AlertModeButton />
</MenuItem> </MenuItem>
</Menu> </Menu>
</Box> </Box>
@@ -146,7 +154,7 @@ function ResponsiveAppBar() {
flexGrow: 1, flexGrow: 1,
display: { xs: "none", md: "flex" }, display: { xs: "none", md: "flex" },
alignItems: "center", alignItems: "center",
gap: "0.2rem" gap: "0.2rem",
}} }}
> >
<LoginButton /> <LoginButton />
@@ -154,15 +162,132 @@ function ResponsiveAppBar() {
<UploadButton /> <UploadButton />
<DiscordButton /> <DiscordButton />
<GitHubButton /> <GitHubButton />
<CCPButton />
<SupportButton />
<SettingsButton /> <SettingsButton />
<CompactModeButton /> <Button onClick={() => setFaqOpen(true)} color="inherit">
<PlanModeButton /> FAQ
<AlertModeButton /> </Button>
<CCPButton />
</Box> </Box>
</Toolbar> </Toolbar>
</Container> </Container>
<Dialog
open={faqOpen}
onClose={() => setFaqOpen(false)}
aria-labelledby="faq-dialog-title"
>
<DialogTitle id="faq-dialog-title">
Frequently Asked Questions
</DialogTitle>
<DialogContent>
<DialogContentText>
<strong>EVE Online Partner Code</strong>
<br />
Consider using my partner code for CCP related purchases to support
this project:
<Button
href=""
style={{ width: "100%" }}
sx={{ color: "white", display: "block" }}
onClick={() => {
navigator.clipboard.writeText("CALLIEVE");
}}
>
CALLIEVE
</Button>{" "}
Click button above to copy to clipboard.
<br />
<br />
<strong>What is this application?</strong>
<br />
This EVE Online Planetary Interaction tool that helps you track and
manage your colonies and production chains. Main usecase is to see
if your extractors are running.
<br />
<br />
<strong>How do I add characters?</strong>
<br />
You can add characters by clicking the &quot;Add Character&quot;
button in the app bar and following the authentication process.
<br />
<br />
<strong>Why don&apos;t my storage numbers add up?</strong>
<br />
EVE Online API (ESI) provides planetary interaction endpoints. These
are updated when you submit changes to planet. For example after an
extractor restart.
<br />
<br />
<strong>What does exclude mean?</strong>
<br />
Exclude means that this planet will not be counted in totals. This
is useful if you have longer production chains where exports of a
planet are consumed by another planet.
<br />
<br />
<strong>How do see my planets production chains?</strong>
<br />
Click on the planet row to open the extraction simulation.
<br />
<br />
<strong>What is Compact Mode?</strong>
<br />
Compact Mode reduces the size of character cards to show more
information at once. You can toggle it in the settings.
<br />
<br />
<strong>What is Alert Mode?</strong>
<br />
Alert mode shows only the planets that have extractors offline and
need attention.
<br />
<br />
<strong>What does off-blanace mean?</strong>
<br />
Off-blanace alert shows up for planets that have two extractors that
are extracting different amount of material. Treshold can be set in
settings. Generally you want to keep this below 1000.
<br />
<br />
<strong>How do I reorder accounts?</strong>
<br />
You can drag and drop account cards to reorder them. The order will
be saved automatically.
<br />
<br />
<strong>How do I add a character to account groups?</strong>
<br />
You can add a character to an account group by clicking the cog on
the character card and typing in the account/group name.
<br />
<br />
<strong>I like icons! Why so much text?</strong>
<br />
Toggle this option in settings.
<br />
<br />
<strong>I like colors! Why your alert colors are so ugly?</strong>
<br />
Change the color scheme in settings.
<br />
<br />
<strong>What does the 3D view do?</strong>
<br />
Nothing. Just made it for fun
<br />
<br />
<strong>Why are planet settings empty?</strong>
<br />
Its a work in progress feature. Plan is to be able to configuer
planet and planet exports to belong to production chains.
<br />
<br />
</DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={() => setFaqOpen(false)}>Close</Button>
</DialogActions>
</Dialog>
</AppBar> </AppBar>
); );
} }

View File

@@ -7,16 +7,18 @@ import { styled, useTheme } from "@mui/material/styles";
import React from "react"; import React from "react";
import { CharacterDialog } from "./CharacterDialog"; import { CharacterDialog } from "./CharacterDialog";
import { AccessToken } from "@/types"; 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 { EVE_IMAGE_URL } from "@/const";
import { CharacterContext } from "@/app/context/Context"; import { CharacterContext } from "@/app/context/Context";
const StackItem = styled(Stack)(({ theme }) => ({ const StackItem = styled(Stack)(({ theme }) => ({
...theme.typography.body2, ...theme.typography.body2,
padding: theme.custom.compactMode ? theme.spacing(1) : theme.spacing(2), padding: theme.custom.compactMode ? theme.spacing(1) : theme.spacing(2),
display: "flex",
textAlign: "left", textAlign: "left",
justifyContent: "center", justifyContent: "flex-start",
alignItems: "center", alignItems: "flex-start",
})); }));
export const CharacterRow = ({ character }: { character: AccessToken }) => { export const CharacterRow = ({ character }: { character: AccessToken }) => {
@@ -29,8 +31,6 @@ export const CharacterRow = ({ character }: { character: AccessToken }) => {
return ( return (
<StackItem <StackItem
key={character.character.characterId} key={character.character.characterId}
alignItems="flex-start"
justifyContent="flex-start"
> >
<CharacterDialog <CharacterDialog
character={selectedCharacter} character={selectedCharacter}
@@ -38,13 +38,49 @@ export const CharacterRow = ({ character }: { character: AccessToken }) => {
updateCharacter={updateCharacter} updateCharacter={updateCharacter}
closeDialog={() => setSelectedCharacter(undefined)} 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}> <Tooltip title={character.comment}>
<Box <Box
display="flex" display="flex"
flexDirection="column" flexDirection="column"
maxWidth={120} maxWidth={120}
onClick={() => setSelectedCharacter(character)} 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 <Image
unoptimized unoptimized
src={`${EVE_IMAGE_URL}/characters/${character.character.characterId}/portrait?size=128`} 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} height={theme.custom.cardImageSize}
style={{ marginBottom: "0.2rem", borderRadius: 8 }} style={{ marginBottom: "0.2rem", borderRadius: 8 }}
/> />
<Button
style={{
padding: 6,
fontSize: theme.custom.smallText,
lineHeight: 1,
}}
variant="outlined"
>
{character.character.name}
</Button>
</Box> </Box>
</Tooltip> </Tooltip>
</StackItem> </StackItem>

View File

@@ -1,21 +0,0 @@
import { SessionContext } from "@/app/context/Context";
import { Button, Tooltip } from "@mui/material";
import { useContext } from "react";
export const CompactModeButton = () => {
const { compactMode, toggleCompactMode } = useContext(SessionContext);
return (
<Tooltip title="Toggle compact layout for widescreen">
<Button
style={{
backgroundColor: compactMode
? "rgba(144, 202, 249, 0.08)"
: "inherit",
}}
onClick={toggleCompactMode}
>
Compact mode
</Button>
</Tooltip>
);
};

View File

@@ -6,15 +6,21 @@ import {
ThemeProvider, ThemeProvider,
createTheme, createTheme,
Button, Button,
Tooltip,
} from "@mui/material"; } from "@mui/material";
import { AccountCard } from "./Account/AccountCard"; import { AccountCard } from "./Account/AccountCard";
import { AccessToken } from "@/types"; import { AccessToken } from "@/types";
import { CharacterContext, SessionContext } from "../context/Context"; import { CharacterContext, SessionContext } from "../context/Context";
import ResponsiveAppBar from "./AppBar/AppBar"; import ResponsiveAppBar from "./AppBar/AppBar";
import { Summary } from "./Summary/Summary"; import { Summary } from "./Summary/Summary";
import { DragDropContext, Droppable, Draggable, DropResult } from "@hello-pangea/dnd"; import {
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown'; DragDropContext,
import KeyboardArrowUpIcon from '@mui/icons-material/KeyboardArrowUp'; Droppable,
Draggable,
DropResult,
} from "@hello-pangea/dnd";
import KeyboardArrowDownIcon from "@mui/icons-material/KeyboardArrowDown";
import KeyboardArrowUpIcon from "@mui/icons-material/KeyboardArrowUp";
interface Grouped { interface Grouped {
[key: string]: AccessToken[]; [key: string]: AccessToken[];
@@ -43,6 +49,7 @@ declare module "@mui/material/styles" {
export const MainGrid = () => { export const MainGrid = () => {
const { characters, updateCharacter } = useContext(CharacterContext); const { characters, updateCharacter } = useContext(CharacterContext);
const { compactMode, toggleCompactMode, alertMode, toggleAlertMode, planMode, togglePlanMode } = useContext(SessionContext);
const [accountOrder, setAccountOrder] = useState<string[]>([]); const [accountOrder, setAccountOrder] = useState<string[]>([]);
const [allCollapsed, setAllCollapsed] = useState(false); const [allCollapsed, setAllCollapsed] = useState(false);
@@ -54,15 +61,19 @@ export const MainGrid = () => {
group[account ?? ""] = group[account ?? ""] ?? []; group[account ?? ""] = group[account ?? ""] ?? [];
group[account ?? ""].push(character); group[account ?? ""].push(character);
return group; return group;
}, {}) }, {}),
); );
const savedOrder = localStorage.getItem('accountOrder'); const savedOrder = localStorage.getItem("accountOrder");
if (savedOrder) { if (savedOrder) {
try { try {
const parsedOrder = JSON.parse(savedOrder); const parsedOrder = JSON.parse(savedOrder);
const validOrder = parsedOrder.filter((account: string) => currentAccounts.includes(account)); const validOrder = parsedOrder.filter((account: string) =>
const newAccounts = currentAccounts.filter(account => !validOrder.includes(account)); currentAccounts.includes(account),
);
const newAccounts = currentAccounts.filter(
(account) => !validOrder.includes(account),
);
setAccountOrder([...validOrder, ...newAccounts]); setAccountOrder([...validOrder, ...newAccounts]);
} catch (e) { } catch (e) {
setAccountOrder(currentAccounts); setAccountOrder(currentAccounts);
@@ -74,7 +85,7 @@ export const MainGrid = () => {
useEffect(() => { useEffect(() => {
if (accountOrder.length > 0) { if (accountOrder.length > 0) {
localStorage.setItem('accountOrder', JSON.stringify(accountOrder)); localStorage.setItem("accountOrder", JSON.stringify(accountOrder));
} }
}, [accountOrder]); }, [accountOrder]);
@@ -85,7 +96,6 @@ export const MainGrid = () => {
return group; return group;
}, {}); }, {});
const { compactMode } = useContext(SessionContext);
const [darkTheme, setDarkTheme] = useState( const [darkTheme, setDarkTheme] = useState(
createTheme({ createTheme({
palette: { palette: {
@@ -138,14 +148,62 @@ export const MainGrid = () => {
<Box sx={{ flexGrow: 1 }}> <Box sx={{ flexGrow: 1 }}>
<ResponsiveAppBar /> <ResponsiveAppBar />
{compactMode ? <></> : <Summary characters={characters} />} {compactMode ? <></> : <Summary characters={characters} />}
<Box sx={{ display: 'flex', justifyContent: 'flex-start', padding: 1 }}> <Box
sx={{
display: "flex",
justifyContent: "flex-start",
padding: 1,
gap: 1,
}}
>
<Button <Button
startIcon={allCollapsed ? <KeyboardArrowDownIcon /> : <KeyboardArrowUpIcon />} startIcon={
allCollapsed ? <KeyboardArrowDownIcon /> : <KeyboardArrowUpIcon />
}
onClick={() => setAllCollapsed(!allCollapsed)} onClick={() => setAllCollapsed(!allCollapsed)}
size="small" size="small"
> >
{allCollapsed ? 'Expand All' : 'Collapse All'} {allCollapsed ? "Expand All" : "Collapse All"}
</Button> </Button>
<Tooltip title="Toggle compact layout for widescreen">
<Button
size="small"
style={{
backgroundColor: compactMode
? "rgba(144, 202, 249, 0.08)"
: "inherit",
}}
onClick={toggleCompactMode}
>
Compact mode
</Button>
</Tooltip>
<Tooltip title="Toggle alert mode to show only accounts and planets that need action.">
<Button
size="small"
style={{
backgroundColor: alertMode
? "rgba(144, 202, 249, 0.08)"
: "inherit",
}}
onClick={toggleAlertMode}
>
Alert mode
</Button>
</Tooltip>
<Tooltip title="Toggle plan mode that show layout for widescreen">
<Button
size="small"
style={{
backgroundColor: planMode
? "rgba(144, 202, 249, 0.08)"
: "inherit",
}}
onClick={togglePlanMode}
>
Plan mode
</Button>
</Tooltip>
</Box> </Box>
<DragDropContextComponent onDragEnd={handleDragEnd}> <DragDropContextComponent onDragEnd={handleDragEnd}>
<DroppableComponent droppableId="accounts"> <DroppableComponent droppableId="accounts">
@@ -153,7 +211,7 @@ export const MainGrid = () => {
<Grid <Grid
container container
spacing={1} spacing={1}
sx={{ padding: 1 }} sx={{ padding: 1, width: "100%" }}
{...provided.droppableProps} {...provided.droppableProps}
ref={provided.innerRef} ref={provided.innerRef}
> >
@@ -172,17 +230,18 @@ export const MainGrid = () => {
{...provided.draggableProps} {...provided.draggableProps}
{...provided.dragHandleProps} {...provided.dragHandleProps}
sx={{ sx={{
'& > *': { "& > *": {
width: '100%', width: "100%",
}, },
}} }}
> >
{groupByAccount[account] && groupByAccount[account].length > 0 && ( {groupByAccount[account] &&
<AccountCard groupByAccount[account].length > 0 && (
characters={groupByAccount[account]} <AccountCard
isCollapsed={allCollapsed} characters={groupByAccount[account]}
/> isCollapsed={allCollapsed}
)} />
)}
</Grid> </Grid>
)} )}
</DraggableComponent> </DraggableComponent>

View File

@@ -1,15 +0,0 @@
import { SessionContext } from "@/app/context/Context";
import { Button, Tooltip } from "@mui/material";
import { useContext } from "react";
export const PlanModeButton = () => {
const { planMode, togglePlanMode } = useContext(SessionContext);
return (
<Tooltip title="Toggle plan mode that show layout for widescreen">
<Button onClick={togglePlanMode} style={{backgroundColor: planMode ? 'rgba(144, 202, 249, 0.08)' : 'inherit'}}>
Plan mode
</Button>
</Tooltip>
);
};

View File

@@ -1,5 +1,5 @@
import { ColorContext, SessionContext } from "@/app/context/Context"; import { ColorContext, SessionContext } from "@/app/context/Context";
import { PI_TYPES_MAP, STORAGE_IDS, STORAGE_CAPACITIES, PI_PRODUCT_VOLUMES } from "@/const"; import { PI_TYPES_MAP, STORAGE_IDS, STORAGE_CAPACITIES, PI_PRODUCT_VOLUMES, EVE_IMAGE_URL } from "@/const";
import { planetCalculations } from "@/planets"; import { planetCalculations } from "@/planets";
import { AccessToken, PlanetWithInfo } from "@/types"; import { AccessToken, PlanetWithInfo } from "@/types";
import CloseIcon from "@mui/icons-material/Close"; import CloseIcon from "@mui/icons-material/Close";
@@ -41,6 +41,7 @@ export const PlanetTableRow = ({
character: AccessToken; character: AccessToken;
}) => { }) => {
const theme = useTheme(); const theme = useTheme();
const { showProductIcons } = useContext(SessionContext);
const [planetRenderOpen, setPlanetRenderOpen] = useState(false); const [planetRenderOpen, setPlanetRenderOpen] = useState(false);
const [planetConfigOpen, setPlanetConfigOpen] = useState(false); const [planetConfigOpen, setPlanetConfigOpen] = useState(false);
@@ -153,6 +154,39 @@ export const PlanetTableRow = ({
}); });
}; };
const renderProductDisplay = (typeId: number, amount?: number) => {
if (showProductIcons) {
return (
<div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", width: "100%" }}>
<Image
src={`${EVE_IMAGE_URL}/types/${typeId}/icon?size=32`}
alt={PI_TYPES_MAP[typeId].name}
width={32}
height={32}
style={{ marginRight: "5px" }}
/>
{amount !== undefined && (
<Typography fontSize={theme.custom.smallText} style={{ marginLeft: "5px", flexShrink: 0 }}>
{amount}
</Typography>
)}
</div>
);
}
return (
<div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", width: "100%" }}>
<Typography fontSize={theme.custom.smallText}>
{PI_TYPES_MAP[typeId].name}
</Typography>
{amount !== undefined && (
<Typography fontSize={theme.custom.smallText} style={{ marginLeft: "5px", flexShrink: 0 }}>
{amount}
</Typography>
)}
</div>
);
};
return ( return (
<> <>
<TableRow <TableRow
@@ -238,11 +272,12 @@ export const PlanetTableRow = ({
<TableCell className="clickable-cell">{planet.upgrade_level}</TableCell> <TableCell className="clickable-cell">{planet.upgrade_level}</TableCell>
<TableCell className="clickable-cell"> <TableCell className="clickable-cell">
<div style={{ display: "flex", flexDirection: "column" }}> <div style={{ display: "flex", flexDirection: "column" }}>
{extractors.length === 0 &&<Typography fontSize={theme.custom.smallText}>No extractors</Typography>}
{extractors.map((e, idx) => { {extractors.map((e, idx) => {
return ( return (
<div <div
key={`${e}-${idx}-${character.character.characterId}`} key={`${e}-${idx}-${character.character.characterId}`}
style={{ display: "flex" }} style={{ display: "flex", alignItems: "center" }}
> >
<Typography <Typography
color={timeColor(e.expiry_time, colors)} color={timeColor(e.expiry_time, colors)}
@@ -258,12 +293,7 @@ export const PlanetTableRow = ({
"STOPPED" "STOPPED"
)} )}
</Typography> </Typography>
<Typography fontSize={theme.custom.smallText}> {renderProductDisplay(e.extractor_details?.product_type_id ?? 0)}
{
PI_TYPES_MAP[e.extractor_details?.product_type_id ?? 0]
?.name
}
</Typography>
</div> </div>
); );
})} })}
@@ -273,12 +303,12 @@ export const PlanetTableRow = ({
<div style={{ display: "flex", flexDirection: "column" }}> <div style={{ display: "flex", flexDirection: "column" }}>
{Array.from(localProduction).map((schematic, idx) => { {Array.from(localProduction).map((schematic, idx) => {
return ( return (
<Typography <div
key={`prod-${character.character.characterId}-${planet.planet_id}-${idx}`} key={`prod-${character.character.characterId}-${planet.planet_id}-${idx}`}
fontSize={theme.custom.smallText} style={{ display: "flex", alignItems: "center" }}
> >
{schematic[1].name} {renderProductDisplay(schematic[1].outputs[0].type_id)}
</Typography> </div>
); );
})} })}
</div> </div>
@@ -286,24 +316,24 @@ export const PlanetTableRow = ({
<TableCell className="clickable-cell"> <TableCell className="clickable-cell">
<div style={{ display: "flex", flexDirection: "column" }}> <div style={{ display: "flex", flexDirection: "column" }}>
{localImports.map((i) => ( {localImports.map((i) => (
<Typography <div
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} style={{ display: "flex", alignItems: "center" }}
> >
{PI_TYPES_MAP[i.type_id].name} ({i.quantity * i.factoryCount}/h) {renderProductDisplay(i.type_id, i.quantity * i.factoryCount)}
</Typography> </div>
))} ))}
</div> </div>
</TableCell> </TableCell>
<TableCell className="clickable-cell"> <TableCell className="clickable-cell">
<div style={{ display: "flex", flexDirection: "column" }}> <div style={{ display: "flex", flexDirection: "column" }}>
{localExports.map((exports) => ( {localExports.map((exports) => (
<Typography <div
key={`export-${character.character.characterId}-${planet.planet_id}-${exports.typeId}`} key={`export-${character.character.characterId}-${planet.planet_id}-${exports.typeId}`}
fontSize={theme.custom.smallText} style={{ display: "flex", alignItems: "center" }}
> >
{PI_TYPES_MAP[exports.typeId].name} {renderProductDisplay(exports.typeId, exports.amount)}
</Typography> </div>
))} ))}
</div> </div>
</TableCell> </TableCell>
@@ -371,6 +401,7 @@ export const PlanetTableRow = ({
</TableCell> </TableCell>
<TableCell className="clickable-cell"> <TableCell className="clickable-cell">
<div style={{ display: "flex", flexDirection: "column" }}> <div style={{ display: "flex", flexDirection: "column" }}>
{storageFacilities.length === 0 &&<Typography fontSize={theme.custom.smallText}>No storage</Typography>}
{storageFacilities {storageFacilities
.sort((a, b) => { .sort((a, b) => {
const isALaunchpad = a.type_id === 2256 || a.type_id === 2542 || a.type_id === 2543 || a.type_id === 2544 || a.type_id === 2552 || a.type_id === 2555 || a.type_id === 2556 || a.type_id === 2557; const isALaunchpad = a.type_id === 2256 || a.type_id === 2542 || a.type_id === 2543 || a.type_id === 2544 || a.type_id === 2552 || a.type_id === 2555 || a.type_id === 2556 || a.type_id === 2557;

View File

@@ -36,8 +36,8 @@ const PlanetaryIteractionTable = ({
return ( return (
<StackItem width="100%"> <StackItem width="100%">
<TableContainer component={Paper}> <TableContainer component={Paper} sx={{ width: '100%' }}>
<Table size="small" aria-label="a dense table"> <Table size="small" aria-label="a dense table" sx={{ width: '100%' }}>
<TableHead> <TableHead>
<TableRow> <TableRow>
<TableCell width="8%"> <TableCell width="8%">
@@ -84,8 +84,8 @@ const PlanetaryIteractionTable = ({
</Tooltip> </Tooltip>
</TableCell> </TableCell>
<TableCell width="2%"> <TableCell width="2%">
<Tooltip title="How many units per hour factories are producing"> <Tooltip title="How many units per hour factories are producing on this planet">
<Typography fontSize={theme.custom.smallText}>u/h</Typography> <Typography fontSize={theme.custom.smallText}>uph</Typography>
</Tooltip> </Tooltip>
</TableCell> </TableCell>
<TableCell width="4%" align="right"> <TableCell width="4%" align="right">
@@ -98,7 +98,7 @@ const PlanetaryIteractionTable = ({
<TableCell width="10%"> <TableCell width="10%">
<Tooltip title="Storage facility fill rate"> <Tooltip title="Storage facility fill rate">
<Typography fontSize={theme.custom.smallText}> <Typography fontSize={theme.custom.smallText}>
Storage Fill rate Storage%
</Typography> </Typography>
</Tooltip> </Tooltip>
</TableCell> </TableCell>
@@ -159,8 +159,8 @@ export const PlanetaryInteractionRow = ({
const theme = useTheme(); const theme = useTheme();
return theme.custom.compactMode ? ( 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>
); );
}; };

View File

@@ -13,13 +13,15 @@ import {
Typography, Typography,
TextField, TextField,
Box, Box,
FormControlLabel,
Checkbox,
} from "@mui/material"; } from "@mui/material";
import { ColorChangeHandler, ColorResult, CompactPicker } from "react-color"; import { ColorChangeHandler, ColorResult, CompactPicker } from "react-color";
import React, { useState, useContext } from "react"; import React, { useState, useContext } from "react";
export const SettingsButton = () => { export const SettingsButton = () => {
const { colors, setColors } = useContext(ColorContext); const { colors, setColors } = useContext(ColorContext);
const { balanceThreshold, setBalanceThreshold } = useContext(SessionContext); const { balanceThreshold, setBalanceThreshold, showProductIcons, setShowProductIcons } = useContext(SessionContext);
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const handleClickOpen = () => { const handleClickOpen = () => {
@@ -45,6 +47,10 @@ export const SettingsButton = () => {
} }
}; };
const handleShowProductIconsChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setShowProductIcons(event.target.checked);
};
return ( return (
<Tooltip title="Toggle settings dialog"> <Tooltip title="Toggle settings dialog">
<> <>
@@ -57,13 +63,24 @@ export const SettingsButton = () => {
aria-labelledby="alert-dialog-title" aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description" aria-describedby="alert-dialog-description"
> >
<DialogTitle id="alert-dialog-title"> <DialogTitle id="alert-dialog-title">
{"Settings"} {"Settings"}
</DialogTitle> </DialogTitle>
<DialogContent style={{ paddingTop: "1rem" }}> <DialogContent style={{ paddingTop: "1rem" }}>
<Box sx={{ mt: 2 }}> <Box sx={{ mt: 2 }}>
<Typography variant="subtitle1">Display Settings</Typography>
<FormControlLabel
control={
<Checkbox
checked={showProductIcons}
onChange={handleShowProductIconsChange}
/>
}
label="Show product icons instead of names"
/>
</Box>
<Box sx={{ mt: 2 }}>
<Typography variant="subtitle1">Balance Threshold</Typography> <Typography variant="subtitle1">Balance Threshold</Typography>
<TextField <TextField
type="number" type="number"
@@ -87,7 +104,6 @@ export const SettingsButton = () => {
</div> </div>
); );
})} })}
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>
<Button onClick={handleClose}>Close</Button> <Button onClick={handleClose}>Close</Button>

View File

@@ -199,8 +199,8 @@ export const Summary = ({ characters }: { characters: AccessToken[] }) => {
sx={{ width: '100px' }} sx={{ width: '100px' }}
/> />
</Box> </Box>
<TableContainer component={Paper}> <TableContainer component={Paper} sx={{ width: '100%' }}>
<Table size="small" aria-label="a dense table"> <Table size="small" aria-label="a dense table" sx={{ width: '100%' }}>
<TableHead> <TableHead>
<TableRow> <TableRow>
<TableCell width="20%"> <TableCell width="20%">

View File

@@ -1,23 +0,0 @@
import { Box, Button, Tooltip } from "@mui/material";
export const SupportButton = () => {
return (
<Box>
<Tooltip
title={`
Consider using code 'CALLIEVE' on EVE store checkout to support the project! Click to copy to clipboard ;)
`}
>
<Button
href=""
style={{ width: "100%" }}
sx={{ color: "white", display: "block" }}
onClick={() => {
navigator.clipboard.writeText("CALLIEVE");
}}
>
CALLIEVE
</Button>
</Tooltip>
</Box>
);
};

View File

@@ -37,6 +37,8 @@ export const SessionContext = createContext<{
}) => PlanetConfig; }) => PlanetConfig;
balanceThreshold: number; balanceThreshold: number;
setBalanceThreshold: Dispatch<SetStateAction<number>>; setBalanceThreshold: Dispatch<SetStateAction<number>>;
showProductIcons: boolean;
setShowProductIcons: (show: boolean) => void;
}>({ }>({
sessionReady: false, sessionReady: false,
refreshSession: () => {}, refreshSession: () => {},
@@ -62,7 +64,10 @@ export const SessionContext = createContext<{
}, },
balanceThreshold: 1000, balanceThreshold: 1000,
setBalanceThreshold: () => {}, setBalanceThreshold: () => {},
showProductIcons: false,
setShowProductIcons: () => {},
}); });
export type ColorSelectionType = { export type ColorSelectionType = {
defaultColor: string; defaultColor: string;
expiredColor: string; expiredColor: string;
@@ -84,6 +89,7 @@ export const defaultColors = {
dayColor: "#2F695A", dayColor: "#2F695A",
twoDaysColor: "#2F695A", twoDaysColor: "#2F695A",
}; };
export const ColorContext = createContext<{ export const ColorContext = createContext<{
colors: ColorSelectionType; colors: ColorSelectionType;
setColors: (colors: ColorSelectionType) => void; setColors: (colors: ColorSelectionType) => void;

View File

@@ -30,6 +30,7 @@ const Home = () => {
undefined, undefined,
); );
const [balanceThreshold, setBalanceThreshold] = useState(1000); const [balanceThreshold, setBalanceThreshold] = useState(1000);
const [showProductIcons, setShowProductIcons] = useState(false);
const [colors, setColors] = useState<ColorSelectionType>(defaultColors); const [colors, setColors] = useState<ColorSelectionType>(defaultColors);
const [alertMode, setAlertMode] = useState(false); const [alertMode, setAlertMode] = useState(false);
@@ -248,7 +249,7 @@ const Home = () => {
}, []); }, []);
useEffect(() => { useEffect(() => {
const ESI_CACHE_TIME_MS = 600000; const ESI_CACHE_TIME_MS = 3000000;
const interval = setInterval(() => { const interval = setInterval(() => {
const characters = initializeCharacters(); const characters = initializeCharacters();
refreshSession(characters) refreshSession(characters)
@@ -278,6 +279,8 @@ const Home = () => {
readPlanetConfig, readPlanetConfig,
balanceThreshold, balanceThreshold,
setBalanceThreshold, setBalanceThreshold,
showProductIcons,
setShowProductIcons,
}} }}
> >
<CharacterContext.Provider <CharacterContext.Provider