-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[feat] Build nav column and header #51
Changes from all commits
d5ec9b5
27e6772
521e7c3
b06272f
d395efe
649119c
c97ec78
8f30101
c8a2dbd
560ec30
4035e4e
aabaf62
314d8f9
5857e04
0d59cb8
a456ad8
1da3ba6
7be8512
c90bede
4207588
c4b3720
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import React from 'react'; | ||
import Link from 'next/link'; | ||
import CONFIG from '@/lib/configs'; | ||
import { Flex } from '@/styles/containers'; | ||
import { useAuth } from '@/utils/AuthProvider'; | ||
import { useProfile } from '@/utils/ProfileProvider'; | ||
import Icon from '../Icon'; | ||
import { Container, HamburgerButton } from './styles'; | ||
|
||
interface HeaderProps { | ||
toggleNavColumn: () => void; | ||
} | ||
|
||
export default function Header({ toggleNavColumn }: HeaderProps) { | ||
const { profileReady, profileData } = useProfile(); | ||
const { userId, loading: authLoading } = useAuth(); | ||
|
||
const onNavColumnClick = () => { | ||
toggleNavColumn(); | ||
}; | ||
|
||
const AuthOrProfileButtons = () => { | ||
// If not (both profile and auth ready) | ||
if (authLoading || !profileReady) return <div></div>; | ||
|
||
// Logged-in user | ||
if (userId) { | ||
// Logged in AND onboarded | ||
// TODO: this should route to /my-account in the future | ||
if (profileData) { | ||
return <Icon type="profile" />; | ||
} | ||
|
||
// Not onboarded | ||
return <Link href={CONFIG.onboarding}>Complete Onboarding</Link>; | ||
} | ||
|
||
// Not logged-in user | ||
return ( | ||
<Flex $direction="row" $gap="8px" $w="max-content"> | ||
<Link href={CONFIG.login}>Login</Link> | ||
<Link href={CONFIG.signup}>Sign Up</Link> | ||
</Flex> | ||
); | ||
}; | ||
|
||
return ( | ||
<Container> | ||
<HamburgerButton onClick={onNavColumnClick}> | ||
<Icon type="hamburger" /> | ||
</HamburgerButton> | ||
<Link href={CONFIG.home}> | ||
<Icon type="logo" /> | ||
</Link> | ||
<AuthOrProfileButtons /> | ||
</Container> | ||
); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import styled from 'styled-components'; | ||
|
||
export const Container = styled.div` | ||
display: flex; | ||
justify-content: space-between; | ||
align-items: center; | ||
padding: 20px 24px 12px; | ||
z-index: 500; | ||
box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.1); | ||
`; | ||
|
||
export const HamburgerButton = styled.button` | ||
background: none; | ||
border: none; | ||
cursor: pointer; | ||
`; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
import React from 'react'; | ||
import Link from 'next/link'; | ||
import { usePathname, useRouter } from 'next/navigation'; | ||
import CONFIG from '@/lib/configs'; | ||
import { IconType } from '@/lib/icons'; | ||
import COLORS from '@/styles/colors'; | ||
import { Flex } from '@/styles/containers'; | ||
import { H4, P3 } from '@/styles/text'; | ||
import { UserTypeEnum } from '@/types/schema'; | ||
import { useAuth } from '@/utils/AuthProvider'; | ||
import { formatUserType } from '@/utils/helpers'; | ||
import { useProfile } from '@/utils/ProfileProvider'; | ||
import Icon from '../Icon'; | ||
import NavColumnItem from '../NavColumnItem'; | ||
import { | ||
HamburgerButton, | ||
HamburgerIcon, | ||
LoginButton, | ||
LoginButtonsContainer, | ||
NameAndStatus, | ||
NavColumnContainer, | ||
NavColumnHeader, | ||
NavLinksContainer, | ||
OnboardingButton, | ||
Overlay, | ||
Profile, | ||
ProfileDisplayContainer, | ||
ProfileIcon, | ||
SignOutButton, | ||
SignUpButton, | ||
} from './styles'; | ||
|
||
interface NavColumnProps { | ||
isOpen: boolean; | ||
onClose: () => void; | ||
} | ||
|
||
type NavLink = { | ||
name: string; | ||
path: string; | ||
iconName: IconType; | ||
}; | ||
|
||
const navLinks: NavLink[] = [ | ||
{ name: 'View Plants', path: CONFIG.viewPlants, iconName: 'plant' }, | ||
{ | ||
name: 'Planting Timeline', | ||
path: CONFIG.plantingTimeline, | ||
iconName: 'calendar', | ||
}, | ||
]; | ||
|
||
export default function NavColumn({ isOpen, onClose }: NavColumnProps) { | ||
const currentPath = usePathname(); | ||
const { signOut, userId, loading: authLoading } = useAuth(); | ||
const router = useRouter(); | ||
const { profileData, profileReady } = useProfile(); | ||
|
||
const handleSignOut = async () => { | ||
await signOut(); | ||
onClose(); | ||
router.push(CONFIG.login); | ||
}; | ||
|
||
const AuthOrProfileButtons = () => { | ||
const authAndProfileReady = profileReady && !authLoading; | ||
if (!authAndProfileReady) { | ||
return <div>Loading...</div>; | ||
} | ||
|
||
// Logged in Users | ||
if (userId) { | ||
// Logged in, not onboarded -> Go To Onboarding button | ||
// Logged in, Onboarded -> Show My Account Info | ||
return ( | ||
<ProfileDisplayContainer> | ||
{!profileData ? ( | ||
<OnboardingButton href={CONFIG.onboarding} onClick={onClose}> | ||
Go to Onboarding | ||
</OnboardingButton> | ||
) : ( | ||
<Profile> | ||
<ProfileIcon type="profile" /> | ||
<NameAndStatus> | ||
<H4 $color={COLORS.shrub} $fontWeight={300}> | ||
Your Account | ||
</H4> | ||
<P3 $color={COLORS.shrub} $fontWeight={300}> | ||
{formatUserType(profileData.user_type as UserTypeEnum)} | ||
</P3> | ||
</NameAndStatus> | ||
</Profile> | ||
)} | ||
<SignOutButton onClick={handleSignOut}>Sign Out</SignOutButton> | ||
</ProfileDisplayContainer> | ||
); | ||
} | ||
|
||
// Not logged -> Go to Auth Pages | ||
return ( | ||
<LoginButtonsContainer> | ||
<LoginButton href={CONFIG.login} onClick={onClose}> | ||
Log In | ||
</LoginButton> | ||
<SignUpButton href={CONFIG.signup} onClick={onClose}> | ||
Sign Up | ||
</SignUpButton> | ||
</LoginButtonsContainer> | ||
); | ||
}; | ||
|
||
return ( | ||
<> | ||
{isOpen && ( | ||
<> | ||
<Overlay onClick={onClose} $isOpen={isOpen} /> | ||
<NavColumnContainer> | ||
<div> | ||
<NavColumnHeader> | ||
<div> | ||
{/* empty whitespace for positioning logo and hamburger */} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. oooo i see what you're doing here! hmm... perhaps it would be cleaner if we made the Logo justify-self: center and the Hamburger Icon justify-self: flex-end or smth? but honestly this way is fine, so i'm ok w keeping it too! |
||
</div> | ||
<Link onClick={onClose} href={CONFIG.home}> | ||
<Icon type="logo" /> | ||
</Link> | ||
<HamburgerButton onClick={onClose}> | ||
<HamburgerIcon type="hamburger" /> | ||
</HamburgerButton> | ||
</NavColumnHeader> | ||
<NavLinksContainer> | ||
{navLinks.map((link: NavLink, key) => ( | ||
<NavColumnItem | ||
key={key} | ||
routeName={link.name} | ||
path={link.path} | ||
isSelected={currentPath === link.path} | ||
icon={link.iconName} | ||
onClose={onClose} | ||
/> | ||
))} | ||
</NavLinksContainer> | ||
</div> | ||
<Flex | ||
$direction="column" | ||
$pb="52px" | ||
$px="16px" | ||
$w="100%" | ||
$h="max-content" | ||
> | ||
<AuthOrProfileButtons /> | ||
</Flex> | ||
</NavColumnContainer> | ||
</> | ||
)} | ||
</> | ||
); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
import Link from 'next/link'; | ||
import styled from 'styled-components'; | ||
import COLORS from '@/styles/colors'; | ||
import Icon from '../Icon'; | ||
|
||
export const NavColumnContainer = styled.div` | ||
min-width: 289px; | ||
height: 100vh; | ||
background: ${COLORS.glimpse}; | ||
position: fixed; | ||
z-index: 1000; | ||
top: 0; | ||
left: 0; | ||
display: flex; | ||
flex-direction: column; | ||
transition: transform 1s ease-in-out; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fancy! do we want to make this a slightly longer transition? maybe to discuss w kyrene |
||
justify-content: space-between; | ||
`; | ||
|
||
export const Overlay = styled.div<{ $isOpen: boolean }>` | ||
position: fixed; | ||
top: 0; | ||
left: 0; | ||
width: 100vw; | ||
height: 100vh; | ||
background-color: rgba(0, 0, 0, 0.5); | ||
z-index: 999; | ||
display: ${({ $isOpen }) => ($isOpen ? 'block' : 'none')}; | ||
`; | ||
|
||
export const HamburgerButton = styled.button` | ||
background: none; | ||
border: none; | ||
cursor: pointer; | ||
color: ${COLORS.shrub}; | ||
justify-self: flex-end; | ||
`; | ||
|
||
// not working | ||
export const HamburgerIcon = styled(Icon)` | ||
fill: ${COLORS.shrub}; | ||
`; | ||
Comment on lines
+40
to
+42
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hm... i think kevin was able to do this before in the Review Onboarding PR - i'll try to link it soon |
||
|
||
export const NavColumnHeader = styled.div` | ||
display: grid; | ||
grid-template-columns: 1fr 1fr 1fr; | ||
align-items: center; | ||
padding: 24px 16px 12px; | ||
z-index: 1001; | ||
`; | ||
|
||
export const NavLinksContainer = styled.div` | ||
display: flex; | ||
flex-direction: column; | ||
gap: 4px; | ||
`; | ||
|
||
export const LoginButtonsContainer = styled.div` | ||
display: grid; | ||
grid-template-columns: 1fr 1fr; | ||
gap: 8px; | ||
`; | ||
|
||
export const LoginButton = styled(Link)` | ||
display: flex; | ||
justify-content: center; | ||
align-items: center; | ||
border-radius: 20px; | ||
border: 1px solid ${COLORS.shrub}; | ||
background-color: inherit; | ||
padding: 12px 0px 12px 0px; | ||
color: ${COLORS.shrub}; | ||
text-decoration: none; | ||
font-size: 0.875rem; | ||
`; | ||
|
||
export const SignUpButton = styled(Link)` | ||
display: flex; | ||
justify-content: center; | ||
align-items: center; | ||
border-radius: 20px; | ||
border: none; | ||
background-color: ${COLORS.shrub}; | ||
padding: 12px 0px 12px 0px; | ||
color: ${COLORS.glimpse}; | ||
text-decoration: none; | ||
font-size: 0.875rem; | ||
`; | ||
|
||
export const OnboardingButton = styled(Link)` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same here, eventually we can consolidate the button styles in |
||
display: flex; | ||
justify-content: center; | ||
align-items: center; | ||
border-radius: 20px; | ||
border: none; | ||
background-color: ${COLORS.shrub}; | ||
color: ${COLORS.glimpse}; | ||
text-decoration: none; | ||
font-size: 0.875rem; | ||
height: 40px; | ||
`; | ||
|
||
export const ProfileDisplayContainer = styled.div` | ||
display: flex; | ||
flex-direction: column; | ||
gap: 20px; | ||
`; | ||
|
||
export const Profile = styled.div` | ||
display: flex; | ||
flex-direction: row; | ||
gap: 16px; | ||
align-items: center; | ||
`; | ||
|
||
export const NameAndStatus = styled.div` | ||
display: flex; | ||
flex-direction: column; | ||
gap: 4px; | ||
`; | ||
|
||
export const SignOutButton = styled.button` | ||
display: flex; | ||
width: 100%; | ||
justify-content: center; | ||
align-items: center; | ||
border-radius: 20px; | ||
border: 1px solid ${COLORS.errorRed}; | ||
background-color: ${COLORS.glimpse}; | ||
padding: 12px 0px; | ||
color: ${COLORS.errorRed}; | ||
text-decoration: none; | ||
cursor: pointer; | ||
font-size: 0.875rem; | ||
`; | ||
|
||
export const ProfileIcon = styled(Icon)` | ||
min-height: 40px; | ||
min-width: 40px; | ||
`; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we might want to eventually consolidate all button styles and include them in components/Button.tsx. in this case, we could use a button that basically has no background, outline etc.