Skip to content

Commit

Permalink
feat(app-menu): adds the user card to the app menu
Browse files Browse the repository at this point in the history
Adds a the user avatar and name to the app menu

closes #105
  • Loading branch information
anguspiv committed Apr 29, 2022
1 parent 845db71 commit 1551a43
Show file tree
Hide file tree
Showing 9 changed files with 159 additions and 34 deletions.
5 changes: 5 additions & 0 deletions src/components/layout/PageLayout/PageLayout.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ jest.mock('@chakra-ui/react', () => ({
useMediaQuery: jest.fn(),
}));

jest.mock('@apollo/client', () => ({
useQuery: jest.fn().mockReturnValue({ data: { profile: { firstName: 'John' } } }),
gql: jest.fn(),
}));

describe('<PageLayout />', () => {
const onOpen = jest.fn();
const onClose = jest.fn();
Expand Down
5 changes: 5 additions & 0 deletions src/components/layout/SideBar/SideBar.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ jest.mock('next-auth/react', () => ({
useSession: jest.fn(),
}));

jest.mock('@apollo/client', () => ({
useQuery: jest.fn().mockReturnValue({ data: { profile: { firstName: 'John' } } }),
gql: jest.fn(),
}));

describe('<SideBar />', () => {
const setupSideBar = (props: object = {}) => {
useSession.mockClear().mockReturnValue({});
Expand Down
29 changes: 15 additions & 14 deletions src/components/navigation/AppDrawer/AppDrawer.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ jest.mock('next-auth/react', () => ({
useSession: jest.fn(),
}));

jest.mock('@apollo/client', () => ({
useQuery: jest.fn().mockReturnValue({ data: { profile: { firstName: 'John' } } }),
gql: jest.fn(),
}));

describe('<AppDrawer />', () => {
const setupAppDrawer = (props: object = {}, context: object = {}) => {
const { session } = context;
Expand All @@ -32,14 +37,6 @@ describe('<AppDrawer />', () => {
expect(getByText('Pokermans')).toBeInTheDocument();
});

it('should not display the user menu', () => {
expect.assertions(1);

const { queryByText } = setupAppDrawer();

expect(queryByText('User')).toBeNull();
});

it('should render the User Menu', () => {
expect.assertions(1);

Expand Down Expand Up @@ -68,10 +65,12 @@ describe('<AppDrawer />', () => {
it('should display a Login Link', () => {
expect.assertions(3);

const { getByText, queryByText } = setupAppDrawer();
const { getAllByText, queryByText } = setupAppDrawer();

expect(getByText('Login')).toBeInTheDocument();
expect(getByText('Login').closest('a')).toHaveAttribute('href', '/api/auth/signin');
const loginLink = getAllByText('Login');

expect(loginLink.length).toBeGreaterThan(0);
expect(loginLink[loginLink.length - 1].closest('a')).toHaveAttribute('href', '/api/auth/signin');
expect(queryByText('Logout')).toBeNull();
});

Expand All @@ -82,10 +81,12 @@ describe('<AppDrawer />', () => {
status: 'authenticated',
};

const { getByText, queryByText } = setupAppDrawer({}, { session });
const { getAllByText, queryByText } = setupAppDrawer({}, { session });

const loginLink = getAllByText('Logout');

expect(getByText('Logout')).toBeInTheDocument();
expect(getByText('Logout').closest('a')).toHaveAttribute('href', '/api/auth/signout');
expect(loginLink.length).toBeGreaterThan(0);
expect(loginLink[loginLink.length - 1].closest('a')).toHaveAttribute('href', '/api/auth/signout');
expect(queryByText('Login')).toBeNull();
});

Expand Down
19 changes: 6 additions & 13 deletions src/components/navigation/AppMenu/AppMenu.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ jest.mock('next-auth/react', () => ({
useSession: jest.fn(),
}));

jest.mock('@apollo/client', () => ({
useQuery: jest.fn().mockReturnValue({ data: { profile: { firstName: 'John' } } }),
gql: jest.fn(),
}));

describe('<AppMenu />', () => {
const setupAppMenu = (props: object = {}, context: object = {}) => {
const { session } = context;
Expand Down Expand Up @@ -47,22 +52,10 @@ describe('<AppMenu />', () => {
expect(getByRole('link', { name: 'PokerMans' })).toHaveStyle('color: var(--chakra-colors-gray-600)');
});

it('should not display the user menu', () => {
expect.assertions(1);

const { queryByText } = setupAppMenu();

expect(queryByText('User')).toBeNull();
});

it('should render the User Menu', () => {
expect.assertions(1);

const session = {
status: 'authenticated',
};

const { getByText } = setupAppMenu({}, { session });
const { getByText } = setupAppMenu({});

expect(getByText('User')).toBeInTheDocument();
});
Expand Down
46 changes: 39 additions & 7 deletions src/components/navigation/AppMenu/AppMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,25 @@
import { Box } from '@chakra-ui/react';
import { faHome } from '@fortawesome/free-solid-svg-icons';
import { faHome, faUser, faSignOutAlt, faSignInAlt } from '@fortawesome/free-solid-svg-icons';
import { useSession } from 'next-auth/react';
import { useQuery, gql } from '@apollo/client';
import Link from 'next/link';
import { getImageUrl } from '@utils/image';
import NavMenu from '../NavMenu';
import NavLink from '../NavLink';
import NavMenuTitle from '../NavMenuTitle';
import NavMenuUser from '../NavMenuUser';

const profileQuery = gql`
query GetNavProfile {
profile {
firstName
lastName
avatar {
filepath
}
}
}
`;

export interface AppMenuProps {
variant?: 'default' | 'transparent';
Expand All @@ -22,6 +38,9 @@ const variants = {

function AppMenu({ variant }: AppMenuProps) {
const { status } = useSession();
const { data } = useQuery(profileQuery);

const profile = data?.profile || {};

const isAuthed = status === 'authenticated';
const { color, bg } = variants[variant ?? 'default'] || variants.default;
Expand All @@ -40,12 +59,25 @@ function AppMenu({ variant }: AppMenuProps) {
<NavMenu>
<NavLink href="/" label="PokerMans" icon={faHome} variant={variant} />
</NavMenu>
{isAuthed && (
<NavMenu>
<NavMenuTitle>User</NavMenuTitle>
<NavLink href="/account" label="Account" variant={variant} />
</NavMenu>
)}
<NavMenu>
<NavMenuTitle>User</NavMenuTitle>
{!isAuthed && <NavLink href="/api/auth/signin" label="Login" icon={faSignInAlt} />}
{isAuthed && (
<>
<Link href="/account" passHref>
<a>
<NavMenuUser
image={getImageUrl(profile?.avatar || {})}
firstName={profile?.firstName}
lastName={profile?.lastName}
/>
</a>
</Link>
<NavLink href="/account" label="Account" variant={variant} icon={faUser} />
<NavLink href="/api/auth/signout" label="Logout" icon={faSignOutAlt} />
</>
)}
</NavMenu>
</Box>
);
}
Expand Down
19 changes: 19 additions & 0 deletions src/components/navigation/NavMenuUser/NavMenuUser.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Story } from '@storybook/react';
import NavMenuUser, { NavMenuUserProps } from './NavMenuUser';

export default {
title: 'components/navigation/NavMenuUser',
component: NavMenuUser,
};

const Template: Story<NavMenuUserProps> = (args) => {
return <NavMenuUser {...args} />;
};

export const Default = Template.bind({});

Default.args = {
image: 'https://picsum.photos/id/237/200/300',
firstName: 'John',
lastName: 'Doe',
};
29 changes: 29 additions & 0 deletions src/components/navigation/NavMenuUser/NavMenuUser.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from 'react';
import { render } from '@testing-library/react';
import NavMenuUser from './NavMenuUser';

describe('<NavMenuUser />', () => {
const setupNavMenuUser = (props) => {
return render(<NavMenuUser {...props} />);
};

it('should render', () => {
expect.assertions(1);
const { container } = setupNavMenuUser();
expect(container).toBeTruthy();
});

it('should render the first name and last initial', () => {
expect.assertions(1);

const firstName = 'John';
const lastName = 'Doe';

const { getByText } = setupNavMenuUser({
firstName,
lastName,
});

expect(getByText(`${firstName} ${lastName[0]}.`)).toBeInTheDocument();
});
});
36 changes: 36 additions & 0 deletions src/components/navigation/NavMenuUser/NavMenuUser.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { Grid, GridItem, Heading, Avatar } from '@chakra-ui/react';

export interface NavMenuUserProps {
image?: string;
firstName: string;
lastName?: string;
}

function NavMenuUser({ image, firstName, lastName }: NavMenuUserProps) {
let name = firstName;

if (lastName) {
name = `${name} ${lastName[0]}.`;
}

return (
<Grid
gap={2}
templateRows="auto"
templateColumns="repeat(2, auto)"
alignItems="center"
justifyContent="start"
px={2}
py={1}
>
<Avatar src={image} data-testid="avatar" size="xs" name={name} />
<GridItem area="info">
<Heading as="p" size="xs">
{name}
</Heading>
</GridItem>
</Grid>
);
}

export default NavMenuUser;
5 changes: 5 additions & 0 deletions src/components/navigation/NavMenuUser/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import NavMenuUser from './NavMenuUser';

export * from './NavMenuUser';

export default NavMenuUser;

1 comment on commit 1551a43

@vercel
Copy link

@vercel vercel bot commented on 1551a43 Apr 29, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.