added changes status fun

This commit is contained in:
pramod.mahajan 2025-11-17 17:06:05 +05:30
commit d95ba4c800
17 changed files with 349 additions and 139 deletions

View File

@ -23,7 +23,7 @@ import Label from "../common/Label";
const ManageContact = ({ contactId, closeModal }) => { const ManageContact = ({ contactId, closeModal }) => {
// fetch master data // fetch master data
const { buckets, loading: bucketsLoaging } = useBuckets(); const { buckets, loading: bucketsLoaging } = useBuckets();
const { data:projects, loading: projectLoading } = useProjects(); const { data: projects, loading: projectLoading } = useProjects();
const { contactCategory, loading: contactCategoryLoading } = const { contactCategory, loading: contactCategoryLoading } =
useContactCategory(); useContactCategory();
const { organizationList } = useOrganization(); const { organizationList } = useOrganization();
@ -210,7 +210,7 @@ const ManageContact = ({ contactId, closeModal }) => {
value={watch("organization") || ""} value={watch("organization") || ""}
onChange={(val) => setValue("organization", val, { shouldValidate: true })} onChange={(val) => setValue("organization", val, { shouldValidate: true })}
error={errors.organization?.message} error={errors.organization?.message}
/> />
</div> </div>
</div> </div>
@ -408,6 +408,7 @@ const ManageContact = ({ contactId, closeModal }) => {
label="Tags" label="Tags"
options={contactTags} options={contactTags}
isRequired={true} isRequired={true}
placeholder="Enter Tag"
/> />
{errors.tags && ( {errors.tags && (
<small className="danger-text">{errors.tags.message}</small> <small className="danger-text">{errors.tags.message}</small>

View File

@ -104,7 +104,6 @@ const hasChanges =
permission: payloadPermissions, permission: payloadPermissions,
}; };
console.log("Final payload:", payload);
updatePermission(payload); updatePermission(payload);
}; };

View File

@ -134,7 +134,6 @@ const ManageRecurringExpense = ({ closeModal, requestToEdit = null }) => {
const StrikeDate = watch("strikeDate") const StrikeDate = watch("strikeDate")
const onSubmit = (fromdata) => { const onSubmit = (fromdata) => {
console.log(fromdata);
let payload = { let payload = {
...fromdata, ...fromdata,
strikeDate: fromdata.strikeDate strikeDate: fromdata.strikeDate

View File

@ -0,0 +1,100 @@
import SelectField from "../common/Forms/SelectField";
import { useJobStatus } from "../../hooks/masterHook/useMaster";
import { SpinnerLoader } from "../common/Loader";
import Error from "../common/Error";
import { z } from "zod";
import {
AppFormController,
AppFormProvider,
useAppForm,
} from "../../hooks/appHooks/useAppForm";
import { zodResolver } from "@hookform/resolvers/zod";
import { useDispatch, useSelector } from "react-redux";
import { closePopup } from "../../slices/localVariablesSlice";
import { useUpdateServiceProjectJob } from "../../hooks/useServiceProject";
export const ChangeStatusSchema = z.object({
statusId: z.string().min(1, { message: "Please select status" }),
});
const ChangeStatus = ({ statusId, projectId, jobId, popUpId }) => {
const { data, isLoading, isError, error } = useJobStatus(statusId, projectId);
const dispatch = useDispatch();
const methods = useAppForm({
resolver: zodResolver(ChangeStatusSchema),
defaultValues: { statusId: "" },
});
const {
control,
handleSubmit,
reset,
formState: { errors },
} = methods;
const { mutate: UpdateStatus, isPending } = useUpdateServiceProjectJob(() => {
// handleClose();
});
const onSubmit = (formData) => {
const payload =
[
{
op: "replace",
path: "/statusId",
value: formData.statusId,
},
];
UpdateStatus({ id: jobId, payload });
};
const handleClose = () => {
dispatch(closePopup(popUpId));
};
return (
<AppFormProvider {...methods}>
<form className="row text-start" onSubmit={handleSubmit(onSubmit)}>
<div className="mb-2">
<AppFormController
name="statusId"
control={control}
render={({ field }) => (
<SelectField
label="Select Status"
options={data ?? []}
placeholder="Choose a Status"
required
labelKeyKey="name"
valueKeyKey="id"
value={field.value}
onChange={field.onChange}
isLoading={isLoading}
className="m-0"
/>
)}
/>
{errors.statusId && (
<small className="danger-text">{errors.statusId.message}</small>
)}
</div>
<div className="d-flex flex-row justify-content-end gap-3">
<button
type="button"
onClick={handleClose}
className="btn btn-label-secondary btn-sm"
>
Cancel
</button>
<button type="submit" className="btn btn-primary btn-sm">
{isPending ? "Please wait" : "Save"}
</button>
</div>
</form>
</AppFormProvider>
);
};
export default ChangeStatus;

View File

@ -2,7 +2,6 @@ import React from "react";
import Avatar from "../common/Avatar"; import Avatar from "../common/Avatar";
const JobStatusLog = ({ data }) => { const JobStatusLog = ({ data }) => {
console.log(data);
return ( return (
<div className="card shadow-none p-0"> <div className="card shadow-none p-0">
<div className="card-body p-0"> <div className="card-body p-0">

View File

@ -20,10 +20,11 @@ import {
AppFormProvider, AppFormProvider,
useAppForm, useAppForm,
} from "../../hooks/appHooks/useAppForm"; } from "../../hooks/appHooks/useAppForm";
import { useServiceProjectJobContext } from "./Jobs"; import { useParams } from "react-router-dom";
const ManageJob = ({ Job }) => { const ManageJob = ({ Job }) => {
const { manageJob, setManageJob } = useServiceProjectJobContext(); const { projectId } = useParams();
const methods = useAppForm({ const methods = useAppForm({
resolver: zodResolver(jobSchema), resolver: zodResolver(jobSchema),
defaultValues: defaultJobValue, defaultValues: defaultJobValue,
@ -69,27 +70,33 @@ const ManageJob = ({ Job }) => {
formData.startDate = localToUtc(formData.startDate); formData.startDate = localToUtc(formData.startDate);
formData.dueDate = localToUtc(formData.dueDate); formData.dueDate = localToUtc(formData.dueDate);
formData.projectId = projectId;
CreateJob(formData); CreateJob(formData);
}; };
useEffect(() => { useEffect(() => {
if (manageJob.jobId && JobData) { if (!JobData && !Job) {
console.log("freshed data"); reset({
...defaultJobValue,
projectId: projectId,
});
return;
}
if (!JobData || !Job) return;
const assignedEmployees = (JobData.assignees || []).map((e) => e.id); const assignedEmployees = (JobData.assignees || []).map((e) => e.id);
reset({ reset({
title: JobData.title ?? "", title: JobData.title ?? "",
description: JobData.description ?? "", description: JobData.description ?? "",
projectId: JobData.project.id ?? "", projectId: JobData.project?.id ?? projectId,
assignees: assignedEmployees, assignees: assignedEmployees,
startDate: JobData.startDate ?? null, startDate: JobData.startDate ?? null,
dueDate: JobData.dueDate ?? null, dueDate: JobData.dueDate ?? null,
tags: JobData.tags ?? [], tags: JobData.tags ?? [],
}); });
} }, [JobData, Job, projectId]);
if (!manageJob.jobId) {
reset(defaultJobValue);
}
}, [JobData, manageJob]);
return ( return (
<div className="container"> <div className="container">
@ -101,27 +108,10 @@ const ManageJob = ({ Job }) => {
type="text" type="text"
{...register("title")} {...register("title")}
className="form-control form-control" className="form-control form-control"
placeholder="Enter Title"
/> />
</div> </div>
<div className="col-12 col-md-6 mb-2">
<AppFormController
name="projectId"
control={control}
render={({ field }) => (
<SelectField
label="Status"
options={data?.data}
placeholder="Choose a Status"
required
labelKeyKey="name"
valueKeyKey="id"
value={field.value}
onChange={field.onChange}
isLoading={isProjectLoading}
/>
)}
/>
</div>
<div className="col-12 col-md-6 mb-2 mb-md-4"> <div className="col-12 col-md-6 mb-2 mb-md-4">
<Label required>Start Date</Label> <Label required>Start Date</Label>
<DatePicker <DatePicker
@ -155,6 +145,7 @@ const ManageJob = ({ Job }) => {
options={JobTags?.data} options={JobTags?.data}
name="tags" name="tags"
label="Tag" label="Tag"
placeholder="Enter Tag"
required required
/> />
</div> </div>

View File

@ -8,8 +8,12 @@ import EmployeeAvatarGroup from "../common/EmployeeAvatarGroup";
import JobStatusLog from "./JobStatusLog"; import JobStatusLog from "./JobStatusLog";
import JobComments from "./JobComments"; import JobComments from "./JobComments";
import { daysLeft } from "../../utils/appUtils"; import { daysLeft } from "../../utils/appUtils";
import HoverPopup from "../common/HoverPopup";
import ChangeStatus from "./ChangeStatus";
import { useParams } from "react-router-dom";
const ManageJobTicket = ({ Job }) => { const ManageJobTicket = ({ Job }) => {
const { projectId } = useParams();
const { data, isLoading, isError, error } = useServiceProjectJobDetails( const { data, isLoading, isError, error } = useServiceProjectJobDetails(
Job?.job Job?.job
); );
@ -31,7 +35,6 @@ const ManageJobTicket = ({ Job }) => {
}, },
]; ];
if (isLoading) return <SpinnerLoader />; if (isLoading) return <SpinnerLoader />;
if (isError) if (isError)
return ( return (
@ -43,8 +46,26 @@ const ManageJobTicket = ({ Job }) => {
<div className="row text-start"> <div className="row text-start">
<div className="col-12"> <div className="col-12">
<div className="d-flex justify-content-between align-items-center mb-3"> <div className="d-flex justify-content-between align-items-center mb-3">
<div className="d-flex flex-row gap-2">
<span className="badge bg-label-primary">{data?.status?.name}</span> <span className="badge bg-label-primary">{data?.status?.name}</span>
{data?.dueDate && (() => { <HoverPopup
id="STATUS_CHANEG"
title="Change Status"
Mode="click"
content={
<ChangeStatus
statusId={data?.status?.id}
projectId={projectId}
jobId={Job?.job}
popUpId={"STATUS_CHANEG"}
/>
}
>
<i className="bx bx-edit bx-sm"></i>
</HoverPopup>
</div>
{data?.dueDate &&
(() => {
const { days, color } = daysLeft(data?.startDate, data?.dueDate); const { days, color } = daysLeft(data?.startDate, data?.dueDate);
return ( return (
<span style={{ fontSize: "12px" }}> <span style={{ fontSize: "12px" }}>
@ -55,7 +76,6 @@ const ManageJobTicket = ({ Job }) => {
</span> </span>
); );
})()} })()}
</div> </div>
<h6 className="fs-5 fw-semibold">{data?.title}</h6> <h6 className="fs-5 fw-semibold">{data?.title}</h6>
@ -66,30 +86,31 @@ const ManageJobTicket = ({ Job }) => {
</p> </p>
</div> </div>
<div className="d-flex justify-content-between mb-4"> <div className="d-flex justify-content-between mb-4">
<div className="d-flex flex-row gap-1 fw-medium"> <div className="d-flex flex-row gap-1 fw-medium">
<i className="bx bx-calendar"></i>{" "} <i className="bx bx-calendar"></i>{" "}
<span>Created Date : {formatUTCToLocalTime(data?.createdAt, true)}</span> <span>
Created Date : {formatUTCToLocalTime(data?.createdAt, true)}
</span>
</div> </div>
</div> </div>
<div> <div>
<div className="d-flex flex-row gap-5"> <div className="d-flex flex-row gap-5">
<span className="fw-medium"> <span className="fw-medium">
<i className="bx bx-calendar"></i> Start Date : {formatUTCToLocalTime(data?.startDate)} <i className="bx bx-calendar"></i> Start Date :{" "}
{formatUTCToLocalTime(data?.startDate)}
</span>{" "} </span>{" "}
<i className="bx bx-right-arrow-alt"></i>{" "} <i className="bx bx-right-arrow-alt"></i>{" "}
<span className="fw-medium"> <span className="fw-medium">
<i className="bx bx-calendar"></i> Due on : {formatUTCToLocalTime(data?.startDate)} <i className="bx bx-calendar"></i> Due on :{" "}
{formatUTCToLocalTime(data?.startDate)}
</span> </span>
</div> </div>
</div> </div>
<div className="d-block mt-4 mb-3"> <div className="d-block mt-4 mb-3">
<div className="d-flex align-items-center mb-2"> <div className="d-flex align-items-center mb-2">
<span className="fs-6 fw-medium me-5"> <span className="fs-6 fw-medium me-5">Created By</span>{" "}
Created By
</span>{" "}
<Avatar <Avatar
size="xs" size="xs"
firstName={data?.createdBy?.firstName} firstName={data?.createdBy?.firstName}
@ -97,20 +118,26 @@ const ManageJobTicket = ({ Job }) => {
/>{" "} />{" "}
<div className="d-flex flex-row align-items-center"> <div className="d-flex flex-row align-items-center">
<p className="m-0">{`${data?.createdBy?.firstName} ${data?.createdBy?.lastName}`}</p> <p className="m-0">{`${data?.createdBy?.firstName} ${data?.createdBy?.lastName}`}</p>
<small className="text-secondary ms-1">({data?.createdBy?.jobRoleName})</small> <small className="text-secondary ms-1">
({data?.createdBy?.jobRoleName})
</small>
</div> </div>
</div> </div>
<div className="d-flex align-items-center"> <div className="d-flex align-items-center">
<small className="fs-6 fw-medium me-3"> <small className="fs-6 fw-medium me-3">Assigned By</small>
Assigned By
</small>
<div className="d-flex flex-row gap-3"> <div className="d-flex flex-row gap-3">
{data?.assignees?.map((emp) => ( {data?.assignees?.map((emp) => (
<div className="d-flex flex-row "> <div className="d-flex flex-row ">
<Avatar size="xs" firstName={emp.firstName} lastName={emp.lastName} /> <Avatar
size="xs"
firstName={emp.firstName}
lastName={emp.lastName}
/>
<div className="d-flex flex-row align-items-center"> <div className="d-flex flex-row align-items-center">
<p className="m-0">{`${emp.firstName} ${emp.lastName}`}</p> <p className="m-0">{`${emp.firstName} ${emp.lastName}`}</p>
<small className="text-secondary ms-1">({emp.jobRoleName})</small> <small className="text-secondary ms-1">
({emp.jobRoleName})
</small>
</div> </div>
</div> </div>
))} ))}

View File

@ -1,54 +1,74 @@
import React, { useEffect, useRef, useState } from "react"; import React, { useEffect, useMemo, useRef, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { closePopup, openPopup, togglePopup } from "../../slices/localVariablesSlice";
const HoverPopup = ({ id, title, content, children, Mode = "hover" }) => {
const dispatch = useDispatch();
const visible = useSelector((s) => s.localVariables.popups[id] || false);
const HoverPopup = ({ title, content, children }) => {
const [visible, setVisible] = useState(false);
const triggerRef = useRef(null); const triggerRef = useRef(null);
const popupRef = useRef(null); const popupRef = useRef(null);
// Toggle popup on hover or click // Hover mode
const handleMouseEnter = () => setVisible(true); const handleMouseEnter = () => {
const handleClick = () => setVisible((prev) => !prev); if (Mode === "hover") dispatch(openPopup(id));
};
// Hide popup on outside click const handleMouseLeave = () => {
if (Mode === "hover") dispatch(closePopup(id));
};
// Click mode
const handleClick = (e) => {
if (Mode === "click") {
e.stopPropagation();
dispatch(togglePopup(id));
}
};
// Outside click handling
useEffect(() => { useEffect(() => {
const handleDocumentClick = (e) => { if (Mode !== "click" || !visible) return;
const handleOutside = (e) => {
if ( if (
!popupRef.current?.contains(e.target) && !popupRef.current?.contains(e.target) &&
!triggerRef.current?.contains(e.target) !triggerRef.current?.contains(e.target)
) { ) {
setVisible(false); dispatch(closePopup(id));
} }
}; };
if (visible) document.addEventListener("click", handleDocumentClick); document.addEventListener("click", handleOutside);
return () => document.removeEventListener("click", handleDocumentClick); return () => document.removeEventListener("click", handleOutside);
}, [visible]); }, [visible, Mode, id]);
return ( return (
<div className="d-inline-block position-relative">
{/* Trigger element */}
<div <div
className="d-inline-block position-relative text-capitalize"
ref={triggerRef} ref={triggerRef}
onMouseEnter={handleMouseEnter} onMouseEnter={handleMouseEnter}
onMouseLeave={() => setVisible(false)} onMouseLeave={handleMouseLeave}
onClick={handleClick} onClick={handleClick}
style={{ cursor: "pointer" }} style={{ cursor: "pointer" }}
> >
{children} {children}
</div>
{/* Popup */}
{visible && ( {visible && (
<div <div
ref={popupRef} ref={popupRef}
className="bg-white border rounded shadow-sm p-3 text-start position-absolute top-100 start-500 translate-middle mt-12" className="bg-white border rounded shadow-sm p-3 position-absolute top-100 start-0 mt-2"
style={{ zIndex: 1000, width: "240px" }}
onClick={(e) => e.stopPropagation()} // prevents closing when clicking inside
> >
{title && ( {title && <h6 className="fw-semibold mb-2">{title}</h6>}
<h6 className="mb-2 fw-semibold text-dark" style={{ fontSize: "0.9rem" }}>
{title} <div>{content}</div>
</h6>
)}
<div className="text-muted" style={{ fontSize: "0.85rem", lineHeight: "1.4" }}>
{content}
</div>
</div> </div>
)} )}
</div> </div>

View File

@ -2,7 +2,7 @@ import { useFormContext, useWatch } from "react-hook-form";
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import Label from "./Label"; import Label from "./Label";
const TagInput = ({ label, name, placeholder, color = "#e9ecef", required=false, options = [] }) => { const TagInput = ({ label, name, placeholder, color = "#e9ecef", required = false, options = [] }) => {
const { setValue, watch } = useFormContext(); const { setValue, watch } = useFormContext();
const tags = watch(name) || []; const tags = watch(name) || [];
const [input, setInput] = useState(""); const [input, setInput] = useState("");
@ -33,7 +33,7 @@ const TagInput = ({ label, name, placeholder, color = "#e9ecef", required=false,
} }
}; };
const handleChange = (e) => { const handleChange = (e) => {
const val = e.target.value; const val = e.target.value;
setInput(val); setInput(val);
@ -55,7 +55,7 @@ const handleChange = (e) => {
} else { } else {
setSuggestions([]); setSuggestions([]);
} }
}; };
const handleSuggestionClick = (sugg) => { const handleSuggestionClick = (sugg) => {
handleAdd(sugg); handleAdd(sugg);
@ -105,6 +105,9 @@ const handleChange = (e) => {
outline: "none", outline: "none",
flex: 1, flex: 1,
minWidth: "120px", minWidth: "120px",
backgroundColor: "white",
color: "black"
}} }}
/> />
</div> </div>

View File

@ -296,13 +296,14 @@ export const useOrganizationType = () => {
}); });
}; };
export const useJobStatus=()=>{ export const useJobStatus=(statusId,projectId)=>{
return useQuery({ return useQuery({
queryKey:["Job_Staus"], queryKey:["Job_Staus",statusId,projectId],
queryFn:async()=>{ queryFn:async()=>{
const resp = await MasterRespository.getJobStatus(); const resp = await MasterRespository.getJobStatus(statusId,projectId);
return resp.data; return resp.data;
} },
enabled:!!statusId && !!projectId
}) })
} }

View File

@ -253,4 +253,35 @@ export const useCreateServiceProjectJob = (onSuccessCallback) => {
}, },
}); });
}; };
export const useUpdateServiceProjectJob = (onSuccessCallback) => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async ({ id, payload }) => {
// Call the repository patch
const resp = await ServiceProjectRepository.UpdateJob(
id,
payload
);
return resp;
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ["serviceProjectJobs"] });
queryClient.invalidateQueries({ queryKey: ["service-job"] });
if (onSuccessCallback) onSuccessCallback();
showToast("Job Updated successfully", "success");
},
onError: (error) => {
showToast(
error?.response?.data?.message ||
error.message ||
"Failed to update project",
"error"
);
},
});
};
//#endregion //#endregion

View File

@ -5,8 +5,18 @@ import { ComingSoonPage } from "../Misc/ComingSoonPage";
import ServiceProjectProfile from "../../components/ServiceProject/ServiceProjectProfile"; import ServiceProjectProfile from "../../components/ServiceProject/ServiceProjectProfile";
import Jobs from "../../components/ServiceProject/Jobs"; import Jobs from "../../components/ServiceProject/Jobs";
import ProjectTeam from "../../components/ServiceProject/ServiceProjectTeam/ProjectTeam"; import ProjectTeam from "../../components/ServiceProject/ServiceProjectTeam/ProjectTeam";
import { useSelectedProject } from "../../slices/apiDataManager";
import { useParams } from "react-router-dom";
import { useServiceProject } from "../../hooks/useServiceProject";
const ServiceProjectDetail = () => { const ServiceProjectDetail = () => {
const { projectId } = useParams();
const {
data: projectdata,
isLoading: isProjectLoading,
isProjectError,
} = useServiceProject(projectId);
const [activePill, setActivePill] = useState( const [activePill, setActivePill] = useState(
sessionStorage.getItem("servicePrjectTab") || "profile" sessionStorage.getItem("servicePrjectTab") || "profile"
); );
@ -26,13 +36,14 @@ const ServiceProjectDetail = () => {
return <ComingSoonPage />; return <ComingSoonPage />;
} }
}; };
return ( return (
<div className="container-fluid"> <div className="container-fluid">
<Breadcrumb <Breadcrumb
data={[ data={[
{ label: "Home", link: "/dashboard" }, { label: "Home", link: "/dashboard" },
{ label: "Sevice Projects", link: "/projects" }, { label: "Sevice Projects", link: "/projects" },
// { label: projects_Details?.name || "Project", link: null }, { label: projectdata?.name || "Project", link: null }
]} ]}
/> />
<div> <div>

View File

@ -150,8 +150,11 @@ export const MasterRespository = {
getCurrencies: () => api.get(`/api/Master/currencies/list`), getCurrencies: () => api.get(`/api/Master/currencies/list`),
getRecurringStatus: () => api.get(`/api/Master/recurring-status/list`), getRecurringStatus: () => api.get(`/api/Master/recurring-status/list`),
// Service Job JobTickets Status
getJobStatus: (statusId,projectId) =>
api.get(
`/api/Master/job-status/list?statusId=${statusId}&projectId=${projectId}`
),
getJobStatus: () => api.get("/api/Master/job-status/list"), getTeamRole: () => api.get(`/api/Master/team-roles/list`),
getTeamRole:()=> api.get(`/api/Master/team-roles/list`),
}; };

View File

@ -31,4 +31,8 @@ export const ServiceProjectRepository = {
`/api/ServiceProject/job/comment/list?jobTicketId=${jobTicketId}&pageSize=${pageSize}&pageNumber=${pageNumber}` `/api/ServiceProject/job/comment/list?jobTicketId=${jobTicketId}&pageSize=${pageSize}&pageNumber=${pageNumber}`
), ),
GetJobTags: () => api.get(`/api/ServiceProject/job/tag/list`), GetJobTags: () => api.get(`/api/ServiceProject/job/tag/list`),
UpdateJob: (id, patchData) =>
api.patch(`/api/ServiceProject/job/edit/${id}`, patchData, {
"Content-Type": "application/json-patch+json",
}),
}; };

View File

@ -24,7 +24,6 @@ const validateToken = async () => {
sessionStorage.getItem("refreshToken"); sessionStorage.getItem("refreshToken");
if (!refreshTokenStored){ if (!refreshTokenStored){
console.log("no refrh tokem");
removeSession() removeSession()
return false return false
}; };

View File

@ -11,6 +11,9 @@ const localVariablesSlice = createSlice({
SelectedOrg: "", SelectedOrg: "",
}, },
// PopUp
popups: {},
// Modal for all simple pass Name // Modal for all simple pass Name
modals: { modals: {
@ -127,6 +130,19 @@ const localVariablesSlice = createSlice({
state.selfTenant.paymentDetailId = state.selfTenant.paymentDetailId =
action.payload.paymentDetailId ?? state.selfTenant.paymentDetailId; action.payload.paymentDetailId ?? state.selfTenant.paymentDetailId;
}, },
openPopup: (state, action) => {
const id = action.payload;
state.popups[id] = true;
},
closePopup: (state, action) => {
const id = action.payload;
state.popups[id] = false;
},
togglePopup: (state, action) => {
const id = action.payload;
state.popups[id] = !state.popups[id];
}
}, },
}); });
@ -145,6 +161,6 @@ export const {
openModal, openModal,
closeModal, closeModal,
toggleModal, toggleModal,
setSelfTenant, setSelfTenant,openPopup, closePopup, togglePopup
} = localVariablesSlice.actions; } = localVariablesSlice.actions;
export default localVariablesSlice.reducer; export default localVariablesSlice.reducer;

View File

@ -178,6 +178,12 @@ export const api = {
headers: { ...customHeaders }, headers: { ...customHeaders },
authRequired: true, authRequired: true,
}), }),
patch: (url, data = {}, customHeaders = {}) =>
apiRequest("patch", url, data, {
headers: { ...customHeaders },
authRequired: true,
}),
}; };
// Redirect helper // Redirect helper