Álvaro Valenzuela Valdes commited on
Commit
4b81263
·
1 Parent(s): 1565213

feat: restore premium search UI and advanced filters with correct syntax

Browse files
Files changed (1) hide show
  1. frontend/components/TenderSearch.tsx +137 -167
frontend/components/TenderSearch.tsx CHANGED
@@ -141,6 +141,7 @@ export default function TenderSearch({ tenders, onSearch, onAnalyze, forceShowFo
141
  <div className="space-y-8 animate-in fade-in slide-in-from-bottom-4 duration-700">
142
  {!selectedTenderForModal ? (
143
  <>
 
144
  <div className={`glass-card rounded-3xl p-8 mb-4 border transition-all duration-500 ${forceShowFollowed ? 'border-purple-500/30 bg-purple-500/5 shadow-[0_0_50px_rgba(168,85,247,0.1)]' : 'border-white/10'}`}>
145
  <div className="mb-6 flex justify-between items-start">
146
  <div>
@@ -169,178 +170,136 @@ export default function TenderSearch({ tenders, onSearch, onAnalyze, forceShowFo
169
  </div>
170
 
171
  {!forceShowFollowed && (
172
- <form onSubmit={handleSearch} className="relative z-10 space-y-4 animate-in slide-in-from-top-4 duration-500">
173
- <div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-6">
174
- <div className="space-y-2 xl:col-span-2">
175
- <label className="text-[10px] uppercase tracking-wider text-slate-500 font-bold px-1">Keyword / Tender Code</label>
 
 
176
  <input
177
  type="text"
178
- placeholder="e.g. Software or 1509-5-L114"
179
- className="w-full bg-white/5 border border-white/10 rounded-xl px-4 py-3 text-white focus:outline-none focus:ring-2 focus:ring-purple-500/40 transition-all"
180
  value={keyword}
181
  onChange={(e) => setKeyword(e.target.value)}
182
  />
183
  </div>
184
- <div className="space-y-2">
185
- <label className="text-[10px] uppercase tracking-wider text-slate-500 font-bold px-1">Buyer name</label>
186
- <input
187
- type="text"
188
- placeholder="e.g. Servicio de Salud"
189
- className="w-full bg-white/5 border border-white/10 rounded-xl px-4 py-3 text-white focus:outline-none focus:ring-2 focus:ring-purple-500/40 transition-all"
190
- value={buyerCode}
191
- onChange={(e) => setBuyerCode(e.target.value)}
192
- />
193
- </div>
194
- <div className="space-y-2">
195
- <label className="text-[10px] uppercase tracking-wider text-slate-500 font-bold px-1">Provider Code</label>
196
- <input
197
- type="text"
198
- placeholder="e.g. 17793"
199
- className="w-full bg-white/5 border border-white/10 rounded-xl px-4 py-3 text-white focus:outline-none focus:ring-2 focus:ring-purple-500/40 transition-all"
200
- value={providerCode}
201
- onChange={(e) => setProviderCode(e.target.value)}
202
- />
203
- </div>
204
- <div className="space-y-2">
205
- <label className="text-[10px] uppercase tracking-wider text-slate-500 font-bold px-1">Org Code</label>
206
- <input
207
- type="text"
208
- placeholder="e.g. 6945"
209
- className="w-full bg-white/5 border border-white/10 rounded-xl px-4 py-3 text-white focus:outline-none focus:ring-2 focus:ring-purple-500/40 transition-all"
210
- value={orgCode}
211
- onChange={(e) => setOrgCode(e.target.value)}
212
- />
213
- </div>
214
- <div className="space-y-2">
215
- <label className="text-[10px] uppercase tracking-wider text-slate-500 font-bold px-1">Status</label>
216
- <select
217
- className="w-full bg-white/5 border border-white/10 rounded-xl px-4 py-3 text-white focus:outline-none focus:ring-2 focus:ring-purple-500/40"
218
- value={status}
219
- onChange={(e) => setStatus(e.target.value)}
220
- >
221
- <option value="">Any state</option>
222
- <option value="activas">Activas (Today)</option>
223
- <option value="5">Publicada (5)</option>
224
- <option value="6">Cerrada (6)</option>
225
- <option value="7">Desierta (7)</option>
226
- <option value="8">Adjudicada (8)</option>
227
- </select>
228
- </div>
229
- <div className="space-y-2">
230
- <label className="text-[10px] uppercase tracking-wider text-slate-500 font-bold px-1">Tender Type</label>
231
- <select
232
- className="w-full bg-white/5 border border-white/10 rounded-xl px-4 py-3 text-white focus:outline-none focus:ring-2 focus:ring-purple-500/40"
233
- value={typeCode}
234
- onChange={(e) => setTypeCode(e.target.value)}
235
- >
236
- <option value="">Any type</option>
237
- <option value="L1">L1 - < 100 UTM</option>
238
- <option value="LE">LE - 100-1000 UTM</option>
239
- <option value="LP">LP - > 1000 UTM</option>
240
- <option value="LS">LS - Servicios Personales</option>
241
- <option value="A1">A1 - Privada por Desierta</option>
242
- </select>
243
- </div>
244
- <div className="space-y-2">
245
- <label className="text-[10px] uppercase tracking-wider text-slate-500 font-bold px-1">Date</label>
246
- <input
247
- type="date"
248
- className="w-full bg-white/5 border border-white/10 rounded-xl px-4 py-3 text-white focus:outline-none focus:ring-2 focus:ring-purple-500/40 [color-scheme:dark]"
249
- value={date}
250
- onChange={(e) => setDate(e.target.value)}
251
- />
252
- </div>
253
- </div>
254
- <div className="rounded-3xl bg-slate-900/70 border border-white/10 p-4 text-slate-400 text-xs flex justify-between items-center">
255
- <div>
256
- <span className="font-bold text-slate-200">Tip:</span> Use Tender Code for exact search or filters for direct live data.
257
  </div>
258
- <button
259
- type="button"
260
- onClick={() => {
261
- setKeyword(""); setBuyerCode(""); setProviderCode(""); setOrgCode(""); setStatus(""); setDate(""); setTypeCode("");
262
- }}
263
- className="text-[10px] font-bold uppercase text-slate-500 hover:text-white transition"
264
- >
265
- Clear All
266
- </button>
267
  </div>
268
- <div className="flex flex-col gap-3 sm:flex-row sm:items-end sm:justify-between">
269
- <div className="flex flex-col gap-2">
270
- <button
271
- type="button"
272
- disabled={isLoading}
273
- onClick={handleSearch}
274
- className="w-full sm:w-auto premium-gradient text-white font-bold py-3.5 rounded-xl px-8 transition-all"
275
- >
276
- {searchButtonLabel}
277
- </button>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
278
  </div>
279
- <button
280
- type="button"
281
- onClick={() => setIsAgileMode(!isAgileMode)}
282
- className={`px-4 py-3.5 rounded-xl border font-bold text-[10px] uppercase tracking-widest transition-all ${isAgileMode ? "bg-cyan/20 border-cyan/40 text-cyan animate-pulse" : "bg-white/5 border-white/10 text-slate-500"}`}
283
- >
284
- 🚀 Agile
285
- </button>
286
- </div>
287
  </form>
288
  )}
289
  </div>
290
 
291
- <div className="flex flex-col gap-3 px-2 md:flex-row md:items-center md:justify-between">
292
- <h3 className="text-lg font-bold text-white">
293
- {showOnlyFollowed ? "Portfolio" : "Market Results"} ({filteredTenders.length})
294
- </h3>
295
- {followedCodes.length > 0 && (
296
- <button
297
- onClick={() => setShowOnlyFollowed(!showOnlyFollowed)}
298
- className={`rounded-xl px-4 py-2 text-xs font-bold border transition-all ${showOnlyFollowed ? "bg-purple-500/20 border-purple-500/40 text-purple-300" : "bg-white/5 border-white/10 text-slate-400"}`}
299
- >
300
- {showOnlyFollowed ? "★ Viewing Portfolio" : "☆ Show Favorites"}
301
- </button>
302
- )}
303
- </div>
304
-
305
  <div className="space-y-4">
 
 
 
 
 
 
 
 
 
306
  {filteredTenders.length === 0 ? (
307
- <div className="flex flex-col items-center justify-center rounded-3xl border border-white/5 bg-white/[0.02] p-20 text-center">
308
- <p className="text-slate-400 text-sm">No opportunities found.</p>
 
309
  </div>
310
  ) : (
311
- <div className="glass-card rounded-3xl overflow-hidden border border-white/5">
312
  <div className="overflow-x-auto custom-scrollbar">
313
  <table className="w-full text-left text-sm table-fixed">
314
  <thead className="bg-white/5 text-slate-500 uppercase text-[10px] font-bold border-b border-white/5">
315
  <tr>
316
- <th className="px-4 py-5 w-[100px]">
317
- <input type="checkbox" checked={selectedCodes.length === filteredTenders.length} onChange={toggleSelectAll} className="mr-2" />
318
- ID
 
 
319
  </th>
320
- <th className="px-4 py-5 w-[250px]">Opportunity</th>
321
- <th className="px-4 py-5 w-[180px]">Buyer</th>
322
- <th className="px-4 py-5 text-center w-[100px]">Status</th>
323
  </tr>
324
  </thead>
325
  <tbody className="divide-y divide-white/5">
326
  {filteredTenders.map((tender) => (
327
  <tr key={tender.code} className="hover:bg-white/[0.04] transition-colors group">
328
- <td className="px-4 py-5">
329
- <div className="flex items-center gap-2">
330
- <input type="checkbox" checked={selectedCodes.includes(tender.code)} onChange={() => toggleSelect(tender.code)} />
331
- <button onClick={() => toggleFollow(tender)} className={followedCodes.includes(tender.code) ? 'text-purple-400' : 'text-slate-600'}>
332
  {followedCodes.includes(tender.code) ? "★" : "☆"}
333
  </button>
334
- <span className="font-mono text-purple-400 text-[9px] truncate">{tender.code}</span>
335
  </div>
336
  </td>
337
- <td className="px-4 py-5 cursor-pointer" onClick={() => setSelectedTenderForModal(tender)}>
338
- <div className="font-semibold text-white group-hover:text-purple-400 transition-colors truncate text-xs">{tender.name}</div>
339
- <div className="text-[9px] text-slate-500">{tender.region || "Nacional"}</div>
340
  </td>
341
- <td className="px-4 py-5 text-slate-400 text-[11px] truncate">{tender.buyer}</td>
342
- <td className="px-4 py-5 text-center">
343
- <span className={`inline-block rounded-full px-2 py-0.5 text-[9px] font-bold ${tender.status.toLowerCase().includes('publicada') ? 'bg-green-500/10 text-green-400' : 'bg-slate-800 text-slate-500'}`}>
344
  {tender.status}
345
  </span>
346
  </td>
@@ -362,58 +321,69 @@ export default function TenderSearch({ tenders, onSearch, onAnalyze, forceShowFo
362
  <span className="text-sm font-bold uppercase tracking-widest">Back to search</span>
363
  </button>
364
  <div className="flex bg-white/5 p-1 rounded-2xl border border-white/10 w-fit">
365
- <button onClick={() => setActiveDetailTab("Overview")} className={`px-6 py-2.5 rounded-xl text-xs font-black uppercase tracking-widest transition-all ${activeDetailTab === "Overview" ? "bg-purple-600 text-white" : "text-slate-500"}`}>Overview</button>
366
- <button onClick={() => setActiveDetailTab("Agent Chat")} className={`px-6 py-2.5 rounded-xl text-xs font-black uppercase tracking-widest transition-all ${activeDetailTab === "Agent Chat" ? "bg-purple-600 text-white" : "text-slate-500"}`}>Agent Chat</button>
367
  </div>
368
  </div>
369
- <button onClick={() => toggleFollow(selectedTenderForModal)} className="px-4 py-3 rounded-lg bg-white/5 border border-white/10 text-xs text-slate-400">
370
- {followedCodes.includes(selectedTenderForModal.code) ? " Saved" : "☆ Save"}
371
- </button>
 
 
 
 
372
  </div>
373
 
374
  {activeDetailTab === "Overview" ? (
375
- <div className="glass-card rounded-[2.5rem] overflow-hidden border border-white/5 bg-slate-900/40 backdrop-blur-xl">
376
  <div className="p-10 md:p-14 border-b border-white/5 relative">
377
- <div className="flex items-center gap-3 mb-6">
378
- <span className="text-sm font-mono text-purple-400 bg-purple-400/10 px-3 py-1 rounded-lg">{selectedTenderForModal.code}</span>
379
- <span className="px-3 py-1 rounded-lg text-xs font-black uppercase bg-green-500/10 text-green-400">{selectedTenderForModal.status}</span>
380
- </div>
381
- <h3 className="text-3xl md:text-4xl font-black text-white leading-tight mb-4">{selectedTenderForModal.name}</h3>
382
- <div className="flex flex-wrap gap-8">
383
- <span className="text-slate-400">🏢 {selectedTenderForModal.buyer}</span>
384
- <span className="text-slate-400">📍 {selectedTenderForModal.buyer_region || "Nacional"}</span>
 
 
 
 
385
  </div>
386
  </div>
387
  <div className="p-10 md:p-14">
388
  <div className="grid gap-16 lg:grid-cols-3">
389
  <div className="lg:col-span-2 space-y-12">
390
  <section>
391
- <h4 className="text-[10px] font-black uppercase tracking-[0.3em] text-slate-500 mb-6">Description</h4>
392
- <div className="text-slate-300 leading-relaxed text-lg bg-white/[0.02] p-8 rounded-[2rem] border border-white/5 whitespace-pre-wrap">
393
- {selectedTenderForModal.description || "No description."}
394
  </div>
395
  </section>
396
  <div className="grid grid-cols-2 gap-6">
397
  <div className="p-6 rounded-3xl bg-white/[0.03] border border-white/5">
398
  <div className="text-[10px] uppercase text-slate-500 font-black mb-2">Estimated Investment</div>
399
- <div className="text-xl text-white font-bold">
400
- {selectedTenderForModal.estimated_amount ? new Intl.NumberFormat("es-CL", { style: "currency", currency: "CLP" }).format(selectedTenderForModal.estimated_amount) : "Not Disclosed"}
401
- </div>
402
  </div>
403
  </div>
404
  </div>
405
  <div className="space-y-12">
406
- <div className="p-8 rounded-[2rem] bg-purple-600/10 border border-purple-500/20">
407
  <h4 className="text-[10px] font-black uppercase tracking-[0.3em] text-purple-400 mb-6">Timeline</h4>
408
  <div className="text-[10px] text-slate-500 font-bold uppercase mb-1">Closing Deadline</div>
409
  <div className="text-2xl font-black text-white font-mono">{selectedTenderForModal.closing_date ? new Date(selectedTenderForModal.closing_date).toLocaleDateString() : "---"}</div>
410
  </div>
411
- <button
412
- onClick={() => { onAnalyze(selectedTenderForModal); setSelectedTenderForModal(null); }}
413
- className="w-full premium-gradient text-white px-8 py-5 rounded-2xl font-black uppercase tracking-widest"
414
- >
415
- Analyze Opportunity
416
- </button>
 
 
 
 
 
417
  </div>
418
  </div>
419
  </div>
 
141
  <div className="space-y-8 animate-in fade-in slide-in-from-bottom-4 duration-700">
142
  {!selectedTenderForModal ? (
143
  <>
144
+ {/* Header Section */}
145
  <div className={`glass-card rounded-3xl p-8 mb-4 border transition-all duration-500 ${forceShowFollowed ? 'border-purple-500/30 bg-purple-500/5 shadow-[0_0_50px_rgba(168,85,247,0.1)]' : 'border-white/10'}`}>
146
  <div className="mb-6 flex justify-between items-start">
147
  <div>
 
170
  </div>
171
 
172
  {!forceShowFollowed && (
173
+ <form onSubmit={handleSearch} className="relative z-10 space-y-6">
174
+ <div className="flex flex-col md:flex-row gap-4">
175
+ <div className="relative flex-1 group">
176
+ <div className="absolute inset-y-0 left-0 pl-4 flex items-center pointer-events-none text-slate-500">
177
+ <span className="text-xl">🔍</span>
178
+ </div>
179
  <input
180
  type="text"
181
+ placeholder={isAgileMode ? "Product keyword for Compra Ágil..." : "Search by name, ID, buyer, or description..."}
182
+ className="w-full bg-slate-900/60 border border-white/10 rounded-2xl pl-12 pr-4 py-4 text-white placeholder:text-slate-600 focus:outline-none focus:ring-2 focus:ring-purple-500/50 transition-all backdrop-blur-sm"
183
  value={keyword}
184
  onChange={(e) => setKeyword(e.target.value)}
185
  />
186
  </div>
187
+
188
+ <div className="flex gap-2">
189
+ <button
190
+ type="button"
191
+ onClick={() => setShowAdvanced(!showAdvanced)}
192
+ className={`px-6 py-4 rounded-2xl border transition-all flex items-center gap-2 font-bold text-sm ${showAdvanced ? 'bg-purple-500/20 border-purple-500/50 text-purple-300' : 'bg-white/5 border-white/10 text-slate-400 hover:bg-white/10'}`}
193
+ >
194
+ <span>⚙️</span> Advanced
195
+ </button>
196
+
197
+ <button
198
+ type="submit"
199
+ disabled={isLoading}
200
+ className="px-8 py-4 bg-purple-600 hover:bg-purple-500 disabled:bg-purple-800 text-white rounded-2xl font-bold transition-all shadow-lg active:scale-95 flex items-center gap-3"
201
+ >
202
+ {isLoading && <div className="w-4 h-4 border-2 border-white/30 border-t-white rounded-full animate-spin" />}
203
+ {searchButtonLabel}
204
+ </button>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
205
  </div>
 
 
 
 
 
 
 
 
 
206
  </div>
207
+
208
+ {showAdvanced && (
209
+ <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 p-6 glass-card rounded-3xl bg-white/[0.02] border border-white/5 animate-in slide-in-from-top-4 duration-300">
210
+ <div className="space-y-2">
211
+ <label className="text-[10px] font-bold uppercase tracking-widest text-slate-500 ml-1">Date</label>
212
+ <input type="date" className="w-full bg-black/40 border border-white/10 rounded-xl px-4 py-2.5 text-white text-sm focus:ring-1 focus:ring-purple-500/50 [color-scheme:dark]" value={date} onChange={(e) => setDate(e.target.value)} />
213
+ </div>
214
+ <div className="space-y-2">
215
+ <label className="text-[10px] font-bold uppercase tracking-widest text-slate-500 ml-1">Organization ID</label>
216
+ <input type="text" placeholder="e.g. 6945" className="w-full bg-black/40 border border-white/10 rounded-xl px-4 py-2.5 text-white text-sm focus:ring-1 focus:ring-purple-500/50" value={orgCode} onChange={(e) => setOrgCode(e.target.value)} />
217
+ </div>
218
+ <div className="space-y-2">
219
+ <label className="text-[10px] font-bold uppercase tracking-widest text-slate-500 ml-1">Status</label>
220
+ <select className="w-full bg-black/40 border border-white/10 rounded-xl px-4 py-2.5 text-white text-sm focus:ring-1 focus:ring-purple-500/50" value={status} onChange={(e) => setStatus(e.target.value)}>
221
+ <option value="">All Statuses</option>
222
+ <option value="activas">Active (Publicada)</option>
223
+ <option value="5">Publicada</option>
224
+ <option value="6">Cerrada</option>
225
+ <option value="7">Desierta</option>
226
+ <option value="8">Adjudicada</option>
227
+ </select>
228
+ </div>
229
+ <div className="space-y-2">
230
+ <label className="text-[10px] font-bold uppercase tracking-widest text-slate-500 ml-1">Tender Type</label>
231
+ <select className="w-full bg-black/40 border border-white/10 rounded-xl px-4 py-2.5 text-white text-sm focus:ring-1 focus:ring-purple-500/50" value={typeCode} onChange={(e) => setTypeCode(e.target.value)}>
232
+ <option value="">All Types</option>
233
+ <option value="L1">L1 - < 100 UTM</option>
234
+ <option value="LE">LE - 100-1000 UTM</option>
235
+ <option value="LP">LP - > 1000 UTM</option>
236
+ <option value="LS">LS - Servicios Personales</option>
237
+ <option value="D1">D1 - Trato Directo</option>
238
+ </select>
239
+ </div>
240
+
241
+ <div className="lg:col-span-4 flex justify-between items-center pt-2">
242
+ <button type="button" onClick={() => setIsAgileMode(!isAgileMode)} className={`px-4 py-2 rounded-xl border text-[10px] font-bold uppercase transition-all ${isAgileMode ? 'bg-cyan/20 border-cyan/40 text-cyan animate-pulse' : 'bg-white/5 border-white/10 text-slate-500'}`}>🚀 Compra Ágil Mode</button>
243
+ <button type="button" onClick={() => { setKeyword(""); setBuyerCode(""); setProviderCode(""); setOrgCode(""); setStatus(""); setDate(""); setTypeCode(""); }} className="text-[10px] font-bold uppercase text-slate-500 hover:text-white transition">Clear Filters</button>
244
+ </div>
245
  </div>
246
+ )}
 
 
 
 
 
 
 
247
  </form>
248
  )}
249
  </div>
250
 
251
+ {/* Results List */}
 
 
 
 
 
 
 
 
 
 
 
 
 
252
  <div className="space-y-4">
253
+ <div className="flex items-center justify-between px-2">
254
+ <h3 className="text-lg font-bold text-white">{showOnlyFollowed ? "Portfolio" : "Market Results"} ({filteredTenders.length})</h3>
255
+ {followedCodes.length > 0 && (
256
+ <button onClick={() => setShowOnlyFollowed(!showOnlyFollowed)} className={`rounded-xl px-4 py-2 text-xs font-bold border transition-all ${showOnlyFollowed ? "bg-purple-500/20 border-purple-500/40 text-purple-300" : "bg-white/5 border-white/10 text-slate-400"}`}>
257
+ {showOnlyFollowed ? "★ Viewing Portfolio" : "☆ Show Favorites"}
258
+ </button>
259
+ )}
260
+ </div>
261
+
262
  {filteredTenders.length === 0 ? (
263
+ <div className="flex flex-col items-center justify-center rounded-3xl border border-white/5 bg-white/[0.02] p-20 text-center text-slate-400">
264
+ <div className="text-4xl mb-4 opacity-50">{showOnlyFollowed ? "🌟" : "📡"}</div>
265
+ <p>No opportunities found.</p>
266
  </div>
267
  ) : (
268
+ <div className="glass-card rounded-3xl overflow-hidden border border-white/5 shadow-2xl">
269
  <div className="overflow-x-auto custom-scrollbar">
270
  <table className="w-full text-left text-sm table-fixed">
271
  <thead className="bg-white/5 text-slate-500 uppercase text-[10px] font-bold border-b border-white/5">
272
  <tr>
273
+ <th className="px-6 py-5 w-[120px]">
274
+ <div className="flex items-center gap-3">
275
+ <input type="checkbox" checked={selectedCodes.length === filteredTenders.length && filteredTenders.length > 0} onChange={toggleSelectAll} className="w-4 h-4 rounded border-white/10 bg-white/5 text-purple-500" />
276
+ ID
277
+ </div>
278
  </th>
279
+ <th className="px-6 py-5 w-[300px]">Opportunity</th>
280
+ <th className="px-6 py-5 w-[200px]">Buyer</th>
281
+ <th className="px-6 py-5 text-center w-[120px]">Status</th>
282
  </tr>
283
  </thead>
284
  <tbody className="divide-y divide-white/5">
285
  {filteredTenders.map((tender) => (
286
  <tr key={tender.code} className="hover:bg-white/[0.04] transition-colors group">
287
+ <td className="px-6 py-5">
288
+ <div className="flex items-center gap-3">
289
+ <input type="checkbox" checked={selectedCodes.includes(tender.code)} onChange={() => toggleSelect(tender.code)} className="w-4 h-4 rounded border-white/10 bg-white/5 text-purple-500" />
290
+ <button onClick={() => toggleFollow(tender)} className={`text-lg transition-all ${followedCodes.includes(tender.code) ? 'text-purple-400' : 'text-slate-600 hover:text-slate-400'}`}>
291
  {followedCodes.includes(tender.code) ? "★" : "☆"}
292
  </button>
293
+ <span className="font-mono text-purple-400 text-[10px] truncate">{tender.code}</span>
294
  </div>
295
  </td>
296
+ <td className="px-6 py-5 cursor-pointer group-hover:text-purple-400 transition-colors" onClick={() => setSelectedTenderForModal(tender)}>
297
+ <div className="font-bold text-white group-hover:text-purple-400 truncate text-xs">{tender.name}</div>
298
+ <div className="text-[10px] text-slate-500 mt-1">{tender.region || "Nacional"}</div>
299
  </td>
300
+ <td className="px-6 py-5 text-slate-400 text-[11px] truncate">{tender.buyer}</td>
301
+ <td className="px-6 py-5 text-center">
302
+ <span className={`inline-block rounded-full px-3 py-1 text-[9px] font-black uppercase tracking-widest ${tender.status.toLowerCase().includes('publicada') ? 'bg-green-500/10 text-green-400 border border-green-500/20' : 'bg-slate-800 text-slate-500'}`}>
303
  {tender.status}
304
  </span>
305
  </td>
 
321
  <span className="text-sm font-bold uppercase tracking-widest">Back to search</span>
322
  </button>
323
  <div className="flex bg-white/5 p-1 rounded-2xl border border-white/10 w-fit">
324
+ <button onClick={() => setActiveDetailTab("Overview")} className={`px-6 py-2.5 rounded-xl text-xs font-black uppercase tracking-widest transition-all ${activeDetailTab === "Overview" ? "bg-purple-600 text-white shadow-lg" : "text-slate-500 hover:text-slate-300"}`}>Overview</button>
325
+ <button onClick={() => setActiveDetailTab("Agent Chat")} className={`px-6 py-2.5 rounded-xl text-xs font-black uppercase tracking-widest transition-all ${activeDetailTab === "Agent Chat" ? "bg-purple-600 text-white shadow-lg" : "text-slate-500 hover:text-slate-300"}`}>Agent Chat</button>
326
  </div>
327
  </div>
328
+
329
+ <div className="flex items-center gap-4">
330
+ <button onClick={() => toggleFollow(selectedTenderForModal)} className={`px-6 py-3 rounded-xl border text-xs font-bold transition-all ${followedCodes.includes(selectedTenderForModal.code) ? 'bg-purple-500/20 border-purple-500/40 text-purple-300' : 'bg-white/5 border-white/10 text-slate-400'}`}>
331
+ {followedCodes.includes(selectedTenderForModal.code) ? "★ Saved to Portfolio" : "☆ Save to Portfolio"}
332
+ </button>
333
+ <button onClick={() => { onAnalyze(selectedTenderForModal); setSelectedTenderForModal(null); }} className="premium-gradient text-white px-8 py-3 rounded-xl font-black text-xs uppercase tracking-widest shadow-xl">Analyze Opportunity</button>
334
+ </div>
335
  </div>
336
 
337
  {activeDetailTab === "Overview" ? (
338
+ <div className="glass-card rounded-[2.5rem] overflow-hidden border border-white/5 bg-slate-900/40 backdrop-blur-xl shadow-2xl">
339
  <div className="p-10 md:p-14 border-b border-white/5 relative">
340
+ <div className="absolute top-0 right-0 w-64 h-64 bg-purple-500/10 blur-[100px] -translate-y-1/2 translate-x-1/2" />
341
+ <div className="relative z-10">
342
+ <div className="flex items-center gap-3 mb-6">
343
+ <span className="text-sm font-mono text-purple-400 bg-purple-400/10 px-3 py-1 rounded-lg border border-purple-400/20">{selectedTenderForModal.code}</span>
344
+ <span className="px-3 py-1 rounded-lg text-xs font-black uppercase bg-green-500/10 text-green-400 border border-green-500/20">{selectedTenderForModal.status}</span>
345
+ </div>
346
+ <h3 className="text-3xl md:text-4xl font-black text-white leading-tight tracking-tight mb-4">{selectedTenderForModal.name}</h3>
347
+ <div className="flex flex-wrap items-center gap-8 text-slate-400 font-medium">
348
+ <span>🏢 {selectedTenderForModal.buyer}</span>
349
+ <span>📍 {selectedTenderForModal.buyer_region || "Nacional"}</span>
350
+ <span>🏷️ Type: {selectedTenderForModal.type || "N/A"}</span>
351
+ </div>
352
  </div>
353
  </div>
354
  <div className="p-10 md:p-14">
355
  <div className="grid gap-16 lg:grid-cols-3">
356
  <div className="lg:col-span-2 space-y-12">
357
  <section>
358
+ <h4 className="text-[10px] font-black uppercase tracking-[0.3em] text-slate-500 mb-6 flex items-center gap-3"><span className="w-8 h-[1px] bg-slate-700" />Project Scope</h4>
359
+ <div className="text-slate-300 leading-relaxed text-lg bg-white/[0.02] p-8 rounded-[2rem] border border-white/5 whitespace-pre-wrap font-light">
360
+ {selectedTenderForModal.description || "No description provided."}
361
  </div>
362
  </section>
363
  <div className="grid grid-cols-2 gap-6">
364
  <div className="p-6 rounded-3xl bg-white/[0.03] border border-white/5">
365
  <div className="text-[10px] uppercase text-slate-500 font-black mb-2">Estimated Investment</div>
366
+ <div className="text-xl text-white font-bold">{selectedTenderForModal.estimated_amount ? new Intl.NumberFormat("es-CL", { style: "currency", currency: "CLP" }).format(selectedTenderForModal.estimated_amount) : "Not Disclosed"}</div>
 
 
367
  </div>
368
  </div>
369
  </div>
370
  <div className="space-y-12">
371
+ <div className="p-8 rounded-[2rem] bg-purple-600/10 border border-purple-500/20 shadow-2xl shadow-purple-500/5">
372
  <h4 className="text-[10px] font-black uppercase tracking-[0.3em] text-purple-400 mb-6">Timeline</h4>
373
  <div className="text-[10px] text-slate-500 font-bold uppercase mb-1">Closing Deadline</div>
374
  <div className="text-2xl font-black text-white font-mono">{selectedTenderForModal.closing_date ? new Date(selectedTenderForModal.closing_date).toLocaleDateString() : "---"}</div>
375
  </div>
376
+ <div>
377
+ <h4 className="text-[10px] font-black uppercase tracking-[0.3em] text-slate-500 mb-6">Official Files</h4>
378
+ <div className="grid gap-3">
379
+ {selectedTenderForModal.attachments?.map((att, i) => (
380
+ <a key={i} href={att.url} target="_blank" className="flex items-center justify-between p-5 rounded-2xl bg-white/[0.03] hover:bg-white/[0.08] border border-white/5 transition-all group/file">
381
+ <span className="text-sm font-bold text-slate-200 group-hover/file:text-white truncate max-w-[200px]">{att.name}</span>
382
+ <span className="text-xl text-slate-600 group-hover/file:text-purple-400">↓</span>
383
+ </a>
384
+ ))}
385
+ </div>
386
+ </div>
387
  </div>
388
  </div>
389
  </div>