feat: implement Phase 4 Home screen with all 5 sections

- Prayer countdown ring (SVG circular progress, Aladhan API + fallback)
- AI morning briefing (gold gradient card, greeting by time of day)
- Verse of the day (Ayatul Kursi with Arabic, translation, gold header)
- Quick Dhikr (3 counters: SubhanAllah 33, Alhamdulillah 33, Allahu Akbar 34)
- Community feed (3 Instagram-style posts with like/comment/share actions)
This commit is contained in:
FalahMobile
2026-07-03 11:34:05 +08:00
parent c2d054e705
commit caa3f794b5
2 changed files with 492 additions and 179 deletions
+487 -174
View File
@@ -1,201 +1,514 @@
'use client'
import { useState, useEffect, useCallback } from 'react'
import { useAuth } from '@/lib/AuthContext'
import { useState, useEffect, useMemo, useCallback } from 'react'
import Link from 'next/link'
import { useRouter } from 'next/navigation'
import { Bell, ChevronRight, Flame, BookOpen } from 'lucide-react'
import { Heart, MessageCircle, Share2, RotateCcw, Bell, Clock } from 'lucide-react'
type Timings = { Fajr: string; Sunrise: string; Dhuhr: string; Asr: string; Maghrib: string; Isha: string }
const PRAYERS = ['Fajr', 'Dhuhr', 'Asr', 'Maghrib', 'Isha'] as const
type PrayerName = typeof PRAYERS[number]
/* ─── Types & Constants ─────────────────────────────────────── */
function toMins(t: string) { const [h, m] = t.replace(/\s*(AM|PM)$/i, '').split(':').map(Number); return h * 60 + m }
function fmt12(t: string) { const [h, m] = t.replace(/\s*(AM|PM)$/i, '').split(':').map(Number); return `${h % 12 || 12}:${String(m).padStart(2,'0')} ${h < 12 ? 'AM' : 'PM'}` }
function fmtCountdown(mins: number) {
const h = Math.floor(mins / 60), m = mins % 60
if (h === 0) return `${m}m`
return m === 0 ? `${h}h` : `${h}h ${m}m`
type PrayerName = 'Fajr' | 'Dhuhr' | 'Asr' | 'Maghrib' | 'Isha'
const PRAYERS: PrayerName[] = ['Fajr', 'Dhuhr', 'Asr', 'Maghrib', 'Isha']
interface Timings {
Fajr: string
Sunrise: string
Dhuhr: string
Asr: string
Maghrib: string
Isha: string
}
const FEATURES = [
{ href: '/nur', emoji: '🤖', label: 'Nur AI', bg: 'from-violet-500 to-purple-600' },
{ href: '/prayer', emoji: '🕌', label: 'Prayer', bg: 'from-emerald-500 to-teal-600' },
{ href: '/dhikr', emoji: '📿', label: 'Dhikr', bg: 'from-teal-500 to-cyan-600' },
{ href: '/souq', emoji: '🛍️', label: 'Souq', bg: 'from-amber-500 to-orange-500' },
{ href: '/halal-monitor', emoji: '🗺️', label: 'Halal Map', bg: 'from-green-500 to-emerald-600' },
{ href: '/forum', emoji: '💬', label: 'Forum', bg: 'from-blue-500 to-indigo-600' },
const AYATUL_KURSI = {
arabic:
'ٱللَّهُ لَآ إِلَـٰهَ إِلَّا هُوَ ٱلْحَىُّ ٱلْقَيُّومُ ۚ لَا تَأْخُذُهُۥ سِنَةٌ وَلَا نَوْمٌ ۚ لَّهُۥ مَا فِى ٱلسَّمَـٰوَٰتِ وَمَا فِى ٱلْأَرْضِ ۗ مَن ذَا ٱلَّذِى يَشْفَعُ عِندَهُۥٓ إِلَّا بِإِذْنِهِۦ ۚ يَعْلَمُ مَا بَيْنَ أَيْدِيهِمْ وَمَا خَلْفَهُمْ ۖ وَلَا يُحِيطُونَ بِشَىْءٍ مِّنْ عِلْمِهِۦٓ إِلَّا بِمَا شَآءَ ۚ وَسِعَ كُرْسِيُّهُ ٱلسَّمَـٰوَٰتِ وَٱلْأَرْضَ ۖ وَلَا يَـُٔودُهُۥ حِفْظُهُمَا ۚ وَهُوَ ٱلْعَلِىُّ ٱلْعَظِيمُ',
translation:
'Allah! There is no god but Him, the Ever-Living, the Sustainer of existence. Neither drowsiness nor sleep overtakes Him. To Him belongs whatever is in the heavens and whatever is on the earth. Who is it that can intercede with Him except by His permission? He knows what is before them and what will be after them, and they encompass nothing of His knowledge except what He wills. His Kursi extends over the heavens and the earth, and their preservation tires Him not. And He is the Most High, the Most Great.',
surah: 'Surah Al-Baqarah (2:255)',
}
const DHIKR_ITEMS = [
{ arabic: 'سُبْحَانَ ٱللَّٰهِ', latin: 'SubhanAllah', target: 33, color: '#D4AF37' },
{ arabic: 'ٱلْحَمْدُ لِلَّٰهِ', latin: 'Alhamdulillah', target: 33, color: '#10B981' },
{ arabic: 'ٱللَّٰهُ أَكْبَرُ', latin: 'Allahu Akbar', target: 34, color: '#D4AF37' },
]
export default function HomePage() {
const { user, token } = useAuth()
const router = useRouter()
const [timings, setTimings] = useState<Timings | null>(null)
const [next, setNext] = useState<{ name: PrayerName; minsLeft: number } | null>(null)
const [city, setCity] = useState('')
const [now, setNow] = useState(new Date())
const [verse, setVerse] = useState<{ surah: string; translation: string; arabic: string } | null>(null)
const [streak, setStreak] = useState(0)
const POSTS = [
{
id: 1,
name: 'Ahmad R.',
avatar: 'AR',
content:
'Alhamdulillah, completed my first full month of Fajr prayer on time! ☀️ The early morning blessings are real.',
likes: 24,
comments: 5,
},
{
id: 2,
name: 'Fatima Z.',
avatar: 'FZ',
content:
'Just finished reading Surah Al-Kahf. The story of the people of the cave never gets old. SubhanAllah how Allah protects the believers! 📖',
likes: 42,
comments: 8,
},
{
id: 3,
name: 'Omar H.',
avatar: 'OH',
content:
'Anyone looking for a good tafsir of Juz Amma? I highly recommend "The Clear Quran" by Dr. Mustafa Khattab. Very accessible English. 🤲',
likes: 18,
comments: 12,
},
]
useEffect(() => { const id = setInterval(() => setNow(new Date()), 60000); return () => clearInterval(id) }, [])
useEffect(() => { fetch('/api/daily/verse').then(r => r.json()).then(setVerse).catch(() => {}) }, [])
useEffect(() => {
if (!token) return
fetch('/api/dhikr/status', { headers: { Authorization: `Bearer ${token}` } })
.then(r => r.json()).then(d => setStreak(d.streak ?? 0)).catch(() => {})
}, [token])
/* ─── Helpers ────────────────────────────────────────────────── */
const fetchPrayer = useCallback((lat: number, lng: number) => {
fetch(`/api/prayer/times?lat=${lat}&lng=${lng}`)
.then(r => r.json()).then(d => {
if (d.timings) {
setTimings(d.timings)
const nowMins = now.getHours() * 60 + now.getMinutes()
for (const p of PRAYERS) {
const pm = toMins(d.timings[p])
if (pm > nowMins) { setNext({ name: p, minsLeft: pm - nowMins }); return }
const RING_R = 40
const RING_CIRCUMFERENCE = 2 * Math.PI * RING_R
const DHIKR_R = 22
const DHIKR_CIRCUMFERENCE = 2 * Math.PI * DHIKR_R
function toMins(t: string): number {
const [h, m] = t.split(':').map(Number)
return h * 60 + m
}
setNext({ name: 'Fajr', minsLeft: (24 * 60 - nowMins) + toMins(d.timings.Fajr) })
function fmtCountdown(mins: number): string {
if (mins <= 0) return 'Now'
const h = Math.floor(mins / 60)
const m = mins % 60
if (h === 0) return `${m}m`
if (m === 0) return `${h}h`
return `${h}h ${m}m`
}
}).catch(() => {})
}, [now])
useEffect(() => {
if (!navigator.geolocation) return
navigator.geolocation.getCurrentPosition(pos => {
const { latitude: lat, longitude: lng } = pos.coords
fetchPrayer(lat, lng)
fetch(`https://nominatim.openstreetmap.org/reverse?lat=${lat}&lon=${lng}&format=json`, { headers: { 'Accept-Language': 'en' } })
.then(r => r.json()).then(d => setCity(d.address?.city || d.address?.town || '')).catch(() => {})
}, () => {}, { timeout: 8000 })
}, [fetchPrayer])
const greeting = (() => {
const h = now.getHours()
function getGreeting(h: number): string {
if (h < 5) return 'Late Night Reflection'
if (h < 12) return 'Good Morning'
if (h < 17) return 'Good Afternoon'
return 'Good Evening'
})()
if (h < 20) return 'Good Evening'
return 'Night Reflection'
}
const name = user?.preferredName || user?.name?.split(' ')[0] || 'Guest'
/* ─── Sub-components ─────────────────────────────────────────── */
function DhikrCard({
item,
count,
onTap,
onReset,
}: {
item: (typeof DHIKR_ITEMS)[number]
count: number
onTap: () => void
onReset: () => void
}) {
const progress = Math.min(count / item.target, 1)
const dashoffset = DHIKR_CIRCUMFERENCE * (1 - progress)
const isComplete = count >= item.target
return (
<div className="min-h-dvh bg-[#f5f4f0] pb-24 select-none">
{/* Header gradient */}
<div className="bg-gradient-to-br from-emerald-700 via-teal-600 to-emerald-800 px-5 pt-12 pb-6 rounded-b-[32px]">
<div className="flex items-start justify-between mb-6">
<div>
<p className="text-emerald-200 text-xs font-medium mb-0.5">{greeting}</p>
<h1 className="text-2xl font-bold text-white">Assalamualaikum</h1>
<p className="text-white/80 text-sm mt-0.5">{name}</p>
</div>
<div className="flex items-center gap-2">
{streak > 0 && (
<div className="flex items-center gap-1 bg-white/15 rounded-xl px-2.5 py-1.5">
<Flame size={13} className="text-orange-300" />
<span className="text-xs font-bold text-white">{streak}</span>
</div>
)}
<button className="w-9 h-9 bg-white/15 rounded-xl flex items-center justify-center">
<Bell size={18} className="text-white" />
<div className="flex flex-col items-center gap-2">
{/* Circular ring + count display */}
<button
onClick={onTap}
className="relative w-20 h-20 flex items-center justify-center active:scale-90 transition-transform"
>
<svg width="80" height="80" viewBox="0 0 80 80" className="absolute inset-0">
<circle
cx="40" cy="40" r={DHIKR_R}
fill="none"
stroke="rgba(255,255,255,0.06)"
strokeWidth="4"
/>
<circle
cx="40" cy="40" r={DHIKR_R}
fill="none"
stroke={item.color}
strokeWidth="4"
strokeLinecap="round"
strokeDasharray={DHIKR_CIRCUMFERENCE}
strokeDashoffset={dashoffset}
className="transition-all duration-500 ease-out"
style={{ transform: 'rotate(-90deg)', transformOrigin: 'center' }}
/>
</svg>
<span className={`text-xl font-bold ${isComplete ? 'text-[#D4AF37]' : 'text-white'}`}>
{count}
</span>
</button>
</div>
{/* Label */}
<div className="flex flex-col items-center gap-0.5">
<span className="text-[13px] font-arabic leading-tight text-white/90">{item.arabic}</span>
<span className="text-[10px] text-[#999]">{item.latin}</span>
<span className="text-[10px] text-[#666]">/ {item.target}</span>
</div>
{/* Prayer time card inside header */}
<div
className="bg-white/15 backdrop-blur-sm rounded-2xl p-4 border border-white/20"
onClick={() => router.push('/prayer')}
{/* Reset */}
{count > 0 && (
<button
onClick={onReset}
className="text-[#666] hover:text-[#999] transition-colors p-0.5"
title={`Reset ${item.latin}`}
>
{next && timings ? (
<div className="flex items-center justify-between">
<div>
<p className="text-emerald-200 text-[11px] font-medium uppercase tracking-wider mb-1">Next Prayer</p>
<p className="text-white text-xl font-bold">{next.name}</p>
<p className="text-white/70 text-sm">{fmt12(timings[next.name])}</p>
{city && <p className="text-white/50 text-[11px] mt-1">{city}</p>}
</div>
<div className="text-right">
<p className="text-3xl font-bold text-white tabular-nums">{fmtCountdown(next.minsLeft)}</p>
<p className="text-white/60 text-xs mt-1">remaining</p>
<div className="flex items-center gap-1 justify-end mt-2">
<span className="text-white/50 text-[11px]">View all</span>
<ChevronRight size={11} className="text-white/50" />
</div>
</div>
</div>
) : (
<div className="flex items-center justify-between">
<div>
<p className="text-emerald-200 text-[11px] font-medium uppercase tracking-wider mb-2">Prayer Times</p>
<p className="text-white/70 text-sm">Tap to enable location</p>
</div>
<ChevronRight size={18} className="text-white/50" />
</div>
)}
</div>
</div>
{/* Features grid */}
<div className="px-5 mt-6 mb-6">
<h2 className="text-sm font-bold text-gray-900 mb-3">Quick Access</h2>
<div className="grid grid-cols-3 gap-3">
{FEATURES.map(f => (
<Link
key={f.href}
href={f.href}
className="flex flex-col items-center gap-2 active:scale-[0.94] transition-transform"
>
<div className={`w-16 h-16 rounded-2xl bg-gradient-to-br ${f.bg} flex items-center justify-center shadow-sm`}>
<span className="text-2xl">{f.emoji}</span>
</div>
<span className="text-xs font-semibold text-gray-700">{f.label}</span>
</Link>
))}
</div>
</div>
{/* Daily verse */}
{verse && (
<div className="mx-5 mb-5 bg-white rounded-2xl shadow-sm border border-gray-100 overflow-hidden">
<div className="bg-gradient-to-r from-amber-500 to-yellow-500 px-4 py-2.5 flex items-center gap-2">
<BookOpen size={14} className="text-white" />
<span className="text-white text-xs font-bold uppercase tracking-wider">Daily Verse</span>
<span className="text-white/70 text-xs ml-auto">{verse.surah}</span>
</div>
<div className="px-4 py-4">
<p className="text-right text-xl text-gray-800 leading-loose mb-3 font-light">{verse.arabic}</p>
<p className="text-gray-600 text-sm leading-relaxed italic">&ldquo;{verse.translation}&rdquo;</p>
</div>
</div>
)}
{/* Nur AI promo */}
<div className="mx-5 mb-5">
<Link href="/nur" className="block bg-gradient-to-r from-violet-600 to-purple-700 rounded-2xl p-4 active:scale-[0.98] transition-transform">
<div className="flex items-center justify-between">
<div>
<p className="text-white font-bold text-base">Ask Nur AI</p>
<p className="text-white/70 text-xs mt-0.5">Your personal Islamic guide</p>
</div>
<div className="w-10 h-10 bg-white/20 rounded-xl flex items-center justify-center">
<span className="text-xl">🤖</span>
</div>
</div>
</Link>
</div>
{/* Sign in prompt for guests */}
{!user && (
<div className="mx-5 mb-5 bg-white rounded-2xl shadow-sm border border-gray-100 p-4">
<p className="text-gray-900 font-semibold text-sm mb-1">Sign in to track your progress</p>
<p className="text-gray-500 text-xs mb-3">Streaks, history, and personalization</p>
<Link href="/login" className="block w-full text-center bg-emerald-600 text-white py-3 rounded-xl font-semibold text-sm active:scale-[0.98] transition-transform">
Sign In
</Link>
</div>
<RotateCcw size={12} />
</button>
)}
</div>
)
}
function PostCard({ post }: { post: (typeof POSTS)[number] }) {
const [liked, setLiked] = useState(false)
const [likeCount, setLikeCount] = useState(post.likes)
const handleLike = () => {
setLiked((p) => !p)
setLikeCount((p) => (liked ? p - 1 : p + 1))
}
return (
<div className="bg-[#111118] rounded-2xl border border-[#222] overflow-hidden">
{/* Author row */}
<div className="flex items-center gap-3 px-4 pt-4 pb-2">
<div className="w-9 h-9 rounded-full bg-[#D4AF37]/20 flex items-center justify-center shrink-0">
<span className="text-xs font-bold text-[#D4AF37]">{post.avatar}</span>
</div>
<div className="flex-1 min-w-0">
<p className="text-sm font-semibold text-white truncate">{post.name}</p>
<p className="text-[11px] text-[#666]">Just now</p>
</div>
</div>
{/* Content */}
<div className="px-4 py-2">
<p className="text-sm text-[#ccc] leading-relaxed">{post.content}</p>
</div>
{/* Action bar */}
<div className="flex items-center gap-5 px-4 py-3 border-t border-[#222]">
<button
onClick={handleLike}
className="flex items-center gap-1.5 active:scale-90 transition-transform"
>
<Heart
size={17}
className={liked ? 'fill-[#D4AF37] text-[#D4AF37]' : 'text-[#666]'}
/>
<span className={`text-xs ${liked ? 'text-[#D4AF37]' : 'text-[#666]'}`}>
{likeCount}
</span>
</button>
<button className="flex items-center gap-1.5 active:scale-90 transition-transform">
<MessageCircle size={17} className="text-[#666]" />
<span className="text-xs text-[#666]">{post.comments}</span>
</button>
<button className="ml-auto active:scale-90 transition-transform">
<Share2 size={16} className="text-[#666]" />
</button>
</div>
</div>
)
}
/* ─── Home Page ──────────────────────────────────────────────── */
export default function HomePage() {
const [now, setNow] = useState(new Date())
const [timings, setTimings] = useState<Timings | null>(null)
const [nextPrayer, setNextPrayer] = useState<{
name: PrayerName
time: string
minsLeft: number
progress: number
} | null>(null)
// Dhikr counters
const [dhikrCounts, setDhikrCounts] = useState([0, 0, 0])
// Tick every 30s
useEffect(() => {
const id = setInterval(() => setNow(new Date()), 30000)
return () => clearInterval(id)
}, [])
// Fetch prayer times
useEffect(() => {
fetch(
'https://api.aladhan.com/v1/timingsByCity?city=Makkah&country=SaudiArabia&method=4'
)
.then((r) => r.json())
.then((d) => {
if (d.data?.timings) {
setTimings(d.data.timings as Timings)
}
})
.catch(() => {
// Hardcoded fallback — approximate Makkah times for the demo
setTimings({
Fajr: '04:30',
Sunrise: '05:45',
Dhuhr: '12:20',
Asr: '15:45',
Maghrib: '18:55',
Isha: '20:15',
})
})
}, [])
// Compute next prayer + ring progress
useEffect(() => {
if (!timings) return
const nowMins = now.getHours() * 60 + now.getMinutes()
for (let i = 0; i < PRAYERS.length; i++) {
const pm = toMins(timings[PRAYERS[i]])
if (pm > nowMins) {
// Found the next prayer
const prevPrayer = i > 0 ? PRAYERS[i - 1] : PRAYERS[PRAYERS.length - 1]
const prevMins = toMins(timings[prevPrayer])
const windowMinutes = pm - prevMins
const elapsed = nowMins - prevMins
const progress = Math.min(Math.max(elapsed / windowMinutes, 0), 1)
setNextPrayer({
name: PRAYERS[i],
time: timings[PRAYERS[i]],
minsLeft: pm - nowMins,
progress,
})
return
}
}
// After Isha — next is Fajr (next day)
const fajrMins = toMins(timings.Fajr) + 24 * 60
const ishaMins = toMins(timings.Isha)
const windowMinutes = fajrMins - ishaMins
const elapsed = nowMins - ishaMins
const progress = Math.min(Math.max(elapsed / windowMinutes, 0), 1)
setNextPrayer({
name: 'Fajr',
time: timings.Fajr,
minsLeft: fajrMins - nowMins,
progress,
})
}, [timings, now])
const ringDashoffset = nextPrayer
? RING_CIRCUMFERENCE * (1 - nextPrayer.progress)
: RING_CIRCUMFERENCE
const greeting = useMemo(() => getGreeting(now.getHours()), [now])
// Dhikr handlers
const handleDhikrTap = useCallback((idx: number) => {
setDhikrCounts((prev) => {
const copy = [...prev]
if (copy[idx] < DHIKR_ITEMS[idx].target) {
copy[idx] = copy[idx] + 1
}
return copy
})
}, [])
const handleDhikrReset = useCallback((idx: number) => {
setDhikrCounts((prev) => {
const copy = [...prev]
copy[idx] = 0
return copy
})
}, [])
const allDhikrComplete = dhikrCounts.every(
(c, i) => c >= DHIKR_ITEMS[i].target
)
return (
<div className="min-h-dvh bg-[#0a0a0f] pb-32 select-none">
{/* ═══ Scrollable content ═══ */}
<div className="overflow-y-auto">
{/* ── Header ── */}
<div className="px-5 pt-14 pb-2">
<div className="flex items-start justify-between mb-1">
<div>
<p className="text-[#999] text-xs font-medium mb-0.5">{greeting}</p>
<h1 className="text-2xl font-bold text-white">
Assalamualaikum
</h1>
<p className="text-[#999] text-sm mt-0.5">Welcome to Falah</p>
</div>
<button className="w-9 h-9 bg-[#111118] rounded-xl flex items-center justify-center border border-[#222] active:scale-90 transition-transform">
<Bell size={17} className="text-[#999]" />
</button>
</div>
</div>
{/* ─── 1. Prayer Countdown Ring ─── */}
<div className="mx-5 mb-5">
<div className="bg-[#111118] rounded-2xl border border-[#222] p-5">
<div className="flex items-center gap-5">
{/* SVG Ring */}
<div className="relative shrink-0">
<svg width="100" height="100" viewBox="0 0 100 100">
<circle
cx="50" cy="50" r={RING_R}
className="prayer-ring-bg"
/>
<circle
cx="50" cy="50" r={RING_R}
className="prayer-ring-fg"
strokeDasharray={RING_CIRCUMFERENCE}
strokeDashoffset={ringDashoffset}
/>
</svg>
{/* Center emoji icon */}
<div className="absolute inset-0 flex items-center justify-center">
<span className="text-2xl">🕌</span>
</div>
</div>
{/* Next prayer info */}
<div className="flex-1 min-w-0">
<p className="text-[11px] text-[#666] font-medium uppercase tracking-wider mb-1">
Next Prayer
</p>
{nextPrayer ? (
<>
<p className="text-xl font-bold text-white">{nextPrayer.name}</p>
<p className="text-sm text-[#D4AF37] mt-0.5">
{nextPrayer.time}
</p>
<div className="flex items-center gap-1.5 mt-2">
<Clock size={13} className="text-[#D4AF37]" />
<span className="text-lg font-bold text-[#D4AF37] tabular-nums">
{fmtCountdown(nextPrayer.minsLeft)}
</span>
<span className="text-[11px] text-[#666]">remaining</span>
</div>
</>
) : (
<p className="text-sm text-[#999]">Loading prayer times...</p>
)}
</div>
</div>
</div>
</div>
{/* ─── 2. AI Morning Briefing ─── */}
<div className="mx-5 mb-5">
<div className="bg-gradient-to-br from-[#D4AF37]/10 to-[#B8860B]/5 rounded-2xl border border-[#D4AF37]/20 p-5 relative overflow-hidden">
{/* Decorative glow */}
<div className="absolute -top-10 -right-10 w-32 h-32 bg-[#D4AF37]/10 rounded-full blur-3xl" />
<div className="relative z-10">
<div className="flex items-center gap-2 mb-3">
<span className="text-lg">🌙</span>
<span className="text-xs font-semibold text-[#D4AF37] uppercase tracking-widest">
Morning Briefing
</span>
</div>
<p className="text-white text-base font-semibold leading-relaxed mb-2">
Assalamualaikum! 🌙 Your spiritual briefing for today...
</p>
<p className="text-[#999] text-sm leading-relaxed">
Today is a new opportunity to grow closer to Allah. Remember that
every good deed, no matter how small, is multiplied by the Most
Generous. Start your day with intention, pray Fajr on time, and
carry that light through the hours ahead.
</p>
<Link
href="/nur"
className="inline-block mt-4 text-xs font-semibold text-[#D4AF37] border border-[#D4AF37]/30 rounded-full px-4 py-1.5 active:scale-95 transition-transform"
>
Chat with NurBuddy
</Link>
</div>
</div>
</div>
{/* ─── 3. Verse of the Day ─── */}
<div className="mx-5 mb-5">
<div className="bg-[#111118] rounded-2xl border border-[#222] overflow-hidden">
{/* Gold header bar */}
<div className="gold-gradient px-4 py-2.5 flex items-center gap-2">
<span className="text-white text-xs font-bold uppercase tracking-wider">
Verse of the Day
</span>
<span className="text-white/70 text-[10px] ml-auto">
{AYATUL_KURSI.surah}
</span>
</div>
<div className="px-5 py-5">
<p
className="text-right text-lg text-white leading-[2] mb-4 font-light"
style={{ fontFamily: '"Noto Naskh Arabic", "Traditional Arabic", serif' }}
>
{AYATUL_KURSI.arabic}
</p>
<div className="w-8 h-px bg-[#D4AF37]/40 mx-auto mb-4" />
<p className="text-[#bbb] text-sm leading-relaxed italic">
&ldquo;{AYATUL_KURSI.translation}&rdquo;
</p>
</div>
</div>
</div>
{/* ─── 4. Quick Dhikr ─── */}
<div className="mx-5 mb-5">
<div className="bg-[#111118] rounded-2xl border border-[#222] p-5">
<div className="flex items-center justify-between mb-5">
<div className="flex items-center gap-2">
<span className="text-base">📿</span>
<span className="text-xs font-semibold text-[#D4AF37] uppercase tracking-widest">
Quick Dhikr
</span>
</div>
{allDhikrComplete && (
<span className="text-[10px] text-emerald-400 font-semibold">
Completed
</span>
)}
</div>
<div className="flex justify-around gap-3">
{DHIKR_ITEMS.map((item, idx) => (
<DhikrCard
key={idx}
item={item}
count={dhikrCounts[idx]}
onTap={() => handleDhikrTap(idx)}
onReset={() => handleDhikrReset(idx)}
/>
))}
</div>
</div>
</div>
{/* ─── 5. Community Feed ─── */}
<div className="mx-5 mb-5">
<div className="flex items-center gap-2 mb-3">
<span className="text-base">💬</span>
<span className="text-xs font-semibold text-[#999] uppercase tracking-widest">
Community
</span>
</div>
<div className="space-y-3">
{POSTS.map((post) => (
<PostCard key={post.id} post={post} />
))}
</div>
</div>
{/* Bottom spacer */}
<div className="h-4" />
</div>
</div>
)
}
+1 -1
View File
File diff suppressed because one or more lines are too long