Skip to content

Commit

Permalink
fixup! feat: improve collection sidebar
Browse files Browse the repository at this point in the history
  • Loading branch information
rpenido committed Sep 25, 2024
1 parent 72f5694 commit 82aba72
Show file tree
Hide file tree
Showing 7 changed files with 113 additions and 46 deletions.
4 changes: 3 additions & 1 deletion src/library-authoring/collections/CollectionDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,9 @@ const CollectionDetails = ({ library, collection }: CollectionDetailsProps) => {
};

return (
<Stack gap={3}>
<Stack
gap={3}
>
<div>
<h3 className="h5">
{intl.formatMessage(messages.detailsTabDescriptionTitle)}
Expand Down
6 changes: 5 additions & 1 deletion src/library-authoring/collections/CollectionInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,11 @@ const CollectionInfo = ({ library, collection }: CollectionInfoProps) => {
Manage tab placeholder
</Tab>
<Tab eventKey="details" title={intl.formatMessage(messages.detailsTabTitle)}>
<CollectionDetails library={library} collection={collection} />
<CollectionDetails
key={collection.id} // This is necessary to force a re-render when the collection changes
library={library}
collection={collection}
/>
</Tab>
</Tabs>
);
Expand Down
2 changes: 2 additions & 0 deletions src/library-authoring/collections/CollectionInfoHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ const CollectionInfoHeader = ({ library, collection } : CollectionInfoHeaderProp
}).finally(() => {
setIsActive(false);
});
} else {
setIsActive(false);
}
},
[collection, showToast, intl],
Expand Down
28 changes: 21 additions & 7 deletions src/library-authoring/common/context.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useToggle } from '@openedx/paragon';
import React from 'react';
import type { CollectionHit } from '../../search-manager';

export enum SidebarBodyComponentId {
AddContent = 'add-content',
Expand All @@ -18,7 +19,8 @@ export interface LibraryContextData {
isCreateCollectionModalOpen: boolean;
openCreateCollectionModal: () => void;
closeCreateCollectionModal: () => void;
openCollectionInfoSidebar: () => void;
openCollectionInfoSidebar: (collectionHit: CollectionHit) => void
currentCollectionHit?: CollectionHit;
}

export const LibraryContext = React.createContext({
Expand All @@ -30,7 +32,8 @@ export const LibraryContext = React.createContext({
isCreateCollectionModalOpen: false,
openCreateCollectionModal: () => {},
closeCreateCollectionModal: () => {},
openCollectionInfoSidebar: () => {},
// eslint-disable-next-line @typescript-eslint/no-unused-vars
openCollectionInfoSidebar: (_collectionHit: CollectionHit) => {},
} as LibraryContextData);

/**
Expand All @@ -39,29 +42,38 @@ export const LibraryContext = React.createContext({
export const LibraryProvider = (props: { children?: React.ReactNode }) => {
const [sidebarBodyComponent, setSidebarBodyComponent] = React.useState<SidebarBodyComponentId | null>(null);
const [currentComponentUsageKey, setCurrentComponentUsageKey] = React.useState<string>();
const [currentCollectionHit, setcurrentCollectionHit] = React.useState<CollectionHit>();
const [isCreateCollectionModalOpen, openCreateCollectionModal, closeCreateCollectionModal] = useToggle(false);

const closeLibrarySidebar = React.useCallback(() => {
const resetSidebar = React.useCallback(() => {
setCurrentComponentUsageKey(undefined);
setcurrentCollectionHit(undefined);
setSidebarBodyComponent(null);
}, []);

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

Expand All @@ -76,6 +88,7 @@ export const LibraryProvider = (props: { children?: React.ReactNode }) => {
openCreateCollectionModal,
closeCreateCollectionModal,
openCollectionInfoSidebar,
currentCollectionHit,
}), [
sidebarBodyComponent,
closeLibrarySidebar,
Expand All @@ -87,6 +100,7 @@ export const LibraryProvider = (props: { children?: React.ReactNode }) => {
openCreateCollectionModal,
closeCreateCollectionModal,
openCollectionInfoSidebar,
currentCollectionHit,
]);

return (
Expand Down
48 changes: 37 additions & 11 deletions src/library-authoring/components/CollectionCard.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,54 @@
import { useIntl } from '@edx/frontend-platform/i18n';
import { useIntl, FormattedMessage } from '@edx/frontend-platform/i18n';
import {
ActionRow,
Dropdown,
Icon,
IconButton,
} from '@openedx/paragon';
import { MoreVert } from '@openedx/paragon/icons';
import { useNavigate } from 'react-router-dom';
import { useContext } from 'react';
import { Link } from 'react-router-dom';

import { type CollectionHit } from '../../search-manager';
import messages from './messages';
import { LibraryContext } from '../common/context';
import BaseComponentCard from './BaseComponentCard';
import messages from './messages';

export const CollectionMenu = ({ collectionHit }: { collectionHit: CollectionHit }) => {
const intl = useIntl();

return (
<Dropdown id="collection-card-dropdown" onClick={(e) => e.stopPropagation()}>
<Dropdown.Toggle
id="collection-card-menu-toggle"
as={IconButton}
src={MoreVert}
iconAs={Icon}
variant="primary"
alt={intl.formatMessage(messages.collectionCardMenuAlt)}
data-testid="collection-card-menu-toggle"
/>
<Dropdown.Menu>
<Dropdown.Item
as={Link}
to={`/library/${collectionHit.contextKey}/collection/${collectionHit.blockId}/`}
>
<FormattedMessage {...messages.menuEdit} />
</Dropdown.Item>
</Dropdown.Menu>
</Dropdown>
);
};

type CollectionCardProps = {
collectionHit: CollectionHit,
};

const CollectionCard = ({ collectionHit }: CollectionCardProps) => {
const intl = useIntl();
const navigate = useNavigate();
const {
openCollectionInfoSidebar,
} = useContext(LibraryContext);

const {
type,
Expand All @@ -39,16 +70,11 @@ const CollectionCard = ({ collectionHit }: CollectionCardProps) => {
tags={tags}
actions={(
<ActionRow>
<IconButton
src={MoreVert}
iconAs={Icon}
variant="primary"
alt={intl.formatMessage(messages.collectionCardMenuAlt)}
/>
<CollectionMenu collectionHit={collectionHit} />
</ActionRow>
)}
blockTypeDisplayName={blockTypeDisplayName}
openInfoSidebar={() => navigate(`/library/${collectionHit.contextKey}/collection/${collectionHit.blockId}`)}
openInfoSidebar={() => openCollectionInfoSidebar(collectionHit)}
/>
);
};
Expand Down
4 changes: 2 additions & 2 deletions src/library-authoring/components/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ const messages = defineMessages({
description: 'Collection type text with children count',
},
menuEdit: {
id: 'course-authoring.library-authoring.component.menu.edit',
id: 'course-authoring.library-authoring.component-collection.menu.edit',
defaultMessage: 'Edit',
description: 'Menu item for edit a component.',
description: 'Menu item for edit a component/collection.',
},
menuCopyToClipboard: {
id: 'course-authoring.library-authoring.component.menu.copy',
Expand Down
67 changes: 43 additions & 24 deletions src/library-authoring/library-sidebar/LibrarySidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,21 @@ import {
} from '@openedx/paragon';
import { Close } from '@openedx/paragon/icons';
import { useIntl } from '@edx/frontend-platform/i18n';
import messages from '../messages';
import { SearchParams } from 'meilisearch';

import {
SearchContextProvider,
} from '../../search-manager';
import { AddContentContainer, AddContentHeader } from '../add-content';
import { CollectionInfo, CollectionInfoHeader } from '../collections';
import { ContentLibrary } from '../data/api';
import { LibraryContext, SidebarBodyComponentId } from '../common/context';
import { LibraryInfo, LibraryInfoHeader } from '../library-info';
import { ComponentInfo, ComponentInfoHeader } from '../component-info';
import { ContentLibrary } from '../data/api';
import { CollectionInfo, CollectionInfoHeader } from '../collections';
import { type CollectionHit } from '../../search-manager/data/api';
import { LibraryInfo, LibraryInfoHeader } from '../library-info';
import messages from '../messages';

type LibrarySidebarProps = {
library: ContentLibrary,
collection?: CollectionHit,
};

/**
Expand All @@ -29,12 +32,13 @@ type LibrarySidebarProps = {
* You can add more components in `bodyComponentMap`.
* Use the returned actions to open and close this sidebar.
*/
const LibrarySidebar = ({ library, collection }: LibrarySidebarProps) => {
const LibrarySidebar = ({ library }: LibrarySidebarProps) => {
const intl = useIntl();
const {
sidebarBodyComponent,
closeLibrarySidebar,
currentComponentUsageKey,
currentCollectionHit,
} = useContext(LibraryContext);

const bodyComponentMap = {
Expand All @@ -43,7 +47,9 @@ const LibrarySidebar = ({ library, collection }: LibrarySidebarProps) => {
[SidebarBodyComponentId.ComponentInfo]: (
currentComponentUsageKey && <ComponentInfo usageKey={currentComponentUsageKey} />
),
[SidebarBodyComponentId.CollectionInfo]: collection && <CollectionInfo library={library} collection={collection} />,
[SidebarBodyComponentId.CollectionInfo]: (
currentCollectionHit && <CollectionInfo library={library} collection={currentCollectionHit} />
),
unknown: null,
};

Expand All @@ -54,31 +60,44 @@ const LibrarySidebar = ({ library, collection }: LibrarySidebarProps) => {
currentComponentUsageKey && <ComponentInfoHeader library={library} usageKey={currentComponentUsageKey} />
),
[SidebarBodyComponentId.CollectionInfo]: (
collection && <CollectionInfoHeader library={library} collection={collection} />
currentCollectionHit && <CollectionInfoHeader library={library} collection={currentCollectionHit} />
),
unknown: null,
};

const buildBody = () : React.ReactNode => bodyComponentMap[sidebarBodyComponent || 'unknown'];
const buildHeader = (): React.ReactNode => headerComponentMap[sidebarBodyComponent || 'unknown'];

const collectionQuery: SearchParams | undefined = currentCollectionHit ? {
filter: ['type = "collection"', `context_key = "${library.id}"`, `block_id = "${currentCollectionHit.blockId}"`],
limit: 1,
} : undefined;

return (
<Stack gap={4} className="p-3 text-primary-700">
<Stack direction="horizontal" className="d-flex justify-content-between">
{buildHeader()}
<IconButton
className="mt-1"
src={Close}
iconAs={Icon}
alt={intl.formatMessage(messages.closeButtonAlt)}
onClick={closeLibrarySidebar}
size="inline"
/>
<SearchContextProvider
extraFilter={[
`context_key = "${library.id}"`,
...(currentCollectionHit ? [`collections.key = "${currentCollectionHit.blockId}"`] : []),
]}
overrideQueries={{ ...(collectionQuery ? { collections: collectionQuery } : {}) }}
>
<Stack gap={4} className="p-3 text-primary-700">
<Stack direction="horizontal" className="d-flex justify-content-between">
{buildHeader()}
<IconButton
className="mt-1"
src={Close}
iconAs={Icon}
alt={intl.formatMessage(messages.closeButtonAlt)}
onClick={closeLibrarySidebar}
size="inline"
/>
</Stack>
<div>
{buildBody()}
</div>
</Stack>
<div>
{buildBody()}
</div>
</Stack>
</SearchContextProvider>
);
};

Expand Down

0 comments on commit 82aba72

Please sign in to comment.