role filter and login issue
This commit is contained in:
@@ -16,7 +16,8 @@ export const rolesApi = {
|
|||||||
getById: (roleId: string) =>
|
getById: (roleId: string) =>
|
||||||
apiClient.get<RoleWithAccesses>(`/api/role/get/${roleId}`),
|
apiClient.get<RoleWithAccesses>(`/api/role/get/${roleId}`),
|
||||||
|
|
||||||
getAccesses: () => apiClient.get<RoleAccess[]>("/api/access/get"),
|
getAccesses: (tenantId?: string) =>
|
||||||
|
apiClient.get<RoleAccess[]>(`/api/access/get${tenantId ? `?tenant_id=${encodeURIComponent(tenantId)}` : ""}`),
|
||||||
|
|
||||||
create: (payload: RoleCreateRequest) =>
|
create: (payload: RoleCreateRequest) =>
|
||||||
apiClient.post<Role>("/api/role/create", payload, { successMessage: "Role created successfully", errorMessage: "Failed to create role" }),
|
apiClient.post<Role>("/api/role/create", payload, { successMessage: "Role created successfully", errorMessage: "Failed to create role" }),
|
||||||
|
|||||||
@@ -40,12 +40,17 @@ const AddRoles = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let isMounted = true;
|
let isMounted = true;
|
||||||
const loadAccesses = async () => {
|
const loadAccesses = async (tenantId?: string) => {
|
||||||
setIsAccessLoading(true);
|
setIsAccessLoading(true);
|
||||||
try {
|
try {
|
||||||
const data = await rolesApi.getAccesses();
|
const data = await rolesApi.getAccesses(tenantId || undefined);
|
||||||
if (isMounted) {
|
if (isMounted) {
|
||||||
setAccessOptions(data);
|
setAccessOptions(data);
|
||||||
|
const validIds = new Set(data.map((d) => d.id));
|
||||||
|
setFormData((prev) => ({
|
||||||
|
...prev,
|
||||||
|
access_ids: (prev.access_ids || []).filter((id) => validIds.has(id)),
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (isMounted) {
|
if (isMounted) {
|
||||||
@@ -128,44 +133,55 @@ const AddRoles = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
loadAccesses();
|
|
||||||
loadTenants();
|
loadTenants();
|
||||||
return () => {
|
return () => {
|
||||||
isMounted = false;
|
isMounted = false;
|
||||||
};
|
};
|
||||||
}, [canReadAllTenants, isAuthLoading, user?.tenant_id, user?.tenant_name]);
|
}, [canReadAllTenants, isAuthLoading, user?.tenant_id, user?.tenant_name]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isAuthLoading) return;
|
||||||
|
let isMounted = true;
|
||||||
|
const loadAccesses = async () => {
|
||||||
|
setIsAccessLoading(true);
|
||||||
|
try {
|
||||||
|
const data = await rolesApi.getAccesses(formData.tenant_id || undefined);
|
||||||
|
if (isMounted) {
|
||||||
|
setAccessOptions(data);
|
||||||
|
const validIds = new Set(data.map((d) => d.id));
|
||||||
|
setFormData((prev) => ({
|
||||||
|
...prev,
|
||||||
|
access_ids: (prev.access_ids || []).filter((id) => validIds.has(id)),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
if (isMounted) {
|
||||||
|
const message =
|
||||||
|
error instanceof Error
|
||||||
|
? error.message
|
||||||
|
: "Unable to load access options.";
|
||||||
|
setErrorMessage(message);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (isMounted) {
|
||||||
|
setIsAccessLoading(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
loadAccesses();
|
||||||
|
return () => {
|
||||||
|
isMounted = false;
|
||||||
|
};
|
||||||
|
}, [formData.tenant_id, isAuthLoading]);
|
||||||
|
|
||||||
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
const { name, value } = event.target;
|
const { name, value } = event.target;
|
||||||
setFormData((prev) => ({ ...prev, [name]: value }));
|
setFormData((prev) => ({ ...prev, [name]: value }));
|
||||||
};
|
};
|
||||||
|
|
||||||
const availableAccessOptions = useMemo(() => {
|
const availableAccessOptions = useMemo(() => {
|
||||||
if (canReadAllTenants) return accessOptions;
|
return accessOptions;
|
||||||
|
}, [accessOptions]);
|
||||||
if (!user?.role?.accesses) return [];
|
|
||||||
|
|
||||||
const accessMap = new Map(accessOptions.map((a) => [a.id, a]));
|
|
||||||
const includedIds = new Set<string>();
|
|
||||||
|
|
||||||
accessOptions.forEach((option) => {
|
|
||||||
if (user.role?.accesses.includes(option.access_code)) {
|
|
||||||
let current: RoleAccess | undefined = option;
|
|
||||||
while (current) {
|
|
||||||
if (includedIds.has(current.id)) break;
|
|
||||||
includedIds.add(current.id);
|
|
||||||
|
|
||||||
if (current.parent_id) {
|
|
||||||
current = accessMap.get(current.parent_id);
|
|
||||||
} else {
|
|
||||||
current = undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return accessOptions.filter((option) => includedIds.has(option.id));
|
|
||||||
}, [accessOptions, user, canReadAllTenants]);
|
|
||||||
|
|
||||||
const handleSubmit = async (event: React.FormEvent) => {
|
const handleSubmit = async (event: React.FormEvent) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|||||||
@@ -94,31 +94,8 @@ const AllRoles = () => {
|
|||||||
const [isDeleting, setIsDeleting] = useState(false);
|
const [isDeleting, setIsDeleting] = useState(false);
|
||||||
|
|
||||||
const availableAccessOptions = useMemo(() => {
|
const availableAccessOptions = useMemo(() => {
|
||||||
if (canReadAllTenants) return accessOptions;
|
return accessOptions;
|
||||||
|
}, [accessOptions]);
|
||||||
if (!currentUser?.role?.accesses) return [];
|
|
||||||
|
|
||||||
const accessMap = new Map(accessOptions.map((a) => [a.id, a]));
|
|
||||||
const includedIds = new Set<string>();
|
|
||||||
|
|
||||||
accessOptions.forEach((option) => {
|
|
||||||
if (currentUser.role?.accesses.includes(option.access_code)) {
|
|
||||||
let current: RoleAccess | undefined = option;
|
|
||||||
while (current) {
|
|
||||||
if (includedIds.has(current.id)) break;
|
|
||||||
includedIds.add(current.id);
|
|
||||||
|
|
||||||
if (current.parent_id) {
|
|
||||||
current = accessMap.get(current.parent_id);
|
|
||||||
} else {
|
|
||||||
current = undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return accessOptions.filter((option) => includedIds.has(option.id));
|
|
||||||
}, [accessOptions, currentUser, canReadAllTenants]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let isMounted = true;
|
let isMounted = true;
|
||||||
@@ -267,7 +244,11 @@ const AllRoles = () => {
|
|||||||
setEditError("");
|
setEditError("");
|
||||||
setIsEditOpen(true);
|
setIsEditOpen(true);
|
||||||
try {
|
try {
|
||||||
const details = await rolesApi.getById(role.id);
|
const [details, tenantAccesses] = await Promise.all([
|
||||||
|
rolesApi.getById(role.id),
|
||||||
|
rolesApi.getAccesses(role.tenant_id || undefined),
|
||||||
|
]);
|
||||||
|
setAccessOptions(tenantAccesses);
|
||||||
setEditAccessIds(details.accesses?.map((a) => a.id) || []);
|
setEditAccessIds(details.accesses?.map((a) => a.id) || []);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setEditError(err instanceof Error ? err.message : t('messages.error'));
|
setEditError(err instanceof Error ? err.message : t('messages.error'));
|
||||||
|
|||||||
@@ -33,15 +33,10 @@ export const AuthProvider: React.FC<{ children: ReactNode }> = ({
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const bootstrapAuth = async () => {
|
const bootstrapAuth = async () => {
|
||||||
const token = getAccessToken();
|
|
||||||
if (!token) {
|
|
||||||
setIsLoading(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const userData = await authApi.me();
|
const userData = await authApi.me();
|
||||||
setUser(userData);
|
setUser(userData);
|
||||||
|
setAuthCookies(null, true);
|
||||||
|
|
||||||
const preferred = userData.preferred_language;
|
const preferred = userData.preferred_language;
|
||||||
if (preferred) {
|
if (preferred) {
|
||||||
|
|||||||
@@ -17,11 +17,13 @@ const API_TOAST_OPTIONS = { autoClose: 2000 };
|
|||||||
|
|
||||||
const hardLogout = () => {
|
const hardLogout = () => {
|
||||||
clearAuthCookies();
|
clearAuthCookies();
|
||||||
toast.error(
|
if (typeof window !== "undefined" && !window.location.pathname.startsWith("/signin")) {
|
||||||
"Your session has expired. Please sign in again.",
|
toast.error(
|
||||||
API_TOAST_OPTIONS
|
"Your session has expired. Please sign in again.",
|
||||||
);
|
API_TOAST_OPTIONS
|
||||||
window.location.href = "/signin";
|
);
|
||||||
|
window.location.href = "/signin";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const refreshAccessToken = async () => {
|
const refreshAccessToken = async () => {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
const LOGGED_IN_KEY = "logged_in";
|
const LOGGED_IN_KEY = "logged_in";
|
||||||
const LOGGED_IN_MAX_AGE_SECONDS = 60 * 15;
|
const LOGGED_IN_MAX_AGE_SECONDS = 60 * 60 * 24 * 30;
|
||||||
|
|
||||||
const buildCookieOptions = (maxAgeSeconds?: number) => {
|
const buildCookieOptions = (maxAgeSeconds?: number) => {
|
||||||
const options = ["path=/", "samesite=lax"];
|
const options = ["path=/", "samesite=lax"];
|
||||||
|
|||||||
Reference in New Issue
Block a user