feat: add answered prayers tab with answer details tracking

This commit is contained in:
nmemmert committed 2026-01-15 14:47:52 -05:00
1 parent 159a7463cd
commit 12377187c8
4 files changed
+133 -4

No files matched your search

+19 -2
View File
@@ -10,6 +10,7 @@ import CalendarView from '@/components/CalendarView';
import ReflectionsList from '@/components/ReflectionsList';
import SettingsPage from '@/components/SettingsPage';
import HomePage from '@/components/HomePage';
import AnsweredPrayers from '@/components/AnsweredPrayers';
import { db } from '@/lib/firebase';
import { collection, addDoc, getDocs, updateDoc, query, where, doc } from 'firebase/firestore';
import toast from 'react-hot-toast';
@@ -20,10 +21,12 @@ interface Prayer {
date: string;
text: string;
prayFor?: string;
answered?: boolean;
answerDetails?: string;
}
export default function Home() {
const [activeTab, setActiveTab] = useState<'home' | 'compose' | 'journal' | 'reflections' | 'settings'>('home');
const [activeTab, setActiveTab] = useState<'home' | 'compose' | 'journal' | 'answered' | 'reflections' | 'settings'>('home');
const [prayers, setPrayers] = useState<Prayer[]>([]);
const [editingPrayer, setEditingPrayer] = useState<Prayer | null>(null);
@@ -31,6 +34,8 @@ export default function Home() {
const [date, setDate] = useState(new Date().toISOString().split('T')[0]);
const [text, setText] = useState('');
const [prayFor, setPrayFor] = useState('');
const [answered, setAnswered] = useState(false);
const [answerDetails, setAnswerDetails] = useState('');
const { user, loading: authLoading } = useAuth();
@@ -98,6 +103,8 @@ export default function Home() {
date,
text,
prayFor: prayFor || undefined,
answered,
answerDetails: answerDetails || undefined,
};
if (editingPrayer) {
@@ -132,7 +139,9 @@ export default function Home() {
setDate(prayer.date);
setText(prayer.text);
setPrayFor(prayer.prayFor || '');
setActiveTab('home');
setAnswered(prayer.answered || false);
setAnswerDetails(prayer.answerDetails || '');
setActiveTab('compose');
};
const handleDateClick = (clickedDate: string) => {
@@ -206,6 +215,10 @@ export default function Home() {
onTextChange={setText}
prayFor={prayFor}
onPrayForChange={setPrayFor}
answered={answered}
onAnsweredChange={setAnswered}
answerDetails={answerDetails}
onAnswerDetailsChange={setAnswerDetails}
onSubmit={handleSubmit}
isEditing={!!editingPrayer}
/>
@@ -215,6 +228,10 @@ export default function Home() {
<CalendarView prayers={prayers} onDayClick={handleDateClick} />
)}
{activeTab === 'answered' && (
<AnsweredPrayers prayers={prayers} onEdit={handleSelectPrayer} />
)}
{activeTab === 'reflections' && (
<ReflectionsList
prayers={prayers}
+72
View File
@@ -0,0 +1,72 @@
'use client';
interface Prayer {
id: string;
userId: string;
date: string;
text: string;
prayFor?: string;
answered?: boolean;
answerDetails?: string;
}
interface AnsweredPrayersProps {
prayers: Prayer[];
onEdit?: (prayer: Prayer) => void;
}
export default function AnsweredPrayers({ prayers, onEdit }: AnsweredPrayersProps) {
const answeredPrayers = prayers.filter(p => p.answered);
return (
<div className="min-h-screen bg-gradient-to-b from-slate-50 to-slate-100 dark:from-slate-900 dark:to-slate-800 p-4 pb-32">
<div className="max-w-md mx-auto">
<h1 className="text-3xl font-bold text-slate-900 dark:text-white mb-2 mt-6">Answered Prayers</h1>
<p className="text-slate-600 dark:text-slate-400 mb-6">Celebrate prayers God has answered</p>
{answeredPrayers.length > 0 ? (
<div className="space-y-4">
{answeredPrayers.map((prayer) => (
<div
key={prayer.id}
className="bg-white dark:bg-slate-800 rounded-lg p-4 shadow-sm border-l-4 border-green-500 hover:shadow-md transition-shadow cursor-pointer"
onClick={() => onEdit?.(prayer)}
>
<div className="flex items-start gap-2 mb-2">
<span className="text-2xl">✅</span>
<div className="flex-1">
{prayer.prayFor && (
<div className="text-xs font-semibold text-green-600 dark:text-green-400 mb-1 uppercase tracking-wide">
{prayer.prayFor}
</div>
)}
<p className="text-sm text-slate-700 dark:text-slate-300 line-clamp-2 font-medium">{prayer.text}</p>
</div>
</div>
{prayer.answerDetails && (
<div className="mt-3 pt-3 border-t border-slate-200 dark:border-slate-700">
<p className="text-xs font-semibold text-slate-600 dark:text-slate-400 mb-1">How it was answered:</p>
<p className="text-sm text-slate-600 dark:text-slate-300 italic line-clamp-3">{prayer.answerDetails}</p>
</div>
)}
<div className="text-xs text-slate-500 dark:text-slate-500 mt-2">
{new Date(prayer.date).toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })}
</div>
</div>
))}
</div>
) : (
<div className="text-center py-12">
<div className="text-4xl mb-3">🙏</div>
<p className="text-slate-600 dark:text-slate-400 mb-2">No answered prayers yet</p>
<p className="text-sm text-slate-500 dark:text-slate-500">
Mark prayers as answered in the Compose tab to see them here
</p>
</div>
)}
</div>
</div>
);
}
+3 -2
View File
@@ -4,8 +4,8 @@ import React from 'react';
import { useAuth } from '@/context/AuthContext';
interface BottomNavProps {
activeTab: 'home' | 'compose' | 'journal' | 'reflections' | 'settings';
onTabChange: (tab: 'home' | 'compose' | 'journal' | 'reflections' | 'settings') => void;
activeTab: 'home' | 'compose' | 'journal' | 'answered' | 'reflections' | 'settings';
onTabChange: (tab: 'home' | 'compose' | 'journal' | 'answered' | 'reflections' | 'settings') => void;
}
export default function BottomNav({ activeTab, onTabChange }: BottomNavProps) {
@@ -15,6 +15,7 @@ export default function BottomNav({ activeTab, onTabChange }: BottomNavProps) {
{ id: 'home' as const, label: 'Home', icon: '🏠' },
{ id: 'compose' as const, label: 'Compose', icon: '✍️' },
{ id: 'journal' as const, label: 'Journal', icon: '📅' },
{ id: 'answered' as const, label: 'Answered', icon: '✅' },
{ id: 'reflections' as const, label: 'Reflections', icon: '📖' },
{ id: 'settings' as const, label: 'Settings', icon: '⚙️' },
];
+39
View File
@@ -10,6 +10,10 @@ interface DailyEntryProps {
onTextChange: (text: string) => void;
prayFor: string;
onPrayForChange: (prayFor: string) => void;
answered?: boolean;
onAnsweredChange?: (answered: boolean) => void;
answerDetails?: string;
onAnswerDetailsChange?: (details: string) => void;
onSubmit: (e: React.FormEvent) => void;
loading?: boolean;
isEditing?: boolean;
@@ -22,6 +26,10 @@ export default function DailyEntry({
onTextChange,
prayFor,
onPrayForChange,
answered = false,
onAnsweredChange,
answerDetails = '',
onAnswerDetailsChange,
onSubmit,
loading = false,
isEditing = false,
@@ -91,6 +99,37 @@ export default function DailyEntry({
/>
</div>
{/* Answered Checkbox */}
<div className="flex items-center gap-3">
<input
type="checkbox"
id="answered"
checked={answered}
onChange={(e) => onAnsweredChange?.(e.target.checked)}
className="w-5 h-5 rounded border-slate-300 text-blue-600 focus:ring-blue-500 cursor-pointer"
/>
<label htmlFor="answered" className="font-semibold text-slate-700 dark:text-slate-300 cursor-pointer">
Mark as answered
</label>
</div>
{/* Answer Details */}
{answered && (
<div>
<label htmlFor="answerDetails" className="block text-sm font-semibold text-slate-700 dark:text-slate-300 mb-2">
How was it answered?
</label>
<textarea
id="answerDetails"
value={answerDetails}
onChange={(e) => onAnswerDetailsChange?.(e.target.value)}
placeholder="Share how God answered this prayer..."
rows={4}
className="w-full px-4 py-3 rounded-lg border border-slate-300 dark:border-slate-600 bg-white dark:bg-slate-800 text-slate-900 dark:text-white placeholder-slate-400 dark:placeholder-slate-500 focus:ring-2 focus:ring-green-500 focus:border-transparent transition-all resize-none font-serif"
/>
</div>
)}
{/* Submit Button */}
<button
type="submit"