Merge pull request #67 from twentyhq/sammy/t-129-i-see-all-text-sorts-available-in-the
feature: Add all sortable fields of People table
This commit is contained in:
@ -17,6 +17,7 @@ type OwnProps<TData> = {
|
|||||||
viewName: string;
|
viewName: string;
|
||||||
viewIcon?: IconProp;
|
viewIcon?: IconProp;
|
||||||
onSortsUpdate?: (sorts: Array<SortType>) => void;
|
onSortsUpdate?: (sorts: Array<SortType>) => void;
|
||||||
|
sortsAvailable?: Array<SortType>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const StyledTable = styled.table`
|
const StyledTable = styled.table`
|
||||||
@ -68,6 +69,7 @@ function Table<TData>({
|
|||||||
viewName,
|
viewName,
|
||||||
viewIcon,
|
viewIcon,
|
||||||
onSortsUpdate,
|
onSortsUpdate,
|
||||||
|
sortsAvailable,
|
||||||
}: OwnProps<TData>) {
|
}: OwnProps<TData>) {
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
data,
|
data,
|
||||||
@ -81,6 +83,7 @@ function Table<TData>({
|
|||||||
viewName={viewName}
|
viewName={viewName}
|
||||||
viewIcon={viewIcon}
|
viewIcon={viewIcon}
|
||||||
onSortsUpdate={onSortsUpdate}
|
onSortsUpdate={onSortsUpdate}
|
||||||
|
sortsAvailable={sortsAvailable || []}
|
||||||
/>
|
/>
|
||||||
<StyledTable>
|
<StyledTable>
|
||||||
<thead>
|
<thead>
|
||||||
|
|||||||
@ -15,6 +15,7 @@ const StyledDropdownButtonContainer = styled.div`
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
type StyledDropdownButtonProps = {
|
type StyledDropdownButtonProps = {
|
||||||
@ -36,16 +37,33 @@ const StyledDropdownButton = styled.div<StyledDropdownButtonProps>`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const StyledDropdown = styled.ul`
|
const StyledDropdown = styled.ul`
|
||||||
|
--wraper-border: 1px;
|
||||||
|
--wraper-border-radius: 8px;
|
||||||
|
--outer-border-radius: calc(var(--wraper-border-radius) - 2px);
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 14px;
|
top: 14px;
|
||||||
right: 0;
|
right: 0;
|
||||||
border: 1px solid ${(props) => props.theme.primaryBorder};
|
border: var(--wraper-border) solid ${(props) => props.theme.primaryBorder};
|
||||||
box-shadow: 0px 3px 12px rgba(0, 0, 0, 0.09);
|
box-shadow: 0px 3px 12px rgba(0, 0, 0, 0.09);
|
||||||
border-radius: 8px;
|
border-radius: var(--wraper-border-radius);
|
||||||
padding: 0px;
|
padding: 0px;
|
||||||
min-width: 160px;
|
min-width: 160px;
|
||||||
${modalBackground}
|
${modalBackground}
|
||||||
|
li {
|
||||||
|
border-radius: 2px;
|
||||||
|
|
||||||
|
&:first-child {
|
||||||
|
border-top-left-radius: var(--outer-border-radius);
|
||||||
|
border-top-right-radius: var(--outer-border-radius);
|
||||||
|
}
|
||||||
|
&:last-child {
|
||||||
|
border-bottom-left-radius: var(--outer-border-radius);
|
||||||
|
border-bottom-right-radius: var(--outer-border-radius);
|
||||||
|
}
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const StyledDropdownItem = styled.li`
|
const StyledDropdownItem = styled.li`
|
||||||
@ -53,14 +71,12 @@ const StyledDropdownItem = styled.li`
|
|||||||
padding: ${(props) => props.theme.spacing(2)}
|
padding: ${(props) => props.theme.spacing(2)}
|
||||||
calc(${(props) => props.theme.spacing(2)} - 2px);
|
calc(${(props) => props.theme.spacing(2)} - 2px);
|
||||||
margin: 2px;
|
margin: 2px;
|
||||||
background: ${(props) => props.theme.primaryBackground};
|
background: rgba(0, 0, 0, 0);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
width: 100%;
|
|
||||||
border-radius: 4px;
|
|
||||||
color: ${(props) => props.theme.text60};
|
color: ${(props) => props.theme.text60};
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
filter: brightness(0.95);
|
background: rgba(0, 0, 0, 0.04);
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|||||||
@ -8,10 +8,10 @@ type OwnProps = {
|
|||||||
onRemoveSort: (sortId: string) => void;
|
onRemoveSort: (sortId: string) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type SortType = {
|
export type SortType<SortIds = string> = {
|
||||||
label: string;
|
label: string;
|
||||||
order: 'asc' | 'desc';
|
order: 'asc' | 'desc';
|
||||||
id: string;
|
id: SortIds;
|
||||||
icon?: IconProp;
|
icon?: IconProp;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -2,14 +2,14 @@ import styled from '@emotion/styled';
|
|||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import DropdownButton from './DropdownButton';
|
import DropdownButton from './DropdownButton';
|
||||||
import { IconProp } from '@fortawesome/fontawesome-svg-core';
|
import { IconProp } from '@fortawesome/fontawesome-svg-core';
|
||||||
import { faCalendar } from '@fortawesome/pro-regular-svg-icons';
|
|
||||||
import SortAndFilterBar, { SortType } from './SortAndFilterBar';
|
import SortAndFilterBar, { SortType } from './SortAndFilterBar';
|
||||||
import { useEffect, useState } from 'react';
|
import { useCallback, useState } from 'react';
|
||||||
|
|
||||||
type OwnProps = {
|
type OwnProps = {
|
||||||
viewName: string;
|
viewName: string;
|
||||||
viewIcon?: IconProp;
|
viewIcon?: IconProp;
|
||||||
onSortsUpdate?: (sorts: Array<SortType>) => void;
|
onSortsUpdate?: (sorts: Array<SortType>) => void;
|
||||||
|
sortsAvailable: Array<SortType>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const StyledContainer = styled.div`
|
const StyledContainer = styled.div`
|
||||||
@ -44,34 +44,37 @@ const StyledFilters = styled.div`
|
|||||||
margin-right: ${(props) => props.theme.spacing(2)};
|
margin-right: ${(props) => props.theme.spacing(2)};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
function TableHeader({ viewName, viewIcon, onSortsUpdate }: OwnProps) {
|
function TableHeader({
|
||||||
|
viewName,
|
||||||
|
viewIcon,
|
||||||
|
onSortsUpdate,
|
||||||
|
sortsAvailable,
|
||||||
|
}: OwnProps) {
|
||||||
const [sorts, setSorts] = useState([] as Array<SortType>);
|
const [sorts, setSorts] = useState([] as Array<SortType>);
|
||||||
|
|
||||||
const onSortItemSelect = (sortId: string) => {
|
const onSortItemSelect = useCallback(
|
||||||
setSorts([
|
(sortId: string) => {
|
||||||
{
|
const newSorts = [
|
||||||
label: 'Created at',
|
{
|
||||||
order: 'asc',
|
label: 'Created at',
|
||||||
id: sortId,
|
order: 'asc',
|
||||||
} as SortType,
|
id: sortId,
|
||||||
]);
|
} satisfies SortType,
|
||||||
};
|
];
|
||||||
const onSortItemUnSelect = (sortId: string) => {
|
setSorts(newSorts);
|
||||||
setSorts([]);
|
onSortsUpdate && onSortsUpdate(newSorts);
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
onSortsUpdate && onSortsUpdate(sorts);
|
|
||||||
}, [sorts, onSortsUpdate]);
|
|
||||||
|
|
||||||
const sortsAvailable: Array<SortType> = [
|
|
||||||
{
|
|
||||||
id: 'created_at',
|
|
||||||
label: 'Created at',
|
|
||||||
order: 'asc',
|
|
||||||
icon: faCalendar,
|
|
||||||
},
|
},
|
||||||
];
|
[onSortsUpdate],
|
||||||
|
);
|
||||||
|
|
||||||
|
const onSortItemUnSelect = useCallback(
|
||||||
|
(sortId: string) => {
|
||||||
|
const newSorts = [] as SortType[];
|
||||||
|
setSorts(newSorts);
|
||||||
|
onSortsUpdate && onSortsUpdate(newSorts);
|
||||||
|
},
|
||||||
|
[onSortsUpdate],
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledContainer>
|
<StyledContainer>
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
import TableHeader from '../TableHeader';
|
import TableHeader from '../TableHeader';
|
||||||
import { ThemeProvider } from '@emotion/react';
|
import { ThemeProvider } from '@emotion/react';
|
||||||
import { lightTheme } from '../../../../layout/styles/themes';
|
import { lightTheme } from '../../../../layout/styles/themes';
|
||||||
import { faBuilding } from '@fortawesome/pro-regular-svg-icons';
|
import { faBuilding, faCalendar } from '@fortawesome/pro-regular-svg-icons';
|
||||||
|
import { SortType } from '../SortAndFilterBar';
|
||||||
|
|
||||||
const component = {
|
const component = {
|
||||||
title: 'TableHeader',
|
title: 'TableHeader',
|
||||||
@ -11,9 +12,21 @@ const component = {
|
|||||||
export default component;
|
export default component;
|
||||||
|
|
||||||
export const RegularTableHeader = () => {
|
export const RegularTableHeader = () => {
|
||||||
|
const sortsAvailable: Array<SortType> = [
|
||||||
|
{
|
||||||
|
id: 'created_at',
|
||||||
|
label: 'Created at',
|
||||||
|
order: 'asc',
|
||||||
|
icon: faCalendar,
|
||||||
|
},
|
||||||
|
];
|
||||||
return (
|
return (
|
||||||
<ThemeProvider theme={lightTheme}>
|
<ThemeProvider theme={lightTheme}>
|
||||||
<TableHeader viewName="Test" viewIcon={faBuilding} />
|
<TableHeader
|
||||||
|
viewName="Test"
|
||||||
|
viewIcon={faBuilding}
|
||||||
|
sortsAvailable={sortsAvailable}
|
||||||
|
/>
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import React from 'react';
|
import React, { StrictMode } from 'react';
|
||||||
import ReactDOM from 'react-dom/client';
|
import ReactDOM from 'react-dom/client';
|
||||||
import './index.css';
|
import './index.css';
|
||||||
import App from './App';
|
import App from './App';
|
||||||
@ -14,7 +14,9 @@ const root = ReactDOM.createRoot(
|
|||||||
root.render(
|
root.render(
|
||||||
<ApolloProvider client={apiClient}>
|
<ApolloProvider client={apiClient}>
|
||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
<App />
|
<StrictMode>
|
||||||
|
<App />
|
||||||
|
</StrictMode>
|
||||||
</BrowserRouter>
|
</BrowserRouter>
|
||||||
</ApolloProvider>,
|
</ApolloProvider>,
|
||||||
);
|
);
|
||||||
|
|||||||
@ -2,9 +2,9 @@ import { faUser, faList } from '@fortawesome/pro-regular-svg-icons';
|
|||||||
import WithTopBarContainer from '../../layout/containers/WithTopBarContainer';
|
import WithTopBarContainer from '../../layout/containers/WithTopBarContainer';
|
||||||
import Table from '../../components/table/Table';
|
import Table from '../../components/table/Table';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { peopleColumns } from './people-table';
|
import { peopleColumns, sortsAvailable } from './people-table';
|
||||||
import { mapPerson } from '../../interfaces/person.interface';
|
import { mapPerson } from '../../interfaces/person.interface';
|
||||||
import { useState } from 'react';
|
import { useCallback, useState } from 'react';
|
||||||
import { SortType } from '../../components/table/table-header/SortAndFilterBar';
|
import { SortType } from '../../components/table/table-header/SortAndFilterBar';
|
||||||
import { OrderBy, usePeopleQuery } from '../../services/people';
|
import { OrderBy, usePeopleQuery } from '../../services/people';
|
||||||
|
|
||||||
@ -31,10 +31,10 @@ function People() {
|
|||||||
const [, setSorts] = useState([] as Array<SortType>);
|
const [, setSorts] = useState([] as Array<SortType>);
|
||||||
const [orderBy, setOrderBy] = useState(defaultOrderBy);
|
const [orderBy, setOrderBy] = useState(defaultOrderBy);
|
||||||
|
|
||||||
const updateSorts = (sorts: Array<SortType>) => {
|
const updateSorts = useCallback((sorts: Array<SortType>) => {
|
||||||
setSorts(sorts);
|
setSorts(sorts);
|
||||||
setOrderBy(sorts.length ? reduceSortsToOrderBy(sorts) : defaultOrderBy);
|
setOrderBy(sorts.length ? reduceSortsToOrderBy(sorts) : defaultOrderBy);
|
||||||
};
|
}, []);
|
||||||
|
|
||||||
const { data } = usePeopleQuery(orderBy);
|
const { data } = usePeopleQuery(orderBy);
|
||||||
|
|
||||||
@ -48,6 +48,7 @@ function People() {
|
|||||||
viewName="All People"
|
viewName="All People"
|
||||||
viewIcon={faList}
|
viewIcon={faList}
|
||||||
onSortsUpdate={updateSorts}
|
onSortsUpdate={updateSorts}
|
||||||
|
sortsAvailable={sortsAvailable}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
</StyledPeopleContainer>
|
</StyledPeopleContainer>
|
||||||
|
|||||||
@ -15,8 +15,26 @@ import Checkbox from '../../components/form/Checkbox';
|
|||||||
import HorizontalyAlignedContainer from '../../layout/containers/HorizontalyAlignedContainer';
|
import HorizontalyAlignedContainer from '../../layout/containers/HorizontalyAlignedContainer';
|
||||||
import CompanyChip from '../../components/chips/CompanyChip';
|
import CompanyChip from '../../components/chips/CompanyChip';
|
||||||
import PersonChip from '../../components/chips/PersonChip';
|
import PersonChip from '../../components/chips/PersonChip';
|
||||||
import { Person } from '../../interfaces/person.interface';
|
import { GraphqlPerson, Person } from '../../interfaces/person.interface';
|
||||||
import PipeChip from '../../components/chips/PipeChip';
|
import PipeChip from '../../components/chips/PipeChip';
|
||||||
|
import { SortType } from '../../components/table/table-header/SortAndFilterBar';
|
||||||
|
|
||||||
|
export const sortsAvailable = [
|
||||||
|
{
|
||||||
|
id: 'email',
|
||||||
|
label: 'Email',
|
||||||
|
order: 'asc',
|
||||||
|
icon: faEnvelope,
|
||||||
|
},
|
||||||
|
{ id: 'phone', label: 'Phone', order: 'asc', icon: faPhone },
|
||||||
|
{
|
||||||
|
id: 'created_at',
|
||||||
|
label: 'Created at',
|
||||||
|
order: 'asc',
|
||||||
|
icon: faCalendar,
|
||||||
|
},
|
||||||
|
{ id: 'city', label: 'City', order: 'asc', icon: faMapPin },
|
||||||
|
] satisfies Array<SortType<keyof GraphqlPerson>>;
|
||||||
|
|
||||||
const columnHelper = createColumnHelper<Person>();
|
const columnHelper = createColumnHelper<Person>();
|
||||||
export const peopleColumns = [
|
export const peopleColumns = [
|
||||||
|
|||||||
Reference in New Issue
Block a user