Remove scrollbars and last updated

This commit is contained in:
2025-01-01 14:08:50 -05:00
parent 6c7aed68cc
commit 42f5033173
2 changed files with 185 additions and 174 deletions

View File

@@ -63,7 +63,7 @@ const PinProtectedLayout = ({ children }) => {
// Small Layout
const SmallLayout = () => {
const DATETIME_SCALE = 2;
const STATS_SCALE = 1.6;
const STATS_SCALE = 1.65;
return (
<div className="min-h-screen w-screen">
@@ -80,7 +80,7 @@ const SmallLayout = () => {
width: `${100/DATETIME_SCALE}%`,
}}
>
<DateTimeWeatherDisplay />
<DateTimeWeatherDisplay scaleFactor={DATETIME_SCALE} />
</div>
</div>

View File

@@ -32,7 +32,12 @@ import {
Loader2,
} from "lucide-react";
import { Skeleton } from "@/components/ui/skeleton";
import { Tooltip, TooltipContent, TooltipTrigger, TooltipProvider } from "@/components/ui/tooltip";
import {
Tooltip,
TooltipContent,
TooltipTrigger,
TooltipProvider,
} from "@/components/ui/tooltip";
import {
Table,
TableBody,
@@ -147,7 +152,7 @@ const MiniStatCards = ({
endDate,
title = "Quick Stats",
description = "",
compact = false
compact = false,
}) => {
const [stats, setStats] = useState(null);
const [loading, setLoading] = useState(true);
@@ -176,8 +181,10 @@ const MiniStatCards = ({
}, []);
const calculateRevenueTrend = useCallback(() => {
if (!stats?.prevPeriodRevenue && stats?.prevPeriodRevenue !== 0) return null;
const currentRevenue = stats.periodProgress < 100 ? stats.projectedRevenue : stats.revenue;
if (!stats?.prevPeriodRevenue && stats?.prevPeriodRevenue !== 0)
return null;
const currentRevenue =
stats.periodProgress < 100 ? stats.projectedRevenue : stats.revenue;
const prevRevenue = stats.prevPeriodRevenue;
if (!currentRevenue || !prevRevenue) return null;
@@ -213,8 +220,11 @@ const MiniStatCards = ({
setLoading(true);
setStats(null);
const params = timeRange === "custom" ? { startDate, endDate } : { timeRange };
const response = await axios.get("/api/klaviyo/events/stats", { params });
const params =
timeRange === "custom" ? { startDate, endDate } : { timeRange };
const response = await axios.get("/api/klaviyo/events/stats", {
params,
});
if (!isMounted) return;
@@ -248,8 +258,11 @@ const MiniStatCards = ({
try {
setProjectionLoading(true);
const params = timeRange === "custom" ? { startDate, endDate } : { timeRange };
const response = await axios.get("/api/klaviyo/events/projection", { params });
const params =
timeRange === "custom" ? { startDate, endDate } : { timeRange };
const response = await axios.get("/api/klaviyo/events/projection", {
params,
});
if (!isMounted) return;
setProjection(response.data);
@@ -275,8 +288,12 @@ const MiniStatCards = ({
const interval = setInterval(async () => {
try {
const [statsResponse, projectionResponse] = await Promise.all([
axios.get("/api/klaviyo/events/stats", { params: { timeRange: "today" } }),
axios.get("/api/klaviyo/events/projection", { params: { timeRange: "today" } }),
axios.get("/api/klaviyo/events/stats", {
params: { timeRange: "today" },
}),
axios.get("/api/klaviyo/events/projection", {
params: { timeRange: "today" },
}),
]);
setStats(statsResponse.data.stats);
@@ -291,7 +308,8 @@ const MiniStatCards = ({
}, [timeRange]);
// Add function to fetch detail data
const fetchDetailData = useCallback(async (metric) => {
const fetchDetailData = useCallback(
async (metric) => {
if (detailData[metric]) return;
setDetailDataLoading((prev) => ({ ...prev, [metric]: true }));
@@ -310,7 +328,9 @@ const MiniStatCards = ({
} finally {
setDetailDataLoading((prev) => ({ ...prev, [metric]: false }));
}
}, [detailData]);
},
[detailData]
);
// Add effect to load detail data when metric is selected
useEffect(() => {
@@ -323,7 +343,7 @@ const MiniStatCards = ({
useEffect(() => {
// Preload all detail data when component mounts
const metrics = ["revenue", "orders", "average_order", "shipping"];
metrics.forEach(metric => {
metrics.forEach((metric) => {
fetchDetailData(metric);
});
}, []); // eslint-disable-line react-hooks/exhaustive-deps
@@ -331,7 +351,6 @@ const MiniStatCards = ({
if (loading && !stats) {
return (
<Card className="w-full bg-white dark:bg-gray-900/60 backdrop-blur-sm">
<CardContent className="p-4 pt-0">
<div className="grid grid-cols-2 gap-2">
{[...Array(4)].map((_, i) => (
@@ -361,33 +380,6 @@ const MiniStatCards = ({
return (
<>
<div className="flex justify-between items-center">
<div>
{lastUpdate && !loading && (
<CardDescription className="text-xs">
Last updated {lastUpdate.toFormat("h:mm a")}
{projection?.confidence > 0 && !projectionLoading && (
<TooltipProvider>
<Tooltip delayDuration={300}>
<TooltipTrigger asChild>
<span className="ml-1 text-muted-foreground">
({Math.round(projection.confidence * 100)}%)
</span>
</TooltipTrigger>
<TooltipContent className="max-w-[250px]">
<p>Confidence level of revenue projection</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
)}
</CardDescription>
)}
</div>
</div>
<div className="grid grid-cols-4 gap-2">
<StatCard
title="Total Revenue"
@@ -399,14 +391,24 @@ const MiniStatCards = ({
{projectionLoading ? (
<Skeleton className="h-4 w-15" />
) : (
formatCurrency(projection?.projectedRevenue || stats.projectedRevenue)
formatCurrency(
projection?.projectedRevenue || stats.projectedRevenue
)
)}
</div>
) : null
}
progress={stats?.periodProgress < 100 ? stats.periodProgress : undefined}
trend={projectionLoading && stats?.periodProgress < 100 ? undefined : revenueTrend?.trend}
trendValue={revenueTrend?.value ? formatPercentage(revenueTrend.value) : null}
progress={
stats?.periodProgress < 100 ? stats.periodProgress : undefined
}
trend={
projectionLoading && stats?.periodProgress < 100
? undefined
: revenueTrend?.trend
}
trendValue={
revenueTrend?.value ? formatPercentage(revenueTrend.value) : null
}
colorClass="text-green-600 dark:text-green-400"
icon={DollarSign}
iconColor="text-green-500"
@@ -419,7 +421,9 @@ const MiniStatCards = ({
value={stats?.orderCount}
description={`${stats?.itemCount} items`}
trend={orderTrend?.trend}
trendValue={orderTrend?.value ? formatPercentage(orderTrend.value) : null}
trendValue={
orderTrend?.value ? formatPercentage(orderTrend.value) : null
}
colorClass="text-blue-600 dark:text-blue-400"
icon={ShoppingCart}
iconColor="text-blue-500"
@@ -453,7 +457,10 @@ const MiniStatCards = ({
/>
</div>
<Dialog open={!!selectedMetric} onOpenChange={() => setSelectedMetric(null)}>
<Dialog
open={!!selectedMetric}
onOpenChange={() => setSelectedMetric(null)}
>
<DialogContent className="w-[80vw] h-[80vh] max-w-none p-0">
<div className="transform scale-[2] origin-top-left h-[40vh] w-[40vw]">
<div className="h-full w-full p-6">
@@ -467,17 +474,21 @@ const MiniStatCards = ({
: ""}
</DialogTitle>
</DialogHeader>
<div className="mt-4 h-[calc(40vh-4rem)] overflow-auto">
<div className="mt-4 h-[calc(40vh-4rem)] overflow-auto [&::-webkit-scrollbar]:hidden [-ms-overflow-style:'none'] [scrollbar-width:'none']">
{detailDataLoading[selectedMetric] ? (
<div className="space-y-4 h-full">
{selectedMetric === "shipping" ? (
<MiniSkeletonTable rows={8} />
) : (
<>
<MiniSkeletonChart type={selectedMetric === "orders" ? "bar" : "line"} />
<MiniSkeletonChart
type={selectedMetric === "orders" ? "bar" : "line"}
/>
{selectedMetric === "orders" && (
<div className="mt-8">
<h3 className="text-lg font-medium mb-4">Hourly Distribution</h3>
<h3 className="text-lg font-medium mb-4">
Hourly Distribution
</h3>
<MiniSkeletonChart type="bar" />
</div>
)}