diff --git a/src/library-authoring/EmptyStates.tsx b/src/library-authoring/EmptyStates.tsx index 71297926de..ac69e56d16 100644 --- a/src/library-authoring/EmptyStates.tsx +++ b/src/library-authoring/EmptyStates.tsx @@ -6,7 +6,7 @@ import { import { Add } from '@openedx/paragon/icons'; import { ClearFiltersButton } from '../search-manager'; import messages from './messages'; -import { useLibraryContext } from './common/context'; +import { useLibraryContext } from './common/context/LibraryContext'; export const NoComponents = ({ infoText = messages.noComponents, diff --git a/src/library-authoring/LibraryAuthoringPage.tsx b/src/library-authoring/LibraryAuthoringPage.tsx index 76cef54178..01fc146b60 100644 --- a/src/library-authoring/LibraryAuthoringPage.tsx +++ b/src/library-authoring/LibraryAuthoringPage.tsx @@ -37,19 +37,25 @@ import { } from '../search-manager'; import LibraryContent, { ContentType } from './LibraryContent'; import { LibrarySidebar } from './library-sidebar'; -import { SidebarBodyComponentId, useLibraryContext } from './common/context'; +import { useComponentPickerContext } from './common/context/ComponentPickerContext'; +import { useLibraryContext } from './common/context/LibraryContext'; +import { SidebarBodyComponentId, useSidebarContext } from './common/context/SidebarContext'; + import messages from './messages'; const HeaderActions = () => { const intl = useIntl(); + + const { readOnly } = useLibraryContext(); + const { - componentPickerMode, openAddContentSidebar, openInfoSidebar, closeLibrarySidebar, sidebarComponentInfo, - readOnly, - } = useLibraryContext(); + } = useSidebarContext(); + + const { componentPickerMode } = useComponentPickerContext(); const infoSidebarIsOpen = () => ( sidebarComponentInfo?.type === SidebarBodyComponentId.Info @@ -94,7 +100,8 @@ const HeaderActions = () => { const SubHeaderTitle = ({ title }: { title: string }) => { const intl = useIntl(); - const { readOnly, componentPickerMode } = useLibraryContext(); + const { readOnly } = useLibraryContext(); + const { componentPickerMode } = useComponentPickerContext(); const showReadOnlyBadge = readOnly && !componentPickerMode; @@ -127,16 +134,14 @@ const LibraryAuthoringPage = ({ returnToLibrarySelection }: LibraryAuthoringPage librariesV2Enabled, } = useStudioHome(); + const { componentPickerMode, restrictToLibrary } = useComponentPickerContext(); const { libraryId, libraryData, isLoadingLibraryData, - componentPickerMode, - restrictToLibrary, showOnlyPublished, - sidebarComponentInfo, - openInfoSidebar, } = useLibraryContext(); + const { openInfoSidebar, sidebarComponentInfo } = useSidebarContext(); const [activeKey, setActiveKey] = useState(ContentType.home); diff --git a/src/library-authoring/LibraryContent.test.tsx b/src/library-authoring/LibraryContent.test.tsx index d7b49320ee..f5dcb0dd28 100644 --- a/src/library-authoring/LibraryContent.test.tsx +++ b/src/library-authoring/LibraryContent.test.tsx @@ -9,7 +9,7 @@ import { import { getContentSearchConfigUrl } from '../search-manager/data/api'; import { mockContentLibrary } from './data/api.mocks'; import mockEmptyResult from '../search-modal/__mocks__/empty-search-result.json'; -import { LibraryProvider } from './common/context'; +import { LibraryProvider } from './common/context/LibraryContext'; import LibraryContent from './LibraryContent'; import { libraryComponentsMock } from './__mocks__'; @@ -56,7 +56,9 @@ const clipboardBroadcastChannelMock = { const withLibraryId = (libraryId: string) => ({ extraWrapper: ({ children }: { children: React.ReactNode }) => ( - {children} + + {children} + ), }); diff --git a/src/library-authoring/LibraryContent.tsx b/src/library-authoring/LibraryContent.tsx index 15049e25b6..5eb0505201 100644 --- a/src/library-authoring/LibraryContent.tsx +++ b/src/library-authoring/LibraryContent.tsx @@ -2,7 +2,8 @@ import { useEffect } from 'react'; import { LoadingSpinner } from '../generic/Loading'; import { useSearchContext } from '../search-manager'; import { NoComponents, NoSearchResults } from './EmptyStates'; -import { useLibraryContext } from './common/context'; +import { useLibraryContext } from './common/context/LibraryContext'; +import { useSidebarContext } from './common/context/SidebarContext'; import CollectionCard from './components/CollectionCard'; import ComponentCard from './components/ComponentCard'; import { useLoadOnScroll } from '../hooks'; @@ -37,7 +38,8 @@ const LibraryContent = ({ contentType = ContentType.home }: LibraryContentProps) isFiltered, usageKey, } = useSearchContext(); - const { openAddContentSidebar, openComponentInfoSidebar, openCreateCollectionModal } = useLibraryContext(); + const { openCreateCollectionModal } = useLibraryContext(); + const { openAddContentSidebar, openComponentInfoSidebar } = useSidebarContext(); useEffect(() => { if (usageKey) { diff --git a/src/library-authoring/LibraryLayout.tsx b/src/library-authoring/LibraryLayout.tsx index 04bfc25c64..610a28eacb 100644 --- a/src/library-authoring/LibraryLayout.tsx +++ b/src/library-authoring/LibraryLayout.tsx @@ -6,9 +6,9 @@ import { } from 'react-router-dom'; import LibraryAuthoringPage from './LibraryAuthoringPage'; -import { LibraryProvider } from './common/context'; +import { LibraryProvider } from './common/context/LibraryContext'; +import { SidebarProvider } from './common/context/SidebarContext'; import { CreateCollectionModal } from './create-collection'; -import { LibraryTeamModal } from './library-team'; import LibraryCollectionPage from './collections/LibraryCollectionPage'; import { ComponentPicker } from './component-picker'; import { ComponentEditorModal } from './components/ComponentEditorModal'; @@ -27,6 +27,8 @@ const LibraryLayout = () => { return ( { * Sidebar > AddContentContainer > ComponentPicker */ componentPicker={ComponentPicker} > - - } - /> - } - /> - - - - + + + } + /> + } + /> + + + + ); }; diff --git a/src/library-authoring/add-content/AddContentContainer.test.tsx b/src/library-authoring/add-content/AddContentContainer.test.tsx index 9bf9a5368e..2f233629cd 100644 --- a/src/library-authoring/add-content/AddContentContainer.test.tsx +++ b/src/library-authoring/add-content/AddContentContainer.test.tsx @@ -12,7 +12,7 @@ import { getContentLibraryApiUrl, getCreateLibraryBlockUrl, getLibraryCollectionComponentApiUrl, getLibraryPasteClipboardUrl, } from '../data/api'; import { mockBroadcastChannel, mockClipboardEmpty, mockClipboardHtml } from '../../generic/data/api.mock'; -import { LibraryProvider } from '../common/context'; +import { LibraryProvider } from '../common/context/LibraryContext'; import AddContentContainer from './AddContentContainer'; import { ComponentEditorModal } from '../components/ComponentEditorModal'; import editorCmsApi from '../../editors/data/services/cms/api'; diff --git a/src/library-authoring/add-content/AddContentContainer.tsx b/src/library-authoring/add-content/AddContentContainer.tsx index 4837d269c0..1a2e28b1a9 100644 --- a/src/library-authoring/add-content/AddContentContainer.tsx +++ b/src/library-authoring/add-content/AddContentContainer.tsx @@ -25,7 +25,7 @@ import { ToastContext } from '../../generic/toast-context'; import { useCopyToClipboard } from '../../generic/clipboard'; import { getCanEdit } from '../../course-unit/data/selectors'; import { useCreateLibraryBlock, useLibraryPasteClipboard, useAddComponentsToCollection } from '../data/apiHooks'; -import { useLibraryContext } from '../common/context'; +import { useLibraryContext } from '../common/context/LibraryContext'; import { canEditComponent } from '../components/ComponentEditorModal'; import { PickLibraryContentModal } from './PickLibraryContentModal'; diff --git a/src/library-authoring/add-content/PickLibraryContentModal.test.tsx b/src/library-authoring/add-content/PickLibraryContentModal.test.tsx index a179dff4b6..f5d3606c5d 100644 --- a/src/library-authoring/add-content/PickLibraryContentModal.test.tsx +++ b/src/library-authoring/add-content/PickLibraryContentModal.test.tsx @@ -9,7 +9,7 @@ import { import { studioHomeMock } from '../../studio-home/__mocks__'; import { getStudioHomeApiUrl } from '../../studio-home/data/api'; import mockResult from '../__mocks__/library-search.json'; -import { LibraryProvider } from '../common/context'; +import { LibraryProvider } from '../common/context/LibraryContext'; import { ComponentPicker } from '../component-picker'; import * as api from '../data/api'; import { diff --git a/src/library-authoring/add-content/PickLibraryContentModal.tsx b/src/library-authoring/add-content/PickLibraryContentModal.tsx index f96723a841..e5977d2407 100644 --- a/src/library-authoring/add-content/PickLibraryContentModal.tsx +++ b/src/library-authoring/add-content/PickLibraryContentModal.tsx @@ -3,7 +3,8 @@ import { FormattedMessage, useIntl } from '@edx/frontend-platform/i18n'; import { ActionRow, Button, StandardModal } from '@openedx/paragon'; import { ToastContext } from '../../generic/toast-context'; -import { type SelectedComponent, useLibraryContext } from '../common/context'; +import { useLibraryContext } from '../common/context/LibraryContext'; +import type { SelectedComponent } from '../common/context/ComponentPickerContext'; import { useAddComponentsToCollection } from '../data/apiHooks'; import messages from './messages'; diff --git a/src/library-authoring/collections/CollectionDetails.test.tsx b/src/library-authoring/collections/CollectionDetails.test.tsx index e2651a1395..b38e4cb48f 100644 --- a/src/library-authoring/collections/CollectionDetails.test.tsx +++ b/src/library-authoring/collections/CollectionDetails.test.tsx @@ -10,7 +10,8 @@ import { waitFor, within, } from '../../testUtils'; -import { LibraryProvider, SidebarBodyComponentId } from '../common/context'; +import { LibraryProvider } from '../common/context/LibraryContext'; +import { SidebarBodyComponentId, SidebarProvider } from '../common/context/SidebarContext'; import * as api from '../data/api'; import { mockContentLibrary, mockGetCollectionMetadata } from '../data/api.mocks'; import CollectionDetails from './CollectionDetails'; @@ -30,14 +31,15 @@ const library = mockContentLibrary.libraryData; const render = () => baseRender(, { extraWrapper: ({ children }) => ( - - { children } + + + { children } + ), }); diff --git a/src/library-authoring/collections/CollectionDetails.tsx b/src/library-authoring/collections/CollectionDetails.tsx index 07a883dea5..d6b4f168cf 100644 --- a/src/library-authoring/collections/CollectionDetails.tsx +++ b/src/library-authoring/collections/CollectionDetails.tsx @@ -6,7 +6,8 @@ import classNames from 'classnames'; import { getItemIcon } from '../../generic/block-type-utils'; import { ToastContext } from '../../generic/toast-context'; import { BlockTypeLabel, useGetBlockTypes } from '../../search-manager'; -import { useLibraryContext } from '../common/context'; +import { useLibraryContext } from '../common/context/LibraryContext'; +import { useSidebarContext } from '../common/context/SidebarContext'; import { useCollection, useUpdateCollection } from '../data/apiHooks'; import HistoryWidget from '../generic/history-widget'; import messages from './messages'; @@ -37,7 +38,8 @@ const BlockCount = ({ }; const CollectionStatsWidget = () => { - const { libraryId, sidebarComponentInfo } = useLibraryContext(); + const { libraryId } = useLibraryContext(); + const { sidebarComponentInfo } = useSidebarContext(); const collectionId = sidebarComponentInfo?.id; const { data: blockTypes } = useGetBlockTypes([ @@ -97,11 +99,8 @@ const CollectionStatsWidget = () => { const CollectionDetails = () => { const intl = useIntl(); const { showToast } = useContext(ToastContext); - const { - libraryId, - sidebarComponentInfo, - readOnly, - } = useLibraryContext(); + const { libraryId, readOnly } = useLibraryContext(); + const { sidebarComponentInfo } = useSidebarContext(); const collectionId = sidebarComponentInfo?.id; // istanbul ignore next: This should never happen diff --git a/src/library-authoring/collections/CollectionInfo.tsx b/src/library-authoring/collections/CollectionInfo.tsx index 245c6155a9..4c370f26e2 100644 --- a/src/library-authoring/collections/CollectionInfo.tsx +++ b/src/library-authoring/collections/CollectionInfo.tsx @@ -8,30 +8,27 @@ import { import { useCallback } from 'react'; import { useNavigate, useMatch } from 'react-router-dom'; +import { useComponentPickerContext } from '../common/context/ComponentPickerContext'; +import { useLibraryContext } from '../common/context/LibraryContext'; import { - useLibraryContext, type CollectionInfoTab, COLLECTION_INFO_TABS, - isCollectionInfoTab, COMPONENT_INFO_TABS, -} from '../common/context'; -import CollectionDetails from './CollectionDetails'; -import messages from './messages'; + isCollectionInfoTab, + useSidebarContext, +} from '../common/context/SidebarContext'; import { ContentTagsDrawer } from '../../content-tags-drawer'; import { buildCollectionUsageKey } from '../../generic/key-utils'; +import CollectionDetails from './CollectionDetails'; +import messages from './messages'; const CollectionInfo = () => { const intl = useIntl(); const navigate = useNavigate(); - const { - libraryId, - collectionId, - setCollectionId, - sidebarComponentInfo, - componentPickerMode, - setSidebarCurrentTab, - } = useLibraryContext(); + const { componentPickerMode } = useComponentPickerContext(); + const { libraryId, collectionId, setCollectionId } = useLibraryContext(); + const { sidebarComponentInfo, setSidebarCurrentTab } = useSidebarContext(); const tab: CollectionInfoTab = ( sidebarComponentInfo?.currentTab && isCollectionInfoTab(sidebarComponentInfo.currentTab) @@ -43,7 +40,7 @@ const CollectionInfo = () => { throw new Error('sidebarCollectionId is required'); } - const url = `/library/${libraryId}/collection/${sidebarCollectionId}/`; + const url = `/library/${libraryId}/collection/${sidebarCollectionId}`; const urlMatch = useMatch(url); const showOpenCollectionButton = !urlMatch && collectionId !== sidebarCollectionId; diff --git a/src/library-authoring/collections/CollectionInfoHeader.test.tsx b/src/library-authoring/collections/CollectionInfoHeader.test.tsx index 7e1b7af374..ac68680c83 100644 --- a/src/library-authoring/collections/CollectionInfoHeader.test.tsx +++ b/src/library-authoring/collections/CollectionInfoHeader.test.tsx @@ -8,7 +8,8 @@ import { screen, waitFor, } from '../../testUtils'; -import { LibraryProvider, SidebarBodyComponentId } from '../common/context'; +import { LibraryProvider } from '../common/context/LibraryContext'; +import { SidebarBodyComponentId, SidebarProvider } from '../common/context/SidebarContext'; import { mockContentLibrary, mockGetCollectionMetadata } from '../data/api.mocks'; import * as api from '../data/api'; import CollectionInfoHeader from './CollectionInfoHeader'; @@ -28,14 +29,15 @@ const { collectionId } = mockGetCollectionMetadata; const render = (libraryId: string = mockLibraryId) => baseRender(, { extraWrapper: ({ children }) => ( - - { children } + + + { children } + ), }); diff --git a/src/library-authoring/collections/CollectionInfoHeader.tsx b/src/library-authoring/collections/CollectionInfoHeader.tsx index 83be4c2139..77fd7d74b7 100644 --- a/src/library-authoring/collections/CollectionInfoHeader.tsx +++ b/src/library-authoring/collections/CollectionInfoHeader.tsx @@ -9,7 +9,8 @@ import { import { Edit } from '@openedx/paragon/icons'; import { ToastContext } from '../../generic/toast-context'; -import { useLibraryContext } from '../common/context'; +import { useLibraryContext } from '../common/context/LibraryContext'; +import { useSidebarContext } from '../common/context/SidebarContext'; import { useCollection, useUpdateCollection } from '../data/apiHooks'; import messages from './messages'; @@ -17,11 +18,8 @@ const CollectionInfoHeader = () => { const intl = useIntl(); const [inputIsActive, setIsActive] = useState(false); - const { - libraryId, - sidebarComponentInfo, - readOnly, - } = useLibraryContext(); + const { libraryId, readOnly } = useLibraryContext(); + const { sidebarComponentInfo } = useSidebarContext(); const collectionId = sidebarComponentInfo?.id; // istanbul ignore if: this should never happen diff --git a/src/library-authoring/collections/LibraryCollectionComponents.tsx b/src/library-authoring/collections/LibraryCollectionComponents.tsx index 87dacd3ab3..e0338dd11e 100644 --- a/src/library-authoring/collections/LibraryCollectionComponents.tsx +++ b/src/library-authoring/collections/LibraryCollectionComponents.tsx @@ -2,12 +2,12 @@ import { Stack } from '@openedx/paragon'; import { NoComponents, NoSearchResults } from '../EmptyStates'; import { useSearchContext } from '../../search-manager'; import messages from './messages'; -import { useLibraryContext } from '../common/context'; +import { useSidebarContext } from '../common/context/SidebarContext'; import LibraryContent, { ContentType } from '../LibraryContent'; const LibraryCollectionComponents = () => { const { totalHits: componentCount, isFiltered } = useSearchContext(); - const { openAddContentSidebar } = useLibraryContext(); + const { openAddContentSidebar } = useSidebarContext(); if (componentCount === 0) { return isFiltered diff --git a/src/library-authoring/collections/LibraryCollectionPage.tsx b/src/library-authoring/collections/LibraryCollectionPage.tsx index bd08309fa3..e59d0decbc 100644 --- a/src/library-authoring/collections/LibraryCollectionPage.tsx +++ b/src/library-authoring/collections/LibraryCollectionPage.tsx @@ -27,17 +27,17 @@ import { SearchSortWidget, } from '../../search-manager'; import { useCollection, useContentLibrary } from '../data/apiHooks'; -import { useLibraryContext } from '../common/context'; +import { useComponentPickerContext } from '../common/context/ComponentPickerContext'; +import { useLibraryContext } from '../common/context/LibraryContext'; +import { useSidebarContext } from '../common/context/SidebarContext'; import messages from './messages'; import { LibrarySidebar } from '../library-sidebar'; import LibraryCollectionComponents from './LibraryCollectionComponents'; const HeaderActions = () => { const intl = useIntl(); - const { - openAddContentSidebar, - readOnly, - } = useLibraryContext(); + const { readOnly } = useLibraryContext(); + const { openAddContentSidebar } = useSidebarContext(); if (readOnly) { return null; @@ -66,7 +66,8 @@ const SubHeaderTitle = ({ }) => { const intl = useIntl(); - const { readOnly, componentPickerMode } = useLibraryContext(); + const { componentPickerMode } = useComponentPickerContext(); + const { readOnly } = useLibraryContext(); const showReadOnlyBadge = readOnly && !componentPickerMode; @@ -103,13 +104,9 @@ const LibraryCollectionPage = () => { throw new Error('Rendered without collectionId or libraryId URL parameter'); } - const { - sidebarComponentInfo, - openCollectionInfoSidebar, - componentPickerMode, - showOnlyPublished, - setCollectionId, - } = useLibraryContext(); + const { componentPickerMode } = useComponentPickerContext(); + const { showOnlyPublished, setCollectionId } = useLibraryContext(); + const { sidebarComponentInfo, openCollectionInfoSidebar } = useSidebarContext(); const { data: collectionData, diff --git a/src/library-authoring/common/context.tsx b/src/library-authoring/common/context.tsx deleted file mode 100644 index a862942f41..0000000000 --- a/src/library-authoring/common/context.tsx +++ /dev/null @@ -1,394 +0,0 @@ -import { useToggle } from '@openedx/paragon'; -import React, { - useCallback, - useContext, - useMemo, - useState, -} from 'react'; - -import type { ComponentPicker } from '../component-picker'; -import type { ContentLibrary } from '../data/api'; -import { useContentLibrary } from '../data/apiHooks'; - -export interface SelectedComponent { - usageKey: string; - blockType: string; -} - -export type ComponentSelectedEvent = (selectedComponent: SelectedComponent) => void; -export type ComponentSelectionChangedEvent = (selectedComponents: SelectedComponent[]) => void; - -type NoComponentPickerType = { - componentPickerMode?: undefined; - onComponentSelected?: never; - selectedComponents?: never; - addComponentToSelectedComponents?: never; - removeComponentFromSelectedComponents?: never; - restrictToLibrary?: never; - /** The component picker modal to use. We need to pass it as a reference instead of - * directly importing it to avoid the import cycle: - * ComponentPicker > LibraryAuthoringPage/LibraryCollectionPage > - * Sidebar > AddContentContainer > ComponentPicker */ - componentPicker?: typeof ComponentPicker; -}; - -type ComponentPickerSingleType = { - componentPickerMode: 'single'; - onComponentSelected: ComponentSelectedEvent; - selectedComponents?: never; - addComponentToSelectedComponents?: never; - removeComponentFromSelectedComponents?: never; - restrictToLibrary: boolean; - componentPicker?: never; -}; - -type ComponentPickerMultipleType = { - componentPickerMode: 'multiple'; - onComponentSelected?: never; - selectedComponents: SelectedComponent[]; - addComponentToSelectedComponents: ComponentSelectedEvent; - removeComponentFromSelectedComponents: ComponentSelectedEvent; - restrictToLibrary: boolean; - componentPicker?: never; -}; - -type ComponentPickerType = NoComponentPickerType | ComponentPickerSingleType | ComponentPickerMultipleType; - -export enum SidebarBodyComponentId { - AddContent = 'add-content', - Info = 'info', - ComponentInfo = 'component-info', - CollectionInfo = 'collection-info', -} - -export const COLLECTION_INFO_TABS = { - Manage: 'manage', - Details: 'details', -} as const; -export type CollectionInfoTab = typeof COLLECTION_INFO_TABS[keyof typeof COLLECTION_INFO_TABS]; -export const isCollectionInfoTab = (tab: string): tab is CollectionInfoTab => ( - Object.values(COLLECTION_INFO_TABS).includes(tab) -); - -export const COMPONENT_INFO_TABS = { - Preview: 'preview', - Manage: 'manage', - Details: 'details', -} as const; -export type ComponentInfoTab = typeof COMPONENT_INFO_TABS[keyof typeof COMPONENT_INFO_TABS]; -export const isComponentInfoTab = (tab: string): tab is ComponentInfoTab => ( - Object.values(COMPONENT_INFO_TABS).includes(tab) -); - -export interface SidebarComponentInfo { - type: SidebarBodyComponentId; - id: string; - /** Additional action on Sidebar display */ - additionalAction?: SidebarAdditionalActions; - /** Current tab in the sidebar */ - currentTab?: CollectionInfoTab | ComponentInfoTab; -} - -export interface ComponentEditorInfo { - usageKey: string; - onClose?: () => void; -} - -export enum SidebarAdditionalActions { - JumpToAddCollections = 'jump-to-add-collections', -} - -export type LibraryContextData = { - /** The ID of the current library */ - libraryId: string; - libraryData?: ContentLibrary; - readOnly: boolean; - isLoadingLibraryData: boolean; - collectionId: string | undefined; - setCollectionId: (collectionId?: string) => void; - // Only show published components - showOnlyPublished: boolean; - // Sidebar stuff - only one sidebar is active at any given time: - closeLibrarySidebar: () => void; - openAddContentSidebar: () => void; - openInfoSidebar: () => void; - openComponentInfoSidebar: (usageKey: string, additionalAction?: SidebarAdditionalActions) => void; - sidebarComponentInfo?: SidebarComponentInfo; - // "Library Team" modal - isLibraryTeamModalOpen: boolean; - openLibraryTeamModal: () => void; - closeLibraryTeamModal: () => void; - // "Create New Collection" modal - isCreateCollectionModalOpen: boolean; - openCreateCollectionModal: () => void; - closeCreateCollectionModal: () => void; - // Current collection - openCollectionInfoSidebar: (collectionId: string, additionalAction?: SidebarAdditionalActions) => void; - // Editor modal - for editing some component - /** If the editor is open and the user is editing some component, this is the component being edited. */ - componentBeingEdited: ComponentEditorInfo | undefined; - /** If an onClose callback is provided, it will be called when the editor is closed. */ - openComponentEditor: (usageKey: string, onClose?: () => void) => void; - closeComponentEditor: () => void; - resetSidebarAdditionalActions: () => void; - setSidebarCurrentTab: (tab: CollectionInfoTab | ComponentInfoTab) => void; -} & ComponentPickerType; - -/** - * Library Context. - * Always available when we're in the context of a single library. - * - * Get this using `useLibraryContext()` - * - * Not used on the "library list" on Studio home. - */ -const LibraryContext = React.createContext(undefined); - -type NoComponentPickerProps = { - componentPickerMode?: undefined; - onComponentSelected?: never; - onChangeComponentSelection?: never; - restrictToLibrary?: never; - componentPicker?: typeof ComponentPicker; -}; - -export type ComponentPickerSingleProps = { - componentPickerMode: 'single'; - onComponentSelected: ComponentSelectedEvent; - onChangeComponentSelection?: never; - restrictToLibrary?: boolean; - componentPicker?: never; -}; - -export type ComponentPickerMultipleProps = { - componentPickerMode: 'multiple'; - onComponentSelected?: never; - onChangeComponentSelection?: ComponentSelectionChangedEvent; - restrictToLibrary?: boolean; - componentPicker?: never; -}; - -type ComponentPickerProps = NoComponentPickerProps | ComponentPickerSingleProps | ComponentPickerMultipleProps; - -type LibraryProviderProps = { - children?: React.ReactNode; - libraryId: string; - /** The initial collection ID to show */ - collectionId?: string; - showOnlyPublished?: boolean; - /** Only used for testing */ - initialSidebarComponentInfo?: SidebarComponentInfo; - componentPicker?: typeof ComponentPicker; -} & ComponentPickerProps; - -/** - * React component to provide `LibraryContext` - */ -export const LibraryProvider = ({ - children, - libraryId, - collectionId: collectionIdProp, - componentPickerMode, - restrictToLibrary = false, - onComponentSelected, - onChangeComponentSelection, - showOnlyPublished = false, - initialSidebarComponentInfo, - componentPicker, -}: LibraryProviderProps) => { - const [collectionId, setCollectionId] = useState(collectionIdProp); - const [sidebarComponentInfo, setSidebarComponentInfo] = useState( - initialSidebarComponentInfo, - ); - const [isLibraryTeamModalOpen, openLibraryTeamModal, closeLibraryTeamModal] = useToggle(false); - const [isCreateCollectionModalOpen, openCreateCollectionModal, closeCreateCollectionModal] = useToggle(false); - const [componentBeingEdited, setComponentBeingEdited] = useState(); - const closeComponentEditor = useCallback(() => { - setComponentBeingEdited((prev) => { - prev?.onClose?.(); - return undefined; - }); - }, []); - const openComponentEditor = useCallback((usageKey: string, onClose?: () => void) => { - setComponentBeingEdited({ usageKey, onClose }); - }, []); - - const [selectedComponents, setSelectedComponents] = useState([]); - - /** Helper function to consume addtional action once performed. - Required to redo the action. - */ - const resetSidebarAdditionalActions = useCallback(() => { - setSidebarComponentInfo((prev) => (prev && { ...prev, additionalAction: undefined })); - }, []); - - const closeLibrarySidebar = useCallback(() => { - setSidebarComponentInfo(undefined); - }, []); - const openAddContentSidebar = useCallback(() => { - setSidebarComponentInfo({ id: '', type: SidebarBodyComponentId.AddContent }); - }, []); - const openInfoSidebar = useCallback(() => { - setSidebarComponentInfo({ id: '', type: SidebarBodyComponentId.Info }); - }, []); - - const openComponentInfoSidebar = useCallback((usageKey: string, additionalAction?: SidebarAdditionalActions) => { - setSidebarComponentInfo((prev) => ({ - ...prev, - id: usageKey, - type: SidebarBodyComponentId.ComponentInfo, - additionalAction, - })); - }, []); - - const openCollectionInfoSidebar = useCallback(( - newCollectionId: string, - additionalAction?: SidebarAdditionalActions, - ) => { - setSidebarComponentInfo((prev) => ({ - ...prev, - id: newCollectionId, - type: SidebarBodyComponentId.CollectionInfo, - additionalAction, - })); - }, []); - - const addComponentToSelectedComponents = useCallback(( - selectedComponent: SelectedComponent, - ) => { - setSelectedComponents((prevSelectedComponents) => { - // istanbul ignore if: this should never happen - if (prevSelectedComponents.some((component) => component.usageKey === selectedComponent.usageKey)) { - return prevSelectedComponents; - } - const newSelectedComponents = [...prevSelectedComponents, selectedComponent]; - onChangeComponentSelection?.(newSelectedComponents); - return newSelectedComponents; - }); - }, []); - - const removeComponentFromSelectedComponents = useCallback(( - selectedComponent: SelectedComponent, - ) => { - setSelectedComponents((prevSelectedComponents) => { - // istanbul ignore if: this should never happen - if (!prevSelectedComponents.some((component) => component.usageKey === selectedComponent.usageKey)) { - return prevSelectedComponents; - } - const newSelectedComponents = prevSelectedComponents.filter( - (component) => component.usageKey !== selectedComponent.usageKey, - ); - onChangeComponentSelection?.(newSelectedComponents); - return newSelectedComponents; - }); - }, []); - - const setSidebarCurrentTab = useCallback((tab: CollectionInfoTab | ComponentInfoTab) => { - setSidebarComponentInfo((prev) => (prev && { ...prev, currentTab: tab })); - }, []); - - const { data: libraryData, isLoading: isLoadingLibraryData } = useContentLibrary(libraryId); - - const readOnly = !!componentPickerMode || !libraryData?.canEditLibrary; - - const context = useMemo(() => { - const contextValue = { - libraryId, - libraryData, - collectionId, - setCollectionId, - readOnly, - isLoadingLibraryData, - showOnlyPublished, - closeLibrarySidebar, - openAddContentSidebar, - openInfoSidebar, - openComponentInfoSidebar, - sidebarComponentInfo, - isLibraryTeamModalOpen, - openLibraryTeamModal, - closeLibraryTeamModal, - isCreateCollectionModalOpen, - openCreateCollectionModal, - closeCreateCollectionModal, - openCollectionInfoSidebar, - componentBeingEdited, - openComponentEditor, - closeComponentEditor, - resetSidebarAdditionalActions, - setSidebarCurrentTab, - }; - if (!componentPickerMode) { - return { - ...contextValue, - componentPicker, - }; - } - if (componentPickerMode === 'single') { - return { - ...contextValue, - componentPickerMode, - restrictToLibrary, - onComponentSelected, - }; - } - if (componentPickerMode === 'multiple') { - return { - ...contextValue, - componentPickerMode, - restrictToLibrary, - selectedComponents, - addComponentToSelectedComponents, - removeComponentFromSelectedComponents, - }; - } - return contextValue; - }, [ - libraryId, - collectionId, - setCollectionId, - libraryData, - readOnly, - isLoadingLibraryData, - showOnlyPublished, - componentPickerMode, - restrictToLibrary, - onComponentSelected, - addComponentToSelectedComponents, - removeComponentFromSelectedComponents, - selectedComponents, - onChangeComponentSelection, - closeLibrarySidebar, - openAddContentSidebar, - openInfoSidebar, - openComponentInfoSidebar, - sidebarComponentInfo, - isLibraryTeamModalOpen, - openLibraryTeamModal, - closeLibraryTeamModal, - isCreateCollectionModalOpen, - openCreateCollectionModal, - closeCreateCollectionModal, - openCollectionInfoSidebar, - componentBeingEdited, - openComponentEditor, - closeComponentEditor, - resetSidebarAdditionalActions, - componentPicker, - ]); - - return ( - - {children} - - ); -}; - -export function useLibraryContext(): LibraryContextData { - const ctx = useContext(LibraryContext); - if (ctx === undefined) { - /* istanbul ignore next */ - throw new Error('useLibraryContext() was used in a component without a ancestor.'); - } - return ctx; -} diff --git a/src/library-authoring/common/context/ComponentPickerContext.tsx b/src/library-authoring/common/context/ComponentPickerContext.tsx new file mode 100644 index 0000000000..83c258ec1d --- /dev/null +++ b/src/library-authoring/common/context/ComponentPickerContext.tsx @@ -0,0 +1,164 @@ +import { + createContext, + useCallback, + useContext, + useMemo, + useState, +} from 'react'; + +export interface SelectedComponent { + usageKey: string; + blockType: string; +} + +export type ComponentSelectedEvent = (selectedComponent: SelectedComponent) => void; +export type ComponentSelectionChangedEvent = (selectedComponents: SelectedComponent[]) => void; + +type NoComponentPickerType = { + componentPickerMode: false; + /** We add the `never` type to ensure that the other properties are not used, + * but allow it to be desconstructed from the return value of `useComponentPickerContext()` + */ + onComponentSelected?: never; + selectedComponents?: never; + addComponentToSelectedComponents?: never; + removeComponentFromSelectedComponents?: never; + restrictToLibrary?: never; +}; + +type ComponentPickerSingleType = { + componentPickerMode: 'single'; + onComponentSelected: ComponentSelectedEvent; + selectedComponents?: never; + addComponentToSelectedComponents?: never; + removeComponentFromSelectedComponents?: never; + restrictToLibrary: boolean; +}; + +type ComponentPickerMultipleType = { + componentPickerMode: 'multiple'; + onComponentSelected?: never; + selectedComponents: SelectedComponent[]; + addComponentToSelectedComponents: ComponentSelectedEvent; + removeComponentFromSelectedComponents: ComponentSelectedEvent; + restrictToLibrary: boolean; +}; + +type ComponentPickerContextData = ComponentPickerSingleType | ComponentPickerMultipleType; + +/** + * Component Picker Context. + * This context is used to provide the component picker mode and the selected components. + * + * Get this using `useComponentPickerContext()` + */ +const ComponentPickerContext = createContext(undefined); + +export type ComponentPickerSingleProps = { + componentPickerMode: 'single'; + onComponentSelected: ComponentSelectedEvent; + onChangeComponentSelection?: never; + restrictToLibrary?: boolean; +}; + +export type ComponentPickerMultipleProps = { + componentPickerMode: 'multiple'; + onComponentSelected?: never; + onChangeComponentSelection?: ComponentSelectionChangedEvent; + restrictToLibrary?: boolean; +}; + +type ComponentPickerProps = ComponentPickerSingleProps | ComponentPickerMultipleProps; + +type ComponentPickerProviderProps = { + children?: React.ReactNode; +} & ComponentPickerProps; + +/** + * React component to provide `ComponentPickerContext` + */ +export const ComponentPickerProvider = ({ + children, + componentPickerMode, + restrictToLibrary = false, + onComponentSelected, + onChangeComponentSelection, +}: ComponentPickerProviderProps) => { + const [selectedComponents, setSelectedComponents] = useState([]); + + const addComponentToSelectedComponents = useCallback(( + selectedComponent: SelectedComponent, + ) => { + setSelectedComponents((prevSelectedComponents) => { + // istanbul ignore if: this should never happen + if (prevSelectedComponents.some((component) => component.usageKey === selectedComponent.usageKey)) { + return prevSelectedComponents; + } + const newSelectedComponents = [...prevSelectedComponents, selectedComponent]; + onChangeComponentSelection?.(newSelectedComponents); + return newSelectedComponents; + }); + }, []); + + const removeComponentFromSelectedComponents = useCallback(( + selectedComponent: SelectedComponent, + ) => { + setSelectedComponents((prevSelectedComponents) => { + // istanbul ignore if: this should never happen + if (!prevSelectedComponents.some((component) => component.usageKey === selectedComponent.usageKey)) { + return prevSelectedComponents; + } + const newSelectedComponents = prevSelectedComponents.filter( + (component) => component.usageKey !== selectedComponent.usageKey, + ); + onChangeComponentSelection?.(newSelectedComponents); + return newSelectedComponents; + }); + }, []); + + const context = useMemo(() => { + switch (componentPickerMode) { + case 'single': + return { + componentPickerMode, + restrictToLibrary, + onComponentSelected, + }; + case 'multiple': + return { + componentPickerMode, + restrictToLibrary, + selectedComponents, + addComponentToSelectedComponents, + removeComponentFromSelectedComponents, + }; + default: + // istanbul ignore next: this should never happen + throw new Error('Invalid component picker mode'); + } + }, [ + componentPickerMode, + restrictToLibrary, + onComponentSelected, + addComponentToSelectedComponents, + removeComponentFromSelectedComponents, + selectedComponents, + onChangeComponentSelection, + ]); + + return ( + + {children} + + ); +}; + +export function useComponentPickerContext(): ComponentPickerContextData | NoComponentPickerType { + const ctx = useContext(ComponentPickerContext); + if (ctx === undefined) { + return { + componentPickerMode: false, + }; + } + return ctx; +} diff --git a/src/library-authoring/common/context/LibraryContext.tsx b/src/library-authoring/common/context/LibraryContext.tsx new file mode 100644 index 0000000000..9612a92855 --- /dev/null +++ b/src/library-authoring/common/context/LibraryContext.tsx @@ -0,0 +1,147 @@ +import { useToggle } from '@openedx/paragon'; +import { + createContext, + useCallback, + useContext, + useMemo, + useState, +} from 'react'; + +import type { ComponentPicker } from '../../component-picker'; +import type { ContentLibrary } from '../../data/api'; +import { useContentLibrary } from '../../data/apiHooks'; +import { useComponentPickerContext } from './ComponentPickerContext'; + +export interface ComponentEditorInfo { + usageKey: string; + onClose?: () => void; +} + +export type LibraryContextData = { + /** The ID of the current library */ + libraryId: string; + libraryData?: ContentLibrary; + readOnly: boolean; + isLoadingLibraryData: boolean; + collectionId: string | undefined; + setCollectionId: (collectionId?: string) => void; + // Only show published components + showOnlyPublished: boolean; + // "Create New Collection" modal + isCreateCollectionModalOpen: boolean; + openCreateCollectionModal: () => void; + closeCreateCollectionModal: () => void; + // Editor modal - for editing some component + /** If the editor is open and the user is editing some component, this is the component being edited. */ + componentBeingEdited: ComponentEditorInfo | undefined; + /** If an onClose callback is provided, it will be called when the editor is closed. */ + openComponentEditor: (usageKey: string, onClose?: () => void) => void; + closeComponentEditor: () => void; + componentPicker?: typeof ComponentPicker; +}; + +/** + * Library Context. + * Always available when we're in the context of a single library. + * + * Get this using `useLibraryContext()` + * + * Not used on the "library list" on Studio home. + */ +const LibraryContext = createContext(undefined); + +type LibraryProviderProps = { + children?: React.ReactNode; + libraryId: string; + /** The initial collection ID to show */ + collectionId?: string; + showOnlyPublished?: boolean; + /** The component picker modal to use. We need to pass it as a reference instead of + * directly importing it to avoid the import cycle: + * ComponentPicker > LibraryAuthoringPage/LibraryCollectionPage > + * Sidebar > AddContentContainer > ComponentPicker */ + componentPicker?: typeof ComponentPicker; +}; + +/** + * React component to provide `LibraryContext` + */ +export const LibraryProvider = ({ + children, + libraryId, + collectionId: collectionIdProp, + showOnlyPublished = false, + componentPicker, +}: LibraryProviderProps) => { + const [collectionId, setCollectionId] = useState(collectionIdProp); + const [isCreateCollectionModalOpen, openCreateCollectionModal, closeCreateCollectionModal] = useToggle(false); + const [componentBeingEdited, setComponentBeingEdited] = useState(); + const closeComponentEditor = useCallback(() => { + setComponentBeingEdited((prev) => { + prev?.onClose?.(); + return undefined; + }); + }, []); + const openComponentEditor = useCallback((usageKey: string, onClose?: () => void) => { + setComponentBeingEdited({ usageKey, onClose }); + }, []); + + const { data: libraryData, isLoading: isLoadingLibraryData } = useContentLibrary(libraryId); + + const { + componentPickerMode, + } = useComponentPickerContext(); + + const readOnly = !!componentPickerMode || !libraryData?.canEditLibrary; + + const context = useMemo(() => { + const contextValue = { + libraryId, + libraryData, + collectionId, + setCollectionId, + readOnly, + isLoadingLibraryData, + showOnlyPublished, + isCreateCollectionModalOpen, + openCreateCollectionModal, + closeCreateCollectionModal, + componentBeingEdited, + openComponentEditor, + closeComponentEditor, + componentPicker, + }; + + return contextValue; + }, [ + libraryId, + collectionId, + setCollectionId, + libraryData, + readOnly, + isLoadingLibraryData, + showOnlyPublished, + isCreateCollectionModalOpen, + openCreateCollectionModal, + closeCreateCollectionModal, + componentBeingEdited, + openComponentEditor, + closeComponentEditor, + componentPicker, + ]); + + return ( + + {children} + + ); +}; + +export function useLibraryContext(): LibraryContextData { + const ctx = useContext(LibraryContext); + if (ctx === undefined) { + /* istanbul ignore next */ + throw new Error('useLibraryContext() was used in a component without a ancestor.'); + } + return ctx; +} diff --git a/src/library-authoring/common/context/SidebarContext.tsx b/src/library-authoring/common/context/SidebarContext.tsx new file mode 100644 index 0000000000..d9ba68d69b --- /dev/null +++ b/src/library-authoring/common/context/SidebarContext.tsx @@ -0,0 +1,173 @@ +import { + createContext, + useCallback, + useContext, + useMemo, + useState, +} from 'react'; + +export enum SidebarBodyComponentId { + AddContent = 'add-content', + Info = 'info', + ComponentInfo = 'component-info', + CollectionInfo = 'collection-info', +} + +export const COLLECTION_INFO_TABS = { + Manage: 'manage', + Details: 'details', +} as const; +export type CollectionInfoTab = typeof COLLECTION_INFO_TABS[keyof typeof COLLECTION_INFO_TABS]; +export const isCollectionInfoTab = (tab: string): tab is CollectionInfoTab => ( + Object.values(COLLECTION_INFO_TABS).includes(tab) +); + +export const COMPONENT_INFO_TABS = { + Preview: 'preview', + Manage: 'manage', + Details: 'details', +} as const; +export type ComponentInfoTab = typeof COMPONENT_INFO_TABS[keyof typeof COMPONENT_INFO_TABS]; +export const isComponentInfoTab = (tab: string): tab is ComponentInfoTab => ( + Object.values(COMPONENT_INFO_TABS).includes(tab) +); + +export interface SidebarComponentInfo { + type: SidebarBodyComponentId; + id: string; + /** Additional action on Sidebar display */ + additionalAction?: SidebarAdditionalActions; + /** Current tab in the sidebar */ + currentTab?: CollectionInfoTab | ComponentInfoTab; +} + +export enum SidebarAdditionalActions { + JumpToAddCollections = 'jump-to-add-collections', +} + +export type SidebarContextData = { + closeLibrarySidebar: () => void; + openAddContentSidebar: () => void; + openInfoSidebar: () => void; + openCollectionInfoSidebar: (collectionId: string, additionalAction?: SidebarAdditionalActions) => void; + openComponentInfoSidebar: (usageKey: string, additionalAction?: SidebarAdditionalActions) => void; + sidebarComponentInfo?: SidebarComponentInfo; + resetSidebarAdditionalActions: () => void; + setSidebarCurrentTab: (tab: CollectionInfoTab | ComponentInfoTab) => void; +}; + +/** + * Sidebar Context. + * + * Get this using `useSidebarContext()` + * + */ +const SidebarContext = createContext(undefined); + +type SidebarProviderProps = { + children?: React.ReactNode; + /** Only used for testing */ + initialSidebarComponentInfo?: SidebarComponentInfo; +}; + +/** + * React component to provide `LibraryContext` + */ +export const SidebarProvider = ({ + children, + initialSidebarComponentInfo, +}: SidebarProviderProps) => { + const [sidebarComponentInfo, setSidebarComponentInfo] = useState( + initialSidebarComponentInfo, + ); + + /** Helper function to consume addtional action once performed. + Required to redo the action. + */ + const resetSidebarAdditionalActions = useCallback(() => { + setSidebarComponentInfo((prev) => (prev && { ...prev, additionalAction: undefined })); + }, []); + + const closeLibrarySidebar = useCallback(() => { + setSidebarComponentInfo(undefined); + }, []); + const openAddContentSidebar = useCallback(() => { + setSidebarComponentInfo({ id: '', type: SidebarBodyComponentId.AddContent }); + }, []); + const openInfoSidebar = useCallback(() => { + setSidebarComponentInfo({ id: '', type: SidebarBodyComponentId.Info }); + }, []); + + const openComponentInfoSidebar = useCallback((usageKey: string, additionalAction?: SidebarAdditionalActions) => { + setSidebarComponentInfo((prev) => ({ + ...prev, + id: usageKey, + type: SidebarBodyComponentId.ComponentInfo, + additionalAction, + })); + }, []); + + const openCollectionInfoSidebar = useCallback(( + newCollectionId: string, + additionalAction?: SidebarAdditionalActions, + ) => { + setSidebarComponentInfo((prev) => ({ + ...prev, + id: newCollectionId, + type: SidebarBodyComponentId.CollectionInfo, + additionalAction, + })); + }, []); + + const setSidebarCurrentTab = useCallback((tab: CollectionInfoTab | ComponentInfoTab) => { + setSidebarComponentInfo((prev) => (prev && { ...prev, currentTab: tab })); + }, []); + + const context = useMemo(() => { + const contextValue = { + closeLibrarySidebar, + openAddContentSidebar, + openInfoSidebar, + openComponentInfoSidebar, + sidebarComponentInfo, + openCollectionInfoSidebar, + resetSidebarAdditionalActions, + setSidebarCurrentTab, + }; + + return contextValue; + }, [ + closeLibrarySidebar, + openAddContentSidebar, + openInfoSidebar, + openComponentInfoSidebar, + sidebarComponentInfo, + openCollectionInfoSidebar, + resetSidebarAdditionalActions, + setSidebarCurrentTab, + ]); + + return ( + + {children} + + ); +}; + +export function useSidebarContext(): SidebarContextData { + const ctx = useContext(SidebarContext); + if (ctx === undefined) { + /* istanbul ignore next */ + return { + closeLibrarySidebar: () => {}, + openAddContentSidebar: () => {}, + openInfoSidebar: () => {}, + openComponentInfoSidebar: () => {}, + openCollectionInfoSidebar: () => {}, + resetSidebarAdditionalActions: () => {}, + setSidebarCurrentTab: () => {}, + sidebarComponentInfo: undefined, + }; + } + return ctx; +} diff --git a/src/library-authoring/component-info/ComponentAdvancedAssets.tsx b/src/library-authoring/component-info/ComponentAdvancedAssets.tsx index b9ea9ba567..38bf5c3e6e 100644 --- a/src/library-authoring/component-info/ComponentAdvancedAssets.tsx +++ b/src/library-authoring/component-info/ComponentAdvancedAssets.tsx @@ -10,14 +10,16 @@ import { FormattedMessage, FormattedNumber, useIntl } from '@edx/frontend-platfo import { LoadingSpinner } from '../../generic/Loading'; import DeleteModal from '../../generic/delete-modal/DeleteModal'; -import { useLibraryContext } from '../common/context'; +import { useLibraryContext } from '../common/context/LibraryContext'; +import { useSidebarContext } from '../common/context/SidebarContext'; import { getXBlockAssetsApiUrl } from '../data/api'; import { useDeleteXBlockAsset, useInvalidateXBlockAssets, useXBlockAssets } from '../data/apiHooks'; import messages from './messages'; export const ComponentAdvancedAssets: React.FC> = () => { const intl = useIntl(); - const { readOnly, sidebarComponentInfo } = useLibraryContext(); + const { readOnly } = useLibraryContext(); + const { sidebarComponentInfo } = useSidebarContext(); const usageKey = sidebarComponentInfo?.id; // istanbul ignore if: this should never happen in production diff --git a/src/library-authoring/component-info/ComponentAdvancedInfo.test.tsx b/src/library-authoring/component-info/ComponentAdvancedInfo.test.tsx index 862ccfe339..360f7d777c 100644 --- a/src/library-authoring/component-info/ComponentAdvancedInfo.test.tsx +++ b/src/library-authoring/component-info/ComponentAdvancedInfo.test.tsx @@ -12,8 +12,9 @@ import { mockXBlockAssets, mockXBlockOLX, } from '../data/api.mocks'; +import { LibraryProvider } from '../common/context/LibraryContext'; +import { SidebarBodyComponentId, SidebarProvider } from '../common/context/SidebarContext'; import * as apiHooks from '../data/apiHooks'; -import { LibraryProvider, SidebarBodyComponentId } from '../common/context'; import { ComponentAdvancedInfo } from './ComponentAdvancedInfo'; import { getXBlockAssetsApiUrl } from '../data/api'; @@ -31,15 +32,15 @@ const render = ( , { extraWrapper: ({ children }: { children: React.ReactNode }) => ( - - {children} + + + {children} + ), }, diff --git a/src/library-authoring/component-info/ComponentAdvancedInfo.tsx b/src/library-authoring/component-info/ComponentAdvancedInfo.tsx index f3396e941f..89d756e4e9 100644 --- a/src/library-authoring/component-info/ComponentAdvancedInfo.tsx +++ b/src/library-authoring/component-info/ComponentAdvancedInfo.tsx @@ -11,7 +11,8 @@ import { FormattedMessage, useIntl } from '@edx/frontend-platform/i18n'; import { LoadingSpinner } from '../../generic/Loading'; import { CodeEditor, EditorAccessor } from '../../generic/CodeEditor'; -import { useLibraryContext } from '../common/context'; +import { useLibraryContext } from '../common/context/LibraryContext'; +import { useSidebarContext } from '../common/context/SidebarContext'; import { useUpdateXBlockOLX, useXBlockOLX, @@ -21,11 +22,8 @@ import { ComponentAdvancedAssets } from './ComponentAdvancedAssets'; const ComponentAdvancedInfoInner: React.FC> = () => { const intl = useIntl(); - const { - readOnly, - sidebarComponentInfo, - showOnlyPublished, - } = useLibraryContext(); + const { readOnly, showOnlyPublished } = useLibraryContext(); + const { sidebarComponentInfo } = useSidebarContext(); const usageKey = sidebarComponentInfo?.id; // istanbul ignore if: this should never happen in production diff --git a/src/library-authoring/component-info/ComponentDetails.test.tsx b/src/library-authoring/component-info/ComponentDetails.test.tsx index 514e66bdf8..33fb4c211a 100644 --- a/src/library-authoring/component-info/ComponentDetails.test.tsx +++ b/src/library-authoring/component-info/ComponentDetails.test.tsx @@ -9,7 +9,7 @@ import { mockXBlockAssets, mockXBlockOLX, } from '../data/api.mocks'; -import { LibraryProvider, SidebarBodyComponentId } from '../common/context'; +import { SidebarBodyComponentId, SidebarProvider } from '../common/context/SidebarContext'; import ComponentDetails from './ComponentDetails'; mockContentLibrary.applyMock(); @@ -17,19 +17,16 @@ mockLibraryBlockMetadata.applyMock(); mockXBlockAssets.applyMock(); mockXBlockOLX.applyMock(); -const { libraryId: mockLibraryId } = mockContentLibrary; - const render = (usageKey: string) => baseRender(, { extraWrapper: ({ children }) => ( - {children} - + ), }); diff --git a/src/library-authoring/component-info/ComponentDetails.tsx b/src/library-authoring/component-info/ComponentDetails.tsx index 0bac9d3234..e41f3ad50c 100644 --- a/src/library-authoring/component-info/ComponentDetails.tsx +++ b/src/library-authoring/component-info/ComponentDetails.tsx @@ -3,14 +3,14 @@ import { Stack } from '@openedx/paragon'; import AlertError from '../../generic/alert-error'; import Loading from '../../generic/Loading'; -import { useLibraryContext } from '../common/context'; +import { useSidebarContext } from '../common/context/SidebarContext'; import { useLibraryBlockMetadata } from '../data/apiHooks'; import HistoryWidget from '../generic/history-widget'; import { ComponentAdvancedInfo } from './ComponentAdvancedInfo'; import messages from './messages'; const ComponentDetails = () => { - const { sidebarComponentInfo } = useLibraryContext(); + const { sidebarComponentInfo } = useSidebarContext(); const usageKey = sidebarComponentInfo?.id; diff --git a/src/library-authoring/component-info/ComponentInfo.test.tsx b/src/library-authoring/component-info/ComponentInfo.test.tsx index 7cb44cfee6..6ccebc29fe 100644 --- a/src/library-authoring/component-info/ComponentInfo.test.tsx +++ b/src/library-authoring/component-info/ComponentInfo.test.tsx @@ -6,7 +6,8 @@ import { } from '../../testUtils'; import { mockContentLibrary, mockLibraryBlockMetadata } from '../data/api.mocks'; import { mockBroadcastChannel } from '../../generic/data/api.mock'; -import { LibraryProvider, SidebarBodyComponentId } from '../common/context'; +import { LibraryProvider } from '../common/context/LibraryContext'; +import { SidebarBodyComponentId, SidebarProvider } from '../common/context/SidebarContext'; import ComponentInfo from './ComponentInfo'; import { getXBlockPublishApiUrl } from '../data/api'; @@ -24,14 +25,15 @@ jest.mock('./ComponentManagement', () => ({ const withLibraryId = (libraryId: string, sidebarComponentUsageKey: string) => ({ extraWrapper: ({ children }: { children: React.ReactNode }) => ( - - {children} + + + {children} + ), }); diff --git a/src/library-authoring/component-info/ComponentInfo.tsx b/src/library-authoring/component-info/ComponentInfo.tsx index e3f60a52ec..c9db685e92 100644 --- a/src/library-authoring/component-info/ComponentInfo.tsx +++ b/src/library-authoring/component-info/ComponentInfo.tsx @@ -11,13 +11,15 @@ import { CheckBoxOutlineBlank, } from '@openedx/paragon/icons'; +import { useComponentPickerContext } from '../common/context/ComponentPickerContext'; +import { useLibraryContext } from '../common/context/LibraryContext'; import { - SidebarAdditionalActions, - useLibraryContext, + type ComponentInfoTab, COMPONENT_INFO_TABS, - ComponentInfoTab, + SidebarAdditionalActions, isComponentInfoTab, -} from '../common/context'; + useSidebarContext, +} from '../common/context/SidebarContext'; import ComponentMenu from '../components'; import { canEditComponent } from '../components/ComponentEditorModal'; import ComponentDetails from './ComponentDetails'; @@ -31,14 +33,15 @@ import { ToastContext } from '../../generic/toast-context'; const AddComponentWidget = () => { const intl = useIntl(); + const { sidebarComponentInfo } = useSidebarContext(); + const { - sidebarComponentInfo, componentPickerMode, onComponentSelected, addComponentToSelectedComponents, removeComponentFromSelectedComponents, selectedComponents, - } = useLibraryContext(); + } = useComponentPickerContext(); const usageKey = sidebarComponentInfo?.id; @@ -97,13 +100,8 @@ const AddComponentWidget = () => { const ComponentInfo = () => { const intl = useIntl(); - const { - sidebarComponentInfo, - readOnly, - openComponentEditor, - resetSidebarAdditionalActions, - setSidebarCurrentTab, - } = useLibraryContext(); + const { readOnly, openComponentEditor } = useLibraryContext(); + const { setSidebarCurrentTab, sidebarComponentInfo, resetSidebarAdditionalActions } = useSidebarContext(); const jumpToCollections = sidebarComponentInfo?.additionalAction === SidebarAdditionalActions.JumpToAddCollections; diff --git a/src/library-authoring/component-info/ComponentInfoHeader.test.tsx b/src/library-authoring/component-info/ComponentInfoHeader.test.tsx index 832f0eebf0..c6b8622cd7 100644 --- a/src/library-authoring/component-info/ComponentInfoHeader.test.tsx +++ b/src/library-authoring/component-info/ComponentInfoHeader.test.tsx @@ -9,7 +9,8 @@ import { } from '../../testUtils'; import { mockContentLibrary } from '../data/api.mocks'; import { getXBlockFieldsVersionApiUrl, getXBlockFieldsApiUrl } from '../data/api'; -import { LibraryProvider, SidebarBodyComponentId } from '../common/context'; +import { LibraryProvider } from '../common/context/LibraryContext'; +import { SidebarBodyComponentId, SidebarProvider } from '../common/context/SidebarContext'; import ComponentInfoHeader from './ComponentInfoHeader'; const { libraryId: mockLibraryId, libraryIdReadOnly } = mockContentLibrary; @@ -24,14 +25,15 @@ const xBlockFields = { const render = (libraryId: string = mockLibraryId) => baseRender(, { extraWrapper: ({ children }) => ( - - {children} + + + {children} + ), }); diff --git a/src/library-authoring/component-info/ComponentInfoHeader.tsx b/src/library-authoring/component-info/ComponentInfoHeader.tsx index 295e4a3821..ac6317d4a7 100644 --- a/src/library-authoring/component-info/ComponentInfoHeader.tsx +++ b/src/library-authoring/component-info/ComponentInfoHeader.tsx @@ -9,7 +9,8 @@ import { import { Edit } from '@openedx/paragon/icons'; import { ToastContext } from '../../generic/toast-context'; -import { useLibraryContext } from '../common/context'; +import { useLibraryContext } from '../common/context/LibraryContext'; +import { useSidebarContext } from '../common/context/SidebarContext'; import { useUpdateXBlockFields, useXBlockFields } from '../data/apiHooks'; import messages from './messages'; @@ -17,11 +18,8 @@ const ComponentInfoHeader = () => { const intl = useIntl(); const [inputIsActive, setIsActive] = useState(false); - const { - sidebarComponentInfo, - readOnly, - showOnlyPublished, - } = useLibraryContext(); + const { readOnly, showOnlyPublished } = useLibraryContext(); + const { sidebarComponentInfo } = useSidebarContext(); const usageKey = sidebarComponentInfo?.id; // istanbul ignore next diff --git a/src/library-authoring/component-info/ComponentManagement.test.tsx b/src/library-authoring/component-info/ComponentManagement.test.tsx index 93a5872df2..b9f9e0a7c9 100644 --- a/src/library-authoring/component-info/ComponentManagement.test.tsx +++ b/src/library-authoring/component-info/ComponentManagement.test.tsx @@ -7,7 +7,8 @@ import { screen, waitFor, } from '../../testUtils'; -import { LibraryProvider, SidebarBodyComponentId } from '../common/context'; +import { LibraryProvider } from '../common/context/LibraryContext'; +import { SidebarBodyComponentId, SidebarProvider } from '../common/context/SidebarContext'; import { mockContentLibrary, mockLibraryBlockMetadata } from '../data/api.mocks'; import ComponentManagement from './ComponentManagement'; @@ -37,14 +38,15 @@ const matchInnerText = (nodeName: string, textToMatch: string) => (_: string, el const render = (usageKey: string, libraryId?: string) => baseRender(, { extraWrapper: ({ children }) => ( - - {children} + + + {children} + ), }); diff --git a/src/library-authoring/component-info/ComponentManagement.tsx b/src/library-authoring/component-info/ComponentManagement.tsx index 0cfb1c14c9..bbdfc51efb 100644 --- a/src/library-authoring/component-info/ComponentManagement.tsx +++ b/src/library-authoring/component-info/ComponentManagement.tsx @@ -6,7 +6,8 @@ import { BookOpen, ExpandLess, ExpandMore, Tag, } from '@openedx/paragon/icons'; -import { SidebarAdditionalActions, useLibraryContext } from '../common/context'; +import { useLibraryContext } from '../common/context/LibraryContext'; +import { SidebarAdditionalActions, useSidebarContext } from '../common/context/SidebarContext'; import { useLibraryBlockMetadata } from '../data/apiHooks'; import StatusWidget from '../generic/status-widget'; import messages from './messages'; @@ -16,9 +17,8 @@ import ManageCollections from './ManageCollections'; const ComponentManagement = () => { const intl = useIntl(); - const { - sidebarComponentInfo, readOnly, resetSidebarAdditionalActions, isLoadingLibraryData, - } = useLibraryContext(); + const { readOnly, isLoadingLibraryData } = useLibraryContext(); + const { sidebarComponentInfo, resetSidebarAdditionalActions } = useSidebarContext(); const jumpToCollections = sidebarComponentInfo?.additionalAction === SidebarAdditionalActions.JumpToAddCollections; const [tagsCollapseIsOpen, setTagsCollapseOpen] = React.useState(!jumpToCollections); const [collectionsCollapseIsOpen, setCollectionsCollapseOpen] = React.useState(true); diff --git a/src/library-authoring/component-info/ComponentPreview.test.tsx b/src/library-authoring/component-info/ComponentPreview.test.tsx index cf71dab382..1233ec6007 100644 --- a/src/library-authoring/component-info/ComponentPreview.test.tsx +++ b/src/library-authoring/component-info/ComponentPreview.test.tsx @@ -4,7 +4,8 @@ import { render as baseRender, screen, } from '../../testUtils'; -import { LibraryProvider, SidebarBodyComponentId } from '../common/context'; +import { LibraryProvider } from '../common/context/LibraryContext'; +import { SidebarBodyComponentId, SidebarProvider } from '../common/context/SidebarContext'; import { mockContentLibrary, mockLibraryBlockMetadata } from '../data/api.mocks'; import ComponentPreview from './ComponentPreview'; @@ -19,14 +20,15 @@ const usageKey = mockLibraryBlockMetadata.usageKeyPublished; const render = () => baseRender(, { extraWrapper: ({ children }) => ( - - { children } + + + {children} + ), }); diff --git a/src/library-authoring/component-info/ComponentPreview.tsx b/src/library-authoring/component-info/ComponentPreview.tsx index 05c91c1468..0f7ff51448 100644 --- a/src/library-authoring/component-info/ComponentPreview.tsx +++ b/src/library-authoring/component-info/ComponentPreview.tsx @@ -2,7 +2,8 @@ import { useIntl } from '@edx/frontend-platform/i18n'; import { Button, StandardModal, useToggle } from '@openedx/paragon'; import { OpenInFull } from '@openedx/paragon/icons'; -import { useLibraryContext } from '../common/context'; +import { useLibraryContext } from '../common/context/LibraryContext'; +import { useSidebarContext } from '../common/context/SidebarContext'; import { LibraryBlock } from '../LibraryBlock'; import messages from './messages'; import { useLibraryBlockMetadata } from '../data/apiHooks'; @@ -37,7 +38,8 @@ const ComponentPreview = () => { const intl = useIntl(); const [isModalOpen, openModal, closeModal] = useToggle(); - const { sidebarComponentInfo, showOnlyPublished } = useLibraryContext(); + const { showOnlyPublished } = useLibraryContext(); + const { sidebarComponentInfo } = useSidebarContext(); const usageKey = sidebarComponentInfo?.id; // istanbul ignore if: this should never happen diff --git a/src/library-authoring/component-info/ManageCollections.test.tsx b/src/library-authoring/component-info/ManageCollections.test.tsx index abcd643dc3..9c3d696546 100644 --- a/src/library-authoring/component-info/ManageCollections.test.tsx +++ b/src/library-authoring/component-info/ManageCollections.test.tsx @@ -12,7 +12,7 @@ import mockCollectionsResults from '../__mocks__/collection-search.json'; import { mockContentSearchConfig } from '../../search-manager/data/api.mock'; import { mockContentLibrary, mockLibraryBlockMetadata } from '../data/api.mocks'; import ManageCollections from './ManageCollections'; -import { LibraryProvider } from '../common/context'; +import { LibraryProvider } from '../common/context/LibraryContext'; import { getLibraryBlockCollectionsUrl } from '../data/api'; let axiosMock: MockAdapter; @@ -24,7 +24,9 @@ mockContentSearchConfig.applyMock(); const render = (ui: React.ReactElement) => baseRender(ui, { extraWrapper: ({ children }) => ( - {children} + + {children} + ), }); diff --git a/src/library-authoring/component-info/ManageCollections.tsx b/src/library-authoring/component-info/ManageCollections.tsx index 099e66631f..b7cbc98323 100644 --- a/src/library-authoring/component-info/ManageCollections.tsx +++ b/src/library-authoring/component-info/ManageCollections.tsx @@ -15,7 +15,8 @@ import messages from './messages'; import { useUpdateComponentCollections } from '../data/apiHooks'; import { ToastContext } from '../../generic/toast-context'; import { CollectionMetadata } from '../data/api'; -import { SidebarAdditionalActions, useLibraryContext } from '../common/context'; +import { useLibraryContext } from '../common/context/LibraryContext'; +import { SidebarAdditionalActions, useSidebarContext } from '../common/context/SidebarContext'; interface ManageCollectionsProps { usageKey: string; @@ -190,7 +191,7 @@ const ComponentCollections = ({ collections, onManageClick }: { }; const ManageCollections = ({ usageKey, collections }: ManageCollectionsProps) => { - const { sidebarComponentInfo, resetSidebarAdditionalActions } = useLibraryContext(); + const { sidebarComponentInfo, resetSidebarAdditionalActions } = useSidebarContext(); const jumpToCollections = sidebarComponentInfo?.additionalAction === SidebarAdditionalActions.JumpToAddCollections; const [editing, setEditing] = useState(jumpToCollections); const collectionNames = collections.map((collection) => collection.title); diff --git a/src/library-authoring/component-picker/ComponentPicker.tsx b/src/library-authoring/component-picker/ComponentPicker.tsx index e57d667c4a..115c081fec 100644 --- a/src/library-authoring/component-picker/ComponentPicker.tsx +++ b/src/library-authoring/component-picker/ComponentPicker.tsx @@ -6,9 +6,10 @@ import { FormattedMessage } from '@edx/frontend-platform/i18n'; import { type ComponentSelectedEvent, type ComponentSelectionChangedEvent, - LibraryProvider, - useLibraryContext, -} from '../common/context'; + ComponentPickerProvider, +} from '../common/context/ComponentPickerContext'; +import { LibraryProvider, useLibraryContext } from '../common/context/LibraryContext'; +import { SidebarProvider } from '../common/context/SidebarContext'; import LibraryAuthoringPage from '../LibraryAuthoringPage'; import LibraryCollectionPage from '../collections/LibraryCollectionPage'; import SelectLibrary from './SelectLibrary'; @@ -81,7 +82,7 @@ export const ComponentPicker: React.FC = ({ const restrictToLibrary = !!libraryId; - const libraryProviderProps = componentPickerMode === 'single' ? { + const componentPickerProviderProps = componentPickerMode === 'single' ? { componentPickerMode, onComponentSelected, restrictToLibrary, @@ -100,19 +101,22 @@ export const ComponentPicker: React.FC = ({ - - { calcShowOnlyPublished - && ( - - - - )} - - + + + + { calcShowOnlyPublished + && ( + + + + )} + + + + ); diff --git a/src/library-authoring/components/CollectionCard.test.tsx b/src/library-authoring/components/CollectionCard.test.tsx index eefbc7ba53..3f7dc7fc88 100644 --- a/src/library-authoring/components/CollectionCard.test.tsx +++ b/src/library-authoring/components/CollectionCard.test.tsx @@ -4,7 +4,7 @@ import type MockAdapter from 'axios-mock-adapter'; import { initializeMocks, render as baseRender, screen, waitFor, waitForElementToBeRemoved, within, } from '../../testUtils'; -import { LibraryProvider } from '../common/context'; +import { LibraryProvider } from '../common/context/LibraryContext'; import { type CollectionHit } from '../../search-manager'; import CollectionCard from './CollectionCard'; import messages from './messages'; @@ -42,7 +42,7 @@ const render = (ui: React.ReactElement, showOnlyPublished: boolean = false) => b libraryId="lib:Axim:TEST" showOnlyPublished={showOnlyPublished} > - { children } + {children} ), }); @@ -81,7 +81,7 @@ describe('', () => { const openMenuItem = screen.getByRole('link', { name: 'Open' }); expect(openMenuItem).toBeInTheDocument(); - expect(openMenuItem).toHaveAttribute('href', '/library/lb:org1:Demo_Course/collection/collection-display-name/'); + expect(openMenuItem).toHaveAttribute('href', '/library/lb:org1:Demo_Course/collection/collection-display-name'); }); it('should show confirmation box, delete collection and show toast to undo deletion', async () => { diff --git a/src/library-authoring/components/CollectionCard.tsx b/src/library-authoring/components/CollectionCard.tsx index 67f97d3b8b..6935bc12c8 100644 --- a/src/library-authoring/components/CollectionCard.tsx +++ b/src/library-authoring/components/CollectionCard.tsx @@ -11,7 +11,9 @@ import { MoreVert } from '@openedx/paragon/icons'; import { Link } from 'react-router-dom'; import { type CollectionHit } from '../../search-manager'; -import { useLibraryContext } from '../common/context'; +import { useComponentPickerContext } from '../common/context/ComponentPickerContext'; +import { useLibraryContext } from '../common/context/LibraryContext'; +import { useSidebarContext } from '../common/context/SidebarContext'; import BaseComponentCard from './BaseComponentCard'; import { ToastContext } from '../../generic/toast-context'; import { useDeleteCollection, useRestoreCollection } from '../data/apiHooks'; @@ -26,7 +28,7 @@ const CollectionMenu = ({ collectionHit } : CollectionMenuProps) => { const intl = useIntl(); const { showToast } = useContext(ToastContext); const [isDeleteModalOpen, openDeleteModal, closeDeleteModal] = useToggle(false); - const { closeLibrarySidebar, sidebarComponentInfo } = useLibraryContext(); + const { closeLibrarySidebar, sidebarComponentInfo } = useSidebarContext(); const restoreCollectionMutation = useRestoreCollection(collectionHit.contextKey, collectionHit.blockId); const restoreCollection = useCallback(() => { @@ -76,7 +78,7 @@ const CollectionMenu = ({ collectionHit } : CollectionMenuProps) => { @@ -104,11 +106,9 @@ type CollectionCardProps = { }; const CollectionCard = ({ collectionHit } : CollectionCardProps) => { - const { - openCollectionInfoSidebar, - componentPickerMode, - showOnlyPublished, - } = useLibraryContext(); + const { componentPickerMode } = useComponentPickerContext(); + const { showOnlyPublished } = useLibraryContext(); + const { openCollectionInfoSidebar } = useSidebarContext(); const { type: componentType, diff --git a/src/library-authoring/components/ComponentCard.test.tsx b/src/library-authoring/components/ComponentCard.test.tsx index fb5fb9685d..9d0c53a304 100644 --- a/src/library-authoring/components/ComponentCard.test.tsx +++ b/src/library-authoring/components/ComponentCard.test.tsx @@ -5,7 +5,7 @@ import { waitFor, initializeMocks, } from '../../testUtils'; -import { LibraryProvider } from '../common/context'; +import { LibraryProvider } from '../common/context/LibraryContext'; import { getClipboardUrl } from '../../generic/data/api'; import { ContentHit } from '../../search-manager'; import ComponentCard from './ComponentCard'; @@ -46,7 +46,11 @@ const clipboardBroadcastChannelMock = { const libraryId = 'lib:org1:Demo_Course'; const render = () => baseRender(, { - extraWrapper: ({ children }) => { children }, + extraWrapper: ({ children }) => ( + + { children } + + ), }); describe('', () => { diff --git a/src/library-authoring/components/ComponentCard.tsx b/src/library-authoring/components/ComponentCard.tsx index c21f15467e..813255b97a 100644 --- a/src/library-authoring/components/ComponentCard.tsx +++ b/src/library-authoring/components/ComponentCard.tsx @@ -19,7 +19,9 @@ import { STUDIO_CLIPBOARD_CHANNEL } from '../../constants'; import { updateClipboard } from '../../generic/data/api'; import { ToastContext } from '../../generic/toast-context'; import { type ContentHit } from '../../search-manager'; -import { SidebarAdditionalActions, useLibraryContext } from '../common/context'; +import { useComponentPickerContext } from '../common/context/ComponentPickerContext'; +import { useLibraryContext } from '../common/context/LibraryContext'; +import { SidebarAdditionalActions, useSidebarContext } from '../common/context/SidebarContext'; import { useRemoveComponentsFromCollection } from '../data/apiHooks'; import BaseComponentCard from './BaseComponentCard'; import { canEditComponent } from './ComponentEditorModal'; @@ -35,11 +37,14 @@ export const ComponentMenu = ({ usageKey }: { usageKey: string }) => { const { libraryId, collectionId, + openComponentEditor, + } = useLibraryContext(); + + const { sidebarComponentInfo, openComponentInfoSidebar, - openComponentEditor, closeLibrarySidebar, - } = useLibraryContext(); + } = useSidebarContext(); const canEdit = usageKey && canEditComponent(usageKey); const { showToast } = useContext(ToastContext); @@ -121,7 +126,7 @@ const AddComponentWidget = ({ usageKey, blockType }: AddComponentWidgetProps) => addComponentToSelectedComponents, removeComponentFromSelectedComponents, selectedComponents, - } = useLibraryContext(); + } = useComponentPickerContext(); // istanbul ignore if: this should never happen if (!usageKey) { @@ -178,11 +183,9 @@ const AddComponentWidget = ({ usageKey, blockType }: AddComponentWidgetProps) => }; const ComponentCard = ({ contentHit }: ComponentCardProps) => { - const { - openComponentInfoSidebar, - componentPickerMode, - showOnlyPublished, - } = useLibraryContext(); + const { showOnlyPublished } = useLibraryContext(); + const { openComponentInfoSidebar } = useSidebarContext(); + const { componentPickerMode } = useComponentPickerContext(); const { blockType, diff --git a/src/library-authoring/components/ComponentDeleter.test.tsx b/src/library-authoring/components/ComponentDeleter.test.tsx index 5db365efe1..ed0e62543a 100644 --- a/src/library-authoring/components/ComponentDeleter.test.tsx +++ b/src/library-authoring/components/ComponentDeleter.test.tsx @@ -1,4 +1,3 @@ -import { getLibraryId } from '../../generic/key-utils'; import { fireEvent, render, @@ -6,7 +5,7 @@ import { initializeMocks, waitFor, } from '../../testUtils'; -import { LibraryProvider } from '../common/context'; +import { SidebarProvider } from '../common/context/SidebarContext'; import { mockContentLibrary, mockDeleteLibraryBlock, mockLibraryBlockMetadata } from '../data/api.mocks'; import ComponentDeleter from './ComponentDeleter'; @@ -17,9 +16,7 @@ const mockDelete = mockDeleteLibraryBlock.applyMock(); const usageKey = mockLibraryBlockMetadata.usageKeyPublished; const renderArgs = { - extraWrapper: ({ children }: { children: React.ReactNode }) => ( - {children} - ), + extraWrapper: SidebarProvider, }; describe('', () => { diff --git a/src/library-authoring/components/ComponentDeleter.tsx b/src/library-authoring/components/ComponentDeleter.tsx index b71f139ae4..f5b85e7f4a 100644 --- a/src/library-authoring/components/ComponentDeleter.tsx +++ b/src/library-authoring/components/ComponentDeleter.tsx @@ -7,7 +7,7 @@ import { } from '@openedx/paragon'; import { Warning } from '@openedx/paragon/icons'; -import { useLibraryContext } from '../common/context'; +import { useSidebarContext } from '../common/context/SidebarContext'; import { useDeleteLibraryBlock, useLibraryBlockMetadata } from '../data/apiHooks'; import messages from './messages'; @@ -34,10 +34,7 @@ interface Props { const ComponentDeleter = ({ usageKey, ...props }: Props) => { const intl = useIntl(); - const { - sidebarComponentInfo, - closeLibrarySidebar, - } = useLibraryContext(); + const { sidebarComponentInfo, closeLibrarySidebar } = useSidebarContext(); const sidebarComponentUsageKey = sidebarComponentInfo?.id; const deleteComponentMutation = useDeleteLibraryBlock(); diff --git a/src/library-authoring/components/ComponentEditorModal.tsx b/src/library-authoring/components/ComponentEditorModal.tsx index 6fbe8a46b3..6ba78979bd 100644 --- a/src/library-authoring/components/ComponentEditorModal.tsx +++ b/src/library-authoring/components/ComponentEditorModal.tsx @@ -4,7 +4,7 @@ import React from 'react'; import { useQueryClient } from '@tanstack/react-query'; import EditorPage from '../../editors/EditorPage'; import { getBlockType } from '../../generic/key-utils'; -import { useLibraryContext } from '../common/context'; +import { useLibraryContext } from '../common/context/LibraryContext'; import { invalidateComponentData } from '../data/apiHooks'; export function canEditComponent(usageKey: string): boolean { diff --git a/src/library-authoring/create-collection/CreateCollectionModal.tsx b/src/library-authoring/create-collection/CreateCollectionModal.tsx index 1b160ab0ee..de9e776cf9 100644 --- a/src/library-authoring/create-collection/CreateCollectionModal.tsx +++ b/src/library-authoring/create-collection/CreateCollectionModal.tsx @@ -10,7 +10,7 @@ import { useIntl } from '@edx/frontend-platform/i18n'; import { Formik } from 'formik'; import * as Yup from 'yup'; import FormikControl from '../../generic/FormikControl'; -import { useLibraryContext } from '../common/context'; +import { useLibraryContext } from '../common/context/LibraryContext'; import messages from './messages'; import { useCreateLibraryCollection } from '../data/apiHooks'; import { ToastContext } from '../../generic/toast-context'; diff --git a/src/library-authoring/legacy-integration/PreviewChangesEmbed.tsx b/src/library-authoring/legacy-integration/PreviewChangesEmbed.tsx index 648ca83d64..c1fa8c90c5 100644 --- a/src/library-authoring/legacy-integration/PreviewChangesEmbed.tsx +++ b/src/library-authoring/legacy-integration/PreviewChangesEmbed.tsx @@ -2,8 +2,6 @@ import { useIntl } from '@edx/frontend-platform/i18n'; import { useParams, useSearchParams } from 'react-router-dom'; import { Helmet } from 'react-helmet'; -import { LibraryProvider } from '../common/context'; -import { getLibraryId } from '../../generic/key-utils'; import CompareChangesWidget from '../component-comparison/CompareChangesWidget'; import { useLibraryBlockMetadata } from '../data/apiHooks'; import messages from '../component-comparison/messages'; @@ -28,16 +26,15 @@ const PreviewChangesEmbed = () => { } const [queryString] = useSearchParams(); const oldVersion = parseInt(queryString.get('old') ?? '', 10) || 'published'; - const libraryId = getLibraryId(usageKey); const { data: metadata } = useLibraryBlockMetadata(usageKey); return ( - + <> {/* It's not necessary since this will usually be in an