Skip to content

Add InfoDialog component and integrate with Redux for state management#488

Merged
rahulharpal1603 merged 4 commits intoAOSSIE-Org:mainfrom
Hemil36:InfoDialog-Feature
Aug 29, 2025
Merged

Add InfoDialog component and integrate with Redux for state management#488
rahulharpal1603 merged 4 commits intoAOSSIE-Org:mainfrom
Hemil36:InfoDialog-Feature

Conversation

@Hemil36
Copy link
Copy Markdown
Contributor

@Hemil36 Hemil36 commented Aug 28, 2025

  • Fixes: Enhancement: Informing user that their app is "up to date" in settings page. #443
  • This pull request adds a reusable info dialog component to the frontend, allowing the application to display informational messages to users via a modal dialog. The main changes include introducing the InfoDialog component, implementing Redux state management for dialog visibility and content, and integrating the dialog into the app and settings page.

Info Dialog Feature Implementation

  • Added a new InfoDialog component in components/Dialog/InfoDialog.tsx that displays a modal with a title, message, and close button, using the Lucide React icon library and custom UI components.
  • Created a Redux slice in features/infoDialogSlice.ts to manage the dialog's open state, title, and message, with actions to show and hide the dialog.
  • Defined the InfoDialogProps interface in types/infoDialog.ts for type safety of dialog properties.

Integration with Application State

  • Registered the new infoDialog reducer in the Redux store (app/store.ts) and connected its state to the main App component, rendering the dialog when appropriate.

Usage Example

Screen.Recording.2025-08-28.164836.mp4
  • Updated the settings page (pages/SettingsPage/Settings.tsx) to show the info dialog when no updates are available, providing user feedback.

Summary by CodeRabbit

  • New Features

    • Added a global Info dialog with "info" and "error" variants for consistent, dismissible messages.
    • Integrated the dialog into the app so success, info, and error messages appear centrally.
  • Settings

    • Shows "No Updates Available" when up-to-date and surfaces cache refresh success/failure via the Info dialog.
  • Other

    • Unified success/error messaging flow to use the new dialog consistently.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Aug 28, 2025

Walkthrough

Adds a Redux-controlled global InfoDialog component (with 'info'/'error' variants), registers an infoDialog slice in the store, mounts the dialog in the app shell, and dispatches it from Settings for update-check, cache, and error flows.

Changes

Cohort / File(s) Summary
Redux slice + store integration
frontend/src/features/infoDialogSlice.ts, frontend/src/app/store.ts
Adds infoDialog slice with state { isOpen, title, message, variant }, actions showInfoDialog / hideInfoDialog, and registers reducer under infoDialog in the root store (RootState extended).
Dialog component + types
frontend/src/components/Dialog/InfoDialog.tsx, frontend/src/types/infoDialog.ts
New InfoDialog React component (props: isOpen,title,message,variant?) using Dialog primitives; variant-aware icon, colors, and button styling; dispatches hideInfoDialog on close. Adds InfoDialogVariant type and updates InfoDialogProps.
App-level mounting
frontend/src/App.tsx
Selects isOpen, title, message (aliased as infoMessage) and variant from state.infoDialog and renders <InfoDialog isOpen={isOpen} title={title} message={infoMessage} variant={variant} />.
Settings integration & usages
frontend/src/pages/SettingsPage/Settings.tsx
Uses showInfoDialog to notify "No Updates Available", cache refresh success/error, and funnels errors through showInfoDialog with variant 'error'.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    actor User
    participant Settings as SettingsPage
    participant Store as Redux Store\n(infoDialog slice)
    participant App as App Shell
    participant Dialog as InfoDialog

    User->>Settings: Click "Check for Updates"
    Settings->>Settings: perform update check
    alt No updates
        Settings->>Store: dispatch showInfoDialog({title, message, variant:'info'})
        Store-->>App: state.infoDialog updated (isOpen=true)
        App->>Dialog: Render with isOpen=true, title, message, variant
        User->>Dialog: Click "Close"
        Dialog->>Store: dispatch hideInfoDialog()
        Store-->>App: state.infoDialog updated (isOpen=false)
        App-->>Dialog: Unmount/close
    else Updates available
        Settings->>Settings: open existing UpdateDialog
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Assessment against linked issues

Objective Addressed Explanation
Create a global Info Dialog component controlled by Redux [#443]
Use standard ShadCN Dialog components similar to UpdateDialog [#443]
Integrate: On Settings “Check for Updates” with no updates, show “up to date” dialog [#443]

Poem

I hop with joy, a dialog in tow,
"You're up to date!" the message will show.
Redux burrows deep, states tidy and bright,
Error or info — the icon's just right.
Close with a click — onward I go 🥕✨

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbit in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbit in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbit gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbit read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbit help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbit ignore or @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbit summary or @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbit or @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
frontend/src/pages/SettingsPage/Settings.tsx (1)

82-96: Hide loader on failure and surface errors.

If checkForUpdates() throws, loader remains visible and users get no feedback. Wrap in try/catch/finally.

Apply:

-  const onCheckUpdatesClick = () => {
-    let checkUpdates = async () => {
-      dispatch(showLoader('Checking for updates...'));
-      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());
-    };
-    checkUpdates();
-  };
+  const onCheckUpdatesClick = async () => {
+    dispatch(showLoader('Checking for updates...'));
+    try {
+      const hasUpdate = await checkForUpdates();
+      if (hasUpdate) {
+        setUpdateDialogOpen(true);
+      } else {
+        dispatch(showInfoDialog({
+          title: 'No Updates Available',
+          message: 'Your application is already up to date with the latest version.'
+        }));
+      }
+    } catch (err) {
+      showErrorDialog('Update check failed', err);
+    } finally {
+      dispatch(hideLoader());
+    }
+  };
🧹 Nitpick comments (7)
frontend/src/features/infoDialogSlice.ts (2)

24-28: Reset state via return to avoid field-by-field clearing.

Returning a fresh copy of initialState is simpler and less error-prone if fields grow.

Apply:

-    hideInfoDialog(state) {
-      state.isOpen = false;
-      state.title = '';
-      state.message = '';
-    },
+    hideInfoDialog() {
+      return { ...initialState };
+    },

3-7: Export the state interface for reuse in selectors/tests.

Helps consumers type state without importing from component props.

-interface InfoDialogState {
+export interface InfoDialogState {
   isOpen: boolean;
   title: string;
   message: string;
 }
frontend/src/App.tsx (1)

8-8: Optionally lazy-load InfoDialog to trim initial bundle.

The dialog shows infrequently; defer its code until needed.

-import { InfoDialog } from './components/Dialog/InfoDialog';
+const InfoDialog = React.lazy(() =>
+  import('./components/Dialog/InfoDialog').then(m => ({ default: m.InfoDialog }))
+);
-        <InfoDialog isOpen={isOpen} title={title} message={infoMessage} />
+        <React.Suspense fallback={null}>
+          <InfoDialog isOpen={isOpen} title={title} message={infoMessage} />
+        </React.Suspense>

Also applies to: 21-21

frontend/src/components/Dialog/InfoDialog.tsx (4)

42-44: Prevent accidental form submit and improve a11y on Close button.

Add type="button" and an explicit aria-label.

-          <Button onClick={handleClose}>
+          <Button type="button" onClick={handleClose} aria-label="Close information dialog">
             Close
           </Button>

37-39: Allow richer message content (lists/links) by widening message to ReactNode.

Current string limits reusability. Switching to ReactNode keeps safety (React escapes strings) and flexibility.

Update the type (outside this file):

// frontend/src/types/infoDialog.ts
export interface InfoDialogProps {
  isOpen: boolean;
  title: string;
  message: React.ReactNode;
}

No changes required here; JSX already supports nodes.


31-46: Testing hook: add stable selectors to ease RTL/E2E tests.

Optional but helpful for asserting title/message and dispatch on close.

-      <DialogContent className="sm:max-w-md">
+      <DialogContent className="sm:max-w-md" data-testid="info-dialog">
...
-          <Button type="button" onClick={handleClose} aria-label="Close information dialog">
+          <Button type="button" onClick={handleClose} aria-label="Close information dialog" data-testid="info-dialog-close">

13-14: Use typed Redux dispatch in InfoDialog.tsx
Import AppDispatch from @/app/store and apply it to useDispatch for compile-time safety:

 import { useDispatch } from 'react-redux';
 import { hideInfoDialog } from '@/features/infoDialogSlice';
+import type { AppDispatch } from '@/app/store';-  const dispatch = useDispatch();
+  const dispatch = useDispatch<AppDispatch>();

AppDispatch is already exported in frontend/src/app/store.ts (line 17).

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between f70f2f7 and 03ec7a8.

📒 Files selected for processing (6)
  • frontend/src/App.tsx (1 hunks)
  • frontend/src/app/store.ts (1 hunks)
  • frontend/src/components/Dialog/InfoDialog.tsx (1 hunks)
  • frontend/src/features/infoDialogSlice.ts (1 hunks)
  • frontend/src/pages/SettingsPage/Settings.tsx (2 hunks)
  • frontend/src/types/infoDialog.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
frontend/src/App.tsx (2)
frontend/src/app/store.ts (1)
  • RootState (15-15)
frontend/src/components/Dialog/InfoDialog.tsx (1)
  • InfoDialog (16-49)
frontend/src/pages/SettingsPage/Settings.tsx (1)
frontend/src/features/infoDialogSlice.ts (1)
  • showInfoDialog (19-23)
frontend/src/components/Dialog/InfoDialog.tsx (2)
frontend/src/types/infoDialog.ts (1)
  • InfoDialogProps (1-5)
frontend/src/features/infoDialogSlice.ts (1)
  • hideInfoDialog (24-28)
🔇 Additional comments (6)
frontend/src/features/infoDialogSlice.ts (1)

19-23: Solid, minimal Redux state for the dialog.

Payload is typed and the state remains fully serializable. No concerns.

frontend/src/App.tsx (1)

13-21: Integration looks correct and non-intrusive.

State is selected and passed to InfoDialog as props; placement alongside GlobalLoader is appropriate.

frontend/src/app/store.ts (1)

4-11: Reducer registration is correct.

infoDialog is added under a clear key; RootState inference updates automatically.

frontend/src/types/infoDialog.ts (1)

1-5: Props shape is clear and aligns with usage.

No changes required now.

frontend/src/pages/SettingsPage/Settings.tsx (1)

88-93: Good UX: show info dialog when app is up to date.

Message/title are concise and user-friendly.

frontend/src/components/Dialog/InfoDialog.tsx (1)

27-49: Well-structured, accessible dialog; control flow looks solid.

Controlled open state, close-on-overlay/ESC via onOpenChange, and explicit Close button are all correct and align with the PR objectives.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
frontend/src/pages/SettingsPage/Settings.tsx (1)

82-101: Ensure loader is always cleared; handle update-check failures

If checkForUpdates() throws, the loader remains visible and users get no feedback. Wrap in try/catch/finally and surface an error dialog.

Apply:

-  let checkUpdates = async () => {
-    dispatch(showLoader('Checking for updates...'));
-    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());
-  };
-  checkUpdates();
+  const checkUpdates = async () => {
+    dispatch(showLoader('Checking for updates...'));
+    try {
+      const hasUpdate = await checkForUpdates();
+      if (hasUpdate) {
+        setUpdateDialogOpen(true);
+      } else {
+        dispatch(
+          showInfoDialog({
+            title: 'No Updates Available',
+            message:
+              'Your application is already up to date with the latest version.',
+          }),
+        );
+      }
+    } catch (err) {
+      showErrorDialog('Update Check Failed', err);
+    } finally {
+      dispatch(hideLoader());
+    }
+  };
+  void checkUpdates();

Also optional: the slice defaults variant to 'info', so passing it is redundant.

🧹 Nitpick comments (4)
frontend/src/pages/SettingsPage/Settings.tsx (4)

121-129: Don’t ship test-only dialog behavior to prod

Guard the test helper to no-op in production.

 const testErrorDialog = () => {
+  if (isProd()) return;
   dispatch(
     showInfoDialog({
       title: 'Error Test',
       message: 'This is a test error message to verify the error styling.',
       variant: 'error',
     })
   );
 };

136-142: Minor: drop explicit variant: 'info'

The slice sets 'info' by default; keep payload minimal.

       showInfoDialog({
         title: 'Cache Refreshed',
         message: 'The application cache has been successfully refreshed.',
-        variant: 'info',
       }),

146-152: Reuse centralized error handler for cache failures

Leverage showErrorDialog to propagate real error messages consistently.

-      dispatch(
-        showInfoDialog({
-          title: 'Cache Refresh Error',
-          message: 'Failed to refresh the application cache. Please try again.',
-          variant: 'error',
-        }),
-      );
+      showErrorDialog('Cache Refresh Error', error);

283-283: Hide “Test Error Dialog” button in production

Prevent exposing internal test controls to end users.

-      <Button onClick={testErrorDialog}>Test Error Dialog</Button>
+      {!isProd() && <Button onClick={testErrorDialog}>Test Error Dialog</Button>}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 67315f7 and 14e1304.

📒 Files selected for processing (5)
  • frontend/src/App.tsx (1 hunks)
  • frontend/src/components/Dialog/InfoDialog.tsx (1 hunks)
  • frontend/src/features/infoDialogSlice.ts (1 hunks)
  • frontend/src/pages/SettingsPage/Settings.tsx (5 hunks)
  • frontend/src/types/infoDialog.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • frontend/src/types/infoDialog.ts
  • frontend/src/App.tsx
  • frontend/src/components/Dialog/InfoDialog.tsx
  • frontend/src/features/infoDialogSlice.ts
🧰 Additional context used
🧬 Code graph analysis (1)
frontend/src/pages/SettingsPage/Settings.tsx (2)
frontend/src/features/infoDialogSlice.ts (1)
  • showInfoDialog (15-27)
frontend/src/services/cacheService.ts (1)
  • deleteCache (3-11)
🔇 Additional comments (1)
frontend/src/pages/SettingsPage/Settings.tsx (1)

20-20: Import looks correct

Redux action import aligns with the new slice API.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (4)
frontend/src/pages/SettingsPage/Settings.tsx (4)

7-7: Delete unused legacy ErrorDialog import.
Now redundant after switching to InfoDialog.

- import ErrorDialog from '@/components/Album/Error';

43-46: Remove unused errorDialogContent state.
No longer needed once legacy dialog is removed.

-  const [errorDialogContent, setErrorDialogContent] = useState<{
-    title: string;
-    description: string;
-  } | null>(null);

274-277: Remove <ErrorDialog /> render block.
Prevents two dialogs and dead UI paths.

-      <ErrorDialog
-        content={errorDialogContent}
-        onClose={() => setErrorDialogContent(null)}
-      />

173-177: Remove legacy ErrorDialog state update to avoid double modals.
This keeps two dialog systems in play; drop the legacy path.

-    // Also set the legacy error dialog content for backward compatibility
-    setErrorDialogContent({
-      title,
-      description: errorMessage,
-    });
🧹 Nitpick comments (3)
frontend/src/pages/SettingsPage/Settings.tsx (3)

104-121: Deduplicate new paths before merge to prevent accidental duplicates.
Covers the case where newPaths contains internal duplicates.

-  const handleFolderPathChange = async (newPaths: string[]) => {
-    const duplicatePaths = newPaths.filter((path) =>
-      currentPaths.includes(path),
-    );
+  const handleFolderPathChange = async (newPaths: string[]) => {
+    const uniqueNewPaths = Array.from(new Set(newPaths));
+    const duplicatePaths = uniqueNewPaths.filter((path) =>
+      currentPaths.includes(path),
+    );
     if (duplicatePaths.length > 0) {
       showErrorDialog(
         'Duplicate Paths',
         new Error(
           `The following paths are already selected: ${duplicatePaths.join(', ')}`,
         ),
       );
       return;
     }
-    generateThumbnailsAPI([...currentPaths, ...newPaths]);
-    setCurrentPaths([...currentPaths, ...newPaths]);
+    const mergedPaths = [...currentPaths, ...uniqueNewPaths];
+    generateThumbnailsAPI(mergedPaths);
+    setCurrentPaths(mergedPaths);
     await deleteCache();
   };

258-261: Use onChange for controlled checkbox; avoid stale state flips.
React convention and clearer intent.

-              onClick={() => {
-                setCheck(!check);
-                setAutoFolder(check ? 'false' : 'true');
-              }}
+              onChange={(e) => {
+                const next = e.currentTarget.checked;
+                setCheck(next);
+                setAutoFolder(next ? 'true' : 'false');
+              }}

295-295: Simplify boolean expression.

-        showCloseButton={false || !isDownloading}
+        showCloseButton={!isDownloading}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 14e1304 and 6ece99b.

📒 Files selected for processing (1)
  • frontend/src/pages/SettingsPage/Settings.tsx (4 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
frontend/src/pages/SettingsPage/Settings.tsx (1)
frontend/src/features/infoDialogSlice.ts (1)
  • showInfoDialog (15-27)
🔇 Additional comments (5)
frontend/src/pages/SettingsPage/Settings.tsx (5)

20-20: InfoDialog slice import — good integration.
Import aligns with the slice API; consistent with Redux wiring noted in the PR.


127-133: LGTM: success path uses InfoDialog (info).
Consistent UX for cache refresh confirmations.


137-143: LGTM: error path uses InfoDialog (error).
Clear user feedback on cache failures.


162-172: Good: centralized error presentation via InfoDialog.
Error message extraction and dispatch look correct.


16-16: Ignore typo warning: the file frontend/src/hooks/useQueryExtensio.ts exists and exports usePictoMutation, so the import is valid.

Likely an incorrect or invalid review comment.

@rahulharpal1603
Copy link
Copy Markdown
Contributor

LGTM! Thanks @Hemil36

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Enhancement: Informing user that their app is "up to date" in settings page.

2 participants