v2-ui #81
|
@ -13,6 +13,7 @@ import workStation from "../../../assets/image/categories/workStation.png";
|
|||
import machines from "../../../assets/image/categories/machines.png";
|
||||
import feneration from "../../../assets/image/categories/feneration.png";
|
||||
import worker from "../../../assets/image/categories/worker.png";
|
||||
import SkeletonUI from "../../templates/SkeletonUI";
|
||||
// -------------------------------------
|
||||
|
||||
interface AssetProp {
|
||||
|
@ -41,6 +42,7 @@ const Assets: React.FC = () => {
|
|||
const [categoryAssets, setCategoryAssets] = useState<AssetProp[]>([]);
|
||||
const [filtereredAssets, setFiltereredAssets] = useState<AssetProp[]>([]);
|
||||
const [categoryList, setCategoryList] = useState<CategoryListProp[]>([]);
|
||||
const [isLoading, setisLoading] = useState<boolean>(false); // Loading state for assets
|
||||
|
||||
const handleSearchChange = (value: string) => {
|
||||
const searchTerm = value.toLowerCase();
|
||||
|
@ -68,6 +70,7 @@ const Assets: React.FC = () => {
|
|||
|
||||
setCategoryAssets(filteredModels);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const filteredAssets = async () => {
|
||||
try {
|
||||
|
@ -104,7 +107,9 @@ const Assets: React.FC = () => {
|
|||
{ category: "Workers", categoryImage: worker },
|
||||
]);
|
||||
}, []);
|
||||
|
||||
const fetchCategoryAssets = async (asset: any) => {
|
||||
setisLoading(true);
|
||||
setSelectedCategory(asset);
|
||||
if (asset === "Feneration") {
|
||||
const localAssets: AssetProp[] = [
|
||||
|
@ -130,12 +135,16 @@ const Assets: React.FC = () => {
|
|||
];
|
||||
setCategoryAssets(localAssets);
|
||||
setFiltereredAssets(localAssets);
|
||||
setisLoading(false);
|
||||
} else {
|
||||
try {
|
||||
const res = await getCategoryAsset(asset);
|
||||
setCategoryAssets(res);
|
||||
setFiltereredAssets(res);
|
||||
} catch (error) {}
|
||||
setisLoading(false); // End loading
|
||||
} catch (error) {
|
||||
setisLoading(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
return (
|
||||
|
@ -143,7 +152,9 @@ const Assets: React.FC = () => {
|
|||
<Search onChange={handleSearchChange} />
|
||||
<div className="assets-list-section">
|
||||
<section>
|
||||
{searchValue ? (
|
||||
{isLoading ? (
|
||||
<SkeletonUI type="asset" /> // Show skeleton when loading
|
||||
) : searchValue ? (
|
||||
<div className="assets-result">
|
||||
<div className="assets-wrapper">
|
||||
<div className="searched-content">
|
||||
|
|
|
@ -31,10 +31,10 @@ const SideBarLeft: React.FC = () => {
|
|||
};
|
||||
|
||||
return (
|
||||
<div className="sidebar-left-wrapper">
|
||||
<div className={`sidebar-left-wrapper ${toggleUI ? "open" : "closed"}`}>
|
||||
<Header />
|
||||
{toggleUI && (
|
||||
<div className="sidebar-left-container">
|
||||
<div className={`sidebar-left-container `}>
|
||||
{activeModule === "visualization" ? (
|
||||
<>
|
||||
<ToggleHeader
|
||||
|
@ -79,3 +79,5 @@ const SideBarLeft: React.FC = () => {
|
|||
};
|
||||
|
||||
export default SideBarLeft;
|
||||
|
||||
// sidebar-left-container opemn close sidebar-left-container smoothly
|
||||
|
|
|
@ -55,7 +55,7 @@ const SideBarRight: React.FC = () => {
|
|||
}, [activeModule, selectedEventData, selectedEventSphere, setSubModule]);
|
||||
|
||||
return (
|
||||
<div className="sidebar-right-wrapper">
|
||||
<div className={`sidebar-right-wrapper ${toggleUI ? "open" : "closed"}`}>
|
||||
<Header />
|
||||
{toggleUI && (
|
||||
<div className="sidebar-actions-container">
|
||||
|
|
|
@ -1,21 +1,70 @@
|
|||
import React from "react";
|
||||
|
||||
// Define the prop types
|
||||
interface SkeletonUIProps {
|
||||
type: "asset" | "assetLibrary" | "assetWidget" | "default"; // You can expand this with other types as needed
|
||||
}
|
||||
|
||||
const SkeletonUI = () => {
|
||||
return (
|
||||
<div className="skeleton-wrapper">
|
||||
<div className="skeleton-header">
|
||||
<div className="skeleton skeleton-title"></div>
|
||||
<div className="skeleton skeleton-subtitle"></div>
|
||||
</div>
|
||||
// Define the SkeletonUI component
|
||||
const SkeletonUI: React.FC<SkeletonUIProps> = ({ type }) => {
|
||||
console.log("type: ", type);
|
||||
|
||||
<div className="skeleton-content">
|
||||
<div className="skeleton skeleton-card"></div>
|
||||
<div className="skeleton skeleton-card"></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
);
|
||||
// Function to render skeleton content based on 'type'
|
||||
const renderSkeleton = () => {
|
||||
switch (type) {
|
||||
case "assetLibrary":
|
||||
return (
|
||||
<>
|
||||
{Array(5)
|
||||
.fill(null) // Create an array of 5 empty items
|
||||
.map((_, index) => (
|
||||
<div key={index} className="skeleton-content">
|
||||
<div className="skeleton asset-image"></div>
|
||||
<div className="skeleton asset-details"></div>
|
||||
<div className="skeleton organization"></div>
|
||||
<div className="skeleton asset-review"></div>
|
||||
<div className="skeleton button"></div>
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
|
||||
case "assetWidget":
|
||||
return (
|
||||
<div className="skeleton-content">
|
||||
<div className="skeleton skeleton-widget"></div>
|
||||
<div className="skeleton skeleton-widget"></div>
|
||||
</div>
|
||||
);
|
||||
case "asset":
|
||||
return (
|
||||
<>
|
||||
<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>
|
||||
</>
|
||||
);
|
||||
|
||||
default:
|
||||
return (
|
||||
<div className="skeleton-content">
|
||||
<div className="skeleton-header">
|
||||
<div className="skeleton skeleton-title"></div>
|
||||
<div className="skeleton skeleton-subtitle"></div>
|
||||
</div>
|
||||
<div className="skeleton skeleton-card"></div>
|
||||
<div className="skeleton skeleton-card"></div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
return <div className="skeleton-wrapper">{renderSkeleton()}</div>;
|
||||
};
|
||||
|
||||
export default SkeletonUI;
|
||||
export default SkeletonUI;
|
||||
|
|
|
@ -73,7 +73,7 @@ const ThroughputSummary = () => {
|
|||
},
|
||||
};
|
||||
|
||||
const isLoading = true;
|
||||
const isLoading = false;
|
||||
|
||||
return (
|
||||
<div className="production analysis-card">
|
||||
|
@ -90,7 +90,7 @@ const ThroughputSummary = () => {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
{isLoading ? (
|
||||
{!isLoading ? (
|
||||
<>
|
||||
<div className="process-container">
|
||||
<div className="throughput-value">
|
||||
|
@ -157,7 +157,7 @@ const ThroughputSummary = () => {
|
|||
</div>
|
||||
</>
|
||||
) : (
|
||||
<SkeletonUI />
|
||||
<SkeletonUI type={"default"} />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -8,56 +8,58 @@ import {
|
|||
} from "../../icons/analysis";
|
||||
import SemiCircleProgress from "./SemiCircleProgress";
|
||||
import { ArrowIcon } from "../../icons/ExportCommonIcons";
|
||||
import SkeletonUI from "../../templates/SkeletonUI";
|
||||
|
||||
const ROISummary = ({
|
||||
roiSummaryData = {
|
||||
productName: "Product name",
|
||||
roiPercentage: 133,
|
||||
paybackPeriod: 50.3,
|
||||
totalCost: "₹ 1,20,000",
|
||||
revenueGenerated: "₹ 2,80,000",
|
||||
netProfit: "₹ 1,60,000",
|
||||
totalCost: "1,20,000",
|
||||
revenueGenerated: "2,80,000",
|
||||
netProfit: "1,60,000",
|
||||
netLoss: null,
|
||||
costBreakdown: [
|
||||
{
|
||||
item: "Raw Material A",
|
||||
unitCost: "₹ 10/unit",
|
||||
laborCost: "₹ 0",
|
||||
totalCost: "₹ 1000",
|
||||
sellingPrice: "₹ 1500",
|
||||
unitCost: "10/unit",
|
||||
laborCost: "0",
|
||||
totalCost: "1000",
|
||||
sellingPrice: "1500",
|
||||
},
|
||||
{
|
||||
item: "Labor",
|
||||
unitCost: "₹ 10/unit",
|
||||
laborCost: "₹ 500",
|
||||
totalCost: "₹ 500",
|
||||
unitCost: "10/unit",
|
||||
laborCost: "500",
|
||||
totalCost: "500",
|
||||
sellingPrice: "N/A",
|
||||
},
|
||||
{
|
||||
item: "Product 1",
|
||||
unitCost: "₹ 10/unit",
|
||||
laborCost: "₹ 200",
|
||||
totalCost: "₹ 200",
|
||||
sellingPrice: "₹ 2000",
|
||||
unitCost: "10/unit",
|
||||
laborCost: "200",
|
||||
totalCost: "200",
|
||||
sellingPrice: "2000",
|
||||
},
|
||||
{
|
||||
item: "Machine",
|
||||
unitCost: "-",
|
||||
laborCost: "-",
|
||||
totalCost: "₹ 20,000",
|
||||
totalCost: "20,000",
|
||||
sellingPrice: "N/A",
|
||||
},
|
||||
{
|
||||
item: "Total",
|
||||
unitCost: "-",
|
||||
laborCost: "-",
|
||||
totalCost: "₹ 1,20,000",
|
||||
totalCost: "1,20,000",
|
||||
sellingPrice: "-",
|
||||
},
|
||||
{
|
||||
item: "Net Profit",
|
||||
unitCost: "-",
|
||||
laborCost: "-",
|
||||
totalCost: "₹ 1,60,000",
|
||||
totalCost: "1,60,000",
|
||||
sellingPrice: "-",
|
||||
},
|
||||
],
|
||||
|
@ -70,6 +72,7 @@ const ROISummary = ({
|
|||
setIsTableOpen(!isTableOpen);
|
||||
};
|
||||
|
||||
const isLoading = false;
|
||||
return (
|
||||
<div className="roiSummary-container analysis-card">
|
||||
<div className="roiSummary-wrapper analysis-card-wrapper">
|
||||
|
@ -82,121 +85,140 @@ const ROISummary = ({
|
|||
<ROISummaryIcon />
|
||||
</div>
|
||||
</div>
|
||||
<div className="product-info">
|
||||
<ROISummaryProductName />
|
||||
<div className="product-label">Product :</div>
|
||||
<div className="product-name">{roiSummaryData.productName}</div>
|
||||
</div>
|
||||
<div className="playBack">
|
||||
<SonarCrownIcon />
|
||||
<div className="icon"></div>
|
||||
<div className="info">
|
||||
<span>+{roiSummaryData.roiPercentage}%</span> ROI with payback in
|
||||
just <span>{roiSummaryData.paybackPeriod}</span> months
|
||||
</div>
|
||||
</div>
|
||||
<div className="roi-details">
|
||||
<div className="progress-wrapper">
|
||||
<SemiCircleProgress />
|
||||
<div className="content">
|
||||
you're on track to hit it by
|
||||
<div className="key">July 2029</div>
|
||||
{!isLoading ? (
|
||||
<>
|
||||
<div className="product-info">
|
||||
<ROISummaryProductName />
|
||||
<div className="product-label">Product :</div>
|
||||
<div className="product-name">{roiSummaryData.productName}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="metrics">
|
||||
<div className="metric-wrapper">
|
||||
<div className="metric-item">
|
||||
<span className="metric-label">Total Cost Incurred</span>
|
||||
<span className="metric-value">{roiSummaryData.totalCost}</span>
|
||||
<div className="playBack">
|
||||
<SonarCrownIcon />
|
||||
<div className="icon"></div>
|
||||
<div className="info">
|
||||
<span>+{roiSummaryData.roiPercentage}%</span> ROI with payback
|
||||
in just <span>{roiSummaryData.paybackPeriod}</span> months
|
||||
</div>
|
||||
<div className="metric-item">
|
||||
<span className="metric-label">Revenue Generated</span>
|
||||
<span className="metric-value">
|
||||
{roiSummaryData.revenueGenerated}
|
||||
</div>
|
||||
<div className="roi-details">
|
||||
<div className="progress-wrapper">
|
||||
<SemiCircleProgress />
|
||||
<div className="content">
|
||||
you're on track to hit it by
|
||||
<div className="key">July 2029</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="metrics">
|
||||
<div className="metric-wrapper">
|
||||
<div className="metric-item">
|
||||
<span className="metric-label">Total Cost Incurred</span>
|
||||
<span className="metric-value">
|
||||
<span>₹</span>
|
||||
{roiSummaryData.totalCost}
|
||||
</span>
|
||||
</div>
|
||||
<div className="metric-item">
|
||||
<span className="metric-label">Revenue Generated</span>
|
||||
<span className="metric-value">
|
||||
<span>₹</span>
|
||||
|
||||
{roiSummaryData.revenueGenerated}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className={`metric-item net-profit ${
|
||||
roiSummaryData.netLoss ?? "loss"
|
||||
}`}
|
||||
>
|
||||
<div className="metric-label">
|
||||
<span>↑</span>
|
||||
Net Profit
|
||||
</div>
|
||||
<div className="metric-value">
|
||||
<span>₹</span>
|
||||
{roiSummaryData.netProfit}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="cost-breakdown">
|
||||
<div className="breakdown-header" onClick={toggleTable}>
|
||||
<div className="section-wrapper">
|
||||
<CostBreakDownIcon />
|
||||
<span className="section-title">Cost Breakdown</span>
|
||||
</div>
|
||||
|
||||
<span className={`expand-icon ${isTableOpen ? "open" : ""}`}>
|
||||
<ArrowIcon />
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
className={`breakdown-table-wrapper ${
|
||||
isTableOpen ? "open" : "closed"
|
||||
}`}
|
||||
style={{
|
||||
transition: "max-height 0.3s ease-in-out",
|
||||
overflow: "hidden",
|
||||
}}
|
||||
>
|
||||
<table className="breakdown-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Item</th>
|
||||
<th>Unit Cost</th>
|
||||
<th>Labor Cost</th>
|
||||
<th>Total Cost</th>
|
||||
<th>Selling Price</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{roiSummaryData.costBreakdown.map((row, index) => (
|
||||
<tr
|
||||
key={index}
|
||||
className={
|
||||
row.item === "Total"
|
||||
? "total-row"
|
||||
: row.item === "Net Profit"
|
||||
? "net-profit-row"
|
||||
: ""
|
||||
}
|
||||
>
|
||||
<td>{row.item}</td>
|
||||
<td>{row.unitCost}</td>
|
||||
<td>{row.laborCost}</td>
|
||||
<td>{row.totalCost}</td>
|
||||
<td>{row.sellingPrice}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div className="metric-item net-profit">
|
||||
<span className="metric-label">
|
||||
<span>↑</span> Net Profit
|
||||
</span>
|
||||
<span className="metric-value">{roiSummaryData.netProfit}</span>
|
||||
<div className="tips-section">
|
||||
<div className="tip-header">
|
||||
<span className="lightbulb-icon">
|
||||
<LightBulpIcon />
|
||||
</span>
|
||||
<span className="tip-title">How to improve ROI?</span>
|
||||
</div>
|
||||
<div className="tip-description">
|
||||
Increase CNC utilization by{" "}
|
||||
<span className="highlight">10%</span> to shave{" "}
|
||||
<span className="highlight">0.5</span> months of payback period
|
||||
<div className="placeHolder-wrapper">
|
||||
<div className="placeHolder"></div>
|
||||
<div className="placeHolder"></div>
|
||||
</div>
|
||||
</div>
|
||||
<button className="get-tips-button">
|
||||
<div className="btn">Get ROI Boost Tips</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="cost-breakdown">
|
||||
<div className="breakdown-header" onClick={toggleTable}>
|
||||
<div className="section-wrapper">
|
||||
<CostBreakDownIcon />
|
||||
<span className="section-title">Cost Breakdown</span>
|
||||
</div>
|
||||
|
||||
<span className={`expand-icon ${isTableOpen ? "open" : ""}`}>
|
||||
<ArrowIcon />
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
className={`breakdown-table-wrapper ${
|
||||
isTableOpen ? "open" : "closed"
|
||||
}`}
|
||||
style={{
|
||||
transition: "max-height 0.3s ease-in-out",
|
||||
overflow: "hidden",
|
||||
}}
|
||||
>
|
||||
<table className="breakdown-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Item</th>
|
||||
<th>Unit Cost</th>
|
||||
<th>Labor Cost</th>
|
||||
<th>Total Cost</th>
|
||||
<th>Selling Price</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{roiSummaryData.costBreakdown.map((row, index) => (
|
||||
<tr
|
||||
key={index}
|
||||
className={
|
||||
row.item === "Total"
|
||||
? "total-row"
|
||||
: row.item === "Net Profit"
|
||||
? "net-profit-row"
|
||||
: ""
|
||||
}
|
||||
>
|
||||
<td>{row.item}</td>
|
||||
<td>{row.unitCost}</td>
|
||||
<td>{row.laborCost}</td>
|
||||
<td>{row.totalCost}</td>
|
||||
<td>{row.sellingPrice}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div className="tips-section">
|
||||
<div className="tip-header">
|
||||
<span className="lightbulb-icon">
|
||||
<LightBulpIcon />
|
||||
</span>
|
||||
<span className="tip-title">How to improve ROI?</span>
|
||||
</div>
|
||||
<div className="tip-description">
|
||||
Increase CNC utilization by <span className="highlight">10%</span>{" "}
|
||||
to shave <span className="highlight">0.5</span> months of payback
|
||||
period
|
||||
<div className="placeHolder-wrapper">
|
||||
<div className="placeHolder"></div>
|
||||
<div className="placeHolder"></div>
|
||||
</div>
|
||||
</div>
|
||||
<button className="get-tips-button">
|
||||
<div className="btn">Get ROI Boost Tips</div>
|
||||
</button>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<SkeletonUI type={"default"} />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -2,6 +2,7 @@ import {
|
|||
ProductionCapacityIcon,
|
||||
ThroughputSummaryIcon,
|
||||
} from "../../icons/analysis";
|
||||
import SkeletonUI from "../../templates/SkeletonUI";
|
||||
|
||||
const ProductionCapacity = ({
|
||||
progressPercent = 50,
|
||||
|
@ -15,6 +16,7 @@ const ProductionCapacity = ({
|
|||
const partialFillPercent =
|
||||
((progressPercent / 100) * totalBars - barsToFill) * 100;
|
||||
|
||||
const isLoading = false;
|
||||
return (
|
||||
<div className="throughtputSummary-container analysis-card">
|
||||
<div className="throughtputSummary-wrapper analysis-card-wrapper">
|
||||
|
@ -29,39 +31,44 @@ const ProductionCapacity = ({
|
|||
<ThroughputSummaryIcon />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="process-container">
|
||||
<div className="throughput-value">
|
||||
<span className="value">{throughputValue}</span> Units/hour
|
||||
</div>
|
||||
|
||||
{/* Dynamic Progress Bar */}
|
||||
<div className="progress-bar-wrapper">
|
||||
{[...Array(totalBars)].map((_, i) => (
|
||||
<div className="progress-bar" key={i}>
|
||||
{i < barsToFill ? (
|
||||
<div className="bar-fill full" />
|
||||
) : i === barsToFill ? (
|
||||
<div
|
||||
className="bar-fill partial"
|
||||
style={{ width: `${partialFillPercent}%` }}
|
||||
/>
|
||||
) : null}
|
||||
{isLoading ? (
|
||||
<>
|
||||
<div className="process-container">
|
||||
<div className="throughput-value">
|
||||
<span className="value">{throughputValue}</span> Units/hour
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="metrics-section">
|
||||
<div className="metric">
|
||||
<span className="label">Avg. Process Time</span>
|
||||
<span className="value">{avgProcessTime}</span>
|
||||
</div>
|
||||
<div className="metric">
|
||||
<span className="label">Machine Utilization</span>
|
||||
<span className="value">{machineUtilization}</span>
|
||||
</div>
|
||||
</div>
|
||||
{/* Dynamic Progress Bar */}
|
||||
<div className="progress-bar-wrapper">
|
||||
{[...Array(totalBars)].map((_, i) => (
|
||||
<div className="progress-bar" key={i}>
|
||||
{i < barsToFill ? (
|
||||
<div className="bar-fill full" />
|
||||
) : i === barsToFill ? (
|
||||
<div
|
||||
className="bar-fill partial"
|
||||
style={{ width: `${partialFillPercent}%` }}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="metrics-section">
|
||||
<div className="metric">
|
||||
<span className="label">Avg. Process Time</span>
|
||||
<span className="value">{avgProcessTime}</span>
|
||||
</div>
|
||||
<div className="metric">
|
||||
<span className="label">Machine Utilization</span>
|
||||
<span className="value">{machineUtilization}</span>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<SkeletonUI type={"default"} />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React, { createContext, useContext, useState, useCallback, useMemo } from "react";
|
||||
// LoggerProvider.tsx
|
||||
import React, { createContext, useContext, useState, useCallback, useMemo, useEffect } from "react";
|
||||
import { MathUtils } from "three";
|
||||
|
||||
export type LogType = "log" | "info" | "warning" | "error" | "success";
|
||||
|
@ -60,6 +61,18 @@ export const LoggerProvider: React.FC<{ children: React.ReactNode }> = ({
|
|||
[logs, setLogs, isLogListVisible, setIsLogListVisible, addLog]
|
||||
);
|
||||
|
||||
// Attach logger globally to window object
|
||||
useEffect(() => {
|
||||
(window as any).echo = {
|
||||
log: loggerMethods.log,
|
||||
info: loggerMethods.info,
|
||||
warn: loggerMethods.warn,
|
||||
error: loggerMethods.error,
|
||||
success: loggerMethods.success,
|
||||
clear: loggerMethods.clear,
|
||||
};
|
||||
}, [loggerMethods]);
|
||||
|
||||
return (
|
||||
<LoggerContext.Provider value={loggerMethods}>
|
||||
{children}
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
import React, { useEffect, useState } from "react";
|
||||
// import RegularDropDown from "./ui/inputs/RegularDropDown";
|
||||
|
||||
import Search from "../../components/ui/inputs/Search";
|
||||
import { StarsIcon } from "../../components/icons/marketPlaceIcons";
|
||||
import RegularDropDown from "../../components/ui/inputs/RegularDropDown";
|
||||
import { getSortedAssets } from "../../services/marketplace/getSortedAssets";
|
||||
|
||||
interface ModelData {
|
||||
CreatedBy: string;
|
||||
animated: string | null;
|
||||
|
@ -19,47 +17,46 @@ interface ModelData {
|
|||
_id: string;
|
||||
price: number;
|
||||
}
|
||||
|
||||
interface ModelsProps {
|
||||
models: ModelData[];
|
||||
setModels: React.Dispatch<React.SetStateAction<ModelData[]>>;
|
||||
filteredModels: ModelData[];
|
||||
}
|
||||
|
||||
const FilterSearch: React.FC<ModelsProps> = ({
|
||||
models,
|
||||
setModels,
|
||||
filteredModels,
|
||||
}) => {
|
||||
const [activeOption, setActiveOption] = useState("Sort by"); // State for active option
|
||||
const [activeOption, setActiveOption] = useState("Sort by");
|
||||
const [rating, setRating] = useState(0);
|
||||
|
||||
const handleSelect = (option: string) => {
|
||||
setActiveOption(option);
|
||||
|
||||
// Alphabet ascending
|
||||
// Alphabet descending
|
||||
// All
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (activeOption == "Alphabet ascending") {
|
||||
let ascending = models
|
||||
?.slice()
|
||||
.sort((a, b) => a.filename.localeCompare(b.filename))
|
||||
.map((val) => val);
|
||||
if (activeOption === "Alphabet ascending") {
|
||||
const ascending = [...models].sort((a, b) => a.filename.localeCompare(b.filename));
|
||||
setModels(ascending);
|
||||
} else if (activeOption == "Alphabet descending") {
|
||||
let descending = models
|
||||
?.slice()
|
||||
.sort((a, b) => b.filename.localeCompare(a.filename))
|
||||
.map((val) => val);
|
||||
} else if (activeOption === "Alphabet descending") {
|
||||
const descending = [...models].sort((a, b) => b.filename.localeCompare(a.filename));
|
||||
setModels(descending);
|
||||
}
|
||||
}, [activeOption]);
|
||||
|
||||
const handleSearch = (val: string) => {
|
||||
const filteredModel = filteredModels?.filter((model) =>
|
||||
const filteredModel = filteredModels.filter((model) =>
|
||||
model.filename.toLowerCase().includes(val.toLowerCase())
|
||||
);
|
||||
setModels(filteredModel);
|
||||
};
|
||||
|
||||
const handleStarClick = (index: number) => {
|
||||
setRating(index + 1);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="filter-search-container">
|
||||
<Search onChange={handleSearch} />
|
||||
|
@ -71,14 +68,19 @@ const FilterSearch: React.FC<ModelsProps> = ({
|
|||
/>
|
||||
<div className="button">Free</div>
|
||||
<div className="button">Animated</div>
|
||||
|
||||
<div className="rating-container">
|
||||
<div className="label">Rating</div>
|
||||
<div className="stars">
|
||||
<StarsIcon />
|
||||
<StarsIcon />
|
||||
<StarsIcon />
|
||||
<StarsIcon />
|
||||
<StarsIcon />
|
||||
{[0, 1, 2, 3, 4].map((i) => (
|
||||
<div
|
||||
key={i}
|
||||
onClick={() => handleStarClick(i)}
|
||||
className={`star-wrapper ${i < rating ? "filled" : "empty"}`}
|
||||
>
|
||||
<StarsIcon />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -3,6 +3,7 @@ import FilterSearch from "./FilterSearch";
|
|||
import CardsContainer from "./CardsContainer";
|
||||
import { fetchAssets } from "../../services/marketplace/fetchAssets";
|
||||
import { getAssetImages } from "../../services/factoryBuilder/assest/assets/getAssetImages";
|
||||
import SkeletonUI from "../../components/templates/SkeletonUI";
|
||||
interface ModelData {
|
||||
CreatedBy: string;
|
||||
animated: string | null;
|
||||
|
@ -20,14 +21,19 @@ interface ModelData {
|
|||
const MarketPlace = () => {
|
||||
const [models, setModels] = useState<ModelData[]>([]);
|
||||
const [filteredModels, setFilteredModels] = useState<ModelData[]>([]);
|
||||
const [isLoading, setisLoading] = useState<boolean>(false); // Loading state
|
||||
|
||||
useEffect(() => {
|
||||
const filteredAssets = async () => {
|
||||
setisLoading(true);
|
||||
try {
|
||||
const filt = await getAssetImages("67d934ad0f42a1fdadb19aa6");
|
||||
setModels(filt.items);
|
||||
setFilteredModels(filt.items);
|
||||
} catch {}
|
||||
setisLoading(false);
|
||||
} catch {
|
||||
setisLoading(false);
|
||||
}
|
||||
};
|
||||
filteredAssets();
|
||||
}, []);
|
||||
|
@ -36,12 +42,18 @@ const MarketPlace = () => {
|
|||
<div className="marketplace-wrapper">
|
||||
<div className="marketplace-container">
|
||||
<div className="marketPlace">
|
||||
<FilterSearch
|
||||
models={models}
|
||||
setModels={setModels}
|
||||
filteredModels={filteredModels}
|
||||
/>
|
||||
<CardsContainer models={models} />
|
||||
{isLoading ? (
|
||||
<SkeletonUI type="assetLibrary" /> // Show loading spinner while fetching
|
||||
) : (
|
||||
<>
|
||||
<FilterSearch
|
||||
models={models}
|
||||
setModels={setModels}
|
||||
filteredModels={filteredModels}
|
||||
/>
|
||||
<CardsContainer models={models} />
|
||||
</>
|
||||
)}{" "}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -99,7 +99,7 @@ export const DraggableWidget = ({
|
|||
const deleteSelectedChart = async () => {
|
||||
try {
|
||||
console.log("delete");
|
||||
|
||||
|
||||
const email = localStorage.getItem("email") || "";
|
||||
const organization = email?.split("@")[1]?.split(".")[0];
|
||||
let deleteWidget = {
|
||||
|
@ -109,9 +109,9 @@ export const DraggableWidget = ({
|
|||
};
|
||||
|
||||
if (visualizationSocket) {
|
||||
setSelectedChartId(null)
|
||||
setSelectedChartId(null);
|
||||
visualizationSocket.emit("v2:viz-widget:delete", deleteWidget);
|
||||
console.log("delete widget",selectedChartId);
|
||||
console.log("delete widget", selectedChartId);
|
||||
}
|
||||
const updatedWidgets = selectedZone.widgets.filter(
|
||||
(w: Widget) => w.id !== widget.id
|
||||
|
@ -176,7 +176,7 @@ export const DraggableWidget = ({
|
|||
|
||||
const duplicatedWidget: Widget = {
|
||||
...widget,
|
||||
title: name === '' ? widget.title : name,
|
||||
title: name === "" ? widget.title : name,
|
||||
Data: {
|
||||
duration: duration,
|
||||
measurements: { ...measurements },
|
||||
|
@ -189,7 +189,7 @@ export const DraggableWidget = ({
|
|||
zoneId: selectedZone.zoneId,
|
||||
widget: duplicatedWidget,
|
||||
};
|
||||
|
||||
|
||||
if (visualizationSocket) {
|
||||
visualizationSocket.emit("v2:viz-widget:add", duplicateWidget);
|
||||
}
|
||||
|
@ -309,9 +309,9 @@ export const DraggableWidget = ({
|
|||
: undefined,
|
||||
}}
|
||||
ref={chartWidget}
|
||||
onClick={() => {setSelectedChartId(widget)
|
||||
console.log('click');
|
||||
|
||||
onClick={() => {
|
||||
setSelectedChartId(widget);
|
||||
console.log("click");
|
||||
}}
|
||||
>
|
||||
{/* Kebab Icon */}
|
||||
|
@ -333,10 +333,13 @@ export const DraggableWidget = ({
|
|||
</div>
|
||||
<div className="label">Duplicate</div>
|
||||
</div>
|
||||
<div className="edit btn" onClick={(e)=>{
|
||||
e.stopPropagation()
|
||||
deleteSelectedChart();
|
||||
}}>
|
||||
<div
|
||||
className="edit btn"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
deleteSelectedChart();
|
||||
}}
|
||||
>
|
||||
<div className="icon">
|
||||
<DeleteIcon />
|
||||
</div>
|
||||
|
|
|
@ -86,7 +86,7 @@ const Project: React.FC = () => {
|
|||
{!selectedUser && (
|
||||
<>
|
||||
<KeyPressListener />
|
||||
{loadingProgress > 0 && <LoadingPage progress={loadingProgress} />}
|
||||
{/* {loadingProgress > 0 && <LoadingPage progress={loadingProgress} />} */}
|
||||
{!isPlaying && (
|
||||
<>
|
||||
{toggleThreeD && <ModuleToggle />}
|
||||
|
@ -122,7 +122,7 @@ const Project: React.FC = () => {
|
|||
}
|
||||
onDragOver={(event) => event.preventDefault()}
|
||||
>
|
||||
<Scene />
|
||||
{/* <Scene /> */}
|
||||
</div>
|
||||
{selectedUser && <FollowPerson />}
|
||||
{isLogListVisible && (
|
||||
|
@ -130,7 +130,7 @@ const Project: React.FC = () => {
|
|||
<LogList />
|
||||
</RenderOverlay>
|
||||
)}
|
||||
<Footer />
|
||||
{activeModule != "market" && <Footer />}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
@use "../../abstracts/mixins.scss" as *;
|
||||
|
||||
.marketplace-wrapper {
|
||||
// transform: scale(0.65);
|
||||
/* Start at 90% width */
|
||||
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
z-index: #{$z-index-marketplace};
|
||||
|
@ -11,6 +14,7 @@
|
|||
top: 0;
|
||||
padding: 10px;
|
||||
padding-top: 100px;
|
||||
// animation: growWidth 0.4s ease-in-out 0.5s forwards;
|
||||
|
||||
.marketplace-container {
|
||||
position: relative;
|
||||
|
@ -31,6 +35,58 @@
|
|||
flex-direction: column;
|
||||
gap: 24px;
|
||||
|
||||
.skeleton-wrapper {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 18px;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
|
||||
.skeleton-content {
|
||||
|
||||
|
||||
width: calc(25% - 14px) !important;
|
||||
height: auto !important;
|
||||
border-radius: #{$border-radius-xlarge};
|
||||
padding: 12px;
|
||||
box-shadow: 0px 2px 10.5px 0px #0000000d;
|
||||
background: var(--background-color-solid-gradient);
|
||||
border: 1px solid var(--border-color);
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
gap: 6px;
|
||||
|
||||
.asset-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.asset-details {
|
||||
width: 100%;
|
||||
height: 33px;
|
||||
}
|
||||
|
||||
.organization {
|
||||
width: 40%;
|
||||
height: 15px;
|
||||
}
|
||||
|
||||
.asset-review {
|
||||
width: 100%;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.button {
|
||||
|
||||
width: 100%;
|
||||
height: 35px;
|
||||
border-radius: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.filter-search-container {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
|
@ -84,6 +140,13 @@
|
|||
.stars {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.star-wrapper.filled {
|
||||
svg {
|
||||
|
||||
fill: #F3A50C;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -226,6 +289,17 @@
|
|||
}
|
||||
}
|
||||
|
||||
@keyframes growWidth {
|
||||
from {
|
||||
transform: scale(0.65);
|
||||
}
|
||||
|
||||
to {
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.assetPreview-wrapper {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
|
|
@ -90,7 +90,7 @@
|
|||
.dropdown-menu {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 103%;
|
||||
left: 100%;
|
||||
background: var(--background-color-solid);
|
||||
min-width: 220px;
|
||||
border-radius: #{$border-radius-medium};
|
||||
|
@ -141,7 +141,7 @@
|
|||
|
||||
.submenu {
|
||||
position: absolute;
|
||||
left: 102%;
|
||||
left: 100%;
|
||||
top: 0;
|
||||
background: var(--background-color-solid);
|
||||
min-width: 200px;
|
||||
|
|
|
@ -378,12 +378,30 @@
|
|||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.metric-label.loss {
|
||||
background: #6D4343;
|
||||
border: 1px solid #FF301D
|
||||
}
|
||||
|
||||
.metric-value {
|
||||
text-align: center;
|
||||
line-height: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.metric-item.loss {
|
||||
background: #6D4343;
|
||||
border: 1px solid #FF301D;
|
||||
|
||||
.metric-label {
|
||||
span {
|
||||
color: #FF311E;
|
||||
display: inline-block;
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.metric-wrapper {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
|
|
|
@ -456,7 +456,7 @@
|
|||
padding: 18px 10px;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
top: -32px;
|
||||
// top: -32px;
|
||||
}
|
||||
|
||||
.barOverflow {
|
||||
|
@ -482,4 +482,3 @@
|
|||
transition: transform 0.5s ease;
|
||||
}
|
||||
|
||||
// progress should be progress {progress}
|
|
@ -1392,4 +1392,36 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.skeleton-wrapper {
|
||||
display: flex;
|
||||
|
||||
.skeleton-content {}
|
||||
|
||||
.asset-name {
|
||||
width: 40%;
|
||||
height: 10px;
|
||||
}
|
||||
|
||||
.asset {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
.sidebar-left-wrapper,
|
||||
.sidebar-right-wrapper {
|
||||
height: calc(50vh + 150px);
|
||||
overflow-y: hidden;
|
||||
transition: height 0.4s ease-in-out;
|
||||
}
|
||||
|
||||
.sidebar-left-wrapper.closed,
|
||||
.sidebar-right-wrapper.closed {
|
||||
height: 52px;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
.skeleton-wrapper {
|
||||
max-width: 600px;
|
||||
// max-width: 600px;
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
|
||||
|
|
Loading…
Reference in New Issue