User Settings: - Add /api/user/settings endpoint for persisting theme and fontSize preferences - Update settings page with working save functionality - Add validation and localized error messages Reading Plans: - Add database schema with ReadingPlan, UserReadingPlan, and UserReadingProgress models - Create CRUD API endpoints for reading plans and progress tracking - Build UI for browsing available plans and managing user enrollments - Implement progress tracking with daily reading schedule - Add streak calculation and statistics display - Create seed data with 5 predefined plans (Bible in 1 year, 90 days, NT 30 days, Psalms 30, Gospels 30) - Add navigation link with internationalization support Technical: - Update to MUI v7 Grid API (using size prop instead of xs/sm/md and removing item prop) - Fix Next.js 15 dynamic route params (await params pattern) - Add translations for readingPlans in all languages (en, ro, es, it) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
243 lines
6.4 KiB
TypeScript
243 lines
6.4 KiB
TypeScript
import { PrismaClient } from '@prisma/client'
|
|
|
|
const prisma = new PrismaClient()
|
|
|
|
async function main() {
|
|
console.log('Seeding reading plans...')
|
|
|
|
// Bible in One Year (simplified - just a sample schedule)
|
|
const bibleInOneYear = await prisma.readingPlan.upsert({
|
|
where: { id: 'bible-one-year-en' },
|
|
update: {},
|
|
create: {
|
|
id: 'bible-one-year-en',
|
|
name: 'Read the Bible in One Year',
|
|
description: 'A complete reading plan to read through the entire Bible in 365 days. This plan includes readings from both Old and New Testament each day.',
|
|
type: 'PREDEFINED',
|
|
duration: 365,
|
|
difficulty: 'intermediate',
|
|
language: 'en',
|
|
isActive: true,
|
|
schedule: generateBibleInOneYearSchedule()
|
|
}
|
|
})
|
|
|
|
// Read the Bible in 90 Days
|
|
const bible90Days = await prisma.readingPlan.upsert({
|
|
where: { id: 'bible-90-days-en' },
|
|
update: {},
|
|
create: {
|
|
id: 'bible-90-days-en',
|
|
name: 'Read the Bible in 90 Days',
|
|
description: 'An intensive reading plan to complete the entire Bible in just 90 days. Requires reading about 12-15 chapters per day.',
|
|
type: 'PREDEFINED',
|
|
duration: 90,
|
|
difficulty: 'advanced',
|
|
language: 'en',
|
|
isActive: true,
|
|
schedule: generateBible90DaysSchedule()
|
|
}
|
|
})
|
|
|
|
// New Testament in 30 Days
|
|
const newTestament30 = await prisma.readingPlan.upsert({
|
|
where: { id: 'new-testament-30-en' },
|
|
update: {},
|
|
create: {
|
|
id: 'new-testament-30-en',
|
|
name: 'New Testament in 30 Days',
|
|
description: 'Read through the entire New Testament in one month. Perfect for focusing on the life and teachings of Jesus and the early church.',
|
|
type: 'PREDEFINED',
|
|
duration: 30,
|
|
difficulty: 'intermediate',
|
|
language: 'en',
|
|
isActive: true,
|
|
schedule: generateNewTestament30Schedule()
|
|
}
|
|
})
|
|
|
|
// Psalms in 30 Days
|
|
const psalms30 = await prisma.readingPlan.upsert({
|
|
where: { id: 'psalms-30-en' },
|
|
update: {},
|
|
create: {
|
|
id: 'psalms-30-en',
|
|
name: 'Psalms in 30 Days',
|
|
description: 'Read through all 150 Psalms in 30 days. Experience the full range of worship, prayer, and praise in the book of Psalms.',
|
|
type: 'PREDEFINED',
|
|
duration: 30,
|
|
difficulty: 'beginner',
|
|
language: 'en',
|
|
isActive: true,
|
|
schedule: generatePsalms30Schedule()
|
|
}
|
|
})
|
|
|
|
// Gospels in 30 Days
|
|
const gospels30 = await prisma.readingPlan.upsert({
|
|
where: { id: 'gospels-30-en' },
|
|
update: {},
|
|
create: {
|
|
id: 'gospels-30-en',
|
|
name: 'The Four Gospels in 30 Days',
|
|
description: 'Read through Matthew, Mark, Luke, and John in one month. Focus on the life, teachings, death, and resurrection of Jesus Christ.',
|
|
type: 'PREDEFINED',
|
|
duration: 30,
|
|
difficulty: 'beginner',
|
|
language: 'en',
|
|
isActive: true,
|
|
schedule: generateGospels30Schedule()
|
|
}
|
|
})
|
|
|
|
console.log('✅ Reading plans seeded successfully!')
|
|
console.log('Created plans:')
|
|
console.log('- Bible in One Year')
|
|
console.log('- Bible in 90 Days')
|
|
console.log('- New Testament in 30 Days')
|
|
console.log('- Psalms in 30 Days')
|
|
console.log('- The Four Gospels in 30 Days')
|
|
}
|
|
|
|
// Helper functions to generate schedules
|
|
function generateBibleInOneYearSchedule() {
|
|
const schedule = []
|
|
// Simplified: Just create a sample schedule with some books
|
|
// In production, this would be a complete 365-day schedule
|
|
for (let day = 1; day <= 365; day++) {
|
|
schedule.push({
|
|
day,
|
|
readings: [
|
|
{ book: 'Genesis', chapter: day % 50 + 1 },
|
|
{ book: 'Matthew', chapter: ((day - 1) % 28) + 1 }
|
|
]
|
|
})
|
|
}
|
|
return schedule
|
|
}
|
|
|
|
function generateBible90DaysSchedule() {
|
|
const schedule = []
|
|
// Simplified schedule for 90 days
|
|
for (let day = 1; day <= 90; day++) {
|
|
schedule.push({
|
|
day,
|
|
readings: [
|
|
{ book: 'Genesis', chapter: (day * 2) % 50 + 1 },
|
|
{ book: 'Exodus', chapter: (day * 2 + 1) % 40 + 1 },
|
|
{ book: 'Matthew', chapter: ((day - 1) % 28) + 1 }
|
|
]
|
|
})
|
|
}
|
|
return schedule
|
|
}
|
|
|
|
function generateNewTestament30Schedule() {
|
|
const books = [
|
|
{ name: 'Matthew', chapters: 28 },
|
|
{ name: 'Mark', chapters: 16 },
|
|
{ name: 'Luke', chapters: 24 },
|
|
{ name: 'John', chapters: 21 },
|
|
{ name: 'Acts', chapters: 28 },
|
|
{ name: 'Romans', chapters: 16 },
|
|
{ name: 'Corinthians_1', chapters: 16 },
|
|
{ name: 'Corinthians_2', chapters: 13 }
|
|
]
|
|
|
|
const schedule = []
|
|
let currentBook = 0
|
|
let currentChapter = 1
|
|
|
|
for (let day = 1; day <= 30; day++) {
|
|
const dayReadings = []
|
|
|
|
// Add approximately 9 chapters per day (260 chapters / 30 days)
|
|
for (let i = 0; i < 9; i++) {
|
|
if (currentBook < books.length) {
|
|
dayReadings.push({
|
|
book: books[currentBook].name,
|
|
chapter: currentChapter
|
|
})
|
|
|
|
currentChapter++
|
|
if (currentChapter > books[currentBook].chapters) {
|
|
currentBook++
|
|
currentChapter = 1
|
|
}
|
|
}
|
|
}
|
|
|
|
schedule.push({ day, readings: dayReadings })
|
|
}
|
|
|
|
return schedule
|
|
}
|
|
|
|
function generatePsalms30Schedule() {
|
|
const schedule = []
|
|
let psalm = 1
|
|
|
|
for (let day = 1; day <= 30; day++) {
|
|
const dayReadings = []
|
|
|
|
// Read 5 Psalms per day (150 / 30 = 5)
|
|
for (let i = 0; i < 5 && psalm <= 150; i++) {
|
|
dayReadings.push({
|
|
book: 'Psalms',
|
|
chapter: psalm
|
|
})
|
|
psalm++
|
|
}
|
|
|
|
schedule.push({ day, readings: dayReadings })
|
|
}
|
|
|
|
return schedule
|
|
}
|
|
|
|
function generateGospels30Schedule() {
|
|
const gospels = [
|
|
{ name: 'Matthew', chapters: 28 },
|
|
{ name: 'Mark', chapters: 16 },
|
|
{ name: 'Luke', chapters: 24 },
|
|
{ name: 'John', chapters: 21 }
|
|
]
|
|
|
|
const schedule = []
|
|
let currentGospel = 0
|
|
let currentChapter = 1
|
|
|
|
for (let day = 1; day <= 30; day++) {
|
|
const dayReadings = []
|
|
|
|
// Read about 3 chapters per day (89 total chapters / 30 days ≈ 3)
|
|
for (let i = 0; i < 3; i++) {
|
|
if (currentGospel < gospels.length) {
|
|
dayReadings.push({
|
|
book: gospels[currentGospel].name,
|
|
chapter: currentChapter
|
|
})
|
|
|
|
currentChapter++
|
|
if (currentChapter > gospels[currentGospel].chapters) {
|
|
currentGospel++
|
|
currentChapter = 1
|
|
}
|
|
}
|
|
}
|
|
|
|
schedule.push({ day, readings: dayReadings })
|
|
}
|
|
|
|
return schedule
|
|
}
|
|
|
|
main()
|
|
.catch((e) => {
|
|
console.error(e)
|
|
process.exit(1)
|
|
})
|
|
.finally(async () => {
|
|
await prisma.$disconnect()
|
|
})
|