Group navigation by discovery preparation market and management
This commit is contained in:
@@ -38,8 +38,8 @@ const KILAVUZ = {
|
||||
kanban: {
|
||||
baslik: 'Kanban Pano',
|
||||
ne: 'Takipteki ihalelerin süreç panosu: İncelenecek → İnceleniyor → Teklif Hazırlanıyor → Verildi → Kazanıldı/Kaybedildi.',
|
||||
adimlar: ['Kartları sürükleyerek kolon değiştirin.', 'İhale detayında "Hazırlık Görevi Aç" deyin: teslim tarihi ihale saati olur, kartta geri sayım başlar (BUGÜN / 2 gün / süresi geçti).', 'Derin analizden gelen belge kontrol listesi görevin içinde işaretlenir.'],
|
||||
ipuclari: ['Görev açılmış ihale sonuçlanınca bildirim gelir: kim, kaça, %kaç kırım.'],
|
||||
adimlar: ['Kartın iş akışı durumunu seçin veya kartı sürükleyin. Kayıt tamamlanana kadar bekleyin; hata varsa işlem kaydedilmiş sayılmaz.', 'İhale detayında "Hazırlık Görevi Aç" ile dosyayı panoya ekleyin; sorumluyu karttan atayın.', 'Hazırlık dosyaları özetinde eksik belge ve sıradaki kontrolü açın. Eksik bağlantısı dosyanın ilgili hazırlık alanına götürür; değişikliği taslağa kaydedince özet güncellenir.'],
|
||||
ipuclari: ['Kontrol sayısı kayıtlı taslağa dayanır ve resmi başvuru onayı değildir. Belge durumunu yenile düğmesiyle depo kayıtlarını tekrar kontrol edin.', 'Slack/Teams gönderimi bu panoda desteklenmez.'],
|
||||
},
|
||||
rakip_radar: { baslik: 'Rakip Radar', ne: 'Kazanan firmalar, kırım oranı, ortalama teklif sayısı, tek teklifle kazanma oranı.', adimlar: ['"Radara Ekle" ile izleyin; teklif verince/kazanınca uyarı alın.', '"⛔ yasaklı sorgula" KİK sorgusunu açar, firma adını panoya kopyalar.'], ipuclari: ['Kırım oranı yalnız kısımsız ihalelerde hesaplanır — kısmi ihalede sayı yanıltıcı olurdu.'] },
|
||||
dokuman_deposu: {
|
||||
@@ -127,6 +127,7 @@ export const KullanimKilavuzu = () => {
|
||||
<button onClick={() => setAcik(false)} className="text-slate-400 hover:text-white p-1" aria-label="Kapat"><X className="w-5 h-5" /></button>
|
||||
</div>
|
||||
<div className="flex-1 overflow-y-auto p-5 space-y-5">
|
||||
<p className="text-xs text-slate-600">Üst menüde Keşfet ilanları ve takvimi, Hazırlan dosyaları ve hesap araçlarını, Pazar sonuçları ve analizleri, Yönetim hesap ve bağlantı ayarlarını açar. AI model ayarları yalnız yöneticilere görünür.</p>
|
||||
<p className="text-xs text-slate-700 leading-relaxed bg-slate-50 border border-slate-200 rounded-xl p-3">{k.ne}</p>
|
||||
<Bolum icon={ListChecks} renk="text-blue-600" baslik="Nasıl kullanılır" satirlar={k.adimlar} sirali />
|
||||
<Bolum icon={Lightbulb} renk="text-amber-500" baslik="İpuçları" satirlar={k.ipuclari} />
|
||||
|
||||
@@ -27,6 +27,13 @@ const RENK = {
|
||||
};
|
||||
const RENK_VARSAYILAN = { ikon: 'text-slate-500', aktif: 'border-blue-200 bg-blue-50 text-blue-700', hover: 'hover:bg-slate-50' };
|
||||
|
||||
const NAV_GROUPS = [
|
||||
{id:'discover',label:'Keşfet',tabs:['list','bulten','takvim','ted_eu']},
|
||||
{id:'prepare',label:'Hazırlan',tabs:['kanban','dokuman_deposu','kdv','sinir','kik_kararlari']},
|
||||
{id:'market',label:'Pazar',tabs:['sonuc','sozlesme','fiyat','rakip_radar','analitik_dashboard','kirmizi_bayrak']},
|
||||
{id:'manage',label:'Yönetim',tabs:['planlar','api_webhooks','pwa_settings','ai_ayarlari']},
|
||||
];
|
||||
|
||||
export const TopNavigation = () => {
|
||||
const { activeTab, setActiveTab, isAdmin } = useApp();
|
||||
|
||||
@@ -66,6 +73,9 @@ export const TopNavigation = () => {
|
||||
{ id: 'pwa_settings', label: 'Mobil PWA', icon: Smartphone }
|
||||
];
|
||||
|
||||
const activeGroup=NAV_GROUPS.find(group=>group.tabs.includes(bekleyen || activeTab)) || NAV_GROUPS[0];
|
||||
const visibleItems=activeGroup.tabs.map(id=>navItems.find(item=>item.id===id)).filter(Boolean);
|
||||
|
||||
// 18 sekme çoğu ekrana sığmıyor. Kaydırma çubuğu gizli olduğu için sondaki
|
||||
// sekmeler (Planlar, API & Webhooks, Mobil PWA) görünmez kalıyordu; taşma
|
||||
// olduğunda ok düğmeleri gösterilir ve etkin sekme görünür alana kaydırılır.
|
||||
@@ -97,7 +107,8 @@ export const TopNavigation = () => {
|
||||
useEffect(() => {
|
||||
const el = seritRef.current?.querySelector(`[data-tab="${activeTab}"]`);
|
||||
el?.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'center' });
|
||||
}, [activeTab]);
|
||||
tasmaHesapla();
|
||||
}, [activeTab, activeGroup.id, tasmaHesapla]);
|
||||
|
||||
const kaydir = (yon) => {
|
||||
seritRef.current?.scrollBy({ left: yon * 280, behavior: 'smooth' });
|
||||
@@ -105,6 +116,13 @@ export const TopNavigation = () => {
|
||||
|
||||
return (
|
||||
<div className="bg-white border-b border-slate-200 shadow-xs sticky top-16 z-30">
|
||||
<nav aria-label="Çalışma alanları" className="max-w-[1600px] mx-auto px-4 pt-2 flex flex-wrap gap-2">
|
||||
{NAV_GROUPS.map(group=><button key={group.id} type="button" aria-pressed={group.id===activeGroup.id}
|
||||
onClick={()=>{if(group.id!==activeGroup.id)sekmeSec(group.tabs.find(id=>navItems.some(item=>item.id===id)));}}
|
||||
className={`px-4 py-2 rounded-lg text-sm font-bold border ${group.id===activeGroup.id ? 'bg-slate-900 text-white border-slate-900' : 'border-slate-200 text-slate-700 hover:bg-slate-50'}`}>
|
||||
{group.label}
|
||||
</button>)}
|
||||
</nav>
|
||||
<div className="max-w-[1600px] mx-auto px-4 relative">
|
||||
{tasma.sol && (
|
||||
<button
|
||||
@@ -126,8 +144,8 @@ export const TopNavigation = () => {
|
||||
<ChevronRight className="w-4 h-4" />
|
||||
</button>
|
||||
)}
|
||||
<div ref={seritRef} className="flex items-center gap-1 overflow-x-auto py-1 scrollbar-none scroll-smooth">
|
||||
{navItems.map(item => {
|
||||
<nav aria-label={`${activeGroup.label} araçları`} ref={seritRef} className="flex items-center gap-1 overflow-x-auto py-1 scrollbar-none scroll-smooth">
|
||||
{visibleItems.map(item => {
|
||||
const Icon = item.icon;
|
||||
const renk = RENK[item.id] || RENK_VARSAYILAN;
|
||||
const isActive = bekleyen ? bekleyen === item.id : activeTab === item.id;
|
||||
@@ -136,6 +154,7 @@ export const TopNavigation = () => {
|
||||
<button
|
||||
key={item.id}
|
||||
data-tab={item.id}
|
||||
aria-current={isActive ? 'page' : undefined}
|
||||
aria-busy={yukleniyor || undefined}
|
||||
onClick={() => sekmeSec(item.id)}
|
||||
className={`flex items-center gap-2 px-3.5 py-2 rounded-lg border text-xs font-semibold whitespace-nowrap transition-all select-none ${
|
||||
@@ -156,7 +175,7 @@ export const TopNavigation = () => {
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user