diff --git a/apps/platform/src/app/(main)/(project)/[workspace]/[project]/@variable/page.tsx b/apps/platform/src/app/(main)/(project)/[workspace]/[project]/@variable/page.tsx index e6280bc6b..13bf1d712 100644 --- a/apps/platform/src/app/(main)/(project)/[workspace]/[project]/@variable/page.tsx +++ b/apps/platform/src/app/(main)/(project)/[workspace]/[project]/@variable/page.tsx @@ -1,8 +1,9 @@ 'use client' -import { useEffect } from 'react' +import { useEffect, useState } from 'react' import { useAtom, useAtomValue, useSetAtom } from 'jotai' import { VariableSVG } from '@public/svg/dashboard' +import { toast } from 'sonner' import { createVariableOpenAtom, selectedProjectAtom, @@ -18,8 +19,14 @@ import ControllerInstance from '@/lib/controller-instance' import { Button } from '@/components/ui/button' import { Accordion } from '@/components/ui/accordion' import { useHttp } from '@/hooks/use-http' +import VariableLoader from '@/components/dashboard/variable/variableLoader' + +const ITEMS_PER_PAGE = 10 function VariablePage(): React.JSX.Element { + const [page, setPage] = useState(0) + const [hasMore, setHasMore] = useState(true) + const [isLoading, setIsLoading] = useState(false) const setIsCreateVariableOpen = useSetAtom(createVariableOpenAtom) const isDeleteVariableOpen = useAtomValue(deleteVariableOpenAtom) const isEditVariableOpen = useAtomValue(editVariableOpenAtom) @@ -28,21 +35,64 @@ function VariablePage(): React.JSX.Element { const selectedProject = useAtomValue(selectedProjectAtom) const getAllVariablesOfProject = useHttp(() => - ControllerInstance.getInstance().variableController.getAllVariablesOfProject( - { - projectSlug: selectedProject!.slug - } - ) + ControllerInstance.getInstance().variableController.getAllVariablesOfProject({ + projectSlug: selectedProject!.slug, + page, + limit: ITEMS_PER_PAGE, + }, {}) ) useEffect(() => { - selectedProject && - getAllVariablesOfProject().then(({ data, success }) => { + const fetchVariables = async () => { + if (!selectedProject) { + toast.error('No project selected', { + description:

+ Please select a project to view variables. +

+ }) + return + } + + try { + setIsLoading(true) + const { data, success } = await getAllVariablesOfProject() if (success && data) { - setVariables(data.items) + setVariables((prev) => page === 0 ? data.items : [...prev, ...data.items]) + if (data.items.length < ITEMS_PER_PAGE) { + setHasMore(false) + } } - }) - }, [getAllVariablesOfProject, selectedProject, setVariables]) + } catch (error) { + // eslint-disable-next-line no-console -- debug error handling + console.error('Error fetching variables:', error) + toast.error('Failed to fetch variables', { + description:

+ Something went wrong while fetching variables. Please try again. +

+ }) + } finally { + setIsLoading(false) + } + } + + fetchVariables() + }, [getAllVariablesOfProject, page, selectedProject, setVariables]) + + const handleLoadMore = () => { + if(!isLoading && hasMore) { + setPage((prevPage) => prevPage + 1) + } + } + + if (isLoading && page === 0) { + return ( +
+ + + +
+ ) + } return (
- + + {variables.map(({ variable, values }) => ( + + ))} + + {isLoading && page > 0 ?
: null} +
+ {/* Delete variable alert dialog */} {isDeleteVariableOpen && selectedVariable ? ( diff --git a/apps/platform/src/components/dashboard/variable/variableLoader/index.tsx b/apps/platform/src/components/dashboard/variable/variableLoader/index.tsx new file mode 100644 index 000000000..b7f402fd7 --- /dev/null +++ b/apps/platform/src/components/dashboard/variable/variableLoader/index.tsx @@ -0,0 +1,19 @@ +import { Skeleton } from '@/components/ui/skeleton' + +export default function VariableLoader(): React.JSX.Element { + return ( +
+
+
+ + +
+
+ + + +
+
+
+ ) +}