From e67ee9ce412a71459c3d03d9a7c7e2fc53c6ef9c Mon Sep 17 00:00:00 2001 From: "Builder.io" Date: Sat, 8 Nov 2025 01:33:58 +0000 Subject: [PATCH] OpportunityCard component for displaying opportunity in grid cgen-2c6b564a7fc040f5b187ff0631eb4dbf --- .../creator-network/OpportunityCard.tsx | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 client/components/creator-network/OpportunityCard.tsx diff --git a/client/components/creator-network/OpportunityCard.tsx b/client/components/creator-network/OpportunityCard.tsx new file mode 100644 index 00000000..67c232ca --- /dev/null +++ b/client/components/creator-network/OpportunityCard.tsx @@ -0,0 +1,106 @@ +import { Card, CardContent } from "@/components/ui/card"; +import { Button } from "@/components/ui/button"; +import { Avatar, AvatarImage, AvatarFallback } from "@/components/ui/avatar"; +import { ArmBadge } from "./ArmBadge"; +import { DollarSign, Clock, Briefcase, ArrowRight } from "lucide-react"; +import { useNavigate } from "react-router-dom"; +import type { Opportunity } from "@/api/opportunities"; + +export interface OpportunityCardProps { + opportunity: Opportunity; +} + +export function OpportunityCard({ opportunity }: OpportunityCardProps) { + const navigate = useNavigate(); + const poster = opportunity.aethex_creators; + + const formatDate = (dateString: string) => { + const date = new Date(dateString); + const now = new Date(); + const diffMs = now.getTime() - date.getTime(); + const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24)); + + if (diffDays === 0) return "Today"; + if (diffDays === 1) return "Yesterday"; + if (diffDays < 7) return `${diffDays}d ago`; + if (diffDays < 30) return `${Math.floor(diffDays / 7)}w ago`; + return `${Math.floor(diffDays / 30)}m ago`; + }; + + const formatSalary = (min?: number, max?: number) => { + if (!min && !max) return "Not specified"; + if (min && max) return `$${min.toLocaleString()} - $${max.toLocaleString()}`; + if (min) return `$${min.toLocaleString()}+`; + if (max) return `Up to $${max.toLocaleString()}`; + }; + + return ( + + +
+
+ + + {poster.username.charAt(0).toUpperCase()} + +
+

Posted by

+

@{poster.username}

+
+
+
+ {formatDate(opportunity.created_at)} +
+
+ +
+ +
+ +

+ {opportunity.title} +

+ +

+ {opportunity.description} +

+ +
+
+ + {opportunity.job_type} + {opportunity.experience_level && ( + <> + + {opportunity.experience_level} + + )} +
+ {(opportunity.salary_min || opportunity.salary_max) && ( +
+ + {formatSalary(opportunity.salary_min, opportunity.salary_max)} +
+ )} + {opportunity.aethex_applications && ( +
+ + {opportunity.aethex_applications.count}{" "} + {opportunity.aethex_applications.count === 1 ? "applicant" : "applicants"} +
+ )} +
+ +
+ +
+
+
+ ); +}