Compare commits

...

4 Commits

4 changed files with 289 additions and 246 deletions

View File

@@ -1,199 +1,200 @@
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { ClockThreeIcon, LocationPinIcon, TargetIcon } from '../../../../icons/ExportCommonIcons' import { ClockThreeIcon, LocationPinIcon, TargetIcon } from '../../../../icons/ExportCommonIcons'
import { useSceneContext } from '../../../../../modules/scene/sceneContext'; import { useSceneContext } from '../../../../../modules/scene/sceneContext';
import { useProductContext } from '../../../../../modules/simulation/products/productContext';
import RenameInput from '../../../../ui/inputs/RenameInput'; import RenameInput from '../../../../ui/inputs/RenameInput';
import { useResourceManagementId } from '../../../../../store/builder/store'; import { useResourceManagementId } from '../../../../../store/builder/store';
import { set } from 'immer/dist/internal'; import { getAssetThumbnail } from '../../../../../services/factoryBuilder/asset/assets/getAssetThumbnail';
// import NavigateCatagory from '../NavigateCatagory' // import NavigateCatagory from '../NavigateCatagory'
const Hrm = () => { const Hrm = () => {
const [selectedCard, setSelectedCard] = useState(0); const [selectedCard, setSelectedCard] = useState(0);
const [workers, setWorkers] = useState<any[]>([]); const [workers, setWorkers] = useState<any[]>([]);
const { productStore } = useSceneContext();
const { products, getProductById } = productStore();
const { selectedProductStore } = useProductContext();
const { selectedProduct } = selectedProductStore();
const { setResourceManagementId } = useResourceManagementId(); const { setResourceManagementId } = useResourceManagementId();
const { assetStore } = useSceneContext();
const { assets: allAssets } = assetStore();
useEffect(() => { async function getAsset(assetId: string) {
if (selectedProduct) { let thumbnail = await getAssetThumbnail(assetId)
const productDetails = getProductById(selectedProduct.productUuid); if (thumbnail.thumbnail) {
const workerDetails = productDetails?.eventDatas || []; let assetImage = thumbnail.thumbnail
return assetImage;
}
}
const formattedWorkers = workerDetails useEffect(() => {
.filter((worker: any) => worker.type === "human") if (allAssets.length > 0) {
.map((worker: any, index: number) => ({ const fetchWorkers = async () => {
employee: { const humans = allAssets.filter((worker: any) => worker.eventData.type === "Human");
image: "",
name: worker.modelName, const formattedWorkers = await Promise.all(
modelId: worker.modelUuid, humans.map(async (worker: any, index: number) => {
employee_id: `HR-${204 + index}`, const assetImage = await getAsset(worker.assetId);
status: "Active",
}, return {
task: { employee: {
status: "Ongoing", image: assetImage,
title: worker.taskTitle || "No Task Assigned", name: worker.modelName,
location: { modelId: worker.modelUuid,
floor: worker.floor || 0, employee_id: `HR-${204 + index}`,
zone: worker.zone || "N/A" status: "Active",
}, },
planned_time_hours: worker.plannedTime || 0, task: {
time_spent_hours: worker.timeSpent || 0, status: "Ongoing",
total_tasks: worker.totalTasks || 0, title: worker.taskTitle ?? "No Task Assigned",
completed_tasks: worker.completedTasks || 0 location: {
}, floor: worker.floor ?? 0,
actions: [ zone: worker.zone ?? "N/A",
"Assign Task", },
"Reassign Task", planned_time_hours: worker.plannedTime ?? 0,
"Pause", time_spent_hours: worker.timeSpent ?? 0,
"Emergency Stop" total_tasks: worker.totalTasks ?? 0,
], completed_tasks: worker.completedTasks ?? 0,
location: `Floor ${worker.floor || "-"} . Zone ${worker.zone || "-"}` },
})); actions: ["Assign Task", "Reassign Task", "Pause", "Emergency Stop"],
location: `Floor ${worker.floor || "-"} . Zone ${worker.zone || "-"}`,
};
})
);
setWorkers(formattedWorkers); setWorkers(formattedWorkers);
} };
}, [selectedProduct, getProductById]);
useEffect(() => {
//
}, [workers]);
// const employee_details = [
// {
// "employee": {
// image: "",
// "name": "John Doe",
// "employee_id": "HR-204",
// "status": "Active",
// },
// "task": {
// "status": "Ongoing",
// "title": "Inspecting Machine X",
// "location": {
// "floor": 4,
// "zone": "B"
// },
// "planned_time_hours": 6,
// "time_spent_hours": 2,
// "total_tasks": 12,
// "completed_tasks": 3
// },
// "actions": [
// "Assign Task",
// "Reassign Task",
// "Pause",
// "Emergency Stop"
// ],
// "location": "Floor 4 . Zone B"
// },
// {
// "employee": {
// image: "",
// "name": "Alice Smith",
// "employee_id": "HR-205",
// "status": "Active",
// },
// "task": {
// "status": "Ongoing",
// "title": "Calibrating Sensor Y",
// "location": {
// "floor": 2,
// "zone": "A"
// },
// "planned_time_hours": 4,
// "time_spent_hours": 1.5,
// "total_tasks": 10,
// "completed_tasks": 2
// },
// "actions": [
// "Assign Task",
// "Reassign Task",
// "Pause",
// "Emergency Stop"
// ],
// "location": "Floor 4 . Zone B"
// },
// {
// "employee": {
// image: "",
// "name": "Michael Lee",
// "employee_id": "HR-206",
// "status": "Active",
// },
// "task": {
// "status": "Ongoing",
// "title": "Testing Conveyor Belt Z",
// "location": {
// "floor": 5,
// "zone": "C"
// },
// "planned_time_hours": 5,
// "time_spent_hours": 3,
// "total_tasks": 8,
// "completed_tasks": 5
// },
// "actions": [
// "Assign Task",
// "Reassign Task",
// "Pause",
// "Emergency Stop"
// ],
// "location": "Floor 4 . Zone B"
// },
// ]
function handleRenameWorker(newName: string) {
//
fetchWorkers();
} }
function handleHumanClick(employee: any) { }, [allAssets]);
if (employee.modelId) {
setResourceManagementId(employee.modelId);
}
// const employee_details = [
// {
// "employee": {
// image: "",
// "name": "John Doe",
// "employee_id": "HR-204",
// "status": "Active",
// },
// "task": {
// "status": "Ongoing",
// "title": "Inspecting Machine X",
// "location": {
// "floor": 4,
// "zone": "B"
// },
// "planned_time_hours": 6,
// "time_spent_hours": 2,
// "total_tasks": 12,
// "completed_tasks": 3
// },
// "actions": [
// "Assign Task",
// "Reassign Task",
// "Pause",
// "Emergency Stop"
// ],
// "location": "Floor 4 . Zone B"
// },
// {
// "employee": {
// image: "",
// "name": "Alice Smith",
// "employee_id": "HR-205",
// "status": "Active",
// },
// "task": {
// "status": "Ongoing",
// "title": "Calibrating Sensor Y",
// "location": {
// "floor": 2,
// "zone": "A"
// },
// "planned_time_hours": 4,
// "time_spent_hours": 1.5,
// "total_tasks": 10,
// "completed_tasks": 2
// },
// "actions": [
// "Assign Task",
// "Reassign Task",
// "Pause",
// "Emergency Stop"
// ],
// "location": "Floor 4 . Zone B"
// },
// {
// "employee": {
// image: "",
// "name": "Michael Lee",
// "employee_id": "HR-206",
// "status": "Active",
// },
// "task": {
// "status": "Ongoing",
// "title": "Testing Conveyor Belt Z",
// "location": {
// "floor": 5,
// "zone": "C"
// },
// "planned_time_hours": 5,
// "time_spent_hours": 3,
// "total_tasks": 8,
// "completed_tasks": 5
// },
// "actions": [
// "Assign Task",
// "Reassign Task",
// "Pause",
// "Emergency Stop"
// ],
// "location": "Floor 4 . Zone B"
// },
// ]
function handleRenameWorker(newName: string) {
}
function handleHumanClick(employee: any) {
if (employee.modelId) {
setResourceManagementId(employee.modelId);
} }
}
return ( return (
<> <>
{/* <NavigateCatagory {/* <NavigateCatagory
category={["All People", "Technician", "Operator", "Supervisor", "Safety Officer"]} category={["All People", "Technician", "Operator", "Supervisor", "Safety Officer"]}
selectedCategory={selectedCategory} selectedCategory={selectedCategory}
setSelectedCategory={setSelectedCategory} setSelectedCategory={setSelectedCategory}
/> */} /> */}
<div className='hrm-container assetManagement-wrapper'> <div className='hrm-container assetManagement-wrapper'>
{workers.map((employee, index) => ( {workers.map((employee, index) => (
<div <div
className={`analysis-wrapper ${selectedCard === index ? "active" : ""}`} className={`analysis-wrapper ${selectedCard === index ? "active" : ""}`}
onClick={() => setSelectedCard(index)} onClick={() => setSelectedCard(index)}
key={index} key={index}
> >
<header> <header>
<div className="user-details"> <div className="user-details">
<div className="user-image-wrapper"> <div className="user-image-wrapper">
<img className='user-image' src={employee.employee.image} alt="" /> <img className='user-image' src={employee.employee.image} alt="" />
<div className={`status ${employee.employee.status}`}></div> <div className={`status ${employee.employee.status}`}></div>
</div>
<div className="details" >
{/* <div className="employee-name">{employee.employee.name}</div> */}
<RenameInput value={employee.employee.name} onRename={handleRenameWorker} />
<div className="employee-id">{employee.employee.employee_id}</div>
</div>
</div> </div>
<div className="details" >
{/* <div className="employee-name">{employee.employee.name}</div> */}
<RenameInput value={employee.employee.name} onRename={handleRenameWorker} />
<div className="employee-id">{employee.employee.employee_id}</div>
</div>
</div>
<div className="see-more" onClick={() => { handleHumanClick(employee.employee) }}>View in Scene</div> <div className="see-more" onClick={() => { handleHumanClick(employee.employee) }}>View in Scene</div>
</header> </header>
<div className="content"> <div className="content">
{/* <div className="task-info"> {/* <div className="task-info">
<div className="task-wrapper"> <div className="task-wrapper">
<div className="task-label"> <div className="task-label">
<span className='label-icon'><ListTaskIcon /></span> <span className='label-icon'><ListTaskIcon /></span>
@@ -214,17 +215,17 @@ const Hrm = () => {
</div> </div>
</div> */} </div> */}
<div className="task-stats"> <div className="task-stats">
<div className="stat-item"> <div className="stat-item">
<div className="stat-wrapper"> <div className="stat-wrapper">
<span className="stat-icon"><ClockThreeIcon /></span> <span className="stat-icon"><ClockThreeIcon /></span>
<span>Planned time:</span> <span>Planned time:</span>
</div>
<span className='stat-value'>{employee.task.planned_time_hours} hr</span>
</div> </div>
{/* <div className="stat-item">
<span className='stat-value'>{employee.task.planned_time_hours} hr</span>
</div>
{/* <div className="stat-item">
<div className="stat-wrapper"> <div className="stat-wrapper">
<span className="stat-icon"><SlectedTickIcon /></span> <span className="stat-icon"><SlectedTickIcon /></span>
@@ -242,39 +243,39 @@ const Hrm = () => {
<span className='stat-value'>{employee.task.time_spent_hours} hr</span> <span className='stat-value'>{employee.task.time_spent_hours} hr</span>
</div> */} </div> */}
<div className="stat-item"> <div className="stat-item">
<div className="stat-wrapper"> <div className="stat-wrapper">
<span className="stat-icon"><TargetIcon /></span> <span className="stat-icon"><TargetIcon /></span>
<span>Cost per hr:</span> <span>Cost per hr:</span>
</div>
<span className='stat-value'>{employee.task.completed_tasks}</span>
</div> </div>
</div>
<div className="location-wrapper"> <span className='stat-value'>{employee.task.completed_tasks}</span>
<div className="location-header">
<div className="icon">
<LocationPinIcon />
</div>
<div className="header">Location:</div>
</div>
<div className="location-value">{employee.location}</div>
</div>
<div className="task-actions">
{/* <button className="btn btn-default">Assign Task</button>
<button className="btn btn-default">Reassign Task</button> */}
<button className="btn btn-default">Pause</button>
<button className="btn btn-danger">Emergency Stop</button>
</div> </div>
</div> </div>
<div className="location-wrapper">
<div className="location-header">
<div className="icon">
<LocationPinIcon />
</div>
<div className="header">Location:</div>
</div>
<div className="location-value">{employee.location}</div>
</div>
<div className="task-actions">
{/* <button className="btn btn-default">Assign Task</button>
<button className="btn btn-default">Reassign Task</button> */}
<button className="btn btn-default">Pause</button>
<button className="btn btn-danger">Emergency Stop</button>
</div>
</div> </div>
))}
</div> </div>
</> ))}
) </div>
</>
)
} }
export default Hrm export default Hrm

View File

@@ -3,60 +3,65 @@ import { useEffect, useState } from 'react'
import { EyeIcon, ForkLiftIcon, KebabIcon, LocationPinIcon, RightHalfFillCircleIcon } from '../../../../../icons/ExportCommonIcons'; import { EyeIcon, ForkLiftIcon, KebabIcon, LocationPinIcon, RightHalfFillCircleIcon } from '../../../../../icons/ExportCommonIcons';
import assetImage from "../../../../../../assets/image/asset-image.png" import assetImage from "../../../../../../assets/image/asset-image.png"
import { useSceneContext } from '../../../../../../modules/scene/sceneContext'; import { useSceneContext } from '../../../../../../modules/scene/sceneContext';
import { useProductContext } from '../../../../../../modules/simulation/products/productContext';
import RenameInput from '../../../../../ui/inputs/RenameInput'; import RenameInput from '../../../../../ui/inputs/RenameInput';
import { useResourceManagementId } from '../../../../../../store/builder/store'; import { useResourceManagementId } from '../../../../../../store/builder/store';
import { getAssetThumbnail } from '../../../../../../services/factoryBuilder/asset/assets/getAssetThumbnail';
const AssetManagement = () => { const AssetManagement = () => {
// const [selectedCategory, setSelectedCategory] = useState("All Assets"); // const [selectedCategory, setSelectedCategory] = useState("All Assets");
const [expandedAssetId, setExpandedAssetId] = useState<string | null>(null); const [expandedAssetId, setExpandedAssetId] = useState<string | null>(null);
const [assets, setAssets] = useState<any[]>([]); const [assets, setAssets] = useState<any[]>([]);
const { productStore } = useSceneContext();
const { products, getProductById } = productStore();
const { selectedProductStore } = useProductContext();
const { selectedProduct } = selectedProductStore();
const { setResourceManagementId } = useResourceManagementId(); const { setResourceManagementId } = useResourceManagementId();
const { assetStore } = useSceneContext();
const { assets: allAssets } = assetStore();
async function getAsset(assetId: string) {
let thumbnail = await getAssetThumbnail(assetId)
if (thumbnail.thumbnail) {
let assetImage = thumbnail.thumbnail
return assetImage;
}
}
useEffect(() => { useEffect(() => {
if (selectedProduct) { if (allAssets.length > 0) {
const productDetails = getProductById(selectedProduct.productUuid); const fetchAssets = async () => {
const productAssets = productDetails?.eventDatas || []; const grouped: Record<string, any> = {};
const grouped: Record<string, any> = {};
productAssets.forEach((asset: any) => {
if (asset.type === "storageUnit" || asset.type === "human") return;
if (!grouped[asset.modelName]) {
grouped[asset.modelName] = {
id: asset.modelUuid,
name: asset.modelName,
model: asset.modelCode || "N/A",
status: asset.status || "Online",
usageRate: asset.usageRate || 15,
level: asset.level || "Level 1",
image: assetImage,
description: asset.description || "No description",
cost: asset.cost || 0,
count: 1,
};
} else {
grouped[asset.modelName].count += 1;
}
});
setAssets(Object.values(grouped)); // Use Promise.all to handle all async operations
await Promise.all(allAssets.map(async (asset: any) => {
if (asset.eventData.type === "Storage" || asset.eventData.type === "Human") return;
const assetImage = await getAsset(asset.assetId);
if (!grouped[asset.assetId]) {
grouped[asset.assetId] = {
id: asset.modelUuid,
assetId: asset.assetId,
name: asset.modelName,
model: asset.modelCode ?? "N/A",
status: asset.status ?? "Online",
usageRate: asset.usageRate ?? 15,
level: asset.level ?? "Level 1",
image: assetImage,
description: asset.description ?? "No description",
cost: asset.cost ?? 0,
count: 1,
};
} else {
grouped[asset.assetId].count += 1;
}
}));
setAssets(Object.values(grouped));
}
fetchAssets();
} }
}, [selectedProduct]); }, [allAssets]);
function handleRenameAsset(newName: string) { function handleRenameAsset(newName: string) {
//
// if (expandedAssetId) {
// setAssets(prevAssets =>
// prevAssets.map(asset =>
// asset.id === expandedAssetId ? { ...asset, name: newName } : asset
// )
// );
// }
} }
useEffect(() => { useEffect(() => {
@@ -65,8 +70,6 @@ const AssetManagement = () => {
}, [assets]); }, [assets]);
function handleAssetClick(id: string) { function handleAssetClick(id: string) {
setResourceManagementId(id); setResourceManagementId(id);
} }
@@ -170,9 +173,9 @@ const AssetManagement = () => {
</div> </div>
</div> </div>
<div className="asset-estimate__view-button"> <div className="asset-estimate__view-button" onClick={() => handleAssetClick(asset.id)}>
<EyeIcon isClosed={false} /> <EyeIcon isClosed={false} />
<div className="asset-estimate__view-text" onClick={() => handleAssetClick(asset.id)}>View in Scene</div> <div className="asset-estimate__view-text">View in Scene</div>
</div> </div>
</div> </div>

View File

@@ -0,0 +1,33 @@
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
export const getAssetThumbnail = async (assetId: String) => {
try {
const response = await fetch(
`${url_Backend_dwinzo}/api/v2/getAssetThumbnail/${assetId}`,
{
method: "GET",
headers: {
Authorization: "Bearer <access_token>",
"Content-Type": "application/json",
token: localStorage.getItem("token") || "",
refresh_token: localStorage.getItem("refreshToken") || "",
},
}
);
const newAccessToken = response.headers.get("x-access-token");
if (newAccessToken) {
localStorage.setItem("token", newAccessToken);
}
if (!response.ok) {
throw new Error("Failed to fetch assets");
}
//
return await response.json();
} catch (error: any) {
echo.error("Failed to get asset image");
}
};

View File

@@ -117,6 +117,12 @@
border-radius: 50%; border-radius: 50%;
background-color: #fff; background-color: #fff;
position: relative; position: relative;
overflow: hidden;
.user-image{
height: 300%;
width: 300%;
transform: translate(-26px, -12px);
}
.status { .status {
border-radius: 50%; border-radius: 50%;