Skip to content
This repository has been archived by the owner on Jul 12, 2022. It is now read-only.

Commit

Permalink
Merge pull request #851 from ZupIT/issue/user-group-pagination
Browse files Browse the repository at this point in the history
Adding pagination for User Groups menu items
  • Loading branch information
monicaribeirozup authored Feb 9, 2021
2 parents d964040 + db38d5d commit a17d7f4
Show file tree
Hide file tree
Showing 13 changed files with 189 additions and 134 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ class V2UserGroupController(
@GetMapping
fun findAll(
@RequestParam("name", required = false) name: String?,
pageable: PageRequest
@Valid pageable: PageRequest
): ResourcePageResponse<UserGroupResponse> {
return this.findAllUserGroupsInteractor.execute(name, pageable)
}
Expand Down
7 changes: 5 additions & 2 deletions ui/src/core/providers/user-group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const endpoint = '/moove/v2/user-groups';

export interface UserGroupFilter {
name?: string;
page?: number;
}

export interface UserGroupSave {
Expand All @@ -32,15 +33,17 @@ export interface UserGroupMemberSave {
}

const initialGroupUserFilter = {
name: ''
name: '',
page: 0
};

export const findAllUserGroup = (
filter: UserGroupFilter = initialGroupUserFilter
) => {
const params = new URLSearchParams({
size: `${DEFAULT_PAGE_SIZE}`,
name: filter?.name
name: filter?.name || '',
page: `${filter.page ?? 0}`
});

return baseRequest(`${endpoint}?${params}`);
Expand Down
6 changes: 3 additions & 3 deletions ui/src/modules/Groups/Menu/Loaders/list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ export const Loader: FunctionComponent = () => (
backgroundColor="#3a393c"
foregroundColor="#2c2b2e"
>
<rect x="0" y="0" rx="4" ry="4" width="260" height="15" />
<rect x="0" y="35" rx="4" ry="4" width="260" height="15" />
<rect x="0" y="70" rx="4" ry="4" width="260" height="15" />
<rect x="16" y="0" rx="4" ry="4" width="260" height="15" />
<rect x="16" y="35" rx="4" ry="4" width="260" height="15" />
<rect x="16" y="70" rx="4" ry="4" width="260" height="15" />
</ContentLoader>
);
4 changes: 2 additions & 2 deletions ui/src/modules/Groups/Menu/MenuItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

import React, { memo } from 'react';
import React from 'react';
import Text from 'core/components/Text';
import Styled from './styled';

Expand All @@ -37,4 +37,4 @@ const MenuItem = ({ id, name, onSelect, isActive }: Props) => (
</Styled.Link>
);

export default memo(MenuItem);
export default MenuItem;
44 changes: 26 additions & 18 deletions ui/src/modules/Groups/Menu/__tests__/Menu.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,44 +15,52 @@
*/

import React from 'react';
import { render, screen, waitFor } from 'unit-test/testUtils';
import { UserGroupItem } from './fixtures';
import { FetchMock } from 'jest-fetch-mock/types';
import userEvent from '@testing-library/user-event';
import { render, screen } from 'unit-test/testUtils';
import * as StateHooks from 'core/state/hooks';
import Menu from '../index';

test('render Menu users groups default', async () => {
test('render Menu user groups default', async () => {
render(
<Menu
onSearch={jest.fn()}
onCreate={jest.fn()}
onSelect={jest.fn()}
isLoading={false}
selectedItems={null}
items={[]}
/>
);

const menu = screen.getByTestId('users-groups-menu');
const emptyItems = screen.getByText('No User group was found');
const menu = await screen.findByTestId('user-groups-action');
const emptyItems = await screen.findByText('No User group was found');

expect(menu).toBeInTheDocument();
expect(emptyItems).toBeInTheDocument();
});

test('render Menu items', async () => {
test('render Menu user groups items', async () => {
jest.spyOn(StateHooks, 'useGlobalState').mockImplementation(() => ({
list: {
content: [{
id: '1',
name: 'group',
page: 0,
size: 1,
totalPages: 1,
last: true,
users: [{
id: '2',
name: 'Charles',
email: '[email protected]',
createdAt: '2021-01-01 01:01'
}]
}]
},
}));

render(
<Menu
onSearch={jest.fn()}
onCreate={jest.fn()}
onSelect={jest.fn()}
isLoading={false}
selectedItems={null}
items={UserGroupItem}
/>
);

const menuItem = screen.getByTestId('group-menu-item-1');
const menuItem = await screen.findByTestId('group-menu-item-1');
expect(menuItem).toBeInTheDocument();

});
103 changes: 62 additions & 41 deletions ui/src/modules/Groups/Menu/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,69 +14,90 @@
* limitations under the License.
*/

import React from 'react';
import React, { Fragment, useEffect, useState, useCallback } from 'react';
import map from 'lodash/map';
import some from 'lodash/some';
import method from 'lodash/method';
import isEmpty from 'lodash/isEmpty';
import Text from 'core/components/Text';
import LabeledIcon from 'core/components/LabeledIcon';
import InfiniteScroll from 'core/components/InfiniteScroll';
import { useDispatch, useGlobalState } from 'core/state/hooks';
import MenuItem from './MenuItem';
import Styled from './styled';
import Loader from './Loaders';

import { isActiveById } from '../helpers';
import { useFindAllUserGroup } from '../hooks';
import { UserGroupPaginationItem } from '../interfaces/UserGroupsPagination';
import { resetUserGroupsAction } from '../state/actions';

interface ListProps {
items: UserGroupPaginationItem[];
selectedItems: string[];
interface Props {
onCreate: () => void;
onSelect: (id: string) => void;
}

interface Props extends ListProps {
onSearch: (name: string) => void;
onCreate: () => void;
isLoading: boolean;
}
const UserGroupMenu = ({ onCreate, onSelect }: Props) => {
const dispatch = useDispatch();
const [name, setName] = useState<string>('');
const [getUserGroups, loading] = useFindAllUserGroup();
const { list } = useGlobalState(({ userGroups }) => userGroups);
const isRenderEmpty = isEmpty(list.content) && !loading;

const onChange = useCallback(() => {
const page = 0;
dispatch(resetUserGroupsAction());
getUserGroups(name, page);
}, [dispatch, getUserGroups, name]);

useEffect(() => {
onChange();
}, [name, onChange]);

const loadMore = (page: number) => {
getUserGroups(name, page);
};

const renderItem = ({ id, name }: UserGroupPaginationItem) => (
<MenuItem
key={id}
id={id}
name={name}
isActive={isActiveById(id)}
onSelect={onSelect}
/>
);

const renderEmpty = () => (
<Styled.Empty>
<Text.h3 color="dark">No User group was found</Text.h3>
</Styled.Empty>
);

const renderList = (data: UserGroupPaginationItem[]) =>
map(data, item => renderItem(item))

const UserGroupList = ({ items, selectedItems, onSelect }: ListProps) =>
isEmpty(items) ? (
<Text.h3 color="dark">No User group was found</Text.h3>
) : (
<>
{map(items, item => (
<MenuItem
key={item.id}
id={item.id}
name={item.name}
isActive={some(selectedItems, method('includes', item.id))}
onSelect={onSelect}
/>
))}
</>
const renderContent = () => (
<InfiniteScroll
hasMore={!list.last}
loadMore={loadMore}
isLoading={loading}
loader={<Styled.Loader />}
>
{isRenderEmpty ? renderEmpty() : renderList(list.content)}
</InfiniteScroll>
);

const UserGroupMenu = ({ onSearch, onCreate, isLoading, ...rest }: Props) => {
return (
<>
<Styled.Actions data-testid={'users-groups-menu'}>
<Fragment>
<Styled.Actions data-testid="user-groups-action">
<Styled.Button onClick={onCreate} id="create-user-group">
<LabeledIcon icon="plus-circle" marginContent="5px">
<Text.h5 color="dark">Create user group</Text.h5>
</LabeledIcon>
</Styled.Button>
</Styled.Actions>
<Styled.Content>
<Styled.SearchInput resume onSearch={onSearch} maxLength={64} />
<Styled.List data-testid="user-group-menu">
{isEmpty(rest.items) && isLoading ? (
<Loader.List />
) : (
<UserGroupList {...rest} />
)}
</Styled.List>
<Styled.Content data-testid="user-groups-menu">
<Styled.SearchInput resume onSearch={setName} maxLength={64} />
{renderContent()}
</Styled.Content>
</>
</Fragment>
);
};

Expand Down
27 changes: 14 additions & 13 deletions ui/src/modules/Groups/Menu/styled.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,31 +22,21 @@ import ButtonComponent from 'core/components/Button';
import Form from 'core/components/Form';
import Text from 'core/components/Text';
import { COLOR_BLACK_MARLIN } from 'core/assets/colors';
import LoaderMenuComponent from './Loaders';

const SearchInput = styled(SearchInputComponent)`
margin: 15px 0;
padding: 0 16px;
`;

const List = styled.div`
display: flex;
flex-direction: column;
margin: 0;
> * {
padding: 0 16px;
}
`;

const ListItem = styled(LabeledIcon)`
padding: 15px 0;
cursor: pointer;
display: flex;
`;

const Content = styled.div`
height: calc(100vh - 200px);
overflow-y: auto;
height: calc(100vh - 250px);
`;

const Actions = styled.div`
Expand All @@ -68,6 +58,8 @@ const Link = styled('button')<LinkProps>`
background: none;
border: none;
text-decoration: none;
width: 100%;
padding: 0 16px;
background-color: ${({ isActive }) =>
isActive ? COLOR_BLACK_MARLIN : 'transparent'};
`;
Expand Down Expand Up @@ -98,15 +90,24 @@ const ButtonModal = styled(ButtonComponent.Default)`
margin-top: 20px;
`;

const Loader = styled(LoaderMenuComponent.List)`
padding: 0 16px;
`;

const Empty = styled.div`
padding: 0 16px;
`;

export default {
SearchInput,
List,
ListItem,
Content,
Actions,
Icon,
Link,
Button,
Loader,
Empty,
Modal: {
Input: ModalInput,
Title: ModalTitle,
Expand Down
2 changes: 1 addition & 1 deletion ui/src/modules/Groups/__tests__/GroupsComponents.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ test('render groups', async () => {

render(<Router history={history}><Groups /></Router>);

const UserGroupMenu = await screen.findByTestId('user-group-menu');
const UserGroupMenu = await screen.findByTestId('user-groups-menu');

expect(UserGroupMenu).toBeInTheDocument();
});
Expand Down
5 changes: 5 additions & 0 deletions ui/src/modules/Groups/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
import without from 'lodash/without';
import { History } from 'history';
import map from 'lodash/map';
import some from 'lodash/some';
import method from 'lodash/method';
import routes from 'core/constants/routes';
import getQueryStrings from 'core/utils/query';
import includes from 'lodash/includes';
Expand Down Expand Up @@ -58,3 +60,6 @@ export const addParamUserGroup = (history: History, usergroupId: string) => {
search: query.toString()
});
};

export const isActiveById = (id: string) =>
some(getSelectedUserGroups(), method('includes', id));
Loading

0 comments on commit a17d7f4

Please sign in to comment.