-
Notifications
You must be signed in to change notification settings - Fork 582
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add Sign-out functionality (#46)
#37 implemented the Sign-_in_ flow, but there wasn't a Sign-_out_ flow as part of that PR (aside from letting the cookie expire... or manually deleting the cookie...), which is obviously not ideal. This PR implements a basic sign-out flow, along with a very simple user dropdown: ![2022-01-21 18 09 14](https://user-images.githubusercontent.com/88213859/150620847-94e4d22f-1dcf-451e-8b4a-cec24702ea6c.gif) Bringing in a few pruned down components for the `<UserDropdown />` to integrate into the `<NavBar />`. In addition, this also implements a simple back-end API for `/logout` which just clears the session token.
- Loading branch information
1 parent
a44056c
commit 69d88b4
Showing
20 changed files
with
414 additions
and
25 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import SvgIcon, { SvgIconProps } from "@material-ui/core/SvgIcon" | ||
import React from "react" | ||
|
||
export const LogoutIcon = (props: SvgIconProps): JSX.Element => ( | ||
<SvgIcon {...props} viewBox="0 0 20 20"> | ||
<path | ||
fillRule="evenodd" | ||
clipRule="evenodd" | ||
d="M3.92523 18.5071H11.2169C11.8878 18.5063 12.4314 17.9626 12.4322 17.2918V15.4689H11.2169V17.2918H3.92523V2.70844H11.2169V4.53136H12.4322V2.70844V2.70845C12.4314 2.03759 11.8878 1.49394 11.2169 1.49316H3.92524C3.25438 1.49393 2.71073 2.03758 2.70996 2.70844V17.2918V17.2918C2.71073 17.9626 3.25438 18.5063 3.92523 18.5071Z" | ||
fill="currentColor" | ||
/> | ||
<path | ||
fillRule="evenodd" | ||
clipRule="evenodd" | ||
d="M12.6751 17.292C12.6742 18.0968 12.022 18.7491 11.2171 18.75H3.92513V18.507L11.2168 18.5072C11.8877 18.5064 12.4313 17.9625 12.4321 17.2917V15.4688H11.2168V17.2917H3.92513V2.70834H11.2168V4.53125H12.4321V2.70848C12.4313 2.03762 11.8877 1.49383 11.2168 1.49306H3.92513V1.25H11.2168C12.0217 1.25093 12.6742 1.90319 12.6751 2.70806V4.77431H10.9737V2.95139H4.16818V17.0486H10.9737V15.2257H12.6751V17.292ZM2.70985 2.70833C2.71062 2.03747 3.25427 1.49383 3.92513 1.49306V1.25C3.12025 1.25092 2.46772 1.90318 2.4668 2.70805V17.2917C2.46772 18.0965 3.12025 18.7491 3.92513 18.75V18.507C3.25427 18.5062 2.71062 17.9624 2.70985 17.2915V2.70833Z" | ||
fill="currentColor" | ||
/> | ||
<path | ||
fillRule="evenodd" | ||
clipRule="evenodd" | ||
d="M12.7879 12.7867L14.9669 10.6077H6.35547V9.39244H14.9669L12.7879 7.21345L13.6471 6.35425L17.293 10.0001L13.6471 13.6459L12.7879 12.7867Z" | ||
fill="currentColor" | ||
/> | ||
<path | ||
fillRule="evenodd" | ||
clipRule="evenodd" | ||
d="M12.4446 12.7867L14.3805 10.8508H6.11279V9.14937H14.3805L12.4446 7.21343L13.6475 6.0105L17.6371 10.0001L13.6475 13.9896L12.4446 12.7867ZM14.9673 9.39243H6.35585V10.6077H14.9673L12.7883 12.7867L13.6475 13.6459L17.2934 10.0001L13.6475 6.35423L12.7883 7.21343L14.9673 9.39243Z" | ||
fill="currentColor" | ||
/> | ||
</SvgIcon> | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
export { CoderIcon } from "./CoderIcon" | ||
export { Logo } from "./Logo" | ||
export * from "./Logout" | ||
export { WorkspacesIcon } from "./WorkspacesIcon" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import Popover, { PopoverProps } from "@material-ui/core/Popover" | ||
import { fade, makeStyles } from "@material-ui/core/styles" | ||
import React from "react" | ||
|
||
type BorderedMenuVariant = "manage-dropdown" | "user-dropdown" | ||
|
||
type BorderedMenuProps = Omit<PopoverProps, "variant"> & { | ||
variant?: BorderedMenuVariant | ||
} | ||
|
||
export const BorderedMenu: React.FC<BorderedMenuProps> = ({ children, variant, ...rest }) => { | ||
const styles = useStyles() | ||
|
||
return ( | ||
<Popover classes={{ root: styles.root, paper: styles.paperRoot }} data-variant={variant} {...rest}> | ||
{children} | ||
</Popover> | ||
) | ||
} | ||
|
||
const useStyles = makeStyles((theme) => ({ | ||
root: { | ||
paddingBottom: theme.spacing(1), | ||
}, | ||
paperRoot: { | ||
width: "292px", | ||
border: `2px solid ${theme.palette.primary.main}`, | ||
borderRadius: 7, | ||
boxShadow: `4px 4px 0px ${fade(theme.palette.primary.main, 0.2)}`, | ||
}, | ||
})) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
import Badge from "@material-ui/core/Badge" | ||
import Divider from "@material-ui/core/Divider" | ||
import ListItemIcon from "@material-ui/core/ListItemIcon" | ||
import ListItemText from "@material-ui/core/ListItemText" | ||
import MenuItem from "@material-ui/core/MenuItem" | ||
import { fade, makeStyles } from "@material-ui/core/styles" | ||
import KeyboardArrowDown from "@material-ui/icons/KeyboardArrowDown" | ||
import KeyboardArrowUp from "@material-ui/icons/KeyboardArrowUp" | ||
import React, { useState } from "react" | ||
import { LogoutIcon } from "../Icons" | ||
import { BorderedMenu } from "./BorderedMenu" | ||
import { UserProfileCard } from "../User/UserProfileCard" | ||
|
||
import { User } from "../../contexts/UserContext" | ||
import { UserAvatar } from "../User" | ||
|
||
export interface UserDropdownProps { | ||
user: User | ||
onSignOut: () => void | ||
} | ||
|
||
export const UserDropdown: React.FC<UserDropdownProps> = ({ user, onSignOut }: UserDropdownProps) => { | ||
const styles = useStyles() | ||
|
||
const [anchorEl, setAnchorEl] = useState<HTMLElement | undefined>() | ||
const handleDropdownClick = (ev: React.MouseEvent<HTMLLIElement>): void => { | ||
setAnchorEl(ev.currentTarget) | ||
} | ||
const onPopoverClose = () => { | ||
setAnchorEl(undefined) | ||
} | ||
|
||
return ( | ||
<> | ||
<div> | ||
<MenuItem onClick={handleDropdownClick}> | ||
<div className={styles.inner}> | ||
{user && ( | ||
<Badge overlap="circle"> | ||
<UserAvatar user={user} /> | ||
</Badge> | ||
)} | ||
{anchorEl ? ( | ||
<KeyboardArrowUp className={`${styles.arrowIcon} ${styles.arrowIconUp}`} /> | ||
) : ( | ||
<KeyboardArrowDown className={styles.arrowIcon} /> | ||
)} | ||
</div> | ||
</MenuItem> | ||
</div> | ||
|
||
<BorderedMenu | ||
anchorEl={anchorEl} | ||
getContentAnchorEl={null} | ||
open={!!anchorEl} | ||
anchorOrigin={{ | ||
vertical: "bottom", | ||
horizontal: "right", | ||
}} | ||
transformOrigin={{ | ||
vertical: "top", | ||
horizontal: "right", | ||
}} | ||
marginThreshold={0} | ||
variant="user-dropdown" | ||
onClose={onPopoverClose} | ||
> | ||
{user && ( | ||
<div className={styles.userInfo}> | ||
<UserProfileCard user={user} /> | ||
|
||
<Divider className={styles.divider} /> | ||
|
||
<MenuItem className={styles.menuItem} onClick={onSignOut}> | ||
<ListItemIcon className={styles.icon}> | ||
<LogoutIcon /> | ||
</ListItemIcon> | ||
<ListItemText primary="Sign Out" /> | ||
</MenuItem> | ||
</div> | ||
)} | ||
</BorderedMenu> | ||
</> | ||
) | ||
} | ||
|
||
export const useStyles = makeStyles((theme) => ({ | ||
divider: { | ||
marginTop: theme.spacing(1), | ||
marginBottom: theme.spacing(1), | ||
}, | ||
inner: { | ||
display: "flex", | ||
alignItems: "center", | ||
minWidth: 0, | ||
maxWidth: 300, | ||
}, | ||
|
||
userInfo: { | ||
marginBottom: theme.spacing(1), | ||
}, | ||
arrowIcon: { | ||
color: fade(theme.palette.primary.contrastText, 0.7), | ||
marginLeft: theme.spacing(1), | ||
width: 16, | ||
height: 16, | ||
}, | ||
arrowIconUp: { | ||
color: theme.palette.primary.contrastText, | ||
}, | ||
|
||
menuItem: { | ||
height: 44, | ||
padding: `${theme.spacing(1.5)}px ${theme.spacing(2.75)}px`, | ||
|
||
"&:hover": { | ||
backgroundColor: fade(theme.palette.primary.light, 0.1), | ||
transition: "background-color 0.3s ease", | ||
}, | ||
}, | ||
|
||
icon: { | ||
color: theme.palette.text.secondary, | ||
}, | ||
})) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,34 @@ | ||
import React from "react" | ||
import { screen } from "@testing-library/react" | ||
|
||
import { render } from "../../test_helpers" | ||
import { render, MockUser } from "../../test_helpers" | ||
import { Navbar } from "./index" | ||
|
||
describe("Navbar", () => { | ||
const noop = () => { | ||
return | ||
} | ||
it("renders content", async () => { | ||
// When | ||
render(<Navbar />) | ||
render(<Navbar onSignOut={noop} />) | ||
|
||
// Then | ||
await screen.findAllByText("Coder", { exact: false }) | ||
}) | ||
|
||
it("renders profile picture for user", async () => { | ||
// Given | ||
const mockUser = { | ||
...MockUser, | ||
username: "bryan", | ||
} | ||
|
||
// When | ||
render(<Navbar user={mockUser} onSignOut={noop} />) | ||
|
||
// Then | ||
// There should be a 'B' avatar! | ||
const element = await screen.findByText("B") | ||
expect(element).toBeDefined() | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.