Files
schedtxt/src/components/ViewContactWizard/useViewContactWizard.js
T
phoenixandphoenix 0202425a09 tsk-10: Edit Contact (#23)
Closes #10

Reviewed-on: phoenix/textsender#23
Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
2026-01-29 22:20:28 +00:00

213 lines
5.5 KiB
JavaScript

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;