fix: unify tender countdowns and add monthly calendar navigation

This commit is contained in:
2026-09-06 08:47:44 +03:00
parent a291b186df
commit b94ab97241
8 changed files with 123 additions and 49 deletions
+26 -22
View File
@@ -1,20 +1,17 @@
import { useDeadlineClock } from '../../hooks/useDeadlineClock';
import { calendarMonthDays, istanbulDateKey, tenderDateKey, deadlineInfo } from '../../services/tenderCalendar';
import React, { useState } from 'react';
import { useApp } from '../../context/AppContext';
import { CalendarDays, Clock, MapPin, AlertCircle } from 'lucide-react';
export const TenderCalendar = () => {
const now = useDeadlineClock();
const { tenders, setActiveTenderDetail } = useApp();
const GUNLER = ['Pazar', 'Pazartesi', 'Salı', 'Çarşamba', 'Perşembe', 'Cuma', 'Cumartesi'];
const ggaayyyy = (d) => `${String(d.getDate()).padStart(2, '0')}.${String(d.getMonth() + 1).padStart(2, '0')}.${d.getFullYear()}`;
// Bugünden başlayan 7 gün; sayılar havuzdaki gerçek ihale tarihlerinden.
const daysList = Array.from({ length: 7 }, (_, i) => {
const d = new Date(); d.setHours(0, 0, 0, 0); d.setDate(d.getDate() + i);
const date = ggaayyyy(d);
return { date, label: i === 0 ? `Bugün (${GUNLER[d.getDay()]})` : i === 1 ? `Yarın (${GUNLER[d.getDay()]})` : GUNLER[d.getDay()], count: tenders.filter(t => t.tarih === date).length };
});
const [selectedDay, setSelectedDay] = useState(daysList[0].date);
const dayTenders = tenders.filter(t => t.tarih === selectedDay);
const today = istanbulDateKey(now);
const [month,setMonth] = useState(today.slice(0,7));
const [selectedDay, setSelectedDay] = useState(today);
const daysList = calendarMonthDays(month).map(day => ({...day,count:tenders.filter(t=>tenderDateKey(t)===day.key).length}));
const dayTenders = tenders.filter(t => tenderDateKey(t) === selectedDay);
return (
<div className="space-y-4 my-4 animate-fade-in">
@@ -26,30 +23,34 @@ export const TenderCalendar = () => {
<CalendarDays className="w-6 h-6" />
</div>
<div>
<h1 className="text-xl font-black text-slate-900">7 Günlük İhale Takvimi</h1>
<p className="text-xs text-slate-500">Önümüzdeki 7 gün içerisinde kapanacak ihaleleri günü gününe takip edin.</p>
<h1 className="text-xl font-black text-slate-900">İhale Takvimi</h1>
<p className="text-xs text-slate-500">Ay ve gün seçerek ihale tarihlerini görüntüleyin. Saatler Türkiye saatidir.</p>
</div>
</div>
</div>
<label className="block text-sm font-semibold">Takvim ayı
<input type="month" value={month} onChange={e => {if(calendarMonthDays(e.target.value).length){setMonth(e.target.value);setSelectedDay(e.target.value+'-01');}}}
className="ml-3 border border-slate-300 rounded-lg p-2"/>
</label>
{/* Day Selector Buttons */}
<div className="flex items-center gap-2 overflow-x-auto pb-1">
<div className="grid grid-cols-2 sm:grid-cols-4 lg:grid-cols-7 gap-2">
{daysList.map(d => (
<button
key={d.date}
onClick={() => setSelectedDay(d.date)}
className={`flex-1 min-w-[130px] p-3 rounded-xl border text-center transition-all cursor-pointer ${
selectedDay === d.date
key={d.key}
onClick={() => setSelectedDay(d.key)}
className={`min-w-0 p-3 rounded-xl border text-center transition-all cursor-pointer ${
selectedDay === d.key
? 'bg-purple-600 text-white border-purple-700 shadow-sm font-bold'
: 'bg-white text-slate-700 border-slate-200 hover:bg-slate-50 font-semibold'
}`}
>
<span className="text-[11px] block text-purple-200 opacity-90">{d.label}</span>
<span className="text-[11px] block opacity-90">{d.label}</span>
<span className="text-sm font-black block mt-0.5">{d.date}</span>
<span className={`text-[10px] mt-1 inline-block px-2 py-0.5 rounded-full ${
selectedDay === d.date ? 'bg-white/20 text-white font-extrabold' : 'bg-purple-100 text-purple-800 font-bold'
selectedDay === d.key ? 'bg-white/20 text-white font-extrabold' : 'bg-purple-100 text-purple-800 font-bold'
}`}>
{d.count} İhale Kapanıyor
{d.count} İhale
</span>
</button>
))}
@@ -57,16 +58,19 @@ export const TenderCalendar = () => {
{/* Tenders List for Selected Day */}
<div className="space-y-3">
<h2 className="text-sm font-bold">{selectedDay.split('-').reverse().join('.')} tarihli ihaleler</h2>
{!dayTenders.length && <p className="text-sm text-slate-500">Bu gün için yüklenen havuzda ihale yok.</p>}
{dayTenders.map(t => (
<div
key={t.id}
role="button" tabIndex={0} onKeyDown={e=>{if(e.key==='Enter' || e.key===' '){e.preventDefault();setActiveTenderDetail(t);}}}
onClick={() => setActiveTenderDetail(t)}
className="bg-white rounded-xl border border-slate-200 p-4 shadow-xs hover:shadow-md cursor-pointer transition-all flex items-center justify-between gap-4"
>
<div className="space-y-1">
<div className="flex items-center gap-2">
<span className="bg-purple-100 text-purple-900 text-[10px] font-extrabold px-2 py-0.5 rounded">
⏰ {t.saat}
⏰ {deadlineInfo(t, now).deadline?.toLocaleTimeString('tr-TR',{hour:'2-digit',minute:'2-digit',timeZone:'Europe/Istanbul'}) || 'Saat doğrulanmalı'}
</span>
<span className="text-xs text-slate-400 font-mono">#{t.ikn}</span>
</div>