| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154 |
- import React, { createContext, useContext, useState, ReactNode, useEffect } from 'react';
- type PageType = 'home' | 'about' | 'blog' | 'careers' | 'privacy' | 'terms' | 'faq' | 'contact';
- interface RouterContextType {
- currentPage: PageType;
- navigateTo: (page: PageType, hash?: string) => void;
- }
- const RouterContext = createContext<RouterContextType | undefined>(undefined);
- // Map page types to URL paths
- const pageToPath: Record<PageType, string> = {
- home: '/',
- about: '/about',
- blog: '/blog',
- careers: '/careers',
- privacy: '/privacy',
- terms: '/terms',
- faq: '/faq',
- contact: '/contact',
- };
- // Map URL paths to page types
- const pathToPage: Record<string, PageType> = {
- '/': 'home',
- '/about': 'about',
- '/blog': 'blog',
- '/careers': 'careers',
- '/privacy': 'privacy',
- '/terms': 'terms',
- '/faq': 'faq',
- '/contact': 'contact',
- };
- // Helper function to scroll to an element with retry logic
- function scrollToElement(elementId: string, initialDelay: number = 150) {
- let attempts = 0;
- const maxAttempts = 10;
-
- const tryScroll = () => {
- const element = document.getElementById(elementId);
- if (element) {
- element.scrollIntoView({ behavior: 'smooth', block: 'start' });
- return true;
- }
- return false;
- };
-
- // Try immediately
- setTimeout(() => {
- if (!tryScroll()) {
- // If element not found, retry with increasing delays
- const retryInterval = setInterval(() => {
- attempts++;
- if (tryScroll() || attempts >= maxAttempts) {
- clearInterval(retryInterval);
- }
- }, 100);
- }
- }, initialDelay);
- }
- export function RouterProvider({ children }: { children: ReactNode }) {
- // Initialize page based on current URL path
- const getInitialPage = (): PageType => {
- const path = window.location.pathname;
- return pathToPage[path] || 'home';
- };
- const [currentPage, setCurrentPage] = useState<PageType>(getInitialPage);
-
- // Handle initial page load
- useEffect(() => {
- const pathname = window.location.pathname;
-
- // Ensure pathname is normalized
- if (pathname === '' || pathname === null) {
- window.history.replaceState({ page: 'home' }, '', '/');
- }
- }, []);
- const navigateTo = (page: PageType, hash?: string) => {
- setCurrentPage(page);
-
- const path = pageToPath[page];
- const url = hash ? `${path}#${hash}` : path;
-
- // Update browser URL without reloading
- window.history.pushState({ page }, '', url);
-
- if (hash) {
- // If there's a hash, scroll to the section
- scrollToElement(hash, 150);
- } else {
- window.scrollTo({ top: 0, behavior: 'smooth' });
- }
- };
- // Handle browser back/forward buttons
- useEffect(() => {
- const handlePopState = (event: PopStateEvent) => {
- const path = window.location.pathname;
- const page = pathToPage[path] || 'home';
- setCurrentPage(page);
-
- // Handle hash if present
- const hash = window.location.hash.replace('#', '');
- if (hash) {
- scrollToElement(hash);
- } else {
- window.scrollTo({ top: 0, behavior: 'smooth' });
- }
- };
- window.addEventListener('popstate', handlePopState);
-
- return () => {
- window.removeEventListener('popstate', handlePopState);
- };
- }, []);
- // Handle initial hash on page load (separate effect to run after render)
- useEffect(() => {
- const hash = window.location.hash.replace('#', '');
- if (hash) {
- // Use longer delay for initial page load to ensure all components are mounted
- scrollToElement(hash, 800);
- }
- }, [currentPage]);
-
- // Additional effect to handle hash on first mount
- useEffect(() => {
- const hash = window.location.hash.replace('#', '');
- if (hash) {
- // Extra attempt with even longer delay for slow network connections
- scrollToElement(hash, 1200);
- }
- }, []);
- return (
- <RouterContext.Provider value={{ currentPage, navigateTo }}>
- {children}
- </RouterContext.Provider>
- );
- }
- export function useRouter() {
- const context = useContext(RouterContext);
- if (context === undefined) {
- throw new Error('useRouter must be used within a RouterProvider');
- }
- return context;
- }
|