import { useState, useCallback, useRef } from 'react'; import { contactApi, UpdateContactNamesRequest } from '../../api/contactApi'; import { tokenService } from '../../services/TokenService'; const useViewContactWizard = () => { const [state, setState] = useState({ step: 'select', selectedContact: null, contactDetails: null, isSubmitting: false, submissionError: null, }); const abortControllerRef = useRef(null); const canProceedToNextStep = useCallback(() => { switch (state.step) { case 'select': return state.selectedContact != null; case 'modify': if (!state.contactDetails) return false; if ( !state.contactDetails.first_name || state.contactDetails.first_name.trim() === '' ) { return false; } else if ( !state.contactDetails.last_name || state.contactDetails.last_name.trim() === '' ) { return false; } else { return true; } // Nickname is optional, so we don't validate it case 'confirm': return true; default: return false; } }, [state.step, state.selectedContact, state.contactDetails]); const canGoBack = state.step !== 'select'; const setContactDetails = (newDetails) => { console.log('Setting contact details:', newDetails); setState((prev) => ({ ...prev, contactDetails: { ...prev.contactDetails, ...newDetails }, })); }; const onSelectedContact = (contact) => { const contactId = contact.id; setState((prev) => ({ ...prev, selectedContact: prev.selectedContact?.id === contactId ? null : { id: contactId, first_name: contact.first_name, last_name: contact.last_name, phone_number: contact.phone_number, user_id: contact.user_id, nickname: contact.nickname || '', }, })); }; const nextStep = () => { if (!canProceedToNextStep()) return; const stepOrder = ['select', 'modify', 'confirm', 'result']; const currentIndex = stepOrder.indexOf(state.step); if (currentIndex < stepOrder.length - 1) { const nextStepValue = stepOrder[currentIndex + 1]; // When moving from select to modify, initialize contactDetails with selected contact if ( state.step === 'select' && nextStepValue === 'modify' && state.selectedContact ) { setState((prev) => ({ ...prev, step: nextStepValue, submissionError: null, contactDetails: { first_name: prev.selectedContact.first_name || '', last_name: prev.selectedContact.last_name || '', nickname: prev.selectedContact.nickname || '', phone_number: prev.selectedContact.phone_number || '', id: prev.selectedContact.id, user_id: prev.selectedContact.user_id, }, })); return; } setState((prev) => ({ ...prev, step: nextStepValue, submissionError: null, })); } }; const prevStep = () => { const stepOrder = ['select', 'modify', 'confirm', 'result']; const currentIndex = stepOrder.indexOf(state.step); if (currentIndex > 0) { 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 { console.log('Updating contact'); const userId = tokenService.getUserId(); console.log('Contact details to update: ', state.contactDetails); let reqBody = new UpdateContactNamesRequest(); reqBody.first_name = state.contactDetails.first_name; reqBody.last_name = state.contactDetails.last_name; reqBody.nickname = state.contactDetails.nickname || ''; // Send empty string if no nickname reqBody.contact_id = state.selectedContact.id; reqBody.user_id = userId; const response = await contactApi.updateContactNames( reqBody, tokenService.bearerToken() ); if (response) { setState((prev) => ({ ...prev, step: 'result', isSubmitting: false, })); } else { throw new Error('Failed to update contact'); } } catch (error) { if (error.name === 'AbortError') { console.log('Submission was aborted'); return; } setState((prev) => ({ ...prev, submissionError: error.message || 'Failed to update contact', isSubmitting: false, })); } }; const reset = () => { abortControllerRef.current?.abort(); setState({ step: 'select', selectedContact: null, contactDetails: null, isSubmitting: false, submissionError: null, }); }; const cleanup = () => { abortControllerRef.current?.abort(); }; return { // Getters currentStep: state.step, selectedContact: state.selectedContact, contactDetails: state.contactDetails, isSubmitting: state.isSubmitting, submissionError: state.submissionError, canProceedToNextStep: canProceedToNextStep(), canGoBack, // Actions setContactDetails, onSelectedContact, nextStep, prevStep, submit, reset, cleanup, }; }; export default useViewContactWizard;