Compare commits

...

4 Commits

7 changed files with 111 additions and 68 deletions

View File

@ -5,6 +5,7 @@ import { zodResolver } from "@hookform/resolvers/zod";
import Label from "../../common/Label"; import Label from "../../common/Label";
import { import {
useBranchDetails, useBranchDetails,
useBranchTypes,
useCreateBranch, useCreateBranch,
useServiceProjects, useServiceProjects,
useUpdateBranch, useUpdateBranch,
@ -12,6 +13,8 @@ import {
import { useAppForm } from "../../../hooks/appHooks/useAppForm"; import { useAppForm } from "../../../hooks/appHooks/useAppForm";
import { useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
import { BranchSchema, defaultBranches } from "../ServiceProjectSchema"; import { BranchSchema, defaultBranches } from "../ServiceProjectSchema";
import InputSuggessionField from "../../common/Forms/InputSuggesstionField";
import InputSuggestions from "../../common/InputSuggestion";
const ManageBranch = ({ closeModal, BranchToEdit = null }) => { const ManageBranch = ({ closeModal, BranchToEdit = null }) => {
const { const {
@ -20,7 +23,7 @@ const ManageBranch = ({ closeModal, BranchToEdit = null }) => {
isError, isError,
error: requestError, error: requestError,
} = useBranchDetails(BranchToEdit); } = useBranchDetails(BranchToEdit);
const { data: branchTypes } = useBranchTypes();
const [contacts, setContacts] = React.useState([ const [contacts, setContacts] = React.useState([
{ {
contactPerson: "", contactPerson: "",
@ -122,15 +125,17 @@ const ManageBranch = ({ closeModal, BranchToEdit = null }) => {
<Label htmlFor="branchType" className="form-label" required> <Label htmlFor="branchType" className="form-label" required>
Branch Type Branch Type
</Label> </Label>
<input
type="text" <InputSuggestions
id="branchType" organizationList={branchTypes}
className="form-control form-control-sm" value={watch("branchType") || ""}
{...register("branchType")} onChange={(val) =>
setValue("branchType", val, { shouldValidate: true })
}
error={errors.branchType?.message}
/> />
{errors.branchType && (
<small className="danger-text">{errors.branchType.message}</small>
)}
</div> </div>
</div> </div>

View File

@ -50,7 +50,7 @@ const ServiceBranch = () => {
const handleDelete = (id) => { const handleDelete = (id) => {
setDeletingId(id); setDeletingId(id);
DeleteBranch( DeleteBranch(
{ id, isActive: false }, { id, isActive: showInactive },
{ {
onSettled: () => { onSettled: () => {
setDeletingId(null); setDeletingId(null);
@ -64,9 +64,13 @@ const ServiceBranch = () => {
{IsDeleteModalOpen && ( {IsDeleteModalOpen && (
<ConfirmModal <ConfirmModal
isOpen={IsDeleteModalOpen} isOpen={IsDeleteModalOpen}
type="delete" type={!showInactive ? "delete" : "undo"}
header="Delete Expense" header={!showInactive ? "Delete Branch" : "Restore Branch"}
message="Are you sure you want delete?" message={
!showInactive
? "Are you sure you want delete?"
: "Are you sure you want restore?"
}
onSubmit={handleDelete} onSubmit={handleDelete}
onClose={() => setIsDeleteModalOpen(false)} onClose={() => setIsDeleteModalOpen(false)}
loading={isPending} loading={isPending}
@ -182,35 +186,47 @@ const ServiceBranch = () => {
> >
<i className="bx bx-dots-vertical-rounded text-muted p-0"></i> <i className="bx bx-dots-vertical-rounded text-muted p-0"></i>
</button> </button>
<ul className="dropdown-menu dropdown-menu-end w-auto"> <ul className="dropdown-menu dropdown-menu-end w-auto">
{/* Modify */} {!showInactive ? (
<li <>
onClick={() => <li
setManageState({ onClick={() =>
IsOpen: true, setManageState({
branchId: branch.id, IsOpen: true,
}) branchId: branch.id,
} })
> }
<a className="dropdown-item px-2 cursor-pointer py-1"> >
<i className="bx bx-edit text-primary bx-xs me-2"></i> <a className="dropdown-item px-2 cursor-pointer py-1">
Modify <i className="bx bx-edit text-primary bx-xs me-2"></i>
</a> Modify
</li> </a>
</li>
{/* Delete */} <li
<li onClick={() => {
onClick={() => { setIsDeleteModalOpen(true);
setIsDeleteModalOpen(true); setDeletingId(branch.id);
setDeletingId(branch.id); }}
}} >
> <a className="dropdown-item px-2 cursor-pointer py-1">
<a className="dropdown-item px-2 cursor-pointer py-1"> <i className="bx bx-trash text-danger bx-xs me-2"></i>
<i className="bx bx-trash text-danger bx-xs me-2"></i> Delete
Delete </a>
</a> </li>
</li> </>
) : (
<li
onClick={() => {
setIsDeleteModalOpen(true);
setDeletingId(branch.id);
}}
>
<a className="dropdown-item px-2 cursor-pointer py-1">
<i className="bx bx-undo text-danger me-2"></i>
Restore
</a>
</li>
)}
</ul> </ul>
</div> </div>
</td> </td>

View File

@ -18,8 +18,10 @@ const ConfirmModal = ({
return <i className="bx bx-x-circle text-danger" style={{ fontSize: "60px" }}></i>; return <i className="bx bx-x-circle text-danger" style={{ fontSize: "60px" }}></i>;
case "success": case "success":
return <i className="bx bx-archive-in text-warning" style={{ fontSize: "60px" }}></i>; return <i className="bx bx-archive-in text-warning" style={{ fontSize: "60px" }}></i>;
case "warning": case "archive":
return <i className="bx bx-error-circle text-warning" style={{ fontSize: "60px" }}></i>; return <i className="bx bx-error-circle text-warning" style={{ fontSize: "60px" }}></i>;
case "undo":
return <i className="bx bx-undo text-info" style={{ fontSize: "50px" }}></i>;
default: default:
return null; return null;
} }

View File

@ -2,15 +2,19 @@ import React, { useEffect, useRef, useState } from "react";
import Label from "../Label"; import Label from "../Label";
const InputSuggessionField = ({ const InputSuggessionField = ({
organizationList = [], suggesstionList = [],
value, value,
onChange, onChange,
error, error,
disabled=false disabled = false,
label = "Label",
placeholder = "Please Enter",
required = false,
isLoading = false,
}) => { }) => {
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const dropdownRef = useRef(null); const dropdownRef = useRef(null);
console.log(suggesstionList)
useEffect(() => { useEffect(() => {
const handleClickOutside = (event) => { const handleClickOutside = (event) => {
if (dropdownRef.current && !dropdownRef.current.contains(event.target)) { if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
@ -21,12 +25,12 @@ const InputSuggessionField = ({
return () => document.removeEventListener("mousedown", handleClickOutside); return () => document.removeEventListener("mousedown", handleClickOutside);
}, []); }, []);
const selectedOption = options.find((opt) => opt[valueKey] === value); const selectedOption = suggesstionList.find((opt) => opt === value);
const displayText = selectedOption ? selectedOption[labelKey] : placeholder; const displayText = selectedOption ? selectedOption : placeholder;
const handleSelect = (option) => { const handleSelect = (option) => {
onChange(option[valueKey]); onChange(option);
setOpen(false); setOpen(false);
}; };
@ -68,16 +72,14 @@ const InputSuggessionField = ({
overflow: "hidden", overflow: "hidden",
}} }}
> >
{options.map((option, i) => ( {suggesstionList.map((option, i) => (
<li key={i}> <li key={i}>
<button <button
type="button" type="button"
className={`dropdown-item ${ className={`dropdown-item ${option === value ? "active" : ""}`}
option[valueKey] === value ? "active" : ""
}`}
onClick={() => handleSelect(option)} onClick={() => handleSelect(option)}
> >
{option[labelKey]} {option}
</button> </button>
</li> </li>
))} ))}

View File

@ -5,14 +5,13 @@ const InputSuggestions = ({
value, value,
onChange, onChange,
error, error,
disabled=false disabled = false,
}) => { }) => {
const [filteredList, setFilteredList] = useState([]); const [filteredList, setFilteredList] = useState([]);
const [showSuggestions, setShowSuggestions] = useState(false); const [showSuggestions, setShowSuggestions] = useState(false);
const handleInputChange = (e) => { const handleInputChange = (e) => {
const val = e.target.value; const val = e.target.value;
onChange(val); onChange(val);
const matches = organizationList.filter((org) => const matches = organizationList.filter((org) =>
org.toLowerCase().includes(val.toLowerCase()) org.toLowerCase().includes(val.toLowerCase())
); );
@ -26,7 +25,7 @@ const InputSuggestions = ({
}; };
return ( return (
<div className="position-relative"> <div className="mb-3 position-relative">
<input <input
className="form-control form-control-sm" className="form-control form-control-sm"
value={value} value={value}
@ -39,19 +38,19 @@ const InputSuggestions = ({
/> />
{showSuggestions && filteredList.length > 0 && ( {showSuggestions && filteredList.length > 0 && (
<ul <ul
className="list-group shadow-sm position-absolute w-100 bg-white border zindex-tooltip" className="dropdown-menu w-100 shadow-sm show animate__fadeIn"
style={{ style={{
maxHeight: "180px", maxHeight: "180px",
overflowY: "auto", overflowY: "auto",
marginTop: "2px", marginTop: "2px",
zIndex: 1000, zIndex: 1000,
borderRadius:"0px" borderRadius: "0px",
}} }}
> >
{filteredList.map((org) => ( {filteredList.map((org) => (
<li <li
key={org} key={org}
className="list-group-item list-group-item-action border-none " className="ropdown-item"
style={{ style={{
cursor: "pointer", cursor: "pointer",
padding: "5px 12px", padding: "5px 12px",
@ -59,17 +58,15 @@ const InputSuggestions = ({
transition: "background-color 0.2s", transition: "background-color 0.2s",
}} }}
onMouseDown={() => handleSelectSuggestion(org)} onMouseDown={() => handleSelectSuggestion(org)}
onMouseEnter={(e) => className={`dropdown-item ${
(e.currentTarget.style.backgroundColor = "#f8f9fa") org === value ? "active" : ""
} }`}
onMouseLeave={(e) =>
(e.currentTarget.style.backgroundColor = "transparent")
}
> >
{org} {org}
</li> </li>
))} ))}
</ul> </ul>
)} )}
{error && <small className="danger-text">{error}</small>} {error && <small className="danger-text">{error}</small>}

View File

@ -148,6 +148,11 @@ export const useAllocationServiceProjectTeam = (onSuccessCallback) => {
//#endregion //#endregion
//#region Service Jobs //#region Service Jobs
export const useServiceProjectJobs = ( export const useServiceProjectJobs = (
@ -294,6 +299,12 @@ export const useUpdateServiceProjectJob = (onSuccessCallback) => {
//#endregion //#endregion
//#region Branch //#region Branch
export const useBranches = ( export const useBranches = (
projectId, projectId,
@ -325,6 +336,15 @@ export const useBranches = (
}); });
}; };
export const useBranchTypes = ()=>{
return useQuery({
queryKey:["branch_Type"],
queryFn:async()=> {
const resp = await ServiceProjectRepository.GetBranchTypeList();
return resp.data;
},
})
}
export const useBranchDetails = (id) => { export const useBranchDetails = (id) => {
return useQuery({ return useQuery({
@ -357,6 +377,7 @@ export const useCreateBranch = (onSuccessCallBack) => {
}, },
}); });
}; };
export const useUpdateBranch = (onSuccessCallBack) => { export const useUpdateBranch = (onSuccessCallBack) => {
const queryClient = useQueryClient(); const queryClient = useQueryClient();
return useMutation({ return useMutation({
@ -388,9 +409,9 @@ export const useDeleteBranch = () => {
mutationFn: async ({ id, isActive }) => mutationFn: async ({ id, isActive }) =>
await ServiceProjectRepository.DeleteBranch(id, isActive), await ServiceProjectRepository.DeleteBranch(id, isActive),
onSuccess: () => { onSuccess: (_,variable) => {
queryClient.invalidateQueries({ queryKey: ["branches"] }); queryClient.invalidateQueries({ queryKey: ["branches"] });
showToast("Branch deleted successfully", "success"); showToast(`Branch ${variable.isActive ? "restored":"deleted"} successfully`, "success");
}, },
onError: (error) => { onError: (error) => {

View File

@ -56,5 +56,5 @@ export const ServiceProjectRepository = {
DeleteBranch: (id, isActive = false) => DeleteBranch: (id, isActive = false) =>
api.delete(`/api/ServiceProject/branch/delete/${id}?isActive=${isActive}`), api.delete(`/api/ServiceProject/branch/delete/${id}?isActive=${isActive}`),
GetBranchTypeList: () => api.get(`/api/serviceproject/branch-type/list`),
}; };