Add Prayer Reminder, Dhikr Counter, Qibla Finder, Halal Monitor updates
- Prayer reminder: /prayer page with 5 daily times, countdown, alAdhan API - Dhikr counter: /dhikr page with 3 presets, custom counter, haptics, DB tracking - Qibla finder: /qibla page with compass SVG, DeviceOrientation, bearing to Kaaba - Halal Monitor: Leaflet + Google Places, 26 KL markers, geolocation, distance sort - BottomNav: added clock icon for prayer - Prisma: schema updates for DhikrSession, DhikrDay, DailyStreak, XpTransaction - Geo utility module - Weighted Traefik routing: Contabo 99% / Synology 1% cold standby
This commit is contained in:
+61
-1
@@ -8,7 +8,7 @@ import {
|
||||
Bot, ShoppingBag, MessageCircle, Wallet,
|
||||
Flame, Sparkles, Star, ChevronRight,
|
||||
BookOpen, MapPin, Crown, Zap, TrendingUp,
|
||||
Gift, Trophy,
|
||||
Gift, Trophy, CircleDot, Compass,
|
||||
} from "lucide-react";
|
||||
import { DAILY_VERSE, generateAIResponse } from "@/lib/ai";
|
||||
import PremiumBadge from "@/components/PremiumBadge";
|
||||
@@ -19,6 +19,7 @@ export default function HomePage() {
|
||||
const [verse] = useState(DAILY_VERSE[Math.floor(Math.random() * DAILY_VERSE.length)]);
|
||||
const [claiming, setClaiming] = useState(false);
|
||||
const [claimResult, setClaimResult] = useState<string | null>(null);
|
||||
const [dhikrTodayCount, setDhikrTodayCount] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
if (!loading && !token) router.push("/auth");
|
||||
@@ -34,6 +35,19 @@ export default function HomePage() {
|
||||
return () => clearInterval(interval);
|
||||
}, [token, refreshStreak, refreshXp]);
|
||||
|
||||
// Fetch dhikr stats
|
||||
useEffect(() => {
|
||||
if (!token) return;
|
||||
fetch("/mobile/api/dhikr/stats", {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
})
|
||||
.then((r) => r.ok ? r.json() : null)
|
||||
.then((data) => {
|
||||
if (data?.dayStats?.totalCount != null) setDhikrTodayCount(data.dayStats.totalCount);
|
||||
})
|
||||
.catch(() => {});
|
||||
}, [token]);
|
||||
|
||||
const handleClaimReward = async () => {
|
||||
if (!token || claiming) return;
|
||||
setClaiming(true);
|
||||
@@ -245,6 +259,52 @@ export default function HomePage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Dhikr Today */}
|
||||
<div className="mx-4 mb-5">
|
||||
<Link href="/dhikr" className="block bg-gradient-to-br from-emerald-900/15 via-[#111118] to-gray-900/80 border border-emerald-800/25 rounded-2xl p-5 active:scale-[0.98] transition-all">
|
||||
<div className="flex items-center justify-between mb-3">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="w-9 h-9 rounded-xl bg-emerald-900/30 flex items-center justify-center">
|
||||
<CircleDot size={18} className="text-emerald-400" />
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-sm font-semibold text-white">Dhikr Today</h3>
|
||||
<p className="text-xs text-gray-500">Digital Tasbih Counter</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-right">
|
||||
<p className="text-lg font-bold text-emerald-400 tabular-nums">{dhikrTodayCount.toLocaleString()}</p>
|
||||
<p className="text-[10px] text-gray-600">counts</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center justify-center gap-3 text-xs text-gray-500">
|
||||
<span className="text-emerald-400/70">سُبْحَانَ ٱللَّٰهِ</span>
|
||||
<span className="text-gray-600">·</span>
|
||||
<span className="text-amber-400/70">ٱلْحَمْدُ لِلَّٰهِ</span>
|
||||
<span className="text-gray-600">·</span>
|
||||
<span className="text-sky-400/70">ٱللَّٰهُ أَكْبَرُ</span>
|
||||
</div>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
{/* Qibla Finder */}
|
||||
<div className="mx-4 mb-5">
|
||||
<Link href="/qibla" className="block bg-gradient-to-br from-amber-900/15 via-[#111118] to-gray-900/80 border border-amber-800/25 rounded-2xl p-5 active:scale-[0.98] transition-all">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="w-9 h-9 rounded-xl bg-amber-900/30 flex items-center justify-center">
|
||||
<Compass size={18} className="text-amber-400" />
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-sm font-semibold text-white">Qibla Finder</h3>
|
||||
<p className="text-xs text-gray-500">Find direction to the Kaaba</p>
|
||||
</div>
|
||||
</div>
|
||||
<ChevronRight size={16} className="text-amber-600" />
|
||||
</div>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
{/* Stats Row */}
|
||||
<div className="mx-4 mb-5">
|
||||
<div className="flex gap-3">
|
||||
|
||||
Reference in New Issue
Block a user