Closes #6 Reviewed-on: phoenix/textsender#22 Co-authored-by: phoenix <kundeng00@pm.me> Co-committed-by: phoenix <kundeng00@pm.me>
206 lines
5.8 KiB
React
206 lines
5.8 KiB
React
import { useState } from 'react';
|
||
|
||
import { contactApi, CreateContactRequest } from '../api/contactApi';
|
||
import { tokenService } from '../services/TokenService';
|
||
import { DATA_KEY_ADDED_CONTACT_ID } from '../constants/app';
|
||
|
||
import './AddContact.css';
|
||
|
||
const AddContact = ({ isOpen, onClose, onSuccess }) => {
|
||
const [formData, setFormData] = useState({
|
||
phoneNumber: '',
|
||
firstName: '',
|
||
lastName: '',
|
||
});
|
||
const [errors, setErrors] = useState({});
|
||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||
const [submitError, setSubmitError] = useState('');
|
||
|
||
if (!isOpen) return null;
|
||
|
||
const handleChange = (e) => {
|
||
const { name, value } = e.target;
|
||
setFormData((prev) => ({
|
||
...prev,
|
||
[name]: value,
|
||
}));
|
||
// Clear error when user starts typing
|
||
if (errors[name]) {
|
||
setErrors((prev) => ({
|
||
...prev,
|
||
[name]: '',
|
||
}));
|
||
}
|
||
// Clear submit error when user modifies form
|
||
if (submitError) {
|
||
setSubmitError('');
|
||
}
|
||
};
|
||
|
||
const validateForm = () => {
|
||
const newErrors = {};
|
||
|
||
// Phone number is required
|
||
if (!formData.phoneNumber.trim()) {
|
||
newErrors.phoneNumber = 'Phone number is required';
|
||
} else if (!/^[\d\s\-\+\(\)]{10,}$/.test(formData.phoneNumber)) {
|
||
newErrors.phoneNumber = 'Please enter a valid phone number';
|
||
}
|
||
|
||
return newErrors;
|
||
};
|
||
|
||
const handleSubmit = async (e) => {
|
||
e.preventDefault();
|
||
const validationErrors = validateForm();
|
||
|
||
if (Object.keys(validationErrors).length > 0) {
|
||
setErrors(validationErrors);
|
||
return;
|
||
}
|
||
|
||
setIsSubmitting(true);
|
||
setSubmitError('');
|
||
|
||
try {
|
||
const userId = tokenService.getUserId();
|
||
let contact = new CreateContactRequest();
|
||
contact.phone_number = formData.phoneNumber;
|
||
contact.first_name = formData.firstName;
|
||
contact.last_name = formData.lastName;
|
||
contact.user_id = userId;
|
||
const result = await contactApi.createContact(
|
||
contact,
|
||
tokenService.bearerToken()
|
||
);
|
||
if (result.data.length > 0) {
|
||
console.log('Contact added');
|
||
const contactId = result.data[0].id;
|
||
localStorage.setItem(DATA_KEY_ADDED_CONTACT_ID, contactId);
|
||
}
|
||
|
||
// Reset form
|
||
setFormData({ phoneNumber: '', firstName: '', lastName: '' });
|
||
|
||
// Call onSuccess callback if provided
|
||
if (onSuccess) {
|
||
onSuccess(result);
|
||
}
|
||
|
||
// Close the modal
|
||
onClose();
|
||
} catch (error) {
|
||
console.error('Error submitting form:', error);
|
||
setSubmitError(
|
||
error.message || 'Failed to create contact. Please try again.'
|
||
);
|
||
} finally {
|
||
setIsSubmitting(false);
|
||
}
|
||
};
|
||
|
||
const handleCancel = () => {
|
||
setFormData({ phoneNumber: '', firstName: '', lastName: '' });
|
||
setErrors({});
|
||
setSubmitError('');
|
||
onClose();
|
||
};
|
||
|
||
return (
|
||
<div className="contact-modal-overlay">
|
||
<div className="contact-modal">
|
||
<div className="contact-header">
|
||
<h2 className="contact-title">Add New Contact</h2>
|
||
<button
|
||
className="close-btn"
|
||
onClick={handleCancel}
|
||
aria-label="Close"
|
||
>
|
||
×
|
||
</button>
|
||
</div>
|
||
|
||
<div className="contact-card">
|
||
{submitError && <div className="submit-error">{submitError}</div>}
|
||
|
||
<form className="contact-form" onSubmit={handleSubmit}>
|
||
<div className="form-group">
|
||
<label htmlFor="phoneNumber" className="form-label">
|
||
Phone Number <span className="required">*</span>
|
||
</label>
|
||
<input
|
||
id="phoneNumber"
|
||
name="phoneNumber"
|
||
type="tel"
|
||
className={`form-input ${errors.phoneNumber ? 'error' : ''}`}
|
||
value={formData.phoneNumber}
|
||
onChange={handleChange}
|
||
placeholder="Enter phone number"
|
||
disabled={isSubmitting}
|
||
required
|
||
/>
|
||
{errors.phoneNumber && (
|
||
<span className="error-message">{errors.phoneNumber}</span>
|
||
)}
|
||
</div>
|
||
|
||
<div className="form-group">
|
||
<label htmlFor="firstName" className="form-label">
|
||
First Name
|
||
</label>
|
||
<input
|
||
id="firstName"
|
||
name="firstName"
|
||
type="text"
|
||
className="form-input"
|
||
value={formData.firstName}
|
||
onChange={handleChange}
|
||
placeholder="Enter first name (optional)"
|
||
disabled={isSubmitting}
|
||
/>
|
||
<span className="form-hint">Optional field</span>
|
||
</div>
|
||
|
||
<div className="form-group">
|
||
<label htmlFor="lastName" className="form-label">
|
||
Last Name
|
||
</label>
|
||
<input
|
||
id="lastName"
|
||
name="lastName"
|
||
type="text"
|
||
className="form-input"
|
||
value={formData.lastName}
|
||
onChange={handleChange}
|
||
placeholder="Enter last name (optional)"
|
||
disabled={isSubmitting}
|
||
/>
|
||
<span className="form-hint">Optional field</span>
|
||
</div>
|
||
|
||
<div className="form-actions">
|
||
<button
|
||
type="button"
|
||
className="cancel-btn"
|
||
onClick={handleCancel}
|
||
disabled={isSubmitting}
|
||
>
|
||
Cancel
|
||
</button>
|
||
<button
|
||
type="submit"
|
||
className="submit-btn"
|
||
disabled={isSubmitting}
|
||
>
|
||
{isSubmitting ? 'Creating...' : 'Create Contact'}
|
||
</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
);
|
||
};
|
||
|
||
export default AddContact;
|