Compare commits
No commits in common. "a1a935b0d5be911147f25a446d78ef4ed82ed4f1" and "1a88f5fec52f9d2c054b9c326646470a643270d2" have entirely different histories.
a1a935b0d5
...
1a88f5fec5
775
package-lock.json
generated
775
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg width="800px" height="800px" viewBox="0 0 120 120" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="120" height="120" fill="#EFF1F3"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M33.2503 38.4816C33.2603 37.0472 34.4199 35.8864 35.8543 35.875H83.1463C84.5848 35.875 85.7503 37.0431 85.7503 38.4816V80.5184C85.7403 81.9528 84.5807 83.1136 83.1463 83.125H35.8543C34.4158 83.1236 33.2503 81.957 33.2503 80.5184V38.4816ZM80.5006 41.1251H38.5006V77.8751L62.8921 53.4783C63.9172 52.4536 65.5788 52.4536 66.6039 53.4783L80.5006 67.4013V41.1251ZM43.75 51.6249C43.75 54.5244 46.1005 56.8749 49 56.8749C51.8995 56.8749 54.25 54.5244 54.25 51.6249C54.25 48.7254 51.8995 46.3749 49 46.3749C46.1005 46.3749 43.75 48.7254 43.75 51.6249Z" fill="#687787"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 888 B |
@ -11,7 +11,6 @@ import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { assignedOrgToProject } from "./OrganizationSchema";
|
||||
import {
|
||||
useAssignOrgToProject,
|
||||
useAssignOrgToTenant,
|
||||
useOrganizationModal,
|
||||
} from "../../hooks/useOrganization";
|
||||
|
||||
@ -25,73 +24,56 @@ const AssignOrg = ({ setStep }) => {
|
||||
useProjectAssignedServices(selectedProject);
|
||||
const { data: orgType, isLoading: orgLoading } = useOrganizationType();
|
||||
|
||||
const { mutate: AssignToProject, isPending: isPendingProject } =
|
||||
useAssignOrgToProject(() => onClose());
|
||||
const { mutate: AssignToTenant, isPending: isPendingTenat } =
|
||||
useAssignOrgToTenant(() => {
|
||||
onClose();
|
||||
});
|
||||
const isPending = isPendingProject || isPendingTenat;
|
||||
const { mutate: AssignToProject, isPending } = useAssignOrgToProject(() =>
|
||||
onClose()
|
||||
);
|
||||
|
||||
const mergedServices = useMemo(() => {
|
||||
if (!masterService || !projectServices) return [];
|
||||
|
||||
const combined = [...masterService?.data, ...projectServices];
|
||||
return combined.filter(
|
||||
|
||||
const unique = combined.filter(
|
||||
(item, index, self) => index === self.findIndex((s) => s.id === item.id)
|
||||
);
|
||||
}, [masterService, projectServices]);
|
||||
|
||||
const resolver =
|
||||
flowType === "default" ? undefined : zodResolver(assignedOrgToProject);
|
||||
return unique;
|
||||
}, [masterService, projectServices]);
|
||||
|
||||
const {
|
||||
register,
|
||||
handleSubmit,
|
||||
setValue,
|
||||
handleSubmit,
|
||||
formState: { errors },
|
||||
} = useForm({
|
||||
resolver,
|
||||
defaultValues: {
|
||||
organizationTypeId: "",
|
||||
serviceIds: [],
|
||||
},
|
||||
resolver: zodResolver(assignedOrgToProject),
|
||||
});
|
||||
|
||||
const onSubmit = (formData) => {
|
||||
if (flowType === "default") {
|
||||
const payload = orgData.id;
|
||||
|
||||
AssignToTenant(payload);
|
||||
} else {
|
||||
const payload = {
|
||||
...formData,
|
||||
projectId: selectedProject,
|
||||
organizationId: orgData.id,
|
||||
parentOrganizationId: null,
|
||||
};
|
||||
AssignToProject(payload);
|
||||
}
|
||||
const payload = {
|
||||
...formData,
|
||||
projectId: selectedProject,
|
||||
organizationId: orgData.id,
|
||||
parentOrganizationId: null,
|
||||
};
|
||||
AssignToProject(payload);
|
||||
};
|
||||
|
||||
const handleEdit = () => {
|
||||
onOpen({ startStep: 4, orgData });
|
||||
onOpen({ startStep: 4, orgData: orgData });
|
||||
};
|
||||
|
||||
const handleBack = () => {
|
||||
if (prevStep === 1 && flowType === "assign") {
|
||||
if (prevStep == 1 && flowType == "assign") {
|
||||
onOpen({ startStep: prevStep });
|
||||
} else if (prevStep === 1 && flowType !== "assign") {
|
||||
} else if (prevStep == 1 && flowType == "assign") {
|
||||
onOpen({ startStep: 1 });
|
||||
} else {
|
||||
onOpen({ startStep: 2 });
|
||||
}
|
||||
};
|
||||
|
||||
if (isMasterserviceLoading || isLoading)
|
||||
return <div className="text-center">Loading....</div>;
|
||||
|
||||
return (
|
||||
<div className="row text-black text-start mb-3">
|
||||
{/* Organization Info Display */}
|
||||
<div className="row text-black mb-3">
|
||||
<div className="col-12 mb-3">
|
||||
<div className="d-flex justify-content-between align-items-center text-start mb-2">
|
||||
<div className="fw-semibold text-wrap">{orgData.name}</div>
|
||||
@ -107,22 +89,21 @@ const AssignOrg = ({ setStep }) => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Contact Info */}
|
||||
<div className="col-md-6 mb-3">
|
||||
<div className="d-flex">
|
||||
<label
|
||||
className="form-label me-2 mb-0 fw-semibold"
|
||||
className="form-label me-2 mb-0 fw-semibold text-start"
|
||||
style={{ minWidth: "130px" }}
|
||||
>
|
||||
Contact Person :
|
||||
Constact Person :
|
||||
</label>
|
||||
<div className="text-muted">{orgData.contactPerson}</div>
|
||||
<div className="text-muted">{orgData.name}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-md-6 mb-3">
|
||||
<div className="d-flex">
|
||||
<label
|
||||
className="form-label me-2 mb-0 fw-semibold"
|
||||
className="form-label me-2 mb-0 fw-semibold text-start"
|
||||
style={{ minWidth: "130px" }}
|
||||
>
|
||||
Contact Number :
|
||||
@ -133,7 +114,7 @@ const AssignOrg = ({ setStep }) => {
|
||||
<div className="col-md-6 mb-3">
|
||||
<div className="d-flex">
|
||||
<label
|
||||
className="form-label me-2 mb-0 fw-semibold"
|
||||
className="form-label me-2 mb-0 fw-semibold text-start"
|
||||
style={{ minWidth: "130px" }}
|
||||
>
|
||||
Email Address :
|
||||
@ -144,7 +125,7 @@ const AssignOrg = ({ setStep }) => {
|
||||
<div className="col-12 mb-3">
|
||||
<div className="d-flex">
|
||||
<label
|
||||
className="form-label me-2 mb-0 fw-semibold"
|
||||
className="form-label me-2 mb-0 fw-semibold text-start text-wrap"
|
||||
style={{ maxWidth: "130px" }}
|
||||
>
|
||||
Service provider Id (SPRID) :
|
||||
@ -152,10 +133,11 @@ const AssignOrg = ({ setStep }) => {
|
||||
<div className="text-muted">{orgData.sprid}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="col-12 mb-3">
|
||||
<div className="d-flex">
|
||||
<label
|
||||
className="form-label me-1 mb-0 fw-semibold"
|
||||
className="form-label me-1 mb-0 fw-semibold text-start"
|
||||
style={{ minWidth: "130px" }}
|
||||
>
|
||||
Address :
|
||||
@ -164,72 +146,68 @@ const AssignOrg = ({ setStep }) => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Form */}
|
||||
<div className="text-black text-start">
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
{/* Show fields only if flowType is NOT default */}
|
||||
{flowType !== "default" && (
|
||||
<>
|
||||
{/* Organization Type */}
|
||||
<div className="mb-1 text-start">
|
||||
<Label htmlFor="organizationTypeId" required>
|
||||
Organization Type
|
||||
</Label>
|
||||
<div className="d-flex flex-wrap gap-3 mt-1">
|
||||
{orgType?.data.map((type) => (
|
||||
<div
|
||||
key={type.id}
|
||||
className="form-check d-flex align-items-center gap-2 p-0 m-0"
|
||||
>
|
||||
<input
|
||||
type="radio"
|
||||
id={`organizationType-${type.id}`}
|
||||
value={type.id}
|
||||
{...register("organizationTypeId")}
|
||||
className="form-check-input m-0"
|
||||
/>
|
||||
<label
|
||||
className="form-check-label m-0"
|
||||
htmlFor={`organizationType-${type.id}`}
|
||||
>
|
||||
{type.name}
|
||||
</label>
|
||||
</div>
|
||||
))}
|
||||
<div className="mb-1 text-start">
|
||||
<Label htmlFor="organizationTypeId" required>
|
||||
Organization Type
|
||||
</Label>
|
||||
|
||||
<div className="d-flex flex-wrap gap-3 mt-1">
|
||||
{orgType?.data.map((type) => (
|
||||
<div
|
||||
key={type.id}
|
||||
className="form-check d-flex align-items-center gap-2 p-0 m-0"
|
||||
>
|
||||
<input
|
||||
type="radio"
|
||||
id={`organizationType-${type.id}`}
|
||||
value={type.id}
|
||||
{...register("organizationTypeId", {
|
||||
required: "Please select an organization type",
|
||||
})}
|
||||
className="form-check-input m-0"
|
||||
/>
|
||||
<label
|
||||
className="form-check-label m-0"
|
||||
htmlFor={`organizationType-${type.id}`}
|
||||
>
|
||||
{type.name}
|
||||
</label>
|
||||
</div>
|
||||
{errors.organizationTypeId && (
|
||||
<span className="text-danger">
|
||||
{errors.organizationTypeId.message}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Services */}
|
||||
<div className="mb-3">
|
||||
<Label htmlFor="serviceIds" required>
|
||||
Select Services
|
||||
</Label>
|
||||
{mergedServices?.map((service) => (
|
||||
<div key={service.id} className="form-check">
|
||||
<input
|
||||
type="checkbox"
|
||||
value={service.id}
|
||||
{...register("serviceIds")}
|
||||
className="form-check-input"
|
||||
/>
|
||||
<label className="form-check-label">{service.name}</label>
|
||||
</div>
|
||||
))}
|
||||
{errors.serviceIds && (
|
||||
<div className="text-danger small">
|
||||
{errors.serviceIds.message}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{errors.organizationTypeId && (
|
||||
<span className="danger-text">
|
||||
{errors.organizationTypeId.message}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Buttons: Always visible */}
|
||||
<div className="mb-3">
|
||||
<Label htmlFor="serviceId" required>
|
||||
Select Services
|
||||
</Label>
|
||||
{mergedServices?.map((service) => (
|
||||
<div key={service.id} className="form-check">
|
||||
<input
|
||||
type="checkbox"
|
||||
value={service.id}
|
||||
{...register("serviceIds")}
|
||||
className="form-check-input"
|
||||
/>
|
||||
<label className="form-check-label">{service.name}</label>
|
||||
</div>
|
||||
))}
|
||||
{errors.serviceIds && (
|
||||
<div className="text-danger small">
|
||||
{errors.serviceIds.message}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Buttons */}
|
||||
<div className="d-flex justify-content-between mt-3">
|
||||
<button
|
||||
type="button"
|
||||
@ -244,11 +222,7 @@ const AssignOrg = ({ setStep }) => {
|
||||
className="btn btn-sm btn-primary"
|
||||
disabled={isPending}
|
||||
>
|
||||
{isPending
|
||||
? "Please wait..."
|
||||
: flowType === "default"
|
||||
? "Assign Organization"
|
||||
: "Add"}
|
||||
{isPending ? "Please wait..." : "Add"}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@ -14,8 +14,7 @@ import { OrgCardSkeleton } from "./OrganizationSkeleton";
|
||||
// Zod schema: only allow exactly 4 digits
|
||||
|
||||
const OrgPickerFromSPId = ({ title, placeholder }) => {
|
||||
const { onClose, startStep, flowType, onOpen, prevStep } =
|
||||
useOrganizationModal();
|
||||
const {onClose, startStep, flowType, onOpen,prevStep } = useOrganizationModal();
|
||||
|
||||
const {
|
||||
register,
|
||||
@ -36,7 +35,18 @@ const OrgPickerFromSPId = ({ title, placeholder }) => {
|
||||
setSPRID(formdata.spridSearchText);
|
||||
};
|
||||
|
||||
const handleOrg = (orgId) => {};
|
||||
const {mutate:AssignToTenant,isPending} = useAssignOrgToTenant(()=>{
|
||||
onClose()
|
||||
})
|
||||
const handleOrg=(orgId)=>{
|
||||
if(flowType == "default"){
|
||||
AssignToTenant(orgId)
|
||||
}else{
|
||||
debugger
|
||||
onOpen({ startStep: 3, orgData: org })
|
||||
}
|
||||
|
||||
}
|
||||
const SP = watch("spridSearchText");
|
||||
return (
|
||||
<div className="d-block">
|
||||
@ -44,20 +54,22 @@ const OrgPickerFromSPId = ({ title, placeholder }) => {
|
||||
className="d-flex flex-row gap-6 text-start align-items-center"
|
||||
onSubmit={handleSubmit(onSubmit)}
|
||||
>
|
||||
<div className="d-flex flex-row align-items-center gap-2">
|
||||
<Label className="text-secondary">Search by SPRID</Label>
|
||||
<div className="d-flex flex-column">
|
||||
<Label className="text-secondary">{title}</Label>
|
||||
<input
|
||||
type="search"
|
||||
{...register("spridSearchText")}
|
||||
className="form-control form-control-sm w-auto"
|
||||
placeholder="Enter SPRID"
|
||||
placeholder={placeholder || "Enter Service Provider ID"}
|
||||
maxLength={4}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<button type="submit" className="btn btn-sm btn-primary">
|
||||
<i className="bx bx-sm bx-search-alt-2"></i> Search
|
||||
</button>
|
||||
<div className="mt-4">
|
||||
<button type="submit" className="btn btn-sm btn-primary">
|
||||
<i className="bx bx-sm bx-search-alt-2"></i> Search
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
<div className="text-start danger-text">
|
||||
{" "}
|
||||
@ -75,32 +87,28 @@ const OrgPickerFromSPId = ({ title, placeholder }) => {
|
||||
<div className="py-2 text-tiny text-center">
|
||||
<div className="d-flex flex-column gap-2 border-0 bg-none">
|
||||
{data.data.map((org) => (
|
||||
<div className="d-flex flex-row gap-2 text-start text-black ">
|
||||
<div className="mt-1">
|
||||
<img
|
||||
src="/public/assets/img/SP-Placeholdeer.svg"
|
||||
alt="logo"
|
||||
width={50}
|
||||
height={50}
|
||||
/>
|
||||
<div
|
||||
key={org.id}
|
||||
className="list-group-item list-group-item-action d-flex align-items-center cursor-pointer border-0 hover-overlay shadow-1-strong rounded"
|
||||
>
|
||||
<div className="d-flex align-items-center justify-content-center me-3">
|
||||
<i className="bx bx-building-house bx-md text-primary"></i>
|
||||
</div>
|
||||
<div
|
||||
className="d-flex flex-column p-0 m-0 cursor-pointer"
|
||||
onClick={() => onOpen({ startStep: 3, orgData: org })}
|
||||
>
|
||||
<span className="fs-6 fw-semibold">{org.name}</span>
|
||||
<div className="d-flex gap-2">
|
||||
<small
|
||||
className=" fw-semibold text-uppercase"
|
||||
style={{ letterSpacing: "1px" }}
|
||||
>
|
||||
SPRID :{" "}
|
||||
</small>
|
||||
<small className="fs-6">{org.sprid}</small>
|
||||
</div>
|
||||
<div className="d-flex flex-row gap-2">
|
||||
<small className="text-small fw-semibold">Address:</small>
|
||||
<div className="d-flex text-wrap">{org.address}</div>
|
||||
|
||||
<div className="w-100">
|
||||
<div className="d-flex justify-content-between cursor-pointer">
|
||||
<div className="user-info text-start">
|
||||
<h6 className="mb-1 fw-normal">{org.name}</h6>
|
||||
</div>
|
||||
<div className="add-btn">
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-primary btn-sm"
|
||||
onClick={()=>handleOrg(org.id)}
|
||||
>
|
||||
{isPending ? "Please Wait..." : flowType === "assign" ? "Select":`Add`}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -111,32 +119,38 @@ const OrgPickerFromSPId = ({ title, placeholder }) => {
|
||||
<div className="py-3 text-center text-secondary">
|
||||
No organization found for "{SPRID}"
|
||||
</div>
|
||||
) : null}
|
||||
<div className="py-12 text-center text-tiny text-black">
|
||||
<small className="d-block text-secondary">
|
||||
Do not have SPRID or could not find organization ?
|
||||
</small>
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-sm btn-primary mt-3"
|
||||
onClick={() => onOpen({ startStep: 4 })}
|
||||
>
|
||||
<i className="bx bx-plus-circle me-2"></i>
|
||||
Create New Organization
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
<div className="py-12 text-center text-tiny text-black">
|
||||
Type a Service Provider ID to find an organization.
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* ---- Footer buttons ---- */}
|
||||
<div className={`d-flex text-secondary mt-3`}>
|
||||
<div
|
||||
className={`d-flex ${
|
||||
flowType !== "default"
|
||||
? "justify-content-between"
|
||||
: "justify-content-end"
|
||||
} text-secondary mt-3`}
|
||||
>
|
||||
{flowType !== "default" && (
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-xs btn-outline-secondary"
|
||||
onClick={() => onOpen({ startStep: prevStep })}
|
||||
>
|
||||
<i className="bx bx-chevron-left"></i> Back
|
||||
<i className='bx bx-chevron-left'></i> Back
|
||||
</button>
|
||||
)}
|
||||
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-sm btn-secondary"
|
||||
onClick={() => onOpen({ startStep: 4 })}
|
||||
>
|
||||
<i className="bx bx-plus-circle me-2"></i>
|
||||
Add New Organization
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -11,7 +11,7 @@ const OrgPickerfromTenant = ({ title }) => {
|
||||
const [searchText, setSearchText] = useState("");
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
const { data, isLoading } = useOrganizationsList(
|
||||
ITEMS_PER_PAGE - 10,
|
||||
ITEMS_PER_PAGE-10,
|
||||
1,
|
||||
true,
|
||||
null,
|
||||
@ -36,38 +36,6 @@ const OrgPickerfromTenant = ({ title }) => {
|
||||
}
|
||||
};
|
||||
|
||||
const contactList = [
|
||||
{
|
||||
key: "name",
|
||||
label: "Name",
|
||||
getValue: (org) => (
|
||||
<div className="d-flex gap-2 py-1 ">
|
||||
<i class="bx bx-buildings"></i>
|
||||
<span
|
||||
className="text-truncate d-inline-block "
|
||||
style={{ maxWidth: "150px" }}
|
||||
>
|
||||
{org?.name || "N/A"}
|
||||
</span>
|
||||
</div>
|
||||
),
|
||||
align: "text-start",
|
||||
},
|
||||
{
|
||||
key: "sprid",
|
||||
label: "SPRID",
|
||||
getValue: (org) => (
|
||||
<span
|
||||
className="text-truncate d-inline-block"
|
||||
style={{ maxWidth: "200px" }}
|
||||
>
|
||||
{org?.sprid || "N/A"}
|
||||
</span>
|
||||
),
|
||||
align: "text-center",
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="d-block">
|
||||
<div className="text-start mb-1">
|
||||
@ -82,60 +50,72 @@ const OrgPickerfromTenant = ({ title }) => {
|
||||
</div>
|
||||
|
||||
{/* ---- Organization list ---- */}
|
||||
{isLoading ? (
|
||||
<div>Loading....</div>
|
||||
) : data && data?.data?.length > 0 ? (
|
||||
<div className="dataTables_wrapper no-footer pb-2">
|
||||
<table className="table dataTable text-nowrap">
|
||||
<thead>
|
||||
<tr className="table_header_border">
|
||||
{contactList.map((col) => (
|
||||
<th key={col.key} className={col.align}>
|
||||
{col.label}
|
||||
</th>
|
||||
))}
|
||||
<th className="sticky-action-column bg-white text-center">
|
||||
Action
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{Array.isArray(data.data) && data.data.length > 0
|
||||
? data.data.map((row, i) => (
|
||||
<tr key={i}>
|
||||
{contactList.map((col) => (
|
||||
<td key={col.key} className={col.align}>
|
||||
{col.getValue(row)}
|
||||
</td>
|
||||
))}
|
||||
<td className="sticky-action-column bg-white">
|
||||
<button
|
||||
className="btn btn-sm btn-primary"
|
||||
onClick={() => onOpen({ startStep: 3, orgData: row })}
|
||||
>
|
||||
Select
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
))
|
||||
: null}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
) : null}
|
||||
<div className="d-flex flex-column align-items-center text-center text-wrap text-black gap-2">
|
||||
<small className="mb-1">
|
||||
Could not find organization in your database? Please search within the
|
||||
global database.
|
||||
</small>
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-sm btn-primary w-auto"
|
||||
onClick={() => onOpen({ startStep: 2 })}
|
||||
{isLoading ? (
|
||||
<div>Loading....</div>
|
||||
) : data && data?.data?.length > 0 ? (
|
||||
<div className="py-2 text-tiny text-center">
|
||||
<div className="d-flex flex-column gap-2 border-0 bg-none">
|
||||
{data?.data?.map((org) => (
|
||||
<div
|
||||
key={org.id}
|
||||
className="list-group-item list-group-item-action d-flex align-items-center cursor-pointer border-0 hover-overlay border-bottom rounded-none pb-1 shadow-1-strong rounded"
|
||||
>
|
||||
Search Using SPRID
|
||||
</button>
|
||||
<div className="d-flex align-items-center justify-content-center me-3">
|
||||
<i className="bx bx-building-house bx-md text-primary"></i>
|
||||
</div>
|
||||
|
||||
<div className="w-100">
|
||||
<div className="d-flex justify-content-between cursor-pointer">
|
||||
<div className="user-info text-start">
|
||||
<h6 className="mb-1 fw-normal">{org.name}</h6>
|
||||
</div>
|
||||
<div className="add-btn">
|
||||
<button
|
||||
className="btn btn-primary btn-sm"
|
||||
onClick={() => onOpen({ startStep: 3, orgData: org })}
|
||||
>
|
||||
select
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
|
||||
<div className="d-flex text-end">
|
||||
{data?.data?.length > 0 && (
|
||||
<Pagination
|
||||
currentPage={currentPage}
|
||||
totalPages={data.totalPages}
|
||||
onPageChange={paginate}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{startStep !== 2 && (
|
||||
<div className="mt-4">
|
||||
<p className="text-secondary">
|
||||
Don't have required organization, Please find using{" "}
|
||||
<span
|
||||
className="text-mutes cursor-pointer text-decoration-underline"
|
||||
onClick={() => {
|
||||
onOpen({ startStep: 2 });
|
||||
}}
|
||||
>
|
||||
SPRID
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<div>Not found Organization</div>
|
||||
)}
|
||||
|
||||
|
||||
|
||||
|
||||
{/* ---- Footer buttons ---- */}
|
||||
<div
|
||||
className={`d-flex justify-content-end
|
||||
@ -151,14 +131,14 @@ const OrgPickerfromTenant = ({ title }) => {
|
||||
</button>
|
||||
)}
|
||||
|
||||
{/* <button
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-sm btn-secondary"
|
||||
onClick={() => onOpen({ startStep: 4 })}
|
||||
>
|
||||
<i className="bx bx-plus-circle me-2"></i>
|
||||
Add New Organization
|
||||
</button> */}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -27,6 +27,7 @@ const OrganizationModal = () => {
|
||||
const [searchText, setSearchText] = useState();
|
||||
const [SPRID, setSPRID] = useState("");
|
||||
|
||||
|
||||
const [Organization, setOrganization] = useState({});
|
||||
|
||||
const method = useForm({
|
||||
@ -60,11 +61,11 @@ const OrganizationModal = () => {
|
||||
if (startStep === 1) {
|
||||
return orgData && orgData !== null
|
||||
? "Add Organization"
|
||||
: "Choose Organization1";
|
||||
: "Choose Organization";
|
||||
}
|
||||
|
||||
if (startStep === 2) {
|
||||
return "Add Organization";
|
||||
return "Choose Organization";
|
||||
}
|
||||
|
||||
if (startStep === 3) {
|
||||
@ -77,13 +78,20 @@ const OrganizationModal = () => {
|
||||
const contentBody = (
|
||||
<div>
|
||||
{/* ---------- STEP 1: Service Provider- Form Own Tenant list ---------- */}
|
||||
{startStep === 1 && <OrgPickerfromTenant title="Find Organization" />}
|
||||
{startStep === 1 && (
|
||||
<OrgPickerfromTenant
|
||||
title="Find Organization"
|
||||
|
||||
|
||||
/>
|
||||
)}
|
||||
|
||||
{startStep === 2 && (
|
||||
<OrgPickerFromSPId
|
||||
title="Find Organization"
|
||||
placeholder="Enter Service Provider Id"
|
||||
projectOrganizations={orgData}
|
||||
|
||||
/>
|
||||
)}
|
||||
|
||||
@ -93,7 +101,10 @@ const OrganizationModal = () => {
|
||||
)}
|
||||
|
||||
{/* ---------- STEP 3: Add New Organization ---------- */}
|
||||
{startStep === 4 && <ManagOrg />}
|
||||
{startStep === 4 && (
|
||||
|
||||
<ManagOrg />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
|
||||
@ -7,8 +7,8 @@ export const organizationSchema = z.object({
|
||||
contactNumber: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(7, { message: "Contact number must be at least 7 digits" })
|
||||
.max(20, { message: "Contact number cannot exceed 12 digits" })
|
||||
.min(7, { message: "Contact number must be at least 7 digits" })
|
||||
.max(20, { message: "Contact number cannot exceed 12 digits" })
|
||||
|
||||
.regex(phoneRegex, { message: "Invalid phone number" }),
|
||||
contactPerson: z.string().min(1, { message: "Person name required" }),
|
||||
@ -31,6 +31,7 @@ export const defaultOrganizationValues = {
|
||||
serviceIds: [],
|
||||
};
|
||||
|
||||
|
||||
export const assignedOrgToProject = z.object({
|
||||
// projectId: z.string().uuid({ message: "Invalid projectId format" }),
|
||||
// organizationId: z.string().string({ message: "Invalid organizationId format" }),
|
||||
@ -38,20 +39,19 @@ export const assignedOrgToProject = z.object({
|
||||
// .string()
|
||||
// .nullable()
|
||||
// .optional(),
|
||||
serviceIds: z.preprocess(
|
||||
serviceIds: z.preprocess(
|
||||
(val) => (Array.isArray(val) ? val : []),
|
||||
z
|
||||
.array(z.string().uuid({ message: "Invalid serviceId format" }))
|
||||
.nonempty({ message: "At least one service must be selected" })
|
||||
),
|
||||
|
||||
organizationTypeId: z
|
||||
.string()
|
||||
.min(1, { message: "Organization is required" }),
|
||||
|
||||
organizationTypeId: z.string().min(1,{ message: "Organization is required" }),
|
||||
});
|
||||
|
||||
export const spridSchema = z.object({
|
||||
spridSearchText: z
|
||||
.string()
|
||||
.regex(/^\d{4}$/, { message: "SPRID must be exactly 4 digits" }),
|
||||
});
|
||||
})
|
||||
|
||||
@ -9,32 +9,27 @@ const SkeletonLine = ({ height = 20, width = "100%", className = "" }) => (
|
||||
);
|
||||
export const OrgCardSkeleton = () => {
|
||||
return (
|
||||
<div className="row p-3">
|
||||
<div className="row p-5">
|
||||
|
||||
{[...Array(1)].map((_, idx) => (
|
||||
<div
|
||||
key={idx}
|
||||
className="list-group-item d-flex flex-row gap-2 align-items-start border-0 shadow-sm rounded mb-3 p-3"
|
||||
className="list-group-item d-flex align-items-center border-0 shadow-sm rounded mb-3"
|
||||
>
|
||||
{/* Left: Logo/avatar placeholder */}
|
||||
<div className="mt-1">
|
||||
<SkeletonLine height={50} width={50} className="rounded-circle" />
|
||||
<div className="d-flex align-items-center justify-content-center me-3 p-1">
|
||||
<SkeletonLine height={40} width={40} className="rounded-circle" />
|
||||
</div>
|
||||
|
||||
{/* Right: Info section */}
|
||||
<div className="d-flex flex-column flex-grow-1 text-start">
|
||||
{/* Org name */}
|
||||
<SkeletonLine height={18} width="160px" className="mb-2" />
|
||||
|
||||
{/* SPRID */}
|
||||
<div className="d-flex gap-2 mb-2">
|
||||
<SkeletonLine height={14} width="60px" />
|
||||
<SkeletonLine height={14} width="100px" />
|
||||
</div>
|
||||
|
||||
{/* Address */}
|
||||
<div className="d-flex gap-2">
|
||||
<SkeletonLine height={14} width="70px" />
|
||||
<SkeletonLine height={14} width="100%" />
|
||||
<div className="w-100 px-1">
|
||||
<div className="d-flex justify-content-between px-">
|
||||
<div className="user-info text-start">
|
||||
<SkeletonLine height={16} width="120px" className="mb-1" />
|
||||
<SkeletonLine height={12} width="80px" />
|
||||
</div>
|
||||
<div className="add-btn px-2">
|
||||
<SkeletonLine height={30} width="60px" className="rounded" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1 +0,0 @@
|
||||
useAssignOrgToTenant
|
||||
@ -1,3 +1,4 @@
|
||||
|
||||
import { useCallback } from "react";
|
||||
|
||||
const Modal = ({
|
||||
@ -6,14 +7,16 @@ const Modal = ({
|
||||
title,
|
||||
body,
|
||||
disabled,
|
||||
size = "md",
|
||||
position = "top",
|
||||
size="md",
|
||||
position="top",
|
||||
}) => {
|
||||
const handleClose = useCallback(() => {
|
||||
if (disabled) return;
|
||||
onClose();
|
||||
}, [disabled, onClose]);
|
||||
|
||||
|
||||
|
||||
if (!isOpen) return null;
|
||||
|
||||
return (
|
||||
@ -23,10 +26,7 @@ const Modal = ({
|
||||
tabIndex="-1"
|
||||
role="dialog"
|
||||
>
|
||||
<div
|
||||
className={`modal-dialog modal-${size} modal-dialog-${position}`}
|
||||
role="document"
|
||||
>
|
||||
<div className={`modal-dialog modal-${size} modal-dialog-${position}`} role="document">
|
||||
<div className="modal-content text-white shadow-lg">
|
||||
{/* Header */}
|
||||
<div className="modal-header pb-2 border-0">
|
||||
@ -36,11 +36,16 @@ const Modal = ({
|
||||
className="btn-close btn-close-white"
|
||||
onClick={handleClose}
|
||||
aria-label="Close"
|
||||
></button>
|
||||
>
|
||||
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Body */}
|
||||
<div className="modal-body pt-0">{body}</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -35,16 +35,21 @@ export const useOrganizationModal = () => {
|
||||
};
|
||||
};
|
||||
|
||||
export const useOrganizationBySPRID = (sprid) => {
|
||||
|
||||
|
||||
|
||||
export const useOrganizationBySPRID =(sprid)=>{
|
||||
return useQuery({
|
||||
queryKey: ["organization by", sprid],
|
||||
queryFn: async () => {
|
||||
queryKey:["organization by",sprid],
|
||||
queryFn:async()=>{
|
||||
|
||||
const resp = await OrganizationRepository.getOrganizationBySPRID(sprid);
|
||||
return resp.data;
|
||||
},
|
||||
enabled: !!sprid,
|
||||
});
|
||||
};
|
||||
enabled:!!sprid
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
export const useOrganizationsList = (
|
||||
pageSize,
|
||||
@ -97,50 +102,8 @@ export const useCreateOrganization = (onSuccessCallback) => {
|
||||
});
|
||||
};
|
||||
|
||||
export const useAssignOrgToProject = (onSuccessCallback) => {
|
||||
const useClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async (payload) =>
|
||||
await OrganizationRepository.assignOrganizationToProject(payload),
|
||||
onSuccess: (_, variables) => {
|
||||
useClient.invalidateQueries({
|
||||
queryKey: ["projectAssignedOrganiztions"],
|
||||
});
|
||||
showToast("Organization successfully", "success");
|
||||
if (onSuccessCallback) onSuccessCallback();
|
||||
},
|
||||
onError: (error) => {
|
||||
showToast(
|
||||
error.response.data.message ||
|
||||
error.message ||
|
||||
"Something went wrong please try again !",
|
||||
"error"
|
||||
);
|
||||
},
|
||||
});
|
||||
};
|
||||
export const useAssignOrgToTenant = (onSuccessCallback) => {
|
||||
const useClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async (payload) =>
|
||||
await OrganizationRepository.assignOrganizationToTenanat(payload),
|
||||
onSuccess: (_, variables) => {
|
||||
useClient.invalidateQueries({ queryKey: ["organizationList"] });
|
||||
showToast("Organization added successfully", "success");
|
||||
if (onSuccessCallback) onSuccessCallback();
|
||||
},
|
||||
onError: (error) => {
|
||||
showToast(
|
||||
error.response.data.message ||
|
||||
error.message ||
|
||||
"Something went wrong please try again !",
|
||||
"error"
|
||||
);
|
||||
},
|
||||
});
|
||||
};
|
||||
export const useUpdateOrganization = () => {
|
||||
const useClient = useQueryClient();
|
||||
export const useAssignOrgToProject=(onSuccessCallback)=>{
|
||||
const useClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async (payload) =>
|
||||
await OrganizationRepository.assignOrganizationToProject(payload),
|
||||
@ -158,4 +121,44 @@ export const useUpdateOrganization = () => {
|
||||
);
|
||||
},
|
||||
});
|
||||
};
|
||||
}
|
||||
export const useAssignOrgToTenant =(onSuccessCallback)=>{
|
||||
const useClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async (payload) =>
|
||||
await OrganizationRepository.assignOrganizationToTenanat(payload),
|
||||
onSuccess: (_, variables) => {
|
||||
useClient.invalidateQueries({ queryKey: ["organizationList"] });
|
||||
showToast("Organization added successfully", "success");
|
||||
if (onSuccessCallback) onSuccessCallback();
|
||||
},
|
||||
onError: (error) => {
|
||||
showToast(
|
||||
error.response.data.message ||
|
||||
error.message ||
|
||||
"Something went wrong please try again !",
|
||||
"error"
|
||||
);
|
||||
},
|
||||
});
|
||||
}
|
||||
export const useUpdateOrganization=()=>{
|
||||
const useClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async (payload) =>
|
||||
await OrganizationRepository.assignOrganizationToProject(payload),
|
||||
onSuccess: (_, variables) => {
|
||||
// useClient.invalidateQueries({ queryKey: ["organizationList"] });
|
||||
showToast("Organization successfully", "success");
|
||||
if (onSuccessCallback) onSuccessCallback();
|
||||
},
|
||||
onError: (error) => {
|
||||
showToast(
|
||||
error.response.data.message ||
|
||||
error.message ||
|
||||
"Something went wrong please try again !",
|
||||
"error"
|
||||
);
|
||||
},
|
||||
});
|
||||
}
|
||||
@ -177,7 +177,7 @@ export const useProjectInfra = (projectId) => {
|
||||
data: projectInfra,
|
||||
isLoading,
|
||||
error,
|
||||
isFetched,
|
||||
isFetched
|
||||
} = useQuery({
|
||||
queryKey: ["ProjectInfra", projectId],
|
||||
queryFn: async () => {
|
||||
@ -191,7 +191,7 @@ export const useProjectInfra = (projectId) => {
|
||||
},
|
||||
});
|
||||
|
||||
return { projectInfra, isLoading, error, isFetched };
|
||||
return { projectInfra, isLoading, error,isFetched };
|
||||
};
|
||||
|
||||
export const useProjectTasks = (workAreaId, IsExpandedArea = false) => {
|
||||
@ -268,30 +268,26 @@ export const useProjectLevelEmployeePermission = (employeeId, projectId) => {
|
||||
});
|
||||
};
|
||||
|
||||
export const useProjectAssignedOrganizations = (projectId) => {
|
||||
return useQuery({
|
||||
queryKey: ["projectAssignedOrganiztions", projectId],
|
||||
queryFn: async () => {
|
||||
const resp = await ProjectRepository.getProjectAssignedOrganizations(
|
||||
projectId
|
||||
);
|
||||
return resp.data;
|
||||
},
|
||||
enabled: !!projectId,
|
||||
});
|
||||
};
|
||||
export const useProjectAssignedServices = (projectId) => {
|
||||
export const useProjectAssignedOrganizations =(projectId)=>{
|
||||
return useQuery({
|
||||
queryKey: ["projectAssignedServices", projectId],
|
||||
queryFn: async () => {
|
||||
const resp = await ProjectRepository.getProjectAssignedServices(
|
||||
projectId
|
||||
);
|
||||
const resp = await ProjectRepository.getProjectAssignedOrganizations(projectId);
|
||||
return resp.data;
|
||||
},
|
||||
enabled: !!projectId,
|
||||
enabled:!!projectId,
|
||||
});
|
||||
};
|
||||
}
|
||||
export const useProjectAssignedServices =(projectId)=>{
|
||||
return useQuery({
|
||||
queryKey: ["projectAssignedServices", projectId],
|
||||
queryFn: async () => {
|
||||
const resp = await ProjectRepository.getProjectAssignedServices(projectId);
|
||||
return resp.data;
|
||||
},
|
||||
enabled:!!projectId,
|
||||
});
|
||||
}
|
||||
|
||||
// -- -------------Mutation-------------------------------
|
||||
|
||||
|
||||
@ -1 +0,0 @@
|
||||
login
|
||||
@ -2,7 +2,7 @@ import { api } from "../utils/axiosClient";
|
||||
|
||||
const AuthRepository = {
|
||||
// Public routes (no auth token required)
|
||||
login: (data) => api.postPublic("/api/auth/login/v1", data),
|
||||
login: (data) => api.postPublic("/api/auth/login", data),
|
||||
refreshToken: (data) => api.postPublic("/api/auth/refresh-token", data),
|
||||
forgotPassword: (data) => api.postPublic("/api/auth/forgot-password", data),
|
||||
resetPassword: (data) => api.postPublic("/api/auth/reset-password", data),
|
||||
@ -15,7 +15,8 @@ const AuthRepository = {
|
||||
logout: (data) => api.post("/api/auth/logout", data),
|
||||
profile: () => api.get("/api/user/profile"),
|
||||
changepassword: (data) => api.post("/api/auth/change-password", data),
|
||||
appmenu: () => api.get("/api/appmenu/get/menu"),
|
||||
appmenu:()=>api.get('/api/appmenu/get/menu')
|
||||
|
||||
};
|
||||
|
||||
export default AuthRepository;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user