diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 62acd1c0c..38ddaa79c 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -5,10 +5,17 @@ import { AppRoutes } from '@/routes/AppRoutes'; import { ThemeProvider } from '@/contexts/ThemeContext'; import QueryClientProviders from '@/config/QueryClientProvider'; import { GlobalLoader } from './components/Loader/GlobalLoader'; +import { InfoDialog } from './components/Dialog/InfoDialog'; import { useSelector } from 'react-redux'; import { RootState } from './app/store'; const App: React.FC = () => { const { loading, message } = useSelector((state: RootState) => state.loader); + const { + isOpen, + title, + message: infoMessage, + variant, + } = useSelector((state: RootState) => state.infoDialog); return ( @@ -16,6 +23,7 @@ const App: React.FC = () => { + ); diff --git a/frontend/src/app/store.ts b/frontend/src/app/store.ts index d2849c5d8..4c4d02206 100644 --- a/frontend/src/app/store.ts +++ b/frontend/src/app/store.ts @@ -1,10 +1,13 @@ import { configureStore } from '@reduxjs/toolkit'; import loaderReducer from '@/features/loaderSlice'; import onboardingReducer from '@/features/onboardingSlice'; +import infoDialogReducer from '@/features/infoDialogSlice'; + export const store = configureStore({ reducer: { loader: loaderReducer, onboarding: onboardingReducer, + infoDialog: infoDialogReducer, }, }); diff --git a/frontend/src/components/Dialog/InfoDialog.tsx b/frontend/src/components/Dialog/InfoDialog.tsx new file mode 100644 index 000000000..7226aa9d5 --- /dev/null +++ b/frontend/src/components/Dialog/InfoDialog.tsx @@ -0,0 +1,69 @@ +import React from 'react'; +import { Info, AlertTriangle } from 'lucide-react'; +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle, + DialogFooter, +} from '@/components/ui/dialog'; +import { Button } from '@/components/ui/button'; +import { InfoDialogProps } from '@/types/infoDialog'; +import { useDispatch } from 'react-redux'; +import { hideInfoDialog } from '@/features/infoDialogSlice'; + +export const InfoDialog: React.FC = ({ + isOpen, + title, + message, + variant = 'info', +}) => { + const dispatch = useDispatch(); + + const handleClose = () => { + dispatch(hideInfoDialog()); + }; + + // Define styles and icons based on variant + const variantStyles = { + info: { + iconColor: 'text-primary', + messageColor: '', + icon: , + buttonVariant: 'default' as const, + }, + error: { + iconColor: 'text-destructive', + messageColor: 'text-destructive', + icon: , + buttonVariant: 'destructive' as const, + }, + }; + + const { icon, iconColor, messageColor, buttonVariant } = variantStyles[variant]; + + return ( + { + if (!open) handleClose(); + }} + > + + + + {icon} + {title} + + {message} + + + + + + + ); +}; diff --git a/frontend/src/features/infoDialogSlice.ts b/frontend/src/features/infoDialogSlice.ts new file mode 100644 index 000000000..cd828ecce --- /dev/null +++ b/frontend/src/features/infoDialogSlice.ts @@ -0,0 +1,38 @@ +import { createSlice, PayloadAction } from '@reduxjs/toolkit'; +import { InfoDialogProps, InfoDialogVariant } from '@/types/infoDialog'; + +const initialState: InfoDialogProps = { + isOpen: false, + title: '', + message: '', + variant: 'info', +}; + +const infoDialogSlice = createSlice({ + name: 'infoDialog', + initialState, + reducers: { + showInfoDialog( + state, + action: PayloadAction<{ + title: string; + message: string; + variant?: InfoDialogVariant; + }>, + ) { + state.isOpen = true; + state.title = action.payload.title; + state.message = action.payload.message; + state.variant = action.payload.variant || 'info'; + }, + hideInfoDialog(state) { + state.isOpen = false; + state.title = ''; + state.message = ''; + state.variant = 'info'; + }, + }, +}); + +export const { showInfoDialog, hideInfoDialog } = infoDialogSlice.actions; +export default infoDialogSlice.reducer; diff --git a/frontend/src/pages/SettingsPage/Settings.tsx b/frontend/src/pages/SettingsPage/Settings.tsx index 61a7b400a..7635c8745 100644 --- a/frontend/src/pages/SettingsPage/Settings.tsx +++ b/frontend/src/pages/SettingsPage/Settings.tsx @@ -17,6 +17,7 @@ import { usePictoMutation } from '@/hooks/useQueryExtensio'; import { useDispatch } from 'react-redux'; import { showLoader, hideLoader } from '@/features/loaderSlice'; +import { showInfoDialog } from '@/features/infoDialogSlice'; import { deleteFolder, @@ -84,6 +85,16 @@ const Settings: React.FC = () => { const hasUpdate = await checkForUpdates(); if (hasUpdate) { setUpdateDialogOpen(true); + } else { + // Show info dialog when no updates are available + dispatch( + showInfoDialog({ + title: 'No Updates Available', + message: + 'Your application is already up to date with the latest version.', + variant: 'info', + }), + ); } dispatch(hideLoader()); }; @@ -113,9 +124,23 @@ const Settings: React.FC = () => { const result = await deleteCache(); if (result) { console.log('Cache deleted'); + dispatch( + showInfoDialog({ + title: 'Cache Refreshed', + message: 'The application cache has been successfully refreshed.', + variant: 'info', + }), + ); } } catch (error) { console.error('Error deleting cache:', error); + dispatch( + showInfoDialog({ + title: 'Cache Refresh Error', + message: 'Failed to refresh the application cache. Please try again.', + variant: 'error', + }), + ); } }; @@ -134,10 +159,21 @@ const Settings: React.FC = () => { }; const showErrorDialog = (title: string, err: unknown) => { + const errorMessage = err instanceof Error ? err.message : 'An unknown error occurred'; + + // Use the InfoDialog with error variant for consistent UI + dispatch( + showInfoDialog({ + title, + message: errorMessage, + variant: 'error', + }), + ); + + // Also set the legacy error dialog content for backward compatibility setErrorDialogContent({ title, - description: - err instanceof Error ? err.message : 'An unknown error occurred', + description: errorMessage, }); }; @@ -235,7 +271,6 @@ const Settings: React.FC = () => {

- setErrorDialogContent(null)} diff --git a/frontend/src/types/infoDialog.ts b/frontend/src/types/infoDialog.ts new file mode 100644 index 000000000..342654375 --- /dev/null +++ b/frontend/src/types/infoDialog.ts @@ -0,0 +1,8 @@ +export type InfoDialogVariant = 'info' | 'error'; + +export interface InfoDialogProps { + isOpen: boolean; + title: string; + message: string; + variant?: InfoDialogVariant; +}