marco.pms.web/src/components/Expenses/ExpenseSkeleton.jsx

305 lines
8.9 KiB
JavaScript

import React from "react";
const SkeletonLine = ({ height = 20, width = "100%", className = "" }) => (
<div
className={`skeleton mb-2 ${className}`}
style={{
height,
width,
}}
></div>
);
const ExpenseSkeleton = () => {
return (
<div className="container p-3">
<div className="d-flex justify-content-center">
<SkeletonLine height={20} width="200px" />
</div>
{[...Array(5)].map((_, idx) => (
<div className="row my-2" key={idx}>
<div className="col-md-6">
<SkeletonLine />
</div>
<div className="col-md-6">
<SkeletonLine />
</div>
</div>
))}
<div className="row my-2">
<div className="col-md-12">
<SkeletonLine height={60} />
</div>
</div>
<div className="row my-2">
<div className="col-md-12">
<SkeletonLine height={120} />
</div>
</div>
<div className="d-flex justify-content-center gap-2 mt-3">
<SkeletonLine height={35} width="100px" />
<SkeletonLine height={35} width="100px" />
</div>
</div>
);
};
export default ExpenseSkeleton;
export const ExpenseDetailsSkeleton = () => {
return (
<div className="container px-3">
<div className="row mb-3">
<div className="d-flex justify-content-center mb-3">
<SkeletonLine height={20} width="180px" className="mb-2" />
</div>
{[...Array(3)].map((_, i) => (
<div className="col-12 col-md-4 mb-3" key={`row-1-${i}`}>
<SkeletonLine height={14} className="mb-1" />
<SkeletonLine />
</div>
))}
{[...Array(6)].map((_, i) => (
<div className="col-12 col-md-4 mb-3" key={`row-2-${i}`}>
<SkeletonLine height={14} className="mb-1" />
<SkeletonLine />
</div>
))}
<div className="col-12 text-start">
<SkeletonLine height={14} width="150px" className="mb-1" />
<div className="d-flex flex-wrap gap-2">
{[...Array(2)].map((_, i) => (
<div
key={i}
className="border rounded p-2 d-flex flex-column align-items-center"
style={{ width: "80px" }}
>
{/* Icon placeholder */}
<div
style={{
height: "30px",
width: "30px",
borderRadius: "4px",
marginBottom: "6px",
}}
className="skeleton"
/>
{/* Filename placeholder */}
<div
style={{
height: "10px",
width: "100%",
}}
className="skeleton"
/>
</div>
))}
</div>
</div>
<hr className="divider my-1" />
<div className="col-12 mb-3">
<SkeletonLine height={14} width="80px" className="mb-1" />
<SkeletonLine height={60} className="mb-2" />
<div className="d-flex gap-2 flex-wrap">
{[...Array(2)].map((_, i) => (
<SkeletonLine
key={i}
height={30}
width="100px"
className="rounded"
/>
))}
</div>
</div>
</div>
</div>
);
};
const SkeletonCell = ({
width = "100%",
height = 20,
className = "",
style = {},
}) => (
<div
className={`skeleton ${className}`}
style={{
width,
height,
borderRadius: 4,
...style,
}}
/>
);
export const ExpenseTableSkeleton = ({
groups = 3,
rowsPerGroup = 3,
headers,
}) => {
return (
<div className="card px-2">
<table
className="card-body table border-top dataTable no-footer dtr-column text-nowrap"
aria-describedby="DataTables_Table_0_info"
id="horizontal-example"
>
<thead>
<tr>
{headers.map((header) => (
<th key={header} className="d-none d-sm-table-cell">
<div className="text-start ms-5">{header}</div>
</th>
))}
</tr>
</thead>
<tbody>
{[...Array(groups)].map((_, groupIdx) => (
<React.Fragment key={`group-${groupIdx}`}>
{/* Fake Date Group Header Row */}
<tr className="bg-light">
<td colSpan={8}>
<SkeletonCell width="150px" height={20} />
</td>
</tr>
{/* Rows under this group */}
{[...Array(rowsPerGroup)].map((__, rowIdx) => (
<tr
key={`row-${groupIdx}-${rowIdx}`}
className={rowIdx % 2 === 0 ? "odd" : "even"}
>
{/* Expense Type */}
<td className="text-start d-none d-sm-table-cell ms-5">
<SkeletonCell width="90px" height={16} />
</td>
{/* Payment Mode */}
<td className="text-start d-none d-sm-table-cell ms-5">
<SkeletonCell width="90px" height={16} />
</td>
{/* Submitted By (Avatar + name) */}
<td className="text-start d-none d-sm-table-cell ms-5">
<div className="d-flex align-items-center gap-2">
<SkeletonCell
width="30px"
height={30}
className="rounded-circle"
/>
<SkeletonCell width="80px" height={16} />
</div>
</td>
{/* Submitted */}
<td className="d-none d-md-table-cell text-end">
<SkeletonCell width="70px" height={16} />
</td>
{/* Amount */}
<td className="d-none d-md-table-cell text-end">
<SkeletonCell width="60px" height={16} />
</td>
{/* Status */}
<td>
<SkeletonCell
width="80px"
height={22}
className="rounded"
/>
</td>
{/* Action */}
<td>
<div className="d-flex justify-content-center align-items-center gap-2">
{[...Array(3)].map((__, i) => (
<SkeletonCell
key={i}
width={20}
height={20}
className="rounded"
style={{ display: "inline-block" }}
/>
))}
</div>
</td>
</tr>
))}
</React.Fragment>
))}
</tbody>
</table>
</div>
);
};
export const ExpenseFilterSkeleton = () => {
return (
<div className="p-3 text-start">
{/* Created Date Label and Skeleton */}
<div className="mb-3 w-100">
<SkeletonLine height={14} width="120px" className="mb-1" />
<SkeletonLine height={36} />
</div>
<div className="row g-2">
{/* Project Select */}
<div className="col-12 col-md-4 mb-3">
<SkeletonLine height={14} width="80px" className="mb-1" />
<SkeletonLine height={36} />
</div>
{/* Submitted By Select */}
<div className="col-12 col-md-4 mb-3">
<SkeletonLine height={14} width="100px" className="mb-1" />
<SkeletonLine height={36} />
</div>
{/* Paid By Select */}
<div className="col-12 col-md-4 mb-3">
<SkeletonLine height={14} width="70px" className="mb-1" />
<SkeletonLine height={36} />
</div>
{/* Status Checkboxes */}
<div className="col-12 mb-3">
<SkeletonLine height={14} width="80px" className="mb-2" />
<div className="d-flex flex-wrap">
{[...Array(3)].map((_, i) => (
<div className="d-flex align-items-center me-3 mb-2" key={i}>
<div
className="form-check-input bg-secondary me-2"
style={{
height: "16px",
width: "16px",
borderRadius: "3px",
}}
/>
<SkeletonLine height={14} width="60px" />
</div>
))}
</div>
</div>
</div>
{/* Buttons */}
<div className="d-flex justify-content-end py-3 gap-2">
<SkeletonLine height={30} width="80px" className="rounded" />
<SkeletonLine height={30} width="80px" className="rounded" />
</div>
</div>
);
};