Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
@import '../../../../../packages/core/src/ui/styles/theme.scss';
@import '../../../../../packages/common/src/ui/styles/theme.scss';

.icon {
width: size_unit(10.5);
height: size_unit(10.5);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React from 'react';
import { Flex, Text } from '@input-output-hk/lace-ui-toolkit';
import { useTranslation } from 'react-i18next';
import styles from './EmptyState.module.scss';
import SmileyFaceIcon from '../../assets/icons/smiley-face.component.svg';

export const EmptyState = (): React.ReactElement => {
const { t } = useTranslation();

return (
<Flex flexDirection="column" gap="$20" alignItems="center" justifyContent="center" data-testid="empty-state">
<SmileyFaceIcon className={styles.icon} />
<Flex alignItems="center" flexDirection="column" gap="$0">
<Text.Body.Large>{t('notificationsCenter.emptyState.title')}</Text.Body.Large>
<Text.Body.Small color="secondary">{t('notificationsCenter.emptyState.description')}</Text.Body.Small>
</Flex>
</Flex>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,32 @@ import TrashOutlineComponent from '../../assets/icons/browser-view/trash-icon.co
import { useTranslation } from 'react-i18next';
import classnames from 'classnames';

export type LaceMessage = {
id: string;
topic: string;
title: string;
body: string;
format: string;
};

export type LaceNotification = {
message: LaceMessage;
read?: boolean;
};

export interface NotificationListItemProps {
id: string;
title: string;
isRead?: boolean;
popupView?: boolean;
publisher: string;
onRemove?: () => void;
onRemove?: (id: string) => void;
onClick: () => void;
withBorder?: boolean;
}

export const NotificationListItem = ({
id,
title,
isRead = false,
popupView = false,
Expand All @@ -28,7 +43,7 @@ export const NotificationListItem = ({

const handleRemove = (e: React.MouseEvent<HTMLButtonElement>) => {
e.stopPropagation();
onRemove();
onRemove?.(id);
};

const PublisherTextComponent = popupView ? Text.Label : Text.Body.Small;
Expand All @@ -55,6 +70,7 @@ export const NotificationListItem = ({
onClick={onClick}
className={classnames(styles.container, withBorder && styles.withBorder)}
p="$20"
w="$fill"
>
<Flex className={styles.content} justifyContent="center" alignItems="flex-start" flexDirection="column" gap="$8">
<Flex alignItems="center" gap="$4" className={styles.copy}>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/* eslint-disable unicorn/no-useless-undefined */
/* eslint-disable @typescript-eslint/explicit-module-boundary-types, promise/catch-or-return, sonarjs/cognitive-complexity, no-magic-numbers, unicorn/no-null */
import React, { useState } from 'react';
import { ContentLayout } from '@src/components/Layout';
import { useTranslation } from 'react-i18next';
import { WarningModal } from '@src/views/browser-view/components';
import { useNotificationsCenter } from '@hooks/useNotificationsCenter';
import { NotificationsList } from './NotificationsList';
import { EmptyState } from './EmptyState';
import { Box, Flex } from '@input-output-hk/lace-ui-toolkit';
import { NavigationButton } from '@lace/common';
import { useHistory } from 'react-router';
import { SectionTitle } from '@components/Layout/SectionTitle';

export const NotificationsCenter = (): React.ReactElement => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two component with the same name and purpose?

I'd suggest a refactor to have only one component with that purpose.

const { t } = useTranslation();
const [isRemoveNotificationModalVisible, setIsRemoveNotificationModalVisible] = useState(false);
const { notifications, remove, unreadNotifications } = useNotificationsCenter();
const [notificationIdToRemove, setNotificationIdToRemove] = useState<string | undefined>();
const history = useHistory();

const onShowRemoveNotificationModal = (id: string) => {
setNotificationIdToRemove(id);
setIsRemoveNotificationModalVisible(true);
};

const onHideRemoveNotificationModal = () => {
setNotificationIdToRemove(undefined);
setIsRemoveNotificationModalVisible(false);
};

const isInitialLoad = typeof notifications === 'undefined';

return (
<ContentLayout
title={
<SectionTitle
isPopup
title={
<Flex alignItems="center" gap="$8">
<NavigationButton icon="arrow" onClick={() => history.goBack()} />
{t('notificationsCenter.title')}
</Flex>
}
sideText={`(${unreadNotifications})`}
data-testid="notifications-center-title"
/>
}
isLoading={isInitialLoad}
>
<div>
{notifications?.length > 0 ? (
<NotificationsList
hasMore
notifications={notifications}
scrollableTarget="contentLayout"
dataLength={notifications.length}
onRemove={onShowRemoveNotificationModal}
popupView
/>
) : (
<Box mt="$96">
<EmptyState />
</Box>
)}
</div>
<WarningModal
visible={isRemoveNotificationModalVisible}
header={t('notificationsCenter.removeNotification')}
content={t('notificationsCenter.removeNotification.description')}
onCancel={onHideRemoveNotificationModal}
cancelLabel={t('notificationsCenter.removeNotification.cancel')}
confirmLabel={t('notificationsCenter.removeNotification.confirm')}
onConfirm={() => {
remove(notificationIdToRemove);
onHideRemoveNotificationModal();
}}
isPopupView
/>
</ContentLayout>
);
};

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,8 @@
padding: size_unit(1) size_unit(2.75) !important;
position: relative;
}

.icon {
width: size_unit(2);
height: size_unit(2);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import { Button } from '@lace/common';

import styles from './NotificationsBell.module.scss';

import NotificationBellIcon from '@lace/core/src/ui/assets/icons/notifications-bell.component.svg';
import NotificationBellIcon from '../../assets/icons/notifications-bell.component.svg';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mirceahasegan asked me to put icons in the core package.

Anyway if there are good reasons to keep them in this package, please remove the other ones (also the happy face).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done here aeae32f


// eslint-disable-next-line no-magic-numbers
const formatNotificationCount = (count: number) => (count < 10 ? count.toString() : '9+');
const MAX_NOTIFICATION_COUNT = 9;
const formatNotificationCount = (count: number) =>
count <= MAX_NOTIFICATION_COUNT ? count.toString() : `${MAX_NOTIFICATION_COUNT}+`;

export interface NotificationsBellProps {
onClick: () => void;
Expand All @@ -16,7 +17,7 @@ export interface NotificationsBellProps {

export const NotificationsBell = ({ onClick, unreadNotifications }: NotificationsBellProps): React.ReactElement => (
<Button className={styles.btn} block color="gradient" data-testid="notifications-bell" onClick={onClick}>
<NotificationBellIcon />
<NotificationBellIcon className={styles.icon} />
{unreadNotifications > 0 && <span className={styles.badge}>{formatNotificationCount(unreadNotifications)}</span>}
</Button>
);
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,14 @@ export interface NotificationsCenterContainerProps {

export const NotificationsBellContainer = ({ popupView }: NotificationsCenterContainerProps): React.ReactElement => {
const { isNotificationsCenterEnabled } = useNotificationsCenterConfig();
const { markAsRead, notifications, unreadNotifications } = useNotificationsCenter();
const { unreadNotifications } = useNotificationsCenter();
const history = useHistory();
const [isOpen, setIsOpen] = useState(false);

const handleDropdownState = (openDropdown: boolean) => {
setIsOpen(openDropdown);
};

const handleViewAll = () => {
setIsOpen(false);
history.push(walletRoutePaths.notifications);
Expand All @@ -27,18 +31,9 @@ export const NotificationsBellContainer = ({ popupView }: NotificationsCenterCon
return (
isNotificationsCenterEnabled && (
<Dropdown
onOpenChange={setIsOpen}
open={isOpen}
dropdownRender={() => (
<NotificationsDropDown
notifications={notifications}
onMarkAllAsRead={() => markAsRead()}
onMarkAsRead={(id: string) => markAsRead(id)}
onViewAll={handleViewAll}
popupView={popupView}
unreadNotifications={unreadNotifications}
/>
)}
onOpenChange={handleDropdownState}
dropdownRender={() => <NotificationsDropDown onViewAll={handleViewAll} popupView={popupView} />}
placement="bottomRight"
trigger={['click']}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,27 @@
.button {
max-width: size_unit(25);
}

.sectionTitle {
margin-bottom: size_unit(0) !important;
}

.scrollContainer {
&::-webkit-scrollbar {
width: 6px;
}

&::-webkit-scrollbar-track {
background: var(--bg-color-secondary, #f5f5f5);
border-radius: 3px;
}

&::-webkit-scrollbar-thumb {
background: var(--text-color-tertiary, #ccc);
border-radius: 3px;

&:hover {
background: var(--text-color-secondary, #999);
}
}
}
Loading
Loading