Add timed message modal component

This commit is contained in:
2025-03-02 12:48:11 -05:00
parent 6f3fe1798b
commit 3d06d8189d
5 changed files with 103 additions and 7 deletions

View File

@@ -8,6 +8,7 @@ export default function Modal(props: ModalProps){
display,
backgroundType = "blur",
backgroundClassName,
top = false,
close,
className,
children
@@ -34,7 +35,11 @@ export default function Modal(props: ModalProps){
<div
{...divProps}
className={clsx(
"fixed left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 max-w-(--breakpoint-sm) z-50",
"fixed left-1/2 -translate-x-1/2 max-w-(--breakpoint-sm) z-50",
{
"top-1/2 -translate-y-1/2": !top,
"top-0": top
},
"flex flex-col rounded-lg max-h-full shadow-lg shadow-[#00000066]",
className
)}

View File

@@ -14,6 +14,7 @@ export interface ModalProps extends HTMLProps<HTMLDivElement>{
display?: boolean;
backgroundType?: ModalBackgroundType;
backgroundClassName?: string;
top?: boolean;
close?: () => void;
children: React.ReactNode;
}

View File

@@ -5,6 +5,7 @@ import App from './App.tsx'
import './index.css'
import { AuthProvider } from './providers/AuthProvider.tsx'
import { ThemeProvider } from './providers/ThemeProvider.tsx'
import { TimedModalProvider } from "./providers/TimedModalProvider.tsx"
const queryClient = new QueryClient();
@@ -17,12 +18,14 @@ createRoot(document.getElementById('root')!).render(
defaultTheme="dark"
storageKey="vite-ui-theme"
>
<TimedModalProvider>
<AuthProvider
jwtStorageKey="jwt"
refreshTokenStorageKey="refreshToken"
>
<App />
</AuthProvider>
</TimedModalProvider>
</ThemeProvider>
</QueryClientProvider>
</StrictMode>

View File

@@ -1,5 +1,6 @@
import { createContext, useContext, useEffect, useMemo, useState } from "react";
type Theme = "dark" | "light" | "system";
type ThemeProviderProps = {

View File

@@ -0,0 +1,86 @@
import Modal from "@/components/modal/Modal";
import ModalBody from "@/components/modal/ModalBody";
import { createContext, useContext, useEffect, useRef, useState } from "react";
type TimedModalProviderState = {
addMessage: (timeout: number, message: React.ReactNode) => void;
}
const initialState: TimedModalProviderState = {
addMessage: () => null
}
const TimedModalProviderContext = createContext<TimedModalProviderState>(initialState);
export function TimedModalProvider({
children
}:{
children: React.ReactNode;
}){
const [ display, setDisplay ] = useState(false);
const [ messages, setMessages ] = useState<React.ReactNode[]>([]);
const messagesRef = useRef<React.ReactNode[]>(messages);
messagesRef.current = messages;
useEffect(() => {
console.log("effect");
console.log(messages);
if(messages.length > 0){
setDisplay(true);
}
else{
setDisplay(false);
}
}, [ messages ]);
const addMessage = (timeout: number, message: React.ReactNode) => {
setMessages([...messages, message]);
setTimeout(() => {
setMessages(messagesRef.current.filter((m) => m !== message));
}, timeout);
}
return (
<TimedModalProviderContext.Provider value={{addMessage}}>
<Modal
display={display}
backgroundType="none"
className="bg-neutral-300 dark:bg-neutral-600"
top={true}
>
<ModalBody>
<div
className="space-y-4"
>
{
messages.map((message, index) => (
<div
key={index}
>
{message}
</div>
))
}
</div>
</ModalBody>
</Modal>
{children}
</TimedModalProviderContext.Provider>
);
}
export const useTimedModal = () => {
const context = useContext(TimedModalProviderContext);
if(context === undefined){
throw new Error("useTimeModal must be used within a TimedModalProvider");
}
return context;
}