mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-30 09:58:12 +00:00
fix ui
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import {
|
||||
getEmployeePlanByPlanId,
|
||||
getEmployeeSubPlanByPlanId,
|
||||
} from "../services/api/employeePlanService";
|
||||
interface CombinedEmployeePlanResponse {
|
||||
items: any[];
|
||||
total: number;
|
||||
}
|
||||
|
||||
export const useCombinedEmployeePlanByPlanId = (planId: string | undefined) => {
|
||||
// Main query that intelligently fetches data
|
||||
const query = useQuery<CombinedEmployeePlanResponse>({
|
||||
queryKey: ["combined-employee-plan", planId],
|
||||
queryFn: async () => {
|
||||
if (!planId) return { items: [], total: 0 };
|
||||
|
||||
try {
|
||||
// First, try to get data from the sub endpoint (this has actual plan data)
|
||||
const subResponse = await getEmployeeSubPlanByPlanId(planId);
|
||||
|
||||
if (subResponse.data?.items && subResponse.data.items.length > 0) {
|
||||
return {
|
||||
items: subResponse.data.items,
|
||||
total: subResponse.data.total || subResponse.data.items.length,
|
||||
};
|
||||
}
|
||||
|
||||
// If sub endpoint returns empty, try the initial endpoint
|
||||
const initialResponse = await getEmployeePlanByPlanId(planId);
|
||||
|
||||
if (initialResponse.data?.items) {
|
||||
// Transform initial data to match the expected format
|
||||
const transformedItems = initialResponse.data.items.map(
|
||||
(item: any) => ({
|
||||
...item,
|
||||
weeks: {}, // Initialize empty weeks object
|
||||
no_of_employee_plans: "0", // No plans exist yet
|
||||
})
|
||||
);
|
||||
|
||||
return {
|
||||
items: transformedItems,
|
||||
total: transformedItems.length,
|
||||
};
|
||||
}
|
||||
|
||||
// Both endpoints returned empty
|
||||
return { items: [], total: 0 };
|
||||
} catch (error) {
|
||||
console.error("Error fetching employee plans:", error);
|
||||
// Return empty but don't throw - we'll show empty state in UI
|
||||
return { items: [], total: 0 };
|
||||
}
|
||||
},
|
||||
enabled: !!planId,
|
||||
staleTime: 5 * 60 * 1000, // 5 minutes
|
||||
gcTime: 10 * 60 * 1000, // 10 minutes
|
||||
});
|
||||
|
||||
return {
|
||||
data: query.data,
|
||||
isLoading: query.isLoading,
|
||||
error: query.error,
|
||||
refetch: query.refetch,
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,182 @@
|
||||
// hooks/useEmployeePlanMutations.ts
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useErrorHandler } from "@/shared/hooks/useErrorHandler";
|
||||
import { toast } from "sonner";
|
||||
import { useAuth } from "@/shared/context/AuthContext";
|
||||
import {
|
||||
createEmployeePlan,
|
||||
getEmployeePlan,
|
||||
getEmployeePlans,
|
||||
updateEmployeePlan,
|
||||
deleteEmployeePlan,
|
||||
getPlansByUnit,
|
||||
getPositionsByUnit,
|
||||
fetchImmediateChild,
|
||||
getServices,
|
||||
getParentEmployeePlanDetail,
|
||||
type CreateEmployeePlanDto,
|
||||
getEmployeePlanByPlanId,
|
||||
getEmployeeSubPlanByPlanId,
|
||||
getMyEmployeePlan,
|
||||
planParam,
|
||||
} from "../services/api/employeePlanService";
|
||||
|
||||
// Query Keys
|
||||
export const EMPLOYEE_PLAN_KEYS = {
|
||||
all: ["employee-plans"] as const,
|
||||
list: (planId: string) => ["employee-plans", "list", planId] as const,
|
||||
detail: (id: string) => ["employee-plans", id] as const,
|
||||
plansByUnit: (unitId: string) => ["employee-plans", "plans", unitId] as const,
|
||||
positionsByUnit: (unitId: string) =>
|
||||
["employee-plans", "positions", unitId] as const,
|
||||
employeePositions: () => ["employee-plans", "employee-positions"] as const,
|
||||
services: ["employee-plans", "services"] as const,
|
||||
parentDetail: (id: string) => ["employee-plans", "parent", id] as const,
|
||||
planId: (planId: string) => ["employee-plans", "plan", planId] as const,
|
||||
subPlanId: (subPlanId: string) =>
|
||||
["sub-employee-plans", "plan", subPlanId] as const,
|
||||
};
|
||||
|
||||
// GET SINGLE Employee Plan
|
||||
export function useEmployeePlan(id: string) {
|
||||
return useQuery({
|
||||
queryKey: EMPLOYEE_PLAN_KEYS.detail(id),
|
||||
queryFn: () => getEmployeePlan(id),
|
||||
enabled: !!id,
|
||||
});
|
||||
}
|
||||
|
||||
// GET Employee Plans LIST by planId
|
||||
export function useEmployeePlanList(planId: string) {
|
||||
return useQuery({
|
||||
queryKey: EMPLOYEE_PLAN_KEYS.list(planId),
|
||||
queryFn: () => getEmployeePlans(planId),
|
||||
enabled: !!planId,
|
||||
});
|
||||
}
|
||||
|
||||
// GET Plans by Unit
|
||||
export function usePlansByUnit(unitId: string) {
|
||||
return useQuery({
|
||||
queryKey: EMPLOYEE_PLAN_KEYS.plansByUnit(unitId),
|
||||
queryFn: () => getPlansByUnit(unitId),
|
||||
enabled: !!unitId,
|
||||
});
|
||||
}
|
||||
|
||||
// GET Positions by Unit
|
||||
export function usePositionsByUnit(unitId: string) {
|
||||
return useQuery({
|
||||
queryKey: EMPLOYEE_PLAN_KEYS.positionsByUnit(unitId),
|
||||
queryFn: () => getPositionsByUnit(unitId),
|
||||
enabled: !!unitId,
|
||||
});
|
||||
}
|
||||
|
||||
// GET Employee Positions by Position ID
|
||||
export function useEmployeePositions() {
|
||||
const { selectedPositionId } = useAuth();
|
||||
return useQuery({
|
||||
queryKey: [...EMPLOYEE_PLAN_KEYS.employeePositions(), selectedPositionId],
|
||||
queryFn: () => fetchImmediateChild(),
|
||||
enabled: true,
|
||||
});
|
||||
}
|
||||
|
||||
// GET Services
|
||||
export function useServices() {
|
||||
return useQuery({
|
||||
queryKey: EMPLOYEE_PLAN_KEYS.services,
|
||||
queryFn: () => getServices(),
|
||||
});
|
||||
}
|
||||
|
||||
// GET MY Employee Plans
|
||||
export function useMineEmployeePlan(params: planParam) {
|
||||
const { selectedPositionId } = useAuth();
|
||||
return useQuery({
|
||||
queryKey: ["my-employee-plans", selectedPositionId, params],
|
||||
queryFn: () => getMyEmployeePlan(params),
|
||||
});
|
||||
}
|
||||
|
||||
// GET Employee Plans by Plan ID
|
||||
export function useEmployeePlanByPlanId(planId: string) {
|
||||
const { selectedPositionId } = useAuth();
|
||||
return useQuery({
|
||||
queryKey: [...EMPLOYEE_PLAN_KEYS.planId(planId), selectedPositionId],
|
||||
queryFn: () => getEmployeePlanByPlanId(planId),
|
||||
enabled: !!planId,
|
||||
});
|
||||
}
|
||||
// GET Sub Employee Plans by Plan ID
|
||||
export function useSubEmployeePlanByPlanId(planId: string) {
|
||||
const { selectedPositionId } = useAuth();
|
||||
return useQuery({
|
||||
queryKey: [...EMPLOYEE_PLAN_KEYS.subPlanId(planId), selectedPositionId],
|
||||
queryFn: () => getEmployeeSubPlanByPlanId(planId),
|
||||
enabled: !!planId,
|
||||
});
|
||||
}
|
||||
// GET Parent Employee Plan Detail
|
||||
export function useParentEmployeePlanDetail(id: string) {
|
||||
return useQuery({
|
||||
queryKey: EMPLOYEE_PLAN_KEYS.parentDetail(id),
|
||||
queryFn: () => getParentEmployeePlanDetail(id),
|
||||
enabled: !!id,
|
||||
});
|
||||
}
|
||||
|
||||
// Extended DTO interface to include all fields from your form
|
||||
export interface ExtendedEmployeePlanDto extends CreateEmployeePlanDto {
|
||||
id?: string;
|
||||
}
|
||||
|
||||
// UNIFIED HOOK - Returns all Employee Plan operations in one object
|
||||
export function useEmployeePlanMutations() {
|
||||
const queryClient = useQueryClient();
|
||||
const { t } = useTranslation();
|
||||
const { handleError } = useErrorHandler(t);
|
||||
|
||||
const createMutation = useMutation({
|
||||
mutationFn: (data: ExtendedEmployeePlanDto) => {
|
||||
const { id, ...createData } = data;
|
||||
return createEmployeePlan(createData);
|
||||
},
|
||||
onError: (exception) => {
|
||||
handleError(exception);
|
||||
},
|
||||
});
|
||||
|
||||
const updateMutation = useMutation({
|
||||
mutationFn: (data: ExtendedEmployeePlanDto) => {
|
||||
if (!data.id) {
|
||||
throw new Error("Employee plan ID is required for update");
|
||||
}
|
||||
const { id, ...updateData } = data;
|
||||
return updateEmployeePlan(id, updateData);
|
||||
},
|
||||
onError: (exception) => {
|
||||
handleError(exception);
|
||||
},
|
||||
});
|
||||
|
||||
const deleteMutation = useMutation({
|
||||
mutationFn: (id: string) => deleteEmployeePlan(id),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: EMPLOYEE_PLAN_KEYS.all });
|
||||
toast.success("Employee plan deleted successfully");
|
||||
},
|
||||
onError: (exception) => {
|
||||
queryClient.invalidateQueries({ queryKey: EMPLOYEE_PLAN_KEYS.all });
|
||||
handleError(exception);
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
create: createMutation,
|
||||
update: updateMutation,
|
||||
delete: deleteMutation,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
import { useState, useEffect, useRef, useCallback } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import {
|
||||
metabaseService,
|
||||
MetabaseDashboard,
|
||||
GetIframeUrlRequest,
|
||||
} from "../services/api/metabaseService";
|
||||
|
||||
export const useMetabaseDashboard = () => {
|
||||
const { i18n } = useTranslation();
|
||||
const [dashboards, setDashboards] = useState<MetabaseDashboard[]>([]);
|
||||
const [selectedDashboard, setSelectedDashboard] =
|
||||
useState<MetabaseDashboard | null>(null);
|
||||
const [iframeUrl, setIframeUrl] = useState<string>("");
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const currentRequestRef = useRef<string | null>(null);
|
||||
|
||||
const fetchDashboards = useCallback(async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
const response = await metabaseService.getPermittedDashboards(
|
||||
i18n.language === "am" ? "am" : "en",
|
||||
);
|
||||
setDashboards(response.items);
|
||||
|
||||
// Auto-select the first dashboard if available
|
||||
if (response.items.length > 0 && !selectedDashboard) {
|
||||
setSelectedDashboard(response.items[0]);
|
||||
}
|
||||
} catch (err) {
|
||||
// Handle different error types
|
||||
const error = err as { response?: { status?: number } };
|
||||
if (error?.response?.status === 403) {
|
||||
setError("You don't have permission to access any dashboards");
|
||||
} else if (error?.response?.status === 401) {
|
||||
setError("Please log in to access dashboards");
|
||||
} else {
|
||||
setError("Failed to load dashboards");
|
||||
}
|
||||
console.error("Error fetching permitted dashboards:", err);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [selectedDashboard, i18n.language]);
|
||||
|
||||
const getIframeUrl = useCallback(
|
||||
async (
|
||||
dashboardId: string,
|
||||
params: GetIframeUrlRequest = { params: {} },
|
||||
) => {
|
||||
// Prevent multiple simultaneous requests for the same dashboard
|
||||
if (currentRequestRef.current === dashboardId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
currentRequestRef.current = dashboardId;
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
const response = await metabaseService.getIframeUrl(
|
||||
dashboardId,
|
||||
params,
|
||||
);
|
||||
|
||||
const secureUrl = response.iframeUrl.replace(/^http:\/\//i, "https://");
|
||||
// Only update if this is still the current request
|
||||
if (currentRequestRef.current === dashboardId) {
|
||||
setIframeUrl(secureUrl);
|
||||
}
|
||||
return secureUrl;
|
||||
} catch (err) {
|
||||
if (currentRequestRef.current === dashboardId) {
|
||||
// Handle permission errors specifically
|
||||
const error = err as { response?: { status?: number } };
|
||||
if (error?.response?.status === 403) {
|
||||
setError("You don't have permission to access this dashboard");
|
||||
} else {
|
||||
setError("Failed to load dashboard");
|
||||
}
|
||||
console.error("Error getting iframe URL:", err);
|
||||
}
|
||||
return null;
|
||||
} finally {
|
||||
if (currentRequestRef.current === dashboardId) {
|
||||
setLoading(false);
|
||||
currentRequestRef.current = null;
|
||||
}
|
||||
}
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
const getFilteredDashboardUrl = useCallback(
|
||||
async (dashboardId: string, planYearId: string) => {
|
||||
// Prevent multiple simultaneous requests for the same dashboard
|
||||
const requestKey = `${dashboardId}-${planYearId}`;
|
||||
if (currentRequestRef.current === requestKey) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
currentRequestRef.current = requestKey;
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
const response = await metabaseService.getFilteredDashboardUrl(
|
||||
dashboardId,
|
||||
planYearId,
|
||||
);
|
||||
|
||||
const secureUrl = response.iframeUrl.replace(/^http:\/\//i, "https://");
|
||||
// Only update if this is still the current request
|
||||
if (currentRequestRef.current === requestKey) {
|
||||
setIframeUrl(secureUrl);
|
||||
}
|
||||
return secureUrl;
|
||||
} catch (err) {
|
||||
if (currentRequestRef.current === requestKey) {
|
||||
// Handle permission errors specifically
|
||||
const error = err as { response?: { status?: number } };
|
||||
if (error?.response?.status === 403) {
|
||||
setError("You don't have permission to access this dashboard");
|
||||
} else {
|
||||
setError("Failed to load filtered dashboard");
|
||||
}
|
||||
console.error("Error getting filtered dashboard URL:", err);
|
||||
}
|
||||
return null;
|
||||
} finally {
|
||||
if (currentRequestRef.current === requestKey) {
|
||||
setLoading(false);
|
||||
currentRequestRef.current = null;
|
||||
}
|
||||
}
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
const selectDashboard = useCallback((dashboard: MetabaseDashboard) => {
|
||||
setSelectedDashboard(dashboard);
|
||||
setIframeUrl(""); // Clear previous iframe URL
|
||||
// The useEffect will handle calling getIframeUrl
|
||||
}, []);
|
||||
|
||||
const getDashboardByNumber = useCallback(
|
||||
(dashboardNumber: number) => {
|
||||
return dashboards.find(
|
||||
(d) => d.metabaseDashboardNumber === dashboardNumber,
|
||||
);
|
||||
},
|
||||
[dashboards],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
fetchDashboards();
|
||||
}, [fetchDashboards]);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedDashboard) {
|
||||
getIframeUrl(selectedDashboard.id);
|
||||
}
|
||||
}, [selectedDashboard, getIframeUrl]);
|
||||
|
||||
return {
|
||||
dashboards,
|
||||
selectedDashboard,
|
||||
iframeUrl,
|
||||
loading,
|
||||
error,
|
||||
fetchDashboards,
|
||||
getIframeUrl,
|
||||
getFilteredDashboardUrl,
|
||||
selectDashboard,
|
||||
getDashboardByNumber,
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,184 @@
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { AxiosError, AxiosResponse } from "axios";
|
||||
import {
|
||||
getPlanYears,
|
||||
getPlanYear,
|
||||
createPlanYear,
|
||||
updatePlanYear,
|
||||
deletePlanYear,
|
||||
PlanYearParams,
|
||||
} from "../services/api/planYearService";
|
||||
import { CreatePlanYearDto, PlanYear } from "../types/planYearTypes";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { toast } from "sonner";
|
||||
import { useErrorHandler } from "@/shared/hooks/useErrorHandler";
|
||||
|
||||
// Query keys
|
||||
const PLAN_YEAR_KEYS = {
|
||||
all: ["planYears"] as const,
|
||||
lists: () => [...PLAN_YEAR_KEYS.all, "list"] as const,
|
||||
list: (unitId: string, params?: PlanYearParams) =>
|
||||
[...PLAN_YEAR_KEYS.lists(), unitId, params] as const,
|
||||
details: () => [...PLAN_YEAR_KEYS.all, "detail"] as const,
|
||||
detail: (id: string) => [...PLAN_YEAR_KEYS.details(), id] as const,
|
||||
active: (unitId: string) =>
|
||||
[...PLAN_YEAR_KEYS.all, "active", unitId] as const,
|
||||
};
|
||||
|
||||
// Fetch all plan years
|
||||
export const usePlanYears = (unitId: string, params?: PlanYearParams) => {
|
||||
return useQuery({
|
||||
queryKey: PLAN_YEAR_KEYS.list(unitId, params),
|
||||
queryFn: () => getPlanYears(unitId, params),
|
||||
enabled: !!unitId,
|
||||
staleTime: 300_000,
|
||||
refetchOnWindowFocus: false,
|
||||
});
|
||||
};
|
||||
// Fetch plan year by ID or year number
|
||||
export const usePlanYearById = (id: string) => {
|
||||
return useQuery({
|
||||
queryKey: PLAN_YEAR_KEYS.list(id),
|
||||
queryFn: () => getPlanYear(id),
|
||||
enabled: !!id,
|
||||
staleTime: 300_000,
|
||||
refetchOnWindowFocus: false,
|
||||
});
|
||||
};
|
||||
|
||||
// Fetch plan year by year number (e.g., "2024")
|
||||
export const usePlanYearByNumber = (unitId: string, year: string) => {
|
||||
return useQuery({
|
||||
queryKey: [...PLAN_YEAR_KEYS.all, "byYear", unitId, year],
|
||||
queryFn: async () => {
|
||||
const response = await getPlanYears(unitId, { take: 100 });
|
||||
const planYear = response.data?.items?.find(
|
||||
(py: any) => py.year.toString() === year
|
||||
);
|
||||
if (!planYear) {
|
||||
throw new Error(`Plan year ${year} not found`);
|
||||
}
|
||||
return { data: planYear };
|
||||
},
|
||||
enabled: !!unitId && !!year && /^\d{4}$/.test(year),
|
||||
staleTime: 300_000,
|
||||
refetchOnWindowFocus: false,
|
||||
});
|
||||
};
|
||||
// Fetch single plan year
|
||||
export const usePlanYear = (id: string) => {
|
||||
return useQuery({
|
||||
queryKey: PLAN_YEAR_KEYS.detail(id),
|
||||
queryFn: () => getPlanYear(id),
|
||||
enabled: !!id,
|
||||
staleTime: 300_000,
|
||||
refetchOnWindowFocus: false,
|
||||
});
|
||||
};
|
||||
|
||||
// Hook to resolve year parameter (supports both year number and UUID)
|
||||
export const useResolvedPlanYear = (
|
||||
yearParam: string,
|
||||
unitId: string
|
||||
): {
|
||||
data: any;
|
||||
isLoading: boolean;
|
||||
error: any;
|
||||
yearId: string | null;
|
||||
} => {
|
||||
const isYearNumber = /^\d{4}$/.test(yearParam);
|
||||
|
||||
const byNumber = usePlanYearByNumber(
|
||||
unitId,
|
||||
isYearNumber ? yearParam : ""
|
||||
);
|
||||
const byId = usePlanYearById(!isYearNumber ? yearParam : "");
|
||||
|
||||
if (isYearNumber) {
|
||||
return {
|
||||
data: byNumber.data,
|
||||
isLoading: byNumber.isLoading,
|
||||
error: byNumber.error,
|
||||
yearId: byNumber.data?.data?.id || null,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
data: byId.data,
|
||||
isLoading: byId.isLoading,
|
||||
error: byId.error,
|
||||
yearId: yearParam,
|
||||
};
|
||||
};
|
||||
|
||||
// Mutations
|
||||
export const usePlanYearMutations = () => {
|
||||
const queryClient = useQueryClient();
|
||||
const { t } = useTranslation();
|
||||
const { handleError } = useErrorHandler(t);
|
||||
|
||||
const create = useMutation<
|
||||
AxiosResponse,
|
||||
AxiosError,
|
||||
CreatePlanYearDto,
|
||||
unknown
|
||||
>({
|
||||
mutationFn: createPlanYear,
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: PLAN_YEAR_KEYS.all });
|
||||
toast.success(
|
||||
t("planYear.createdSuccessfully", "Plan year created successfully")
|
||||
);
|
||||
},
|
||||
onError: (error: AxiosError) => {
|
||||
handleError(error);
|
||||
},
|
||||
});
|
||||
|
||||
const update = useMutation<
|
||||
AxiosResponse,
|
||||
AxiosError,
|
||||
CreatePlanYearDto,
|
||||
unknown
|
||||
>({
|
||||
mutationFn: updatePlanYear,
|
||||
onSuccess: (_, variables) => {
|
||||
queryClient.invalidateQueries({ queryKey: PLAN_YEAR_KEYS.all });
|
||||
if (variables.id) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: PLAN_YEAR_KEYS.detail(variables.id),
|
||||
});
|
||||
}
|
||||
toast.success(
|
||||
t("planYear.updatedSuccessfully", "Plan year updated successfully")
|
||||
);
|
||||
},
|
||||
onError: (error: AxiosError) => {
|
||||
handleError(error);
|
||||
},
|
||||
});
|
||||
|
||||
const deleteMutation = useMutation<
|
||||
AxiosResponse,
|
||||
AxiosError,
|
||||
string,
|
||||
unknown
|
||||
>({
|
||||
mutationFn: deletePlanYear,
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: PLAN_YEAR_KEYS.all });
|
||||
toast.success(
|
||||
t("planYear.deletedSuccessfully", "Plan year deleted successfully")
|
||||
);
|
||||
},
|
||||
onError: (error: AxiosError) => {
|
||||
handleError(error);
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
create,
|
||||
update,
|
||||
delete: deleteMutation,
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,201 @@
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { useAuth } from "@/shared/context/AuthContext";
|
||||
import {
|
||||
approvePlan,
|
||||
createPlan,
|
||||
CreatePlanDto,
|
||||
deletePlan,
|
||||
getMinePlan,
|
||||
getMySubPlans,
|
||||
getPlan,
|
||||
getPlanList,
|
||||
getSectorList,
|
||||
getSubPlans,
|
||||
getTeamSubPlans,
|
||||
PlanParams,
|
||||
rejectPlan,
|
||||
requestApproval,
|
||||
updatePlan,
|
||||
} from "../services/api/planService";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useErrorHandler } from "@/shared/hooks/useErrorHandler";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { toast } from "sonner";
|
||||
import { MeDto } from "@/shared/dto/user/meDto";
|
||||
import { SectorListParam } from "../types/planTypes";
|
||||
|
||||
// Query Keys
|
||||
const Plan_KEYS = {
|
||||
all: ["plans"] as const,
|
||||
list: (id: string, params?: PlanParams) =>
|
||||
["plans", "list", id, params] as const,
|
||||
detail: (id: string) => ["plans", id] as const,
|
||||
};
|
||||
|
||||
// Helper function to check if user is unit admin
|
||||
export const checkIsUnitAdmin = (user: MeDto | null): boolean => {
|
||||
if (!user || !user.roles) return false;
|
||||
return user.roles.some((role) => role.key === "unit_admin");
|
||||
};
|
||||
|
||||
export const checkIsPlanInitiator = (
|
||||
user: MeDto | null,
|
||||
positionId?: string
|
||||
): boolean => {
|
||||
if (!user || !user.employee) return false;
|
||||
|
||||
if (positionId) {
|
||||
// Check specific position
|
||||
return user.employee.some((emp) =>
|
||||
emp.positions.some(
|
||||
(pos) =>
|
||||
pos.employeePositionId === positionId &&
|
||||
pos.permissions.some((perm) => perm.key === "can:initiatePlan")
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Check all positions (fallback)
|
||||
return user.employee.some((emp) =>
|
||||
emp.positions.some((pos) =>
|
||||
pos.permissions.some((perm) => perm.key === "can:initiatePlan")
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
// GET SINGLE Plan
|
||||
export function usePlan(id: string) {
|
||||
return useQuery({
|
||||
queryKey: Plan_KEYS.detail(id),
|
||||
queryFn: () => getPlan(id),
|
||||
enabled: !!id,
|
||||
});
|
||||
}
|
||||
export function useSectorList(id?: string) {
|
||||
return useQuery({
|
||||
queryKey: ["plans-sector", "sector", id],
|
||||
queryFn: () => getSectorList(id),
|
||||
enabled: !!id,
|
||||
});
|
||||
}
|
||||
|
||||
export function useMinePlan(params?: SectorListParam) {
|
||||
const { selectedPositionId } = useAuth();
|
||||
return useQuery({
|
||||
// Include selectedPositionId in the key so switching positions yields a
|
||||
// distinct cache entry and refetches with the up-to-date header.
|
||||
queryKey: ["my-plans", selectedPositionId, params],
|
||||
queryFn: () => getMinePlan(params),
|
||||
});
|
||||
}
|
||||
// GET Plan LIST with optional params filtering
|
||||
export function usePlanList(unitId: string, params?: PlanParams) {
|
||||
return useQuery({
|
||||
queryKey: Plan_KEYS.list(unitId, params),
|
||||
queryFn: () => getPlanList(unitId, params),
|
||||
enabled: !!unitId,
|
||||
});
|
||||
}
|
||||
|
||||
export function useSubPlans(id: string) {
|
||||
return useQuery({
|
||||
queryKey: ["plans", "sub-plans", id],
|
||||
queryFn: () => getSubPlans(id),
|
||||
enabled: !!id,
|
||||
});
|
||||
}
|
||||
export function useMySubPlans(id: string) {
|
||||
return useQuery({
|
||||
queryKey: ["plans", "my-sub-plans", id],
|
||||
queryFn: () => getMySubPlans(id),
|
||||
enabled: !!id,
|
||||
});
|
||||
}
|
||||
export function useTeamSubPlans(id: string) {
|
||||
return useQuery({
|
||||
queryKey: ["plans", "team-sub-plans", id],
|
||||
queryFn: () => getTeamSubPlans(id),
|
||||
enabled: !!id,
|
||||
});
|
||||
}
|
||||
//UNIFIED HOOK - Returns all Plan operations in one object
|
||||
export function usePlanMutations() {
|
||||
const queryClient = useQueryClient();
|
||||
const { t } = useTranslation();
|
||||
const { handleError } = useErrorHandler(t);
|
||||
const createMutation = useMutation({
|
||||
mutationFn: (data: CreatePlanDto) => createPlan(data),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: Plan_KEYS.all });
|
||||
toast("Plan created successfully");
|
||||
},
|
||||
onError: (exception) => {
|
||||
queryClient.invalidateQueries({ queryKey: Plan_KEYS.all });
|
||||
handleError(exception);
|
||||
},
|
||||
});
|
||||
|
||||
const updateMutation = useMutation({
|
||||
mutationFn: (data: CreatePlanDto) => updatePlan(data),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: Plan_KEYS.all });
|
||||
},
|
||||
onError: (exception) => {
|
||||
queryClient.invalidateQueries({ queryKey: Plan_KEYS.all });
|
||||
handleError(exception);
|
||||
},
|
||||
});
|
||||
const requestApprovalMutation = useMutation({
|
||||
mutationFn: (id: string) => requestApproval(id),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: Plan_KEYS.all });
|
||||
toast("Plan Approval Requested successfully");
|
||||
},
|
||||
onError: (exception) => {
|
||||
queryClient.invalidateQueries({ queryKey: Plan_KEYS.all });
|
||||
handleError(exception);
|
||||
},
|
||||
});
|
||||
const approveMutation = useMutation({
|
||||
mutationFn: (id: string) => approvePlan(id),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: Plan_KEYS.all });
|
||||
toast("Plan Approved successfully");
|
||||
},
|
||||
onError: (exception) => {
|
||||
queryClient.invalidateQueries({ queryKey: Plan_KEYS.all });
|
||||
handleError(exception);
|
||||
},
|
||||
});
|
||||
const rejectMutation = useMutation({
|
||||
mutationFn: (id: string) => rejectPlan(id),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: Plan_KEYS.all });
|
||||
toast("Plan Rejected successfully");
|
||||
},
|
||||
onError: (exception) => {
|
||||
queryClient.invalidateQueries({ queryKey: Plan_KEYS.all });
|
||||
handleError(exception);
|
||||
},
|
||||
});
|
||||
const deleteMutation = useMutation({
|
||||
mutationFn: (id: string) => deletePlan(id),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: Plan_KEYS.all });
|
||||
toast("Plan deleted successfully");
|
||||
},
|
||||
onError: (exception) => {
|
||||
queryClient.invalidateQueries({ queryKey: Plan_KEYS.all });
|
||||
handleError(exception);
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
create: createMutation,
|
||||
update: updateMutation,
|
||||
delete: deleteMutation,
|
||||
requestApproval: requestApprovalMutation,
|
||||
approve: approveMutation,
|
||||
reject: rejectMutation,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import {
|
||||
serviceCategoryService,
|
||||
CreateServiceCategoryRequest,
|
||||
} from "../services/api/serviceCategoryService";
|
||||
import { useErrorHandler } from "@/shared/hooks/useErrorHandler";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { toast } from "sonner";
|
||||
|
||||
// Query Keys
|
||||
const SERVICE_CATEGORY_KEYS = {
|
||||
all: ["service-categories"] as const,
|
||||
list: (organizationId: string) =>
|
||||
["service-categories", "list", organizationId] as const,
|
||||
};
|
||||
|
||||
// GET SERVICE CATEGORY LIST
|
||||
export function useServiceCategoryList(organizationId: string) {
|
||||
return useQuery({
|
||||
queryKey: SERVICE_CATEGORY_KEYS.list(organizationId),
|
||||
queryFn: () => serviceCategoryService.getList(organizationId),
|
||||
enabled: !!organizationId,
|
||||
});
|
||||
}
|
||||
|
||||
// 🎯 UNIFIED HOOK - Returns all service category operations in one object
|
||||
export function useServiceCategoryMutations() {
|
||||
const queryClient = useQueryClient();
|
||||
const { t } = useTranslation();
|
||||
const { handleError } = useErrorHandler(t);
|
||||
|
||||
const createMutation = useMutation({
|
||||
mutationFn: (data: CreateServiceCategoryRequest) =>
|
||||
serviceCategoryService.create(data),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: SERVICE_CATEGORY_KEYS.all });
|
||||
toast("Service Category created successfully");
|
||||
},
|
||||
onError: (exception) => {
|
||||
handleError(exception);
|
||||
},
|
||||
});
|
||||
|
||||
const updateMutation = useMutation({
|
||||
mutationFn: ({
|
||||
id,
|
||||
data,
|
||||
}: {
|
||||
id: string;
|
||||
data: CreateServiceCategoryRequest;
|
||||
}) => serviceCategoryService.update(id, data),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: SERVICE_CATEGORY_KEYS.all });
|
||||
toast("Service Category updated successfully");
|
||||
},
|
||||
onError: (exception) => {
|
||||
handleError(exception);
|
||||
},
|
||||
});
|
||||
|
||||
const deleteMutation = useMutation({
|
||||
mutationFn: (id: string) => serviceCategoryService.delete(id),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: SERVICE_CATEGORY_KEYS.all });
|
||||
toast("Service Category deleted successfully");
|
||||
},
|
||||
onError: (exception) => {
|
||||
handleError(exception);
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
create: createMutation,
|
||||
update: updateMutation,
|
||||
delete: deleteMutation,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import {
|
||||
createService,
|
||||
updateService,
|
||||
deleteService,
|
||||
getService,
|
||||
getServiceList,
|
||||
CreateServiceDto,
|
||||
} from "../services/api/performanceService";
|
||||
import { useAuth } from "@/shared/context/AuthContext";
|
||||
import { useUnit } from "@/user-management/hooks/useUnit";
|
||||
import { useErrorHandler } from "@/shared/hooks/useErrorHandler";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { toast } from "sonner";
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
|
||||
// Query Keys
|
||||
const SERVICE_KEYS = {
|
||||
all: ["services"] as const,
|
||||
list: (id: string) => ["services", "list", id] as const,
|
||||
detail: (id: string) => ["services", id] as const,
|
||||
};
|
||||
|
||||
// GET SINGLE SERVICE
|
||||
export function useService(id: string) {
|
||||
return useQuery({
|
||||
queryKey: SERVICE_KEYS.detail(id),
|
||||
queryFn: () => getService(id),
|
||||
enabled: !!id,
|
||||
});
|
||||
}
|
||||
|
||||
// GET SERVICE LIST
|
||||
export function useServiceList(
|
||||
organizationId: string,
|
||||
serviceCategoryId?: string,
|
||||
parentServiceId?: string
|
||||
) {
|
||||
// react-query
|
||||
const queryKey = [
|
||||
...SERVICE_KEYS.list(organizationId as string),
|
||||
...(serviceCategoryId ? [serviceCategoryId] : []),
|
||||
...(parentServiceId ? [parentServiceId] : []),
|
||||
];
|
||||
|
||||
return useQuery({
|
||||
queryKey,
|
||||
queryFn: () =>
|
||||
getServiceList(
|
||||
organizationId as string,
|
||||
serviceCategoryId,
|
||||
parentServiceId
|
||||
),
|
||||
enabled: !!organizationId, // only fetch when organizationId exists
|
||||
});
|
||||
}
|
||||
|
||||
// 🎯 UNIFIED HOOK - Returns all service operations in one object
|
||||
export function useServiceMutations() {
|
||||
const queryClient = useQueryClient();
|
||||
const { t } = useTranslation();
|
||||
const { handleError } = useErrorHandler(t);
|
||||
const navigate = useNavigate();
|
||||
|
||||
const createMutation = useMutation({
|
||||
mutationFn: (data: CreateServiceDto) => createService(data),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: SERVICE_KEYS.all });
|
||||
toast("Service created successfully");
|
||||
navigate(`/performance-management/services`);
|
||||
},
|
||||
onError: (exception) => {
|
||||
queryClient.invalidateQueries({ queryKey: SERVICE_KEYS.all });
|
||||
handleError(exception);
|
||||
},
|
||||
});
|
||||
|
||||
const updateMutation = useMutation({
|
||||
mutationFn: (data: CreateServiceDto) => updateService(data),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: SERVICE_KEYS.all });
|
||||
toast("Service updated successfully");
|
||||
navigate(`/performance-management/services`);
|
||||
},
|
||||
onError: (exception) => {
|
||||
queryClient.invalidateQueries({ queryKey: SERVICE_KEYS.all });
|
||||
handleError(exception);
|
||||
},
|
||||
});
|
||||
|
||||
const deleteMutation = useMutation({
|
||||
mutationFn: (id: string) => deleteService(id),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: SERVICE_KEYS.all });
|
||||
toast("Service deleted successfully");
|
||||
navigate(`/performance-management/services`);
|
||||
},
|
||||
onError: (exception) => {
|
||||
queryClient.invalidateQueries({ queryKey: SERVICE_KEYS.all });
|
||||
handleError(exception);
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
create: createMutation,
|
||||
update: updateMutation,
|
||||
delete: deleteMutation,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import {
|
||||
createPlanBulkTeamMember,
|
||||
CreatePlanBulkTeamMemberDto,
|
||||
createPlanTeam,
|
||||
CreatePlanTeamDto,
|
||||
createPlanTeamMember,
|
||||
CreatePlanTeamMemberDto,
|
||||
deletePlanTeam,
|
||||
deletePlanTeamMember,
|
||||
getPlanTeamList,
|
||||
getPlanTeamMemberList,
|
||||
updatePlanTeam,
|
||||
updatePlanTeamMember,
|
||||
} from "../services/api/planTeamServices";
|
||||
import { toast } from "sonner";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useErrorHandler } from "@/shared/hooks/useErrorHandler";
|
||||
import { getEnvUrl } from "@/shared/config/env";
|
||||
import { id } from "date-fns/locale";
|
||||
|
||||
// Fetch teams
|
||||
export const usePlanTeamList = (id: string, options?: { enabled?: boolean }) =>
|
||||
useQuery({
|
||||
queryKey: ["plan-team-list", id],
|
||||
queryFn: () => getPlanTeamList(id),
|
||||
enabled: options?.enabled !== false && !!id, // Only fetch when enabled and id exists
|
||||
});
|
||||
|
||||
export const usePlanTeamMemberList = (
|
||||
id: string,
|
||||
options?: { enabled?: boolean },
|
||||
) =>
|
||||
useQuery({
|
||||
queryKey: ["plan-team-member-list", id],
|
||||
queryFn: () => getPlanTeamMemberList(id),
|
||||
enabled: options?.enabled !== false && !!id, // Only fetch when enabled and id exists
|
||||
});
|
||||
|
||||
export const usePlanTeamMutation = () => {
|
||||
const { t } = useTranslation();
|
||||
const { handleError } = useErrorHandler(t);
|
||||
const queryClient = useQueryClient();
|
||||
const createPlanTeamMutation = useMutation({
|
||||
mutationFn: ({ data }: { data: CreatePlanTeamDto }) => createPlanTeam(data),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ["plan-team-list"] });
|
||||
},
|
||||
onError: (error) => {
|
||||
handleError(error);
|
||||
},
|
||||
});
|
||||
|
||||
const updatePlanTeamMutation = useMutation({
|
||||
mutationFn: ({ id, data }: { id: string; data: CreatePlanTeamDto }) =>
|
||||
updatePlanTeam(id, data),
|
||||
onSuccess: () => {},
|
||||
onError: (error) => {
|
||||
handleError(error);
|
||||
},
|
||||
});
|
||||
|
||||
const deletePlanTeamMutation = useMutation({
|
||||
mutationFn: ({ id }: { id: string }) => deletePlanTeam(id),
|
||||
onSuccess: () => {
|
||||
toast.success("Plan team deleted successfully");
|
||||
},
|
||||
onError: (error) => {
|
||||
handleError(error);
|
||||
},
|
||||
});
|
||||
|
||||
const createPlanTeamMemberMutation = useMutation({
|
||||
mutationFn: ({ data }: { data: CreatePlanTeamMemberDto }) =>
|
||||
createPlanTeamMember(data),
|
||||
onSuccess: () => {
|
||||
toast.success("Plan team member created successfully");
|
||||
},
|
||||
onError: (error) => {
|
||||
handleError(error);
|
||||
},
|
||||
});
|
||||
const createPlanBulkTeamMemberMutation = useMutation({
|
||||
mutationFn: ({ data }: { data: CreatePlanBulkTeamMemberDto }) =>
|
||||
createPlanBulkTeamMember(data),
|
||||
onSuccess: () => {
|
||||
toast.success("Plan team member created successfully");
|
||||
},
|
||||
onError: (error) => {
|
||||
handleError(error);
|
||||
},
|
||||
});
|
||||
const updatePlanTeamMemberMutation = useMutation({
|
||||
mutationFn: ({ id, data }: { id: string; data: CreatePlanTeamMemberDto }) =>
|
||||
updatePlanTeamMember(id, data),
|
||||
onSuccess: () => {
|
||||
toast.success("Plan team member updated successfully");
|
||||
},
|
||||
onError: (error) => {
|
||||
handleError(error);
|
||||
},
|
||||
});
|
||||
|
||||
const deletePlanTeamMemberMutation = useMutation({
|
||||
mutationFn: deletePlanTeamMember,
|
||||
onSuccess: () => {
|
||||
toast.success("Plan team member deleted successfully");
|
||||
},
|
||||
onError: (error) => {
|
||||
handleError(error);
|
||||
},
|
||||
});
|
||||
return {
|
||||
createPlanTeam: createPlanTeamMutation.mutate,
|
||||
isLoading: createPlanTeamMutation.isPending,
|
||||
isError: createPlanTeamMutation.isError,
|
||||
error: createPlanTeamMutation.error,
|
||||
updatePlanTeam: updatePlanTeamMutation.mutate,
|
||||
deletePlanTeam: deletePlanTeamMutation.mutate,
|
||||
createPlanTeamMember: createPlanTeamMemberMutation.mutate,
|
||||
updatePlanTeamMember: updatePlanTeamMemberMutation.mutate,
|
||||
deletePlanTeamMember: deletePlanTeamMemberMutation.mutate,
|
||||
isPlanTeamLoading: updatePlanTeamMutation.isPending,
|
||||
isPlanTeamError: updatePlanTeamMutation.isError,
|
||||
planTeamError: updatePlanTeamMutation.error,
|
||||
isPlanTeamMemberLoading: deletePlanTeamMutation.isPending,
|
||||
isPlanTeamMemberError: deletePlanTeamMutation.isError,
|
||||
planTeamMemberError: deletePlanTeamMutation.error,
|
||||
isPlanTeamMemberCreateLoading: createPlanTeamMemberMutation.isPending,
|
||||
isPlanTeamMemberCreateError: createPlanTeamMemberMutation.isError,
|
||||
planTeamMemberCreateError: createPlanTeamMemberMutation.error,
|
||||
isPlanTeamMemberUpdateLoading: updatePlanTeamMemberMutation.isPending,
|
||||
isPlanTeamMemberUpdateError: updatePlanTeamMemberMutation.isError,
|
||||
planTeamMemberUpdateError: updatePlanTeamMemberMutation.error,
|
||||
isPlanTeamMemberDeleteLoading: deletePlanTeamMemberMutation.isPending,
|
||||
isPlanTeamMemberDeleteError: deletePlanTeamMemberMutation.isError,
|
||||
planTeamMemberDeleteError: deletePlanTeamMemberMutation.error,
|
||||
createPlanBulkTeamMember: createPlanBulkTeamMemberMutation.mutate,
|
||||
isPlanBulkTeamMemberCreateLoading:
|
||||
createPlanBulkTeamMemberMutation.isPending,
|
||||
};
|
||||
};
|
||||
// Fetch users for team member selection
|
||||
export const useUsers = () =>
|
||||
useQuery({
|
||||
queryKey: ["users"],
|
||||
queryFn: async () => {
|
||||
const apiBaseUrl = getEnvUrl("VITE_API_URL");
|
||||
const response = await fetch(`${apiBaseUrl}/users/active`);
|
||||
return response.json();
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,75 @@
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { toast } from "sonner";
|
||||
import {
|
||||
createWorkingHours,
|
||||
getWorkingHoursList,
|
||||
getWorkingHoursByPositionServiceId,
|
||||
updateWorkingHours,
|
||||
deleteWorkingHours,
|
||||
} from "../services/api/workingHoursService";
|
||||
import { CreateWorkingHoursDto } from "../types/workingHoursTypes";
|
||||
import { useErrorHandler } from "@/shared/hooks/useErrorHandler";
|
||||
|
||||
export const useWorkingHoursList = () => {
|
||||
return useQuery({
|
||||
queryKey: ["workingHours"],
|
||||
queryFn: getWorkingHoursList,
|
||||
});
|
||||
};
|
||||
|
||||
export const useWorkingHoursByPositionService = (positionServiceId: string) => {
|
||||
return useQuery({
|
||||
queryKey: ["workingHours", positionServiceId],
|
||||
queryFn: () => getWorkingHoursByPositionServiceId(positionServiceId),
|
||||
enabled: !!positionServiceId,
|
||||
});
|
||||
};
|
||||
|
||||
export const useWorkingHoursMutations = () => {
|
||||
const queryClient = useQueryClient();
|
||||
const { t } = useTranslation();
|
||||
const { handleError } = useErrorHandler(t);
|
||||
|
||||
const create = useMutation({
|
||||
mutationFn: (data: CreateWorkingHoursDto) => createWorkingHours(data),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ["workingHours"] });
|
||||
toast.success(
|
||||
t("workingHours.createdSuccessfully", "Working hours created successfully")
|
||||
);
|
||||
},
|
||||
onError: (error: any) => {
|
||||
handleError(error);
|
||||
},
|
||||
});
|
||||
|
||||
const update = useMutation({
|
||||
mutationFn: ({ id, data }: { id: string; data: CreateWorkingHoursDto }) =>
|
||||
updateWorkingHours(id, data),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ["workingHours"] });
|
||||
toast.success(
|
||||
t("workingHours.updatedSuccessfully", "Working hours updated successfully")
|
||||
);
|
||||
},
|
||||
onError: (error: any) => {
|
||||
handleError(error);
|
||||
},
|
||||
});
|
||||
|
||||
const deleteHours = useMutation({
|
||||
mutationFn: (id: string) => deleteWorkingHours(id),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ["workingHours"] });
|
||||
toast.success(
|
||||
t("workingHours.deletedSuccessfully", "Working hours deleted successfully")
|
||||
);
|
||||
},
|
||||
onError: (error: any) => {
|
||||
handleError(error);
|
||||
},
|
||||
});
|
||||
|
||||
return { create, update, delete: deleteHours };
|
||||
};
|
||||
Reference in New Issue
Block a user