Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sites Management Dashboard: add search mechanism #65505

Merged
merged 10 commits into from
Jul 14, 2022
8 changes: 1 addition & 7 deletions client/components/search-sites/index.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
import { get } from 'lodash';
import { Component } from 'react';
import { connect } from 'react-redux';
import getSites from 'calypso/state/selectors/get-sites';

const matches = ( item, term, keys ) =>
keys.some( ( key ) => get( item, key, '' ).toLowerCase().indexOf( term ) > -1 );

const searchCollection = ( collection, term, keys ) =>
collection.filter( ( item ) => matches( item, term, keys ) );
import { searchCollection } from './utils';

const mapState = ( state ) => ( {
sites: getSites( state ),
Expand Down
13 changes: 13 additions & 0 deletions client/components/search-sites/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
const matches = < T >( item: T, term: string, keys: ( keyof T )[] ) =>
keys.some( ( key ) => {
const value = item[ key ];

if ( ! value || typeof value !== 'string' ) {
return false;
}

return value.toLowerCase().indexOf( term ) > -1;
} );

export const searchCollection = < T >( collection: T[], term: string, keys: ( keyof T )[] ) =>
collection.filter( ( item ) => item && matches( item, term, keys ) );
53 changes: 53 additions & 0 deletions client/sites-dashboard/components/searchable-sites-table.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { ClassNames } from '@emotion/react';
import { useI18n } from '@wordpress/react-i18n';
import { useMemo, useState } from 'react';
import { searchCollection } from 'calypso/components/search-sites/utils';
import { SitesSearch } from './sites-search';
import { SitesSearchIcon } from './sites-search-icon';
import { SitesTable } from './sites-table';
import type { SiteData } from 'calypso/state/ui/selectors/site-data';

interface SearchableSitesTableProps {
sites: SiteData[];
}

export function SearchableSitesTable( { sites }: SearchableSitesTableProps ) {
const { __ } = useI18n();

const [ term, setTerm ] = useState( '' );

const filteredSites = useMemo( () => {
if ( ! term ) {
return sites;
}

return searchCollection( sites, term.toLowerCase(), [ 'URL', 'domain', 'name', 'slug' ] );
}, [ term, sites ] );

const handleSearch = ( rawTerm: string ) => setTerm( rawTerm.trim() );

return (
<ClassNames>
{ ( { css } ) => (
<>
<div
className={ css`
margin: 32px 0;
width: 286px;
max-width: 100%;
` }
>
<SitesSearch
searchIcon={ <SitesSearchIcon /> }
onSearch={ handleSearch }
delaySearch
isReskinned
placeholder={ __( 'Search by name or domain…' ) }
/>
</div>
<SitesTable sites={ filteredSites } />
</>
) }
</ClassNames>
);
}
15 changes: 2 additions & 13 deletions client/sites-dashboard/components/sites-dashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { useI18n } from '@wordpress/react-i18n';
import { useSelector } from 'react-redux';
import getSites from 'calypso/state/selectors/get-sites';
import { notNullish } from '../util';
import { SitesTable } from './sites-table';
import { SearchableSitesTable } from './searchable-sites-table';
import { SitesTableFilterTabs } from './sites-table-filter-tabs';

interface SitesDashboardProps {
Expand Down Expand Up @@ -85,18 +85,7 @@ export function SitesDashboard( { launchStatus }: SitesDashboardProps ) {
` }
launchStatus={ launchStatus }
>
{ ( filteredSites ) => (
<ClassNames>
{ ( { css } ) => (
<SitesTable
className={ css`
margin-top: 32px;
` }
sites={ filteredSites }
/>
) }
</ClassNames>
) }
{ ( filteredSites ) => <SearchableSitesTable sites={ filteredSites } /> }
</SitesTableFilterTabs>
) }
</ClassNames>
Expand Down
32 changes: 32 additions & 0 deletions client/sites-dashboard/components/sites-search-icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
export const SitesSearchIcon = () => {
return (
<svg
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
style={ {
paddingLeft: '16px',
paddingRight: '10px',
height: '100%',
backgroundColor: 'var( --color-surface )',
} }
>
<path
d="M9.16667 15.8333C12.8486 15.8333 15.8333 12.8486 15.8333 9.16667C15.8333 5.48477 12.8486 2.5 9.16667 2.5C5.48477 2.5 2.5 5.48477 2.5 9.16667C2.5 12.8486 5.48477 15.8333 9.16667 15.8333Z"
stroke="#8C8F94"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M17.5 17.5L13.875 13.875"
stroke="#8C8F94"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
);
};
14 changes: 14 additions & 0 deletions client/sites-dashboard/components/sites-search.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import Search from '@automattic/search';
import styled from '@emotion/styled';

export const SitesSearch = styled( Search )`
--color-surface: #f6f7f7;
zaguiini marked this conversation as resolved.
Show resolved Hide resolved
border-radius: 4px;
overflow: hidden;
height: 44px;

// TODO: make the fade optional in the component
.search-component__input-fade::before {
zaguiini marked this conversation as resolved.
Show resolved Hide resolved
display: none !important;
}
`;
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ interface SiteTab extends Omit< TabPanel.Tab, 'title' > {
const SitesTabPanel = styled( TabPanel )`
.components-tab-panel__tabs {
overflow-x: auto;
padding-bottom: 10px;
}

.components-tab-panel__tabs-item {
Expand Down