← back to Dear Bubbe Nextjs

app/messagespaid/page.tsx

544 lines

'use client'

import { useState, useEffect, useRef } from 'react'
import { useSession } from 'next-auth/react'
import { useRouter } from 'next/navigation'
import Link from 'next/link'
import DatingPhotoUpload from '@/components/DatingPhotoUpload'

interface Message {
  id: string
  timestamp: Date
  content: string
  sender: 'user' | 'bubbe'
  saved: boolean
  incognito: boolean
  hasPhoto?: boolean
  photoUrl?: string
}

interface Conversation {
  id: string
  title: string
  messages: Message[]
  createdAt: Date
  lastMessage: Date
  saved: boolean
  incognito: boolean
}

export default function MessagesPaidPage() {
  const { data: session, status } = useSession()
  const router = useRouter()
  const messagesEndRef = useRef<HTMLDivElement>(null)
  
  // State
  const [conversations, setConversations] = useState<Conversation[]>([])
  const [currentConversation, setCurrentConversation] = useState<Conversation | null>(null)
  const [input, setInput] = useState('')
  const [isLoading, setIsLoading] = useState(false)
  const [incognitoMode, setIncognitoMode] = useState(false)
  const [showPhotoUpload, setShowPhotoUpload] = useState(false)
  const [smsEnabled, setSmsEnabled] = useState(false)
  const [phoneNumber, setPhoneNumber] = useState('')
  const [showSettings, setShowSettings] = useState(false)

  // Redirect if not logged in
  useEffect(() => {
    if (status === 'unauthenticated') {
      router.push('/')
    }
  }, [status, router])

  // Load saved conversations
  useEffect(() => {
    if (session?.user?.email) {
      loadConversations()
      loadSmsSettings()
    }
  }, [session])

  // Auto-scroll to bottom
  useEffect(() => {
    messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' })
  }, [currentConversation?.messages])

  const loadConversations = async () => {
    try {
      const savedConvos = localStorage.getItem(`bubbe_dm_${session?.user?.email}`)
      if (savedConvos) {
        const parsed = JSON.parse(savedConvos)
        // Filter out incognito conversations that weren't saved
        const filtered = parsed.filter((c: Conversation) => c.saved || !c.incognito)
        setConversations(filtered)
      }
    } catch (error) {
      console.error('Failed to load conversations:', error)
    }
  }

  const loadSmsSettings = async () => {
    try {
      const settings = localStorage.getItem(`bubbe_sms_${session?.user?.email}`)
      if (settings) {
        const { enabled, phone } = JSON.parse(settings)
        setSmsEnabled(enabled)
        setPhoneNumber(phone)
      }
    } catch (error) {
      console.error('Failed to load SMS settings:', error)
    }
  }

  const saveSmsSettings = () => {
    localStorage.setItem(`bubbe_sms_${session?.user?.email}`, JSON.stringify({
      enabled: smsEnabled,
      phone: phoneNumber
    }))
    setShowSettings(false)
  }

  const startNewConversation = () => {
    const newConvo: Conversation = {
      id: Date.now().toString(),
      title: `Chat ${new Date().toLocaleDateString()}`,
      messages: [],
      createdAt: new Date(),
      lastMessage: new Date(),
      saved: !incognitoMode,
      incognito: incognitoMode
    }
    
    if (!incognitoMode) {
      setConversations([...conversations, newConvo])
      saveConversations([...conversations, newConvo])
    }
    
    setCurrentConversation(newConvo)
  }

  const saveConversations = (convos: Conversation[]) => {
    const toSave = convos.filter(c => c.saved)
    localStorage.setItem(`bubbe_dm_${session?.user?.email}`, JSON.stringify(toSave))
  }

  const sendMessage = async () => {
    if (!input.trim() || !currentConversation) return

    const userMessage: Message = {
      id: Date.now().toString(),
      timestamp: new Date(),
      content: input.trim(),
      sender: 'user',
      saved: !incognitoMode,
      incognito: incognitoMode
    }

    // Add user message
    const updatedMessages = [...currentConversation.messages, userMessage]
    const updatedConvo = { 
      ...currentConversation, 
      messages: updatedMessages,
      lastMessage: new Date()
    }
    setCurrentConversation(updatedConvo)
    setInput('')
    setIsLoading(true)

    try {
      // Send to API
      const response = await fetch('/api/chat', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          message: input,
          userId: session?.user?.email,
          mode: 'bubbe',
          incognito: incognitoMode,
          userProfile: { 
            preferredName: session?.user?.name,
            incognito: incognitoMode
          }
        })
      })

      if (response.ok) {
        const data = await response.json()
        
        const bubbeMessage: Message = {
          id: (Date.now() + 1).toString(),
          timestamp: new Date(),
          content: data.response,
          sender: 'bubbe',
          saved: !incognitoMode,
          incognito: incognitoMode
        }

        // Add Bubbe's response
        const finalMessages = [...updatedMessages, bubbeMessage]
        const finalConvo = { 
          ...updatedConvo, 
          messages: finalMessages 
        }
        
        setCurrentConversation(finalConvo)
        
        // Update saved conversations if not incognito
        if (!incognitoMode) {
          const updatedConvos = conversations.map(c => 
            c.id === finalConvo.id ? finalConvo : c
          )
          setConversations(updatedConvos)
          saveConversations(updatedConvos)
        }

        // Send SMS if enabled
        if (smsEnabled && phoneNumber) {
          sendSmsNotification(data.response)
        }
      }
    } catch (error) {
      console.error('Failed to send message:', error)
    } finally {
      setIsLoading(false)
    }
  }

  const sendSmsNotification = async (message: string) => {
    try {
      await fetch('/api/sms', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          phone: phoneNumber,
          message: `Bubbe says: ${message.substring(0, 140)}...`
        })
      })
    } catch (error) {
      console.error('Failed to send SMS:', error)
    }
  }

  const toggleSaveConversation = () => {
    if (!currentConversation) return
    
    const updated = { 
      ...currentConversation, 
      saved: !currentConversation.saved 
    }
    setCurrentConversation(updated)
    
    if (updated.saved) {
      // Add to saved conversations
      const exists = conversations.find(c => c.id === updated.id)
      if (!exists) {
        const newConvos = [...conversations, updated]
        setConversations(newConvos)
        saveConversations(newConvos)
      }
    } else {
      // Remove from saved conversations
      const filtered = conversations.filter(c => c.id !== updated.id)
      setConversations(filtered)
      saveConversations(filtered)
    }
  }

  const deleteConversation = (id: string) => {
    const filtered = conversations.filter(c => c.id !== id)
    setConversations(filtered)
    saveConversations(filtered)
    
    if (currentConversation?.id === id) {
      setCurrentConversation(null)
    }
  }

  const handlePhotoUpload = (response: any) => {
    setShowPhotoUpload(false)
    // Add the response as a message
    if (response.bubbeResponse && currentConversation) {
      const photoMessage: Message = {
        id: Date.now().toString(),
        timestamp: new Date(),
        content: response.bubbeResponse,
        sender: 'bubbe',
        saved: !incognitoMode,
        incognito: incognitoMode,
        hasPhoto: true,
        photoUrl: response.filename
      }
      
      const updatedMessages = [...currentConversation.messages, photoMessage]
      const updatedConvo = { 
        ...currentConversation, 
        messages: updatedMessages 
      }
      setCurrentConversation(updatedConvo)
    }
  }

  if (status === 'loading') {
    return (
      <div className="min-h-screen bg-gradient-to-br from-amber-50 to-orange-100 flex items-center justify-center">
        <div className="text-2xl text-amber-600">Loading...</div>
      </div>
    )
  }

  return (
    <div className="min-h-screen bg-gradient-to-br from-amber-50 to-orange-100">
      <div className="flex h-screen">
        {/* Sidebar */}
        <div className="w-80 bg-white shadow-lg flex flex-col">
          {/* Header */}
          <div className="p-4 border-b">
            <Link href="/" className="text-amber-600 hover:text-amber-700 text-sm">
              ← Back to Bubbe
            </Link>
            <h2 className="text-xl font-bold text-gray-800 mt-2">Private Messages</h2>
            
            {/* Incognito Toggle */}
            <label className="flex items-center mt-3 cursor-pointer">
              <input
                type="checkbox"
                checked={incognitoMode}
                onChange={(e) => setIncognitoMode(e.target.checked)}
                className="mr-2"
              />
              <span className="text-sm text-gray-600">
                🕵️ Incognito Mode (not saved)
              </span>
            </label>
          </div>

          {/* Conversations List */}
          <div className="flex-1 overflow-y-auto p-4 space-y-2">
            <button
              onClick={startNewConversation}
              className="w-full px-4 py-2 bg-amber-500 text-white rounded-lg hover:bg-amber-600 transition-colors"
            >
              + New Conversation
            </button>
            
            {conversations.map((convo) => (
              <div
                key={convo.id}
                onClick={() => setCurrentConversation(convo)}
                className={`p-3 rounded-lg cursor-pointer transition-colors ${
                  currentConversation?.id === convo.id 
                    ? 'bg-amber-100 border-amber-500 border' 
                    : 'bg-gray-50 hover:bg-gray-100'
                }`}
              >
                <div className="flex justify-between items-start">
                  <div>
                    <div className="font-medium text-gray-800">{convo.title}</div>
                    <div className="text-xs text-gray-500">
                      {new Date(convo.lastMessage).toLocaleDateString()}
                    </div>
                  </div>
                  <button
                    onClick={(e) => {
                      e.stopPropagation()
                      deleteConversation(convo.id)
                    }}
                    className="text-red-500 hover:text-red-700"
                  >
                    ×
                  </button>
                </div>
              </div>
            ))}
          </div>

          {/* Settings */}
          <div className="p-4 border-t">
            <button
              onClick={() => setShowSettings(!showSettings)}
              className="w-full px-4 py-2 bg-gray-600 text-white rounded-lg hover:bg-gray-700 transition-colors"
            >
              ⚙️ SMS Settings
            </button>
          </div>
        </div>

        {/* Main Chat Area */}
        <div className="flex-1 flex flex-col">
          {currentConversation ? (
            <>
              {/* Chat Header */}
              <div className="bg-white shadow-sm p-4 flex justify-between items-center">
                <div>
                  <h3 className="text-lg font-semibold text-gray-800">
                    {currentConversation.title}
                  </h3>
                  {currentConversation.incognito && (
                    <span className="text-xs text-gray-500">🕵️ Incognito - Not Saved</span>
                  )}
                </div>
                
                <div className="flex gap-2">
                  <button
                    onClick={() => setShowPhotoUpload(!showPhotoUpload)}
                    className="px-3 py-1 bg-blue-500 text-white rounded hover:bg-blue-600"
                  >
                    📸 Upload Photo
                  </button>
                  
                  <button
                    onClick={toggleSaveConversation}
                    className={`px-3 py-1 rounded ${
                      currentConversation.saved
                        ? 'bg-green-500 text-white hover:bg-green-600'
                        : 'bg-gray-300 text-gray-700 hover:bg-gray-400'
                    }`}
                  >
                    {currentConversation.saved ? '💾 Saved' : '💾 Save'}
                  </button>
                </div>
              </div>

              {/* Photo Upload Section */}
              {showPhotoUpload && (
                <div className="p-4 bg-white border-b">
                  <DatingPhotoUpload
                    userId={session?.user?.email || ''}
                    onUploadComplete={handlePhotoUpload}
                  />
                </div>
              )}

              {/* Messages */}
              <div className="flex-1 overflow-y-auto p-4 space-y-3 bg-gray-50">
                {currentConversation.messages.map((msg) => (
                  <div
                    key={msg.id}
                    className={`flex ${msg.sender === 'user' ? 'justify-end' : 'justify-start'}`}
                  >
                    <div
                      className={`max-w-2xl p-3 rounded-lg ${
                        msg.sender === 'user'
                          ? 'bg-blue-500 text-white'
                          : 'bg-white text-gray-800 shadow'
                      }`}
                    >
                      {msg.hasPhoto && (
                        <div className="text-xs mb-1 opacity-75">📸 Photo shared</div>
                      )}
                      <p className="whitespace-pre-wrap">{msg.content}</p>
                      <div className="text-xs opacity-70 mt-1">
                        {new Date(msg.timestamp).toLocaleTimeString()}
                      </div>
                    </div>
                  </div>
                ))}
                {isLoading && (
                  <div className="flex justify-start">
                    <div className="bg-white text-gray-500 p-3 rounded-lg shadow">
                      Bubbe is typing...
                    </div>
                  </div>
                )}
                <div ref={messagesEndRef} />
              </div>

              {/* Input */}
              <div className="bg-white p-4 border-t">
                <div className="flex gap-2">
                  <input
                    type="text"
                    value={input}
                    onChange={(e) => setInput(e.target.value)}
                    onKeyPress={(e) => e.key === 'Enter' && sendMessage()}
                    placeholder={incognitoMode ? "Message Bubbe privately..." : "Message Bubbe..."}
                    className="flex-1 px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-amber-500"
                    disabled={isLoading}
                  />
                  <button
                    onClick={sendMessage}
                    disabled={!input.trim() || isLoading}
                    className="px-6 py-2 bg-amber-500 text-white rounded-lg hover:bg-amber-600 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
                  >
                    Send
                  </button>
                </div>
                {incognitoMode && (
                  <p className="text-xs text-gray-500 mt-2">
                    🕵️ This conversation won't be saved unless you click Save
                  </p>
                )}
              </div>
            </>
          ) : (
            <div className="flex-1 flex items-center justify-center">
              <div className="text-center">
                <h3 className="text-2xl font-bold text-gray-700 mb-4">
                  Welcome to Bubbe DMs! 💌
                </h3>
                <p className="text-gray-600 mb-6">
                  Have private conversations with Bubbe. Choose to save or delete anything.
                </p>
                <button
                  onClick={startNewConversation}
                  className="px-6 py-3 bg-amber-500 text-white rounded-lg hover:bg-amber-600 transition-colors"
                >
                  Start New Conversation
                </button>
              </div>
            </div>
          )}
        </div>
      </div>

      {/* SMS Settings Modal */}
      {showSettings && (
        <div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
          <div className="bg-white rounded-lg p-6 max-w-md w-full">
            <h3 className="text-xl font-bold text-gray-800 mb-4">SMS Settings</h3>
            
            <label className="flex items-center mb-4">
              <input
                type="checkbox"
                checked={smsEnabled}
                onChange={(e) => setSmsEnabled(e.target.checked)}
                className="mr-2"
              />
              <span>Enable SMS notifications from Bubbe</span>
            </label>
            
            {smsEnabled && (
              <div className="mb-4">
                <label className="block text-sm font-medium text-gray-700 mb-2">
                  Phone Number
                </label>
                <input
                  type="tel"
                  value={phoneNumber}
                  onChange={(e) => setPhoneNumber(e.target.value)}
                  placeholder="+1234567890"
                  className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-amber-500"
                />
              </div>
            )}
            
            <div className="flex gap-2">
              <button
                onClick={saveSmsSettings}
                className="flex-1 px-4 py-2 bg-amber-500 text-white rounded-lg hover:bg-amber-600"
              >
                Save
              </button>
              <button
                onClick={() => setShowSettings(false)}
                className="flex-1 px-4 py-2 bg-gray-300 text-gray-700 rounded-lg hover:bg-gray-400"
              >
                Cancel
              </button>
            </div>
          </div>
        </div>
      )}
    </div>
  )
}