feat: demo özelliklerini gerçekleştir — canlı veri + localStorage
- analytics.js: firmStats/itemStats/provinceDensity (gerçek hesaplama) - Rakip Radar: canlı veriden kazanan firma analizi (mock 3 firma kaldırıldı) - Fiyat Analizi: gerçek kalem min/medyan/ort/maks + CSV export - TurkeyHeatMap: 81 il gerçek interaktif yoğunluk haritası (tıkla→filtrele) - Favori kurumlar: kart yıldızı + hızlı filtre (localStorage) - Ekip yönetimi: gerçek CRUD (RightSidebar) + Kanban ataması ekipten - Bildirimler: gerçek Notification API + izin + test + sessiz saatler - PDF: jsPDF ile gerçek birim fiyat teklif cetveli (kaşe/imza alanı)
This commit is contained in:
@@ -1,13 +1,24 @@
|
||||
import React, { useState } from 'react';
|
||||
import { useApp } from '../../context/AppContext';
|
||||
import { Smartphone, Wifi, WifiOff, Download, Bell, CheckCircle2, ShieldCheck, Zap, Sparkles } from 'lucide-react';
|
||||
import { Smartphone, Wifi, WifiOff, Download, Bell, CheckCircle2, ShieldCheck, Zap, Sparkles, Moon } from 'lucide-react';
|
||||
import confetti from 'canvas-confetti';
|
||||
|
||||
export const PwaSettings = () => {
|
||||
const { userProfile } = useApp();
|
||||
const { userProfile, reminderSettings, setReminderSettings, requestPushPermission, notify, isQuietNow } = useApp();
|
||||
const [offlineMode, setOfflineMode] = useState(true);
|
||||
const [pushSubscribed, setPushSubscribed] = useState(true);
|
||||
const [installed, setInstalled] = useState(false);
|
||||
const [permission, setPermission] = useState(typeof Notification !== 'undefined' ? Notification.permission : 'unsupported');
|
||||
|
||||
const handleEnablePush = async () => {
|
||||
const p = await requestPushPermission();
|
||||
setPermission(p);
|
||||
if (p === 'granted') {
|
||||
setReminderSettings((s) => ({ ...s, pushEnabled: true }));
|
||||
notify('Bildirimler açıldı', 'Yeni ihale ve son tarih uyarıları buradan gelecek.');
|
||||
confetti({ particleCount: 50 });
|
||||
}
|
||||
};
|
||||
const setQuiet = (patch) => setReminderSettings((s) => ({ ...s, ...patch }));
|
||||
|
||||
const handleInstallPwa = () => {
|
||||
setInstalled(true);
|
||||
@@ -67,30 +78,60 @@ export const PwaSettings = () => {
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Mobile Push Notifications */}
|
||||
{/* Gerçek Tarayıcı Bildirimleri + Sessiz Saatler */}
|
||||
<div className="bg-white p-6 rounded-2xl border border-slate-200 shadow-xs space-y-4">
|
||||
<div className="flex items-center justify-between border-b border-slate-100 pb-3">
|
||||
<h3 className="font-extrabold text-sm text-slate-900 flex items-center gap-2">
|
||||
<Bell className="w-4 h-4 text-amber-500" /> Anlık Mobil Push Bildirimleri
|
||||
<Bell className="w-4 h-4 text-amber-500" /> Anlık Bildirimler
|
||||
</h3>
|
||||
<span className="bg-amber-100 text-amber-800 font-extrabold text-[10px] px-2 py-0.5 rounded-full">
|
||||
İzin Verildi
|
||||
<span className={`font-extrabold text-[10px] px-2 py-0.5 rounded-full ${
|
||||
permission === 'granted' ? 'bg-emerald-100 text-emerald-800' : permission === 'denied' ? 'bg-red-100 text-red-700' : 'bg-slate-100 text-slate-600'
|
||||
}`}>
|
||||
{permission === 'granted' ? 'İzin Verildi' : permission === 'denied' ? 'Reddedildi' : permission === 'unsupported' ? 'Desteklenmiyor' : 'İzin Bekliyor'}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<p className="text-xs text-slate-600 leading-relaxed">
|
||||
İhale son başvuru saatine 3 saat kala mobil cihazınıza sesli ve titreşimli anlık uyarı bildirimi gönderilir.
|
||||
Tarayıcı bildirimlerine izin verin; yeni ihale ve son tarih uyarıları gerçek bildirim olarak gelir.
|
||||
</p>
|
||||
|
||||
<label className="flex items-center justify-between p-3 bg-slate-50 rounded-xl border border-slate-200 cursor-pointer text-xs font-bold text-slate-800">
|
||||
<span>Mobil Push Uyarısı</span>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={pushSubscribed}
|
||||
onChange={() => setPushSubscribed(!pushSubscribed)}
|
||||
className="w-4 h-4 accent-cyan-600 rounded"
|
||||
/>
|
||||
</label>
|
||||
{permission !== 'granted' ? (
|
||||
<button onClick={handleEnablePush} disabled={permission === 'unsupported'}
|
||||
className="w-full bg-amber-500 hover:bg-amber-400 disabled:opacity-40 text-white font-bold text-xs py-2.5 rounded-xl">
|
||||
Bildirimlere İzin Ver
|
||||
</button>
|
||||
) : (
|
||||
<button onClick={() => notify('Test bildirimi', isQuietNow() ? 'Sessiz saatte — sadece listeye eklendi.' : 'Bildirimler çalışıyor ✓')}
|
||||
className="w-full bg-emerald-600 hover:bg-emerald-500 text-white font-bold text-xs py-2.5 rounded-xl">
|
||||
Test Bildirimi Gönder
|
||||
</button>
|
||||
)}
|
||||
|
||||
{/* Sessiz saatler — gerçek */}
|
||||
<div className="pt-2 border-t border-slate-100 space-y-2">
|
||||
<label className="flex items-center justify-between text-xs font-bold text-slate-800 cursor-pointer">
|
||||
<span className="flex items-center gap-1.5"><Moon className="w-3.5 h-3.5 text-indigo-500" /> Sessiz Saatler</span>
|
||||
<input type="checkbox" checked={reminderSettings.quietEnabled}
|
||||
onChange={(e) => setQuiet({ quietEnabled: e.target.checked })}
|
||||
className="w-4 h-4 accent-indigo-600 rounded" />
|
||||
</label>
|
||||
{reminderSettings.quietEnabled && (
|
||||
<div className="flex items-center gap-2 text-xs">
|
||||
<input type="time" value={reminderSettings.quietStart}
|
||||
onChange={(e) => setQuiet({ quietStart: e.target.value })}
|
||||
className="bg-slate-50 border border-slate-300 rounded-lg px-2 py-1.5 flex-1" />
|
||||
<span className="text-slate-400">→</span>
|
||||
<input type="time" value={reminderSettings.quietEnd}
|
||||
onChange={(e) => setQuiet({ quietEnd: e.target.value })}
|
||||
className="bg-slate-50 border border-slate-300 rounded-lg px-2 py-1.5 flex-1" />
|
||||
</div>
|
||||
)}
|
||||
{reminderSettings.quietEnabled && (
|
||||
<p className="text-[10px] text-slate-400">
|
||||
{isQuietNow() ? '🔕 Şu an sessiz saatte — tarayıcı bildirimi gösterilmez, uyarılar listeye eklenir.' : '🔔 Şu an aktif — bildirimler gösterilir.'}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Install PWA Application */}
|
||||
|
||||
Reference in New Issue
Block a user