added branch for projects

This commit is contained in:
pramod.mahajan 2025-11-19 21:28:01 +05:30
parent 7e4dffff34
commit e7fddd41c2
18 changed files with 571 additions and 506 deletions

View File

@ -40,7 +40,6 @@ const ActionPaymentRequest = ({ requestId }) => {
error: PaymentModeError,
} = usePaymentMode();
console.log("Kartik", data)
const IsReview = useHasUserPermission(REVIEW_EXPENSE);
const [imageLoaded, setImageLoaded] = useState({});

View File

@ -82,7 +82,6 @@ const EditActivityModal = ({
useEffect(() => {
if (!workItem) return;
console.log(workItem)
reset({
activityID: String(
workItem?.workItem?.activityId || workItem?.activityMaster?.id

View File

@ -1,43 +0,0 @@
import { z } from "zod";
export const BranchSchema = () =>
z.object({
projectId: z
.string()
.trim()
.min(1, { message: "Project is required" }),
branchName: z
.string()
.trim()
.min(1, { message: "Branch Name is required" }),
contactInformation: z
.string()
.trim()
.min(1, { message: "Contact Information is required" }),
address: z
.string()
.trim()
.min(1, { message: "Address is required" }),
branchType: z
.string()
.trim()
.min(1, { message: "Branch Type is required" }),
googleMapUrl: z
.string()
.trim()
.url({ message: "Enter a valid Google Map URL" }),
});
export const defaultBranches = {
branchName: "",
projectId: "",
contactInformation: "",
address: "",
branchType: "",
googleMapUrl: "",
};

View File

@ -1,186 +0,0 @@
import React, { useEffect } from 'react'
import { useProjectName } from '../../hooks/useProjects';
import { BranchSchema, defaultBranches } from './BranchSchema';
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import Label from '../common/Label';
import { useCreateBranch, useServiceProjects, useUpdateBranch } from '../../hooks/useServiceProject';
import { useAppForm } from '../../hooks/appHooks/useAppForm';
import { useParams } from 'react-router-dom';
const ManageBranch = ({ closeModal, BranchToEdit = null }) => {
const { data } = {}
const { projectId } = useParams();
const schema = BranchSchema();
const {
register,
control,
watch,
handleSubmit,
setValue,
reset,
formState: { errors },
} = useAppForm({
resolver: zodResolver(schema),
defaultValues: {
...defaultBranches,
projectId: projectId || ""
},
});
const handleClose = () => {
reset();
closeModal();
};
useEffect(() => {
if (BranchToEdit && data) {
reset({
branchName: data.branchName || "",
projectId: data.project?.id || projectId || "",
contactInformation: data.contactInformation || "",
address: data.address || "",
branchType: data.branchType || "",
googleMapUrl: data.googleMapUrl || "",
});
}
}, [data, reset]);
const { mutate: CreateServiceBranch, isPending: createPending } =
useCreateBranch(() => {
handleClose();
});
const { mutate: ServiceBranchUpdate, isPending } =
useUpdateBranch(() => handleClose());
const onSubmit = (fromdata) => {
let payload = {
...fromdata, projectId,
};
if (BranchToEdit) {
const editPayload = { ...payload, id: data.id };
ServiceBranchUpdate({ id: data.id, payload: editPayload });
} else {
CreateServiceBranch(payload);
}
};
return (
<div className="container p-3">
<h5 className="m-0">
{BranchToEdit
? "Update Branch"
: "Create Branch"}
</h5>
<form onSubmit={handleSubmit(onSubmit)}>
<div className="row my-2 text-start">
<div className="col-md-6">
<Label htmlFor="branchName" className="form-label" required>
Branch Name
</Label>
<input
type="text"
id="branchName"
className="form-control form-control-sm"
{...register("branchName")}
placeholder="Enter Branch"
/>
{errors.branchName && (
<small className="danger-text">{errors.branchName.message}</small>
)}
</div>
<div className="col-md-6">
<Label htmlFor="contactInformation" className="form-label" required>
Contact Information
</Label>
<input
type="text"
id="contactInformation"
className="form-control form-control-sm"
{...register("contactInformation")}
/>
{errors.contactInformation && (
<small className="danger-text">{errors.contactInformation.message}</small>
)}
</div>
</div>
<div className="row my-2 text-start">
<div className="col-md-6">
<Label htmlFor="address" className="form-label" required>
Address
</Label>
<input
type="text"
id="address"
className="form-control form-control-sm"
{...register("address")}
/>
{errors.address && (
<small className="danger-text">{errors.address.message}</small>
)}
</div>
<div className="col-md-6">
<Label htmlFor="branchType" className="form-label" required>
Branch Type
</Label>
<input
type="text"
id="branchType"
className="form-control form-control-sm"
{...register("branchType")}
/>
{errors.branchType && (
<small className="danger-text">{errors.branchType.message}</small>
)}
</div>
</div>
<div className="row my-2 text-start">
<div className="col-md-6">
<Label htmlFor="googleMapUrl" className="form-label" required>
Google Map URL
</Label>
<input
type="text"
id="googleMapUrl"
className="form-control form-control-sm"
{...register("googleMapUrl")}
/>
{errors.googleMapUrl && (
<small className="danger-text">{errors.googleMapUrl.message}</small>
)}
</div>
</div>
<div className="d-flex justify-content-end gap-3">
<button
type="reset"
onClick={handleClose}
className="btn btn-label-secondary btn-sm mt-3"
>
Cancel
</button>
<button type="submit" className="btn btn-primary btn-sm mt-3">
Submit
</button>
</div>
</form>
</div>
)
}
export default ManageBranch

View File

@ -41,7 +41,8 @@ const ManageJob = ({ Job }) => {
control,
watch,
handleSubmit,
reset,setValue,
reset,
setValue,
formState: { errors },
} = methods;
@ -164,6 +165,7 @@ const ManageJob = ({ Job }) => {
dueDate: JobData.dueDate ?? null,
tags: JobData.tags ?? [],
statusId: JobData.status.id,
branchId : JobData?.projectBranch?.id
});
}, [JobData, Job, projectId]);
return (
@ -201,7 +203,7 @@ const ManageJob = ({ Job }) => {
/>
</div>
<div className="col-12 col-md-6 mb-2 mb-md-4">
<Label >Select Employee</Label>
<Label>Select Employee</Label>
<PmsEmployeeInputTag
control={control}
name="assignees"
@ -240,21 +242,20 @@ const ManageJob = ({ Job }) => {
name="tags"
label="Tag"
placeholder="Enter Tag"
/>
</div>
<div className="col-12 col-md-6 mb-2 mb-md-4">
<SelectFieldSearch
label="Select Branch"
placeholder="Select Branch"
required
value={watch("branchId")}
onChange={(val) => setValue("branchId", val)}
valueKey="id"
labelKey="branchName"
hookParams={[projectId,true,10,1]}
hookParams={[projectId, true, 10, 1]}
useFetchHook={useBranches}
isMultiple={false}
disabled={Job}
/>
</div>
<div className="col-12">

View File

@ -124,10 +124,16 @@ const ManageJobTicket = ({ Job }) => {
);
})()}
</div>
<div className="d-flex my-2">
<span className="fw-semibold">
{" "}
<i className="bx bx-buildings me-1"></i>Branch Name :
</span>
</div>
<div className="d-block mt-4 mb-3">
<div className="row align-items-start align-items-md-start gap-2 mb-1">
<div className="col-12 col-md-auto">
<small className="fs-6 fw-medium">Created By</small>
<small className="fs-6 ">Created By</small>
</div>
<div className="col d-flex flex-row align-items-center ">
<Avatar
@ -147,7 +153,7 @@ const ManageJobTicket = ({ Job }) => {
{data?.assignees?.length > 0 && (
<div className="row align-items-start align-items-md-start gap-2">
<div className="col-12 col-md-auto">
<small className="fs-6 fw-medium">Assigned To</small>
<small className="fs-6">Assigned To</small>
</div>
<div className="col">

View File

@ -1,162 +0,0 @@
import React, { useState } from 'react'
import GlobalModel from '../common/GlobalModel';
import ManageBranch from './ManageBranch';
import { Pagination } from 'swiper/modules';
import { useBranches } from '../../hooks/useServiceProject';
import { ITEMS_PER_PAGE } from '../../utils/constants';
import { useDebounce } from '../../utils/appUtils';
import { useParams } from 'react-router-dom';
const ServiceBranch = () => {
const [ManageServiceBranch, setManageServiceBranch] = useState({
IsOpen: null,
branchId: null,
});
const { projectId } = useParams();
const [search, setSearch] = useState("");
const [currentPage, setCurrentPage] = useState(1);
const debouncedSearch = useDebounce(search, 500);
const { data, isLoading, isError, error } = useBranches(
projectId,
true,
ITEMS_PER_PAGE,
currentPage,
debouncedSearch,
);
const paginate = (page) => {
if (page >= 1 && page <= (data?.totalPages ?? 1)) {
setCurrentPage(page);
}
};
const ServiceBranch = [
{
key: "branchName",
label: "Branch Name",
align: "text-start",
getValue: (e) => e?.branchName || "N/A",
},
];
return (
<div className="card h-100 table-responsive px-sm-4">
<div className="card-datatable" id="payment-request-table">
<div className="row align-items-center justify-content-end mt-3">
<div className="col-md-4 col-sm-12 text-md-end text-end">
<button
className="btn btn-sm btn-primary"
type="button"
onClick={() =>
setManageServiceBranch({
IsOpen: true,
branchId: null,
})
}
>
<i className="bx bx-plus-circle me-2"></i>
<span className="d-none d-md-inline-block">
Add Branch
</span>
</button>
</div>
</div>
<div className="mx-2">
{/* {Array.isArray(filteredData) && filteredData.length > 0 && ( */}
<table className="table border-top text-nowrap align-middle">
<thead>
<tr>
{ServiceBranch.map((col) => (
<th key={col.key} className={col.align}>
{col.label}
</th>
))}
<th className="text-center">Action</th>
</tr>
</thead>
<tbody>
{isLoading ? (
<tr>
<td colSpan={ServiceBranch.length + 1} className="text-center py-5">
Loading...
</td>
</tr>
) : isError ? (
<tr>
<td colSpan={ServiceBranch.length + 1} className="text-center py-5">
{error?.message || "Error loading branches"}
</td>
</tr>
) : data?.data?.length > 0 ? (
data.data.map((branch) => (
<tr key={branch.id}>
{ServiceBranch.map((col) => (
<td key={col.key} className={col.align}>
{col.getValue(branch)}
</td>
))}
<td className="text-center">
<i
className="bx bx-edit text-primary cursor-pointer"
onClick={() =>
setManageServiceBranch({
IsOpen: true,
branchId: branch.id,
})
}
/>
</td>
</tr>
))
) : (
<tr>
<td colSpan={ServiceBranch.length + 1} className="text-center py-5">
No Branch Found
</td>
</tr>
)}
</tbody>
</table>
{/* )} */}
{/* {!filteredData ||
filteredData.length === 0
&& (
<div className="d-flex justify-content-center align-items-center h-64">
{isError ? (<p>{error.message}</p>) : (<p>No Recurring Expense Found</p>)}
</div>
)} */}
</div>
{ManageServiceBranch.IsOpen && (
<GlobalModel
isOpen
size="lg"
closeModal={() =>
setManageServiceBranch({ IsOpen: null, branchId: null })
}
>
<ManageBranch
key={ManageServiceBranch.branchId ?? "new"}
closeModal={() =>
setManageServiceBranch({ IsOpen: null, branchId: null })
}
// requestToEdit={ManageServiceBranch.branchId}
/>
</GlobalModel>
)}
{/* <Pagination
currentPage={currentPage}
totalPages={data?.totalPages}
onPageChange={paginate}
/> */}
</div>
</div>
)
}
export default ServiceBranch

View File

@ -0,0 +1,95 @@
import React from 'react'
import { formatUTCToLocalTime } from '../../utils/dateUtils'
const ServiceProfile = ({data,setIsOpenModal}) => {
return (
<div className="card mb-4 h-100">
<div className="card-header text-start">
<h5 className="card-action-title mb-0 ps-1">
{" "}
<i className="fa fa-building rounded-circle text-primary"></i>
<span className="ms-2 fw-bold">Project Profile</span>
</h5>
</div>
<div className="card-body">
<ul className="list-unstyled my-3 ps-0 text-start">
<li className="d-flex mb-3">
<div className="d-flex align-items-start" style={{ minWidth: "150px" }}>
<i className="bx bx-cog"></i>
<span className="fw-medium mx-2 text-nowrap">Name:</span>
</div>
<div className="flex-grow-1 text-start text-wrap">
{data.name}
</div>
</li>
<li className="d-flex mb-3">
<div className="d-flex align-items-center" style={{ width: '150px' }}>
<i className="bx bx-fingerprint"></i>
<span className="fw-medium mx-2">Nick Name:</span>
</div>
<span>{data.shortName}</span>
</li>
<li className="d-flex mb-3">
<div className="d-flex align-items-center" style={{ width: '150px' }}>
<i className="bx bx-check"></i>
<span className="fw-medium mx-2">Assign Date:</span>
</div>
<span>
{data.assignedDate ? formatUTCToLocalTime(data.assignedDate) : "NA"}
</span>
</li>
<li className="d-flex mb-3">
<div className="d-flex align-items-center" style={{ width: '150px' }}>
<i className="bx bx-trophy"></i>
<span className="fw-medium mx-2">Status:</span>
</div>
<span>{data?.status.status}</span>
</li>
<li className="d-flex mb-3">
<div className="d-flex align-items-center" style={{ width: '150px' }}>
<i className="bx bx-user"></i>
<span className="fw-medium mx-2">Contact:</span>
</div>
<span>{data.contactName}</span>
</li>
<li className="d-flex mb-3">
{/* Label section with icon */}
<div className="d-flex align-items-start" style={{ minWidth: "150px" }}>
<i className="bx bx-flag mt-1"></i>
<span className="fw-medium mx-2 text-nowrap">Address:</span>
</div>
{/* Content section that wraps nicely */}
<div className="flex-grow-1 text-start text-wrap">
{data.address}
</div>
</li>
<li className="d-flex justify-content-center mt-4">
<a className="d-flex justify-content-center mt-4">
<button
type="button"
className="btn btn-sm btn-primary"
data-bs-toggle="modal"
data-bs-target="#edit-project-modal"
onClick={() => setIsOpenModal(true)}
>
Modify Details
</button>
</a>
</li>
</ul>
</div>
</div>
)
}
export default ServiceProfile

View File

@ -0,0 +1,183 @@
import React, { useEffect } from "react";
import { useProjectName } from "../../../hooks/useProjects";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import Label from "../../common/Label";
import {
useCreateBranch,
useServiceProjects,
useUpdateBranch,
} from "../../../hooks/useServiceProject";
import { useAppForm } from "../../../hooks/appHooks/useAppForm";
import { useParams } from "react-router-dom";
import { BranchSchema, defaultBranches } from "../ServiceProjectSchema";
const ManageBranch = ({ closeModal, BranchToEdit = null }) => {
const { data } = {};
const { projectId } = useParams();
const schema = BranchSchema();
const {
register,
control,
watch,
handleSubmit,
setValue,
reset,
formState: { errors },
} = useAppForm({
resolver: zodResolver(schema),
defaultValues: {
...defaultBranches,
projectId: projectId || "",
},
});
const handleClose = () => {
reset();
closeModal();
};
useEffect(() => {
if (BranchToEdit && data) {
reset({
branchName: data.branchName || "",
projectId: data.project?.id || projectId || "",
contactInformation: data.contactInformation || "",
address: data.address || "",
branchType: data.branchType || "",
googleMapUrl: data.googleMapUrl || "",
});
}
}, [data, reset]);
const { mutate: CreateServiceBranch, isPending: createPending } =
useCreateBranch(() => {
handleClose();
});
const { mutate: ServiceBranchUpdate, isPending } = useUpdateBranch(() =>
handleClose()
);
const onSubmit = (fromdata) => {
let payload = {
...fromdata,
projectId,
};
if (BranchToEdit) {
const editPayload = { ...payload, id: data.id };
ServiceBranchUpdate({ id: data.id, payload: editPayload });
} else {
CreateServiceBranch(payload);
}
};
return (
<div className="container p-3">
<h5 className="m-0">
{BranchToEdit ? "Update Branch" : "Create Branch"}
</h5>
<form onSubmit={handleSubmit(onSubmit)}>
<div className="row my-2 text-start">
<div className="col-md-6">
<Label htmlFor="branchName" className="form-label" required>
Branch Name
</Label>
<input
type="text"
id="branchName"
className="form-control form-control-sm"
{...register("branchName")}
placeholder="Enter Branch"
/>
{errors.branchName && (
<small className="danger-text">{errors.branchName.message}</small>
)}
</div>
<div className="col-md-6">
<Label htmlFor="contactInformation" className="form-label" required>
Contact Number
</Label>
<input
type="text"
id="contactInformation"
className="form-control form-control-sm"
{...register("contactInformation")}
/>
{errors.contactInformation && (
<small className="danger-text">
{errors.contactInformation.message}
</small>
)}
</div>
</div>
<div className="row my-2 text-start">
<div className="col-md-6">
<Label htmlFor="branchType" className="form-label" required>
Branch Type
</Label>
<input
type="text"
id="branchType"
className="form-control form-control-sm"
{...register("branchType")}
/>
{errors.branchType && (
<small className="danger-text">{errors.branchType.message}</small>
)}
</div>
<div className="col-md-6">
<Label htmlFor="googleMapUrl" className="form-label" required>
Google Map URL
</Label>
<input
type="text"
id="googleMapUrl"
className="form-control form-control-sm"
{...register("googleMapUrl")}
/>
{errors.googleMapUrl && (
<small className="danger-text">
{errors.googleMapUrl.message}
</small>
)}
</div>
</div>
<div className="row my-2 text-start">
<div className="col-12">
<Label htmlFor="address" className="form-label" required>
Address
</Label>
<textarea
id="address"
className="form-control form-control-sm"
{...register("address")}
/>
{errors.address && (
<small className="danger-text">{errors.address.message}</small>
)}
</div>
</div>
<div className="d-flex justify-content-end gap-3">
<button
type="reset"
onClick={handleClose}
className="btn btn-label-secondary btn-sm mt-3"
>
Cancel
</button>
<button type="submit" className="btn btn-primary btn-sm mt-3">
{isPending ? "Please wait...":"Submit"}
</button>
</div>
</form>
</div>
);
};
export default ManageBranch;

View File

@ -0,0 +1,174 @@
import React, { useState } from "react";
import GlobalModel from "../../common/GlobalModel";
import ManageBranch from "./ManageBranch";
import { useBranches } from "../../../hooks/useServiceProject";
import { ITEMS_PER_PAGE } from "../../../utils/constants";
import { useDebounce } from "../../../utils/appUtils";
import { useParams } from "react-router-dom";
import Pagination from "../../common/Pagination";
const ServiceBranch = () => {
const { projectId } = useParams();
const [manageState, setManageState] = useState({
IsOpen: false,
branchId: null,
});
const [search, setSearch] = useState("");
const [currentPage, setCurrentPage] = useState(1);
const debouncedSearch = useDebounce(search, 500);
const { data, isLoading, isError, error } = useBranches(
projectId,
true,
ITEMS_PER_PAGE - 10,
currentPage,
debouncedSearch
);
const paginate = (page) => {
if (page >= 1 && page <= (data?.totalPages ?? 1)) {
setCurrentPage(page);
}
};
const columns = [
{
key: "branchName",
label: "Name",
align: "text-start",
getValue: (e) => e?.branchName || "N/A",
},
];
return (
<div className="card h-100 table-responsive px-sm-4">
<div className="card-datatable" id="payment-request-table">
{/* Header Section */}
<div className="row align-items-center justify-content-between mt-3 mx-1">
<div className="col-md-6 col-sm-12 text-start">
<h5 className="mb-0">
<i className="bx bx-buildings text-primary me-2"></i>
Branches
</h5>
</div>
<div className="col-md-3 col-sm-12 text-end">
<button
className="btn btn-sm btn-primary"
type="button"
onClick={() =>
setManageState({
IsOpen: true,
branchId: null,
})
}
>
<i className="bx bx-sm bx-plus-circle me-2"></i>
<span className="d-none d-md-inline-block">Add Branch</span>
</button>
</div>
</div>
<div className="mx-2 mt-3">
<table className="table border-top text-nowrap align-middle table-borderless">
<thead>
<tr>
{columns.map((col) => (
<th key={col.key} className={col.align}>
{col.label}
</th>
))}
<th className="text-center">Action</th>
</tr>
</thead>
<tbody>
{isLoading && (
<tr>
<td colSpan={columns.length + 1} className="text-center py-5">
Loading...
</td>
</tr>
)}
{isError && (
<tr>
<td
colSpan={columns.length + 1}
className="text-center text-danger py-5"
>
{error?.message || "Error loading branches"}
</td>
</tr>
)}
{!isLoading &&
!isError &&
data?.data?.length > 0 &&
data.data.map((branch) => (
<tr key={branch.id}>
{columns.map((col) => (
<td key={col.key} className={`${col.align} py-3`}>
{col.getValue(branch)}
</td>
))}
<td className="text-center">
<i
className="bx bx-edit text-primary cursor-pointer"
onClick={() =>
setManageState({
IsOpen: true,
branchId: branch.id,
})
}
/>
</td>
</tr>
))}
{!isLoading &&
!isError &&
(!data?.data || data.data.length === 0) && (
<tr>
<td
colSpan={columns.length + 1}
className="text-center py-12"
>
No Branch Found
</td>
</tr>
)}
</tbody>
</table>
{data?.data?.length > 0 && (
<Pagination
currentPage={currentPage}
totalPages={data.totalPages}
onPageChange={paginate}
/>
)}
</div>
{manageState.IsOpen && (
<GlobalModel
isOpen
size="md"
closeModal={() => setManageState({ IsOpen: false, branchId: null })}
>
<ManageBranch
key={manageState.branchId ?? "new"}
closeModal={() =>
setManageState({ IsOpen: false, branchId: null })
}
/>
</GlobalModel>
)}
</div>
</div>
);
};
export default ServiceBranch;

View File

@ -5,17 +5,26 @@ import { formatUTCToLocalTime } from "../../utils/dateUtils";
import ManageServiceProject from "./ManageServiceProject";
import GlobalModel from "../common/GlobalModel";
import { SpinnerLoader } from "../common/Loader";
import ServiceBranch from "./ServiceBranch";
import ServiceBranch from "./ServiceProjectBranch/ServiceBranch";
import ServiceProfile from "./ServiceProfile";
const ServiceProjectProfile = () => {
const { projectId } = useParams();
const [IsOpenModal, setIsOpenModal] = useState(false);
const { data, isLoading, isError, error } = useServiceProject(projectId);
if (isLoading) return <div className="py-8"><SpinnerLoader/></div>
if (isLoading)
return (
<div className="py-8">
<SpinnerLoader />
</div>
);
return (
<>
{IsOpenModal && (
<GlobalModel isOpen={IsOpenModal} closeModal={() => setIsOpenModal(false)}>
<GlobalModel
isOpen={IsOpenModal}
closeModal={() => setIsOpenModal(false)}
>
<ManageServiceProject
serviceProjectId={projectId}
onClose={() => setIsOpenModal(false)}
@ -25,101 +34,12 @@ const ServiceProjectProfile = () => {
<div className="row py-2">
<div className="col-md-6 col-lg-4 order-2 mb-6">
<div className="card mb-4">
<div className="card-header text-start">
<h5 className="card-action-title mb-0 ps-1">
{" "}
<i className="fa fa-building rounded-circle text-primary"></i>
<span className="ms-2 fw-bold">Project Profile</span>
</h5>
</div>
<div className="card-body">
<ul className="list-unstyled my-3 ps-0 text-start">
<li className="d-flex mb-3">
<div className="d-flex align-items-start" style={{ minWidth: "150px" }}>
<i className="bx bx-cog"></i>
<span className="fw-medium mx-2 text-nowrap">Name:</span>
</div>
{/* Content section that wraps nicely */}
<div className="flex-grow-1 text-start text-wrap">
{data.name}
</div>
</li>
<li className="d-flex mb-3">
<div className="d-flex align-items-center" style={{ width: '150px' }}>
<i className="bx bx-fingerprint"></i>
<span className="fw-medium mx-2">Nick Name:</span>
</div>
<span>{data.shortName}</span>
</li>
<li className="d-flex mb-3">
<div className="d-flex align-items-center" style={{ width: '150px' }}>
<i className="bx bx-check"></i>
<span className="fw-medium mx-2">Assign Date:</span>
</div>
<span>
{data.assignedDate ? formatUTCToLocalTime(data.assignedDate) : "NA"}
</span>
</li>
<li className="d-flex mb-3">
<div className="d-flex align-items-center" style={{ width: '150px' }}>
<i className="bx bx-trophy"></i>
<span className="fw-medium mx-2">Status:</span>
</div>
<span>{data?.status.status}</span>
</li>
<li className="d-flex mb-3">
<div className="d-flex align-items-center" style={{ width: '150px' }}>
<i className="bx bx-user"></i>
<span className="fw-medium mx-2">Contact:</span>
</div>
<span>{data.contactName}</span>
</li>
<li className="d-flex mb-3">
{/* Label section with icon */}
<div className="d-flex align-items-start" style={{ minWidth: "150px" }}>
<i className="bx bx-flag mt-1"></i>
<span className="fw-medium mx-2 text-nowrap">Address:</span>
</div>
{/* Content section that wraps nicely */}
<div className="flex-grow-1 text-start text-wrap">
{data.address}
</div>
</li>
<li className="d-flex justify-content-center mt-4"> {/* Added mt-4 for some top margin */}
<a className="d-flex justify-content-center mt-4"> {/* Added mt-4 for some top margin */}
<button
type="button"
className="btn btn-sm btn-primary"
data-bs-toggle="modal"
data-bs-target="#edit-project-modal"
onClick={() => setIsOpenModal(true)}
>
Modify Details
</button>
</a>
</li>
</ul>
</div>
</div>
<ServiceProfile data={data} setIsOpenModal={setIsOpenModal}/>
</div>
<div className="col-md-6 col-lg-8 order-2 mb-6">
<ServiceBranch/>
<ServiceBranch />
</div>
</div>
</>
);

View File

@ -50,6 +50,10 @@ export const defaultProjectValues = {
//#endregion
//#region JobSchema
export const TagSchema = z.object({
@ -115,3 +119,54 @@ export const defaultJobValue = {
};
//#endregion
//#region Branch
export const BranchSchema = () =>
z.object({
projectId: z
.string()
.trim()
.min(1, { message: "Project is required" }),
branchName: z
.string()
.trim()
.min(1, { message: "Branch Name is required" }),
contactInformation: z
.string()
.trim()
.min(1, { message: "Contact Information is required" }),
address: z
.string()
.trim()
.min(1, { message: "Address is required" }),
branchType: z
.string()
.trim()
.min(1, { message: "Branch Type is required" }),
googleMapUrl: z
.string()
.trim()
.url({ message: "Enter a valid Google Map URL" }),
});
export const defaultBranches = {
branchName: "",
projectId: "",
contactInformation: "",
address: "",
branchType: "",
googleMapUrl: "",
};
//#endregion

View File

@ -104,8 +104,7 @@ const SubScriptionHistory = ({ tenantId }) => {
</button>
<button
className="dropdown-item py-1"
onClick={() =>
console.log("Download clicked for", item.id)
onClick={() =>{}
}
>
<i className="bx bx-cloud-download bx-sm"></i> Download

View File

@ -93,11 +93,9 @@ const TenantForm = () => {
};
const onSubmitTenant = (data) => {
console.log("Tenant Data:", data);
};
const onSubmitSubScription = (data) => {
console.log("Subscription Data:", data);
};
const newTenantConfig = [

View File

@ -362,8 +362,6 @@ export const SelectProjectField = ({
);
};
export const SelectFieldSearch = ({
label = "Select",
placeholder = "Select ",
@ -372,7 +370,7 @@ export const SelectFieldSearch = ({
onChange,
valueKey = "id",
labelKey = "name",
disabled = false,
isFullObject = false,
isMultiple = false,
hookParams,
@ -381,7 +379,7 @@ export const SelectFieldSearch = ({
const [searchText, setSearchText] = useState("");
const debounce = useDebounce(searchText, 300);
const { data, isLoading } = useFetchHook(...hookParams,debounce);
const { data, isLoading } = useFetchHook(...hookParams, debounce);
const options = data?.data ?? [];
const [open, setOpen] = useState(false);
const dropdownRef = useRef(null);
@ -434,6 +432,36 @@ export const SelectFieldSearch = ({
return () => document.removeEventListener("mousedown", handleClickOutside);
}, []);
// MERGED OPTIONS TO ENSURE SELECTED VALUE APPEARS EVEN IF NOT IN SEARCH RESULT
const [mergedOptions, setMergedOptions] = useState([]);
useEffect(() => {
let finalList = [...options];
if (!isMultiple && value && !isFullObject) {
// already selected option inside options?
const exists = options.some((o) => o[valueKey] === value);
// if selected item not found, try to get from props (value) as fallback
if (!exists && typeof value === "object") {
finalList.unshift(value);
}
}
if (isMultiple && Array.isArray(value)) {
value.forEach((val) => {
const id = isFullObject ? val[valueKey] : val;
const exists = options.some((o) => o[valueKey] === id);
if (!exists && typeof val === "object") {
finalList.unshift(val);
}
});
}
setMergedOptions(finalList);
}, [options, value]);
/** -----------------------------
* HANDLE SELECT
* ----------------------------- */
@ -472,9 +500,10 @@ export const SelectFieldSearch = ({
{/* MAIN BUTTON */}
<button
type="button"
className={`select2-icons form-select d-flex align-items-center justify-content-between ${
className={`select2-icons form-select d-flex align-items-center justify-content-between ${
open ? "show" : ""
}`}
disabled={disabled}
onClick={() => setOpen((prev) => !prev)}
>
<span className={`text-truncate ${!displayText ? "text-muted" : ""}`}>
@ -503,6 +532,7 @@ export const SelectFieldSearch = ({
onChange={(e) => setSearchText(e.target.value)}
className="form-control form-control-sm"
placeholder="Search..."
disabled={disabled}
/>
</div>

View File

@ -28,7 +28,6 @@ const CommentEditor = () => {
const [value, setValue] = useState("");
const handleSubmit = () => {
console.log("Comment:", value);
// Submit or handle content
};

View File

@ -411,7 +411,6 @@ export const useUpdateProject = (onSuccessCallback) => {
},
onError: (error) => {
console.log(error);
showToast(error?.message || "Error while updating project", "error");
},
});

View File

@ -308,7 +308,6 @@ export const useBranches = (
pageNumber,
searchString
);
console.log(resp)
return resp.data;
},
enabled: !!projectId,