Files
frontend-app-authoring/src/library-authoring/components/ComponentCard.tsx

115 lines
3.5 KiB
TypeScript

import React, { useContext, useMemo } from 'react';
import { useIntl } from '@edx/frontend-platform/i18n';
import {
ActionRow,
Card,
Container,
Icon,
IconButton,
Dropdown,
Stack,
} from '@openedx/paragon';
import { MoreVert } from '@openedx/paragon/icons';
import { getItemIcon, getComponentStyleColor } from '../../generic/block-type-utils';
import { updateClipboard } from '../../generic/data/api';
import TagCount from '../../generic/tag-count';
import { ToastContext } from '../../generic/toast-context';
import { type ContentHit, Highlight } from '../../search-manager';
import messages from './messages';
type ComponentCardProps = {
contentHit: ContentHit,
blockTypeDisplayName: string,
};
const ComponentCardMenu = ({ usageKey }: { usageKey: string }) => {
const intl = useIntl();
const { showToast } = useContext(ToastContext);
const updateClipboardClick = () => {
updateClipboard(usageKey)
.then(() => showToast(intl.formatMessage(messages.copyToClipboardSuccess)))
.catch(() => showToast(intl.formatMessage(messages.copyToClipboardError)));
};
return (
<Dropdown id="component-card-dropdown">
<Dropdown.Toggle
id="component-card-menu-toggle"
as={IconButton}
src={MoreVert}
iconAs={Icon}
variant="primary"
alt={intl.formatMessage(messages.componentCardMenuAlt)}
data-testid="component-card-menu-toggle"
/>
<Dropdown.Menu>
<Dropdown.Item disabled>
{intl.formatMessage(messages.menuEdit)}
</Dropdown.Item>
<Dropdown.Item onClick={updateClipboardClick}>
{intl.formatMessage(messages.menuCopyToClipboard)}
</Dropdown.Item>
<Dropdown.Item disabled>
{intl.formatMessage(messages.menuAddToCollection)}
</Dropdown.Item>
</Dropdown.Menu>
</Dropdown>
);
};
const ComponentCard = ({ contentHit, blockTypeDisplayName } : ComponentCardProps) => {
const {
blockType,
formatted,
tags,
usageKey,
} = contentHit;
const description = formatted?.content?.htmlContent ?? '';
const displayName = formatted?.displayName ?? '';
const tagCount = useMemo(() => {
if (!tags) {
return 0;
}
return (tags.level0?.length || 0) + (tags.level1?.length || 0)
+ (tags.level2?.length || 0) + (tags.level3?.length || 0);
}, [tags]);
const componentIcon = getItemIcon(blockType);
return (
<Container className="library-component-card">
<Card>
<Card.Header
className={`library-component-header ${getComponentStyleColor(blockType)}`}
title={
<Icon src={componentIcon} className="library-component-header-icon" />
}
actions={(
<ActionRow>
<ComponentCardMenu usageKey={usageKey} />
</ActionRow>
)}
/>
<Card.Body>
<Card.Section>
<Stack direction="horizontal" className="d-flex justify-content-between">
<Stack direction="horizontal" gap={1}>
<Icon src={componentIcon} size="sm" />
<span className="small">{blockTypeDisplayName}</span>
</Stack>
<TagCount count={tagCount} />
</Stack>
<div className="text-truncate h3 mt-2">
<Highlight text={displayName} />
</div>
<Highlight text={description} />
</Card.Section>
</Card.Body>
</Card>
</Container>
);
};
export default ComponentCard;