Closes #10 Reviewed-on: phoenix/textsender#23 Co-authored-by: phoenix <kundeng00@pm.me> Co-committed-by: phoenix <kundeng00@pm.me>
213 lines
5.5 KiB
JavaScript
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;
|