Skip to content

Commit

Permalink
Feature/CV2-5806: implement media cluster origin button (#2239)
Browse files Browse the repository at this point in the history
implements the MediaOrigin This component includes a button and a tooltip that displays:

The action performed that caused the media to appear in the item.
The username, if the action was performed by a user.
The component has been added to the sandbox for testing with fake data and includes unit tests.
implements the MediaClusterOriginButton UI component. This component includes a button and a tooltip that displays:

The action that was performed caused the media to appear in the item.
The username, if the action was performed by a user.
The component has been added to the sandbox for testing with fake data and includes unit tests.

Reference: CV2-5806
  • Loading branch information
danielevalverde authored Jan 8, 2025
1 parent 65c87ea commit 89287bc
Show file tree
Hide file tree
Showing 5 changed files with 296 additions and 20 deletions.
52 changes: 52 additions & 0 deletions localization/react-intl/src/app/components/media/MediaOrigin.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
[
{
"id": "MediaOrigin.userMerged",
"description": "Message for User Merged",
"defaultMessage": "User Merged"
},
{
"id": "MediaOrigin.userMergedTooltip",
"description": "Tooltip message for User Merged",
"defaultMessage": "<strong>{user}</strong> added this media by merging from another cluster"
},
{
"id": "MediaOrigin.userMatched",
"description": "Message for User Matched",
"defaultMessage": "User Matched"
},
{
"id": "MediaOrigin.userMatchedTooltip",
"description": "Tooltip message for User Matched",
"defaultMessage": "<strong>{user}</strong> accepted this media as a suggested match"
},
{
"id": "MediaOrigin.userAdded",
"description": "This media was added by a user.",
"defaultMessage": "User Added"
},
{
"id": "MediaOrigin.userAddedTooltip",
"description": "Tooltip message for User Added",
"defaultMessage": "<strong>{user}</strong> uploaded this media using the Check interface"
},
{
"id": "MediaOrigin.tiplineSubmitted",
"description": "Message for Tipline Submitted",
"defaultMessage": "Tipline Submitted"
},
{
"id": "MediaOrigin.tiplineSubmittedTooltip",
"description": "Tooltip message for Tipline Submitted",
"defaultMessage": "Original cluster media submitted by Tipline User"
},
{
"id": "MediaOrigin.autoMatched",
"description": "Message for Auto Matched",
"defaultMessage": "Auto Matched"
},
{
"id": "MediaOrigin.autoMatchedTooltip",
"description": "Tooltip message for Auto Matched",
"defaultMessage": "Automatically matched media by Check"
}
]
30 changes: 30 additions & 0 deletions src/app/components/cds/Sandbox.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import TabWrapper from './menus-lists-dialogs/TabWrapper';
import Reorder from '../layout/Reorder';
import AddIcon from '../../icons/settings.svg';
import CalendarIcon from '../../icons/calendar_month.svg';
import MediaOrigin from '../media/MediaOrigin';
import ListIcon from '../../icons/list.svg';
import FigmaColorLogo from '../../icons/figma_color.svg';
import ArticleCard from '../search/SearchResultsCards/ArticleCard';
Expand Down Expand Up @@ -484,6 +485,10 @@ const SandboxComponent = ({ admin }) => {
label: 'Tabs',
value: 'tabs',
},
{
label: 'Media Cluster Origin Buttons',
value: 'media-cluster-origin-buttons',
},
]}
value={categoryTab}
wrapContent
Expand Down Expand Up @@ -2383,6 +2388,31 @@ const SandboxComponent = ({ admin }) => {
</div>
</section>
}
{ (categoryTab === 'all' || categoryTab === 'media-cluster-origin-buttons') && (
<section>
<div className={styles.componentWrapper}>
<div className={cx('typography-subtitle2', [styles.componentName])}>
Media Origin
<a
className={styles.figmaLink}
href="https://www.figma.com/design/aVRaTgms3H4jY8hOslFq5y/Media?node-id=901-1203&p=f&m=dev"
rel="noopener noreferrer"
target="_blank"
title="Figma Designs"
>
<FigmaColorLogo />
</a>

<MediaOrigin type="typeA" />
<MediaOrigin type="typeB" />
<MediaOrigin type="typeC" />
<MediaOrigin type="typeD" />
<MediaOrigin type="typeE" />
<MediaOrigin type="invalidType" />
</div>
</div>
</section>
)}
</div>
);
};
Expand Down
43 changes: 23 additions & 20 deletions src/app/components/media/MediaCardLargeFooter.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,26 +99,29 @@ const MediaCardLargeFooter = ({
{ footerBody && !inModal ? <>{transcriptionOrExtractedFooter}</> : null }
{ !inModal ?
<MediaSlug
details={[(
<LastRequestDate
lastRequestDate={projectMedia.last_seen * 1000}
theme="lightText"
variant="text"
/>
), (
<RequestsCount
requestsCount={projectMedia.requests_count}
theme="lightText"
variant="text"
/>
), (
<MediaIdentifier
mediaType={mediaType}
slug={projectMedia.media_slug || projectMedia.title}
theme="lightText"
variant="text"
/>
),
details={[
(
<LastRequestDate
lastRequestDate={projectMedia.last_seen * 1000}
theme="lightText"
variant="text"
/>
),
(
<RequestsCount
requestsCount={projectMedia.requests_count}
theme="lightText"
variant="text"
/>
),
(
<MediaIdentifier
mediaType={mediaType}
slug={projectMedia.media_slug || projectMedia.title}
theme="lightText"
variant="text"
/>
),
]}
/>
: null
Expand Down
152 changes: 152 additions & 0 deletions src/app/components/media/MediaOrigin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
import React from 'react';
import PropTypes from 'prop-types';
import { FormattedMessage, FormattedHTMLMessage } from 'react-intl';
import ButtonMain from '../cds/buttons-checkboxes-chips/ButtonMain';
import Person from '../../icons/person.svg';
import PersonAdd from '../../icons/person_add.svg';
import PersonCheck from '../../icons/person_check.svg';
import Bolt from '../../icons/bolt.svg';
import Tipline from '../../icons/question_answer.svg';
import Tooltip from '../cds/alerts-and-prompts/Tooltip';

const allowedTypes = new Set(['typeA', 'typeB', 'typeC', 'typeD', 'typeE']);

const getIconAndMessage = (type, user) => {
switch (type) {
case 'typeA':
return {
icon: <Person />,
message: (
<FormattedMessage
defaultMessage="User Merged"
description="Message for User Merged"
id="MediaOrigin.userMerged"
/>
),
tooltipMessage: (
<FormattedHTMLMessage
defaultMessage="<strong>{user}</strong> added this media by merging from another cluster"
description="Tooltip message for User Merged"
id="MediaOrigin.userMergedTooltip"
values={{ user }}
/>
),
};
case 'typeB':
return {
icon: <PersonCheck />,
message: (
<FormattedMessage
defaultMessage="User Matched"
description="Message for User Matched"
id="MediaOrigin.userMatched"
/>
),
tooltipMessage: (
<FormattedHTMLMessage
defaultMessage="<strong>{user}</strong> accepted this media as a suggested match"
description="Tooltip message for User Matched"
id="MediaOrigin.userMatchedTooltip"
values={{ user }}
/>
),
};
case 'typeC':
return {
icon: <PersonAdd />,
message: (
<FormattedMessage
defaultMessage="User Added"
description="This media was added by a user."
id="MediaOrigin.userAdded"
/>
),
tooltipMessage: (
<FormattedHTMLMessage
defaultMessage="<strong>{user}</strong> uploaded this media using the Check interface"
description="Tooltip message for User Added"
id="MediaOrigin.userAddedTooltip"
values={{ user }}
/>
),
};
case 'typeD':
return {
icon: <Tipline />,
message: (
<FormattedMessage
defaultMessage="Tipline Submitted"
description="Message for Tipline Submitted"
id="MediaOrigin.tiplineSubmitted"
/>
),
tooltipMessage: (
<FormattedMessage
defaultMessage="Original cluster media submitted by Tipline User"
description="Tooltip message for Tipline Submitted"
id="MediaOrigin.tiplineSubmittedTooltip"
/>
),
};
case 'typeE':
return {
icon: <Bolt />,
message: (
<FormattedMessage
defaultMessage="Auto Matched"
description="Message for Auto Matched"
id="MediaOrigin.autoMatched"
/>
),
tooltipMessage: (
<FormattedMessage
defaultMessage="Automatically matched media by Check"
description="Tooltip message for Auto Matched"
id="MediaOrigin.autoMatchedTooltip"
/>
),
};
default:
return {
icon: null,
message: null,
tooltipMessage: null,
};
}
};

const MediaOrigin = ({ type, user }) => {
if (!allowedTypes.has(type)) {
return null;
}

const { icon, message, tooltipMessage } = getIconAndMessage(type, user);

return (
<Tooltip
arrow
title={tooltipMessage}
>
<span>
<ButtonMain
iconLeft={icon}
label={message}
size="small"
theme="lightText"
variant="text"
/>
</span>
</Tooltip>
);
};

MediaOrigin.defaultProps = {
user: 'Unknown User',
};

MediaOrigin.propTypes = {
type: PropTypes.string.isRequired,
user: PropTypes.string,
};

export default MediaOrigin;
39 changes: 39 additions & 0 deletions src/app/components/media/MediaOrigin.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React from 'react';
import MediaOrigin from './MediaOrigin';
import { mountWithIntl } from '../../../../test/unit/helpers/intl-test';
import Person from '../../icons/person.svg';
import PersonAdd from '../../icons/person_add.svg';
import PersonCheck from '../../icons/person_check.svg';
import Bolt from '../../icons/bolt.svg';
import Tipline from '../../icons/question_answer.svg';

describe('<MediaOrigin />', () => {
it('should render a button with the correct icon and message for each type', () => {
const userMerged = mountWithIntl(<MediaOrigin type="typeA" />);
expect(userMerged.find(Person).length).toEqual(1);
expect(userMerged.html()).toMatch('User Merged');

const userMatched = mountWithIntl(<MediaOrigin type="typeB" />);
expect(userMatched.find(PersonCheck).length).toEqual(1);
expect(userMatched.html()).toMatch('User Matched');


const userAdded = mountWithIntl(<MediaOrigin type="typeC" />);
expect(userAdded.find(PersonAdd).length).toEqual(1);
expect(userAdded.html()).toMatch('User Added');

const tiplineSubmitted = mountWithIntl(<MediaOrigin type="typeD" />);
expect(tiplineSubmitted.find(Tipline).length).toEqual(1);
expect(tiplineSubmitted.html()).toMatch('Tipline Submitted');

const autoMatched = mountWithIntl(<MediaOrigin type="typeE" />);
expect(autoMatched.find(Bolt).length).toEqual(1);
expect(autoMatched.html()).toMatch('Auto Matched');
});


it('should return null for invalid type', () => {
const wrapper = mountWithIntl(<MediaOrigin type="invalidType" />);
expect(wrapper.find('FormattedMessage').length).toEqual(0);
});
});

0 comments on commit 89287bc

Please sign in to comment.