adding features store
This commit is contained in:
parent
768a7cd754
commit
3e315012e1
10 changed files with 168 additions and 13 deletions
|
|
@ -6,6 +6,7 @@ import { USER_PROJECTS_HEADER } from "../../constants/constants";
|
|||
import { alertContext } from "../../contexts/alertContext";
|
||||
import { AuthContext } from "../../contexts/authContext";
|
||||
import { darkContext } from "../../contexts/darkContext";
|
||||
import { StoreContext } from "../../contexts/storeContext";
|
||||
import { TabsContext } from "../../contexts/tabsContext";
|
||||
import { gradients } from "../../utils/styleUtils";
|
||||
import IconComponent from "../genericIconComponent";
|
||||
|
|
@ -27,6 +28,7 @@ export default function Header(): JSX.Element {
|
|||
const { notificationCenter } = useContext(alertContext);
|
||||
const location = useLocation();
|
||||
const { logout, autoLogin, isAdmin, userData } = useContext(AuthContext);
|
||||
const { hasStore } = useContext(StoreContext);
|
||||
const { stars, gradientIndex } = useContext(darkContext);
|
||||
const navigate = useNavigate();
|
||||
|
||||
|
|
@ -64,16 +66,18 @@ export default function Header(): JSX.Element {
|
|||
<div className="flex-1">Community Examples</div>
|
||||
</Button>
|
||||
</Link>
|
||||
<Link to="/store">
|
||||
<Button
|
||||
className="gap-2"
|
||||
variant={location.pathname === "/store" ? "primary" : "secondary"}
|
||||
size="sm"
|
||||
>
|
||||
<IconComponent name="Store" className="h-4 w-4" />
|
||||
<div className="flex-1">Store</div>
|
||||
</Button>
|
||||
</Link>
|
||||
{hasStore && (
|
||||
<Link to="/store">
|
||||
<Button
|
||||
className="gap-2"
|
||||
variant={location.pathname === "/store" ? "primary" : "secondary"}
|
||||
size="sm"
|
||||
>
|
||||
<IconComponent name="Store" className="h-4 w-4" />
|
||||
<div className="flex-1">Store</div>
|
||||
</Button>
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
<div className="header-end-division">
|
||||
<div className="header-end-display">
|
||||
|
|
|
|||
12
src/frontend/src/components/storeGuard/index.tsx
Normal file
12
src/frontend/src/components/storeGuard/index.tsx
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
import { useContext } from "react";
|
||||
import { Navigate } from "react-router-dom";
|
||||
import { StoreContext } from "../../contexts/storeContext";
|
||||
|
||||
export const StoreGuard = ({ children }) => {
|
||||
const { hasStore } = useContext(StoreContext);
|
||||
if (!hasStore) {
|
||||
return <Navigate to="/flows" replace />;
|
||||
}
|
||||
|
||||
return children;
|
||||
};
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
import { createContext, useState } from "react";
|
||||
import { checkHasStore } from "../controllers/API";
|
||||
import { storeContextType } from "../types/contexts/store";
|
||||
import { FlowType } from "../types/flow";
|
||||
|
||||
|
|
@ -6,15 +7,24 @@ import { FlowType } from "../types/flow";
|
|||
const initialValue = {
|
||||
savedFlows: {},
|
||||
setSavedFlows: () => {},
|
||||
hasStore: false,
|
||||
setHasStore: () => {},
|
||||
};
|
||||
|
||||
export const StoreContext = createContext<storeContextType>(initialValue);
|
||||
|
||||
export function StoreProvider({ children }) {
|
||||
const [savedFlows, setSavedFlows] = useState<{ [key: string]: FlowType }>({});
|
||||
const [hasStore, setHasStore] = useState(false);
|
||||
|
||||
checkHasStore().then((res) => {
|
||||
setHasStore(res[0].has_store);
|
||||
});
|
||||
|
||||
return (
|
||||
<StoreContext.Provider value={{ savedFlows, setSavedFlows }}>
|
||||
<StoreContext.Provider
|
||||
value={{ savedFlows, setSavedFlows, hasStore, setHasStore }}
|
||||
>
|
||||
{children}
|
||||
</StoreContext.Provider>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -662,3 +662,17 @@ export async function searchComponent(
|
|||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
export async function checkHasStore() {
|
||||
try {
|
||||
const res = await api.get(
|
||||
`https://65384701a543859d1bb15e63.mockapi.io/Store`
|
||||
);
|
||||
if (res.status === 200) {
|
||||
return res.data;
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("Error:", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ export default function ComponentsComponent() {
|
|||
isLoading,
|
||||
} = useContext(TabsContext);
|
||||
const { setErrorData } = useContext(alertContext);
|
||||
|
||||
const dropdownOptions = [
|
||||
{
|
||||
name: "Import from JSON",
|
||||
|
|
@ -69,6 +70,7 @@ export default function ComponentsComponent() {
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
onDragOver={dragOver}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,70 @@
|
|||
import { useContext, useEffect, useState } from "react";
|
||||
|
||||
import { alertContext } from "../../../../contexts/alertContext";
|
||||
import { AuthContext } from "../../../../contexts/authContext";
|
||||
import { TabsContext } from "../../../../contexts/tabsContext";
|
||||
import { getStoreComponents } from "../../../../controllers/API";
|
||||
import { FlowComponent } from "../../../../types/store";
|
||||
import { MarketCardComponent } from "../../../StorePage/components/market-card";
|
||||
|
||||
export default function SavedComponents(): JSX.Element {
|
||||
const { setTabId } = useContext(TabsContext);
|
||||
|
||||
const { setApiKey, apiKey } = useContext(AuthContext);
|
||||
|
||||
// set null id
|
||||
useEffect(() => {
|
||||
setTabId("");
|
||||
}, []);
|
||||
const [data, setData] = useState<FlowComponent[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [filteredCategories, setFilteredCategories] = useState(new Set());
|
||||
const { setErrorData } = useContext(alertContext);
|
||||
|
||||
useEffect(() => {
|
||||
handleGetComponents();
|
||||
}, []);
|
||||
|
||||
const handleGetComponents = () => {
|
||||
setLoading(true);
|
||||
getStoreComponents(1, 10)
|
||||
.then((res) => {
|
||||
setLoading(false);
|
||||
setData(res);
|
||||
})
|
||||
.catch((err) => {
|
||||
setLoading(false);
|
||||
setErrorData({
|
||||
title: "Error to get components.",
|
||||
list: [err["response"]["data"]["detail"]],
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const loadingWithApiKey = loading;
|
||||
const renderComponents = !loading;
|
||||
|
||||
return (
|
||||
<>
|
||||
{renderComponents && (
|
||||
<div className="flex w-full flex-col gap-4 p-4">
|
||||
<div className="mt-6 grid w-full gap-4 md:grid-cols-2 lg:grid-cols-3">
|
||||
{data
|
||||
.filter(
|
||||
(f) =>
|
||||
Array.from(filteredCategories).length === 0 ||
|
||||
filteredCategories.has(f.is_component)
|
||||
)
|
||||
.map((item, idx) => (
|
||||
<MarketCardComponent key={idx} data={item} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{loadingWithApiKey && (
|
||||
<div className="flex w-full flex-col gap-4 p-4">Loading...</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
@ -8,6 +8,7 @@ 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 { StoreContext } from "../../contexts/storeContext";
|
||||
import { TabsContext } from "../../contexts/tabsContext";
|
||||
export default function HomePage(): JSX.Element {
|
||||
const {
|
||||
|
|
@ -20,6 +21,7 @@ export default function HomePage(): JSX.Element {
|
|||
isLoading,
|
||||
} = useContext(TabsContext);
|
||||
const { setErrorData } = useContext(alertContext);
|
||||
const { hasStore } = useContext(StoreContext);
|
||||
const dropdownOptions = [
|
||||
{
|
||||
name: "Import from JSON",
|
||||
|
|
@ -40,6 +42,13 @@ export default function HomePage(): JSX.Element {
|
|||
},
|
||||
];
|
||||
|
||||
if (hasStore) {
|
||||
sidebarNavItems.push({
|
||||
title: "Saved Components",
|
||||
href: "/saved-components",
|
||||
});
|
||||
}
|
||||
|
||||
// Set a null id
|
||||
useEffect(() => {
|
||||
setTabId("");
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { cloneDeep } from "lodash";
|
||||
import { Link, Search } from "lucide-react";
|
||||
import { useContext, useEffect, useState } from "react";
|
||||
import PaginatorComponent from "../../components/PaginatorComponent";
|
||||
import IconComponent from "../../components/genericIconComponent";
|
||||
import Header from "../../components/headerComponent";
|
||||
import { Badge } from "../../components/ui/badge";
|
||||
|
|
@ -40,6 +41,11 @@ export default function StorePage(): JSX.Element {
|
|||
const [errorApiKey, setErrorApiKey] = useState(false);
|
||||
const { setErrorData } = useContext(alertContext);
|
||||
const { addFlow } = useContext(TabsContext);
|
||||
const [totalRowsCount, setTotalRowsCount] = useState(0);
|
||||
const [size, setPageSize] = useState(10);
|
||||
const [index, setPageIndex] = useState(1);
|
||||
|
||||
function handleChangePagination(pageIndex: number, pageSize: number) {}
|
||||
|
||||
useEffect(() => {
|
||||
handleGetComponents();
|
||||
|
|
@ -66,11 +72,15 @@ export default function StorePage(): JSX.Element {
|
|||
};
|
||||
|
||||
const handleSearch = (inputText: string) => {
|
||||
setLoading(true);
|
||||
searchComponent(inputText).then(
|
||||
(res) => {
|
||||
setLoading(false);
|
||||
setSearchData(res);
|
||||
},
|
||||
(error) => {}
|
||||
(error) => {
|
||||
setLoading(false);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -198,6 +208,15 @@ export default function StorePage(): JSX.Element {
|
|||
<MarketCardComponent key={idx} data={item} />
|
||||
))}
|
||||
</div>
|
||||
|
||||
<PaginatorComponent
|
||||
pageIndex={index}
|
||||
pageSize={size}
|
||||
totalRowsCount={totalRowsCount}
|
||||
paginate={(pageSize, pageIndex) => {
|
||||
handleChangePagination(pageIndex, pageSize);
|
||||
}}
|
||||
></PaginatorComponent>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { ProtectedAdminRoute } from "./components/authAdminGuard";
|
|||
import { ProtectedRoute } from "./components/authGuard";
|
||||
import { ProtectedLoginRoute } from "./components/authLoginGuard";
|
||||
import { CatchAllRoute } from "./components/catchAllRoutes";
|
||||
import { StoreGuard } from "./components/storeGuard";
|
||||
import AdminPage from "./pages/AdminPage";
|
||||
import LoginAdminPage from "./pages/AdminPage/LoginPage";
|
||||
import ApiKeysPage from "./pages/ApiKeysPage";
|
||||
|
|
@ -11,6 +12,7 @@ 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 SavedComponents from "./pages/MainPage/components/saved-components";
|
||||
import ProfileSettingsPage from "./pages/ProfileSettingsPage";
|
||||
import StorePage from "./pages/StorePage";
|
||||
import ViewPage from "./pages/ViewPage";
|
||||
|
|
@ -38,6 +40,14 @@ const Router = () => {
|
|||
>
|
||||
<Route path="flows" element={<FlowsComponent />} />
|
||||
<Route path="components" element={<ComponentsComponent />} />
|
||||
<Route
|
||||
path="saved-components"
|
||||
element={
|
||||
<StoreGuard>
|
||||
<SavedComponents />
|
||||
</StoreGuard>
|
||||
}
|
||||
/>
|
||||
</Route>
|
||||
<Route
|
||||
path="/community"
|
||||
|
|
@ -51,10 +61,13 @@ const Router = () => {
|
|||
path="/store"
|
||||
element={
|
||||
<ProtectedRoute>
|
||||
<StorePage />
|
||||
<StoreGuard>
|
||||
<StorePage />
|
||||
</StoreGuard>
|
||||
</ProtectedRoute>
|
||||
}
|
||||
/>
|
||||
|
||||
<Route path="/flow/:id/">
|
||||
<Route
|
||||
path=""
|
||||
|
|
|
|||
|
|
@ -3,4 +3,6 @@ import { FlowType } from "../flow";
|
|||
export type storeContextType = {
|
||||
savedFlows: { [key: string]: FlowType };
|
||||
setSavedFlows: (newState: { [key: string]: FlowType }) => void;
|
||||
setHasStore: (store: boolean) => void;
|
||||
hasStore: boolean;
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue