diff --git a/app/bounty/[bountyId]/page.tsx b/app/bounty/[bountyId]/page.tsx index 9f266a8..304edb4 100644 --- a/app/bounty/[bountyId]/page.tsx +++ b/app/bounty/[bountyId]/page.tsx @@ -21,7 +21,7 @@ export default async function BountyDetailPage({ params }: Props) { className="flex items-center gap-1.5 text-xs text-gray-500 mb-8" > Bounties diff --git a/app/bounty/page.tsx b/app/bounty/page.tsx index bb231e5..444e64c 100644 --- a/app/bounty/page.tsx +++ b/app/bounty/page.tsx @@ -1,6 +1,7 @@ "use client"; import { useState, useMemo, useCallback } from "react"; +import Link from "next/link"; import { useBounties } from "@/hooks/use-bounties"; import { BountyCard } from "@/components/bounty/bounty-card"; import { BountyListSkeleton } from "@/components/bounty/bounty-card-skeleton"; @@ -156,14 +157,11 @@ export default function BountiesPage() { ); }, []); - const toggleTag = useCallback( - (tag: string) => { - setSelectedTags((prev) => - prev.includes(tag) ? prev.filter((t) => t !== tag) : [...prev, tag], - ); - }, - [], - ); + const toggleTag = useCallback((tag: string) => { + setSelectedTags((prev) => + prev.includes(tag) ? prev.filter((t) => t !== tag) : [...prev, tag], + ); + }, []); const clearFilters = () => { setSearchQuery(""); @@ -208,23 +206,21 @@ export default function BountiesPage() { rewardRange[0] !== 0 || rewardRange[1] !== 5000 || statusFilter !== "open") && ( - - )} + + )}
{/* Search */}
- +
0 ? (
{filteredBounties.map((bounty) => ( -
+ -
+ ))}
) : ( @@ -501,7 +501,7 @@ export default function BountiesPage() { )}
-
-
+ + ); } diff --git a/app/bounty/review/page.tsx b/app/bounty/review/page.tsx new file mode 100644 index 0000000..d038b18 --- /dev/null +++ b/app/bounty/review/page.tsx @@ -0,0 +1,71 @@ +"use client"; + +import { SponsorReviewDashboard } from "@/components/bounty/sponsor-review-dashboard"; +import { ReviewSubmission } from "@/types/participation"; +import { Button } from "@/components/ui/button"; +import { ChevronLeft } from "lucide-react"; +import Link from "next/link"; + +// Mock data for the dashboard +const mockSubmissions: ReviewSubmission[] = [ + { + submissionId: "sub-1", + contributor: { + username: "alex_dev", + avatarUrl: "https://github.com/shadcn.png", + }, + milestoneId: "Milestone 1", + submittedAt: new Date().toISOString(), + status: "pending", + }, + { + submissionId: "sub-2", + contributor: { + username: "sarah_smith", + }, + milestoneId: "Milestone 2", + submittedAt: new Date(Date.now() - 86400000).toISOString(), + status: "pending", + }, +]; + +export default function ReviewDashboardPage() { + const handleAction = async (id: string, action: string) => { + console.log(`Action ${action} on submission ${id}`); + // In a real app, this would be an API call + await new Promise((resolve) => setTimeout(resolve, 500)); + }; + + return ( +
+
+
+ +

+ Review Submissions +

+

+ Manage and review contributions submitted for your bounties. +

+
+
+ +
+ +
+
+ ); +} diff --git a/components/bounty-detail/bounty-detail-client.tsx b/components/bounty-detail/bounty-detail-client.tsx index 9467c5b..5e38854 100644 --- a/components/bounty-detail/bounty-detail-client.tsx +++ b/components/bounty-detail/bounty-detail-client.tsx @@ -1,95 +1,95 @@ -"use client"; - -import { useRouter } from "next/navigation"; -import { AlertCircle, ArrowLeft } from "lucide-react"; -import { Button } from "@/components/ui/button"; -import { - ClaimModelInfo, - MobileCTA, - SidebarCTA, -} from "./bounty-detail-sidebar-cta"; -import { RequirementsCard, ScopeCard } from "./bounty-detail-requirements-card"; -import { HeaderCard } from "./bounty-detail-header-card"; -import { DescriptionCard } from "./bounty-detail-description-card"; -import { BountyDetailSkeleton } from "./bounty-detail-bounty-detail-skeleton"; -import { useBountyDetail } from "@/hooks/Use-bounty-detail"; - -export function BountyDetailClient({ bountyId }: { bountyId: string }) { - const router = useRouter(); - const { data: bounty, isPending, isError, error } = useBountyDetail(bountyId); - - if (isPending) return ; - - if (isError) { - return ( -
-
- -
-

- Failed to load bounty -

-

- {error instanceof Error - ? error.message - : "Something went wrong. Please try again."} -

- -
- ); - } - - if (!bounty) { - return ( -
-
- -
-

Bounty not found

-

- This bounty may have been removed or doesn't exist. -

- -
- ); - } - - return ( -
- {/* Main content */} -
- - - {bounty.requirements && bounty.requirements.length > 0 && ( - - )} - {bounty.scope && } -
- - {/* Sidebar */} - - - {/* Mobile sticky CTA */} - -
- ); -} +"use client"; + +import { useRouter } from "next/navigation"; +import { AlertCircle, ArrowLeft } from "lucide-react"; +import { Button } from "@/components/ui/button"; +import { + ClaimModelInfo, + MobileCTA, + SidebarCTA, +} from "./bounty-detail-sidebar-cta"; +import { RequirementsCard, ScopeCard } from "./bounty-detail-requirements-card"; +import { HeaderCard } from "./bounty-detail-header-card"; +import { DescriptionCard } from "./bounty-detail-description-card"; +import { BountyDetailSkeleton } from "./bounty-detail-bounty-detail-skeleton"; +import { useBountyDetail } from "@/hooks/Use-bounty-detail"; + +export function BountyDetailClient({ bountyId }: { bountyId: string }) { + const router = useRouter(); + const { data: bounty, isPending, isError, error } = useBountyDetail(bountyId); + + if (isPending) return ; + + if (isError) { + return ( +
+
+ +
+

+ Failed to load bounty +

+

+ {error instanceof Error + ? error.message + : "Something went wrong. Please try again."} +

+ +
+ ); + } + + if (!bounty) { + return ( +
+
+ +
+

Bounty not found

+

+ This bounty may have been removed or doesn't exist. +

+ +
+ ); + } + + return ( +
+ {/* Main content */} +
+ + + {bounty.requirements && bounty.requirements.length > 0 && ( + + )} + {bounty.scope && } +
+ + {/* Sidebar */} + + + {/* Mobile sticky CTA */} + +
+ ); +} diff --git a/components/bounty/bounty-list.tsx b/components/bounty/bounty-list.tsx index aa855fe..365539d 100644 --- a/components/bounty/bounty-list.tsx +++ b/components/bounty/bounty-list.tsx @@ -1,49 +1,65 @@ -'use client'; +"use client"; -import { BountyCard } from './bounty-card'; -import { BountyListSkeleton } from './bounty-card-skeleton'; -import { BountyError } from './bounty-error'; -import { BountyEmpty } from './bounty-empty'; -import { useBounties } from '@/hooks/use-bounties'; -import type { BountyListParams } from '@/lib/api'; -import type { Bounty } from '@/types/bounty'; +import Link from "next/link"; +import { BountyCard } from "./bounty-card"; +import { BountyListSkeleton } from "./bounty-card-skeleton"; +import { BountyError } from "./bounty-error"; +import { BountyEmpty } from "./bounty-empty"; +import { useBounties } from "@/hooks/use-bounties"; +import type { BountyListParams } from "@/lib/api"; +import type { Bounty } from "@/types/bounty"; interface BountyListProps { - params?: BountyListParams; - hasFilters?: boolean; - onClearFilters?: () => void; - onBountyClick?: (bounty: Bounty) => void; + params?: BountyListParams; + hasFilters?: boolean; + onClearFilters?: () => void; + onBountyClick?: (bounty: Bounty) => void; } -export function BountyList({ params, hasFilters = false, onClearFilters, onBountyClick }: BountyListProps) { - const { data, isLoading, isError, error, refetch } = useBounties(params); +export function BountyList({ + params, + hasFilters = false, + onClearFilters, + onBountyClick, +}: BountyListProps) { + const { data, isLoading, isError, error, refetch } = useBounties(params); - if (isLoading) { - return ; - } + if (isLoading) { + return ; + } - if (isError) { - return ( - refetch()} - /> - ); - } - - const bounties = data?.data ?? []; + if (isError) { + return ( + refetch()} + /> + ); + } - if (bounties.length === 0) { - return ; - } + const bounties = data?.data ?? []; + if (bounties.length === 0) { return ( -
- {bounties.map((bounty) => ( -
- onBountyClick?.(bounty)} /> -
- ))} -
+ ); + } + + return ( +
+ {bounties.map((bounty) => ( +
+ {onBountyClick ? ( + onBountyClick(bounty)} /> + ) : ( + + + + )} +
+ ))} +
+ ); } diff --git a/components/global-navbar.tsx b/components/global-navbar.tsx index a1b1a04..df91580 100644 --- a/components/global-navbar.tsx +++ b/components/global-navbar.tsx @@ -29,40 +29,54 @@ export function GlobalNavbar() {
Explore Projects Leaderboard Wallet + + Review +