133 lines
5.1 KiB
TypeScript
133 lines
5.1 KiB
TypeScript
import {
|
|
ActionRow, Card, Icon, Stack,
|
|
} from '@openedx/paragon';
|
|
import type { MessageDescriptor } from 'react-intl';
|
|
import { useMemo } from 'react';
|
|
import {
|
|
Cached, ChevronRight, Delete, Done, Plus,
|
|
} from '@openedx/paragon/icons';
|
|
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
|
import { getItemIcon } from '@src/generic/block-type-utils';
|
|
import { ContainerType } from '@src/generic/key-utils';
|
|
import messages from './messages';
|
|
import { ContainerState } from './types';
|
|
import { isRowClickable } from './utils';
|
|
|
|
export interface ContainerRowProps {
|
|
title: string;
|
|
/** containerType: can be one of `ContainerType` | `COMPONENT_TYPES` or any other string (3rd party XBlocks) */
|
|
containerType: ContainerType | string;
|
|
state?: ContainerState;
|
|
side: 'Before' | 'After';
|
|
originalName?: string;
|
|
onClick?: () => void;
|
|
}
|
|
|
|
interface StateContext {
|
|
className: string;
|
|
icon: React.ComponentType;
|
|
message?: MessageDescriptor;
|
|
message2?: MessageDescriptor;
|
|
}
|
|
|
|
const ContainerRow = ({
|
|
title, containerType, state, side, originalName, onClick,
|
|
}: ContainerRowProps) => {
|
|
const isClickable = isRowClickable(state, containerType as ContainerType);
|
|
const stateContext: StateContext = useMemo(() => {
|
|
let message: MessageDescriptor | undefined;
|
|
let message2: MessageDescriptor | undefined;
|
|
switch (state) {
|
|
case 'added':
|
|
message = side === 'Before' ? messages.addedDiffBeforeMessage : messages.addedDiffAfterMessage;
|
|
return { className: 'text-white bg-success-500', icon: Plus, message };
|
|
case 'modified':
|
|
message = side === 'Before' ? messages.modifiedDiffBeforeMessage : messages.modifiedDiffAfterMessage;
|
|
return { className: 'text-white bg-warning-900', icon: Cached, message };
|
|
case 'removed':
|
|
message = side === 'Before' ? messages.removedDiffBeforeMessage : messages.removedDiffAfterMessage;
|
|
return { className: 'text-white bg-danger-600', icon: Delete, message };
|
|
case 'locallyRenamed':
|
|
message = side === 'Before' ? messages.renamedDiffBeforeMessage : messages.renamedUpdatedDiffAfterMessage;
|
|
return { className: 'bg-light-300 text-light-300 ', icon: Done, message };
|
|
case 'locallyContentUpdated':
|
|
message = side === 'Before' ? messages.locallyContentUpdatedBeforeMessage : messages.locallyContentUpdatedAfterMessage;
|
|
return { className: 'bg-light-300 text-light-300 ', icon: Done, message };
|
|
case 'locallyRenamedAndContentUpdated':
|
|
message = side === 'Before' ? messages.renamedDiffBeforeMessage : messages.renamedUpdatedDiffAfterMessage;
|
|
message2 = side === 'Before' ? messages.locallyContentUpdatedBeforeMessage : messages.locallyContentUpdatedAfterMessage;
|
|
return {
|
|
className: 'bg-light-300 text-light-300 ', icon: Done, message, message2,
|
|
};
|
|
case 'moved':
|
|
message = side === 'Before' ? messages.movedDiffBeforeMessage : messages.movedDiffAfterMessage;
|
|
return { className: 'bg-light-300 text-light-300', icon: Done, message };
|
|
default:
|
|
return { className: 'bg-light-300 text-light-300', icon: Done, message };
|
|
}
|
|
}, [state, side]);
|
|
|
|
return (
|
|
<Card
|
|
isClickable={isClickable}
|
|
onClick={onClick}
|
|
onKeyDown={(e: KeyboardEvent) => {
|
|
if (e.key === 'Enter' || e.key === ' ') {
|
|
onClick?.();
|
|
}
|
|
}}
|
|
className="mb-2 rounded shadow-sm border border-light-100"
|
|
>
|
|
<Stack direction="horizontal" gap={0}>
|
|
<div
|
|
className={`px-1 align-self-stretch align-content-center rounded-left ${stateContext.className}`}
|
|
>
|
|
<Icon size="sm" src={stateContext.icon} />
|
|
</div>
|
|
<ActionRow className="p-2">
|
|
<Stack direction="vertical" gap={2}>
|
|
<Stack direction="horizontal" gap={2}>
|
|
<Icon
|
|
src={getItemIcon(containerType)}
|
|
screenReaderText={containerType}
|
|
title={title}
|
|
/>
|
|
<span className="small font-weight-bold">{title}</span>
|
|
</Stack>
|
|
{stateContext.message ? (
|
|
<div className="d-flex flex-column">
|
|
<span className="micro">
|
|
<FormattedMessage
|
|
{...stateContext.message}
|
|
values={{
|
|
blockType: containerType,
|
|
name: originalName,
|
|
}}
|
|
/>
|
|
</span>
|
|
{stateContext.message2 && (
|
|
<span className="micro">
|
|
<FormattedMessage
|
|
{...stateContext.message2}
|
|
values={{
|
|
blockType: containerType,
|
|
name: originalName,
|
|
}}
|
|
/>
|
|
</span>
|
|
)}
|
|
</div>
|
|
) : (
|
|
<span className="micro"> </span>
|
|
)}
|
|
</Stack>
|
|
<ActionRow.Spacer />
|
|
{isClickable && <Icon size="md" src={ChevronRight} />}
|
|
</ActionRow>
|
|
</Stack>
|
|
</Card>
|
|
);
|
|
};
|
|
|
|
export default ContainerRow;
|