From ce0b42814b1c6cdee3487930bba48275faaf0d3a Mon Sep 17 00:00:00 2001 From: Philipp Schmitt Date: Tue, 11 Feb 2025 20:04:51 +0100 Subject: [PATCH 1/5] BA-2205 --- packages/components/.storybook/main.ts | 5 + .../UserMessage/MessageItem/index.tsx | 7 +- packages/design-system/.storybook/main.ts | 2 + .../components/web/icons/ErrorIcon/index.tsx | 42 ++++++ .../components/web/icons/index.ts | 1 + .../SnackbarProvider/ProgressBar/index.tsx | 12 ++ .../SnackbarProvider/ProgressBar/styled.tsx | 34 +++++ .../web/SnackbarProvider/ProgressBar/types.ts | 9 ++ .../__storybook__/Snackbar.mdx | 45 ++++++ .../__storybook__/stories.tsx | 131 ++++++++++++++++++ .../web/SnackbarProvider/constants.tsx | 10 ++ .../providers/web/SnackbarProvider/index.tsx | 67 +++++++-- .../providers/web/SnackbarProvider/styled.tsx | 22 +++ .../utils/hooks/useNotification/constants.ts | 1 + .../utils/hooks/useNotification/index.tsx | 12 +- packages/utils/hooks/useNotification/types.ts | 2 + packages/utils/index.ts | 1 + 17 files changed, 391 insertions(+), 12 deletions(-) create mode 100644 packages/design-system/components/web/icons/ErrorIcon/index.tsx create mode 100644 packages/design-system/providers/web/SnackbarProvider/ProgressBar/index.tsx create mode 100644 packages/design-system/providers/web/SnackbarProvider/ProgressBar/styled.tsx create mode 100644 packages/design-system/providers/web/SnackbarProvider/ProgressBar/types.ts create mode 100644 packages/design-system/providers/web/SnackbarProvider/__storybook__/Snackbar.mdx create mode 100644 packages/design-system/providers/web/SnackbarProvider/__storybook__/stories.tsx create mode 100644 packages/design-system/providers/web/SnackbarProvider/constants.tsx create mode 100644 packages/design-system/providers/web/SnackbarProvider/styled.tsx diff --git a/packages/components/.storybook/main.ts b/packages/components/.storybook/main.ts index 6394798f..6fbad6e4 100644 --- a/packages/components/.storybook/main.ts +++ b/packages/components/.storybook/main.ts @@ -14,11 +14,16 @@ const config: StorybookConfig = { resolve(__dirname, './*.mdx'), resolve(__dirname, '../modules/**/__storybook__/*.mdx'), resolve(__dirname, '../../design-system/components/**/__storybook__/*.mdx'), + resolve(__dirname, '../../design-system/providers/**/__storybook__/*.mdx'), resolve(__dirname, '../modules/**/__storybook__/stories.@(js|jsx|mjs|ts|tsx)'), resolve( __dirname, '../../design-system/components/**/__storybook__/stories.@(js|jsx|mjs|ts|tsx)', ), + resolve( + __dirname, + '../../design-system/providers/**/__storybook__/stories.@(js|jsx|mjs|ts|tsx)', + ), ], framework: { name: getAbsolutePath('@storybook/react-webpack5'), diff --git a/packages/components/modules/messages/web/MessagesList/MessagesGroup/UserMessage/MessageItem/index.tsx b/packages/components/modules/messages/web/MessagesList/MessagesGroup/UserMessage/MessageItem/index.tsx index 44f94e37..fe53de80 100644 --- a/packages/components/modules/messages/web/MessagesList/MessagesGroup/UserMessage/MessageItem/index.tsx +++ b/packages/components/modules/messages/web/MessagesList/MessagesGroup/UserMessage/MessageItem/index.tsx @@ -6,6 +6,7 @@ import { DownloadIcon, PenEditIcon, } from '@baseapp-frontend/design-system/components/web/icons' +import { useNotification } from '@baseapp-frontend/utils' import { Typography } from '@mui/material' import { useFragment } from 'react-relay' @@ -21,6 +22,7 @@ const MessageItem: FC = ({ messageRef, isFirstGroupedMessage } const message = useFragment(MessageItemFragment, messageRef) const isOwnMessage = currentProfile?.id === message?.profile?.id const messageCardRef = useRef(null) + const { sendSnack } = useNotification() const [isEditMode, setIsEditMode] = useState(false) @@ -53,7 +55,10 @@ const MessageItem: FC = ({ messageRef, isFirstGroupedMessage } disabled: false, icon: , label: 'Copy', - onClick: () => {}, // TODO: Implement copy message + onClick: () => { + navigator.clipboard.writeText(message?.content || '') + sendSnack('Message copied to clipboard.', { type: 'info' }) + }, hasPermission: true, }, { diff --git a/packages/design-system/.storybook/main.ts b/packages/design-system/.storybook/main.ts index d0f29dbc..3c9377f5 100644 --- a/packages/design-system/.storybook/main.ts +++ b/packages/design-system/.storybook/main.ts @@ -13,7 +13,9 @@ const config: StorybookConfig = { stories: [ './*.mdx', '../components/**/__storybook__/*.mdx', + '../providers/**/__storybook__/*.mdx', '../components/**/__storybook__/stories.@(js|jsx|mjs|ts|tsx)', + '../providers/**/__storybook__/stories.@(js|jsx|mjs|ts|tsx)', ], framework: { name: getAbsolutePath('@storybook/react-webpack5'), diff --git a/packages/design-system/components/web/icons/ErrorIcon/index.tsx b/packages/design-system/components/web/icons/ErrorIcon/index.tsx new file mode 100644 index 00000000..d217325d --- /dev/null +++ b/packages/design-system/components/web/icons/ErrorIcon/index.tsx @@ -0,0 +1,42 @@ +import { FC } from 'react' + +import { SvgIcon, SvgIconProps } from '@mui/material' + +const ErrorIcon: FC = ({ sx, ...props }) => ( + + + + + + + + + + + +) + +export default ErrorIcon diff --git a/packages/design-system/components/web/icons/index.ts b/packages/design-system/components/web/icons/index.ts index 797df81a..a13759d6 100644 --- a/packages/design-system/components/web/icons/index.ts +++ b/packages/design-system/components/web/icons/index.ts @@ -11,6 +11,7 @@ export { default as CloseIcon } from './CloseIcon' export { default as CommentReplyIcon } from './CommentReplyIcon' export { default as CopyIcon } from './CopyIcon' export { default as DownloadIcon } from './DownloadIcon' +export { default as ErrorIcon } from './ErrorIcon' export { default as FavoriteIcon } from './FavoriteIcon' export { default as FavoriteSelectedIcon } from './FavoriteSelectedIcon' export { default as LinkIcon } from './LinkIcon' diff --git a/packages/design-system/providers/web/SnackbarProvider/ProgressBar/index.tsx b/packages/design-system/providers/web/SnackbarProvider/ProgressBar/index.tsx new file mode 100644 index 00000000..48801803 --- /dev/null +++ b/packages/design-system/providers/web/SnackbarProvider/ProgressBar/index.tsx @@ -0,0 +1,12 @@ +import { FC } from 'react' + +import { ProgressBarContainer, ProgressContainer } from './styled' +import { ProgressAnimationProps } from './types' + +const ProgressAnimation: FC = ({ animationTime, severity }) => ( + + + +) + +export default ProgressAnimation diff --git a/packages/design-system/providers/web/SnackbarProvider/ProgressBar/styled.tsx b/packages/design-system/providers/web/SnackbarProvider/ProgressBar/styled.tsx new file mode 100644 index 00000000..96f26b14 --- /dev/null +++ b/packages/design-system/providers/web/SnackbarProvider/ProgressBar/styled.tsx @@ -0,0 +1,34 @@ +import { Box, alpha } from '@mui/material' +import { styled } from '@mui/material/styles' + +import { AlertContainerProps, ProgressBarContainerProps } from './types' + +export const ProgressContainer = styled(Box)(({ theme, severity }) => ({ + display: 'flex', + flexDirection: 'column', + alignItems: 'flex-start', + width: '100%', + height: '4px', + backgroundColor: + severity === 'info' + ? alpha(theme.palette.grey[500], 0.24) + : alpha(theme.palette[severity].main, 0.24), +})) + +export const ProgressBarContainer = styled(Box)( + ({ theme, animationTime, severity }) => ({ + borderRadius: '50px', + animation: `increase-width ${animationTime}ms linear forwards`, + '@keyframes increase-width': { + from: { + width: 0, + }, + to: { + width: '100%', + }, + }, + height: '100%', + backgroundColor: + severity === 'info' ? theme.palette.text.primary : theme.palette[severity].main, + }), +) diff --git a/packages/design-system/providers/web/SnackbarProvider/ProgressBar/types.ts b/packages/design-system/providers/web/SnackbarProvider/ProgressBar/types.ts new file mode 100644 index 00000000..65272b07 --- /dev/null +++ b/packages/design-system/providers/web/SnackbarProvider/ProgressBar/types.ts @@ -0,0 +1,9 @@ +import { AlertColor, BoxProps } from '@mui/material' + +type SeverityProp = { severity: AlertColor } +type AnimationTimeProp = { animationTime: number } + +export type ProgressAnimationProps = SeverityProp & AnimationTimeProp + +export type AlertContainerProps = SeverityProp & BoxProps +export type ProgressBarContainerProps = ProgressAnimationProps & BoxProps diff --git a/packages/design-system/providers/web/SnackbarProvider/__storybook__/Snackbar.mdx b/packages/design-system/providers/web/SnackbarProvider/__storybook__/Snackbar.mdx new file mode 100644 index 00000000..ccfb6371 --- /dev/null +++ b/packages/design-system/providers/web/SnackbarProvider/__storybook__/Snackbar.mdx @@ -0,0 +1,45 @@ +import { Meta } from '@storybook/addon-docs' + + + +# Component Documentation + +## SnackbarProvider + +- **Purpose**: A customized wrapper around MUI's snackbar displaying messages from the notification store. It provides consistent styling for icons and a uniform color scheme. +- **Expected Behavior**: Renders messages set with 'useNotification'. The messages disappear automatically after a fixed amount of time, but can also be dismissed before by clicking on a close icon. The component can be used with or without a bar indicating the remaining time before the message is dismissed. If used without a bar, the time until automatic dismissal is restarted after the user interacts with the message, if used with bar the message is always dismissed after the timeout, no matter whether the user interacted with it or not. + +## Props + +- **children** (ReactNode): The content wrapped by the SnackbarProvider. Any components in this wrapped content can make use of 'useNotification' to display messages +- **...other**: All other props are passed to the snackbar + +## Example Usage + +```javascript +import { SnackbarProvider } from '@baseapp-frontend/design-system' +import { useNotification } from '@baseapp-frontend/utils' + +const MessageEmitter = () => { + const { sendToast, sendSnack } = useNotification() + + return ( + <> + + + < /> + ) +} + +const MyComponent = () => { + return ( + + + + ) +} +``` diff --git a/packages/design-system/providers/web/SnackbarProvider/__storybook__/stories.tsx b/packages/design-system/providers/web/SnackbarProvider/__storybook__/stories.tsx new file mode 100644 index 00000000..64cb8374 --- /dev/null +++ b/packages/design-system/providers/web/SnackbarProvider/__storybook__/stories.tsx @@ -0,0 +1,131 @@ +import { FC } from 'react' + +import { NotificationState, useNotification } from '@baseapp-frontend/utils' + +import { Button } from '@mui/material' +import { Meta, StoryObj } from '@storybook/react' + +import SnackbarProvider from '..' + +interface SnackbarProps { + message: string + shouldShowProgress: boolean + type: NotificationState['type'] +} + +const SnackbarWrapper: FC = ({ message, shouldShowProgress, type }) => { + const { sendToast, sendSnack } = useNotification() + const send = shouldShowProgress ? sendSnack : sendToast + return ( + + + + ) +} + +const meta: Meta = { + title: '@baseapp-frontend | designSystem/SnackbarProvider/SnackbarProvider', + component: SnackbarWrapper, + argTypes: { + type: { + control: 'select', + options: ['info', 'success', 'warning', 'error'], + }, + }, +} + +export default meta + +type Story = StoryObj + +export const InfoWithProgress: Story = { + render: (args) => , + args: { + message: 'This is an info message with progress bar', + shouldShowProgress: true, + type: 'info', + }, +} + +export const SuccessWithProgress: Story = { + render: (args) => , + args: { + message: 'This is a success message with progress bar', + shouldShowProgress: true, + type: 'success', + }, +} + +export const WarningWithProgress: Story = { + render: (args) => , + args: { + message: 'This is a warning message with progress bar', + shouldShowProgress: true, + type: 'warning', + }, +} + +export const ErrorWithProgress: Story = { + render: (args) => , + args: { + message: 'This is an error message with progress bar', + shouldShowProgress: true, + type: 'error', + }, +} + +export const LongInfoWithProgress: Story = { + render: (args) => , + args: { + message: + 'Mr. Jones, of the Manor Farm, had locked the hen-houses for the night, but was too drunk to remember to shut the popholes. With the ring of light from his lantern dancing from side to side, he lurched across the yard, kicked off his boots at the back door, drew himself a last glass of beer from the barrel in the scullery, and made his way up to bed, where Mrs. Jones was already snoring. From Geoge Orwell, Animal Farm, Chapter 1', + shouldShowProgress: true, + type: 'info', + }, +} + +export const InfoWithoutProgress: Story = { + render: (args) => , + args: { + message: 'This is an info message without progress bar', + shouldShowProgress: false, + type: 'info', + }, +} + +export const SuccessWithoutProgress: Story = { + render: (args) => , + args: { + message: 'This is a success message without progress bar', + shouldShowProgress: false, + type: 'success', + }, +} + +export const WarningWithoutProgress: Story = { + render: (args) => , + args: { + message: 'This is a warning message without progress bar', + shouldShowProgress: false, + type: 'warning', + }, +} + +export const ErrorWithoutProgress: Story = { + render: (args) => , + args: { + message: 'This is an error message without progress bar', + shouldShowProgress: false, + type: 'error', + }, +} + +export const LongInfoWithoutProgress: Story = { + render: (args) => , + args: { + message: + 'Mr. Jones, of the Manor Farm, had locked the hen-houses for the night, but was too drunk to remember to shut the popholes. With the ring of light from his lantern dancing from side to side, he lurched across the yard, kicked off his boots at the back door, drew himself a last glass of beer from the barrel in the scullery, and made his way up to bed, where Mrs. Jones was already snoring. From Geoge Orwell, Animal Farm, Chapter 1', + shouldShowProgress: false, + type: 'info', + }, +} diff --git a/packages/design-system/providers/web/SnackbarProvider/constants.tsx b/packages/design-system/providers/web/SnackbarProvider/constants.tsx new file mode 100644 index 00000000..3f74c137 --- /dev/null +++ b/packages/design-system/providers/web/SnackbarProvider/constants.tsx @@ -0,0 +1,10 @@ +import Iconify from '../../components/Iconify' +import ErrorIcon from '../../components/icons/ErrorIcon' + +export const HIDE_DURATION = 3000 +export const OUTLINED_ALERT_ICONS = { + error: , + info: , + success: , + warning: , +} diff --git a/packages/design-system/providers/web/SnackbarProvider/index.tsx b/packages/design-system/providers/web/SnackbarProvider/index.tsx index 5ac52675..795aba96 100644 --- a/packages/design-system/providers/web/SnackbarProvider/index.tsx +++ b/packages/design-system/providers/web/SnackbarProvider/index.tsx @@ -1,21 +1,56 @@ 'use client' -import { FC, SyntheticEvent } from 'react' +import { FC, SyntheticEvent, useRef } from 'react' import { useNotification } from '@baseapp-frontend/utils' -import { Alert, Snackbar } from '@mui/material' +import { Alert, Snackbar, useTheme } from '@mui/material' +import ProgressAnimation from './ProgressBar' +import { HIDE_DURATION, OUTLINED_ALERT_ICONS } from './constants' +import { SnackbarContentContainer } from './styled' import { SnackbarProviderProps } from './types' const SnackbarProvider: FC = ({ children, ...props }) => { - const { closeToast, open, message, type } = useNotification() + const { closeToast, open, shouldShowProgress, message, type } = useNotification() + const timeoutID = useRef(null) + const theme = useTheme() const handleClose = (_event?: SyntheticEvent | Event, reason?: string) => { if (reason === 'clickaway') { return } closeToast() + if (timeoutID.current) clearTimeout(timeoutID.current) + } + + if (!shouldShowProgress) { + return ( + <> + {children} + + + {message} + + + + ) + } + + if (!timeoutID.current && open) { + timeoutID.current = setTimeout(() => { + timeoutID.current = null + handleClose() + }, HIDE_DURATION) // MUI would resume with different remaining time after user interaction + // so we explicitly set this timeout ourselves to make sure that the progress bar is right } return ( @@ -25,14 +60,28 @@ const SnackbarProvider: FC = ({ children, ...props }) => key={message} onClose={handleClose} open={open} - autoHideDuration={3000} - anchorOrigin={{ vertical: 'top', horizontal: 'right' }} - resumeHideDuration={3000} + anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }} + sx={{ width: 'calc(100% - 16px)' }} {...props} > - - {message} - + + + {message} + + + ) diff --git a/packages/design-system/providers/web/SnackbarProvider/styled.tsx b/packages/design-system/providers/web/SnackbarProvider/styled.tsx new file mode 100644 index 00000000..ee72d5bd --- /dev/null +++ b/packages/design-system/providers/web/SnackbarProvider/styled.tsx @@ -0,0 +1,22 @@ +import { Box } from '@mui/material' +import { styled } from '@mui/material/styles' + +export const SnackbarContentContainer = styled(Box)(({ theme }) => ({ + display: 'flex', + minWidth: '360px', + flexDirection: 'column', + justifyContent: 'center', + alignItems: 'flex-start', + borderRadius: '8px', + border: `1px solid ${theme.palette.grey[400]}`, + backgroundColor: theme.palette.common.white, + boxShadow: theme.customShadows.z8, + overflow: 'hidden', + maxWidth: '60%', + [theme.breakpoints.down('md')]: { + maxWidth: '80%', + }, + [theme.breakpoints.down('sm')]: { + maxWidth: '100%', + }, +})) diff --git a/packages/utils/hooks/useNotification/constants.ts b/packages/utils/hooks/useNotification/constants.ts index 1f136eed..7f8ccf7d 100644 --- a/packages/utils/hooks/useNotification/constants.ts +++ b/packages/utils/hooks/useNotification/constants.ts @@ -2,6 +2,7 @@ import type { NotificationState } from './types' export const INITIAL_NOTIFICATION_STATE: NotificationState = { open: false, + shouldShowProgress: false, message: '', type: 'success', } diff --git a/packages/utils/hooks/useNotification/index.tsx b/packages/utils/hooks/useNotification/index.tsx index cfae74a7..30dbaab6 100644 --- a/packages/utils/hooks/useNotification/index.tsx +++ b/packages/utils/hooks/useNotification/index.tsx @@ -11,9 +11,17 @@ import type { UseNotification } from './types' const createNotificationStore = () => createStore((set) => ({ ...INITIAL_NOTIFICATION_STATE, - sendToast: (message, { type = 'success' } = {}) => set({ message, type, open: true }), + sendSnack: (message, { type = 'success' } = {}) => + set({ message, type, open: true, shouldShowProgress: true }), + sendToast: (message, { type = 'success' } = {}) => + set({ message, type, open: true, shouldShowProgress: false }), sendApiErrorToast: (error) => - set({ message: getApiErrorMessage(error), type: 'error', open: true }), + set({ + message: getApiErrorMessage(error), + type: 'error', + open: true, + shouldShowProgress: false, + }), closeToast: () => set({ open: false }), })) diff --git a/packages/utils/hooks/useNotification/types.ts b/packages/utils/hooks/useNotification/types.ts index 5bb10f30..9ecd6a85 100644 --- a/packages/utils/hooks/useNotification/types.ts +++ b/packages/utils/hooks/useNotification/types.ts @@ -1,10 +1,12 @@ export type NotificationState = { open: boolean + shouldShowProgress: boolean message: string type: 'success' | 'info' | 'warning' | 'error' } type NotificationFunctions = { + sendSnack: (message: string, options?: { type?: NotificationState['type'] }) => void sendToast: (message: string, options?: { type?: NotificationState['type'] }) => void sendApiErrorToast: (error: unknown) => void closeToast: () => void diff --git a/packages/utils/index.ts b/packages/utils/index.ts index 1f136b17..199ac0a0 100644 --- a/packages/utils/index.ts +++ b/packages/utils/index.ts @@ -25,6 +25,7 @@ export { default as useDjangoOrderBy } from './hooks/useDjangoOrderBy' export { default as useEventSubscription } from './hooks/useEventSubscription' export { default as useNotification } from './hooks/useNotification' export { NotificationProvider } from './hooks/useNotification' +export type * from './hooks/useNotification/types' export { default as useSSR } from './hooks/useSSR' export { default as useBoolean } from './hooks/useBoolean' From 2fd0311bf95b6b08c41445cbc4a46cd6e88dc9d2 Mon Sep 17 00:00:00 2001 From: Philipp Schmitt Date: Tue, 11 Feb 2025 20:28:31 +0100 Subject: [PATCH 2/5] BA-2205 More timeout to effect --- .../providers/web/SnackbarProvider/index.tsx | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/packages/design-system/providers/web/SnackbarProvider/index.tsx b/packages/design-system/providers/web/SnackbarProvider/index.tsx index 795aba96..8d9744a0 100644 --- a/packages/design-system/providers/web/SnackbarProvider/index.tsx +++ b/packages/design-system/providers/web/SnackbarProvider/index.tsx @@ -1,6 +1,6 @@ 'use client' -import { FC, SyntheticEvent, useRef } from 'react' +import { FC, SyntheticEvent, useEffect, useRef } from 'react' import { useNotification } from '@baseapp-frontend/utils' @@ -24,6 +24,24 @@ const SnackbarProvider: FC = ({ children, ...props }) => if (timeoutID.current) clearTimeout(timeoutID.current) } + useEffect(() => { + // MUI has no option to just ignore user interactions with a snackbar. + // It always pauses its timer and restarts it at a (customizable fixed) value. + // Therefore, if we show a 'progress bar', we explicitly set the timeout for closing the snackbar ourselves. + if (shouldShowProgress && open && !timeoutID.current) { + timeoutID.current = setTimeout(() => { + timeoutID.current = null + handleClose() + }, HIDE_DURATION) + } + return () => { + if (timeoutID.current) { + clearTimeout(timeoutID.current) + timeoutID.current = null + } + } + }, [open, shouldShowProgress]) + if (!shouldShowProgress) { return ( <> @@ -45,14 +63,6 @@ const SnackbarProvider: FC = ({ children, ...props }) => ) } - if (!timeoutID.current && open) { - timeoutID.current = setTimeout(() => { - timeoutID.current = null - handleClose() - }, HIDE_DURATION) // MUI would resume with different remaining time after user interaction - // so we explicitly set this timeout ourselves to make sure that the progress bar is right - } - return ( <> {children} From 4e02fef9ecb4e149eda31f232a8cfacc9d920668 Mon Sep 17 00:00:00 2001 From: Philipp Schmitt Date: Tue, 11 Feb 2025 21:24:10 +0100 Subject: [PATCH 3/5] BA-2205 fix rebase errors --- .../providers/web/SnackbarProvider/__storybook__/Snackbar.mdx | 2 +- .../providers/web/SnackbarProvider/constants.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/design-system/providers/web/SnackbarProvider/__storybook__/Snackbar.mdx b/packages/design-system/providers/web/SnackbarProvider/__storybook__/Snackbar.mdx index ccfb6371..9c5bb028 100644 --- a/packages/design-system/providers/web/SnackbarProvider/__storybook__/Snackbar.mdx +++ b/packages/design-system/providers/web/SnackbarProvider/__storybook__/Snackbar.mdx @@ -17,7 +17,7 @@ import { Meta } from '@storybook/addon-docs' ## Example Usage ```javascript -import { SnackbarProvider } from '@baseapp-frontend/design-system' +import { SnackbarProvider } from '@baseapp-frontend/design-system/web' import { useNotification } from '@baseapp-frontend/utils' const MessageEmitter = () => { diff --git a/packages/design-system/providers/web/SnackbarProvider/constants.tsx b/packages/design-system/providers/web/SnackbarProvider/constants.tsx index 3f74c137..f38b9003 100644 --- a/packages/design-system/providers/web/SnackbarProvider/constants.tsx +++ b/packages/design-system/providers/web/SnackbarProvider/constants.tsx @@ -1,5 +1,5 @@ -import Iconify from '../../components/Iconify' -import ErrorIcon from '../../components/icons/ErrorIcon' +import { ErrorIcon } from '../../../components/web/icons' +import { Iconify } from '../../../components/web/images' export const HIDE_DURATION = 3000 export const OUTLINED_ALERT_ICONS = { From dcd3259f8c0b54cee42e876565739ec2c2bb4f1e Mon Sep 17 00:00:00 2001 From: Philipp Schmitt Date: Wed, 12 Feb 2025 16:00:48 +0100 Subject: [PATCH 4/5] BA-2205 shouldShowProgress option --- .../UserMessage/MessageItem/index.tsx | 4 ++-- .../SnackbarProvider/__storybook__/Snackbar.mdx | 5 +++-- .../SnackbarProvider/__storybook__/stories.tsx | 5 ++--- .../providers/web/SnackbarProvider/index.tsx | 16 ++++++++++++++-- .../providers/web/SnackbarProvider/types.ts | 3 ++- .../utils/hooks/useNotification/constants.ts | 1 - packages/utils/hooks/useNotification/index.tsx | 10 ++++------ packages/utils/hooks/useNotification/types.ts | 10 ++++++---- 8 files changed, 33 insertions(+), 21 deletions(-) diff --git a/packages/components/modules/messages/web/MessagesList/MessagesGroup/UserMessage/MessageItem/index.tsx b/packages/components/modules/messages/web/MessagesList/MessagesGroup/UserMessage/MessageItem/index.tsx index fe53de80..4486817f 100644 --- a/packages/components/modules/messages/web/MessagesList/MessagesGroup/UserMessage/MessageItem/index.tsx +++ b/packages/components/modules/messages/web/MessagesList/MessagesGroup/UserMessage/MessageItem/index.tsx @@ -22,7 +22,7 @@ const MessageItem: FC = ({ messageRef, isFirstGroupedMessage } const message = useFragment(MessageItemFragment, messageRef) const isOwnMessage = currentProfile?.id === message?.profile?.id const messageCardRef = useRef(null) - const { sendSnack } = useNotification() + const { sendToast } = useNotification() const [isEditMode, setIsEditMode] = useState(false) @@ -57,7 +57,7 @@ const MessageItem: FC = ({ messageRef, isFirstGroupedMessage } label: 'Copy', onClick: () => { navigator.clipboard.writeText(message?.content || '') - sendSnack('Message copied to clipboard.', { type: 'info' }) + sendToast('Message copied to clipboard.', { type: 'info', shouldShowProgress: true }) }, hasPermission: true, }, diff --git a/packages/design-system/providers/web/SnackbarProvider/__storybook__/Snackbar.mdx b/packages/design-system/providers/web/SnackbarProvider/__storybook__/Snackbar.mdx index 9c5bb028..8f40953d 100644 --- a/packages/design-system/providers/web/SnackbarProvider/__storybook__/Snackbar.mdx +++ b/packages/design-system/providers/web/SnackbarProvider/__storybook__/Snackbar.mdx @@ -12,6 +12,7 @@ import { Meta } from '@storybook/addon-docs' ## Props - **children** (ReactNode): The content wrapped by the SnackbarProvider. Any components in this wrapped content can make use of 'useNotification' to display messages +- **shouldShowProgress** (Boolean): The default for showing the progress bar, indicating the time left before the snackbar disappears. Will be overwritten by the 'shouldShowProgress' option of sendToast, if it is set. - **...other**: All other props are passed to the snackbar ## Example Usage @@ -21,14 +22,14 @@ import { SnackbarProvider } from '@baseapp-frontend/design-system/web' import { useNotification } from '@baseapp-frontend/utils' const MessageEmitter = () => { - const { sendToast, sendSnack } = useNotification() + const { sendToast } = useNotification() return ( <> - < /> diff --git a/packages/design-system/providers/web/SnackbarProvider/__storybook__/stories.tsx b/packages/design-system/providers/web/SnackbarProvider/__storybook__/stories.tsx index 64cb8374..9ac31065 100644 --- a/packages/design-system/providers/web/SnackbarProvider/__storybook__/stories.tsx +++ b/packages/design-system/providers/web/SnackbarProvider/__storybook__/stories.tsx @@ -14,11 +14,10 @@ interface SnackbarProps { } const SnackbarWrapper: FC = ({ message, shouldShowProgress, type }) => { - const { sendToast, sendSnack } = useNotification() - const send = shouldShowProgress ? sendSnack : sendToast + const { sendToast } = useNotification() return ( - + ) } diff --git a/packages/design-system/providers/web/SnackbarProvider/index.tsx b/packages/design-system/providers/web/SnackbarProvider/index.tsx index 8d9744a0..f933a5ba 100644 --- a/packages/design-system/providers/web/SnackbarProvider/index.tsx +++ b/packages/design-system/providers/web/SnackbarProvider/index.tsx @@ -11,11 +11,23 @@ import { HIDE_DURATION, OUTLINED_ALERT_ICONS } from './constants' import { SnackbarContentContainer } from './styled' import { SnackbarProviderProps } from './types' -const SnackbarProvider: FC = ({ children, ...props }) => { - const { closeToast, open, shouldShowProgress, message, type } = useNotification() +const SnackbarProvider: FC = ({ + children, + shouldShowProgress: shouldShowProgressProvider, + ...props +}) => { + const { + closeToast, + open, + shouldShowProgress: shouldShowProgressToast, + message, + type, + } = useNotification() const timeoutID = useRef(null) const theme = useTheme() + const shouldShowProgress = shouldShowProgressToast ?? shouldShowProgressProvider + const handleClose = (_event?: SyntheticEvent | Event, reason?: string) => { if (reason === 'clickaway') { return diff --git a/packages/design-system/providers/web/SnackbarProvider/types.ts b/packages/design-system/providers/web/SnackbarProvider/types.ts index aa8efddb..3396efb9 100644 --- a/packages/design-system/providers/web/SnackbarProvider/types.ts +++ b/packages/design-system/providers/web/SnackbarProvider/types.ts @@ -2,4 +2,5 @@ import { PropsWithChildren } from 'react' import { SnackbarProps } from '@mui/material' -export type SnackbarProviderProps = PropsWithChildren & SnackbarProps +export type SnackbarProviderProps = PropsWithChildren & + SnackbarProps & { shouldShowProgress?: boolean } diff --git a/packages/utils/hooks/useNotification/constants.ts b/packages/utils/hooks/useNotification/constants.ts index 7f8ccf7d..1f136eed 100644 --- a/packages/utils/hooks/useNotification/constants.ts +++ b/packages/utils/hooks/useNotification/constants.ts @@ -2,7 +2,6 @@ import type { NotificationState } from './types' export const INITIAL_NOTIFICATION_STATE: NotificationState = { open: false, - shouldShowProgress: false, message: '', type: 'success', } diff --git a/packages/utils/hooks/useNotification/index.tsx b/packages/utils/hooks/useNotification/index.tsx index 30dbaab6..a9da695a 100644 --- a/packages/utils/hooks/useNotification/index.tsx +++ b/packages/utils/hooks/useNotification/index.tsx @@ -11,16 +11,14 @@ import type { UseNotification } from './types' const createNotificationStore = () => createStore((set) => ({ ...INITIAL_NOTIFICATION_STATE, - sendSnack: (message, { type = 'success' } = {}) => - set({ message, type, open: true, shouldShowProgress: true }), - sendToast: (message, { type = 'success' } = {}) => - set({ message, type, open: true, shouldShowProgress: false }), - sendApiErrorToast: (error) => + sendToast: (message, { type = 'success', shouldShowProgress } = {}) => + set({ message, type, open: true, shouldShowProgress }), + sendApiErrorToast: (error, { shouldShowProgress } = {}) => set({ message: getApiErrorMessage(error), type: 'error', open: true, - shouldShowProgress: false, + shouldShowProgress, }), closeToast: () => set({ open: false }), })) diff --git a/packages/utils/hooks/useNotification/types.ts b/packages/utils/hooks/useNotification/types.ts index 9ecd6a85..6cca6ade 100644 --- a/packages/utils/hooks/useNotification/types.ts +++ b/packages/utils/hooks/useNotification/types.ts @@ -1,14 +1,16 @@ export type NotificationState = { open: boolean - shouldShowProgress: boolean + shouldShowProgress?: boolean message: string type: 'success' | 'info' | 'warning' | 'error' } type NotificationFunctions = { - sendSnack: (message: string, options?: { type?: NotificationState['type'] }) => void - sendToast: (message: string, options?: { type?: NotificationState['type'] }) => void - sendApiErrorToast: (error: unknown) => void + sendToast: ( + message: string, + options?: { type?: NotificationState['type']; shouldShowProgress?: boolean }, + ) => void + sendApiErrorToast: (error: unknown, options?: { shouldShowProgress?: boolean }) => void closeToast: () => void } From f44bb475f73c65080579a3924d2fd979ac19bcd7 Mon Sep 17 00:00:00 2001 From: Philipp Schmitt Date: Wed, 12 Feb 2025 16:12:53 +0100 Subject: [PATCH 5/5] BA-2205 Versioning --- packages/authentication/CHANGELOG.md | 7 +++++++ packages/authentication/package.json | 2 +- packages/components/CHANGELOG.md | 11 +++++++++++ packages/components/package.json | 2 +- packages/design-system/CHANGELOG.md | 8 ++++++++ packages/design-system/package.json | 2 +- packages/graphql/CHANGELOG.md | 7 +++++++ packages/graphql/package.json | 2 +- packages/provider/CHANGELOG.md | 7 +++++++ packages/provider/package.json | 2 +- packages/utils/CHANGELOG.md | 6 ++++++ packages/utils/package.json | 2 +- packages/wagtail/CHANGELOG.md | 9 +++++++++ packages/wagtail/package.json | 2 +- 14 files changed, 62 insertions(+), 7 deletions(-) diff --git a/packages/authentication/CHANGELOG.md b/packages/authentication/CHANGELOG.md index f5693432..b465a7dd 100644 --- a/packages/authentication/CHANGELOG.md +++ b/packages/authentication/CHANGELOG.md @@ -1,5 +1,12 @@ # @baseapp-frontend/authentication +## 4.1.6 + +### Patch Changes + +- Updated dependencies + - @baseapp-frontend/utils@3.1.5 + ## 4.1.5 ### Patch Changes diff --git a/packages/authentication/package.json b/packages/authentication/package.json index 69e8f8f1..8cfd0356 100644 --- a/packages/authentication/package.json +++ b/packages/authentication/package.json @@ -1,7 +1,7 @@ { "name": "@baseapp-frontend/authentication", "description": "Authentication modules.", - "version": "4.1.5", + "version": "4.1.6", "main": "./index.ts", "types": "dist/index.d.ts", "sideEffects": false, diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index c3581411..69c32231 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -1,5 +1,16 @@ # @baseapp-frontend/components +## 1.0.4 + +### Patch Changes + +- Implement a snackbar component with a 'progress bar' indicating the remaining time before it automatically disappears +- Updated dependencies + - @baseapp-frontend/design-system@1.0.4 + - @baseapp-frontend/utils@3.1.5 + - @baseapp-frontend/authentication@4.1.6 + - @baseapp-frontend/graphql@1.2.6 + ## 1.0.3 ### Patch Changes diff --git a/packages/components/package.json b/packages/components/package.json index ee75f9ab..c2f26263 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -1,7 +1,7 @@ { "name": "@baseapp-frontend/components", "description": "BaseApp components modules such as comments, notifications, messages, and more.", - "version": "1.0.3", + "version": "1.0.4", "sideEffects": false, "scripts": { "babel:bundle": "babel modules -d tmp-babel --extensions .ts,.tsx --ignore '**/__tests__/**','**/__storybook__/**'", diff --git a/packages/design-system/CHANGELOG.md b/packages/design-system/CHANGELOG.md index f445836d..a093e499 100644 --- a/packages/design-system/CHANGELOG.md +++ b/packages/design-system/CHANGELOG.md @@ -1,5 +1,13 @@ # @baseapp-frontend/design-system +## 1.0.4 + +### Patch Changes + +- Implement a snackbar component with a 'progress bar' indicating the remaining time before it automatically disappears +- Updated dependencies + - @baseapp-frontend/utils@3.1.5 + ## 1.0.3 ### Patch Changes diff --git a/packages/design-system/package.json b/packages/design-system/package.json index 5a487565..def0a90a 100644 --- a/packages/design-system/package.json +++ b/packages/design-system/package.json @@ -1,7 +1,7 @@ { "name": "@baseapp-frontend/design-system", "description": "Design System components and configurations.", - "version": "1.0.3", + "version": "1.0.4", "sideEffects": false, "scripts": { "tsup:bundle": "tsup --tsconfig tsconfig.build.json", diff --git a/packages/graphql/CHANGELOG.md b/packages/graphql/CHANGELOG.md index d86dfc36..c33ba43e 100644 --- a/packages/graphql/CHANGELOG.md +++ b/packages/graphql/CHANGELOG.md @@ -1,5 +1,12 @@ # @baseapp-frontend/graphql +## 1.2.6 + +### Patch Changes + +- Updated dependencies + - @baseapp-frontend/utils@3.1.5 + ## 1.2.5 ### Patch Changes diff --git a/packages/graphql/package.json b/packages/graphql/package.json index aadc1b4b..4569f7ba 100644 --- a/packages/graphql/package.json +++ b/packages/graphql/package.json @@ -1,7 +1,7 @@ { "name": "@baseapp-frontend/graphql", "description": "GraphQL configurations and utilities", - "version": "1.2.5", + "version": "1.2.6", "main": "./index.ts", "types": "dist/index.d.ts", "sideEffects": false, diff --git a/packages/provider/CHANGELOG.md b/packages/provider/CHANGELOG.md index 506ac931..2ed36f5e 100644 --- a/packages/provider/CHANGELOG.md +++ b/packages/provider/CHANGELOG.md @@ -1,5 +1,12 @@ # @baseapp-frontend/provider +## 2.0.12 + +### Patch Changes + +- Updated dependencies + - @baseapp-frontend/utils@3.1.5 + ## 2.0.11 ### Patch Changes diff --git a/packages/provider/package.json b/packages/provider/package.json index 47532d08..934f6214 100644 --- a/packages/provider/package.json +++ b/packages/provider/package.json @@ -1,7 +1,7 @@ { "name": "@baseapp-frontend/provider", "description": "Providers for React Query and Emotion.", - "version": "2.0.11", + "version": "2.0.12", "main": "./index.ts", "types": "dist/index.d.ts", "sideEffects": false, diff --git a/packages/utils/CHANGELOG.md b/packages/utils/CHANGELOG.md index bc05a007..a75eefe1 100644 --- a/packages/utils/CHANGELOG.md +++ b/packages/utils/CHANGELOG.md @@ -1,5 +1,11 @@ # @baseapp-frontend/utils +## 3.1.5 + +### Patch Changes + +- Implement a snackbar component with a 'progress bar' indicating the remaining time before it automatically disappears + ## 3.1.4 ### Patch Changes diff --git a/packages/utils/package.json b/packages/utils/package.json index cabd91e8..dc3ba04a 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,7 +1,7 @@ { "name": "@baseapp-frontend/utils", "description": "Util functions, constants and types.", - "version": "3.1.4", + "version": "3.1.5", "main": "./index.ts", "types": "dist/index.d.ts", "sideEffects": false, diff --git a/packages/wagtail/CHANGELOG.md b/packages/wagtail/CHANGELOG.md index 8b221dbc..01223382 100644 --- a/packages/wagtail/CHANGELOG.md +++ b/packages/wagtail/CHANGELOG.md @@ -1,5 +1,14 @@ # @baseapp-frontend/wagtail +## 1.0.22 + +### Patch Changes + +- Updated dependencies + - @baseapp-frontend/design-system@1.0.4 + - @baseapp-frontend/utils@3.1.5 + - @baseapp-frontend/graphql@1.2.6 + ## 1.0.21 ### Patch Changes diff --git a/packages/wagtail/package.json b/packages/wagtail/package.json index a95af40e..16f7596c 100644 --- a/packages/wagtail/package.json +++ b/packages/wagtail/package.json @@ -1,7 +1,7 @@ { "name": "@baseapp-frontend/wagtail", "description": "BaseApp Wagtail", - "version": "1.0.21", + "version": "1.0.22", "main": "./index.ts", "types": "dist/index.d.ts", "sideEffects": false,