From eab93c1372ba8fdb5a333f7bbf509cefdc8142a2 Mon Sep 17 00:00:00 2001 From: Huilensolis Date: Wed, 13 Mar 2024 01:45:39 -0300 Subject: [PATCH 1/8] feat(app): 95 add infinte scroll to main feed --- src/app/(site)/app/components/feed/index.tsx | 116 +++++++++++++----- src/app/(site)/app/page.tsx | 18 +-- src/app/(site)/app/search/page.tsx | 4 +- .../posts-grid/components/post/index.tsx | 1 - src/components/feature/posts-grid/index.tsx | 3 - .../posts-grid/posts-grid.component.tsx | 46 ------- .../images-grid-row.component.tsx} | 4 +- .../components/image-grid-row/index.tsx | 1 + .../ui/images-grid/images-grid.component.tsx | 86 +++++++++++++ .../images-grid/images-grid.models.ts} | 0 src/components/ui/images-grid/index.ts | 1 + 11 files changed, 177 insertions(+), 103 deletions(-) delete mode 100644 src/components/feature/posts-grid/components/post/index.tsx delete mode 100644 src/components/feature/posts-grid/index.tsx delete mode 100644 src/components/feature/posts-grid/posts-grid.component.tsx rename src/components/{feature/posts-grid/components/post/post.component.tsx => ui/images-grid/components/image-grid-row/images-grid-row.component.tsx} (90%) create mode 100644 src/components/ui/images-grid/components/image-grid-row/index.tsx create mode 100644 src/components/ui/images-grid/images-grid.component.tsx rename src/components/{feature/posts-grid/posts-grid.models.ts => ui/images-grid/images-grid.models.ts} (100%) create mode 100644 src/components/ui/images-grid/index.ts diff --git a/src/app/(site)/app/components/feed/index.tsx b/src/app/(site)/app/components/feed/index.tsx index c9e812f..9e09f42 100644 --- a/src/app/(site)/app/components/feed/index.tsx +++ b/src/app/(site)/app/components/feed/index.tsx @@ -1,43 +1,93 @@ -import { getSuapabaseServerComponent } from "@/supabase/models/index.models"; +"use client"; + import { Heading } from "@/components/ui/typography/heading"; -import { PostsGrid } from "@/components/feature/posts-grid"; -import { Suspense } from "react"; +import { useEffect, useState } from "react"; import { Skeleton } from "@/components/ui/skeleton"; +import { ImagesGrid } from "@/components/ui/images-grid"; +import { useSupabase } from "@/hooks/use-supabase"; +import { Database } from "@/supabase/types"; + +export function Feed() { + const { supabase } = useSupabase(); + + const [posts, setPosts] = useState< + Database["public"]["Tables"]["posts"]["Row"][] + >([]); + + const [error, setError] = useState(false); + + const [isLoading, setIsLoading] = useState(true); + const [isFetching, setIsFetching] = useState(false); + + const [lastPostIndex, setLastPostIndex] = useState(1); + + useEffect(() => { + const controller = new AbortController(); -export async function Feed() { - const supabase = await getSuapabaseServerComponent(); + try { + setIsLoading(true); + setIsFetching(true); - const { data: posts, error } = await supabase - .from("posts") - .select("*") - .order("id", { ascending: false }) - .limit(24); + supabase + .from("posts") + .select("*") + .order("id", { ascending: false }) + .limit(32) + .range(lastPostIndex, lastPostIndex + 32) + .abortSignal(controller.signal) + .then(({ data: posts, error }) => { + if (error) return; - const doesPostsExist = posts && posts.length > 0 && !error; + 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); + } return ( - <> - {doesPostsExist ? ( -
- - {Array(16) - .fill(" ") - .map((_, i) => ( - - ))} - - } - > - - -
- ) : ( -
- Something wen wrong, reload the page -
+
+ {isLoading && ( +
    + {Array(16) + .fill(" ") + .map((_, i) => ( + + ))} +
+ )} + {!isLoading && !isFetching && ( + <> + {!error ? ( +
+ +
+ ) : ( +
+ + Something wen wrong, please reload the page + +
+ )} + )} - +
); } diff --git a/src/app/(site)/app/page.tsx b/src/app/(site)/app/page.tsx index 870165c..270338d 100644 --- a/src/app/(site)/app/page.tsx +++ b/src/app/(site)/app/page.tsx @@ -21,22 +21,8 @@ export default function AppPage() { function DesktopLayout() { return ( -
- - {Array(8) - .fill("") - .map((_, i) => ( -
  • - -
  • - ))} - - } - > - -
    +
    +
    ); } diff --git a/src/app/(site)/app/search/page.tsx b/src/app/(site)/app/search/page.tsx index 354cf9d..91ea7d0 100644 --- a/src/app/(site)/app/search/page.tsx +++ b/src/app/(site)/app/search/page.tsx @@ -1,8 +1,8 @@ import { getSuapabaseServerComponent } from "@/supabase/models/index.models"; import { SearchForm } from "./components/SearchForm/SearchForm"; -import { PostsGrid } from "@/components/feature/posts-grid"; import { Suspense } from "react"; import { Skeleton } from "@/components/ui/skeleton"; +import { ImagesGrid } from "@/components/ui/images-grid"; interface SearchParams { search_query?: string; @@ -40,7 +40,7 @@ const SearchPage: React.FC = async ({ searchParams }) => { } > - + )} diff --git a/src/components/feature/posts-grid/components/post/index.tsx b/src/components/feature/posts-grid/components/post/index.tsx deleted file mode 100644 index c1a4c34..0000000 --- a/src/components/feature/posts-grid/components/post/index.tsx +++ /dev/null @@ -1 +0,0 @@ -export * from "./post.component"; diff --git a/src/components/feature/posts-grid/index.tsx b/src/components/feature/posts-grid/index.tsx deleted file mode 100644 index 87b5b78..0000000 --- a/src/components/feature/posts-grid/index.tsx +++ /dev/null @@ -1,3 +0,0 @@ -import { PostsGrid } from "./posts-grid.component"; - -export { PostsGrid }; diff --git a/src/components/feature/posts-grid/posts-grid.component.tsx b/src/components/feature/posts-grid/posts-grid.component.tsx deleted file mode 100644 index dafd7f7..0000000 --- a/src/components/feature/posts-grid/posts-grid.component.tsx +++ /dev/null @@ -1,46 +0,0 @@ -"use client"; - -import { useEffect, useRef, useState } from "react"; -import { PostsGridRow } from "./components/post"; -import { TPostsGridItem } from "./posts-grid.models"; - -export function PostsGrid({ posts }: { posts: TPostsGridItem[] }) { - const [columnWidth, setColumnWidth] = useState(null); - - const containerRef = useRef(null); - - useEffect(() => { - function calculateColumnWidth() { - if (!containerRef.current) return; - - const containerWidth = containerRef.current.offsetWidth; - if (containerWidth <= 0 || !containerWidth) return; - - const columnCount = window.innerWidth > 1024 ? 3 : 2; - console.log(window.innerWidth); - setColumnWidth((containerWidth - 8 * 2) / columnCount); - } - - calculateColumnWidth(); - - window.addEventListener("resize", calculateColumnWidth); - - return () => window.removeEventListener("resize", calculateColumnWidth); - }, []); - return ( -
      - {posts.length > 0 && - containerRef.current && - posts.map((post) => ( - - ))} -
    - ); -} diff --git a/src/components/feature/posts-grid/components/post/post.component.tsx b/src/components/ui/images-grid/components/image-grid-row/images-grid-row.component.tsx similarity index 90% rename from src/components/feature/posts-grid/components/post/post.component.tsx rename to src/components/ui/images-grid/components/image-grid-row/images-grid-row.component.tsx index a5101e3..cd4657b 100644 --- a/src/components/feature/posts-grid/components/post/post.component.tsx +++ b/src/components/ui/images-grid/components/image-grid-row/images-grid-row.component.tsx @@ -5,7 +5,7 @@ import { ClientRouting } from "@/models/routing/client"; import { Database } from "@/supabase/types"; import Link from "next/link"; -export function PostsGridRow({ +export function ImagesGridRow({ post, columnWidth, }: { @@ -14,7 +14,7 @@ export function PostsGridRow({ }) { const imageHeight = (post.asset_height * columnWidth) / post.asset_width; return ( -
  • +
  • void; +}) { + const [columnWidth, setColumnWidth] = useState(null); + + const containerRef = useRef(null); + + useEffect(() => { + function calculateColumnWidth() { + if (!containerRef.current) return; + + const containerWidth = containerRef.current.offsetWidth; + if (containerWidth <= 0 || !containerWidth) return; + + const columnCount = window.innerWidth > 1024 ? 3 : 2; + setColumnWidth((containerWidth - 8 * 2) / columnCount); + } + + calculateColumnWidth(); + + window.addEventListener("resize", calculateColumnWidth); + + return () => window.removeEventListener("resize", calculateColumnWidth); + }, []); + + const [lastElementRef, setLastElementRef] = useState( + null, + ); + + const lastItemRef = useCallback((node: HTMLDivElement) => { + if (!node) return; + + setLastElementRef(node); + }, []); + + useEffect(() => { + if (!lastElementRef || typeof window === "undefined") return; + + const observerOptions: IntersectionObserverInit = { + root: null, + rootMargin: `${window.innerHeight * 2}px`, + threshold: 1.0, + }; + + const observer = new IntersectionObserver( + onFetchNewImages, + observerOptions, + ); + + observer.observe(lastElementRef); + + return () => { + observer.unobserve(lastElementRef); + }; + }, [lastElementRef]); + + return ( +
      + {posts.length > 0 && containerRef.current && ( + <> + {posts.map((post, i) => ( + + ))} +
      + + )} +
    + ); +} diff --git a/src/components/feature/posts-grid/posts-grid.models.ts b/src/components/ui/images-grid/images-grid.models.ts similarity index 100% rename from src/components/feature/posts-grid/posts-grid.models.ts rename to src/components/ui/images-grid/images-grid.models.ts diff --git a/src/components/ui/images-grid/index.ts b/src/components/ui/images-grid/index.ts new file mode 100644 index 0000000..d3ae27e --- /dev/null +++ b/src/components/ui/images-grid/index.ts @@ -0,0 +1 @@ +export * from "./images-grid.component"; From 7a443ee088f93847a0020bda4ca00fcf8b4265bb Mon Sep 17 00:00:00 2001 From: Huilensolis Date: Wed, 13 Mar 2024 18:53:46 -0300 Subject: [PATCH 2/8] refactor(app): 95 posts grid --- src/app/(site)/app/components/feed/index.tsx | 4 ++-- .../components/posts-grid-row/index.ts} | 0 .../posts-grid-row.component.tsx} | 2 +- .../posts-grid}/index.ts | 0 .../posts-grid/posts-grid.component.tsx} | 19 +++++++++---------- .../posts-grid/posts-grid.models.ts} | 0 6 files changed, 12 insertions(+), 13 deletions(-) rename src/components/{ui/images-grid/components/image-grid-row/index.tsx => feature/posts-grid/components/posts-grid-row/index.ts} (100%) rename src/components/{ui/images-grid/components/image-grid-row/images-grid-row.component.tsx => feature/posts-grid/components/posts-grid-row/posts-grid-row.component.tsx} (96%) rename src/components/{ui/images-grid => feature/posts-grid}/index.ts (100%) rename src/components/{ui/images-grid/images-grid.component.tsx => feature/posts-grid/posts-grid.component.tsx} (83%) rename src/components/{ui/images-grid/images-grid.models.ts => feature/posts-grid/posts-grid.models.ts} (100%) diff --git a/src/app/(site)/app/components/feed/index.tsx b/src/app/(site)/app/components/feed/index.tsx index 9e09f42..2e67ac9 100644 --- a/src/app/(site)/app/components/feed/index.tsx +++ b/src/app/(site)/app/components/feed/index.tsx @@ -3,9 +3,9 @@ import { Heading } from "@/components/ui/typography/heading"; import { useEffect, useState } from "react"; import { Skeleton } from "@/components/ui/skeleton"; -import { ImagesGrid } from "@/components/ui/images-grid"; import { useSupabase } from "@/hooks/use-supabase"; import { Database } from "@/supabase/types"; +import { PostsGrid } from "@/components/feature/posts-grid/posts-grid.component"; export function Feed() { const { supabase } = useSupabase(); @@ -77,7 +77,7 @@ export function Feed() { <> {!error ? (
    - +
    ) : (
    diff --git a/src/components/ui/images-grid/components/image-grid-row/index.tsx b/src/components/feature/posts-grid/components/posts-grid-row/index.ts similarity index 100% rename from src/components/ui/images-grid/components/image-grid-row/index.tsx rename to src/components/feature/posts-grid/components/posts-grid-row/index.ts diff --git a/src/components/ui/images-grid/components/image-grid-row/images-grid-row.component.tsx b/src/components/feature/posts-grid/components/posts-grid-row/posts-grid-row.component.tsx similarity index 96% rename from src/components/ui/images-grid/components/image-grid-row/images-grid-row.component.tsx rename to src/components/feature/posts-grid/components/posts-grid-row/posts-grid-row.component.tsx index cd4657b..ad24a88 100644 --- a/src/components/ui/images-grid/components/image-grid-row/images-grid-row.component.tsx +++ b/src/components/feature/posts-grid/components/posts-grid-row/posts-grid-row.component.tsx @@ -5,7 +5,7 @@ import { ClientRouting } from "@/models/routing/client"; import { Database } from "@/supabase/types"; import Link from "next/link"; -export function ImagesGridRow({ +export function PostsGridRow({ post, columnWidth, }: { diff --git a/src/components/ui/images-grid/index.ts b/src/components/feature/posts-grid/index.ts similarity index 100% rename from src/components/ui/images-grid/index.ts rename to src/components/feature/posts-grid/index.ts diff --git a/src/components/ui/images-grid/images-grid.component.tsx b/src/components/feature/posts-grid/posts-grid.component.tsx similarity index 83% rename from src/components/ui/images-grid/images-grid.component.tsx rename to src/components/feature/posts-grid/posts-grid.component.tsx index 4c1b15c..6ef2a12 100644 --- a/src/components/ui/images-grid/images-grid.component.tsx +++ b/src/components/feature/posts-grid/posts-grid.component.tsx @@ -1,13 +1,13 @@ import { useCallback, useEffect, useRef, useState } from "react"; -import { TPostsGridItem } from "./images-grid.models"; -import { ImagesGridRow } from "./components/image-grid-row"; +import { TPostsGridItem } from "./posts-grid.models"; +import { PostsGridRow } from "./components/posts-grid-row/posts-grid-row.component"; -export function ImagesGrid({ +export function PostsGrid({ posts, - onFetchNewImages, + onFetchNewPosts, }: { posts: TPostsGridItem[]; - onFetchNewImages: () => void; + onFetchNewPosts: () => void; }) { const [columnWidth, setColumnWidth] = useState(null); @@ -50,16 +50,15 @@ export function ImagesGrid({ threshold: 1.0, }; - const observer = new IntersectionObserver( - onFetchNewImages, - observerOptions, - ); + const observer = new IntersectionObserver(onFetchNewPosts, observerOptions); observer.observe(lastElementRef); return () => { observer.unobserve(lastElementRef); }; + + // eslint-disable-next-line react-hooks/exhaustive-deps }, [lastElementRef]); return ( @@ -70,7 +69,7 @@ export function ImagesGrid({ {posts.length > 0 && containerRef.current && ( <> {posts.map((post, i) => ( - Date: Wed, 13 Mar 2024 19:51:38 -0300 Subject: [PATCH 3/8] refactor(app): 95 post --- src/app/(site)/app/components/feed/index.tsx | 11 +-- src/app/(site)/app/layout.tsx | 2 +- .../post/components/options/index.tsx | 1 - .../post/[postid]/components/post/index.tsx | 75 ++++++++------- .../[postid]/components/recent-posts/index.ts | 1 + .../recent-posts/recent-pots.component.tsx | 93 +++++++++++++++++++ src/app/(site)/app/post/[postid]/page.tsx | 36 +------ .../(site)/app/profile/[username]/page.tsx | 4 +- src/components/feature/lazy-image/index.tsx | 26 +++--- .../components/posts-grid-container/index.ts | 1 + .../posts-grid-container.component.tsx | 23 +++++ .../components/posts-grid-skeleton/index.ts | 1 + .../posts-grid-skeleton.component.tsx | 14 +++ .../posts-grid/posts-grid.component.tsx | 8 +- 14 files changed, 198 insertions(+), 98 deletions(-) create mode 100644 src/app/(site)/app/post/[postid]/components/recent-posts/index.ts create mode 100644 src/app/(site)/app/post/[postid]/components/recent-posts/recent-pots.component.tsx create mode 100644 src/components/feature/posts-grid/components/posts-grid-container/index.ts create mode 100644 src/components/feature/posts-grid/components/posts-grid-container/posts-grid-container.component.tsx create mode 100644 src/components/feature/posts-grid/components/posts-grid-skeleton/index.ts create mode 100644 src/components/feature/posts-grid/components/posts-grid-skeleton/posts-grid-skeleton.component.tsx diff --git a/src/app/(site)/app/components/feed/index.tsx b/src/app/(site)/app/components/feed/index.tsx index 2e67ac9..d86a07d 100644 --- a/src/app/(site)/app/components/feed/index.tsx +++ b/src/app/(site)/app/components/feed/index.tsx @@ -6,6 +6,7 @@ import { Skeleton } from "@/components/ui/skeleton"; 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(); @@ -64,15 +65,7 @@ export function Feed() { return (
    - {isLoading && ( -
      - {Array(16) - .fill(" ") - .map((_, i) => ( - - ))} -
    - )} + {isLoading && } {!isLoading && !isFetching && ( <> {!error ? ( diff --git a/src/app/(site)/app/layout.tsx b/src/app/(site)/app/layout.tsx index 0593fc6..2c82e52 100644 --- a/src/app/(site)/app/layout.tsx +++ b/src/app/(site)/app/layout.tsx @@ -13,7 +13,7 @@ export default function AppLayout({ children }: { children: ReactNode }) {
    -
    +
    {children}
    diff --git a/src/app/(site)/app/post/[postid]/components/post/components/options/index.tsx b/src/app/(site)/app/post/[postid]/components/post/components/options/index.tsx index c36b1fc..f4c24e1 100644 --- a/src/app/(site)/app/post/[postid]/components/post/components/options/index.tsx +++ b/src/app/(site)/app/post/[postid]/components/post/components/options/index.tsx @@ -45,7 +45,6 @@ export function PostOptions({ return router.push("/app"); // Navigate to '/app' if no history } } - router.refresh(); } catch (e) { console.log(e); } diff --git a/src/app/(site)/app/post/[postid]/components/post/index.tsx b/src/app/(site)/app/post/[postid]/components/post/index.tsx index e594e6e..b09c154 100644 --- a/src/app/(site)/app/post/[postid]/components/post/index.tsx +++ b/src/app/(site)/app/post/[postid]/components/post/index.tsx @@ -22,48 +22,47 @@ export async function Post({ .single(); return ( -
    -
    -
    - -

    - {title} -

    - {postOwnerProfile && ( - -
    - {postOwnerProfile.avatar_url ? ( - - ) : ( -
    - )} -

    - {postOwnerProfile.name} -

    -
    - - )} -
    +
    +
    +

    + {title} +

    + {postOwnerProfile && ( + +
    + {postOwnerProfile.avatar_url ? ( + + ) : ( +
    + )} +

    + {postOwnerProfile.name} +

    +
    + + )} +
    diff --git a/src/app/(site)/app/post/[postid]/components/recent-posts/index.ts b/src/app/(site)/app/post/[postid]/components/recent-posts/index.ts new file mode 100644 index 0000000..04da9a5 --- /dev/null +++ b/src/app/(site)/app/post/[postid]/components/recent-posts/index.ts @@ -0,0 +1 @@ +export * from "./recent-pots.component"; diff --git a/src/app/(site)/app/post/[postid]/components/recent-posts/recent-pots.component.tsx b/src/app/(site)/app/post/[postid]/components/recent-posts/recent-pots.component.tsx new file mode 100644 index 0000000..9902630 --- /dev/null +++ b/src/app/(site)/app/post/[postid]/components/recent-posts/recent-pots.component.tsx @@ -0,0 +1,93 @@ +"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(true); + const [isFetching, setIsFetching] = useState(false); + + const [lastPostIndex, setLastPostIndex] = useState(1); + const [error, setError] = useState(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); + } + + return ( +
    + {isLoading && } + {!isLoading && !isFetching && ( + <> + {!error ? ( +
    + +
    + ) : ( +
    + + Something wen wrong, please reload the page + +
    + )} + + )} +
    + ); +} diff --git a/src/app/(site)/app/post/[postid]/page.tsx b/src/app/(site)/app/post/[postid]/page.tsx index b35b0d1..898380d 100644 --- a/src/app/(site)/app/post/[postid]/page.tsx +++ b/src/app/(site)/app/post/[postid]/page.tsx @@ -1,9 +1,8 @@ import { BackwardsNav } from "@/components/feature/nav/backwards"; import { Heading } from "@/components/ui/typography/heading"; import { getSuapabaseServerComponent } from "@/supabase/models/index.models"; -import { PostsGrid } from "@/components/feature/posts-grid"; -import { Database } from "@/supabase/types"; import { Post } from "./components/post"; +import { RecentPosts } from "./components/recent-posts"; export default async function PostPage({ params: { postid }, @@ -28,15 +27,15 @@ export default async function PostPage({ ); return ( -
    -
    {userPosts?.length > 0 && (
    - + {}} />
    )}
    diff --git a/src/components/feature/lazy-image/index.tsx b/src/components/feature/lazy-image/index.tsx index 7f2657f..dc4eb35 100644 --- a/src/components/feature/lazy-image/index.tsx +++ b/src/components/feature/lazy-image/index.tsx @@ -2,7 +2,18 @@ import { Skeleton } from "@/components/ui/skeleton"; import { ImageOff } from "lucide-react"; -import { useEffect, useRef, useState } from "react"; +import { type HTMLAttributes, useEffect, useRef, useState } from "react"; + +type TProps = { + src: string; + alt: string; + className?: string; + height?: number; + width?: number; + containerClassname?: HTMLAttributes["className"]; + skeletonClassName?: string; + skeletonBgColor?: string; +}; export function LazyImage({ src, @@ -12,15 +23,8 @@ export function LazyImage({ height, skeletonClassName = "", skeletonBgColor = "", -}: { - src: string; - alt: string; - className?: string; - height?: number; - width?: number; - skeletonClassName?: string; - skeletonBgColor?: string; -}) { + containerClassname = "", +}: TProps) { const [loading, setLoading] = useState(true); const [error, setError] = useState(false); @@ -46,7 +50,7 @@ export function LazyImage({ }, []); return ( -
    +
    {!error && ( (({ children }, ref) => { + return ( +
      + {children} +
    + ); +}); + +PostsGridContainer.displayName = "PostsGridContainer"; + +export { PostsGridContainer }; diff --git a/src/components/feature/posts-grid/components/posts-grid-skeleton/index.ts b/src/components/feature/posts-grid/components/posts-grid-skeleton/index.ts new file mode 100644 index 0000000..c034279 --- /dev/null +++ b/src/components/feature/posts-grid/components/posts-grid-skeleton/index.ts @@ -0,0 +1 @@ +export * from "./posts-grid-skeleton.component"; diff --git a/src/components/feature/posts-grid/components/posts-grid-skeleton/posts-grid-skeleton.component.tsx b/src/components/feature/posts-grid/components/posts-grid-skeleton/posts-grid-skeleton.component.tsx new file mode 100644 index 0000000..50ab527 --- /dev/null +++ b/src/components/feature/posts-grid/components/posts-grid-skeleton/posts-grid-skeleton.component.tsx @@ -0,0 +1,14 @@ +import { Skeleton } from "@/components/ui/skeleton"; +import { PostsGridContainer } from "../posts-grid-container"; + +export function PostsGridSkeleton({ cuantity = 16 }: { cuantity?: number }) { + return ( + + {Array(cuantity) + .fill(" ") + .map((_, i) => ( + + ))} + + ); +} diff --git a/src/components/feature/posts-grid/posts-grid.component.tsx b/src/components/feature/posts-grid/posts-grid.component.tsx index 6ef2a12..e059f3c 100644 --- a/src/components/feature/posts-grid/posts-grid.component.tsx +++ b/src/components/feature/posts-grid/posts-grid.component.tsx @@ -1,6 +1,7 @@ import { useCallback, useEffect, useRef, useState } from "react"; import { TPostsGridItem } from "./posts-grid.models"; import { PostsGridRow } from "./components/posts-grid-row/posts-grid-row.component"; +import { PostsGridContainer } from "./components/posts-grid-container"; export function PostsGrid({ posts, @@ -62,10 +63,7 @@ export function PostsGrid({ }, [lastElementRef]); return ( -
      + {posts.length > 0 && containerRef.current && ( <> {posts.map((post, i) => ( @@ -80,6 +78,6 @@ export function PostsGrid({
      )} -
    + ); } From 30205ca8bba6b03f5258b0e6c48d9e345b95c282 Mon Sep 17 00:00:00 2001 From: Huilensolis Date: Wed, 13 Mar 2024 20:10:51 -0300 Subject: [PATCH 4/8] refactor(app): 95 user profile --- .../[username]/components/user-posts/index.ts | 1 + .../user-posts/user-posts.component.tsx | 9 + .../(site)/app/profile/[username]/page.tsx | 209 +++++++++--------- src/components/feature/lazy-image/index.tsx | 7 +- .../posts-grid-row.component.tsx | 2 +- 5 files changed, 112 insertions(+), 116 deletions(-) create mode 100644 src/app/(site)/app/profile/[username]/components/user-posts/index.ts create mode 100644 src/app/(site)/app/profile/[username]/components/user-posts/user-posts.component.tsx diff --git a/src/app/(site)/app/profile/[username]/components/user-posts/index.ts b/src/app/(site)/app/profile/[username]/components/user-posts/index.ts new file mode 100644 index 0000000..b5e137b --- /dev/null +++ b/src/app/(site)/app/profile/[username]/components/user-posts/index.ts @@ -0,0 +1 @@ +export * from "./user-posts.component"; diff --git a/src/app/(site)/app/profile/[username]/components/user-posts/user-posts.component.tsx b/src/app/(site)/app/profile/[username]/components/user-posts/user-posts.component.tsx new file mode 100644 index 0000000..43d4b7f --- /dev/null +++ b/src/app/(site)/app/profile/[username]/components/user-posts/user-posts.component.tsx @@ -0,0 +1,9 @@ +"use client"; + +import { PostsGrid } from "@/components/feature/posts-grid/posts-grid.component"; + +export function UserPosts({ profileId }: { profileId: string }) { + function handleScroll() {} + + return ; +} diff --git a/src/app/(site)/app/profile/[username]/page.tsx b/src/app/(site)/app/profile/[username]/page.tsx index 013cf95..b8ac5a9 100644 --- a/src/app/(site)/app/profile/[username]/page.tsx +++ b/src/app/(site)/app/profile/[username]/page.tsx @@ -1,13 +1,14 @@ +import { CalendarIcon, LinkIcon, MapPinIcon } from "lucide-react"; +import Link from "next/link"; +import { Suspense } from "react"; + import { LazyImage } from "@/components/feature/lazy-image"; import { BackwardsNav } from "@/components/feature/nav/backwards"; -import { PostsGrid } from "@/components/feature/posts-grid/posts-grid.component"; import { Skeleton } from "@/components/ui/skeleton"; import { Heading } from "@/components/ui/typography/heading"; import { getSuapabaseServerComponent } from "@/supabase/models/index.models"; import { Database } from "@/supabase/types"; -import { CalendarIcon, LinkIcon, MapPinIcon } from "lucide-react"; -import Link from "next/link"; -import { Suspense } from "react"; +import { UserPosts } from "./components/user-posts"; export default function ProfilePage({ params: { username }, @@ -36,122 +37,112 @@ async function UserProfile({ username }: { username: string }) { data: { user: user }, } = await supabase.auth.getUser(); - const { data: userPosts } = await supabase - .from("posts") - .select("*") - .eq("user_id", userProfile?.user_id || "") - .order("created_at", { ascending: false }) - .limit(24); + return ( +
    + {doesUserProfileExist && userProfile ? ( + + ) : ( + + )} +
    + ); +} - function Profile({ - data, - userId, - userPosts, - }: { - data: Database["public"]["Tables"]["profiles"]["Row"]; - userId: Database["public"]["Tables"]["users"]["Row"]["id"]; - userPosts: Database["public"]["Tables"]["posts"]["Row"][]; - }) { - const dateWhenUserJoined = data.created_at - ? new Date(data.created_at).getFullYear() - : null; +function UserProfileNotFound() { + return <>404; +} - return ( -
    - -
    -
    +function Profile({ + profile, + currentUserId, +}: { + profile: Database["public"]["Tables"]["profiles"]["Row"]; + currentUserId: Database["public"]["Tables"]["users"]["Row"]["id"]; +}) { + const dateWhenUserJoined = profile.created_at + ? new Date(profile.created_at).getFullYear() + : null; + + return ( +
    + +
    +
    +
    +
    +
    + -
    - -
    -
    )} -
    - {data?.location && ( -
    - - {data.location} -
    - )} - {data?.website && ( - - )} - {dateWhenUserJoined && ( -
    - - joined in {dateWhenUserJoined} -
    - )} -
    -
    - - {userPosts?.length > 0 && ( -
    - {}} /> -
    - )} + {dateWhenUserJoined && ( +
    + + joined in {dateWhenUserJoined} +
    + )} + + + +
    +
    - ); - } - function UserProfileNotFound() { - return <>404; - } - - return ( -
    - {doesUserProfileExist && userProfile ? ( - - ) : ( - - )}
    ); } diff --git a/src/components/feature/lazy-image/index.tsx b/src/components/feature/lazy-image/index.tsx index dc4eb35..5bab7b4 100644 --- a/src/components/feature/lazy-image/index.tsx +++ b/src/components/feature/lazy-image/index.tsx @@ -64,13 +64,8 @@ export function LazyImage({ )} {loading && !error && ( Date: Wed, 13 Mar 2024 20:20:49 -0300 Subject: [PATCH 5/8] refactor(app): 95 use rprofile posts grid --- src/app/(site)/app/components/feed/index.tsx | 1 - .../user-posts/user-posts.component.tsx | 87 ++++++++++++++++++- 2 files changed, 85 insertions(+), 3 deletions(-) diff --git a/src/app/(site)/app/components/feed/index.tsx b/src/app/(site)/app/components/feed/index.tsx index d86a07d..c33a748 100644 --- a/src/app/(site)/app/components/feed/index.tsx +++ b/src/app/(site)/app/components/feed/index.tsx @@ -2,7 +2,6 @@ import { Heading } from "@/components/ui/typography/heading"; import { useEffect, useState } from "react"; -import { Skeleton } from "@/components/ui/skeleton"; import { useSupabase } from "@/hooks/use-supabase"; import { Database } from "@/supabase/types"; import { PostsGrid } from "@/components/feature/posts-grid/posts-grid.component"; diff --git a/src/app/(site)/app/profile/[username]/components/user-posts/user-posts.component.tsx b/src/app/(site)/app/profile/[username]/components/user-posts/user-posts.component.tsx index 43d4b7f..d2e0caf 100644 --- a/src/app/(site)/app/profile/[username]/components/user-posts/user-posts.component.tsx +++ b/src/app/(site)/app/profile/[username]/components/user-posts/user-posts.component.tsx @@ -1,9 +1,92 @@ "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 }) { - function handleScroll() {} + const { supabase } = useSupabase(); - return ; + const [posts, setPosts] = useState< + Database["public"]["Tables"]["posts"]["Row"][] + >([]); + + const [error, setError] = useState(false); + + const [isLoading, setIsLoading] = useState(true); + const [isFetching, setIsFetching] = useState(false); + + const [lastPostIndex, setLastPostIndex] = useState(1); + + const [userHasNoMorePosts, setUserHasNoMorePosts] = useState(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); + } + + return ( +
    + {isLoading && } + {!isLoading && !isFetching && ( + <> + {!error ? ( +
    + +
    + ) : ( +
    + + Something wen wrong, please reload the page + +
    + )} + + )} +
    + ); } From 9418d63311c19efd096b963fc52b93df7277b8f4 Mon Sep 17 00:00:00 2001 From: Huilensolis Date: Wed, 13 Mar 2024 20:58:38 -0300 Subject: [PATCH 6/8] refactor(app): 95 search --- .../components/SearchForm/SearchForm.tsx | 71 +++++----- .../SearchForm/hooks/useSearchForm.ts | 38 +++--- .../components/searched-posts-grid/index.ts | 1 + .../searched-posts-grid.component.tsx | 123 ++++++++++++++++++ src/app/(site)/app/search/page.tsx | 35 +---- 5 files changed, 181 insertions(+), 87 deletions(-) create mode 100644 src/app/(site)/app/search/components/searched-posts-grid/index.ts create mode 100644 src/app/(site)/app/search/components/searched-posts-grid/searched-posts-grid.component.tsx diff --git a/src/app/(site)/app/search/components/SearchForm/SearchForm.tsx b/src/app/(site)/app/search/components/SearchForm/SearchForm.tsx index c361d8d..24fc95d 100644 --- a/src/app/(site)/app/search/components/SearchForm/SearchForm.tsx +++ b/src/app/(site)/app/search/components/SearchForm/SearchForm.tsx @@ -1,46 +1,45 @@ -'use client' -import { Input } from "@/components/ui/input" -import { useForm } from "react-hook-form" -import { useSearchForm } from "./hooks/useSearchForm" +"use client"; +import { Input } from "@/components/ui/input"; +import { useForm } from "react-hook-form"; +import { useSearchForm } from "./hooks/useSearchForm"; const formInputs = { - search: 'search' -} + search: "search", +}; -export type formType = typeof formInputs +export type formType = typeof formInputs; interface SearchFormProps { - defaultSearchValue: string + defaultSearchValue: string; } -export const SearchForm: React.FC = ({ defaultSearchValue }) => { - const { - register - } = useForm() +export const SearchForm: React.FC = ({ + defaultSearchValue, +}) => { + const { register } = useForm(); - const { changeSearchValue } = useSearchForm(defaultSearchValue) + const { changeSearchValue } = useSearchForm(defaultSearchValue); - const handleOnChangeToSearch = (event: React.ChangeEvent) => { - const newValue = event.currentTarget.value - changeSearchValue(newValue) - } + const handleOnChangeToSearch = ( + event: React.ChangeEvent, + ) => { + const newValue = event.currentTarget.value; + changeSearchValue(newValue); + }; - return ( - - - - ) -} \ No newline at end of file + return ( + + + + ); +}; diff --git a/src/app/(site)/app/search/components/SearchForm/hooks/useSearchForm.ts b/src/app/(site)/app/search/components/SearchForm/hooks/useSearchForm.ts index 7adc47d..f9909be 100644 --- a/src/app/(site)/app/search/components/SearchForm/hooks/useSearchForm.ts +++ b/src/app/(site)/app/search/components/SearchForm/hooks/useSearchForm.ts @@ -1,27 +1,25 @@ -'use client' -import { useDebounce } from "@/hooks/use-debounce" -import { useRouting } from "@/hooks/useRouting" -import { useEffect, useState } from "react" +"use client"; +import { useDebounce } from "@/hooks/use-debounce"; +import { useRouting } from "@/hooks/useRouting"; +import { useEffect, useState } from "react"; export const useSearchForm = (defaultSearchValue: string) => { - const [searchValue, setSearchValue] = useState(defaultSearchValue) - const { debouncedValue } = useDebounce(searchValue) - const { goTo } = useRouting() + const [searchValue, setSearchValue] = useState(defaultSearchValue); + const { debouncedValue } = useDebounce(searchValue, 500); + const { goTo } = useRouting(); - useEffect(() => { - const currentURL = new URL(location.origin + location.pathname) + useEffect(() => { + const currentURL = new URL(location.origin + location.pathname); - if (debouncedValue !== '') { - currentURL.searchParams.set('search_query', debouncedValue) - } + currentURL.searchParams.set("search_query", debouncedValue); - goTo(currentURL.toString()) - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [debouncedValue]) + goTo(currentURL.toString()); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [debouncedValue]); - const changeSearchValue = (value: string) => { - setSearchValue(value) - } + const changeSearchValue = (value: string) => { + setSearchValue(value); + }; - return { valueToSearch: debouncedValue, changeSearchValue } -} \ No newline at end of file + return { valueToSearch: debouncedValue, changeSearchValue }; +}; diff --git a/src/app/(site)/app/search/components/searched-posts-grid/index.ts b/src/app/(site)/app/search/components/searched-posts-grid/index.ts new file mode 100644 index 0000000..6c37b1c --- /dev/null +++ b/src/app/(site)/app/search/components/searched-posts-grid/index.ts @@ -0,0 +1 @@ +export * from "./searched-posts-grid.component"; diff --git a/src/app/(site)/app/search/components/searched-posts-grid/searched-posts-grid.component.tsx b/src/app/(site)/app/search/components/searched-posts-grid/searched-posts-grid.component.tsx new file mode 100644 index 0000000..cd46005 --- /dev/null +++ b/src/app/(site)/app/search/components/searched-posts-grid/searched-posts-grid.component.tsx @@ -0,0 +1,123 @@ +"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 SearchedPostsGrid({ searchValue }: { searchValue: string }) { + const { supabase } = useSupabase(); + + const [posts, setPosts] = useState< + Database["public"]["Tables"]["posts"]["Row"][] + >([]); + + const [error, setError] = useState(false); + + const [isLoading, setIsLoading] = useState(true); + const [isFetching, setIsFetching] = useState(false); + + const [lastPostIndex, setLastPostIndex] = useState(1); + + const [notFound, setNotFound] = useState(false); + + function getAndSetPosts({ signal }: { signal: AbortSignal }) { + try { + setIsLoading(true); + setIsFetching(true); + + setNotFound(false); + + supabase + .from("posts") + .select("*") + .like("title", `%${searchValue}%`) + .order("created_at", { ascending: false }) + .range(lastPostIndex, lastPostIndex + 32) + .abortSignal(signal) + .limit(32) + .then(({ data: posts, error }) => { + if (error) return; + + if (!posts) return; + + if (posts.length === 0) { + setNotFound(true); + return; + } + setNotFound(false); + + setPosts((prev) => [...prev, ...posts]); + }); + } catch (error: unknown) { + if ((error as Error).name === "AbortError") return; + + setError(true); + } finally { + setIsLoading(false); + setIsFetching(false); + } + } + + useEffect(() => { + const controller = new AbortController(); + + getAndSetPosts({ signal: controller.signal }); + + return () => { + controller.abort(); + }; + + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [lastPostIndex]); + + useEffect(() => { + const controller = new AbortController(); + + if (isLoading || isFetching) return; + + setLastPostIndex(1); + + setPosts([]); + + getAndSetPosts({ signal: controller.signal }); + + return () => { + controller.abort(); + }; + }, [searchValue]); + + function handleScroll() { + setLastPostIndex((prev) => prev + 32); + } + + console.log({ isLoading, isFetching }); + + return ( +
    + {isLoading && } + {!isLoading && !isFetching && ( + <> + {!error ? ( +
    + +
    + ) : ( +
    + + Something wen wrong, please reload the page + +
    + )} + + )} + {notFound && posts.length === 0 && ( +
    + 404 not found +
    + )} +
    + ); +} diff --git a/src/app/(site)/app/search/page.tsx b/src/app/(site)/app/search/page.tsx index 91ea7d0..704a00e 100644 --- a/src/app/(site)/app/search/page.tsx +++ b/src/app/(site)/app/search/page.tsx @@ -1,8 +1,5 @@ -import { getSuapabaseServerComponent } from "@/supabase/models/index.models"; import { SearchForm } from "./components/SearchForm/SearchForm"; -import { Suspense } from "react"; -import { Skeleton } from "@/components/ui/skeleton"; -import { ImagesGrid } from "@/components/ui/images-grid"; +import { SearchedPostsGrid } from "./components/searched-posts-grid"; interface SearchParams { search_query?: string; @@ -13,37 +10,13 @@ interface Props { } const SearchPage: React.FC = async ({ searchParams }) => { - const supabase = await getSuapabaseServerComponent(); - const searchValue = searchParams?.search_query ?? ""; - - const { data: posts } = await supabase - .from("posts") - .select("*") - .ilike("title", `%${searchValue}%`) - .order("created_at", { ascending: false }) - .limit(24); - + const searchValue = searchParams.search_query ?? "painting"; + console.log({ searchValue }); return (
    -
    - {posts?.length !== undefined && posts?.length > 0 && ( - - {Array(16) - .fill(" ") - .map((_, i) => ( - - ))} - - } - > - - - )} -
    +
    ); From 633465effe61f0ea607abba1a7795b6d8d98f2cf Mon Sep 17 00:00:00 2001 From: Huilensolis Date: Wed, 13 Mar 2024 20:59:31 -0300 Subject: [PATCH 7/8] refactor(app): 95 clean console.log --- .../searched-posts-grid/searched-posts-grid.component.tsx | 2 -- src/app/(site)/app/search/page.tsx | 1 - 2 files changed, 3 deletions(-) diff --git a/src/app/(site)/app/search/components/searched-posts-grid/searched-posts-grid.component.tsx b/src/app/(site)/app/search/components/searched-posts-grid/searched-posts-grid.component.tsx index cd46005..b65d39f 100644 --- a/src/app/(site)/app/search/components/searched-posts-grid/searched-posts-grid.component.tsx +++ b/src/app/(site)/app/search/components/searched-posts-grid/searched-posts-grid.component.tsx @@ -93,8 +93,6 @@ export function SearchedPostsGrid({ searchValue }: { searchValue: string }) { setLastPostIndex((prev) => prev + 32); } - console.log({ isLoading, isFetching }); - return (
    {isLoading && } diff --git a/src/app/(site)/app/search/page.tsx b/src/app/(site)/app/search/page.tsx index 704a00e..e068359 100644 --- a/src/app/(site)/app/search/page.tsx +++ b/src/app/(site)/app/search/page.tsx @@ -11,7 +11,6 @@ interface Props { const SearchPage: React.FC = async ({ searchParams }) => { const searchValue = searchParams.search_query ?? "painting"; - console.log({ searchValue }); return (
    From d25b0520f10093da8bbc6d93eb78f1c0d3a8cbdd Mon Sep 17 00:00:00 2001 From: Huilensolis Date: Wed, 13 Mar 2024 21:15:39 -0300 Subject: [PATCH 8/8] build(app): 95 fix linter errors --- src/app/(site)/app/search/components/SearchForm/SearchForm.tsx | 1 + .../feature/posts-grid/components/posts-grid-row/index.ts | 2 +- .../components/posts-grid-row/posts-grid-row.component.tsx | 2 +- src/components/feature/posts-grid/index.ts | 2 +- src/components/feature/posts-grid/posts-grid.component.tsx | 2 +- 5 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/app/(site)/app/search/components/SearchForm/SearchForm.tsx b/src/app/(site)/app/search/components/SearchForm/SearchForm.tsx index 24fc95d..a9666e4 100644 --- a/src/app/(site)/app/search/components/SearchForm/SearchForm.tsx +++ b/src/app/(site)/app/search/components/SearchForm/SearchForm.tsx @@ -33,6 +33,7 @@ export const SearchForm: React.FC = ({ onInput={handleOnChangeToSearch} name={formInputs.search} register={register} + validationScheme={{}} type="text" id="search-input" label="Search" diff --git a/src/components/feature/posts-grid/components/posts-grid-row/index.ts b/src/components/feature/posts-grid/components/posts-grid-row/index.ts index b931318..2e870e8 100644 --- a/src/components/feature/posts-grid/components/posts-grid-row/index.ts +++ b/src/components/feature/posts-grid/components/posts-grid-row/index.ts @@ -1 +1 @@ -export * from "./images-grid-row.component"; +export * from "./posts-grid-row.component"; diff --git a/src/components/feature/posts-grid/components/posts-grid-row/posts-grid-row.component.tsx b/src/components/feature/posts-grid/components/posts-grid-row/posts-grid-row.component.tsx index 0c70b48..a920fea 100644 --- a/src/components/feature/posts-grid/components/posts-grid-row/posts-grid-row.component.tsx +++ b/src/components/feature/posts-grid/components/posts-grid-row/posts-grid-row.component.tsx @@ -1,9 +1,9 @@ "use client"; +import Link from "next/link"; import { LazyImage } from "@/components/feature/lazy-image"; import { ClientRouting } from "@/models/routing/client"; import { Database } from "@/supabase/types"; -import Link from "next/link"; export function PostsGridRow({ post, diff --git a/src/components/feature/posts-grid/index.ts b/src/components/feature/posts-grid/index.ts index d3ae27e..d670f2d 100644 --- a/src/components/feature/posts-grid/index.ts +++ b/src/components/feature/posts-grid/index.ts @@ -1 +1 @@ -export * from "./images-grid.component"; +export * from "./posts-grid.component"; diff --git a/src/components/feature/posts-grid/posts-grid.component.tsx b/src/components/feature/posts-grid/posts-grid.component.tsx index e059f3c..4ba9fe5 100644 --- a/src/components/feature/posts-grid/posts-grid.component.tsx +++ b/src/components/feature/posts-grid/posts-grid.component.tsx @@ -1,6 +1,6 @@ import { useCallback, useEffect, useRef, useState } from "react"; import { TPostsGridItem } from "./posts-grid.models"; -import { PostsGridRow } from "./components/posts-grid-row/posts-grid-row.component"; +import { PostsGridRow } from "./components/posts-grid-row"; import { PostsGridContainer } from "./components/posts-grid-container"; export function PostsGrid({