Álvaro Valenzuela Valdes commited on
Commit
2bc1093
·
1 Parent(s): 3272da1

ui: Replace modal with immersive inline detail view to fix nested scrolling

Browse files
Files changed (1) hide show
  1. frontend/components/TenderSearch.tsx +271 -227
frontend/components/TenderSearch.tsx CHANGED
@@ -95,249 +95,284 @@ export default function TenderSearch({ tenders, onSearch, onAnalyze, forceShowFo
95
 
96
  return (
97
  <div className="space-y-8 animate-in fade-in slide-in-from-bottom-4 duration-700">
98
- {/* Search Bar Section */}
99
- <div className="glass-card rounded-3xl p-8">
100
- <div className="mb-6 flex justify-between items-start">
101
- <div>
102
- <h2 className="text-2xl font-bold text-white mb-2">Tender Discovery</h2>
103
- <p className="text-slate-400 text-sm">Real-time access to the Chilean public procurement market.</p>
104
- </div>
105
- {selectedCodes.length > 0 && (
106
- <button
107
- onClick={handleSyncToAgents}
108
- disabled={isSyncingToAgents}
109
- className="premium-gradient text-white px-6 py-3 rounded-2xl font-black text-xs tracking-widest shadow-xl shadow-purple-500/40 animate-bounce transition-all active:scale-95 disabled:opacity-50"
110
- >
111
- {isSyncingToAgents ? "📥 INGESTING DOCUMENTS..." : `⚡ ANALYZE ${selectedCodes.length} SELECTED`}
112
- </button>
113
- )}
114
- </div>
115
-
116
- <form onSubmit={handleSubmit} className="grid grid-cols-1 md:grid-cols-4 gap-6">
117
- <div className="space-y-2">
118
- <label className="text-[10px] uppercase tracking-wider text-slate-500 font-bold px-1">Keyword</label>
119
- <input
120
- type="text"
121
- placeholder="e.g. Software, Cloud..."
122
- className="w-full bg-white/5 border border-white/10 rounded-xl px-4 py-3 text-white placeholder:text-slate-600 focus:outline-none focus:ring-2 focus:ring-purple-500/40 transition-all"
123
- value={keyword}
124
- onChange={(e) => setKeyword(e.target.value)}
125
- />
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
126
  </div>
127
- <div className="space-y-2">
128
- <label className="text-[10px] uppercase tracking-wider text-slate-500 font-bold px-1">Buyer Code</label>
129
- <input
130
- type="text"
131
- placeholder="e.g. 6945"
132
- className="w-full bg-white/5 border border-white/10 rounded-xl px-4 py-3 text-white placeholder:text-slate-600 focus:outline-none focus:ring-2 focus:ring-purple-500/40 transition-all"
133
- value={buyerCode}
134
- onChange={(e) => setBuyerCode(e.target.value)}
135
- />
 
 
 
 
 
 
 
 
 
 
 
 
 
 
136
  </div>
137
- <div className="space-y-2">
138
- <label className="text-[10px] uppercase tracking-wider text-slate-500 font-bold px-1">Date Limit</label>
139
- <input
140
- type="date"
141
- 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 [color-scheme:dark]"
142
- value={date}
143
- onChange={(e) => setDate(e.target.value)}
144
- />
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
145
  </div>
146
- <div className="flex items-end">
147
- <button
148
- type="submit"
149
- disabled={isLoading}
150
- className="w-full premium-gradient hover:opacity-90 text-white font-bold py-3.5 rounded-xl transition-all shadow-lg shadow-purple-500/20 active:scale-[0.98] disabled:opacity-50"
 
 
 
151
  >
152
- {isLoading ? "Searching..." : "Fetch Opportunities"}
 
153
  </button>
154
- </div>
155
- </form>
156
- </div>
157
-
158
- {/* Results Controls */}
159
- <div className="flex items-center justify-between px-2">
160
- <div className="flex items-center gap-3">
161
- <h3 className="text-lg font-bold text-white">
162
- {showOnlyFollowed ? "Saved Opportunities" : "Market Results"}
163
- </h3>
164
- <span className="text-[10px] bg-white/5 text-slate-400 px-2 py-0.5 rounded-full border border-white/5">
165
- {filteredTenders.length} items
166
- </span>
167
- </div>
168
- {followedCodes.length > 0 && (
169
- <button
170
- onClick={() => setShowOnlyFollowed(!showOnlyFollowed)}
171
- className={`flex items-center gap-2 rounded-xl px-4 py-2 text-xs font-bold transition-all border ${
172
- showOnlyFollowed
173
- ? "bg-purple-500/20 border-purple-500/40 text-purple-300"
174
- : "bg-white/5 border-white/10 text-slate-400 hover:border-white/20"
175
- }`}
176
- >
177
- {showOnlyFollowed ? "★ Viewing Portfolio" : "☆ Show Favorites Only"}
178
- </button>
179
- )}
180
- </div>
181
-
182
- {/* Results List */}
183
- <div className="space-y-4">
184
- {filteredTenders.length === 0 ? (
185
- <div className="flex flex-col items-center justify-center rounded-3xl border border-white/5 bg-white/[0.02] p-20 text-center">
186
- <div className="w-16 h-16 rounded-2xl bg-white/5 flex items-center justify-center text-3xl mb-4 opacity-50">
187
- {showOnlyFollowed ? "🌟" : "📡"}
188
- </div>
189
- <p className="text-slate-400 max-w-xs mx-auto text-sm">
190
- {showOnlyFollowed
191
- ? "No followed opportunities found."
192
- : "Enter keywords above to fetch real-time data."}
193
- </p>
194
- </div>
195
- ) : (
196
- <div className="glass-card rounded-3xl overflow-hidden shadow-2xl border border-white/5">
197
- <div className="overflow-x-auto custom-scrollbar">
198
- <table className="w-full text-left text-sm table-fixed border-collapse">
199
- <thead className="bg-white/5 text-slate-500 uppercase text-[10px] tracking-widest font-bold border-b border-white/5">
200
- <tr>
201
- <th className="px-4 py-5 w-[100px]">{t.idSelect}</th>
202
- <th className="px-4 py-5 w-[250px]">{t.opportunity}</th>
203
- <th className="px-4 py-5 w-[180px]">{t.buyer}</th>
204
- <th className="px-4 py-5 text-center w-[100px]">{t.status}</th>
205
- </tr>
206
- </thead>
207
- <tbody className="divide-y divide-white/5">
208
- {filteredTenders.map((tender) => (
209
- <tr
210
- key={tender.code}
211
- className={`hover:bg-white/[0.04] cursor-pointer transition-colors group ${selectedCodes.includes(tender.code) ? 'bg-purple-500/5' : ''}`}
212
- onClick={() => setSelectedTenderForModal(tender)}
213
- >
214
- <td className="px-4 py-5">
215
- <div className="flex items-center gap-2">
216
- <input
217
- type="checkbox"
218
- checked={selectedCodes.includes(tender.code)}
219
- onChange={(e) => {
220
- e.stopPropagation();
221
- toggleSelect(tender.code);
222
- }}
223
- className="w-3.5 h-3.5 rounded border-white/10 bg-white/5 text-purple-500 focus:ring-purple-500/40"
224
- />
225
- <button
226
- onClick={(e) => {
227
- e.stopPropagation();
228
- toggleFollow(tender.code);
229
- }}
230
- className={`text-base transition-all hover:scale-125 ${followedCodes.includes(tender.code) ? 'text-purple-400 drop-shadow-[0_0_8px_rgba(168,85,247,0.4)]' : 'text-slate-600 hover:text-slate-400'}`}
231
- >
232
- {followedCodes.includes(tender.code) ? "★" : "☆"}
233
- </button>
234
- <span className="font-mono text-purple-400 text-[9px] truncate">{tender.code}</span>
235
- </div>
236
- </td>
237
- <td className="px-4 py-5">
238
- <div className="font-semibold text-white group-hover:text-purple-400 transition-colors truncate text-xs">{tender.name}</div>
239
- <div className="flex items-center gap-2 mt-1">
240
- <span className="text-[9px] text-slate-500 truncate">{tender.region || "Nacional"}</span>
241
- <span className="text-[8px] px-1.5 py-0.5 rounded-md bg-white/5 text-slate-600 border border-white/5 uppercase tracking-tighter">{tender.sector}</span>
242
- </div>
243
- </td>
244
- <td className="px-4 py-5 text-slate-400 text-[11px] truncate">{tender.buyer}</td>
245
- <td className="px-4 py-5 text-center">
246
- <span className={`inline-block rounded-full px-2 py-0.5 text-[9px] font-bold ${
247
- tender.status.toLowerCase().includes('publicada') ? 'bg-green-500/10 text-green-400 border border-green-500/20' : 'bg-slate-800/50 text-slate-500'
248
- }`}>
249
- {tender.status}
250
- </span>
251
- </td>
252
- </tr>
253
- ))}
254
- </tbody>
255
- </table>
256
  </div>
257
  </div>
258
- )}
259
- </div>
260
 
261
- {/* Details Modal */}
262
- {selectedTenderForModal && (
263
- <div className="fixed inset-0 z-[100] flex items-center justify-center p-4 md:p-10">
264
- <div className="absolute inset-0 bg-slate-950/80 backdrop-blur-md" onClick={() => setSelectedTenderForModal(null)} />
265
- <div className="relative w-full max-w-4xl max-h-[90vh] bg-slate-900 border border-white/10 rounded-3xl shadow-2xl flex flex-col overflow-hidden animate-in zoom-in-95 duration-300">
266
- {/* Modal Header */}
267
- <div className="p-6 md:p-8 border-b border-white/10 flex justify-between items-start">
268
- <div>
269
- <div className="flex items-center gap-3 mb-2">
270
- <span className="text-xs font-mono text-purple-400 bg-purple-400/10 px-2 py-0.5 rounded-md">{selectedTenderForModal.code}</span>
271
- <span className={`px-2 py-0.5 rounded-md text-[10px] font-bold uppercase tracking-tighter ${
272
- selectedTenderForModal.status.toLowerCase().includes('publicada') ? 'bg-green-500/10 text-green-400' : 'bg-slate-800 text-slate-500'
273
  }`}>
274
  {selectedTenderForModal.status}
275
  </span>
276
  </div>
277
- <h3 className="text-2xl font-bold text-white">{selectedTenderForModal.name}</h3>
278
- <p className="text-slate-400 text-sm mt-1">{selectedTenderForModal.buyer}</p>
 
 
 
 
 
 
 
 
 
279
  </div>
280
- <button
281
- onClick={() => setSelectedTenderForModal(null)}
282
- className="p-2 bg-white/5 hover:bg-white/10 text-slate-400 hover:text-white rounded-xl transition-all"
283
- >
284
-
285
- </button>
286
  </div>
287
 
288
- {/* Modal Content */}
289
- <div className="flex-1 overflow-y-auto p-6 md:p-8 custom-scrollbar">
290
- <div className="grid gap-10 md:grid-cols-3">
291
- {/* Left Column: Main Info */}
292
- <div className="md:col-span-2 space-y-8">
293
- <div>
294
- <h4 className="text-[10px] font-black uppercase tracking-[0.2em] text-slate-500 mb-4 flex items-center gap-2">
295
- <span className="w-4 h-[1px] bg-slate-700" />
296
- Project Description
297
  </h4>
298
- <p className="text-slate-300 leading-relaxed text-sm bg-slate-800/50 p-6 rounded-2xl border border-white/5 whitespace-pre-wrap">
299
  {selectedTenderForModal.description || "No detailed description provided."}
300
- </p>
301
- </div>
302
 
303
- <div className="grid grid-cols-2 gap-4">
304
- <div className="p-5 rounded-2xl bg-white/[0.03] border border-white/5">
305
- <div className="text-[9px] uppercase text-slate-500 font-black mb-1">Estimated Amount</div>
306
- <div className="text-sm text-white font-bold">
307
  {selectedTenderForModal.estimated_amount ? new Intl.NumberFormat("es-CL", { style: "currency", currency: "CLP" }).format(selectedTenderForModal.estimated_amount) : "Not Disclosed"}
308
  </div>
309
  </div>
310
- <div className="p-5 rounded-2xl bg-white/[0.03] border border-white/5">
311
- <div className="text-[9px] uppercase text-slate-500 font-black mb-1">Market Sector</div>
312
- <div className="text-sm text-white font-bold">{selectedTenderForModal.sector || "General"}</div>
313
  </div>
314
  </div>
315
  </div>
316
 
317
- {/* Right Column: Meta & Links */}
318
- <div className="space-y-8">
319
- <div className="p-6 rounded-2xl bg-purple-500/5 border border-purple-500/10">
320
- <h4 className="text-[10px] font-black uppercase tracking-[0.2em] text-purple-400 mb-4">Deadline</h4>
321
- <div className="text-xl font-mono text-white mb-1">
 
322
  {selectedTenderForModal.closing_date ? new Date(selectedTenderForModal.closing_date).toLocaleDateString() : "---"}
323
  </div>
324
- <p className="text-[10px] text-purple-400/60 uppercase">Final day for submission</p>
325
  </div>
326
 
327
  <div>
328
- <h4 className="text-[10px] font-black uppercase tracking-[0.2em] text-slate-500 mb-4">Official Resources</h4>
329
- <div className="space-y-3">
330
  {selectedTenderForModal.attachments?.map((att, i) => (
331
- <a key={i} href={att.url} target="_blank" className="flex items-center justify-between p-4 rounded-xl bg-slate-800 hover:bg-slate-700 border border-white/5 transition-all group/file">
332
- <div className="flex items-center gap-3">
333
- <span className="text-xl">{att.name.endsWith('.pdf') ? "📕" : "📘"}</span>
334
- <span className="text-xs font-medium text-slate-300 truncate max-w-[120px]">{att.name}</span>
 
 
 
 
 
335
  </div>
336
- <span className="text-[8px] font-black text-purple-400 opacity-0 group-hover/file:opacity-100 uppercase transition-all tracking-tighter">Download</span>
337
  </a>
338
  ))}
339
  {!selectedTenderForModal.attachments?.length && (
340
- <p className="text-[10px] text-slate-600 italic">No attachments found.</p>
 
 
341
  )}
342
  </div>
343
  </div>
@@ -345,31 +380,40 @@ export default function TenderSearch({ tenders, onSearch, onAnalyze, forceShowFo
345
  <a
346
  href={`https://www.mercadopublico.cl/fichaLicitacion.html?code=${selectedTenderForModal.code}`}
347
  target="_blank"
348
- className="flex items-center justify-center gap-2 w-full p-4 rounded-xl bg-white/5 border border-white/10 text-slate-300 text-xs font-bold hover:bg-white/10 transition"
349
  >
350
- Open official portal
351
  </a>
352
  </div>
353
  </div>
354
  </div>
355
 
356
- {/* Modal Footer */}
357
- <div className="p-6 bg-slate-950/50 border-t border-white/10 flex justify-end gap-4">
358
- <button
359
- onClick={() => setSelectedTenderForModal(null)}
360
- className="px-6 py-3 text-sm font-bold text-slate-400 hover:text-white transition"
361
- >
362
- Cancel
363
- </button>
364
- <button
365
- onClick={() => {
366
- onAnalyze(selectedTenderForModal);
367
- setSelectedTenderForModal(null);
368
- }}
369
- className="premium-gradient text-white px-8 py-3 rounded-xl font-bold text-sm shadow-xl shadow-purple-500/20 active:scale-95 transition-all"
370
- >
371
- {t.analyze}
372
- </button>
 
 
 
 
 
 
 
 
 
373
  </div>
374
  </div>
375
  </div>
 
95
 
96
  return (
97
  <div className="space-y-8 animate-in fade-in slide-in-from-bottom-4 duration-700">
98
+ {!selectedTenderForModal ? (
99
+ <>
100
+ {/* Search Bar Section */}
101
+ <div className="glass-card rounded-3xl p-8">
102
+ <div className="mb-6 flex justify-between items-start">
103
+ <div>
104
+ <h2 className="text-2xl font-bold text-white mb-2">Tender Discovery</h2>
105
+ <p className="text-slate-400 text-sm">Real-time access to the Chilean public procurement market.</p>
106
+ </div>
107
+ {selectedCodes.length > 0 && (
108
+ <button
109
+ onClick={handleSyncToAgents}
110
+ disabled={isSyncingToAgents}
111
+ className="premium-gradient text-white px-6 py-3 rounded-2xl font-black text-xs tracking-widest shadow-xl shadow-purple-500/40 animate-bounce transition-all active:scale-95 disabled:opacity-50"
112
+ >
113
+ {isSyncingToAgents ? "📥 INGESTING DOCUMENTS..." : `⚡ ANALYZE ${selectedCodes.length} SELECTED`}
114
+ </button>
115
+ )}
116
+ </div>
117
+
118
+ <form onSubmit={handleSubmit} className="grid grid-cols-1 md:grid-cols-4 gap-6">
119
+ <div className="space-y-2">
120
+ <label className="text-[10px] uppercase tracking-wider text-slate-500 font-bold px-1">Keyword</label>
121
+ <input
122
+ type="text"
123
+ placeholder="e.g. Software, Cloud..."
124
+ className="w-full bg-white/5 border border-white/10 rounded-xl px-4 py-3 text-white placeholder:text-slate-600 focus:outline-none focus:ring-2 focus:ring-purple-500/40 transition-all"
125
+ value={keyword}
126
+ onChange={(e) => setKeyword(e.target.value)}
127
+ />
128
+ </div>
129
+ <div className="space-y-2">
130
+ <label className="text-[10px] uppercase tracking-wider text-slate-500 font-bold px-1">Buyer Code</label>
131
+ <input
132
+ type="text"
133
+ placeholder="e.g. 6945"
134
+ className="w-full bg-white/5 border border-white/10 rounded-xl px-4 py-3 text-white placeholder:text-slate-600 focus:outline-none focus:ring-2 focus:ring-purple-500/40 transition-all"
135
+ value={buyerCode}
136
+ onChange={(e) => setBuyerCode(e.target.value)}
137
+ />
138
+ </div>
139
+ <div className="space-y-2">
140
+ <label className="text-[10px] uppercase tracking-wider text-slate-500 font-bold px-1">Date Limit</label>
141
+ <input
142
+ type="date"
143
+ 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 [color-scheme:dark]"
144
+ value={date}
145
+ onChange={(e) => setDate(e.target.value)}
146
+ />
147
+ </div>
148
+ <div className="flex items-end">
149
+ <button
150
+ type="submit"
151
+ disabled={isLoading}
152
+ className="w-full premium-gradient hover:opacity-90 text-white font-bold py-3.5 rounded-xl transition-all shadow-lg shadow-purple-500/20 active:scale-[0.98] disabled:opacity-50"
153
+ >
154
+ {isLoading ? "Searching..." : "Fetch Opportunities"}
155
+ </button>
156
+ </div>
157
+ </form>
158
  </div>
159
+
160
+ {/* Results Controls */}
161
+ <div className="flex items-center justify-between px-2">
162
+ <div className="flex items-center gap-3">
163
+ <h3 className="text-lg font-bold text-white">
164
+ {showOnlyFollowed ? "Saved Opportunities" : "Market Results"}
165
+ </h3>
166
+ <span className="text-[10px] bg-white/5 text-slate-400 px-2 py-0.5 rounded-full border border-white/5">
167
+ {filteredTenders.length} items
168
+ </span>
169
+ </div>
170
+ {followedCodes.length > 0 && (
171
+ <button
172
+ onClick={() => setShowOnlyFollowed(!showOnlyFollowed)}
173
+ className={`flex items-center gap-2 rounded-xl px-4 py-2 text-xs font-bold transition-all border ${
174
+ showOnlyFollowed
175
+ ? "bg-purple-500/20 border-purple-500/40 text-purple-300"
176
+ : "bg-white/5 border-white/10 text-slate-400 hover:border-white/20"
177
+ }`}
178
+ >
179
+ {showOnlyFollowed ? "★ Viewing Portfolio" : "☆ Show Favorites Only"}
180
+ </button>
181
+ )}
182
  </div>
183
+
184
+ {/* Results List */}
185
+ <div className="space-y-4">
186
+ {filteredTenders.length === 0 ? (
187
+ <div className="flex flex-col items-center justify-center rounded-3xl border border-white/5 bg-white/[0.02] p-20 text-center">
188
+ <div className="w-16 h-16 rounded-2xl bg-white/5 flex items-center justify-center text-3xl mb-4 opacity-50">
189
+ {showOnlyFollowed ? "🌟" : "📡"}
190
+ </div>
191
+ <p className="text-slate-400 max-w-xs mx-auto text-sm">
192
+ {showOnlyFollowed
193
+ ? "No followed opportunities found."
194
+ : "Enter keywords above to fetch real-time data."}
195
+ </p>
196
+ </div>
197
+ ) : (
198
+ <div className="glass-card rounded-3xl overflow-hidden shadow-2xl border border-white/5">
199
+ <div className="overflow-x-auto custom-scrollbar">
200
+ <table className="w-full text-left text-sm table-fixed border-collapse">
201
+ <thead className="bg-white/5 text-slate-500 uppercase text-[10px] tracking-widest font-bold border-b border-white/5">
202
+ <tr>
203
+ <th className="px-4 py-5 w-[100px]">{t.idSelect}</th>
204
+ <th className="px-4 py-5 w-[250px]">{t.opportunity}</th>
205
+ <th className="px-4 py-5 w-[180px]">{t.buyer}</th>
206
+ <th className="px-4 py-5 text-center w-[100px]">{t.status}</th>
207
+ </tr>
208
+ </thead>
209
+ <tbody className="divide-y divide-white/5">
210
+ {filteredTenders.map((tender) => (
211
+ <tr
212
+ key={tender.code}
213
+ className={`hover:bg-white/[0.04] cursor-pointer transition-colors group ${selectedCodes.includes(tender.code) ? 'bg-purple-500/5' : ''}`}
214
+ onClick={() => setSelectedTenderForModal(tender)}
215
+ >
216
+ <td className="px-4 py-5">
217
+ <div className="flex items-center gap-2">
218
+ <input
219
+ type="checkbox"
220
+ checked={selectedCodes.includes(tender.code)}
221
+ onChange={(e) => {
222
+ e.stopPropagation();
223
+ toggleSelect(tender.code);
224
+ }}
225
+ className="w-3.5 h-3.5 rounded border-white/10 bg-white/5 text-purple-500 focus:ring-purple-500/40"
226
+ />
227
+ <button
228
+ onClick={(e) => {
229
+ e.stopPropagation();
230
+ toggleFollow(tender.code);
231
+ }}
232
+ className={`text-base transition-all hover:scale-125 ${followedCodes.includes(tender.code) ? 'text-purple-400 drop-shadow-[0_0_8px_rgba(168,85,247,0.4)]' : 'text-slate-600 hover:text-slate-400'}`}
233
+ >
234
+ {followedCodes.includes(tender.code) ? "★" : "☆"}
235
+ </button>
236
+ <span className="font-mono text-purple-400 text-[9px] truncate">{tender.code}</span>
237
+ </div>
238
+ </td>
239
+ <td className="px-4 py-5">
240
+ <div className="font-semibold text-white group-hover:text-purple-400 transition-colors truncate text-xs">{tender.name}</div>
241
+ <div className="flex items-center gap-2 mt-1">
242
+ <span className="text-[9px] text-slate-500 truncate">{tender.region || "Nacional"}</span>
243
+ <span className="text-[8px] px-1.5 py-0.5 rounded-md bg-white/5 text-slate-600 border border-white/5 uppercase tracking-tighter">{tender.sector}</span>
244
+ </div>
245
+ </td>
246
+ <td className="px-4 py-5 text-slate-400 text-[111px] truncate">{tender.buyer}</td>
247
+ <td className="px-4 py-5 text-center">
248
+ <span className={`inline-block rounded-full px-2 py-0.5 text-[9px] font-bold ${
249
+ tender.status.toLowerCase().includes('publicada') ? 'bg-green-500/10 text-green-400 border border-green-500/20' : 'bg-slate-800/50 text-slate-500'
250
+ }`}>
251
+ {tender.status}
252
+ </span>
253
+ </td>
254
+ </tr>
255
+ ))}
256
+ </tbody>
257
+ </table>
258
+ </div>
259
+ </div>
260
+ )}
261
  </div>
262
+ </>
263
+ ) : (
264
+ /* Immersive Detail View (Replaces List) */
265
+ <div className="animate-in slide-in-from-right-8 duration-500">
266
+ <div className="flex items-center justify-between mb-8">
267
+ <button
268
+ onClick={() => setSelectedTenderForModal(null)}
269
+ className="flex items-center gap-2 text-slate-400 hover:text-white transition group"
270
  >
271
+ <span className="text-xl group-hover:-translate-x-1 transition-transform">←</span>
272
+ <span className="text-sm font-bold uppercase tracking-widest">{lang === 'en' ? 'Back to opportunities' : 'Volver a licitaciones'}</span>
273
  </button>
274
+ <div className="flex gap-4">
275
+ <button
276
+ onClick={() => toggleFollow(selectedTenderForModal.code)}
277
+ className={`px-4 py-2 rounded-xl border font-bold text-xs transition-all ${
278
+ followedCodes.includes(selectedTenderForModal.code)
279
+ ? "bg-purple-500/20 border-purple-500/40 text-purple-300"
280
+ : "bg-white/5 border-white/10 text-slate-400 hover:bg-white/10"
281
+ }`}
282
+ >
283
+ {followedCodes.includes(selectedTenderForModal.code) ? "★ Saved" : "☆ Save to Portfolio"}
284
+ </button>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
285
  </div>
286
  </div>
 
 
287
 
288
+ <div className="glass-card rounded-[2.5rem] overflow-hidden border border-white/5 bg-slate-900/40 backdrop-blur-xl shadow-2xl">
289
+ {/* Header Section */}
290
+ <div className="p-10 md:p-14 border-b border-white/5 relative overflow-hidden">
291
+ <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" />
292
+ <div className="relative z-10">
293
+ <div className="flex items-center gap-3 mb-6">
294
+ <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>
295
+ <span className={`px-3 py-1 rounded-lg text-xs font-black uppercase tracking-widest ${
296
+ selectedTenderForModal.status.toLowerCase().includes('publicada') ? 'bg-green-500/10 text-green-400 border border-green-500/20' : 'bg-slate-800 text-slate-500'
 
 
 
297
  }`}>
298
  {selectedTenderForModal.status}
299
  </span>
300
  </div>
301
+ <h3 className="text-4xl md:text-5xl font-black text-white leading-tight tracking-tight mb-4">{selectedTenderForModal.name}</h3>
302
+ <div className="flex flex-wrap items-center gap-x-8 gap-y-4">
303
+ <div className="flex items-center gap-3">
304
+ <div className="w-8 h-8 rounded-full bg-white/5 flex items-center justify-center text-lg">🏢</div>
305
+ <span className="text-slate-400 font-medium">{selectedTenderForModal.buyer}</span>
306
+ </div>
307
+ <div className="flex items-center gap-3">
308
+ <div className="w-8 h-8 rounded-full bg-white/5 flex items-center justify-center text-lg">📍</div>
309
+ <span className="text-slate-400 font-medium">{selectedTenderForModal.region || "Nacional"}</span>
310
+ </div>
311
+ </div>
312
  </div>
 
 
 
 
 
 
313
  </div>
314
 
315
+ {/* Content Section */}
316
+ <div className="p-10 md:p-14">
317
+ <div className="grid gap-16 lg:grid-cols-3">
318
+ {/* Main Column */}
319
+ <div className="lg:col-span-2 space-y-12">
320
+ <section>
321
+ <h4 className="text-[10px] font-black uppercase tracking-[0.3em] text-slate-500 mb-6 flex items-center gap-3">
322
+ <span className="w-8 h-[1px] bg-slate-700" />
323
+ Project Scope & Description
324
  </h4>
325
+ <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">
326
  {selectedTenderForModal.description || "No detailed description provided."}
327
+ </div>
328
+ </section>
329
 
330
+ <div className="grid grid-cols-2 gap-6">
331
+ <div className="p-8 rounded-3xl bg-white/[0.03] border border-white/5 group hover:bg-white/[0.05] transition-colors">
332
+ <div className="text-[10px] uppercase text-slate-500 font-black mb-2 tracking-widest">Estimated Investment</div>
333
+ <div className="text-2xl text-white font-bold tracking-tight">
334
  {selectedTenderForModal.estimated_amount ? new Intl.NumberFormat("es-CL", { style: "currency", currency: "CLP" }).format(selectedTenderForModal.estimated_amount) : "Not Disclosed"}
335
  </div>
336
  </div>
337
+ <div className="p-8 rounded-3xl bg-white/[0.03] border border-white/5 group hover:bg-white/[0.05] transition-colors">
338
+ <div className="text-[10px] uppercase text-slate-500 font-black mb-2 tracking-widest">Industry Classification</div>
339
+ <div className="text-2xl text-white font-bold tracking-tight">{selectedTenderForModal.sector || "General Procurement"}</div>
340
  </div>
341
  </div>
342
  </div>
343
 
344
+ {/* Sidebar Column */}
345
+ <div className="space-y-12">
346
+ <div className="p-10 rounded-[2rem] bg-purple-600/10 border border-purple-500/20 shadow-2xl shadow-purple-500/5 relative overflow-hidden group">
347
+ <div className="absolute top-0 right-0 w-32 h-32 bg-purple-500/20 blur-[60px] opacity-0 group-hover:opacity-100 transition-opacity" />
348
+ <h4 className="text-[10px] font-black uppercase tracking-[0.3em] text-purple-400 mb-6">Submission Deadline</h4>
349
+ <div className="text-4xl font-black text-white mb-2 font-mono">
350
  {selectedTenderForModal.closing_date ? new Date(selectedTenderForModal.closing_date).toLocaleDateString() : "---"}
351
  </div>
352
+ <p className="text-xs text-purple-400/60 font-bold uppercase tracking-tighter">Final Window for Proposal Submission</p>
353
  </div>
354
 
355
  <div>
356
+ <h4 className="text-[10px] font-black uppercase tracking-[0.3em] text-slate-500 mb-6">Official Documentation</h4>
357
+ <div className="grid gap-3">
358
  {selectedTenderForModal.attachments?.map((att, i) => (
359
+ <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">
360
+ <div className="flex items-center gap-4">
361
+ <div className="w-10 h-10 rounded-xl bg-white/5 flex items-center justify-center text-2xl">
362
+ {att.name.endsWith('.pdf') ? "📕" : "📘"}
363
+ </div>
364
+ <div className="flex flex-col">
365
+ <span className="text-sm font-bold text-slate-200 group-hover/file:text-white transition-colors truncate max-w-[150px]">{att.name}</span>
366
+ <span className="text-[9px] text-slate-600 uppercase font-black">Official Basis</span>
367
+ </div>
368
  </div>
369
+ <span className="text-xl text-slate-600 group-hover/file:text-purple-400 transition-colors"></span>
370
  </a>
371
  ))}
372
  {!selectedTenderForModal.attachments?.length && (
373
+ <div className="p-8 text-center rounded-2xl border border-white/5 bg-white/[0.01]">
374
+ <p className="text-xs text-slate-600 italic font-medium">No external files registered.</p>
375
+ </div>
376
  )}
377
  </div>
378
  </div>
 
380
  <a
381
  href={`https://www.mercadopublico.cl/fichaLicitacion.html?code=${selectedTenderForModal.code}`}
382
  target="_blank"
383
+ className="flex items-center justify-center gap-3 w-full p-5 rounded-2xl bg-white/5 border border-white/10 text-white text-sm font-black uppercase tracking-widest hover:bg-white/10 transition-all shadow-xl active:scale-[0.98]"
384
  >
385
+ Mercado Público Portal
386
  </a>
387
  </div>
388
  </div>
389
  </div>
390
 
391
+ {/* Action Footer */}
392
+ <div className="p-10 md:p-14 bg-slate-950/40 border-t border-white/5 flex flex-col md:flex-row items-center justify-between gap-8">
393
+ <div className="flex items-center gap-4">
394
+ <div className="w-12 h-12 rounded-full bg-cyan/10 border border-cyan/20 flex items-center justify-center text-cyan">🤖</div>
395
+ <div>
396
+ <p className="text-white font-bold text-sm">Ready for Agent Analysis</p>
397
+ <p className="text-slate-500 text-xs">Our multi-agent system will evaluate compliance and technical fit.</p>
398
+ </div>
399
+ </div>
400
+ <div className="flex items-center gap-6 w-full md:w-auto">
401
+ <button
402
+ onClick={() => setSelectedTenderForModal(null)}
403
+ className="flex-1 md:flex-none px-8 py-4 text-xs font-black uppercase tracking-widest text-slate-500 hover:text-white transition"
404
+ >
405
+ {lang === 'en' ? 'Close View' : 'Cerrar Vista'}
406
+ </button>
407
+ <button
408
+ onClick={() => {
409
+ onAnalyze(selectedTenderForModal);
410
+ setSelectedTenderForModal(null);
411
+ }}
412
+ className="flex-1 md:flex-none premium-gradient text-white px-10 py-5 rounded-2xl font-black text-xs uppercase tracking-[0.2em] shadow-2xl shadow-purple-500/30 hover:scale-105 active:scale-95 transition-all"
413
+ >
414
+ {t.analyze}
415
+ </button>
416
+ </div>
417
  </div>
418
  </div>
419
  </div>