feat: project pagination

pull/68/head
Artem Golub 3 years ago committed by Samuel Rowe
parent 386b5e137b
commit 94bc646189

@ -1,11 +1,16 @@
import { useState } from "react";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import { PROJECTS_FETCH_LIMIT } from "../../constants";
import { IProject } from "../../types"; import { IProject } from "../../types";
import Spinner from "../../components/global/Spinner"; import Spinner from "../../components/global/Spinner";
import PreviewBlock from "./PreviewBlock"; import PreviewBlock from "./PreviewBlock";
import { useProjects } from "../../hooks/useProjects"; import { useProjects } from "../../hooks/useProjects";
const Projects = () => { const Projects = () => {
const { data, error, isFetching } = useProjects(); const [limit] = useState(PROJECTS_FETCH_LIMIT);
const [offset, setOffset] = useState(0);
const { isLoading, isError, error, data, isFetching, isPreviousData } =
useProjects(limit, offset);
return ( return (
<> <>
@ -33,37 +38,80 @@ const Projects = () => {
)} )}
{!isFetching && ( {!isFetching && (
<div className="py-4"> <>
{error && ( <div className="py-4">
<div className="text-center"> {error && (
<h3 className="mt-12 text-sm font-medium text-gray-900 dark:text-white"> <div className="text-center">
Something went wrong... <h3 className="mt-12 text-sm font-medium text-gray-900 dark:text-white">
</h3> Something went wrong...
</h3>
</div>
)}
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
{data.results.length > 0 &&
data.results.map((project: IProject) => {
return (
<div key={`${project.uuid}`}>
<PreviewBlock project={project} />
</div>
);
})}
</div> </div>
)}
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3"> {data.results.length === 0 && (
{data.results.length > 0 && <div className="text-center">
data.results.map((project: IProject) => { <h3 className="mt-12 text-sm font-medium text-gray-900 dark:text-white">
return ( Nothing here
<div key={`${project.uuid}`}> </h3>
<PreviewBlock project={project} /> <p className="mt-1 text-sm text-gray-500 dark:text-gray-400">
</div> Get started by creating a project.
); </p>
})} </div>
)}
</div> </div>
{data.results.length === 0 && ( {data.count > PROJECTS_FETCH_LIMIT && (
<div className="text-center"> <div className="flex justify-center space-x-1 my-4">
<h3 className="mt-12 text-sm font-medium text-gray-900 dark:text-white"> <button
Nothing here className={`
</h3> text-xs border-dotted border-b
<p className="mt-1 text-sm text-gray-500 dark:text-gray-400"> ${
Get started by creating a project. !data.previous
</p> ? "text-gray-500 border-gray-500"
: "text-blue-600 border-blue-600"
}
`}
onClick={() =>
setOffset((old) =>
Math.max(old - PROJECTS_FETCH_LIMIT, 0)
)
}
disabled={!data.previous}
>
Previous
</button>
<button
className={`
text-xs border-dotted border-b
${
!data.next
? "text-gray-500 border-gray-500"
: "text-blue-600 border-blue-600"
}
`}
onClick={() => {
if (!isPreviousData && data.next) {
setOffset((old) => old + PROJECTS_FETCH_LIMIT);
}
}}
disabled={isPreviousData || !data.next}
>
Next
</button>
</div> </div>
)} )}
</div> </>
)} )}
</div> </div>
</div> </div>

@ -164,19 +164,21 @@ export const useDeleteProject = (uuid: string | undefined) => {
}, },
{ {
onSuccess: () => { onSuccess: () => {
// could just invalidate the query here and refetch everything
// queryClient.invalidateQueries(['projects']);
queryClient.cancelQueries("projects"); queryClient.cancelQueries("projects");
const previousProjects = queryClient.getQueryData( const previousProjects = queryClient.getQueryData(
"projects" "projects"
) as IProjectsReturn; ) as IProjectsReturn;
const filtered = _.filter(previousProjects.results, (project) => {
return project.uuid !== uuid; if (previousProjects) {
}); const filtered = _.filter(previousProjects.results, (project) => {
previousProjects.count = filtered.length; return project.uuid !== uuid;
previousProjects.results = filtered; });
queryClient.setQueryData("projects", previousProjects); previousProjects.count = filtered.length;
previousProjects.results = filtered;
queryClient.setQueryData("projects", previousProjects);
} else {
queryClient.invalidateQueries(["projects"]);
}
} }
} }
); );

@ -3,12 +3,12 @@ import { useQuery } from "react-query";
import { API_SERVER_URL } from "../constants"; import { API_SERVER_URL } from "../constants";
import { getLocalStorageJWTKeys } from "../utils"; import { getLocalStorageJWTKeys } from "../utils";
const fetchProjects = async () => { export const fetchProjects = async (limit: number, offset: number) => {
const jwtKeys = getLocalStorageJWTKeys(); const jwtKeys = getLocalStorageJWTKeys();
const response = await axios({ const response = await axios({
method: "get", method: "get",
url: `${API_SERVER_URL}/projects/`, url: `${API_SERVER_URL}/projects/?limit=${limit}&offset=${offset}`,
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
Authorization: `Bearer ${jwtKeys.access_token}` Authorization: `Bearer ${jwtKeys.access_token}`
@ -17,13 +17,12 @@ const fetchProjects = async () => {
return response.data; return response.data;
}; };
export const useProjects = () => { export const useProjects = (limit: number, offset: number) => {
return useQuery( return useQuery(
["projects"], ["projects", limit, offset],
async () => { () => fetchProjects(limit, offset),
return await fetchProjects();
},
{ {
keepPreviousData: true,
staleTime: Infinity staleTime: Infinity
} }
); );

Loading…
Cancel
Save