Skip to content

Commit b43b5ce

Browse files
sorting implemented on members table.
1 parent 233273c commit b43b5ce

File tree

7 files changed

+400
-22
lines changed

7 files changed

+400
-22
lines changed
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import React from 'react';
2+
import { iconColors, iconSizes } from '../../../../../constants';
3+
import { Box, FlexBox, icons, If, LinkBox } from '../../../../components';
4+
import { Sorting, SortingDirection } from './types';
5+
6+
import styles from './index.module.scss';
7+
8+
export const SortingHeader: React.FC<{
9+
sortMethod: void;
10+
activeSorting: Sorting | null;
11+
activeSortingDirection: SortingDirection | null;
12+
sorting: Sorting;
13+
}> = ({
14+
children,
15+
sortMethod,
16+
activeSorting,
17+
activeSortingDirection,
18+
sorting,
19+
}) => {
20+
return (
21+
<LinkBox className={styles.sortingBox} onClick={sortMethod}>
22+
<FlexBox alignItems="center">
23+
{children}
24+
<If
25+
condition={
26+
!!activeSorting &&
27+
activeSorting === sorting &&
28+
activeSortingDirection === 'DESC'
29+
}
30+
>
31+
{() => (
32+
<Box paddingLeft="xs">
33+
<icons.chevronDownLight
34+
color={iconColors.darkGrey}
35+
size={iconSizes.xs}
36+
/>
37+
</Box>
38+
)}
39+
</If>
40+
<If
41+
condition={
42+
!!activeSorting &&
43+
activeSorting === sorting &&
44+
activeSortingDirection === 'ASC'
45+
}
46+
>
47+
{() => (
48+
<Box paddingLeft="xs">
49+
<icons.chevronUpLight
50+
color={iconColors.darkGrey}
51+
size={iconSizes.xs}
52+
/>
53+
</Box>
54+
)}
55+
</If>
56+
</FlexBox>
57+
</LinkBox>
58+
);
59+
};
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
@import '../../../../globalStyles';
2+
3+
.checkbox {
4+
height: 1.4rem;
5+
width: 1.4rem;
6+
border-radius: 2px;
7+
border: 1px solid $darkGreyColor;
8+
cursor: pointer;
9+
position: relative;
10+
}
11+
12+
.checkedCheckbox {
13+
background: $greenColor;
14+
border: 1px solid $greenColor;
15+
&:before {
16+
position: absolute;
17+
content: '';
18+
display: inline-block;
19+
transform: rotate(45deg);
20+
height: 10px;
21+
width: 5px;
22+
border-bottom: 2px solid $whiteColor;
23+
border-right: 2px solid $whiteColor;
24+
left: 4px;
25+
bottom: 2px;
26+
}
27+
}
28+
29+
.sortingBox {
30+
user-select: none;
31+
32+
& p {
33+
transition: 0.2s ease-in all;
34+
}
35+
36+
&:hover {
37+
& p {
38+
color: $darkGreyColor;
39+
}
40+
}
41+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export type Sorting =
2+
| 'id'
3+
| 'name'
4+
| 'status'
5+
| 'datasourceCommit'
6+
| 'createdAt';
7+
8+
export type SortingDirection = 'ASC' | 'DESC';
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
import { useDispatch, useSelector } from 'react-redux';
2+
import { stackPagesActions } from '../../../../../redux/actions';
3+
import { stackPagesSelectors } from '../../../../../redux/selectors';
4+
import { Sorting, SortingDirection } from './types';
5+
6+
export type SortMethod = (
7+
sorting: Sorting,
8+
{
9+
asc,
10+
desc,
11+
}: {
12+
asc: (members: TMember[]) => TMember[];
13+
desc: (members: TMember[]) => TMember[];
14+
},
15+
) => void;
16+
17+
interface ServiceInterface {
18+
toggleSelectRun: (members: TMember) => void;
19+
isRunSelected: (members: TMember) => boolean;
20+
allRunsSelected: (members: TMember[]) => boolean;
21+
selectRuns: (members: TMember[]) => void;
22+
unselectRuns: (members: TMember[]) => void;
23+
sortMethod: SortMethod;
24+
}
25+
26+
export const useService = ({
27+
activeSorting,
28+
activeSortingDirection,
29+
setActiveSortingDirection,
30+
setActiveSorting,
31+
setFilteredMembers,
32+
filteredMembers,
33+
}: {
34+
activeSorting: Sorting | null;
35+
activeSortingDirection: SortingDirection | null;
36+
setActiveSortingDirection: (arg: SortingDirection | null) => void;
37+
setActiveSorting: (arg: Sorting | null) => void;
38+
setFilteredMembers: (members: TMember[]) => void;
39+
filteredMembers: TMember[];
40+
}): ServiceInterface => {
41+
const dispatch = useDispatch();
42+
43+
const setSelectedRunIds = (ids: TId[]) => {
44+
dispatch(stackPagesActions.setSelectedRunIds({ runIds: ids }));
45+
};
46+
47+
const selectedRunIds = useSelector(stackPagesSelectors.selectedRunIds);
48+
49+
const toggleSelectRun = (member: TMember): void => {
50+
if (selectedRunIds.indexOf(member.id) === -1) {
51+
setSelectedRunIds([...selectedRunIds, member.id]);
52+
} else {
53+
setSelectedRunIds(selectedRunIds.filter((id: TId) => id !== member.id));
54+
}
55+
};
56+
57+
const isRunSelected = (member: TMember): boolean => {
58+
return selectedRunIds.indexOf(member.id) !== -1;
59+
};
60+
61+
const selectRuns = (members: TMember[]): void => {
62+
setSelectedRunIds([
63+
...selectedRunIds,
64+
...members.map((member: TMember) => member.id),
65+
]);
66+
};
67+
68+
const unselectRuns = (members: TMember[]): void => {
69+
const runIdsToUnselect = members.map((member: TMember) => member.id);
70+
71+
const newRunIds = selectedRunIds.filter(
72+
(id: TId) => !runIdsToUnselect.includes(id),
73+
);
74+
75+
setSelectedRunIds(newRunIds);
76+
};
77+
78+
const allRunsSelected = (members: TMember[]): boolean => {
79+
return members.every((member: TMember) => isRunSelected(member));
80+
};
81+
82+
const sortMethod = (
83+
sorting: Sorting,
84+
sort?: {
85+
asc: (members: TMember[]) => TMember[];
86+
desc: (members: TMember[]) => TMember[];
87+
},
88+
) => () => {
89+
if (sorting === activeSorting) {
90+
if (!!activeSortingDirection && activeSortingDirection === 'ASC') {
91+
sort && setFilteredMembers(sort.desc(filteredMembers));
92+
setActiveSortingDirection('DESC');
93+
} else if (
94+
!!activeSortingDirection &&
95+
activeSortingDirection === 'DESC'
96+
) {
97+
sort && setFilteredMembers(sort.asc(filteredMembers));
98+
setActiveSortingDirection('ASC');
99+
}
100+
} else {
101+
sort && setFilteredMembers(sort.desc(filteredMembers));
102+
setActiveSortingDirection('DESC');
103+
}
104+
setActiveSorting(sorting);
105+
};
106+
107+
return {
108+
toggleSelectRun,
109+
isRunSelected,
110+
unselectRuns,
111+
selectRuns,
112+
allRunsSelected,
113+
sortMethod,
114+
};
115+
};

src/ui/layouts/settings/Organization/index.tsx

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,44 +15,58 @@ import { Table } from '../../common/Table';
1515
import { translate } from './translate';
1616
import { useMemberHeaderCols } from './useHeaderCols';
1717
import { InvitePopup } from './InvitePopup';
18+
import { useService } from './useService';
1819

1920
type Table = 'members' | 'invites';
2021

2122
export const Organization: React.FC = () => {
22-
23-
const dispatch = useDispatch()
23+
const dispatch = useDispatch();
2424

2525
const [fetchingMembers, setFetchingMembers] = useState(true);
2626

2727
const [popupOpen, setPopupOpen] = useState(false);
2828
const [currentTable, setCurrentTable] = useState('members');
2929

3030
const organization = useSelector(organizationSelectors.myOrganization);
31-
const members = useSelector(organizationSelectors.myMembers);
32-
const memberHeaderCols = useMemberHeaderCols();
31+
// const members = useSelector(organizationSelectors.myMembers);
3332

34-
// useRequestOnMount(organizationActions.getMy);
33+
const {
34+
filteredMembers,
35+
setFilteredMembers,
36+
activeSorting,
37+
setActiveSorting,
38+
activeSortingDirection,
39+
setActiveSortingDirection,
40+
setSelectedRunIds,
41+
} = useService();
42+
43+
const memberHeaderCols = useMemberHeaderCols({
44+
filteredMembers,
45+
setFilteredMembers: setFilteredMembers,
46+
activeSorting,
47+
setActiveSorting,
48+
activeSortingDirection,
49+
setActiveSortingDirection,
50+
});
51+
// useRequestOnMount(organizationActions.getMy);
3552
useRequestOnMount(organizationActions.getRoles);
3653

3754
useEffect(() => {
38-
dispatch(organizationActions.getMembers({
55+
dispatch(
56+
organizationActions.getMembers({
3957
onSuccess: () => setFetchingMembers(false),
4058
onFailure: () => setFetchingMembers(false),
4159
}),
4260
);
43-
}, [dispatch])
61+
}, [dispatch]);
4462

4563
if (!organization) return null;
4664

4765
return (
4866
<>
49-
{popupOpen && (
50-
<InvitePopup
51-
setPopupOpen={setPopupOpen}
52-
/>
53-
)}
67+
{popupOpen && <InvitePopup setPopupOpen={setPopupOpen} />}
5468
<FlexBox.Column flex={1} style={{ width: '100%', marginLeft: '40px' }}>
55-
<FlexBox.Row marginTop='lg' alignItems="center" justifyContent="end">
69+
<FlexBox.Row marginTop="lg" alignItems="center" justifyContent="end">
5670
<Box>
5771
<PrimaryButton onClick={() => setPopupOpen(true)}>
5872
{translate('button.text')}
@@ -67,7 +81,7 @@ export const Organization: React.FC = () => {
6781
bold
6882
color={currentTable === 'members' ? 'primary' : 'darkGrey'}
6983
>
70-
{translate('members')} {`(${members.length})`}
84+
{translate('members')} {`(${filteredMembers.length})`}
7185
</Paragraph>
7286
</LinkBox>
7387
</Box>
@@ -78,7 +92,7 @@ export const Organization: React.FC = () => {
7892
headerCols={memberHeaderCols}
7993
loading={fetchingMembers}
8094
showHeader={true}
81-
tableRows={members}
95+
tableRows={filteredMembers}
8296
emptyState={{ text: translate('emptyState.text') }}
8397
/>
8498
)}

0 commit comments

Comments
 (0)