'use client' import { useState, useCallback, useMemo } from 'react' import { useDropzone } from 'react-dropzone' import Papa from 'papaparse' import { Upload, Send, AlertCircle, CheckCircle } from 'lucide-react' import { Card, CardContent, CardHeader, CardTitle, CardDescription, } from '@/components/ui/card' import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' import { Label } from '@/components/ui/label' import { Textarea } from '@/components/ui/textarea' import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select' import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert' import { ApiEndpoints } from '@/config/api' import { useMutation, useQuery } from '@tanstack/react-query' import { Spinner } from '@/components/ui/spinner' import httpBrowserClient from '@/lib/httpBrowserClient' const DEFAULT_MAX_FILE_SIZE = 1024 * 1024 // 1 MB const DEFAULT_MAX_ROWS = 50 export default function BulkSMSSend() { const [csvData, setCsvData] = useState([]) const [columns, setColumns] = useState([]) const [selectedColumn, setSelectedColumn] = useState('') const [messageTemplate, setMessageTemplate] = useState('') const [selectedRecipient, setSelectedRecipient] = useState('') const [error, setError] = useState(null) const { data: currentSubscription, isLoading: isLoadingSubscription, error: subscriptionError, } = useQuery({ queryKey: ['currentSubscription'], queryFn: () => httpBrowserClient .get(ApiEndpoints.billing.currentSubscription()) .then((res) => res.data), }) const maxRows = useMemo(() => { if (currentSubscription?.plan?.bulkSendLimit == -1) { return 9999 } return currentSubscription?.plan?.bulkSendLimit || DEFAULT_MAX_ROWS }, [currentSubscription]) const onDrop = useCallback((acceptedFiles: File[]) => { const file = acceptedFiles[0] if (file.size > DEFAULT_MAX_FILE_SIZE) { setError('File size exceeds 1 MB limit.') return } Papa.parse(file, { complete: (results) => { if (results.data && results.data.length > 0) { if (results.data.length > maxRows) { setError(`CSV file exceeds ${maxRows} rows limit.`) return } setCsvData(results.data as any[]) const headerRow = results.data[0] as Record setColumns(Object.keys(headerRow)) setError(null) } else { setError('CSV file is empty or invalid') setCsvData([]) setColumns([]) } }, header: true, skipEmptyLines: true, }) }, [maxRows]) const { getRootProps, getInputProps, isDragActive } = useDropzone({ onDrop }) const previewMessage = useMemo(() => { if (!selectedRecipient || !messageTemplate) return '' const recipient = csvData.find( (row) => row[selectedColumn] === selectedRecipient ) if (!recipient) return '' return messageTemplate.replace(/\{\{\s*([^}]+)\s*\}\}/g, (_, key) => { return recipient[key.trim()] || '' }) }, [selectedRecipient, messageTemplate, csvData, selectedColumn]) const handleSendBulkSMS = async () => { const messages = csvData.map((row) => ({ message: messageTemplate.replace(/\{\{\s*([^}]+)\s*\}\}/g, (_, key) => { return row[key.trim()] || '' }), recipients: [row[selectedColumn]], })) const payload = { messageTemplate, messages, } await httpBrowserClient.post( ApiEndpoints.gateway.sendBulkSMS(selectedDeviceId), payload ) } const [selectedDeviceId, setSelectedDeviceId] = useState(null) const { data: devices } = useQuery({ queryKey: ['devices'], queryFn: () => httpBrowserClient .get(ApiEndpoints.gateway.listDevices()) .then((res) => res.data), }) const { mutate: sendBulkSMS, isPending: isSendingBulkSMS, isSuccess: isSendingBulkSMSuccess, isError: isSendingBulkSMSError, error: sendingBulkSMSError, } = useMutation({ mutationFn: handleSendBulkSMS, }) const isStep2Disabled = csvData.length === 0 const isStep3Disabled = isStep2Disabled || !selectedColumn || !messageTemplate return (
Send Bulk SMS Upload a CSV, configure your message, and send bulk SMS in 3 simple steps.

1. Upload CSV

Upload a CSV file (max {DEFAULT_MAX_FILE_SIZE} bytes, {maxRows} rows) containing recipient information.

Drag & drop a CSV file here, or click to select one

Max file size: {DEFAULT_MAX_FILE_SIZE} bytes, Max rows:{' '} {maxRows}

{error && ( Error {error} )} {csvData.length > 0 && (

CSV uploaded successfully! {csvData.length} rows found.

)}

2. Configure SMS

Select the recipient column and create your message template.

{/* select device to send SMS from */}