diff --git a/src/content/OperationDashboard/DashboardView.tsx b/src/content/OperationDashboard/DashboardView.tsx index 8066a3f31..4b4c760ca 100644 --- a/src/content/OperationDashboard/DashboardView.tsx +++ b/src/content/OperationDashboard/DashboardView.tsx @@ -14,7 +14,8 @@ import StyledLabel from "../../components/StyledFormComponents/StyledLabel"; import SuspenseLoader from "../../components/SuspenseLoader"; import bannerSvg from "../../assets/banner/submission_banner.png"; import { useAuthContext } from "../../components/Contexts/AuthContext"; -import { Logger } from "../../utils"; +import { addDataCommonsParameter, addStudiesParameter } from "../../utils"; +import { RequiresStudiesAssigned } from "../../config/AuthRoles"; export type DashboardViewProps = { url: string; @@ -87,32 +88,28 @@ const DashboardView: FC = ({ const dashboardElementRef = useRef(null); const contentParameters = useMemo(() => { - const { role, studies, dataCommons } = user || {}; - const params: DashboardContentOptions["parameters"] = []; - - if (role === "Federal Lead" && Array.isArray(studies) && studies.length > 0) { - params.push({ - Name: "studiesParameter", - Values: studies?.map((study: ApprovedStudy) => study?._id), - }); - } else if (role === "Federal Lead") { - Logger.error("This role requires studies to be set but none were found.", studies); - params.push({ Name: "studiesParameter", Values: ["NO-CONTENT"] }); + if (!user?.role) { + return []; } - if (role === "Data Commons Personnel" && Array.isArray(dataCommons) && dataCommons.length > 0) { - params.push({ Name: "dataCommonsParameter", Values: dataCommons }); - } else if (role === "Data Commons Personnel") { - Logger.error("This role requires dataCommons to be set but none were found.", dataCommons); - params.push({ Name: "dataCommonsParameter", Values: ["NO-CONTENT"] }); + const { role } = user; + + if (RequiresStudiesAssigned.includes(role)) { + return addStudiesParameter(user); + } + + if (role === "Data Commons Personnel") { + return addDataCommonsParameter(user); } - return params; + return []; }, [user]); const handleDashboardChange = (e: SelectChangeEvent) => { setSearchParams({ type: e.target.value }); - dashboardElementRef.current.innerHTML = ""; + if (dashboardElementRef.current) { + dashboardElementRef.current.innerHTML = ""; + } setEmbeddedDashboard(null); }; diff --git a/src/utils/dashboardUtils.test.ts b/src/utils/dashboardUtils.test.ts new file mode 100644 index 000000000..6188e80c9 --- /dev/null +++ b/src/utils/dashboardUtils.test.ts @@ -0,0 +1,177 @@ +import { DashboardContentOptions } from "amazon-quicksight-embedding-sdk"; +import { addStudiesParameter, addDataCommonsParameter } from "./dashboardUtils"; +import { Logger } from "./logger"; + +jest.mock("./logger", () => ({ + Logger: { + error: jest.fn(), + }, +})); + +describe("addStudiesParameter", () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it("should return an empty array if user has 'All' as the first study", () => { + const user = { + studies: [{ _id: "All" }, { _id: "AnotherStudy" }], + } as unknown as User; + + const result = addStudiesParameter(user); + expect(result).toEqual([]); + expect(Logger.error).not.toHaveBeenCalled(); + }); + + it("should return an array with studiesParameter if user has valid studies", () => { + const user = { + studies: [{ _id: "StudyA" }, { _id: "StudyB" }], + } as unknown as User; + + const result = addStudiesParameter(user); + expect(result).toEqual([ + { + Name: "studiesParameter", + Values: ["StudyA", "StudyB"], + }, + ]); + expect(Logger.error).not.toHaveBeenCalled(); + }); + + it("should return NO-CONTENT if user has an empty studies array", () => { + const user = { + studies: [], + } as unknown as User; + + const result = addStudiesParameter(user); + expect(result).toEqual([ + { + Name: "studiesParameter", + Values: ["NO-CONTENT"], + }, + ]); + expect(Logger.error).toHaveBeenCalledTimes(1); + expect(Logger.error).toHaveBeenCalledWith( + "Federal Lead requires studies to be set but none or invalid values were found.", + [] + ); + }); + + it("should return NO-CONTENT if user studies is undefined or null", () => { + const user = { + studies: null, + } as unknown as User; + + const result = addStudiesParameter(user); + expect(result).toEqual([ + { + Name: "studiesParameter", + Values: ["NO-CONTENT"], + }, + ]); + expect(Logger.error).toHaveBeenCalledTimes(1); + }); + + it("should handle a null user gracefully", () => { + const user = null as unknown as User; + const result = addStudiesParameter(user); + expect(result).toEqual([ + { + Name: "studiesParameter", + Values: ["NO-CONTENT"], + }, + ]); + expect(Logger.error).toHaveBeenCalledTimes(1); + }); + + it("should handle an undefined user gracefully", () => { + const user = undefined as unknown as User; + const result = addStudiesParameter(user); + expect(result).toEqual([ + { + Name: "studiesParameter", + Values: ["NO-CONTENT"], + }, + ]); + expect(Logger.error).toHaveBeenCalledTimes(1); + }); +}); + +describe("addDataCommonsParameter", () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it("should return an array with dataCommonsParameter if user has valid dataCommons", () => { + const user = { + dataCommons: ["CommonsA", "CommonsB"], + } as unknown as User; + + const result = addDataCommonsParameter(user); + expect(result).toEqual([ + { + Name: "dataCommonsParameter", + Values: ["CommonsA", "CommonsB"], + }, + ]); + expect(Logger.error).not.toHaveBeenCalled(); + }); + + it("should return NO-CONTENT if user dataCommons is an empty array", () => { + const user = { + dataCommons: [], + } as unknown as User; + + const result = addDataCommonsParameter(user); + expect(result).toEqual([ + { + Name: "dataCommonsParameter", + Values: ["NO-CONTENT"], + }, + ]); + expect(Logger.error).toHaveBeenCalledTimes(1); + expect(Logger.error).toHaveBeenCalledWith( + "Data Commons Personnel requires dataCommons to be set but none were found.", + [] + ); + }); + + it("should return NO-CONTENT if user dataCommons is null or undefined", () => { + const user = { + dataCommons: null, + } as unknown as User; + + const result = addDataCommonsParameter(user); + expect(result).toEqual([ + { + Name: "dataCommonsParameter", + Values: ["NO-CONTENT"], + }, + ]); + expect(Logger.error).toHaveBeenCalledTimes(1); + }); + + it("should handle a null user gracefully", () => { + const user = null as unknown as User; + const result = addDataCommonsParameter(user); + expect(result).toEqual([ + { + Name: "dataCommonsParameter", + Values: ["NO-CONTENT"], + }, + ]); + expect(Logger.error).toHaveBeenCalledTimes(1); + }); + + it("should handle an undefined user gracefully", () => { + const user = undefined as unknown as User; + const result = addDataCommonsParameter(user); + expect(result).toEqual([ + { + Name: "dataCommonsParameter", + Values: ["NO-CONTENT"], + }, + ]); + expect(Logger.error).toHaveBeenCalledTimes(1); + }); +}); diff --git a/src/utils/dashboardUtils.ts b/src/utils/dashboardUtils.ts new file mode 100644 index 000000000..add5b8965 --- /dev/null +++ b/src/utils/dashboardUtils.ts @@ -0,0 +1,66 @@ +import { DashboardContentOptions } from "amazon-quicksight-embedding-sdk"; +import { Logger } from "./logger"; + +/** + * Constructs and returns an array of QuickSight parameter objects for a user's studies. + * + * - If the user's first study is `All`, the function returns an empty array (allowing QuickSight to display all data). + * - If the user has a valid array of studies, it creates a `studiesParameter` whose values are the `_id` fields of each study. + * - Otherwise, it logs an error and returns a parameter array with `["NO-CONTENT"]`. + * + * + * @param {User} user - The current user + * @returns {DashboardContentOptions["parameters"]} The updated dashboard parameters + */ +export const addStudiesParameter = (user: User): DashboardContentOptions["parameters"] => { + const params: DashboardContentOptions["parameters"] = []; + const { studies } = user || {}; + + // If user contains the "All" study, do NOT push the "studiesParameter" + if ((studies || [])?.findIndex((s) => s?._id === "All") !== -1) { + return params; + } + + // Otherwise, push a real or fallback param + if (Array.isArray(studies) && studies.length > 0) { + params.push({ + Name: "studiesParameter", + Values: studies.map((s) => s._id), + }); + return params; + } + + Logger.error( + "Federal Lead requires studies to be set but none or invalid values were found.", + studies + ); + params.push({ Name: "studiesParameter", Values: ["NO-CONTENT"] }); + return params; +}; + +/** + * Constructs and returns an array of QuickSight parameter objects for a user's data commons. + * + * - If the user has a valid array of data commons, it creates a `dataCommonsParameter` whose values are the array elements. + * - Otherwise, it logs an error and returns a parameter array with `["NO-CONTENT"]`. + * + * + * @param {User} user - The current user + * @returns {DashboardContentOptions["parameters"]} The updated dashboard parameters + */ +export const addDataCommonsParameter = (user: User): DashboardContentOptions["parameters"] => { + const params: DashboardContentOptions["parameters"] = []; + const { dataCommons } = user || {}; + + if (Array.isArray(dataCommons) && dataCommons.length > 0) { + params.push({ Name: "dataCommonsParameter", Values: dataCommons }); + return params; + } + + Logger.error( + "Data Commons Personnel requires dataCommons to be set but none were found.", + dataCommons + ); + params.push({ Name: "dataCommonsParameter", Values: ["NO-CONTENT"] }); + return params; +}; diff --git a/src/utils/index.ts b/src/utils/index.ts index 740ade86a..8be715d00 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -15,3 +15,4 @@ export * from "./searchParamUtils"; export * from "./envUtils"; export * from "./logger"; export * from "./fetchUtils"; +export * from "./dashboardUtils";