Files
frontend-app/src/pages/kaza.js
T

291 lines
12 KiB
JavaScript
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { calculateMissedPrayers } from "../utils/hijri.js";
const PRAYERS = [
{ id: "fajr", name: "SABAH", arabic: "Fecr" },
{ id: "dhuhr", name: "ÖĞLE", arabic: "Zuhur" },
{ 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İTİR", arabic: "Vitr" },
];
export function renderKaza(pb) {
const user = pb.authStore.model;
const birthDate = user?.birthDate || user?.birthdate;
const gender = user?.gender || "male";
const html = `
<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>
<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ı Sayaç & Takip</h2>
<p class="text-slate-400 text-xs">Tamamladığın vakitler anlık olarak PocketBase hesabında güncellenir.</p>
</div>
</div>
${
!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">
<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 hesaplayabilmemiz için profil bilgilerinizi girin.</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 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>
<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 Başla
</button>
</form>
</div>
`
: `
<!-- 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="flex items-center justify-between mb-2">
<span class="text-xs font-bold text-indigo-300 flex items-center gap-1.5">
<span>🎯</span> GENEL KAZA BİTİRME ORANI
</span>
<span id="overallPercentage" class="text-sm font-extrabold text-emerald-400">%0</span>
</div>
<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>
<div class="flex justify-between items-center text-[11px] text-slate-400 mt-2.5">
<span>Kılınan Toplam: <b id="totalCompletedText" class="text-emerald-400">0</b> vakit</span>
<span>Kalan Toplam Borç: <b id="totalRemainingText" class="text-amber-400">0</b> vakit</span>
</div>
</div>
<!-- VAKİT İLERLEME 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-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-xs text-slate-400">Kalan: <span id="remaining-${p.id}" class="font-extrabold text-emerald-300">-</span></p>
<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>
</div>
`,
).join("")}
</div>
<!-- HIZLI SAYAÇ GÜNCELLEME ALANI -->
<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">
<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("")}
</select>
<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.5 rounded-xl text-sm font-semibold transition-all shadow-lg active:scale-95 flex items-center gap-1.5">
<span>✓</span> Kıldım / Ekle (+)
</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.5 rounded-xl text-sm font-medium transition-all active:scale-95">
Geri Al (-)
</button>
</form>
<p id="kazaMsg" class="text-xs mt-3 hidden"></p>
</div>
`
}
</div>
`;
return {
html,
initEvents: (container) => {
container.querySelector("#closeBtn")?.addEventListener("click", () => {
window.dispatchEvent(
new CustomEvent("navigate", { detail: "desktop" }),
);
});
if (!birthDate) {
container
.querySelector("#profileForm")
?.addEventListener("submit", async (e) => {
e.preventDefault();
const bInput = container.querySelector("#birthDateInput").value;
const gInput = container.querySelector("#genderInput").value;
try {
await pb.collection("users").update(pb.authStore.model.id, {
birthdate: bInput,
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 alan adlarını kontrol edin.",
);
}
});
} else {
refreshKazaStats(container, pb, birthDate, gender);
container
.querySelector("#addKazaBtn")
?.addEventListener("click", async () => {
await updateKazaCount(container, pb, birthDate, gender, 1);
});
container
.querySelector("#removeKazaBtn")
?.addEventListener("click", async () => {
await updateKazaCount(container, pb, birthDate, gender, -1);
});
}
},
};
}
// PocketBase Tek Satır Güncelleme Mantığı
async function updateKazaCount(container, pb, birthDate, gender, direction) {
const prayerId = container.querySelector("#kazaPrayerType").value;
const countInput = container.querySelector("#kazaCount");
const amount =
Math.max(1, parseInt(countInput?.value || "1", 10)) * direction;
const msg = container.querySelector("#kazaMsg");
try {
const userId = pb.authStore.model.id;
// Kullanıcının kaza sayacı kaydı var mı kontrol et
let userRecord = null;
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(
msg,
amount > 0
? `🎉 ${amount} vakit kılınanlara eklendi!`
: `${Math.abs(amount)} vakit düşüldü.`,
true,
);
if (countInput) countInput.value = "1";
await refreshKazaStats(container, pb, birthDate, gender);
} catch (err) {
console.error("Sayaç güncelleme hatası:", err);
showKazaMsg(
msg,
"Güncelleme başarısız! PocketBase alanlarını ve izinlerini kontrol edin.",
false,
);
}
}
async function refreshKazaStats(container, pb, birthDate, gender) {
const calc = calculateMissedPrayers(birthDate, gender);
const userId = pb.authStore.model.id;
let userRecord = { fajr: 0, dhuhr: 0, asr: 0, maghrib: 0, isha: 0, vitr: 0 };
try {
const record = await pb
.collection("kaza_logs")
.getFirstListItem(`user = "${userId}"`);
if (record) userRecord = record;
} catch (err) {
// Kayıt yoksa sorun değil, varsayılan 0 değerleriyle devam eder
}
let grandTotalMissed = 0;
let grandTotalCompleted = 0;
PRAYERS.forEach((p) => {
const totalMissed = calc[p.id] || 0; // Doğumdan beri olan toplam borç
const completed = userRecord[p.id] || 0; // Kılınan miktar
const remaining = Math.max(0, totalMissed - completed); // Kalan borç
grandTotalMissed += totalMissed;
grandTotalCompleted += completed;
const remainEl = container.querySelector(`#remaining-${p.id}`);
const completedEl = container.querySelector(`#completed-${p.id}`);
const progressEl = container.querySelector(`#progress-${p.id}`);
if (remainEl) remainEl.textContent = remaining;
if (completedEl) completedEl.textContent = completed;
if (progressEl) {
const pct =
totalMissed > 0
? Math.min(100, Math.round((completed / totalMissed) * 100))
: 100;
progressEl.style.width = `${pct}%`;
}
});
// Genel İlerleme Hesabı
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);
}
function showKazaMsg(el, text, success) {
if (!el) return;
el.textContent = text;
el.className = `text-xs mt-3 ${success ? "text-emerald-400 font-medium" : "text-rose-400"}`;
el.classList.remove("hidden");
}