diff --git a/src/app/settings/__tests__/page.test.tsx b/src/app/settings/__tests__/page.test.tsx
new file mode 100644
index 00000000..8e1430fc
--- /dev/null
+++ b/src/app/settings/__tests__/page.test.tsx
@@ -0,0 +1,32 @@
+import { render, screen, fireEvent, waitFor } from '@testing-library/react';
+import SettingsPage from '@/app/settings/page';
+import '@testing-library/jest-dom';
+
+// Mock the useUnsavedChangesGuard hook to control isDirty state.
+jest.mock('@/hooks/useUnsavedChangesGuard', () => ({
+ useUnsavedChangesGuard: jest.fn(() => ({ isDirty: false, resetBaseline: jest.fn() })),
+}));
+
+describe('SettingsPage unsaved changes UI', () => {
+ test('shows unsaved changes badge when dirty', async () => {
+ // Re-mock to return dirty after toggling.
+ const mockReset = jest.fn();
+ const useUnsavedChangesGuard = require('@/hooks/useUnsavedChangesGuard').useUnsavedChangesGuard;
+ useUnsavedChangesGuard.mockImplementation(() => ({ isDirty: true, resetBaseline: mockReset }));
+
+ render();
+ // The badge should be visible.
+ expect(screen.getByText('Unsaved changes')).toBeInTheDocument();
+ // Save button should be enabled.
+ const saveBtn = screen.getByRole('button', { name: /Save Preferences/i });
+ expect(saveBtn).toBeEnabled();
+ });
+
+ test('disables Save button when no changes', () => {
+ const useUnsavedChangesGuard = require('@/hooks/useUnsavedChangesGuard').useUnsavedChangesGuard;
+ useUnsavedChangesGuard.mockImplementation(() => ({ isDirty: false, resetBaseline: jest.fn() }));
+ render();
+ const saveBtn = screen.getByRole('button', { name: /Save Preferences/i });
+ expect(saveBtn).toBeDisabled();
+ });
+});
diff --git a/src/app/settings/page.tsx b/src/app/settings/page.tsx
index 4c313398..55b5cdf2 100644
--- a/src/app/settings/page.tsx
+++ b/src/app/settings/page.tsx
@@ -3,6 +3,7 @@
import React, { useState } from 'react'
import { NotificationSection } from '@/components/settings/NotificationSection'
import { NotificationToggle } from '@/components/settings/NotificationToggle'
+import { useUnsavedChangesGuard } from '@/hooks/useUnsavedChangesGuard';
import { AppShellLayout } from '@/components/shell/AppShellLayout'
import { AccountWalletSection } from '@/components/settings/AccountWalletSection'
import {
@@ -28,6 +29,7 @@ export default function SettingsPage() {
})
const [isSaving, setIsSaving] = useState(false)
+ const { isDirty, resetBaseline } = useUnsavedChangesGuard(preferences);
const [showSuccess, setShowSuccess] = useState(false)
const handleToggle = (key: keyof typeof preferences) => {
@@ -40,6 +42,7 @@ export default function SettingsPage() {
setTimeout(() => {
setIsSaving(false)
setShowSuccess(true)
+ resetBaseline();
setTimeout(() => setShowSuccess(false), 3000)
}, 1000)
}
@@ -69,6 +72,7 @@ export default function SettingsPage() {
Settings
+ {isDirty && Unsaved changes}
Manage your account, wallet, and notification preferences.
@@ -199,7 +203,7 @@ export default function SettingsPage() {