genel olarak yapılan düzeltmeler
This commit is contained in:
+54
-58
@@ -3,7 +3,7 @@ import PocketBase from "pocketbase";
|
|||||||
import { renderSettings } from "./pages/settings.js";
|
import { renderSettings } from "./pages/settings.js";
|
||||||
import { renderDesktop } from "./pages/desktop.js";
|
import { renderDesktop } from "./pages/desktop.js";
|
||||||
import { renderKaza } from "./pages/kaza.js";
|
import { renderKaza } from "./pages/kaza.js";
|
||||||
import { getDefaultCity, getCityByName } from "./utils/locations.js";
|
import { getDefaultCity } from "./utils/locations.js";
|
||||||
|
|
||||||
const pb = new PocketBase("https://pocketbase.iontalp.com");
|
const pb = new PocketBase("https://pocketbase.iontalp.com");
|
||||||
const app = document.getElementById("app");
|
const app = document.getElementById("app");
|
||||||
@@ -42,14 +42,20 @@ async function render() {
|
|||||||
|
|
||||||
let currentPage;
|
let currentPage;
|
||||||
if (activeTab === "settings") {
|
if (activeTab === "settings") {
|
||||||
currentPage = await renderSettings(pb, currentBg, (newBg) => {
|
currentPage = await renderSettings(
|
||||||
pb.authStore.model.selected_bg = newBg;
|
pb,
|
||||||
render();
|
currentBg,
|
||||||
}, selectedCity, (city) => {
|
(newBg) => {
|
||||||
selectedCity = city;
|
pb.authStore.model.selected_bg = newBg;
|
||||||
localStorage.setItem("selected_city", city);
|
render();
|
||||||
render();
|
},
|
||||||
});
|
selectedCity,
|
||||||
|
(city) => {
|
||||||
|
selectedCity = city;
|
||||||
|
localStorage.setItem("selected_city", city);
|
||||||
|
render();
|
||||||
|
},
|
||||||
|
);
|
||||||
} else if (activeTab === "kaza") {
|
} else if (activeTab === "kaza") {
|
||||||
currentPage = renderKaza(pb);
|
currentPage = renderKaza(pb);
|
||||||
} else {
|
} else {
|
||||||
@@ -59,32 +65,33 @@ async function render() {
|
|||||||
app.innerHTML = `
|
app.innerHTML = `
|
||||||
<div class="relative w-full h-screen overflow-hidden bg-slate-950 text-slate-100 flex">
|
<div class="relative w-full h-screen overflow-hidden bg-slate-950 text-slate-100 flex">
|
||||||
<div class="absolute inset-0 z-0 bg-center bg-no-repeat transition-all duration-700"
|
<div class="absolute inset-0 z-0 bg-center bg-no-repeat transition-all duration-700"
|
||||||
style="background-image: url('${currentBg}'); background-size: 1920px 1080px;">
|
style="background-image: url('${currentBg}'); background-size: cover;">
|
||||||
</div>
|
</div>
|
||||||
<div class="absolute inset-0 z-10 bg-slate-950/50"></div>
|
<div class="absolute inset-0 z-10 bg-slate-950/60 backdrop-blur-[2px]"></div>
|
||||||
|
|
||||||
<button id="globalSidebarToggle" class="fixed top-4 left-4 z-50 bg-white/10 hover:bg-white/20 text-white p-3 rounded-xl transition-all">
|
<button id="globalSidebarToggle" class="fixed top-4 left-4 z-50 bg-white/10 hover:bg-white/20 text-white p-2.5 rounded-xl backdrop-blur-md transition-all border border-white/10">
|
||||||
${sidebarOpen ? "✕" : "☰"}
|
${sidebarOpen ? "◀" : "▶"}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
${sidebarOpen ? `<div id="sidebarOverlay" class="fixed inset-0 bg-black/50 z-30 md:hidden"></div>` : ""}
|
${sidebarOpen ? `<div id="sidebarOverlay" class="fixed inset-0 bg-black/50 z-30 md:hidden"></div>` : ""}
|
||||||
|
|
||||||
<aside id="sidebar" class="fixed md:relative z-40 md:z-30 inset-y-0 left-0 ${sidebarOpen ? "w-72 translate-x-0" : "w-72 -translate-x-full md:w-20 md:translate-x-0"} h-screen bg-slate-900/80 backdrop-blur-xl border-r border-white/10 ${sidebarOpen ? "p-6" : "md:p-0"} flex flex-col ${sidebarOpen ? "" : "md:items-center"} justify-between transition-all duration-300 overflow-hidden">
|
<aside id="sidebar" class="fixed md:relative z-40 md:z-30 inset-y-0 left-0 ${sidebarOpen ? "w-72 translate-x-0 p-6" : "w-72 -translate-x-full md:w-20 md:translate-x-0 md:p-3"} h-screen bg-slate-900/80 backdrop-blur-xl border-r border-white/10 flex flex-col justify-between transition-all duration-300 overflow-hidden">
|
||||||
<div>
|
<div>
|
||||||
<div class="flex items-center justify-between mb-6">
|
<div class="flex items-center justify-between mb-8 mt-2">
|
||||||
<h1 class="font-bold text-white text-xl ${sidebarOpen ? "block" : "hidden md:hidden"}">Dashboard OS</h1>
|
<h1 class="font-bold text-white text-xl ${sidebarOpen ? "block" : "hidden md:hidden"}">Dashboard OS</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<nav class="space-y-2 w-full">
|
<nav class="space-y-2 w-full">
|
||||||
<button id="navDesktop" class="w-full flex items-center ${sidebarOpen ? "" : "md:justify-center"} gap-3 px-4 py-3 rounded-xl font-medium ${activeTab === "desktop" ? "bg-white/10 text-white" : "text-slate-400 hover:text-white"}">
|
<button id="navDesktop" class="w-full flex items-center ${sidebarOpen ? "" : "md:justify-center"} gap-3 px-4 py-3 rounded-xl font-medium ${activeTab === "desktop" ? "bg-indigo-600/30 text-indigo-300 border border-indigo-500/30" : "text-slate-400 hover:text-white hover:bg-white/5"}">
|
||||||
<span>🏠</span> <span class="${sidebarOpen ? "block" : "hidden md:hidden"}">Masaüstü</span>
|
<span>🏠</span> <span class="${sidebarOpen ? "block" : "hidden md:hidden"}">Masaüstü</span>
|
||||||
</button>
|
</button>
|
||||||
<button id="navKaza" class="w-full flex items-center ${sidebarOpen ? "" : "md:justify-center"} gap-3 px-4 py-3 rounded-xl font-medium ${activeTab === "kaza" ? "bg-white/10 text-white" : "text-slate-400 hover:text-white"}">
|
<button id="navKaza" class="w-full flex items-center ${sidebarOpen ? "" : "md:justify-center"} gap-3 px-4 py-3 rounded-xl font-medium ${activeTab === "kaza" ? "bg-indigo-600/30 text-indigo-300 border border-indigo-500/30" : "text-slate-400 hover:text-white hover:bg-white/5"}">
|
||||||
<span>🕌</span> <span class="${sidebarOpen ? "block" : "hidden md:hidden"}">Kaza Namaz</span>
|
<span>📿</span> <span class="${sidebarOpen ? "block" : "hidden md:hidden"}">Kaza Namazı</span>
|
||||||
</button>
|
</button>
|
||||||
<button id="navSettings" class="w-full flex items-center ${sidebarOpen ? "" : "md:justify-center"} gap-3 px-4 py-3 rounded-xl font-medium ${activeTab === "settings" ? "bg-white/10 text-white" : "text-slate-400 hover:text-white"}">
|
<button id="navSettings" class="w-full flex items-center ${sidebarOpen ? "" : "md:justify-center"} gap-3 px-4 py-3 rounded-xl font-medium ${activeTab === "settings" ? "bg-indigo-600/30 text-indigo-300 border border-indigo-500/30" : "text-slate-400 hover:text-white hover:bg-white/5"}">
|
||||||
<span>⚙️</span> <span class="${sidebarOpen ? "block" : "hidden md:hidden"}">Ayarlar</span>
|
<span>⚙️</span> <span class="${sidebarOpen ? "block" : "hidden md:hidden"}">Ayarlar</span>
|
||||||
</button>
|
</button>
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="space-y-3 pt-4 border-t border-white/10 w-full">
|
<div class="space-y-3 pt-4 border-t border-white/10 w-full">
|
||||||
@@ -94,19 +101,19 @@ async function render() {
|
|||||||
? `<img src="${avatarUrl}" alt="Avatar" class="w-10 h-10 rounded-full object-cover border border-white/20 shadow-md flex-shrink-0" />`
|
? `<img src="${avatarUrl}" alt="Avatar" class="w-10 h-10 rounded-full object-cover border border-white/20 shadow-md flex-shrink-0" />`
|
||||||
: `<div class="w-10 h-10 rounded-full bg-indigo-600/30 border border-indigo-500/30 flex items-center justify-center font-bold text-indigo-400 flex-shrink-0">${(user.username || user.email).charAt(0).toUpperCase()}</div>`
|
: `<div class="w-10 h-10 rounded-full bg-indigo-600/30 border border-indigo-500/30 flex items-center justify-center font-bold text-indigo-400 flex-shrink-0">${(user.username || user.email).charAt(0).toUpperCase()}</div>`
|
||||||
}
|
}
|
||||||
<div class="${sidebarOpen ? "block" : "hidden md:hidden"}">
|
<div class="${sidebarOpen ? "block" : "hidden md:hidden"} overflow-hidden">
|
||||||
<p class="text-sm font-medium text-white truncate">${user.name || user.email}</p>
|
<p class="text-sm font-medium text-white truncate">${user.name || user.username || user.email}</p>
|
||||||
<p class="text-xs text-slate-400">Çevrimiçi</p>
|
<p class="text-xs text-emerald-400">Çevrimiçi</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button id="logoutBtn" class="w-full bg-rose-500/20 text-rose-300 hover:bg-rose-500/30 py-2 rounded-xl border border-rose-500/30 text-sm font-medium transition-all">
|
<button id="logoutBtn" class="w-full bg-rose-500/20 text-rose-300 hover:bg-rose-500/30 py-2.5 rounded-xl border border-rose-500/30 text-sm font-medium transition-all flex items-center justify-center gap-2">
|
||||||
🚪 Çıkış Yap
|
<span>🚪</span> <span class="${sidebarOpen ? "inline" : "hidden md:hidden"}">Çıkış Yap</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
<main id="mainContent" class="relative z-20 flex-1 h-screen p-8 flex items-center justify-center overflow-hidden">
|
<main id="mainContent" class="relative z-20 flex-1 h-screen p-4 md:p-8 flex items-center justify-center overflow-y-auto">
|
||||||
${currentPage.html}
|
${currentPage.html}
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
@@ -115,46 +122,35 @@ async function render() {
|
|||||||
const mainContent = document.getElementById("mainContent");
|
const mainContent = document.getElementById("mainContent");
|
||||||
currentPage.initEvents(mainContent);
|
currentPage.initEvents(mainContent);
|
||||||
|
|
||||||
document.getElementById("navDesktop").addEventListener("click", () => {
|
document.getElementById("navDesktop")?.addEventListener("click", () => {
|
||||||
activeTab = "desktop";
|
activeTab = "desktop";
|
||||||
render();
|
render();
|
||||||
});
|
});
|
||||||
document.getElementById("navKaza").addEventListener("click", () => {
|
document.getElementById("navKaza")?.addEventListener("click", () => {
|
||||||
activeTab = "kaza";
|
activeTab = "kaza";
|
||||||
render();
|
render();
|
||||||
});
|
});
|
||||||
document.getElementById("navSettings").addEventListener("click", () => {
|
document.getElementById("navSettings")?.addEventListener("click", () => {
|
||||||
activeTab = "settings";
|
activeTab = "settings";
|
||||||
render();
|
render();
|
||||||
});
|
});
|
||||||
document.getElementById("logoutBtn").addEventListener("click", () => {
|
|
||||||
|
document.getElementById("logoutBtn")?.addEventListener("click", () => {
|
||||||
pb.authStore.clear();
|
pb.authStore.clear();
|
||||||
render();
|
render();
|
||||||
});
|
});
|
||||||
|
|
||||||
const globalToggle = document.getElementById("globalSidebarToggle");
|
document
|
||||||
if (globalToggle) {
|
.getElementById("globalSidebarToggle")
|
||||||
globalToggle.addEventListener("click", () => {
|
?.addEventListener("click", () => {
|
||||||
sidebarOpen = !sidebarOpen;
|
sidebarOpen = !sidebarOpen;
|
||||||
render();
|
render();
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
const overlay = document.getElementById("sidebarOverlay");
|
document.getElementById("sidebarOverlay")?.addEventListener("click", () => {
|
||||||
if (overlay) {
|
sidebarOpen = false;
|
||||||
overlay.addEventListener("click", () => {
|
render();
|
||||||
sidebarOpen = false;
|
});
|
||||||
render();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const closeBtn = document.getElementById("closeBtn");
|
|
||||||
if (closeBtn) {
|
|
||||||
closeBtn.addEventListener("click", () => {
|
|
||||||
activeTab = "desktop";
|
|
||||||
render();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener("navigate", (e) => {
|
window.addEventListener("navigate", (e) => {
|
||||||
@@ -168,9 +164,9 @@ function renderLogin() {
|
|||||||
<div class="bg-slate-900 border border-slate-800 p-8 rounded-2xl shadow-2xl w-full max-w-md">
|
<div class="bg-slate-900 border border-slate-800 p-8 rounded-2xl shadow-2xl w-full max-w-md">
|
||||||
<h1 class="text-2xl font-bold text-center mb-6">Giriş Yap</h1>
|
<h1 class="text-2xl font-bold text-center mb-6">Giriş Yap</h1>
|
||||||
<form id="loginForm" class="space-y-4">
|
<form id="loginForm" class="space-y-4">
|
||||||
<input type="text" id="identity" placeholder="E-posta / Kullanıcı Adı" required class="w-full bg-slate-950 border border-slate-800 rounded-xl px-4 py-2 text-white" />
|
<input type="text" id="identity" placeholder="E-posta / Kullanıcı Adı" required class="w-full bg-slate-950 border border-slate-800 rounded-xl px-4 py-2 text-white focus:outline-none focus:border-indigo-500" />
|
||||||
<input type="password" id="password" placeholder="Şifre" required class="w-full bg-slate-950 border border-slate-800 rounded-xl px-4 py-2 text-white" />
|
<input type="password" id="password" placeholder="Şifre" required class="w-full bg-slate-950 border border-slate-800 rounded-xl px-4 py-2 text-white focus:outline-none focus:border-indigo-500" />
|
||||||
<button type="submit" class="w-full bg-indigo-600 py-2 rounded-xl text-white font-medium">Giriş</button>
|
<button type="submit" class="w-full bg-indigo-600 hover:bg-indigo-500 py-2.5 rounded-xl text-white font-medium transition-all">Giriş Yap</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -186,7 +182,7 @@ function renderLogin() {
|
|||||||
);
|
);
|
||||||
render();
|
render();
|
||||||
} catch {
|
} catch {
|
||||||
alert("Giriş başarısız!");
|
alert("Giriş başarısız! Bilgilerinizi kontrol edin.");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
+77
-92
@@ -1,9 +1,8 @@
|
|||||||
import { gregorianToHijri } from "../utils/hijri.js";
|
import { gregorianToHijri } from "../utils/hijri.js";
|
||||||
import { fetchWeather, getWeatherIcon, getWeatherDesc } from "../utils/weather.js";
|
import { fetchWeather, getWeatherIcon, getWeatherDesc } from "../utils/weather.js";
|
||||||
import { fetchPrayerTimes } from "../utils/prayerTimes.js";
|
import { fetchPrayerTimes } from "../utils/prayerTimes.js";
|
||||||
import { getCityByName } from "../utils/locations.js";
|
|
||||||
|
|
||||||
export function renderDesktop(selectedCity = "İstanbul") {
|
export function renderDesktop(selectedCity = "Edremit") {
|
||||||
const hijri = gregorianToHijri();
|
const hijri = gregorianToHijri();
|
||||||
const today = new Date();
|
const today = new Date();
|
||||||
const dateStr = today.toLocaleDateString("tr-TR", {
|
const dateStr = today.toLocaleDateString("tr-TR", {
|
||||||
@@ -14,77 +13,58 @@ export function renderDesktop(selectedCity = "İstanbul") {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const html = `
|
const html = `
|
||||||
<div class="flex flex-col items-end gap-4 w-full max-w-6xl">
|
<div class="flex justify-end w-full max-w-6xl h-full items-start pt-4">
|
||||||
<div class="w-full max-w-md">
|
<!-- Windows Vista Tarzı Entegre Tek Kolon Sidebar -->
|
||||||
<div class="bg-slate-900/40 backdrop-blur-2xl border border-white/10 p-6 rounded-3xl shadow-2xl text-left space-y-3">
|
<div class="w-full max-w-sm bg-slate-900/50 backdrop-blur-2xl border border-white/10 rounded-3xl p-6 shadow-2xl space-y-6">
|
||||||
<div class="flex items-center gap-3">
|
|
||||||
<div class="inline-flex p-2 bg-indigo-500/20 border border-indigo-500/30 rounded-xl text-indigo-300 text-xl">
|
|
||||||
✨
|
|
||||||
</div>
|
|
||||||
<h2 class="text-xl font-bold text-white">Masaüstü</h2>
|
|
||||||
</div>
|
|
||||||
<p class="text-slate-300 text-xs leading-relaxed">
|
|
||||||
Arka planı değiştirmek için sol menüdeki <b>Ayarlar</b> sekmesine geçebilirsin.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="w-full max-w-md">
|
<!-- Header -->
|
||||||
<div class="bg-slate-900/40 backdrop-blur-2xl border border-white/10 p-6 rounded-3xl shadow-2xl text-left space-y-3">
|
<div class="flex items-center justify-between pb-4 border-b border-white/10">
|
||||||
<div class="flex items-center gap-3">
|
<h2 class="text-lg font-bold text-white flex items-center gap-2">
|
||||||
<div class="inline-flex p-2 bg-emerald-500/20 border border-emerald-500/30 rounded-xl text-emerald-300 text-xl">
|
<span>🖥️</span> Masaüstü Araçları
|
||||||
📅
|
</h2>
|
||||||
</div>
|
<span class="text-xs text-slate-400 font-medium">${selectedCity}</span>
|
||||||
<h2 class="text-xl font-bold text-white">Hicri Takvim</h2>
|
|
||||||
</div>
|
|
||||||
<p class="text-slate-300 text-xs leading-relaxed">
|
|
||||||
<span class="text-white font-semibold">${hijri.weekday}</span><br />
|
|
||||||
${hijri.day} ${hijri.monthName} ${hijri.year}<br />
|
|
||||||
<span class="text-slate-400">${dateStr}</span>
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="w-full max-w-md">
|
<!-- Bölüm 1: Hicri Takvim -->
|
||||||
<div class="bg-slate-900/40 backdrop-blur-2xl border border-white/10 p-6 rounded-3xl shadow-2xl text-left space-y-3">
|
<div class="space-y-1.5">
|
||||||
<div class="flex items-center gap-3">
|
<div class="flex items-center gap-2 text-xs font-semibold text-emerald-400">
|
||||||
<div class="inline-flex p-2 bg-sky-500/20 border border-sky-500/30 rounded-xl text-sky-300 text-xl">
|
<span>📅</span> HİCRİ TAKVİM
|
||||||
🌤️
|
|
||||||
</div>
|
|
||||||
<h2 class="text-xl font-bold text-white">Hava Durumu</h2>
|
|
||||||
</div>
|
</div>
|
||||||
<p class="text-slate-300 text-xs leading-relaxed" id="weatherWidget">
|
<p class="text-white font-bold text-base">${hijri.day} ${hijri.monthName} ${hijri.year}</p>
|
||||||
Yükleniyor...
|
<p class="text-xs text-slate-400">${dateStr} / ${hijri.weekday}</p>
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="w-full max-w-md">
|
<hr class="border-white/5" />
|
||||||
<div class="bg-slate-900/40 backdrop-blur-2xl border border-white/10 p-6 rounded-3xl shadow-2xl text-left space-y-3">
|
|
||||||
<div class="flex items-center gap-3">
|
|
||||||
<div class="inline-flex p-2 bg-orange-500/20 border border-orange-500/30 rounded-xl text-orange-300 text-xl">
|
|
||||||
🌅
|
|
||||||
</div>
|
|
||||||
<h2 class="text-xl font-bold text-white">İmsakiye</h2>
|
|
||||||
</div>
|
|
||||||
<p class="text-slate-300 text-xs leading-relaxed" id="imsakiyeWidget">
|
|
||||||
Yükleniyor...
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="w-full max-w-md">
|
<!-- Bölüm 2: Hava Durumu -->
|
||||||
<div class="bg-slate-900/40 backdrop-blur-2xl border border-white/10 p-6 rounded-3xl shadow-2xl text-left space-y-3 cursor-pointer hover:border-white/20 transition-all" id="kazaShortcut">
|
<div class="space-y-1.5" id="weatherWidget">
|
||||||
<div class="flex items-center gap-3">
|
<div class="flex items-center gap-2 text-xs font-semibold text-sky-400">
|
||||||
<div class="inline-flex p-2 bg-amber-500/20 border border-amber-500/30 rounded-xl text-amber-300 text-xl">
|
<span>Yükleniyor...</span>
|
||||||
🕌
|
|
||||||
</div>
|
|
||||||
<h2 class="text-xl font-bold text-white">Kaza Namaz</h2>
|
|
||||||
</div>
|
</div>
|
||||||
<p class="text-slate-300 text-xs leading-relaxed">
|
|
||||||
Kaza namaz takibine geçmek için tıkla.
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<hr class="border-white/5" />
|
||||||
|
|
||||||
|
<!-- Bölüm 3: İmsakiye & Aktif Vakit -->
|
||||||
|
<div class="space-y-3" id="imsakiyeWidget">
|
||||||
|
<div class="text-xs font-semibold text-orange-400">İMSAKİYE</div>
|
||||||
|
<p class="text-xs text-slate-400">Yükleniyor...</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr class="border-white/5" />
|
||||||
|
|
||||||
|
<!-- Bölüm 4: Kaza Namazı Kısayolu -->
|
||||||
|
<div id="kazaShortcut" class="bg-indigo-600/20 hover:bg-indigo-600/30 border border-indigo-500/30 p-4 rounded-2xl cursor-pointer transition-all group flex items-center justify-between">
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<span class="text-2xl group-hover:scale-110 transition-transform">📿</span>
|
||||||
|
<div>
|
||||||
|
<h3 class="text-sm font-bold text-white">Kaza Namazı Takibi</h3>
|
||||||
|
<p class="text-[11px] text-indigo-300">Kaydetmeye ve takibe başla</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<span class="text-slate-400 group-hover:translate-x-1 transition-transform">➔</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
@@ -94,7 +74,10 @@ export function renderDesktop(selectedCity = "İstanbul") {
|
|||||||
initEvents: (container) => {
|
initEvents: (container) => {
|
||||||
loadWeather(container, selectedCity);
|
loadWeather(container, selectedCity);
|
||||||
loadImsakiye(container, selectedCity);
|
loadImsakiye(container, selectedCity);
|
||||||
setupKazaShortcut(container);
|
|
||||||
|
container.querySelector("#kazaShortcut")?.addEventListener("click", () => {
|
||||||
|
window.dispatchEvent(new CustomEvent("navigate", { detail: "kaza" }));
|
||||||
|
});
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -102,51 +85,53 @@ export function renderDesktop(selectedCity = "İstanbul") {
|
|||||||
async function loadWeather(container, selectedCity) {
|
async function loadWeather(container, selectedCity) {
|
||||||
const widget = container.querySelector("#weatherWidget");
|
const widget = container.querySelector("#weatherWidget");
|
||||||
if (!widget) return;
|
if (!widget) return;
|
||||||
|
|
||||||
const data = await fetchWeather(selectedCity);
|
const data = await fetchWeather(selectedCity);
|
||||||
if (!data) {
|
if (!data) {
|
||||||
widget.innerHTML = "Hava durumu alınamadı.";
|
widget.innerHTML = `<span class="text-xs text-rose-400">Hava durumu alınamadı</span>`;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const icon = getWeatherIcon(data.weathercode);
|
const icon = getWeatherIcon(data.weathercode);
|
||||||
const desc = getWeatherDesc(data.weathercode);
|
const desc = getWeatherDesc(data.weathercode);
|
||||||
const temp = Math.round(data.temperature);
|
const temp = Math.round(data.temperature);
|
||||||
|
|
||||||
widget.innerHTML = `
|
widget.innerHTML = `
|
||||||
<span class="text-2xl">${icon}</span> <span class="text-white font-semibold">${temp}°C</span>
|
<div class="flex items-center justify-between">
|
||||||
<br />
|
<div>
|
||||||
${desc} <span class="text-slate-400">(${data.cityName})</span>
|
<div class="flex items-center gap-2 text-xs font-semibold text-sky-400">
|
||||||
|
<span>🌤️</span> HAVA DURUMU
|
||||||
|
</div>
|
||||||
|
<p class="text-xs text-slate-300 mt-1">${desc}</p>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<span class="text-3xl">${icon}</span>
|
||||||
|
<span class="text-2xl font-bold text-white">${temp}°C</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadImsakiye(container, selectedCity) {
|
async function loadImsakiye(container, selectedCity) {
|
||||||
const widget = container.querySelector("#imsakiyeWidget");
|
const widget = container.querySelector("#imsakiyeWidget");
|
||||||
if (!widget) return;
|
if (!widget) return;
|
||||||
|
const times = await fetchPrayerTimes(selectedCity);
|
||||||
const city = getCityByName(selectedCity);
|
|
||||||
const times = await fetchPrayerTimes(selectedCity, city.lat, city.lon);
|
|
||||||
if (!times) {
|
if (!times) {
|
||||||
widget.innerHTML = "Namaz vakitleri alınamadı.";
|
widget.innerHTML = `<span class="text-xs text-rose-400">Vakitler alınamadı</span>`;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const activeKey = times.currentPrayer?.key;
|
||||||
|
|
||||||
widget.innerHTML = `
|
widget.innerHTML = `
|
||||||
🌅 İmsak: <span class="text-white font-semibold">${times.imsak}</span><br />
|
<div class="flex items-center justify-between mb-2">
|
||||||
🌅 Güneş: <span class="text-white font-semibold">${times.sunrise}</span><br />
|
<span class="text-xs font-semibold text-orange-400">🕌 NAMAZ VAKİTLERİ</span>
|
||||||
🌅 Öğle: <span class="text-white font-semibold">${times.dhuhr}</span><br />
|
<span class="text-[10px] bg-indigo-500/20 text-indigo-300 border border-indigo-500/30 px-2 py-0.5 rounded-full">Şu an: ${times.currentPrayer?.name}</span>
|
||||||
🌅 İkindi: <span class="text-white font-semibold">${times.asr}</span><br />
|
</div>
|
||||||
🕌 Akşam: <span class="text-emerald-300 font-semibold">${times.maghrib}</span>
|
<div class="grid grid-cols-2 gap-2 text-xs">
|
||||||
🌅 Yatsı: <span class="text-white font-semibold">${times.isha}</span><br />
|
<div class="p-2 rounded-xl ${activeKey === 'fajr' ? 'bg-emerald-500/20 border border-emerald-500/40 text-emerald-300 font-bold' : 'bg-slate-900/40 text-slate-300'}">İmsak: ${times.imsak}</div>
|
||||||
|
<div class="p-2 rounded-xl bg-slate-900/40 text-slate-300">Güneş: ${times.sunrise}</div>
|
||||||
|
<div class="p-2 rounded-xl ${activeKey === 'dhuhr' ? 'bg-emerald-500/20 border border-emerald-500/40 text-emerald-300 font-bold' : 'bg-slate-900/40 text-slate-300'}">Öğle: ${times.dhuhr}</div>
|
||||||
|
<div class="p-2 rounded-xl ${activeKey === 'asr' ? 'bg-emerald-500/20 border border-emerald-500/40 text-emerald-300 font-bold' : 'bg-slate-900/40 text-slate-300'}">İkindi: ${times.asr}</div>
|
||||||
|
<div class="p-2 rounded-xl ${activeKey === 'maghrib' ? 'bg-emerald-500/20 border border-emerald-500/40 text-emerald-300 font-bold' : 'bg-slate-900/40 text-slate-300'}">Akşam: ${times.maghrib}</div>
|
||||||
|
<div class="p-2 rounded-xl ${activeKey === 'isha' ? 'bg-emerald-500/20 border border-emerald-500/40 text-emerald-300 font-bold' : 'bg-slate-900/40 text-slate-300'}">Yatsı: ${times.isha}</div>
|
||||||
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function setupKazaShortcut(container) {
|
|
||||||
const shortcut = container.querySelector("#kazaShortcut");
|
|
||||||
if (!shortcut) return;
|
|
||||||
|
|
||||||
shortcut.addEventListener("click", () => {
|
|
||||||
const event = new CustomEvent("navigate", { detail: "kaza" });
|
|
||||||
window.dispatchEvent(event);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|||||||
+154
-223
@@ -1,9 +1,4 @@
|
|||||||
import {
|
import { calculateMissedPrayers, getHijriBirthDate } from "../utils/hijri.js";
|
||||||
gregorianToHijri,
|
|
||||||
calculateMissedPrayers,
|
|
||||||
getHijriAge,
|
|
||||||
getHijriBirthDate,
|
|
||||||
} from "../utils/hijri.js";
|
|
||||||
|
|
||||||
const PRAYERS = [
|
const PRAYERS = [
|
||||||
{ id: "fajr", name: "SABAH", arabic: "Fecr" },
|
{ id: "fajr", name: "SABAH", arabic: "Fecr" },
|
||||||
@@ -11,107 +6,107 @@ const PRAYERS = [
|
|||||||
{ id: "asr", name: "İKİNDİ", arabic: "Asr" },
|
{ id: "asr", name: "İKİNDİ", arabic: "Asr" },
|
||||||
{ id: "maghrib", name: "AKŞAM", arabic: "Mağrib" },
|
{ id: "maghrib", name: "AKŞAM", arabic: "Mağrib" },
|
||||||
{ id: "isha", name: "YATSI", arabic: "İşa" },
|
{ 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) {
|
export function renderKaza(pb) {
|
||||||
const pbBirthDate = pb.authStore.model?.birthdate;
|
// Sıfır localStorage! Her şey PocketBase authStore modelinden okunuyor.
|
||||||
const pbGender = pb.authStore.model?.gender;
|
const user = pb.authStore.model;
|
||||||
const profileS = localStorage.getItem("kaza_profile");
|
const birthDate = user?.birthDate || user?.birthdate;
|
||||||
let profile = profileS ? JSON.parse(profileS) : null;
|
const gender = user?.gender || "male";
|
||||||
|
|
||||||
const birthDate = pbBirthDate || profile?.birthDate;
|
|
||||||
const gender = pbGender || profile?.gender;
|
|
||||||
|
|
||||||
const html = `
|
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 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>
|
</button>
|
||||||
|
|
||||||
<h2 class="text-2xl font-bold text-white mb-1">🕌 Kaza Namaz Takibi</h2>
|
<div class="flex items-center gap-3 mb-2">
|
||||||
<p class="text-slate-400 text-sm mb-6">
|
<span class="text-3xl">📿</span>
|
||||||
Hicri yaşını ve kalan kaza namazını takip et.
|
<div>
|
||||||
</p>
|
<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
|
!birthDate
|
||||||
? `
|
? `
|
||||||
<div class="bg-slate-900/40 border border-white/10 p-6 rounded-2xl mb-6">
|
<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-sm font-semibold text-slate-300 mb-4">Profil Bilgileri</h3>
|
<h3 class="text-base font-bold text-white mb-2">Doğum Tarihi Gerekli</h3>
|
||||||
<form id="profileForm" class="grid grid-cols-1 md:grid-cols-3 gap-4">
|
<p class="text-xs text-slate-400 mb-6">Kaza namazı borcunu tam hesaplayabilmemiz için bilgilerinizi kaydedin.</p>
|
||||||
<div>
|
<form id="profileForm" class="space-y-4">
|
||||||
<label class="block text-xs text-slate-400 mb-1">Doğum Tarihi</label>
|
<div class="text-left">
|
||||||
<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" />
|
<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>
|
||||||
<div>
|
<div class="text-left">
|
||||||
<label class="block text-xs text-slate-400 mb-1">Cinsiyet</label>
|
<label class="block text-xs text-slate-300 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">
|
<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="male">Erkek</option>
|
||||||
<option value="female">Kadın</option>
|
<option value="female">Kadın</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-end">
|
<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-700 text-white px-4 py-2 rounded-xl text-sm font-medium transition-all">
|
Hesapla ve Kaydet
|
||||||
Hesapla
|
</button>
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
: `
|
: `
|
||||||
<div class="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 gap-3 mb-6">
|
<!-- OYUNLAŞTIRILMIŞ GENEL İLERLEME (PROGRESS BAR) -->
|
||||||
<div class="bg-slate-900/40 border border-white/10 p-3 rounded-2xl text-center">
|
<div class="bg-slate-950/60 border border-white/10 p-5 rounded-2xl mb-6 mt-2">
|
||||||
<p class="text-[10px] text-slate-400 mb-1">Hicri Doğum Tarihi</p>
|
<div class="flex items-center justify-between mb-2">
|
||||||
<p class="text-sm font-bold text-white" id="hijriBirthDateDisplay">-</p>
|
<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>
|
||||||
|
<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(
|
${PRAYERS.map(
|
||||||
(p) => `
|
(p) => `
|
||||||
<div class="bg-slate-900/40 border border-white/10 p-3 rounded-2xl text-center">
|
<div class="bg-slate-950/40 border border-white/10 p-3 rounded-2xl text-center relative overflow-hidden group">
|
||||||
<p class="text-[10px] text-slate-400 mb-1">${p.name}</p>
|
<p class="text-[11px] font-bold text-slate-300 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-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-1">Toplam: <span id="total-${p.id}">-</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>
|
</div>
|
||||||
`,
|
`
|
||||||
).join("")}
|
).join("")}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="bg-slate-900/40 border border-white/10 p-4 rounded-2xl mb-6">
|
<!-- KAZA EKLE / DÜŞ ALANI -->
|
||||||
<h3 class="text-sm font-semibold text-slate-300 mb-3">Kaza Namaz Ekle / Çıkar</h3>
|
<div class="bg-slate-950/40 border border-white/10 p-4 rounded-2xl mb-6">
|
||||||
<form id="addKazaForm" class="flex items-center gap-3">
|
<form id="addKazaForm" class="flex flex-wrap 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">
|
<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("")}
|
${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-950 border border-slate-800 rounded-xl px-4 py-2 text-white text-sm" />
|
<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-indigo-600 hover:bg-indigo-700 text-white px-4 py-2 rounded-xl text-sm font-medium transition-all">
|
|
||||||
Ekle
|
<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>
|
||||||
<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">
|
<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">
|
||||||
Çıkar
|
Geri Al (-)
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
<p id="kazaMsg" class="text-xs mt-2 hidden"></p>
|
<p id="kazaMsg" class="text-xs mt-2.5 hidden"></p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex-1 overflow-y-auto pr-2">
|
<!-- SON İŞLEMLER -->
|
||||||
<h3 class="text-sm font-semibold text-slate-300 mb-4">Bugünkü Namazlar</h3>
|
<div class="flex-1 overflow-y-auto pr-1">
|
||||||
<div class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-3 mb-6">
|
<h3 class="text-xs font-bold text-slate-400 uppercase tracking-wider mb-3">Son Kaza Geçmişi</h3>
|
||||||
${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>
|
|
||||||
<div class="space-y-2" id="logsContainer">
|
<div class="space-y-2" id="logsContainer">
|
||||||
<p class="text-xs text-slate-500">Yükleniyor...</p>
|
<p class="text-xs text-slate-500">Yükleniyor...</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -124,146 +119,69 @@ export function renderKaza(pb) {
|
|||||||
return {
|
return {
|
||||||
html,
|
html,
|
||||||
initEvents: (container) => {
|
initEvents: (container) => {
|
||||||
const closeBtn = container.querySelector("#closeBtn");
|
container.querySelector("#closeBtn")?.addEventListener("click", () => {
|
||||||
if (closeBtn) {
|
window.dispatchEvent(new CustomEvent("navigate", { detail: "desktop" }));
|
||||||
closeBtn.addEventListener("click", () => {
|
});
|
||||||
const event = new CustomEvent("navigate", { detail: "desktop" });
|
|
||||||
window.dispatchEvent(event);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!birthDate) {
|
if (!birthDate) {
|
||||||
const form = container.querySelector("#profileForm");
|
container.querySelector("#profileForm")?.addEventListener("submit", async (e) => {
|
||||||
const genderSelect = container.querySelector("#gender");
|
e.preventDefault();
|
||||||
if (gender && genderSelect) {
|
const bInput = container.querySelector("#birthDateInput").value;
|
||||||
genderSelect.value = gender;
|
const gInput = container.querySelector("#genderInput").value;
|
||||||
}
|
|
||||||
if (form) {
|
|
||||||
form.addEventListener("submit", async (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
const birthDateInput = container.querySelector("#birthDate").value;
|
|
||||||
const genderInput = container.querySelector("#gender").value;
|
|
||||||
|
|
||||||
if (!birthDateInput) {
|
try {
|
||||||
alert("Lütfen doğum tarihinizi girin.");
|
await pb.collection("users").update(pb.authStore.model.id, {
|
||||||
return;
|
birthDate: bInput,
|
||||||
}
|
gender: gInput,
|
||||||
|
});
|
||||||
try {
|
pb.authStore.model.birthDate = bInput;
|
||||||
await pb.collection("users").update(pb.authStore.model.id, {
|
pb.authStore.model.gender = gInput;
|
||||||
birthDate: birthDateInput,
|
window.dispatchEvent(new CustomEvent("navigate", { detail: "kaza" }));
|
||||||
gender: genderInput,
|
} catch (err) {
|
||||||
});
|
alert("Profil kaydedilemedi. PocketBase bağlantısını kontrol edin.");
|
||||||
} 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);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
refreshKazaStats(container, pb, birthDate, gender, profile);
|
refreshKazaStats(container, pb, birthDate, gender);
|
||||||
|
|
||||||
const addBtn = container.querySelector("#addKazaBtn");
|
container.querySelector("#addKazaBtn")?.addEventListener("click", async () => {
|
||||||
const removeBtn = container.querySelector("#removeKazaBtn");
|
await handleKazaLog(container, pb, birthDate, gender, 1);
|
||||||
|
});
|
||||||
|
|
||||||
if (addBtn) {
|
container.querySelector("#removeKazaBtn")?.addEventListener("click", async () => {
|
||||||
addBtn.addEventListener("click", async () => {
|
await handleKazaLog(container, pb, birthDate, gender, -1);
|
||||||
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,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function refreshKazaStats(container, pb, birthDate, gender, profile) {
|
async function handleKazaLog(container, pb, birthDate, gender, multiplier) {
|
||||||
if (!birthDate) return;
|
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);
|
try {
|
||||||
const hijriBirth = getHijriBirthDate(birthDate);
|
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");
|
showKazaMsg(msg, count > 0 ? `🎉 ${count} vakit kaza kılındı olarak işlendi!` : `${Math.abs(count)} vakit düşüldü.`, true);
|
||||||
if (birthDateEl) {
|
if (countInput) countInput.value = "1";
|
||||||
birthDateEl.textContent = `${hijriBirth.day} ${hijriBirth.monthName} ${hijriBirth.year}`;
|
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 logsByPrayer = {};
|
||||||
|
let logs = [];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const records = await pb.collection("kaza_logs").getFullList({
|
const records = await pb.collection("kaza_logs").getFullList({
|
||||||
@@ -271,60 +189,73 @@ async function refreshKazaStats(container, pb, birthDate, gender, profile) {
|
|||||||
sort: "-createdAt",
|
sort: "-createdAt",
|
||||||
});
|
});
|
||||||
|
|
||||||
logs = records.map((r) => ({
|
logs = records;
|
||||||
id: r.id,
|
records.forEach((l) => {
|
||||||
prayerId: r.prayerId,
|
logsByPrayer[l.prayerId] = (logsByPrayer[l.prayerId] || 0) + (l.count || 0);
|
||||||
count: r.count || 1,
|
|
||||||
date: r.date,
|
|
||||||
createdAt: r.createdAt,
|
|
||||||
}));
|
|
||||||
|
|
||||||
logs.forEach((l) => {
|
|
||||||
logsByPrayer[l.prayerId] =
|
|
||||||
(logsByPrayer[l.prayerId] || 0) + (l.count || 1);
|
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Loglar yüklenemedi:", err);
|
console.error("Loglar çekilemedi:", err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let grandTotalMissed = 0;
|
||||||
|
let grandTotalCompleted = 0;
|
||||||
|
|
||||||
PRAYERS.forEach((p) => {
|
PRAYERS.forEach((p) => {
|
||||||
const totalEl = container.querySelector(`#total-${p.id}`);
|
|
||||||
const remainEl = container.querySelector(`#remaining-${p.id}`);
|
|
||||||
const missed = calc[p.id] || 0;
|
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);
|
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 (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];
|
// Genel İlerleme Çubuğu ve Yüzde Hesaplama
|
||||||
const todayLogs = logs.filter((l) => l.date === todayKey);
|
const overallPct = grandTotalMissed > 0
|
||||||
if (profile) {
|
? Math.min(100, Math.round((grandTotalCompleted / grandTotalMissed) * 100))
|
||||||
profile.todayLogs = todayLogs;
|
: 100;
|
||||||
localStorage.setItem("kaza_profile", JSON.stringify(profile));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
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");
|
const logsContainer = container.querySelector("#logsContainer");
|
||||||
if (logsContainer) {
|
if (logsContainer) {
|
||||||
logsContainer.innerHTML =
|
logsContainer.innerHTML =
|
||||||
logs
|
logs
|
||||||
.slice(0, 20)
|
.slice(0, 10)
|
||||||
.map((log) => {
|
.map((log) => {
|
||||||
const prayer = PRAYERS.find((p) => p.id === log.prayerId);
|
const prayer = PRAYERS.find((p) => p.id === log.prayerId);
|
||||||
|
const isPlus = log.count > 0;
|
||||||
return `
|
return `
|
||||||
<div class="flex items-center justify-between bg-slate-900/20 border border-white/5 rounded-xl px-4 py-2">
|
<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">${prayer?.name || log.prayerId} x${log.count} - ${log.date}</span>
|
<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 text-emerald-400">+${log.count}</span>
|
<span class="text-xs font-bold ${isPlus ? "text-emerald-400" : "text-rose-400"}">${isPlus ? '+' : ''}${log.count}</span>
|
||||||
</div>
|
</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) {
|
function showKazaMsg(el, text, success) {
|
||||||
|
if (!el) return;
|
||||||
el.textContent = text;
|
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");
|
el.classList.remove("hidden");
|
||||||
}
|
}
|
||||||
+32
-13
@@ -2,24 +2,16 @@ export async function fetchPrayerTimes(cityName = "Edremit", lat, lon) {
|
|||||||
try {
|
try {
|
||||||
let url;
|
let url;
|
||||||
if (lat !== undefined && lon !== undefined) {
|
if (lat !== undefined && lon !== undefined) {
|
||||||
url =
|
url = `https://api.aladhan.com/v1/timings?latitude=${encodeURIComponent(lat)}&longitude=${encodeURIComponent(lon)}&method=13`;
|
||||||
"https://api.aladhan.com/v1/timings?latitude=" +
|
|
||||||
encodeURIComponent(lat) +
|
|
||||||
"&longitude=" +
|
|
||||||
encodeURIComponent(lon) +
|
|
||||||
"&method=13";
|
|
||||||
} else {
|
} else {
|
||||||
url =
|
url = `https://api.aladhan.com/v1/timingsByCity?city=${encodeURIComponent(cityName)}&country=Turkey&method=13`;
|
||||||
"https://api.aladhan.com/v1/timingsByCity?city=" +
|
|
||||||
encodeURIComponent(cityName) +
|
|
||||||
"&country=Turkey&method=2";
|
|
||||||
}
|
}
|
||||||
const res = await fetch(url);
|
const res = await fetch(url);
|
||||||
if (!res.ok) {
|
if (!res.ok) throw new Error("Namaz vakitleri alınamadı");
|
||||||
throw new Error("Namaz vakitleri alınamadı");
|
|
||||||
}
|
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
const t = data.data.timings;
|
const t = data.data.timings;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
fajr: t.Fajr,
|
fajr: t.Fajr,
|
||||||
sunrise: t.Sunrise,
|
sunrise: t.Sunrise,
|
||||||
@@ -28,9 +20,36 @@ export async function fetchPrayerTimes(cityName = "Edremit", lat, lon) {
|
|||||||
maghrib: t.Maghrib,
|
maghrib: t.Maghrib,
|
||||||
isha: t.Isha,
|
isha: t.Isha,
|
||||||
imsak: t.Imsak,
|
imsak: t.Imsak,
|
||||||
|
currentPrayer: getCurrentPrayer(t),
|
||||||
};
|
};
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Namaz vakti hatası:", err);
|
console.error("Namaz vakti hatası:", err);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getCurrentPrayer(timings) {
|
||||||
|
const now = new Date();
|
||||||
|
const currentMinutes = now.getHours() * 60 + now.getMinutes();
|
||||||
|
|
||||||
|
const parseTime = (timeStr) => {
|
||||||
|
const [h, m] = timeStr.split(":").map(Number);
|
||||||
|
return h * 60 + m;
|
||||||
|
};
|
||||||
|
|
||||||
|
const imsak = parseTime(timings.Imsak);
|
||||||
|
const dhuhr = parseTime(timings.Dhuhr);
|
||||||
|
const asr = parseTime(timings.Asr);
|
||||||
|
const maghrib = parseTime(timings.Maghrib);
|
||||||
|
const isha = parseTime(timings.Isha);
|
||||||
|
|
||||||
|
if (currentMinutes >= imsak && currentMinutes < dhuhr)
|
||||||
|
return { name: "Sabah", key: "fajr" };
|
||||||
|
if (currentMinutes >= dhuhr && currentMinutes < asr)
|
||||||
|
return { name: "Öğle", key: "dhuhr" };
|
||||||
|
if (currentMinutes >= asr && currentMinutes < maghrib)
|
||||||
|
return { name: "İkindi", key: "asr" };
|
||||||
|
if (currentMinutes >= maghrib && currentMinutes < isha)
|
||||||
|
return { name: "Akşam", key: "maghrib" };
|
||||||
|
return { name: "Yatsı", key: "isha" };
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user