added usecase creation and dashboard changes
This commit is contained in:
@@ -1,42 +1,34 @@
|
||||
import { MathUtils } from "three";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import DashboardNavBar from "./DashboardNavBar";
|
||||
import { projectTutorialApi } from "../../services/dashboard/projectTutorialApi";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { TutorialCard } from "./TutorialCard";
|
||||
import { useSocketStore } from "../../store/socket/useSocketStore";
|
||||
import { getUserData } from "../../functions/getUserData";
|
||||
import { ALPHA_ORG } from "../../pages/Dashboard";
|
||||
import { useLoadingProgress, useProjectName } from "../../store/builder/store";
|
||||
import DashboardNavBar from "./DashboardNavBar";
|
||||
|
||||
const DUMMY_DATA = [
|
||||
//remove later
|
||||
{
|
||||
_id: "1",
|
||||
name: "Robotic Arm Control",
|
||||
thumbnail: "https://signfix.com.au/wp-content/uploads/2017/09/placeholder-600x400.png",
|
||||
updatedAt: new Date().toISOString(),
|
||||
},
|
||||
{
|
||||
_id: "2",
|
||||
name: "Simulation Basics",
|
||||
thumbnail: "https://signfix.com.au/wp-content/uploads/2017/09/placeholder-600x400.png",
|
||||
updatedAt: new Date().toISOString(),
|
||||
},
|
||||
{
|
||||
_id: "3",
|
||||
name: "3D Visualization",
|
||||
thumbnail: "https://signfix.com.au/wp-content/uploads/2017/09/placeholder-600x400.png",
|
||||
updatedAt: new Date().toISOString(),
|
||||
},
|
||||
];
|
||||
import darkThemeImage from "../../assets/image/darkThemeProject.png";
|
||||
import lightThemeImage from "../../assets/image/lightThemeProject.png";
|
||||
|
||||
import { createProjectApi } from "../../services/dashboard/createProjectApi";
|
||||
import { getUseCaseProjectsApi } from "../../services/dashboard/getuseCaseProjectsApi";
|
||||
|
||||
const DashboardUseCases: React.FC = () => {
|
||||
const [useCases, setUseCases] = useState<Tutorial[]>(DUMMY_DATA || []); // default []
|
||||
const { organization } = getUserData();
|
||||
const navigate = useNavigate();
|
||||
const { setLoadingProgress } = useLoadingProgress();
|
||||
const { setProjectName } = useProjectName();
|
||||
const [useCases, setUseCases] = useState<Tutorial[]>([]);
|
||||
const { projectSocket, initializeProjectSocket } = useSocketStore();
|
||||
const { organization, userId } = getUserData();
|
||||
const savedTheme = localStorage.getItem("theme") ?? "light";
|
||||
|
||||
useEffect(() => {
|
||||
const fetchTutorials = async () => {
|
||||
try {
|
||||
const res = await projectTutorialApi();
|
||||
if (res && Array.isArray(res) && res.length > 0) {
|
||||
setUseCases(res);
|
||||
const res = await getUseCaseProjectsApi();
|
||||
if (res.Projects.length > 0) {
|
||||
setUseCases(res.Projects);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching useCases:", error);
|
||||
@@ -46,6 +38,47 @@ const DashboardUseCases: React.FC = () => {
|
||||
fetchTutorials();
|
||||
}, []);
|
||||
|
||||
const handleCreateNewUseCase = async () => {
|
||||
const token = localStorage.getItem("token");
|
||||
const refreshToken = localStorage.getItem("refreshToken");
|
||||
if (!token || !refreshToken) {
|
||||
console.error("token expired");
|
||||
return;
|
||||
}
|
||||
|
||||
const projectId = MathUtils.generateUUID();
|
||||
initializeProjectSocket(token, refreshToken);
|
||||
|
||||
if (projectSocket?.connected) {
|
||||
// SOCKET
|
||||
|
||||
const addProject = {
|
||||
userId,
|
||||
thumbnail: savedTheme === "dark" ? darkThemeImage : lightThemeImage,
|
||||
organization: organization,
|
||||
projectUuid: projectId,
|
||||
projectType: "useCase",
|
||||
};
|
||||
|
||||
projectSocket.emit("v1:project:add", addProject);
|
||||
} else {
|
||||
// API
|
||||
|
||||
createProjectApi(projectId, userId, savedTheme === "dark" ? darkThemeImage : lightThemeImage, organization, "useCase").then((data) => {
|
||||
if (data.message === "Project created Successfully") {
|
||||
setLoadingProgress(1);
|
||||
navigate(`/projects/${data.data.projectId}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const handleNavigateToUseCase = (useCase: Tutorial) => {
|
||||
setLoadingProgress(1);
|
||||
setProjectName(useCase.projectName);
|
||||
navigate(`/projects/${useCase._id}`);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="dashboard-home-container">
|
||||
<DashboardNavBar page="tutorial" />
|
||||
@@ -54,18 +87,21 @@ const DashboardUseCases: React.FC = () => {
|
||||
{organization === ALPHA_ORG && (
|
||||
<div className="tutorials-main-header">
|
||||
<div className="tutorial-buttons-container">
|
||||
<button className="add-tutorials-button">
|
||||
<button
|
||||
onClick={() => {
|
||||
handleCreateNewUseCase();
|
||||
}}
|
||||
className="add-tutorials-button"
|
||||
>
|
||||
<span>+</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{useCases.length > 0 ? (
|
||||
useCases.map((tut) => <TutorialCard key={tut._id} tutorial={tut} />)
|
||||
useCases.map((tut) => <TutorialCard onClick={handleNavigateToUseCase} key={tut._id} tutorial={tut} />)
|
||||
) : (
|
||||
<div className="empty-state">
|
||||
No Use Cases available click on '+' button to add
|
||||
</div>
|
||||
<div className="empty-state">No Use Cases available click on '+' button to add</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2,7 +2,6 @@ import React, { useEffect, useState } from "react";
|
||||
import { getUserData } from "../../functions/getUserData";
|
||||
import { useSocketStore } from "../../store/socket/useSocketStore";
|
||||
|
||||
import ProjectSocketRes from "./socket/projectSocketRes";
|
||||
import DashboardNavBar from "./DashboardNavBar";
|
||||
import DashboardCard from "./DashboardCard";
|
||||
import MarketPlaceBanner from "./MarketPlaceBanner";
|
||||
@@ -18,13 +17,16 @@ import { generateUniqueId } from "../../functions/generateUniqueId";
|
||||
|
||||
interface DashboardMainProps {
|
||||
activeFolder: Folder;
|
||||
projectsData: DashboardProjectCollection;
|
||||
projectsCache: Record<string, DashboardProjectCollection>;
|
||||
isSearchActive: boolean;
|
||||
setProjectsData: React.Dispatch<React.SetStateAction<DashboardProjectCollection>>;
|
||||
setProjectsCache: React.Dispatch<React.SetStateAction<Record<string, DashboardProjectCollection>>>;
|
||||
setIsSearchActive: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
}
|
||||
|
||||
const DashboardMain: React.FC<DashboardMainProps> = ({ activeFolder }) => {
|
||||
const DashboardMain: React.FC<DashboardMainProps> = ({ activeFolder, projectsData, projectsCache, isSearchActive, setProjectsData, setProjectsCache, setIsSearchActive }) => {
|
||||
const [activeSubFolder, setActiveSubFolder] = useState("myProjects");
|
||||
const [projectsData, setProjectsData] = useState<DashboardProjectCollection>({});
|
||||
const [projectsCache, setProjectsCache] = useState<Record<string, DashboardProjectCollection>>({});
|
||||
const [isSearchActive, setIsSearchActive] = useState<boolean>(false);
|
||||
const [openKebabProjectId, setOpenKebabProjectId] = useState<string | null>(null);
|
||||
|
||||
const { userId, organization } = getUserData();
|
||||
@@ -173,7 +175,7 @@ const DashboardMain: React.FC<DashboardMainProps> = ({ activeFolder }) => {
|
||||
const key = Object.keys(projectsData)[0];
|
||||
const projectList = projectsData[key];
|
||||
|
||||
if (!projectList?.length) {
|
||||
if (!projectList || projectList.length === 0) {
|
||||
return <div className="empty-state">No projects found</div>;
|
||||
}
|
||||
|
||||
@@ -237,8 +239,6 @@ const DashboardMain: React.FC<DashboardMainProps> = ({ activeFolder }) => {
|
||||
)}
|
||||
|
||||
<div className="cards-container">{renderProjects()}</div>
|
||||
|
||||
<ProjectSocketRes setIsSearchActive={setIsSearchActive} {...(activeFolder === "home" ? { setRecentProjects: setProjectsData } : { setWorkspaceProjects: setProjectsData })} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -22,6 +22,8 @@ const DashboardTutorial: React.FC = () => {
|
||||
fetchTutorials();
|
||||
}, []);
|
||||
|
||||
const handleNavigateToTutorial = () => {};
|
||||
|
||||
return (
|
||||
<div className="dashboard-home-container">
|
||||
<DashboardNavBar page="tutorial" />
|
||||
@@ -36,7 +38,7 @@ const DashboardTutorial: React.FC = () => {
|
||||
</div>
|
||||
<div className="tutorials-list">
|
||||
{tutorials.length > 0 ? (
|
||||
tutorials.map((tut) => <TutorialCard key={tut._id} tutorial={tut} />)
|
||||
tutorials.map((tut) => <TutorialCard onClick={handleNavigateToTutorial} key={tut._id} tutorial={tut} />)
|
||||
) : (
|
||||
<div className="empty-state">No tutorials available</div>
|
||||
)}
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
import React from "react";
|
||||
import { DocumentationIcon, HelpIcon, HomeIcon, LogoutIcon, NotificationIcon, ProjectsIcon, TrashIcon, TutorialsIcon } from "../icons/DashboardIcon";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import darkThemeImage from "../../assets/image/darkThemeProject.png";
|
||||
import lightThemeImage from "../../assets/image/lightThemeProject.png";
|
||||
import { DocumentationIcon, HelpIcon, HomeIcon, LogoutIcon, NotificationIcon, ProjectsIcon, TrashIcon, TutorialsIcon } from "../icons/DashboardIcon";
|
||||
import { SettingsIcon } from "../icons/ExportCommonIcons";
|
||||
import { getUserData } from "../../functions/getUserData";
|
||||
import { useSocketStore } from "../../store/socket/useSocketStore";
|
||||
import { useLoadingProgress } from "../../store/builder/store";
|
||||
|
||||
// import { createProject } from "../../services/dashboard/createProject";
|
||||
import { createProjectApi } from "../../services/dashboard/createProjectApi";
|
||||
|
||||
import darkThemeImage from "../../assets/image/darkThemeProject.png";
|
||||
import lightThemeImage from "../../assets/image/lightThemeProject.png";
|
||||
|
||||
interface SidePannelProps {
|
||||
setActiveTab: React.Dispatch<React.SetStateAction<string>>;
|
||||
@@ -15,8 +17,9 @@ interface SidePannelProps {
|
||||
}
|
||||
|
||||
const SidePannel: React.FC<SidePannelProps> = ({ setActiveTab, activeTab }) => {
|
||||
const { userName, userId, organization } = getUserData();
|
||||
const navigate = useNavigate();
|
||||
const { setLoadingProgress } = useLoadingProgress();
|
||||
const { userName, userId, organization } = getUserData();
|
||||
const { projectSocket, initializeProjectSocket } = useSocketStore();
|
||||
const savedTheme = localStorage.getItem("theme") ?? "light";
|
||||
|
||||
@@ -49,12 +52,12 @@ const SidePannel: React.FC<SidePannelProps> = ({ setActiveTab, activeTab }) => {
|
||||
projectSocket.emit("v1:project:add", addProject);
|
||||
} else {
|
||||
// API
|
||||
// const project = await createProject(
|
||||
// projectId,
|
||||
// userId,
|
||||
// savedTheme === "dark" ? darkThemeImage : lightThemeImage,
|
||||
// organization
|
||||
// );
|
||||
createProjectApi(projectId, userId, savedTheme === "dark" ? darkThemeImage : lightThemeImage, organization).then((data) => {
|
||||
if (data.message === "Project created Successfully") {
|
||||
setLoadingProgress(1);
|
||||
navigate(`/projects/${data.data.projectId}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -92,7 +95,6 @@ const SidePannel: React.FC<SidePannelProps> = ({ setActiveTab, activeTab }) => {
|
||||
// disabled
|
||||
onClick={() => {
|
||||
setActiveTab("Use Cases");
|
||||
console.warn("Use Cases comming soon");
|
||||
}}
|
||||
>
|
||||
<TutorialsIcon isActive={activeTab === "Use Cases"} />
|
||||
|
||||
@@ -2,24 +2,20 @@ import { getUserData } from "../../functions/getUserData";
|
||||
import { ALPHA_ORG } from "../../pages/Dashboard";
|
||||
import { DeleteIcon } from "../icons/ContextMenuIcons";
|
||||
|
||||
export const TutorialCard: React.FC<{ tutorial: Tutorial }> = ({ tutorial }) => {
|
||||
export const TutorialCard: React.FC<{ tutorial: Tutorial; onClick: (tutorial: Tutorial) => void }> = ({ tutorial, onClick }) => {
|
||||
const { organization } = getUserData();
|
||||
return (
|
||||
<div className="tutorial-card-container">
|
||||
<div className="tutorial-card-container" onClick={() => onClick(tutorial)}>
|
||||
<div
|
||||
className="preview-container"
|
||||
style={{
|
||||
backgroundImage: tutorial.thumbnail
|
||||
? `url(${tutorial.thumbnail})`
|
||||
: "linear-gradient(135deg, #ddd, #bbb)",
|
||||
backgroundImage: tutorial.thumbnail ? `url(${tutorial.thumbnail})` : "linear-gradient(135deg, #ddd, #bbb)",
|
||||
}}
|
||||
></div>
|
||||
<div className="tutorial-details">
|
||||
<div className="context">
|
||||
<div className="tutorial-name">{tutorial.name}</div>
|
||||
<div className="updated-date">
|
||||
{new Date(tutorial.updatedAt).toLocaleDateString()}
|
||||
</div>
|
||||
<div className="tutorial-name">{tutorial.projectName}</div>
|
||||
<div className="updated-date">{new Date(tutorial.createdAt).toLocaleDateString()}</div>
|
||||
</div>
|
||||
{organization === ALPHA_ORG && (
|
||||
<div className="delete-option">
|
||||
|
||||
@@ -5,14 +5,23 @@ import SidePannel from "../components/Dashboard/SidePannel";
|
||||
import DashboardTutorial from "../components/Dashboard/DashboardTutorial";
|
||||
import DashboardMain from "../components/Dashboard/DashboardMain";
|
||||
import DashboardUseCases from "../components/Dashboard/DasboardUseCases";
|
||||
import ProjectSocketRes from "../components/Dashboard/socket/projectSocketRes";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
export const ALPHA_ORG = "hexrfactory";
|
||||
|
||||
const Dashboard: React.FC = () => {
|
||||
const navigate = useNavigate();
|
||||
const [activeTab, setActiveTab] = useState<string>("Home");
|
||||
const [projectsData, setProjectsData] = useState<DashboardProjectCollection>({});
|
||||
const [projectsCache, setProjectsCache] = useState<Record<string, DashboardProjectCollection>>({});
|
||||
const [isSearchActive, setIsSearchActive] = useState<boolean>(false);
|
||||
const { organization, email } = getUserData();
|
||||
|
||||
useEffect(() => {
|
||||
if (email === "" || organization === "") {
|
||||
navigate("/");
|
||||
}
|
||||
const token = localStorage.getItem("token");
|
||||
const refreshToken = localStorage.getItem("refreshToken");
|
||||
if (token && refreshToken) {
|
||||
@@ -20,12 +29,31 @@ const Dashboard: React.FC = () => {
|
||||
}
|
||||
}, [email, organization]);
|
||||
|
||||
if (email === "" || organization === "") {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="dashboard-main">
|
||||
<SidePannel setActiveTab={setActiveTab} activeTab={activeTab} />
|
||||
{["Home", "Projects", "Shared", "Trash"].includes(activeTab) && <DashboardMain activeFolder={activeTab.toLowerCase() as Folder} />}
|
||||
{["Home", "Projects", "Shared", "Trash"].includes(activeTab) && (
|
||||
<DashboardMain
|
||||
activeFolder={activeTab.toLowerCase() as Folder}
|
||||
projectsData={projectsData}
|
||||
projectsCache={projectsCache}
|
||||
isSearchActive={isSearchActive}
|
||||
setProjectsData={setProjectsData}
|
||||
setProjectsCache={setProjectsCache}
|
||||
setIsSearchActive={setIsSearchActive}
|
||||
/>
|
||||
)}
|
||||
{activeTab === "Tutorials" && <DashboardTutorial />}
|
||||
{activeTab === "Use Cases" && <DashboardUseCases />}
|
||||
|
||||
<ProjectSocketRes
|
||||
setIsSearchActive={setIsSearchActive}
|
||||
{...((activeTab.toLowerCase() as Folder) === "home" ? { setRecentProjects: setProjectsData } : { setWorkspaceProjects: setProjectsData })}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
|
||||
|
||||
export const createProjectApi = async (projectUuid: string, userId: string, thumbnail: string, organization: string) => {
|
||||
export const createProjectApi = async (projectUuid: string, userId: string, thumbnail: string, organization: string, projectType?: string) => {
|
||||
try {
|
||||
const response = await fetch(`${url_Backend_dwinzo}/api/V1/NewProject`, {
|
||||
method: "POST",
|
||||
@@ -10,7 +10,7 @@ export const createProjectApi = async (projectUuid: string, userId: string, thum
|
||||
token: localStorage.getItem("token") || "",
|
||||
refresh_token: localStorage.getItem("refreshToken") || "",
|
||||
},
|
||||
body: JSON.stringify({ projectUuid, userId, thumbnail, organization }),
|
||||
body: JSON.stringify({ projectUuid, userId, thumbnail, organization, projectType }),
|
||||
});
|
||||
const newAccessToken = response.headers.get("x-access-token");
|
||||
if (newAccessToken) {
|
||||
|
||||
28
app/src/services/dashboard/getuseCaseProjectsApi.ts
Normal file
28
app/src/services/dashboard/getuseCaseProjectsApi.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
|
||||
|
||||
export const getUseCaseProjectsApi = async () => {
|
||||
try {
|
||||
const response = await fetch(`${url_Backend_dwinzo}/api/V1/useCases/projects`, {
|
||||
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) {
|
||||
console.error("Failed to get usecase Projects");
|
||||
}
|
||||
|
||||
const result = await response.json();
|
||||
return result;
|
||||
} catch {
|
||||
console.log("Failed to get usecase Projects");
|
||||
}
|
||||
};
|
||||
4
app/src/types/uiTypes.d.ts
vendored
4
app/src/types/uiTypes.d.ts
vendored
@@ -73,7 +73,7 @@ interface ListProps {
|
||||
|
||||
interface Tutorial {
|
||||
_id: string;
|
||||
name: string;
|
||||
projectName: string;
|
||||
thumbnail?: string;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user