diff --git a/src/components/accounts/TransactionDataTable.tsx b/src/components/accounts/TransactionDataTable.tsx index 4784589..d3952de 100644 --- a/src/components/accounts/TransactionDataTable.tsx +++ b/src/components/accounts/TransactionDataTable.tsx @@ -3,7 +3,6 @@ import { PiDotsThreeOutlineVerticalFill } from 'react-icons/pi'; import api from '../../config/api'; import { Transaction } from '../transactions/Transactions'; import { useNavigate } from 'react-router-dom'; - import { FaCheck } from 'react-icons/fa'; diff --git a/src/components/contacts/Contacts.tsx b/src/components/contacts/Contacts.tsx index 86bc7a9..655e92e 100644 --- a/src/components/contacts/Contacts.tsx +++ b/src/components/contacts/Contacts.tsx @@ -12,6 +12,7 @@ type ContactSchema = [{ firstName: string lastName: string email: string + phone: string }] const Contacts = () => { @@ -121,7 +122,10 @@ const Contacts = () => {
setShowModal((prev) => !prev)} + onClick={() => { + setShowModal((prev) => !prev); + setActionStatus("Add") + }} className="flex items-center gap-2 bg-[var(--primary)] px-3 py-1.5 rounded-sm hover:opacity-90 "> {openMenuId === contact.id && ( -
+
-
+
*/} -
- - - - - -
-
-
+
+ + +
- ); + + + ); }; export default ContactFormModal; diff --git a/src/components/setting/ContactForm.tsx b/src/components/setting/ContactForm.tsx index 920b650..2bdefe6 100644 --- a/src/components/setting/ContactForm.tsx +++ b/src/components/setting/ContactForm.tsx @@ -1,230 +1,232 @@ // ContactForm.tsx -import React, { useState } from 'react'; -import { FaSpinner } from 'react-icons/fa'; +import React, { useState } from "react"; +import { FaSpinner } from "react-icons/fa"; export interface ContactData { - contactId?: number; - email: string; - firstName: string; - lastName: string; - title: string; - company: string; - website: string; - phones: string[]; + contactId?: number; + email: string; + firstName: string; + lastName: string; + title: string; + company: string; + website: string; + phone: string; } interface Props { - onSubmit: (data: ContactData) => void; - loading: boolean; + onSubmit: (data: ContactData) => void; + loading: boolean; } const ContactForm = ({ onSubmit, loading }: Props) => { - const [formData, setFormData] = useState({ - email: '', - firstName: '', - lastName: '', - title: '', - company: '', - website: '', - phones: [''], - }); + const [formData, setFormData] = useState({ + email: "", + firstName: "", + lastName: "", + title: "", + company: "", + website: "", + phone: "", + }); - const [errors, setErrors] = useState<{ [key: string]: string }>({}); + const [errors, setErrors] = useState<{ [key: string]: string }>({}); - const handleChange = (field: keyof ContactData, value: string) => { - setFormData((prev) => ({ ...prev, [field]: value })); - if (errors[field]) { - setErrors((prev) => ({ ...prev, [field]: '' })); - } - }; + const handleChange = (field: keyof ContactData, value: string) => { + setFormData((prev) => ({ ...prev, [field]: value })); + if (errors[field]) { + setErrors((prev) => ({ ...prev, [field]: "" })); + } + }; - const handlePhoneChange = (index: number, value: string) => { - const numericValue = value.replace(/\D/g, ''); // Remove non-numeric - const updatedPhones = [...formData.phones]; - updatedPhones[index] = numericValue; - setFormData((prev) => ({ ...prev, phones: updatedPhones })); +// const handlePhoneChange = (index: number, value: string) => { +// const numericValue = value.replace(/\D/g, ""); // Remove non-numeric +// const updatedPhone = [...formData.phone]; +// updatedPhone[index] = numericValue; +// setFormData((prev) => ({ ...prev, phone: updatedPhone })); - const errorKey = `phones_${index}`; - if (errors[errorKey]) { - setErrors((prev) => ({ ...prev, [errorKey]: '' })); - } - }; +// const errorKey = `phone_${index}`; +// if (errors[errorKey]) { +// setErrors((prev) => ({ ...prev, [errorKey]: "" })); +// } +// }; +// const addPhoneField = () => { +// setFormData((prev) => ({ ...prev, phone: [...prev.phone, ""] })); +// }; - const addPhoneField = () => { - setFormData((prev) => ({ ...prev, phones: [...prev.phones, ''] })); - }; +// const removePhoneField = (index: number) => { +// const updatedPhone = formData.phone.filter((_, i) => i !== index); +// setFormData((prev) => ({ ...prev, phone: updatedPhone })); +// }; - const removePhoneField = (index: number) => { - const updatedPhones = formData.phones.filter((_, i) => i !== index); - setFormData((prev) => ({ ...prev, phones: updatedPhones })); - }; + const validate = () => { + const newErrors: { [key: string]: string } = {}; - const validate = () => { - const newErrors: { [key: string]: string } = {}; + // const nameRegex = /^[a-zA-Z\s\-']+$/; + const urlRegex = /^(https?:\/\/)?([\w-]+\.)+[\w-]{2,}(\/.*)?$/; + const phoneRegex = + /^\+?\d{1,4}?[-.\s]?\(?\d{2,5}\)?[-.\s]?\d{3,5}[-.\s]?\d{3,5}$/; - const nameRegex = /^[a-zA-Z\s\-']+$/; - const urlRegex = /^(https?:\/\/)?([\w-]+\.)+[\w-]{2,}(\/.*)?$/; - const phoneRegex = /^\d+$/; + // Email + if (!formData.email.trim()) { + newErrors.email = "Email is required"; + } else if (!/\S+@\S+\.\S+/.test(formData.email)) { + newErrors.email = "Invalid email address"; + } - // Email - if (!formData.email.trim()) { - newErrors.email = 'Email is required'; - } else if (!/\S+@\S+\.\S+/.test(formData.email)) { - newErrors.email = 'Invalid email address'; - } + // // First Name + // if (!formData.firstName.trim()) { + // newErrors.firstName = 'First name is required'; + // } else if (!nameRegex.test(formData.firstName)) { + // newErrors.firstName = 'First name contains invalid characters'; + // } - // // First Name - // if (!formData.firstName.trim()) { - // newErrors.firstName = 'First name is required'; - // } else if (!nameRegex.test(formData.firstName)) { - // newErrors.firstName = 'First name contains invalid characters'; - // } + // Last Name + if (!formData.lastName.trim()) { + newErrors.lastName = "Last name is required"; + } - // Last Name - if (!formData.lastName.trim()) { - newErrors.lastName = 'Last name is required'; - } else if (!nameRegex.test(formData.lastName)) { - newErrors.lastName = 'Last name contains invalid characters'; - } + // // Title + // if (!formData.title.trim()) { + // newErrors.title = 'Title is required'; + // } - // // Title - // if (!formData.title.trim()) { - // newErrors.title = 'Title is required'; - // } + // Website (optional but validate if present) + if (formData.website.trim() && !urlRegex.test(formData.website)) { + newErrors.website = "Invalid website URL"; + } + // Phone + if (formData.phone.trim() && !phoneRegex.test(formData.phone)) { + newErrors.phone = "Phone number must contain only digits"; + } - // Website (optional but validate if present) - if (formData.website.trim() && !urlRegex.test(formData.website)) { - newErrors.website = 'Invalid website URL'; - } + return newErrors; + }; - // Phones - // formData.phones.forEach((phone, index) => { - // if (!phone.trim()) { - // newErrors[`phones_${index}`] = 'Phone number is required'; - // } else if (!phoneRegex.test(phone)) { - // newErrors[`phones_${index}`] = 'Phone number must contain only digits'; - // } - // }); + const handleSubmit = async () => { + const validationErrors = validate(); + if (Object.keys(validationErrors).length > 0) { + setErrors(validationErrors); + return; + } - return newErrors; - }; + try { + await onSubmit(formData); + setFormData({ + email: "", + firstName: "", + lastName: "", + title: "", + company: "", + website: "", + phone: "", + }); + setErrors({}); + } catch (err) { + console.error("Submit failed:", err); + } + }; - const handleSubmit = async () => { - const validationErrors = validate(); - if (Object.keys(validationErrors).length > 0) { - setErrors(validationErrors); - return; - } + return ( +
+

Add Contact

- try { - await onSubmit(formData); +
+ {[ + { label: "First Name", field: "firstName" }, + { label: "Last Name", field: "lastName" }, + { label: "Email", field: "email", fieldType: "email" }, + { label: "Title", field: "title" }, + { label: "Company", field: "company" }, + { label: "Website", field: "website", fieldType: "url" }, + { label: "Phone", field: "phone", fieldType: "tel" }, + ].map(({ label, field, fieldType }) => ( +
+ + + handleChange(field as keyof ContactData, e.target.value) + } + required={true} + className="px-3 py-1.5 border border-gray-400 rounded-md focus:outline-none focus:ring-1 focus:ring-[var(--primary)] text-sm" + placeholder={`Enter ${label}`} + /> + {errors[field] && ( + {errors[field]} + )} +
+ ))} +
- setFormData({ - email: '', - firstName: '', - lastName: '', - title: '', - company: '', - website: '', - phones: [''], - }); - setErrors({}); - } catch (err) { - console.error('Submit failed:', err); - } - }; - - - return ( -
-

Add Contact

- -
- {[ - { label: 'First Name', field: 'firstName' }, - { label: 'Last Name', field: 'lastName' }, - { label: 'Email', field: 'email' }, - { label: 'Title', field: 'title' }, - { label: 'Company', field: 'company' }, - { label: 'Website', field: 'website' }, - ].map(({ label, field }) => ( -
- - handleChange(field as keyof ContactData, e.target.value)} - required={true} - className="px-3 py-1.5 border border-gray-400 rounded-md focus:outline-none focus:ring-1 focus:ring-[var(--primary)] text-sm" - placeholder={`Enter ${label}`} - /> - {errors[field] && {errors[field]}} -
- ))} -
- -
- -
- {formData.phones.map((phone, index) => ( -
-
- handlePhoneChange(index, e.target.value)} - className="flex-1 px-3 py-1.5 border border-gray-400 rounded-md focus:outline-none focus:ring-1 focus:ring-[var(--primary)] text-sm" - maxLength={15} - placeholder='Enter Phone Numbers' - /> - {formData.phones.length > 1 && ( - - )} -
- {errors[`phones_${index}`] && ( - {errors[`phones_${index}`]} - )} -
- ))} - - -
-
- -
- + onClick={() => removePhoneField(index)} + className="text-xs text-red-500 hover:underline" + > + Remove + + )} +
+ {errors[`phone_${index}`] && ( + + {errors[`phone_${index}`]} + + )}
+ ))} + +
- ); + */} + +
+ +
+ + ); }; export default ContactForm;