diff --git a/packages/ui/src/Footer.tsx b/apps/router/src/components/Footer.tsx similarity index 100% rename from packages/ui/src/Footer.tsx rename to apps/router/src/components/Footer.tsx diff --git a/apps/router/src/components/Header.tsx b/apps/router/src/components/Header.tsx new file mode 100644 index 000000000..d8f223772 --- /dev/null +++ b/apps/router/src/components/Header.tsx @@ -0,0 +1,31 @@ +import React from 'react'; +import { Flex } from '@chakra-ui/react'; +import { Logo } from './Logo'; +import { ServiceMenu } from './ServiceMenu'; +import { useActiveService } from '../hooks'; +import { useAppContext } from '../context/hooks'; + +export const Header = React.memo(function Header() { + const { guardians, gateways } = useAppContext(); + const { activeServiceId } = useActiveService(); + + const hasServices = + Object.keys(guardians).length > 0 || Object.keys(gateways).length > 0; + + return ( + + + {hasServices && ( + + )} + + ); +}); diff --git a/apps/router/src/components/Logo.tsx b/apps/router/src/components/Logo.tsx new file mode 100644 index 000000000..00aa66986 --- /dev/null +++ b/apps/router/src/components/Logo.tsx @@ -0,0 +1,42 @@ +import React from 'react'; +import { Flex } from '@chakra-ui/react'; + +export const Logo = () => ( + + + + + + + + + + + + + + +); diff --git a/apps/router/src/components/ServiceMenu.tsx b/apps/router/src/components/ServiceMenu.tsx new file mode 100644 index 000000000..14dc2799a --- /dev/null +++ b/apps/router/src/components/ServiceMenu.tsx @@ -0,0 +1,87 @@ +import React, { useState } from 'react'; +import { + Menu, + MenuButton, + MenuItem, + MenuList, + Button, + Text, +} from '@chakra-ui/react'; +import { FiMenu } from 'react-icons/fi'; +import { useNavigate } from 'react-router-dom'; +import { ServiceType, ServiceConfig } from '../types'; + +type ServiceMenuProps = { + guardians: Record; + gateways: Record; + activeServiceId: string | null; +}; + +export const ServiceMenu: React.FC = ({ + guardians, + gateways, + activeServiceId, +}) => { + const [isOpen, setIsOpen] = useState(false); + const navigate = useNavigate(); + + const handleServiceSelect = (type: ServiceType, id: string) => { + navigate(`/${type}/${id}`); + setIsOpen(false); + }; + + const renderServiceList = ( + services: Record, + type: ServiceType + ) => ( + <> + + {type === 'guardian' ? 'Guardians' : 'Gateways'} + + {Object.entries(services).map(([id, service]) => ( + + `${type}/${id}` !== activeServiceId && handleServiceSelect(type, id) + } + pl={4} + bg={`${type}/${id}` === activeServiceId ? 'blue.50' : 'transparent'} + _hover={{ + bg: `${type}/${id}` === activeServiceId ? 'blue.50' : 'gray.100', + }} + cursor={`${type}/${id}` === activeServiceId ? 'default' : 'pointer'} + > + {service.config.baseUrl} + + ))} + + ); + + return ( + setIsOpen(false)} + placement='bottom-end' + closeOnBlur={true} + > + } + size='md' + variant='outline' + onClick={() => setIsOpen(!isOpen)} + /> + + {Object.keys(guardians).length > 0 && + renderServiceList(guardians, 'guardian')} + {Object.keys(gateways).length > 0 && + renderServiceList(gateways, 'gateway')} + + + ); +}; diff --git a/packages/ui/src/Wrapper.tsx b/apps/router/src/components/Wrapper.tsx similarity index 85% rename from packages/ui/src/Wrapper.tsx rename to apps/router/src/components/Wrapper.tsx index 556281b9f..cec9b0801 100644 --- a/packages/ui/src/Wrapper.tsx +++ b/apps/router/src/components/Wrapper.tsx @@ -1,15 +1,13 @@ import React, { memo } from 'react'; import { Box, Flex, useBreakpointValue } from '@chakra-ui/react'; -import { Header, HeaderProps } from './Header'; +import { Header } from './Header'; import { Footer } from './Footer'; export interface WrapperProps { - headerProps?: HeaderProps; children: React.ReactNode; } export const Wrapper = memo(function Wrapper({ - headerProps, children, }: WrapperProps): JSX.Element { const size = useBreakpointValue({ base: 'md', lg: 'lg' }); @@ -30,7 +28,7 @@ export const Wrapper = memo(function Wrapper({ width='100%' alignItems='center' > -
+
{children}