"use client"; import { useState, useEffect, useRef, Suspense, useCallback } from "react"; import { useAuth } from "@/lib/AuthContext"; import { PERSONAS, getPersona } from "@/lib/personas"; import Link from "next/link"; import { useRouter } from "next/navigation"; import { Send, Lock, Sparkles, Crown, Bot, ChevronLeft, AlertTriangle, Loader2, CheckCircle2, MessageSquare, } from "lucide-react"; import PremiumBadge from "@/components/PremiumBadge"; /* ── Types ── */ interface ChatMessage { id?: string; role: "user" | "assistant"; content: string; createdAt?: string; metadata?: { personaId?: string } | null; } /* ── Main Page ── */ export default function NurPage() { return ( } > ); } /* ── Chat Component ── */ function NurChat() { const { user, token, loading } = useAuth(); const router = useRouter(); const [messages, setMessages] = useState([]); const [input, setInput] = useState(""); const [activePersona, setActivePersona] = useState("nurbuddy"); const [isTyping, setIsTyping] = useState(false); const [dailyCount, setDailyCount] = useState(0); const [dailyLimit, setDailyLimit] = useState(10); const [error, setError] = useState(null); const [initialLoading, setInitialLoading] = useState(true); const messagesEndRef = useRef(null); const inputRef = useRef(null); /* Redirect if not logged in */ useEffect(() => { if (!loading && !token) { router.push("/login"); } }, [loading, token, router]); /* Load chat history + daily stats */ useEffect(() => { if (!token || !user) return; const loadData = async () => { try { const [historyRes, dailyRes] = await Promise.all([ fetch(`/api/chat/history/${user.id}`, { headers: { Authorization: `Bearer ${token}` }, }), fetch("/api/chat/daily", { headers: { Authorization: `Bearer ${token}` }, }), ]); if (historyRes.ok) { const hist = await historyRes.json(); setMessages(hist.messages || []); } if (dailyRes.ok) { const daily = await dailyRes.json(); setDailyCount(daily.count || 0); setDailyLimit(daily.limit === -1 ? Infinity : daily.limit); } } catch { // silent } finally { setInitialLoading(false); } }; loadData(); }, [token, user]); /* Auto-scroll on new messages */ const scrollToBottom = useCallback(() => { setTimeout(() => { messagesEndRef.current?.scrollIntoView({ behavior: "smooth" }); }, 100); }, []); useEffect(() => { scrollToBottom(); }, [messages, isTyping, scrollToBottom]); /* Send message */ const sendMessage = async () => { const trimmed = input.trim(); if (!trimmed || isTyping) return; setError(null); const userMsg: ChatMessage = { role: "user", content: trimmed }; setMessages((prev) => [...prev, userMsg]); setInput(""); setIsTyping(true); try { const res = await fetch("/api/chat/send", { method: "POST", headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}`, }, body: JSON.stringify({ messages: [{ role: "user", content: trimmed }], personaId: activePersona, }), }); const data = await res.json(); if (!res.ok) { if (res.status === 429) { setError("Daily message limit reached. Upgrade to continue chatting!"); } else if (res.status === 403) { setError(data.error || "This persona requires an upgrade."); } else { setError(data.error || "Failed to send message"); } // Remove the optimistic user message on error setMessages((prev) => prev.slice(0, -1)); return; } const aiMsg: ChatMessage = { id: data.message.id, role: "assistant", content: data.message.content, createdAt: data.message.createdAt, }; setMessages((prev) => [...prev, aiMsg]); // Update daily count if (data.daily) { setDailyCount(data.daily.count); setDailyLimit(data.daily.limit === -1 ? Infinity : data.daily.limit); } } catch { setError("Network error. Please try again."); setMessages((prev) => prev.slice(0, -1)); } finally { setIsTyping(false); } }; /* Keyboard shortcut */ const handleKeyDown = (e: React.KeyboardEvent) => { if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); sendMessage(); } }; if (loading || initialLoading) { return (
); } if (!user || !token) return null; const isPremium = user.isPremium || user.isPro; const isPro = user.isPro; const isUnlimited = dailyLimit === Infinity; const atLimit = !isUnlimited && dailyCount >= dailyLimit; const limitPercent = isUnlimited ? 0 : Math.min(100, (dailyCount / dailyLimit) * 100); const remaining = isUnlimited ? -1 : dailyLimit - dailyCount; return (
{/* ── Header ── */}

Nur AI

{isPro ? "Pro Plan" : isPremium ? "Premium Plan" : "Free Plan"}

{!isPremium && ( Upgrade )}
{/* ── Persona Selector ── */} } > {/* ── Daily Cap Bar ── */}
{isUnlimited ? ( Unlimited messages ) : ( `${dailyCount}/${dailyLimit} messages today` )} {!isUnlimited && remaining <= 3 && remaining > 0 && ( {remaining} left )}
{!isUnlimited && (
= 80 ? "bg-red-500" : limitPercent >= 50 ? "bg-amber-500" : "bg-[#D4AF37]" }`} style={{ width: `${limitPercent}%` }} />
)}
{/* ── Upgrade Banner (hitting limit) ── */} {!isPremium && atLimit && (

You've hit your daily limit

Upgrade to Premium for 100 messages/day or Pro for unlimited access.

See Plans
)} {/* ── Messages Area ── */}
{messages.length === 0 && !isTyping && (

Start a conversation

Choose a persona and send a message to get AI-powered Islamic guidance.

)} {messages.map((msg, idx) => ( ))} {isTyping && (
)}
{/* ── Error Message ── */} {error && (

{error}

)} {/* ── Input Area ── */}