diff --git a/packages/api-core/src/domain-suggestions/fetchers.ts b/packages/api-core/src/domain-suggestions/fetchers.ts index 47a41605039a..af7a12b94500 100644 --- a/packages/api-core/src/domain-suggestions/fetchers.ts +++ b/packages/api-core/src/domain-suggestions/fetchers.ts @@ -45,3 +45,23 @@ export async function fetchFreeDomainSuggestion( search: string ): Promise< Free return suggestion; } + +export async function fetchAvailableTlds( search?: string, vendor?: string ): Promise< string[] > { + const defaultAvailableTldsQuery = { + vendor: 'variation2_front', + }; + + const tlds = await wpcom.req.get( + { + apiVersion: '1.1', + path: '/domains/suggestions/tlds', + }, + { + ...defaultAvailableTldsQuery, + search, + vendor, + } + ); + + return tlds; +} diff --git a/packages/api-core/src/domain-suggestions/types.ts b/packages/api-core/src/domain-suggestions/types.ts index 0ec56db00baf..6ab1ec6428b8 100644 --- a/packages/api-core/src/domain-suggestions/types.ts +++ b/packages/api-core/src/domain-suggestions/types.ts @@ -9,6 +9,11 @@ export type DomainSuggestionQueryVendor = | 'domain-upsell'; export interface DomainSuggestionQuery { + /** + * True to only provide exact domain name match suggestions + */ + exact_sld_matches_only?: boolean; + /** * True to include .blog subdomain suggestions * @example diff --git a/packages/api-queries/src/domains.ts b/packages/api-queries/src/domains.ts index d7b928e90a6b..3764d083285e 100644 --- a/packages/api-queries/src/domains.ts +++ b/packages/api-queries/src/domains.ts @@ -1,4 +1,5 @@ import { + fetchAvailableTlds, fetchDomainSuggestions, fetchFreeDomainSuggestion, type DomainSuggestionQuery, @@ -27,3 +28,9 @@ export const freeSuggestionQuery = ( query: string ) => queryKey: [ 'free-suggestion', query ], queryFn: () => fetchFreeDomainSuggestion( query ), } ); + +export const availableTldsQuery = ( query?: string, vendor?: string ) => + queryOptions( { + queryKey: [ 'available-tlds', query, vendor ], + queryFn: () => fetchAvailableTlds( query, vendor ), + } ); diff --git a/packages/domain-search/src/components/search-bar/filter.tsx b/packages/domain-search/src/components/search-bar/filter.tsx index 8210fabf691d..bd8513691b42 100644 --- a/packages/domain-search/src/components/search-bar/filter.tsx +++ b/packages/domain-search/src/components/search-bar/filter.tsx @@ -1,3 +1,4 @@ +import { useQuery } from '@tanstack/react-query'; import { Dropdown } from '@wordpress/components'; import { useCallback, useMemo } from 'react'; import { useDomainSearch } from '../../page/context'; @@ -10,13 +11,11 @@ const emptyFilter: FilterState = { }; export const Filter = () => { - const { filter, setFilter } = useDomainSearch(); - - // TODO: Hardcoded for testing, should get those from the https://public-api.wordpress.com/rest/v1.1/domains/suggestions/tlds endpoint - const availableTlds = useMemo( - () => [ 'com', 'net', 'org', 'blog', 'dev', 'io', 'co', 'co.uk', 'com.br', 'de' ], - [] - ); + const { filter, setFilter, query, queries } = useDomainSearch(); + const { data: availableTlds = [], isFetching: isFetchingTlds } = useQuery( { + ...queries.availableTlds( query ), + enabled: true, + } ) as { data: string[]; isFetching: boolean }; const resetFilter = useCallback( () => { setFilter( emptyFilter ); @@ -27,12 +26,22 @@ export const Filter = () => { [ filter ] ); + if ( ! isFetchingTlds && ( ! availableTlds || availableTlds.length === 0 ) ) { + return null; + } + return ( { - return ; + return ( + + ); } } renderContent={ ( { onClose } ) => { return ( diff --git a/packages/domain-search/src/hooks/use-suggestion.ts b/packages/domain-search/src/hooks/use-suggestion.ts index b9385a13733b..de150f45a1ca 100644 --- a/packages/domain-search/src/hooks/use-suggestion.ts +++ b/packages/domain-search/src/hooks/use-suggestion.ts @@ -2,10 +2,13 @@ import { useQuery } from '@tanstack/react-query'; import { useDomainSearch } from '../page/context'; export const useSuggestion = ( domainName: string ) => { - const { query, queries } = useDomainSearch(); + const { query, queries, filter } = useDomainSearch(); const { data: suggestion } = useQuery( { - ...queries.domainSuggestions( query ), + ...queries.domainSuggestions( query, { + tlds: filter.tlds, + exact_sld_matches_only: filter.exactSldMatchesOnly, + } ), select: ( data ) => { const suggestion = data.find( ( suggestion ) => suggestion.domain_name === domainName ); diff --git a/packages/domain-search/src/hooks/use-suggestions-list.ts b/packages/domain-search/src/hooks/use-suggestions-list.ts index 6f154d097e78..e31f025764b3 100644 --- a/packages/domain-search/src/hooks/use-suggestions-list.ts +++ b/packages/domain-search/src/hooks/use-suggestions-list.ts @@ -5,10 +5,13 @@ import { partitionSuggestions } from '../helpers/partition-suggestions'; import { useDomainSearch } from '../page/context'; export const useSuggestionsList = () => { - const { query, queries, config } = useDomainSearch(); + const { query, queries, config, filter } = useDomainSearch(); const { data: suggestions = [], isLoading: isLoadingSuggestions } = useQuery( { - ...queries.domainSuggestions( query ), + ...queries.domainSuggestions( query, { + tlds: filter.tlds, + exact_sld_matches_only: filter.exactSldMatchesOnly, + } ), enabled: true, } ); diff --git a/packages/domain-search/src/page/context.ts b/packages/domain-search/src/page/context.ts index 0b8af6cf2398..ddce1382e409 100644 --- a/packages/domain-search/src/page/context.ts +++ b/packages/domain-search/src/page/context.ts @@ -1,4 +1,5 @@ import { + availableTldsQuery, domainAvailabilityQuery, domainSuggestionsQuery, freeSuggestionQuery, @@ -21,7 +22,9 @@ export const DEFAULT_CONTEXT_VALUE: DomainSearchContextType = { onMapDomainClick: noop, }, queries: { - domainSuggestions: ( query: string ) => domainSuggestionsQuery( query ), + availableTlds: ( search?: string, vendor?: string ) => availableTldsQuery( vendor, search ), + domainSuggestions: ( query: string, params?: Partial< typeof domainSuggestionsQuery > ) => + domainSuggestionsQuery( query, params ), domainAvailability: ( domainName: string ) => domainAvailabilityQuery( domainName ), freeSuggestion: ( query: string ) => freeSuggestionQuery( query ), }, @@ -101,8 +104,9 @@ export const useDomainSearchContextValue = ( events: normalizedEvents, config: normalizedConfig, queries: { - domainSuggestions: ( query ) => ( { + domainSuggestions: ( query, params = {} ) => ( { ...domainSuggestionsQuery( query, { + ...params, quantity: 30, vendor: normalizedConfig.vendor, } ), @@ -116,6 +120,10 @@ export const useDomainSearchContextValue = ( ...domainAvailabilityQuery( domainName ), enabled: false, } ), + availableTlds: ( vendor, search ) => ( { + ...availableTldsQuery( vendor, search ), + enabled: false, + } ), }, cart, isFullCartOpen, diff --git a/packages/domain-search/src/page/types.ts b/packages/domain-search/src/page/types.ts index e14e76254648..f0a1b52440cc 100644 --- a/packages/domain-search/src/page/types.ts +++ b/packages/domain-search/src/page/types.ts @@ -1,4 +1,5 @@ import { + availableTldsQuery, domainSuggestionsQuery, freeSuggestionQuery, domainAvailabilityQuery, @@ -72,7 +73,11 @@ export interface DomainSearchContextType filter: FilterState; setFilter: ( filter: FilterState ) => void; queries: { - domainSuggestions: ( query: string ) => ReturnType< typeof domainSuggestionsQuery >; + availableTlds: ( query?: string, vendor?: string ) => ReturnType< typeof availableTldsQuery >; + domainSuggestions: ( + query: string, + params?: Partial< typeof domainSuggestionsQuery > + ) => ReturnType< typeof domainSuggestionsQuery >; domainAvailability: ( domainName: string ) => ReturnType< typeof domainAvailabilityQuery >; freeSuggestion: ( query: string ) => ReturnType< typeof freeSuggestionQuery >; }; diff --git a/packages/domain-search/src/ui/domain-search-controls/filter-button.tsx b/packages/domain-search/src/ui/domain-search-controls/filter-button.tsx index b0dbc542606e..9405c9ee8220 100644 --- a/packages/domain-search/src/ui/domain-search-controls/filter-button.tsx +++ b/packages/domain-search/src/ui/domain-search-controls/filter-button.tsx @@ -9,10 +9,11 @@ type Props = { count: number; onClick: () => void; children?: React.ReactNode; + disabled?: boolean; }; export const DomainSearchControlsFilterButton = forwardRef( - ( { count, onClick, children }: Props, ref: Ref< HTMLButtonElement > ) => { + ( { count, onClick, disabled, children }: Props, ref: Ref< HTMLButtonElement > ) => { const { __, _n } = useI18n(); let ariaLabel = ''; @@ -32,7 +33,14 @@ export const DomainSearchControlsFilterButton = forwardRef( return (
-