Files
donetick/src/service/AlertsProvider.jsx

86 lines
2.2 KiB
JavaScript

import { Alert, Box } from '@mui/joy'
import PropTypes from 'prop-types'
import { createContext, useCallback, useContext, useState } from 'react'
const FADE_DURATION = 400 // ms
const ALERT_DURATION = 5000 // ms
const AlertsContext = createContext()
// Helper function to create a delay
const delay = ms => new Promise(res => setTimeout(res, ms))
export const AlertsProvider = ({ children }) => {
const [show, setShow] = useState(false)
const [visibleAlert, setVisibleAlert] = useState(null)
const showAlert = useCallback(async alertObj => {
setVisibleAlert(alertObj)
setShow(false)
await delay(10)
setShow(true)
await delay(ALERT_DURATION)
setShow(false)
await delay(FADE_DURATION)
setVisibleAlert(null)
}, [])
const hideAlert = useCallback(() => {
setShow(false)
// Wait for the fade out transition to complete before unmounting
setTimeout(() => {
setVisibleAlert(null)
}, FADE_DURATION)
}, [])
return (
<AlertsContext.Provider value={{ showAlert, hideAlert }}>
{children}
{visibleAlert && (
<Box
sx={{
pt: `calc( env(safe-area-inset-top, 0px))`,
position: 'fixed',
top: 0,
left: 0,
width: '100%',
zIndex: 10000,
overflow: 'hidden',
}}
>
<Alert
variant='soft'
color={visibleAlert.color || 'primary'}
startDecorator={visibleAlert.icon}
onClick={hideAlert}
sx={{
transition: `transform ${FADE_DURATION}ms ease-in-out, opacity ${FADE_DURATION}ms ease-in-out`,
transform: show ? 'translateY(0)' : 'translateY(-100%)',
opacity: show ? 1 : 0,
pointerEvents: show ? 'auto' : 'none',
width: '100%',
justifyContent: 'center',
alignItems: 'center',
padding: '4px',
fontSize: '10px',
fontWeight: 'md',
}}
>
{visibleAlert.message}
</Alert>
</Box>
)}
</AlertsContext.Provider>
)
}
AlertsProvider.propTypes = {
children: PropTypes.node.isRequired,
}
export const useAlerts = () => useContext(AlertsContext)