diff --git a/.env.example b/.env.example index b366880..4e27316 100644 --- a/.env.example +++ b/.env.example @@ -11,6 +11,7 @@ JWT_SECRET=your-jwt-secret AZURE_OPENAI_KEY=your-azure-key AZURE_OPENAI_ENDPOINT=https://your-resource.openai.azure.com AZURE_OPENAI_DEPLOYMENT=gpt-4 +AZURE_OPENAI_API_VERSION=2024-02-15-preview # Ollama (optional) OLLAMA_API_URL=http://your-ollama-server:11434 \ No newline at end of file diff --git a/app/[locale]/page.tsx b/app/[locale]/page.tsx index 5342212..285e90e 100644 --- a/app/[locale]/page.tsx +++ b/app/[locale]/page.tsx @@ -49,6 +49,15 @@ export default function Home() { verse: string reference: string } | null>(null) + const [stats] = useState<{ + bibleVersions: number + verses: number + books: number + }>({ + bibleVersions: 1416, + verses: 17000000, + books: 66 + }) // Fetch daily verse useEffect(() => { @@ -72,6 +81,7 @@ export default function Home() { fetchDailyVerse() }, [locale, t]) + // Simulate live user counter useEffect(() => { const interval = setInterval(() => { @@ -564,13 +574,13 @@ export default function Home() { - 66 + {stats.bibleVersions.toLocaleString()} - {t('stats.books')} + {t('stats.bibleVersions')} - 31,000+ + 17M+ {t('stats.verses')} diff --git a/app/api/prayers/route.ts b/app/api/prayers/route.ts index 0002444..823950c 100644 --- a/app/api/prayers/route.ts +++ b/app/api/prayers/route.ts @@ -6,7 +6,9 @@ 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']), - isAnonymous: z.boolean().optional().default(false) + isAnonymous: z.boolean().optional().default(false), + isPublic: z.boolean().optional().default(false), + language: z.string().min(2).max(5).optional() }) export async function GET(request: Request) { @@ -14,7 +16,35 @@ export async function GET(request: Request) { const { searchParams } = new URL(request.url) const category = searchParams.get('category') const limit = parseInt(searchParams.get('limit') || '20') - const userId = searchParams.get('userId') + const visibility = (searchParams.get('visibility') || 'public').toLowerCase() + const languagesParam = searchParams.getAll('languages') + + const languages = languagesParam + .flatMap(value => + value + .split(',') + .map(part => part.trim().toLowerCase()) + .filter(Boolean) + ) + .filter((value, index, self) => self.indexOf(value) === index) + + const authHeader = request.headers.get('authorization') + let sessionUserId: string | null = null + + if (authHeader && authHeader.startsWith('Bearer ')) { + const token = authHeader.slice(7) + const session = await prisma.session.findUnique({ + where: { token }, + select: { + userId: true, + expiresAt: true + } + }) + + if (session && session.expiresAt > new Date()) { + sessionUserId = session.userId + } + } // Build the where clause const where: any = { @@ -25,6 +55,30 @@ export async function GET(request: Request) { where.category = category } + if (visibility === 'private') { + if (!sessionUserId) { + return NextResponse.json( + { + success: false, + error: 'Authentication required to view private prayers', + prayers: [] + }, + { status: 401 } + ) + } + + where.userId = sessionUserId + where.isPublic = false + } else { + where.isPublic = true + + if (languages.length > 0) { + where.language = { + in: languages + } + } + } + // Fetch prayers from database with user prayer status const prayers = await prisma.prayerRequest.findMany({ where, @@ -38,9 +92,9 @@ export async function GET(request: Request) { name: true } }, - userPrayers: userId ? { + userPrayers: sessionUserId ? { where: { - userId: userId + userId: sessionUserId } } : false } @@ -55,7 +109,10 @@ export async function GET(request: Request) { author: prayer.isAnonymous ? 'Anonim' : prayer.author, timestamp: prayer.createdAt, prayerCount: prayer.prayerCount, - isPrayedFor: userId && prayer.userPrayers ? prayer.userPrayers.length > 0 : false + isPrayedFor: sessionUserId && prayer.userPrayers ? prayer.userPrayers.length > 0 : false, + isPublic: prayer.isPublic, + language: prayer.language, + isOwner: sessionUserId ? prayer.userId === sessionUserId : false })) return NextResponse.json({ @@ -100,6 +157,26 @@ export async function POST(request: Request) { } } + if (!userId && !validatedData.isAnonymous) { + return NextResponse.json( + { + success: false, + error: 'Authentication required' + }, + { status: 401 } + ) + } + + if (!validatedData.isPublic && !userId) { + return NextResponse.json( + { + success: false, + error: 'Authentication required for private prayers' + }, + { status: 401 } + ) + } + // Create new prayer in database const newPrayer = await prisma.prayerRequest.create({ data: { @@ -108,6 +185,8 @@ export async function POST(request: Request) { category: validatedData.category, author: validatedData.isAnonymous ? 'Anonim' : userName, isAnonymous: validatedData.isAnonymous, + isPublic: validatedData.isPublic ?? false, + language: validatedData.language?.toLowerCase() || 'en', userId: validatedData.isAnonymous ? null : userId, prayerCount: 0, isActive: true @@ -124,7 +203,10 @@ export async function POST(request: Request) { author: newPrayer.author, timestamp: newPrayer.createdAt, prayerCount: newPrayer.prayerCount, - isPrayedFor: false + isPrayedFor: false, + isPublic: newPrayer.isPublic, + language: newPrayer.language, + isOwner: !!userId && newPrayer.userId === userId }, message: 'Prayer request submitted successfully' }, { status: 201 }) diff --git a/app/api/stats/route.ts b/app/api/stats/route.ts new file mode 100644 index 0000000..b514a78 --- /dev/null +++ b/app/api/stats/route.ts @@ -0,0 +1,39 @@ +import { NextResponse } from 'next/server'; +import { prisma } from '@/lib/db'; + +export const runtime = 'nodejs'; + +export async function GET() { + try { + // Get bible statistics + const [ + totalBibleVersions, + totalVerses, + totalBooks + ] = await Promise.all([ + // Count total Bible versions + prisma.bibleVersion.count(), + + // Count total verses across all versions + prisma.bibleVerse.count(), + + // Count unique books (66 biblical books) + prisma.bibleBook.groupBy({ + by: ['bookKey'], + }).then(result => result.length) + ]); + + return NextResponse.json({ + bibleVersions: totalBibleVersions, + verses: totalVerses, + books: totalBooks + }); + + } catch (error) { + console.error('Stats API error:', error); + return NextResponse.json( + { error: 'Failed to fetch statistics' }, + { status: 500 } + ); + } +} \ No newline at end of file diff --git a/messages/en.json b/messages/en.json index 303f369..76f807f 100644 --- a/messages/en.json +++ b/messages/en.json @@ -63,7 +63,7 @@ } }, "stats": { - "books": "Biblical books", + "bibleVersions": "Bible versions", "verses": "Verses", "aiAvailable": "AI Chat available" }, @@ -257,6 +257,7 @@ "chapters": "chapters", "addBookmark": "Add bookmark", "removeBookmark": "Remove bookmark", + "loginToBookmark": "Login to bookmark", "bookmarkVerse": "Bookmark verse", "removeVerseBookmark": "Remove verse bookmark", "toggleFullscreen": "Toggle fullscreen", @@ -268,6 +269,30 @@ "prayers": { "title": "Prayers", "subtitle": "Share prayers and pray together with the community", + "viewModes": { + "private": "My private prayers", + "public": "Public prayer wall" + }, + "chips": { + "private": "Private", + "public": "Public" + }, + "languageFilter": { + "title": "Languages", + "helper": "Choose which languages to include. Your current language stays selected.", + "options": { + "en": "English", + "ro": "Romanian" + } + }, + "alerts": { + "privateInfo": "Private prayers are visible only to you. Turn on public sharing to post them on the prayer wall.", + "publicInfo": "Browsing public prayers for your selected language. Add more languages from the filter." + }, + "empty": { + "private": "You have no private prayers yet. Create one to start your prayer journal.", + "public": "No public prayers match the selected filters yet." + }, "addRequest": "Add prayer request", "anonymous": "Anonymous", "prayFor": "Pray for this", @@ -299,7 +324,10 @@ "descriptionLabel": "Description", "placeholder": "Describe your prayer request...", "cancel": "Cancel", - "submit": "Add prayer" + "submit": "Add prayer", + "makePublic": "Share on the public prayer wall", + "visibilityPrivate": "Private prayers stay visible only to you.", + "visibilityPublic": "Public prayers are visible to everyone on the prayer wall." }, "samples": { "item1": { diff --git a/messages/ro.json b/messages/ro.json index d1ab774..258d270 100644 --- a/messages/ro.json +++ b/messages/ro.json @@ -63,7 +63,7 @@ } }, "stats": { - "books": "Cărți biblice", + "bibleVersions": "Versiuni Biblia", "verses": "Versete", "aiAvailable": "Chat AI disponibil" }, @@ -257,6 +257,7 @@ "chapters": "capitole", "addBookmark": "Adaugă la favorite", "removeBookmark": "Elimină din favorite", + "loginToBookmark": "Loghează-te pentru marcaj", "bookmarkVerse": "Adaugă verset la favorite", "removeVerseBookmark": "Elimină verset din favorite", "toggleFullscreen": "Comută ecran complet", @@ -268,6 +269,30 @@ "prayers": { "title": "Rugăciuni", "subtitle": "Partajează rugăciuni și roagă-te împreună cu comunitatea", + "viewModes": { + "private": "Rugăciunile mele", + "public": "Peretele de rugăciuni public" + }, + "chips": { + "private": "Privată", + "public": "Publică" + }, + "languageFilter": { + "title": "Limbi", + "helper": "Alege limbile pentru care vrei să vezi rugăciuni. Limba curentă rămâne selectată.", + "options": { + "en": "Engleză", + "ro": "Română" + } + }, + "alerts": { + "privateInfo": "Rugăciunile private sunt vizibile doar pentru tine. Activează opțiunea publică pentru a le împărtăși comunității.", + "publicInfo": "Vizualizezi rugăciuni publice pentru limba selectată. Adaugă alte limbi din filtru." + }, + "empty": { + "private": "Nu ai încă rugăciuni private. Creează una pentru a începe jurnalul tău de rugăciuni.", + "public": "Nu există încă rugăciuni publice pentru filtrele selectate." + }, "addRequest": "Adaugă cerere de rugăciune", "anonymous": "Anonim", "prayFor": "Mă rog pentru aceasta", @@ -299,7 +324,10 @@ "descriptionLabel": "Descriere", "placeholder": "Descrie cererea ta de rugăciune...", "cancel": "Anulează", - "submit": "Adaugă rugăciunea" + "submit": "Adaugă rugăciunea", + "makePublic": "Publică pe peretele de rugăciuni", + "visibilityPrivate": "Rugăciunile private sunt vizibile doar pentru tine.", + "visibilityPublic": "Rugăciunile publice sunt vizibile tuturor pe peretele de rugăciuni." }, "samples": { "item1": { diff --git a/public/robots.txt b/public/robots.txt new file mode 100644 index 0000000..7545b2d --- /dev/null +++ b/public/robots.txt @@ -0,0 +1,39 @@ +User-agent: * +Allow: / + +# Allow access to public pages +Allow: /en/ +Allow: /ro/ +Allow: /en/bible +Allow: /ro/bible +Allow: /en/prayers +Allow: /ro/prayers +Allow: /en/search +Allow: /ro/search +Allow: /en/contact +Allow: /ro/contact + +# Disallow admin pages +Disallow: /admin/ + +# Disallow private user pages +Disallow: /*/dashboard +Disallow: /*/profile +Disallow: /*/settings +Disallow: /*/bookmarks + +# Disallow API endpoints +Disallow: /api/ + +# Disallow authentication pages from indexing +Disallow: /*/login +Disallow: /*/auth/ + +# Allow static assets +Allow: /_next/static/ +Allow: /favicon.ico +Allow: /images/ +Allow: /icons/ + +# Sitemap location +Sitemap: https://biblicalguide.com/sitemap.xml \ No newline at end of file diff --git a/public/sitemap.xml b/public/sitemap.xml new file mode 100644 index 0000000..94d4c79 --- /dev/null +++ b/public/sitemap.xml @@ -0,0 +1,116 @@ + + + + + https://biblicalguide.com/en + daily + 1.0 + + + + + + https://biblicalguide.com/en/bible + weekly + 0.9 + + + + + + https://biblicalguide.com/en/prayers + daily + 0.8 + + + + + + https://biblicalguide.com/en/search + weekly + 0.7 + + + + + + https://biblicalguide.com/en/contact + monthly + 0.6 + + + + + + https://biblicalguide.com/en/login + monthly + 0.5 + + + + + + https://biblicalguide.com/en/auth/login + monthly + 0.5 + + + + + + + https://biblicalguide.com/ro + daily + 1.0 + + + + + + https://biblicalguide.com/ro/bible + weekly + 0.9 + + + + + + https://biblicalguide.com/ro/prayers + daily + 0.8 + + + + + + https://biblicalguide.com/ro/search + weekly + 0.7 + + + + + + https://biblicalguide.com/ro/contact + monthly + 0.6 + + + + + + https://biblicalguide.com/ro/login + monthly + 0.5 + + + + + + https://biblicalguide.com/ro/auth/login + monthly + 0.5 + + + + \ No newline at end of file