Skip to content

Commit

Permalink
Merge pull request #4 from spencer-rafada/spencer/add-navbar
Browse files Browse the repository at this point in the history
NAVBAR - Implement Navbar to Main Layout
  • Loading branch information
spencer-rafada authored Dec 28, 2023
2 parents 5e3bc57 + 593f7f8 commit 12873db
Show file tree
Hide file tree
Showing 16 changed files with 336 additions and 14 deletions.
3 changes: 2 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"extends": ["next/core-web-vitals", "prettier"],
"rules": {
"indent": ["error", 2],
"quotes": ["error", "single"]
"quotes": ["error", "single"],
"no-unused-vars": "error"
}
}
13 changes: 13 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"test:watch": "jest --watch"
},
"dependencies": {
"@chakra-ui/icons": "^2.1.1",
"@chakra-ui/next-js": "^2.2.0",
"@chakra-ui/react": "^2.8.2",
"@emotion/react": "^11.11.1",
Expand Down
46 changes: 46 additions & 0 deletions src/app/components/CTAButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
'use client'
import { Button } from '@chakra-ui/react'
import React, { useEffect, useState } from 'react'

export default function CTAButton({
type,
variant,
size,
colorScheme = 'brand',
}: {
type: string
variant: string
size: string
colorScheme: string
}) {
const [text, setText] = useState('')
const [url, setUrl] = useState('')

useEffect(() => {
if (type === 'cta_donate') {
setText('Donate Now')
}
}, [type])

useEffect(() => {
if (type === 'cta_donate') {
setUrl('https://www.paypal.com/donate/?hosted_button_id=WT7WGSCGNCF9U')
}
}, [type])

const onClick = () => {
window.open(url, '_blank')
}

return (
<Button
variant={variant}
size={size}
colorScheme={colorScheme}
onClick={onClick}
textTransform='uppercase'
>
{text || 'CTA Button'}
</Button>
)
}
62 changes: 62 additions & 0 deletions src/app/components/Navbar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
'use client'
import { Box, Flex, HStack, Text, useDisclosure } from '@chakra-ui/react'
import React, { useRef } from 'react'
import NavbarLinkToggle from './NavbarLinkToggle'
import NavbarLinks from './NavbarLinks'
import Link from 'next/link'
import CTAButton from './CTAButton'

const links = [
{ to: '/about', text: 'About Us' },
{ to: '/contact', text: 'Contact' },
{ to: '/projects', text: 'Our Projects' },
{ to: '/team', text: 'Team' },
]

export default function Navbar() {
const { isOpen, onOpen, onClose } = useDisclosure()
const btnRef = useRef<HTMLButtonElement | null>(null)

return (
<Flex
alignItems='center'
p={{ base: 4, md: 6 }}
justifyContent='space-between'
border='1px'
borderColor='gray.200'
bg='white'
boxShadow='md'
>
{/* Logo */}
<Box>
<Link href='/'>
<Text
fontSize={{ base: '1rem', md: '1.5rem' }}
fontWeight={700}
textTransform='uppercase'
color='brand.300'
>
Ray Foundation
</Text>
</Link>
</Box>
{/* Links */}
<HStack>
<CTAButton
type='cta_donate'
variant='solid'
size='md'
colorScheme='brand'
/>
<NavbarLinks
links={links}
isOpen={isOpen}
onClose={onClose}
btnRef={btnRef}
/>
{/* Toggle */}
<NavbarLinkToggle isOpen={isOpen} toggle={onOpen} btnRef={btnRef} />
</HStack>
</Flex>
)
}
13 changes: 13 additions & 0 deletions src/app/components/NavbarLink.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React from 'react'
import Link from 'next/link'
import { Button } from '@chakra-ui/react'

export default function NavbarLink({ to, text }: { to: string; text: string }) {
return (
<Link href={to}>
<Button fontSize={'1.1rem'} variant='ghost' colorScheme='brand'>
{text}
</Button>
</Link>
)
}
22 changes: 22 additions & 0 deletions src/app/components/NavbarLinkToggle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
'use client'
import { Box, Button } from '@chakra-ui/react'
import React, { RefObject } from 'react'
import { CloseIcon, HamburgerIcon } from '@chakra-ui/icons'

export default function NavbarLinkToggle({
isOpen,
toggle,
btnRef,
}: {
isOpen: boolean
toggle: () => void
btnRef: RefObject<HTMLButtonElement>
}) {
return (
<Box display={{ base: 'block', md: 'none' }}>
<Button onClick={toggle} ref={btnRef} variant='ghost' colorScheme='brand'>
{isOpen ? <CloseIcon /> : <HamburgerIcon />}
</Button>
</Box>
)
}
59 changes: 59 additions & 0 deletions src/app/components/NavbarLinks.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
'use client'
import React from 'react'
import {
Box,
Drawer,
DrawerBody,
DrawerCloseButton,
DrawerContent,
DrawerHeader,
DrawerOverlay,
Stack,
StackDivider,
} from '@chakra-ui/react'
import NavbarLink from './NavbarLink'

export default function NavbarLinks({
links,
isOpen,
onClose,
btnRef,
}: {
links: { to: string; text: string }[]
isOpen: boolean
onClose: () => void
btnRef: React.RefObject<HTMLButtonElement>
}) {
return (
<>
<Box display={{ base: 'none', md: 'block' }}>
<Stack direction={{ base: 'column', md: 'row' }}>
{links.map((link) => {
return <NavbarLink key={link.to} to={link.to} text={link.text} />
})}
</Stack>
</Box>
<Drawer
isOpen={isOpen}
placement='right'
onClose={onClose}
finalFocusRef={btnRef}
>
<DrawerOverlay />
<DrawerContent>
<DrawerCloseButton />
<DrawerHeader>Menu</DrawerHeader>
<DrawerBody>
<Stack divider={<StackDivider borderColor='gray.200' />}>
{links.map((link) => {
return (
<NavbarLink key={link.to} to={link.to} text={link.text} />
)
})}
</Stack>
</DrawerBody>
</DrawerContent>
</Drawer>
</>
)
}
29 changes: 29 additions & 0 deletions src/app/components/__tests__/CTAButton.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { screen, render } from '@testing-library/react'
import '@testing-library/jest-dom'
import CTAButton from '../CTAButton'
import React from 'react'

describe('CTAButton', () => {
it('should render the donate button', () => {
render(
<CTAButton
type='cta_donate'
variant='solid'
size='md'
colorScheme='brand'
/>
)
expect(screen.getByText('Donate Now')).toBeInTheDocument()
})
it('should render Button when type is incorrect', () => {
render(
<CTAButton
type='cta_test'
variant='solid'
size='md'
colorScheme='brand'
/>
)
expect(screen.getByText('CTA Button')).toBeInTheDocument()
})
})
15 changes: 15 additions & 0 deletions src/app/components/__tests__/Navbar.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { screen, render } from '@testing-library/react'
import '@testing-library/jest-dom'
import React from 'react'
import Navbar from '../Navbar'

describe('NavBar', () => {
it('should render the logo', () => {
render(<Navbar />)
expect(screen.getByText('Ray Foundation')).toBeInTheDocument()
})
it('should render the call to action button', () => {
render(<Navbar />)
expect(screen.getByText('Donate Now')).toBeInTheDocument()
})
})
12 changes: 12 additions & 0 deletions src/app/components/__tests__/NavbarLink.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { screen, render } from '@testing-library/react'
import '@testing-library/jest-dom'
import React from 'react'
import NavbarLink from '../NavbarLink'

describe('NavbarLink', () => {
it('should render the link', () => {
render(<NavbarLink to='/' text='Home' />)
expect(screen.getByText('Home')).toBeInTheDocument()
expect(screen.getByRole('link')).toHaveAttribute('href', '/')
})
})
18 changes: 18 additions & 0 deletions src/app/components/__tests__/NavbarLinkToggle.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { screen, render, fireEvent } from '@testing-library/react'
import '@testing-library/jest-dom'
import React from 'react'
import NavbarLinkToggle from '../NavbarLinkToggle'

describe('NavbarLinkToggle', () => {
it('should render the toggle button', () => {
render(<NavbarLinkToggle isOpen={true} toggle={jest.fn()} />)
expect(screen.getByRole('button')).toBeInTheDocument()
})
it('should call the toggle button when clicked', () => {
const toggle = jest.fn()
render(<NavbarLinkToggle isOpen={true} toggle={toggle} />)
expect(screen.getByRole('button')).toBeInTheDocument()
fireEvent.click(screen.getByRole('button'))
expect(toggle).toHaveBeenCalled()
})
})
33 changes: 33 additions & 0 deletions src/app/components/__tests__/NavbarLinks.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { screen, render } from '@testing-library/react'
import '@testing-library/jest-dom'
import React from 'react'
import NavbarLinks from '../NavbarLinks'

describe('NavbarLinks', () => {
it('should render one link if drawer is closed', () => {
render(
<NavbarLinks
links={[{ to: '/', text: 'Home' }]}
isOpen={false}
onClose={jest.fn()}
btnRef={React.createRef()}
/>
)
expect(screen.getByText('Home')).toBeInTheDocument()
})

it('should render two links if drawer is open', () => {
render(
<NavbarLinks
links={[
{ to: '/', text: 'Home' },
{ to: '/about', text: 'About' },
]}
isOpen={true}
onClose={jest.fn()}
btnRef={React.createRef()}
/>
)
expect(screen.getAllByText('Home')).toHaveLength(2)
})
})
12 changes: 6 additions & 6 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import type { Metadata } from 'next'
import { Inter } from 'next/font/google'
import './globals.css'
import ThemeProvider from './_providers/ThemeProvider'

const inter = Inter({ subsets: ['latin'] })
import Navbar from './components/Navbar'

export const metadata: Metadata = {
title: 'Ray Foundation',
Expand All @@ -17,8 +14,11 @@ export default function RootLayout({
}) {
return (
<html lang='en'>
<body className={inter.className}>
<ThemeProvider>{children}</ThemeProvider>
<body>
<ThemeProvider>
<Navbar></Navbar>
<section>{children}</section>
</ThemeProvider>
</body>
</html>
)
Expand Down
2 changes: 0 additions & 2 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import Image from 'next/image'

export default function Home() {
return <div>Ray Foundation</div>
}
Loading

0 comments on commit 12873db

Please sign in to comment.