import React, { useState, useRef, useCallback, useEffect } from "react"; import { motion, AnimatePresence } from "framer-motion"; import { useTranslation } from "react-i18next"; import { uploadPostMedia, fetchPostPreview } from "../../api/client"; // Content modes const CONTENT_MODES = [ { id: "text", icon: "fa-pen", label: "Text", color: "from-blue-500 to-cyan-500" }, { id: "photo", icon: "fa-image", label: "Photo", color: "from-emerald-500 to-green-500" }, { id: "link", icon: "fa-link", label: "Link", color: "from-purple-500 to-violet-500" }, { id: "live", icon: "fa-broadcast-tower", label: "Live", color: "from-red-500 to-rose-500" }, ]; const CATEGORIES = [ { id: "News", icon: "fa-newspaper", color: "from-blue-500 to-cyan-500" }, { id: "Friends", icon: "fa-user-group", color: "from-emerald-500 to-green-500" }, { id: "Events", icon: "fa-calendar", color: "from-purple-500 to-violet-500" }, { id: "Market", icon: "fa-store", color: "from-amber-500 to-orange-500" }, ]; const SUB_CATEGORIES = { News: ["World", "Local", "Politics", "Tech", "Finance", "Sports"], Friends: ["Nearby", "Stories", "Hangout", "Help"], Events: ["Today", "Weekend", "Music", "Sports", "Food"], Market: ["Deals", "Services", "Jobs", "Housing"], }; export default function PostCreateModal({ isOpen, onClose, onSubmit, onGoLive, coords, initialCategory = "News", isSaving = false, saveError = "", }) { const { t } = useTranslation(); const [mode, setMode] = useState("text"); const [category, setCategory] = useState(initialCategory); const [subCategory, setSubCategory] = useState(SUB_CATEGORIES[initialCategory]?.[0] || ""); const [title, setTitle] = useState(""); const [body, setBody] = useState(""); const [linkUrl, setLinkUrl] = useState(""); const [linkPreview, setLinkPreview] = useState(null); const [linkLoading, setLinkLoading] = useState(false); const [images, setImages] = useState([]); const [uploading, setUploading] = useState(false); const fileInputRef = useRef(null); const cameraInputRef = useRef(null); const textareaRef = useRef(null); const linkTimeoutRef = useRef(null); // Reset only when modal opens (not on every initialCategory change) const wasOpenRef = useRef(false); useEffect(() => { if (isOpen && !wasOpenRef.current) { // Modal just opened - reset everything setMode("text"); setTitle(""); setBody(""); setLinkUrl(""); setLinkPreview(null); setImages([]); setUploadError(""); setCategory(initialCategory); setSubCategory(SUB_CATEGORIES[initialCategory]?.[0] || ""); } wasOpenRef.current = isOpen; }, [isOpen, initialCategory]); // Auto-resize textarea useEffect(() => { if (textareaRef.current) { textareaRef.current.style.height = "auto"; textareaRef.current.style.height = Math.min(textareaRef.current.scrollHeight, 200) + "px"; } }, [body]); // Link preview fetch useEffect(() => { if (mode !== "link" || !linkUrl.trim()) { setLinkPreview(null); return; } clearTimeout(linkTimeoutRef.current); linkTimeoutRef.current = setTimeout(async () => { try { setLinkLoading(true); const preview = await fetchPostPreview(linkUrl.trim()); if (preview) { setLinkPreview(preview); if (!title && preview.title) setTitle(preview.title); if (!body && preview.description) setBody(preview.description); } } catch {} setLinkLoading(false); }, 500); return () => clearTimeout(linkTimeoutRef.current); }, [linkUrl, mode, title, body]); const [uploadError, setUploadError] = useState(""); const handleFileChange = useCallback(async (e) => { const files = Array.from(e.target.files || []); if (files.length === 0) return; setUploading(true); setUploadError(""); try { for (const file of files) { const result = await uploadPostMedia(file); if (result?.url) { setImages((prev) => { const newImages = [...prev, result.url]; return newImages; }); } else { setUploadError(result?.error || "Upload failed - no URL returned"); } } } catch (err) { setUploadError(err.message || "Upload failed"); } setUploading(false); e.target.value = ""; }, []); const removeImage = (index) => { setImages((prev) => prev.filter((_, i) => i !== index)); }; const handleSubmit = () => { if (mode === "live") { onGoLive?.({ category, subCategory, title, body, coords }); return; } if (!title.trim() && !body.trim() && images.length === 0 && !linkUrl.trim()) return; onSubmit?.({ mode, title: title.trim(), body: body.trim(), category, subCategory, images, linkUrl: linkUrl.trim(), linkPreview, coords, }); }; const canSubmit = mode === "live" || (title.trim() || body.trim() || images.length > 0 || linkUrl.trim()) && !isSaving && !uploading; if (!isOpen) return null; return ( {/* Backdrop - only covers bottom half, allows map interaction above */} {/* Invisible close trigger at top */}
{/* Modal - positioned at bottom, shorter to show map with crosshair */} {/* Glowing top border */}
{/* Header */}

Create Post

{isSaving ? ( ) : mode === "live" ? ( <> Go Live ) : ( "Post" )}
{/* Content modes */}
{CONTENT_MODES.map((m) => ( setMode(m.id)} > {m.label} ))}
{/* Scrollable content */}
{/* Category row */}
{CATEGORIES.map((cat) => ( { setCategory(cat.id); setSubCategory(SUB_CATEGORIES[cat.id]?.[0] || ""); }} > {cat.id} ))}
{/* Sub-category */}
{SUB_CATEGORIES[category]?.map((sub) => ( ))}
{/* Link input (for link mode) */} {mode === "link" && (
setLinkUrl(e.target.value)} className="w-full pl-10 pr-4 py-3 rounded-xl bg-surface-700/50 border border-white/10 text-surface-100 text-sm placeholder:text-surface-500 focus:outline-none focus:border-cyan-500/50" /> {linkLoading && ( )}
{/* Link preview card */} {linkPreview && ( {linkPreview.image && ( )}

{linkPreview.site_name || new URL(linkUrl).hostname}

{linkPreview.title}

)}
)} {/* Live mode info */} {mode === "live" && (

Start a Live Stream

Broadcast to your followers in real-time

Your location will be visible to viewers. The stream will appear on the map.

)} {/* Title input */} setTitle(e.target.value)} className="w-full px-4 py-3 rounded-xl bg-surface-700/50 border border-white/10 text-white text-base font-medium placeholder:text-surface-500 focus:outline-none focus:border-cyan-500/50" /> {/* Body textarea (hidden for live mode) */} {mode !== "live" && (