Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(platform): added pagination & loading state for variables page #787

Open
wants to merge 10 commits into
base: develop
Choose a base branch
from
Open
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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)
Expand All @@ -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: <p className="text-xs text-red-300">
Please select a project to view variables.
</p>
})
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: <p className="text-xs text-red-300">
Something went wrong while fetching variables. Please try again.
</p>
})
} finally {
setIsLoading(false)
}
}

fetchVariables()
}, [getAllVariablesOfProject, page, selectedProject, setVariables])

const handleLoadMore = () => {
if(!isLoading && hasMore) {
setPage((prevPage) => prevPage + 1)
}
}

if (isLoading && page === 0) {
return (
<div className="space-y-4">
<VariableLoader />
<VariableLoader />
<VariableLoader />
</div>
)
}

return (
<div
Expand Down Expand Up @@ -74,19 +124,29 @@ function VariablePage(): React.JSX.Element {
<div
className={`flex h-full w-full flex-col items-center justify-start gap-y-8 p-3 text-white ${isDeleteVariableOpen ? 'inert' : ''} `}
>
<Accordion
className="flex h-fit w-full flex-col gap-4"
collapsible
type="single"
<div className="flex h-fit w-full flex-col gap-4">
<Accordion
className="flex h-fit w-full flex-col gap-4"
collapsible
type="single"
>
{variables.map(({ variable, values }) => (
<VariableCard
key={variable.id}
values={values}
variable={variable}
/>
))}
</Accordion>
{isLoading && page > 0 ? <div className="w-full"><VariableLoader /></div> : null}
</div>
<Button
className="h-[2.25rem] rounded-md bg-white text-black hover:bg-gray-300"
disabled={isLoading || !hasMore}
onClick={handleLoadMore}
>
{variables.map(({ variable, values }) => (
<VariableCard
key={variable.id}
values={values}
variable={variable}
/>
))}
</Accordion>
Load more
</Button>
{/* Delete variable alert dialog */}
{isDeleteVariableOpen && selectedVariable ? (
<ConfirmDeleteVariable />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Skeleton } from '@/components/ui/skeleton'

export default function VariableLoader(): React.JSX.Element {
return (
<div className="rounded-xl bg-white/5 p-4">
<div className="flex justify-between">
<div className="flex items-center gap-x-6">
<Skeleton className="h-6 w-32 rounded" />
<Skeleton className="size-6 rounded" />
</div>
<div className="flex items-center gap-x-3">
<Skeleton className="h-6 w-24 rounded" />
<Skeleton className="h-6 w-16 rounded" />
<Skeleton className="ml-5 size-4 rounded" />
</div>
</div>
</div>
)
}
Loading