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 { alertContext } from "../../contexts/alertContext";
|
||||||
import { AuthContext } from "../../contexts/authContext";
|
import { AuthContext } from "../../contexts/authContext";
|
||||||
import { darkContext } from "../../contexts/darkContext";
|
import { darkContext } from "../../contexts/darkContext";
|
||||||
|
import { StoreContext } from "../../contexts/storeContext";
|
||||||
import { TabsContext } from "../../contexts/tabsContext";
|
import { TabsContext } from "../../contexts/tabsContext";
|
||||||
import { gradients } from "../../utils/styleUtils";
|
import { gradients } from "../../utils/styleUtils";
|
||||||
import IconComponent from "../genericIconComponent";
|
import IconComponent from "../genericIconComponent";
|
||||||
|
|
@ -27,6 +28,7 @@ export default function Header(): JSX.Element {
|
||||||
const { notificationCenter } = useContext(alertContext);
|
const { notificationCenter } = useContext(alertContext);
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const { logout, autoLogin, isAdmin, userData } = useContext(AuthContext);
|
const { logout, autoLogin, isAdmin, userData } = useContext(AuthContext);
|
||||||
|
const { hasStore } = useContext(StoreContext);
|
||||||
const { stars, gradientIndex } = useContext(darkContext);
|
const { stars, gradientIndex } = useContext(darkContext);
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
|
@ -64,6 +66,7 @@ export default function Header(): JSX.Element {
|
||||||
<div className="flex-1">Community Examples</div>
|
<div className="flex-1">Community Examples</div>
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</Link>
|
||||||
|
{hasStore && (
|
||||||
<Link to="/store">
|
<Link to="/store">
|
||||||
<Button
|
<Button
|
||||||
className="gap-2"
|
className="gap-2"
|
||||||
|
|
@ -74,6 +77,7 @@ export default function Header(): JSX.Element {
|
||||||
<div className="flex-1">Store</div>
|
<div className="flex-1">Store</div>
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</Link>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="header-end-division">
|
<div className="header-end-division">
|
||||||
<div className="header-end-display">
|
<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 { createContext, useState } from "react";
|
||||||
|
import { checkHasStore } from "../controllers/API";
|
||||||
import { storeContextType } from "../types/contexts/store";
|
import { storeContextType } from "../types/contexts/store";
|
||||||
import { FlowType } from "../types/flow";
|
import { FlowType } from "../types/flow";
|
||||||
|
|
||||||
|
|
@ -6,15 +7,24 @@ import { FlowType } from "../types/flow";
|
||||||
const initialValue = {
|
const initialValue = {
|
||||||
savedFlows: {},
|
savedFlows: {},
|
||||||
setSavedFlows: () => {},
|
setSavedFlows: () => {},
|
||||||
|
hasStore: false,
|
||||||
|
setHasStore: () => {},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const StoreContext = createContext<storeContextType>(initialValue);
|
export const StoreContext = createContext<storeContextType>(initialValue);
|
||||||
|
|
||||||
export function StoreProvider({ children }) {
|
export function StoreProvider({ children }) {
|
||||||
const [savedFlows, setSavedFlows] = useState<{ [key: string]: FlowType }>({});
|
const [savedFlows, setSavedFlows] = useState<{ [key: string]: FlowType }>({});
|
||||||
|
const [hasStore, setHasStore] = useState(false);
|
||||||
|
|
||||||
|
checkHasStore().then((res) => {
|
||||||
|
setHasStore(res[0].has_store);
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StoreContext.Provider value={{ savedFlows, setSavedFlows }}>
|
<StoreContext.Provider
|
||||||
|
value={{ savedFlows, setSavedFlows, hasStore, setHasStore }}
|
||||||
|
>
|
||||||
{children}
|
{children}
|
||||||
</StoreContext.Provider>
|
</StoreContext.Provider>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -662,3 +662,17 @@ export async function searchComponent(
|
||||||
throw error;
|
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,
|
isLoading,
|
||||||
} = useContext(TabsContext);
|
} = useContext(TabsContext);
|
||||||
const { setErrorData } = useContext(alertContext);
|
const { setErrorData } = useContext(alertContext);
|
||||||
|
|
||||||
const dropdownOptions = [
|
const dropdownOptions = [
|
||||||
{
|
{
|
||||||
name: "Import from JSON",
|
name: "Import from JSON",
|
||||||
|
|
@ -69,6 +70,7 @@ export default function ComponentsComponent() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
onDragOver={dragOver}
|
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 { Separator } from "../../components/ui/separator";
|
||||||
import { USER_PROJECTS_HEADER } from "../../constants/constants";
|
import { USER_PROJECTS_HEADER } from "../../constants/constants";
|
||||||
import { alertContext } from "../../contexts/alertContext";
|
import { alertContext } from "../../contexts/alertContext";
|
||||||
|
import { StoreContext } from "../../contexts/storeContext";
|
||||||
import { TabsContext } from "../../contexts/tabsContext";
|
import { TabsContext } from "../../contexts/tabsContext";
|
||||||
export default function HomePage(): JSX.Element {
|
export default function HomePage(): JSX.Element {
|
||||||
const {
|
const {
|
||||||
|
|
@ -20,6 +21,7 @@ export default function HomePage(): JSX.Element {
|
||||||
isLoading,
|
isLoading,
|
||||||
} = useContext(TabsContext);
|
} = useContext(TabsContext);
|
||||||
const { setErrorData } = useContext(alertContext);
|
const { setErrorData } = useContext(alertContext);
|
||||||
|
const { hasStore } = useContext(StoreContext);
|
||||||
const dropdownOptions = [
|
const dropdownOptions = [
|
||||||
{
|
{
|
||||||
name: "Import from JSON",
|
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
|
// Set a null id
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setTabId("");
|
setTabId("");
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { cloneDeep } from "lodash";
|
import { cloneDeep } from "lodash";
|
||||||
import { Link, Search } from "lucide-react";
|
import { Link, Search } from "lucide-react";
|
||||||
import { useContext, useEffect, useState } from "react";
|
import { useContext, useEffect, useState } from "react";
|
||||||
|
import PaginatorComponent from "../../components/PaginatorComponent";
|
||||||
import IconComponent from "../../components/genericIconComponent";
|
import IconComponent from "../../components/genericIconComponent";
|
||||||
import Header from "../../components/headerComponent";
|
import Header from "../../components/headerComponent";
|
||||||
import { Badge } from "../../components/ui/badge";
|
import { Badge } from "../../components/ui/badge";
|
||||||
|
|
@ -40,6 +41,11 @@ export default function StorePage(): JSX.Element {
|
||||||
const [errorApiKey, setErrorApiKey] = useState(false);
|
const [errorApiKey, setErrorApiKey] = useState(false);
|
||||||
const { setErrorData } = useContext(alertContext);
|
const { setErrorData } = useContext(alertContext);
|
||||||
const { addFlow } = useContext(TabsContext);
|
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(() => {
|
useEffect(() => {
|
||||||
handleGetComponents();
|
handleGetComponents();
|
||||||
|
|
@ -66,11 +72,15 @@ export default function StorePage(): JSX.Element {
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSearch = (inputText: string) => {
|
const handleSearch = (inputText: string) => {
|
||||||
|
setLoading(true);
|
||||||
searchComponent(inputText).then(
|
searchComponent(inputText).then(
|
||||||
(res) => {
|
(res) => {
|
||||||
|
setLoading(false);
|
||||||
setSearchData(res);
|
setSearchData(res);
|
||||||
},
|
},
|
||||||
(error) => {}
|
(error) => {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -198,6 +208,15 @@ export default function StorePage(): JSX.Element {
|
||||||
<MarketCardComponent key={idx} data={item} />
|
<MarketCardComponent key={idx} data={item} />
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<PaginatorComponent
|
||||||
|
pageIndex={index}
|
||||||
|
pageSize={size}
|
||||||
|
totalRowsCount={totalRowsCount}
|
||||||
|
paginate={(pageSize, pageIndex) => {
|
||||||
|
handleChangePagination(pageIndex, pageSize);
|
||||||
|
}}
|
||||||
|
></PaginatorComponent>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import { ProtectedAdminRoute } from "./components/authAdminGuard";
|
||||||
import { ProtectedRoute } from "./components/authGuard";
|
import { ProtectedRoute } from "./components/authGuard";
|
||||||
import { ProtectedLoginRoute } from "./components/authLoginGuard";
|
import { ProtectedLoginRoute } from "./components/authLoginGuard";
|
||||||
import { CatchAllRoute } from "./components/catchAllRoutes";
|
import { CatchAllRoute } from "./components/catchAllRoutes";
|
||||||
|
import { StoreGuard } from "./components/storeGuard";
|
||||||
import AdminPage from "./pages/AdminPage";
|
import AdminPage from "./pages/AdminPage";
|
||||||
import LoginAdminPage from "./pages/AdminPage/LoginPage";
|
import LoginAdminPage from "./pages/AdminPage/LoginPage";
|
||||||
import ApiKeysPage from "./pages/ApiKeysPage";
|
import ApiKeysPage from "./pages/ApiKeysPage";
|
||||||
|
|
@ -11,6 +12,7 @@ import FlowPage from "./pages/FlowPage";
|
||||||
import HomePage from "./pages/MainPage";
|
import HomePage from "./pages/MainPage";
|
||||||
import ComponentsComponent from "./pages/MainPage/components/components";
|
import ComponentsComponent from "./pages/MainPage/components/components";
|
||||||
import FlowsComponent from "./pages/MainPage/components/flows";
|
import FlowsComponent from "./pages/MainPage/components/flows";
|
||||||
|
import SavedComponents from "./pages/MainPage/components/saved-components";
|
||||||
import ProfileSettingsPage from "./pages/ProfileSettingsPage";
|
import ProfileSettingsPage from "./pages/ProfileSettingsPage";
|
||||||
import StorePage from "./pages/StorePage";
|
import StorePage from "./pages/StorePage";
|
||||||
import ViewPage from "./pages/ViewPage";
|
import ViewPage from "./pages/ViewPage";
|
||||||
|
|
@ -38,6 +40,14 @@ const Router = () => {
|
||||||
>
|
>
|
||||||
<Route path="flows" element={<FlowsComponent />} />
|
<Route path="flows" element={<FlowsComponent />} />
|
||||||
<Route path="components" element={<ComponentsComponent />} />
|
<Route path="components" element={<ComponentsComponent />} />
|
||||||
|
<Route
|
||||||
|
path="saved-components"
|
||||||
|
element={
|
||||||
|
<StoreGuard>
|
||||||
|
<SavedComponents />
|
||||||
|
</StoreGuard>
|
||||||
|
}
|
||||||
|
/>
|
||||||
</Route>
|
</Route>
|
||||||
<Route
|
<Route
|
||||||
path="/community"
|
path="/community"
|
||||||
|
|
@ -51,10 +61,13 @@ const Router = () => {
|
||||||
path="/store"
|
path="/store"
|
||||||
element={
|
element={
|
||||||
<ProtectedRoute>
|
<ProtectedRoute>
|
||||||
|
<StoreGuard>
|
||||||
<StorePage />
|
<StorePage />
|
||||||
|
</StoreGuard>
|
||||||
</ProtectedRoute>
|
</ProtectedRoute>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Route path="/flow/:id/">
|
<Route path="/flow/:id/">
|
||||||
<Route
|
<Route
|
||||||
path=""
|
path=""
|
||||||
|
|
|
||||||
|
|
@ -3,4 +3,6 @@ import { FlowType } from "../flow";
|
||||||
export type storeContextType = {
|
export type storeContextType = {
|
||||||
savedFlows: { [key: string]: FlowType };
|
savedFlows: { [key: string]: FlowType };
|
||||||
setSavedFlows: (newState: { [key: string]: FlowType }) => void;
|
setSavedFlows: (newState: { [key: string]: FlowType }) => void;
|
||||||
|
setHasStore: (store: boolean) => void;
|
||||||
|
hasStore: boolean;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue