1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-11-22 01:47:00 +01:00

[MMI] Added code fences in whats new popup (#19581)

* added code fences in whats new popup

* Improved code

* Added missing prop

* Update LavaMoat policies

* updated functions by using an options object for the rendering functions in order to bypass possible typsecript issues

---------

Co-authored-by: MetaMask Bot <metamaskbot@users.noreply.github.com>
This commit is contained in:
Albert Olivé 2023-06-27 08:30:42 +02:00 committed by GitHub
parent ec4c4050e6
commit 1e56fdbf66
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 157 additions and 28 deletions

View File

@ -5162,6 +5162,9 @@
"viewOnOpensea": { "viewOnOpensea": {
"message": "View on Opensea" "message": "View on Opensea"
}, },
"viewPortfolioDashboard": {
"message": "View Portfolio Dashboard"
},
"viewinCustodianApp": { "viewinCustodianApp": {
"message": "View in custodian app" "message": "View in custodian app"
}, },

View File

@ -121,6 +121,9 @@ import {
///: END:ONLY_INCLUDE_IN ///: END:ONLY_INCLUDE_IN
} from '../../shared/constants/permissions'; } from '../../shared/constants/permissions';
import { UI_NOTIFICATIONS } from '../../shared/notifications'; import { UI_NOTIFICATIONS } from '../../shared/notifications';
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
import { UI_INSTITUTIONAL_NOTIFICATIONS } from '../../shared/notifications/institutional';
///: END:ONLY_INCLUDE_IN
import { MILLISECOND, SECOND } from '../../shared/constants/time'; import { MILLISECOND, SECOND } from '../../shared/constants/time';
import { import {
ORIGIN_METAMASK, ORIGIN_METAMASK,
@ -618,9 +621,16 @@ export default class MetamaskController extends EventEmitter {
const announcementMessenger = this.controllerMessenger.getRestricted({ const announcementMessenger = this.controllerMessenger.getRestricted({
name: 'AnnouncementController', name: 'AnnouncementController',
}); });
let allAnnouncements = UI_NOTIFICATIONS;
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
allAnnouncements = UI_INSTITUTIONAL_NOTIFICATIONS;
///: END:ONLY_INCLUDE_IN
this.announcementController = new AnnouncementController({ this.announcementController = new AnnouncementController({
messenger: announcementMessenger, messenger: announcementMessenger,
allAnnouncements: UI_NOTIFICATIONS, allAnnouncements,
state: initState.AnnouncementController, state: initState.AnnouncementController,
}); });

View File

@ -0,0 +1,35 @@
export const UI_INSTITUTIONAL_NOTIFICATIONS = {
1: {
id: 11,
date: '2022-08-28',
image: {
src: 'images/portfolio.svg',
},
hideDate: true,
descriptionInBullets: true,
},
};
export const getTranslatedInstitutionalUINotifications = (t, locale) => {
const formattedLocale = locale.replace('_', '-');
return {
1: {
...UI_INSTITUTIONAL_NOTIFICATIONS[11],
title: 'Portfolio dashboard',
description: [
'Portfolio snapshots',
'Filtering by account and network',
'Sector and protocol allocation',
'Improved navigation',
],
date: new Intl.DateTimeFormat(formattedLocale).format(
new Date(UI_INSTITUTIONAL_NOTIFICATIONS[11].date),
),
customButton: {
name: 'mmi-portfolio',
text: t('viewPortfolioDashboard'),
logo: true,
},
},
};
};

View File

@ -7,9 +7,14 @@ import { debounce } from 'lodash';
import { getCurrentLocale } from '../../../ducks/locale/locale'; import { getCurrentLocale } from '../../../ducks/locale/locale';
import { I18nContext } from '../../../contexts/i18n'; import { I18nContext } from '../../../contexts/i18n';
import { useEqualityCheck } from '../../../hooks/useEqualityCheck'; import { useEqualityCheck } from '../../../hooks/useEqualityCheck';
import Button from '../../ui/button';
import Popover from '../../ui/popover'; import Popover from '../../ui/popover';
import { Text } from '../../component-library'; import {
Button,
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
IconName,
///: END:ONLY_INCLUDE_IN
Text,
} from '../../component-library';
import { updateViewedNotifications } from '../../../store/actions'; import { updateViewedNotifications } from '../../../store/actions';
import { getTranslatedUINotifications } from '../../../../shared/notifications'; import { getTranslatedUINotifications } from '../../../../shared/notifications';
import { getSortedAnnouncementsToShow } from '../../../selectors'; import { getSortedAnnouncementsToShow } from '../../../selectors';
@ -20,7 +25,12 @@ import {
EXPERIMENTAL_ROUTE, EXPERIMENTAL_ROUTE,
SECURITY_ROUTE, SECURITY_ROUTE,
} from '../../../helpers/constants/routes'; } from '../../../helpers/constants/routes';
import { TextVariant } from '../../../helpers/constants/design-system'; import {
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
Size,
///: END:ONLY_INCLUDE_IN
TextVariant,
} from '../../../helpers/constants/design-system';
import ZENDESK_URLS from '../../../helpers/constants/zendesk-url'; import ZENDESK_URLS from '../../../helpers/constants/zendesk-url';
import { MetaMetricsContext } from '../../../contexts/metametrics'; import { MetaMetricsContext } from '../../../contexts/metametrics';
import { import {
@ -118,15 +128,36 @@ const renderDescription = (description) => {
); );
}; };
const renderFirstNotification = ( const renderFirstNotification = ({
notification, notification,
idRefMap, idRefMap,
history, history,
isLast, isLast,
trackEvent, trackEvent,
) => { ///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
const { id, date, title, description, image, actionText } = notification; mmiPortfolioUrl,
seenNotifications,
onClose,
///: END:ONLY_INCLUDE_IN
}) => {
const {
id,
date,
title,
description,
image,
actionText,
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
customButton,
hideDate,
///: END:ONLY_INCLUDE_IN
} = notification;
const actionFunction = getActionFunctionById(id, history); const actionFunction = getActionFunctionById(id, history);
let showNotificationDate = true;
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
showNotificationDate = !hideDate;
///: END:ONLY_INCLUDE_IN
const imageComponent = image && ( const imageComponent = image && (
<img <img
@ -155,7 +186,9 @@ const renderFirstNotification = (
<div className="whats-new-popup__notification-description"> <div className="whats-new-popup__notification-description">
{renderDescription(description)} {renderDescription(description)}
</div> </div>
<div className="whats-new-popup__notification-date">{date}</div> {showNotificationDate && (
<div className="whats-new-popup__notification-date">{date}</div>
)}
</div> </div>
{placeImageBelowDescription && imageComponent} {placeImageBelowDescription && imageComponent}
{actionText && ( {actionText && (
@ -173,6 +206,25 @@ const renderFirstNotification = (
{actionText} {actionText}
</Button> </Button>
)} )}
{
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
customButton && customButton.name === 'mmi-portfolio' && (
<Button
className="whats-new-popup__button"
data-testid="view-mmi-portfolio"
size={Size.SM}
startIconName={IconName.MmmiPortfolioDashboard}
onClick={() => {
updateViewedNotifications(seenNotifications);
onClose();
window.open(mmiPortfolioUrl, '_blank');
}}
>
{customButton.text}
</Button>
)
///: END:ONLY_INCLUDE_IN
}
<div <div
className="whats-new-popup__intersection-observable" className="whats-new-popup__intersection-observable"
ref={idRefMap[id]} ref={idRefMap[id]}
@ -181,12 +233,12 @@ const renderFirstNotification = (
); );
}; };
const renderSubsequentNotification = ( const renderSubsequentNotification = ({
notification, notification,
idRefMap, idRefMap,
history, history,
isLast, isLast,
) => { }) => {
const { id, date, title, description, actionText } = notification; const { id, date, title, description, actionText } = notification;
const actionFunction = getActionFunctionById(id, history); const actionFunction = getActionFunctionById(id, history);
@ -217,7 +269,12 @@ const renderSubsequentNotification = (
); );
}; };
export default function WhatsNewPopup({ onClose }) { export default function WhatsNewPopup({
onClose,
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
mmiPortfolioUrl,
///: END:ONLY_INCLUDE_IN
}) {
const t = useContext(I18nContext); const t = useContext(I18nContext);
const history = useHistory(); const history = useHistory();
@ -295,6 +352,16 @@ export default function WhatsNewPopup({ onClose }) {
}; };
}, [idRefMap, setSeenNotifications]); }, [idRefMap, setSeenNotifications]);
// Display the swaps notification with full image
// Displays the NFTs & OpenSea notifications 18,19 with full image
const notificationRenderers = {
0: renderFirstNotification,
1: renderFirstNotification,
18: renderFirstNotification,
19: renderFirstNotification,
21: renderFirstNotification,
};
return ( return (
<Popover <Popover
title={t('whatsNew')} title={t('whatsNew')}
@ -321,22 +388,26 @@ export default function WhatsNewPopup({ onClose }) {
{notifications.map(({ id }, index) => { {notifications.map(({ id }, index) => {
const notification = getTranslatedUINotifications(t, locale)[id]; const notification = getTranslatedUINotifications(t, locale)[id];
const isLast = index === notifications.length - 1; const isLast = index === notifications.length - 1;
// Display the swaps notification with full image // Choose the appropriate rendering function based on the id
// Displays the NFTs & OpenSea notifications 18,19 with full image let renderNotification =
return index === 0 || id === 1 || id === 18 || id === 19 || id === 21 notificationRenderers[id] || renderSubsequentNotification;
? renderFirstNotification(
notification, ///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
idRefMap, renderNotification = renderFirstNotification;
history, ///: END:ONLY_INCLUDE_IN
isLast,
trackEvent, return renderNotification({
) notification,
: renderSubsequentNotification( idRefMap,
notification, history,
idRefMap, isLast,
history, trackEvent,
isLast, ///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
); mmiPortfolioUrl,
seenNotifications,
onClose,
///: END:ONLY_INCLUDE_IN
});
})} })}
</div> </div>
</Popover> </Popover>
@ -345,4 +416,7 @@ export default function WhatsNewPopup({ onClose }) {
WhatsNewPopup.propTypes = { WhatsNewPopup.propTypes = {
onClose: PropTypes.func.isRequired, onClose: PropTypes.func.isRequired,
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
mmiPortfolioUrl: PropTypes.string.isRequired,
///: END:ONLY_INCLUDE_IN
}; };

View File

@ -755,10 +755,17 @@ export default class Home extends PureComponent {
exact exact
/> />
<div className="home__container"> <div className="home__container">
{showWhatsNew ? (
<WhatsNewPopup
onClose={hideWhatsNewPopup}
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
mmiPortfolioUrl={mmiPortfolioUrl}
///: END:ONLY_INCLUDE_IN
/>
) : null}
{ {
///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask) ///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask)
} }
{showWhatsNew ? <WhatsNewPopup onClose={hideWhatsNewPopup} /> : null}
{!showWhatsNew && showRecoveryPhraseReminder ? ( {!showWhatsNew && showRecoveryPhraseReminder ? (
<RecoveryPhraseReminder <RecoveryPhraseReminder
hasBackedUp={seedPhraseBackedUp} hasBackedUp={seedPhraseBackedUp}