From 93474f2b2c3908a3ac31cf84c3d401dcd3d78805 Mon Sep 17 00:00:00 2001 From: "Builder.io" Date: Sat, 15 Nov 2025 09:20:45 +0000 Subject: [PATCH] Create reusable Payouts widget component with Stripe Connect cgen-241a86ab85104b0fa43d67c3c5ecfef4 --- client/components/PayoutsWidget.tsx | 231 ++++++++++++++++++++++++++++ 1 file changed, 231 insertions(+) create mode 100644 client/components/PayoutsWidget.tsx diff --git a/client/components/PayoutsWidget.tsx b/client/components/PayoutsWidget.tsx new file mode 100644 index 00000000..85245f20 --- /dev/null +++ b/client/components/PayoutsWidget.tsx @@ -0,0 +1,231 @@ +import { useState } from "react"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { Button } from "@/components/ui/button"; +import { Badge } from "@/components/ui/badge"; +import { DollarSign, AlertCircle, CheckCircle, Clock, ExternalLink } from "lucide-react"; + +export interface PayoutData { + available_for_payout: number; + pending_30_day_clearance: number; + total_earned: number; + stripe_connected: boolean; + stripe_account_id?: string; + last_payout_date?: string; + next_payout_date?: string; + payout_history?: PayoutRecord[]; +} + +export interface PayoutRecord { + id: string; + amount: number; + status: "completed" | "pending" | "failed"; + date: string; + description?: string; +} + +interface PayoutsWidgetProps { + data: PayoutData; + onConnectStripe?: () => void; + onRequestPayout?: () => void; + accentColor?: "purple" | "blue" | "cyan" | "green" | "amber" | "red"; +} + +const colorMap = { + purple: { + bg: "bg-gradient-to-br from-purple-950/40 to-purple-900/20", + border: "border-purple-500/20", + accent: "bg-purple-600 hover:bg-purple-700", + text: "text-purple-300", + }, + blue: { + bg: "bg-gradient-to-br from-blue-950/40 to-blue-900/20", + border: "border-blue-500/20", + accent: "bg-blue-600 hover:bg-blue-700", + text: "text-blue-300", + }, + cyan: { + bg: "bg-gradient-to-br from-cyan-950/40 to-cyan-900/20", + border: "border-cyan-500/20", + accent: "bg-cyan-600 hover:bg-cyan-700", + text: "text-cyan-300", + }, + green: { + bg: "bg-gradient-to-br from-green-950/40 to-green-900/20", + border: "border-green-500/20", + accent: "bg-green-600 hover:bg-green-700", + text: "text-green-300", + }, + amber: { + bg: "bg-gradient-to-br from-amber-950/40 to-amber-900/20", + border: "border-amber-500/20", + accent: "bg-amber-600 hover:bg-amber-700", + text: "text-amber-300", + }, + red: { + bg: "bg-gradient-to-br from-red-950/40 to-red-900/20", + border: "border-red-500/20", + accent: "bg-red-600 hover:bg-red-700", + text: "text-red-300", + }, +}; + +export function PayoutsWidget({ + data, + onConnectStripe, + onRequestPayout, + accentColor = "purple", +}: PayoutsWidgetProps) { + const colors = colorMap[accentColor]; + + if (!data.stripe_connected) { + return ( + + + + + Payout Information + + Manage how you receive payments + + +
+ +
+

Connect Stripe Account

+

+ To receive payouts for completed contracts, you need to connect your Stripe account. +

+
+
+ +
+
+ ); + } + + return ( + + + + + Payout Information + + + {data.stripe_account_id && ( + <>Connected to {data.stripe_account_id} • + )} + Manage your earnings + + + + {/* Main Stats */} +
+ {/* Available for Payout */} +
+

Available for Payout

+

+ ${data.available_for_payout.toLocaleString('en-US', { minimumFractionDigits: 2 })} +

+
+ +
+
+ + {/* Pending Clearance */} +
+

Pending (30-day Clearance)

+

+ ${data.pending_30_day_clearance.toLocaleString('en-US', { minimumFractionDigits: 2 })} +

+

+ Next payout: {data.next_payout_date ? new Date(data.next_payout_date).toLocaleDateString() : "TBD"} +

+
+ + {/* Total Earned */} +
+

Total Earned (All-Time)

+

+ ${data.total_earned.toLocaleString('en-US', { minimumFractionDigits: 2 })} +

+

+ Last payout: {data.last_payout_date ? new Date(data.last_payout_date).toLocaleDateString() : "Never"} +

+
+
+ + {/* Payout History */} + {data.payout_history && data.payout_history.length > 0 && ( +
+

Payout History

+
+ {data.payout_history.map((payout) => ( +
+
+ {payout.status === "completed" ? ( + + ) : payout.status === "pending" ? ( + + ) : ( + + )} +
+

+ ${payout.amount.toLocaleString('en-US', { minimumFractionDigits: 2 })} +

+ {payout.description && ( +

{payout.description}

+ )} +

+ {new Date(payout.date).toLocaleDateString()} +

+
+
+ + {payout.status} + +
+ ))} +
+
+ )} + + {/* Info Box */} +
+

How Payouts Work

+
    +
  • Earnings are available 30 days after contract completion
  • +
  • Payouts are processed on Mondays (if minimum balance met)
  • +
  • Stripe processes payments to your connected bank account
  • +
  • Check your Stripe dashboard for payment tracking
  • +
+
+
+
+ ); +} + +export default PayoutsWidget;