docker exefix: reimplement the admin form

This commit is contained in:
Nathnael
2026-07-23 11:48:08 +00:00
parent cbff529e31
commit d47e3ae4f5
8 changed files with 659 additions and 141 deletions

View File

@@ -1,14 +1,16 @@
import { useState } from "react";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { toast } from "sonner";
import { useTranslation } from "react-i18next";
import { useErrorHandler } from "@/shared/hooks/useErrorHandler";
import {
assignOrganizationAdmin,
assignUnitAdmin,
fetchAllUnitAdminById,
OrganizationAdminPayload,
} from "@/super-admin/services/api/organizationAdminService";
import {
assignOrgAdminRole,
assignUnitAdminRole,
removeOrgAdminRole,
removeUnitAdminRole,
} from "@/super-admin/services/api/userRoleService";
@@ -54,13 +56,42 @@ export interface RemoveAdminInput {
unitId?: string;
}
export interface AddAdminInput {
organizationId: string;
/** set → create as unit admin of this unit instead of org admin */
unitId?: string;
name: { am: string; en: string };
username: string;
email: string;
phoneNumber: string;
}
export const useOrgAdmins = (
orgId?: string,
params?: { take?: number; skip?: number },
) => {
const queryClient = useQueryClient();
const { t } = useTranslation();
const { handleError } = useErrorHandler(t);
const { handleError, getErrorMessage } = useErrorHandler(t);
// dialog mutations surface their API errors inline, not via toast
const [formError, setFormError] = useState<string | null>(null);
const [assignError, setAssignError] = useState<string | null>(null);
const [removeError, setRemoveError] = useState<string | null>(null);
const [toggleError, setToggleError] = useState<string | null>(null);
const inlineError =
(set: (message: string | null) => void) => async (err: unknown) => {
console.error(err);
set(await getErrorMessage(err));
};
const clearErrors = () => {
setFormError(null);
setAssignError(null);
setRemoveError(null);
setToggleError(null);
};
const {
data: adminsResponse,
@@ -89,28 +120,49 @@ export const useOrgAdmins = (
queryClient.invalidateQueries({ queryKey: ["organizationAdmins"] });
};
const { mutate: inviteAdmin, isPending: isInviting } = useMutation({
mutationFn: async (payload: OrganizationAdminPayload) => {
const { data } = await assignOrganizationAdmin(payload);
const { mutate: addAdmin, isPending: isAdding } = useMutation({
mutationFn: async ({
organizationId,
unitId,
...person
}: AddAdminInput) => {
// both iam invite endpoints create the user (employee + role +
// SET_PASSWORD OTP in one tx); unitId decides the admin scope
const { data } = unitId
? await assignUnitAdmin({ unitId, ...person })
: await assignOrganizationAdmin({ organizationId, ...person });
return data;
},
onMutate: () => setFormError(null),
onSuccess: () => {
toast.success(t("orgAdmins.toasts.invited"));
toast.success(t("orgAdmins.toasts.added"));
invalidate();
},
onError: handleError,
onError: inlineError(setFormError),
});
const { mutate: assignAdmin, isPending: isAssigning } = useMutation({
mutationFn: async (payload: { organizationId: string; userId: string }) => {
const { data } = await assignOrgAdminRole(payload);
mutationFn: async ({
organizationId,
userId,
unitId,
}: {
organizationId: string;
userId: string;
/** set → grant unit-admin of this unit instead of org-admin */
unitId?: string;
}) => {
const { data } = unitId
? await assignUnitAdminRole({ unitId, userId })
: await assignOrgAdminRole({ organizationId, userId });
return data;
},
onMutate: () => setAssignError(null),
onSuccess: () => {
toast.success(t("orgAdmins.toasts.assigned"));
invalidate();
},
onError: handleError,
onError: inlineError(setAssignError),
});
const { mutate: removeAdmin, isPending: isRemoving } = useMutation({
@@ -123,11 +175,12 @@ export const useOrgAdmins = (
});
return data;
},
onMutate: () => setRemoveError(null),
onSuccess: () => {
toast.success(t("orgAdmins.toasts.removed"));
invalidate();
},
onError: handleError,
onError: inlineError(setRemoveError),
});
const { mutate: resendInvite, isPending: isResending } = useMutation({
@@ -148,6 +201,7 @@ export const useOrgAdmins = (
: await deactivateUser(id);
return data;
},
onMutate: () => setToggleError(null),
onSuccess: (_data, variables) => {
toast.success(
variables.activate
@@ -156,7 +210,7 @@ export const useOrgAdmins = (
);
invalidate();
},
onError: handleError,
onError: inlineError(setToggleError),
});
const { mutate: updateAdminProfile, isPending: isUpdatingProfile } =
@@ -171,11 +225,12 @@ export const useOrgAdmins = (
const { data } = await updateProfile(payload, id);
return data;
},
onMutate: () => setFormError(null),
onSuccess: () => {
toast.success(t("orgAdmins.toasts.profileUpdated"));
invalidate();
},
onError: handleError,
onError: inlineError(setFormError),
});
return {
@@ -183,8 +238,8 @@ export const useOrgAdmins = (
isLoading,
isError,
refetch,
inviteAdmin,
isInviting,
addAdmin,
isAdding,
assignAdmin,
isAssigning,
removeAdmin,
@@ -195,5 +250,10 @@ export const useOrgAdmins = (
isToggling,
updateAdminProfile,
isUpdatingProfile,
formError,
assignError,
removeError,
toggleError,
clearErrors,
};
};