Add all filters to tables + make column width fixed (#133)
* Add additional filters on companies and people page * Make colunn width fixed * Remove duplicate declaration of Unknown type
This commit is contained in:
@ -31,10 +31,11 @@ type StyledEditModeContainerProps = {
|
|||||||
const StyledNonEditModeContainer = styled.div`
|
const StyledNonEditModeContainer = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
width: 100%;
|
width: calc(100% - ${(props) => props.theme.spacing(5)});
|
||||||
height: 100%;
|
height: 100%;
|
||||||
padding-left: ${(props) => props.theme.spacing(2)};
|
padding-left: ${(props) => props.theme.spacing(2)};
|
||||||
padding-right: ${(props) => props.theme.spacing(2)};
|
padding-right: ${(props) => props.theme.spacing(2)};
|
||||||
|
overflow: hidden;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const StyledEditModeContainer = styled.div<StyledEditModeContainerProps>`
|
const StyledEditModeContainer = styled.div<StyledEditModeContainerProps>`
|
||||||
|
|||||||
@ -21,13 +21,17 @@ const StyledContainer = styled.span`
|
|||||||
|
|
||||||
input[type='checkbox']::before {
|
input[type='checkbox']::before {
|
||||||
content: '';
|
content: '';
|
||||||
border: 1px solid ${(props) => props.theme.text80};
|
border: 1px solid ${(props) => props.theme.text40};
|
||||||
width: 12px;
|
width: 12px;
|
||||||
height: 12px;
|
height: 12px;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input[type='checkbox']:hover::before {
|
||||||
|
border: 1px solid ${(props) => props.theme.text80};
|
||||||
|
}
|
||||||
|
|
||||||
input[type='checkbox']:checked::before {
|
input[type='checkbox']:checked::before {
|
||||||
border: 1px solid ${(props) => props.theme.blue};
|
border: 1px solid ${(props) => props.theme.blue};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -43,6 +43,7 @@ const StyledTable = styled.table`
|
|||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
margin-left: ${(props) => props.theme.spacing(2)};
|
margin-left: ${(props) => props.theme.spacing(2)};
|
||||||
margin-right: ${(props) => props.theme.spacing(2)};
|
margin-right: ${(props) => props.theme.spacing(2)};
|
||||||
|
table-layout: fixed;
|
||||||
|
|
||||||
th {
|
th {
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
@ -148,7 +149,12 @@ const Table = <
|
|||||||
{table.getHeaderGroups().map((headerGroup) => (
|
{table.getHeaderGroups().map((headerGroup) => (
|
||||||
<tr key={headerGroup.id}>
|
<tr key={headerGroup.id}>
|
||||||
{headerGroup.headers.map((header) => (
|
{headerGroup.headers.map((header) => (
|
||||||
<th key={header.id}>
|
<th
|
||||||
|
key={header.id}
|
||||||
|
style={{
|
||||||
|
width: `${header.getSize()}px`,
|
||||||
|
}}
|
||||||
|
>
|
||||||
{header.isPlaceholder
|
{header.isPlaceholder
|
||||||
? null
|
? null
|
||||||
: flexRender(
|
: flexRender(
|
||||||
|
|||||||
@ -91,25 +91,27 @@ export const FilterDropdownButton = <TData extends FilterableFieldsType>({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return filterSearchResults.results.map((result, index) => (
|
return filterSearchResults.results.map((result, index) => {
|
||||||
<DropdownButton.StyledDropdownItem
|
return (
|
||||||
key={`fields-value-${index}`}
|
<DropdownButton.StyledDropdownItem
|
||||||
onClick={() => {
|
key={`fields-value-${index}`}
|
||||||
onFilterSelect({
|
onClick={() => {
|
||||||
key: selectedFilter.key,
|
onFilterSelect({
|
||||||
label: selectedFilter.label,
|
key: selectedFilter.key,
|
||||||
value: result.value,
|
label: selectedFilter.label,
|
||||||
displayValue: result.render(result.value),
|
value: result.value,
|
||||||
icon: selectedFilter.icon,
|
displayValue: result.render(result.value),
|
||||||
operand: selectedFilterOperand,
|
icon: selectedFilter.icon,
|
||||||
});
|
operand: selectedFilterOperand,
|
||||||
setIsUnfolded(false);
|
});
|
||||||
setSelectedFilter(undefined);
|
setIsUnfolded(false);
|
||||||
}}
|
setSelectedFilter(undefined);
|
||||||
>
|
}}
|
||||||
{result.render(result.value)}
|
>
|
||||||
</DropdownButton.StyledDropdownItem>
|
{result.render(result.value)}
|
||||||
));
|
</DropdownButton.StyledDropdownItem>
|
||||||
|
);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
function renderValueSelection(
|
function renderValueSelection(
|
||||||
|
|||||||
@ -20,6 +20,7 @@ const StyledChip = styled.div`
|
|||||||
padding: ${(props) => props.theme.spacing(1) + ' ' + props.theme.spacing(2)};
|
padding: ${(props) => props.theme.spacing(1) + ' ' + props.theme.spacing(2)};
|
||||||
margin-left: ${(props) => props.theme.spacing(2)};
|
margin-left: ${(props) => props.theme.spacing(2)};
|
||||||
font-size: ${(props) => props.theme.fontSizeSmall};
|
font-size: ${(props) => props.theme.fontSizeSmall};
|
||||||
|
align-items: center;
|
||||||
`;
|
`;
|
||||||
const StyledIcon = styled.div`
|
const StyledIcon = styled.div`
|
||||||
margin-right: ${(props) => props.theme.spacing(1)};
|
margin-right: ${(props) => props.theme.spacing(1)};
|
||||||
|
|||||||
@ -12,6 +12,8 @@ export type AnyEntity = {
|
|||||||
__typename: string;
|
__typename: string;
|
||||||
} & Record<string, any>;
|
} & Record<string, any>;
|
||||||
|
|
||||||
|
export type UnknownType = void;
|
||||||
|
|
||||||
export type GqlType<T> = T extends Company
|
export type GqlType<T> = T extends Company
|
||||||
? GraphqlQueryCompany
|
? GraphqlQueryCompany
|
||||||
: T extends Person
|
: T extends Person
|
||||||
|
|||||||
@ -1,10 +1,13 @@
|
|||||||
import { ReactNode } from 'react';
|
import { ReactNode } from 'react';
|
||||||
import { SearchConfigType } from '../search/interface';
|
import { SearchConfigType } from '../search/interface';
|
||||||
import { AnyEntity, BoolExpType } from '../entities/generic.interface';
|
import {
|
||||||
|
AnyEntity,
|
||||||
|
BoolExpType,
|
||||||
|
UnknownType,
|
||||||
|
} from '../entities/generic.interface';
|
||||||
|
|
||||||
export type FilterableFieldsType = AnyEntity;
|
export type FilterableFieldsType = AnyEntity;
|
||||||
export type FilterWhereRelationType = AnyEntity;
|
export type FilterWhereRelationType = AnyEntity;
|
||||||
type UnknownType = void;
|
|
||||||
export type FilterWhereType = FilterWhereRelationType | string | UnknownType;
|
export type FilterWhereType = FilterWhereRelationType | string | UnknownType;
|
||||||
|
|
||||||
export type FilterConfigType<
|
export type FilterConfigType<
|
||||||
|
|||||||
@ -1,29 +1,25 @@
|
|||||||
import { DocumentNode } from 'graphql';
|
import { DocumentNode } from 'graphql';
|
||||||
import { ReactNode } from 'react';
|
import { ReactNode } from 'react';
|
||||||
import {
|
import {
|
||||||
Companies_Bool_Exp,
|
AnyEntity,
|
||||||
People_Bool_Exp,
|
BoolExpType,
|
||||||
Users_Bool_Exp,
|
GqlType,
|
||||||
} from '../../generated/graphql';
|
UnknownType,
|
||||||
import { AnyEntity, GqlType } from '../entities/generic.interface';
|
} from '../entities/generic.interface';
|
||||||
|
|
||||||
type UnknownType = void;
|
|
||||||
|
|
||||||
export type SearchConfigType<
|
export type SearchConfigType<
|
||||||
SearchType extends AnyEntity | UnknownType = AnyEntity,
|
SearchType extends AnyEntity | UnknownType = UnknownType,
|
||||||
> = SearchType extends AnyEntity
|
> = SearchType extends UnknownType
|
||||||
? {
|
? {
|
||||||
query: DocumentNode;
|
query: DocumentNode;
|
||||||
template: (
|
template: (searchInput: string) => any;
|
||||||
searchInput: string,
|
resultMapper: (data: any) => any;
|
||||||
) => People_Bool_Exp | Companies_Bool_Exp | Users_Bool_Exp;
|
}
|
||||||
|
: {
|
||||||
|
query: DocumentNode;
|
||||||
|
template: (searchInput: string) => BoolExpType<SearchType>;
|
||||||
resultMapper: (data: GqlType<SearchType>) => {
|
resultMapper: (data: GqlType<SearchType>) => {
|
||||||
value: SearchType;
|
value: SearchType;
|
||||||
render: (value: SearchType) => ReactNode;
|
render: (value: SearchType) => ReactNode;
|
||||||
};
|
};
|
||||||
}
|
|
||||||
: {
|
|
||||||
query: DocumentNode;
|
|
||||||
template: (searchInput: string) => any;
|
|
||||||
resultMapper: (data: any) => any;
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -50,6 +50,7 @@ export const useCompaniesColumns = () => {
|
|||||||
onChange={props.row.getToggleSelectedHandler()}
|
onChange={props.row.getToggleSelectedHandler()}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
|
size: 25,
|
||||||
},
|
},
|
||||||
columnHelper.accessor('name', {
|
columnHelper.accessor('name', {
|
||||||
header: () => (
|
header: () => (
|
||||||
@ -68,6 +69,7 @@ export const useCompaniesColumns = () => {
|
|||||||
ChipComponent={CompanyChip}
|
ChipComponent={CompanyChip}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
|
size: 120,
|
||||||
}),
|
}),
|
||||||
columnHelper.accessor('employees', {
|
columnHelper.accessor('employees', {
|
||||||
header: () => (
|
header: () => (
|
||||||
@ -89,6 +91,7 @@ export const useCompaniesColumns = () => {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
|
size: 70,
|
||||||
}),
|
}),
|
||||||
columnHelper.accessor('domainName', {
|
columnHelper.accessor('domainName', {
|
||||||
header: () => (
|
header: () => (
|
||||||
@ -104,6 +107,7 @@ export const useCompaniesColumns = () => {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
|
size: 100,
|
||||||
}),
|
}),
|
||||||
columnHelper.accessor('address', {
|
columnHelper.accessor('address', {
|
||||||
header: () => (
|
header: () => (
|
||||||
@ -119,6 +123,7 @@ export const useCompaniesColumns = () => {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
|
size: 170,
|
||||||
}),
|
}),
|
||||||
columnHelper.accessor('creationDate', {
|
columnHelper.accessor('creationDate', {
|
||||||
header: () => (
|
header: () => (
|
||||||
@ -134,6 +139,7 @@ export const useCompaniesColumns = () => {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
|
size: 70,
|
||||||
}),
|
}),
|
||||||
columnHelper.accessor('accountOwner', {
|
columnHelper.accessor('accountOwner', {
|
||||||
header: () => (
|
header: () => (
|
||||||
|
|||||||
@ -4,9 +4,12 @@ import {
|
|||||||
TbLink,
|
TbLink,
|
||||||
TbMapPin,
|
TbMapPin,
|
||||||
TbSum,
|
TbSum,
|
||||||
|
TbUser,
|
||||||
} from 'react-icons/tb';
|
} from 'react-icons/tb';
|
||||||
import { Company } from '../../interfaces/entities/company.interface';
|
import { Company } from '../../interfaces/entities/company.interface';
|
||||||
import { FilterConfigType } from '../../interfaces/filters/interface';
|
import { FilterConfigType } from '../../interfaces/filters/interface';
|
||||||
|
import { SEARCH_USER_QUERY } from '../../services/api/search/search';
|
||||||
|
import { User, mapToUser } from '../../interfaces/entities/user.interface';
|
||||||
|
|
||||||
export const nameFilter = {
|
export const nameFilter = {
|
||||||
key: 'company_name',
|
key: 'company_name',
|
||||||
@ -31,6 +34,33 @@ export const nameFilter = {
|
|||||||
],
|
],
|
||||||
} satisfies FilterConfigType<Company, string>;
|
} satisfies FilterConfigType<Company, string>;
|
||||||
|
|
||||||
|
export const employeesFilter = {
|
||||||
|
key: 'company_employees',
|
||||||
|
label: 'Employees',
|
||||||
|
icon: <TbSum size={16} />,
|
||||||
|
type: 'text',
|
||||||
|
operands: [
|
||||||
|
{
|
||||||
|
label: 'Greater than',
|
||||||
|
id: 'greater_than',
|
||||||
|
whereTemplate: (searchString) => ({
|
||||||
|
employees: {
|
||||||
|
_gte: isNaN(Number(searchString)) ? undefined : Number(searchString),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Less than',
|
||||||
|
id: 'less_than',
|
||||||
|
whereTemplate: (searchString) => ({
|
||||||
|
employees: {
|
||||||
|
_lte: isNaN(Number(searchString)) ? undefined : Number(searchString),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
} satisfies FilterConfigType<Company, string>;
|
||||||
|
|
||||||
export const urlFilter = {
|
export const urlFilter = {
|
||||||
key: 'company_domain_name',
|
key: 'company_domain_name',
|
||||||
label: 'Url',
|
label: 'Url',
|
||||||
@ -77,33 +107,6 @@ export const addressFilter = {
|
|||||||
],
|
],
|
||||||
} satisfies FilterConfigType<Company, string>;
|
} satisfies FilterConfigType<Company, string>;
|
||||||
|
|
||||||
export const employeesFilter = {
|
|
||||||
key: 'company_employees',
|
|
||||||
label: 'Employees',
|
|
||||||
icon: <TbSum size={16} />,
|
|
||||||
type: 'text',
|
|
||||||
operands: [
|
|
||||||
{
|
|
||||||
label: 'Greater than',
|
|
||||||
id: 'greater_than',
|
|
||||||
whereTemplate: (searchString) => ({
|
|
||||||
employees: {
|
|
||||||
_gte: isNaN(Number(searchString)) ? undefined : Number(searchString),
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Less than',
|
|
||||||
id: 'less_than',
|
|
||||||
whereTemplate: (searchString) => ({
|
|
||||||
employees: {
|
|
||||||
_lte: isNaN(Number(searchString)) ? undefined : Number(searchString),
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
} satisfies FilterConfigType<Company, string>;
|
|
||||||
|
|
||||||
export const creationDateFilter = {
|
export const creationDateFilter = {
|
||||||
key: 'company_created_at',
|
key: 'company_created_at',
|
||||||
label: 'Created At',
|
label: 'Created At',
|
||||||
@ -131,10 +134,45 @@ export const creationDateFilter = {
|
|||||||
],
|
],
|
||||||
} satisfies FilterConfigType<Company, string>;
|
} satisfies FilterConfigType<Company, string>;
|
||||||
|
|
||||||
|
export const accountOwnerFilter = {
|
||||||
|
key: 'account_owner_name',
|
||||||
|
label: 'Account Owner',
|
||||||
|
icon: <TbUser size={16} />,
|
||||||
|
type: 'relation',
|
||||||
|
searchConfig: {
|
||||||
|
query: SEARCH_USER_QUERY,
|
||||||
|
template: (searchString: string) => ({
|
||||||
|
displayName: { _ilike: `%${searchString}%` },
|
||||||
|
}),
|
||||||
|
resultMapper: (data) => ({
|
||||||
|
value: mapToUser(data),
|
||||||
|
render: (owner) => owner.displayName,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
selectedValueRender: (owner) => owner.displayName || '',
|
||||||
|
operands: [
|
||||||
|
{
|
||||||
|
label: 'Is',
|
||||||
|
id: 'is',
|
||||||
|
whereTemplate: (owner) => ({
|
||||||
|
account_owner: { displayName: { _eq: owner.displayName } },
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Is not',
|
||||||
|
id: 'is_not',
|
||||||
|
whereTemplate: (owner) => ({
|
||||||
|
_not: { account_owner: { displayName: { _eq: owner.displayName } } },
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
} satisfies FilterConfigType<Company, User>;
|
||||||
|
|
||||||
export const availableFilters = [
|
export const availableFilters = [
|
||||||
nameFilter,
|
nameFilter,
|
||||||
|
employeesFilter,
|
||||||
urlFilter,
|
urlFilter,
|
||||||
addressFilter,
|
addressFilter,
|
||||||
employeesFilter,
|
|
||||||
creationDateFilter,
|
creationDateFilter,
|
||||||
|
accountOwnerFilter,
|
||||||
];
|
];
|
||||||
|
|||||||
@ -53,6 +53,7 @@ export const usePeopleColumns = () => {
|
|||||||
onChange={props.row.getToggleSelectedHandler()}
|
onChange={props.row.getToggleSelectedHandler()}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
|
size: 25,
|
||||||
},
|
},
|
||||||
columnHelper.accessor('firstname', {
|
columnHelper.accessor('firstname', {
|
||||||
header: () => (
|
header: () => (
|
||||||
@ -70,6 +71,7 @@ export const usePeopleColumns = () => {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
|
size: 200,
|
||||||
}),
|
}),
|
||||||
columnHelper.accessor('email', {
|
columnHelper.accessor('email', {
|
||||||
header: () => (
|
header: () => (
|
||||||
@ -86,6 +88,7 @@ export const usePeopleColumns = () => {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
|
size: 200,
|
||||||
}),
|
}),
|
||||||
columnHelper.accessor('company', {
|
columnHelper.accessor('company', {
|
||||||
header: () => (
|
header: () => (
|
||||||
@ -125,6 +128,7 @@ export const usePeopleColumns = () => {
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
|
size: 150,
|
||||||
}),
|
}),
|
||||||
columnHelper.accessor('phone', {
|
columnHelper.accessor('phone', {
|
||||||
header: () => (
|
header: () => (
|
||||||
@ -141,6 +145,7 @@ export const usePeopleColumns = () => {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
|
size: 130,
|
||||||
}),
|
}),
|
||||||
columnHelper.accessor('creationDate', {
|
columnHelper.accessor('creationDate', {
|
||||||
header: () => (
|
header: () => (
|
||||||
@ -156,6 +161,7 @@ export const usePeopleColumns = () => {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
|
size: 100,
|
||||||
}),
|
}),
|
||||||
columnHelper.accessor('city', {
|
columnHelper.accessor('city', {
|
||||||
header: () => (
|
header: () => (
|
||||||
|
|||||||
@ -5,7 +5,14 @@ import {
|
|||||||
mapToCompany,
|
mapToCompany,
|
||||||
} from '../../interfaces/entities/company.interface';
|
} from '../../interfaces/entities/company.interface';
|
||||||
import { FilterConfigType } from '../../interfaces/filters/interface';
|
import { FilterConfigType } from '../../interfaces/filters/interface';
|
||||||
import { TbBuilding, TbMail, TbMapPin, TbUser } from 'react-icons/tb';
|
import {
|
||||||
|
TbBuilding,
|
||||||
|
TbCalendar,
|
||||||
|
TbMail,
|
||||||
|
TbMapPin,
|
||||||
|
TbPhone,
|
||||||
|
TbUser,
|
||||||
|
} from 'react-icons/tb';
|
||||||
|
|
||||||
export const fullnameFilter = {
|
export const fullnameFilter = {
|
||||||
key: 'fullname',
|
key: 'fullname',
|
||||||
@ -38,6 +45,29 @@ export const fullnameFilter = {
|
|||||||
],
|
],
|
||||||
} satisfies FilterConfigType<Person, string>;
|
} satisfies FilterConfigType<Person, string>;
|
||||||
|
|
||||||
|
export const emailFilter = {
|
||||||
|
key: 'email',
|
||||||
|
label: 'Email',
|
||||||
|
icon: <TbMail size={16} />,
|
||||||
|
type: 'text',
|
||||||
|
operands: [
|
||||||
|
{
|
||||||
|
label: 'Contains',
|
||||||
|
id: 'like',
|
||||||
|
whereTemplate: (searchString) => ({
|
||||||
|
email: { _ilike: `%${searchString}%` },
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Does not contain',
|
||||||
|
id: 'not_like',
|
||||||
|
whereTemplate: (searchString) => ({
|
||||||
|
_not: { email: { _ilike: `%${searchString}%` } },
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
} satisfies FilterConfigType<Person, string>;
|
||||||
|
|
||||||
export const companyFilter = {
|
export const companyFilter = {
|
||||||
key: 'company_name',
|
key: 'company_name',
|
||||||
label: 'Company',
|
label: 'Company',
|
||||||
@ -72,29 +102,56 @@ export const companyFilter = {
|
|||||||
],
|
],
|
||||||
} satisfies FilterConfigType<Person, Company>;
|
} satisfies FilterConfigType<Person, Company>;
|
||||||
|
|
||||||
export const emailFilter = {
|
export const phoneFilter = {
|
||||||
key: 'email',
|
key: 'phone',
|
||||||
label: 'Email',
|
label: 'Phone',
|
||||||
icon: <TbMail size={16} />,
|
icon: <TbPhone size={16} />,
|
||||||
type: 'text',
|
type: 'text',
|
||||||
operands: [
|
operands: [
|
||||||
{
|
{
|
||||||
label: 'Contains',
|
label: 'Contains',
|
||||||
id: 'like',
|
id: 'like',
|
||||||
whereTemplate: (searchString) => ({
|
whereTemplate: (searchString) => ({
|
||||||
email: { _ilike: `%${searchString}%` },
|
phone: { _ilike: `%${searchString}%` },
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Does not contain',
|
label: 'Does not contain',
|
||||||
id: 'not_like',
|
id: 'not_like',
|
||||||
whereTemplate: (searchString) => ({
|
whereTemplate: (searchString) => ({
|
||||||
_not: { email: { _ilike: `%${searchString}%` } },
|
_not: { phone: { _ilike: `%${searchString}%` } },
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
} satisfies FilterConfigType<Person, string>;
|
} satisfies FilterConfigType<Person, string>;
|
||||||
|
|
||||||
|
export const creationDateFilter = {
|
||||||
|
key: 'person_created_at',
|
||||||
|
label: 'Created At',
|
||||||
|
icon: <TbCalendar size={16} />,
|
||||||
|
type: 'date',
|
||||||
|
operands: [
|
||||||
|
{
|
||||||
|
label: 'Greater than',
|
||||||
|
id: 'greater_than',
|
||||||
|
whereTemplate: (searchString) => ({
|
||||||
|
created_at: {
|
||||||
|
_gte: searchString,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Less than',
|
||||||
|
id: 'less_than',
|
||||||
|
whereTemplate: (searchString) => ({
|
||||||
|
created_at: {
|
||||||
|
_lte: searchString,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
} satisfies FilterConfigType<Company, string>;
|
||||||
|
|
||||||
export const cityFilter = {
|
export const cityFilter = {
|
||||||
key: 'city',
|
key: 'city',
|
||||||
label: 'City',
|
label: 'City',
|
||||||
@ -120,7 +177,9 @@ export const cityFilter = {
|
|||||||
|
|
||||||
export const availableFilters = [
|
export const availableFilters = [
|
||||||
fullnameFilter,
|
fullnameFilter,
|
||||||
companyFilter,
|
|
||||||
emailFilter,
|
emailFilter,
|
||||||
|
companyFilter,
|
||||||
|
phoneFilter,
|
||||||
|
creationDateFilter,
|
||||||
cityFilter,
|
cityFilter,
|
||||||
] satisfies FilterConfigType<Person>[];
|
] satisfies FilterConfigType<Person>[];
|
||||||
|
|||||||
@ -1,7 +1,10 @@
|
|||||||
import { gql, useQuery } from '@apollo/client';
|
import { gql, useQuery } from '@apollo/client';
|
||||||
import { useMemo, useState } from 'react';
|
import { useMemo, useState } from 'react';
|
||||||
import { SearchConfigType } from '../../../interfaces/search/interface';
|
import { SearchConfigType } from '../../../interfaces/search/interface';
|
||||||
import { AnyEntity } from '../../../interfaces/entities/generic.interface';
|
import {
|
||||||
|
AnyEntity,
|
||||||
|
UnknownType,
|
||||||
|
} from '../../../interfaces/entities/generic.interface';
|
||||||
|
|
||||||
export const SEARCH_PEOPLE_QUERY = gql`
|
export const SEARCH_PEOPLE_QUERY = gql`
|
||||||
query SearchPeopleQuery($where: people_bool_exp, $limit: Int) {
|
query SearchPeopleQuery($where: people_bool_exp, $limit: Int) {
|
||||||
@ -58,15 +61,16 @@ const debounce = <FuncArgs extends any[]>(
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export type SearchResultsType<T extends AnyEntity = AnyEntity> = {
|
export type SearchResultsType<T extends AnyEntity | UnknownType = UnknownType> =
|
||||||
results: {
|
{
|
||||||
render: (value: T) => string;
|
results: {
|
||||||
value: T;
|
render: (value: T) => string;
|
||||||
}[];
|
value: T;
|
||||||
loading: boolean;
|
}[];
|
||||||
};
|
loading: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
export const useSearch = <T extends AnyEntity = AnyEntity>(): [
|
export const useSearch = <T extends AnyEntity | UnknownType = UnknownType>(): [
|
||||||
SearchResultsType<T>,
|
SearchResultsType<T>,
|
||||||
React.Dispatch<React.SetStateAction<string>>,
|
React.Dispatch<React.SetStateAction<string>>,
|
||||||
React.Dispatch<React.SetStateAction<SearchConfigType<T> | null>>,
|
React.Dispatch<React.SetStateAction<SearchConfigType<T> | null>>,
|
||||||
|
|||||||
Reference in New Issue
Block a user