From 5aa49399d04eecc4c515e05a0eef234d06698adb Mon Sep 17 00:00:00 2001 From: poduck Date: Wed, 3 Dec 2025 02:23:28 -0500 Subject: [PATCH] feat(help): Add floating help button to all pages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaced inline HelpButton components with a global FloatingHelpButton that appears fixed in the top-right corner of all pages. The button: - Automatically detects the current route and links to the appropriate help page - Uses a consistent position across all pages (fixed, top-right) - Is hidden on help pages themselves - Works on both business and platform layouts 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../src/components/FloatingHelpButton.tsx | 94 +++++++++++++++++++ frontend/src/layouts/BusinessLayout.tsx | 4 + frontend/src/layouts/PlatformLayout.tsx | 4 + frontend/src/pages/Customers.tsx | 10 +- frontend/src/pages/Dashboard.tsx | 19 ++-- frontend/src/pages/Services.tsx | 18 ++-- frontend/src/pages/Tasks.tsx | 18 ++-- 7 files changed, 125 insertions(+), 42 deletions(-) create mode 100644 frontend/src/components/FloatingHelpButton.tsx diff --git a/frontend/src/components/FloatingHelpButton.tsx b/frontend/src/components/FloatingHelpButton.tsx new file mode 100644 index 0000000..b0451f1 --- /dev/null +++ b/frontend/src/components/FloatingHelpButton.tsx @@ -0,0 +1,94 @@ +/** + * FloatingHelpButton Component + * + * A floating help button fixed in the top-right corner of the screen. + * Automatically determines the help path based on the current route. + */ + +import React from 'react'; +import { Link, useLocation } from 'react-router-dom'; +import { HelpCircle } from 'lucide-react'; +import { useTranslation } from 'react-i18next'; + +// Map routes to their help paths +const routeToHelpPath: Record = { + '/': '/help/dashboard', + '/dashboard': '/help/dashboard', + '/scheduler': '/help/scheduler', + '/tasks': '/help/tasks', + '/customers': '/help/customers', + '/services': '/help/services', + '/resources': '/help/resources', + '/staff': '/help/staff', + '/messages': '/help/messages', + '/tickets': '/help/ticketing', + '/payments': '/help/payments', + '/plugins': '/help/plugins', + '/plugins/marketplace': '/help/plugins', + '/plugins/my-plugins': '/help/plugins', + '/plugins/create': '/help/plugins/create', + '/settings': '/help/settings/general', + '/settings/general': '/help/settings/general', + '/settings/resource-types': '/help/settings/resource-types', + '/settings/booking': '/help/settings/booking', + '/settings/appearance': '/help/settings/appearance', + '/settings/email': '/help/settings/email', + '/settings/domains': '/help/settings/domains', + '/settings/api': '/help/settings/api', + '/settings/auth': '/help/settings/auth', + '/settings/billing': '/help/settings/billing', + '/settings/quota': '/help/settings/quota', + // Platform routes + '/platform/dashboard': '/help/dashboard', + '/platform/businesses': '/help/dashboard', + '/platform/users': '/help/staff', + '/platform/tickets': '/help/ticketing', +}; + +const FloatingHelpButton: React.FC = () => { + const { t } = useTranslation(); + const location = useLocation(); + + // Get the help path for the current route + const getHelpPath = (): string => { + // Exact match first + if (routeToHelpPath[location.pathname]) { + return routeToHelpPath[location.pathname]; + } + + // Try matching with a prefix (for dynamic routes like /customers/:id) + const pathSegments = location.pathname.split('/').filter(Boolean); + if (pathSegments.length > 0) { + // Try progressively shorter paths + for (let i = pathSegments.length; i > 0; i--) { + const testPath = '/' + pathSegments.slice(0, i).join('/'); + if (routeToHelpPath[testPath]) { + return routeToHelpPath[testPath]; + } + } + } + + // Default to the main help guide + return '/help'; + }; + + const helpPath = getHelpPath(); + + // Don't show on help pages themselves + if (location.pathname.startsWith('/help')) { + return null; + } + + return ( + + + + ); +}; + +export default FloatingHelpButton; diff --git a/frontend/src/layouts/BusinessLayout.tsx b/frontend/src/layouts/BusinessLayout.tsx index c762002..af3ab1f 100644 --- a/frontend/src/layouts/BusinessLayout.tsx +++ b/frontend/src/layouts/BusinessLayout.tsx @@ -9,6 +9,7 @@ import { Business, User } from '../types'; import MasqueradeBanner from '../components/MasqueradeBanner'; import OnboardingWizard from '../components/OnboardingWizard'; import TicketModal from '../components/TicketModal'; +import FloatingHelpButton from '../components/FloatingHelpButton'; import { useStopMasquerade } from '../hooks/useAuth'; import { useNotificationWebSocket } from '../hooks/useNotificationWebSocket'; import { useTicket } from '../hooks/useTickets'; @@ -167,6 +168,9 @@ const BusinessLayoutContent: React.FC = ({ business, user, return (
+ {/* Floating Help Button */} + +
{ }} />
diff --git a/frontend/src/layouts/PlatformLayout.tsx b/frontend/src/layouts/PlatformLayout.tsx index 8288a27..187a945 100644 --- a/frontend/src/layouts/PlatformLayout.tsx +++ b/frontend/src/layouts/PlatformLayout.tsx @@ -6,6 +6,7 @@ import PlatformSidebar from '../components/PlatformSidebar'; import UserProfileDropdown from '../components/UserProfileDropdown'; import NotificationDropdown from '../components/NotificationDropdown'; import TicketModal from '../components/TicketModal'; +import FloatingHelpButton from '../components/FloatingHelpButton'; import { useTicket } from '../hooks/useTickets'; import { useScrollToTop } from '../hooks/useScrollToTop'; @@ -36,6 +37,9 @@ const PlatformLayout: React.FC = ({ user, darkMode, toggleT return (
+ {/* Floating Help Button */} + + {/* Mobile menu */}
{ }} /> diff --git a/frontend/src/pages/Customers.tsx b/frontend/src/pages/Customers.tsx index 7715a16..72291f5 100644 --- a/frontend/src/pages/Customers.tsx +++ b/frontend/src/pages/Customers.tsx @@ -16,7 +16,6 @@ import { Eye } from 'lucide-react'; import Portal from '../components/Portal'; -import HelpButton from '../components/HelpButton'; interface CustomersProps { onMasquerade: (user: User) => void; @@ -126,12 +125,9 @@ const Customers: React.FC = ({ onMasquerade, effectiveUser }) => return (
-
-
-

{t('customers.title')}

-

{t('customers.description')}

-
- +
+

{t('customers.title')}

+

{t('customers.description')}