Move Add Prayer button to sidebar and implement comprehensive prayer functionality

- Integrated prayer data with Prisma database schema
- Updated API endpoints to use actual database
- Implemented AI prayer generation with Azure OpenAI
- Added user authentication for prayer creation
- Moved Add Prayer button from FAB to sidebar top
- Added prayer count tracking and user prayer status

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
andupetcu
2025-09-21 23:17:20 +03:00
parent 6492601355
commit 5a3c6a6691
7 changed files with 669 additions and 259 deletions

View File

@@ -1,4 +1,5 @@
import { NextRequest, NextResponse } from 'next/server'
import { prisma } from '@/lib/db'
export async function POST(
request: NextRequest,
@@ -17,16 +18,123 @@ export async function POST(
)
}
// TODO: Update prayer count in database
// For now, just return success
console.log(`Prayer count updated for prayer ${prayerId}`)
// Get user from auth token if available
const authHeader = request.headers.get('authorization')
let userId: string | null = null
if (authHeader && authHeader.startsWith('Bearer ')) {
const token = authHeader.slice(7)
// Verify token and get user
const session = await prisma.session.findUnique({
where: { token },
include: { user: true }
})
if (session && session.expiresAt > new Date()) {
userId = session.userId
}
}
// Get client IP for anonymous counting
const ip = request.headers.get('x-forwarded-for') ||
request.headers.get('x-real-ip') ||
'unknown'
// Start a transaction to update both the prayer count and user prayer record
const result = await prisma.$transaction(async (tx) => {
// Check if prayer request exists
const prayerRequest = await tx.prayerRequest.findUnique({
where: { id: prayerId }
})
if (!prayerRequest) {
throw new Error('Prayer request not found')
}
// If user is logged in, track user prayer
if (userId) {
// Check if user already prayed for this
const existingUserPrayer = await tx.userPrayer.findUnique({
where: {
userId_requestId: {
userId: userId,
requestId: prayerId
}
}
})
if (!existingUserPrayer) {
// Create user prayer record
await tx.userPrayer.create({
data: {
userId: userId,
requestId: prayerId
}
})
// Increment prayer count
await tx.prayerRequest.update({
where: { id: prayerId },
data: {
prayerCount: {
increment: 1
}
}
})
}
} else {
// For anonymous users, track by IP
const existingPrayer = await tx.prayer.findUnique({
where: {
requestId_ipAddress: {
requestId: prayerId,
ipAddress: ip
}
}
})
if (!existingPrayer) {
// Create anonymous prayer record
await tx.prayer.create({
data: {
requestId: prayerId,
ipAddress: ip
}
})
// Increment prayer count
await tx.prayerRequest.update({
where: { id: prayerId },
data: {
prayerCount: {
increment: 1
}
}
})
}
}
return prayerRequest
})
return NextResponse.json({
success: true,
message: 'Prayer count updated successfully'
message: 'Prayer count updated successfully',
prayerCount: result.prayerCount + 1
})
} catch (error) {
} catch (error: any) {
console.error('Error updating prayer count:', error)
if (error.message === 'Prayer request not found') {
return NextResponse.json(
{
success: false,
error: 'Prayer request not found'
},
{ status: 404 }
)
}
return NextResponse.json(
{
success: false,

View File

@@ -1,7 +1,16 @@
import { NextRequest, NextResponse } from 'next/server'
import { AzureOpenAI } from 'openai'
export const runtime = 'nodejs'
// Initialize Azure OpenAI client
const client = new AzureOpenAI({
apiKey: process.env.AZURE_OPENAI_KEY || '',
endpoint: process.env.AZURE_OPENAI_ENDPOINT || '',
apiVersion: process.env.AZURE_OPENAI_API_VERSION || '2024-05-01-preview',
deployment: 'gpt-4o' // Using GPT-4 for better quality prayers
})
export async function POST(request: NextRequest) {
try {
const { prompt, category, locale } = await request.json()
@@ -13,89 +22,97 @@ export async function POST(request: NextRequest) {
)
}
// In a real implementation, you would call an AI service like OpenAI
// For now, we'll create a mock response based on the prompt and locale
// Call Azure OpenAI to generate a prayer
const isRomanian = locale === 'ro'
// Mock AI-generated prayer based on category and prompt
const prayers = {
personal: {
en: {
title: "Personal Guidance Prayer",
prayer: `Heavenly Father, I come before You seeking Your guidance and wisdom. ${prompt} I trust in Your perfect plan for my life and ask for strength to walk in Your ways. Help me to find peace in Your presence and confidence in Your love. Grant me clarity in my decisions and courage to follow Your will. In Jesus' name, Amen.`
},
ro: {
title: "Rugăciune pentru îndrumarea personală",
prayer: `Tatăl ceresc, vin înaintea Ta căutând îndrumarea și înțelepciunea Ta. ${prompt} Mă încred în planul Tău perfect pentru viața mea și îți cer putere să umblu pe căile Tale. Ajută-mă să găsesc pace în prezența Ta și încredere în dragostea Ta. Dă-mi claritate în deciziile mele și curaj să urmez voia Ta. În numele lui Isus, Amin.`
}
},
family: {
en: {
title: "Family Blessing Prayer",
prayer: `Lord God, I lift up my family to You today. ${prompt} Bless each member of our household with Your love, protection, and guidance. Strengthen our bonds of love and help us to support one another through all of life's challenges. May Your peace fill our home and Your wisdom guide our relationships. Keep us united in faith and love. In Christ's name, Amen.`
},
ro: {
title: "Rugăciune pentru binecuvântarea familiei",
prayer: `Doamne Dumnezeule, îmi ridic familia către Tine astăzi. ${prompt} Binecuvântează fiecare membru al casei noastre cu dragostea, protecția și îndrumarea Ta. Întărește legăturile noastre de dragoste și ajută-ne să ne sprijinim unii pe alții prin toate provocările vieții. Să umple pacea Ta casa noastră și înțelepciunea Ta să ne călăuzească relațiile. Păstrează-ne uniți în credință și dragoste. În numele lui Hristos, Amin.`
}
},
health: {
en: {
title: "Healing and Health Prayer",
prayer: `Great Physician, I bring before You our need for healing and health. ${prompt} You are the source of all healing and restoration. I pray for Your healing touch upon every area of concern. Grant wisdom to medical professionals, comfort to those who suffer, and strength to caregivers. May Your peace that surpasses understanding guard our hearts and minds. I trust in Your goodness and mercy. In Jesus' healing name, Amen.`
},
ro: {
title: "Rugăciune pentru vindecarea și sănătatea",
prayer: `Mare Doctor, aduc înaintea Ta nevoia noastră de vindecare și sănătate. ${prompt} Tu ești sursa oricărei vindecări și restaurări. Mă rog pentru atingerea Ta vindecătoare asupra fiecărei zone de îngrijorare. Dă înțelepciune profesioniștilor medicali, mângâiere celor care suferă, și putere îngrijitorilor. Să păzească pacea Ta care întrece orice pricepere, inimile și mințile noastre. Mă încred în bunătatea și mila Ta. În numele vindecător al lui Isus, Amin.`
}
},
work: {
en: {
title: "Workplace and Career Prayer",
prayer: `Lord of all creation, I bring my work and career before You. ${prompt} Guide my steps in my professional life and help me to be a light for You wherever You place me. Grant me wisdom in my decisions, integrity in my actions, and favor in my relationships. May I work with excellence and find fulfillment in serving others through my calling. Bless the work of my hands. In Your name, Amen.`
},
ro: {
title: "Rugăciune pentru locul de muncă și carieră",
prayer: `Doamne al întregii creații, îmi aduc munca și cariera înaintea Ta. ${prompt} Călăuzește-mi pașii în viața mea profesională și ajută-mă să fiu o lumină pentru Tine oriunde mă pui. Dă-mi înțelepciune în deciziile mele, integritate în acțiunile mele, și favoare în relațiile mele. Să lucrez cu excelență și să găsesc împlinire în a-i sluji pe alții prin chemarea mea. Binecuvântează lucrarea mâinilor mele. În numele Tău, Amin.`
}
},
ministry: {
en: {
title: "Ministry and Service Prayer",
prayer: `Heavenly Father, I dedicate my service to You and Your kingdom. ${prompt} Use me as an instrument of Your love and grace in this world. Fill me with Your Spirit and equip me for every good work You have prepared for me. Help me to serve with humility, compassion, and wisdom. May Your glory be revealed through my life and ministry. Strengthen me for the journey ahead. In Christ's name, Amen.`
},
ro: {
title: "Rugăciune pentru serviciu și lucrare",
prayer: `Tatăl ceresc, îmi dedic slujirea către Tine și împărăția Ta. ${prompt} Folosește-mă ca un instrument al dragostei și harului Tău în această lume. Umple-mă cu Duhul Tău și echipează-mă pentru orice lucrare bună pe care ai pregătit-o pentru mine. Ajută-mă să slujesc cu smerenie, compasiune și înțelepciune. Să se reveleze gloria Ta prin viața și lucrarea mea. Întărește-mă pentru călătoria care urmează. În numele lui Hristos, Amin.`
}
},
world: {
en: {
title: "Global and World Prayer",
prayer: `Sovereign Lord, You rule over all nations and peoples. ${prompt} I pray for Your kingdom to come and Your will to be done on earth as it is in heaven. Bring peace where there is conflict, hope where there is despair, and healing where there is brokenness. Raise up leaders who will serve with righteousness and justice. May Your love transform our world. Come, Lord Jesus. Amen.`
},
ro: {
title: "Rugăciune pentru lume și global",
prayer: `Domn Suveran, Tu domnești peste toate națiunile și popoarele. ${prompt} Mă rog ca împărăția Ta să vină și voia Ta să se facă pe pământ cum se face în cer. Adu pace unde este conflict, speranță unde este deznădejde, și vindecare unde este zdrobire. Ridică conducători care să slujească cu dreptate și neprihănire. Să transforme dragostea Ta lumea noastră. Vino, Doamne Isuse. Amin.`
}
// Create system prompt for the AI
const systemPrompt = isRomanian
? `Ești un asistent creștin care ajută oamenii să formuleze rugăciuni sincere și biblice.
Creează rugăciuni care sunt:
- Respectuoase și reverenți față de Dumnezeu
- Bazate pe principii și învățături biblice
- Personale și pline de compasiune
- Încurajatoare și pline de speranță
- Scurte și concise (maxim 150 de cuvinte)
- Potrivite pentru categoria: ${category}
- În limba română`
: `You are a Christian assistant helping people formulate sincere and biblical prayers.
Create prayers that are:
- Respectful and reverent toward God
- Based on biblical principles and teachings
- Personal and compassionate
- Encouraging and hopeful
- Brief and concise (maximum 150 words)
- Appropriate for the category: ${category}
- In English`
// Create user prompt
const userPrompt = isRomanian
? `Te rog să creezi o rugăciune sinceră pentru următoarea situație: ${prompt}
Categoria: ${category}
Răspunde în format JSON cu structura: {"title": "titlul rugăciunii", "prayer": "textul rugăciunii"}`
: `Please create a sincere prayer for the following situation: ${prompt}
Category: ${category}
Respond in JSON format with structure: {"title": "prayer title", "prayer": "prayer text"}`
try {
// Call Azure OpenAI
const completion = await client.chat.completions.create({
model: 'gpt-4o',
messages: [
{ role: 'system', content: systemPrompt },
{ role: 'user', content: userPrompt }
],
temperature: 0.7,
max_tokens: 500,
response_format: { type: 'json_object' }
})
const responseText = completion.choices[0]?.message?.content || '{}'
const prayerData = JSON.parse(responseText)
return NextResponse.json({
title: prayerData.title || (isRomanian ? 'Rugăciune generată' : 'Generated Prayer'),
prayer: prayerData.prayer || (isRomanian ? 'Nu s-a putut genera rugăciunea.' : 'Could not generate prayer.'),
category,
generated: true
})
} catch (aiError) {
console.error('Error calling Azure OpenAI:', aiError)
// Fallback to template-based generation
const categoryTemplates = {
personal: isRomanian
? { title: 'Rugăciune personală', prayer: `Doamne, îți aduc înaintea Ta această cerere personală: ${prompt}. Te rog să mă îndrumi și să-mi dai pace. În numele lui Isus, Amin.` }
: { title: 'Personal Prayer', prayer: `Lord, I bring before You this personal request: ${prompt}. Please guide me and grant me peace. In Jesus' name, Amen.` },
family: isRomanian
? { title: 'Rugăciune pentru familie', prayer: `Tată ceresc, îți încredințez familia mea. ${prompt}. Binecuvântează-ne și păstrează-ne uniți în dragoste. În numele lui Isus, Amin.` }
: { title: 'Family Prayer', prayer: `Heavenly Father, I entrust my family to You. ${prompt}. Bless us and keep us united in love. In Jesus' name, Amen.` },
health: isRomanian
? { title: 'Rugăciune pentru sănătate', prayer: `Mare Vindecător, vin la Tine cu această nevoie de sănătate: ${prompt}. Te rog pentru vindecare și restaurare. În numele lui Isus, Amin.` }
: { title: 'Health Prayer', prayer: `Great Healer, I come to You with this health need: ${prompt}. I pray for healing and restoration. In Jesus' name, Amen.` },
work: isRomanian
? { title: 'Rugăciune pentru muncă', prayer: `Doamne, îți aduc situația mea profesională: ${prompt}. Îndrumă-mă și binecuvântează munca mâinilor mele. În numele lui Isus, Amin.` }
: { title: 'Work Prayer', prayer: `Lord, I bring my professional situation: ${prompt}. Guide me and bless the work of my hands. In Jesus' name, Amen.` },
ministry: isRomanian
? { title: 'Rugăciune pentru lucrare', prayer: `Doamne, îți dedic această lucrare: ${prompt}. Folosește-mă pentru gloria Ta. În numele lui Isus, Amin.` }
: { title: 'Ministry Prayer', prayer: `Lord, I dedicate this ministry to You: ${prompt}. Use me for Your glory. In Jesus' name, Amen.` },
world: isRomanian
? { title: 'Rugăciune pentru lume', prayer: `Domn Suveran, mă rog pentru această situație globală: ${prompt}. Fie voia Ta pe pământ. În numele lui Isus, Amin.` }
: { title: 'World Prayer', prayer: `Sovereign Lord, I pray for this global situation: ${prompt}. May Your will be done on earth. In Jesus' name, Amen.` }
}
const template = categoryTemplates[category as keyof typeof categoryTemplates] || categoryTemplates.personal
return NextResponse.json({
title: template.title,
prayer: template.prayer,
category,
generated: true
})
}
const language = isRomanian ? 'ro' : 'en'
const categoryPrayers = prayers[category as keyof typeof prayers] || prayers.personal
const prayerData = categoryPrayers[language]
// Simulate AI processing delay
await new Promise(resolve => setTimeout(resolve, 1500))
return NextResponse.json({
title: prayerData.title,
prayer: prayerData.prayer,
category,
generated: true
})
} catch (error) {
console.error('Error generating prayer:', error)
return NextResponse.json(

View File

@@ -1,11 +1,13 @@
import { NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { prisma } from '@/lib/db'
import { getServerSession } from 'next-auth'
const createPrayerSchema = z.object({
title: z.string().min(1).max(200),
description: z.string().min(1).max(1000),
category: z.enum(['personal', 'family', 'health', 'work', 'ministry', 'world']),
author: z.string().optional().default('Anonim')
isAnonymous: z.boolean().optional().default(false)
})
export async function GET(request: NextRequest) {
@@ -13,89 +15,54 @@ export async function GET(request: NextRequest) {
const { searchParams } = new URL(request.url)
const category = searchParams.get('category')
const limit = parseInt(searchParams.get('limit') || '20')
const userId = searchParams.get('userId')
// Mock prayer data for now
// TODO: Replace with actual database queries
const allPrayers = [
{
id: '1',
title: 'Rugăciune pentru vindecare',
description: 'Te rog să te rogi pentru tatăl meu care se află în spital. Are nevoie de vindecarea lui Dumnezeu.',
category: 'health',
author: 'Maria P.',
timestamp: new Date(Date.now() - 2 * 60 * 60 * 1000),
prayerCount: 23,
isPrayedFor: false,
},
{
id: '2',
title: 'Îndrumarea lui Dumnezeu în carieră',
description: 'Caut direcția lui Dumnezeu pentru următorul pas în cariera mea. Te rog să te rogi pentru claritate și pace.',
category: 'work',
author: 'Alexandru M.',
timestamp: new Date(Date.now() - 5 * 60 * 60 * 1000),
prayerCount: 15,
isPrayedFor: true,
},
{
id: '3',
title: 'Unitatea în familia noastră',
description: 'Rugați-vă pentru restaurarea relațiilor în familia noastră și pentru iertarea reciprocă.',
category: 'family',
author: 'Anonim',
timestamp: new Date(Date.now() - 1 * 24 * 60 * 60 * 1000),
prayerCount: 41,
isPrayedFor: false,
},
{
id: '4',
title: 'Pentru misionarii din Africa',
description: 'Rugați-vă pentru protecția și proviziunea pentru misionarii noștri care lucrează în Africa.',
category: 'ministry',
author: 'Pavel R.',
timestamp: new Date(Date.now() - 6 * 60 * 60 * 1000),
prayerCount: 12,
isPrayedFor: false,
},
{
id: '5',
title: 'Pace în Ucraina',
description: 'Să ne rugăm pentru pace și protecție pentru poporul ucrainean în aceste timpuri dificile.',
category: 'world',
author: 'Comunitatea',
timestamp: new Date(Date.now() - 12 * 60 * 60 * 1000),
prayerCount: 89,
isPrayedFor: true,
},
{
id: '6',
title: 'Trecerea prin depresie',
description: 'Am nevoie de rugăciuni pentru a trece prin această perioadă grea de depresie și anxietate.',
category: 'personal',
author: 'Anonim',
timestamp: new Date(Date.now() - 8 * 60 * 60 * 1000),
prayerCount: 34,
isPrayedFor: false,
}
]
let filteredPrayers = allPrayers
// Apply category filter
if (category && category !== 'all') {
filteredPrayers = allPrayers.filter(prayer => prayer.category === category)
// Build the where clause
const where: any = {
isActive: true
}
// Apply limit
filteredPrayers = filteredPrayers.slice(0, limit)
if (category && category !== 'all') {
where.category = category
}
// Sort by timestamp (newest first)
filteredPrayers.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime())
// Fetch prayers from database with user prayer status
const prayers = await prisma.prayerRequest.findMany({
where,
take: limit,
orderBy: {
createdAt: 'desc'
},
include: {
user: {
select: {
name: true
}
},
userPrayers: userId ? {
where: {
userId: userId
}
} : false
}
})
// Format prayers for response
const formattedPrayers = prayers.map(prayer => ({
id: prayer.id,
title: prayer.title,
description: prayer.description,
category: prayer.category,
author: prayer.isAnonymous ? 'Anonim' : prayer.author,
timestamp: prayer.createdAt,
prayerCount: prayer.prayerCount,
isPrayedFor: userId && prayer.userPrayers ? prayer.userPrayers.length > 0 : false
}))
return NextResponse.json({
success: true,
prayers: filteredPrayers,
total: filteredPrayers.length
prayers: formattedPrayers,
total: formattedPrayers.length
})
} catch (error) {
console.error('Error fetching prayers:', error)
@@ -115,25 +82,51 @@ export async function POST(request: NextRequest) {
const body = await request.json()
const validatedData = createPrayerSchema.parse(body)
// Create new prayer object
const newPrayer = {
id: Date.now().toString(),
title: validatedData.title,
description: validatedData.description,
category: validatedData.category,
author: validatedData.author,
timestamp: new Date(),
prayerCount: 0,
isPrayedFor: false,
// Get user from auth token if available
const authHeader = request.headers.get('authorization')
let userId: string | null = null
let userName: string = 'Anonim'
if (authHeader && authHeader.startsWith('Bearer ')) {
const token = authHeader.slice(7)
// Verify token and get user
const session = await prisma.session.findUnique({
where: { token },
include: { user: true }
})
if (session && session.expiresAt > new Date()) {
userId = session.userId
userName = session.user.name || 'Anonim'
}
}
// TODO: Save to database
// For now, just return the created prayer
console.log('New prayer created:', newPrayer)
// Create new prayer in database
const newPrayer = await prisma.prayerRequest.create({
data: {
title: validatedData.title,
description: validatedData.description,
category: validatedData.category,
author: validatedData.isAnonymous ? 'Anonim' : userName,
isAnonymous: validatedData.isAnonymous,
userId: validatedData.isAnonymous ? null : userId,
prayerCount: 0,
isActive: true
}
})
return NextResponse.json({
success: true,
prayer: newPrayer,
prayer: {
id: newPrayer.id,
title: newPrayer.title,
description: newPrayer.description,
category: newPrayer.category,
author: newPrayer.author,
timestamp: newPrayer.createdAt,
prayerCount: newPrayer.prayerCount,
isPrayedFor: false
},
message: 'Prayer request submitted successfully'
}, { status: 201 })
} catch (error) {