kaza namazı düşme düzeltmesi.

This commit is contained in:
2026-07-29 04:31:41 +02:00
parent 579a51f899
commit 9b62e4b312
+92 -96
View File
@@ -1,4 +1,4 @@
import { calculateMissedPrayers, getHijribirthdate } from "../utils/hijri.js"; import { calculateMissedPrayers } from "../utils/hijri.js";
const PRAYERS = [ const PRAYERS = [
{ id: "fajr", name: "SABAH", arabic: "Fecr" }, { id: "fajr", name: "SABAH", arabic: "Fecr" },
@@ -10,9 +10,8 @@ const PRAYERS = [
]; ];
export function renderKaza(pb) { export function renderKaza(pb) {
// Sıfır localStorage! Her şey PocketBase authStore modelinden okunuyor.
const user = pb.authStore.model; const user = pb.authStore.model;
const birthdate = user?.birthdate || user?.birthdate; const birthDate = user?.birthDate || user?.birthdate;
const gender = user?.gender || "male"; const gender = user?.gender || "male";
const html = ` const html = `
@@ -24,21 +23,21 @@ export function renderKaza(pb) {
<div class="flex items-center gap-3 mb-2"> <div class="flex items-center gap-3 mb-2">
<span class="text-3xl">📿</span> <span class="text-3xl">📿</span>
<div> <div>
<h2 class="text-2xl font-bold text-white">Kaza Namazı Takibi</h2> <h2 class="text-2xl font-bold text-white">Kaza Namazı Sayaç & Takip</h2>
<p class="text-slate-400 text-xs">Tamamlanan namazlar anlık olarak PocketBase hesabınla eşzamanlanır.</p> <p class="text-slate-400 text-xs">Tamamladığın vakitler anlık olarak PocketBase hesabında güncellenir.</p>
</div> </div>
</div> </div>
${ ${
!birthdate !birthDate
? ` ? `
<div class="bg-slate-900/50 border border-white/10 p-6 rounded-2xl my-auto text-center max-w-md mx-auto w-full"> <div class="bg-slate-900/50 border border-white/10 p-6 rounded-2xl my-auto text-center max-w-md mx-auto w-full">
<h3 class="text-base font-bold text-white mb-2">Doğum Tarihi Gerekli</h3> <h3 class="text-base font-bold text-white mb-2">Doğum Tarihi Gerekli</h3>
<p class="text-xs text-slate-400 mb-6">Kaza namazı borcunu tam hesaplayabilmemiz için bilgilerinizi kaydedin.</p> <p class="text-xs text-slate-400 mb-6">Kaza namazı borcunu hesaplayabilmemiz için profil bilgilerinizi girin.</p>
<form id="profileForm" class="space-y-4"> <form id="profileForm" class="space-y-4">
<div class="text-left"> <div class="text-left">
<label class="block text-xs text-slate-300 mb-1">Doğum Tarihi</label> <label class="block text-xs text-slate-300 mb-1">Doğum Tarihi</label>
<input type="date" id="birthdateInput" required class="w-full bg-slate-950 border border-slate-800 rounded-xl px-4 py-2.5 text-white text-sm focus:border-indigo-500 focus:outline-none" /> <input type="date" id="birthDateInput" required class="w-full bg-slate-950 border border-slate-800 rounded-xl px-4 py-2.5 text-white text-sm focus:border-indigo-500 focus:outline-none" />
</div> </div>
<div class="text-left"> <div class="text-left">
<label class="block text-xs text-slate-300 mb-1">Cinsiyet</label> <label class="block text-xs text-slate-300 mb-1">Cinsiyet</label>
@@ -48,37 +47,38 @@ export function renderKaza(pb) {
</select> </select>
</div> </div>
<button type="submit" class="w-full bg-indigo-600 hover:bg-indigo-500 text-white py-2.5 rounded-xl text-sm font-semibold transition-all"> <button type="submit" class="w-full bg-indigo-600 hover:bg-indigo-500 text-white py-2.5 rounded-xl text-sm font-semibold transition-all">
Hesapla ve Kaydet Hesapla ve Başla
</button> </button>
</form> </form>
</div> </div>
` `
: ` : `
<!-- OYUNLAŞTIRILMIŞ GENEL İLERLEME (PROGRESS BAR) --> <!-- GENEL İLERLEME BARI (XP/PERCENTAGE) -->
<div class="bg-slate-950/60 border border-white/10 p-5 rounded-2xl mb-6 mt-2"> <div class="bg-slate-950/60 border border-white/10 p-5 rounded-2xl mb-6 mt-2">
<div class="flex items-center justify-between mb-2"> <div class="flex items-center justify-between mb-2">
<span class="text-xs font-bold text-indigo-300 flex items-center gap-1.5"> <span class="text-xs font-bold text-indigo-300 flex items-center gap-1.5">
<span>🎯</span> TOPLAM İLERLEME (XP) <span>🎯</span> GENEL KAZA BİTİRME ORANI
</span> </span>
<span id="overallPercentage" class="text-sm font-extrabold text-emerald-400">%0</span> <span id="overallPercentage" class="text-sm font-extrabold text-emerald-400">%0</span>
</div> </div>
<div class="w-full h-3.5 bg-slate-900 rounded-full overflow-hidden border border-white/5 p-0.5"> <div class="w-full h-4 bg-slate-900 rounded-full overflow-hidden border border-white/5 p-0.5">
<div id="overallProgressBar" class="h-full bg-linear-to-r from-indigo-500 via-purple-500 to-emerald-400 rounded-full transition-all duration-700 ease-out w-[0%]"></div> <div id="overallProgressBar" class="h-full bg-linear-to-r from-indigo-500 via-purple-500 to-emerald-400 rounded-full transition-all duration-700 ease-out w-[0%]"></div>
</div> </div>
<div class="flex justify-between items-center text-[10px] text-slate-400 mt-2"> <div class="flex justify-between items-center text-[11px] text-slate-400 mt-2.5">
<span>Kılınan: <b id="totalCompletedText" class="text-white">0</b> vakit</span> <span>Kılınan Toplam: <b id="totalCompletedText" class="text-emerald-400">0</b> vakit</span>
<span>Kalan Borç: <b id="totalRemainingText" class="text-amber-400">0</b> vakit</span> <span>Kalan Toplam Borç: <b id="totalRemainingText" class="text-amber-400">0</b> vakit</span>
</div> </div>
</div> </div>
<!-- VAKİT KARTLARI --> <!-- VAKİT İLERLEME KARTLARI -->
<div class="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-6 gap-3 mb-6"> <div class="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-6 gap-3 mb-6">
${PRAYERS.map( ${PRAYERS.map(
(p) => ` (p) => `
<div class="bg-slate-950/40 border border-white/10 p-3 rounded-2xl text-center relative overflow-hidden group"> <div class="bg-slate-950/40 border border-white/10 p-3.5 rounded-2xl text-center relative overflow-hidden group">
<p class="text-[11px] font-bold text-slate-300 mb-1">${p.name}</p> <p class="text-[11px] font-bold text-slate-300 mb-1">${p.name}</p>
<p class="text-xs text-slate-400">Kalan: <span id="remaining-${p.id}" class="font-extrabold text-emerald-300">-</span></p> <p class="text-xs text-slate-400">Kalan: <span id="remaining-${p.id}" class="font-extrabold text-emerald-300">-</span></p>
<div class="w-full bg-slate-800 h-1.5 rounded-full mt-2 overflow-hidden"> <p class="text-[10px] text-slate-500 mt-0.5">Kılınan: <span id="completed-${p.id}" class="text-slate-300">0</span></p>
<div class="w-full bg-slate-800 h-1.5 rounded-full mt-2.5 overflow-hidden">
<div id="progress-${p.id}" class="bg-emerald-400 h-full w-[0%] transition-all duration-500"></div> <div id="progress-${p.id}" class="bg-emerald-400 h-full w-[0%] transition-all duration-500"></div>
</div> </div>
</div> </div>
@@ -86,30 +86,23 @@ export function renderKaza(pb) {
).join("")} ).join("")}
</div> </div>
<!-- KAZA EKLE / DÜŞ ALANI --> <!-- HIZLI SAYAÇ GÜNCELLEME ALANI -->
<div class="bg-slate-950/40 border border-white/10 p-4 rounded-2xl mb-6"> <div class="bg-slate-950/40 border border-white/10 p-5 rounded-2xl mb-auto">
<h3 class="text-xs font-bold text-slate-300 uppercase tracking-wider mb-3">Kaza Sayacı İşlem</h3>
<form id="addKazaForm" class="flex flex-wrap items-center gap-3"> <form id="addKazaForm" class="flex flex-wrap items-center gap-3">
<select id="kazaPrayerType" class="bg-slate-900 border border-slate-800 rounded-xl px-4 py-2 text-white text-sm focus:outline-none"> <select id="kazaPrayerType" class="bg-slate-900 border border-slate-800 rounded-xl px-4 py-2.5 text-white text-sm focus:outline-none">
${PRAYERS.map((p) => `<option value="${p.id}">${p.name}</option>`).join("")} ${PRAYERS.map((p) => `<option value="${p.id}">${p.name}</option>`).join("")}
</select> </select>
<input type="number" id="kazaCount" min="1" value="1" required class="w-20 bg-slate-900 border border-slate-800 rounded-xl px-4 py-2 text-white text-sm text-center focus:outline-none" /> <input type="number" id="kazaCount" min="1" value="1" required class="w-24 bg-slate-900 border border-slate-800 rounded-xl px-4 py-2.5 text-white text-sm text-center focus:outline-none font-bold" />
<button type="button" id="addKazaBtn" class="bg-emerald-600 hover:bg-emerald-500 text-white px-5 py-2 rounded-xl text-sm font-semibold transition-all shadow-lg active:scale-95 flex items-center gap-1.5"> <button type="button" id="addKazaBtn" class="bg-emerald-600 hover:bg-emerald-500 text-white px-5 py-2.5 rounded-xl text-sm font-semibold transition-all shadow-lg active:scale-95 flex items-center gap-1.5">
<span>✓</span> Kılınan Ekle <span>✓</span> Kıldım / Ekle (+)
</button> </button>
<button type="button" id="removeKazaBtn" class="bg-rose-600/30 hover:bg-rose-600/50 text-rose-300 border border-rose-500/30 px-4 py-2 rounded-xl text-sm font-medium transition-all active:scale-95"> <button type="button" id="removeKazaBtn" class="bg-rose-600/30 hover:bg-rose-600/50 text-rose-300 border border-rose-500/30 px-4 py-2.5 rounded-xl text-sm font-medium transition-all active:scale-95">
Geri Al (-) Geri Al (-)
</button> </button>
</form> </form>
<p id="kazaMsg" class="text-xs mt-2.5 hidden"></p> <p id="kazaMsg" class="text-xs mt-3 hidden"></p>
</div>
<!-- SON İŞLEMLER -->
<div class="flex-1 overflow-y-auto pr-1">
<h3 class="text-xs font-bold text-slate-400 uppercase tracking-wider mb-3">Son Kaza Geçmişi</h3>
<div class="space-y-2" id="logsContainer">
<p class="text-xs text-slate-500">Yükleniyor...</p>
</div>
</div> </div>
` `
} }
@@ -125,17 +118,18 @@ export function renderKaza(pb) {
); );
}); });
if (!birthdate) { if (!birthDate) {
container container
.querySelector("#profileForm") .querySelector("#profileForm")
?.addEventListener("submit", async (e) => { ?.addEventListener("submit", async (e) => {
e.preventDefault(); e.preventDefault();
const bInput = container.querySelector("#birthdateInput").value; const bInput = container.querySelector("#birthDateInput").value;
const gInput = container.querySelector("#genderInput").value; const gInput = container.querySelector("#genderInput").value;
try { try {
await pb.collection("users").update(pb.authStore.model.id, { await pb.collection("users").update(pb.authStore.model.id, {
birthdate: bInput, birthdate: bInput,
birthDate: bInput,
gender: gInput, gender: gInput,
}); });
pb.authStore.model.birthdate = bInput; pb.authStore.model.birthdate = bInput;
@@ -145,107 +139,129 @@ export function renderKaza(pb) {
); );
} catch (err) { } catch (err) {
alert( alert(
"Profil kaydedilemedi. PocketBase bağlantısını kontrol edin.", "Profil kaydedilemedi. PocketBase alan adlarını kontrol edin.",
); );
} }
}); });
} else { } else {
refreshKazaStats(container, pb, birthdate, gender); refreshKazaStats(container, pb, birthDate, gender);
container container
.querySelector("#addKazaBtn") .querySelector("#addKazaBtn")
?.addEventListener("click", async () => { ?.addEventListener("click", async () => {
await handleKazaLog(container, pb, birthdate, gender, 1); await updateKazaCount(container, pb, birthDate, gender, 1);
}); });
container container
.querySelector("#removeKazaBtn") .querySelector("#removeKazaBtn")
?.addEventListener("click", async () => { ?.addEventListener("click", async () => {
await handleKazaLog(container, pb, birthdate, gender, -1); await updateKazaCount(container, pb, birthDate, gender, -1);
}); });
} }
}, },
}; };
} }
async function handleKazaLog(container, pb, birthdate, gender, multiplier) { // PocketBase Tek Satır Güncelleme Mantığı
async function updateKazaCount(container, pb, birthDate, gender, direction) {
const prayerId = container.querySelector("#kazaPrayerType").value; const prayerId = container.querySelector("#kazaPrayerType").value;
const countInput = container.querySelector("#kazaCount"); const countInput = container.querySelector("#kazaCount");
const count = const amount =
Math.max(1, parseInt(countInput?.value || "1", 10)) * multiplier; Math.max(1, parseInt(countInput?.value || "1", 10)) * direction;
const msg = container.querySelector("#kazaMsg"); const msg = container.querySelector("#kazaMsg");
try { try {
await pb.collection("kaza_logs").create({ const userId = pb.authStore.model.id;
user: pb.authStore.model.id,
prayerId, // Kullanıcının kaza sayacı kaydı var mı kontrol et
count, let userRecord = null;
date: new Date().toISOString().split("T")[0], try {
userRecord = await pb
.collection("kaza_logs")
.getFirstListItem(`user = "${userId}"`);
} catch {
// Yoksa ilk kaydı oluştur
userRecord = await pb.collection("kaza_logs").create({
user: userId,
fajr: 0,
dhuhr: 0,
asr: 0,
maghrib: 0,
isha: 0,
vitr: 0,
});
}
const currentCompleted = userRecord[prayerId] || 0;
const newCompleted = Math.max(0, currentCompleted + amount);
// Tek satır kaydı güncelle
await pb.collection("kaza_logs").update(userRecord.id, {
[prayerId]: newCompleted,
}); });
showKazaMsg( showKazaMsg(
msg, msg,
count > 0 amount > 0
? `🎉 ${count} vakit kaza kılındı olarak işlendi!` ? `🎉 ${amount} vakit kılınanlara eklendi!`
: `${Math.abs(count)} vakit düşüldü.`, : `${Math.abs(amount)} vakit düşüldü.`,
true, true,
); );
if (countInput) countInput.value = "1"; if (countInput) countInput.value = "1";
await refreshKazaStats(container, pb, birthdate, gender); await refreshKazaStats(container, pb, birthDate, gender);
} catch (err) { } catch (err) {
console.error("Sayaç güncelleme hatası:", err);
showKazaMsg( showKazaMsg(
msg, msg,
"İşlem kaydedilemedi! PocketBase izinlerini veya bağlantısını kontrol edin.", "Güncelleme başarısız! PocketBase alanlarını ve izinlerini kontrol edin.",
false, false,
); );
} }
} }
async function refreshKazaStats(container, pb, birthdate, gender) { async function refreshKazaStats(container, pb, birthDate, gender) {
const calc = calculateMissedPrayers(birthdate, gender); const calc = calculateMissedPrayers(birthDate, gender);
let logsByPrayer = {}; const userId = pb.authStore.model.id;
let logs = [];
let userRecord = { fajr: 0, dhuhr: 0, asr: 0, maghrib: 0, isha: 0, vitr: 0 };
try { try {
const records = await pb.collection("kaza_logs").getFullList({ const record = await pb
filter: `user = "${pb.authStore.model.id}"`, .collection("kaza_logs")
sort: "-createdAt", .getFirstListItem(`user = "${userId}"`);
}); if (record) userRecord = record;
logs = records;
records.forEach((l) => {
logsByPrayer[l.prayerId] =
(logsByPrayer[l.prayerId] || 0) + (l.count || 0);
});
} catch (err) { } catch (err) {
console.error("Loglar çekilemedi:", err); // Kayıt yoksa sorun değil, varsayılan 0 değerleriyle devam eder
} }
let grandTotalMissed = 0; let grandTotalMissed = 0;
let grandTotalCompleted = 0; let grandTotalCompleted = 0;
PRAYERS.forEach((p) => { PRAYERS.forEach((p) => {
const missed = calc[p.id] || 0; const totalMissed = calc[p.id] || 0; // Doğumdan beri olan toplam borç
const completed = Math.max(0, logsByPrayer[p.id] || 0); const completed = userRecord[p.id] || 0; // Kılınan miktar
const remaining = Math.max(0, missed - completed); const remaining = Math.max(0, totalMissed - completed); // Kalan borç
grandTotalMissed += missed; grandTotalMissed += totalMissed;
grandTotalCompleted += completed; grandTotalCompleted += completed;
const remainEl = container.querySelector(`#remaining-${p.id}`); const remainEl = container.querySelector(`#remaining-${p.id}`);
const completedEl = container.querySelector(`#completed-${p.id}`);
const progressEl = container.querySelector(`#progress-${p.id}`); const progressEl = container.querySelector(`#progress-${p.id}`);
if (remainEl) remainEl.textContent = remaining; if (remainEl) remainEl.textContent = remaining;
if (completedEl) completedEl.textContent = completed;
if (progressEl) { if (progressEl) {
const pct = const pct =
missed > 0 totalMissed > 0
? Math.min(100, Math.round((completed / missed) * 100)) ? Math.min(100, Math.round((completed / totalMissed) * 100))
: 100; : 100;
progressEl.style.width = `${pct}%`; progressEl.style.width = `${pct}%`;
} }
}); });
// Genel İlerleme Çubuğu ve Yüzde Hesaplama // Genel İlerleme Hesabı
const overallPct = const overallPct =
grandTotalMissed > 0 grandTotalMissed > 0
? Math.min( ? Math.min(
@@ -264,31 +280,11 @@ async function refreshKazaStats(container, pb, birthdate, gender) {
if (compText) compText.textContent = grandTotalCompleted; if (compText) compText.textContent = grandTotalCompleted;
if (remText) if (remText)
remText.textContent = Math.max(0, grandTotalMissed - grandTotalCompleted); remText.textContent = Math.max(0, grandTotalMissed - grandTotalCompleted);
// İşlem Geçmişi
const logsContainer = container.querySelector("#logsContainer");
if (logsContainer) {
logsContainer.innerHTML =
logs
.slice(0, 10)
.map((log) => {
const prayer = PRAYERS.find((p) => p.id === log.prayerId);
const isPlus = log.count > 0;
return `
<div class="flex items-center justify-between bg-slate-950/30 border border-white/5 rounded-xl px-4 py-2">
<span class="text-xs text-slate-300 font-medium">${prayer?.name || log.prayerId} - <span class="text-slate-500">${log.date || ""}</span></span>
<span class="text-xs font-bold ${isPlus ? "text-emerald-400" : "text-rose-400"}">${isPlus ? "+" : ""}${log.count}</span>
</div>
`;
})
.join("") ||
'<p class="text-xs text-slate-500">Henüz kayıt bulunmuyor.</p>';
}
} }
function showKazaMsg(el, text, success) { function showKazaMsg(el, text, success) {
if (!el) return; if (!el) return;
el.textContent = text; el.textContent = text;
el.className = `text-xs mt-2.5 ${success ? "text-emerald-400 font-medium" : "text-rose-400"}`; el.className = `text-xs mt-3 ${success ? "text-emerald-400 font-medium" : "text-rose-400"}`;
el.classList.remove("hidden"); el.classList.remove("hidden");
} }