From 703fc709e047f733467683f4225011d6e324208f Mon Sep 17 00:00:00 2001 From: Ivan Date: Thu, 14 Nov 2024 20:49:11 -0800 Subject: [PATCH 1/2] Added missing border for GDPR banner, updated image artifacts, small updates to Navbar and sidebar --- frontend/src/components/gdpr/gdprbanner.tsx | 2 +- .../listing/ListingImageFlipper.tsx | 51 ++++++++---- .../components/listing/ListingRenderer.tsx | 7 +- .../src/components/listings/ListingGrid.tsx | 9 +++ .../src/components/listings/MyListingGrid.tsx | 42 ++++++---- .../src/components/listings/UpvotedGrid.tsx | 9 +++ frontend/src/components/nav/Navbar.tsx | 78 ++++++++++++++++--- frontend/src/components/nav/Sidebar.tsx | 2 +- 8 files changed, 156 insertions(+), 44 deletions(-) diff --git a/frontend/src/components/gdpr/gdprbanner.tsx b/frontend/src/components/gdpr/gdprbanner.tsx index 445cc90e..5a3313f8 100644 --- a/frontend/src/components/gdpr/gdprbanner.tsx +++ b/frontend/src/components/gdpr/gdprbanner.tsx @@ -81,7 +81,7 @@ const GDPRBanner: React.FC = () => { )} {showOptOutForm && ( -
+
Please select which services you would like to opt out of.
diff --git a/frontend/src/components/listing/ListingImageFlipper.tsx b/frontend/src/components/listing/ListingImageFlipper.tsx index 2d5180f0..890c82b8 100644 --- a/frontend/src/components/listing/ListingImageFlipper.tsx +++ b/frontend/src/components/listing/ListingImageFlipper.tsx @@ -1,4 +1,4 @@ -import { useState } from "react"; +import { useMemo, useState } from "react"; import { FaChevronLeft, FaChevronRight, FaTimes } from "react-icons/fa"; import placeholder from "@/components/listing/pics/placeholder.jpg"; @@ -15,7 +15,27 @@ const ListingImageFlipper = (props: Props) => { const { artifacts, name, currentImageIndex, setCurrentImageIndex } = props; const [isFullScreen, setIsFullScreen] = useState(false); - if (artifacts.length === 0) { + const imageArtifacts = useMemo( + () => + artifacts + .map((artifact, index) => ({ artifact, originalIndex: index })) + .filter(({ artifact }) => artifact.artifact_type === "image") + .map(({ artifact, originalIndex }, newIndex) => ({ + artifact, + originalIndex, + newIndex, + })), + [artifacts], + ); + + const currentImageArrayIndex = useMemo(() => { + const found = imageArtifacts.findIndex( + ({ originalIndex }) => originalIndex === currentImageIndex, + ); + return found >= 0 ? found : 0; + }, [imageArtifacts, currentImageIndex]); + + if (imageArtifacts.length === 0) { return (
@@ -29,7 +49,18 @@ const ListingImageFlipper = (props: Props) => { ); } - const currentArtifact = artifacts[currentImageIndex]; + const handleNavigate = (direction: "next" | "prev") => { + const nextIndex = + direction === "next" + ? (currentImageArrayIndex + 1) % imageArtifacts.length + : currentImageArrayIndex === 0 + ? imageArtifacts.length - 1 + : currentImageArrayIndex - 1; + + setCurrentImageIndex(imageArtifacts[nextIndex].originalIndex); + }; + + const currentArtifact = imageArtifacts[currentImageArrayIndex].artifact; return ( <> @@ -41,24 +72,16 @@ const ListingImageFlipper = (props: Props) => { className="cursor-zoom-in rounded-lg w-[500px]" /> {/* Navigation arrows */} - {artifacts.length > 1 && ( + {imageArtifacts.length > 1 && ( <> @@ -87,9 +103,15 @@ const Navbar = () => { key={item.name} asChild variant={ - location.pathname === item.path ? "default" : "outline" + location.pathname.startsWith(item.path) + ? "ghost" + : "outline" } - className="px-2 xl:px-3 py-2 text-sm tracking-widest" + className={`px-2 xl:px-3 py-2 text-sm tracking-widest ${ + location.pathname.startsWith(item.path) + ? "underline underline-offset-4 decoration-2" + : "" + }`} >
{item.name}
@@ -103,15 +125,31 @@ const Navbar = () => { <> @@ -120,15 +158,31 @@ const Navbar = () => { <> diff --git a/frontend/src/components/nav/Sidebar.tsx b/frontend/src/components/nav/Sidebar.tsx index 739b9262..80ef79e4 100644 --- a/frontend/src/components/nav/Sidebar.tsx +++ b/frontend/src/components/nav/Sidebar.tsx @@ -28,7 +28,7 @@ const SidebarItem = ({
  • + ); + } + + return ( + + ); +}; diff --git a/frontend/src/components/nav/Navbar.tsx b/frontend/src/components/nav/Navbar.tsx index 5fa62156..3fc63eee 100644 --- a/frontend/src/components/nav/Navbar.tsx +++ b/frontend/src/components/nav/Navbar.tsx @@ -1,5 +1,4 @@ import { useState } from "react"; -import { FaExternalLinkAlt } from "react-icons/fa"; import { FaBars } from "react-icons/fa6"; import { Link, useLocation, useNavigate } from "react-router-dom"; @@ -10,6 +9,8 @@ import { Button } from "@/components/ui/button"; import { useAuthentication } from "@/hooks/useAuth"; import ROUTES from "@/lib/types/routes"; +import { NavButton } from "./NavButton"; + const Navbar = () => { const { isAuthenticated } = useAuthentication(); const [showSidebar, setShowSidebar] = useState(false); @@ -82,110 +83,55 @@ const Navbar = () => {
  • {navItems.map((item) => item.isExternal ? ( - + {item.name} + ) : ( - + {item.name} + ), )}
    {isAuthenticated ? ( <> - - + Logout + ) : ( <> - - + Sign Up + )}
    diff --git a/frontend/src/lib/utils/listingUtils.ts b/frontend/src/lib/utils/listingUtils.ts new file mode 100644 index 00000000..7913a0e3 --- /dev/null +++ b/frontend/src/lib/utils/listingUtils.ts @@ -0,0 +1,25 @@ +import { paths } from "@/gen/api"; + +type ListingDetails = + paths["/listings/batch"]["get"]["responses"][200]["content"]["application/json"]["listings"][number]; + +export const createListingDetailsMap = (listings: ListingDetails[]) => { + const detailsMap: Record = {}; + + listings.forEach((listing) => { + const firstImageArtifact = listing.artifacts?.find( + (artifact) => artifact.artifact_type === "image", + ); + + if (firstImageArtifact) { + listing.artifacts = [ + firstImageArtifact, + ...listing.artifacts.filter((a) => a !== firstImageArtifact), + ]; + } + + detailsMap[listing.id] = listing; + }); + + return detailsMap; +};