feat: İhaleist - Akıllı İhale Takip ve Analiz Platformu (Full PRD + 7 Enterprise Modül)

This commit is contained in:
2026-08-07 16:30:24 +03:00
commit ece74feefe
35 changed files with 7820 additions and 0 deletions
+129
View File
@@ -0,0 +1,129 @@
import React from 'react';
import { useApp } from '../context/AppContext';
import { Star, MapPin, Clock, Tag, Package, Building2, AlertTriangle, Sparkles } from 'lucide-react';
export const TenderCard = ({ tender }) => {
const { toggleTrackTender, setActiveTenderDetail } = useApp();
const [day, monthYear] = tender.tarih ? tender.tarih.split('.') : ['01', '01.2026'];
const monthYearFormatted = monthYear ? `${monthYear}` : '08.2026';
return (
<div className="bg-white rounded-xl border border-blue-200/80 shadow-xs hover:shadow-md transition-all overflow-hidden flex flex-col md:flex-row group border-l-4 border-l-blue-600">
{/* Left Date Block */}
<div
onClick={() => setActiveTenderDetail(tender)}
className="bg-[#edf4ff] group-hover:bg-[#e2edff] text-blue-900 md:w-36 p-4 flex flex-col items-center justify-center shrink-0 border-b md:border-b-0 md:border-r border-blue-100 cursor-pointer select-none transition-colors"
>
<span className="text-3xl font-black tracking-tight text-blue-700">{day}</span>
<span className="text-xs font-bold text-blue-900/80 mt-0.5">{monthYearFormatted}</span>
<span className="text-[11px] font-semibold bg-white/80 px-2 py-0.5 rounded-full text-blue-800 mt-2 border border-blue-200">
{tender.saat}
</span>
</div>
{/* Main Card Content */}
<div className="flex-1 p-4 flex flex-col justify-between space-y-3">
{/* Top Header Row */}
<div>
<div className="flex items-start justify-between gap-3">
<h3
onClick={() => setActiveTenderDetail(tender)}
className="font-bold text-sm sm:text-base text-slate-900 hover:text-blue-600 cursor-pointer leading-snug tracking-tight"
>
{tender.baslik}
{tender.isYeni && (
<span className="ml-2 inline-block bg-purple-600 text-white text-[10px] font-extrabold px-2 py-0.5 rounded-md uppercase tracking-wider">
YENİ
</span>
)}
</h3>
{/* Bookmark Star Button */}
<button
type="button"
onClick={(e) => {
e.stopPropagation();
toggleTrackTender(tender.id);
}}
title={tender.takipte ? 'Takibi Bırak' : 'Takibe Al'}
className={`p-1.5 rounded-lg transition-transform active:scale-95 ${
tender.takipte ? 'text-amber-400 bg-amber-50' : 'text-slate-300 hover:text-amber-400 hover:bg-slate-50'
}`}
>
<Star className={`w-5 h-5 ${tender.takipte ? 'fill-amber-400' : ''}`} />
</button>
</div>
{/* Subtitle Details */}
<div className="flex flex-wrap items-center gap-y-1 gap-x-3 text-xs text-slate-500 mt-1.5 font-medium">
<span className="flex items-center gap-1 text-slate-700 font-semibold truncate max-w-md">
<Building2 className="w-3.5 h-3.5 text-slate-400 shrink-0" />
<span className="truncate">{tender.kurum}</span>
</span>
<span className="flex items-center gap-1 text-slate-600">
<MapPin className="w-3.5 h-3.5 text-rose-500 shrink-0" />
<span>{tender.sehir}</span>
</span>
<span className="bg-emerald-50 text-emerald-700 border border-emerald-200 px-2 py-0.5 rounded-full text-[10px] font-bold flex items-center gap-1">
<Clock className="w-3 h-3 text-emerald-600" />
<span>{tender.eklenmeZamani}</span>
</span>
<span className="text-slate-400 font-mono text-[11px]">
# {tender.ikn}
</span>
</div>
</div>
{/* Badges Row */}
<div className="flex flex-wrap items-center gap-1.5 text-xs">
<span className="bg-amber-500 text-white font-extrabold text-[11px] px-2.5 py-1 rounded-md shadow-2xs">
{tender.alimTuru}
</span>
<span className="bg-slate-100 text-slate-700 font-medium text-[11px] px-2.5 py-1 rounded-md border border-slate-200">
{tender.sektor}
</span>
{tender.aciliyetBadge && (
<span className="bg-red-500 text-white font-extrabold text-[11px] px-2 py-1 rounded-md flex items-center gap-1 shadow-2xs">
<AlertTriangle className="w-3 h-3" />
<span>{tender.aciliyetBadge}</span>
</span>
)}
<span className="bg-blue-50 text-blue-700 border border-blue-200 text-[11px] font-bold px-2 py-1 rounded-md flex items-center gap-1">
<Sparkles className="w-3 h-3 text-blue-600" />
<span>%{tender.aiMatchScore} Uyumlu</span>
</span>
</div>
{/* Material Items Preview Box */}
{tender.items && tender.items.length > 0 && (
<div
onClick={() => setActiveTenderDetail(tender)}
className="bg-slate-50 hover:bg-slate-100/80 rounded-lg p-2.5 border border-slate-200 space-y-1.5 cursor-pointer transition-colors"
>
{tender.items.slice(0, 3).map((item, idx) => (
<div key={idx} className="flex items-center justify-between text-xs font-semibold text-slate-700">
<span className="flex items-center gap-2 truncate">
<Package className="w-3.5 h-3.5 text-blue-500 shrink-0" />
<span className="truncate">{item.ad}</span>
</span>
<span className="bg-white border border-slate-200 px-2 py-0.5 rounded text-[11px] font-bold text-slate-900 shrink-0">
{item.miktar} {item.birim || 'adet'}
</span>
</div>
))}
{tender.items.length > 3 && (
<p className="text-[10px] font-bold text-blue-600 hover:underline pt-0.5 text-right">
+ {tender.items.length - 3} malzeme kalemi daha...
</p>
)}
</div>
)}
</div>
</div>
);
};