Modularized components page and made it similar to LangStore

This commit is contained in:
Lucas Oliveira 2023-11-18 20:44:07 -03:00
commit 422e4bd5a0
6 changed files with 164 additions and 154 deletions

View file

@ -1,16 +1,13 @@
import { useState } from "react";
import IconComponent from "../../components/genericIconComponent";
import { SkeletonCardComponent } from "../skeletonCardComponent";
export default function CardsWrapComponent({
onFileDrop,
children,
isLoading,
dragMessage,
}: {
onFileDrop?: (e: any) => void;
children: JSX.Element | JSX.Element[];
isLoading: boolean;
dragMessage?: string;
}) {
const [isDragging, setIsDragging] = useState(false);
@ -59,17 +56,7 @@ export default function CardsWrapComponent({
{dragMessage ? dragMessage : "Drop your file here"}
</>
) : (
<div className="main-page-flows-display">
{isLoading ? (
<>
<SkeletonCardComponent />
<SkeletonCardComponent />
<SkeletonCardComponent />
</>
) : (
children
)}
</div>
children
)}
</div>
);

View file

@ -16,7 +16,7 @@ export default function PageLayout({
<div className="flex h-screen w-full flex-col">
<Header />
<div className="flex h-full w-full flex-col justify-between overflow-auto bg-background px-16">
<div className="flex w-full items-center justify-between space-y-0.5 py-8 pb-2">
<div className="flex w-full items-center justify-between gap-4 space-y-0.5 py-8 pb-2">
<div className="flex w-full flex-col">
<h2 className="text-2xl font-bold tracking-tight">{title}</h2>
<p className="text-muted-foreground">{description}</p>

View file

@ -1,12 +1,43 @@
import { useContext } from "react";
import { useContext, useEffect, useState } from "react";
import { useNavigate } from "react-router-dom";
import PaginatorComponent from "../../../../components/PaginatorComponent";
import CollectionCardComponent from "../../../../components/cardComponent";
import CardsWrapComponent from "../../../../components/cardsWrapComponent";
import IconComponent from "../../../../components/genericIconComponent";
import { SkeletonCardComponent } from "../../../../components/skeletonCardComponent";
import { Button } from "../../../../components/ui/button";
import { alertContext } from "../../../../contexts/alertContext";
import { FlowsContext } from "../../../../contexts/flowsContext";
import { FlowType } from "../../../../types/flow";
export default function ComponentsComponent() {
export default function ComponentsComponent({
is_component = true,
}: {
is_component?: boolean;
}) {
const { flows, removeFlow, uploadFlow, isLoading } = useContext(FlowsContext);
const { setErrorData } = useContext(alertContext);
const [pageSize, setPageSize] = useState(10);
const [pageIndex, setPageIndex] = useState(1);
const [allData, setAllData] = useState(
flows.filter((f) => f.is_component === is_component)
);
const navigate = useNavigate();
useEffect(() => {
setAllData(flows.filter((f) => f.is_component === is_component));
}, [flows]);
useEffect(() => {
const start = (pageIndex - 1) * pageSize;
const end = start + pageSize;
setData(allData.slice(start, end));
}, [pageIndex, pageSize, allData]);
const [data, setData] = useState<FlowType[]>([]);
const name = is_component ? "Component" : "Flow";
const onFileDrop = (e) => {
e.preventDefault();
@ -25,20 +56,74 @@ export default function ComponentsComponent() {
return (
<CardsWrapComponent
onFileDrop={onFileDrop}
isLoading={isLoading && flows.length == 0}
dragMessage={"Drop your component here"}
dragMessage={`Drag your ${name} here`}
>
{flows
.filter((flow) => flow.is_component)
.map((flow, idx) => (
<CollectionCardComponent
key={idx}
data={flow}
onDelete={() => {
removeFlow(flow.id);
}}
/>
))}
<div className="flex h-full w-full flex-col justify-between">
<div className="flex w-full flex-col gap-4">
<div className="grid w-full gap-4 md:grid-cols-2 lg:grid-cols-2">
{!isLoading || data?.length > 0 ? (
data
?.sort(
(a, b) =>
new Date(b?.date_created!).getTime() -
new Date(a?.date_created!).getTime()
)
.map((item, idx) => (
<CollectionCardComponent
onDelete={() => {
removeFlow(item.id);
}}
key={idx}
data={item}
disabled={isLoading}
button={
!is_component ? (
<Button
variant="outline"
size="sm"
className="whitespace-nowrap "
onClick={() => {
navigate("/flow/" + item.id);
}}
>
<IconComponent
name="ExternalLink"
className="main-page-nav-button"
/>
Edit Flow
</Button>
) : (
<></>
)
}
/>
))
) : !isLoading && data?.length === 0 ? (
<>You haven't created {name}s yet.</>
) : (
<>
<SkeletonCardComponent />
<SkeletonCardComponent />
</>
)}
</div>
</div>
{!isLoading && allData.length > 0 && (
<div className="relative py-6">
<PaginatorComponent
storeComponent={true}
pageIndex={pageIndex}
pageSize={pageSize}
rowsCount={[10, 20, 50, 100]}
totalRowsCount={allData.length}
paginate={(pageSize, pageIndex) => {
setPageIndex(pageIndex);
setPageSize(pageSize);
}}
></PaginatorComponent>
</div>
)}
</div>
</CardsWrapComponent>
);
}

View file

@ -1,62 +0,0 @@
import { useContext } from "react";
import { Link } from "react-router-dom";
import CollectionCardComponent from "../../../../components/cardComponent";
import CardsWrapComponent from "../../../../components/cardsWrapComponent";
import IconComponent from "../../../../components/genericIconComponent";
import { Button } from "../../../../components/ui/button";
import { alertContext } from "../../../../contexts/alertContext";
import { FlowsContext } from "../../../../contexts/flowsContext";
export default function FlowsComponent() {
const { uploadFlow, removeFlow, flows, isLoading } = useContext(FlowsContext);
const { setErrorData } = useContext(alertContext);
const onFileDrop = (e) => {
e.preventDefault();
if (e.dataTransfer.types.some((types) => types === "Files")) {
if (e.dataTransfer.files.item(0).type === "application/json") {
uploadFlow(true, e.dataTransfer.files.item(0)!);
} else {
setErrorData({
title: "Invalid file type",
list: ["Please upload a JSON file"],
});
}
}
};
return (
<CardsWrapComponent
onFileDrop={onFileDrop}
dragMessage={"Drag your flow here"}
isLoading={isLoading && flows.length == 0}
>
{flows
.filter((flow) => !flow.is_component)
.reverse()
.map((flow, idx) => (
<CollectionCardComponent
key={idx}
data={flow}
button={
<Link to={"/flow/" + flow.id}>
<Button
variant="outline"
size="sm"
className="whitespace-nowrap "
>
<IconComponent
name="ExternalLink"
className="main-page-nav-button"
/>
Edit Flow
</Button>
</Link>
}
onDelete={() => {
removeFlow(flow.id);
}}
/>
))}
</CardsWrapComponent>
);
}

View file

@ -2,10 +2,9 @@ import { useContext, useEffect } from "react";
import { Outlet, useNavigate } from "react-router-dom";
import DropdownButton from "../../components/DropdownButtonComponent";
import IconComponent from "../../components/genericIconComponent";
import Header from "../../components/headerComponent";
import PageLayout from "../../components/pageLayout";
import SidebarNav from "../../components/sidebarComponent";
import { Button } from "../../components/ui/button";
import { Separator } from "../../components/ui/separator";
import { USER_PROJECTS_HEADER } from "../../constants/constants";
import { alertContext } from "../../contexts/alertContext";
import { FlowsContext } from "../../contexts/flowsContext";
@ -24,10 +23,18 @@ export default function HomePage(): JSX.Element {
const dropdownOptions = [
{
name: "Import from JSON",
onBtnClick: () =>
uploadFlow(true).then((id) => {
navigate("/flow/" + id);
}),
onBtnClick: () => {
try {
uploadFlow(true).then((id) => {
navigate("/flow/" + id);
});
} catch (error: any) {
setErrorData({
title: "Invalid file type",
list: [error],
});
}
},
},
];
const sidebarNavItems = [
@ -49,61 +56,49 @@ export default function HomePage(): JSX.Element {
// Personal flows display
return (
<>
<Header />
<div className="main-page-panel">
<div className="main-page-nav-arrangement">
<span className="main-page-nav-title">
<IconComponent name="Home" className="w-6" />
{USER_PROJECTS_HEADER}
</span>
<div className="button-div-style">
<Button
variant="primary"
onClick={() => {
downloadFlows();
}}
>
<IconComponent name="Download" className="main-page-nav-button" />
Download Collection
</Button>
<Button
variant="primary"
onClick={() => {
uploadFlows();
}}
>
<IconComponent name="Upload" className="main-page-nav-button" />
Upload Collection
</Button>
<DropdownButton
firstButtonName="New Project"
onFirstBtnClick={() => {
addFlow(true).then((id) => {
navigate("/flow/" + id);
});
}}
options={dropdownOptions}
/>
</div>
<PageLayout
title={USER_PROJECTS_HEADER}
description="Manage your personal projects. Download or upload your collection."
button={
<div className="flex gap-2">
<Button
variant="primary"
onClick={() => {
downloadFlows();
}}
>
<IconComponent name="Download" className="main-page-nav-button" />
Download Collection
</Button>
<Button
variant="primary"
onClick={() => {
uploadFlows();
}}
>
<IconComponent name="Upload" className="main-page-nav-button" />
Upload Collection
</Button>
<DropdownButton
firstButtonName="New Project"
onFirstBtnClick={() => {
addFlow(true).then((id) => {
navigate("/flow/" + id);
});
}}
options={dropdownOptions}
/>
</div>
<span className="main-page-description-text">
Manage your personal projects. Download or upload your collection.
</span>
<Separator className="my-6" />
<div className="flex flex-col space-y-8 lg:flex-row lg:space-x-8 lg:space-y-0">
<aside className="space-y-6 lg:w-1/5">
{/* <Input placeholder="Search" onChange={(e) => {}} /> */}
<SidebarNav
items={sidebarNavItems}
secondaryItems={sidebarNavItems}
/>
</aside>
<div className="w-full flex-1">
<Outlet />
</div>
}
>
<div className="flex h-full w-full space-y-8 lg:flex-row lg:space-x-8 lg:space-y-0">
<aside className="flex h-full flex-col space-y-6 lg:w-1/5">
<SidebarNav items={sidebarNavItems} />
</aside>
<div className="h-full w-full flex-1">
<Outlet />
</div>
</div>
</>
</PageLayout>
);
}

View file

@ -11,7 +11,6 @@ import ApiKeysPage from "./pages/ApiKeysPage";
import FlowPage from "./pages/FlowPage";
import HomePage from "./pages/MainPage";
import ComponentsComponent from "./pages/MainPage/components/components";
import FlowsComponent from "./pages/MainPage/components/flows";
import ProfileSettingsPage from "./pages/ProfileSettingsPage";
import StorePage from "./pages/StorePage";
import ViewPage from "./pages/ViewPage";
@ -37,8 +36,14 @@ const Router = () => {
</ProtectedRoute>
}
>
<Route path="flows" element={<FlowsComponent />} />
<Route path="components" element={<ComponentsComponent />} />
<Route
path="flows"
element={<ComponentsComponent key="flows" is_component={false} />}
/>
<Route
path="components"
element={<ComponentsComponent key="components" />}
/>
</Route>
<Route
path="/store"