diff --git a/.env b/.env index b454ca74..ce4703c7 100644 --- a/.env +++ b/.env @@ -1 +1,5 @@ DATABASE_URL="postgresql://user:password@host:port/db" +ENABLE_AUTH=false +OPENAI_API_KEY=sk-dummy +NEXT_PUBLIC_MAPBOX_ACCESS_TOKEN=pk.dummy +MAPBOX_ACCESS_TOKEN=pk.dummy diff --git a/components/followup-panel.tsx b/components/followup-panel.tsx index 53321e1a..f3f28749 100644 --- a/components/followup-panel.tsx +++ b/components/followup-panel.tsx @@ -1,67 +1,164 @@ 'use client' -import { useState } from 'react' +import { useState, useRef, ChangeEvent } from 'react' import { Button } from './ui/button' -import { Input } from './ui/input' import { useActions, useUIState } from 'ai/rsc' import type { AI } from '@/app/actions' import { UserMessage } from './user-message' -import { ArrowRight } from 'lucide-react' +import { ArrowRight, Paperclip, X } from 'lucide-react' import { useMapData } from './map/map-data-context' -import { nanoid } from '@/lib/utils' +import { nanoid, cn } from '@/lib/utils' +import Textarea from 'react-textarea-autosize' export function FollowupPanel() { const [input, setInput] = useState('') + const [selectedFile, setSelectedFile] = useState(null) const { submit } = useActions() const [, setMessages] = useUIState() const { mapData } = useMapData() + const fileInputRef = useRef(null) + + const handleFileChange = (e: ChangeEvent) => { + const file = e.target.files?.[0] + if (file) { + if (file.size > 10 * 1024 * 1024) { + alert('File size must be less than 10MB') + return + } + setSelectedFile(file) + } + } + + const handleAttachmentClick = () => { + fileInputRef.current?.click() + } + + const clearAttachment = () => { + setSelectedFile(null) + if (fileInputRef.current) { + fileInputRef.current.value = '' + } + } const handleSubmit = async (event: React.FormEvent) => { event.preventDefault() - const formData = new FormData() - formData.append("input", input) + + if (!input.trim() && !selectedFile) { + return + } + + const content: ({ type: 'text'; text: string } | { type: 'image'; image: string })[] = [] + if (input) { + content.push({ type: 'text', text: input }) + } + if (selectedFile && selectedFile.type.startsWith('image/')) { + content.push({ + type: 'image', + image: URL.createObjectURL(selectedFile) + }) + } const userMessage = { id: nanoid(), isGenerating: false, - component: + component: 0 ? content : input} /> } - // Include drawn features in the form data + const formData = new FormData() + formData.append('input', input) + if (selectedFile) { + formData.append('file', selectedFile) + } formData.append('drawnFeatures', JSON.stringify(mapData.drawnFeatures || [])) + setInput('') + clearAttachment() + const responseMessage = await submit(formData) setMessages(currentMessages => [ ...currentMessages, userMessage, responseMessage ]) - - setInput('') } return ( -
- setInput(e.target.value)} - /> - -
+ + +