From 69ae23fee113bccdc20b1fe443570ef70d92ec94 Mon Sep 17 00:00:00 2001 From: jonathan Date: Mon, 2 Feb 2026 13:08:01 -0300 Subject: [PATCH] feat(alerts): actualizar FlashNotification con ancho, centrado y auto-cerrado MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Revierte la implementación de FlashNotification y elimina FlashNotificationGlobal. - Agrega soporte para propiedades `width` y `maxContent` para un dimensionamiento flexible. - Implementa lógica de auto-cerrado por estado (automático para 'success', persistente para otros). - Actualiza el cálculo del tiempo de lectura basado en 150 palabras por minuto. - Usa `Portal` y `mx="auto"` para asegurar un centrado perfecto sin importar el layout padre. - Actualiza la documentación y los componentes de demostración con las nuevas funcionalidades. --- src/documentation/Documentation.tsx | 2 - .../components/FlashNotificationDemo.tsx | 12 +++- .../pages/Organisms/FlashNotification.tsx | 57 +++++++++++++------ src/organisms/Alerts/Alert.tsx | 6 +- src/organisms/Alerts/FlashNotification.tsx | 54 ++++++++---------- src/organisms/Alerts/types.d.ts | 2 + src/organisms/Alerts/utils/handleTime.ts | 25 ++++---- .../Alerts/utils/useFlashNotification.ts | 7 ++- 8 files changed, 98 insertions(+), 67 deletions(-) diff --git a/src/documentation/Documentation.tsx b/src/documentation/Documentation.tsx index f21acb61..ca195e89 100644 --- a/src/documentation/Documentation.tsx +++ b/src/documentation/Documentation.tsx @@ -5,7 +5,6 @@ import { routes } from './utils/routes' import { Home, NoMatch } from './pages' import { Layout } from './components' import { Box } from '@chakra-ui/react' -import { FlashNotificationGlobal } from '@/organisms/Alerts/FlashNotification' export const Documentation = (): JSX.Element => { React.useEffect(() => { @@ -17,7 +16,6 @@ export const Documentation = (): JSX.Element => { return ( - }> diff --git a/src/documentation/components/FlashNotificationDemo.tsx b/src/documentation/components/FlashNotificationDemo.tsx index cf82b462..5d826ef9 100644 --- a/src/documentation/components/FlashNotificationDemo.tsx +++ b/src/documentation/components/FlashNotificationDemo.tsx @@ -6,16 +6,24 @@ export default function FlashNotificationDemo({ state, message, maxContent, + width, }: IFlashNotificationProps): JSX.Element { const { show, active, config } = useFlashNotification({ state: state, message: message, maxContent: maxContent, - }) + width, + }) as { show: boolean; active: () => void; config: IFlashNotificationProps } return ( - + ) } diff --git a/src/documentation/pages/Organisms/FlashNotification.tsx b/src/documentation/pages/Organisms/FlashNotification.tsx index 3873fc3b..5259d852 100644 --- a/src/documentation/pages/Organisms/FlashNotification.tsx +++ b/src/documentation/pages/Organisms/FlashNotification.tsx @@ -15,20 +15,43 @@ export const ViewFlashNotification = (): JSX.Element => { (Ej: Problemas de conexión, fallos al guardar o cargar datos, etc.) - Tiempo de permanencia en pantalla: Se recomienda no exceder las 25 palabras para - alertas flash para una correcta lectura de la información. - - - Según la cantidad de la palabras la duración será la siguiente:{' '} + Tiempo de permanencia y auto-cerrado: +
+ La duración de la notificación depende de su estado y la longitud del mensaje (basado en una + velocidad de lectura de 150 palabras por minuto):
  • - De 1 a 5 palabras: 3 segundos. -
  • {' '} + Estado Success: Se cierra automáticamente tras el tiempo calculado para su lectura + (mínimo 3 segundos). +
  • - De 11 a 25 palabras: 6 segundos. -
  • {' '} -
    + Otros Estados (Error, Warning, Info): Permanecen visibles de forma persistente y + requieren que el usuario las cierre manualmente mediante la "X" integrada. + +
    + + Ancho del Contenido y Centrado + + Mediante la propiedad maxContent, la notificación tomará exactamente el ancho de su + contenido y se mantendrá perfectamente centrada en la pantalla. Alternativamente, puedes + pasar un ancho fijo mediante width. + + + + + + + Implementación + El componente de FlashNotification se implementa en conjunto con el hook - useFlashNotification + useFlashNotification: @@ -40,15 +63,17 @@ export const ViewFlashNotification = (): JSX.Element => { state="info" message="¡Grupo creado!
    Tu grupo ha sido creado. Ahora puedes invitar a tus compañeros." /> - - - + + + */ + export function FlashNotification({ message, state, show, - maxContent, -}: IFlashNotificationProps): null { - const hasShownRef = useRef(false) - + m, + width, +}: IFlashNotificationProps): JSX.Element { const showToast = useCallback(() => { toast( (t) => ( @@ -35,42 +36,37 @@ export function FlashNotification({ state={state} canDismiss onClick={() => toast.dismiss(t.id)} - maxContent={maxContent} + width={width} + m={m} > {message} ), { + duration: state === 'success' ? handleTime(message) : Infinity, id: alertStates[state].id, - duration: handleTime(message), } ) - }, [message, state, maxContent]) + }, [message, state, width, m]) useEffect(() => { - if (show && !hasShownRef.current) { + if (show) { showToast() - hasShownRef.current = true - } - - if (!show) { - hasShownRef.current = false } }, [show, showToast]) - return null + return ( + + + + ) } - -export const FlashNotificationGlobal = (): JSX.Element => ( - -) diff --git a/src/organisms/Alerts/types.d.ts b/src/organisms/Alerts/types.d.ts index a351555d..63042d3a 100644 --- a/src/organisms/Alerts/types.d.ts +++ b/src/organisms/Alerts/types.d.ts @@ -52,6 +52,7 @@ export interface IAlertProps { endTextLink?: string onClickLink?: () => void maxContent?: boolean + width?: string sx?: CSSObject } @@ -76,4 +77,5 @@ export interface IFlashNotificationProps { state: TState show?: boolean maxContent?: boolean + width?: string } diff --git a/src/organisms/Alerts/utils/handleTime.ts b/src/organisms/Alerts/utils/handleTime.ts index 20797937..7399ea56 100644 --- a/src/organisms/Alerts/utils/handleTime.ts +++ b/src/organisms/Alerts/utils/handleTime.ts @@ -1,16 +1,13 @@ -/* Método que cuenta la cantidad de palabras del mensaje de alerta o notificación -y según eso calcula el tiempo que durará en pantalla */ - export const handleTime = (message: string): number => { - // Se recibe el mensaje y se retorna la cantidad de palabras - function countWords(input: string): number { - const wordCount = input.match(/(\w+)/g)?.length ?? 0 - return wordCount - } - // Por defecto la duración es de 3seg, si el mensaje tiene más de 5 palabras, se cambia a 6 - let time = 3000 - if (message && countWords(message) > 5) { - time = 6000 - } - return time + if (!message) return 3000 + + const words = message.trim().split(/\s+/).length + const wordsPerMinute = 150 + const baseMinutes = words / wordsPerMinute + + // Convertimos a milisegundos: minutos * 60 segundos * 1000 ms + const totalMs = Math.round(baseMinutes * 60 * 1000) + + // Aseguramos un mínimo de 3 segundos para mensajes muy cortos + return Math.max(3000, totalMs) } diff --git a/src/organisms/Alerts/utils/useFlashNotification.ts b/src/organisms/Alerts/utils/useFlashNotification.ts index b42ab6ac..5f8e508e 100644 --- a/src/organisms/Alerts/utils/useFlashNotification.ts +++ b/src/organisms/Alerts/utils/useFlashNotification.ts @@ -23,6 +23,7 @@ export const useFlashNotification = ({ state, message, maxContent, + width, }: IFlashNotificationProps): any => { // Estado que maneja si la notificación debe mostrarse. const [show, setShow] = useState(false) @@ -31,12 +32,13 @@ export const useFlashNotification = ({ useEffect(() => { // Si la notificación se está mostrando, se determina el tiempo tras el cual se ocultará. if (show) { + const duration = state === 'success' ? handleTime(message) : 1000 const timeOut = setTimeout(() => { setShow(false) - }, handleTime(message)) + }, duration) return () => clearTimeout(timeOut) } - }, [message, show]) + }, [message, show, state]) // Función que activa la notificación const active = (): any => { @@ -53,6 +55,7 @@ export const useFlashNotification = ({ state, message, maxContent, + width, }, } }