From ca466ddc235a23fd8d97597b96cd54b44a3a2c46 Mon Sep 17 00:00:00 2001 From: Benjtalkshow Date: Sun, 17 Aug 2025 10:40:42 +0100 Subject: [PATCH 01/10] feat: initialize back project flow and project history demo page --- app/user/back-project/page.tsx | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 app/user/back-project/page.tsx diff --git a/app/user/back-project/page.tsx b/app/user/back-project/page.tsx new file mode 100644 index 000000000..3856f2a1f --- /dev/null +++ b/app/user/back-project/page.tsx @@ -0,0 +1,13 @@ +import { BoundlessButton } from '@/components/buttons'; +import React from 'react'; + +const page = () => { + return ( +
+ Back Project + View History +
+ ); +}; + +export default page; From 3b254b7bccba51c7df3b8b66e4ece418a00b6d29 Mon Sep 17 00:00:00 2001 From: Benjtalkshow Date: Sun, 17 Aug 2025 23:20:05 +0100 Subject: [PATCH 02/10] fix: implement back project form --- app/globals.css | 12 ++ app/user/back-project/page.tsx | 13 -- .../flows/back-project/back-project-form.tsx | 202 ++++++++++++++++++ components/flows/back-project/index.tsx | 111 ++++++++++ .../project-submission-loading.tsx | 15 ++ .../project/ProjectSubmissionSuccess.tsx | 42 +++- 6 files changed, 371 insertions(+), 24 deletions(-) delete mode 100644 app/user/back-project/page.tsx create mode 100644 components/flows/back-project/back-project-form.tsx create mode 100644 components/flows/back-project/index.tsx create mode 100644 components/flows/back-project/project-submission-loading.tsx diff --git a/app/globals.css b/app/globals.css index 532b272b2..e8921ec9c 100644 --- a/app/globals.css +++ b/app/globals.css @@ -134,3 +134,15 @@ button { cursor: pointer; } +/* Hide arrows in Chrome, Safari, Edge, Opera */ +input[type='number']::-webkit-inner-spin-button, +input[type='number']::-webkit-outer-spin-button { + -webkit-appearance: none; + margin: 0; +} + +/* Hide arrows in Firefox */ +input[type='number'] { + -moz-appearance: textfield; + appearance: textfield; +} diff --git a/app/user/back-project/page.tsx b/app/user/back-project/page.tsx deleted file mode 100644 index 3856f2a1f..000000000 --- a/app/user/back-project/page.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import { BoundlessButton } from '@/components/buttons'; -import React from 'react'; - -const page = () => { - return ( -
- Back Project - View History -
- ); -}; - -export default page; diff --git a/components/flows/back-project/back-project-form.tsx b/components/flows/back-project/back-project-form.tsx new file mode 100644 index 000000000..99b54750d --- /dev/null +++ b/components/flows/back-project/back-project-form.tsx @@ -0,0 +1,202 @@ +'use client'; + +import type React from 'react'; +import { useState } from 'react'; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from '@/components/ui/select'; +import { Checkbox } from '@/components/ui/checkbox'; +import { ArrowLeft, Check, Copy } from 'lucide-react'; +import { BoundlessButton } from '@/components/buttons'; + +interface BackProjectFormProps { + onSubmit: (data: { + amount: string; + currency: string; + token: string; + network: string; + walletAddress: string; + keepAnonymous: boolean; + }) => void; + isLoading?: boolean; +} + +const QUICK_AMOUNTS = [10, 20, 30, 50, 100, 500, 1000]; + +export function BackProjectForm({ + onSubmit, + isLoading = false, +}: BackProjectFormProps) { + const [amount, setAmount] = useState(''); + const [currency] = useState('USDT'); + const [token, setToken] = useState(''); + const [network, setNetwork] = useState('Stella / Soroban'); + const [walletAddress] = useState('GDS3...GB7'); + const [keepAnonymous, setKeepAnonymous] = useState(false); + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + onSubmit({ + amount, + currency, + token, + network, + walletAddress, + keepAnonymous, + }); + }; + + const handleQuickAmount = (quickAmount: number) => { + setAmount(quickAmount.toString()); + }; + + const handleCopyAddress = async (e: React.MouseEvent) => { + e.preventDefault(); + try { + await navigator.clipboard.writeText(walletAddress); + // Could add toast notification here instead of state + } catch (err) { + // Fallback for browsers that don't support clipboard API + const textArea = document.createElement('textarea'); + console.error(err); + + textArea.value = walletAddress; + document.body.appendChild(textArea); + textArea.select(); + try { + document.execCommand('copy'); + } catch (copyErr) { + console.error('Failed to copy address:', copyErr); + } + document.body.removeChild(textArea); + } + }; + + const isFormValid = amount && currency && token && walletAddress; + + return ( +
+
+ +

Back Project

+
+
+
+

+ Funds will be held in escrow and released only upon milestone + approvals. +

+
+ +
+ +
+ {currency} + setAmount(e.target.value)} + type='number' + className='w-full bg-transparent font-normal text-base text-placeholder focus:outline-none' + placeholder='1000' + disabled={isLoading} + /> +
+

min. amount: $10

+ +
+ {QUICK_AMOUNTS.map(quickAmount => ( + + ))} +
+
+ +
+ + +
+ +
+ +
+ setNetwork(e.target.value)} + type='text' + className='w-full bg-transparent font-normal text-base text-placeholder focus:outline-none' + disabled={isLoading} + /> +
+
+ +
+ + + + {walletAddress} + + +
+ +
+ setKeepAnonymous(checked as boolean)} + disabled={isLoading} + className='border-stepper-border data-[state=checked]:bg-primary data-[state=checked]:border-primary' + /> + +
+ + + Confirm Contribution + +
+
+ ); +} diff --git a/components/flows/back-project/index.tsx b/components/flows/back-project/index.tsx new file mode 100644 index 000000000..2f7d0d103 --- /dev/null +++ b/components/flows/back-project/index.tsx @@ -0,0 +1,111 @@ +'use client'; + +import { useState } from 'react'; +import { BoundlessButton } from '@/components/buttons'; +import { ProjectSubmissionSuccess } from '@/components/project'; +import BoundlessSheet from '@/components/sheet/boundless-sheet'; +import { ProjectSubmissionLoading } from '@/components/flows/back-project/project-submission-loading'; +import { BackProjectForm } from './back-project-form'; + +type BackProjectState = 'form' | 'loading' | 'success'; + +interface BackProjectData { + amount: string; + currency: string; + token: string; + network: string; + walletAddress: string; + keepAnonymous: boolean; +} + +const BackProject = () => { + const [isSheetOpen, setIsSheetOpen] = useState(false); + const [backProjectState, setBackProjectState] = + useState('form'); + + const handleBackProject = (data: BackProjectData) => { + setBackProjectState('loading'); + console.log(data); + + // Simulate API call + setTimeout(() => { + setBackProjectState('success'); + }, 2000); + }; + + // const handleContinue = () => { + // setIsSheetOpen(false) + // setBackProjectState("form") + // } + + // const handleViewHistory = () => { + // // Navigate to history page or open history modal + // setIsSheetOpen(false) + // // TODO: Implement backing history modal or navigation + // } + + // const handleBack = () => { + // if (backProjectState === "success") { + // setBackProjectState("form") + // } + // } + + const renderSheetContent = () => { + if (backProjectState === 'success') { + return ( +
+
+ {/* */} +
+ +
+ ); + } + + return ( +
+ + + {backProjectState === 'loading' && ( +
+ +
+ )} +
+ ); + }; + + return ( +
+ + {renderSheetContent()} + + + setIsSheetOpen(true)}> + Back Project + +
+ ); +}; + +export default BackProject; diff --git a/components/flows/back-project/project-submission-loading.tsx b/components/flows/back-project/project-submission-loading.tsx new file mode 100644 index 000000000..4dc27ea2d --- /dev/null +++ b/components/flows/back-project/project-submission-loading.tsx @@ -0,0 +1,15 @@ +export function ProjectSubmissionLoading() { + return ( +
+
+ {/* Outer spinning ring */} +
+ {/* Inner spinning arc */} +
+
+

+ Processing your contribution... +

+
+ ); +} diff --git a/components/project/ProjectSubmissionSuccess.tsx b/components/project/ProjectSubmissionSuccess.tsx index cc3683512..fa2e2e31c 100644 --- a/components/project/ProjectSubmissionSuccess.tsx +++ b/components/project/ProjectSubmissionSuccess.tsx @@ -1,26 +1,46 @@ import Image from 'next/image'; +import Link from 'next/link'; import React from 'react'; -function ProjectSubmissionSuccess() { +interface ProjectSubmissionSuccessProps { + title?: string; + description?: string; + linkSection?: string; + linkName?: string; + url?: string; + continueAction?: () => void; +} + +function ProjectSubmissionSuccess({ + title = 'Project Submitted!', + description = 'Your project has been submitted and is now under admin review. You’ll receive an update within 72 hours. Once approved, your project will proceed to public validation.', + linkSection = 'You can track the status of your submission anytime on the', + linkName = 'Projects page.', + url = '/projects', + continueAction, +}: ProjectSubmissionSuccessProps) { return (
-
Project Submitted!
-
+
{title}
+
done
-
+

- Your project has been submitted and is now under admin review. You’ll - receive an update within 72 hours. Once approved, your project will - proceed to public validation. + {description}

-

- You can track the status of your submission anytime on the{' '} - Projects page. +

+ {linkSection}{' '} + + {linkName} +

-
From 1312a12e65310e2760f579d9ab71edb1fe1cf27e Mon Sep 17 00:00:00 2001 From: Benjtalkshow Date: Tue, 19 Aug 2025 10:32:31 +0100 Subject: [PATCH 03/10] fix: fix back project flow --- components/flows/back-project/index.tsx | 2 +- lib/data/backing-history-mock.ts | 142 ++++++++++++++++++++++++ types/backing-history.ts | 32 ++++++ 3 files changed, 175 insertions(+), 1 deletion(-) create mode 100644 lib/data/backing-history-mock.ts create mode 100644 types/backing-history.ts diff --git a/components/flows/back-project/index.tsx b/components/flows/back-project/index.tsx index 2f7d0d103..972d5a0e9 100644 --- a/components/flows/back-project/index.tsx +++ b/components/flows/back-project/index.tsx @@ -95,7 +95,7 @@ const BackProject = () => { setOpen={setIsSheetOpen} // title="Back Project" showCloseButton={true} - contentClassName={backProjectState === 'form' ? 'h-[60vh]' : 'h-[85vh]'} + contentClassName={`h-[100vh]`} className='mx-4' > {renderSheetContent()} diff --git a/lib/data/backing-history-mock.ts b/lib/data/backing-history-mock.ts new file mode 100644 index 000000000..3de9417e2 --- /dev/null +++ b/lib/data/backing-history-mock.ts @@ -0,0 +1,142 @@ +import type { BackingHistoryItem } from '@/types/backing-history'; + +export const mockBackingHistory: BackingHistoryItem[] = [ + { + id: '1', + backer: { + name: 'Collins Odumeje', + isAnonymous: false, + avatar: '/diverse-user-avatars.png', + walletAddress: 'GDS3...GB7', + }, + amount: 2300, + currency: 'USDT', + date: new Date('2025-08-17'), + timeAgo: '3s', + }, + { + id: '2', + backer: { + name: 'Sarah Chen', + isAnonymous: false, + avatar: '/diverse-user-avatars.png', + walletAddress: 'ABC1...XYZ', + }, + amount: 1500, + currency: 'USDT', + date: new Date('2025-08-16'), + timeAgo: '1d', + }, + { + id: '3', + backer: { + name: 'Anonymous', + isAnonymous: true, + avatar: '/anonymous-user-concept.png', + walletAddress: 'DEF4...789', + }, + amount: 5000, + currency: 'USDT', + date: new Date('2025-08-15'), + timeAgo: '2d', + }, + { + id: '4', + backer: { + name: 'Michael Rodriguez', + isAnonymous: false, + avatar: '/diverse-user-avatars.png', + walletAddress: 'HIJ7...456', + }, + amount: 750, + currency: 'USDT', + date: new Date('2025-08-14'), + timeAgo: '3d', + }, + { + id: '5', + backer: { + name: 'Anonymous', + isAnonymous: true, + avatar: '/anonymous-user-concept.png', + walletAddress: 'KLM0...123', + }, + amount: 3200, + currency: 'USDT', + date: new Date('2025-08-13'), + timeAgo: '4d', + }, + { + id: '6', + backer: { + name: 'Emma Thompson', + isAnonymous: false, + avatar: '/diverse-user-avatars.png', + walletAddress: 'NOP3...890', + }, + amount: 1800, + currency: 'USDT', + date: new Date('2025-08-12'), + timeAgo: '5d', + }, + { + id: '7', + backer: { + name: 'David Kim', + isAnonymous: false, + avatar: '/diverse-user-avatars.png', + walletAddress: 'QRS6...567', + }, + amount: 4500, + currency: 'USDT', + date: new Date('2025-08-11'), + timeAgo: '6d', + }, + { + id: '8', + backer: { + name: 'Anonymous', + isAnonymous: true, + avatar: '/anonymous-user-concept.png', + walletAddress: 'TUV9...234', + }, + amount: 950, + currency: 'USDT', + date: new Date('2025-08-10'), + timeAgo: '1w', + }, + { + id: '9', + backer: { + name: 'Lisa Wang', + isAnonymous: false, + avatar: '/diverse-user-avatars.png', + walletAddress: 'WXY2...901', + }, + amount: 2750, + currency: 'USDT', + date: new Date('2025-08-09'), + timeAgo: '1w', + }, + { + id: '10', + backer: { + name: 'Anonymous', + isAnonymous: true, + avatar: '/anonymous-user-concept.png', + walletAddress: 'ZAB5...678', + }, + amount: 6200, + currency: 'USDT', + date: new Date('2025-08-08'), + timeAgo: '1w', + }, +]; + +export const sortOptions = [ + { value: 'newest', label: 'Newest first' }, + { value: 'oldest', label: 'Oldest first' }, + { value: 'alphabetical', label: 'Alphabetical' }, + { value: 'amount-high', label: 'Highest first' }, + { value: 'amount-low', label: 'Lowest first' }, +]; diff --git a/types/backing-history.ts b/types/backing-history.ts new file mode 100644 index 000000000..054c4506b --- /dev/null +++ b/types/backing-history.ts @@ -0,0 +1,32 @@ +export interface BackingHistoryItem { + id: string; + backer: { + name: string; + isAnonymous: boolean; + avatar?: string; + walletAddress: string; + }; + amount: number; + currency: string; + date: Date; + timeAgo: string; +} + +export interface BackingHistoryFilters { + searchQuery: string; + sortBy: 'newest' | 'oldest' | 'alphabetical' | 'amount-high' | 'amount-low'; + dateRange: { + from: Date | null; + to: Date | null; + }; + amountRange: { + min: number; + max: number; + }; + identityType: 'all' | 'identified' | 'anonymous'; +} + +export interface BackingHistorySortOption { + value: string; + label: string; +} From 52f2d2617de64f1c008626eaf49df83ccb3f5825 Mon Sep 17 00:00:00 2001 From: Benjtalkshow Date: Wed, 20 Aug 2025 02:56:37 +0100 Subject: [PATCH 04/10] feat: backing history --- app/user/backing-history/page.tsx | 111 ++++ .../flows/backing-history/backing-history.tsx | 506 ++++++++++++++++++ lib/data/backing-history-mock.ts | 142 ----- types/backing-history.ts | 32 -- 4 files changed, 617 insertions(+), 174 deletions(-) create mode 100644 app/user/backing-history/page.tsx create mode 100644 components/flows/backing-history/backing-history.tsx delete mode 100644 lib/data/backing-history-mock.ts delete mode 100644 types/backing-history.ts diff --git a/app/user/backing-history/page.tsx b/app/user/backing-history/page.tsx new file mode 100644 index 000000000..58fdebd9d --- /dev/null +++ b/app/user/backing-history/page.tsx @@ -0,0 +1,111 @@ +'use client'; + +import { useState } from 'react'; +import { Button } from '@/components/ui/button'; +import BackingHistory from '@/components/flows/backing-history/backing-history'; + +// Sample data matching the images +const sampleBackers = [ + { + id: '1', + name: 'Collins Odumeje', + avatar: '/placeholder.svg?height=32&width=32', + amount: 2300, + date: new Date('2025-08-05'), + walletId: 'GDS3...GB7', + isAnonymous: false, + }, + { + id: '2', + name: 'Collins Odumeje', + avatar: '/placeholder.svg?height=32&width=32', + amount: 2300, + date: new Date('2025-08-05'), + walletId: 'GDS3...GB7', + isAnonymous: false, + }, + { + id: '3', + name: 'Collins Odumeje', + avatar: '/placeholder.svg?height=32&width=32', + amount: 2300, + date: new Date('2025-08-05'), + walletId: 'GDS3...GB7', + isAnonymous: false, + }, + { + id: '4', + name: 'Anonymous', + amount: 2300, + date: new Date('2025-08-05'), + walletId: 'GDS3...GB7', + isAnonymous: true, + }, + { + id: '5', + name: 'Collins Odumeje', + avatar: '/placeholder.svg?height=32&width=32', + amount: 2300, + date: new Date('2025-08-05'), + walletId: 'GDS3...GB7', + isAnonymous: false, + }, + { + id: '6', + name: 'Anonymous', + amount: 2300, + date: new Date('2025-08-05'), + walletId: 'GDS3...GB7', + isAnonymous: true, + }, + { + id: '7', + name: 'Anonymous', + amount: 2300, + date: new Date('2025-08-05'), + walletId: 'GDS3...GB7', + isAnonymous: true, + }, + { + id: '8', + name: 'Collins Odumeje', + avatar: '/placeholder.svg?height=32&width=32', + amount: 2300, + date: new Date('2025-08-05'), + walletId: 'GDS3...GB7', + isAnonymous: false, + }, + { + id: '9', + name: 'Anonymous', + amount: 2300, + date: new Date('2025-08-05'), + walletId: 'GDS3...GB7', + isAnonymous: true, + }, +]; + +export default function Home() { + const [showBackingHistory, setShowBackingHistory] = useState(false); + + return ( +
+
+

Crowdfunding Dashboard

+ + + + +
+
+ ); +} diff --git a/components/flows/backing-history/backing-history.tsx b/components/flows/backing-history/backing-history.tsx new file mode 100644 index 000000000..6f8e85275 --- /dev/null +++ b/components/flows/backing-history/backing-history.tsx @@ -0,0 +1,506 @@ +'use client'; + +import type React from 'react'; +import { useState, useMemo } from 'react'; +import { + Search, + Filter, + ArrowUpDown, + Calendar, + DollarSign, + User, + Wallet, + Check, + CheckIcon, +} from 'lucide-react'; +import { Button } from '@/components/ui/button'; +import { Input } from '@/components/ui/input'; +import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'; +import { Slider } from '@/components/ui/slider'; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from '@/components/ui/select'; +import { + Popover, + PopoverContent, + PopoverTrigger, +} from '@/components/ui/popover'; +import { format } from 'date-fns'; +import BoundlessSheet from '@/components/sheet/boundless-sheet'; + +interface Backer { + id: string; + name: string; + avatar?: string; + amount: number; + date: Date; + walletId: string; + isAnonymous: boolean; +} + +interface BackingHistoryProps { + open: boolean; + setOpen: (open: boolean) => void; + backers: Backer[]; +} + +type SortOption = 'newest' | 'oldest' | 'alphabetical' | 'highest' | 'lowest'; +type IdentityFilter = 'all' | 'identified' | 'anonymous'; + +const BackingHistory: React.FC = ({ + open, + setOpen, + backers, +}) => { + const [searchQuery, setSearchQuery] = useState(''); + const [sortBy, setSortBy] = useState('newest'); + const [amountRange, setAmountRange] = useState([0, 10000]); + const [dateRange, setDateRange] = useState<{ from?: Date; to?: Date }>({}); + const [identityFilter, setIdentityFilter] = useState('all'); + const [showFilters, setShowFilters] = useState(false); + const [showSortPopover, setShowSortPopover] = useState(false); + + const setQuickDateFilter = (days: number) => { + const today = new Date(); + const pastDate = new Date(today.getTime() - days * 24 * 60 * 60 * 1000); + setDateRange({ from: pastDate, to: today }); + }; + + const resetFilters = () => { + setSearchQuery(''); + setSortBy('newest'); + setAmountRange([0, 10000]); + setDateRange({}); + setIdentityFilter('all'); + }; + + const resetDateRange = () => { + setDateRange({}); + }; + + const resetAmountRange = () => { + setAmountRange([10, 1000]); + }; + + const resetIdentityFilter = () => { + setIdentityFilter('all'); + }; + + const applyFilters = () => { + setShowSortPopover(false); + }; + + const filteredAndSortedBackers = useMemo(() => { + const filtered = backers.filter(backer => { + const matchesSearch = + backer.name.toLowerCase().includes(searchQuery.toLowerCase()) || + backer.walletId.toLowerCase().includes(searchQuery.toLowerCase()); + + const matchesAmount = + backer.amount >= amountRange[0] && backer.amount <= amountRange[1]; + + const matchesDate = + !dateRange.from || + !dateRange.to || + (backer.date >= dateRange.from && backer.date <= dateRange.to); + + const matchesIdentity = + identityFilter === 'all' || + (identityFilter === 'anonymous' && backer.isAnonymous) || + (identityFilter === 'identified' && !backer.isAnonymous); + + return matchesSearch && matchesAmount && matchesDate && matchesIdentity; + }); + + filtered.sort((a, b) => { + switch (sortBy) { + case 'newest': + return b.date.getTime() - a.date.getTime(); + case 'oldest': + return a.date.getTime() - b.date.getTime(); + case 'alphabetical': + return a.name.localeCompare(b.name); + case 'highest': + return b.amount - a.amount; + case 'lowest': + return a.amount - b.amount; + default: + return 0; + } + }); + + return filtered; + }, [backers, searchQuery, sortBy, amountRange, dateRange, identityFilter]); + + const formatDate = (date: Date) => { + const now = new Date(); + const diffInDays = Math.floor( + (now.getTime() - date.getTime()) / (1000 * 60 * 60 * 24) + ); + + if (diffInDays === 0) return 'Today'; + if (diffInDays === 1) return '1d'; + if (diffInDays < 7) return `${diffInDays}d`; + if (diffInDays < 30) return `${Math.floor(diffInDays / 7)}w`; + return format(date, 'MMM dd, yyyy'); + }; + + return ( + +
+
+ {/* Search and Controls */} +
+
+ + setSearchQuery(e.target.value)} + className='pl-10 py-5 placeholder:font-medium bg-muted/20 border-muted-foreground/20 text-white placeholder:text-muted-foreground' + /> +
+ + + + + + +
+ {/* Date Range Section */} +
+
+

+ Date range +

+ +
+
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+
+ + + +
+
+
+ + {/* Amount Range Section */} +
+
+

+ Amount range +

+ +
+
+
+
+ +
+ + + setAmountRange([ + Number.parseInt(e.target.value) || 0, + amountRange[1], + ]) + } + className='bg-muted/20 border-muted-foreground/20 text-white pl-8' + /> +
+
+
+ +
+ + + setAmountRange([ + amountRange[0], + Number.parseInt(e.target.value) || 0, + ]) + } + className='bg-muted/20 border-muted-foreground/20 text-white pl-8' + /> +
+
+
+ +
+
+ + {/* Identity Type Section */} +
+
+

+ Identity Type +

+ +
+
+ + + +
+
+ + {/* Action Buttons */} +
+ + +
+
+
+
+
+ + {/* Filters Panel */} + {showFilters && ( +
+ {/* Sort Options */} +
+
+ + +
+ +
+
+ )} + + {/* Results Header */} +
+
Backer
+
Amount
+
Date
+
+ + {/* Backing List */} +
+ {filteredAndSortedBackers.map(backer => ( +
+
+
+ + + + {backer.isAnonymous ? ( + + ) : ( + backer.name.charAt(0) + )} + + +
+ +
+
+
+
{backer.name}
+
+ + {backer.walletId} +
+
+
+
+ ${backer.amount.toLocaleString()} +
+
+ {formatDate(backer.date)} +
+
+ ))} +
+ + {filteredAndSortedBackers.length === 0 && ( +
+ No backers found matching your criteria +
+ )} +
+
+
+ ); +}; + +export default BackingHistory; diff --git a/lib/data/backing-history-mock.ts b/lib/data/backing-history-mock.ts deleted file mode 100644 index 3de9417e2..000000000 --- a/lib/data/backing-history-mock.ts +++ /dev/null @@ -1,142 +0,0 @@ -import type { BackingHistoryItem } from '@/types/backing-history'; - -export const mockBackingHistory: BackingHistoryItem[] = [ - { - id: '1', - backer: { - name: 'Collins Odumeje', - isAnonymous: false, - avatar: '/diverse-user-avatars.png', - walletAddress: 'GDS3...GB7', - }, - amount: 2300, - currency: 'USDT', - date: new Date('2025-08-17'), - timeAgo: '3s', - }, - { - id: '2', - backer: { - name: 'Sarah Chen', - isAnonymous: false, - avatar: '/diverse-user-avatars.png', - walletAddress: 'ABC1...XYZ', - }, - amount: 1500, - currency: 'USDT', - date: new Date('2025-08-16'), - timeAgo: '1d', - }, - { - id: '3', - backer: { - name: 'Anonymous', - isAnonymous: true, - avatar: '/anonymous-user-concept.png', - walletAddress: 'DEF4...789', - }, - amount: 5000, - currency: 'USDT', - date: new Date('2025-08-15'), - timeAgo: '2d', - }, - { - id: '4', - backer: { - name: 'Michael Rodriguez', - isAnonymous: false, - avatar: '/diverse-user-avatars.png', - walletAddress: 'HIJ7...456', - }, - amount: 750, - currency: 'USDT', - date: new Date('2025-08-14'), - timeAgo: '3d', - }, - { - id: '5', - backer: { - name: 'Anonymous', - isAnonymous: true, - avatar: '/anonymous-user-concept.png', - walletAddress: 'KLM0...123', - }, - amount: 3200, - currency: 'USDT', - date: new Date('2025-08-13'), - timeAgo: '4d', - }, - { - id: '6', - backer: { - name: 'Emma Thompson', - isAnonymous: false, - avatar: '/diverse-user-avatars.png', - walletAddress: 'NOP3...890', - }, - amount: 1800, - currency: 'USDT', - date: new Date('2025-08-12'), - timeAgo: '5d', - }, - { - id: '7', - backer: { - name: 'David Kim', - isAnonymous: false, - avatar: '/diverse-user-avatars.png', - walletAddress: 'QRS6...567', - }, - amount: 4500, - currency: 'USDT', - date: new Date('2025-08-11'), - timeAgo: '6d', - }, - { - id: '8', - backer: { - name: 'Anonymous', - isAnonymous: true, - avatar: '/anonymous-user-concept.png', - walletAddress: 'TUV9...234', - }, - amount: 950, - currency: 'USDT', - date: new Date('2025-08-10'), - timeAgo: '1w', - }, - { - id: '9', - backer: { - name: 'Lisa Wang', - isAnonymous: false, - avatar: '/diverse-user-avatars.png', - walletAddress: 'WXY2...901', - }, - amount: 2750, - currency: 'USDT', - date: new Date('2025-08-09'), - timeAgo: '1w', - }, - { - id: '10', - backer: { - name: 'Anonymous', - isAnonymous: true, - avatar: '/anonymous-user-concept.png', - walletAddress: 'ZAB5...678', - }, - amount: 6200, - currency: 'USDT', - date: new Date('2025-08-08'), - timeAgo: '1w', - }, -]; - -export const sortOptions = [ - { value: 'newest', label: 'Newest first' }, - { value: 'oldest', label: 'Oldest first' }, - { value: 'alphabetical', label: 'Alphabetical' }, - { value: 'amount-high', label: 'Highest first' }, - { value: 'amount-low', label: 'Lowest first' }, -]; diff --git a/types/backing-history.ts b/types/backing-history.ts deleted file mode 100644 index 054c4506b..000000000 --- a/types/backing-history.ts +++ /dev/null @@ -1,32 +0,0 @@ -export interface BackingHistoryItem { - id: string; - backer: { - name: string; - isAnonymous: boolean; - avatar?: string; - walletAddress: string; - }; - amount: number; - currency: string; - date: Date; - timeAgo: string; -} - -export interface BackingHistoryFilters { - searchQuery: string; - sortBy: 'newest' | 'oldest' | 'alphabetical' | 'amount-high' | 'amount-low'; - dateRange: { - from: Date | null; - to: Date | null; - }; - amountRange: { - min: number; - max: number; - }; - identityType: 'all' | 'identified' | 'anonymous'; -} - -export interface BackingHistorySortOption { - value: string; - label: string; -} From 1642230f1b8497bc6cee74c95134a31469095bd4 Mon Sep 17 00:00:00 2001 From: Benjtalkshow Date: Sun, 24 Aug 2025 00:51:34 +0100 Subject: [PATCH 05/10] fix: link backing history flow --- app/user/backing-history/page.tsx | 109 ---------- components/campaigns/CampaignTable.tsx | 10 +- .../back-project/back-project-form.tsx | 201 ++++++++++++++++++ components/campaigns/back-project/index.tsx | 112 ++++++++++ .../project-submission-loading.tsx | 15 ++ .../backing-history/backing-history-table.tsx | 0 .../backing-history/backing-history.tsx | 0 .../backing-history/filter-popover.tsx | 0 .../backing-history/index.tsx | 1 + .../backing-history/sort-filter-popover.tsx | 0 lib/data/backing-history-mock.ts | 163 +++++--------- 11 files changed, 388 insertions(+), 223 deletions(-) delete mode 100644 app/user/backing-history/page.tsx create mode 100644 components/campaigns/back-project/back-project-form.tsx create mode 100644 components/campaigns/back-project/index.tsx create mode 100644 components/campaigns/back-project/project-submission-loading.tsx rename components/{flows => campaigns}/backing-history/backing-history-table.tsx (100%) rename components/{flows => campaigns}/backing-history/backing-history.tsx (100%) rename components/{flows => campaigns}/backing-history/filter-popover.tsx (100%) rename components/{flows => campaigns}/backing-history/index.tsx (98%) rename components/{flows => campaigns}/backing-history/sort-filter-popover.tsx (100%) diff --git a/app/user/backing-history/page.tsx b/app/user/backing-history/page.tsx deleted file mode 100644 index b42193df7..000000000 --- a/app/user/backing-history/page.tsx +++ /dev/null @@ -1,109 +0,0 @@ -'use client'; - -import { useState } from 'react'; -import { Button } from '@/components/ui/button'; -import BackingHistory from '@/components/flows/backing-history/index'; - -// Sample data matching the images -const sampleBackers = [ - { - id: '1', - name: 'Collins Odumeje', - avatar: '/placeholder.svg?height=32&width=32', - amount: 2300, - date: new Date('2025-08-05'), - walletId: 'GDS3...GB7', - isAnonymous: false, - }, - { - id: '2', - name: 'Collins Odumeje', - avatar: '/placeholder.svg?height=32&width=32', - amount: 2300, - date: new Date('2025-08-05'), - walletId: 'GDS3...GB7', - isAnonymous: false, - }, - { - id: '3', - name: 'Collins Odumeje', - avatar: '/placeholder.svg?height=32&width=32', - amount: 2300, - date: new Date('2025-08-05'), - walletId: 'GDS3...GB7', - isAnonymous: false, - }, - { - id: '4', - name: 'Anonymous', - amount: 2300, - date: new Date('2025-08-05'), - walletId: 'GDS3...GB7', - isAnonymous: true, - }, - { - id: '5', - name: 'Collins Odumeje', - avatar: '/placeholder.svg?height=32&width=32', - amount: 2300, - date: new Date('2025-08-05'), - walletId: 'GDS3...GB7', - isAnonymous: false, - }, - { - id: '6', - name: 'Anonymous', - amount: 2300, - date: new Date('2025-08-05'), - walletId: 'GDS3...GB7', - isAnonymous: true, - }, - { - id: '7', - name: 'Anonymous', - amount: 2300, - date: new Date('2025-08-05'), - walletId: 'GDS3...GB7', - isAnonymous: true, - }, - { - id: '8', - name: 'Collins Odumeje', - avatar: '/placeholder.svg?height=32&width=32', - amount: 2300, - date: new Date('2025-08-05'), - walletId: 'GDS3...GB7', - isAnonymous: false, - }, - { - id: '9', - name: 'Anonymous', - amount: 2300, - date: new Date('2025-08-05'), - walletId: 'GDS3...GB7', - isAnonymous: true, - }, -]; - -export default function Home() { - const [showBackingHistory, setShowBackingHistory] = useState(false); - - return ( -
-
- - - -
-
- ); -} diff --git a/components/campaigns/CampaignTable.tsx b/components/campaigns/CampaignTable.tsx index f2a8ee2f0..3cf47c587 100644 --- a/components/campaigns/CampaignTable.tsx +++ b/components/campaigns/CampaignTable.tsx @@ -25,6 +25,8 @@ import { TabFilter, mockApiService, } from '@/lib/data/campaigns-mock'; +import BackingHistory from './backing-history'; +import { sampleBackers } from '@/lib/data/backing-history-mock'; const CampaignRow = ({ campaign, @@ -420,6 +422,7 @@ const CampaignTable = () => { const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [campaignSummaryOpen, setCampaignSummaryOpen] = useState(false); + const [backingHistoryOpen, setBackingHistoryOpen] = useState(false); const [currentPage, setCurrentPage] = useState(1); const [totalPages, setTotalPages] = useState(1); const itemsPerPage = 10; @@ -477,8 +480,8 @@ const CampaignTable = () => { setCampaignSummaryOpen(true); break; case 'view-history': - // TODO: Navigate to history page toast.info('Opening history...'); + setBackingHistoryOpen(true); break; case 'campaign-details': // TODO: Navigate to details page @@ -719,6 +722,11 @@ const CampaignTable = () => { open={campaignSummaryOpen} setOpen={setCampaignSummaryOpen} /> + ); }; diff --git a/components/campaigns/back-project/back-project-form.tsx b/components/campaigns/back-project/back-project-form.tsx new file mode 100644 index 000000000..21c52022d --- /dev/null +++ b/components/campaigns/back-project/back-project-form.tsx @@ -0,0 +1,201 @@ +'use client'; + +import type React from 'react'; +import { useState } from 'react'; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from '@/components/ui/select'; +import { Checkbox } from '@/components/ui/checkbox'; +import { ArrowLeft, Check, Copy } from 'lucide-react'; +import { BoundlessButton } from '@/components/buttons'; + +interface BackProjectFormProps { + onSubmit: (data: { + amount: string; + currency: string; + token: string; + network: string; + walletAddress: string; + keepAnonymous: boolean; + }) => void; + isLoading?: boolean; +} + +const QUICK_AMOUNTS = [10, 20, 30, 50, 100, 500, 1000]; + +export function BackProjectForm({ + onSubmit, + isLoading = false, +}: BackProjectFormProps) { + const [amount, setAmount] = useState(''); + const [currency] = useState('USDT'); + const [token, setToken] = useState(''); + const [network, setNetwork] = useState('Stella / Soroban'); + const [walletAddress] = useState('GDS3...GB7'); + const [keepAnonymous, setKeepAnonymous] = useState(false); + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + onSubmit({ + amount, + currency, + token, + network, + walletAddress, + keepAnonymous, + }); + }; + + const handleQuickAmount = (quickAmount: number) => { + setAmount(quickAmount.toString()); + }; + + const handleCopyAddress = async (e: React.MouseEvent) => { + e.preventDefault(); + try { + await navigator.clipboard.writeText(walletAddress); + // Could add toast notification here instead of state + } catch { + // Fallback for browsers that don't support clipboard API + const textArea = document.createElement('textarea'); + // Silent fallback for older browsers + textArea.value = walletAddress; + document.body.appendChild(textArea); + textArea.select(); + try { + document.execCommand('copy'); + } catch { + // Copy failed, but no need to log in production + } + document.body.removeChild(textArea); + } + }; + + const isFormValid = amount && currency && token && walletAddress; + + return ( +
+
+ +

Back Project

+
+
+
+

+ Funds will be held in escrow and released only upon milestone + approvals. +

+
+ +
+ +
+ {currency} + setAmount(e.target.value)} + type='number' + className='w-full bg-transparent font-normal text-base text-placeholder focus:outline-none' + placeholder='1000' + disabled={isLoading} + /> +
+

min. amount: $10

+ +
+ {QUICK_AMOUNTS.map(quickAmount => ( + + ))} +
+
+ +
+ + +
+ +
+ +
+ setNetwork(e.target.value)} + type='text' + className='w-full bg-transparent font-normal text-base text-placeholder focus:outline-none' + disabled={isLoading} + /> +
+
+ +
+ + + + {walletAddress} + + +
+ +
+ setKeepAnonymous(checked as boolean)} + disabled={isLoading} + className='border-stepper-border data-[state=checked]:bg-primary data-[state=checked]:border-primary' + /> + +
+ + + Confirm Contribution + +
+
+ ); +} diff --git a/components/campaigns/back-project/index.tsx b/components/campaigns/back-project/index.tsx new file mode 100644 index 000000000..c8a3207ba --- /dev/null +++ b/components/campaigns/back-project/index.tsx @@ -0,0 +1,112 @@ +'use client'; + +import { useState } from 'react'; +import { BoundlessButton } from '@/components/buttons'; +import { ProjectSubmissionSuccess } from '@/components/project'; +import BoundlessSheet from '@/components/sheet/boundless-sheet'; +import { ProjectSubmissionLoading } from '@/components/flows/back-project/project-submission-loading'; +import { BackProjectForm } from './back-project-form'; + +type BackProjectState = 'form' | 'loading' | 'success'; + +interface BackProjectData { + amount: string; + currency: string; + token: string; + network: string; + walletAddress: string; + keepAnonymous: boolean; +} + +const BackProject = () => { + const [isSheetOpen, setIsSheetOpen] = useState(false); + const [backProjectState, setBackProjectState] = + useState('form'); + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const handleBackProject = (data: BackProjectData) => { + setBackProjectState('loading'); + // TODO: Send data to actual API endpoint when backend is ready + + // Simulate API call - data will be used when API is implemented + setTimeout(() => { + setBackProjectState('success'); + }, 2000); + }; + + // const handleContinue = () => { + // setIsSheetOpen(false) + // setBackProjectState("form") + // } + + // const handleViewHistory = () => { + // // Navigate to history page or open history modal + // setIsSheetOpen(false) + // // TODO: Implement backing history modal or navigation + // } + + // const handleBack = () => { + // if (backProjectState === "success") { + // setBackProjectState("form") + // } + // } + + const renderSheetContent = () => { + if (backProjectState === 'success') { + return ( +
+
+ {/* */} +
+ +
+ ); + } + + return ( +
+ + + {backProjectState === 'loading' && ( +
+ +
+ )} +
+ ); + }; + + return ( +
+ + {renderSheetContent()} + + + setIsSheetOpen(true)}> + Back Project + +
+ ); +}; + +export default BackProject; diff --git a/components/campaigns/back-project/project-submission-loading.tsx b/components/campaigns/back-project/project-submission-loading.tsx new file mode 100644 index 000000000..4dc27ea2d --- /dev/null +++ b/components/campaigns/back-project/project-submission-loading.tsx @@ -0,0 +1,15 @@ +export function ProjectSubmissionLoading() { + return ( +
+
+ {/* Outer spinning ring */} +
+ {/* Inner spinning arc */} +
+
+

+ Processing your contribution... +

+
+ ); +} diff --git a/components/flows/backing-history/backing-history-table.tsx b/components/campaigns/backing-history/backing-history-table.tsx similarity index 100% rename from components/flows/backing-history/backing-history-table.tsx rename to components/campaigns/backing-history/backing-history-table.tsx diff --git a/components/flows/backing-history/backing-history.tsx b/components/campaigns/backing-history/backing-history.tsx similarity index 100% rename from components/flows/backing-history/backing-history.tsx rename to components/campaigns/backing-history/backing-history.tsx diff --git a/components/flows/backing-history/filter-popover.tsx b/components/campaigns/backing-history/filter-popover.tsx similarity index 100% rename from components/flows/backing-history/filter-popover.tsx rename to components/campaigns/backing-history/filter-popover.tsx diff --git a/components/flows/backing-history/index.tsx b/components/campaigns/backing-history/index.tsx similarity index 98% rename from components/flows/backing-history/index.tsx rename to components/campaigns/backing-history/index.tsx index af9bf4c98..f457a3f33 100644 --- a/components/flows/backing-history/index.tsx +++ b/components/campaigns/backing-history/index.tsx @@ -119,6 +119,7 @@ const BackingHistory: React.FC = ({
+

Backing History

{/* Search and Controls */}
diff --git a/components/flows/backing-history/sort-filter-popover.tsx b/components/campaigns/backing-history/sort-filter-popover.tsx similarity index 100% rename from components/flows/backing-history/sort-filter-popover.tsx rename to components/campaigns/backing-history/sort-filter-popover.tsx diff --git a/lib/data/backing-history-mock.ts b/lib/data/backing-history-mock.ts index 3de9417e2..e20b387a4 100644 --- a/lib/data/backing-history-mock.ts +++ b/lib/data/backing-history-mock.ts @@ -1,142 +1,79 @@ -import type { BackingHistoryItem } from '@/types/backing-history'; - -export const mockBackingHistory: BackingHistoryItem[] = [ +export const sampleBackers = [ { id: '1', - backer: { - name: 'Collins Odumeje', - isAnonymous: false, - avatar: '/diverse-user-avatars.png', - walletAddress: 'GDS3...GB7', - }, + name: 'Collins Odumeje', + avatar: '/placeholder.svg?height=32&width=32', amount: 2300, - currency: 'USDT', - date: new Date('2025-08-17'), - timeAgo: '3s', + date: new Date('2025-08-05'), + walletId: 'GDS3...GB7', + isAnonymous: false, }, { id: '2', - backer: { - name: 'Sarah Chen', - isAnonymous: false, - avatar: '/diverse-user-avatars.png', - walletAddress: 'ABC1...XYZ', - }, - amount: 1500, - currency: 'USDT', - date: new Date('2025-08-16'), - timeAgo: '1d', + name: 'Collins Odumeje', + avatar: '/placeholder.svg?height=32&width=32', + amount: 2300, + date: new Date('2025-08-05'), + walletId: 'GDS3...GB7', + isAnonymous: false, }, { id: '3', - backer: { - name: 'Anonymous', - isAnonymous: true, - avatar: '/anonymous-user-concept.png', - walletAddress: 'DEF4...789', - }, - amount: 5000, - currency: 'USDT', - date: new Date('2025-08-15'), - timeAgo: '2d', + name: 'Collins Odumeje', + avatar: '/placeholder.svg?height=32&width=32', + amount: 2300, + date: new Date('2025-08-05'), + walletId: 'GDS3...GB7', + isAnonymous: false, }, { id: '4', - backer: { - name: 'Michael Rodriguez', - isAnonymous: false, - avatar: '/diverse-user-avatars.png', - walletAddress: 'HIJ7...456', - }, - amount: 750, - currency: 'USDT', - date: new Date('2025-08-14'), - timeAgo: '3d', + name: 'Anonymous', + amount: 2300, + date: new Date('2025-08-05'), + walletId: 'GDS3...GB7', + isAnonymous: true, }, { id: '5', - backer: { - name: 'Anonymous', - isAnonymous: true, - avatar: '/anonymous-user-concept.png', - walletAddress: 'KLM0...123', - }, - amount: 3200, - currency: 'USDT', - date: new Date('2025-08-13'), - timeAgo: '4d', + name: 'Collins Odumeje', + avatar: '/placeholder.svg?height=32&width=32', + amount: 2300, + date: new Date('2025-08-05'), + walletId: 'GDS3...GB7', + isAnonymous: false, }, { id: '6', - backer: { - name: 'Emma Thompson', - isAnonymous: false, - avatar: '/diverse-user-avatars.png', - walletAddress: 'NOP3...890', - }, - amount: 1800, - currency: 'USDT', - date: new Date('2025-08-12'), - timeAgo: '5d', + name: 'Anonymous', + amount: 2300, + date: new Date('2025-08-05'), + walletId: 'GDS3...GB7', + isAnonymous: true, }, { id: '7', - backer: { - name: 'David Kim', - isAnonymous: false, - avatar: '/diverse-user-avatars.png', - walletAddress: 'QRS6...567', - }, - amount: 4500, - currency: 'USDT', - date: new Date('2025-08-11'), - timeAgo: '6d', + name: 'Anonymous', + amount: 2300, + date: new Date('2025-08-05'), + walletId: 'GDS3...GB7', + isAnonymous: true, }, { id: '8', - backer: { - name: 'Anonymous', - isAnonymous: true, - avatar: '/anonymous-user-concept.png', - walletAddress: 'TUV9...234', - }, - amount: 950, - currency: 'USDT', - date: new Date('2025-08-10'), - timeAgo: '1w', + name: 'Collins Odumeje', + avatar: '/placeholder.svg?height=32&width=32', + amount: 2300, + date: new Date('2025-08-05'), + walletId: 'GDS3...GB7', + isAnonymous: false, }, { id: '9', - backer: { - name: 'Lisa Wang', - isAnonymous: false, - avatar: '/diverse-user-avatars.png', - walletAddress: 'WXY2...901', - }, - amount: 2750, - currency: 'USDT', - date: new Date('2025-08-09'), - timeAgo: '1w', - }, - { - id: '10', - backer: { - name: 'Anonymous', - isAnonymous: true, - avatar: '/anonymous-user-concept.png', - walletAddress: 'ZAB5...678', - }, - amount: 6200, - currency: 'USDT', - date: new Date('2025-08-08'), - timeAgo: '1w', + name: 'Anonymous', + amount: 2300, + date: new Date('2025-08-05'), + walletId: 'GDS3...GB7', + isAnonymous: true, }, ]; - -export const sortOptions = [ - { value: 'newest', label: 'Newest first' }, - { value: 'oldest', label: 'Oldest first' }, - { value: 'alphabetical', label: 'Alphabetical' }, - { value: 'amount-high', label: 'Highest first' }, - { value: 'amount-low', label: 'Lowest first' }, -]; From a6a09e71923488b9b181d2bfce1584c95e8757f7 Mon Sep 17 00:00:00 2001 From: Benjtalkshow Date: Sun, 24 Aug 2025 01:05:15 +0100 Subject: [PATCH 06/10] fix: lint back project flow --- components/campaigns/CampaignTable.tsx | 13 ++++++++ components/campaigns/back-project/index.tsx | 36 ++++++++++----------- 2 files changed, 30 insertions(+), 19 deletions(-) diff --git a/components/campaigns/CampaignTable.tsx b/components/campaigns/CampaignTable.tsx index 3cf47c587..defd95ba2 100644 --- a/components/campaigns/CampaignTable.tsx +++ b/components/campaigns/CampaignTable.tsx @@ -27,6 +27,7 @@ import { } from '@/lib/data/campaigns-mock'; import BackingHistory from './backing-history'; import { sampleBackers } from '@/lib/data/backing-history-mock'; +import BackProject from './back-project'; const CampaignRow = ({ campaign, @@ -156,6 +157,12 @@ const CampaignRow = ({ > {campaign.status === 'live' && ( <> + handleAction('back-project')} + className='text-white font-medium hover:!text-white text-sm py-2 px-3 rounded-md hover:!bg-[#2B2B2B] hover:shadow-[0_1px_4px_0_rgba(40,45,40,0.04),_0_0_24px_1px_rgba(10,15,10,0.14)] transition-colors duration-200 cursor-pointer' + > + Back Project + handleAction('share')} className='text-white font-medium hover:!text-white text-sm py-2 px-3 rounded-md hover:!bg-[#2B2B2B] hover:shadow-[0_1px_4px_0_rgba(40,45,40,0.04),_0_0_24px_1px_rgba(10,15,10,0.14)] transition-colors duration-200 cursor-pointer' @@ -423,6 +430,7 @@ const CampaignTable = () => { const [error, setError] = useState(null); const [campaignSummaryOpen, setCampaignSummaryOpen] = useState(false); const [backingHistoryOpen, setBackingHistoryOpen] = useState(false); + const [backingProjectOpen, setBackingProjectOpen] = useState(false); const [currentPage, setCurrentPage] = useState(1); const [totalPages, setTotalPages] = useState(1); const itemsPerPage = 10; @@ -483,6 +491,10 @@ const CampaignTable = () => { toast.info('Opening history...'); setBackingHistoryOpen(true); break; + case 'back-project': + toast.info('Opening back project...'); + setBackingProjectOpen(true); + break; case 'campaign-details': // TODO: Navigate to details page toast.info('Opening details...'); @@ -727,6 +739,7 @@ const CampaignTable = () => { setOpen={setBackingHistoryOpen} backers={sampleBackers} /> +
); }; diff --git a/components/campaigns/back-project/index.tsx b/components/campaigns/back-project/index.tsx index c8a3207ba..8b226e5e9 100644 --- a/components/campaigns/back-project/index.tsx +++ b/components/campaigns/back-project/index.tsx @@ -1,7 +1,7 @@ 'use client'; import { useState } from 'react'; -import { BoundlessButton } from '@/components/buttons'; +// import { BoundlessButton } from '@/components/buttons'; import { ProjectSubmissionSuccess } from '@/components/project'; import BoundlessSheet from '@/components/sheet/boundless-sheet'; import { ProjectSubmissionLoading } from '@/components/flows/back-project/project-submission-loading'; @@ -18,8 +18,12 @@ interface BackProjectData { keepAnonymous: boolean; } -const BackProject = () => { - const [isSheetOpen, setIsSheetOpen] = useState(false); +interface BackingProjectProps { + open: boolean; + setOpen: (open: boolean) => void; +} +const BackProject = ({ open, setOpen }: BackingProjectProps) => { + // const [isSheetOpen, setIsSheetOpen] = useState(false); const [backProjectState, setBackProjectState] = useState('form'); @@ -90,22 +94,16 @@ const BackProject = () => { }; return ( -
- - {renderSheetContent()} - - - setIsSheetOpen(true)}> - Back Project - -
+ + {renderSheetContent()} + ); }; From 6efefa19354398d96e1a42a4b0f435c2be28a159 Mon Sep 17 00:00:00 2001 From: Benjtalkshow Date: Sun, 24 Aug 2025 13:15:04 +0100 Subject: [PATCH 07/10] fix: remove flows folder --- components/campaigns/back-project/index.tsx | 2 +- .../backing-history/backing-history.tsx | 506 ------------------ .../flows/back-project/back-project-form.tsx | 201 ------- components/flows/back-project/index.tsx | 112 ---- .../project-submission-loading.tsx | 15 - .../flows/backing-history/backing-history.tsx | 506 ------------------ 6 files changed, 1 insertion(+), 1341 deletions(-) delete mode 100644 components/campaigns/backing-history/backing-history.tsx delete mode 100644 components/flows/back-project/back-project-form.tsx delete mode 100644 components/flows/back-project/index.tsx delete mode 100644 components/flows/back-project/project-submission-loading.tsx delete mode 100644 components/flows/backing-history/backing-history.tsx diff --git a/components/campaigns/back-project/index.tsx b/components/campaigns/back-project/index.tsx index c8a3207ba..9d89eee73 100644 --- a/components/campaigns/back-project/index.tsx +++ b/components/campaigns/back-project/index.tsx @@ -4,7 +4,7 @@ import { useState } from 'react'; import { BoundlessButton } from '@/components/buttons'; import { ProjectSubmissionSuccess } from '@/components/project'; import BoundlessSheet from '@/components/sheet/boundless-sheet'; -import { ProjectSubmissionLoading } from '@/components/flows/back-project/project-submission-loading'; +import { ProjectSubmissionLoading } from './project-submission-loading'; import { BackProjectForm } from './back-project-form'; type BackProjectState = 'form' | 'loading' | 'success'; diff --git a/components/campaigns/backing-history/backing-history.tsx b/components/campaigns/backing-history/backing-history.tsx deleted file mode 100644 index 6f8e85275..000000000 --- a/components/campaigns/backing-history/backing-history.tsx +++ /dev/null @@ -1,506 +0,0 @@ -'use client'; - -import type React from 'react'; -import { useState, useMemo } from 'react'; -import { - Search, - Filter, - ArrowUpDown, - Calendar, - DollarSign, - User, - Wallet, - Check, - CheckIcon, -} from 'lucide-react'; -import { Button } from '@/components/ui/button'; -import { Input } from '@/components/ui/input'; -import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'; -import { Slider } from '@/components/ui/slider'; -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from '@/components/ui/select'; -import { - Popover, - PopoverContent, - PopoverTrigger, -} from '@/components/ui/popover'; -import { format } from 'date-fns'; -import BoundlessSheet from '@/components/sheet/boundless-sheet'; - -interface Backer { - id: string; - name: string; - avatar?: string; - amount: number; - date: Date; - walletId: string; - isAnonymous: boolean; -} - -interface BackingHistoryProps { - open: boolean; - setOpen: (open: boolean) => void; - backers: Backer[]; -} - -type SortOption = 'newest' | 'oldest' | 'alphabetical' | 'highest' | 'lowest'; -type IdentityFilter = 'all' | 'identified' | 'anonymous'; - -const BackingHistory: React.FC = ({ - open, - setOpen, - backers, -}) => { - const [searchQuery, setSearchQuery] = useState(''); - const [sortBy, setSortBy] = useState('newest'); - const [amountRange, setAmountRange] = useState([0, 10000]); - const [dateRange, setDateRange] = useState<{ from?: Date; to?: Date }>({}); - const [identityFilter, setIdentityFilter] = useState('all'); - const [showFilters, setShowFilters] = useState(false); - const [showSortPopover, setShowSortPopover] = useState(false); - - const setQuickDateFilter = (days: number) => { - const today = new Date(); - const pastDate = new Date(today.getTime() - days * 24 * 60 * 60 * 1000); - setDateRange({ from: pastDate, to: today }); - }; - - const resetFilters = () => { - setSearchQuery(''); - setSortBy('newest'); - setAmountRange([0, 10000]); - setDateRange({}); - setIdentityFilter('all'); - }; - - const resetDateRange = () => { - setDateRange({}); - }; - - const resetAmountRange = () => { - setAmountRange([10, 1000]); - }; - - const resetIdentityFilter = () => { - setIdentityFilter('all'); - }; - - const applyFilters = () => { - setShowSortPopover(false); - }; - - const filteredAndSortedBackers = useMemo(() => { - const filtered = backers.filter(backer => { - const matchesSearch = - backer.name.toLowerCase().includes(searchQuery.toLowerCase()) || - backer.walletId.toLowerCase().includes(searchQuery.toLowerCase()); - - const matchesAmount = - backer.amount >= amountRange[0] && backer.amount <= amountRange[1]; - - const matchesDate = - !dateRange.from || - !dateRange.to || - (backer.date >= dateRange.from && backer.date <= dateRange.to); - - const matchesIdentity = - identityFilter === 'all' || - (identityFilter === 'anonymous' && backer.isAnonymous) || - (identityFilter === 'identified' && !backer.isAnonymous); - - return matchesSearch && matchesAmount && matchesDate && matchesIdentity; - }); - - filtered.sort((a, b) => { - switch (sortBy) { - case 'newest': - return b.date.getTime() - a.date.getTime(); - case 'oldest': - return a.date.getTime() - b.date.getTime(); - case 'alphabetical': - return a.name.localeCompare(b.name); - case 'highest': - return b.amount - a.amount; - case 'lowest': - return a.amount - b.amount; - default: - return 0; - } - }); - - return filtered; - }, [backers, searchQuery, sortBy, amountRange, dateRange, identityFilter]); - - const formatDate = (date: Date) => { - const now = new Date(); - const diffInDays = Math.floor( - (now.getTime() - date.getTime()) / (1000 * 60 * 60 * 24) - ); - - if (diffInDays === 0) return 'Today'; - if (diffInDays === 1) return '1d'; - if (diffInDays < 7) return `${diffInDays}d`; - if (diffInDays < 30) return `${Math.floor(diffInDays / 7)}w`; - return format(date, 'MMM dd, yyyy'); - }; - - return ( - -
-
- {/* Search and Controls */} -
-
- - setSearchQuery(e.target.value)} - className='pl-10 py-5 placeholder:font-medium bg-muted/20 border-muted-foreground/20 text-white placeholder:text-muted-foreground' - /> -
- - - - - - -
- {/* Date Range Section */} -
-
-

- Date range -

- -
-
-
-
- -
- - -
-
-
- -
- - -
-
-
-
- - - -
-
-
- - {/* Amount Range Section */} -
-
-

- Amount range -

- -
-
-
-
- -
- - - setAmountRange([ - Number.parseInt(e.target.value) || 0, - amountRange[1], - ]) - } - className='bg-muted/20 border-muted-foreground/20 text-white pl-8' - /> -
-
-
- -
- - - setAmountRange([ - amountRange[0], - Number.parseInt(e.target.value) || 0, - ]) - } - className='bg-muted/20 border-muted-foreground/20 text-white pl-8' - /> -
-
-
- -
-
- - {/* Identity Type Section */} -
-
-

- Identity Type -

- -
-
- - - -
-
- - {/* Action Buttons */} -
- - -
-
-
-
-
- - {/* Filters Panel */} - {showFilters && ( -
- {/* Sort Options */} -
-
- - -
- -
-
- )} - - {/* Results Header */} -
-
Backer
-
Amount
-
Date
-
- - {/* Backing List */} -
- {filteredAndSortedBackers.map(backer => ( -
-
-
- - - - {backer.isAnonymous ? ( - - ) : ( - backer.name.charAt(0) - )} - - -
- -
-
-
-
{backer.name}
-
- - {backer.walletId} -
-
-
-
- ${backer.amount.toLocaleString()} -
-
- {formatDate(backer.date)} -
-
- ))} -
- - {filteredAndSortedBackers.length === 0 && ( -
- No backers found matching your criteria -
- )} -
-
-
- ); -}; - -export default BackingHistory; diff --git a/components/flows/back-project/back-project-form.tsx b/components/flows/back-project/back-project-form.tsx deleted file mode 100644 index 21c52022d..000000000 --- a/components/flows/back-project/back-project-form.tsx +++ /dev/null @@ -1,201 +0,0 @@ -'use client'; - -import type React from 'react'; -import { useState } from 'react'; -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from '@/components/ui/select'; -import { Checkbox } from '@/components/ui/checkbox'; -import { ArrowLeft, Check, Copy } from 'lucide-react'; -import { BoundlessButton } from '@/components/buttons'; - -interface BackProjectFormProps { - onSubmit: (data: { - amount: string; - currency: string; - token: string; - network: string; - walletAddress: string; - keepAnonymous: boolean; - }) => void; - isLoading?: boolean; -} - -const QUICK_AMOUNTS = [10, 20, 30, 50, 100, 500, 1000]; - -export function BackProjectForm({ - onSubmit, - isLoading = false, -}: BackProjectFormProps) { - const [amount, setAmount] = useState(''); - const [currency] = useState('USDT'); - const [token, setToken] = useState(''); - const [network, setNetwork] = useState('Stella / Soroban'); - const [walletAddress] = useState('GDS3...GB7'); - const [keepAnonymous, setKeepAnonymous] = useState(false); - - const handleSubmit = (e: React.FormEvent) => { - e.preventDefault(); - onSubmit({ - amount, - currency, - token, - network, - walletAddress, - keepAnonymous, - }); - }; - - const handleQuickAmount = (quickAmount: number) => { - setAmount(quickAmount.toString()); - }; - - const handleCopyAddress = async (e: React.MouseEvent) => { - e.preventDefault(); - try { - await navigator.clipboard.writeText(walletAddress); - // Could add toast notification here instead of state - } catch { - // Fallback for browsers that don't support clipboard API - const textArea = document.createElement('textarea'); - // Silent fallback for older browsers - textArea.value = walletAddress; - document.body.appendChild(textArea); - textArea.select(); - try { - document.execCommand('copy'); - } catch { - // Copy failed, but no need to log in production - } - document.body.removeChild(textArea); - } - }; - - const isFormValid = amount && currency && token && walletAddress; - - return ( -
-
- -

Back Project

-
-
-
-

- Funds will be held in escrow and released only upon milestone - approvals. -

-
- -
- -
- {currency} - setAmount(e.target.value)} - type='number' - className='w-full bg-transparent font-normal text-base text-placeholder focus:outline-none' - placeholder='1000' - disabled={isLoading} - /> -
-

min. amount: $10

- -
- {QUICK_AMOUNTS.map(quickAmount => ( - - ))} -
-
- -
- - -
- -
- -
- setNetwork(e.target.value)} - type='text' - className='w-full bg-transparent font-normal text-base text-placeholder focus:outline-none' - disabled={isLoading} - /> -
-
- -
- - - - {walletAddress} - - -
- -
- setKeepAnonymous(checked as boolean)} - disabled={isLoading} - className='border-stepper-border data-[state=checked]:bg-primary data-[state=checked]:border-primary' - /> - -
- - - Confirm Contribution - -
-
- ); -} diff --git a/components/flows/back-project/index.tsx b/components/flows/back-project/index.tsx deleted file mode 100644 index c8a3207ba..000000000 --- a/components/flows/back-project/index.tsx +++ /dev/null @@ -1,112 +0,0 @@ -'use client'; - -import { useState } from 'react'; -import { BoundlessButton } from '@/components/buttons'; -import { ProjectSubmissionSuccess } from '@/components/project'; -import BoundlessSheet from '@/components/sheet/boundless-sheet'; -import { ProjectSubmissionLoading } from '@/components/flows/back-project/project-submission-loading'; -import { BackProjectForm } from './back-project-form'; - -type BackProjectState = 'form' | 'loading' | 'success'; - -interface BackProjectData { - amount: string; - currency: string; - token: string; - network: string; - walletAddress: string; - keepAnonymous: boolean; -} - -const BackProject = () => { - const [isSheetOpen, setIsSheetOpen] = useState(false); - const [backProjectState, setBackProjectState] = - useState('form'); - - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const handleBackProject = (data: BackProjectData) => { - setBackProjectState('loading'); - // TODO: Send data to actual API endpoint when backend is ready - - // Simulate API call - data will be used when API is implemented - setTimeout(() => { - setBackProjectState('success'); - }, 2000); - }; - - // const handleContinue = () => { - // setIsSheetOpen(false) - // setBackProjectState("form") - // } - - // const handleViewHistory = () => { - // // Navigate to history page or open history modal - // setIsSheetOpen(false) - // // TODO: Implement backing history modal or navigation - // } - - // const handleBack = () => { - // if (backProjectState === "success") { - // setBackProjectState("form") - // } - // } - - const renderSheetContent = () => { - if (backProjectState === 'success') { - return ( -
-
- {/* */} -
- -
- ); - } - - return ( -
- - - {backProjectState === 'loading' && ( -
- -
- )} -
- ); - }; - - return ( -
- - {renderSheetContent()} - - - setIsSheetOpen(true)}> - Back Project - -
- ); -}; - -export default BackProject; diff --git a/components/flows/back-project/project-submission-loading.tsx b/components/flows/back-project/project-submission-loading.tsx deleted file mode 100644 index 4dc27ea2d..000000000 --- a/components/flows/back-project/project-submission-loading.tsx +++ /dev/null @@ -1,15 +0,0 @@ -export function ProjectSubmissionLoading() { - return ( -
-
- {/* Outer spinning ring */} -
- {/* Inner spinning arc */} -
-
-

- Processing your contribution... -

-
- ); -} diff --git a/components/flows/backing-history/backing-history.tsx b/components/flows/backing-history/backing-history.tsx deleted file mode 100644 index 6f8e85275..000000000 --- a/components/flows/backing-history/backing-history.tsx +++ /dev/null @@ -1,506 +0,0 @@ -'use client'; - -import type React from 'react'; -import { useState, useMemo } from 'react'; -import { - Search, - Filter, - ArrowUpDown, - Calendar, - DollarSign, - User, - Wallet, - Check, - CheckIcon, -} from 'lucide-react'; -import { Button } from '@/components/ui/button'; -import { Input } from '@/components/ui/input'; -import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'; -import { Slider } from '@/components/ui/slider'; -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from '@/components/ui/select'; -import { - Popover, - PopoverContent, - PopoverTrigger, -} from '@/components/ui/popover'; -import { format } from 'date-fns'; -import BoundlessSheet from '@/components/sheet/boundless-sheet'; - -interface Backer { - id: string; - name: string; - avatar?: string; - amount: number; - date: Date; - walletId: string; - isAnonymous: boolean; -} - -interface BackingHistoryProps { - open: boolean; - setOpen: (open: boolean) => void; - backers: Backer[]; -} - -type SortOption = 'newest' | 'oldest' | 'alphabetical' | 'highest' | 'lowest'; -type IdentityFilter = 'all' | 'identified' | 'anonymous'; - -const BackingHistory: React.FC = ({ - open, - setOpen, - backers, -}) => { - const [searchQuery, setSearchQuery] = useState(''); - const [sortBy, setSortBy] = useState('newest'); - const [amountRange, setAmountRange] = useState([0, 10000]); - const [dateRange, setDateRange] = useState<{ from?: Date; to?: Date }>({}); - const [identityFilter, setIdentityFilter] = useState('all'); - const [showFilters, setShowFilters] = useState(false); - const [showSortPopover, setShowSortPopover] = useState(false); - - const setQuickDateFilter = (days: number) => { - const today = new Date(); - const pastDate = new Date(today.getTime() - days * 24 * 60 * 60 * 1000); - setDateRange({ from: pastDate, to: today }); - }; - - const resetFilters = () => { - setSearchQuery(''); - setSortBy('newest'); - setAmountRange([0, 10000]); - setDateRange({}); - setIdentityFilter('all'); - }; - - const resetDateRange = () => { - setDateRange({}); - }; - - const resetAmountRange = () => { - setAmountRange([10, 1000]); - }; - - const resetIdentityFilter = () => { - setIdentityFilter('all'); - }; - - const applyFilters = () => { - setShowSortPopover(false); - }; - - const filteredAndSortedBackers = useMemo(() => { - const filtered = backers.filter(backer => { - const matchesSearch = - backer.name.toLowerCase().includes(searchQuery.toLowerCase()) || - backer.walletId.toLowerCase().includes(searchQuery.toLowerCase()); - - const matchesAmount = - backer.amount >= amountRange[0] && backer.amount <= amountRange[1]; - - const matchesDate = - !dateRange.from || - !dateRange.to || - (backer.date >= dateRange.from && backer.date <= dateRange.to); - - const matchesIdentity = - identityFilter === 'all' || - (identityFilter === 'anonymous' && backer.isAnonymous) || - (identityFilter === 'identified' && !backer.isAnonymous); - - return matchesSearch && matchesAmount && matchesDate && matchesIdentity; - }); - - filtered.sort((a, b) => { - switch (sortBy) { - case 'newest': - return b.date.getTime() - a.date.getTime(); - case 'oldest': - return a.date.getTime() - b.date.getTime(); - case 'alphabetical': - return a.name.localeCompare(b.name); - case 'highest': - return b.amount - a.amount; - case 'lowest': - return a.amount - b.amount; - default: - return 0; - } - }); - - return filtered; - }, [backers, searchQuery, sortBy, amountRange, dateRange, identityFilter]); - - const formatDate = (date: Date) => { - const now = new Date(); - const diffInDays = Math.floor( - (now.getTime() - date.getTime()) / (1000 * 60 * 60 * 24) - ); - - if (diffInDays === 0) return 'Today'; - if (diffInDays === 1) return '1d'; - if (diffInDays < 7) return `${diffInDays}d`; - if (diffInDays < 30) return `${Math.floor(diffInDays / 7)}w`; - return format(date, 'MMM dd, yyyy'); - }; - - return ( - -
-
- {/* Search and Controls */} -
-
- - setSearchQuery(e.target.value)} - className='pl-10 py-5 placeholder:font-medium bg-muted/20 border-muted-foreground/20 text-white placeholder:text-muted-foreground' - /> -
- - - - - - -
- {/* Date Range Section */} -
-
-

- Date range -

- -
-
-
-
- -
- - -
-
-
- -
- - -
-
-
-
- - - -
-
-
- - {/* Amount Range Section */} -
-
-

- Amount range -

- -
-
-
-
- -
- - - setAmountRange([ - Number.parseInt(e.target.value) || 0, - amountRange[1], - ]) - } - className='bg-muted/20 border-muted-foreground/20 text-white pl-8' - /> -
-
-
- -
- - - setAmountRange([ - amountRange[0], - Number.parseInt(e.target.value) || 0, - ]) - } - className='bg-muted/20 border-muted-foreground/20 text-white pl-8' - /> -
-
-
- -
-
- - {/* Identity Type Section */} -
-
-

- Identity Type -

- -
-
- - - -
-
- - {/* Action Buttons */} -
- - -
-
-
-
-
- - {/* Filters Panel */} - {showFilters && ( -
- {/* Sort Options */} -
-
- - -
- -
-
- )} - - {/* Results Header */} -
-
Backer
-
Amount
-
Date
-
- - {/* Backing List */} -
- {filteredAndSortedBackers.map(backer => ( -
-
-
- - - - {backer.isAnonymous ? ( - - ) : ( - backer.name.charAt(0) - )} - - -
- -
-
-
-
{backer.name}
-
- - {backer.walletId} -
-
-
-
- ${backer.amount.toLocaleString()} -
-
- {formatDate(backer.date)} -
-
- ))} -
- - {filteredAndSortedBackers.length === 0 && ( -
- No backers found matching your criteria -
- )} -
-
-
- ); -}; - -export default BackingHistory; From 88c55a18ec6df19b0ef0fbb8fa00fb92861267b8 Mon Sep 17 00:00:00 2001 From: Benjtalkshow Date: Tue, 26 Aug 2025 02:11:51 +0100 Subject: [PATCH 08/10] fix: use same colors from figma --- .../backing-history/filter-popover.tsx | 20 ++++----- .../backing-history/sort-filter-popover.tsx | 42 ++++++++----------- 2 files changed, 28 insertions(+), 34 deletions(-) diff --git a/components/campaigns/backing-history/filter-popover.tsx b/components/campaigns/backing-history/filter-popover.tsx index 686d5db16..eb5fd8a96 100644 --- a/components/campaigns/backing-history/filter-popover.tsx +++ b/components/campaigns/backing-history/filter-popover.tsx @@ -102,7 +102,7 @@ const AdvancedFilterPopover: React.FC = ({ ? format(dateRange.from, 'MM-dd-yy') : '06-04-25' } - className='bg-muted/20 p-5 border-muted-foreground/30 text-white pr-8 cursor-pointer' + className='bg-[#101010] p-5 border-muted-foreground/30 text-white pr-8 cursor-pointer' readOnly /> @@ -135,7 +135,7 @@ const AdvancedFilterPopover: React.FC = ({ ? format(dateRange.to, 'MM-dd-yy') : '06-04-25' } - className='bg-muted/20 p-5 border-muted-foreground/20 text-white pr-8 cursor-pointer' + className='bg-[#101010] p-5 border-muted-foreground/20 text-white pr-8 cursor-pointer' readOnly /> @@ -160,7 +160,7 @@ const AdvancedFilterPopover: React.FC = ({ variant='outline' size='sm' onClick={() => setQuickDateFilter(0)} - className='bg-muted/20 p-5 border-muted-foreground/20 rounded-3xl text-white hover:bg-muted/30 text-xs' + className='bg-[#101010] p-5 border-muted-foreground/20 rounded-3xl text-white hover:bg-muted/30 text-xs' > Today @@ -168,7 +168,7 @@ const AdvancedFilterPopover: React.FC = ({ variant='outline' size='sm' onClick={() => setQuickDateFilter(7)} - className='bg-muted/20 rounded-3xl p-5 border-muted-foreground/20 text-white hover:bg-muted/30 text-xs' + className='bg-[#101010] rounded-3xl p-5 border-muted-foreground/20 text-white hover:bg-muted/30 text-xs' > Last 7 days @@ -176,7 +176,7 @@ const AdvancedFilterPopover: React.FC = ({ variant='outline' size='sm' onClick={() => setQuickDateFilter(30)} - className='bg-muted/20 rounded-3xl p-5 border-muted-foreground/20 text-white hover:bg-muted/30 text-xs' + className='bg-[#101010] rounded-3xl p-5 border-muted-foreground/20 text-white hover:bg-muted/30 text-xs' > Last month @@ -211,7 +211,7 @@ const AdvancedFilterPopover: React.FC = ({ amountRange[1], ]) } - className='bg-muted/20 border-muted-foreground/20 text-white pl-8 p-5' + className='bg-[#101010] border-muted-foreground/20 text-white pl-8 p-5' />
@@ -227,7 +227,7 @@ const AdvancedFilterPopover: React.FC = ({ Number.parseInt(e.target.value) || 0, ]) } - className='bg-muted/20 border-muted-foreground/20 text-white pl-8 p-5' + className='bg-[#101010] border-muted-foreground/20 text-white pl-8 p-5' /> @@ -262,7 +262,7 @@ const AdvancedFilterPopover: React.FC = ({ onClick={() => setIdentityFilter('all')} className={`w-full justify-between bg-transparent p-5 border-none text-white hover:bg-muted/30 ${ identityFilter === 'all' - ? 'bg-muted/40 border-muted-foreground/20' + ? 'bg-[#2b2b2b] border-muted-foreground/20' : '' }`} > @@ -274,7 +274,7 @@ const AdvancedFilterPopover: React.FC = ({ onClick={() => setIdentityFilter('identified')} className={`w-full justify-start p-5 bg-transparent border-none text-white hover:bg-muted/30 ${ identityFilter === 'identified' - ? 'bg-muted/40 border-muted-foreground/20' + ? 'bg-[#2b2b2b] border-muted-foreground/20' : '' }`} > @@ -299,7 +299,7 @@ const AdvancedFilterPopover: React.FC = ({ diff --git a/components/campaigns/backing-history/sort-filter-popover.tsx b/components/campaigns/backing-history/sort-filter-popover.tsx index ecb0629bc..98f2a7d7c 100644 --- a/components/campaigns/backing-history/sort-filter-popover.tsx +++ b/components/campaigns/backing-history/sort-filter-popover.tsx @@ -48,33 +48,30 @@ const SortFilterPopover: React.FC = ({
@@ -85,18 +82,17 @@ const SortFilterPopover: React.FC = ({ Backer name @@ -107,32 +103,30 @@ const SortFilterPopover: React.FC = ({
From ca0102d17f3b4882875fdf842209e7368c581c80 Mon Sep 17 00:00:00 2001 From: Benjtalkshow Date: Tue, 26 Aug 2025 22:45:34 +0100 Subject: [PATCH 09/10] fix: fix responsive designs --- .../backing-history/backing-history-table.tsx | 110 +++++++++--------- .../backing-history/filter-popover.tsx | 23 ++-- .../campaigns/backing-history/index.tsx | 62 +++++----- 3 files changed, 100 insertions(+), 95 deletions(-) diff --git a/components/campaigns/backing-history/backing-history-table.tsx b/components/campaigns/backing-history/backing-history-table.tsx index bbbf3da68..04c0e4c18 100644 --- a/components/campaigns/backing-history/backing-history-table.tsx +++ b/components/campaigns/backing-history/backing-history-table.tsx @@ -36,67 +36,69 @@ const BackingHistoryTable: React.FC = ({ }; return ( - <> - {/* Results Header */} -
-
Backer
-
Amount
-
Date
-
+
+
+ {/* Results Header */} +
+
Backer
+
Amount
+
Date
+
- {/* Backing List */} -
- {backers.map(backer => ( -
-
-
- - - - {backer.isAnonymous ? ( - - ) : ( - backer.name.charAt(0) - )} - - -
- -
-
-
-
- {backer.name} + {/* Backing List */} +
+ {backers.map(backer => ( +
+
+
+ + + + {backer.isAnonymous ? ( + + ) : ( + backer.name.charAt(0) + )} + + +
+ +
-
- - {backer.walletId} +
+
+ {backer.name} +
+
+ + {backer.walletId} +
+
+ ${backer.amount.toLocaleString()} +
+
+ {formatDate(backer.date)} +
-
- ${backer.amount.toLocaleString()} -
-
- {formatDate(backer.date)} -
+ ))} +
+ + {backers.length === 0 && ( +
+ No backers found matching your criteria
- ))} + )}
- - {backers.length === 0 && ( -
- No backers found matching your criteria -
- )} - +
); }; diff --git a/components/campaigns/backing-history/filter-popover.tsx b/components/campaigns/backing-history/filter-popover.tsx index eb5fd8a96..eff70158b 100644 --- a/components/campaigns/backing-history/filter-popover.tsx +++ b/components/campaigns/backing-history/filter-popover.tsx @@ -68,8 +68,9 @@ const AdvancedFilterPopover: React.FC = ({
@@ -87,7 +88,7 @@ const AdvancedFilterPopover: React.FC = ({
-
+
= ({ onOpenChange={setShowFromCalendar} > -
+
= ({
-
+
= ({
-
+
@@ -168,7 +169,7 @@ const AdvancedFilterPopover: React.FC = ({ variant='outline' size='sm' onClick={() => setQuickDateFilter(7)} - className='bg-[#101010] rounded-3xl p-5 border-muted-foreground/20 text-white hover:bg-muted/30 text-xs' + className='bg-[#101010] rounded-3xl p-3 sm:p-5 border-muted-foreground/20 text-white hover:bg-muted/30 text-xs flex-1 sm:flex-none min-w-0' > Last 7 days @@ -176,7 +177,7 @@ const AdvancedFilterPopover: React.FC = ({ variant='outline' size='sm' onClick={() => setQuickDateFilter(30)} - className='bg-[#101010] rounded-3xl p-5 border-muted-foreground/20 text-white hover:bg-muted/30 text-xs' + className='bg-[#101010] rounded-3xl p-3 sm:p-5 border-muted-foreground/20 text-white hover:bg-muted/30 text-xs flex-1 sm:flex-none min-w-0' > Last month @@ -198,7 +199,7 @@ const AdvancedFilterPopover: React.FC = ({
-
+
@@ -295,7 +296,7 @@ const AdvancedFilterPopover: React.FC = ({
{/* Action Buttons */} -
+
+
+
+

+ Campaign Details +

+ +

+ Boundless is a trustless, decentralized application (dApp) + that empowers changemakers and builders to raise funds + transparently without intermediaries. Campaigns are structured + around clearly defined milestones, with funds held in escrow + and released only upon approval. Grant creators can launch + programs with rule-based logic, and applicants can apply with + proposals that go through public validation. The platform is + built on the Stellar blockchain and powered by Soroban smart + contracts to ensure transparency, security, and autonomy. +

+
+
+
+

Milestones

+
+ {milestones.map((milestone, idx) => { + const isExpanded = expandedMilestone === milestone.id; + return ( +
+
+ Milestone {idx + 1}
- {isExpanded && ( -
-
- {milestone.description} +
+
toggle(milestone.id)} + > +
+ {milestone.title || `Milestone ${idx + 1}`}
-
-
- - - {formatDate(milestone.deliveryDate)} - + +
+ {isExpanded && ( +
+
+ {milestone.description}
-
- - $ - {calculateFundAmount( - milestone.fundPercentage - ).toLocaleString()}{' '} - ({milestone.fundPercentage || 0}%) - +
+
+ + + {formatDate(milestone.deliveryDate)} + +
+
+ + $ + {calculateFundAmount( + milestone.fundPercentage + ).toLocaleString()}{' '} + ({milestone.fundPercentage || 0}%) + +
-
- )} + )} +
-
- ); - })} -
-
-
-
-

- Backing History -

- + ); + })} +
-
- {backingHistory.map(backer => ( -
+
+

+ Backing History +

+ +
+
+ {backingHistory.map(backer => ( +
+
+
+ + + + {backer.name.charAt(0)} + + + {backer.isVerified && ( +
+ +
+ )} +
+
+
+ {backer.name} +
+
+ + {backer.wallet}
- )} -
-
-
- {backer.name}
-
- - {backer.wallet} +
+
+
+ ${backer.amount.toLocaleString()}
-
-
-
- ${backer.amount.toLocaleString()} +
+
+ {backer.time} +
-
-
{backer.time}
-
-
- ))} + ))} +
+
-
-
- + + ); };