Issues_Aug_2W #371

Merged
pramod.mahajan merged 29 commits from Issues_Aug_2W into main 2025-09-05 05:45:32 +00:00
3 changed files with 156 additions and 150 deletions
Showing only changes of commit 3c9dd1595a - Show all commits

View File

@ -1,6 +1,6 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import Label from '../common/Label'; import Label from '../common/Label';
import { useFormContext,useForm,FormProvider } from 'react-hook-form'; import { useFormContext, useForm, FormProvider } from 'react-hook-form';
import { useIndustries, useTenantDetails, useUpdateTenantDetails } from '../../hooks/useTenant'; import { useIndustries, useTenantDetails, useUpdateTenantDetails } from '../../hooks/useTenant';
import { orgSize, reference } from '../../utils/constants'; import { orgSize, reference } from '../../utils/constants';
import { LogoUpload } from './LogoUpload'; import { LogoUpload } from './LogoUpload';
@ -8,18 +8,18 @@ import showToast from '../../services/toastService';
import { zodResolver } from '@hookform/resolvers/zod'; import { zodResolver } from '@hookform/resolvers/zod';
import { EditTenant } from './TenantSchema'; import { EditTenant } from './TenantSchema';
const EditProfile = ({ TenantId,onClose }) => { const EditProfile = ({ TenantId, onClose }) => {
const { data, isLoading, isError, error } = useTenantDetails(TenantId); const { data, isLoading, isError, error } = useTenantDetails(TenantId);
const [logoPreview, setLogoPreview] = useState(null); const [logoPreview, setLogoPreview] = useState(null);
const [logoName, setLogoName] = useState(""); const [logoName, setLogoName] = useState("");
const { data: Industries, isLoading: industryLoading, isError: industryError } = useIndustries(); const { data: Industries, isLoading: industryLoading, isError: industryError } = useIndustries();
const {mutate:UpdateTenant,isPending,} = useUpdateTenantDetails(()=>{ const { mutate: UpdateTenant, isPending, } = useUpdateTenantDetails(() => {
showToast("Tenant Details Updated Successfully","success") showToast("Tenant Details Updated Successfully", "success")
onClose() onClose()
}) })
const methods = useForm({ const methods = useForm({
resolver:zodResolver(EditTenant), resolver: zodResolver(EditTenant),
defaultValues: { defaultValues: {
firstName: "", firstName: "",
lastName: "", lastName: "",
@ -40,8 +40,8 @@ const EditProfile = ({ TenantId,onClose }) => {
const { register, reset, handleSubmit, formState: { errors } } = methods; const { register, reset, handleSubmit, formState: { errors } } = methods;
const onSubmit = (formData) => { const onSubmit = (formData) => {
const tenantPayload = {...formData,contactName:`${formData.firstName} ${formData.lastName}`,id:data.id,} const tenantPayload = { ...formData, contactName: `${formData.firstName} ${formData.lastName}`, id: data.id, }
UpdateTenant({id:data.id,tenantPayload}) UpdateTenant({ id: data.id, tenantPayload })
}; };
useEffect(() => { useEffect(() => {
@ -70,117 +70,117 @@ const EditProfile = ({ TenantId,onClose }) => {
return ( return (
<FormProvider {...methods}> <FormProvider {...methods}>
<form className="row g-6" onSubmit={handleSubmit(onSubmit)}> <form className="row g-6" onSubmit={handleSubmit(onSubmit)}>
<h6>Edit Tenant</h6> <h6>Edit Tenant</h6>
<div className="col-sm-6 mt-1"> <div className="col-sm-6 mt-1">
<Label htmlFor="firstName" required>First Name</Label> <Label htmlFor="firstName" required>First Name</Label>
<input id="firstName" type="text" className="form-control form-control-sm" {...register("firstName")} inputMode='text' /> <input id="firstName" type="text" className="form-control form-control-sm" {...register("firstName")} inputMode='text' />
{errors.firstName && <div className="danger-text">{errors.firstName.message}</div>} {errors.firstName && <div className="danger-text">{errors.firstName.message}</div>}
</div> </div>
<div className="col-sm-6 mt-1"> <div className="col-sm-6 mt-1">
<Label htmlFor="lastName" required>Last Name</Label> <Label htmlFor="lastName" required>Last Name</Label>
<input id="lastName" type="text" className="form-control form-control-sm" {...register("lastName")} /> <input id="lastName" type="text" className="form-control form-control-sm" {...register("lastName")} />
{errors.lastName && <div className="danger-text">{errors.lastName.message}</div>} {errors.lastName && <div className="danger-text">{errors.lastName.message}</div>}
</div> </div>
<div className="col-sm-6 mt-1"> <div className="col-sm-6 mt-1">
<Label htmlFor="contactNumber" required>Contact Number</Label> <Label htmlFor="contactNumber" required>Contact Number</Label>
<input id="contactNumber" type="text" className="form-control form-control-sm" {...register("contactNumber")} inputMode="tel" <input id="contactNumber" type="text" className="form-control form-control-sm" {...register("contactNumber")} inputMode="tel"
placeholder="+91 9876543210" /> placeholder="+91 9876543210" />
{errors.contactNumber && <div className="danger-text">{errors.contactNumber.message}</div>} {errors.contactNumber && <div className="danger-text">{errors.contactNumber.message}</div>}
</div> </div>
<div className="col-sm-6 mt-1"> <div className="col-sm-6 mt-1">
<Label htmlFor="domainName" required>Domain Name</Label> <Label htmlFor="domainName" >Domain Name</Label>
<input id="domainName" type="text" className="form-control form-control-sm" {...register("domainName")} /> <input id="domainName" type="text" className="form-control form-control-sm" {...register("domainName")} />
{errors.domainName && <div className="danger-text">{errors.domainName.message}</div>} {errors.domainName && <div className="danger-text">{errors.domainName.message}</div>}
</div> </div>
<div className="col-sm-6 mt-1"> <div className="col-sm-6 mt-1">
<Label htmlFor="taxId" required>Tax ID</Label> <Label htmlFor="taxId" >Tax ID</Label>
<input id="taxId" type="text" className="form-control form-control-sm" {...register("taxId")} /> <input id="taxId" type="text" className="form-control form-control-sm" {...register("taxId")} />
{errors.taxId && <div className="danger-text">{errors.taxId.message}</div>} {errors.taxId && <div className="danger-text">{errors.taxId.message}</div>}
</div> </div>
<div className="col-sm-6 mt-1"> <div className="col-sm-6 mt-1">
<Label htmlFor="officeNumber" required>Office Number</Label> <Label htmlFor="officeNumber" >Office Number</Label>
<input id="officeNumber" type="text" className="form-control form-control-sm" {...register("officeNumber")} /> <input id="officeNumber" type="text" className="form-control form-control-sm" {...register("officeNumber")} />
{errors.officeNumber && <div className="danger-text">{errors.officeNumber.message}</div>} {errors.officeNumber && <div className="danger-text">{errors.officeNumber.message}</div>}
</div> </div>
<div className="col-sm-6 mt-1"> <div className="col-sm-6 mt-1">
<Label htmlFor="industryId" required>Industry</Label> <Label htmlFor="industryId" required>Industry</Label>
<select className="form-select form-select-sm" {...register("industryId")}> <select className="form-select form-select-sm" {...register("industryId")}>
{industryLoading ? <option value="">Loading...</option> : {industryLoading ? <option value="">Loading...</option> :
Industries?.map((indu) => ( Industries?.map((indu) => (
<option key={indu.id} value={indu.id}>{indu.name}</option> <option key={indu.id} value={indu.id}>{indu.name}</option>
)) ))
} }
</select> </select>
{errors.industryId && <div className="danger-text">{errors.industryId.message}</div>} {errors.industryId && <div className="danger-text">{errors.industryId.message}</div>}
</div> </div>
<div className="col-sm-6 mt-1"> <div className="col-sm-6 mt-1">
<Label htmlFor="reference">Reference</Label> <Label htmlFor="reference">Reference</Label>
<select className="form-select form-select-sm" {...register("reference")}> <select className="form-select form-select-sm" {...register("reference")}>
{reference.map((org) => ( {reference.map((org) => (
<option key={org.val} value={org.val}>{org.name}</option> <option key={org.val} value={org.val}>{org.name}</option>
))} ))}
</select> </select>
{errors.reference && <div className="danger-text">{errors.reference.message}</div>} {errors.reference && <div className="danger-text">{errors.reference.message}</div>}
</div> </div>
<div className="col-sm-6"> <div className="col-sm-6">
<Label htmlFor="organizationSize" required> <Label htmlFor="organizationSize" required>
Organization Size Organization Size
</Label> </Label>
<select <select
className="form-select form-select-sm" className="form-select form-select-sm"
{...register("organizationSize")} {...register("organizationSize")}
> >
{orgSize.map((org) => ( {orgSize.map((org) => (
<option key={org.val} value={org.val}> <option key={org.val} value={org.val}>
{org.name} {org.name}
</option> </option>
))} ))}
</select> </select>
{errors.organizationSize && ( {errors.organizationSize && (
<div className="danger-text">{errors.organizationSize.message}</div> <div className="danger-text">{errors.organizationSize.message}</div>
)} )}
</div> </div>
<div className="col-12 mt-1"> <div className="col-12 mt-1">
<Label htmlFor="billingAddress" required>Billing Address</Label> <Label htmlFor="billingAddress" required>Billing Address</Label>
<textarea id="billingAddress" className="form-control" {...register("billingAddress")} rows={2} /> <textarea id="billingAddress" className="form-control" {...register("billingAddress")} rows={2} />
{errors.billingAddress && <div className="danger-text">{errors.billingAddress.message}</div>} {errors.billingAddress && <div className="danger-text">{errors.billingAddress.message}</div>}
</div> </div>
<div className="col-12 mt-1"> <div className="col-12 mt-1">
<Label htmlFor="description">Description</Label> <Label htmlFor="description">Description</Label>
<textarea id="description" className="form-control" {...register("description")} rows={2} /> <textarea id="description" className="form-control" {...register("description")} rows={2} />
{errors.description && <div className="danger-text">{errors.description.message}</div>} {errors.description && <div className="danger-text">{errors.description.message}</div>}
</div> </div>
<div className="col-sm-12"> <div className="col-sm-12">
<Label htmlFor="logImage">Logo Image</Label> <Label htmlFor="logImage">Logo Image</Label>
<LogoUpload <LogoUpload
preview={logoPreview} preview={logoPreview}
setPreview={setLogoPreview} setPreview={setLogoPreview}
fileName={logoName} fileName={logoName}
setFileName={setLogoName} setFileName={setLogoName}
/> />
</div> </div>
<div className="d-flex justify-content-center gap-2 mt-3"> <div className="d-flex justify-content-center gap-2 mt-3">
<button type="submit" disabled={isPending} className="btn btn-sm btn-primary">{isPending ? "Please Wait..." : "Submit"}</button> <button type="submit" disabled={isPending} className="btn btn-sm btn-primary">{isPending ? "Please Wait..." : "Submit"}</button>
<button type="button" disabled={isPending} className="btn btn-sm btn-secondary" onClick={onClose}>Cancel</button> <button type="button" disabled={isPending} className="btn btn-sm btn-secondary" onClick={onClose}>Cancel</button>
</div> </div>
</form> </form>
</FormProvider> </FormProvider>
); );
}; };

View File

@ -48,7 +48,7 @@ const OrganizationInfo = ({ onNext, onPrev, onSubmitTenant }) => {
const data = getValues(); const data = getValues();
// onSubmitTenant(data); // onSubmitTenant(data);
// onNext(); // onNext();
const tenantPayload = {...data,onBoardingDate: moment.utc(data.onBoardingDate, "DD-MM-YYYY").toISOString() } const tenantPayload = { ...data, onBoardingDate: moment.utc(data.onBoardingDate, "DD-MM-YYYY").toISOString() }
CreateTenant(tenantPayload); CreateTenant(tenantPayload);
} }
}; };
@ -73,7 +73,7 @@ const OrganizationInfo = ({ onNext, onPrev, onSubmitTenant }) => {
</div> </div>
<div className="col-sm-6"> <div className="col-sm-6">
<Label htmlFor="officeNumber" required> <Label htmlFor="officeNumber" >
Office Number Office Number
</Label> </Label>
<input <input
@ -87,7 +87,7 @@ const OrganizationInfo = ({ onNext, onPrev, onSubmitTenant }) => {
</div> </div>
<div className="col-sm-6"> <div className="col-sm-6">
<Label htmlFor="domainName" required> <Label htmlFor="domainName" >
Domain Name Domain Name
</Label> </Label>
<input <input
@ -101,7 +101,7 @@ const OrganizationInfo = ({ onNext, onPrev, onSubmitTenant }) => {
</div> </div>
<div className="col-sm-6"> <div className="col-sm-6">
<Label htmlFor="taxId" required> <Label htmlFor="taxId" >
Tax ID Tax ID
</Label> </Label>
<input <input
@ -138,8 +138,10 @@ const OrganizationInfo = ({ onNext, onPrev, onSubmitTenant }) => {
</Label> </Label>
<select <select
className="form-select form-select-sm" id="organizationSize"
{...register("organizationSize")} className="form-select shadow-none border py-1 px-2"
style={{ fontSize: "0.875rem" }} // Bootstrap's small text size
{...register("organizationSize", { required: "Organization size is required" })}
> >
{orgSize.map((org) => ( {orgSize.map((org) => (
<option key={org.val} value={org.val}> <option key={org.val} value={org.val}>
@ -147,17 +149,20 @@ const OrganizationInfo = ({ onNext, onPrev, onSubmitTenant }) => {
</option> </option>
))} ))}
</select> </select>
{errors.organizationSize && ( {errors.organizationSize && (
<div className="danger-text">{errors.organizationSize.message}</div> <div className="danger-text">{errors.organizationSize.message}</div>
)} )}
</div> </div>
<div className="col-sm-6"> <div className="col-sm-6">
<Label htmlFor="industryId" required> <Label htmlFor="industryId" required>
Industry Industry
</Label> </Label>
<select <select
className="form-select form-select-sm" id="industryId"
className="form-select shadow-none border py-1 px-2 small"
{...register("industryId")} {...register("industryId")}
> >
{industryLoading ? ( {industryLoading ? (
@ -177,9 +182,9 @@ const OrganizationInfo = ({ onNext, onPrev, onSubmitTenant }) => {
<div className="col-sm-6"> <div className="col-sm-6">
<Label htmlFor="reference">Reference</Label> <Label htmlFor="reference">Reference</Label>
<select <select
className="form-select form-select-sm" id="reference"
className="form-select shadow-none border py-1 px-2 small"
{...register("reference")} {...register("reference")}
> >
{reference.map((org) => ( {reference.map((org) => (
@ -193,6 +198,7 @@ const OrganizationInfo = ({ onNext, onPrev, onSubmitTenant }) => {
)} )}
</div> </div>
<div className="col-sm-12"> <div className="col-sm-12">
<Label htmlFor="description">Description</Label> <Label htmlFor="description">Description</Label>
<textarea <textarea

View File

@ -2,34 +2,34 @@ import { z } from "zod";
export const newTenantSchema = z.object({ export const newTenantSchema = z.object({
firstName: z firstName: z
.string().trim() .string().trim()
.min(1, { message: "First Name is required!" }) .min(1, { message: "First Name is required!" })
.regex(/^[A-Za-z]+$/, { message: "First Name should contain only letters!" }), .regex(/^[A-Za-z]+$/, { message: "First Name should contain only letters!" }),
lastName: z lastName: z
.string().trim() .string().trim()
.min(1, { message: "Last Name is required!" }) .min(1, { message: "Last Name is required!" })
.regex(/^[A-Za-z]+$/, { message: "Last Name should contain only letters!" }), .regex(/^[A-Za-z]+$/, { message: "Last Name should contain only letters!" }),
email: z.string().trim().email("Invalid email address"), email: z.string().trim().email("Invalid email address"),
description: z.string().trim().optional(), description: z.string().trim().optional(),
domainName: z.string().trim().nonempty("Domain name is required"), domainName: z.string().trim().optional(),
billingAddress: z.string().trim().nonempty("Billing address is required"), billingAddress: z.string().trim().nonempty("Billing address is required"),
taxId: z.string().trim().nonempty("Tax ID is required"), taxId: z.string().trim().optional(),
logoImage: z.string().trim().optional(), logoImage: z.string().trim().optional(),
organizationName: z.string().trim().nonempty("Organization name is required"), organizationName: z.string().trim().nonempty("Organization name is required"),
officeNumber: z.string().trim().nonempty("Office number is required"), officeNumber: z.string().trim().optional(),
contactNumber: z.string().trim() contactNumber: z.string().trim()
.nonempty("Contact number is required") .nonempty("Contact number is required")
.regex(/^\+?[1-9]\d{7,14}$/, "Enter a valid contact number"), .regex(/^\+?[1-9]\d{7,14}$/, "Enter a valid contact number"),
onBoardingDate: z.preprocess((val) => { onBoardingDate: z.preprocess((val) => {
if (typeof val === "string" && val.includes("-")) { if (typeof val === "string" && val.includes("-")) {
const [day, month, year] = val.split("-"); const [day, month, year] = val.split("-");
return new Date(`${year}-${month}-${day}`); return new Date(`${year}-${month}-${day}`);
} }
return val; return val;
}, z.date({ }, z.date({
required_error: "Onboarding date is required", required_error: "Onboarding date is required",
invalid_type_error: "Invalid date format", invalid_type_error: "Invalid date format",
})), })),
organizationSize: z.string().nonempty("Organization size is required"), organizationSize: z.string().nonempty("Organization size is required"),
industryId: z.string().uuid("Invalid industry ID"), industryId: z.string().uuid("Invalid industry ID"),
reference: z.string().nonempty("Reference is required"), reference: z.string().nonempty("Reference is required"),
@ -133,23 +133,23 @@ export const getStepFields = (stepIndex) => {
export const EditTenant = z.object({ export const EditTenant = z.object({
firstName: z firstName: z
.string().trim() .string().trim()
.min(1, { message: "First Name is required!" }) .min(1, { message: "First Name is required!" })
.regex(/^[A-Za-z]+$/, { message: "First Name should contain only letters!" }), .regex(/^[A-Za-z]+$/, { message: "First Name should contain only letters!" }),
lastName: z lastName: z
.string().trim() .string().trim()
.min(1, { message: "Last Name is required!" }) .min(1, { message: "Last Name is required!" })
.regex(/^[A-Za-z]+$/, { message: "Last Name should contain only letters!" }), .regex(/^[A-Za-z]+$/, { message: "Last Name should contain only letters!" }),
description: z.string().trim().optional(), description: z.string().trim().optional(),
domainName: z.string().trim().min(1, { message: "Domain Name is required!" }), domainName: z.string().trim().optional(),
billingAddress: z.string().trim().min(1, { message: "Billing Address is required!" }), billingAddress: z.string().trim().min(1, { message: "Billing Address is required!" }),
taxId: z.string().trim().min(1, { message: "Tax ID is required!" }), taxId: z.string().trim().optional(),
logoImage: z.string().optional(), logoImage: z.string().optional(),
officeNumber: z.string().trim().min(1, { message: "Office Number is required!" }), officeNumber: z.string().trim().optional(),
contactNumber: z.string().trim() contactNumber: z.string().trim()
.nonempty("Contact number is required") .nonempty("Contact number is required")
.regex(/^\+?[1-9]\d{7,14}$/, "Enter a valid contact number"), .regex(/^\+?[1-9]\d{7,14}$/, "Enter a valid contact number"),
organizationSize: z.string().min(1, { message: "Organization Size is required!" }), organizationSize: z.string().min(1, { message: "Organization Size is required!" }),
industryId: z.string().min(1,{ message: "Invalid Industry ID!" }), industryId: z.string().min(1, { message: "Invalid Industry ID!" }),
reference: z.string().optional(), reference: z.string().optional(),
}); });