Skip to content

Commit

Permalink
feat: add ComponentDetails component
Browse files Browse the repository at this point in the history
  • Loading branch information
rpenido committed Sep 20, 2024
1 parent 9d3a05f commit eef8426
Show file tree
Hide file tree
Showing 13 changed files with 181 additions and 8 deletions.
28 changes: 28 additions & 0 deletions src/library-authoring/component-info/ComponentDetails.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import {
initializeMocks,
render,
screen,
} from '../../testUtils';
import { mockLibraryBlockMetadata } from '../data/api.mocks';
import ComponentDetails from './ComponentDetails';

describe('<ComponentDetails />', () => {
it('should render the component usage', async () => {
initializeMocks();
mockLibraryBlockMetadata.applyMock();
render(<ComponentDetails usageKey={mockLibraryBlockMetadata.usageKeyNeverPublished} />);
expect(await screen.findByText('Component Usage')).toBeInTheDocument();
// TODO: replace with actual data when implement tag list
expect(screen.queryByText('This will show the courses that use this component.')).toBeInTheDocument();
});

it('should render the component history', async () => {
initializeMocks();
mockLibraryBlockMetadata.applyMock();
render(<ComponentDetails usageKey={mockLibraryBlockMetadata.usageKeyNeverPublished} />);
// Show created date
expect(await screen.findByText('June 20, 2024')).toBeInTheDocument();
// Show modified date
expect(await screen.findByText('June 21, 2024')).toBeInTheDocument();
});
});
52 changes: 52 additions & 0 deletions src/library-authoring/component-info/ComponentDetails.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { useIntl } from '@edx/frontend-platform/i18n';
import { Stack } from '@openedx/paragon';

import { useLibraryBlockMetadata } from '../data/apiHooks';
import HistoryWidget from '../generic/history-widget';
import { ComponentDeveloperInfo } from './ComponentDeveloperInfo';
import messages from './messages';

interface ComponentDetailsProps {
usageKey: string;
}

const ComponentDetails = ({ usageKey }: ComponentDetailsProps) => {
const intl = useIntl();
const { data: componentMetadata } = useLibraryBlockMetadata(usageKey);

// istanbul ignore if: this should never happen
if (!componentMetadata) {
return null;
}

return (
<Stack gap={3}>
<div>
<h3 className="h5">
{intl.formatMessage(messages.detailsTabDescriptionTitle)}
</h3>
<input type="text" className="form-control" placeholder="Description / Card Preview Text" />
</div>
<div>
<h3 className="h5">
{intl.formatMessage(messages.detailsTabUsageTitle)}
</h3>
<small>This will show the courses that use this component.</small>
</div>
<hr className="w-100" />
<div>
<h3 className="h5">
{intl.formatMessage(messages.detailsTabHistoryTitle)}
</h3>
<HistoryWidget
{...componentMetadata}
/>
</div>
{
(process.env.NODE_ENV === 'development' ? <ComponentDeveloperInfo usageKey={usageKey} /> : null)
}
</Stack>
);
};

export default ComponentDetails;
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export const ComponentDeveloperInfo: React.FC<Props> = ({ usageKey }) => {
const { data: olx, isLoading: isOLXLoading } = useXBlockOLX(usageKey);
return (
<>
<hr />
<hr className="w-100" />
<h3 className="h5">Developer Component Details</h3>
<p><small>(This panel is only visible in development builds.)</small></p>
<dl>
Expand Down
8 changes: 2 additions & 6 deletions src/library-authoring/component-info/ComponentInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { Link } from 'react-router-dom';

import { getEditUrl } from '../components/utils';
import { ComponentMenu } from '../components';
import { ComponentDeveloperInfo } from './ComponentDeveloperInfo';
import ComponentDetails from './ComponentDetails';
import ComponentManagement from './ComponentManagement';
import ComponentPreview from './ComponentPreview';
import messages from './messages';
Expand Down Expand Up @@ -50,11 +50,7 @@ const ComponentInfo = ({ usageKey }: ComponentInfoProps) => {
<ComponentManagement usageKey={usageKey} />
</Tab>
<Tab eventKey="details" title={intl.formatMessage(messages.detailsTabTitle)}>
Details tab placeholder

{
(process.env.NODE_ENV === 'development' ? <ComponentDeveloperInfo usageKey={usageKey} /> : null)
}
<ComponentDetails usageKey={usageKey} />
</Tab>
</Tabs>
</Stack>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { mockLibraryBlockMetadata } from '../data/api.mocks';
import ComponentManagement from './ComponentManagement';

/*
* FIXME: Summarize the reason here
* This function is used to get the inner text of an element.
* https://stackoverflow.com/questions/47902335/innertext-is-undefined-in-jest-test
*/
const getInnerText = (element: Element) => element?.textContent
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const ComponentManagement = ({ usageKey }: ComponentManagementProps) => {
const intl = useIntl();
const { data: componentMetadata } = useLibraryBlockMetadata(usageKey);

// istanbul ignore if: this should never happen
if (!componentMetadata) {
return null;
}
Expand Down
15 changes: 15 additions & 0 deletions src/library-authoring/component-info/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,21 @@ const messages = defineMessages({
defaultMessage: 'Details',
description: 'Title for details tab',
},
detailsTabDescriptionTitle: {
id: 'course-authoring.library-authoring.component.details-tab.description-title',
defaultMessage: 'Description / Card Preview Text',
description: 'Title for the Description container in the details tab',
},
detailsTabUsageTitle: {
id: 'course-authoring.library-authoring.component.details-tab.usage-title',
defaultMessage: 'Component Usage',
description: 'Title for the Component Usage container in the details tab',
},
detailsTabHistoryTitle: {
id: 'course-authoring.library-authoring.component.details-tab.history-title',
defaultMessage: 'Component History',
description: 'Title for the Component History container in the details tab',
},
previewExpandButtonTitle: {
id: 'course-authoring.library-authoring.component.preview.expand.title',
defaultMessage: 'Expand',
Expand Down
5 changes: 5 additions & 0 deletions src/library-authoring/data/api.mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ mockCreateLibraryBlock.newHtmlData = {
lastDraftCreated: '2024-07-22T21:37:49Z',
lastDraftCreatedBy: null,
created: '2024-07-22T21:37:49Z',
modified: '2024-07-22T21:37:49Z',
tagsCount: 0,
} satisfies api.LibraryBlockMetadata;
mockCreateLibraryBlock.newProblemData = {
Expand All @@ -147,6 +148,7 @@ mockCreateLibraryBlock.newProblemData = {
lastDraftCreated: '2024-07-22T21:37:49Z',
lastDraftCreatedBy: null,
created: '2024-07-22T21:37:49Z',
modified: '2024-07-22T21:37:49Z',
tagsCount: 0,
} satisfies api.LibraryBlockMetadata;
mockCreateLibraryBlock.newVideoData = {
Expand All @@ -160,6 +162,7 @@ mockCreateLibraryBlock.newVideoData = {
lastDraftCreated: '2024-07-22T21:37:49Z',
lastDraftCreatedBy: null,
created: '2024-07-22T21:37:49Z',
modified: '2024-07-22T21:37:49Z',
tagsCount: 0,
} satisfies api.LibraryBlockMetadata;
/** Apply this mock. Returns a spy object that can tell you if it's been called. */
Expand Down Expand Up @@ -234,6 +237,7 @@ mockLibraryBlockMetadata.dataNeverPublished = {
lastDraftCreatedBy: null,
hasUnpublishedChanges: false,
created: '2024-06-20T13:54:21Z',
modified: '2024-06-21T13:54:21Z',
tagsCount: 0,
} satisfies api.LibraryBlockMetadata;
mockLibraryBlockMetadata.usageKeyPublished = 'lb:Axim:TEST2:html:571fe018-f3ce-45c9-8f53-5dafcb422fd2';
Expand All @@ -248,6 +252,7 @@ mockLibraryBlockMetadata.dataPublished = {
lastDraftCreatedBy: '2024-06-20T20:00:00Z',
hasUnpublishedChanges: false,
created: '2024-06-20T13:54:21Z',
modified: '2024-06-21T13:54:21Z',
tagsCount: 0,
} satisfies api.LibraryBlockMetadata;
/** Apply this mock. Returns a spy object that can tell you if it's been called. */
Expand Down
1 change: 1 addition & 0 deletions src/library-authoring/data/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ export interface LibraryBlockMetadata {
lastDraftCreatedBy: string | null,
hasUnpublishedChanges: boolean;
created: string | null,
modified: string | null,
tagsCount: number;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.history-widget-bar {
border-left: 8px solid $info-300;
border-radius: 4px;
padding-left: 1rem;
}

52 changes: 52 additions & 0 deletions src/library-authoring/generic/history-widget/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { FormattedMessage, FormattedDate } from '@edx/frontend-platform/i18n';
import { Stack } from '@openedx/paragon';

import messages from './messages';

const CustomFormattedDate = ({ date }: { date: string }) => (
<FormattedDate
value={date}
year="numeric"
month="long"
day="2-digit"
/>
);

type HistoryWidgedProps = {
modified: string | null;
created: string | null;
};

/**
* This component displays the history of an entity (Last Modified and Created dates)
*
* This component doesn't handle fetching the data or any other side effects. It only displays the dates.
*
* @example
* ```tsx
* const { data: componentMetadata } = useLibraryBlockMetadata(usageKey);
*
* return <HistoryWidget {...componentMetadata} />;
* ```
*/
const HistoryWidget = ({
modified,
created,
}: HistoryWidgedProps) => (
<Stack className="history-widget-bar small" gap={3}>
{modified && (
<div>
<div className="text-muted"><FormattedMessage {...messages.lastModifiedTitle} /> </div>
<CustomFormattedDate date={modified} />
</div>
)}
{created && (
<div>
<div className="text-muted"><FormattedMessage {...messages.createdTitle} /> </div>
<CustomFormattedDate date={created} />
</div>
)}
</Stack>
);

export default HistoryWidget;
16 changes: 16 additions & 0 deletions src/library-authoring/generic/history-widget/messages.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { defineMessages } from '@edx/frontend-platform/i18n';

const messages = defineMessages({
lastModifiedTitle: {
id: 'course-authoring.library-authoring.generic.history-widget.last-modified',
defaultMessage: 'Last Modified',
description: 'Title of the last modified section in the library authoring sidebar.',
},
createdTitle: {
id: 'course-authoring.library-authoring.generic.history-widget.created',
defaultMessage: 'Created',
description: 'Title of the created section in the library authoring sidebar.',
},
});

export default messages;
1 change: 1 addition & 0 deletions src/library-authoring/generic/index.scss
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
@import "./status-widget/StatusWidget";
@import "./history-widget/HistoryWidget";

0 comments on commit eef8426

Please sign in to comment.