isolate analytics targets by account
This commit is contained in:
@@ -2146,3 +2146,9 @@ Doğrulama: masaüstü ve mobil browser kabulü başarılı; mobil görünümde
|
|||||||
Browser QA artık evrak kontrol listesinin Türkçe başlığını ve en az bir kontrol listesi satırını doğruluyor. Yazdırma medyasında `.yazdirma` eylem alanının gizlendiği de kontrol ediliyor; böylece başlık açılması tek başına çıktı kabulü sayılmıyor.
|
Browser QA artık evrak kontrol listesinin Türkçe başlığını ve en az bir kontrol listesi satırını doğruluyor. Yazdırma medyasında `.yazdirma` eylem alanının gizlendiği de kontrol ediliyor; böylece başlık açılması tek başına çıktı kabulü sayılmıyor.
|
||||||
|
|
||||||
Doğrulama: yerel sentetik hazır taslakta çıktı penceresi başlığı, Türkçe içerik, kontrol listesi satırı ve print görünümü kontrolleri başarılı.
|
Doğrulama: yerel sentetik hazır taslakta çıktı penceresi başlığı, Türkçe içerik, kontrol listesi satırı ve print görünümü kontrolleri başarılı.
|
||||||
|
|
||||||
|
### 2026-09-06 · Analitik hedefinin hesap izolasyonu
|
||||||
|
|
||||||
|
Analitik ekranındaki ciro hedefi daha önce ortak `localStorage` anahtarına yazılıyordu; bu, aynı tarayıcıda hesap değiştirildiğinde hedefin yanlış hesaba görünmesine neden olabilirdi. Hedef anahtarı artık normalize edilmiş hesap e-postasıyla ayrılıyor, depolama hataları güvenle ele alınıyor ve hesap değişiminde eski hedef yeni hesaba yazılmıyor.
|
||||||
|
|
||||||
|
Doğrulama: 293 otomatik test ve üretim derlemesi başarılı. Gerçek iki hesaplı tarayıcı kabulü ve canlı deployment hâlâ ayrıca yapılmalı.
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { companyStats, monthlyStats, sectorStats, formatTL } from '../../service
|
|||||||
const PIE_COLORS = ['#2563eb', '#059669', '#7c3aed', '#d97706', '#dc2626', '#0891b2', '#db2777', '#65a30d'];
|
const PIE_COLORS = ['#2563eb', '#059669', '#7c3aed', '#d97706', '#dc2626', '#0891b2', '#db2777', '#65a30d'];
|
||||||
|
|
||||||
export const AnalyticsDashboard = () => {
|
export const AnalyticsDashboard = () => {
|
||||||
const { tenders, userProfile } = useApp();
|
const { tenders, userProfile, authUser } = useApp();
|
||||||
|
|
||||||
const cs = companyStats(tenders);
|
const cs = companyStats(tenders);
|
||||||
const monthlyData = monthlyStats(tenders);
|
const monthlyData = monthlyStats(tenders);
|
||||||
@@ -16,10 +16,20 @@ export const AnalyticsDashboard = () => {
|
|||||||
const pieData = sektorler.slice(0, 6).map((s, i) => ({ name: s.sektor, value: s.count, color: PIE_COLORS[i % PIE_COLORS.length] }));
|
const pieData = sektorler.slice(0, 6).map((s, i) => ({ name: s.sektor, value: s.count, color: PIE_COLORS[i % PIE_COLORS.length] }));
|
||||||
const pieToplam = pieData.reduce((s, p) => s + p.value, 0);
|
const pieToplam = pieData.reduce((s, p) => s + p.value, 0);
|
||||||
|
|
||||||
// Ciro hedefi — kullanıcı belirler (localStorage)
|
// Ciro hedefi hesap bazında tutulur; ortak anahtar hesaplar arası veri sızdırır.
|
||||||
const [hedef, setHedef] = useState(() => Number(localStorage.getItem('ihaleist_ciro_hedefi') || 0));
|
const hedefAnahtari = authUser?.email ? `ihaleist_ciro_hedefi:${encodeURIComponent(authUser.email.toLowerCase())}` : null;
|
||||||
|
const [hedef, setHedef] = useState(0);
|
||||||
|
const [hedefYuklenenAnahtar, setHedefYuklenenAnahtar] = useState(null);
|
||||||
const [editing, setEditing] = useState(false);
|
const [editing, setEditing] = useState(false);
|
||||||
useEffect(() => { localStorage.setItem('ihaleist_ciro_hedefi', String(hedef)); }, [hedef]);
|
useEffect(() => {
|
||||||
|
if (!hedefAnahtari) { setHedef(0); setHedefYuklenenAnahtar(null); return; }
|
||||||
|
try { setHedef(Number(localStorage.getItem(hedefAnahtari) || 0) || 0); } catch { setHedef(0); }
|
||||||
|
setHedefYuklenenAnahtar(hedefAnahtari);
|
||||||
|
}, [hedefAnahtari]);
|
||||||
|
useEffect(() => {
|
||||||
|
if (!hedefAnahtari || hedefYuklenenAnahtar !== hedefAnahtari) return;
|
||||||
|
try { localStorage.setItem(hedefAnahtari, String(hedef)); } catch { /* özel tarama/kota */ }
|
||||||
|
}, [hedef, hedefAnahtari, hedefYuklenenAnahtar]);
|
||||||
const hedefYuzde = hedef > 0 ? Math.min(Math.round((cs.wonTotal / hedef) * 100), 100) : 0;
|
const hedefYuzde = hedef > 0 ? Math.min(Math.round((cs.wonTotal / hedef) * 100), 100) : 0;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
Reference in New Issue
Block a user