Refactor Assets component to streamline category fetching and enhance loading state handling; improve SkeletonUI styles for better asset representation

This commit is contained in:
Vishnu 2025-05-13 12:20:04 +05:30
parent 980d27c91f
commit 59a3cb4704
4 changed files with 172 additions and 174 deletions

View File

@ -90,24 +90,7 @@ const Assets: React.FC = () => {
useEffect(() => { useEffect(() => {
setCategoryList([ setCategoryList([
{ { category: "Fenestration", categoryImage: feneration },
assetName: "Doors",
assetImage: "",
category: "Feneration",
categoryImage: feneration,
},
{
assetName: "Windows",
assetImage: "",
category: "Feneration",
categoryImage: feneration,
},
{
assetName: "Pillars",
assetImage: "",
category: "Feneration",
categoryImage: feneration,
},
{ category: "Vehicles", categoryImage: vehicle }, { category: "Vehicles", categoryImage: vehicle },
{ category: "Workstation", categoryImage: workStation }, { category: "Workstation", categoryImage: workStation },
{ category: "Machines", categoryImage: machines }, { category: "Machines", categoryImage: machines },
@ -121,44 +104,15 @@ const Assets: React.FC = () => {
const fetchCategoryAssets = async (asset: any) => { const fetchCategoryAssets = async (asset: any) => {
setisLoading(true); setisLoading(true);
setSelectedCategory(asset); setSelectedCategory(asset);
if (asset === "Feneration") { try {
const localAssets: AssetProp[] = [ const res = await getCategoryAsset(asset);
{ setCategoryAssets(res);
filename: "arch", setFiltereredAssets(res);
category: "Feneration", setisLoading(false); // End loading
url: arch, // eslint-disable-next-line
thumbnail: archThumbnail, } catch (error) {
tags: "arch", echo.error("failed to fetch assets");
},
{
filename: "door",
category: "Feneration",
url: door,
thumbnail: feneration,
tags: "door",
},
{
filename: "window",
category: "Feneration",
url: window,
thumbnail: windowThumbnail,
tags: "window",
},
];
setCategoryAssets(localAssets);
setFiltereredAssets(localAssets);
setisLoading(false); setisLoading(false);
} else {
try {
const res = await getCategoryAsset(asset);
setCategoryAssets(res);
setFiltereredAssets(res);
setisLoading(false); // End loading
// eslint-disable-next-line
} catch (error) {
echo.error("failed to fetch assets");
setisLoading(false);
}
} }
}; };
@ -167,62 +121,19 @@ const Assets: React.FC = () => {
<Search onChange={handleSearchChange} /> <Search onChange={handleSearchChange} />
<div className="assets-list-section"> <div className="assets-list-section">
<section> <section>
{isLoading ? ( {(() => {
<SkeletonUI type="asset" /> // Show skeleton when loading if (isLoading) {
) : searchValue ? ( return <SkeletonUI type="asset" />; // Show skeleton when loading
<div className="assets-result"> }
<div className="assets-wrapper"> if (searchValue) {
<div className="searched-content"> return (
<p>Results for {searchValue}</p> <div className="assets-result">
</div> <div className="assets-wrapper">
<div className="assets-container"> <div className="searched-content">
{categoryAssets?.map((asset: any, index: number) => ( <p>Results for {searchValue}</p>
<div
key={index}
className="assets"
id={asset.filename}
title={asset.filename}
>
<img
src={asset?.thumbnail}
alt={asset.filename}
className="asset-image"
/>
<div className="asset-name">
{asset.filename
.split("_")
.map(
(word: any) =>
word.charAt(0).toUpperCase() + word.slice(1)
)
.join(" ")}
</div>
</div> </div>
))} <div className="assets-container">
</div> {categoryAssets?.map((asset: any, index: number) => (
</div>
</div>
) : (
<>
{selectedCategory ? (
<div className="assets-wrapper">
<h2>
{selectedCategory}{" "}
<div
className="back-button"
id="asset-backButtom"
onClick={() => {
setSelectedCategory(null);
setCategoryAssets([]);
}}
>
Back
</div>
</h2>
<div className="assets-container">
{categoryAssets &&
categoryAssets?.map((asset: any, index: number) => (
<div <div
key={index} key={index}
className="assets" className="assets"
@ -233,17 +144,8 @@ const Assets: React.FC = () => {
src={asset?.thumbnail} src={asset?.thumbnail}
alt={asset.filename} alt={asset.filename}
className="asset-image" className="asset-image"
onPointerDown={() => {
setSelectedItem({
name: asset.filename,
id: asset.AssetID,
type:
asset.type === "undefined"
? undefined
: asset.type,
});
}}
/> />
<div className="asset-name"> <div className="asset-name">
{asset.filename {asset.filename
.split("_") .split("_")
@ -255,40 +157,104 @@ const Assets: React.FC = () => {
</div> </div>
</div> </div>
))} ))}
</div>
</div> </div>
</div> </div>
) : ( );
}
if (selectedCategory) {
return (
<div className="assets-wrapper"> <div className="assets-wrapper">
<h2>Categories</h2> <h2>
<div className="categories-container"> {selectedCategory}
{Array.from( <button
new Set(categoryList.map((asset) => asset.category)) className="back-button"
).map((category, index) => { id="asset-backButtom"
const categoryInfo = categoryList.find( onClick={() => {
(asset) => asset.category === category setSelectedCategory(null);
); setCategoryAssets([]);
return ( }}
<div >
key={index} Back
className="category" </button>
id={category} </h2>
onClick={() => fetchCategoryAssets(category)} <div className="assets-container">
> {categoryAssets?.map((asset: any, index: number) => (
<img <div
src={categoryInfo?.categoryImage || ""} key={`${index}-${asset}`}
alt={category} className="assets"
className="category-image" id={asset.filename}
draggable={false} title={asset.filename}
/> >
<div className="category-name">{category}</div> <img
src={asset?.thumbnail}
alt={asset.filename}
className="asset-image"
onPointerDown={() => {
setSelectedItem({
name: asset.filename,
id: asset.AssetID,
type:
asset.type === "undefined"
? undefined
: asset.type,
});
}}
/>
<div className="asset-name">
{asset.filename
.split("_")
.map(
(word: any) =>
word.charAt(0).toUpperCase() + word.slice(1)
)
.join(" ")}
</div> </div>
); </div>
})} ))}
{categoryAssets.length === 0 && (
<div className="no-asset">
🚧 The asset shelf is empty. We're working on filling it
up!
</div>
)}
</div> </div>
</div> </div>
)} );
</> }
)}
return (
<div className="assets-wrapper">
<h2>Categories</h2>
<div className="categories-container">
{Array.from(
new Set(categoryList.map((asset) => asset.category))
).map((category, index) => {
const categoryInfo = categoryList.find(
(asset) => asset.category === category
);
return (
<div
key={index}
className="category"
id={category}
onClick={() => fetchCategoryAssets(category)}
>
<img
src={categoryInfo?.categoryImage ?? ""}
alt={category}
className="category-image"
draggable={false}
/>
<div className="category-name">{category}</div>
</div>
);
})}
</div>
</div>
);
})()}
</section> </section>
</div> </div>
</div> </div>

View File

@ -7,7 +7,6 @@ interface SkeletonUIProps {
// Define the SkeletonUI component // Define the SkeletonUI component
const SkeletonUI: React.FC<SkeletonUIProps> = ({ type }) => { const SkeletonUI: React.FC<SkeletonUIProps> = ({ type }) => {
// Function to render skeleton content based on 'type' // Function to render skeleton content based on 'type'
const renderSkeleton = () => { const renderSkeleton = () => {
switch (type) { switch (type) {
@ -38,17 +37,28 @@ const SkeletonUI: React.FC<SkeletonUIProps> = ({ type }) => {
case "asset": case "asset":
return ( return (
<> <>
<div className="skeleton-content"> <div className="skeleton asset-category-title"></div>
<div className="skeleton asset-name"></div> <div className="skeleton-content-asset">
<div className="skeleton asset"></div> <div className="skeleton-content">
</div> <div className="skeleton asset-name"></div>
<div className="skeleton-content"> <div className="skeleton asset"></div>
<div className="skeleton asset-name"></div> </div>
<div className="skeleton asset"></div> <div className="skeleton-content">
<div className="skeleton asset-name"></div>
<div className="skeleton asset"></div>
</div>
<div className="skeleton-content">
<div className="skeleton asset-name"></div>
<div className="skeleton asset"></div>
</div>
<div className="skeleton-content">
<div className="skeleton asset-name"></div>
<div className="skeleton asset"></div>
</div>
</div> </div>
</> </>
); );
default: default:
return ( return (
<div className="skeleton-content"> <div className="skeleton-content">

View File

@ -1278,7 +1278,7 @@
} }
} }
.toggle-sidebar-ui-button { .toggle-sidebar-ui-button {
svg{ svg {
transform: scaleX(-1); transform: scaleX(-1);
} }
.tooltip { .tooltip {
@ -1455,7 +1455,11 @@
height: 100%; height: 100%;
gap: 6px; gap: 6px;
padding: 2px; padding: 2px;
.no-asset {
text-align: center;
margin: 12px;
width: 100%;
}
.assets { .assets {
width: 122px; width: 122px;
height: 95px; height: 95px;

View File

@ -1,18 +1,8 @@
.skeleton-wrapper { .skeleton-wrapper {
// max-width: 600px; // max-width: 600px;
display: flex; margin: 0 auto;
margin: 0 auto; width: 100%;
width: 100%;
.asset-name {
width: 40%;
height: 10px;
}
.asset {
width: 100%;
height: 100%;
}
.skeleton { .skeleton {
background: var(--background-color-gray); background: var(--background-color-gray);
@ -31,7 +21,7 @@
90deg, 90deg,
rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0) 0%,
rgba(255, 255, 255, 0.2) 20%, rgba(255, 255, 255, 0.2) 20%,
rgba(255, 255, 255, 0.5) 60%, rgba(255, 255, 255, 0.39) 60%,
rgba(255, 255, 255, 0) 100% rgba(255, 255, 255, 0) 100%
); );
transform: translateX(-100%); transform: translateX(-100%);
@ -66,6 +56,34 @@
} }
} }
.asset-category-title{
width: 60%;
height: 12px;
margin-bottom: 12px;
margin-top: 4px;
}
.skeleton-content-asset{
display: flex;
height: calc(95px * 2 + 10px);
gap: 10px;
flex-wrap: wrap;
.skeleton-content {
gap: 8px;
flex-direction: column;
min-width: 122px;
min-height: 95px;
.asset-name {
width: 40%;
height: 10px;
}
.asset {
flex: 1;
width: 100%;
height: 100%;
}
}
}
@keyframes shimmer { @keyframes shimmer {
100% { 100% {
transform: translateX(100%); transform: translateX(100%);