refactored ProgressCard to component

This commit is contained in:
2026-04-24 14:04:24 +05:30
parent b1509fd5ab
commit 49bdb85088
5 changed files with 82 additions and 25 deletions

View File

@@ -0,0 +1,7 @@
export interface ProgressCardProps {
header: string;
summary?: string;
progressAmount: number;
totalAmount: number;
colorTheme?: "primary" | "secondary" | "error" | "info" | "success" | "warning";
}

View File

@@ -0,0 +1,23 @@
import ProgressCardView from "./ProgressCard.view";
import { ProgressCardProps } from "./ProgressCard.models";
import { getPercentage, parseSummary } from "./ProgressCard.utils";
export default function ProgressCard(props: ProgressCardProps) {
const { progressAmount, totalAmount, summary } = props;
const percentage = getPercentage(progressAmount, totalAmount);
const { prefixAmount, suffixString } = parseSummary(
summary,
progressAmount,
totalAmount
);
return (
<ProgressCardView
{...props}
percentage={percentage}
prefixAmount={prefixAmount}
suffixString={suffixString}
/>
);
}

View File

@@ -0,0 +1,19 @@
export const getPercentage = (progressAmount: number, totalAmount: number) => {
if (!totalAmount) return 0;
return Math.min(100, Math.max(0, (progressAmount / totalAmount) * 100));
};
export const parseSummary = (
summary: string | undefined,
progressAmount: number,
totalAmount: number
) => {
const displaySummary = summary ?? `Rs ${progressAmount} / Rs ${totalAmount}`;
const parts = displaySummary.split("/");
const prefixAmount = parts[0]?.trim() || "";
const suffixString =
parts.length > 1 ? `/ ${parts.slice(1).join("/").trim()}` : "";
return { prefixAmount, suffixString };
};

View File

@@ -0,0 +1,86 @@
import * as React from "react";
import {
Box,
Typography,
Paper,
LinearProgress,
linearProgressClasses
} from "@mui/material";
import { ProgressCardProps } from "./ProgressCard.models";
interface ViewProps extends ProgressCardProps {
percentage: number;
prefixAmount: string;
suffixString: string;
}
export default function ProgressCardView({
header,
colorTheme = "info",
percentage,
prefixAmount,
suffixString,
}: ViewProps) {
return (
<Paper
elevation={4}
sx={{
width: "100%",
p: { xs: 3, md: 4 },
borderRadius: 4,
background: (theme) =>
colorTheme === "info"
? "linear-gradient(135deg, #0284c7 0%, #06b6d4 100%)"
: `linear-gradient(135deg, ${theme.palette[colorTheme].main} 0%, ${theme.palette[colorTheme].light} 100%)`,
color: "#fff",
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
position: "relative",
overflow: "hidden",
boxShadow: (theme) =>
`0 12px 24px -10px ${
theme.palette.mode === "dark"
? "#000"
: theme.palette[colorTheme].main
}`,
}}
>
<Typography variant="subtitle1" fontWeight={600} sx={{ opacity: 0.9, mb: 1 }}>
{header}
</Typography>
<Typography variant="h3" fontWeight={800} sx={{ mb: 3 }}>
{prefixAmount}{" "}
{suffixString && (
<Typography
component="span"
variant="subtitle1"
sx={{ opacity: 0.7, fontWeight: 500 }}
>
{suffixString}
</Typography>
)}
</Typography>
<Box sx={{ width: "85%" }}>
<LinearProgress
variant="determinate"
value={percentage}
sx={{
height: 10,
borderRadius: 5,
[`&.${linearProgressClasses.colorPrimary}`]: {
backgroundColor: "rgba(0, 0, 0, 0.2)",
},
[`& .${linearProgressClasses.bar}`]: {
borderRadius: 5,
backgroundColor: "#fff",
},
}}
/>
</Box>
</Paper>
);
}

View File

@@ -0,0 +1,2 @@
export { default } from "./LatestItems";
export * from "./LatestItems.models";