Skip to content

Commit

Permalink
Merge pull request #128 from Huilensolis/95-feature-add-infinite-scro…
Browse files Browse the repository at this point in the history
…ll-to-posts-grid

95 feature add infinite scroll to posts grid
  • Loading branch information
huilensolis authored Mar 15, 2024
2 parents ecf5fb2 + af96e3a commit 3edd25f
Show file tree
Hide file tree
Showing 13 changed files with 211 additions and 404 deletions.
86 changes: 15 additions & 71 deletions src/app/(site)/app/components/feed/index.tsx
Original file line number Diff line number Diff line change
@@ -1,85 +1,29 @@
"use client";

import { Heading } from "@/components/ui/typography/heading";
import { useEffect, useState } from "react";
import { useSupabase } from "@/hooks/use-supabase";
import { Database } from "@/supabase/types";
import { PostsGrid } from "@/components/feature/posts-grid/posts-grid.component";
import { PostsGridSkeleton } from "@/components/feature/posts-grid/components/posts-grid-skeleton";

export function Feed() {
const { supabase } = useSupabase();

const [posts, setPosts] = useState<
Database["public"]["Tables"]["posts"]["Row"][]
>([]);

const [error, setError] = useState<boolean>(false);

const [isLoading, setIsLoading] = useState<boolean>(true);
const [isFetching, setIsFetching] = useState<boolean>(false);

const [lastPostIndex, setLastPostIndex] = useState<number>(1);

useEffect(() => {
const controller = new AbortController();

try {
setIsLoading(true);
setIsFetching(true);

supabase
.from("posts")
.select("*")
.order("id", { ascending: false })
.limit(32)
.range(lastPostIndex, lastPostIndex + 32)
.abortSignal(controller.signal)
.then(({ data: posts, error }) => {
if (error) return;

if (!posts) return;

setPosts((prev) => [...prev, ...posts]);
});
} catch (error: unknown) {
if ((error as Error).name === "AbortError") return;

setError(true);
} finally {
setIsLoading(false);
setIsFetching(false);
}

return () => {
controller.abort();
};

// eslint-disable-next-line react-hooks/exhaustive-deps
}, [lastPostIndex]);

function handleScroll() {
setLastPostIndex((prev) => prev + 32);
async function fetchNewPosts({
currentPage,
signal,
pageSize,
}: {
currentPage: number;
signal: AbortSignal;
pageSize: number;
}) {
return await supabase
.from("posts")
.select("*")
.range(currentPage, currentPage + pageSize)
.abortSignal(signal);
}

return (
<main className="w-full h-full flex flex-col gap-2">
{isLoading && <PostsGridSkeleton cuantity={32} />}
{!isLoading && !isFetching && (
<>
{!error ? (
<div>
<PostsGrid posts={posts} onFetchNewPosts={handleScroll} />
</div>
) : (
<article className="flex items-center justify-center w-full max-h-96 py-32 text-center border-y border-neutral-300">
<Heading level={10}>
Something wen wrong, please reload the page
</Heading>
</article>
)}
</>
)}
<PostsGrid onFetchNewPosts={fetchNewPosts} />
</main>
);
}
18 changes: 1 addition & 17 deletions src/app/(site)/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import { Feed } from "./components/feed";
import { protectRouteFromUnauthUsers } from "@/utils/auth/server-side-validations";
import { Suspense } from "react";
import { Skeleton } from "@/components/ui/skeleton";

export const dynamic = "force-dynamic";

Expand Down Expand Up @@ -30,21 +28,7 @@ function DesktopLayout() {
function MobileLayout() {
return (
<main className="w-full h-full py-2">
<Suspense
fallback={
<ul className="w-full grid grid-cols-2 gap-2">
{Array(6)
.fill("")
.map((_, i) => (
<li key={i}>
<Skeleton className="h-[500px] w-full rounded-md" />
</li>
))}
</ul>
}
>
<Feed />
</Suspense>
<Feed />
</main>
);
}
2 changes: 1 addition & 1 deletion src/app/(site)/app/post/[postid]/components/post/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export async function Post({
<LazyImage
src={asset_url}
alt={title}
className="w-full h-full max-h-[80vh] object-cover object-center rounded-md"
className="w-full h-full max-h-[1300px] object-cover object-center rounded-md"
skeletonClassName="w-full h-96 rounded-md"
containerClassname="w-full"
skeletonBgColor={post.asset_color || undefined}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,93 +1,33 @@
"use client";

import { PostsGridSkeleton } from "@/components/feature/posts-grid/components/posts-grid-skeleton";
import { PostsGrid } from "@/components/feature/posts-grid/posts-grid.component";
import { Heading } from "@/components/ui/typography/heading";
import { useSupabase } from "@/hooks/use-supabase";
import { Database } from "@/supabase/types";
import { useEffect, useState } from "react";

export function RecentPosts({
excludedPostId,
}: {
excludedPostId: Database["public"]["Tables"]["posts"]["Row"]["id"];
}) {
const [posts, setPosts] = useState<
Database["public"]["Tables"]["posts"]["Row"][]
>([]);

const [isLoading, setIsLoading] = useState<boolean>(true);
const [isFetching, setIsFetching] = useState<boolean>(false);

const [lastPostIndex, setLastPostIndex] = useState<number>(1);
const [error, setError] = useState<boolean>(false);

const { supabase } = useSupabase();

useEffect(() => {
const controller = new AbortController();

try {
setIsLoading(true);
setIsFetching(true);

supabase
.from("posts")
.select("*")
.order("created_at", { ascending: false })
.limit(32)
.range(lastPostIndex, lastPostIndex + 32)
.abortSignal(controller.signal)
.then(({ data: posts, error }) => {
if (error) return;

if (!posts) return;

setPosts((prev) => [
...prev,
...posts.filter((post) => post.id !== excludedPostId),
]);
});
} catch (error: unknown) {
if ((error as Error).name === "AbortError") return;

setError(true);
} finally {
setIsLoading(false);
setIsFetching(false);
}

return () => {
controller.abort();
};

// eslint-disable-next-line react-hooks/exhaustive-deps
}, [lastPostIndex]);

function handleScroll() {
if (isLoading || isFetching) return;

setLastPostIndex((prev) => prev + 32);
async function fetchNewPosts({
currentPage,
signal,
pageSize,
}: {
currentPage: number;
signal: AbortSignal;
pageSize: number;
}) {
return supabase
.from("posts")
.select("*")
.neq("id", excludedPostId) // exclude the posts that has the id equal to excludedPostId
.order("title", { ascending: false })
.range(currentPage, currentPage + pageSize)
.abortSignal(signal);
}

return (
<section>
{isLoading && <PostsGridSkeleton cuantity={32} />}
{!isLoading && !isFetching && (
<>
{!error ? (
<div>
<PostsGrid posts={posts} onFetchNewPosts={handleScroll} />
</div>
) : (
<article className="flex items-center justify-center w-full max-h-96 py-32 text-center border-y border-neutral-300">
<Heading level={10}>
Something wen wrong, please reload the page
</Heading>
</article>
)}
</>
)}
</section>
);
return <PostsGrid onFetchNewPosts={fetchNewPosts} />;
}
Original file line number Diff line number Diff line change
@@ -1,92 +1,32 @@
"use client";

import { PostsGridSkeleton } from "@/components/feature/posts-grid/components/posts-grid-skeleton";
import { PostsGrid } from "@/components/feature/posts-grid/posts-grid.component";
import { Heading } from "@/components/ui/typography/heading";
import { useSupabase } from "@/hooks/use-supabase";
import { Database } from "@/supabase/types";
import { useEffect, useState } from "react";

export function UserPosts({ profileId }: { profileId: string }) {
const { supabase } = useSupabase();

const [posts, setPosts] = useState<
Database["public"]["Tables"]["posts"]["Row"][]
>([]);

const [error, setError] = useState<boolean>(false);

const [isLoading, setIsLoading] = useState<boolean>(true);
const [isFetching, setIsFetching] = useState<boolean>(false);

const [lastPostIndex, setLastPostIndex] = useState<number>(1);

const [userHasNoMorePosts, setUserHasNoMorePosts] = useState<boolean>(false);

useEffect(() => {
if (userHasNoMorePosts) return;

const controller = new AbortController();

try {
setIsLoading(true);
setIsFetching(true);

supabase
.from("posts")
.select("*")
.eq("profile_id", profileId)
.order("id", { ascending: false })
.limit(32)
.range(lastPostIndex, lastPostIndex + 32)
.abortSignal(controller.signal)
.then(({ data: posts, error }) => {
if (error) return;

if (!posts) return;

if (posts.length === 0) setUserHasNoMorePosts(true);

setPosts((prev) => [...prev, ...posts]);
});
} catch (error: unknown) {
if ((error as Error).name === "AbortError") return;

setError(true);
} finally {
setIsLoading(false);
setIsFetching(false);
}

return () => {
controller.abort();
};

// eslint-disable-next-line react-hooks/exhaustive-deps
}, [lastPostIndex]);

function handleScroll() {
setLastPostIndex((prev) => prev + 32);
async function fetchNewPosts({
currentPage,
signal,
pageSize,
}: {
currentPage: number;
signal: AbortSignal;
pageSize: number;
}) {
return await supabase
.from("posts")
.select("*")
.eq("profile_id", profileId)
.order("created_at", { ascending: false })
.range(currentPage, currentPage + pageSize)
.abortSignal(signal);
}

return (
<main className="w-full h-full flex flex-col gap-2">
{isLoading && <PostsGridSkeleton cuantity={32} />}
{!isLoading && !isFetching && (
<>
{!error ? (
<div>
<PostsGrid posts={posts} onFetchNewPosts={handleScroll} />
</div>
) : (
<article className="flex items-center justify-center w-full max-h-96 py-32 text-center border-y border-neutral-300">
<Heading level={10}>
Something wen wrong, please reload the page
</Heading>
</article>
)}
</>
)}
<PostsGrid onFetchNewPosts={fetchNewPosts} />
</main>
);
}
Loading

0 comments on commit 3edd25f

Please sign in to comment.