fixed card size for dashboard cards
This commit is contained in:
parent
cc4cea0f27
commit
d3acf13c0a
@ -94,3 +94,36 @@
|
|||||||
.h-screen{ height: 100vh; }
|
.h-screen{ height: 100vh; }
|
||||||
.h-min { height: min-content; }
|
.h-min { height: min-content; }
|
||||||
.h-max { height: max-content; }
|
.h-max { height: max-content; }
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------Text------------------------- */
|
||||||
|
@media (min-width: 576px) {
|
||||||
|
.fs-sm-1 { font-size: calc(1.3rem + 1.6vw) !important; }
|
||||||
|
.fs-sm-2 { font-size: calc(1.2rem + 1.2vw) !important; }
|
||||||
|
.fs-sm-3 { font-size: calc(1.1rem + 0.8vw) !important; }
|
||||||
|
.fs-sm-4 { font-size: calc(1rem + 0.5vw) !important; }
|
||||||
|
.fs-sm-5 { font-size: 1.05rem !important; }
|
||||||
|
.fs-sm-6 { font-size: 0.9rem !important; }
|
||||||
|
|
||||||
|
.fs-sm-tiny { font-size: 72% !important; }
|
||||||
|
.fs-sm-big { font-size: 115% !important; }
|
||||||
|
.fs-sm-large { font-size: 155% !important; }
|
||||||
|
.fs-sm-xlarge { font-size: 175% !important; }
|
||||||
|
.fs-sm-xxlarge { font-size: calc(1.6rem + 3.5vw) !important; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 💻 Medium devices (≥768px) */
|
||||||
|
@media (min-width: 768px) {
|
||||||
|
.fs-md-1 { font-size: calc(1.4125rem + 1.95vw) !important; }
|
||||||
|
.fs-md-2 { font-size: calc(1.3625rem + 1.35vw) !important; }
|
||||||
|
.fs-md-3 { font-size: calc(1.3rem + 0.6vw) !important; }
|
||||||
|
.fs-md-4 { font-size: calc(1.275rem + 0.3vw) !important; }
|
||||||
|
.fs-md-5 { font-size: 1.125rem !important; }
|
||||||
|
.fs-md-6 { font-size: 0.9375rem !important; }
|
||||||
|
|
||||||
|
.fs-md-tiny { font-size: 70% !important; }
|
||||||
|
.fs-md-big { font-size: 112% !important; }
|
||||||
|
.fs-md-large { font-size: 150% !important; }
|
||||||
|
.fs-md-xlarge { font-size: 170% !important; }
|
||||||
|
.fs-md-xxlarge { font-size: calc(1.725rem + 5.7vw) !important; }
|
||||||
|
}
|
||||||
@ -7,17 +7,17 @@ import ChartSkeleton from "../Charts/Skelton";
|
|||||||
import { useSelectedProject } from "../../slices/apiDataManager";
|
import { useSelectedProject } from "../../slices/apiDataManager";
|
||||||
import { formatDate_DayMonth } from "../../utils/dateUtils";
|
import { formatDate_DayMonth } from "../../utils/dateUtils";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const AttendanceOverview = () => {
|
const AttendanceOverview = () => {
|
||||||
const [dayRange, setDayRange] = useState(7);
|
const [dayRange, setDayRange] = useState(7);
|
||||||
const [view, setView] = useState("chart");
|
const [view, setView] = useState("chart");
|
||||||
const selectedProject = useSelectedProject();
|
const selectedProject = useSelectedProject();
|
||||||
|
|
||||||
const { data: attendanceOverviewData, isLoading, isError, error } = useAttendanceOverviewData(
|
const {
|
||||||
selectedProject,
|
data: attendanceOverviewData,
|
||||||
dayRange
|
isLoading,
|
||||||
);
|
isError,
|
||||||
|
error,
|
||||||
|
} = useAttendanceOverviewData(selectedProject, dayRange);
|
||||||
|
|
||||||
// Use empty array while loading
|
// Use empty array while loading
|
||||||
const attendanceData = attendanceOverviewData || [];
|
const attendanceData = attendanceOverviewData || [];
|
||||||
@ -55,73 +55,129 @@ const AttendanceOverview = () => {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
const chartOptions = {
|
const chartOptions = {
|
||||||
chart: { type: "bar", stacked: true, height: 400, toolbar: { show: false } },
|
chart: {
|
||||||
|
type: "bar",
|
||||||
|
stacked: true,
|
||||||
|
height: 400,
|
||||||
|
toolbar: { show: false },
|
||||||
|
},
|
||||||
plotOptions: { bar: { borderRadius: 2, columnWidth: "60%" } },
|
plotOptions: { bar: { borderRadius: 2, columnWidth: "60%" } },
|
||||||
xaxis: { categories: tableData.map((row) => row.date) },
|
xaxis: { categories: tableData.map((row) => row.date) },
|
||||||
yaxis: { show: true, axisBorder: { show: true, color: "#78909C" }, axisTicks: { show: true, color: "#78909C", width: 6 } },
|
yaxis: {
|
||||||
|
show: true,
|
||||||
|
axisBorder: { show: true, color: "#78909C" },
|
||||||
|
axisTicks: { show: true, color: "#78909C", width: 6 },
|
||||||
|
},
|
||||||
legend: { position: "bottom" },
|
legend: { position: "bottom" },
|
||||||
fill: { opacity: 1 },
|
fill: { opacity: 1 },
|
||||||
colors: roles.map((_, i) => flatColors[i % flatColors.length]),
|
colors: roles.map((_, i) => flatColors[i % flatColors.length]),
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-white p-4 rounded shadow d-flex flex-column position-relative " >
|
<div className="bg-white p-4 rounded shadow d-flex flex-column position-relative">
|
||||||
{/* Optional subtle loading overlay */}
|
<div className="row mb-3 align-items-center">
|
||||||
{isLoading && (
|
<div className="col-md-6 text-start">
|
||||||
<div className="position-absolute w-100 h-100 d-flex align-items-center justify-content-center bg-white bg-opacity-50 z-index-1">
|
<p className="mb-1 fs-6 fs-md-5 fw-medium">Attendance Overview</p>
|
||||||
<span>Loading...</span>
|
<p className="card-subtitle text-muted mb-0">
|
||||||
|
Role-wise present count
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Header */}
|
<div className="col-md-6 d-flex flex-column align-items-end gap-2">
|
||||||
<div className="d-flex justify-content-between align-items-center mb-3">
|
<select
|
||||||
<div className="card-title mb-0 text-start">
|
className="form-select form-select-sm w-auto"
|
||||||
<h5 className="mb-1 card-title">Attendance Overview</h5>
|
value={dayRange}
|
||||||
<p className="card-subtitle">Role-wise present count</p>
|
onChange={(e) => setDayRange(Number(e.target.value))}
|
||||||
</div>
|
>
|
||||||
<div className="d-flex gap-2">
|
|
||||||
<select className="form-select form-select-sm" value={dayRange} onChange={(e) => setDayRange(Number(e.target.value))}>
|
|
||||||
<option value={7}>Last 7 Days</option>
|
<option value={7}>Last 7 Days</option>
|
||||||
<option value={15}>Last 15 Days</option>
|
<option value={15}>Last 15 Days</option>
|
||||||
<option value={30}>Last 30 Days</option>
|
<option value={30}>Last 30 Days</option>
|
||||||
</select>
|
</select>
|
||||||
<button className={`btn btn-sm p-1 ${view === "chart" ? "btn-primary" : "btn-outline-primary"}`} onClick={() => setView("chart")} title="Chart View">
|
|
||||||
<i className="bx bx-bar-chart-alt-2"></i>
|
<div className="d-flex gap-2 justify-content-end">
|
||||||
</button>
|
<button
|
||||||
<button className={`btn btn-sm p-1 ${view === "table" ? "btn-primary" : "btn-outline-primary"}`} onClick={() => setView("table")} title="Table View">
|
className={`btn btn-sm p-1 ${
|
||||||
<i className="bx bx-list-ul fs-5"></i>
|
view === "chart" ? "btn-primary" : "btn-outline-primary"
|
||||||
</button>
|
}`}
|
||||||
|
onClick={() => setView("chart")}
|
||||||
|
title="Chart View"
|
||||||
|
>
|
||||||
|
<i className="bx bx-bar-chart-alt-2 fs-5"></i>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
className={`btn btn-sm p-1 ${
|
||||||
|
view === "table" ? "btn-primary" : "btn-outline-primary"
|
||||||
|
}`}
|
||||||
|
onClick={() => setView("table")}
|
||||||
|
title="Table View"
|
||||||
|
>
|
||||||
|
<i className="bx bx-list-ul fs-5"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Content */}
|
{/* Content Section */}
|
||||||
<div className="flex-grow-1 d-flex align-items-center justify-content-center ">
|
<div className="flex-grow-1 d-flex align-items-center justify-content-center position-relative">
|
||||||
|
{isLoading && (
|
||||||
|
<div className="position-absolute top-0 start-0 w-100 h-100 d-flex align-items-center justify-content-center bg-white bg-opacity-50">
|
||||||
|
<span>Loading...</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{!isLoading && (!attendanceData || attendanceData.length === 0) ? (
|
{!isLoading && (!attendanceData || attendanceData.length === 0) ? (
|
||||||
<div
|
<div
|
||||||
className="text-muted fw-semibold d-flex align-items-center justify-content-center"
|
className="text-muted fw-semibold d-flex align-items-center justify-content-center"
|
||||||
style={{ minHeight: "250px" }}>No data found</div>
|
style={{ minHeight: "250px" }}
|
||||||
|
>
|
||||||
|
No data found
|
||||||
|
</div>
|
||||||
) : view === "chart" ? (
|
) : view === "chart" ? (
|
||||||
<div className="w-100">
|
<div className="w-100">
|
||||||
<ReactApexChart options={chartOptions} series={chartSeries} type="bar" height={300} />
|
<ReactApexChart
|
||||||
|
options={chartOptions}
|
||||||
|
series={chartSeries}
|
||||||
|
type="bar"
|
||||||
|
height={300}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="table-responsive w-100" style={{ maxHeight: "350px", overflowY: "auto" }}>
|
<div
|
||||||
<table className="table table-bordered table-sm text-start align-middle mb-0">
|
className="table-responsive w-100"
|
||||||
<thead className="table-light" style={{ position: "sticky", top: 0, zIndex: 1 }}>
|
style={{ maxHeight: "350px", overflowY: "auto" }}
|
||||||
|
>
|
||||||
|
<table className="table table-bordered table-sm align-middle mb-0">
|
||||||
|
<thead
|
||||||
|
className="table-light"
|
||||||
|
style={{ position: "sticky", top: 0, zIndex: 1 }}
|
||||||
|
>
|
||||||
<tr>
|
<tr>
|
||||||
<th style={{ background: "#f8f9fa", textTransform: "none" }}>Role</th>
|
<th style={{ background: "#f8f9fa" }}>Role</th>
|
||||||
{dates.map((date, idx) => (
|
{dates.map((date, idx) => (
|
||||||
<th key={idx} style={{ background: "#f8f9fa", textTransform: "none" }}>{date}</th>
|
<th key={idx} style={{ background: "#f8f9fa" }}>
|
||||||
|
{date}
|
||||||
|
</th>
|
||||||
))}
|
))}
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
||||||
<tbody>
|
<tbody>
|
||||||
{roles.map((role) => (
|
{roles.map((role) => (
|
||||||
<tr key={role}>
|
<tr key={role}>
|
||||||
<td>{role}</td>
|
<td className="fw-medium text-start table-cell">{role}</td>
|
||||||
{tableData.map((row, idx) => {
|
{tableData.map((row, idx) => {
|
||||||
const value = row[role];
|
const value = row[role];
|
||||||
return <td key={idx} style={value > 0 ? { backgroundColor: "#d5d5d5" } : {}}>{value}</td>;
|
return (
|
||||||
|
<td
|
||||||
|
key={idx}
|
||||||
|
style={
|
||||||
|
value > 0 ? { backgroundColor: "#e9ecef" } : {}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{value}
|
||||||
|
</td>
|
||||||
|
);
|
||||||
})}
|
})}
|
||||||
</tr>
|
</tr>
|
||||||
))}
|
))}
|
||||||
@ -134,4 +190,4 @@ const AttendanceOverview = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default AttendanceOverview;
|
export default AttendanceOverview;
|
||||||
|
|||||||
@ -45,7 +45,7 @@ const Dashboard = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="row ">
|
<div className="row vh-100">
|
||||||
{!isAllProjectsSelected && (
|
{!isAllProjectsSelected && (
|
||||||
<div className="col-12 col-md-6 mb-sm-0 mb-4 ">
|
<div className="col-12 col-md-6 mb-sm-0 mb-4 ">
|
||||||
<AttendanceOverview />
|
<AttendanceOverview />
|
||||||
|
|||||||
@ -87,18 +87,18 @@ const ExpenseAnalysis = () => {
|
|||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="card-header d-flex flex-column flex-sm-row justify-content-between align-items-start align-items-sm-center gap-2">
|
<div className="card-header d-flex flex-column flex-sm-row justify-content-between align-items-start align-items-sm-center gap-2">
|
||||||
<div className="text-start w-100">
|
<div className="text-start w-100">
|
||||||
<p className="mb-1 fw-medium fs-sm-6 fs-md-4">Expense Breakdown</p>
|
<p className="mb-1 fw-medium fs-6 fs-md-5">Expense Breakdown</p>
|
||||||
<p className="card-subtitle mb-0">Category Wise Expense Breakdown</p>
|
<p className="card-subtitle mb-0">Category Wise Expense Breakdown</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="d-flex justify-content-end te w-75">
|
<div className="d-flex justify-content-start justify-content-md-end te w-75">
|
||||||
<FormProvider {...methods}>
|
<FormProvider {...methods}>
|
||||||
<DateRangePicker1 />
|
<DateRangePicker1 />
|
||||||
</FormProvider>
|
</FormProvider>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Card body */}
|
|
||||||
<div className="card-body position-relative">
|
<div className="card-body position-relative">
|
||||||
{isLoading && (
|
{isLoading && (
|
||||||
<div
|
<div
|
||||||
|
|||||||
@ -67,13 +67,19 @@ const ExpenseByProject = () => {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
|
const ExpenseCategoryType = [
|
||||||
|
{id:1,category:"Category",label:"Category"},
|
||||||
|
{id:2,category:"Project",label:"Project"}
|
||||||
|
]
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="card shadow-sm rounded ">
|
<div className="card shadow-sm rounded ">
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="card-header">
|
<div className="card-header">
|
||||||
<div className="d-flex justify-content-start align-items-center mb-3 mt-3">
|
<div className="d-flex justify-content-between align-items-center mb-3 mt-3">
|
||||||
<div>
|
<div className="text-start">
|
||||||
<h5 className="mb-1 me-6 card-title">Monthly Expense -</h5>
|
<p className="mb-1 fw-medium fs-6 fs-md-5 ">Monthly Expense -</p>
|
||||||
<p className="card-subtitle me-5 mb-0">Detailed project expenses</p>
|
<p className="card-subtitle me-5 mb-0">Detailed project expenses</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="btn-group mb-4 ms-n8">
|
<div className="btn-group mb-4 ms-n8">
|
||||||
@ -85,29 +91,20 @@ const ExpenseByProject = () => {
|
|||||||
>
|
>
|
||||||
{viewMode}
|
{viewMode}
|
||||||
</button>
|
</button>
|
||||||
<ul className="dropdown-menu dropdown-menu-end ">
|
<ul className="dropdown-menu dropdown-menu-end ">
|
||||||
<li>
|
{ExpenseCategoryType.map((cat)=>(
|
||||||
|
<li>
|
||||||
<button
|
<button
|
||||||
className="dropdown-item"
|
className="dropdown-item"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setViewMode("Category");
|
setViewMode(cat.category);
|
||||||
setSelectedType("");
|
setSelectedType("");
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Category
|
{cat.label}
|
||||||
</button>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<button
|
|
||||||
className="dropdown-item"
|
|
||||||
onClick={() => {
|
|
||||||
setViewMode("Project");
|
|
||||||
setSelectedType("");
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Project
|
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -36,7 +36,7 @@ const ExpenseStatus = () => {
|
|||||||
<>
|
<>
|
||||||
<div className="card-header d-flex justify-content-between text-start ">
|
<div className="card-header d-flex justify-content-between text-start ">
|
||||||
<div className="m-0">
|
<div className="m-0">
|
||||||
<h5 className="card-title mb-1">Expense - By Status</h5>
|
<p className="fs-6 fw-medium fs-md-5 mb-1">Expense - By Status</p>
|
||||||
<p className="card-subtitle m-0 ">{projectName}</p>
|
<p className="card-subtitle m-0 ">{projectName}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user