added logic to only show 7 or 6 bars based on daily period or not
This commit is contained in:
@@ -11,6 +11,9 @@ import {
|
||||
HistoryChartProps,
|
||||
ChartData,
|
||||
} from "../types/historyChart";
|
||||
import IconButton from "@mui/material/IconButton";
|
||||
import ChevronLeftIcon from "@mui/icons-material/ChevronLeft";
|
||||
import ChevronRightIcon from "@mui/icons-material/ChevronRight";
|
||||
|
||||
const formatDisplay = (
|
||||
point: ChartDataPoint,
|
||||
@@ -99,6 +102,32 @@ export default function HistoryChart({
|
||||
)
|
||||
: 1;
|
||||
|
||||
const [startIndex, setStartIndex] = React.useState(0);
|
||||
const visibleCount = activeDataKey == 'daily' ? 7 : 6;
|
||||
const total = currentData.length;
|
||||
|
||||
// clamp startIndex so we always show full 5 (when possible)
|
||||
const clampedStartIndex = Math.min(
|
||||
startIndex,
|
||||
Math.max(total - visibleCount, 0)
|
||||
);
|
||||
|
||||
const visibleData = currentData.slice(
|
||||
clampedStartIndex,
|
||||
clampedStartIndex + visibleCount
|
||||
);
|
||||
|
||||
const canGoLeft = startIndex > 0;
|
||||
const canGoRight = startIndex + visibleCount < currentData.length;
|
||||
|
||||
const handlePrev = () => {
|
||||
if (canGoLeft) setStartIndex((prev) => prev - visibleCount);
|
||||
};
|
||||
|
||||
const handleNext = () => {
|
||||
if (canGoRight) setStartIndex((prev) => prev + visibleCount);
|
||||
};
|
||||
|
||||
return (
|
||||
<Paper
|
||||
sx={{
|
||||
@@ -159,116 +188,158 @@ export default function HistoryChart({
|
||||
</ToggleButtonGroup>
|
||||
|
||||
{currentData.length > 0 ? (
|
||||
<Box sx={{ display: "flex", alignItems: "flex-end", height: 220, mt: 4 }}>
|
||||
{currentData.map((point) => {
|
||||
const currentHeight = (point.amount / maxAmount) * 100;
|
||||
const compareHeight = comparison
|
||||
? ((point.compareAmount || 0) / maxAmount) * 100
|
||||
: 0;
|
||||
const labelHeight = Math.max(currentHeight, compareHeight);
|
||||
<Box sx={{ position: "relative", mt: 4 }}>
|
||||
|
||||
return (
|
||||
<Box
|
||||
key={point.id}
|
||||
sx={{
|
||||
flex: 1,
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
justifyContent: "flex-end",
|
||||
height: "100%"
|
||||
}}
|
||||
>
|
||||
{/* LEFT ARROW */}
|
||||
{canGoLeft && (
|
||||
<IconButton
|
||||
onClick={handlePrev}
|
||||
size="small"
|
||||
sx={{
|
||||
position: "absolute",
|
||||
left: 0,
|
||||
top: "50%",
|
||||
transform: "translateY(-50%)",
|
||||
zIndex: 2,
|
||||
bgcolor: "background.paper",
|
||||
boxShadow: 1
|
||||
}}
|
||||
>
|
||||
<ChevronLeftIcon fontSize="small" />
|
||||
</IconButton>
|
||||
)}
|
||||
|
||||
{/* CHART */}
|
||||
<Box sx={{ display: "flex", alignItems: "flex-end", height: 220, mt: 4 }}>
|
||||
{visibleData.map((point) => {
|
||||
const currentHeight = (point.amount / maxAmount) * 100;
|
||||
const compareHeight = comparison
|
||||
? ((point.compareAmount || 0) / maxAmount) * 100
|
||||
: 0;
|
||||
const labelHeight = Math.max(currentHeight, compareHeight);
|
||||
|
||||
return (
|
||||
<Box
|
||||
key={point.id}
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "flex-end",
|
||||
gap: comparison ? 0.5 : 0,
|
||||
height: "100%",
|
||||
position: "relative"
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
variant="caption"
|
||||
sx={{
|
||||
position: "absolute",
|
||||
bottom: `${labelHeight}%`,
|
||||
left: "50%",
|
||||
transform: "translate(-50%, -6px)",
|
||||
fontSize: "0.65rem",
|
||||
whiteSpace: "nowrap",
|
||||
pointerEvents: "none"
|
||||
}}
|
||||
>
|
||||
{formatDisplay(point, activeTab.toLowerCase(), comparison)}
|
||||
</Typography>
|
||||
|
||||
{/* Compare */}
|
||||
{comparison && (
|
||||
<Box
|
||||
sx={{
|
||||
width: 6,
|
||||
height: `${compareHeight}%`,
|
||||
bgcolor: "grey.400",
|
||||
borderRadius: 2
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Spacer */}
|
||||
<Box sx={{ width: 4 }} />
|
||||
|
||||
{/* Current */}
|
||||
<Box
|
||||
sx={{
|
||||
width: 10,
|
||||
height: `${currentHeight}%`,
|
||||
bgcolor: point.highlighted ? "error.main" : "primary.main",
|
||||
borderRadius: 2
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
<Box
|
||||
sx={{
|
||||
mt: 1,
|
||||
textAlign: "center",
|
||||
flex: 1,
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
lineHeight: 1.1
|
||||
justifyContent: "flex-end",
|
||||
height: "100%"
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
variant="caption"
|
||||
<Box
|
||||
sx={{
|
||||
fontSize: "0.7rem",
|
||||
opacity: 0.7,
|
||||
color: "text.primary",
|
||||
display: "flex",
|
||||
alignItems: "flex-end",
|
||||
gap: comparison ? 0.5 : 0,
|
||||
height: "100%",
|
||||
position: "relative"
|
||||
}}
|
||||
>
|
||||
{formatLabel(point.id, activeDataKey)}
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="caption"
|
||||
sx={{
|
||||
position: "absolute",
|
||||
bottom: `${labelHeight}%`,
|
||||
left: "50%",
|
||||
transform: "translate(-50%, -6px)",
|
||||
fontSize: "0.65rem",
|
||||
whiteSpace: "nowrap",
|
||||
pointerEvents: "none"
|
||||
}}
|
||||
>
|
||||
{formatDisplay(point, activeTab.toLowerCase(), comparison)}
|
||||
</Typography>
|
||||
|
||||
<Typography
|
||||
variant="caption"
|
||||
{/* Compare */}
|
||||
{comparison && (
|
||||
<Box
|
||||
sx={{
|
||||
width: 6,
|
||||
height: `${compareHeight}%`,
|
||||
bgcolor: "grey.400",
|
||||
borderRadius: 2
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Spacer */}
|
||||
<Box sx={{ width: 4 }} />
|
||||
|
||||
{/* Current */}
|
||||
<Box
|
||||
sx={{
|
||||
width: 10,
|
||||
height: `${currentHeight}%`,
|
||||
bgcolor: point.highlighted ? "error.main" : "primary.main",
|
||||
borderRadius: 2
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
<Box
|
||||
sx={{
|
||||
fontSize: "0.65rem",
|
||||
color: "grey.400",
|
||||
visibility:
|
||||
comparison && point.compareLabel && activeDataKey !== "daily"
|
||||
? "visible"
|
||||
: "hidden"
|
||||
mt: 1,
|
||||
textAlign: "center",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
lineHeight: 1.1
|
||||
}}
|
||||
>
|
||||
{point.compareLabel
|
||||
? formatLabel(point.compareLabel, activeDataKey)
|
||||
: "placeholder"}
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="caption"
|
||||
sx={{
|
||||
fontSize: "0.7rem",
|
||||
opacity: 0.7,
|
||||
color: "text.primary",
|
||||
}}
|
||||
>
|
||||
{formatLabel(point.id, activeDataKey)}
|
||||
</Typography>
|
||||
|
||||
<Typography
|
||||
variant="caption"
|
||||
sx={{
|
||||
fontSize: "0.65rem",
|
||||
color: "grey.400",
|
||||
visibility:
|
||||
comparison && point.compareLabel && activeDataKey !== "daily"
|
||||
? "visible"
|
||||
: "hidden"
|
||||
}}
|
||||
>
|
||||
{point.compareLabel
|
||||
? formatLabel(point.compareLabel, activeDataKey)
|
||||
: "placeholder"}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
})}
|
||||
);
|
||||
})}
|
||||
</Box>
|
||||
|
||||
{/* RIGHT ARROW */}
|
||||
{canGoRight && (
|
||||
<IconButton
|
||||
onClick={handleNext}
|
||||
size="small"
|
||||
sx={{
|
||||
position: "absolute",
|
||||
right: 0,
|
||||
top: "50%",
|
||||
transform: "translateY(-50%)",
|
||||
zIndex: 2,
|
||||
bgcolor: "background.paper",
|
||||
boxShadow: 1
|
||||
}}
|
||||
>
|
||||
<ChevronRightIcon fontSize="small" />
|
||||
</IconButton>
|
||||
)}
|
||||
</Box>
|
||||
) : (
|
||||
<Box sx={{ height: 200, display: "flex", alignItems: "center", justifyContent: "center" }}>
|
||||
|
||||
Reference in New Issue
Block a user