diff --git a/apps/web/app/gig-list/page.tsx b/apps/web/app/gig-list/page.tsx
index 3b75b78..5bd419a 100644
--- a/apps/web/app/gig-list/page.tsx
+++ b/apps/web/app/gig-list/page.tsx
@@ -2,14 +2,16 @@
import { useState, useEffect, useCallback } from "react";
import Link from "next/link";
import Image from "next/image";
-import { Check, ArrowRight, Calendar } from "lucide-react";
+import { Check, ArrowRight, Calendar, Search, Zap, X, Filter, ChevronDown } from "lucide-react";
+import { motion, AnimatePresence } from "framer-motion";
+
import api from "@/lib/axios.client";
import Navbar from "@/components/Navbar";
import Footer from "@/components/Footer";
// ─── Types ───────────────────────────────────────────────────────────────────
-type ViewMode = "grid" | "list";
+
type SortOption = "recommended" | "price_asc" | "price_desc" | "next_available";
interface GigPricing {
@@ -72,15 +74,7 @@ const sortOptions: { label: string; value: SortOption }[] = [
{ label: "Next Available", value: "next_available" },
];
-// Deterministic avatar color based on id string
-const avatarColor = (id: string) => {
- const colors = [
- "#e8736c", "#5b8dee", "#4db89e", "#f0a500", "#b57bee", "#e06060",
- ];
- let hash = 0;
- for (let i = 0; i < id.length; i++) hash = id.charCodeAt(i) + ((hash << 5) - hash);
- return colors[Math.abs(hash) % colors.length];
-};
+
const initials = (name: string) => {
if (!name) return "";
@@ -133,12 +127,11 @@ function SkeletonCard() {
// ─── Gig Card ─────────────────────────────────────────────────────────────────
-function GigCard({ gig, view }: { gig: Gig; view: ViewMode }) {
+function GigCard({ gig }: { gig: Gig }) {
const influencer = gig.primaryInfluencerId;
const name = influencer?.fullName ?? "Unknown Creator";
const niche = gig.category;
const availableFrom = undefined;
- const color = avatarColor(gig._id);
const availableLabel = availableFrom
? new Date(availableFrom).toLocaleDateString("en-US", { month: "short", day: "numeric" })
@@ -156,61 +149,6 @@ function GigCard({ gig, view }: { gig: Gig; view: ViewMode }) {
const gigImage = gig.bannerUrl || categoryImages[gig.category] || categoryImages["default"];
- if (view === "list") {
- return (
-
-
- {(influencer?.profileImageUrl || influencer?.profileImage) ? (
- {
- const target = e.target as HTMLImageElement;
- target.style.display = 'none';
- const sibling = target.nextElementSibling as HTMLElement;
- if (sibling) sibling.style.display = 'block';
- }}
- />
- ) : null}
- {initials(name)}
-
-
-
-
-
{gig.title}
-
{gig.shortDescription}
-
-
-
-
Starting at
-
- {formatCurrency(gig.pricing.basePrice, gig.pricing.currency)}
-
-
-
-
-
-
- {availableLabel}
-
-
-
-
- );
- }
return (
-
{
const target = e.target as HTMLImageElement;
const fallback = categoryImages[gig.category] || categoryImages["default"];
@@ -241,24 +179,24 @@ function GigCard({ gig, view }: { gig: Gig; view: ViewMode }) {
- {(influencer?.profileImageUrl || influencer?.profileImage) ? (
- <>
- {
- const target = e.target as HTMLImageElement;
- target.style.display = 'none';
- const fallback = target.nextElementSibling as HTMLElement;
- if (fallback) fallback.style.display = 'flex';
- }}
- />
- {initials(name)}
- >
- ) : initials(name)}
+ {(influencer?.profileImageUrl || influencer?.profileImage) ? (
+ <>
+ {
+ const target = e.target as HTMLImageElement;
+ target.style.display = 'none';
+ const fallback = target.nextElementSibling as HTMLElement;
+ if (fallback) fallback.style.display = 'flex';
+ }}
+ />
+ {initials(name)}
+ >
+ ) : initials(name)}
@@ -307,7 +245,6 @@ export default function ExploreGigs() {
const [activeCategory, setActiveCategory] = useState(null);
const [activePlatform, setActivePlatform] = useState(null);
const [availableOnly, setAvailableOnly] = useState(false);
- const [view, setView] = useState("grid");
const [sort, setSort] = useState("recommended");
const [maxPrice, setMaxPrice] = useState(MAX_PRICE_LIMIT);
const [page, setPage] = useState(1);
@@ -322,6 +259,7 @@ export default function ExploreGigs() {
// the user finishes typing (blur / Enter) or stops dragging the slider.
const [committedSearch, setCommittedSearch] = useState("");
const [committedMaxPrice, setCommittedMaxPrice] = useState(MAX_PRICE_LIMIT);
+ const [isFilterOpen, setIsFilterOpen] = useState(false);
const fetchGigs = useCallback(async (
opts: {
@@ -398,6 +336,7 @@ export default function ExploreGigs() {
setPage(1);
}
};
+
const handleSearchBlur = () => {
if (search !== committedSearch) {
setCommittedSearch(search);
@@ -405,6 +344,11 @@ export default function ExploreGigs() {
}
};
+ const handleSearchClick = () => {
+ setCommittedSearch(search);
+ setPage(1);
+ };
+
const totalPages = pagination?.totalPages ?? 1;
const pageNumbers = (): (number | "…")[] => {
@@ -435,145 +379,244 @@ export default function ExploreGigs() {
The world's most elite creators, verified and ready for your next campaign.
-
- {/* Grid/List Toggle */}
-
-
-
-
-
- {/* Modern Filter System - Sticky Glassmorphism Header */}
-
- {/* Category & Platform Pills */}
-
-
- Niche:
-
- {categories.map((c) => (
-
- ))}
-
-
-
- Platform:
- {platformList.map((p) => (
-
- ))}
-
-
-
- {/* Utility Bar */}
-
-
-
-
+ {/* Premium Minimal Filter System */}
+
+
+ {/* Unified Search Bar */}
+
+
+
setSearch(e.target.value)}
onKeyDown={handleSearchKeyDown}
onBlur={handleSearchBlur}
- className="w-full pl-14 pr-6 py-4 bg-white border border-slate-200 rounded-[2rem] text-sm font-medium focus:outline-none focus:ring-4 focus:ring-emerald-500/10 focus:border-emerald-500 transition-all shadow-sm"
+ className="w-full pl-10 md:pl-14 pr-24 md:pr-32 py-3.5 md:py-5 bg-white/70 backdrop-blur-xl border border-white shadow-[0_8px_30px_rgb(0,0,0,0.04)] rounded-2xl md:rounded-3xl text-xs md:text-sm font-semibold focus:outline-none focus:ring-4 focus:ring-emerald-500/5 focus:border-emerald-500/20 transition-all placeholder:text-slate-400"
/>
+
+
+ {search && (
+ { setSearch(""); setCommittedSearch(""); setPage(1); }}
+ className="w-6 h-6 md:w-8 md:h-8 flex items-center justify-center rounded-full hover:bg-slate-100 text-slate-400 transition-colors"
+ >
+
+
+ )}
+
+
+
-
-
- Budget:
-
-
- {maxPrice >= MAX_PRICE_LIMIT ? "50k+" : `${(maxPrice / 1000).toFixed(0)}k`}
-
-
+ {/* Filter Toggle Button */}
+
+
-
-
-
-
-
+
+ {/* Column 1: Categories */}
+
+
+
+
+ {categories.map((c) => (
+
+ ))}
+
+
+
+ {/* Column 2: Platform & Status */}
+
+
+
+
+
Platform Preference
+
+
+
+ {platformList.map((p) => (
+
+ ))}
+
+
+
+
+
+
+
+
+
+ {/* Column 3: Budget & Sorting */}
+
+
+
+
+
+ {maxPrice >= MAX_PRICE_LIMIT ? "Any" : `₹${(maxPrice / 1000).toFixed(0)}k`}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* Footer of Dropdown */}
+
+
+ Adjust filters to refine your search results
+
+
+
+
+ )}
+
+
+
{/* Stats Context Bar */}
-
-
+
+
{loading ? (
-
-
- Synchronizing...
+
+
+ Updating Catalog...
) : pagination ? (
- <>Found {pagination.total} Results Matches>
+ <>Found {pagination.total} Matching Opportunities>
) : null}
- {(activeCategory || activePlatform || maxPrice < MAX_PRICE_LIMIT || availableOnly) && (
-
+ Reset All Filters
+
+
)}
+
{/* Error state */}
{error && (
@@ -608,17 +650,12 @@ export default function ExploreGigs() {
)}
{/* Cards */}
-
+
{loading
? Array.from({ length: LIMIT }).map((_, i) => )
: gigs.map((gig) => (
-
- ))}
+
+ ))}
{/* Empty state */}
diff --git a/apps/web/app/globals.css b/apps/web/app/globals.css
index 67d4808..0917b5c 100644
--- a/apps/web/app/globals.css
+++ b/apps/web/app/globals.css
@@ -129,6 +129,21 @@
html {
@apply font-sans;
}
+
+ /* Custom minimal scrollbar */
+ ::-webkit-scrollbar {
+ width: 6px;
+ }
+ ::-webkit-scrollbar-track {
+ background: transparent;
+ }
+ ::-webkit-scrollbar-thumb {
+ background: rgba(0, 0, 0, 0.1);
+ border-radius: 10px;
+ }
+ ::-webkit-scrollbar-thumb:hover {
+ background: rgba(16, 185, 129, 0.4);
+ }
}
@keyframes progress-flow {
@@ -140,4 +155,24 @@
.animate-progress-flow {
background-size: 200% 200%;
animation: progress-flow 3s ease infinite;
-}
\ No newline at end of file
+}
+/* Lenis recommended CSS */
+html.lenis, html.lenis body {
+ height: auto;
+}
+
+.lenis.lenis-smooth {
+ scroll-behavior: auto !important;
+}
+
+.lenis.lenis-smooth [data-lenis-prevent] {
+ overscroll-behavior: contain;
+}
+
+.lenis.lenis-stopped {
+ overflow: hidden;
+}
+
+.lenis.lenis-scrolling iframe {
+ pointer-events: none;
+}
diff --git a/apps/web/app/layout.tsx b/apps/web/app/layout.tsx
index 03dc085..364d0c2 100644
--- a/apps/web/app/layout.tsx
+++ b/apps/web/app/layout.tsx
@@ -3,6 +3,7 @@ import { Inter } from "next/font/google";
import "./globals.css";
import AuthInitializer from "@/components/AuthInitializer";
+import SmoothScroll from "@/components/SmoothScroll";
@@ -26,8 +27,10 @@ export default function RootLayout({
-
- {children}
+
+
+ {children}
+