From a1734b504a156b5d4b0e2ea00fb41ef6f837b653 Mon Sep 17 00:00:00 2001 From: Prime5700 Date: Sat, 2 Aug 2025 00:41:08 +0530 Subject: [PATCH] single contact phone --- src/components/contacts/Contacts.tsx | 1 + src/components/contacts/ContactsFormModal.tsx | 415 +++++++++--------- src/components/setting/ContactForm.tsx | 390 ++++++++-------- 3 files changed, 409 insertions(+), 397 deletions(-) diff --git a/src/components/contacts/Contacts.tsx b/src/components/contacts/Contacts.tsx index b4cce43..f835612 100644 --- a/src/components/contacts/Contacts.tsx +++ b/src/components/contacts/Contacts.tsx @@ -11,6 +11,7 @@ type ContactSchema = [{ firstName: string lastName: string email: string + phone: string }] const Contacts = () => { diff --git a/src/components/contacts/ContactsFormModal.tsx b/src/components/contacts/ContactsFormModal.tsx index fcc25cc..457f158 100644 --- a/src/components/contacts/ContactsFormModal.tsx +++ b/src/components/contacts/ContactsFormModal.tsx @@ -1,203 +1,214 @@ // ContactForm.tsx -import React, { useEffect, useState } from 'react'; -import { FaSpinner } from 'react-icons/fa'; +import React, { useEffect, 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; - setShowModal: () => React.Dispatch> - actionStatus: string, - editJsonData: any + onSubmit: (data: ContactData) => void; + loading: boolean; + setShowModal: () => React.Dispatch>; + actionStatus: string; + editJsonData: any; } -const ContactFormModal = ({ onSubmit, loading, setShowModal, actionStatus, editJsonData }: Props) => { - const [formData, setFormData] = useState({ - email: '', - firstName: '', - lastName: '', - title: '', - company: '', - website: '', - phones: [''], - }); +const ContactFormModal = ({ + onSubmit, + loading, + setShowModal, + actionStatus, + editJsonData, +}: Props) => { + 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 }>({}); - useEffect(() => { - if (actionStatus === 'Edit' && editJsonData) { - setFormData({ - email: editJsonData.email, - firstName: editJsonData.firstName, - lastName: editJsonData.lastName, - title: editJsonData.title, - company: editJsonData.company, - website: editJsonData.website, - phones: editJsonData.phones, - }) - } - }, [actionStatus, editJsonData]) + useEffect(() => { + if (actionStatus === "Edit" && editJsonData) { + setFormData({ + email: editJsonData.email, + firstName: editJsonData.firstName, + lastName: editJsonData.lastName, + title: editJsonData.title, + company: editJsonData.company, + website: editJsonData.website, + phone: editJsonData.phone, + }); + } + }, [actionStatus, editJsonData]); + const handleChange = (field: keyof ContactData, value: string) => { + console.log(field, value); + 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.phone]; +// updatedPhones[index] = numericValue; +// setFormData((prev) => ({ ...prev, phones: updatedPhones })); - 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 errorKey = `phones_${index}`; +// if (errors[errorKey]) { +// setErrors((prev) => ({ ...prev, [errorKey]: "" })); +// } +// }; - const errorKey = `phones_${index}`; - if (errors[errorKey]) { - setErrors((prev) => ({ ...prev, [errorKey]: '' })); - } - }; + // const addPhoneField = () => { + // setFormData((prev) => ({ ...prev, phone: [...prev.phone, ''] })); + // }; + // const removePhoneField = (index: number) => { + // const updatedPhones = formData.phones.filter((_, i) => i !== index); + // setFormData((prev) => ({ ...prev, phones: updatedPhones })); + // }; - const addPhoneField = () => { - setFormData((prev) => ({ ...prev, phones: [...prev.phones, ''] })); - }; + const validate = () => { + const newErrors: { [key: string]: string } = {}; - const removePhoneField = (index: number) => { - const updatedPhones = formData.phones.filter((_, i) => i !== index); - setFormData((prev) => ({ ...prev, phones: updatedPhones })); - }; + const emailRegex = /\S+@\S+\.\S+/; + // 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 validate = () => { - const newErrors: { [key: string]: string } = {}; + // Email + if (!formData.email.trim()) { + newErrors.email = "Email is required"; + } else if (!emailRegex.test(formData.email)) { + newErrors.email = "Invalid email address"; + } - const nameRegex = /^[a-zA-Z\s\-']+$/; - const urlRegex = /^(https?:\/\/)?([\w-]+\.)+[\w-]{2,}(\/.*)?$/; - const phoneRegex = /^\d+$/; + // // First Name + // if (!formData.firstName.trim()) { + // newErrors.firstName = 'First name is required'; + // } else + // if (formData.firstName.trim() && !nameRegex.test(formData.firstName)) { + // newErrors.firstName = "First name contains invalid characters"; + // } - // Email - if (!formData.email.trim()) { - newErrors.email = 'Email is required'; - } else if (!/\S+@\S+\.\S+/.test(formData.email)) { - newErrors.email = 'Invalid email address'; - } + // 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"; + // } - // // 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'; - // } + // // Title + // if (!formData.title.trim()) { + // newErrors.title = 'Title 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'; - } + // Website (optional but validate if present) + if (formData.website.trim() && !urlRegex.test(formData.website)) { + newErrors.website = "Invalid website URL"; + } - // // Title - // if (!formData.title.trim()) { - // newErrors.title = 'Title is required'; - // } + // Phone + if (formData.phone.trim() && !phoneRegex.test(formData.phone)) { + newErrors.phone = "Phone number must contain only digits"; + } + return newErrors; + }; + const handleSubmit = async () => { + const validationErrors = validate(); + let type = "Add"; + let payload = formData; + console.log(payload); - // Website (optional but validate if present) - if (formData.website.trim() && !urlRegex.test(formData.website)) { - newErrors.website = 'Invalid website URL'; - } + if (Object.keys(validationErrors).length > 0) { + setErrors(validationErrors); + return; + } + try { + if (actionStatus === "Edit") { + type = "Edit"; + payload = { + ...formData, + contactId: editJsonData.id, + }; + } + await onSubmit(payload, type); - // 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'; - // } - // }); + setFormData({ + email: "", + firstName: "", + lastName: "", + title: "", + company: "", + website: "", + phone: "", + }); + setErrors({}); + } catch (err) { + console.error("Submit failed:", err); + } + }; - return newErrors; - }; + return ( +
+
+
+

Add Contact

+
+ {[ + { 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]} + + )} +
+ ))} +
- const handleSubmit = async () => { - const validationErrors = validate(); - let type = 'Add' - let payload = formData - if (Object.keys(validationErrors).length > 0) { - setErrors(validationErrors); - return; - } - try { - if (actionStatus === 'Edit') { - type = 'Edit' - payload = { - ...formData, - contactId: editJsonData.id - } - } - await onSubmit(payload, type); - - - 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) => (
@@ -233,40 +244,38 @@ const ContactFormModal = ({ onSubmit, loading, setShowModal, actionStatus, editJ + Add another phone
-
+
*/} -
- - - - - -
-
-
+
+ + +
- ); +
+
+ ); }; 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; -- 2.40.1