From 250d23d2ae229d04e7db861f4dae327ff4d715bd Mon Sep 17 00:00:00 2001 From: Henry Date: Wed, 7 Aug 2024 22:27:12 +0100 Subject: [PATCH] feat: add popup error messages --- src/components/Popup.tsx | 76 +++++++++++++++++++++++++ src/pages/_app.tsx | 9 ++- src/pages/boards/[...boardId]/index.tsx | 2 + src/pages/boards/index.tsx | 2 + src/providers/board.tsx | 17 ++++++ src/providers/popup.tsx | 53 +++++++++++++++++ 6 files changed, 156 insertions(+), 3 deletions(-) create mode 100644 src/components/Popup.tsx create mode 100644 src/providers/popup.tsx diff --git a/src/components/Popup.tsx b/src/components/Popup.tsx new file mode 100644 index 00000000..396c30e0 --- /dev/null +++ b/src/components/Popup.tsx @@ -0,0 +1,76 @@ +import { useEffect } from "react"; +import { HiOutlineExclamationCircle } from "react-icons/hi2"; +import { HiXMark } from "react-icons/hi2"; +import { Transition } from "@headlessui/react"; + +import { usePopup } from "~/providers/popup"; + +const Popup: React.FC = () => { + const { isOpen, popupHeader, popupMessage, hidePopup } = usePopup(); + + useEffect(() => { + if (isOpen) { + const timer = setTimeout(() => { + hidePopup(); + }, 5000); + + return () => clearTimeout(timer); + } + }, [isOpen, hidePopup]); + + return ( +
+ +
+
+
+
+
+
+

+ {popupHeader} +

+

+ {popupMessage} +

+
+
+ +
+
+
+
+
+
+ ); +}; + +export default Popup; diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index 1bf598aa..087df155 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -5,6 +5,7 @@ import { Plus_Jakarta_Sans } from "next/font/google"; import { ModalProvider } from "~/providers/modal"; import { BoardProvider } from "~/providers/board"; +import { PopupProvider } from "~/providers/popup"; import { ThemeProvider } from "~/providers/theme"; import { api } from "~/utils/api"; @@ -33,9 +34,11 @@ const MyApp: AppType = ({ Component, pageProps }) => {
- - - + + + + +
diff --git a/src/pages/boards/[...boardId]/index.tsx b/src/pages/boards/[...boardId]/index.tsx index a249463f..8bb46d5e 100644 --- a/src/pages/boards/[...boardId]/index.tsx +++ b/src/pages/boards/[...boardId]/index.tsx @@ -1,5 +1,6 @@ import { WorkspaceProvider } from "~/providers/workspace"; import Dashboard from "~/components/dashboard"; +import Popup from "~/components/Popup"; import BoardView from "~/views/board"; export default function BoardPage() { @@ -8,6 +9,7 @@ export default function BoardPage() { + ); } diff --git a/src/pages/boards/index.tsx b/src/pages/boards/index.tsx index 2c8beb9a..61333c93 100644 --- a/src/pages/boards/index.tsx +++ b/src/pages/boards/index.tsx @@ -1,5 +1,6 @@ import { WorkspaceProvider } from "~/providers/workspace"; import Dashboard from "~/components/dashboard"; +import Popup from "~/components/Popup"; import BoardsView from "~/views/boards"; export default function BoardsPage() { @@ -8,6 +9,7 @@ export default function BoardsPage() { + ); } diff --git a/src/providers/board.tsx b/src/providers/board.tsx index 107ce580..6143f514 100644 --- a/src/providers/board.tsx +++ b/src/providers/board.tsx @@ -6,6 +6,7 @@ import React, { } from "react"; import { api } from "~/utils/api"; +import { usePopup } from "~/providers/popup"; import { type GetBoardByIdOutput, @@ -40,6 +41,8 @@ export const BoardProvider: React.FC<{ children: ReactNode }> = ({ const [boardData, setBoardData] = useState(initialBoardData); + const { showPopup } = usePopup(); + const refetchBoard = async () => { if (boardData?.publicId) { try { @@ -52,10 +55,24 @@ export const BoardProvider: React.FC<{ children: ReactNode }> = ({ const updateCardMutation = api.card.reorder.useMutation({ onSuccess: () => refetchBoard(), + onError: () => { + refetchBoard(); + showPopup({ + header: "Unable to update card", + message: "Please try again later, or contact customer support.", + }); + }, }); const updateListMutation = api.list.reorder.useMutation({ onSuccess: () => refetchBoard(), + onError: () => { + refetchBoard(); + showPopup({ + header: "Unable to update list", + message: "Please try again later, or contact customer support.", + }); + }, }); const updateList = ({ diff --git a/src/providers/popup.tsx b/src/providers/popup.tsx new file mode 100644 index 00000000..a61a0255 --- /dev/null +++ b/src/providers/popup.tsx @@ -0,0 +1,53 @@ +import { createContext, useContext, useState } from "react"; + +type PopupContextType = { + isOpen: boolean; + showPopup: (params: { header: string; message: string }) => void; + hidePopup: () => void; + popupHeader: string; + popupMessage: string; +}; + +interface Props { + children: React.ReactNode; +} + +const PopupContext = createContext(undefined); + +export const PopupProvider: React.FC = ({ children }) => { + const [isOpen, setIsOpen] = useState(false); + const [popupHeader, setPopupHeader] = useState(""); + const [popupMessage, setPopupMessage] = useState(""); + + const showPopup = ({ + header, + message, + }: { + header: string; + message: string; + }) => { + setIsOpen(true); + setPopupHeader(header); + setPopupMessage(message); + }; + + const hidePopup = () => { + setIsOpen(false); + }; + + return ( + + {children} + + ); +}; + +export const usePopup = () => { + const context = useContext(PopupContext); + if (context === undefined) { + throw new Error("usePopup must be used within a PopupProvider"); + } + return context; +};