1import { j as jsxRuntimeExports } from "./vendor-react-BoGG1wja.js"; 2import { I as Image, A as Avatar, n as navigate, h as namedRoutes } from "./index-Cn8jK25t.js"; 3import { u as useBreakpoint } from "./useMediaQuery-C69IUzRZ.js"; 4import { F as ForwardRef } from "./PhotoIcon-CgxDqnvo.js"; 5import { F as ForwardRef$1 } from "./ClockIcon-B6vIAdIF.js"; 6import { F as ForwardRef$2 } from "./CurrencyDollarIcon-P1LKg5m9.js"; 7const ChallengeCard = ({ 8 challenge 9}) => { 10 const { 11 isMobile 12 } = useBreakpoint(); 13 const { 14 slug, 15 title, 16 description, 17 coverImage, 18 goalAmount, 19 startDate, 20 endDate, 21 publisher, 22 publishAsNetwork, 23 networks = [], 24 cities = [] 25 } = challenge; 26 const formatCurrency = (amount) => { 27 if (!amount) return "N/A"; 28 return new Intl.NumberFormat("en-US", { 29 style: "currency", 30 currency: "USD", 31 minimumFractionDigits: 0, 32 maximumFractionDigits: 0 33 }).format(amount); 34 }; 35 const formatDate = (timestamp) => { 36 if (!timestamp) return null; 37 const date = new Date(timestamp); 38 return date.toLocaleDateString("en-US", { 39 month: "short", 40 day: "numeric", 41 year: "numeric" 42 }); 43 }; 44 const getDaysRemaining = () => { 45 if (!endDate) return null; 46 const now = (/* @__PURE__ */ new Date()).getTime(); 47 const end = new Date(endDate).getTime(); 48 const diff = end - now; 49 const days = Math.ceil(diff / (1e3 * 60 * 60 * 24)); 50 return days > 0 ? days : 0; 51 }; 52 const daysRemaining = getDaysRemaining(); 53 const publisherDisplay = publishAsNetwork && networks[0] ? { 54 name: networks[0].name, 55 icon: networks[0].img 56 } : publisher; 57 const getChallengeStatus = () => { 58 const now = (/* @__PURE__ */ new Date()).getTime(); 59 if (!startDate && !endDate) return "unknown"; 60 const start = startDate ? new Date(startDate).getTime() : null; 61 const end = endDate ? new Date(endDate).getTime() : null; 62 if (start && now < start) return "upcoming"; 63 if (end && now > end) return "expired"; 64 if (start && now >= start) return "ongoing"; 65 return "unknown"; 66 }; 67 const challengeStatus = getChallengeStatus(); 68 const getStatusConfig = () => { 69 switch (challengeStatus) { 70 case "upcoming": 71 return { 72 label: "Upcoming", 73 bgColor: "bg-brandYellow/20", 74 textColor: "text-brandYellow" 75 }; 76 case "ongoing": 77 return { 78 label: "Ongoing", 79 bgColor: "bg-brandYellow/20", 80 textColor: "text-brandYellow" 81 }; 82 case "expired": 83 return { 84 label: "Expired", 85 bgColor: "bg-brandNeutralMedium/20", 86 textColor: "text-brandNeutralMedium" 87 }; 88 default: 89 return { 90 label: "No Timeline", 91 bgColor: "bg-brandBackgroundBorder/20", 92 textColor: "text-brandNeutralMedium" 93 }; 94 } 95 }; 96 const statusConfig = getStatusConfig(); 97 const getDaysUntilStart = () => { 98 if (!startDate) return null; 99 const now = (/* @__PURE__ */ new Date()).getTime(); 100 const start = new Date(startDate).getTime(); 101 const diff = start - now; 102 const days = Math.ceil(diff / (1e3 * 60 * 60 * 24)); 103 return days > 0 ? days : 0; 104 }; 105 const daysUntilStart = getDaysUntilStart(); 106 const handleViewChallenge = () => { 107 navigate(namedRoutes.challenge({ 108 slug 109 })); 110 }; 111 if (isMobile) { 112 return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { onClick: handleViewChallenge, className: "bg-brandBackgroundBlack hover:bg-brandBackgroundBlack/95 cursor-pointer rounded-2xl p-4 transition-colors", children: [
113 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mb-3", children: coverImage ? /* @__PURE__ */ jsxRuntimeExports.jsx(Image, { src: coverImage, alt: title, className: "h-40 w-full rounded-xl object-cover", showDefaultFallback: true }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-brandBackgroundBorder/50 text-brandNeutralMedium flex h-40 w-full flex-col items-center justify-center rounded-xl", children: [ 114 /* @__PURE__ */ jsxRuntimeExports.jsx(ForwardRef, { className: "mb-1 h-10 w-10" }), 115 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs", children: "No image" }) 116 ] }) }), 117 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mb-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx("h5", { className: "text-brandYellow text-lg font-semibold", children: title }) }), 118 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-brandNeutralMedium mb-3 line-clamp-2 text-sm", children: description }), 119 publisherDisplay && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mb-3 flex items-center", children: [
120 /* @__PURE__ */ jsxRuntimeExports.jsx(Avatar, { src: publisherDisplay.icon, username: publisherDisplay.name, className: "mr-2 h-6 w-6" }), 121 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-brandNeutral text-sm", children: publisherDisplay.name }) 122 ] }), 123 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2", children: [ 124 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between text-sm", children: [ 125 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-brandNeutralMedium", children: "Funds Available:" }), 126 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `font-semibold ${goalAmount ? "text-brandSemanticSuccessStrong" : "text-brandNeutralMedium"}`, children: formatCurrency(goalAmount) }) 127 ] }), 128 (startDate || endDate) && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-brandBackgroundBorder/30 rounded-lg p-2", children: [ 129 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mb-2 flex items-center justify-between", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: `inline-flex items-center gap-1 rounded-full px-2 py-0.5 ${statusConfig.bgColor} ${statusConfig.textColor} text-xs font-semibold`, children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: statusConfig.label }) }) }),
130 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between text-xs", children: [ 131 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 132 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-brandNeutralMedium mb-0.5", children: "Start" }), 133 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-brandNeutral font-medium", children: formatDate(startDate) || "TBD" }) 134 ] }), 135 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "border-brandBackgroundBorder mx-2 flex-1 border-t border-dashed" }), 136 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-right", children: [ 137 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-brandNeutralMedium mb-0.5", children: "End" }), 138 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-brandNeutral font-medium", children: formatDate(endDate) || "TBD" }) 139 ] }) 140 ] }), 141 challengeStatus === "ongoing" && daysRemaining !== null && daysRemaining > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-brandYellow mt-2 flex items-center justify-center text-xs", children: [
142 /* @__PURE__ */ jsxRuntimeExports.jsx(ForwardRef$1, { className: "mr-1 h-3 w-3" }), 143 daysRemaining, 144 " days remaining" 145 ] }), 146 challengeStatus === "upcoming" && daysUntilStart !== null && daysUntilStart > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-brandYellow mt-2 flex items-center justify-center text-xs", children: [ 147 /* @__PURE__ */ jsxRuntimeExports.jsx(ForwardRef$1, { className: "mr-1 h-3 w-3" }), 148 "Starts in ", 149 daysUntilStart, 150 " days" 151 ] }) 152 ] }) 153 ] }), 154 (networks.length > 0 || cities.length > 0) && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-3 flex flex-wrap gap-1", children: [ 155 networks.slice(0, 2).map((network) => /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "bg-brandBackgroundBorder text-brandNeutralMedium rounded-full px-2 py-1 text-xs", children: network.name }, network.id)), 156 cities.slice(0, 2).map((city) => /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "bg-brandBackgroundBorder text-brandNeutralMedium rounded-full px-2 py-1 text-xs", children: city.name }, city.id)) 157 ] }) 158 ] }); 159 } 160 return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { onClick: handleViewChallenge, className: "bg-brandBackgroundBlack hover:bg-brandBackgroundBlack/95 cursor-pointer rounded-2xl p-5 transition-colors", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-5", children: [ 161 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-shrink-0", children: coverImage ? /* @__P
161URE__ */ jsxRuntimeExports.jsx(Image, { src: coverImage, alt: title, className: "h-36 w-36 rounded-xl object-cover", showDefaultFallback: true }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-brandBackgroundBorder/50 text-brandNeutralMedium flex h-36 w-36 flex-col items-center justify-center rounded-xl", children: [ 162 /* @__PURE__ */ jsxRuntimeExports.jsx(ForwardRef, { className: "mb-1 h-10 w-10" }), 163 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs", children: "No image" }) 164 ] }) }), 165 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "min-w-0 flex-1", children: [ 166 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mb-2", children: [ 167 /* @__PURE__ */ jsxRuntimeExports.jsx("h5", { className: "text-brandYellow mb-1 text-xl font-semibold", children: title }), 168 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-brandNeutralMedium line-clamp-1 text-sm", children: description }) 169 ] }), 170 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mb-3 flex items-center justify-between", children: [
171 publisherDisplay && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center", children: [ 172 /* @__PURE__ */ jsxRuntimeExports.jsx(Avatar, { src: publisherDisplay.icon, username: publisherDisplay.name, className: "mr-2 h-6 w-6" }), 173 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-brandNeutral text-sm font-medium", children: publisherDisplay.name }) 174 ] }), 175 (networks.length > 0 || cities.length > 0) && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-wrap gap-1.5", children: [ 176 networks.slice(0, 2).map((network) => /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "bg-brandBackgroundBorder text-brandNeutralMedium rounded-full px-2.5 py-0.5 text-xs", children: network.name }, network.id)), 177 cities.slice(0, 2).map((city) => /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "bg-brandBackgroundBorder text-brandNeutralMedium rounded-full px-2.5 py-0.5 text-xs", children: city.name }, city.id)) 178 ] }) 179 ] }),
180 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-start gap-6", children: [ 181 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-shrink-0", children: [ 182 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-brandNeutralMedium mb-1 flex items-center text-xs", children: [ 183 /* @__PURE__ */ jsxRuntimeExports.jsx(ForwardRef$2, { className: "mr-1 h-4 w-4" }), 184 "Funds Available" 185 ] }), 186 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: `text-lg font-semibold ${goalAmount ? "text-brandSemanticSuccessStrong" : "text-brandNeutralMedium"}`, children: formatCurrency(goalAmount) }) 187 ] }), 188 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1", children: [ 189 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-brandNeutralMedium mb-1 flex items-center justify-between text-xs", children: [ 190 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center", children: [
191 /* @__PURE__ */ jsxRuntimeExports.jsx(ForwardRef$1, { className: "mr-1 h-4 w-4" }), 192 "Timeline" 193 ] }), 194 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: `inline-flex items-center gap-1 rounded-full px-2 py-0.5 ${statusConfig.bgColor} ${statusConfig.textColor} text-xs font-semibold`, children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: statusConfig.label }) }) 195 ] }), 196 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "bg-brandBackgroundBorder/30 rounded-lg px-4 py-2", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-4 text-sm", children: [ 197 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-brandNeutral whitespace-nowrap", children: formatDate(startDate) || "TBD" }), 198 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "border-brandNeutralMedium/30 min-w-[40px] flex-1 border-t-2 border-dashed" }), 199 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-brandNeutral whitespace-nowrap", children: formatDate(endDate) || "TBD" }), 200 challengeStatus === "ongoing" && daysRemaining !== null && daysRemaining > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-brandYellow whitespace-nowrap text-sm font-medium", children: [ 201 daysRemaining, 202 " days remaining" 203 ] }), 204 challengeStatus === "upcoming" && daysUntilStart !== null && daysUntilStart > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-brandYellow whitespace-nowrap text-sm font-medium", children: [ 205 "Starts in ", 206 daysUntilStart, 207 " days" 208 ] }) 209 ] }) }) 210 ] }) 211 ] }) 212 ] }) 213 ] }) }); 214}; 215export { 216 ChallengeCard as C 217};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.