genel olarak yapılan düzeltmeler

This commit is contained in:
2026-07-29 04:01:21 +02:00
parent cb67fb4a84
commit dc4af9cc1d
4 changed files with 319 additions and 388 deletions
+156 -225
View File
@@ -1,9 +1,4 @@
import {
gregorianToHijri,
calculateMissedPrayers,
getHijriAge,
getHijriBirthDate,
} from "../utils/hijri.js";
import { calculateMissedPrayers, getHijriBirthDate } from "../utils/hijri.js";
const PRAYERS = [
{ id: "fajr", name: "SABAH", arabic: "Fecr" },
@@ -11,107 +6,107 @@ const PRAYERS = [
{ id: "asr", name: "İKİNDİ", arabic: "Asr" },
{ id: "maghrib", name: "AKŞAM", arabic: "Mağrib" },
{ id: "isha", name: "YATSI", arabic: "İşa" },
{ id: "vitr", name: "VİTR", arabic: "Vitr" },
{ id: "vitr", name: "VİTİR", arabic: "Vitr" },
];
export function renderKaza(pb) {
const pbBirthDate = pb.authStore.model?.birthdate;
const pbGender = pb.authStore.model?.gender;
const profileS = localStorage.getItem("kaza_profile");
let profile = profileS ? JSON.parse(profileS) : null;
const birthDate = pbBirthDate || profile?.birthDate;
const gender = pbGender || profile?.gender;
// Sıfır localStorage! Her şey PocketBase authStore modelinden okunuyor.
const user = pb.authStore.model;
const birthDate = user?.birthDate || user?.birthdate;
const gender = user?.gender || "male";
const html = `
<div class="bg-slate-900/60 backdrop-blur-2xl border border-white/10 p-8 rounded-3xl shadow-2xl max-w-4xl w-full h-[80vh] flex flex-col">
<div class="relative bg-slate-900/70 backdrop-blur-2xl border border-white/10 p-6 md:p-8 rounded-3xl shadow-2xl max-w-4xl w-full h-[85vh] flex flex-col overflow-hidden">
<button id="closeBtn" class="absolute top-4 right-4 bg-rose-500/20 hover:bg-rose-500/40 text-rose-300 border border-rose-500/30 w-8 h-8 rounded-full flex items-center justify-center font-bold text-xs transition-all">
</button>
<h2 class="text-2xl font-bold text-white mb-1">🕌 Kaza Namaz Takibi</h2>
<p class="text-slate-400 text-sm mb-6">
Hicri yaşını ve kalan kaza namazını takip et.
</p>
<div class="flex items-center gap-3 mb-2">
<span class="text-3xl">📿</span>
<div>
<h2 class="text-2xl font-bold text-white">Kaza Namazı Takibi</h2>
<p class="text-slate-400 text-xs">Tamamlanan namazlar anlık olarak PocketBase hesabınla eşzamanlanır.</p>
</div>
</div>
${
!birthDate
? `
<div class="bg-slate-900/40 border border-white/10 p-6 rounded-2xl mb-6">
<h3 class="text-sm font-semibold text-slate-300 mb-4">Profil Bilgileri</h3>
<form id="profileForm" class="grid grid-cols-1 md:grid-cols-3 gap-4">
<div>
<label class="block text-xs text-slate-400 mb-1">Doğum Tarihi</label>
<input type="date" id="birthDate" required class="w-full bg-slate-950 border border-slate-800 rounded-xl px-4 py-2 text-white text-sm" />
<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>
<p class="text-xs text-slate-400 mb-6">Kaza namazı borcunu tam hesaplayabilmemiz için bilgilerinizi kaydedin.</p>
<form id="profileForm" class="space-y-4">
<div class="text-left">
<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" />
</div>
<div>
<label class="block text-xs text-slate-400 mb-1">Cinsiyet</label>
<select id="gender" required class="w-full bg-slate-950 border border-slate-800 rounded-xl px-4 py-2 text-white text-sm">
<div class="text-left">
<label class="block text-xs text-slate-300 mb-1">Cinsiyet</label>
<select id="genderInput" 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">
<option value="male">Erkek</option>
<option value="female">Kadın</option>
</select>
</div>
<div class="flex items-end">
<button type="submit" class="w-full bg-indigo-600 hover:bg-indigo-700 text-white px-4 py-2 rounded-xl text-sm font-medium transition-all">
Hesapla
</button>
</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">
Hesapla ve Kaydet
</button>
</form>
</div>
`
: `
<div class="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 gap-3 mb-6">
<div class="bg-slate-900/40 border border-white/10 p-3 rounded-2xl text-center">
<p class="text-[10px] text-slate-400 mb-1">Hicri Doğum Tarihi</p>
<p class="text-sm font-bold text-white" id="hijriBirthDateDisplay">-</p>
<!-- OYUNLAŞTIRILMIŞ GENEL İLERLEME (PROGRESS BAR) -->
<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">
<span class="text-xs font-bold text-indigo-300 flex items-center gap-1.5">
<span>🎯</span> TOPLAM İLERLEME (XP)
</span>
<span id="overallPercentage" class="text-sm font-extrabold text-emerald-400">%0</span>
</div>
<div class="w-full h-3.5 bg-slate-900 rounded-full overflow-hidden border border-white/5 p-0.5">
<div id="overallProgressBar" class="h-full bg-gradient-to-r from-indigo-500 via-purple-500 to-emerald-400 rounded-full transition-all duration-700 ease-out w-[0%]"></div>
</div>
<div class="flex justify-between items-center text-[10px] text-slate-400 mt-2">
<span>Kılınan: <b id="totalCompletedText" class="text-white">0</b> vakit</span>
<span>Kalan Borç: <b id="totalRemainingText" class="text-amber-400">0</b> vakit</span>
</div>
</div>
<!-- VAKİT KARTLARI -->
<div class="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-6 gap-3 mb-6">
${PRAYERS.map(
(p) => `
<div class="bg-slate-900/40 border border-white/10 p-3 rounded-2xl text-center">
<p class="text-[10px] text-slate-400 mb-1">${p.name}</p>
<p class="text-xs text-white">Kalan: <span id="remaining-${p.id}" class="font-bold text-emerald-300">-</span></p>
<p class="text-[10px] text-slate-500 mt-1">Toplam: <span id="total-${p.id}">-</span></p>
<div class="bg-slate-950/40 border border-white/10 p-3 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-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">
<div id="progress-${p.id}" class="bg-emerald-400 h-full w-[0%] transition-all duration-500"></div>
</div>
</div>
`,
`
).join("")}
</div>
<div class="bg-slate-900/40 border border-white/10 p-4 rounded-2xl mb-6">
<h3 class="text-sm font-semibold text-slate-300 mb-3">Kaza Namaz Ekle / Çıkar</h3>
<form id="addKazaForm" class="flex items-center gap-3">
<select id="kazaPrayerType" class="bg-slate-950 border border-slate-800 rounded-xl px-4 py-2 text-white text-sm">
<!-- KAZA EKLE / DÜŞ ALANI -->
<div class="bg-slate-950/40 border border-white/10 p-4 rounded-2xl mb-6">
<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">
${PRAYERS.map((p) => `<option value="${p.id}">${p.name}</option>`).join("")}
</select>
<input type="number" id="kazaCount" min="1" value="1" required class="w-20 bg-slate-950 border border-slate-800 rounded-xl px-4 py-2 text-white text-sm" />
<button type="button" id="addKazaBtn" class="bg-indigo-600 hover:bg-indigo-700 text-white px-4 py-2 rounded-xl text-sm font-medium transition-all">
Ekle
<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" />
<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">
<span>✓</span> Kılınan Ekle
</button>
<button type="button" id="removeKazaBtn" class="bg-rose-600 hover:bg-rose-700 text-white px-4 py-2 rounded-xl text-sm font-medium transition-all">
Çıkar
<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">
Geri Al (-)
</button>
</form>
<p id="kazaMsg" class="text-xs mt-2 hidden"></p>
<p id="kazaMsg" class="text-xs mt-2.5 hidden"></p>
</div>
<div class="flex-1 overflow-y-auto pr-2">
<h3 class="text-sm font-semibold text-slate-300 mb-4">Bugünkü Namazlar</h3>
<div class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-3 mb-6">
${PRAYERS.map((p) => {
const todayKey = new Date().toISOString().split("T")[0];
const alreadyDone = profile?.todayLogs?.some(
(l) => l.prayerId === p.id && l.date === todayKey,
);
return `
<div class="bg-slate-900/40 border ${alreadyDone ? "border-emerald-500/50 bg-emerald-500/10" : "border-white/10"} rounded-2xl p-4 text-center transition-all">
<p class="text-xs text-slate-400">${p.arabic}</p>
<p class="text-sm font-semibold text-white">${p.name}</p>
${alreadyDone ? "<p class='text-xs text-emerald-400 mt-1'>✓ Kılındı</p>" : ""}
</div>
`;
}).join("")}
</div>
<h3 class="text-sm font-semibold text-slate-300 mb-4">Son İşlemler</h3>
<!-- 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>
@@ -124,146 +119,69 @@ export function renderKaza(pb) {
return {
html,
initEvents: (container) => {
const closeBtn = container.querySelector("#closeBtn");
if (closeBtn) {
closeBtn.addEventListener("click", () => {
const event = new CustomEvent("navigate", { detail: "desktop" });
window.dispatchEvent(event);
});
}
container.querySelector("#closeBtn")?.addEventListener("click", () => {
window.dispatchEvent(new CustomEvent("navigate", { detail: "desktop" }));
});
if (!birthDate) {
const form = container.querySelector("#profileForm");
const genderSelect = container.querySelector("#gender");
if (gender && genderSelect) {
genderSelect.value = gender;
}
if (form) {
form.addEventListener("submit", async (e) => {
e.preventDefault();
const birthDateInput = container.querySelector("#birthDate").value;
const genderInput = container.querySelector("#gender").value;
container.querySelector("#profileForm")?.addEventListener("submit", async (e) => {
e.preventDefault();
const bInput = container.querySelector("#birthDateInput").value;
const gInput = container.querySelector("#genderInput").value;
if (!birthDateInput) {
alert("Lütfen doğum tarihinizi girin.");
return;
}
try {
await pb.collection("users").update(pb.authStore.model.id, {
birthDate: birthDateInput,
gender: genderInput,
});
} catch (err) {
console.error("PocketBase kaydedilemedi:", err);
}
profile = {
gender: genderInput,
logs: profile?.logs || [],
todayLogs: profile?.todayLogs || [],
createdAt: profile?.createdAt || new Date().toISOString(),
};
localStorage.setItem("kaza_profile", JSON.stringify(profile));
const event = new CustomEvent("navigate", { detail: "kaza" });
window.dispatchEvent(event);
});
}
try {
await pb.collection("users").update(pb.authStore.model.id, {
birthDate: bInput,
gender: gInput,
});
pb.authStore.model.birthDate = bInput;
pb.authStore.model.gender = gInput;
window.dispatchEvent(new CustomEvent("navigate", { detail: "kaza" }));
} catch (err) {
alert("Profil kaydedilemedi. PocketBase bağlantısını kontrol edin.");
}
});
} else {
refreshKazaStats(container, pb, birthDate, gender, profile);
refreshKazaStats(container, pb, birthDate, gender);
const addBtn = container.querySelector("#addKazaBtn");
const removeBtn = container.querySelector("#removeKazaBtn");
container.querySelector("#addKazaBtn")?.addEventListener("click", async () => {
await handleKazaLog(container, pb, birthDate, gender, 1);
});
if (addBtn) {
addBtn.addEventListener("click", async () => {
const prayerId = container.querySelector("#kazaPrayerType").value;
const countInput = container.querySelector("#kazaCount");
const count = Math.max(1, parseInt(countInput?.value || "1", 10));
const msg = container.querySelector("#kazaMsg");
try {
await pb.collection("kaza_logs").create({
user: pb.authStore.model.id,
prayerId,
count,
date: new Date().toISOString().split("T")[0],
});
showKazaMsg(msg, `${count} kaza namaz eklendi!`, true);
if (countInput) countInput.value = "1";
await refreshKazaStats(container, pb, birthDate, gender, profile);
} catch (err) {
console.error("Kaza eklenemedi:", err);
showKazaMsg(
msg,
"Eklenemedi. PocketBase bağlantısını kontrol et.",
false,
);
}
});
}
if (removeBtn) {
removeBtn.addEventListener("click", async () => {
const prayerId = container.querySelector("#kazaPrayerType").value;
const countInput = container.querySelector("#kazaCount");
const count = Math.max(1, parseInt(countInput?.value || "1", 10));
const msg = container.querySelector("#kazaMsg");
try {
const records = await pb.collection("kaza_logs").getFullList({
filter: `user = "${pb.authStore.model.id}" && prayerId = "${prayerId}"`,
sort: "-createdAt",
});
let remaining = count;
for (const record of records) {
if (remaining <= 0) break;
const recordCount = record.count || 1;
if (recordCount > remaining) {
await pb.collection("kaza_logs").update(record.id, {
count: recordCount - remaining,
});
remaining = 0;
} else {
await pb.collection("kaza_logs").delete(record.id);
remaining -= recordCount;
}
}
showKazaMsg(msg, `${count} kaza namaz çıkarıldı!`, true);
if (countInput) countInput.value = "1";
await refreshKazaStats(container, pb, birthDate, gender, profile);
} catch (err) {
console.error("Kaza çıkarılamadı:", err);
showKazaMsg(
msg,
"Çıkarılamadı. PocketBase bağlantısını kontrol et.",
false,
);
}
});
}
container.querySelector("#removeKazaBtn")?.addEventListener("click", async () => {
await handleKazaLog(container, pb, birthDate, gender, -1);
});
}
},
};
}
async function refreshKazaStats(container, pb, birthDate, gender, profile) {
if (!birthDate) return;
async function handleKazaLog(container, pb, birthDate, gender, multiplier) {
const prayerId = container.querySelector("#kazaPrayerType").value;
const countInput = container.querySelector("#kazaCount");
const count = Math.max(1, parseInt(countInput?.value || "1", 10)) * multiplier;
const msg = container.querySelector("#kazaMsg");
const calc = calculateMissedPrayers(birthDate, gender);
const hijriBirth = getHijriBirthDate(birthDate);
try {
await pb.collection("kaza_logs").create({
user: pb.authStore.model.id,
prayerId,
count,
date: new Date().toISOString().split("T")[0],
});
const birthDateEl = container.querySelector("#hijriBirthDateDisplay");
if (birthDateEl) {
birthDateEl.textContent = `${hijriBirth.day} ${hijriBirth.monthName} ${hijriBirth.year}`;
showKazaMsg(msg, count > 0 ? `🎉 ${count} vakit kaza kılındı olarak işlendi!` : `${Math.abs(count)} vakit düşüldü.`, true);
if (countInput) countInput.value = "1";
await refreshKazaStats(container, pb, birthDate, gender);
} catch (err) {
showKazaMsg(msg, "İşlem kaydedilemedi! PocketBase izinlerini veya bağlantısını kontrol edin.", false);
}
}
let logs = [];
async function refreshKazaStats(container, pb, birthDate, gender) {
const calc = calculateMissedPrayers(birthDate, gender);
let logsByPrayer = {};
let logs = [];
try {
const records = await pb.collection("kaza_logs").getFullList({
@@ -271,60 +189,73 @@ async function refreshKazaStats(container, pb, birthDate, gender, profile) {
sort: "-createdAt",
});
logs = records.map((r) => ({
id: r.id,
prayerId: r.prayerId,
count: r.count || 1,
date: r.date,
createdAt: r.createdAt,
}));
logs.forEach((l) => {
logsByPrayer[l.prayerId] =
(logsByPrayer[l.prayerId] || 0) + (l.count || 1);
logs = records;
records.forEach((l) => {
logsByPrayer[l.prayerId] = (logsByPrayer[l.prayerId] || 0) + (l.count || 0);
});
} catch (err) {
console.error("Loglar yüklenemedi:", err);
console.error("Loglar çekilemedi:", err);
}
let grandTotalMissed = 0;
let grandTotalCompleted = 0;
PRAYERS.forEach((p) => {
const totalEl = container.querySelector(`#total-${p.id}`);
const remainEl = container.querySelector(`#remaining-${p.id}`);
const missed = calc[p.id] || 0;
const completed = logsByPrayer[p.id] || 0;
const completed = Math.max(0, logsByPrayer[p.id] || 0);
const remaining = Math.max(0, missed - completed);
if (totalEl) totalEl.textContent = missed;
grandTotalMissed += missed;
grandTotalCompleted += completed;
const remainEl = container.querySelector(`#remaining-${p.id}`);
const progressEl = container.querySelector(`#progress-${p.id}`);
if (remainEl) remainEl.textContent = remaining;
if (progressEl) {
const pct = missed > 0 ? Math.min(100, Math.round((completed / missed) * 100)) : 100;
progressEl.style.width = `${pct}%`;
}
});
const todayKey = new Date().toISOString().split("T")[0];
const todayLogs = logs.filter((l) => l.date === todayKey);
if (profile) {
profile.todayLogs = todayLogs;
localStorage.setItem("kaza_profile", JSON.stringify(profile));
}
// Genel İlerleme Çubuğu ve Yüzde Hesaplama
const overallPct = grandTotalMissed > 0
? Math.min(100, Math.round((grandTotalCompleted / grandTotalMissed) * 100))
: 100;
const bar = container.querySelector("#overallProgressBar");
const pctText = container.querySelector("#overallPercentage");
const compText = container.querySelector("#totalCompletedText");
const remText = container.querySelector("#totalRemainingText");
if (bar) bar.style.width = `${overallPct}%`;
if (pctText) pctText.textContent = `%${overallPct}`;
if (compText) compText.textContent = grandTotalCompleted;
if (remText) remText.textContent = Math.max(0, grandTotalMissed - grandTotalCompleted);
// İşlem Geçmişi
const logsContainer = container.querySelector("#logsContainer");
if (logsContainer) {
logsContainer.innerHTML =
logs
.slice(0, 20)
.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-900/20 border border-white/5 rounded-xl px-4 py-2">
<span class="text-xs text-slate-300">${prayer?.name || log.prayerId} x${log.count} - ${log.date}</span>
<span class="text-xs text-emerald-400">+${log.count}</span>
<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 yok.</p>';
.join("") || '<p class="text-xs text-slate-500">Henüz kayıt bulunmuyor.</p>';
}
}
function showKazaMsg(el, text, success) {
if (!el) return;
el.textContent = text;
el.className = `text-xs mt-2 ${success ? "text-emerald-400" : "text-rose-400"}`;
el.className = `text-xs mt-2.5 ${success ? "text-emerald-400 font-medium" : "text-rose-400"}`;
el.classList.remove("hidden");
}
}