import React, { memo, useMemo, useEffect, useState } from "react"; import buyOutline from "app/assets/icons/navbar/buy-outline.svg"; import homeOutline from "app/assets/icons/navbar/home-outline.svg"; import profileOutline from "app/assets/icons/navbar/profile-outline.svg"; import searchOutline from "app/assets/icons/navbar/search-outline.svg"; import buyFilled from "app/assets/icons/navbar/buy-filled.svg"; import homeFilled from "app/assets/icons/navbar/home-filled.svg"; import profileFilled from "app/assets/icons/navbar/profile-filled.svg"; import searchFilled from "app/assets/icons/navbar/search-filled.svg"; import { Link, useLocation, useParams } from "@remix-run/react"; import { detectPage } from "~/utils/helpers"; import { useRootData } from "~/hooks/use-root-data"; import { useCartCount } from "~/requestHandler/use-cart-hooks"; import { useSellerOrderCount } from "~/requestHandler/use-order-hooks"; import settingIconFilled from "~/assets/icons/navbar/setting-filled.svg"; import settingIconOutline from "~/assets/icons/navbar/setting-outline.svg"; import documentFilled from "~/assets/icons/navbar/document-filled.svg"; import documentOutline from "~/assets/icons/navbar/document-outline.svg"; import productsFilled from "~/assets/icons/navbar/products-filled.svg"; import productsOutline from "~/assets/icons/navbar/products-outline.svg"; /** * Primary application layout component * Renders either mobile or desktop header based on screen size */ const MyLayout = React.memo(({ children }: { children: React.ReactNode }) => { const location = useLocation(); return (
{children} {location.pathname.split("threads")[1] ? ( <> ) : ( )}
); }); MyLayout.displayName = "Layout"; const MobileBottomNavigation = () => { const { theme } = useRootData(); const location = useLocation(); const currentPage = useMemo( () => detectPage(location?.pathname), [location?.pathname] ); const cartCount = useCartCount(); const { user } = useRootData(); const [isStoreMode, setIsStoreMode] = useState(false); const sellerOrderCount = useSellerOrderCount(!!isStoreMode); const [storeId, setStoreId] = useState(null); // Initialize state from sessionStorage on mount - only once useEffect(() => { if (typeof window === "undefined") return; const savedMode = sessionStorage.getItem("navigationMode"); const savedStoreId = sessionStorage.getItem("currentStoreId"); if (savedMode === "store" && savedStoreId) { setIsStoreMode(true); setStoreId(savedStoreId); } // eslint-disable-next-line react-hooks/exhaustive-deps }, []); const params = useParams(); // Function to determine page type const getPageType = useMemo(() => { const path = location.pathname; const mode = params.mode; // Store management pages const isStoreManagementPage = path.match(/^\/store\/[^/]+$/) || // Main store page: /store/{id} path.match(/^\/store\/[^/]+\/setting$/) || // Store settings: /store/{id}/setting path.match(/^\/store\/[^/]+\/orders/) || // Store orders: /store/{id}/orders path.match(/^\/store\/[^/]+\/shipping-method$/) || // Shipping method: /store/{id}/shipping-method path.match(/^\/store\/[^/]+\/financial-dashboard$/) || // Financial dashboard: /store/{id}/financial-dashboard path.match(/^\/store\/[^/]+\/financial-dashboard\/cash-funds$/) || // Financial dashboard: /store/{id}/financial-dashboard path.match(/^\/store\/[^/]+\/financial-dashboard\/transactions$/) || // Financial dashboard: /store/{id}/financial-dashboard path.match(/^\/store\/[^/]+\/financial-dashboard\/reports$/) || // Financial dashboard: /store/{id}/financial-dashboard path.match(/^\/store\/[^/]+\/products$/) || // Products list: /store/{id}/products path.match(/^\/store\/[^/]+\/product\/[^/]+$/) || // Product detail: /store/{id}/products/{id} path.match(/^\/store\/[^/]+\/edit$/) || // Edit store: /store/{id}/edit path.match(/^\/store\/add\/manual\/[^/]+$/) || // Add product: /store/add/manual/{id} path.match(/^\/store\/create$/) || // Create store: /store/create path.match(/^\/store\/authenticate\/instagram\/[^/]+$/) || // Instagram auth: /store/authenticate/instagram/{id} path.match(/^\/store\/[^/]+\/threads$/) || // Threads: /store/{id}/threads path.match(/^\/store\/[^/]+\/threads\/[^/]+$/); // Threads: /store/{id}/threads/{threadId} // Shared pages (should preserve current mode) const isSharedPage = path.match(/^\/explore$/) || // Explore page path.match(/^\/search\//) || // Search pages path.match(/^\/product\//) || // Product detail pages path.match(/^\/seller\/[^/]+$/); // Seller view pages (not management) // Regular user pages const isRegularPage = path.match(/^\/profile/) || // Profile pages path.match(/^\/cart/) || // Cart pages path.match(/^\/login$/) || // Login page path.match(/^\/logout$/) || // Logout page path === "/"; // Home page if (isStoreManagementPage || mode === "store") return "store"; if (isSharedPage) return "shared"; if (isRegularPage) return "regular"; return "regular"; // Default }, [location.pathname, params.mode]); // Update store mode based on current page useEffect(() => { const pageType = getPageType; const extractStoreId = (path: string): string | null => { let match; // Order matters here: more specific paths first. // Case: /store/add/manual/{id} match = path.match(/^\/store\/add\/manual\/([^/]+)/); if (match) return match[1]; // Case: /store/authenticate/instagram/{id} match = path.match(/^\/store\/authenticate\/instagram\/([^/]+)/); if (match) return match[1]; // Case: /store/{id}/* (e.g., /store/my-store/settings) match = path.match(/^\/store\/([^/]+)\//); if (match) return match[1]; // Case: /store/{id} (e.g., /store/my-store) match = path.match(/^\/store\/([^/]+)$/); if (match && match[1] !== "create") { return match[1]; } return null; }; if (pageType === "store") { // We're in store management - set store mode const currentStoreId = extractStoreId(location.pathname); if (currentStoreId) { setIsStoreMode((prev) => { if (!prev && typeof window !== "undefined") { sessionStorage.setItem("navigationMode", "store"); } return true; }); setStoreId((prev) => { if (prev !== currentStoreId && typeof window !== "undefined") { sessionStorage.setItem("currentStoreId", currentStoreId); } return currentStoreId; }); } else { // It's a store page without an ID, like /store/create. setIsStoreMode((prev) => { if (prev && typeof window !== "undefined") { sessionStorage.setItem("navigationMode", "regular"); sessionStorage.removeItem("currentStoreId"); } return false; }); setStoreId(null); } } else if (pageType === "regular") { // We're in regular user pages - set regular mode setIsStoreMode((prev) => { if (prev && typeof window !== "undefined") { sessionStorage.setItem("navigationMode", "regular"); sessionStorage.removeItem("currentStoreId"); } return false; }); setStoreId(null); // Clear store mode if user logs out if (location.pathname === "/logout" && typeof window !== "undefined") { sessionStorage.removeItem("navigationMode"); sessionStorage.removeItem("currentStoreId"); } } else if (pageType === "shared") { // We're in shared pages - preserve current mode (don't read from storage on every navigation) // State is already set from initial mount } }, [location.pathname, getPageType]); const navItems = useMemo(() => { if (isStoreMode) { // Store mode navigation return [ { link: `/store/${storeId}/setting`, icon: currentPage === "setting" ? theme === "dark" ? settingIconOutline : settingIconFilled : theme === "dark" ? settingIconFilled : settingIconOutline, }, { link: `/store/${storeId}/orders`, icon: currentPage === "orders" ? theme === "dark" ? documentOutline : documentFilled : theme === "dark" ? documentFilled : documentOutline, badge: sellerOrderCount > 0 && user?.access_token ? sellerOrderCount : null, }, { link: `/store/${storeId}/products`, icon: currentPage === "products" ? theme === "dark" ? productsOutline : productsFilled : theme === "dark" ? productsFilled : productsOutline, }, { link: `/store/${storeId}`, icon: currentPage === "store" ? theme === "dark" ? homeOutline : homeFilled : theme === "dark" ? homeFilled : homeOutline, }, ]; } else { // Normal mode navigation return [ { link: "/profile", icon: currentPage === "profile" ? theme === "dark" ? profileOutline : profileFilled : theme === "dark" ? profileFilled : profileOutline, }, { link: "/cart", icon: currentPage === "cart" ? theme === "dark" ? buyOutline : buyFilled : theme === "dark" ? buyFilled : buyOutline, badge: cartCount > 0 && user?.access_token ? cartCount : null, }, { link: "/explore", icon: currentPage === "explore" || currentPage === "search" ? theme === "dark" ? searchOutline : searchFilled : theme === "dark" ? searchFilled : searchOutline, }, { link: "/", icon: currentPage === "home" ? theme === "dark" ? homeOutline : homeFilled : theme === "dark" ? homeFilled : homeOutline, }, ]; } }, [ currentPage, cartCount, sellerOrderCount, user?.access_token, isStoreMode, storeId, theme, ]); return ( <>
{navItems.map((item) => ( {typeof item.icon === "string" ? ( {item.link} ) : ( item.icon )} {item.badge && ( {item.badge} )} ))}
); }; const LanguageToggle = memo( ({ onToggle, currentLanguage, }: { onToggle: () => Promise; currentLanguage: string; }) => ( ) ); LanguageToggle.displayName = "LanguageToggle"; export default MyLayout;