From b3de91de4dd2ba7770bf912cdba7ccc442eee7b3 Mon Sep 17 00:00:00 2001 From: "Builder.io" Date: Sat, 15 Nov 2025 09:25:33 +0000 Subject: [PATCH] Create PostedOpportunitiesWidget for NEXUS Client cgen-90c1b2c496e9467a82a6349daedf6b13 --- .../components/PostedOpportunitiesWidget.tsx | 241 ++++++++++++++++++ 1 file changed, 241 insertions(+) create mode 100644 client/components/PostedOpportunitiesWidget.tsx diff --git a/client/components/PostedOpportunitiesWidget.tsx b/client/components/PostedOpportunitiesWidget.tsx new file mode 100644 index 00000000..b08ccbcd --- /dev/null +++ b/client/components/PostedOpportunitiesWidget.tsx @@ -0,0 +1,241 @@ +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { Badge } from "@/components/ui/badge"; +import { Button } from "@/components/ui/button"; +import { Briefcase, AlertCircle, BarChart3, Clock, Users, DollarSign, ArrowRight } from "lucide-react"; + +export interface PostedOpportunity { + id: string; + title: string; + description?: string; + category?: string; + budget?: number; + status: "open" | "in_progress" | "closed" | "paused"; + applications_count?: number; + created_at?: string; + deadline?: string; + required_skills?: string[]; + experience_level?: string; +} + +interface PostedOpportunitiesWidgetProps { + opportunities: PostedOpportunity[]; + title?: string; + description?: string; + onViewDetails?: (oppId: string) => void; + onEdit?: (oppId: string) => void; + onViewApplications?: (oppId: string) => void; + accentColor?: "blue" | "purple" | "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", + }, + blue: { + bg: "bg-gradient-to-br from-blue-950/40 to-blue-900/20", + border: "border-blue-500/20", + }, + cyan: { + bg: "bg-gradient-to-br from-cyan-950/40 to-cyan-900/20", + border: "border-cyan-500/20", + }, + green: { + bg: "bg-gradient-to-br from-green-950/40 to-green-900/20", + border: "border-green-500/20", + }, + amber: { + bg: "bg-gradient-to-br from-amber-950/40 to-amber-900/20", + border: "border-amber-500/20", + }, + red: { + bg: "bg-gradient-to-br from-red-950/40 to-red-900/20", + border: "border-red-500/20", + }, +}; + +const statusBadge = { + open: "bg-green-600/50 text-green-100", + in_progress: "bg-blue-600/50 text-blue-100", + paused: "bg-yellow-600/50 text-yellow-100", + closed: "bg-gray-600/50 text-gray-100", +}; + +export function PostedOpportunitiesWidget({ + opportunities, + title = "My Posted Opportunities", + description = "Manage your job postings", + onViewDetails, + onEdit, + onViewApplications, + accentColor = "blue", +}: PostedOpportunitiesWidgetProps) { + const colors = colorMap[accentColor]; + + return ( + + + + + {title} + + {description} + + + {opportunities.length === 0 ? ( +
+ +

No opportunities posted yet

+

+ Start by posting a job opportunity to find talented creators +

+
+ ) : ( +
+ {/* Stats Summary */} +
+
+

Total Posted

+

{opportunities.length}

+
+
+

Open

+

+ {opportunities.filter(o => o.status === "open").length} +

+
+
+

In Progress

+

+ {opportunities.filter(o => o.status === "in_progress").length} +

+
+
+

Total Applicants

+

+ {opportunities.reduce((sum, o) => sum + (o.applications_count || 0), 0)} +

+
+
+ + {/* Opportunities List */} +
+ {opportunities.map((opp) => ( +
+ {/* Header */} +
+
+

+ {opp.title} +

+ {opp.category && ( +

{opp.category}

+ )} +
+ + {opp.status} + +
+ + {/* Description */} + {opp.description && ( +

+ {opp.description} +

+ )} + + {/* Skills */} + {opp.required_skills && opp.required_skills.length > 0 && ( +
+ {opp.required_skills.slice(0, 3).map((skill) => ( + + {skill} + + ))} + {opp.required_skills.length > 3 && ( + + +{opp.required_skills.length - 3} + + )} +
+ )} + + {/* Meta Information */} +
+ {opp.budget && ( +
+ + ${opp.budget.toLocaleString()} +
+ )} + {opp.experience_level && ( +
+ + {opp.experience_level} +
+ )} + {opp.deadline && ( +
+ + Due {new Date(opp.deadline).toLocaleDateString()} +
+ )} + {opp.applications_count !== undefined && ( +
+ + {opp.applications_count} {opp.applications_count === 1 ? "application" : "applications"} +
+ )} +
+ + {/* Actions */} +
+ {onViewApplications && opp.applications_count! > 0 && ( + + )} + {onViewDetails && ( + + )} + {onEdit && ( + + )} +
+
+ ))} +
+
+ )} +
+
+ ); +} + +export default PostedOpportunitiesWidget;