role filter and login issue
This commit is contained in:
@@ -16,7 +16,8 @@ export const rolesApi = {
|
||||
getById: (roleId: string) =>
|
||||
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) =>
|
||||
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;
|
||||
const loadAccesses = async () => {
|
||||
const loadAccesses = async (tenantId?: string) => {
|
||||
setIsAccessLoading(true);
|
||||
try {
|
||||
const data = await rolesApi.getAccesses();
|
||||
const data = await rolesApi.getAccesses(tenantId || 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) {
|
||||
@@ -128,44 +133,55 @@ const AddRoles = () => {
|
||||
}
|
||||
};
|
||||
|
||||
loadAccesses();
|
||||
loadTenants();
|
||||
return () => {
|
||||
isMounted = false;
|
||||
};
|
||||
}, [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 { name, value } = event.target;
|
||||
setFormData((prev) => ({ ...prev, [name]: value }));
|
||||
};
|
||||
|
||||
const availableAccessOptions = useMemo(() => {
|
||||
if (canReadAllTenants) return 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]);
|
||||
return accessOptions;
|
||||
}, [accessOptions]);
|
||||
|
||||
const handleSubmit = async (event: React.FormEvent) => {
|
||||
event.preventDefault();
|
||||
|
||||
@@ -94,31 +94,8 @@ const AllRoles = () => {
|
||||
const [isDeleting, setIsDeleting] = useState(false);
|
||||
|
||||
const availableAccessOptions = useMemo(() => {
|
||||
if (canReadAllTenants) return 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]);
|
||||
return accessOptions;
|
||||
}, [accessOptions]);
|
||||
|
||||
useEffect(() => {
|
||||
let isMounted = true;
|
||||
@@ -267,7 +244,11 @@ const AllRoles = () => {
|
||||
setEditError("");
|
||||
setIsEditOpen(true);
|
||||
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) || []);
|
||||
} catch (err) {
|
||||
setEditError(err instanceof Error ? err.message : t('messages.error'));
|
||||
|
||||
@@ -33,15 +33,10 @@ export const AuthProvider: React.FC<{ children: ReactNode }> = ({
|
||||
|
||||
useEffect(() => {
|
||||
const bootstrapAuth = async () => {
|
||||
const token = getAccessToken();
|
||||
if (!token) {
|
||||
setIsLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const userData = await authApi.me();
|
||||
setUser(userData);
|
||||
setAuthCookies(null, true);
|
||||
|
||||
const preferred = userData.preferred_language;
|
||||
if (preferred) {
|
||||
|
||||
@@ -17,11 +17,13 @@ const API_TOAST_OPTIONS = { autoClose: 2000 };
|
||||
|
||||
const hardLogout = () => {
|
||||
clearAuthCookies();
|
||||
if (typeof window !== "undefined" && !window.location.pathname.startsWith("/signin")) {
|
||||
toast.error(
|
||||
"Your session has expired. Please sign in again.",
|
||||
API_TOAST_OPTIONS
|
||||
);
|
||||
window.location.href = "/signin";
|
||||
}
|
||||
};
|
||||
|
||||
const refreshAccessToken = async () => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
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 options = ["path=/", "samesite=lax"];
|
||||
|
||||
Reference in New Issue
Block a user