import { useState, useCallback, useRef } from 'react'; import { tokenService } from '../../services/TokenService'; import { sendMessageApi, SendInstantMessageRequest, } from '../../api/sendMessageApi'; import { scheduleApi } from '../../api/scheduleApi.js'; import { scheduleEventApi } from '../../api/scheduleEventApi.js'; const useSendMessageWizard = () => { const [state, setState] = useState({ step: 'select', selectedContacts: [], scheduledTime: null, message: '', createdMessage: null, isSubmitting: false, isScheduled: false, submissionError: null, }); const abortControllerRef = useRef(null); // Computed values const canProceedToNextStep = useCallback(() => { switch (state.step) { case 'select': return state.selectedContacts.length > 0; case 'message': if (state.message.trim().length > 0) { if (state.createdMessage != null) { return true; } else { return false; } } else { return false; } case 'schedule': console.log('Checking to see if schedule can go to the next step'); if (state.scheduledTime == null) { return false; } console.log('Scheduled time is not null'); const result = state.scheduledTime instanceof Date && isNaN(state.scheduledTime.getTime()); return !result; case 'confirm': return true; default: return false; } }, [ state.step, state.selectedContacts.length, state.message, state.createdMessage, state.scheduledTime, ]); const canGoBack = state.step !== 'select'; // Actions const toggleContact = (contactId) => { setState((prev) => ({ ...prev, selectedContacts: prev.selectedContacts.includes(contactId) ? prev.selectedContacts.filter((id) => id !== contactId) : [...prev.selectedContacts, contactId], })); }; const toggleScheduled = (scheduled) => { console.log('Yup'); setState((prev) => ({ ...prev, isScheduled: scheduled, })); }; const setMessage = (message) => { setState((prev) => ({ ...prev, message })); }; const setCreatedMessage = (message) => { console.log('Setting created message'); setState((prev) => ({ ...prev, createdMessage: message })); }; const setScheduledTime = (selectedTime) => { console.log('Setting scheduled time'); setState((prev) => ({ ...prev, scheduledTime: selectedTime })); }; const nextStep = () => { if (!canProceedToNextStep()) return; const stepOrder = ['select', 'message', 'schedule', 'confirm', 'result']; const currentIndex = stepOrder.indexOf(state.step); if (currentIndex < stepOrder.length - 1) { if (state.step === 'message') { if (state.isScheduled) { setState((prev) => ({ ...prev, step: stepOrder[currentIndex + 1], submissionError: null, })); } else { setState((prev) => ({ ...prev, step: stepOrder[currentIndex + 2], submissionError: null, })); } } else { setState((prev) => ({ ...prev, step: stepOrder[currentIndex + 1], submissionError: null, })); } } }; const prevStep = () => { const stepOrder = ['select', 'message', 'schedule', 'confirm', 'result']; const currentIndex = stepOrder.indexOf(state.step); if (currentIndex > 0) { if (state.step === 'confirm') { if (state.isScheduled) { setState((prev) => ({ ...prev, step: stepOrder[currentIndex - 1], submissionError: null, })); } else { setState((prev) => ({ ...prev, step: stepOrder[currentIndex - 2], submissionError: null, })); } } else { setState((prev) => ({ ...prev, step: stepOrder[currentIndex - 1], submissionError: null, })); } } }; const submit = async () => { if (state.isSubmitting) return; abortControllerRef.current = new AbortController(); setState((prev) => ({ ...prev, isSubmitting: true, submissionError: null, })); try { if (state.scheduledTime != null) { console.log('Going to schedule message'); const schMsgReq = { scheduled: state.scheduledTime.toISOString(), status: 'PENDING', user_id: tokenService.getUserId(), }; const token = tokenService.bearerToken(); const schMsgResponse = await scheduleApi.scheduleMessage( schMsgReq, token ); if (schMsgResponse) { console.log('Message scheduled'); const scheduledMessageId = schMsgResponse.data[0].id; for (let contact of state.selectedContacts) { let schMsgEvtReq = { contact_id: contact, message_id: state.createdMessage.id, scheduled_message_id: scheduledMessageId, }; const schMsgEvtResponse = await scheduleEventApi.scheduleMessageEvent(schMsgEvtReq, token); } console.log('Updating message status'); const req = { scheduled_message_id: scheduledMessageId, status: 'READY', }; console.log(req); const response = await scheduleApi.prepareMessage(req, token); if (response) { console.log('Message scheduled'); setState((prev) => ({ ...prev, step: 'result', isSubmitting: false, isScheduled: false, scheduledTime: null, })); } } } else { console.log('Sending message'); let reqBod = new SendInstantMessageRequest(); reqBod.user_id = tokenService.getUserId(); reqBod.message_id = state.createdMessage.id; state.selectedContacts.forEach((selectedContact) => { reqBod.contact_ids.push(selectedContact); }); const response = await sendMessageApi.sendInstantMessage( reqBod, tokenService.bearerToken() ); if (response) { // Success - move to result step setState((prev) => ({ ...prev, step: 'result', isSubmitting: false, isScheduled: false, scheduledTime: null, })); } } } catch (error) { if (error.name === 'AbortError') { console.log('Submission was aborted'); return; } setState((prev) => ({ ...prev, submissionError: error.message || 'Failed to send messages', isSubmitting: false, isScheduled: false, scheduledTime: null, })); } }; const reset = () => { abortControllerRef.current?.abort(); setState({ step: 'select', selectedContacts: [], scheduledTime: null, message: '', createdMessage: null, isSubmitting: false, isScheduled: false, submissionError: null, }); }; // Cleanup const cleanup = () => { abortControllerRef.current?.abort(); }; return { // Getters currentStep: state.step, selectedContacts: state.selectedContacts, scheduledTime: state.scheduledTime, message: state.message, createdMessage: state.createdMessage, isSubmitting: state.isSubmitting, isScheduled: state.isScheduled, submissionError: state.submissionError, canProceedToNextStep: canProceedToNextStep(), canGoBack, // Actions toggleContact, toggleScheduled, setMessage, setCreatedMessage, setScheduledTime, nextStep, prevStep, submit, reset, cleanup, }; }; export default useSendMessageWizard;