11'use client' ;
22
3- import React , { useState , useEffect , Fragment } from 'react' ;
3+ import React , { useState , Fragment } from 'react' ;
44import Link from 'next/link' ;
55import type { Route } from 'next' ;
6- import { usePathname } from 'next/navigation' ;
76import { Dialog , Transition } from '@headlessui/react' ;
87import { BotSwitcher , SiteMenuDropdown } from '@/components/navigation' ;
98import { menuItems } from '@/data/menuItems' ;
10-
11- interface MenuItem {
12- id : string ;
13- label : string ;
14- icon ?: string ;
15- section ?: string ;
16- }
9+ import { useScrollNavigation , getNavColors } from '@/lib/hooks' ;
10+ import type { BotMenuItem } from '@/types/bot' ;
1711
1812interface BotNavigationProps {
1913 botSlug : string ;
2014 botTitle : string ;
2115 botEmoji : string ;
2216 botDescription ?: string ;
2317 accentColor ?: string ;
24- menuItems : MenuItem [ ] ;
18+ menuItems : BotMenuItem [ ] ;
2519 chatLink ?: string ;
2620 sections ?: boolean ;
2721}
2822
2923/**
3024 * Reusable navigation component for bot detail pages
25+ * Uses shared scroll navigation hook and centralized color config
3126 */
32- const BotNavigation : React . FC < BotNavigationProps > = ( {
27+ export const BotNavigation : React . FC < BotNavigationProps > = ( {
3328 botSlug,
3429 botTitle,
3530 botEmoji,
@@ -39,111 +34,28 @@ const BotNavigation: React.FC<BotNavigationProps> = ({
3934 chatLink,
4035 sections = true ,
4136} ) => {
42- const _pathname = usePathname ( ) ;
43- const [ activeSection , setActiveSection ] = useState ( '' ) ;
44- const [ lastScrollY , setLastScrollY ] = useState ( 0 ) ;
4537 const [ isMobileMenuOpen , setIsMobileMenuOpen ] = useState ( false ) ;
4638
39+ // Use shared scroll navigation hook
40+ const { activeSection, isScrolled, scrollToSection } = useScrollNavigation ( {
41+ menuItems : sectionMenuItems ,
42+ scrollOffset : 300 ,
43+ enabled : sections ,
44+ } ) ;
45+
4746 // Filter site nav items (exclude button items like "Contact Us")
4847 const siteNavItems = menuItems . filter ( item => ! item . isButton ) ;
4948
50- // Handle scroll events to highlight active section
51- useEffect ( ( ) => {
52- const handleScroll = ( ) => {
53- const currentScrollY = window . scrollY ;
54-
55- // Determine active section when sections are enabled
56- if ( sections ) {
57- const sectionIds = sectionMenuItems
58- . filter ( item => item . section )
59- . map ( item => item . section as string ) ;
60-
61- // Find which section is currently in view
62- const sectionElements = sectionIds
63- . map ( id => document . getElementById ( id ) )
64- . filter ( Boolean ) ;
65-
66- for ( let i = sectionElements . length - 1 ; i >= 0 ; i -- ) {
67- const section = sectionElements [ i ] ;
68- if ( section && section . getBoundingClientRect ( ) . top <= 300 ) {
69- setActiveSection ( section . id ) ;
70- break ;
71- }
72- }
73- }
74-
75- setLastScrollY ( currentScrollY ) ;
76- } ;
77-
78- window . addEventListener ( 'scroll' , handleScroll , { passive : true } ) ;
79- handleScroll ( ) ; // Initial check
80-
81- return ( ) => window . removeEventListener ( 'scroll' , handleScroll ) ;
82- } , [ lastScrollY , sectionMenuItems , sections ] ) ;
83-
84- // Handle smooth scrolling when clicking a menu item
85- const scrollToSection = ( sectionId : string | undefined ) => {
86- if ( ! sectionId ) return ;
87-
88- const element = document . getElementById ( sectionId ) ;
89- if ( element ) {
90- window . scrollTo ( {
91- top : element . offsetTop - 100 ,
92- behavior : 'smooth' ,
93- } ) ;
94- setActiveSection ( sectionId ) ;
95- // Close mobile menu after clicking
96- setIsMobileMenuOpen ( false ) ;
97- }
98- } ;
99-
100- const colorClasses = {
101- blue : {
102- logo : 'bg-blue-100' ,
103- title : 'text-blue-900' ,
104- active : 'text-blue-700 bg-blue-50' ,
105- hover : 'hover:text-blue-700 hover:bg-blue-50' ,
106- accent : 'bg-blue-600 hover:bg-blue-700' ,
107- border : 'border-blue-300' ,
108- } ,
109- green : {
110- logo : 'bg-green-100' ,
111- title : 'text-green-900' ,
112- active : 'text-green-700 bg-green-50' ,
113- hover : 'hover:text-green-700 hover:bg-green-50' ,
114- accent : 'bg-green-600 hover:bg-green-700' ,
115- border : 'border-green-300' ,
116- } ,
117- indigo : {
118- logo : 'bg-indigo-100' ,
119- title : 'text-indigo-900' ,
120- active : 'text-indigo-700 bg-indigo-50' ,
121- hover : 'hover:text-indigo-700 hover:bg-indigo-50' ,
122- accent : 'bg-indigo-600 hover:bg-indigo-700' ,
123- border : 'border-indigo-300' ,
124- } ,
125- red : {
126- logo : 'bg-red-100' ,
127- title : 'text-red-900' ,
128- active : 'text-red-700 bg-red-50' ,
129- hover : 'hover:text-red-700 hover:bg-red-50' ,
130- accent : 'bg-red-600 hover:bg-red-700' ,
131- border : 'border-red-300' ,
132- } ,
133- amber : {
134- logo : 'bg-amber-100' ,
135- title : 'text-amber-900' ,
136- active : 'text-amber-700 bg-amber-50' ,
137- hover : 'hover:text-amber-700 hover:bg-amber-50' ,
138- accent : 'bg-amber-600 hover:bg-amber-700' ,
139- border : 'border-amber-300' ,
140- } ,
49+ // Handle scroll to section with mobile menu close
50+ const handleScrollToSection = ( sectionId : string | undefined ) => {
51+ scrollToSection ( sectionId ) ;
52+ setIsMobileMenuOpen ( false ) ;
14153 } ;
14254
143- // Get the appropriate color classes or default to blue
144- const colors = colorClasses [ accentColor as keyof typeof colorClasses ] || colorClasses . blue ;
55+ // Get color classes from centralized config
56+ const colors = getNavColors ( accentColor ) ;
14557
146- const navClasses = lastScrollY > 100
58+ const navClasses = isScrolled
14759 ? 'bg-white shadow-md border-b border-gray-200'
14860 : 'bg-white border-b border-gray-200' ;
14961
@@ -152,9 +64,9 @@ const BotNavigation: React.FC<BotNavigationProps> = ({
15264 className = { `transition-all duration-300 w-full py-3 fixed top-0 left-0 right-0 z-50 ${ navClasses } ` }
15365 >
15466 < div className = "max-w-screen-xl mx-auto px-4 sm:px-6" >
155- < div className = "flex justify-between items-center" >
67+ < div className = "flex justify-between items-center h-12 " >
15668 { /* Left side: Botsmann logo + divider + Bot Switcher */ }
157- < div className = "flex items-center" >
69+ < div className = "flex items-center h-full " >
15870 { /* Botsmann 'B' logo - links to home */ }
15971 < Link
16072 href = "/"
@@ -181,7 +93,7 @@ const BotNavigation: React.FC<BotNavigationProps> = ({
18193 { sectionMenuItems . map ( item => (
18294 < button
18395 key = { item . id }
184- onClick = { ( ) => scrollToSection ( item . section ) }
96+ onClick = { ( ) => handleScrollToSection ( item . section ) }
18597 className = { `px-3 py-2 rounded-md text-sm font-medium transition-colors whitespace-nowrap flex items-center ${
18698 activeSection === item . section
18799 ? colors . active
@@ -333,7 +245,7 @@ const BotNavigation: React.FC<BotNavigationProps> = ({
333245 { sectionMenuItems . map ( item => (
334246 < button
335247 key = { item . id }
336- onClick = { ( ) => scrollToSection ( item . section ) }
248+ onClick = { ( ) => handleScrollToSection ( item . section ) }
337249 className = { `w-full text-left flex items-center px-3 py-2 rounded-md text-base font-medium transition-colors ${
338250 activeSection === item . section
339251 ? colors . active
@@ -371,4 +283,6 @@ const BotNavigation: React.FC<BotNavigationProps> = ({
371283 ) ;
372284} ;
373285
286+ // Named export for consistency with best practices
287+ // Default export kept for backwards compatibility with existing imports
374288export default BotNavigation ;
0 commit comments