feat: add answered prayers tab with answer details tracking
This commit is contained in:
1 parent
159a7463cd
commit
12377187c8
4 files changed
+133
-4
No files matched your search
+19
-2
@@ -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}
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
@@ -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: '⚙️' },
|
||||
];
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in new issue
Block a user