From 03ec7a8d9036f84473d9bbb6383a2261999ba00e Mon Sep 17 00:00:00 2001 From: Hemil Date: Thu, 28 Aug 2025 16:36:23 +0530 Subject: [PATCH 1/4] Add InfoDialog component and integrate with Redux for state management --- frontend/src/App.tsx | 3 ++ frontend/src/app/store.ts | 3 ++ frontend/src/components/Dialog/InfoDialog.tsx | 49 +++++++++++++++++++ frontend/src/features/infoDialogSlice.ts | 33 +++++++++++++ frontend/src/pages/SettingsPage/Settings.tsx | 7 +++ frontend/src/types/infoDialog.ts | 5 ++ 6 files changed, 100 insertions(+) create mode 100644 frontend/src/components/Dialog/InfoDialog.tsx create mode 100644 frontend/src/features/infoDialogSlice.ts create mode 100644 frontend/src/types/infoDialog.ts diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 62acd1c0c..c7f51fbff 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -5,10 +5,12 @@ 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 } = useSelector((state: RootState) => state.infoDialog); return ( @@ -16,6 +18,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..08e85bef9 --- /dev/null +++ b/frontend/src/components/Dialog/InfoDialog.tsx @@ -0,0 +1,49 @@ +import React from 'react'; +import { Info } 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 +}) => { + const dispatch = useDispatch(); + + const handleClose = () => { + dispatch(hideInfoDialog()); + }; + + return ( + { + if (!open) handleClose(); + }}> + + + + + {title} + + + {message} + + + + + + + + ); +}; diff --git a/frontend/src/features/infoDialogSlice.ts b/frontend/src/features/infoDialogSlice.ts new file mode 100644 index 000000000..51ac9dd74 --- /dev/null +++ b/frontend/src/features/infoDialogSlice.ts @@ -0,0 +1,33 @@ +import { createSlice, PayloadAction } from '@reduxjs/toolkit'; + +interface InfoDialogState { + isOpen: boolean; + title: string; + message: string; +} + +const initialState: InfoDialogState = { + isOpen: false, + title: '', + message: '', +}; + +const infoDialogSlice = createSlice({ + name: 'infoDialog', + initialState, + reducers: { + showInfoDialog(state, action: PayloadAction<{ title: string; message: string }>) { + state.isOpen = true; + state.title = action.payload.title; + state.message = action.payload.message; + }, + hideInfoDialog(state) { + state.isOpen = false; + state.title = ''; + state.message = ''; + }, + }, +}); + +export const { showInfoDialog, hideInfoDialog } = infoDialogSlice.actions; +export default infoDialogSlice.reducer; \ No newline at end of file diff --git a/frontend/src/pages/SettingsPage/Settings.tsx b/frontend/src/pages/SettingsPage/Settings.tsx index 61a7b400a..980b7216c 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,12 @@ 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.' + })); } dispatch(hideLoader()); }; diff --git a/frontend/src/types/infoDialog.ts b/frontend/src/types/infoDialog.ts new file mode 100644 index 000000000..de86c12c4 --- /dev/null +++ b/frontend/src/types/infoDialog.ts @@ -0,0 +1,5 @@ +export interface InfoDialogProps { + isOpen: boolean; + title: string; + message: string; +} From 67315f74a57b71b5bab836d26b4c1ac5ac28b0eb Mon Sep 17 00:00:00 2001 From: Hemil Date: Thu, 28 Aug 2025 18:08:08 +0530 Subject: [PATCH 2/4] Refactor code for improved readability and formatting in App, InfoDialog, and Settings components --- frontend/src/App.tsx | 6 ++++- frontend/src/components/Dialog/InfoDialog.tsx | 25 +++++++++---------- frontend/src/features/infoDialogSlice.ts | 7 ++++-- frontend/src/pages/SettingsPage/Settings.tsx | 11 +++++--- 4 files changed, 29 insertions(+), 20 deletions(-) diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index c7f51fbff..305a01635 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -10,7 +10,11 @@ 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 } = useSelector((state: RootState) => state.infoDialog); + const { + isOpen, + title, + message: infoMessage, + } = useSelector((state: RootState) => state.infoDialog); return ( diff --git a/frontend/src/components/Dialog/InfoDialog.tsx b/frontend/src/components/Dialog/InfoDialog.tsx index 08e85bef9..ce54e8ccb 100644 --- a/frontend/src/components/Dialog/InfoDialog.tsx +++ b/frontend/src/components/Dialog/InfoDialog.tsx @@ -1,12 +1,12 @@ import React from 'react'; import { Info } from 'lucide-react'; -import { +import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, - DialogFooter + DialogFooter, } from '@/components/ui/dialog'; import { Button } from '@/components/ui/button'; import { InfoDialogProps } from '@/types/infoDialog'; @@ -16,7 +16,7 @@ import { hideInfoDialog } from '@/features/infoDialogSlice'; export const InfoDialog: React.FC = ({ isOpen, title, - message + message, }) => { const dispatch = useDispatch(); @@ -25,23 +25,22 @@ export const InfoDialog: React.FC = ({ }; return ( - { - if (!open) handleClose(); - }}> + { + if (!open) handleClose(); + }} + > - + {title} - - {message} - + {message} - + diff --git a/frontend/src/features/infoDialogSlice.ts b/frontend/src/features/infoDialogSlice.ts index 51ac9dd74..26b3df75d 100644 --- a/frontend/src/features/infoDialogSlice.ts +++ b/frontend/src/features/infoDialogSlice.ts @@ -16,7 +16,10 @@ const infoDialogSlice = createSlice({ name: 'infoDialog', initialState, reducers: { - showInfoDialog(state, action: PayloadAction<{ title: string; message: string }>) { + showInfoDialog( + state, + action: PayloadAction<{ title: string; message: string }>, + ) { state.isOpen = true; state.title = action.payload.title; state.message = action.payload.message; @@ -30,4 +33,4 @@ const infoDialogSlice = createSlice({ }); export const { showInfoDialog, hideInfoDialog } = infoDialogSlice.actions; -export default infoDialogSlice.reducer; \ No newline at end of file +export default infoDialogSlice.reducer; diff --git a/frontend/src/pages/SettingsPage/Settings.tsx b/frontend/src/pages/SettingsPage/Settings.tsx index 980b7216c..d1410de3b 100644 --- a/frontend/src/pages/SettingsPage/Settings.tsx +++ b/frontend/src/pages/SettingsPage/Settings.tsx @@ -87,10 +87,13 @@ const Settings: React.FC = () => { 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.' - })); + dispatch( + showInfoDialog({ + title: 'No Updates Available', + message: + 'Your application is already up to date with the latest version.', + }), + ); } dispatch(hideLoader()); }; From 14e13047ca1deaea71cd8e534acd4aa5508ec393 Mon Sep 17 00:00:00 2001 From: Hemil Date: Thu, 28 Aug 2025 18:23:34 +0530 Subject: [PATCH 3/4] Enhance InfoDialog component with variant support for dynamic styling and update related state management --- frontend/src/App.tsx | 3 +- frontend/src/components/Dialog/InfoDialog.tsx | 29 +++++++++++-- frontend/src/features/infoDialogSlice.ts | 18 ++++---- frontend/src/pages/SettingsPage/Settings.tsx | 41 +++++++++++++++++-- frontend/src/types/infoDialog.ts | 3 ++ 5 files changed, 78 insertions(+), 16 deletions(-) diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 305a01635..38ddaa79c 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -14,6 +14,7 @@ const App: React.FC = () => { isOpen, title, message: infoMessage, + variant, } = useSelector((state: RootState) => state.infoDialog); return ( @@ -22,7 +23,7 @@ const App: React.FC = () => { - + ); diff --git a/frontend/src/components/Dialog/InfoDialog.tsx b/frontend/src/components/Dialog/InfoDialog.tsx index ce54e8ccb..7226aa9d5 100644 --- a/frontend/src/components/Dialog/InfoDialog.tsx +++ b/frontend/src/components/Dialog/InfoDialog.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Info } from 'lucide-react'; +import { Info, AlertTriangle } from 'lucide-react'; import { Dialog, DialogContent, @@ -17,6 +17,7 @@ export const InfoDialog: React.FC = ({ isOpen, title, message, + variant = 'info', }) => { const dispatch = useDispatch(); @@ -24,6 +25,24 @@ export const InfoDialog: React.FC = ({ 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 ( = ({ - + {icon} {title} - {message} + {message} - + diff --git a/frontend/src/features/infoDialogSlice.ts b/frontend/src/features/infoDialogSlice.ts index 26b3df75d..cd828ecce 100644 --- a/frontend/src/features/infoDialogSlice.ts +++ b/frontend/src/features/infoDialogSlice.ts @@ -1,15 +1,11 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit'; +import { InfoDialogProps, InfoDialogVariant } from '@/types/infoDialog'; -interface InfoDialogState { - isOpen: boolean; - title: string; - message: string; -} - -const initialState: InfoDialogState = { +const initialState: InfoDialogProps = { isOpen: false, title: '', message: '', + variant: 'info', }; const infoDialogSlice = createSlice({ @@ -18,16 +14,22 @@ const infoDialogSlice = createSlice({ reducers: { showInfoDialog( state, - action: PayloadAction<{ title: string; message: string }>, + 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'; }, }, }); diff --git a/frontend/src/pages/SettingsPage/Settings.tsx b/frontend/src/pages/SettingsPage/Settings.tsx index d1410de3b..162125b09 100644 --- a/frontend/src/pages/SettingsPage/Settings.tsx +++ b/frontend/src/pages/SettingsPage/Settings.tsx @@ -92,6 +92,7 @@ const Settings: React.FC = () => { title: 'No Updates Available', message: 'Your application is already up to date with the latest version.', + variant: 'info', }), ); } @@ -117,15 +118,38 @@ const Settings: React.FC = () => { setCurrentPaths([...currentPaths, ...newPaths]); await deleteCache(); }; + const testErrorDialog = () => { + dispatch( + showInfoDialog({ + title: 'Error Test', + message: 'This is a test error message to verify the error styling.', + variant: 'error', + }) + ); +}; const handleDeleteCache = async () => { try { 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', + }), + ); } }; @@ -144,10 +168,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, }); }; @@ -245,7 +280,7 @@ const Settings: React.FC = () => {

- + setErrorDialogContent(null)} diff --git a/frontend/src/types/infoDialog.ts b/frontend/src/types/infoDialog.ts index de86c12c4..342654375 100644 --- a/frontend/src/types/infoDialog.ts +++ b/frontend/src/types/infoDialog.ts @@ -1,5 +1,8 @@ +export type InfoDialogVariant = 'info' | 'error'; + export interface InfoDialogProps { isOpen: boolean; title: string; message: string; + variant?: InfoDialogVariant; } From 6ece99bb9fc2d6c221808615a2ff3f7448249ada Mon Sep 17 00:00:00 2001 From: Hemil Date: Thu, 28 Aug 2025 18:32:18 +0530 Subject: [PATCH 4/4] Remove test error dialog function and associated button from Settings component --- frontend/src/pages/SettingsPage/Settings.tsx | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/frontend/src/pages/SettingsPage/Settings.tsx b/frontend/src/pages/SettingsPage/Settings.tsx index 162125b09..7635c8745 100644 --- a/frontend/src/pages/SettingsPage/Settings.tsx +++ b/frontend/src/pages/SettingsPage/Settings.tsx @@ -118,15 +118,6 @@ const Settings: React.FC = () => { setCurrentPaths([...currentPaths, ...newPaths]); await deleteCache(); }; - const testErrorDialog = () => { - dispatch( - showInfoDialog({ - title: 'Error Test', - message: 'This is a test error message to verify the error styling.', - variant: 'error', - }) - ); -}; const handleDeleteCache = async () => { try { @@ -280,7 +271,6 @@ const Settings: React.FC = () => {

- setErrorDialogContent(null)}