Co-authored-by: lethemanh <lethemanh@lethemanhs-MacBook-Pro.local>
This commit is contained in:
@@ -87,7 +87,7 @@ const baseCalendar: Calendar = {
|
|||||||
events: {},
|
events: {},
|
||||||
invite: [],
|
invite: [],
|
||||||
owner: { emails: ["user1@example.com"] },
|
owner: { emails: ["user1@example.com"] },
|
||||||
access: { write: true },
|
access: { write: true } as any,
|
||||||
delegated: true,
|
delegated: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -261,6 +261,82 @@ describe("CalendarAccessRights", () => {
|
|||||||
|
|
||||||
expect(document.querySelector('[role="progressbar"]')).toBeInTheDocument();
|
expect(document.querySelector('[role="progressbar"]')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("displays the calendar owner information", () => {
|
||||||
|
renderWithProviders(
|
||||||
|
<CalendarAccessRights
|
||||||
|
calendar={baseCalendar}
|
||||||
|
value={[]}
|
||||||
|
onChange={mockOnChange}
|
||||||
|
onInvitesLoaded={mockOnInvitesLoaded}
|
||||||
|
/>,
|
||||||
|
{ ...userState }
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(screen.getAllByText("user1@example.com").length).toBeGreaterThan(0);
|
||||||
|
expect(
|
||||||
|
screen.getByText("calendarPopover.access.owner")
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("fetches and displays resource administrators for resource calendars", async () => {
|
||||||
|
const resourceCalendar: any = {
|
||||||
|
...baseCalendar,
|
||||||
|
owner: {
|
||||||
|
_id: "resource1",
|
||||||
|
resource: true,
|
||||||
|
emails: ["resource1@example.com"],
|
||||||
|
administrators: [
|
||||||
|
{ id: "admin1" },
|
||||||
|
{ id: "admin2" },
|
||||||
|
{ id: "resource1" }, // Owner shouldn't be loaded as an admin
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
(getUserDetails as jest.Mock).mockImplementation((id: string) => {
|
||||||
|
if (id === "admin1") {
|
||||||
|
return Promise.resolve({
|
||||||
|
preferredEmail: "admin1@example.com",
|
||||||
|
firstname: "Admin",
|
||||||
|
lastname: "One",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (id === "admin2") {
|
||||||
|
return Promise.resolve({
|
||||||
|
preferredEmail: "admin2@example.com",
|
||||||
|
firstname: "Admin",
|
||||||
|
lastname: "Two",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Promise.resolve(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
renderWithProviders(
|
||||||
|
<CalendarAccessRights
|
||||||
|
calendar={resourceCalendar}
|
||||||
|
value={[]}
|
||||||
|
onChange={mockOnChange}
|
||||||
|
onInvitesLoaded={mockOnInvitesLoaded}
|
||||||
|
/>,
|
||||||
|
{ ...userState }
|
||||||
|
);
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(getUserDetails).toHaveBeenCalledWith("admin1");
|
||||||
|
expect(getUserDetails).toHaveBeenCalledWith("admin2");
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(getUserDetails).not.toHaveBeenCalledWith("resource1");
|
||||||
|
|
||||||
|
expect(await screen.findByText("Admin One")).toBeInTheDocument();
|
||||||
|
expect(screen.getByText("admin1@example.com")).toBeInTheDocument();
|
||||||
|
expect(screen.getByText("Admin Two")).toBeInTheDocument();
|
||||||
|
expect(screen.getByText("admin2@example.com")).toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
screen.getAllByText("calendarPopover.access.administrator")
|
||||||
|
).toHaveLength(2);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const userState = {
|
const userState = {
|
||||||
|
|||||||
@@ -1,16 +1,15 @@
|
|||||||
import { addCalendarResourceAsync } from "@/features/Calendars/api/addCalendarResourceAsync";
|
import { addCalendarResourceAsync } from "@/features/Calendars/api/addCalendarResourceAsync";
|
||||||
import { addSharedCalendar } from "@/features/Calendars/CalendarApi";
|
import { addSharedCalendar } from "@/features/Calendars/CalendarApi";
|
||||||
import { getResourceDetails, getUserDetails } from "@/features/User/userAPI";
|
import { fetchOwnerOfResource } from "@/features/Calendars/services/helpers";
|
||||||
import { toRejectedError } from "@/utils/errorUtils";
|
import { toRejectedError } from "@/utils/errorUtils";
|
||||||
import { configureStore } from "@reduxjs/toolkit";
|
import { configureStore } from "@reduxjs/toolkit";
|
||||||
|
|
||||||
jest.mock("@/features/Calendars/CalendarApi");
|
jest.mock("@/features/Calendars/CalendarApi");
|
||||||
jest.mock("@/features/User/userAPI");
|
jest.mock("@/features/Calendars/services/helpers");
|
||||||
jest.mock("@/utils/errorUtils");
|
jest.mock("@/utils/errorUtils");
|
||||||
|
|
||||||
const mockedAddSharedCalendar = addSharedCalendar as jest.Mock;
|
const mockedAddSharedCalendar = addSharedCalendar as jest.Mock;
|
||||||
const mockedGetResourceDetails = getResourceDetails as jest.Mock;
|
const mockedFetchOwnerOfResource = fetchOwnerOfResource as jest.Mock;
|
||||||
const mockedGetUserDetails = getUserDetails as jest.Mock;
|
|
||||||
const mockedToRejectedError = toRejectedError as jest.Mock;
|
const mockedToRejectedError = toRejectedError as jest.Mock;
|
||||||
|
|
||||||
describe("addCalendarResourceAsync thunk", () => {
|
describe("addCalendarResourceAsync thunk", () => {
|
||||||
@@ -55,8 +54,7 @@ describe("addCalendarResourceAsync thunk", () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
it("should add shared calendar, fetch resource details, map userData", async () => {
|
it("should add shared calendar, fetch resource details, map userData", async () => {
|
||||||
mockedGetResourceDetails.mockResolvedValueOnce(mockResolvedResourceData);
|
mockedFetchOwnerOfResource.mockResolvedValueOnce({
|
||||||
mockedGetUserDetails.mockResolvedValueOnce({
|
|
||||||
firstname: "Creator",
|
firstname: "Creator",
|
||||||
lastname: "User",
|
lastname: "User",
|
||||||
emails: ["creator@example.com"],
|
emails: ["creator@example.com"],
|
||||||
@@ -72,8 +70,7 @@ describe("addCalendarResourceAsync thunk", () => {
|
|||||||
mockPayload.calId,
|
mockPayload.calId,
|
||||||
mockPayload.cal
|
mockPayload.cal
|
||||||
);
|
);
|
||||||
expect(mockedGetResourceDetails).toHaveBeenCalledWith("res-456");
|
expect(mockedFetchOwnerOfResource).toHaveBeenCalledWith("res-456");
|
||||||
expect(mockedGetUserDetails).toHaveBeenCalledWith("user-789");
|
|
||||||
|
|
||||||
expect(result.type).toBe("calendars/addCalendarResource/fulfilled");
|
expect(result.type).toBe("calendars/addCalendarResource/fulfilled");
|
||||||
expect(result.payload).toEqual({
|
expect(result.payload).toEqual({
|
||||||
@@ -94,9 +91,12 @@ describe("addCalendarResourceAsync thunk", () => {
|
|||||||
it("should fallback to name if resource details fetch fails", async () => {
|
it("should fallback to name if resource details fetch fails", async () => {
|
||||||
mockedAddSharedCalendar.mockResolvedValueOnce({});
|
mockedAddSharedCalendar.mockResolvedValueOnce({});
|
||||||
const errorDetails = new Error("Fetch failed");
|
const errorDetails = new Error("Fetch failed");
|
||||||
mockedGetResourceDetails.mockRejectedValueOnce(errorDetails);
|
mockedFetchOwnerOfResource.mockRejectedValueOnce(errorDetails);
|
||||||
const mockRejectedErrorResult = { message: "Fetch failed" };
|
|
||||||
mockedToRejectedError.mockReturnValueOnce(mockRejectedErrorResult);
|
// Silence expected console error in tests
|
||||||
|
const consoleSpy = jest
|
||||||
|
.spyOn(console, "error")
|
||||||
|
.mockImplementation(() => {});
|
||||||
|
|
||||||
const result = await addCalendarResourceAsync(
|
const result = await addCalendarResourceAsync(
|
||||||
mockPayload as unknown as Parameters<typeof addCalendarResourceAsync>[0]
|
mockPayload as unknown as Parameters<typeof addCalendarResourceAsync>[0]
|
||||||
@@ -107,9 +107,9 @@ describe("addCalendarResourceAsync thunk", () => {
|
|||||||
mockPayload.calId,
|
mockPayload.calId,
|
||||||
mockPayload.cal
|
mockPayload.cal
|
||||||
);
|
);
|
||||||
expect(mockedGetResourceDetails).toHaveBeenCalledWith("res-456");
|
expect(mockedFetchOwnerOfResource).toHaveBeenCalledWith("res-456");
|
||||||
|
|
||||||
expect(mockedToRejectedError).toHaveBeenCalledWith(errorDetails);
|
consoleSpy.mockRestore();
|
||||||
|
|
||||||
expect(result.type).toBe("calendars/addCalendarResource/fulfilled");
|
expect(result.type).toBe("calendars/addCalendarResource/fulfilled");
|
||||||
expect(result.payload).toEqual({
|
expect(result.payload).toEqual({
|
||||||
@@ -142,7 +142,7 @@ describe("addCalendarResourceAsync thunk", () => {
|
|||||||
mockPayload.calId,
|
mockPayload.calId,
|
||||||
mockPayload.cal
|
mockPayload.cal
|
||||||
);
|
);
|
||||||
expect(mockedGetResourceDetails).not.toHaveBeenCalled();
|
expect(mockedFetchOwnerOfResource).not.toHaveBeenCalled();
|
||||||
|
|
||||||
expect(mockedToRejectedError).toHaveBeenCalledWith(errorAdd);
|
expect(mockedToRejectedError).toHaveBeenCalledWith(errorAdd);
|
||||||
|
|
||||||
|
|||||||
@@ -17,11 +17,12 @@ import {
|
|||||||
} from "@linagora/twake-mui";
|
} from "@linagora/twake-mui";
|
||||||
import HighlightOffIcon from "@mui/icons-material/HighlightOff";
|
import HighlightOffIcon from "@mui/icons-material/HighlightOff";
|
||||||
import PeopleOutlineOutlinedIcon from "@mui/icons-material/PeopleOutlineOutlined";
|
import PeopleOutlineOutlinedIcon from "@mui/icons-material/PeopleOutlineOutlined";
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { useCallback, useEffect, useRef, useState } from "react";
|
||||||
import { useI18n } from "twake-i18n";
|
import { useI18n } from "twake-i18n";
|
||||||
import { PeopleSearch, User } from "../Attendees/PeopleSearch";
|
import { PeopleSearch, User } from "../Attendees/PeopleSearch";
|
||||||
import { FieldWithLabel } from "../Event/components/FieldWithLabel";
|
import { FieldWithLabel } from "../Event/components/FieldWithLabel";
|
||||||
import { stringAvatar } from "../Event/utils/eventUtils";
|
import { stringAvatar } from "../Event/utils/eventUtils";
|
||||||
|
import { ResourceAdmin } from "./ResourceAdmins";
|
||||||
|
|
||||||
export interface UserWithAccess extends User {
|
export interface UserWithAccess extends User {
|
||||||
accessRight: AccessRight;
|
accessRight: AccessRight;
|
||||||
@@ -34,6 +35,11 @@ interface CalendarAccessRightsProps {
|
|||||||
onInvitesLoaded: (users: UserWithAccess[]) => void;
|
onInvitesLoaded: (users: UserWithAccess[]) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface UserInCalendar {
|
||||||
|
id: string;
|
||||||
|
access: AccessRight;
|
||||||
|
}
|
||||||
|
|
||||||
export function CalendarAccessRights({
|
export function CalendarAccessRights({
|
||||||
calendar,
|
calendar,
|
||||||
value: usersWithAccess,
|
value: usersWithAccess,
|
||||||
@@ -57,6 +63,8 @@ export function CalendarAccessRights({
|
|||||||
const [searchWidth, setSearchWidth] = useState<number | undefined>(undefined);
|
const [searchWidth, setSearchWidth] = useState<number | undefined>(undefined);
|
||||||
const [accessRight, setAccessRight] = useState<AccessRight>(2);
|
const [accessRight, setAccessRight] = useState<AccessRight>(2);
|
||||||
const [inviteLoading, setInvitesLoading] = useState(false);
|
const [inviteLoading, setInvitesLoading] = useState(false);
|
||||||
|
const [resourceAdmins, setResourceAdmins] = useState<UserWithAccess[]>([]);
|
||||||
|
const [adminLoading, setAdminLoading] = useState(false);
|
||||||
|
|
||||||
const currentUsersRef = useRef<UserWithAccess[]>(usersWithAccess);
|
const currentUsersRef = useRef<UserWithAccess[]>(usersWithAccess);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -74,6 +82,39 @@ export function CalendarAccessRights({
|
|||||||
return () => observer.disconnect();
|
return () => observer.disconnect();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const handleLoadUsers = useCallback(
|
||||||
|
async (usersInCal: UserInCalendar[], cancelled: boolean) => {
|
||||||
|
const results = await Promise.allSettled(
|
||||||
|
usersInCal.map(async (user) => {
|
||||||
|
const details = await getUserDetails(user.id);
|
||||||
|
const email = details?.preferredEmail ?? details?.emails?.[0] ?? "";
|
||||||
|
return {
|
||||||
|
openpaasId: user.id,
|
||||||
|
displayName:
|
||||||
|
[details?.firstname, details?.lastname]
|
||||||
|
.filter(Boolean)
|
||||||
|
.join(" ")
|
||||||
|
.trim() || email,
|
||||||
|
email,
|
||||||
|
accessRight: user.access as AccessRight,
|
||||||
|
} satisfies UserWithAccess;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
if (cancelled) {
|
||||||
|
return [] as UserWithAccess[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const loaded: UserWithAccess[] = results
|
||||||
|
.filter((r) => r.status === "fulfilled")
|
||||||
|
.map((r) => (r as PromiseFulfilledResult<UserWithAccess>).value)
|
||||||
|
.filter(Boolean) as UserWithAccess[];
|
||||||
|
|
||||||
|
return loaded;
|
||||||
|
},
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!calendar.invite?.length) return;
|
if (!calendar.invite?.length) return;
|
||||||
|
|
||||||
@@ -82,33 +123,19 @@ export function CalendarAccessRights({
|
|||||||
async function loadInvitedUsers() {
|
async function loadInvitedUsers() {
|
||||||
setInvitesLoading(true);
|
setInvitesLoading(true);
|
||||||
try {
|
try {
|
||||||
const loaded: UserWithAccess[] = (
|
const usersInCal = (calendar.invite
|
||||||
await Promise.all(
|
?.map((invite) => {
|
||||||
calendar.invite.map(async (invite) => {
|
const principalId = invite.principal.split("/").pop();
|
||||||
const principalId = invite.principal.split("/").pop();
|
if (!principalId) return null;
|
||||||
if (!principalId) return null;
|
|
||||||
try {
|
|
||||||
const details = await getUserDetails(principalId);
|
|
||||||
const email =
|
|
||||||
details?.preferredEmail ?? details?.emails?.[0] ?? "";
|
|
||||||
return {
|
|
||||||
openpaasId: principalId,
|
|
||||||
displayName:
|
|
||||||
[details?.firstname, details?.lastname]
|
|
||||||
.filter(Boolean)
|
|
||||||
.join(" ")
|
|
||||||
.trim() || email,
|
|
||||||
email,
|
|
||||||
accessRight: invite.access as AccessRight,
|
|
||||||
} satisfies UserWithAccess;
|
|
||||||
} catch {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
)
|
|
||||||
).filter((u) => u !== null && !!u.email);
|
|
||||||
|
|
||||||
if (cancelled) return;
|
return {
|
||||||
|
id: principalId,
|
||||||
|
access: invite.access,
|
||||||
|
};
|
||||||
|
})
|
||||||
|
?.filter((invite) => !!invite) || []) satisfies UserInCalendar[];
|
||||||
|
|
||||||
|
const loaded = await handleLoadUsers(usersInCal, cancelled);
|
||||||
|
|
||||||
const loadedIds = new Set(loaded.map((u) => normalizeEmail(u.email)));
|
const loadedIds = new Set(loaded.map((u) => normalizeEmail(u.email)));
|
||||||
const manuallyAdded = currentUsersRef.current.filter(
|
const manuallyAdded = currentUsersRef.current.filter(
|
||||||
@@ -127,7 +154,42 @@ export function CalendarAccessRights({
|
|||||||
return () => {
|
return () => {
|
||||||
cancelled = true;
|
cancelled = true;
|
||||||
};
|
};
|
||||||
}, [calendar.invite, onChange, onInvitesLoaded]);
|
}, [calendar.invite, handleLoadUsers, onChange, onInvitesLoaded]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const isResource = calendar.owner.resource;
|
||||||
|
const resourceAdmins = calendar.owner.administrators || [];
|
||||||
|
if (!isResource || !resourceAdmins?.length) return;
|
||||||
|
|
||||||
|
let cancelled = false;
|
||||||
|
|
||||||
|
async function loadAdmins() {
|
||||||
|
try {
|
||||||
|
setAdminLoading(true);
|
||||||
|
const resourceAdminsWithoutOwner = resourceAdmins
|
||||||
|
.filter((admin) => admin.id !== calendar.owner._id)
|
||||||
|
.map((admin) => ({
|
||||||
|
id: admin.id,
|
||||||
|
access: 5, // ADMIN
|
||||||
|
})) satisfies UserInCalendar[];
|
||||||
|
const admins = await handleLoadUsers(
|
||||||
|
resourceAdminsWithoutOwner,
|
||||||
|
cancelled
|
||||||
|
);
|
||||||
|
|
||||||
|
setResourceAdmins(admins);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
} finally {
|
||||||
|
if (!cancelled) setAdminLoading(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
loadAdmins();
|
||||||
|
return () => {
|
||||||
|
cancelled = true;
|
||||||
|
};
|
||||||
|
}, [calendar.owner, handleLoadUsers, setResourceAdmins]);
|
||||||
|
|
||||||
const handleUserSelect = (_event: unknown, users: User[]) => {
|
const handleUserSelect = (_event: unknown, users: User[]) => {
|
||||||
const updated: UserWithAccess[] = users.map((user) => {
|
const updated: UserWithAccess[] = users.map((user) => {
|
||||||
@@ -309,6 +371,15 @@ export function CalendarAccessRights({
|
|||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
{adminLoading ? (
|
||||||
|
<Box mt={2} display="flex" justifyContent="center">
|
||||||
|
<CircularProgress size={24} />
|
||||||
|
</Box>
|
||||||
|
) : (
|
||||||
|
resourceAdmins.map((admin) => (
|
||||||
|
<ResourceAdmin key={admin.email} admin={admin} />
|
||||||
|
))
|
||||||
|
)}
|
||||||
{inviteLoading ? (
|
{inviteLoading ? (
|
||||||
<Box mt={2} display="flex" justifyContent="center">
|
<Box mt={2} display="flex" justifyContent="center">
|
||||||
<CircularProgress size={24} />
|
<CircularProgress size={24} />
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
import { Avatar, Box, Typography } from "@linagora/twake-mui";
|
||||||
|
import { useI18n } from "twake-i18n";
|
||||||
|
import { stringAvatar } from "../Event/utils/eventUtils";
|
||||||
|
import { UserWithAccess } from "./CalendarAccessRights";
|
||||||
|
|
||||||
|
interface ResourceAdminProps {
|
||||||
|
admin: UserWithAccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ResourceAdmin({ admin }: ResourceAdminProps) {
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
display="flex"
|
||||||
|
alignItems="center"
|
||||||
|
justifyContent="space-between"
|
||||||
|
px={1}
|
||||||
|
py={0.5}
|
||||||
|
sx={{
|
||||||
|
borderRadius: "8px",
|
||||||
|
"&:hover": { backgroundColor: "action.hover" },
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box display="flex" alignItems="center" gap={1.5} minWidth={0}>
|
||||||
|
<Avatar
|
||||||
|
{...stringAvatar(admin.displayName)}
|
||||||
|
sx={{ width: 28, height: 28, fontSize: "0.875rem" }}
|
||||||
|
/>
|
||||||
|
<Box minWidth={0} display="flex" flexDirection="column" gap={0}>
|
||||||
|
<Typography noWrap>{admin.displayName}</Typography>
|
||||||
|
<Typography variant="caption" color="text.secondary">
|
||||||
|
{admin.email}
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Box display="flex" alignItems="center" gap={0.5} flexShrink={0}>
|
||||||
|
<Typography variant="caption">
|
||||||
|
{t("calendarPopover.access.administrator")}
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
import { OpenPaasUserData } from "@/features/User/type/OpenPaasUserData";
|
import { OpenPaasUserData } from "@/features/User/type/OpenPaasUserData";
|
||||||
import { getResourceDetails, getUserDetails } from "@/features/User/userAPI";
|
|
||||||
import { toRejectedError } from "@/utils/errorUtils";
|
import { toRejectedError } from "@/utils/errorUtils";
|
||||||
import { createAsyncThunk } from "@reduxjs/toolkit";
|
import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||||
import { addSharedCalendar } from "../CalendarApi";
|
import { addSharedCalendar } from "../CalendarApi";
|
||||||
import { CalendarInput } from "../types/CalendarData";
|
import { CalendarInput } from "../types/CalendarData";
|
||||||
import { RejectedError } from "../types/RejectedError";
|
import { RejectedError } from "../types/RejectedError";
|
||||||
import { User } from "@/components/Attendees/PeopleSearch";
|
import { User } from "@/components/Attendees/PeopleSearch";
|
||||||
|
import { fetchOwnerOfResource } from "../services/helpers";
|
||||||
|
|
||||||
export const addCalendarResourceAsync = createAsyncThunk<
|
export const addCalendarResourceAsync = createAsyncThunk<
|
||||||
{
|
{
|
||||||
@@ -43,13 +43,12 @@ export const addCalendarResourceAsync = createAsyncThunk<
|
|||||||
|
|
||||||
if (resourceId) {
|
if (resourceId) {
|
||||||
try {
|
try {
|
||||||
const resource = await getResourceDetails(resourceId);
|
|
||||||
owner = {
|
owner = {
|
||||||
...(await getUserDetails(resource.creator)),
|
...(await fetchOwnerOfResource(resourceId)),
|
||||||
resource: true,
|
resource: true,
|
||||||
};
|
};
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
toRejectedError(e);
|
console.error("Error while fetching owner of resource: ", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,18 @@
|
|||||||
import { OpenPaasUserData } from "@/features/User/type/OpenPaasUserData";
|
import { OpenPaasUserData } from "@/features/User/type/OpenPaasUserData";
|
||||||
import { getResourceDetails, getUserDetails } from "@/features/User/userAPI";
|
import { getResourceDetails, getUserDetails } from "@/features/User/userAPI";
|
||||||
|
|
||||||
const fetchOwnerOfResource = async (
|
export const fetchOwnerOfResource = async (
|
||||||
ownerId: string
|
resourceId: string
|
||||||
): Promise<OpenPaasUserData> => {
|
): Promise<OpenPaasUserData> => {
|
||||||
try {
|
try {
|
||||||
const data = await getResourceDetails(ownerId);
|
const data = await getResourceDetails(resourceId);
|
||||||
const ownerData = await getUserDetails(data.creator);
|
const ownerData = await getUserDetails(data.creator);
|
||||||
return ownerData;
|
return {
|
||||||
|
...ownerData,
|
||||||
|
administrators: data.administrators,
|
||||||
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`Failed to fetch resource details for ${ownerId}:`, error);
|
console.error(`Failed to fetch resource details for ${resourceId}:`, error);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,12 +4,18 @@ export interface OpenPaasUserData {
|
|||||||
firstname?: string;
|
firstname?: string;
|
||||||
lastname?: string;
|
lastname?: string;
|
||||||
id?: string;
|
id?: string;
|
||||||
|
_id?: string;
|
||||||
preferredEmail?: string;
|
preferredEmail?: string;
|
||||||
configurations?: {
|
configurations?: {
|
||||||
modules?: ModuleConfiguration[];
|
modules?: ModuleConfiguration[];
|
||||||
};
|
};
|
||||||
emails: string[];
|
emails: string[];
|
||||||
resource?: boolean;
|
resource?: boolean;
|
||||||
|
administrators?: {
|
||||||
|
_id: string;
|
||||||
|
id: string;
|
||||||
|
objectType: string;
|
||||||
|
}[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ToUserData(
|
export function ToUserData(
|
||||||
|
|||||||
Reference in New Issue
Block a user