Skip to content

Commit

Permalink
Merge pull request #789 from newsrevenuehub/DEV-1968-avatar-settings-…
Browse files Browse the repository at this point in the history
…menu-basic

DEV-1968: Avatar Menu
  • Loading branch information
x110dc authored Nov 4, 2022
2 parents c540faf + 6042ad7 commit 2320097
Show file tree
Hide file tree
Showing 21 changed files with 486 additions and 96 deletions.
6 changes: 3 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ repos:
rev: 5.10.1
hooks:
- id: isort
args: ["--profile", "black", "--filter-files"]
args: ['--profile', 'black', '--filter-files']
exclude: ^.*\b(migrations)\b.*$
# Pythonic checks.
- repo: https://github.com/PyCQA/flake8
Expand All @@ -41,7 +41,7 @@ repos:
- id: flake8
exclude: docs|migrations|node_modules|revengine/settings
additional_dependencies:
- "flake8-logging-format"
- 'flake8-logging-format'
# # Pylint code checks.
# # "local" because pylint needs all packages to dynamically import.
# - repo: local
Expand Down Expand Up @@ -77,7 +77,7 @@ repos:
rev: v2.7.1
hooks:
- id: prettier
types: [javascript]
types_or: [javascript, ts, tsx]
# JS code linter.
- repo: https://github.com/pre-commit/mirrors-eslint
rev: v8.18.0
Expand Down
11 changes: 11 additions & 0 deletions spa/src/assets/assets.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Required to import .svg files to TS files
declare module '*.svg' {
const content: any;
export default content;
}

// Required to import .png files to TS files
declare module '*.png' {
const content: any;
export default content;
}
8 changes: 8 additions & 0 deletions spa/src/assets/icons/logout.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
40 changes: 40 additions & 0 deletions spa/src/components/common/AvatarMenu/AvatarMenu.stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import AvatarMenu from './AvatarMenu';

export default {
title: 'Common/AvatarMenu',
component: AvatarMenu
};

export const Default = (props) => (
<div style={{ background: '#523A5E', display: 'flex', justifyContent: 'end' }}>
<AvatarMenu {...props} />
</div>
);

Default.args = {
user: {
firstName: 'Gui',
lastName: 'Mend',
email: 'gm@gmail.com'
}
};

export const NoNameAvatar = (props) => (
<div style={{ background: '#523A5E', display: 'flex', justifyContent: 'end' }}>
<AvatarMenu {...props} />
</div>
);

NoNameAvatar.args = {
user: {
email: 'gm@gmail.com'
}
};

export const EmptyAvatar = (props) => (
<div style={{ background: '#523A5E', display: 'flex', justifyContent: 'end' }}>
<AvatarMenu {...props} />
</div>
);

EmptyAvatar.args = {};
110 changes: 110 additions & 0 deletions spa/src/components/common/AvatarMenu/AvatarMenu.styled.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import {
Avatar as MuiAvatar,
Popover as MuiPopover,
MenuItem as MuiMenuItem,
Typography as MuiTypography,
ListItemIcon as MuiListItemIcon
} from '@material-ui/core';
import styled from 'styled-components';

export const Container = styled.button<{ open: string }>`
display: flex;
align-items: center;
cursor: pointer;
padding: 0;
background: transparent;
border: none;
padding: 9px 0 9px 10px;
max-height: 48px;
svg {
fill: white;
height: 27px;
width: 27px;
margin-left: -3px;
}
${(props) =>
props.open === 'open' &&
`background-color: ${props.theme.colors.account.purple[1]};
`}
:hover {
background-color: ${(props) => props.theme.colors.account.purple[1]};
}
`;

export const ModalHeader = styled.p`
font-size: ${(props) => props.theme.fontSizesUpdated.sm};
font-family: ${(props) => props.theme.systemFont};
color: ${(props) => props.theme.colors.muiGrey[700]};
font-weight: 600;
margin: 0 0 9px;
`;

export const ListWrapper = styled.ul`
padding: 0;
margin: 0;
`;

export const ListItemIcon = styled(MuiListItemIcon)`
&& {
min-width: unset;
color: ${(props) => props.theme.colors.sidebarBackground};
svg {
width: 20px;
height: 20px;
}
}
`;

export const LogoutIconWrapper = styled.img`
width: 20px;
height: 20px;
`;

export const Avatar = styled(MuiAvatar)`
&& {
height: 31px;
width: 31px;
border: 1px solid white;
font-size: ${(props) => props.theme.fontSizesUpdated.sm};
background-color: ${(props) => props.theme.colors.muiLightBlue[800]};
}
`;

export const Popover = styled(MuiPopover)`
.MuiPaper-rounded {
min-width: 207px;
box-shadow: none;
padding: 12px 15px;
border: 1px solid ${(props) => props.theme.colors.muiGrey[300]};
background-color: ${(props) => props.theme.colors.muiGrey[100]};
filter: drop-shadow(0px 2px 20px rgba(0, 0, 0, 0.1));
}
`;

export const Typography = styled(MuiTypography)`
&& {
color: ${(props) => props.theme.colors.sidebarBackground};
font-size: ${(props) => props.theme.fontSizesUpdated.sm};
font-weight: 400;
}
`;

export const MenuItem = styled(MuiMenuItem)`
&& {
padding: 5px 7px;
margin: 0 -7px;
border-radius: ${(props) => props.theme.muiBorderRadius.lg};
background-color: ${(props) => props.theme.colors.muiGrey[100]};
display: flex;
align-items: center;
gap: 18px;
:hover {
background-color: ${(props) => props.theme.colors.navSectionLabelColor};
}
}
`;
102 changes: 102 additions & 0 deletions spa/src/components/common/AvatarMenu/AvatarMenu.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import { axe } from 'jest-axe';
import { render, screen, within } from 'test-utils';
import userEvent from '@testing-library/user-event';

import { FAQ_URL } from 'constants/helperUrls';
import onLogout from 'components/authentication/logout';
import AvatarMenu, { AvatarMenuProps } from './AvatarMenu';

jest.mock('components/authentication/logout');

const tree = (props?: AvatarMenuProps) => {
return render(<AvatarMenu {...props} />);
};

const settingsMenu = 'Settings';

describe('AvatarMenu', () => {
it('should be enabled if has user', () => {
tree({ user: { email: 'a@a.com' } });
expect(screen.getByRole('button', { name: settingsMenu })).toBeEnabled();
});

it('should be disabled if user is undefined', () => {
tree();
expect(screen.getByRole('button', { name: settingsMenu })).toBeEnabled();
});

it('should render name initials', () => {
const nameUser = {
firstName: 'first-mock',
lastName: 'last-mock',
email: 'email@mock.com'
};
tree({ user: nameUser });

const avatar = screen.getByTestId('avatar');
const title = within(avatar).getByText('FL');
expect(title).toBeInTheDocument();
});

it('should render email initial if name is empty', () => {
const emailUser = {
email: 'email@mock.com'
};
tree({ user: emailUser });

const avatar = screen.getByTestId('avatar');
expect(avatar.innerHTML).toBe('E');
const title = within(avatar).getByText('E');
expect(title).toBeInTheDocument();
});

it('should render nothing if user is undefined', () => {
tree();

const avatar = screen.getByTestId('avatar');
expect(avatar.innerHTML).toBe('');
});

it('should open settings menu with correct buttons', () => {
const emailUser = {
email: 'email@mock.com'
};
tree({ user: emailUser });

userEvent.click(screen.getByRole('button', { name: settingsMenu }));
expect(screen.getByRole('menuitem', { name: 'FAQ' })).toBeEnabled();
expect(screen.getByRole('menuitem', { name: 'Sign out' })).toBeEnabled();
});

it('should have correct FAQ link', () => {
const oldOpen = jest.spyOn(window, 'open').mockImplementation();
const emailUser = {
email: 'email@mock.com'
};
tree({ user: emailUser });

userEvent.click(screen.getByRole('button', { name: settingsMenu }));
userEvent.click(screen.getByRole('menuitem', { name: 'FAQ' }));
expect(oldOpen).toBeCalledWith(FAQ_URL, '_blank', 'noopener, noreferrer');
oldOpen.mockRestore();
});

it('should logout', () => {
const emailUser = {
email: 'email@mock.com'
};
tree({ user: emailUser });

userEvent.click(screen.getByRole('button', { name: settingsMenu }));
userEvent.click(screen.getByRole('menuitem', { name: 'Sign out' }));
expect(onLogout).toBeCalledTimes(1);
});

it('is accessible', async () => {
const { container } = tree({ user: { email: 'a@a.com' } });
expect(await axe(container)).toHaveNoViolations();

userEvent.click(screen.getByRole('button', { name: settingsMenu }));
expect(await axe(container)).toHaveNoViolations();
});
});
Loading

0 comments on commit 2320097

Please sign in to comment.