import * as React from 'react' ; import { useState } from 'react' ; import { useSearchParams } from 'remix' ; import { AnimatePresence , motion } from 'framer-motion' ; import clsx from 'clsx' ; import { PlusIcon } from './icons/plus-icon' ; function NotificationMessage ( { queryStringKey , visibleMs = 8000 , visible : controlledVisible , autoClose , children , position = 'bottom-right' , delay = typeof controlledVisible === 'undefined' ? 1 : 0 , } ) { const [ searchParams ] = useSearchParams ( ) ; const hasQueryStringValue = queryStringKey ? searchParams . has ( queryStringKey ) : false ; const [ isVisible , setIsVisible ] = useState ( ! queryStringKey || hasQueryStringValue ) ; const messageFromQuery = queryStringKey && searchParams . get ( queryStringKey ) ; const message = messageFromQuery || children ; const latestMessageRef = React . useRef ( message ) ; React . useEffect ( ( ) => { if ( hasQueryStringValue ) setIsVisible ( true ) ; } , [ hasQueryStringValue ] ) ; React . useEffect ( ( ) => { latestMessageRef . current = message ; } , [ message ] ) ; React . useEffect ( ( ) => { if ( ! latestMessageRef . current ) return ; if ( autoClose === false ) return ; if ( controlledVisible === false ) return ; const timeout = setTimeout ( ( ) => { setIsVisible ( false ) ; } , visibleMs + delay ) ; return ( ) => clearTimeout ( timeout ) ; } , [ queryStringKey , delay , autoClose , controlledVisible , visibleMs ] ) ; React . useEffect ( ( ) => { if ( ! latestMessageRef . current ) return ; if ( queryStringKey && searchParams . has ( queryStringKey ) ) { const newSearchParams = new URLSearchParams ( searchParams ) ; newSearchParams . delete ( queryStringKey ) ; window . history . replaceState ( null , '' , [ window . location . pathname , newSearchParams . toString ( ) ] . filter ( Boolean ) . join ( '?' ) ) ; } } , [ queryStringKey , searchParams ] ) ; const initialY = position . includes ( 'bottom' ) ? 50 : - 50 ; const show = message && typeof controlledVisible === 'boolean' ? controlledVisible : isVisible ; return ( < AnimatePresence > { show ? ( < motion . div initial = { { y : initialY , opacity : 0 } } animate = { { y : 0 , opacity : 1 , transition : { delay } } } exit = { { y : initialY , opacity : 0 } } transition = { { ease : 'easeInOut' , duration : 0.3 } } className = { clsx ( 'fixed z-50 left-0 right-0 px-5vw pointer-events-none' , { 'bottom-8' : position === 'bottom-right' , 'top-8' : position === 'top-center' , } ) } > < div className = { clsx ( 'flex mx-auto w-full max-w-8xl' , { 'justify-end' : position === 'bottom-right' , 'justify-center' : position === 'top-center' , } ) } > < div className = "bg-inverse text-inverse relative p-8 pr-14 max-w-xl rounded-lg shadow-md pointer-events-auto" > { typeof controlledVisible === 'undefined' ? ( < button aria - label = "dismiss message" onClick = { ( ) => setIsVisible ( false ) } className = "text-secondary hover:text-inverse focus:text-inverse absolute right-4 top-8 transform rotate-45" > < PlusIcon /> < /button>) : null} { message } < /div> < /div> < /motion.div>) : null} < /AnimatePresence>); } export { NotificationMessage } ;