Skip to content

Commit d34bf28

Browse files
epeichersejas
andauthored
Add loading and empty placeholders to the list of sites (#2190)
- Extracts the content of the `SyncSitesSelector` modal to an external component and uses it as part of the `pull-remote-site` component so both uses the same `Loading...` and _empty search_ logic - Adds a [new Gutenberg color](https://github.com/WordPress/gutenberg/blob/80739d1c14df3419bfabe53fbc2963a687de4644/packages/base-styles/_colors.scss#L7) to use the same style than in the [Gutenberg modal](https://github.com/WordPress/gutenberg/blob/728f06a3216bcbea37e7ba4e95636f62c0c78184/packages/components/src/modal/style.scss#L41) --------- Co-authored-by: Antonio Sejas <antonio.sejas@automattic.com>
1 parent 925ac7b commit d34bf28

File tree

3 files changed

+68
-54
lines changed

3 files changed

+68
-54
lines changed

src/modules/add-site/components/pull-remote-site.tsx

Lines changed: 10 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {
44
} from '@wordpress/components';
55
import { check, Icon } from '@wordpress/icons';
66
import { useI18n } from '@wordpress/react-i18n';
7-
import { PropsWithChildren, useState } from 'react';
7+
import { PropsWithChildren } from 'react';
88
import { ArrowIcon } from 'src/components/arrow-icon';
99
import Button from 'src/components/button';
1010
import offlineIcon from 'src/components/offline-icon';
@@ -13,7 +13,7 @@ import { useAuth } from 'src/hooks/use-auth';
1313
import { useOffline } from 'src/hooks/use-offline';
1414
import { useSiteDetails } from 'src/hooks/use-site-details';
1515
import { getIpcApi } from 'src/lib/get-ipc-api';
16-
import { ListSites, SearchSites } from 'src/modules/sync/components/sync-sites-modal-selector';
16+
import { SitesListContent } from 'src/modules/sync/components/sync-sites-modal-selector';
1717
import { SyncTabImage } from 'src/modules/sync/components/sync-tab-image';
1818
import { useGetConnectedSitesForLocalSiteQuery } from 'src/stores/sync/connected-sites';
1919
import { useGetWpComSitesQuery } from 'src/stores/sync/wpcom-sites';
@@ -127,24 +127,14 @@ export function PullRemoteSite( {
127127
userId: user?.id,
128128
} );
129129
const connectedSiteIds = connectedSites.map( ( { id } ) => id );
130-
const { data: syncSites = [] } = useGetWpComSitesQuery(
130+
const { data: syncSites = [], isLoading } = useGetWpComSitesQuery(
131131
{
132132
connectedSiteIds,
133133
userId: user?.id,
134134
},
135135
{ refetchOnMountOrArgChange: true }
136136
);
137137

138-
const [ searchQuery, setSearchQuery ] = useState< string >( '' );
139-
140-
const filteredSites = syncSites.filter( ( site ) => {
141-
const searchQueryLower = searchQuery.toLowerCase();
142-
return (
143-
site.name?.toLowerCase().includes( searchQueryLower ) ||
144-
site.url?.toLowerCase().includes( searchQueryLower )
145-
);
146-
} );
147-
148138
const handleSiteSelect = ( siteId: number ) => {
149139
const site = syncSites.find( ( s ) => s.id === siteId );
150140
setSelectedRemoteSite( site );
@@ -156,15 +146,13 @@ export function PullRemoteSite( {
156146
{ __( 'Pull an existing site' ) }
157147
</Heading>
158148
{ isAuthenticated ? (
159-
<VStack className="flex flex-col w-full max-w-[650px] flex-1">
160-
<SearchSites searchQuery={ searchQuery } setSearchQuery={ setSearchQuery } />
161-
<div className="h-full">
162-
<ListSites
163-
syncSites={ filteredSites }
164-
selectedSiteId={ selectedRemoteSite?.id || null }
165-
onSelectSite={ handleSiteSelect }
166-
/>
167-
</div>
149+
<VStack className="flex flex-col w-full max-w-[650px] flex-1 text-a8c-gray-900">
150+
<SitesListContent
151+
isLoading={ isLoading }
152+
syncSites={ syncSites }
153+
selectedSiteId={ selectedRemoteSite?.id || null }
154+
onSelectSite={ handleSiteSelect }
155+
/>
168156
</VStack>
169157
) : (
170158
<NoAuthPullRemoteSiteView />

src/modules/sync/components/sync-sites-modal-selector.tsx

Lines changed: 57 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ export function SyncSitesModalSelector( {
4343
const { __ } = useI18n();
4444
const { user } = useAuth();
4545
const [ selectedSiteId, setSelectedSiteId ] = useState< number | null >( null );
46-
const [ searchQuery, setSearchQuery ] = useState< string >( '' );
4746
const isOffline = useOffline();
4847

4948
const { data: connectedSites = [] } = useGetConnectedSitesForLocalSiteQuery( {
@@ -61,15 +60,6 @@ export function SyncSitesModalSelector( {
6160
{ refetchOnMountOrArgChange: true }
6261
);
6362

64-
const filteredSites = syncSites.filter( ( site ) => {
65-
const searchQueryLower = searchQuery.toLowerCase();
66-
return (
67-
site.name?.toLowerCase().includes( searchQueryLower ) ||
68-
site.url?.toLowerCase().includes( searchQueryLower )
69-
);
70-
} );
71-
const isEmpty = filteredSites.length === 0;
72-
7363
if ( syncSites.length === 0 && isSuccess && ! isLoading ) {
7464
return <NoWpcomSitesModal onRequestClose={ onRequestClose } selectedSite={ selectedSite } />;
7565
}
@@ -93,28 +83,12 @@ export function SyncSitesModalSelector( {
9383
title={ getModalTitle() }
9484
>
9585
<div className="relative" data-testid="sync-sites-modal-selector">
96-
<SearchSites searchQuery={ searchQuery } setSearchQuery={ setSearchQuery } />
97-
<div className="h-[calc(84vh-232px)]">
98-
{ isLoading && (
99-
<div className="flex justify-center items-center h-full">
100-
{ __( 'Loading sites…' ) }
101-
</div>
102-
) }
103-
104-
{ ! isLoading && isEmpty && searchQuery && (
105-
<div className="flex justify-center items-center h-full">
106-
{ sprintf( __( 'No sites found for "%s"' ), searchQuery ) }
107-
</div>
108-
) }
109-
110-
{ ! isLoading && ! isEmpty && (
111-
<ListSites
112-
syncSites={ filteredSites }
113-
selectedSiteId={ selectedSiteId }
114-
onSelectSite={ setSelectedSiteId }
115-
/>
116-
) }
117-
</div>
86+
<SitesListContent
87+
isLoading={ isLoading }
88+
syncSites={ syncSites }
89+
selectedSiteId={ selectedSiteId }
90+
onSelectSite={ setSelectedSiteId }
91+
/>
11892
<Footer
11993
onRequestClose={ onRequestClose }
12094
onConnect={ () => {
@@ -176,6 +150,57 @@ export function SearchSites( {
176150
);
177151
}
178152

153+
export function SitesListContent( {
154+
isLoading,
155+
syncSites,
156+
selectedSiteId,
157+
onSelectSite,
158+
}: {
159+
isLoading: boolean;
160+
syncSites: SyncSite[];
161+
selectedSiteId: number | null;
162+
onSelectSite: ( id: number ) => void;
163+
} ) {
164+
const { __ } = useI18n();
165+
const [ searchQuery, setSearchQuery ] = useState< string >( '' );
166+
167+
const filteredSites = syncSites.filter( ( site ) => {
168+
const searchQueryLower = searchQuery.toLowerCase();
169+
return (
170+
site.name?.toLowerCase().includes( searchQueryLower ) ||
171+
site.url?.toLowerCase().includes( searchQueryLower )
172+
);
173+
} );
174+
const isEmpty = filteredSites.length === 0;
175+
176+
return (
177+
<>
178+
<SearchSites searchQuery={ searchQuery } setSearchQuery={ setSearchQuery } />
179+
<div className="h-[calc(84vh-232px)]">
180+
{ isLoading && (
181+
<div className="flex justify-center items-center h-full">{ __( 'Loading sites…' ) }</div>
182+
) }
183+
184+
{ ! isLoading && isEmpty && searchQuery && (
185+
<div className="flex justify-center items-center h-full">
186+
{ sprintf( __( 'No sites found for "%s"' ), searchQuery ) }
187+
</div>
188+
) }
189+
190+
{ ! isLoading && isEmpty ? (
191+
<div className="flex justify-center items-center h-full">{ __( 'No sites found' ) }</div>
192+
) : (
193+
<ListSites
194+
syncSites={ filteredSites }
195+
selectedSiteId={ selectedSiteId }
196+
onSelectSite={ onSelectSite }
197+
/>
198+
) }
199+
</div>
200+
</>
201+
);
202+
}
203+
179204
const getSortedSites = ( sites: SyncSite[] ) => {
180205
const order: Record< SyncSite[ 'syncSupport' ], number > = {
181206
syncable: 1,

tailwind.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ for ( const [ key, value ] of Object.entries( palette.colors ) ) {
129129

130130
// These colors are not in the color studio but are used in the design system.
131131
// Reference: https://github.com/WordPress/gutenberg/blob/trunk/packages/base-styles/_colors.scss
132+
a8cToTailwindColors[ `${ PREFIX }-gray-900` ] = '#1e1e1e'; // Gray 900
132133
a8cToTailwindColors[ `${ PREFIX }-gray-800` ] = '#2F2F2F'; // Gray 800
133134
a8cToTailwindColors[ `${ PREFIX }-gray-700` ] = '#757575'; // Gray 700
134135
a8cToTailwindColors[ `${ PREFIX }-gray-400` ] = '#CCC'; // Gray 400

0 commit comments

Comments
 (0)