feat(storeContext.tsx): add hasApiKey state and setHasApiKey function to storeContext to track if API key is present
fix(StorePage/index.tsx): fix useEffect dependencies and add missing handleChangeTab function fix(API/index.ts): rename getNumberOfComponents function to getCountComponents to improve semantics
This commit is contained in:
parent
0c90c12c94
commit
b3bb568526
4 changed files with 107 additions and 149 deletions
|
|
@ -8,6 +8,8 @@ const initialValue = {
|
||||||
setSavedFlows: () => {},
|
setSavedFlows: () => {},
|
||||||
hasStore: true,
|
hasStore: true,
|
||||||
setHasStore: () => {},
|
setHasStore: () => {},
|
||||||
|
hasApiKey: true,
|
||||||
|
setHasApiKey: () => {},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const StoreContext = createContext<storeContextType>(initialValue);
|
export const StoreContext = createContext<storeContextType>(initialValue);
|
||||||
|
|
@ -16,14 +18,23 @@ export function StoreProvider({ children }) {
|
||||||
const [savedFlows, setSavedFlows] = useState<Set<string>>(new Set());
|
const [savedFlows, setSavedFlows] = useState<Set<string>>(new Set());
|
||||||
|
|
||||||
const [hasStore, setHasStore] = useState(true);
|
const [hasStore, setHasStore] = useState(true);
|
||||||
|
const [hasApiKey, setHasApiKey] = useState(true);
|
||||||
|
|
||||||
checkHasStore().then((res) => {
|
checkHasStore().then((res) => {
|
||||||
setHasStore(res["enabled"]);
|
setHasStore(res["enabled"]);
|
||||||
|
setHasApiKey(res["has_api_key"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StoreContext.Provider
|
<StoreContext.Provider
|
||||||
value={{ savedFlows, setSavedFlows, hasStore, setHasStore }}
|
value={{
|
||||||
|
savedFlows,
|
||||||
|
setSavedFlows,
|
||||||
|
hasStore,
|
||||||
|
setHasStore,
|
||||||
|
hasApiKey,
|
||||||
|
setHasApiKey,
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</StoreContext.Provider>
|
</StoreContext.Provider>
|
||||||
|
|
|
||||||
|
|
@ -713,9 +713,20 @@ export async function checkHasStore() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getNumberOfComponents() {
|
export async function getCountComponents(is_component?: boolean | null) {
|
||||||
try {
|
try {
|
||||||
const res = await api.get(`${BASE_URL_API}store/components/count`);
|
let url = `${BASE_URL_API}store/components/count`;
|
||||||
|
const queryParams: any = [];
|
||||||
|
if (is_component !== undefined) {
|
||||||
|
queryParams.push(`is_component=${is_component}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (queryParams.length > 0) {
|
||||||
|
url += `?${queryParams.join("&")}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await api.get(url);
|
||||||
|
|
||||||
if (res.status === 200) {
|
if (res.status === 200) {
|
||||||
return res.data;
|
return res.data;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ import { alertContext } from "../../contexts/alertContext";
|
||||||
import { StoreContext } from "../../contexts/storeContext";
|
import { StoreContext } from "../../contexts/storeContext";
|
||||||
import { TabsContext } from "../../contexts/tabsContext";
|
import { TabsContext } from "../../contexts/tabsContext";
|
||||||
import {
|
import {
|
||||||
getNumberOfComponents,
|
getCountComponents,
|
||||||
getStoreComponents,
|
getStoreComponents,
|
||||||
getStoreSavedComponents,
|
getStoreSavedComponents,
|
||||||
getStoreTags,
|
getStoreTags,
|
||||||
|
|
@ -32,25 +32,24 @@ import { cn } from "../../utils/utils";
|
||||||
import { MarketCardComponent } from "./components/market-card";
|
import { MarketCardComponent } from "./components/market-card";
|
||||||
export default function StorePage(): JSX.Element {
|
export default function StorePage(): JSX.Element {
|
||||||
const { setTabId } = useContext(TabsContext);
|
const { setTabId } = useContext(TabsContext);
|
||||||
// set null id
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setTabId("");
|
setTabId("");
|
||||||
}, []);
|
}, []);
|
||||||
const [data, setData] = useState<storeComponent[]>([]);
|
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [filteredCategories, setFilterCategories] = useState<any[]>([]);
|
const [filteredCategories, setFilterCategories] = useState<any[]>([]);
|
||||||
const [inputText, setInputText] = useState<string>("");
|
const [inputText, setInputText] = useState<string>("");
|
||||||
const [searchData, setSearchData] = useState(data);
|
const [searchData, setSearchData] = useState<storeComponent[]>([]);
|
||||||
const { setErrorData } = useContext(alertContext);
|
const { setErrorData } = useContext(alertContext);
|
||||||
const [totalRowsCount, setTotalRowsCount] = useState(0);
|
const [totalRowsCount, setTotalRowsCount] = useState(0);
|
||||||
const [size, setPageSize] = useState(10);
|
const [size, setPageSize] = useState(10);
|
||||||
const [index, setPageIndex] = useState(1);
|
const [index, setPageIndex] = useState(1);
|
||||||
const [errorApiKey, setErrorApiKey] = useState(false);
|
const [errorApiKey, setErrorApiKey] = useState(false);
|
||||||
const { setSavedFlows, savedFlows } = useContext(StoreContext);
|
const { setSavedFlows, savedFlows, hasApiKey } = useContext(StoreContext);
|
||||||
const [tags, setTags] = useState<{ id: string; name: string }[]>([]);
|
const [tags, setTags] = useState<{ id: string; name: string }[]>([]);
|
||||||
const tagListId = useRef<{ id: string; name: string }[]>([]);
|
const tagListId = useRef<{ id: string; name: string }[]>([]);
|
||||||
const [renderPagination, setRenderPagination] = useState(false);
|
const [renderPagination, setRenderPagination] = useState(false);
|
||||||
const filterComponent = useRef<boolean | null>(null);
|
const filterComponent = useRef<boolean | null>(null);
|
||||||
|
const [tabActive, setTabActive] = useState("Flows");
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getStoreTags().then((res) => {
|
getStoreTags().then((res) => {
|
||||||
|
|
@ -59,6 +58,16 @@ export default function StorePage(): JSX.Element {
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
filterComponent.current = false;
|
||||||
|
getSavedComponents()
|
||||||
|
.finally(() => handleGetComponents())
|
||||||
|
.catch((err) => {
|
||||||
|
setErrorApiKey(true);
|
||||||
|
console.error(err);
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
async function getSavedComponents() {
|
async function getSavedComponents() {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
const result = await getStoreSavedComponents();
|
const result = await getStoreSavedComponents();
|
||||||
|
|
@ -70,17 +79,12 @@ export default function StorePage(): JSX.Element {
|
||||||
setErrorApiKey(false);
|
setErrorApiKey(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
async function getNumberSavedComponents() {
|
||||||
getNumberOfComponents().then((res) => {
|
getCountComponents(filterComponent.current).then((res) => {
|
||||||
setTotalRowsCount(Number(res["count"]));
|
setTotalRowsCount(Number(res["count"]));
|
||||||
|
setLoading(false);
|
||||||
});
|
});
|
||||||
getSavedComponents()
|
}
|
||||||
.finally(() => handleGetComponents())
|
|
||||||
.catch((err) => {
|
|
||||||
setErrorApiKey(true);
|
|
||||||
console.error(err);
|
|
||||||
});
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const handleGetComponents = () => {
|
const handleGetComponents = () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
|
@ -89,8 +93,7 @@ export default function StorePage(): JSX.Element {
|
||||||
getStoreComponents(index - 1, size, filterComponent.current)
|
getStoreComponents(index - 1, size, filterComponent.current)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
setSearchData(res);
|
setSearchData(res);
|
||||||
setData(res);
|
getNumberSavedComponents();
|
||||||
setLoading(false);
|
|
||||||
setErrorApiKey(true);
|
setErrorApiKey(true);
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
|
|
@ -112,9 +115,9 @@ export default function StorePage(): JSX.Element {
|
||||||
searchComponent(inputText).then(
|
searchComponent(inputText).then(
|
||||||
(res) => {
|
(res) => {
|
||||||
setSearchData(res);
|
setSearchData(res);
|
||||||
setData(res);
|
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
setRenderPagination(false);
|
setRenderPagination(false);
|
||||||
|
setTotalRowsCount(res.length);
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
|
|
@ -127,7 +130,6 @@ export default function StorePage(): JSX.Element {
|
||||||
setRenderPagination(true);
|
setRenderPagination(true);
|
||||||
getStoreComponents(pageIndex, pageSize, filterComponent.current)
|
getStoreComponents(pageIndex, pageSize, filterComponent.current)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
setData(res);
|
|
||||||
setSearchData(res);
|
setSearchData(res);
|
||||||
setPageIndex(pageIndex);
|
setPageIndex(pageIndex);
|
||||||
setPageSize(pageSize);
|
setPageSize(pageSize);
|
||||||
|
|
@ -152,8 +154,8 @@ export default function StorePage(): JSX.Element {
|
||||||
searchComponent(null, 1, 10000, null, filterArray).then(
|
searchComponent(null, 1, 10000, null, filterArray).then(
|
||||||
(res) => {
|
(res) => {
|
||||||
setSearchData(res);
|
setSearchData(res);
|
||||||
setData(res);
|
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
|
setTotalRowsCount(res.length);
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
|
|
@ -162,7 +164,32 @@ export default function StorePage(): JSX.Element {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const [tabActive, setTabActive] = useState("Flows");
|
function handleChangeTab(tab: string) {
|
||||||
|
if (tab === "All") {
|
||||||
|
filterComponent.current = null;
|
||||||
|
} else if (tab === "Flows") {
|
||||||
|
filterComponent.current = false;
|
||||||
|
} else if (tab === "Components") {
|
||||||
|
filterComponent.current = true;
|
||||||
|
}
|
||||||
|
setPageIndex(1);
|
||||||
|
setPageSize(10);
|
||||||
|
handleGetComponents();
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleOrderPage = (e) => {
|
||||||
|
let sortedData = cloneDeep(searchData);
|
||||||
|
|
||||||
|
if (e === "Popular") {
|
||||||
|
sortedData = sortedData.sort(
|
||||||
|
(a, b) => Number(b.liked_by_count) - Number(a.liked_by_count)
|
||||||
|
);
|
||||||
|
} else if (e === "Alphabetical") {
|
||||||
|
sortedData = sortedData.sort((a, b) => a.name.localeCompare(b.name));
|
||||||
|
}
|
||||||
|
|
||||||
|
setSearchData([...sortedData]);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
@ -181,7 +208,9 @@ export default function StorePage(): JSX.Element {
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
className={`${errorApiKey ? "animate-pulse border-error" : ""}`}
|
className={`${
|
||||||
|
errorApiKey && !hasApiKey ? "animate-pulse border-error" : ""
|
||||||
|
}`}
|
||||||
variant="primary"
|
variant="primary"
|
||||||
>
|
>
|
||||||
<IconComponent name="Key" className="main-page-nav-button" />
|
<IconComponent name="Key" className="main-page-nav-button" />
|
||||||
|
|
@ -209,12 +238,18 @@ export default function StorePage(): JSX.Element {
|
||||||
}}
|
}}
|
||||||
value={inputText}
|
value={inputText}
|
||||||
/>
|
/>
|
||||||
<Search className="absolute bottom-0 right-4 top-0 my-auto h-6 stroke-1 text-muted-foreground " />
|
<Search
|
||||||
|
onClick={() => {
|
||||||
|
handleSearch(inputText);
|
||||||
|
}}
|
||||||
|
className="absolute bottom-0 right-4 top-0 my-auto h-6 cursor-pointer stroke-1 text-muted-foreground"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="ml-4 flex w-full gap-2 border-b border-border">
|
<div className="ml-4 flex w-full gap-2 border-b border-border">
|
||||||
<button
|
<button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setTabActive("All");
|
setTabActive("All");
|
||||||
|
handleChangeTab("All");
|
||||||
}}
|
}}
|
||||||
className={
|
className={
|
||||||
tabActive === "All"
|
tabActive === "All"
|
||||||
|
|
@ -227,6 +262,7 @@ export default function StorePage(): JSX.Element {
|
||||||
<button
|
<button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setTabActive("Flows");
|
setTabActive("Flows");
|
||||||
|
handleChangeTab("Flows");
|
||||||
}}
|
}}
|
||||||
className={
|
className={
|
||||||
tabActive === "Flows"
|
tabActive === "Flows"
|
||||||
|
|
@ -239,6 +275,7 @@ export default function StorePage(): JSX.Element {
|
||||||
<button
|
<button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setTabActive("Components");
|
setTabActive("Components");
|
||||||
|
handleChangeTab("Components");
|
||||||
}}
|
}}
|
||||||
className={
|
className={
|
||||||
tabActive === "Components"
|
tabActive === "Components"
|
||||||
|
|
@ -255,104 +292,7 @@ export default function StorePage(): JSX.Element {
|
||||||
</ShadTooltip>
|
</ShadTooltip>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/* <div className="flex items-center gap-3 text-sm">
|
|
||||||
<button className="flex h-8 items-center justify-between rounded-md border border-ring/60 px-4 py-2 text-sm text-primary hover:bg-muted">
|
|
||||||
<IconComponent name="CheckCircle2" className="mr-2 h-4 w-4 " />
|
|
||||||
Installed Locally
|
|
||||||
</button>
|
|
||||||
<Select
|
|
||||||
onValueChange={(value) => {
|
|
||||||
if (value === "Flow") {
|
|
||||||
filterComponent.current = false;
|
|
||||||
} else if (value === "Component") {
|
|
||||||
filterComponent.current = true;
|
|
||||||
} else {
|
|
||||||
filterComponent.current = null;
|
|
||||||
}
|
|
||||||
setPageIndex(1);
|
|
||||||
setPageSize(10);
|
|
||||||
handleGetComponents();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<SelectTrigger>
|
|
||||||
<SelectValue placeholder="Component Types" />
|
|
||||||
</SelectTrigger>
|
|
||||||
<SelectContent>
|
|
||||||
<SelectItem value="">Both</SelectItem>
|
|
||||||
<SelectItem value="Flow">Flows</SelectItem>
|
|
||||||
<SelectItem value="Component">Components</SelectItem>
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
<Select
|
|
||||||
onValueChange={(value) => {
|
|
||||||
if (value === "Flow") {
|
|
||||||
filterComponent.current = false;
|
|
||||||
} else if (value === "Component") {
|
|
||||||
filterComponent.current = true;
|
|
||||||
} else {
|
|
||||||
filterComponent.current = null;
|
|
||||||
}
|
|
||||||
setPageIndex(1);
|
|
||||||
setPageSize(10);
|
|
||||||
handleGetComponents();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<SelectTrigger>
|
|
||||||
<SelectValue placeholder="Use Cases" />
|
|
||||||
</SelectTrigger>
|
|
||||||
<SelectContent>
|
|
||||||
<SelectItem value="">Both</SelectItem>
|
|
||||||
<SelectItem value="Flow">Flows</SelectItem>
|
|
||||||
<SelectItem value="Component">Components</SelectItem>
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
<Select
|
|
||||||
onValueChange={(value) => {
|
|
||||||
if (value === "Flow") {
|
|
||||||
filterComponent.current = false;
|
|
||||||
} else if (value === "Component") {
|
|
||||||
filterComponent.current = true;
|
|
||||||
} else {
|
|
||||||
filterComponent.current = null;
|
|
||||||
}
|
|
||||||
setPageIndex(1);
|
|
||||||
setPageSize(10);
|
|
||||||
handleGetComponents();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<SelectTrigger>
|
|
||||||
<SelectValue placeholder="Models" />
|
|
||||||
</SelectTrigger>
|
|
||||||
<SelectContent>
|
|
||||||
<SelectItem value="">Both</SelectItem>
|
|
||||||
<SelectItem value="Flow">Flows</SelectItem>
|
|
||||||
<SelectItem value="Component">Components</SelectItem>
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
<Select
|
|
||||||
onValueChange={(value) => {
|
|
||||||
if (value === "Flow") {
|
|
||||||
filterComponent.current = false;
|
|
||||||
} else if (value === "Component") {
|
|
||||||
filterComponent.current = true;
|
|
||||||
} else {
|
|
||||||
filterComponent.current = null;
|
|
||||||
}
|
|
||||||
setPageIndex(1);
|
|
||||||
setPageSize(10);
|
|
||||||
handleGetComponents();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<SelectTrigger>
|
|
||||||
<SelectValue placeholder="Payment" />
|
|
||||||
</SelectTrigger>
|
|
||||||
<SelectContent>
|
|
||||||
<SelectItem value="">Both</SelectItem>
|
|
||||||
<SelectItem value="Flow">Flows</SelectItem>
|
|
||||||
<SelectItem value="Component">Components</SelectItem>
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
</div> */}
|
|
||||||
<div className="flex items-center gap-2 px-2">
|
<div className="flex items-center gap-2 px-2">
|
||||||
{!loading &&
|
{!loading &&
|
||||||
tags.map((i, idx) => (
|
tags.map((i, idx) => (
|
||||||
|
|
@ -383,29 +323,25 @@ export default function StorePage(): JSX.Element {
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-end justify-between">
|
<div className="flex items-end justify-between">
|
||||||
<span className="px-0.5 text-sm text-muted-foreground">
|
<span className="px-0.5 text-sm text-muted-foreground">
|
||||||
2,117 results
|
{!loading && (
|
||||||
|
<>
|
||||||
|
{totalRowsCount} {totalRowsCount > 0 ? "results" : "result"}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<Select
|
<Select
|
||||||
onValueChange={(value) => {
|
onValueChange={(e) => {
|
||||||
if (value === "Flow") {
|
handleOrderPage(e);
|
||||||
filterComponent.current = false;
|
|
||||||
} else if (value === "Component") {
|
|
||||||
filterComponent.current = true;
|
|
||||||
} else {
|
|
||||||
filterComponent.current = null;
|
|
||||||
}
|
|
||||||
setPageIndex(1);
|
|
||||||
setPageSize(10);
|
|
||||||
handleGetComponents();
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<SelectTrigger>
|
<SelectTrigger>
|
||||||
<SelectValue placeholder="Sort By" />
|
<SelectValue placeholder="Sort By" />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
<SelectItem value="">Most Popular</SelectItem>
|
<SelectItem value="Popular">Most Popular</SelectItem>
|
||||||
<SelectItem value="Flow">Most Recent</SelectItem>
|
{/* <SelectItem value="Recent">Most Recent</SelectItem> */}
|
||||||
<SelectItem value="Component">Alphabetical</SelectItem>
|
<SelectItem value="Alphabetical">Alphabetical</SelectItem>
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -418,17 +354,15 @@ export default function StorePage(): JSX.Element {
|
||||||
<SkeletonCardComponent />
|
<SkeletonCardComponent />
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
searchData
|
searchData.map((item, idx) => {
|
||||||
.filter(
|
console.log(item);
|
||||||
(f) =>
|
|
||||||
filteredCategories?.length === 0 ||
|
return (
|
||||||
filteredCategories.some(
|
<>
|
||||||
(category) => category === f.is_component
|
<MarketCardComponent key={idx} data={item} />
|
||||||
)
|
</>
|
||||||
)
|
);
|
||||||
.map((item, idx) => (
|
})
|
||||||
<MarketCardComponent key={idx} data={item} />
|
|
||||||
))
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -3,4 +3,6 @@ export type storeContextType = {
|
||||||
setSavedFlows: (newState: Set<string>) => void;
|
setSavedFlows: (newState: Set<string>) => void;
|
||||||
setHasStore: (store: boolean) => void;
|
setHasStore: (store: boolean) => void;
|
||||||
hasStore: boolean;
|
hasStore: boolean;
|
||||||
|
setHasApiKey: (key: boolean) => void;
|
||||||
|
hasApiKey: boolean;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue