diff --git a/app/globals.css b/app/globals.css
index a5c68ecf0..e57eb72d1 100644
--- a/app/globals.css
+++ b/app/globals.css
@@ -173,3 +173,16 @@ button {
.slim-scrollbar::-webkit-scrollbar-track {
background-color: transparent;
}
+
+/* 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/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 (
+
+
+
+
+
+ Funds will be held in escrow and released only upon milestone
+ approvals.
+
+
+
+
+
+ Amount *
+
+
+ {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 => (
+ handleQuickAmount(quickAmount)}
+ className='px-3 py-1 text-sm bg-stepper-foreground border border-stepper-border text-card rounded-[8px] hover:bg-stepper-foreground/80 transition-colors'
+ disabled={isLoading}
+ >
+ ${quickAmount}
+
+ ))}
+
+
+
+
+
+ Select Token *
+
+
+
+
+
+
+ XLM
+ USDT
+ USDC
+
+
+
+
+
+
+ Network *
+
+
+ setNetwork(e.target.value)}
+ type='text'
+ className='w-full bg-transparent font-normal text-base text-placeholder focus:outline-none'
+ disabled={isLoading}
+ />
+
+
+
+
+
+ Wallet Address *
+
+
+
+ {walletAddress}
+
+
+
+
+
+ setKeepAnonymous(checked as boolean)}
+ disabled={isLoading}
+ className='border-stepper-border data-[state=checked]:bg-primary data-[state=checked]:border-primary'
+ />
+
+ Keep me anonymous
+
+
+
+
+ Confirm Contribution
+
+
+
+ );
+}
diff --git a/components/flows/back-project/index.tsx b/components/flows/back-project/index.tsx
new file mode 100644
index 000000000..972d5a0e9
--- /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}
+
-
+
- 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}
+
-
+
Continue
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;
+}