diff --git a/docs/quality/qa-deferred-views.json b/docs/quality/qa-deferred-views.json new file mode 100644 index 0000000..bfdab7c --- /dev/null +++ b/docs/quality/qa-deferred-views.json @@ -0,0 +1,7 @@ +{ + "vat": "\n - heading \"İhale KDV & Tevkifat Hesaplayıcı\" [level=1]\n - paragraph: Teklif matrahından KDV dahil tutarı veya KDV dahilden net matrahı hesaplayın.\n - button \"KDV Hariç ➔ KDV Dahil Hesapla\"\n - button \"KDV Dahil ➔ Matrah Hesapla\"\n - generic: Teklif Tutarı (KDV Hariç Matrah)\n - spinbutton: \"100000\"\n - generic: TL\n - generic: KDV Oranı\n - button \"%1\"\n - button \"%10\"\n - button \"%20\"\n - generic: Tevkifat Oranı (Varsa)\n - combobox:\n - option \"Tevkifat Yok\" [selected]\n - option \"5/10 Tevkifat (%50)\"\n - option \"7/10 Tevkifat (%70)\"\n - option \"9/10 Tevkifat (%90)\"\n - generic: Hesaplama Sonucu\n - button \"Kopyala\":\n - generic: Kopyala\n - generic: Net Matrah (KDV Hariç)\n - generic: ₺100.000\n - generic: Hesaplanan KDV (%20)\n - generic: ₺20.000\n - generic: Genel Toplam (KDV Dahil)\n - generic: ₺120.000\n- button \"Kullanım kılavuzu (? tuşu)\":", + "api": "\n - heading \"API Erişimi\" [level=2]\n - paragraph: İhale verisini kendi sistemlerinize (ERP, CRM) taşımak için sunucu doğrulamalı API anahtarları.\n - paragraph:\n - text: API erişimi\n - strong: Kurumsal\n - text: planda sunulur. Mevcut planınızda API anahtarı oluşturulamaz — Planlar sekmesinden yükseltebilirsiniz.\n - heading \"API Anahtarları\" [level=3]:\n - text: API Anahtarları\n - generic: 0 / 0 anahtar\n - paragraph: Henüz anahtar yok.\n - textbox \"Anahtar adı\" [disabled]:\n - /placeholder: Anahtar adı (ör. ERP Entegrasyonu)\n - button \"Oluştur\" [disabled]:\n - text: Oluştur\n - heading \"MCP Sunucusu — yapay zekâ araçlarınıza İhaleist'i bağlayın\" [level=3]:\n - text: MCP Sunucusu — yapay zekâ araçlarınıza İhaleist'i bağlayın\n - paragraph:\n - text: \"Claude Code, Cursor, Claude Desktop gibi MCP destekli araçlar İhaleist'i doğrudan sorgular:\"\n - code: search_tenders\n - text: \",\"\n - code: get_tender\n - text: \",\"\n - code: search_results\n - text: \",\"\n - code: search_items\n - text: \",\"\n - code: upcoming_deadlines\n - text: . Yukarıdaki API anahtarınızı kullanır.\n - paragraph:\n - text: Claude Code\n - generic: — terminalde tek komut\n - button \"Kopyala\":\n - text: Kopyala\n - generic: \"claude mcp add --transport http ihaleist http://127.0.0.1:5176/mcp --header \\\"Authorization: Bearer ih_live_ANAHTARINIZ\\\"\"\n - paragraph:\n - text: Cursor / Windsurf\n - generic: — .cursor/mcp.json\n - button \"Kopyala\":\n - text: Kopyala\n - generic: \"{ \\\"mcpServers\\\": { \\\"ihaleist\\\": { \\\"url\\\": \\\"http://127.0.0.1:5176/mcp\\\", \\\"headers\\\": { \\\"Authorization\\\": \\\"Bearer ih_live_ANAHTARINIZ\\\" } } } }\"\n - paragraph:\n - text: Claude Desktop\n - generic: — claude_desktop_config.json (mcp-remote)\n - button \"Kopyala\":\n - text: Kopyala\n - generic: \"{ \\\"mcpServers\\\": { \\\"ihaleist\\\": { \\\"command\\\": \\\"npx\\\", \\\"args\\\": [ \\\"-y\\\", \\\"mcp-remote\\\", \\\"http://127.0.0.1:5176/mcp\\\", \\\"--header\\\", \\\"Authorization: Bearer ih_live_ANAHTARINIZ\\\" ] } } }\"\n - paragraph:\n - text: RSS beslemesi\n - generic: — Feedly, Outlook, Slack RSS, n8n… (il, sektor, q filtreleri)\n - button \"Kopyala\":\n - text: Kopyala\n - generic: http://127.0.0.1:5176/api/feeds/tenders.rss?key=ih_live_ANAHTARINIZ&il=İstanbul&q=eldiven\n - paragraph:\n - text: \"Sonuç ilanları beslemesi anahtarsız:\"\n - code: http://127.0.0.1:5176/api/feeds/sonuc.rss\n - text: (firma, idare, il filtreleri). Anahtarı\n - code: ih_live_ANAHTARINIZ\n - text: yerine yazın.\n - paragraph:\n - strong: \"Kullanım:\"\n - text: İsteklerinize\n - code: \"Authorization: Bearer ih_live_…\"\n - text: başlığını ekleyin. Anahtar sunucuda doğrulanır, her kullanımda son kullanım zamanı güncellenir, iptal ettiğinizde anında geçersiz olur.\n- button \"Kullanım kılavuzu (? tuşu)\":", + "documents": "\n - heading \"Belge Kasası\" [level=2]\n - paragraph: İhale dosyalarınıza her cihazdan erişin — belgeler sunucuda saklanır, tarayıcınızda değil.\n - text: Kullanım\n - generic: 0 / 5 belge · 0 B / 25.0 MB\n - heading \"Belge Yükleyin\" [level=3]\n - paragraph: İmza sirküleri, sertifikalar, vergi levhası… (en fazla 10 MB)\n - combobox:\n - option \"Yasal Belgeler\" [selected]\n - option \"Kalite Belgeleri\"\n - option \"Mali Belgeler\"\n - option \"Resmi Kayıtlar\"\n - option \"Teknik Belgeler\"\n - option \"Diğer\"\n - text: Dosya Seç\n - heading \"İhale Dokümanlarını Toplu Yükle\" [level=3]\n - paragraph:\n - text: EKAP'tan indirdiğiniz şartname/doküman dosyalarını (PDF, DOCX, XLSX, ZIP) hepsini birden seçin. Her dosyanın\n - strong: İKN'si metninden bulunur\n - text: \", ihaleye bağlanır ve teklif cetveli kalemleri otomatik çıkarılır — o ihale herkesin kartında kalemleriyle görünür.\"\n - text: Dosyaları Seç (çoklu)\n - paragraph: Henüz belge yüklemediniz\n- button \"Kullanım kılavuzu (? tuşu)\":", + "analytics": "\n - heading \"Analitik Dashboard & Fiyat Isı Haritası\" [level=2]\n - paragraph: — kanban süreçlerinizden hesaplanan gerçek kazanma oranı ve il bazlı ihale yoğunluğu.\n - generic: Katıldığımız İhaleler\n - generic: 0 İhale\n - text: Teklif verilen + sonuçlanan\n - generic: İhale Kazanma Oranımız\n - generic: \"%0\"\n - text: Henüz sonuçlanan ihale yok\n - generic: Toplam Kazanılan Bedel\n - generic: 0 ₺\n - generic: 0 sözleşme\n - text: Ciro Hedefi\n - button \"Hedefi düzenle\":\n - spinbutton\n - button \"Kaydet\"\n - heading \"Aylık İhale Kazanım ve Teklif Hacmi (TL)\" [level=3]:\n - text: Aylık İhale Kazanım ve Teklif Hacmi (TL)\n - paragraph: Henüz teklif/sonuç verisi yok\n - paragraph: Kanban'da ihaleleri \"teklif verildi / kazanıldı / kaybedildi\" durumuna aldıkça aylık hacim grafiği oluşur.\n - heading \"Sektörel İhale Dağılımı\" [level=3]\n - generic: Laboratuvar & Ölçüm\n - generic: \"%100\"\n - heading \"İl Bazlı İhale Yoğunluk Haritası — Canlı\" [level=3]:\n - text: İl Bazlı İhale Yoğunluk Haritası — Canlı\n - paragraph: Yüklü ihalelerin illere dağılımı. Bir ile tıklayınca liste o ile filtrelenir. 3/81 ilde aktif ihale (%4).\n - generic: Az\n - generic: Çok\n - button \"Adana ·\" [disabled]:\n - generic: Adana\n - generic: ·\n - button \"Adıyaman ·\" [disabled]:\n - generic: Adıyaman\n - generic: ·\n - button \"Afyonkarahisar ·\" [disabled]:\n - generic: Afyonkarahisar\n - generic: ·\n - button \"Ağrı ·\" [disabled]:\n - generic: Ağrı\n - generic: ·\n - button \"Amasya ·\" [disabled]:\n - generic: Amasya\n - generic: ·\n - button \"Ankara ·\" [disabled]:\n - generic: Ankara\n - generic: ·\n - button \"Antalya ·\" [disabled]:\n - generic: Antalya\n - generic: ·\n - button \"Artvin ·\" [disabled]:\n - generic: Artvin\n - generic: ·\n - button \"Aydın ·\" [disabled]:\n - generic: Aydın\n - generic: ·\n - button \"Balıkesir ·\" [disabled]:\n - generic: Balıkesir\n - generic: ·\n - button \"Bilecik ·\" [disabled]:\n - generic: Bilecik\n - generic: ·\n - button \"Bingöl ·\" [disabled]:\n - generic: Bingöl\n - generic: ·\n - button \"Bitlis ·\" [disabled]:\n - generic: Bitlis\n - generic: ·\n - button \"Bolu ·\" [disabled]:\n - generic: Bolu\n - generic: ·\n - button \"Burdur ·\" [disabled]:\n - generic: Burdur\n - generic: ·\n - button \"Bursa ·\" [disabled]:\n - generic: Bursa\n - generic: ·\n - button \"Çanakkale ·\" [disabled]:\n - generic: Çanakkale\n - generic: ·\n - button \"Çankırı ·\" [disabled]:\n - generic: Çankırı\n - generic: ·\n - button \"Çorum ·\" [disabled]:\n - generic: Çorum\n - generic: ·\n - button \"Denizli ·\" [disabled]:\n - generic: Denizli\n - generic: ·\n - button \"Diyarbakır ·\" [disabled]:\n - generic: Diyarbakır\n - generic: ·\n - button \"Edirne ·\" [disabled]:\n - generic: Edirne\n - generic: ·\n - button \"Elazığ ·\" [disabled]:\n - generic: Elazığ\n - generic: ·\n - button \"Erzincan ·\" [disabled]:\n - generic: Erzincan\n - generic: ·\n - button \"Erzurum ·\" [disabled]:\n - generic: Erzurum\n - generic: ·\n - button \"Eskişehir ·\" [disabled]:\n - generic: Eskişehir\n - generic: ·\n - button \"Gaziantep ·\" [disabled]:\n - generic: Gaziantep\n - generic: ·\n - button \"Giresun 1\":\n - generic: Giresun\n - generic: \"1\"\n - button \"Gümüşhane ·\" [disabled]:\n - generic: Gümüşhane\n - generic: ·\n - button \"Hakkari ·\" [disabled]:\n - generic: Hakkari\n - generic: ·\n - button \"Hatay ·\" [disabled]:\n - generic: Hatay\n - generic: ·\n - button \"Isparta ·\" [disabled]:\n - generic: Isparta\n - generic: ·\n - button \"Mersin ·\" [disabled]:\n - generic: Mersin\n - generic: ·\n - button \"İstanbul ·\" [disabled]:\n - generic: İstanbul\n - generic: ·\n - button \"İzmir ·\" [disabled]:\n - generic: İzmir\n - generic: ·\n - button \"Kars ·\" [disabled]:\n - generic: Kars\n - generic: ·\n - button \"Kastamonu ·\" [disabled]:\n - generic: Kastamonu\n - generic: ·\n - button \"Kayseri 1\":\n - generic: Kayseri\n - generic: \"1\"\n - button \"Kırklareli ·\" [disabled]:\n - generic: Kırklareli\n - generic: ·\n - button \"Kırşehir ·\" [disabled]:\n - generic: Kırşehir\n - generic: ·\n - button \"Kocaeli ·\" [disabled]:\n - generic: Kocaeli\n - generic: ·\n - button \"Konya ·\" [disabled]:\n - generic: Konya\n - generic: ·\n - button \"Kütahya ·\" [disabled]:\n - generic: Kütahya\n - generic: ·\n - button \"Malatya ·\" [disabled]:\n - generic: Malatya\n - generic: ·\n - button \"Manisa ·\" [disabled]:\n - generic: Manisa\n - generic: ·\n - button \"Kahramanmaraş ·\" [disabled]:\n - generic: Kahramanmaraş\n - generic: ·\n - button \"Mardin ·\" [disabled]:\n - generic: Mardin\n - generic: ·\n - button \"Muğla ·\" [disabled]:\n - generic: Muğla\n - generic: ·\n - button \"Muş ·\" [disabled]:\n - generic: Muş\n - generic: ·\n - button \"Nevşehir ·\" [disabled]:\n - generic: Nevşehir\n - generic: ·\n - button \"Niğde ·\" [disabled]:\n - generic: Niğde\n - generic: ·\n - button \"Ordu ·\" [disabled]:\n - generic: Ordu\n - generic: ·\n - button \"Rize ·\" [disabled]:\n - generic: Rize\n - generic: ·\n - button \"Sakarya ·\" [disabled]:\n - generic: Sakarya\n - generic: ·\n - button \"Samsun ·\" [disabled]:\n - generic: Samsun\n - generic: ·\n - button \"Siirt ·\" [disabled]:\n - generic: Siirt\n - generic: ·\n - button \"Sinop ·\" [disabled]:\n - generic: Sinop\n - generic: ·\n - button \"Sivas ·\" [disabled]:\n - generic: Sivas\n - generic: ·\n - button \"Tekirdağ ·\" [disabled]:\n - generic: Tekirdağ\n - generic: ·\n - button \"Tokat ·\" [disabled]:\n - generic: Tokat\n - generic: ·\n - button \"Trabzon ·\" [disabled]:\n - generic: Trabzon\n - generic: ·\n - button \"Tunceli ·\" [disabled]:\n - generic: Tunceli\n - generic: ·\n - button \"Şanlıurfa ·\" [disabled]:\n - generic: Şanlıurfa\n - generic: ·\n - button \"Uşak ·\" [disabled]:\n - generic: Uşak\n - generic: ·\n - button \"Van ·\" [disabled]:\n - generic: Van\n - generic: ·\n - button \"Yozgat ·\" [disabled]:\n - generic: Yozgat\n - generic: ·\n - button \"Zonguldak ·\" [disabled]:\n - generic: Zonguldak\n - generic: ·\n - button \"Aksaray 1\":\n - generic: Aksaray\n - generic: \"1\"\n - button \"Bayburt ·\" [disabled]:\n - generic: Bayburt\n - generic: ·\n - button \"Karaman ·\" [disabled]:\n - generic: Karaman\n - generic: ·\n - button \"Kırıkkale ·\" [disabled]:\n - generic: Kırıkkale\n - generic: ·\n - button \"Batman ·\" [disabled]:\n - generic: Batman\n - generic: ·\n - button \"Şırnak ·\" [disabled]:\n - generic: Şırnak\n - generic: ·\n - button \"Bartın ·\" [disabled]:\n - generic: Bartın\n - generic: ·\n - button \"Ardahan ·\" [disabled]:\n - generic: Ardahan\n - generic: ·\n - button \"Iğdır ·\" [disabled]:\n - generic: Iğdır\n - generic: ·\n - button \"Yalova ·\" [disabled]:\n - generic: Yalova\n - generic: ·\n - button \"Karabük ·\" [disabled]:\n - generic: Karabük\n - generic: ·\n - button \"Kilis ·\" [disabled]:\n - generic: Kilis\n - generic: ·\n - button \"Osmaniye ·\" [disabled]:\n - generic: Osmaniye\n - generic: ·\n - button \"Düzce ·\" [disabled]:\n - generic: Düzce\n - generic: ·\n- button \"Kullanım kılavuzu (? tuşu)\":", + "returnToList": true +} \ No newline at end of file diff --git a/docs/quality/uygulama-durumu.md b/docs/quality/uygulama-durumu.md index cb0bac4..eb9e697 100644 --- a/docs/quality/uygulama-durumu.md +++ b/docs/quality/uygulama-durumu.md @@ -631,3 +631,11 @@ Sınırlar: Bir parçanın işlenmesi tüm şartlarının anlam bakımından tas Bozuk JSON'un boş gövdeye çevrilip varsayılan anahtar oluşturması kaldırıldı. Anahtar adı metin ve en fazla 120 karakter olmalı; çevresindeki boşluklar temizlenir. GET/POST/DELETE dışındaki metotlar 405 döner. Doğrulama: yerel izole HTTP testinde eşzamanlı 16 oluşturma isteğinden tam 10 başarı, 6 kota reddi; bir anahtar iptal edilince yeni kayıt mümkün. Bozuk JSON/geçersiz ad kayıt oluşturmuyor. Gerçek SQLite testinde kota reddi sonrası işlem kapanıyor, iptal ve yeni kayıt çalışıyor. Tüm 137 test geçti; ön yüz değişmediğinden derleme tekrarlanmadı. Farklı sunucu süreçlerinden yük testi yapılmadı. Planın diğer kabul işleri ve canlı yayın açık. + +### D09 — Araç ekranlarını ihtiyaç anında yükleme + +19 araç görünümü başlangıçtaki statik importlardan çıkarıldı; kullanıcı ilgili menüyü açınca dinamik yüklenir. Yükleme durumu erişilebilir status olarak gösterilir. Görünüm yüklenemezse hata sınırı yalnız o görünümü kapsar; yeniden deneme ana uygulamayı veya kayıt durumunu yeniden başlatmaz. Yönetici ekranının mevcut yetki koşulu korunur. + +Üretim derlemesi ölçümü: ana JavaScript 1.097,39 KB'den 526,09 KB'ye (gzip 306,24 KB'den 156,35 KB'ye) düştü. Grafik ortak paketi 384,20 KB olarak ayrıldı. Bunlar dosya boyutlarıdır; gerçek ağda ilk açılış süresi/LCP ölçülmüş değildir. 940 KB ExcelJS ve 500 KB üstü ana paket uyarıları hâlâ var; performans maddesi tamamen kapanmadı. + +Yerel tarayıcı kabulünde KDV, API, Belge Kasası ve Analitik ekranları açıldı; ana ihale listesine dönüşte beş sentetik ihale korundu. Kanıt qa-deferred-views.json. Geliştirme sunucusunda menü geçişi kabulüdür; üretim paketi ağ hatası/yeniden deneme ve tüm 19 ekranın etkileşim kabulü değildir. Tüm 137 test ve üretim derlemesi geçti. Canlı yayın yapılmadı. diff --git a/src/App.jsx b/src/App.jsx index 2ba8c82..e908bdd 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -8,36 +8,41 @@ import { SummaryCards } from './components/SummaryCards'; import { LeftSidebar } from './components/LeftSidebar'; import { TenderList } from './components/TenderList'; import { RightSidebar } from './components/RightSidebar'; -import { SmartFilterBuilder } from './components/SmartFilterBuilder'; import { DetailedSearchModal } from './components/DetailedSearchModal'; import { TenderDetailModal } from './components/TenderDetailModal'; import { CompanyScannerModal } from './components/CompanyScannerModal'; import { AiSpecAnalyzerModal } from './components/AiSpecAnalyzerModal'; import { UrunAramaModal } from './components/UrunAramaModal'; -import { KanbanBoard } from './components/KanbanBoard'; -import { DailyBulletin } from './components/tools/DailyBulletin'; -import { ResultSearch } from './components/tools/ResultSearch'; -import { TenderCalendar } from './components/tools/TenderCalendar'; -import { ContractSearch } from './components/tools/ContractSearch'; -import { VatCalculator } from './components/tools/VatCalculator'; -import { SinirDeger } from './components/tools/SinirDeger'; import { KullanimKilavuzu } from './components/KullanimKilavuzu'; import { MobilFiltreCekmecesi } from './components/MobilFiltreCekmecesi'; -import { PriceAnalysis } from './components/tools/PriceAnalysis'; -import { CompetitorRadar } from './components/tools/CompetitorRadar'; -import { DocumentVault } from './components/tools/DocumentVault'; -import { AnalyticsDashboard } from './components/tools/AnalyticsDashboard'; -import { RedFlags } from './components/tools/RedFlags'; -import { TedTenders } from './components/tools/TedTenders'; -import { Pricing } from './components/tools/Pricing'; -import { KikDecisions } from './components/tools/KikDecisions'; -import { ApiWebhooks } from './components/tools/ApiWebhooks'; -import { PwaSettings } from './components/tools/PwaSettings'; -import { AiModelSettings } from './components/tools/AiModelSettings'; import { LoginPage } from './components/LoginPage'; import { LandingPage } from './components/LandingPage'; +import { DeferredView } from './components/DeferredView'; + +const toolViews = { + smart_filter_builder: () => import('./components/SmartFilterBuilder').then(module => ({ default: module.SmartFilterBuilder })), + bulten: () => import('./components/tools/DailyBulletin').then(module => ({ default: module.DailyBulletin })), + sonuc: () => import('./components/tools/ResultSearch').then(module => ({ default: module.ResultSearch })), + takvim: () => import('./components/tools/TenderCalendar').then(module => ({ default: module.TenderCalendar })), + sozlesme: () => import('./components/tools/ContractSearch').then(module => ({ default: module.ContractSearch })), + kdv: () => import('./components/tools/VatCalculator').then(module => ({ default: module.VatCalculator })), + sinir: () => import('./components/tools/SinirDeger').then(module => ({ default: module.SinirDeger })), + fiyat: () => import('./components/tools/PriceAnalysis').then(module => ({ default: module.PriceAnalysis })), + kanban: () => import('./components/KanbanBoard').then(module => ({ default: module.KanbanBoard })), + rakip_radar: () => import('./components/tools/CompetitorRadar').then(module => ({ default: module.CompetitorRadar })), + dokuman_deposu: () => import('./components/tools/DocumentVault').then(module => ({ default: module.DocumentVault })), + analitik_dashboard: () => import('./components/tools/AnalyticsDashboard').then(module => ({ default: module.AnalyticsDashboard })), + kirmizi_bayrak: () => import('./components/tools/RedFlags').then(module => ({ default: module.RedFlags })), + ted_eu: () => import('./components/tools/TedTenders').then(module => ({ default: module.TedTenders })), + kik_kararlari: () => import('./components/tools/KikDecisions').then(module => ({ default: module.KikDecisions })), + planlar: () => import('./components/tools/Pricing').then(module => ({ default: module.Pricing })), + api_webhooks: () => import('./components/tools/ApiWebhooks').then(module => ({ default: module.ApiWebhooks })), + pwa_settings: () => import('./components/tools/PwaSettings').then(module => ({ default: module.PwaSettings })), + ai_ayarlari: () => import('./components/tools/AiModelSettings').then(module => ({ default: module.AiModelSettings })), +}; + const MainContent = () => { const { activeTab, isAdmin, saveError, savingCount } = useApp(); @@ -62,26 +67,8 @@ const MainContent = () => { )} - {/* Dedicated Tool Views */} - {activeTab === 'smart_filter_builder' && } - {activeTab === 'bulten' && } - {activeTab === 'sonuc' && } - {activeTab === 'takvim' && } - {activeTab === 'sozlesme' && } - {activeTab === 'kdv' && } - {activeTab === 'sinir' && } - {activeTab === 'fiyat' && } - {activeTab === 'kanban' && } - {activeTab === 'rakip_radar' && } - {activeTab === 'dokuman_deposu' && } - {activeTab === 'analitik_dashboard' && } - {activeTab === 'kirmizi_bayrak' && } - {activeTab === 'ted_eu' && } - {activeTab === 'kik_kararlari' && } - {activeTab === 'planlar' && } - {activeTab === 'api_webhooks' && } - {activeTab === 'pwa_settings' && } - {activeTab === 'ai_ayarlari' && isAdmin && } + {toolViews[activeTab] && (activeTab !== 'ai_ayarlari' || isAdmin) && + } {/* Global Modals */} diff --git a/src/components/DeferredView.jsx b/src/components/DeferredView.jsx new file mode 100644 index 0000000..110ebda --- /dev/null +++ b/src/components/DeferredView.jsx @@ -0,0 +1,22 @@ +import React, { Suspense, lazy, useMemo, useState } from 'react'; + +class ViewErrorBoundary extends React.Component { + state = { failed: false }; + static getDerivedStateFromError() { return { failed: true }; } + render() { + if (this.state.failed) return
+

Bu ekran yüklenemedi. Bağlantınızı kontrol edip yeniden deneyebilirsiniz.

+ +
; + return this.props.children; + } +} + +/** Retry only this view; keep the application and saved work mounted. */ +export function DeferredView({ load }) { + const [attempt, setAttempt] = useState(0); + const View = useMemo(() => lazy(load), [load, attempt]); + return setAttempt(n => n + 1)}> + Ekran yükleniyor…

}>
+
; +}