Skip to content

Commit

Permalink
refactor: change context state names
Browse files Browse the repository at this point in the history
  • Loading branch information
rpenido committed Oct 10, 2024
1 parent ecc2de5 commit 9062b52
Show file tree
Hide file tree
Showing 20 changed files with 111 additions and 72 deletions.
6 changes: 1 addition & 5 deletions src/library-authoring/LibraryAuthoringPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,6 @@ const HeaderActions = () => {
readOnly,
} = useLibraryContext();

if (!readOnly) {
return null;
}

const infoSidebarIsOpen = () => (
sidebarBodyComponent === SidebarBodyComponentId.Info
);
Expand Down Expand Up @@ -105,7 +101,7 @@ const HeaderActions = () => {
iconBefore={Add}
variant="primary rounded-0"
onClick={openAddContentSidebar}
disabled={!canEditLibrary}
disabled={readOnly}
>
{intl.formatMessage(messages.newContentButton)}
</Button>
Expand Down
4 changes: 2 additions & 2 deletions src/library-authoring/LibraryLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ import LibraryCollectionPage from './collections/LibraryCollectionPage';
import { ComponentEditorModal } from './components/ComponentEditorModal';

const LibraryLayout = () => {
const { libraryId } = useParams();
const { libraryId, collectionId } = useParams();

if (libraryId === undefined) {
// istanbul ignore next - This shouldn't be possible; it's just here to satisfy the type checker.
throw new Error('Error: route is missing libraryId.');
}

return (
<LibraryProvider libraryId={libraryId}>
<LibraryProvider libraryId={libraryId} collectionId={collectionId}>
<Routes>
<Route
path="collection/:collectionId"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const library = mockContentLibrary.libraryData;

const render = () => baseRender(<CollectionDetails />, {
extraWrapper: ({ children }) => (
<LibraryProvider libraryId={library.id} collectionId={collectionId}>
<LibraryProvider libraryId={library.id} sidebarCollectionId={collectionId}>
{ children }
</LibraryProvider>
),
Expand Down
4 changes: 2 additions & 2 deletions src/library-authoring/collections/CollectionDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ const BlockCount = ({
};

const CollectionStatsWidget = () => {
const { libraryId, currentCollectionId: collectionId } = useLibraryContext();
const { libraryId, sidebarCollectionId: collectionId } = useLibraryContext();

const { data: blockTypes } = useGetBlockTypes([
`context_key = "${libraryId}"`,
Expand Down Expand Up @@ -98,7 +98,7 @@ const CollectionDetails = () => {
const { showToast } = useContext(ToastContext);
const {
libraryId,
currentCollectionId: collectionId,
sidebarCollectionId: collectionId,
readOnly,
} = useLibraryContext();

Expand Down
17 changes: 13 additions & 4 deletions src/library-authoring/collections/CollectionInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,30 @@ import {
Tab,
Tabs,
} from '@openedx/paragon';
import { Link, useMatch } from 'react-router-dom';
import { useCallback } from 'react';
import { useNavigate, useMatch } from 'react-router-dom';

import { useLibraryContext } from '../common/context';
import CollectionDetails from './CollectionDetails';
import messages from './messages';

const CollectionInfo = () => {
const intl = useIntl();
const navigate = useNavigate();

const { libraryId, currentCollectionId: collectionId } = useLibraryContext();
const { libraryId, sidebarCollectionId: collectionId, componentPickerMode } = useLibraryContext();

const url = `/library/${libraryId}/collection/${collectionId}/`;
const urlMatch = useMatch(url);

const handleOpenCollection = useCallback(() => {
if (!componentPickerMode) {
navigate(url);
} else {
// FIXME: Set state here
}
}, [componentPickerMode, url]);

if (!collectionId) {
return null;
}
Expand All @@ -28,8 +38,7 @@ const CollectionInfo = () => {
{!urlMatch && (
<div className="d-flex flex-wrap">
<Button
as={Link}
to={url}
onClick={handleOpenCollection}
variant="outline-primary"
className="m-1 text-nowrap flex-grow-1"
disabled={!!urlMatch}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const { collectionId } = mockGetCollectionMetadata;

const render = (libraryId: string = mockLibraryId) => baseRender(<CollectionInfoHeader />, {
extraWrapper: ({ children }) => (
<LibraryProvider libraryId={libraryId} collectionId={collectionId}>
<LibraryProvider libraryId={libraryId} sidebarCollectionId={collectionId}>
{ children }
</LibraryProvider>
),
Expand Down
2 changes: 1 addition & 1 deletion src/library-authoring/collections/CollectionInfoHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const CollectionInfoHeader = () => {

const {
libraryId,
currentCollectionId: collectionId,
sidebarCollectionId: collectionId,
readOnly,
} = useLibraryContext();

Expand Down
4 changes: 2 additions & 2 deletions src/library-authoring/collections/LibraryCollectionPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ const SubHeaderTitle = ({
variant="primary"
/>
</Stack>
{ !canEditLibrary && (
{!canEditLibrary && (
<div>
<Badge variant="primary" style={{ fontSize: '50%' }}>
{intl.formatMessage(messages.readOnlyBadge)}
Expand Down Expand Up @@ -194,7 +194,7 @@ const LibraryCollectionPage = () => {
</Container>
<StudioFooter />
</div>
{ !!sidebarBodyComponent && (
{!!sidebarBodyComponent && (
<div className="library-authoring-sidebar box-shadow-left-1 bg-white" data-testid="library-sidebar">
<LibrarySidebar />
</div>
Expand Down
70 changes: 41 additions & 29 deletions src/library-authoring/common/context.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { useToggle } from '@openedx/paragon';
import React from 'react';
import React, {
useCallback,
useContext,
useMemo,
useState,
} from 'react';

import type { ContentLibrary } from '../data/api';
import { useContentLibrary } from '../data/apiHooks';
Expand All @@ -19,20 +24,21 @@ export interface LibraryContextData {
isLoadingLibraryData: boolean;
// Whether we're in "component picker" mode
componentPickerMode: boolean;
homeCollectionId?: string;
// Sidebar stuff - only one sidebar is active at any given time:
sidebarBodyComponent: SidebarBodyComponentId | null;
closeLibrarySidebar: () => void;
openAddContentSidebar: () => void;
openInfoSidebar: () => void;
openComponentInfoSidebar: (usageKey: string) => void;
currentComponentUsageKey?: string;
sidebarComponentUsageKey?: string;
// "Create New Collection" modal
isCreateCollectionModalOpen: boolean;
openCreateCollectionModal: () => void;
closeCreateCollectionModal: () => void;
// Current collection
openCollectionInfoSidebar: (collectionId: string) => void;
currentCollectionId?: string;
sidebarCollectionId?: string;
// Editor modal - for editing some component
/** If the editor is open and the user is editing some component, this is its usageKey */
componentBeingEdited: string | undefined;
Expand All @@ -53,9 +59,10 @@ const LibraryContext = React.createContext<LibraryContextData | undefined>(undef
interface LibraryProviderProps {
children?: React.ReactNode;
libraryId: string;
componentPickerMode?: boolean;
collectionId?: string;
componentUsageKey?: string;
componentPickerMode?: boolean;
sidebarCollectionId?: string;
sidebarComponentUsageKey?: string;
}

/**
Expand All @@ -64,56 +71,60 @@ interface LibraryProviderProps {
export const LibraryProvider = ({
children,
libraryId,
componentPickerMode = false,
collectionId,
componentUsageKey,
componentPickerMode = false,
sidebarCollectionId: sideBarCollectionIdProp,
sidebarComponentUsageKey: sidebarComponentUsageKeyProp,
}: LibraryProviderProps) => {
const [sidebarBodyComponent, setSidebarBodyComponent] = React.useState<SidebarBodyComponentId | null>(null);
const [currentComponentUsageKey, setCurrentComponentUsageKey] = React.useState<string | undefined>(componentUsageKey);
const [currentCollectionId, setcurrentCollectionId] = React.useState<string | undefined>(collectionId);
const [sidebarBodyComponent, setSidebarBodyComponent] = useState<SidebarBodyComponentId | null>(null);
const [sidebarComponentUsageKey, setSidebarComponentUsageKey] = useState<string | undefined>(
sidebarComponentUsageKeyProp,
);
const [sidebarCollectionId, setSidebarCollectionId] = useState<string | undefined>(sideBarCollectionIdProp);
const [isCreateCollectionModalOpen, openCreateCollectionModal, closeCreateCollectionModal] = useToggle(false);
const [componentBeingEdited, openComponentEditor] = React.useState<string | undefined>();
const closeComponentEditor = React.useCallback(() => openComponentEditor(undefined), []);
const [componentBeingEdited, openComponentEditor] = useState<string | undefined>();
const closeComponentEditor = useCallback(() => openComponentEditor(undefined), []);

const resetSidebar = React.useCallback(() => {
setCurrentComponentUsageKey(undefined);
setcurrentCollectionId(undefined);
const resetSidebar = useCallback(() => {
setSidebarComponentUsageKey(undefined);
setSidebarCollectionId(undefined);
setSidebarBodyComponent(null);
}, []);

const closeLibrarySidebar = React.useCallback(() => {
const closeLibrarySidebar = useCallback(() => {
resetSidebar();
setCurrentComponentUsageKey(undefined);
setSidebarComponentUsageKey(undefined);
}, []);
const openAddContentSidebar = React.useCallback(() => {
const openAddContentSidebar = useCallback(() => {
resetSidebar();
setSidebarBodyComponent(SidebarBodyComponentId.AddContent);
}, []);
const openInfoSidebar = React.useCallback(() => {
const openInfoSidebar = useCallback(() => {
resetSidebar();
setSidebarBodyComponent(SidebarBodyComponentId.Info);
}, []);
const openComponentInfoSidebar = React.useCallback(
const openComponentInfoSidebar = useCallback(
(usageKey: string) => {
resetSidebar();
setCurrentComponentUsageKey(usageKey);
setSidebarComponentUsageKey(usageKey);
setSidebarBodyComponent(SidebarBodyComponentId.ComponentInfo);
},
[],
);
const openCollectionInfoSidebar = React.useCallback((newCollectionId: string) => {
const openCollectionInfoSidebar = useCallback((newCollectionId: string) => {
resetSidebar();
setcurrentCollectionId(newCollectionId);
setSidebarCollectionId(newCollectionId);
setSidebarBodyComponent(SidebarBodyComponentId.CollectionInfo);
}, []);

const { data: libraryData, isLoading: isLoadingLibraryData } = useContentLibrary(libraryId);

const readOnly = componentPickerMode || !libraryData?.canEditLibrary;

const context = React.useMemo<LibraryContextData>(() => ({
const context = useMemo<LibraryContextData>(() => ({
libraryId,
libraryData,
collectionId,
readOnly,
isLoadingLibraryData,
componentPickerMode,
Expand All @@ -122,17 +133,18 @@ export const LibraryProvider = ({
openAddContentSidebar,
openInfoSidebar,
openComponentInfoSidebar,
currentComponentUsageKey,
sidebarComponentUsageKey,
isCreateCollectionModalOpen,
openCreateCollectionModal,
closeCreateCollectionModal,
openCollectionInfoSidebar,
currentCollectionId,
sidebarCollectionId,
componentBeingEdited,
openComponentEditor,
closeComponentEditor,
}), [
libraryId,
collectionId,
libraryData,
readOnly,
isLoadingLibraryData,
Expand All @@ -142,12 +154,12 @@ export const LibraryProvider = ({
openAddContentSidebar,
openInfoSidebar,
openComponentInfoSidebar,
currentComponentUsageKey,
sidebarComponentUsageKey,
isCreateCollectionModalOpen,
openCreateCollectionModal,
closeCreateCollectionModal,
openCollectionInfoSidebar,
currentCollectionId,
sidebarCollectionId,
componentBeingEdited,
openComponentEditor,
closeComponentEditor,
Expand All @@ -161,7 +173,7 @@ export const LibraryProvider = ({
};

export function useLibraryContext(): LibraryContextData {
const ctx = React.useContext(LibraryContext);
const ctx = useContext(LibraryContext);
if (ctx === undefined) {
/* istanbul ignore next */
throw new Error('useLibraryContext() was used in a component without a <LibraryProvider> ancestor.');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const { libraryId: mockLibraryId } = mockContentLibrary;

const render = (usageKey: string) => baseRender(<ComponentDetails />, {
extraWrapper: ({ children }) => (
<LibraryProvider libraryId={mockLibraryId} componentUsageKey={usageKey}>
<LibraryProvider libraryId={mockLibraryId} sidebarComponentUsageKey={usageKey}>
{children}
</LibraryProvider>
),
Expand Down
2 changes: 1 addition & 1 deletion src/library-authoring/component-info/ComponentDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import messages from './messages';
const ComponentDetails = () => {
const intl = useIntl();

const { currentComponentUsageKey: usageKey } = useLibraryContext();
const { sidebarComponentUsageKey: usageKey } = useLibraryContext();

// istanbul ignore if: this should never happen
if (!usageKey) {
Expand Down
21 changes: 13 additions & 8 deletions src/library-authoring/component-info/ComponentInfo.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,23 @@ jest.mock('./ComponentManagement', () => ({
default: () => <div>Mocked management tab</div>,
}));

const withLibraryId = (libraryId: string) => ({
const withLibraryId = (libraryId: string, sidebarComponentUsageKey: string) => ({
extraWrapper: ({ children }: { children: React.ReactNode }) => (
<LibraryProvider libraryId={libraryId}>{children}</LibraryProvider>
<LibraryProvider
libraryId={libraryId}
sidebarComponentUsageKey={sidebarComponentUsageKey}
>
{children}
</LibraryProvider>
),
});

describe('<ComponentInfo> Sidebar', () => {
it('should show a disabled "Edit" button when the component type is not editable', async () => {
initializeMocks();
render(
<ComponentInfo usageKey={mockLibraryBlockMetadata.usageKeyThirdPartyXBlock} />,
withLibraryId(mockContentLibrary.libraryId),
<ComponentInfo />,
withLibraryId(mockContentLibrary.libraryId, mockLibraryBlockMetadata.usageKeyThirdPartyXBlock),
);

const editButton = await screen.findByRole('button', { name: /Edit component/ });
Expand All @@ -42,8 +47,8 @@ describe('<ComponentInfo> Sidebar', () => {
it('should show a disabled "Edit" button when the library is read-only', async () => {
initializeMocks();
render(
<ComponentInfo usageKey={mockLibraryBlockMetadata.usageKeyPublished} />,
withLibraryId(mockContentLibrary.libraryIdReadOnly),
<ComponentInfo />,
withLibraryId(mockContentLibrary.libraryIdReadOnly, mockLibraryBlockMetadata.usageKeyPublished),
);

const editButton = await screen.findByRole('button', { name: /Edit component/ });
Expand All @@ -53,8 +58,8 @@ describe('<ComponentInfo> Sidebar', () => {
it('should show a working "Edit" button for a normal component', async () => {
initializeMocks();
render(
<ComponentInfo usageKey={mockLibraryBlockMetadata.usageKeyPublished} />,
withLibraryId(mockContentLibrary.libraryId),
<ComponentInfo />,
withLibraryId(mockContentLibrary.libraryId, mockLibraryBlockMetadata.usageKeyPublished),
);

const editButton = await screen.findByRole('button', { name: /Edit component/ });
Expand Down
2 changes: 1 addition & 1 deletion src/library-authoring/component-info/ComponentInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const ComponentInfo = () => {
const { showToast } = useContext(ToastContext);

const {
currentComponentUsageKey: usageKey,
sidebarComponentUsageKey: usageKey,
readOnly,
openComponentEditor,
componentPickerMode,
Expand Down
Loading

0 comments on commit 9062b52

Please sign in to comment.