Skip to content

Commit

Permalink
feat: Notifications UI (#237)
Browse files Browse the repository at this point in the history
  • Loading branch information
Xavier-Charles authored Feb 15, 2024
1 parent 4916130 commit df037eb
Show file tree
Hide file tree
Showing 7 changed files with 280 additions and 13 deletions.
8 changes: 8 additions & 0 deletions packages/frontend/src/MobileApp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ import "@alphaday/ui-kit/global.scss";
const SuperfeedPage = lazyRetry(() => import("./mobile-pages/superfeed"));
const AuthPage = lazyRetry(() => import("./mobile-pages/auth"));
const FiltersPage = lazyRetry(() => import("./mobile-pages/filters"));
const NotificationsPage = lazyRetry(
() => import("./mobile-pages/notifications")
);
const UserSettingsPage = lazyRetry(
() => import("./mobile-pages/user-settings")
);
Expand All @@ -27,6 +30,11 @@ const MobileApp: React.FC = () => {
exact
component={UserSettingsPage}
/>
<Route
path="/notifications"
exact
component={NotificationsPage}
/>
{/* Add more routes as needed */}
</Suspense>
</Switch>
Expand Down
4 changes: 2 additions & 2 deletions packages/frontend/src/layout/PagedMobileLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ const PagedMobileLayout: FC<{
handleBack?: () => void;
}> = ({ children, title, onScroll, handleBack, handleClose }) => {
return (
<ScrollBar onScroll={onScroll}>
<ScrollBar className="h-screen flex flex-col" onScroll={onScroll}>
<Pager
title={title}
handleBack={handleBack}
handleClose={handleClose}
/>
{children}
<div className="w-full flex flex-grow min-w-max">{children}</div>
</ScrollBar>
);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import { FC, MouseEventHandler, useState } from "react";
import { twMerge } from "@alphaday/ui-kit";
import { ReactComponent as BellSVG } from "src/assets/icons/bell.svg";
import { ReactComponent as CloseSVG } from "src/assets/icons/close2.svg";
import {
EFeedItemType,
feedItemIconMap,
} from "src/mobile-components/superfeed/types";
import { computeDuration } from "src/utils/dateUtils";

type TNotification = {
id: string;
title: string;
description: string;
date: string;
isRead: boolean;
contentType: EFeedItemType;
source: string;
};

interface INotifications {
notifications: TNotification[] | undefined;
isAuthenticated: boolean;
markAsRead: (id: string) => void;
removeNotification: (id: string) => void;
}

const NoNotifications = () => {
return (
<div className="w-full mx-5 flex flex-col justify-center items-center">
<div className="p-5 rounded-full bg-primaryVariant100 mx-auto flex-wrap">
<BellSVG className="w-8 h-8 text-background" />
</div>
<p className="fontGroup-highlightSemi m-5">No notifications yet</p>
<p className="fontGroup-normal whitespace-normal break-words max-w-screen-single-col text-center">
You’ll get notifications on new trending posts, when people
interact with your comments, and more.
</p>
</div>
);
};

const NotificationItem: FC<
TNotification & {
onMarkAsRead: (id: string) => void;
removeNotification: (id: string) => void;
}
> = ({
id,
title,
description,
date,
isRead,
contentType,
source,
onMarkAsRead,
removeNotification,
}) => {
const [showDesc, setShowDesc] = useState(false);

const handleShowDesc = () => {
setShowDesc(true);
onMarkAsRead(id);
};

const handleClose: MouseEventHandler<SVGSVGElement> = (e) => {
e.stopPropagation();
removeNotification(id);
};
return (
<div
onClick={handleShowDesc}
role="button"
tabIndex={0}
className={twMerge(
"flex flex-col w-full p-4 rounded-lg mb-3 cursor-pointer",
isRead ? "bg-backgroundVariant100" : "bg-backgroundVariant200"
)}
>
<div className="flex justify-between items-center">
<div className="flex items-center">
<img
src={feedItemIconMap[contentType]}
alt="feed icon"
className="w-8 h-8 mr-2"
/>
<div className="text-primaryVariant100 fontGroup-mini leading-[18px] flex flex-wrap whitespace-nowrap">
<p className="text-primaryVariant100 fontGroup-mini leading-[18px] flex flex-wrap whitespace-nowrap">
{computeDuration(date)}
<span className="mx-1.5 my-0 self-center"></span>
<span>
<span className="capitalize">{source}</span>
</span>
</p>
</div>
</div>
<CloseSVG
onClick={handleClose}
className="w-4 h-4 text-primary"
/>
</div>
<div className="flex justify-between">
<p className="fontGroup-highlightSemi m-0 mt-2">{title}</p>
{!isRead && (
<div
onClick={handleShowDesc}
role="button"
tabIndex={0}
className="fontGroup-normal text-primary border-b border-accentVariant100 self-end m-0"
>
view
</div>
)}
</div>
{showDesc && <p className="fontGroup-normal">{description}</p>}
</div>
);
};
const Notifications: FC<INotifications> = ({
notifications,
markAsRead,
removeNotification,
}) => {
if (notifications === undefined) {
return <NoNotifications />;
}
return (
<div className="w-full flex flex-col px-4">
{notifications.map((notification) => (
<NotificationItem
key={notification.id}
{...notification}
onMarkAsRead={markAsRead}
removeNotification={removeNotification}
/>
))}
</div>
);
};

export default Notifications;
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ const UserMenu: FC<IUserMenu> = ({ isAuthenticated }) => {
history.push(link);
};
return (
<div className="mx-5">
<div className="mx-5 w-full">
{/* <div className="flex flex-start w-full items-center mb-4">
<ChevronSVG
onClick={onClose}
Expand Down
114 changes: 114 additions & 0 deletions packages/frontend/src/mobile-pages/notifications.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import { useState } from "react";
import { useHistory } from "react-router";
import { useAuth } from "src/api/hooks";
import { EFeedItemType } from "src/api/types";
import PagedMobileLayout from "src/layout/PagedMobileLayout";
import Notifications from "src/mobile-components/notifications/Notifications";

const mockNotifications = [
{
id: "1",
title: "New post",
description: "A new post has been made",
date: "2021-09-14",
isRead: false,
contentType: EFeedItemType.NEWS,
source: "coinTelegraph",
},
{
id: "2",
title: "New comment",
description: "A new comment has been made",
date: "2021-09-14",
isRead: false,
contentType: EFeedItemType.NEWS,
source: "coinTeleg",
},
{
id: "3",
title: "New post",
description: "A new post has been made",
date: "2021-09-14",
isRead: false,
contentType: EFeedItemType.NEWS,
source: "coinTeleg",
},
{
id: "4",
title: "New comment",
description: "A new comment has been made",
date: "2021-09-14",
isRead: false,
contentType: EFeedItemType.NEWS,
source: "coinTeleg",
},
{
id: "5",
title: "New post",
description: "A new post has been made",
date: "2021-09-14",
isRead: false,
contentType: EFeedItemType.NEWS,
source: "coinTeleg",
},
{
id: "6",
title: "New comment",
description: "A new comment has been made",
date: "2021-09-14",
isRead: false,
contentType: EFeedItemType.NEWS,
source: "coinTeleg",
},
{
id: "7",
title: "New post",
description: "A new post has been made",
date: "2021-09-14",
isRead: false,
contentType: EFeedItemType.NEWS,
source: "coinTeleg",
},
{
id: "8",
title: "New comment",
description: "A new comment has been made",
date: "2021-09-14",
isRead: false,
contentType: EFeedItemType.NEWS,
source: "coinTeleg",
},
];

const NotificationsPage = () => {
const history = useHistory();
const { isAuthenticated } = useAuth();

const [notifications, setNotifications] = useState(mockNotifications);

const markAsRead = (id: string) => {
setNotifications(
notifications.map((n) => (n.id === id ? { ...n, isRead: true } : n))
);
};
const removeNotification = (id: string) => {
setNotifications((prev) => prev.filter((n) => n.id !== id));
};
return (
<PagedMobileLayout
title="Notifications"
handleBack={() =>
history.length > 1 ? history.goBack() : history.push("/")
}
>
<Notifications
isAuthenticated={isAuthenticated}
notifications={notifications}
markAsRead={markAsRead}
removeNotification={removeNotification}
/>
</PagedMobileLayout>
);
};

export default NotificationsPage;
4 changes: 3 additions & 1 deletion packages/ui-kit/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import {
} from "./src/components/charts/apexchart";
import { ChatForm } from "./src/components/chat/ChatForm";
import { Dialog } from "./src/components/dialog/Dialog";
import { MiniDialog } from "./src/components/dialog/MiniDialog";
import { ShareViewDialog } from "./src/components/dialog/ShareViewDialog";
import {
ViewDialog,
Expand Down Expand Up @@ -94,7 +95,7 @@ import { NavBottom } from "./src/mobile-components/navigation/NavBottom";
import { NavHeader } from "./src/mobile-components/navigation/NavHeader";
import { Pager } from "./src/mobile-components/pager/Pager";
import { FeedCard } from "./src/mobile-components/superfeed/FeedCard";
import { MiniDialog } from "./src/components/dialog/MiniDialog";
import { feedItemIconMap } from "./src/mobile-components/superfeed/types";

export type { TViewTabMenuOption, DatesSetArg, EventClickArg, TDatePos };
export {
Expand All @@ -120,6 +121,7 @@ export {
Carousel,
CarouselImage,
Lightbox,
feedItemIconMap,
Timer,
Toggle,
ErrorModal,
Expand Down
20 changes: 11 additions & 9 deletions packages/ui-kit/src/mobile-components/pager/Pager.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { ReactComponent as ChevronLeftIcon } from "src/assets/svg/chevron-left.svg";
import { ReactComponent as Close3Icon } from "src/assets/svg/close3.svg";
import { twMerge } from "tailwind-merge";

interface PagerProps {
title?: string;
Expand All @@ -24,15 +25,16 @@ export const Pager: React.FC<PagerProps> = ({
<div className="flex flex-grow justify-center uppercase font-bold text-base">
{title}
</div>
{handleClose && (
<button
type="button"
className="flex flex-grow justify-end"
onClick={handleClose}
>
<Close3Icon />
</button>
)}
<button
type="button"
className={twMerge(
"flex flex-grow justify-end",
!handleClose && "invisible"
)}
onClick={handleClose}
>
<Close3Icon />
</button>
</div>
);
};

0 comments on commit df037eb

Please sign in to comment.