From f820ca9781082155626c1eec04042d01a40d3aed Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 24 May 2026 06:18:22 +0000 Subject: [PATCH] Fix crash when viewing problem set content list while not logged in When a logged-out user clicked the edit mode button on a sequence (problem set) in the activity viewer, the CompoundActivityEditor would crash with "Cannot read properties of undefined (reading 'userId')" because the Add menu JSX eagerly evaluated `user!.userId` even though the menu button was hidden via `hidden={readOnlyStructure}`. Fix by wrapping the entire Add menu in `{!readOnlyStructure && ...}` so the JSX (and user!.userId) is never evaluated when the menu can't be shown. Also guard the ActivateAuthorMode modal to only render when user is defined. Closes #2788 https://claude.ai/code/session_012L3AUuFDfGTspJMf9W7Sf2 --- apps/app/src/views/CompoundActivityEditor.tsx | 97 ++++++++++--------- .../e2e/Activities/activityViewer.cy.ts | 43 ++++++++ 2 files changed, 92 insertions(+), 48 deletions(-) diff --git a/apps/app/src/views/CompoundActivityEditor.tsx b/apps/app/src/views/CompoundActivityEditor.tsx index f0a277132..6f91e48a5 100644 --- a/apps/app/src/views/CompoundActivityEditor.tsx +++ b/apps/app/src/views/CompoundActivityEditor.tsx @@ -192,18 +192,18 @@ export function CompoundActivityEditor({ onClose: authorModePromptOnClose, } = useDisclosure(); - const authorModeModal = ( + const authorModeModal = user ? ( { createNewDocument(createDocumentParentId); }} fetcher={fetcher} /> - ); + ) : null; // TODO: figure out functions inside hooks // eslint-disable-next-line react-hooks/exhaustive-deps @@ -475,52 +475,53 @@ export function CompoundActivityEditor({ {selectedItemsActions} - - - - { - setAddTo(activity); - }} - > - Items from Explore - - { - setAddTo(activity); - }} - > - Items from My Activities - - { - if (user?.isAuthor) { - createNewDocument(); - } else { - setCreateDocumentParentId(activity.contentId); - authorModePromptOnOpen(); - } - }} + {!readOnlyStructure && ( + + - Blank Document {!user?.isAuthor && <>(with source code)} - - - + {haveContentSpinner ? : "Add"} + + + { + setAddTo(activity); + }} + > + Items from Explore + + { + setAddTo(activity); + }} + > + Items from My Activities + + { + if (user?.isAuthor) { + createNewDocument(); + } else { + setCreateDocumentParentId(activity.contentId); + authorModePromptOnOpen(); + } + }} + > + Blank Document {!user?.isAuthor && <>(with source code)} + + + + )} ); diff --git a/packages/e2e-tests/e2e/Activities/activityViewer.cy.ts b/packages/e2e-tests/e2e/Activities/activityViewer.cy.ts index 17d7eb83a..56470d200 100644 --- a/packages/e2e-tests/e2e/Activities/activityViewer.cy.ts +++ b/packages/e2e-tests/e2e/Activities/activityViewer.cy.ts @@ -1,4 +1,47 @@ describe("Activity Viewer Tests", { tags: ["@group1"] }, function () { + it("can view content list of problem set when not logged in", () => { + cy.loginAsTestUser({ isAuthor: true }); + + cy.createContent({ + name: "Public Problem Set", + contentType: "sequence", + makePublic: true, + }).then((sequenceId) => { + cy.createContent({ + name: "Doc Inside Problem Set", + contentType: "singleDoc", + parentId: sequenceId, + doenetML: "Hello from inside!", + }); + + // Log out so we visit as an anonymous/unauthenticated user + cy.clearCookies(); + + cy.visit(`/activityViewer/${sequenceId}`); + + // The activity name should render + cy.get('[data-test="Activity Name"]').should( + "contain.text", + "Public Problem Set", + ); + + // Click the "Edit Mode Button" (shows "See source code" / "See list") + cy.get('[data-test="Edit Mode Button"]').click(); + + // The activities list should appear without crashing + cy.get('[data-test="Activities"]').should("exist"); + + // The doc inside the problem set should be listed + cy.get('[data-test="Activities"]').should( + "contain.text", + "Doc Inside Problem Set", + ); + + // The "Add" button should NOT be visible (read-only for non-logged-in users) + cy.get('[data-test="New Button"]').should("not.exist"); + }); + }); + it("classifications shown in activity viewer", () => { cy.loginAsTestUser(); cy.createContent({