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, display,
backgroundType = "blur", backgroundType = "blur",
backgroundClassName, backgroundClassName,
top = false,
close, close,
className, className,
children children
@@ -34,7 +35,11 @@ export default function Modal(props: ModalProps){
<div <div
{...divProps} {...divProps}
className={clsx( 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]", "flex flex-col rounded-lg max-h-full shadow-lg shadow-[#00000066]",
className className
)} )}

View File

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

View File

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

View File

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