From d6474fc63e35976e44f74fd89b2e0de1f550b101 Mon Sep 17 00:00:00 2001 From: Barbara Honhoff Date: Thu, 14 Sep 2023 11:29:12 +0200 Subject: [PATCH] Layout communities page with searching, sorting and pagination --- .../dataset-browser/src/app/[locale]/page.tsx | 4 +- .../src/messages/en/messages.json | 9 +- .../src/messages/nl/messages.json | 9 +- .../[locale]/communities/community-card.tsx | 2 - .../src/app/[locale]/communities/page.tsx | 83 ++++++------ apps/researcher/src/app/[locale]/page.tsx | 4 +- .../src/app/[locale]/persons/page.tsx | 4 +- apps/researcher/src/lib/community.test.ts | 119 +++++++++++++++++- apps/researcher/src/lib/community.ts | 51 +++++--- apps/researcher/src/messages/en/messages.json | 13 +- apps/researcher/src/messages/nl/messages.json | 13 +- packages/list-store/src/client-list-store.tsx | 21 +++- packages/list-store/src/search-params.test.ts | 12 +- packages/list-store/src/search-params.ts | 39 +++--- packages/list-store/src/useListStore.ts | 9 +- .../list-store/src/useSearchParamsUpdate.ts | 6 +- packages/ui/list/order-selector.tsx | 12 +- packages/ui/list/search-field.tsx | 60 +++++---- 18 files changed, 334 insertions(+), 136 deletions(-) diff --git a/apps/dataset-browser/src/app/[locale]/page.tsx b/apps/dataset-browser/src/app/[locale]/page.tsx index db61fec96..6b8b88513 100644 --- a/apps/dataset-browser/src/app/[locale]/page.tsx +++ b/apps/dataset-browser/src/app/[locale]/page.tsx @@ -19,7 +19,7 @@ import { FilterSet, Paginator, SelectedFilters, - SearchField, + SearchFieldWithLabel, OrderSelector, } from 'ui/list'; import { @@ -52,7 +52,7 @@ function FacetMenu({filterKeysOrder, filters}: FacetMenuProps) { return ( <> - + {filterKeysOrder.map( filterKey => !!filters[filterKey]?.length && ( diff --git a/apps/dataset-browser/src/messages/en/messages.json b/apps/dataset-browser/src/messages/en/messages.json index b6ed78667..8dca895c1 100644 --- a/apps/dataset-browser/src/messages/en/messages.json +++ b/apps/dataset-browser/src/messages/en/messages.json @@ -115,12 +115,13 @@ "clearAllFilters": "Clear all", "filterSearchPlaceholder": "Filter on {filterName}", "accessibilityTypeToFilter": "Type to filter on text.", - "accessibilitySelectToFilter": "Select a checkbox to filter" + "accessibilitySelectToFilter": "Select a checkbox to filter", + "accessibilityClickToSearch": "Click to search" }, "Sort": { - "sortRelevanceDesc": "Relevance", - "sortNameAsc": "Name - Ascending", - "sortNameDesc": "Name - Descending", + "relevanceDesc": "Relevance", + "nameAsc": "Name - Ascending", + "nameDesc": "Name - Descending", "accessibilitySelectToChangeOrder": "Select to change the ordering of the result" }, "WorkInProgress": { diff --git a/apps/dataset-browser/src/messages/nl/messages.json b/apps/dataset-browser/src/messages/nl/messages.json index bb954c8f3..22c9edd36 100644 --- a/apps/dataset-browser/src/messages/nl/messages.json +++ b/apps/dataset-browser/src/messages/nl/messages.json @@ -114,12 +114,13 @@ "clearAllFilters": "Alles verwijderen", "filterSearchPlaceholder": "Filteren op {filterName}", "accessibilityTypeToFilter": "Typ om op tekst te filteren", - "accessibilitySelectToFilter": "Selecteer een selectievakje om te filteren" + "accessibilitySelectToFilter": "Selecteer een selectievakje om te filteren", + "accessibilityClickToSearch": "klik om te zoeken" }, "Sort": { - "sortRelevanceDesc": "Relevantie", - "sortNameAsc": "Naam - Oplopend", - "sortNameDesc": "Naam - Aflopend", + "relevanceDesc": "Relevantie", + "nameAsc": "Naam - Oplopend", + "nameDesc": "Naam - Aflopend", "accessibilitySelectToChangeOrder": "Selecteer om de volgorde van het resultaat te wijzigen" }, "WorkInProgress": { diff --git a/apps/researcher/src/app/[locale]/communities/community-card.tsx b/apps/researcher/src/app/[locale]/communities/community-card.tsx index 55bb5fabf..9241377c4 100644 --- a/apps/researcher/src/app/[locale]/communities/community-card.tsx +++ b/apps/researcher/src/app/[locale]/communities/community-card.tsx @@ -10,8 +10,6 @@ interface MembershipCountProps { locale: string; } -// TODO: This is a workaround for the fact that `includeMembersCount` does not work. -// See comment in `community.ts` for more information. async function MembershipCount({communityId, locale}: MembershipCountProps) { const t = await getTranslator(locale, 'Communities'); const memberships = await getMemberships(communityId); diff --git a/apps/researcher/src/app/[locale]/communities/page.tsx b/apps/researcher/src/app/[locale]/communities/page.tsx index 686ea1b5f..0a985d5a6 100644 --- a/apps/researcher/src/app/[locale]/communities/page.tsx +++ b/apps/researcher/src/app/[locale]/communities/page.tsx @@ -1,66 +1,76 @@ -import {getAllCommunities} from '@/lib/community'; +import { + getAllCommunities, + CommunitySortBy, + defaultCommunitySortBy, +} from '@/lib/community'; import {getTranslator} from 'next-intl/server'; import ErrorMessage from '@/components/error-message'; -import {MagnifyingGlassIcon} from '@heroicons/react/24/solid'; import CommunityCard from './community-card'; +import {ClientListStore} from '@colonial-collections/list-store'; +import {Paginator, SearchField, OrderSelector} from 'ui/list'; + interface Props { params: { locale: string; }; + searchParams?: { + query?: string; + sortBy?: CommunitySortBy; + offset?: number; + }; } // Revalidate the page export const revalidate = 0; -export default async function CommunitiesPage({params}: Props) { +export default async function CommunitiesPage({ + params, + searchParams = {}, +}: Props) { const t = await getTranslator(params.locale, 'Communities'); + const {query, sortBy, offset} = searchParams; + let communities; try { - communities = await getAllCommunities(); + communities = await getAllCommunities({ + query, + sortBy, + offset, + }); } catch (err) { return ; } return ( <> +

{t('title')}

-
-
- -
- - -
-
+
+
-
- +
+
@@ -72,6 +82,9 @@ export default async function CommunitiesPage({params}: Props) { /> ))}
+
+ +
); } diff --git a/apps/researcher/src/app/[locale]/page.tsx b/apps/researcher/src/app/[locale]/page.tsx index 1cfedbdd3..2ec7159e0 100644 --- a/apps/researcher/src/app/[locale]/page.tsx +++ b/apps/researcher/src/app/[locale]/page.tsx @@ -19,7 +19,7 @@ import { FilterSet, Paginator, SelectedFilters, - SearchField, + SearchFieldWithLabel, OrderSelector, } from 'ui/list'; import {SmallScreenSubMenu, SubMenuButton, SubMenuDialog} from 'ui'; @@ -46,7 +46,7 @@ function FacetMenu({filterKeysOrder, filters}: FacetMenuProps) { return ( <> - + {filterKeysOrder.map( filterKey => !!filters[filterKey]?.length && ( diff --git a/apps/researcher/src/app/[locale]/persons/page.tsx b/apps/researcher/src/app/[locale]/persons/page.tsx index 23b74189e..d73a831b1 100644 --- a/apps/researcher/src/app/[locale]/persons/page.tsx +++ b/apps/researcher/src/app/[locale]/persons/page.tsx @@ -19,7 +19,7 @@ import { FilterSet, Paginator, SelectedFilters, - SearchField, + SearchFieldWithLabel, OrderSelector, } from 'ui/list'; import { @@ -53,7 +53,7 @@ function FacetMenu({filterKeysOrder, filters}: FacetMenuProps) { return ( <> - + {filterKeysOrder.map( filterKey => !!filters[filterKey]?.length && ( diff --git a/apps/researcher/src/lib/community.test.ts b/apps/researcher/src/lib/community.test.ts index d2139adbb..1393ca841 100644 --- a/apps/researcher/src/lib/community.test.ts +++ b/apps/researcher/src/lib/community.test.ts @@ -1,6 +1,11 @@ import {describe, expect, it} from '@jest/globals'; import {auth} from '@clerk/nextjs'; -import {isAdmin, Membership} from './community'; +import { + isAdmin, + Membership, + sortCommunities, + CommunitySortBy, +} from './community'; jest.mock('@clerk/nextjs', () => ({ auth: jest.fn().mockImplementation(() => ({ @@ -92,3 +97,115 @@ describe('isAdmin', () => { expect(isAdmin(memberships)).toEqual(false); }); }); + +describe('sortCommunities', () => { + const communities = [ + { + id: 'community2', + name: 'Community 2', + slug: 'community-2', + imageUrl: 'https://example.com/image.png', + createdAt: 1690000000000, + }, + { + id: 'community1', + name: 'Community 1', + slug: 'community-1', + imageUrl: 'https://example.com/image.png', + createdAt: 1600000000000, + }, + { + id: 'community4', + name: 'Community 4', + slug: 'community-4', + imageUrl: 'https://example.com/image.png', + createdAt: 1680000000000, + }, + { + id: 'community3', + name: 'Community 3', + slug: 'community-3', + imageUrl: 'https://example.com/image.png', + createdAt: 1650000000000, + }, + { + id: 'community5', + name: 'Community 5', + slug: 'community-5', + imageUrl: 'https://example.com/image.png', + createdAt: 1670000000000, + }, + ]; + it('sorts communities by name ascending', () => { + const sortedCommunities = sortCommunities( + communities, + CommunitySortBy.NameAsc + ); + const sortedCommunitiesIds = sortedCommunities.map( + community => community.id + ); + expect(sortedCommunitiesIds).toEqual([ + 'community1', + 'community2', + 'community3', + 'community4', + 'community5', + ]); + }); + + it('sorts communities by name descending', () => { + const sortedCommunities = sortCommunities( + communities, + CommunitySortBy.NameDesc + ); + const sortedCommunitiesIds = sortedCommunities.map( + community => community.id + ); + expect(sortedCommunitiesIds).toEqual([ + 'community5', + 'community4', + 'community3', + 'community2', + 'community1', + ]); + }); + + it('sorts communities by creation date descending', () => { + const sortedCommunities = sortCommunities( + communities, + CommunitySortBy.CreatedAtDesc + ); + const sortedCommunitiesIds = sortedCommunities.map( + community => community.id + ); + expect(sortedCommunitiesIds).toEqual([ + 'community2', + 'community4', + 'community5', + 'community3', + 'community1', + ]); + }); + + it('works with an empty array', () => { + const sortedCommunities = sortCommunities([], CommunitySortBy.NameAsc); + expect(sortedCommunities).toEqual([]); + }); + + it('returns the list unsorted if sortBy is an incorrect value', () => { + const sortedCommunities = sortCommunities( + communities, + 'incorrect' as CommunitySortBy + ); + const sortedCommunitiesIds = sortedCommunities.map( + community => community.id + ); + expect(sortedCommunitiesIds).toEqual([ + 'community2', + 'community1', + 'community4', + 'community3', + 'community5', + ]); + }); +}); diff --git a/apps/researcher/src/lib/community.ts b/apps/researcher/src/lib/community.ts index ad0b25ac2..5929e2271 100644 --- a/apps/researcher/src/lib/community.ts +++ b/apps/researcher/src/lib/community.ts @@ -31,18 +31,45 @@ export async function getMemberships( }); } +export enum CommunitySortBy { + NameAsc = 'nameAsc', + NameDesc = 'nameDesc', + CreatedAtDesc = 'createdAtDesc', + MembershipCountDesc = 'membershipCountDesc', +} + +export const defaultCommunitySortBy: CommunitySortBy = + CommunitySortBy.CreatedAtDesc; + +export function sortCommunities( + communities: Community[], + sortBy: CommunitySortBy +) { + return [...communities].sort((a, b) => { + if (sortBy === CommunitySortBy.NameAsc) { + return a.name.localeCompare(b.name); + } else if (sortBy === CommunitySortBy.NameDesc) { + return b.name.localeCompare(a.name); + } else if (sortBy === CommunitySortBy.CreatedAtDesc) { + return b.createdAt - a.createdAt; + } else { + return 0; + } + }); +} + interface GetAllCommunitiesProps { query?: string; - orderBy?: 'nameAsc' | 'nameDsc' | 'createdAt'; - limit: number; - offset: number; + sortBy?: CommunitySortBy; + limit?: number; + offset?: number; } export async function getAllCommunities({ query = '', - orderBy = 'nameAsc', - limit, - offset, + sortBy = defaultCommunitySortBy, + limit = 24, + offset = 0, }: GetAllCommunitiesProps): Promise { const communities = await clerkClient.organizations.getOrganizationList({ limit, @@ -55,17 +82,7 @@ export async function getAllCommunities({ includeMembersCount: true, }); - return communities.sort((a, b) => { - if (orderBy === 'nameAsc') { - return a.name.localeCompare(b.name); - } else if (orderBy === 'nameDsc') { - return b.name.localeCompare(a.name); - } else if (orderBy === 'createdAt') { - return b.createdAt - a.createdAt; - } else { - return 0; - } - }); + return sortCommunities(communities, sortBy); } export function isAdmin(memberships: ReadonlyArray): boolean { diff --git a/apps/researcher/src/messages/en/messages.json b/apps/researcher/src/messages/en/messages.json index dfbe6796b..c53c31494 100644 --- a/apps/researcher/src/messages/en/messages.json +++ b/apps/researcher/src/messages/en/messages.json @@ -113,12 +113,14 @@ "clearAllFilters": "Clear all", "filterSearchPlaceholder": "Filter on {filterName}", "accessibilityTypeToFilter": "Type to filter on text.", - "accessibilitySelectToFilter": "Select a checkbox to filter" + "accessibilitySelectToFilter": "Select a checkbox to filter", + "accessibilityClickToSearch": "Click to search" }, "Sort": { - "sortRelevanceDesc": "Relevance", - "sortNameAsc": "Name - Ascending", - "sortNameDesc": "Name - Descending", + "relevanceDesc": "Relevance", + "nameAsc": "Name - Ascending", + "nameDesc": "Name - Descending", + "createdAtDesc": "Date created", "accessibilitySelectToChangeOrder": "Select to change the ordering of the result" }, "WorkInProgress": { @@ -135,7 +137,8 @@ "title": "Communities", "error": "Something went wrong while fetching communities. Please try again later.", "communityName": "Community of ", - "membershipCount": "{count, plural, =0 {0 members} =1 {1 member} other {# members}}" + "membershipCount": "{count, plural, =0 {0 members} =1 {1 member} other {# members}}", + "searchPlaceholder": "Search for community" }, "Community": { "title": "Community of", diff --git a/apps/researcher/src/messages/nl/messages.json b/apps/researcher/src/messages/nl/messages.json index 115d30d66..b3b67589e 100644 --- a/apps/researcher/src/messages/nl/messages.json +++ b/apps/researcher/src/messages/nl/messages.json @@ -113,12 +113,14 @@ "clearAllFilters": "Alles verwijderen", "filterSearchPlaceholder": "Filteren op {filterName}", "accessibilityTypeToFilter": "Typ om op tekst te filteren", - "accessibilitySelectToFilter": "Selecteer een selectievakje om te filteren" + "accessibilitySelectToFilter": "Selecteer een selectievakje om te filteren", + "accessibilityClickToSearch": "klik om te zoeken" }, "Sort": { - "sortRelevanceDesc": "Relevantie", - "sortNameAsc": "Naam - Oplopend", - "sortNameDesc": "Naam - Aflopend", + "relevanceDesc": "Relevantie", + "nameAsc": "Naam - Oplopend", + "nameDesc": "Naam - Aflopend", + "createdAtDesc": "Datum gecreeƫrd", "accessibilitySelectToChangeOrder": "Selecteer om de volgorde van het resultaat te wijzigen" }, "WorkInProgress": { @@ -135,7 +137,8 @@ "title": "Communities", "error": "Er is een fout opgetreden bij het ophalen van de communities. Probeer het later opnieuw.", "communityName": "Community van ", - "membershipCount": "{count, plural, =0 {0 members} =1 {1 member} other {# members}}" + "membershipCount": "{count, plural, =0 {0 members} =1 {1 member} other {# members}}", + "searchPlaceholder": "Zoek naar community" }, "Community": { "title": "Community van", diff --git a/packages/list-store/src/client-list-store.tsx b/packages/list-store/src/client-list-store.tsx index 042847068..38c0fcf84 100644 --- a/packages/list-store/src/client-list-store.tsx +++ b/packages/list-store/src/client-list-store.tsx @@ -2,17 +2,18 @@ import {useEffect} from 'react'; import {useListStore} from './useListStore'; -import {SortBy} from './sort'; import {useSearchParamsUpdate} from './useSearchParamsUpdate'; +import {defaultSortBy as packageDefaultSortBy} from './sort'; interface Props { totalCount: number; offset: number; limit: number; query: string; - sortBy: SortBy; + sortBy?: string; selectedFilters?: {[filterKey: string]: string[] | undefined}; baseUrl: string; + defaultSortBy?: string; } // The server component that does the API call loads this component. @@ -25,6 +26,7 @@ export function ClientListStore({ sortBy, selectedFilters, baseUrl, + defaultSortBy = packageDefaultSortBy, }: Props) { const listStore = useListStore(); @@ -34,12 +36,21 @@ export function ClientListStore({ offset, limit, query, - sortBy, + sortBy: sortBy ?? defaultSortBy, selectedFilters: selectedFilters ?? {}, }); - }, [limit, offset, query, selectedFilters, sortBy, listStore, totalCount]); + }, [ + limit, + offset, + query, + selectedFilters, + sortBy, + listStore, + totalCount, + defaultSortBy, + ]); - useSearchParamsUpdate({baseUrl}); + useSearchParamsUpdate({baseUrl, defaultSortBy}); return null; } diff --git a/packages/list-store/src/search-params.test.ts b/packages/list-store/src/search-params.test.ts index ebbe64ab7..37a60678d 100644 --- a/packages/list-store/src/search-params.test.ts +++ b/packages/list-store/src/search-params.test.ts @@ -45,14 +45,15 @@ const sortOptions = { }; describe('getUrlWithSearchParams', () => { - it('returns "/" if there are no options', () => { - expect(getUrlWithSearchParams({})).toBe('/'); + it('returns "/" if there are no filter options', () => { + expect(getUrlWithSearchParams({defaultSortBy: defaultSortBy})).toBe('/'); }); it('returns "/" with only default values', () => { const options = { offset: 0, sortBy: defaultSortBy, + defaultSortBy: defaultSortBy, }; expect(getUrlWithSearchParams(options)).toBe('/'); @@ -61,6 +62,7 @@ describe('getUrlWithSearchParams', () => { it('returns "/" with an empty query string', () => { const options = { query: '', + defaultSortBy: defaultSortBy, }; expect(getUrlWithSearchParams(options)).toBe('/'); @@ -69,6 +71,7 @@ describe('getUrlWithSearchParams', () => { it('returns "/" with empty filter arrays', () => { const options = { query: '', + defaultSortBy: defaultSortBy, filters: { licenses: [], publishers: [], @@ -83,6 +86,7 @@ describe('getUrlWithSearchParams', () => { it('adds "query" to the search params if `query` is not empty', () => { const options = { query: 'my query', + defaultSortBy: defaultSortBy, }; expect(getUrlWithSearchParams(options)).toBe('/?query=my+query'); @@ -91,6 +95,7 @@ describe('getUrlWithSearchParams', () => { it('adds "offset" to the search params if `offset` is not 0', () => { const options = { offset: 12, + defaultSortBy: defaultSortBy, }; expect(getUrlWithSearchParams(options)).toBe('/?offset=12'); @@ -99,6 +104,7 @@ describe('getUrlWithSearchParams', () => { it('adds "sortBy" to the search params if `sortBy` is not the default', () => { const options = { sortBy: SortBy.NameAsc, + defaultSortBy: defaultSortBy, }; expect(getUrlWithSearchParams(options)).toBe('/?sortBy=nameAsc'); @@ -106,6 +112,7 @@ describe('getUrlWithSearchParams', () => { it('adds "filters" to the search params if the filter arrays are not empty', () => { const options = { + defaultSortBy: defaultSortBy, filters: { licenses: ['filter1'], publishers: ['filter2'], @@ -124,6 +131,7 @@ describe('getUrlWithSearchParams', () => { query: 'my query', offset: 20, sortBy: SortBy.NameDesc, + defaultSortBy: defaultSortBy, filters: { licenses: ['filter1', 'filter2'], publishers: ['filter3'], diff --git a/packages/list-store/src/search-params.ts b/packages/list-store/src/search-params.ts index ae52ac6cd..b35bee4ba 100644 --- a/packages/list-store/src/search-params.ts +++ b/packages/list-store/src/search-params.ts @@ -1,31 +1,35 @@ import {z, Schema} from 'zod'; -import {SortBy, defaultSortBy} from './sort'; +import {SortBy} from './sort'; +import {defaultSortBy as packageDefaultSortBy} from './sort'; const searchParamFilterSchema = z .array(z.string()) .default([]) .transform(filterValues => filterValues.join(',')); -const searchParamsSchema = z.object({ - query: z.string().default(''), - offset: z - .number() - .default(0) - // Don't add the default offset of 0 to the search params - .transform(offset => (offset > 0 ? `${offset}` : '')), - sortBy: z - .nativeEnum(SortBy) - .default(defaultSortBy) - // Don't add the default sort to the search params - .transform(sortBy => (sortBy === defaultSortBy ? '' : sortBy)), -}); +function getSearchParamsSchema(defaultSortBy: string) { + return z.object({ + query: z.string().default(''), + offset: z + .number() + .default(0) + // Don't add the default offset of 0 to the search params + .transform(offset => (offset > 0 ? `${offset}` : '')), + sortBy: z + .string() + .default(defaultSortBy) + // Don't add the default sort to the search params + .transform(sortBy => (sortBy === defaultSortBy ? '' : sortBy)), + }); +} interface ClientSearchOptions { query?: string; offset?: number; - sortBy?: SortBy; + sortBy?: string; filters?: {[filterKey: string]: string[] | undefined}; baseUrl?: string; + defaultSortBy?: string; } export function getUrlWithSearchParams({ @@ -33,9 +37,12 @@ export function getUrlWithSearchParams({ offset, sortBy, filters, + defaultSortBy = packageDefaultSortBy, baseUrl = '/', }: ClientSearchOptions): string { - const searchParams: {[key: string]: string} = searchParamsSchema.parse({ + const searchParams: {[key: string]: string} = getSearchParamsSchema( + defaultSortBy + ).parse({ query, offset, sortBy, diff --git a/packages/list-store/src/useListStore.ts b/packages/list-store/src/useListStore.ts index 25bd2d577..c49862551 100644 --- a/packages/list-store/src/useListStore.ts +++ b/packages/list-store/src/useListStore.ts @@ -1,18 +1,17 @@ import {create} from 'zustand'; -import {SortBy, defaultSortBy} from './sort'; export interface Props { totalCount: number; offset: number; limit: number; query: string; - sortBy: SortBy; + sortBy?: string; // Setting newDataNeeded to true will trigger a page reload with new search params newDataNeeded: boolean; isInitialized: boolean; selectedFilters: {[filterKey: string]: string[] | undefined}; filterChange: (key: string, value: string[]) => void; - sortChange: (sortBy: SortBy) => void; + sortChange: (sortBy: string) => void; queryChange: (query: string) => void; pageChange: (direction: 1 | -1) => void; setNewData: ({ @@ -27,7 +26,7 @@ export interface Props { offset: number; limit: number; query: string; - sortBy: SortBy; + sortBy: string; selectedFilters: {[filterKey: string]: string[] | undefined}; }) => void; transitionStarted: () => void; @@ -38,7 +37,7 @@ export const useListStore = create((set, get) => ({ totalCount: 0, offset: 0, limit: 10, - sortBy: defaultSortBy, + sortBy: undefined, selectedFilters: {}, newDataNeeded: false, isInitialized: false, diff --git a/packages/list-store/src/useSearchParamsUpdate.ts b/packages/list-store/src/useSearchParamsUpdate.ts index 8f39f6806..0394df2d7 100644 --- a/packages/list-store/src/useSearchParamsUpdate.ts +++ b/packages/list-store/src/useSearchParamsUpdate.ts @@ -7,9 +7,10 @@ import {getUrlWithSearchParams} from './search-params'; interface Props { baseUrl: string; + defaultSortBy: string; } -export function useSearchParamsUpdate({baseUrl}: Props) { +export function useSearchParamsUpdate({baseUrl, defaultSortBy}: Props) { const router = useRouter(); const [isPending, startTransition] = useTransition(); const listStore = useListStore(); @@ -22,13 +23,14 @@ export function useSearchParamsUpdate({baseUrl}: Props) { sortBy: listStore.sortBy, filters: listStore.selectedFilters, baseUrl: baseUrl, + defaultSortBy, }); startTransition(() => { listStore.transitionStarted(); router.replace(url); }); } - }, [isPending, router, listStore, baseUrl]); + }, [isPending, router, listStore, baseUrl, defaultSortBy]); return {isPending}; } diff --git a/packages/ui/list/order-selector.tsx b/packages/ui/list/order-selector.tsx index 1eb197cf3..623076a74 100644 --- a/packages/ui/list/order-selector.tsx +++ b/packages/ui/list/order-selector.tsx @@ -3,7 +3,9 @@ import {useListStore, SortBy} from '@colonial-collections/list-store'; import {useTranslations} from 'next-intl'; -export function OrderSelector() { +const defaultValues = [SortBy.RelevanceDesc, SortBy.NameAsc, SortBy.NameDesc]; + +export function OrderSelector({values = defaultValues}: {values?: string[]}) { const t = useTranslations('Sort'); const {sortBy, sortChange} = useListStore(); @@ -19,9 +21,11 @@ export function OrderSelector() { onChange={handleSortByChange} aria-label={t('accessibilitySelectToChangeOrder')} > - - - + {values.map(value => ( + + ))} ); } diff --git a/packages/ui/list/search-field.tsx b/packages/ui/list/search-field.tsx index bb66c9dec..75286c3da 100644 --- a/packages/ui/list/search-field.tsx +++ b/packages/ui/list/search-field.tsx @@ -4,7 +4,7 @@ import {useListStore} from '@colonial-collections/list-store'; import {MagnifyingGlassIcon} from '@heroicons/react/24/solid'; import {useTranslations} from 'next-intl'; -export function SearchField() { +export function SearchField({placeholder = ''}: {placeholder?: string}) { const {query, queryChange} = useListStore(); const t = useTranslations('Filters'); @@ -12,30 +12,44 @@ export function SearchField() { queryChange(e.target.value); }; + return ( +
+ + +
+ ); +} + +function Label() { + const t = useTranslations('Filters'); + + return ( + + ); +} + +export function SearchFieldWithLabel() { return (
- -
- - -
+
); }