Merge branch 'Project_Branch_Management' of https://git.marcoaiot.com/admin/marco.pms.web into Project_Branch_Management
This commit is contained in:
commit
e7a68aeab7
@ -4,6 +4,7 @@ import Label from "../common/Label";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { defaultJobValue, jobSchema } from "./ServiceProjectSchema";
|
||||
import {
|
||||
useBranches,
|
||||
useCreateServiceProjectJob,
|
||||
useJobTags,
|
||||
useServiceProjectJobDetails,
|
||||
@ -25,6 +26,7 @@ import { useParams } from "react-router-dom";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { useJobStatus } from "../../hooks/masterHook/useMaster";
|
||||
import { useServiceProjectJobContext } from "./Jobs";
|
||||
import { SelectFieldSearch } from "../common/Forms/SelectFieldServerSide";
|
||||
|
||||
const ManageJob = ({ Job }) => {
|
||||
const { setManageJob, setSelectedJob } = useServiceProjectJobContext();
|
||||
@ -39,7 +41,7 @@ const ManageJob = ({ Job }) => {
|
||||
control,
|
||||
watch,
|
||||
handleSubmit,
|
||||
reset,
|
||||
reset,setValue,
|
||||
formState: { errors },
|
||||
} = methods;
|
||||
|
||||
@ -199,7 +201,7 @@ const ManageJob = ({ Job }) => {
|
||||
/>
|
||||
</div>
|
||||
<div className="col-12 col-md-6 mb-2 mb-md-4">
|
||||
<Label required>Select Employee</Label>
|
||||
<Label >Select Employee</Label>
|
||||
<PmsEmployeeInputTag
|
||||
control={control}
|
||||
name="assignees"
|
||||
@ -238,7 +240,21 @@ 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]}
|
||||
useFetchHook={useBranches}
|
||||
isMultiple={false}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-12">
|
||||
|
||||
@ -70,6 +70,8 @@ export const jobSchema = z.object({
|
||||
tags: z.array(TagSchema).optional().default([]),
|
||||
|
||||
statusId: z.string().optional().nullable(),
|
||||
|
||||
branchId: z.string().optional().nullable(),
|
||||
});
|
||||
|
||||
const MAX_FILE_SIZE = 5 * 1024 * 1024; // 5MB
|
||||
@ -109,6 +111,7 @@ export const defaultJobValue = {
|
||||
startDate: null,
|
||||
dueDate: null,
|
||||
tags: [],
|
||||
branchId: null,
|
||||
};
|
||||
|
||||
//#endregion
|
||||
|
||||
@ -361,3 +361,182 @@ export const SelectProjectField = ({
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
|
||||
export const SelectFieldSearch = ({
|
||||
label = "Select",
|
||||
placeholder = "Select ",
|
||||
required = false,
|
||||
value = null,
|
||||
onChange,
|
||||
valueKey = "id",
|
||||
labelKey = "name",
|
||||
|
||||
isFullObject = false,
|
||||
isMultiple = false,
|
||||
hookParams,
|
||||
useFetchHook,
|
||||
}) => {
|
||||
const [searchText, setSearchText] = useState("");
|
||||
const debounce = useDebounce(searchText, 300);
|
||||
|
||||
const { data, isLoading } = useFetchHook(...hookParams,debounce);
|
||||
const options = data?.data ?? [];
|
||||
const [open, setOpen] = useState(false);
|
||||
const dropdownRef = useRef(null);
|
||||
|
||||
const getDisplayName = (entity) => {
|
||||
if (!entity) return "";
|
||||
return `${entity[labelKey] || ""}`.trim();
|
||||
};
|
||||
|
||||
/** -----------------------------
|
||||
* SELECTED OPTION (SINGLE)
|
||||
* ----------------------------- */
|
||||
let selectedSingle = null;
|
||||
|
||||
if (!isMultiple) {
|
||||
if (isFullObject && value) selectedSingle = value;
|
||||
else if (!isFullObject && value)
|
||||
selectedSingle = options.find((o) => o[valueKey] === value);
|
||||
}
|
||||
|
||||
/** -----------------------------
|
||||
* SELECTED OPTION (MULTIPLE)
|
||||
* ----------------------------- */
|
||||
let selectedList = [];
|
||||
if (isMultiple && Array.isArray(value)) {
|
||||
if (isFullObject) selectedList = value;
|
||||
else {
|
||||
selectedList = options.filter((opt) => value.includes(opt[valueKey]));
|
||||
}
|
||||
}
|
||||
|
||||
/** Main button label */
|
||||
const displayText = !isMultiple
|
||||
? getDisplayName(selectedSingle) || placeholder
|
||||
: selectedList.length > 0
|
||||
? selectedList.map((e) => getDisplayName(e)).join(", ")
|
||||
: placeholder;
|
||||
|
||||
/** -----------------------------
|
||||
* HANDLE OUTSIDE CLICK
|
||||
* ----------------------------- */
|
||||
useEffect(() => {
|
||||
const handleClickOutside = (e) => {
|
||||
if (dropdownRef.current && !dropdownRef.current.contains(e.target)) {
|
||||
setOpen(false);
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener("mousedown", handleClickOutside);
|
||||
return () => document.removeEventListener("mousedown", handleClickOutside);
|
||||
}, []);
|
||||
|
||||
/** -----------------------------
|
||||
* HANDLE SELECT
|
||||
* ----------------------------- */
|
||||
const handleSelect = (option) => {
|
||||
if (!isMultiple) {
|
||||
// SINGLE SELECT
|
||||
if (isFullObject) onChange(option);
|
||||
else onChange(option[valueKey]);
|
||||
} else {
|
||||
// MULTIPLE SELECT
|
||||
let updated = [];
|
||||
|
||||
const exists = selectedList.some((e) => e[valueKey] === option[valueKey]);
|
||||
|
||||
if (exists) {
|
||||
// remove
|
||||
updated = selectedList.filter((e) => e[valueKey] !== option[valueKey]);
|
||||
} else {
|
||||
// add
|
||||
updated = [...selectedList, option];
|
||||
}
|
||||
|
||||
if (isFullObject) onChange(updated);
|
||||
else onChange(updated.map((x) => x[valueKey]));
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="mb-3 position-relative" ref={dropdownRef}>
|
||||
{label && (
|
||||
<Label className="form-label" required={required}>
|
||||
{label}
|
||||
</Label>
|
||||
)}
|
||||
|
||||
{/* MAIN BUTTON */}
|
||||
<button
|
||||
type="button"
|
||||
className={`select2-icons form-select d-flex align-items-center justify-content-between ${
|
||||
open ? "show" : ""
|
||||
}`}
|
||||
onClick={() => setOpen((prev) => !prev)}
|
||||
>
|
||||
<span className={`text-truncate ${!displayText ? "text-muted" : ""}`}>
|
||||
{displayText}
|
||||
</span>
|
||||
</button>
|
||||
|
||||
{/* DROPDOWN */}
|
||||
{open && (
|
||||
<ul
|
||||
className="dropdown-menu w-100 shadow-sm show animate__fadeIn h-64 overflow-auto rounded"
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: "100%",
|
||||
left: 0,
|
||||
zIndex: 1050,
|
||||
marginTop: "2px",
|
||||
borderRadius: "0.375rem",
|
||||
overflow: "hidden",
|
||||
}}
|
||||
>
|
||||
<div className="p-1">
|
||||
<input
|
||||
type="search"
|
||||
value={searchText}
|
||||
onChange={(e) => setSearchText(e.target.value)}
|
||||
className="form-control form-control-sm"
|
||||
placeholder="Search..."
|
||||
/>
|
||||
</div>
|
||||
|
||||
{isLoading && (
|
||||
<li className="dropdown-item text-muted text-center">Loading...</li>
|
||||
)}
|
||||
|
||||
{!isLoading && options.length === 0 && (
|
||||
<li className="dropdown-item text-muted text-center">
|
||||
No results found
|
||||
</li>
|
||||
)}
|
||||
|
||||
{!isLoading &&
|
||||
options.map((option) => {
|
||||
const isActive = isMultiple
|
||||
? selectedList.some((x) => x[valueKey] === option[valueKey])
|
||||
: selectedSingle &&
|
||||
selectedSingle[valueKey] === option[valueKey];
|
||||
|
||||
return (
|
||||
<li key={option[valueKey]}>
|
||||
<button
|
||||
type="button"
|
||||
className={`dropdown-item ${isActive ? "active" : ""}`}
|
||||
onClick={() => handleSelect(option)}
|
||||
>
|
||||
{getDisplayName(option)}
|
||||
</button>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@ -308,13 +308,15 @@ export const useBranches = (
|
||||
pageNumber,
|
||||
searchString
|
||||
);
|
||||
console.log(resp)
|
||||
return resp.data;
|
||||
},
|
||||
enabled: !!projectId,
|
||||
});
|
||||
};
|
||||
|
||||
export const useBranch = (id) => {
|
||||
|
||||
export const useBranch = (id)=>{
|
||||
return useQuery({
|
||||
queryKey: ["branch", id],
|
||||
queryFn: async () => {
|
||||
|
||||
@ -45,8 +45,8 @@ export const ServiceProjectRepository = {
|
||||
UpdateBranch: (id, data) =>
|
||||
api.put("/api/ServiceProject/branch/edit/${id}", data),
|
||||
GetBranchList: (projectId, isActive, pageSize, pageNumber, searchString) => {
|
||||
api.get(
|
||||
`/api/ServiceProject/branch/list/${projectId}/?isActive=${isActive}&pageSize=${pageSize}&pageNumber=${pageNumber}&searchString=${searchString}`
|
||||
return api.get(
|
||||
`/api/ServiceProject/branch/list/${projectId}?isActive=${isActive}&pageSize=${pageSize}&pageNumber=${pageNumber}&searchString=${searchString}`
|
||||
);
|
||||
},
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user