diff --git a/src/components/Tenant/CreateTenant.jsx b/src/components/Tenant/CreateTenant.jsx index b759f5ce..0391642e 100644 --- a/src/components/Tenant/CreateTenant.jsx +++ b/src/components/Tenant/CreateTenant.jsx @@ -1,12 +1,12 @@ import React, { useEffect, useState, useCallback } from "react"; import { useNavigate, useLocation } from "react-router-dom"; -import Breadcrumb from "../common/Breadcrumb"; import { Modal } from "react-bootstrap"; +import Breadcrumb from "../common/Breadcrumb"; import { apiTenant } from "./apiTenant"; import { useCreateTenant } from "./useTenants"; +import TenantSubscription from "./TenantSubscription"; const defaultAvatar = "https://via.placeholder.com/100x100.png?text=Avatar"; - const initialData = { firstName: "", lastName: "", @@ -24,64 +24,84 @@ const initialData = { onBoardingDate: "", }; +const RequiredLabel = ({ label, name }) => ( + +); + +const validateForm = (form, step) => { + let errors = {}; + let fieldsToValidate = []; + + if (step === 1) { + fieldsToValidate = [ + "firstName", + "lastName", + "email", + "phone", + "billingAddress", + ]; + } else if (step === 2) { + fieldsToValidate = [ + "organizationName", + "organizationSize", + "industryId", + "reference", + "domainName", + "onBoardingDate", + ]; + } + + fieldsToValidate.forEach((field) => { + if (!form?.[field] || String(form?.[field]).trim() === "") { + const fieldName = field.replace(/([A-Z])/g, " $1").replace(/^./, (str) => str.toUpperCase()); + errors[field] = `${fieldName} is required.`; + } + }); + + if (step === 1 && form.phone && !/^[0-9]{10}$/.test(form.phone)) { + errors.phone = "Phone number must be a 10-digit number."; + } + + return errors; +}; + const CreateTenant = () => { const navigate = useNavigate(); - const location = useLocation(); - const formData = location.state?.formData || null; - - const { createTenant, updateTenant, loading, error, success } = useCreateTenant(); + const { state } = useLocation(); + const formData = state?.formData || null; + const { createTenant, updateTenant, loading } = useCreateTenant(); const [form, setForm] = useState(initialData); + const [formErrors, setFormErrors] = useState({}); const [imagePreview, setImagePreview] = useState(defaultAvatar); const [imageFile, setImageFile] = useState(null); const [showImageModal, setShowImageModal] = useState(false); const [showImageSizeModal, setShowImageSizeModal] = useState(false); const [industryOptions, setIndustryOptions] = useState([]); + const [step, setStep] = useState(1); - // Load form data if it's passed via location state useEffect(() => { if (formData) { const { contactName, contactNumber, logoImage, ...rest } = formData; - - let firstName = ""; - let lastName = ""; - if (contactName) { - const nameParts = contactName.trim().split(" "); - firstName = nameParts.shift() || ""; - lastName = nameParts.join(" ") || ""; - } - - setForm({ - ...initialData, - ...rest, - firstName, - lastName, - phone: contactNumber || "", - }); - - if (logoImage) { - setImagePreview(logoImage); - } + const [firstName, ...lastNameParts] = (contactName || "").trim().split(" "); + const lastName = lastNameParts.join(" "); + setForm({ ...initialData, ...rest, firstName, lastName, phone: contactNumber || "" }); + if (logoImage) setImagePreview(logoImage); } }, [formData]); - // Load industry options from the API when the component mounts useEffect(() => { const fetchIndustries = async () => { try { - const res = await apiTenant.getIndustries(); - if (Array.isArray(res.data)) { - setIndustryOptions(res.data); + const { data } = await apiTenant.getIndustries(); + if (Array.isArray(data)) { + setIndustryOptions(data); if (formData?.industry) { - const matchedIndustry = res.data.find( - (industry) => industry.name === formData.industry.name - ); - if (matchedIndustry) { - setForm((prev) => ({ ...prev, industryId: matchedIndustry.id })); - } + const matchedIndustry = data.find((i) => i.name === formData.industry.name); + if (matchedIndustry) setForm((prev) => ({ ...prev, industryId: matchedIndustry.id })); } - } else { - console.error("Unexpected response format for industries", res); } } catch (err) { console.error("Failed to load industries:", err); @@ -92,23 +112,28 @@ const CreateTenant = () => { const handleChange = (e) => { const { name, value } = e.target; - setForm((prev) => ({ ...prev, [name]: value })); + const sanitizedValue = name === "phone" ? value.replace(/\D/g, "") : value; + setForm((prev) => ({ ...prev, [name]: sanitizedValue })); + if (formErrors?.[name]) { + setFormErrors((prev) => { + const newErrors = { ...prev }; + delete newErrors?.[name]; + return newErrors; + }); + } }; const handleImageChange = (e) => { - const file = e.target.files[0]; - if (file) { - if (file.size <= 200 * 1024) { - setImageFile(file); - const reader = new FileReader(); - reader.onloadend = () => { - setImagePreview(reader.result); - }; - reader.readAsDataURL(file); - } else { - setShowImageSizeModal(true); - } + const file = e.target.files?.[0]; + if (!file) return; + if (file.size > 200 * 1024) { + setShowImageSizeModal(true); + return; } + setImageFile(file); + const reader = new FileReader(); + reader.onloadend = () => setImagePreview(reader.result); + reader.readAsDataURL(file); }; const handleImageReset = () => { @@ -118,355 +143,234 @@ const CreateTenant = () => { const handleClearForm = () => { setForm(initialData); - setImagePreview(defaultAvatar); - setImageFile(null); + setFormErrors({}); + handleImageReset(); + setStep(1); + }; + + const handleNext = () => { + const errors = validateForm(form, step); + if (Object.keys(errors).length > 0) { + setFormErrors(errors); + return; + } + setFormErrors({}); + setStep((prev) => prev + 1); }; const handleSubmit = useCallback( async (e) => { e.preventDefault(); - - // Determine the image to send to the API - // If there's a new file selected (imageFile), use it. - // If the image was reset (imagePreview is defaultAvatar), send null. - // Otherwise, use the existing logo image (imagePreview). - const finalLogoImage = imageFile - ? imageFile - : imagePreview === defaultAvatar - ? null - : imagePreview; - + const errors = validateForm(form, 2); + if (Object.keys(errors).length > 0) { + setFormErrors(errors); + setStep(2); + return; + } + setFormErrors({}); + const finalLogoImage = imageFile || (imagePreview === defaultAvatar ? null : imagePreview); const submissionData = { ...form, logoImage: finalLogoImage, contactNumber: form.phone, contactName: `${form.firstName} ${form.lastName}`.trim(), }; - let result; if (formData?.id) { result = await updateTenant(formData.id, submissionData); - - if (result) { - alert("Tenant updated successfully!"); - navigate("/tenant/profile", { state: { newTenant: result } }); - } else { - alert("Failed to update tenant. Please check the form and try again."); - } + if (result) navigate("/tenant/profile", { state: { newTenant: result } }); } else { result = await createTenant(submissionData); - - if (result) { - alert("Tenant created successfully!"); - navigate("/tenant/profile/subscription", { state: { formData: result } }); - } else { - alert("Failed to create tenant. Please check the form and try again."); - } + if (result) navigate("/tenant/profile/viewtenant", { state: { formData: result } }); } }, [form, imagePreview, imageFile, formData, navigate, createTenant, updateTenant] ); - const RequiredLabel = ({ label }) => ( - - ); + const renderFormStep = () => { + switch (step) { + case 1: + return ( + <> +
{formErrors.firstName}
)} +{formErrors.lastName}
)} +{formErrors.email}
)} +{formErrors.phone}
)} +{formErrors.billingAddress}
)} +{formErrors.onBoardingDate}
)} +{form.organizationName}
)} +{formErrors.organizationSize}
)} +{formErrors.industryId}
)} +{formErrors.reference}
)} +{formErrors.domainName}
)} +