Skip to content

Commit

Permalink
add notification component (#260)
Browse files Browse the repository at this point in the history
* # This is a combination of 3 commits.
# This is the 1st commit message:

add notification component

# This is the commit message #2:

Update src/app/components/Notification/FloatingTopBar.tsx

Co-authored-by: David Totrashvili <[email protected]>
# This is the commit message #3:

review feedback

* add notification component

Update src/app/components/Notification/FloatingTopBar.tsx

Co-authored-by: David Totrashvili <[email protected]>

review feedback

extract screen breakpoints from tailwind config

add notification component

Update src/app/components/Notification/FloatingTopBar.tsx

Co-authored-by: David Totrashvili <[email protected]>

review feedback

extract screen breakpoints from tailwind config
  • Loading branch information
supertong authored Nov 4, 2024
1 parent 9fa36c9 commit 9073b76
Show file tree
Hide file tree
Showing 14 changed files with 556 additions and 163 deletions.
498 changes: 342 additions & 156 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
"react-number-format": "^5.4.2",
"react-responsive-modal": "^6.4.2",
"react-tabs": "^6.0.2",
"react-toastify": "^10.0.6",
"react-tooltip": "^5.26.4",
"sharp": "^0.33.4",
"tailwind-merge": "^2.5.2",
Expand Down
10 changes: 10 additions & 0 deletions src/app/components/Notification/DetailsButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export const DetailsButton = () => {
return (
<button
className="text-base font-medium dark:text-white text-black whitespace-nowrap"
onClick={() => {}}
>
Details
</button>
);
};
22 changes: 22 additions & 0 deletions src/app/components/Notification/FloatingTopBar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { TypeOptions } from "react-toastify";
import { twJoin } from "tailwind-merge";

interface Props {
type: TypeOptions;
}

const BG_COLOR = {
success: "bg-[#49B149]",
warning: "bg-[#C5882D]",
error: "bg-[#DD6464]",
info: "bg-[#919191]",
default: "bg-[#919191]",
} as const;

export const FloatingTopBar = ({ type }: Props) => {
return (
<div
className={twJoin(BG_COLOR[type], "h-1 absolute left-0 right-0 top-0")}
></div>
);
};
24 changes: 24 additions & 0 deletions src/app/components/Notification/IconWrapper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { IconType } from "react-icons";
import { TypeOptions } from "react-toastify";
import { twJoin } from "tailwind-merge";

interface Props {
ReactIcon: IconType;
type: TypeOptions;
}

const BG_TEXT_COLOR = {
success: "bg-[#49B149]/15 text-[#49B149]",
warning: "bg-[#C5882D]/15 text-[#C5882D]",
error: "bg-[#DD6464]/15 text-[#DD6464]",
info: "bg-[#919191]/15 text-[#919191]",
default: "bg-[#919191]/15 text-[#919191]",
} as const;

export const IconWrapper = ({ ReactIcon, type }: Props) => {
return (
<div className={twJoin("p-2 rounded-full", BG_TEXT_COLOR[type])}>
<ReactIcon size={24} />
</div>
);
};
52 changes: 52 additions & 0 deletions src/app/components/Notification/Notification.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { ReactNode } from "react";
import { IconType } from "react-icons";
import { IoClose } from "react-icons/io5";
import { ToastContentProps } from "react-toastify";

import { DetailsButton } from "./DetailsButton";
import { FloatingTopBar } from "./FloatingTopBar";
import { IconWrapper } from "./IconWrapper";
import { NotificationText } from "./NotificationText";
import { NotificationTitle } from "./NotificationTitle";

interface Props extends Partial<ToastContentProps> {
title: string;
text: string;
actionComponent?: ReactNode;
reactIcon: IconType;
}

export const Notification = ({
closeToast,
toastProps,
title,
text,
actionComponent = <DetailsButton />,
reactIcon,
}: Props) => {
if (closeToast === undefined || toastProps === undefined) {
throw new SyntaxError(
"Notification should only be used with toast from react-toastify",
);
}
return (
<div>
<FloatingTopBar type={toastProps.type} />
<div className="flex flex-row justify-evenly items-start md:items-center gap-2">
<IconWrapper ReactIcon={reactIcon} type={toastProps.type} />
<div className="flex flex-col items-start gap-1">
<NotificationTitle>{title}</NotificationTitle>
<NotificationText>{text}</NotificationText>
<div className="md:hidden">{actionComponent}</div>
</div>
<div className="hidden md:flex">{actionComponent}</div>
<button
className="text-[#AFAFAF] dark:text-[#E6EAEA]"
onClick={closeToast}
>
<IoClose size={24} />
</button>
</div>
</div>
);
};
35 changes: 35 additions & 0 deletions src/app/components/Notification/NotificationContainer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { ToastContainer } from "react-toastify";
import { twJoin } from "tailwind-merge";
import { useMediaQuery } from "usehooks-ts";

import { screenBreakPoints } from "@/config/screen-breakpoints";

const commonClassName = "relative overflow-hidden rounded-lg px-4 py-3 md:p-3";

const BG_COLOR = {
success:
"dark:bg-[linear-gradient(0deg,rgba(73,177,73,0.1),rgba(73,177,73,0.1))] dark:bg-[#191919] bg-[linear-gradient(0deg,rgba(73,177,73,0.05),rgba(73,177,73,0.05))] bg-[#FFFFFF]",
warning:
"bg-[linear-gradient(0deg,rgba(197,136,45,0.05),rgba(197,136,45,0.05))] bg-[#FFFFFF] dark:bg-[linear-gradient(0deg,rgba(197,136,45,0.1),rgba(197,136,45,0.1))] dark:bg-[#191919]",
error:
"bg-[linear-gradient(0deg,rgba(221,100,100,0.05),rgba(221,100,100,0.05))] bg-[#FFFFFF] dark:bg-[linear-gradient(0deg,rgba(221,100,100,0.1),rgba(221,100,100,0.1))] dark:bg-[#191919]",
info: "bg-[#FFFFFF] dark:bg-[#191919]",
default: "bg-[#FFFFFF] dark:bg-[#191919]",
} as const;

export const NotificationContainer = () => {
const isMobileView = useMediaQuery(`(max-width: ${screenBreakPoints.md})`);

return (
<ToastContainer
toastClassName={(context) => {
return twJoin(commonClassName, BG_COLOR[context?.type ?? "default"]);
}}
autoClose={false}
closeButton={false}
icon={false}
hideProgressBar={true}
position={isMobileView ? "top-center" : "top-right"}
/>
);
};
11 changes: 11 additions & 0 deletions src/app/components/Notification/NotificationText.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
interface Props {
children: string;
}

export const NotificationText = ({ children }: Props) => {
return (
<span className="text-sm font-normal dark:text-[#AFAFAF] text-[#303030]">
{children}
</span>
);
};
11 changes: 11 additions & 0 deletions src/app/components/Notification/NotificationTitle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
interface Props {
children: string;
}

export const NotificationTitle = ({ children }: Props) => {
return (
<span className="text-base font-bold dark:text-white text-black">
{children}
</span>
);
};
8 changes: 8 additions & 0 deletions src/app/globals.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
@import "react-responsive-modal/styles.css";
@import "react-tooltip/dist/react-tooltip.css";
@import "react-toastify/dist/ReactToastify.css";

@tailwind base;
@tailwind components;
Expand All @@ -8,6 +9,13 @@
:root {
--primary: #ff7c2a;
--secondary: "#0DB7BF";
--toastify-toast-width: 344px;
}

@media screen and (min-width: 768px) {
:root {
--toastify-toast-width: 671px;
}
}

/* disable number input arrows */
Expand Down
28 changes: 28 additions & 0 deletions src/app/hooks/useNotification.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { FaCheck } from "react-icons/fa6";
import { LuBadgeCheck } from "react-icons/lu";
import { PiWarningCircleBold } from "react-icons/pi";
import { toast } from "react-toastify";

import { Notification } from "@/app/components/Notification/Notification";

export const notifySuccess = (title: string, text: string) => {
toast.success(<Notification title={title} text={text} reactIcon={FaCheck} />);
};

export const notifyWraning = (title: string, text: string) => {
toast.warning(
<Notification title={title} text={text} reactIcon={PiWarningCircleBold} />,
);
};

export const notifyError = (title: string, text: string) => {
toast.error(
<Notification title={title} text={text} reactIcon={PiWarningCircleBold} />,
);
};

export const notifyInfo = (title: string, text: string) => {
toast.info(
<Notification title={title} text={text} reactIcon={LuBadgeCheck} />,
);
};
2 changes: 2 additions & 0 deletions src/app/providers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { ReactQueryStreamedHydration } from "@tanstack/react-query-next-experime
import { ThemeProvider } from "next-themes";
import React from "react";

import { NotificationContainer } from "./components/Notification/NotificationContainer";
import { ErrorProvider } from "./context/Error/ErrorContext";
import { StakingStatsProvider } from "./context/api/StakingStatsProvider";
import { BTCWalletProvider } from "./context/wallet/BTCWalletProvider";
Expand Down Expand Up @@ -39,6 +40,7 @@ function Providers({ children }: React.PropsWithChildren) {
initialIsOpen={false}
/>
</QueryClientProvider>
<NotificationContainer />
</ThemeProvider>
);
}
Expand Down
7 changes: 7 additions & 0 deletions src/config/screen-breakpoints.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export const screenBreakPoints = {
sm: "600px",
md: "768px",
lg: "1000px",
xl: "1130px",
"2xl": "1350px",
} as const;
10 changes: 3 additions & 7 deletions tailwind.config.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import type { Config } from "tailwindcss";

import { screenBreakPoints } from "./src/config/screen-breakpoints";

const config: Config = {
darkMode: ["selector", '[data-theme="dark"]'],
content: [
Expand All @@ -8,13 +10,7 @@ const config: Config = {
"./src/app/**/*.{js,ts,jsx,tsx,mdx}",
],
theme: {
screens: {
sm: "600px",
md: "768px",
lg: "1000px",
xl: "1130px",
"2xl": "1350px",
},
screens: screenBreakPoints,
extend: {
colors: {
primary: "#FF7C2A",
Expand Down

0 comments on commit 9073b76

Please sign in to comment.