import React, { useState, useEffect } from 'react'; import { Box, Typography, Paper, Button, Stepper, Step, StepLabel, Grid, Card, CardContent, CircularProgress, Alert, TextField, FormControlLabel, Checkbox, Radio, RadioGroup, FormControl, FormLabel, Chip, Divider, Dialog, DialogTitle, DialogContent, DialogActions, IconButton, List, ListItem, ListItemText, Tooltip, MenuItem, Select, InputLabel } from '@mui/material'; import { ArrowBack as ArrowBackIcon, Send as SendIcon, Schedule as ScheduleIcon, Preview as PreviewIcon, InfoOutlined as InfoIcon, WarningAmber as WarningIcon, CheckCircle as CheckCircleIcon } from '@mui/icons-material'; import { useNavigate, useParams } from 'react-router-dom'; import { format, addHours, addDays, setHours, setMinutes } from 'date-fns'; import { useEmailCampaign, useMailingList, useSendCampaign, useScheduleCampaign, usePreviewCampaign } from '@hooks/emailCampaignHooks'; const CampaignSendPage = () => { const navigate = useNavigate(); const { id } = useParams(); // Stepper state const [activeStep, setActiveStep] = useState(0); const steps = ['Review Campaign', 'Select Delivery Options', 'Confirm & Send']; // Custom date time picker state const initialDate = addHours(new Date(), 1); const [scheduledDate, setScheduledDate] = useState(initialDate); const [selectedDate, setSelectedDate] = useState(format(initialDate, 'yyyy-MM-dd')); const [selectedHour, setSelectedHour] = useState(initialDate.getHours()); const [selectedMinute, setSelectedMinute] = useState(initialDate.getMinutes()); // Delivery options const [deliveryOption, setDeliveryOption] = useState('send_now'); const [confirmChecked, setConfirmChecked] = useState(false); // Preview dialog const [previewDialogOpen, setPreviewDialogOpen] = useState(false); const [testEmailAddress, setTestEmailAddress] = useState(''); // Fetch campaign and related data const { data: campaign, isLoading: campaignLoading, error: campaignError } = useEmailCampaign(id); // Load lists information for selected lists const { data: listData, isLoading: listLoading } = useMailingList( campaign?.list_ids?.length > 0 ? campaign.list_ids[0] : null ); // Mutations const sendCampaign = useSendCampaign(); const scheduleCampaign = useScheduleCampaign(); const previewCampaign = usePreviewCampaign(); // Generate hours and minutes for dropdowns const hours = Array.from({ length: 24 }, (_, i) => i); const minutes = Array.from({ length: 60 }, (_, i) => i); // Update the scheduledDate when date/time components change useEffect(() => { try { const dateObj = new Date(selectedDate); dateObj.setHours(selectedHour); dateObj.setMinutes(selectedMinute); setScheduledDate(dateObj); } catch (error) { console.error("Invalid date selection:", error); } }, [selectedDate, selectedHour, selectedMinute]); // Handle step changes const handleNext = () => { setActiveStep((prevStep) => Math.min(prevStep + 1, steps.length - 1)); }; const handleBack = () => { setActiveStep((prevStep) => Math.max(prevStep - 1, 0)); }; // Handle delivery option change const handleDeliveryOptionChange = (event) => { setDeliveryOption(event.target.value); }; // Handle date change const handleDateChange = (event) => { setSelectedDate(event.target.value); }; // Handle hour change const handleHourChange = (event) => { setSelectedHour(Number(event.target.value)); }; // Handle minute change const handleMinuteChange = (event) => { setSelectedMinute(Number(event.target.value)); }; // Handle preview const handleOpenPreview = () => { setPreviewDialogOpen(true); }; // Send test email const handleSendTest = async () => { if (!testEmailAddress || !campaign) return; try { await previewCampaign.mutateAsync({ campaignId: campaign.id, email: testEmailAddress }); // Clear the field after successful send if (!previewCampaign.error) { setTestEmailAddress(''); } } catch (error) { console.error('Failed to send test email:', error); } }; // Handle final campaign send/schedule const handleSendCampaign = async () => { if (!campaign) return; try { if (deliveryOption === 'send_now') { await sendCampaign.mutateAsync(campaign.id); } else { await scheduleCampaign.mutateAsync({ campaignId: campaign.id, scheduledDate: scheduledDate.toISOString() }); } // Navigate back to campaigns list on success if (!sendCampaign.error && !scheduleCampaign.error) { navigate('/admin/email-campaigns'); } } catch (error) { console.error('Failed to send/schedule campaign:', error); } }; // Get estimated recipient count const getRecipientCount = () => { if (!campaign || !campaign.list_ids || campaign.list_ids.length === 0) { return 0; } return listData?.subscriber_count || 0; }; // Format hour for display (add leading zero if needed) const formatTimeValue = (value) => { return value.toString().padStart(2, '0'); }; // Validate that selected date is in the future const isDateInPast = () => { const now = new Date(); return scheduledDate < now; }; // Loading state if (campaignLoading) { return ; } // Error state if (campaignError) { return {campaignError.message}; } // Campaign not found if (!campaign) { return ( Campaign not found. Please select a valid campaign. ); } return ( {/* Header with back button */} navigate(`/admin/email-campaigns/${id}`)} sx={{ mr: 1 }}> Send Campaign: {campaign.name} {/* Stepper */} {steps.map((label) => ( {label} ))} {/* Step content */} {/* Step 1: Review Campaign */} {activeStep === 0 && ( Review Campaign Details Campaign Details Name: {campaign.name} Subject: {campaign.subject} From: {campaign.from_name} ({campaign.from_email}) {campaign.preheader && ( <> Preheader: {campaign.preheader} )} Audience Mailing Lists: {listLoading ? ( ) : ( )} Estimated Recipients: {getRecipientCount()} {getRecipientCount() === 0 && ( No recipients in selected mailing lists. Your campaign won't be delivered to anyone. )} )} {/* Step 2: Delivery Options */} {activeStep === 1 && ( Delivery Options When should this campaign be sent? } label="Send immediately" /> } label="Schedule for later" /> {deliveryOption === 'schedule' && ( {/* Custom Date Time Picker */} Hour Minute {isDateInPast() && ( Selected time is in the past. Please choose a future date and time. )} Selected Date/Time: {format(scheduledDate, 'PPpp')} Campaigns are sent in your local timezone: {Intl.DateTimeFormat().resolvedOptions().timeZone} )} Send Test Email Send a test email to verify how your campaign will look before sending to your list. setTestEmailAddress(e.target.value)} /> {previewCampaign.isSuccess && ( Test email sent successfully! )} {previewCampaign.error && ( {previewCampaign.error.message || 'Failed to send test email'} )} )} {/* Step 3: Confirm & Send */} {activeStep === 2 && ( Confirm & Send Please review your campaign before sending Once a campaign is sent, it cannot be recalled or edited. Sending Summary setConfirmChecked(e.target.checked)} /> } label="I confirm that this campaign is ready to send" /> {(sendCampaign.error || scheduleCampaign.error) && ( {sendCampaign.error?.message || scheduleCampaign.error?.message || 'An error occurred'} )} )} {/* Preview Dialog */} setPreviewDialogOpen(false)} maxWidth="md" fullWidth > Campaign Preview Subject: {campaign.subject} {campaign.preheader && ( <> Preheader: {campaign.preheader} )} Email Content: ); }; export default CampaignSendPage;