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>
This commit is contained in:
@@ -0,0 +1,212 @@
|
||||
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;
|
||||
Reference in New Issue
Block a user