From 57b66f3f586f59392d2337fd4923a198000df9d4 Mon Sep 17 00:00:00 2001 From: Neil Dwyer Date: Thu, 15 Aug 2024 13:06:24 -0700 Subject: [PATCH] Refactor toast --- package-lock.json | 29 ++-------- package.json | 3 +- src/components/toast/PlaygroundToast.tsx | 18 +++++-- src/components/toast/ToasterProvider.tsx | 40 ++++++++++++++ src/hooks/useConnection.tsx | 67 ++++++++++++++---------- src/pages/_app.tsx | 2 - src/pages/index.tsx | 26 ++++----- 7 files changed, 106 insertions(+), 79 deletions(-) create mode 100644 src/components/toast/ToasterProvider.tsx diff --git a/package-lock.json b/package-lock.json index 11b495d..eb44095 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,8 +19,7 @@ "next": "^14.0.4", "qrcode.react": "^3.1.0", "react": "^18", - "react-dom": "^18", - "react-hot-toast": "^2.4.1" + "react-dom": "^18" }, "devDependencies": { "@types/js-yaml": "^4.0.9", @@ -2008,7 +2007,8 @@ "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "devOptional": true }, "node_modules/damerau-levenshtein": { "version": "1.0.8", @@ -3073,14 +3073,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/goober": { - "version": "2.1.14", - "resolved": "https://registry.npmjs.org/goober/-/goober-2.1.14.tgz", - "integrity": "sha512-4UpC0NdGyAFqLNPnhCT2iHpza2q+RAY3GV85a/mRPdzyPQMsj0KmMMuetdIkzWRbJ+Hgau1EZztq8ImmiMGhsg==", - "peerDependencies": { - "csstype": "^3.0.10" - } - }, "node_modules/gopd": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", @@ -4609,21 +4601,6 @@ "react": "^18.3.1" } }, - "node_modules/react-hot-toast": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/react-hot-toast/-/react-hot-toast-2.4.1.tgz", - "integrity": "sha512-j8z+cQbWIM5LY37pR6uZR6D4LfseplqnuAO4co4u8917hBUvXlEqyP1ZzqVLcqoyUesZZv/ImreoCeHVDpE5pQ==", - "dependencies": { - "goober": "^2.1.10" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "react": ">=16", - "react-dom": ">=16" - } - }, "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", diff --git a/package.json b/package.json index 0db5564..612a7c5 100644 --- a/package.json +++ b/package.json @@ -20,8 +20,7 @@ "next": "^14.0.4", "qrcode.react": "^3.1.0", "react": "^18", - "react-dom": "^18", - "react-hot-toast": "^2.4.1" + "react-dom": "^18" }, "devDependencies": { "@types/js-yaml": "^4.0.9", diff --git a/src/components/toast/PlaygroundToast.tsx b/src/components/toast/PlaygroundToast.tsx index a444fde..86e72d5 100644 --- a/src/components/toast/PlaygroundToast.tsx +++ b/src/components/toast/PlaygroundToast.tsx @@ -1,3 +1,5 @@ +import { useToast } from "./ToasterProvider"; + export type ToastType = "error" | "success" | "info"; export type ToastProps = { message: string; @@ -5,16 +7,24 @@ export type ToastProps = { onDismiss: () => void; }; -export const PlaygroundToast = ({ message, type, onDismiss }: ToastProps) => { +export const PlaygroundToast = () => { + const { toastMessage, setToastMessage } = useToast(); const color = - type === "error" ? "red" : type === "success" ? "green" : "amber"; + toastMessage?.type === "error" + ? "red" + : toastMessage?.type === "success" + ? "green" + : "amber"; + return (
- {message} + {toastMessage?.message}
); }; diff --git a/src/components/toast/ToasterProvider.tsx b/src/components/toast/ToasterProvider.tsx new file mode 100644 index 0000000..38aa174 --- /dev/null +++ b/src/components/toast/ToasterProvider.tsx @@ -0,0 +1,40 @@ +"use client" + +import React, { createContext, useState } from "react"; +import { ToastType } from "./PlaygroundToast"; + +type ToastProviderData = { + setToastMessage: ( + message: { message: string; type: ToastType } | null + ) => void; + toastMessage: { message: string; type: ToastType } | null; +}; + +const ToastContext = createContext(undefined); + +export const ToastProvider = ({ + children, +}: { + children: React.ReactNode; +}) => { + const [toastMessage, setToastMessage] = useState<{message: string, type: ToastType} | null>(null); + + return ( + + {children} + + ); +}; + +export const useToast = () => { + const context = React.useContext(ToastContext); + if (context === undefined) { + throw new Error("useToast must be used within a ToastProvider"); + } + return context; +} \ No newline at end of file diff --git a/src/hooks/useConnection.tsx b/src/hooks/useConnection.tsx index 0ed145f..f0fa548 100644 --- a/src/hooks/useConnection.tsx +++ b/src/hooks/useConnection.tsx @@ -4,7 +4,7 @@ import { useCloud } from "@/cloud/useCloud"; import React, { createContext, useState } from "react"; import { useCallback } from "react"; import { useConfig } from "./useConfig"; -import toast from "react-hot-toast"; +import { useToast } from "@/components/toast/ToasterProvider"; export type ConnectionMode = "cloud" | "manual" | "env" @@ -25,6 +25,7 @@ export const ConnectionProvider = ({ children: React.ReactNode; }) => { const { generateToken, wsUrl: cloudWSUrl } = useCloud(); + const { setToastMessage } = useToast(); const { config } = useConfig(); const [connectionDetails, setConnectionDetails] = useState<{ wsUrl: string; @@ -33,36 +34,44 @@ export const ConnectionProvider = ({ shouldConnect: boolean; }>({ wsUrl: "", token: "", shouldConnect: false, mode: "manual" }); - const connect = useCallback(async (mode: ConnectionMode) => { - let token = ""; - let url = ""; - if (mode === "cloud") { - try { - token = await generateToken(); - } catch (error) { - toast.error( - "Failed to generate token, you may need to increase your role in this LiveKit Cloud project." + const connect = useCallback( + async (mode: ConnectionMode) => { + let token = ""; + let url = ""; + if (mode === "cloud") { + try { + token = await generateToken(); + } catch (error) { + setToastMessage({ + type: "error", + message: + "Failed to generate token, you may need to increase your role in this LiveKit Cloud project.", + }); + } + url = cloudWSUrl; + } else if (mode === "env") { + if (!process.env.NEXT_PUBLIC_LIVEKIT_URL) { + throw new Error("NEXT_PUBLIC_LIVEKIT_URL is not set"); + } + url = process.env.NEXT_PUBLIC_LIVEKIT_URL; + const { accessToken } = await fetch("/api/token").then((res) => + res.json() ); + token = accessToken; + } else { + token = config.settings.token; + url = config.settings.ws_url; } - url = cloudWSUrl; - } else if (mode === "env") { - if(!process.env.NEXT_PUBLIC_LIVEKIT_URL) { - throw new Error("NEXT_PUBLIC_LIVEKIT_URL is not set"); - } - url = process.env.NEXT_PUBLIC_LIVEKIT_URL; - const {accessToken} = await fetch("/api/token").then((res) => res.json()); - token = accessToken; - } else { - token = config.settings.token; - url = config.settings.ws_url; - } - setConnectionDetails({ wsUrl: url, token, shouldConnect: true, mode }); - }, [ - cloudWSUrl, - config.settings.token, - config.settings.ws_url, - generateToken, - ]); + setConnectionDetails({ wsUrl: url, token, shouldConnect: true, mode }); + }, + [ + cloudWSUrl, + config.settings.token, + config.settings.ws_url, + generateToken, + setToastMessage, + ] + ); const disconnect = useCallback(async () => { setConnectionDetails((prev) => ({ ...prev, shouldConnect: false })); diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index c68396e..7c501ee 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -1,12 +1,10 @@ import { CloudProvider } from "@/cloud/useCloud"; import "@/styles/globals.css"; import type { AppProps } from "next/app"; -import { Toaster } from "react-hot-toast"; export default function App({ Component, pageProps }: AppProps) { return ( - );} diff --git a/src/pages/index.tsx b/src/pages/index.tsx index 7517966..9243af0 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -14,6 +14,7 @@ import { PlaygroundToast, ToastType } from "@/components/toast/PlaygroundToast"; import { ConfigProvider, useConfig } from "@/hooks/useConfig"; import { ConnectionMode, ConnectionProvider, useConnection } from "@/hooks/useConnection"; import { useMemo } from "react"; +import { ToastProvider, useToast } from "@/components/toast/ToasterProvider"; const themeColors = [ "cyan", @@ -30,23 +31,22 @@ const inter = Inter({ subsets: ["latin"] }); export default function Home() { return ( - - - - - + + + + + + + ); } export function HomeInner() { - const [toastMessage, setToastMessage] = useState<{ - message: string; - type: ToastType; - } | null>(null); const { shouldConnect, wsUrl, token, mode, connect, disconnect } = useConnection(); const {config} = useConfig(); + const { toastMessage, setToastMessage } = useToast(); const handleConnect = useCallback( async (c: boolean, mode: ConnectionMode) => { @@ -93,13 +93,7 @@ export function HomeInner() { animate={{ opacity: 1, translateY: 0 }} exit={{ opacity: 0, translateY: -50 }} > - { - setToastMessage(null); - }} - /> + )}