"use client"; import { useState, useRef } from "react"; import { Button } from "@/components/ui/button"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog"; import { Send, Bold, Italic, Code, Link as LinkIcon, Image as ImageIcon, X, Eye, EyeOff } from "lucide-react"; import { toast } from "sonner"; import { apiRequest } from "@/lib/storeHelper"; import { cn } from "@/lib/utils"; import { Textarea } from "@/components/ui/textarea"; import ReactMarkdown from 'react-markdown'; interface BroadcastDialogProps { open: boolean; setOpen: (open: boolean) => void; } export default function BroadcastDialog({ open, setOpen }: BroadcastDialogProps) { const [broadcastMessage, setBroadcastMessage] = useState(""); const [showPreview, setShowPreview] = useState(true); const [isSending, setIsSending] = useState(false); const [selectedImage, setSelectedImage] = useState(null); const [imagePreview, setImagePreview] = useState(null); const textareaRef = useRef(null); const fileInputRef = useRef(null); const handleImageSelect = (event: React.ChangeEvent) => { const file = event.target.files?.[0]; if (file) { if (file.size > 10 * 1024 * 1024) { // 10MB limit toast.error("Image size must be less than 10MB"); return; } setSelectedImage(file); const reader = new FileReader(); reader.onloadend = () => { setImagePreview(reader.result as string); }; reader.readAsDataURL(file); } }; const removeImage = () => { setSelectedImage(null); setImagePreview(null); if (fileInputRef.current) { fileInputRef.current.value = ''; } }; const insertMarkdown = (type: 'bold' | 'italic' | 'code' | 'link') => { const textarea = textareaRef.current; if (!textarea) return; const start = textarea.selectionStart; const end = textarea.selectionEnd; const selectedText = textarea.value.substring(start, end); let insertText = ''; switch (type) { case 'bold': insertText = `**${selectedText || 'bold text'}**`; break; case 'italic': insertText = `__${selectedText || 'italic text'}__`; break; case 'code': insertText = `\`${selectedText || 'code'}\``; break; case 'link': insertText = `[${selectedText || 'link text'}](URL)`; break; } const newText = textarea.value.substring(0, start) + insertText + textarea.value.substring(end); setBroadcastMessage(newText); // Set cursor position after the inserted text const newCursorPos = start + insertText.length; textarea.focus(); textarea.setSelectionRange(newCursorPos, newCursorPos); }; const sendBroadcast = async () => { if (!broadcastMessage.trim() && !selectedImage) { toast.warning("Please provide a message or image to broadcast."); return; } try { setIsSending(true); const API_URL = process.env.NEXT_PUBLIC_API_URL; if (!API_URL) throw new Error("API URL not configured"); // Get auth token from cookie const authToken = document.cookie .split("; ") .find((row) => row.startsWith("Authorization=")) ?.split("=")[1]; if (!authToken) { document.location.href = "/login"; throw new Error("No authentication token found"); } let response; if (selectedImage) { const formData = new FormData(); formData.append('file', selectedImage); if (broadcastMessage.trim()) { formData.append('message', broadcastMessage); } const res = await fetch(`${API_URL}/storefront/broadcast`, { method: 'POST', headers: { Authorization: `Bearer ${authToken}`, }, body: formData, }); if (!res.ok) { const errorData = await res.json().catch(() => ({})); throw new Error(errorData.error || 'Failed to send broadcast'); } response = await res.json(); } else { response = await apiRequest("/storefront/broadcast", "POST", { message: broadcastMessage }); } if (response.error) throw new Error(response.error); toast.success(`Broadcast sent to ${response.totalUsers} users!`); setBroadcastMessage(""); setSelectedImage(null); setImagePreview(null); setOpen(false); } catch (error) { console.error("Broadcast error:", error); toast.error(error instanceof Error ? error.message : "Failed to send broadcast message."); } finally { setIsSending(false); } }; return ( Global Broadcast Message