import React, { useState, useEffect, useRef } from 'react'; import { useApp } from '../../context/AppContext'; import { listDocuments, uploadDocument, deleteDocument, downloadDocument, formatBayt, updateDocumentMeta } from '../../services/account'; import { FolderKanban, Upload, Trash2, Download, Loader2, AlertTriangle, FileText, HardDrive, Layers, Package, CheckCircle2, XCircle, CalendarClock } from 'lucide-react'; const KATEGORILER = ['Yasal Belgeler', 'Kalite Belgeleri', 'Mali Belgeler', 'Resmi Kayıtlar', 'Teknik Belgeler', 'Diğer']; /** * Gerçek belge deposu — dosyalar sunucudaki kalıcı diske yazılır, * boyut gerçek bayt cinsindendir ve plan kotası sunucu tarafında uygulanır. * (Önceden dosya hiç yüklenmiyordu; boyut Math.random ile uyduruluyordu.) */ export const DocumentVault = () => { const { authUser } = useApp(); const [durum, setDurum] = useState(null); const [busy, setBusy] = useState(false); const [hata, setHata] = useState(null); const [kategori, setKategori] = useState(KATEGORILER[0]); const dosyaRef = useRef(null); const yukle = () => { if (!authUser) return; setHata(null); listDocuments().then(setDurum).catch((e) => setHata(e.message)); }; useEffect(yukle, [authUser]); const dosyaSecildi = async (e) => { const f = e.target.files?.[0]; if (!f) return; setBusy(true); setHata(null); try { setDurum(await uploadDocument(f, kategori)); } catch (err) { setHata(err.message); } finally { setBusy(false); if (dosyaRef.current) dosyaRef.current.value = ''; } }; // Toplu ihale dokümanı: her dosyanın İKN'si METNİNDEN bulunur, kullanıcıya // sorulmaz; kalemler otomatik havuza yazılır. docx/xlsx/zip sunucuda, // PDF tarayıcıda (pdfjs) okunur. Onlarca şartnameyi tek seferde atmak için. const topluRef = useRef(null); const [toplu, setToplu] = useState([]); // [{ad, durum, ikn, kalem, hata}] const topluSecildi = async (e) => { const dosyalar = [...(e.target.files || [])]; if (!dosyalar.length) return; setBusy(true); setHata(null); setToplu(dosyalar.map((f) => ({ ad: f.name, durum: 'bekliyor' }))); const guncelle = (i, veri) => setToplu((o) => o.map((x, j) => (j === i ? { ...x, ...veri } : x))); for (let i = 0; i < dosyalar.length; i++) { const f = dosyalar[i]; guncelle(i, { durum: 'yukleniyor' }); try { if (f.size > 10 * 1024 * 1024) throw new Error('10 MB sınırı'); const pdfGibi = /\.(pdf|txt|md)$/i.test(f.name); let ikn = null; let metin = null; if (pdfGibi) { const { extractText } = await import('../../services/pdfText'); const { iknCikar } = await import('../../services/kalem'); metin = (await extractText(f)).text; ikn = iknCikar(metin); } const cevap = await uploadDocument(f, 'İhale Dokümanı', ikn, { otoIkn: true }); ikn = cevap?.ikn || ikn; let kalem = cevap?.kalem?.sayi || null; if (ikn && !kalem && metin) { try { const { kalemCikar } = await import('../../services/kalem'); kalem = (await kalemCikar({ ikn, metin, dosya: f.name })).sayi || null; } catch { /* kalem çıkmazsa yükleme yine başarılı */ } } guncelle(i, { durum: 'tamam', ikn, kalem }); setDurum(cevap); } catch (err) { guncelle(i, { durum: 'hata', hata: err.message }); } } setBusy(false); if (topluRef.current) topluRef.current.value = ''; }; // Şirket belgesi süre takibi: imza sirküleri, oda kayıt, borcu yoktur — // hepsinin süresi dolar, kimse teklif hazırlanana kadar fark etmez. const sureYaz = async (id, tarih) => { setHata(null); try { setDurum(await updateDocumentMeta(id, { sonKullanma: tarih || null })); } catch (e) { setHata(e.message); } }; const kalanGun = (b) => (b.son_kullanma ? Math.ceil((new Date(b.son_kullanma).getTime() - Date.now()) / 86400000) : null); const suresiDolan = (durum?.belgeler || []).filter((b) => kalanGun(b) != null && kalanGun(b) < 0); const yakinda = (durum?.belgeler || []).filter((b) => kalanGun(b) != null && kalanGun(b) >= 0 && kalanGun(b) <= 30); const sil = async (id) => { setBusy(true); setHata(null); try { setDurum(await deleteDocument(id)); } catch (e) { setHata(e.message); } finally { setBusy(false); } }; const k = durum?.kullanim; const h = durum?.haklar; const doluluk = h?.bayt ? Math.min(100, Math.round(((k?.bayt || 0) / h.bayt) * 100)) : 0; return (
İhale dosyalarınıza her cihazdan erişin — belgeler sunucuda saklanır, tarayıcınızda değil.
İmza sirküleri, sertifikalar, vergi levhası… (en fazla 8 MB)
Süresi dolmuş: {suresiDolan.map((b) => b.ad).join(', ')}
)} {yakinda.length > 0 && (30 gün içinde doluyor: {yakinda.map((b) => `${b.ad} (${kalanGun(b)} gün)`).join(', ')}
)}Teklif zarfına süresi dolmuş belge girerse teklif değerlendirme dışı kalır. Yenileyip yeni tarihi girin.
EKAP'tan indirdiğiniz şartname/doküman dosyalarını (PDF, DOCX, XLSX, ZIP) hepsini birden seçin. Her dosyanın İKN'si metninden bulunur, ihaleye bağlanır ve teklif cetveli kalemleri otomatik çıkarılır — o ihale herkesin kartında kalemleriyle görünür.
{hata}
Henüz belge yüklemediniz
{d.ad}
{d.kategori || 'Diğer'} · {formatBayt(d.boyut)}
{new Date(d.olusturma).toLocaleString('tr-TR')}