From df762b41548094cd99ab3817728cdd5067898891 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Yusuf=20Akg=C3=BCl?= <s86116@bht-berlin.de>
Date: Mon, 29 May 2023 23:16:17 +0200
Subject: [PATCH] scroll to top btn

---
 app/(content)/(gaming)/games/page.tsx | 22 +++++++++-------
 components/filter-sort-games.tsx      |  8 ++----
 components/icons.tsx                  |  2 ++
 components/infinity-scroll.tsx        | 32 ++++++++++++-----------
 components/scroll-to-top.tsx          | 37 +++++++++++++++++++++++++++
 5 files changed, 71 insertions(+), 30 deletions(-)
 create mode 100644 components/scroll-to-top.tsx

diff --git a/app/(content)/(gaming)/games/page.tsx b/app/(content)/(gaming)/games/page.tsx
index cacec50..d0f8a42 100644
--- a/app/(content)/(gaming)/games/page.tsx
+++ b/app/(content)/(gaming)/games/page.tsx
@@ -1,22 +1,26 @@
 import Sort from "@/components/filter-sort-games";
 import { InfiniteScrollGames } from "@/components/infinity-scroll";
+import ScrollToTop from "@/components/scroll-to-top";
 import SearchInput from "@/components/search-input";
 
 // renders a list of games infinitely (presumably)
 export default async function GamesPage() {
     return (
-        <main className="relative lg:gap-10 xl:grid xl:grid-cols-[1fr_240px]">
-            <div className="grid">
-                <div className="flex flex-col gap-10 items-center w-full">
-                    <SearchInput className="p-3 lg:w-2/3 2xl:w-1/3" />
+        <>
+            <main className="relative lg:gap-10 xl:grid xl:grid-cols-[1fr_240px]">
+                <div className="grid">
+                    <div className="flex flex-col gap-10 items-center w-full">
+                        <SearchInput className="p-3 lg:w-2/3 2xl:w-1/3" />
+                    </div>
+                    <InfiniteScrollGames />
                 </div>
-                <InfiniteScrollGames />
-            </div>
-            <div className="hidden xl:block flex-col md:flex">
-                <div className="sticky top-0">
+                <div className="hidden xl:block flex-col md:flex">
                     <Sort />
                 </div>
+            </main>
+            <div className="fixed top-6 left-1/2 -ml-7">
+                <ScrollToTop />
             </div>
-        </main>
+        </>
     )
 }
\ No newline at end of file
diff --git a/components/filter-sort-games.tsx b/components/filter-sort-games.tsx
index a229a73..bf38172 100644
--- a/components/filter-sort-games.tsx
+++ b/components/filter-sort-games.tsx
@@ -34,13 +34,9 @@ export default function Sort() {
     .map((param, index) => (index === 0 ? `?${param}` : `&${param}`))
     .join('');
 
-  const queryString = `${queryParamString ? `${queryParamString}` : ''}`;
+  const url = `${pathname}${queryParamString ? `${queryParamString}` : ''}`;
 
-  const url = `${pathname}${queryString ? `${queryString}` : ''}`;
-
-  useEffect(() => {
-    router.push(url);
-  }, [router, url]);
+  router.replace(url);
 
   function toggleSortOrder() {
     const newSortOrder = selectedSortOrder === 'desc' ? 'asc' : 'desc';
diff --git a/components/icons.tsx b/components/icons.tsx
index ca3cca6..e9a8c6b 100644
--- a/components/icons.tsx
+++ b/components/icons.tsx
@@ -2,6 +2,7 @@ import {
     AlertTriangle,
     ArrowDown,
     ArrowRight,
+    ArrowUpToLine,
     BellRing,
     Check,
     ChevronLeft,
@@ -72,6 +73,7 @@ export const Icons: IconsType = {
     moon: Moon, // Dark Mode Toggle Nav
     arrowdown: ArrowDown, // Descending Sort
     heart: Heart, // Like Button
+    arrowupline: ArrowUpToLine, // Back to Top Button
     close: X,
     spinner: Loader2,
     chevronLeft: ChevronLeft,
diff --git a/components/infinity-scroll.tsx b/components/infinity-scroll.tsx
index d59b27b..179db1d 100644
--- a/components/infinity-scroll.tsx
+++ b/components/infinity-scroll.tsx
@@ -49,30 +49,32 @@ export function InfiniteScrollGames() {
         <Card className="p-6">
             {status === 'error'
                 ?
-                (<span>Error: {(error as Error).message}</span>)
+                (<span>Uh oh... something went wrong: {(error as Error).message}</span>)
                 :
                 (status === 'success' && (
                     <InfiniteScroll
                         dataLength={data?.pages.length * 20}
                         next={fetchNextPage}
                         hasMore={hasNextPage ? true : false}
-                        loader={<h4>Loading more...</h4>}
+                        loader={
+                            <h1 className="text-center pt-6">
+                                <b>Trying to load more...</b>
+                            </h1>
+                        }
                         endMessage={
-                            <p style={{ textAlign: 'center' }}>
-                                <b>Yay! You have seen it all</b>
-                            </p>
+                            <h1 className="text-center pt-6">
+                                <b>Yay! You have seen it all!</b>
+                            </h1>
                         }
                     >
-                        <div className="">
-                            <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 gap-4 lg:gap-8">
-                                {data.pages.map((page, i) => (
-                                    <Fragment key={i}>
-                                        {page.map((game: IGame) => (
-                                            <Game id={game.id} name={game.name} cover={game.cover} key={game.id} />
-                                        ))}
-                                    </Fragment>
-                                ))}
-                            </div>
+                        <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 gap-4 lg:gap-8">
+                            {data.pages.map((page, i) => (
+                                <Fragment key={i}>
+                                    {page.map((game: IGame) => (
+                                        <Game id={game.id} name={game.name} cover={game.cover} key={game.id} />
+                                    ))}
+                                </Fragment>
+                            ))}
                         </div>
                     </InfiniteScroll>
                 ))}
diff --git a/components/scroll-to-top.tsx b/components/scroll-to-top.tsx
new file mode 100644
index 0000000..bd045be
--- /dev/null
+++ b/components/scroll-to-top.tsx
@@ -0,0 +1,37 @@
+"use client"
+
+import { cn } from "@/lib/utils";
+import { useEffect, useState } from "react";
+import { Icons } from "./icons";
+import { Button } from "./ui/button";
+
+export default function ScrollToTop() {
+    const [isVisible, setIsVisible] = useState(false);
+
+    const toggleVisibility = () => {
+        if (window.pageYOffset > 300) {
+            setIsVisible(true);
+        } else {
+            setIsVisible(false);
+        }
+    };
+
+    const scrollToTop = () => {
+        window.scrollTo({
+            top: 0,
+            behavior: "smooth"
+        });
+    };
+
+    useEffect(() => {
+        window.addEventListener("scroll", toggleVisibility);
+        return () => window.removeEventListener("scroll", toggleVisibility);
+    }, []);
+
+    return (
+        <Button size="lg" onClick={scrollToTop}
+            className={cn(isVisible ? "block" : "hidden", "")}>
+            <Icons.arrowupline className="h-3 w-3" aria-hidden="true" />
+        </Button>
+    );
+}
\ No newline at end of file
-- 
GitLab