diff --git a/package-lock.json b/package-lock.json index 39e9a3b4..a6396dc5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,6 +18,7 @@ "apexcharts": "^4.5.0", "axios": "^1.7.9", "axios-retry": "^4.5.0", + "bootstrap": "^5.3.7", "dotenv": "^16.4.7", "dotenv-webpack": "^8.1.0", "eventemitter3": "^5.0.1", @@ -29,6 +30,7 @@ "perfect-scrollbar": "^1.5.5", "react": "^18.2.0", "react-apexcharts": "^1.7.0", + "react-bootstrap": "^2.10.10", "react-dom": "^18.2.0", "react-hook-form": "^7.54.2", "react-quill": "^2.0.0", @@ -897,6 +899,31 @@ "pako": "^1.0.10" } }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@react-aria/ssr": { + "version": "3.9.10", + "resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.9.10.tgz", + "integrity": "sha512-hvTm77Pf+pMBhuBm760Li0BVIO38jv1IBws1xFm1NoL26PU+fe+FMW5+VZWyANR6nYL65joaJKZqOdTQMkO9IQ==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0" + }, + "engines": { + "node": ">= 12" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, "node_modules/@reduxjs/toolkit": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.5.0.tgz", @@ -928,6 +955,60 @@ "node": ">=14.0.0" } }, + "node_modules/@restart/hooks": { + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.4.16.tgz", + "integrity": "sha512-f7aCv7c+nU/3mF7NWLtVVr0Ra80RqsO89hO72r+Y/nvQr5+q0UFGkocElTH6MJApvReVh6JHUFYn2cw1WdHF3w==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.3" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@restart/ui": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@restart/ui/-/ui-1.9.4.tgz", + "integrity": "sha512-N4C7haUc3vn4LTwVUPlkJN8Ach/+yIMvRuTVIhjilNHqegY60SGLrzud6errOMNJwSnmYFnt1J0H/k8FE3A4KA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.26.0", + "@popperjs/core": "^2.11.8", + "@react-aria/ssr": "^3.5.0", + "@restart/hooks": "^0.5.0", + "@types/warning": "^3.0.3", + "dequal": "^2.0.3", + "dom-helpers": "^5.2.0", + "uncontrollable": "^8.0.4", + "warning": "^4.0.3" + }, + "peerDependencies": { + "react": ">=16.14.0", + "react-dom": ">=16.14.0" + } + }, + "node_modules/@restart/ui/node_modules/@restart/hooks": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.5.1.tgz", + "integrity": "sha512-EMoH04NHS1pbn07iLTjIjgttuqb7qu4+/EyhAx27MHpoENcB2ZdSsLTNxmKD+WEPnZigo62Qc8zjGnNxoSE/5Q==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.3" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@restart/ui/node_modules/uncontrollable": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-8.0.4.tgz", + "integrity": "sha512-ulRWYWHvscPFc0QQXvyJjY6LIXU56f0h8pQFvhxiKk5V1fcI8gp9Ht9leVAhrVjzqMw0BgjspBINx9r6oyJUvQ==", + "license": "MIT", + "peerDependencies": { + "react": ">=16.14.0" + } + }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.28.1", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.28.1.tgz", @@ -1416,6 +1497,21 @@ "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", "dev": true }, + "node_modules/@swc/helpers": { + "version": "0.5.17", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.17.tgz", + "integrity": "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@swc/helpers/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, "node_modules/@swc/types": { "version": "0.1.17", "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.17.tgz", @@ -1562,8 +1658,7 @@ "node_modules/@types/prop-types": { "version": "15.7.14", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.14.tgz", - "integrity": "sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==", - "devOptional": true + "integrity": "sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==" }, "node_modules/@types/quill": { "version": "1.3.10", @@ -1578,7 +1673,6 @@ "version": "18.3.16", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.16.tgz", "integrity": "sha512-oh8AMIC4Y2ciKufU8hnKgs+ufgbA/dhPTACaZPM86AbwX9QwnFtSoPWEeRUj8fge+v6kFt78BXcDhAU1SrrAsw==", - "devOptional": true, "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" @@ -1593,11 +1687,26 @@ "@types/react": "^18.0.0" } }, + "node_modules/@types/react-transition-group": { + "version": "4.4.12", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz", + "integrity": "sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*" + } + }, "node_modules/@types/use-sync-external-store": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz", "integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==" }, + "node_modules/@types/warning": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.3.tgz", + "integrity": "sha512-D1XC7WK8K+zZEveUPY+cf4+kgauk8N4eHr/XIHXGlGYkHLud6hK9lYfZk1ry1TNh798cZUCgb6MqGEG8DkJt6Q==", + "license": "MIT" + }, "node_modules/@types/web": { "version": "0.0.216", "resolved": "https://registry.npmjs.org/@types/web/-/web-0.0.216.tgz", @@ -2140,6 +2249,25 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "node_modules/bootstrap": { + "version": "5.3.7", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.7.tgz", + "integrity": "sha512-7KgiD8UHjfcPBHEpDNg+zGz8L3LqR3GVwqZiBRFX04a1BCArZOz1r2kjly2HQ0WokqTO0v1nF+QAt8dsW4lKlw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/twbs" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/bootstrap" + } + ], + "license": "MIT", + "peerDependencies": { + "@popperjs/core": "^2.11.8" + } + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -2299,6 +2427,12 @@ "node": ">=6.0" } }, + "node_modules/classnames": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==", + "license": "MIT" + }, "node_modules/clone": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", @@ -2401,8 +2535,7 @@ "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "devOptional": true + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" }, "node_modules/data-view-buffer": { "version": "1.0.1", @@ -2537,6 +2670,15 @@ "node": ">=0.4.0" } }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -2549,6 +2691,16 @@ "node": ">=6.0.0" } }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, "node_modules/dotenv": { "version": "16.4.7", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", @@ -3611,6 +3763,15 @@ "node": ">= 0.4" } }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, "node_modules/is-arguments": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz", @@ -4646,6 +4807,19 @@ "react-is": "^16.13.1" } }, + "node_modules/prop-types-extra": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/prop-types-extra/-/prop-types-extra-1.1.1.tgz", + "integrity": "sha512-59+AHNnHYCdiC+vMwY52WmvP5dM3QLeoumYuEyceQDi9aEhtwN9zIQ2ZNo25sMyXnbh32h+P1ezDsUpUH3JAew==", + "license": "MIT", + "dependencies": { + "react-is": "^16.3.2", + "warning": "^4.0.0" + }, + "peerDependencies": { + "react": ">=0.14.0" + } + }, "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", @@ -4765,6 +4939,37 @@ "react": ">=0.13" } }, + "node_modules/react-bootstrap": { + "version": "2.10.10", + "resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-2.10.10.tgz", + "integrity": "sha512-gMckKUqn8aK/vCnfwoBpBVFUGT9SVQxwsYrp9yDHt0arXMamxALerliKBxr1TPbntirK/HGrUAHYbAeQTa9GHQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.24.7", + "@restart/hooks": "^0.4.9", + "@restart/ui": "^1.9.4", + "@types/prop-types": "^15.7.12", + "@types/react-transition-group": "^4.4.6", + "classnames": "^2.3.2", + "dom-helpers": "^5.2.1", + "invariant": "^2.2.4", + "prop-types": "^15.8.1", + "prop-types-extra": "^1.1.0", + "react-transition-group": "^4.4.5", + "uncontrollable": "^7.2.1", + "warning": "^4.0.3" + }, + "peerDependencies": { + "@types/react": ">=16.14.8", + "react": ">=16.14.0", + "react-dom": ">=16.14.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/react-dom": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", @@ -4798,6 +5003,12 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, + "node_modules/react-lifecycles-compat": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", + "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==", + "license": "MIT" + }, "node_modules/react-quill": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/react-quill/-/react-quill-2.0.0.tgz", @@ -4885,6 +5096,22 @@ "react-dom": "^18 || ^19" } }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "license": "BSD-3-Clause", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, "node_modules/redux": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", @@ -5746,6 +5973,21 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/uncontrollable": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-7.2.1.tgz", + "integrity": "sha512-svtcfoTADIB0nT9nltgjujTi7BzVmwjZClOmskKu/E8FW9BXzg9os8OLr4f8Dlnk0rYWJIWr4wv9eKUXiQvQwQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.6.3", + "@types/react": ">=16.9.11", + "invariant": "^2.2.4", + "react-lifecycles-compat": "^3.0.4" + }, + "peerDependencies": { + "react": ">=15.0.0" + } + }, "node_modules/undici-types": { "version": "6.20.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", @@ -5876,6 +6118,15 @@ } } }, + "node_modules/warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, "node_modules/watchpack": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz", diff --git a/package.json b/package.json index 3f4d52fe..3b9e4593 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "apexcharts": "^4.5.0", "axios": "^1.7.9", "axios-retry": "^4.5.0", + "bootstrap": "^5.3.7", "dotenv": "^16.4.7", "dotenv-webpack": "^8.1.0", "eventemitter3": "^5.0.1", @@ -32,6 +33,7 @@ "perfect-scrollbar": "^1.5.5", "react": "^18.2.0", "react-apexcharts": "^1.7.0", + "react-bootstrap": "^2.10.10", "react-dom": "^18.2.0", "react-hook-form": "^7.54.2", "react-quill": "^2.0.0", diff --git a/src/components/Tenant/CreateTenant.jsx b/src/components/Tenant/CreateTenant.jsx new file mode 100644 index 00000000..a78a7332 --- /dev/null +++ b/src/components/Tenant/CreateTenant.jsx @@ -0,0 +1,406 @@ +import React, { useEffect, useState, useCallback } from "react"; +import { useNavigate, useLocation } from "react-router-dom"; +import { Modal } from "react-bootstrap"; +import Breadcrumb from "../common/Breadcrumb"; +import { apiTenant } from "./apiTenant"; +import { useCreateTenant } from "./useTenants"; +import TenantSubscription from "./TenantSubscription"; +import { useQueryClient } from "@tanstack/react-query"; + +const defaultAvatar = "https://via.placeholder.com/100x100.png?text=Avatar"; +const initialData = { + firstName: "", + lastName: "", + email: "", + phone: "", + mobile: "", + domainName: "", + organizationName: "", + description: "", + organizationSize: "", + industryId: "", + reference: "", + taxId: "", + billingAddress: "", + onBoardingDate: "", + status: "", +}; + +// RequiredLabel component remains the same for mandatory fields +const RequiredLabel = ({ label, name }) => ( + +); + +// Regular label for non-mandatory fields +const RegularLabel = ({ label, name }) => ( + +); + +const validateForm = (form, step) => { + let errors = {}; + let fieldsToValidate = []; + + // Updated list of mandatory fields for each step + if (step === 1) { + fieldsToValidate = [ + "firstName", + "lastName", + "email", + "phone", + "billingAddress", + ]; + } else if (step === 2) { + fieldsToValidate = [ + "organizationName", + "onBoardingDate", + "organizationSize", + "industryId", + "reference", + "status", + ]; + } + + 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 { state } = useLocation(); + const formData = state?.formData || null; + // const { createTenant, updateTenant, loading } = useCreateTenant(); + const { mutate: createTenant, isPending } = useCreateTenant(); + const queryClient = useQueryClient(); + + 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); + + useEffect(() => { + if (formData) { + const { contactName, contactNumber, logoImage, ...rest } = formData; + const [firstName, ...lastNameParts] = (contactName || "").trim().split(" "); + const lastName = lastNameParts.join(" "); + setForm({ ...initialData, ...rest, firstName, lastName, phone: contactNumber || "" }); + if (logoImage) setImagePreview(logoImage); + } + }, [formData]); + + useEffect(() => { + const fetchIndustries = async () => { + try { + const { data } = await apiTenant.getIndustries(); + if (Array.isArray(data)) { + setIndustryOptions(data); + if (formData?.industry) { + const matchedIndustry = data.find((i) => i.name === formData.industry.name); + if (matchedIndustry) setForm((prev) => ({ ...prev, industryId: matchedIndustry.id })); + } + } + } catch (err) { + console.error("Failed to load industries:", err); + } + }; + fetchIndustries(); + }, [formData]); + + const handleChange = (e) => { + const { name, value } = e.target; + 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) 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 = () => { + setImageFile(null); + setImagePreview(defaultAvatar); + }; + + const handleClearForm = () => { + setForm(initialData); + 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(); + 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 tenantPayload = { + ...form, + logoImage: finalLogoImage, + contactNumber: form.phone, + contactName: `${form.firstName} ${form.lastName}`.trim(), + }; + let result; + if (formData?.id) { + // result = await updateTenant(formData.id, tenantPayload); + if (result) navigate("/tenant/profile", { state: { newTenant: result } }); + } else { + // result = await createTenant(submissionData); + // if (result) navigate("/tenant/profile/viewtenant", { state: { formData: result } }); + createTenant(tenantPayload); + } + }, + [form, imagePreview, imageFile, formData, navigate, createTenant] + ); + + const renderFormStep = () => { + switch (step) { + case 1: + return ( + <> +
{formErrors.firstName}
)} +{formErrors.lastName}
)} +{formErrors.email}
)} +{formErrors.phone}
)} +{formErrors.billingAddress}
)} +{formErrors.onBoardingDate}
)} +{formErrors.organizationName}
)} +{formErrors.organizationSize}
)} +{formErrors.industryId}
)} +{formErrors.reference}
)} +{formErrors.status}
)} +{formErrors.taxId}
)} +{formErrors.domainName}
)} +{formErrors.mobile}
)} +{formErrors.description}
)} +| Organization | +Name | +Phone | +User | +Industry | +Actions | +||
|---|---|---|---|---|---|---|---|
| {tenant.name} | +
+
+ {tenant.logoImage ? (
+
+
+
+ ) : (
+ |
+ {tenant.contactNumber} | +{tenant.organizationSize} | +{tenant.industry?.name} | +
+
+ handleView(tenant)}
+ >
+ handleEdit(tenant)}
+ >
+ handleDelete(tenant.id)}
+ >
+
+ |
+ ||
| + No matching tenants found. + | +|||||||
| Organization | +Name | +Phone | +Size | +Industry | +Actions | +
|---|
Choose your billing cycle:
+Loading plans...
} + {error &&{error}
} + + {plans.length > 0 && ( +Select a plan:
+{currentPlan.description}
+