Add Prayer Times, Dhikr counter, Quran tracker with mobile UI overhaul
- Prayer times page: arc progress ring, next-prayer countdown, clean prayer list - Dhikr counter: SVG ring with glow, 3-phase sequence (SubhanAllah/Alhamdulillah/AllahuAkbar), streak tracking - Daily Quran reading tracker API routes (GET/POST) - Bottom nav updated: Prayer + Dhikr tabs, Repeat2 icon for dhikr, Moon for prayer - Home page redirects to /prayer as primary entry point - Dockerfile: openssl added to builder stage, explicit prisma schema path fixes build - Schema: dhikrStreak, quranStreak on User; DhikrSession and QuranReading models - Stub wallet top-up checkout to fix TypeScript build error Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import { prisma } from '@/lib/prisma'
|
||||
import { verifyJWT } from '@/lib/auth'
|
||||
|
||||
export async function GET(req: NextRequest) {
|
||||
const auth = req.headers.get('authorization')
|
||||
if (!auth?.startsWith('Bearer ')) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
|
||||
const payload = await verifyJWT(auth.slice(7))
|
||||
if (!payload) return NextResponse.json({ error: 'Invalid token' }, { status: 401 })
|
||||
|
||||
const today = new Date().toISOString().slice(0, 10)
|
||||
const [user, reading] = await Promise.all([
|
||||
prisma.user.findUnique({ where: { id: payload.id }, select: { quranStreak: true, quranStreakDate: true } }),
|
||||
prisma.quranReading.findUnique({ where: { userId_date: { userId: payload.id, date: today } } }),
|
||||
])
|
||||
|
||||
return NextResponse.json({
|
||||
streak: user?.quranStreak ?? 0,
|
||||
todayRead: reading?.pagesRead ?? 0,
|
||||
todayGoal: reading?.goalPages ?? 1,
|
||||
date: today,
|
||||
})
|
||||
}
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
const auth = req.headers.get('authorization')
|
||||
if (!auth?.startsWith('Bearer ')) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
|
||||
const payload = await verifyJWT(auth.slice(7))
|
||||
if (!payload) return NextResponse.json({ error: 'Invalid token' }, { status: 401 })
|
||||
|
||||
const { pages = 1, goal = 1 } = await req.json()
|
||||
const today = new Date().toISOString().slice(0, 10)
|
||||
|
||||
const reading = await prisma.quranReading.upsert({
|
||||
where: { userId_date: { userId: payload.id, date: today } },
|
||||
create: { userId: payload.id, date: today, pagesRead: pages, goalPages: goal },
|
||||
update: { pagesRead: pages, goalPages: goal },
|
||||
})
|
||||
|
||||
const goalMet = reading.pagesRead >= reading.goalPages
|
||||
|
||||
if (goalMet) {
|
||||
const user = await prisma.user.findUnique({
|
||||
where: { id: payload.id },
|
||||
select: { quranStreak: true, quranStreakDate: true },
|
||||
})
|
||||
const yesterday = new Date()
|
||||
yesterday.setDate(yesterday.getDate() - 1)
|
||||
const yesterdayStr = yesterday.toISOString().slice(0, 10)
|
||||
const lastDate = user?.quranStreakDate?.toISOString().slice(0, 10)
|
||||
|
||||
let newStreak = 1
|
||||
if (lastDate === yesterdayStr) newStreak = (user?.quranStreak ?? 0) + 1
|
||||
else if (lastDate === today) newStreak = user?.quranStreak ?? 1
|
||||
|
||||
await prisma.user.update({
|
||||
where: { id: payload.id },
|
||||
data: { quranStreak: newStreak, quranStreakDate: new Date() },
|
||||
})
|
||||
|
||||
return NextResponse.json({ streak: newStreak, goalMet: true, pagesRead: reading.pagesRead })
|
||||
}
|
||||
|
||||
return NextResponse.json({ streak: null, goalMet: false, pagesRead: reading.pagesRead })
|
||||
}
|
||||
Reference in New Issue
Block a user