diff --git a/pro/src/commons/core/Offers/hooks/useQuerySearchFilters.ts b/pro/src/commons/core/Offers/hooks/useQuerySearchFilters.ts index 789752b8771..bc2b4705502 100644 --- a/pro/src/commons/core/Offers/hooks/useQuerySearchFilters.ts +++ b/pro/src/commons/core/Offers/hooks/useQuerySearchFilters.ts @@ -1,35 +1,26 @@ import { useMemo } from 'react' import { useLocation } from 'react-router-dom' -import { - DEFAULT_COLLECTIVE_SEARCH_FILTERS, - DEFAULT_SEARCH_FILTERS, -} from 'commons/core/Offers/constants' import { Audience } from 'commons/core/shared/types' import { parseUrlParams } from 'commons/utils/parseUrlParams' import { translateQueryParamsToApiParams } from 'commons/utils/translate' import { CollectiveSearchFiltersParams, SearchFiltersParams } from '../types' -export const useQuerySearchFilters = (): SearchFiltersParams => { +export const useQuerySearchFilters = (): Partial => { const { search } = useLocation() - const urlSearchFilters: SearchFiltersParams = useMemo(() => { + const urlSearchFilters = useMemo(() => { const urlParams = new URLSearchParams(search) const queryParams = parseUrlParams(urlParams) - const translatedQuery = translateQueryParamsToApiParams( + const urlFilters: Partial = translateQueryParamsToApiParams( { ...queryParams, }, Audience.INDIVIDUAL ) - const urlFilters = { - ...DEFAULT_SEARCH_FILTERS, - ...translatedQuery, - } - // Convert page type to number urlFilters.page = typeof urlFilters.page === 'string' @@ -42,26 +33,19 @@ export const useQuerySearchFilters = (): SearchFiltersParams => { return urlSearchFilters } -export const useQueryCollectiveSearchFilters = ( - defaultCollectiveSearchFilters: CollectiveSearchFiltersParams = DEFAULT_COLLECTIVE_SEARCH_FILTERS -): CollectiveSearchFiltersParams => { +export const useQueryCollectiveSearchFilters = (): Partial => { const { search } = useLocation() const urlParams = new URLSearchParams(search) const queryParams = parseUrlParams(urlParams) - const translatedQuery = translateQueryParamsToApiParams( + const urlFilters: Partial = translateQueryParamsToApiParams( { ...queryParams, }, Audience.COLLECTIVE ) - const urlFilters = { - ...defaultCollectiveSearchFilters, - ...translatedQuery, - } - // Convert page type to number urlFilters.page = typeof urlFilters.page === 'string' diff --git a/pro/src/commons/core/Offers/utils/getCollectiveOffersSwrKeys.ts b/pro/src/commons/core/Offers/utils/getCollectiveOffersSwrKeys.ts index d00db8c9371..10d1fedc91d 100644 --- a/pro/src/commons/core/Offers/utils/getCollectiveOffersSwrKeys.ts +++ b/pro/src/commons/core/Offers/utils/getCollectiveOffersSwrKeys.ts @@ -14,7 +14,7 @@ import { CollectiveSearchFiltersParams } from '../types' export type GetCollectiveOffersSwrKeysProps = { isNewOffersAndBookingsActive: boolean isInTemplateOffersPage: boolean - urlSearchFilters: CollectiveSearchFiltersParams + urlSearchFilters: Partial selectedOffererId?: string | null } diff --git a/pro/src/components/CollectiveOffersTable/CollectiveOfferRow/CollectiveActionsCells/CollectiveActionsCells.tsx b/pro/src/components/CollectiveOffersTable/CollectiveOfferRow/CollectiveActionsCells/CollectiveActionsCells.tsx index cad4c138ba0..dff7051eac3 100644 --- a/pro/src/components/CollectiveOffersTable/CollectiveOfferRow/CollectiveActionsCells/CollectiveActionsCells.tsx +++ b/pro/src/components/CollectiveOffersTable/CollectiveOfferRow/CollectiveActionsCells/CollectiveActionsCells.tsx @@ -63,7 +63,7 @@ export interface CollectiveActionsCellsProps { rowId: string offer: CollectiveOfferResponseModel editionOfferLink: string - urlSearchFilters: CollectiveSearchFiltersParams + urlSearchFilters: Partial deselectOffer: (offer: CollectiveOfferResponseModel) => void isSelected: boolean className?: string diff --git a/pro/src/components/CollectiveOffersTable/CollectiveOfferRow/CollectiveOfferRow.tsx b/pro/src/components/CollectiveOffersTable/CollectiveOfferRow/CollectiveOfferRow.tsx index 2d85d31753e..2c60a305e90 100644 --- a/pro/src/components/CollectiveOffersTable/CollectiveOfferRow/CollectiveOfferRow.tsx +++ b/pro/src/components/CollectiveOffersTable/CollectiveOfferRow/CollectiveOfferRow.tsx @@ -23,7 +23,7 @@ export type CollectiveOfferRowProps = { isSelected: boolean offer: CollectiveOfferResponseModel selectOffer: (offer: CollectiveOfferResponseModel) => void - urlSearchFilters: CollectiveSearchFiltersParams + urlSearchFilters: Partial isFirstRow: boolean } diff --git a/pro/src/components/CollectiveOffersTable/CollectiveOffersTable.tsx b/pro/src/components/CollectiveOffersTable/CollectiveOffersTable.tsx index bea993c2167..280eceb6806 100644 --- a/pro/src/components/CollectiveOffersTable/CollectiveOffersTable.tsx +++ b/pro/src/components/CollectiveOffersTable/CollectiveOffersTable.tsx @@ -18,7 +18,7 @@ type CollectiveOffersTableProps = { resetFilters: () => void setSelectedOffer: (offer: CollectiveOfferResponseModel) => void toggleSelectAllCheckboxes: () => void - urlSearchFilters: CollectiveSearchFiltersParams + urlSearchFilters: Partial isAtLeastOneOfferChecked: boolean isRestrictedAsAdmin?: boolean selectedOffers: CollectiveOfferResponseModel[] diff --git a/pro/src/components/CollectiveOffersTable/CollectiveOffersTableBody/CollectiveOffersTableBody.tsx b/pro/src/components/CollectiveOffersTable/CollectiveOffersTableBody/CollectiveOffersTableBody.tsx index fdbc4ea3240..54b7b249858 100644 --- a/pro/src/components/CollectiveOffersTable/CollectiveOffersTableBody/CollectiveOffersTableBody.tsx +++ b/pro/src/components/CollectiveOffersTable/CollectiveOffersTableBody/CollectiveOffersTableBody.tsx @@ -10,7 +10,7 @@ type CollectiveOffersTableBodyProps = { offers: CollectiveOfferResponseModel[] selectOffer: (offer: CollectiveOfferResponseModel) => void selectedOffers: CollectiveOfferResponseModel[] - urlSearchFilters: CollectiveSearchFiltersParams + urlSearchFilters: Partial } export const CollectiveOffersTableBody = ({ diff --git a/pro/src/components/OffersTable/OffersTableSearch/OffersTableSearch.module.scss b/pro/src/components/OffersTable/OffersTableSearch/OffersTableSearch.module.scss new file mode 100644 index 00000000000..0f3e4473bc5 --- /dev/null +++ b/pro/src/components/OffersTable/OffersTableSearch/OffersTableSearch.module.scss @@ -0,0 +1,115 @@ +@use "styles/mixins/_rem.scss" as rem; +@use "styles/mixins/_size.scss" as size; +@use "styles/mixins/_fonts.scss" as fonts; +@use "styles/mixins/_a11y.scss" as a11y; + +.offers-table-search { + margin-bottom: rem.torem(32px); + + &-name-and-toggle-row { + display: flex; + flex-direction: column; + align-items: flex-start; + } + + &-name-input, &-toggle-button { + margin-bottom: rem.torem(16px); + } + + &-toggle-button { + @include fonts.body; + + display: flex; + justify-content: center; + align-items: center; + height: fit-content; + width: fit-content; + padding: rem.torem(8px) rem.torem(16px); + + &-active { + @include fonts.button; + + border-color: var(--color-black); + + &::before { + content: ""; + display: block; + width: rem.torem(8px); + height: rem.torem(8px); + background-color: var(--color-secondary-light); + border-radius: 50%; + margin-right: rem.torem(8px); + } + } + } + + &-filters { + margin-top: rem.torem(16px); + + &-collapsed { + display: none; + } + } + + &-reset { + &-wrapper { + flex-direction: column; + margin-top: rem.torem(32px); + } + + &-button { + min-height: size.$input-min-height; + margin-top: 0; + display: block; + text-align: left; + } + } + + &-separator { + &-wrapper { + align-items: center; + display: flex; + margin-top: rem.torem(23px); + } + + &-element { + background-color: var(--color-grey-medium); + flex: 1; + height: rem.torem(1px); + } + } +} + +@media (min-width: size.$tablet) { + .offers-table-search { + &-name-and-toggle-row { + flex-direction: row; + } + + &-name-input { + width: unset; + max-width: rem.torem(606px); + flex-grow: 1; + } + + &-toggle-button { + margin-top: rem.torem(26px); + } + } +} + +@media (min-width: size.$laptop) { + .offers-table-search { + &-reset { + &-wrapper { + margin-top: 0; + flex-direction: row; + align-items: center; + } + } + } +} + +.visually-hidden { + @include a11y.visually-hidden; +} \ No newline at end of file diff --git a/pro/src/components/OffersTable/OffersTableSearch/OffersTableSearch.spec.tsx b/pro/src/components/OffersTable/OffersTableSearch/OffersTableSearch.spec.tsx new file mode 100644 index 00000000000..d2d0cbee4bb --- /dev/null +++ b/pro/src/components/OffersTable/OffersTableSearch/OffersTableSearch.spec.tsx @@ -0,0 +1,111 @@ +import { render, screen } from '@testing-library/react' +import { userEvent } from '@testing-library/user-event' + +import { OffersTableSearch, OffersTableSearchProps } from './OffersTableSearch' + +type OffersTableSearchTestProps = Partial + +const LABELS = { + nameInput: /Nom/, + resetButton: /Réinitialiser/, + searchButton: /Rechercher/, + filterToggleButton: /Filtres/, +} + +const renderOffersTableSearch = (props: OffersTableSearchTestProps = {}) => { + return render( + + {props.children} + + ) +} + +describe('OffersTableSearch', () => { + it('should display a text input and a search button', async () => { + const nameInputLabel = 'Nom de l’offre ou EAN-13' + const mockedOnChange = vi.fn() + renderOffersTableSearch({ + nameInputProps: { + label: nameInputLabel, + disabled: false, + onChange: mockedOnChange, + value: '', + }, + }) + + const nameInput = screen.getByRole('textbox', { name: nameInputLabel }) + const searchButton = screen.getByRole('button', { name: LABELS.searchButton }) + + expect(nameInput).toBeInTheDocument() + expect(searchButton).toBeInTheDocument() + + const newText = 'New text' + await userEvent.type(nameInput, newText) + expect(mockedOnChange).toHaveBeenCalledTimes(newText.length) + }) + + it('should hide filters passed as children and the reset button by default', () => { + const childrenTestId = 'filters' + renderOffersTableSearch({ + filtersVisibility: false, + children:
Filters
, + }) + + // Filters and reset button are always rendered. + const filters = screen.getByTestId(childrenTestId) + const resetButton = screen.getByRole('button', { name: LABELS.resetButton }) + expect(filters).toBeInTheDocument() + expect(resetButton).toBeInTheDocument() + + // However, they are hidden by default. + // There is a better way to do this, but .isVisible() does not seem to work. + const filtersWrapper= screen.getByTestId('offers-filter') + expect(filtersWrapper).toBeInTheDocument() + expect(filtersWrapper).toHaveClass('offers-table-search-filters-collapsed') + }) + + it('should make filters passed as children and reset button visible when expected', () => { + const childrenTestId = 'filters' + renderOffersTableSearch({ + filtersVisibility: true, + children:
Filters
, + }) + + // Filters and reset button are always rendered. + const filters = screen.getByTestId(childrenTestId) + const resetButton = screen.getByRole('button', { name: LABELS.resetButton }) + expect(filters).toBeInTheDocument() + expect(resetButton).toBeInTheDocument() + + // They are visible. + // There is a better way to do this, but .isVisible() does not seem to work. + const filtersWrapper = screen.getByTestId('offers-filter') + expect(filtersWrapper).not.toHaveClass('offers-table-search-filters-collapsed') + }) + + it('should call onFiltersToggle when clicking the filter toggle button', async () => { + const mockedOnFiltersToggle = vi.fn() + renderOffersTableSearch({ + onFiltersToggle: mockedOnFiltersToggle, + }) + + const filterToggleButton = screen.getByRole('button', { name: LABELS.filterToggleButton }) + await userEvent.click(filterToggleButton) + + expect(mockedOnFiltersToggle).toHaveBeenCalledTimes(1) + }) +}) \ No newline at end of file diff --git a/pro/src/components/OffersTable/OffersTableSearch/OffersTableSearch.tsx b/pro/src/components/OffersTable/OffersTableSearch/OffersTableSearch.tsx new file mode 100644 index 00000000000..d2a228a1a3f --- /dev/null +++ b/pro/src/components/OffersTable/OffersTableSearch/OffersTableSearch.tsx @@ -0,0 +1,109 @@ +import cn from 'classnames' + +import { FormLayout } from 'components/FormLayout/FormLayout' +import fullRefreshIcon from 'icons/full-refresh.svg' +import strokeDownIcon from 'icons/stroke-down.svg' +import strokeUpIcon from 'icons/stroke-up.svg' +import { Button } from 'ui-kit/Button/Button' +import { ButtonVariant, IconPositionEnum } from 'ui-kit/Button/types' +import { BaseInput } from 'ui-kit/form/shared/BaseInput/BaseInput' +import { FieldLayout } from 'ui-kit/form/shared/FieldLayout/FieldLayout' + +import styles from './OffersTableSearch.module.scss' + +export type OffersTableSearchProps = { + onSubmit: (e: React.FormEvent) => void + filtersVisibility: boolean + onFiltersToggle: () => void + isDisabled: boolean + hasActiveFilters: boolean + nameInputProps: { + label: JSX.Element | string + disabled: boolean + onChange: (e: React.ChangeEvent) => void + value: string + } + onResetFilters: () => void + children: React.ReactNode +} + +export const OffersTableSearch = ({ + onSubmit, + filtersVisibility, + onFiltersToggle, + isDisabled, + hasActiveFilters, + nameInputProps, + onResetFilters, + children, +}: OffersTableSearchProps) => { + return ( +
+ + + + + + +
+ {children} +
+ +
+
+
+
+ +
+
+ + ) +} diff --git a/pro/src/components/OffersTable/OffersTableSearch/utils.ts b/pro/src/components/OffersTable/OffersTableSearch/utils.ts new file mode 100644 index 00000000000..2061f8e9c54 --- /dev/null +++ b/pro/src/components/OffersTable/OffersTableSearch/utils.ts @@ -0,0 +1,80 @@ +import { useState } from 'react' + +import { SearchFiltersParams, CollectiveSearchFiltersParams } from 'commons/core/Offers/types' +import { localStorageAvailable } from 'commons/utils/localStorageAvailable' + +type FilterConfigType = 'individual' | 'collective' | 'template' +type SelectedFilters = Partial +type StoredFilterConfig = { + filtersVisibility: boolean + storedFilters: SelectedFilters +} + +const locallyStoredFilterConfig: Record = { + individual: 'INDIVIDUAL_OFFERS_FILTER_CONFIG', + collective: 'COLLECTIVE_OFFERS_FILTER_CONFIG', + template: 'TEMPLATE_OFFERS_FILTER_CONFIG', +} + +export const getStoredFilterConfig = (type: FilterConfigType): StoredFilterConfig => { + const isLocalStorageAvailable = localStorageAvailable() + const storedFilterConfig: StoredFilterConfig = isLocalStorageAvailable ? + JSON.parse(localStorage.getItem(locallyStoredFilterConfig[type]) || '{}') : + {} + const { filtersVisibility, storedFilters } = storedFilterConfig + + return { + filtersVisibility, + storedFilters, + } +} + +export const useStoredFilterConfig = (type: FilterConfigType) => { + const isLocalStorageAvailable = localStorageAvailable() + + const initialFilterConfig = getStoredFilterConfig(type) + const [filterConfig, setFilterConfig] = useState(initialFilterConfig) + const { filtersVisibility, storedFilters } = filterConfig + + const onFiltersToggle = () => { + const newFilterConfig: StoredFilterConfig = { + ...filterConfig, + filtersVisibility: !filtersVisibility, + } + + if (isLocalStorageAvailable) { + localStorage.setItem( + locallyStoredFilterConfig[type], + JSON.stringify(newFilterConfig) + ) + } + + setFilterConfig(newFilterConfig) + } + + const onApplyFilters = (selectedFilters: SelectedFilters) => { + const newFilterConfig: StoredFilterConfig = { + ...filterConfig, + storedFilters: { + ...filterConfig.storedFilters, + ...selectedFilters, + } + } + + if (isLocalStorageAvailable) { + localStorage.setItem( + locallyStoredFilterConfig[type], + JSON.stringify(newFilterConfig) + ) + } + + setFilterConfig(newFilterConfig) + } + + return { + filtersVisibility, + onFiltersToggle, + storedFilters, + onApplyFilters, + } +} \ No newline at end of file diff --git a/pro/src/pages/CollectiveOffers/CollectiveOffers.tsx b/pro/src/pages/CollectiveOffers/CollectiveOffers.tsx index 5420a4d90d1..9b1238192a0 100644 --- a/pro/src/pages/CollectiveOffers/CollectiveOffers.tsx +++ b/pro/src/pages/CollectiveOffers/CollectiveOffers.tsx @@ -20,6 +20,7 @@ import { serializeApiCollectiveFilters } from 'commons/core/Offers/utils/seriali import { useActiveFeature } from 'commons/hooks/useActiveFeature' import { useCurrentUser } from 'commons/hooks/useCurrentUser' import { selectCurrentOffererId } from 'commons/store/offerer/selectors' +import { getStoredFilterConfig } from 'components/OffersTable/OffersTableSearch/utils' import { formatAndOrderVenues } from 'repository/venuesService' import { Spinner } from 'ui-kit/Spinner/Spinner' @@ -36,10 +37,7 @@ export const CollectiveOffers = (): JSX.Element => { const defaultCollectiveFilters = useDefaultCollectiveSearchFilters() - const urlSearchFilters = useQueryCollectiveSearchFilters({ - ...defaultCollectiveFilters, - offererId: offererId ?? 'all', - }) + const urlSearchFilters = useQueryCollectiveSearchFilters() const currentPageNumber = urlSearchFilters.page ?? DEFAULT_PAGE @@ -61,7 +59,7 @@ export const CollectiveOffers = (): JSX.Element => { const venues = formatAndOrderVenues(data.venues) - const redirectWithUrlFilters = (filters: CollectiveSearchFiltersParams) => { + const redirectWithUrlFilters = (filters: Partial) => { navigate(computeCollectiveOffersUrl(filters, defaultCollectiveFilters), { replace: true, }) @@ -84,6 +82,7 @@ export const CollectiveOffers = (): JSX.Element => { const apiFilters: CollectiveSearchFiltersParams = { ...defaultCollectiveFilters, + ...(getStoredFilterConfig('collective').storedFilters as CollectiveSearchFiltersParams), ...urlSearchFilters, ...(isRestrictedAsAdmin ? { status: [] } : {}), ...{ offererId: offererId?.toString() ?? 'all' }, diff --git a/pro/src/pages/CollectiveOffers/__specs__/CollectiveOffers.spec.tsx b/pro/src/pages/CollectiveOffers/__specs__/CollectiveOffers.spec.tsx index 770aa8eb1a4..d5d9b7616f1 100644 --- a/pro/src/pages/CollectiveOffers/__specs__/CollectiveOffers.spec.tsx +++ b/pro/src/pages/CollectiveOffers/__specs__/CollectiveOffers.spec.tsx @@ -44,6 +44,10 @@ const proVenues = [ }), ] +const LABELS = { + nameSearchInput: /Nom de l’offre/, +} + const renderOffers = async ( filters: Partial = DEFAULT_COLLECTIVE_SEARCH_FILTERS, features: string[] = [] @@ -202,7 +206,9 @@ describe('route CollectiveOffers', () => { it('should load offers with written offer name filter', async () => { await renderOffers() await userEvent.type( - screen.getByPlaceholderText('Rechercher par nom d’offre'), + screen.getByRole('textbox', { + name: LABELS.nameSearchInput, + }), 'Any word' ) @@ -225,9 +231,9 @@ describe('route CollectiveOffers', () => { it('should store search value', async () => { await renderOffers() - const searchInput = screen.getByPlaceholderText( - 'Rechercher par nom d’offre' - ) + const searchInput = screen.getByRole('textbox', { + name: LABELS.nameSearchInput, + }) await userEvent.type(searchInput, 'search string') await userEvent.click(screen.getByText('Rechercher')) diff --git a/pro/src/pages/CollectiveOffers/__specs__/CollectiveOffersQueryParams.spec.tsx b/pro/src/pages/CollectiveOffers/__specs__/CollectiveOffersQueryParams.spec.tsx index 35d0b48d2cd..8b65ec40a5f 100644 --- a/pro/src/pages/CollectiveOffers/__specs__/CollectiveOffersQueryParams.spec.tsx +++ b/pro/src/pages/CollectiveOffers/__specs__/CollectiveOffersQueryParams.spec.tsx @@ -32,6 +32,10 @@ vi.mock('react-router-dom', async () => ({ useNavigate: vi.fn(), })) +const LABELS = { + nameSearchInput: /Nom de l’offre/, +} + const renderOffers = async ( filters: Partial = DEFAULT_COLLECTIVE_SEARCH_FILTERS ) => { @@ -119,7 +123,9 @@ describe('route CollectiveOffers', () => { await renderOffers() await userEvent.type( - screen.getByPlaceholderText('Rechercher par nom d’offre'), + screen.getByRole('textbox', { + name: LABELS.nameSearchInput, + }), 'AnyWord' ) await userEvent.click(screen.getByText('Rechercher')) @@ -136,7 +142,9 @@ describe('route CollectiveOffers', () => { await renderOffers() await userEvent.clear( - screen.getByPlaceholderText('Rechercher par nom d’offre') + screen.getByRole('textbox', { + name: LABELS.nameSearchInput, + }), ) await userEvent.click(screen.getByText('Rechercher')) diff --git a/pro/src/pages/CollectiveOffers/components/CollectiveOffersScreen/CollectiveOffersScreen.tsx b/pro/src/pages/CollectiveOffers/components/CollectiveOffersScreen/CollectiveOffersScreen.tsx index 3c233f1dea6..5cd0fde64b6 100644 --- a/pro/src/pages/CollectiveOffers/components/CollectiveOffersScreen/CollectiveOffersScreen.tsx +++ b/pro/src/pages/CollectiveOffers/components/CollectiveOffersScreen/CollectiveOffersScreen.tsx @@ -37,11 +37,11 @@ export type CollectiveOffersScreenProps = { offerer: GetOffererResponseModel | null initialSearchFilters: CollectiveSearchFiltersParams redirectWithUrlFilters: ( - filters: CollectiveSearchFiltersParams & { + filters: Partial & { page?: number } ) => void - urlSearchFilters: CollectiveSearchFiltersParams + urlSearchFilters: Partial venues: SelectOption[] categories?: SelectOption[] isRestrictedAsAdmin?: boolean @@ -120,7 +120,7 @@ export const CollectiveOffersScreen = ({ ) const applyUrlFiltersAndRedirect = ( - filters: CollectiveSearchFiltersParams + filters: Partial ) => { setPage(filters.page ?? 1) redirectWithUrlFilters(filters) diff --git a/pro/src/pages/CollectiveOffers/components/CollectiveOffersScreen/CollectiveOffersSearchFilters/CollectiveOffersSearchFilters.module.scss b/pro/src/pages/CollectiveOffers/components/CollectiveOffersScreen/CollectiveOffersSearchFilters/CollectiveOffersSearchFilters.module.scss index 86850a48df2..f5773425a86 100644 --- a/pro/src/pages/CollectiveOffers/components/CollectiveOffersScreen/CollectiveOffersSearchFilters/CollectiveOffersSearchFilters.module.scss +++ b/pro/src/pages/CollectiveOffers/components/CollectiveOffersScreen/CollectiveOffersSearchFilters/CollectiveOffersSearchFilters.module.scss @@ -4,8 +4,28 @@ $status-filter-margin-top: rem.torem(24px); -.search-filters-form { - margin-bottom: rem.torem(32px); +.search-filters { + &-form { + margin-bottom: rem.torem(32px); + } + + &-name-and-toggle-row { + display: flex; + flex-direction: column; + align-items: flex-start; + } + + &-toggle-button { + @include fonts.body; + + height: fit-content; + width: fit-content; + padding: rem.torem(8px) rem.torem(16px); + } + + &-collapsed { + display: none; + } } .search-separator { @@ -42,6 +62,24 @@ $status-filter-margin-top: rem.torem(24px); flex-direction: column; } +@media (min-width: size.$tablet) { + .search-filters { + &-name-and-toggle-row { + flex-direction: row; + } + + &-toggle-button { + margin-top: rem.torem(26px); + } + + &-name-input { + width: unset; + max-width: rem.torem(606px); + flex-grow: 1; + } + } +} + @media (min-width: size.$laptop) { .status-filter { margin-bottom: rem.torem(8px); diff --git a/pro/src/pages/CollectiveOffers/components/CollectiveOffersScreen/CollectiveOffersSearchFilters/CollectiveOffersSearchFilters.tsx b/pro/src/pages/CollectiveOffers/components/CollectiveOffersScreen/CollectiveOffersSearchFilters/CollectiveOffersSearchFilters.tsx index 6dc11a5af3f..b06fc19ae51 100644 --- a/pro/src/pages/CollectiveOffers/components/CollectiveOffersScreen/CollectiveOffersSearchFilters/CollectiveOffersSearchFilters.tsx +++ b/pro/src/pages/CollectiveOffers/components/CollectiveOffersScreen/CollectiveOffersSearchFilters/CollectiveOffersSearchFilters.tsx @@ -1,6 +1,6 @@ import { FormikProvider, useFormik } from 'formik' import isEqual from 'lodash.isequal' -import { Dispatch, FormEvent, SetStateAction, useEffect } from 'react' +import { Dispatch, FormEvent, SetStateAction, useEffect, useState } from 'react' import { CollectiveOfferDisplayedStatus, @@ -21,13 +21,11 @@ import { import { SelectOption } from 'commons/custom_types/form' import { useActiveFeature } from 'commons/hooks/useActiveFeature' import { FormLayout } from 'components/FormLayout/FormLayout' -import fullRefreshIcon from 'icons/full-refresh.svg' -import { Button } from 'ui-kit/Button/Button' -import { ButtonVariant } from 'ui-kit/Button/types' +import { OffersTableSearch } from 'components/OffersTable/OffersTableSearch/OffersTableSearch' +import { useStoredFilterConfig } from 'components/OffersTable/OffersTableSearch/utils' import { PeriodSelector } from 'ui-kit/form/PeriodSelector/PeriodSelector' import { SelectInput } from 'ui-kit/form/Select/SelectInput' import { SelectAutocomplete } from 'ui-kit/form/SelectAutoComplete/SelectAutocomplete' -import { BaseInput } from 'ui-kit/form/shared/BaseInput/BaseInput' import { FieldLayout } from 'ui-kit/form/shared/FieldLayout/FieldLayout' import styles from './CollectiveOffersSearchFilters.module.scss' @@ -87,6 +85,8 @@ export const CollectiveOffersSearchFilters = ({ venues, isRestrictedAsAdmin = false, }: CollectiveOffersSearchFiltersProps): JSX.Element => { + const { filtersVisibility, onFiltersToggle, onApplyFilters } = useStoredFilterConfig('collective') + const isNewOffersAndBookingsActive = useActiveFeature( 'WIP_ENABLE_NEW_COLLECTIVE_OFFERS_AND_BOOKINGS_STRUCTURE' ) @@ -165,20 +165,21 @@ export const CollectiveOffersSearchFilters = ({ const requestFilteredOffers = (event: FormEvent) => { event.preventDefault() - applyFilters({ + const newSearchFilters = { ...selectedFilters, offererId: offerer?.id.toString() ?? 'all', - }) + } + + applyFilters(newSearchFilters) + onApplyFilters(newSearchFilters) } - const resetCollectiveFilters = async () => { + const onResetFilters = async () => { await formik.setFieldValue('status', defaultCollectiveFilters.status) - resetFilters() } const searchByOfferNameLabel = 'Nom de l’offre' - const searchByOfferNamePlaceholder = 'Rechercher par nom d’offre' const statusFilterOptions = [ ...collectiveFilterStatus @@ -215,117 +216,95 @@ export const CollectiveOffersSearchFilters = ({ : []), ] + const hasActiveFilters = !isEqual( + { ...selectedFilters, offererId: 'all', page: 1 }, + defaultCollectiveFilters + ) + return ( - <> -
- - + + + + + + - + {!isNewOffersAndBookingsActive && ( - - - - - - - {!isNewOffersAndBookingsActive && ( - - - - )} - - -
- Période de l’évènement - - -
- - - - -
- -
- -
-
-
- -
-
- - + + )} + + +
+ Période de l’évènement + +
+ + + +
+ ) } diff --git a/pro/src/pages/IndividualOffers/IndividualOffers.tsx b/pro/src/pages/IndividualOffers/IndividualOffers.tsx index fb27e9100c8..4f589bd629e 100644 --- a/pro/src/pages/IndividualOffers/IndividualOffers.tsx +++ b/pro/src/pages/IndividualOffers/IndividualOffers.tsx @@ -54,7 +54,7 @@ export const IndividualOffers = (): JSX.Element => { ) const redirectWithUrlFilters = ( - filters: SearchFiltersParams & { audience?: Audience } + filters: Partial & { audience?: Audience } ) => { navigate(computeIndividualOffersUrl(filters), { replace: true }) } diff --git a/pro/src/pages/IndividualOffers/IndividualOffersContainer/IndividualOffersContainer.spec.tsx b/pro/src/pages/IndividualOffers/IndividualOffersContainer/IndividualOffersContainer.spec.tsx index 216bb4df595..8de739f1608 100644 --- a/pro/src/pages/IndividualOffers/IndividualOffersContainer/IndividualOffersContainer.spec.tsx +++ b/pro/src/pages/IndividualOffers/IndividualOffersContainer/IndividualOffersContainer.spec.tsx @@ -30,6 +30,10 @@ import { IndividualOffersContainerProps, } from './IndividualOffersContainer' +const LABELS = { + nameSearchInput: /Nom de l’offre/, +} + const renderOffers = ( props: IndividualOffersContainerProps, options?: RenderWithProvidersOptions @@ -232,11 +236,15 @@ describe('IndividualOffersScreen', () => { await searchAndChecked({}) expect( - screen.getByPlaceholderText('Rechercher par nom d’offre ou par EAN-13') + screen.getByRole('textbox', { + name: LABELS.nameSearchInput, + }), ).toBeInTheDocument() await userEvent.type( - screen.getByPlaceholderText('Rechercher par nom d’offre ou par EAN-13'), + screen.getByRole('textbox', { + name: LABELS.nameSearchInput, + }), 'Test' ) diff --git a/pro/src/pages/IndividualOffers/IndividualOffersContainer/IndividualOffersContainer.tsx b/pro/src/pages/IndividualOffers/IndividualOffersContainer/IndividualOffersContainer.tsx index 0ab92819ddf..e7c8d0b9d36 100644 --- a/pro/src/pages/IndividualOffers/IndividualOffersContainer/IndividualOffersContainer.tsx +++ b/pro/src/pages/IndividualOffers/IndividualOffersContainer/IndividualOffersContainer.tsx @@ -23,12 +23,12 @@ export type IndividualOffersContainerProps = { isLoading: boolean initialSearchFilters: SearchFiltersParams redirectWithUrlFilters: ( - filters: SearchFiltersParams & { + filters: Partial & { page?: number audience?: Audience } ) => void - urlSearchFilters: SearchFiltersParams + urlSearchFilters: Partial venues: SelectOption[] offererAddresses: SelectOption[] categories?: SelectOption[] @@ -85,7 +85,7 @@ export const IndividualOffersContainer = ({ const pageCount = Math.min(numberOfPages, MAX_TOTAL_PAGES) const applyUrlFiltersAndRedirect = ( - filters: SearchFiltersParams & { audience?: Audience } + filters: Partial & { audience?: Audience } ) => { redirectWithUrlFilters(filters) } diff --git a/pro/src/pages/IndividualOffers/IndividualOffersContainer/components/IndividualOffersSearchFilters/IndividualOffersSearchFilters.module.scss b/pro/src/pages/IndividualOffers/IndividualOffersContainer/components/IndividualOffersSearchFilters/IndividualOffersSearchFilters.module.scss index 95fc66726b9..d009e69b4f1 100644 --- a/pro/src/pages/IndividualOffers/IndividualOffersContainer/components/IndividualOffersSearchFilters/IndividualOffersSearchFilters.module.scss +++ b/pro/src/pages/IndividualOffers/IndividualOffersContainer/components/IndividualOffersSearchFilters/IndividualOffersSearchFilters.module.scss @@ -4,8 +4,28 @@ $status-filter-margin-top: rem.torem(24px); -.search-filters-form { - margin-bottom: rem.torem(32px); +.search-filters { + &-form { + margin-bottom: rem.torem(32px); + } + + &-name-and-toggle-row { + display: flex; + flex-direction: column; + align-items: flex-start; + } + + &-toggle-button { + @include fonts.body; + + height: fit-content; + width: fit-content; + padding: rem.torem(8px) rem.torem(16px); + } + + &-collapsed { + display: none; + } } .search-separator { @@ -41,6 +61,24 @@ $status-filter-margin-top: rem.torem(24px); flex-direction: column; } +@media (min-width: size.$tablet) { + .search-filters { + &-name-and-toggle-row { + flex-direction: row; + } + + &-toggle-button { + margin-top: rem.torem(26px); + } + + &-name-input { + width: unset; + max-width: rem.torem(606px); + flex-grow: 1; + } + } +} + @media (min-width: size.$laptop) { .reset-filters-row { flex-direction: row; diff --git a/pro/src/pages/IndividualOffers/IndividualOffersContainer/components/IndividualOffersSearchFilters/IndividualOffersSearchFilters.tsx b/pro/src/pages/IndividualOffers/IndividualOffersContainer/components/IndividualOffersSearchFilters/IndividualOffersSearchFilters.tsx index 2d101fdbf13..d527ac28363 100644 --- a/pro/src/pages/IndividualOffers/IndividualOffersContainer/components/IndividualOffersSearchFilters/IndividualOffersSearchFilters.tsx +++ b/pro/src/pages/IndividualOffers/IndividualOffersContainer/components/IndividualOffersSearchFilters/IndividualOffersSearchFilters.tsx @@ -1,4 +1,4 @@ -import { Dispatch, FormEvent, SetStateAction } from 'react' +import { Dispatch, FormEvent, SetStateAction, useState } from 'react' import { OfferStatus } from 'apiClient/v1' import { @@ -14,12 +14,10 @@ import { hasSearchFilters } from 'commons/core/Offers/utils/hasSearchFilters' import { SelectOption } from 'commons/custom_types/form' import { useActiveFeature } from 'commons/hooks/useActiveFeature' import { FormLayout } from 'components/FormLayout/FormLayout' -import fullRefreshIcon from 'icons/full-refresh.svg' -import { Button } from 'ui-kit/Button/Button' -import { ButtonVariant } from 'ui-kit/Button/types' +import { OffersTableSearch } from 'components/OffersTable/OffersTableSearch/OffersTableSearch' +import { useStoredFilterConfig } from 'components/OffersTable/OffersTableSearch/utils' import { PeriodSelector } from 'ui-kit/form/PeriodSelector/PeriodSelector' import { SelectInput } from 'ui-kit/form/Select/SelectInput' -import { BaseInput } from 'ui-kit/form/shared/BaseInput/BaseInput' import { FieldLayout } from 'ui-kit/form/shared/FieldLayout/FieldLayout' import styles from './IndividualOffersSearchFilters.module.scss' @@ -58,6 +56,7 @@ export const IndividualOffersSearchFilters = ({ categories, isRestrictedAsAdmin = false, }: IndividualOffersSearchFiltersProps): JSX.Element => { + const { filtersVisibility, onFiltersToggle, onApplyFilters } = useStoredFilterConfig('individual') const isOfferAddressEnabled = useActiveFeature('WIP_ENABLE_OFFER_ADDRESS') const areCollectiveNewStatusesEnabled = useActiveFeature( 'ENABLE_COLLECTIVE_NEW_STATUSES' @@ -115,6 +114,7 @@ export const IndividualOffersSearchFilters = ({ const requestFilteredOffers = (event: FormEvent) => { event.preventDefault() applyFilters(selectedFilters) + onApplyFilters(selectedFilters) } const searchByOfferNameLabel = ( @@ -122,8 +122,6 @@ export const IndividualOffersSearchFilters = ({ Nom de l’offre ou EAN-13 ) - const searchByOfferNamePlaceholder = - 'Rechercher par nom d’offre ou par EAN-13' const statusFilterOptions = individualFilterStatus.map((status) => { if (areCollectiveNewStatusesEnabled) { @@ -140,119 +138,99 @@ export const IndividualOffersSearchFilters = ({ return status }) - return ( - <> -
- - - - - {isOfferAddressEnabled ? ( - - - - ) : ( - - - - )} - - {categories && ( - - - - )} + const hasActiveFilters = hasSearchFilters(selectedFilters) - + return ( + + + {isOfferAddressEnabled ? ( + - + ) : ( + -
- Période de l’évènement - + -
-
- - - -
-
- -
-
- - + + )} + + + + + + +
+ Période de l’évènement + +
+ + ) } diff --git a/pro/src/pages/IndividualOffers/IndividualOffersContainer/components/IndividualOffersTable/IndividualOffersTable.tsx b/pro/src/pages/IndividualOffers/IndividualOffersContainer/components/IndividualOffersTable/IndividualOffersTable.tsx index 70aee1ddc98..3da917f190e 100644 --- a/pro/src/pages/IndividualOffers/IndividualOffersContainer/components/IndividualOffersTable/IndividualOffersTable.tsx +++ b/pro/src/pages/IndividualOffers/IndividualOffersContainer/components/IndividualOffersTable/IndividualOffersTable.tsx @@ -11,7 +11,7 @@ import { IndividualOffersTableBody } from './components/IndividualOffersTableBod type IndividualOffersTableProps = { applyUrlFiltersAndRedirect: ( - filters: SearchFiltersParams, + filters: Partial, isRefreshing: boolean ) => void areAllOffersSelected: boolean @@ -23,7 +23,7 @@ type IndividualOffersTableProps = { resetFilters: () => void setSelectedOffer: (offer: ListOffersOfferResponseModel) => void toggleSelectAllCheckboxes: () => void - urlSearchFilters: SearchFiltersParams + urlSearchFilters: Partial isAtLeastOneOfferChecked: boolean isRestrictedAsAdmin?: boolean currentPageOffersSubset: ListOffersOfferResponseModel[] diff --git a/pro/src/pages/IndividualOffers/__specs__/IndividualOffers.spec.tsx b/pro/src/pages/IndividualOffers/__specs__/IndividualOffers.spec.tsx index 85ea171ac63..d674f52f200 100644 --- a/pro/src/pages/IndividualOffers/__specs__/IndividualOffers.spec.tsx +++ b/pro/src/pages/IndividualOffers/__specs__/IndividualOffers.spec.tsx @@ -67,6 +67,11 @@ const offererAddress: GetOffererAddressResponseModel[] = [ city: 'New York', }), ] + +const LABELS = { + nameSearchInput: /Nom de l’offre/, +} + const renderOffers = async ( filters: Partial & { page?: number @@ -218,9 +223,9 @@ describe('route Offers', () => { it('should load offers with written offer name filter', async () => { await renderOffers() await userEvent.type( - screen.getByPlaceholderText( - 'Rechercher par nom d’offre ou par EAN-13' - ), + screen.getByRole('textbox', { + name: LABELS.nameSearchInput, + }), 'Any word' ) @@ -400,9 +405,9 @@ describe('route Offers', () => { it('should store search value', async () => { await renderOffers() - const searchInput = screen.getByPlaceholderText( - 'Rechercher par nom d’offre ou par EAN-13' - ) + const searchInput = screen.getByRole('textbox', { + name: LABELS.nameSearchInput, + }) await userEvent.type(searchInput, 'search string') await userEvent.click(screen.getByText('Rechercher')) @@ -427,7 +432,9 @@ describe('route Offers', () => { await renderOffers() await userEvent.clear( - screen.getByPlaceholderText('Rechercher par nom d’offre ou par EAN-13') + screen.getByRole('textbox', { + name: LABELS.nameSearchInput, + }) ) await userEvent.click(screen.getByText('Rechercher')) await waitFor(() => { diff --git a/pro/src/pages/IndividualOffers/utils/computeIndividualApiFilters.ts b/pro/src/pages/IndividualOffers/utils/computeIndividualApiFilters.ts index a6ca3b8e936..168b56a1315 100644 --- a/pro/src/pages/IndividualOffers/utils/computeIndividualApiFilters.ts +++ b/pro/src/pages/IndividualOffers/utils/computeIndividualApiFilters.ts @@ -3,14 +3,16 @@ import { DEFAULT_SEARCH_FILTERS, } from 'commons/core/Offers/constants' import { SearchFiltersParams } from 'commons/core/Offers/types' +import { getStoredFilterConfig } from 'components/OffersTable/OffersTableSearch/utils' export function computeIndividualApiFilters( - urlSearchFilters: SearchFiltersParams, + urlSearchFilters: Partial, selectedOffererId?: string | null, isRestrictedAsAdmin?: boolean ): SearchFiltersParams { const apiFilters: SearchFiltersParams = { ...DEFAULT_SEARCH_FILTERS, + ...(getStoredFilterConfig('individual').storedFilters as SearchFiltersParams), ...urlSearchFilters, ...(isRestrictedAsAdmin ? { status: ALL_STATUS } : {}), ...{ offererId: selectedOffererId?.toString() ?? '' }, diff --git a/pro/src/pages/TemplateCollectiveOffers/TemplateCollectiveOffers.tsx b/pro/src/pages/TemplateCollectiveOffers/TemplateCollectiveOffers.tsx index dbdce8eb6c3..3e6fe8a6b42 100644 --- a/pro/src/pages/TemplateCollectiveOffers/TemplateCollectiveOffers.tsx +++ b/pro/src/pages/TemplateCollectiveOffers/TemplateCollectiveOffers.tsx @@ -21,6 +21,7 @@ import { hasCollectiveSearchFilters } from 'commons/core/Offers/utils/hasSearchF import { serializeApiCollectiveFilters } from 'commons/core/Offers/utils/serializer' import { useCurrentUser } from 'commons/hooks/useCurrentUser' import { selectCurrentOffererId } from 'commons/store/offerer/selectors' +import { getStoredFilterConfig } from 'components/OffersTable/OffersTableSearch/utils' import { TemplateCollectiveOffersScreen } from 'pages/TemplateCollectiveOffers/TemplateCollectiveOffersScreen/TemplateCollectiveOffersScreen' import { formatAndOrderVenues } from 'repository/venuesService' import { Spinner } from 'ui-kit/Spinner/Spinner' @@ -28,10 +29,7 @@ import { Spinner } from 'ui-kit/Spinner/Spinner' export const TemplateCollectiveOffers = (): JSX.Element => { const offererId = useSelector(selectCurrentOffererId)?.toString() - const urlSearchFilters = useQueryCollectiveSearchFilters({ - ...DEFAULT_COLLECTIVE_TEMPLATE_SEARCH_FILTERS, - offererId: offererId ?? 'all', - }) + const urlSearchFilters = useQueryCollectiveSearchFilters() const currentPageNumber = urlSearchFilters.page ?? DEFAULT_PAGE const navigate = useNavigate() @@ -54,7 +52,7 @@ export const TemplateCollectiveOffers = (): JSX.Element => { ) const venues = formatAndOrderVenues(data.venues) - const redirectWithUrlFilters = (filters: CollectiveSearchFiltersParams) => { + const redirectWithUrlFilters = (filters: Partial) => { navigate( computeCollectiveOffersUrl( filters, @@ -82,6 +80,7 @@ export const TemplateCollectiveOffers = (): JSX.Element => { const apiFilters: CollectiveSearchFiltersParams = { ...DEFAULT_COLLECTIVE_TEMPLATE_SEARCH_FILTERS, + ...(getStoredFilterConfig('template').storedFilters as CollectiveSearchFiltersParams), ...urlSearchFilters, ...(isRestrictedAsAdmin ? { status: [] } : {}), ...{ offererId: offererId ?? '' }, diff --git a/pro/src/pages/TemplateCollectiveOffers/TemplateCollectiveOffersScreen/TemplateCollectiveOffersScreen.tsx b/pro/src/pages/TemplateCollectiveOffers/TemplateCollectiveOffersScreen/TemplateCollectiveOffersScreen.tsx index af9c8f08d6b..5882896db92 100644 --- a/pro/src/pages/TemplateCollectiveOffers/TemplateCollectiveOffersScreen/TemplateCollectiveOffersScreen.tsx +++ b/pro/src/pages/TemplateCollectiveOffers/TemplateCollectiveOffersScreen/TemplateCollectiveOffersScreen.tsx @@ -37,11 +37,11 @@ export type TemplateCollectiveOffersScreenProps = { offerer: GetOffererResponseModel | null initialSearchFilters: CollectiveSearchFiltersParams redirectWithUrlFilters: ( - filters: CollectiveSearchFiltersParams & { + filters: Partial & { page?: number } ) => void - urlSearchFilters: CollectiveSearchFiltersParams + urlSearchFilters: Partial venues: SelectOption[] categories?: SelectOption[] isRestrictedAsAdmin?: boolean @@ -118,7 +118,7 @@ export const TemplateCollectiveOffersScreen = ({ ) const applyUrlFiltersAndRedirect = ( - filters: CollectiveSearchFiltersParams + filters: Partial ) => { setPage(filters.page ?? 1) redirectWithUrlFilters(filters) diff --git a/pro/src/pages/TemplateCollectiveOffers/TemplateCollectiveOffersScreen/TemplateOffersSearchFilters/TemplateOffersSearchFilters.tsx b/pro/src/pages/TemplateCollectiveOffers/TemplateCollectiveOffersScreen/TemplateOffersSearchFilters/TemplateOffersSearchFilters.tsx index 8e2c9a4c078..17564f3850b 100644 --- a/pro/src/pages/TemplateCollectiveOffers/TemplateCollectiveOffersScreen/TemplateOffersSearchFilters/TemplateOffersSearchFilters.tsx +++ b/pro/src/pages/TemplateCollectiveOffers/TemplateCollectiveOffersScreen/TemplateOffersSearchFilters/TemplateOffersSearchFilters.tsx @@ -1,5 +1,5 @@ import { FormikProvider, useFormik } from 'formik' -import { Dispatch, FormEvent, SetStateAction, useEffect } from 'react' +import { Dispatch, FormEvent, SetStateAction, useEffect, useState } from 'react' import { CollectiveOfferDisplayedStatus, @@ -15,13 +15,11 @@ import { CollectiveSearchFiltersParams } from 'commons/core/Offers/types' import { hasCollectiveSearchFilters } from 'commons/core/Offers/utils/hasSearchFilters' import { SelectOption } from 'commons/custom_types/form' import { FormLayout } from 'components/FormLayout/FormLayout' -import fullRefreshIcon from 'icons/full-refresh.svg' -import { Button } from 'ui-kit/Button/Button' -import { ButtonVariant } from 'ui-kit/Button/types' +import { OffersTableSearch } from 'components/OffersTable/OffersTableSearch/OffersTableSearch' +import { useStoredFilterConfig } from 'components/OffersTable/OffersTableSearch/utils' import { PeriodSelector } from 'ui-kit/form/PeriodSelector/PeriodSelector' import { SelectInput } from 'ui-kit/form/Select/SelectInput' import { SelectAutocomplete } from 'ui-kit/form/SelectAutoComplete/SelectAutocomplete' -import { BaseInput } from 'ui-kit/form/shared/BaseInput/BaseInput' import { FieldLayout } from 'ui-kit/form/shared/FieldLayout/FieldLayout' import styles from './TemplateOffersSearchFilters.module.scss' @@ -74,6 +72,8 @@ export const TemplateOffersSearchFilters = ({ venues, isRestrictedAsAdmin = false, }: TemplateOffersSearchFiltersProps): JSX.Element => { + const { filtersVisibility, onFiltersToggle, onApplyFilters } = useStoredFilterConfig('template') + const formats: SelectOption[] = Object.values(EacFormat).map((format) => ({ value: format, label: format, @@ -136,10 +136,13 @@ export const TemplateOffersSearchFilters = ({ const requestFilteredOffers = (event: FormEvent) => { event.preventDefault() - applyFilters({ + const newSearchFilters = { ...selectedFilters, offererId: offerer?.id.toString() ?? '', - }) + } + + applyFilters(newSearchFilters) + onApplyFilters(newSearchFilters) } const resetCollectiveFilters = async () => { @@ -150,97 +153,70 @@ export const TemplateOffersSearchFilters = ({ resetFilters() } - const searchByOfferNameLabel = 'Nom de l’offre' - const searchByOfferNamePlaceholder = 'Rechercher par nom d’offre' + const hasActiveFilters = hasCollectiveSearchFilters( + selectedFilters, + DEFAULT_COLLECTIVE_TEMPLATE_SEARCH_FILTERS + ) return ( - <> -
- - + + + + + + - - - - - - - - - -
- Période de l’évènement - - -
-
- - - + Période de l’évènement + - - -
- -
-
-
- -
-
- - + + + + + + ) } diff --git a/pro/src/ui-kit/Button/Button.tsx b/pro/src/ui-kit/Button/Button.tsx index 1ae0fd2b618..20f2d225c6a 100644 --- a/pro/src/ui-kit/Button/Button.tsx +++ b/pro/src/ui-kit/Button/Button.tsx @@ -104,15 +104,10 @@ export const Button = forwardRef( width="20" /> )} - {variant === ButtonVariant.BOX ? ( -
- ) : ( - <> - {isLoading && loadingDiv} - {!isLoading && !hasTooltip && children} - - )} - + <> + {isLoading && loadingDiv} + {!isLoading && !hasTooltip && children} + {icon && !isLoading && iconPosition === IconPositionEnum.RIGHT && (