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

LINK-1992 | add organization filter to event and registration search page #393

Merged
merged 1 commit into from
May 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ module.exports = buildSchema(/* GraphQL */ `
include: [String]
page: Int
pageSize: Int
publisher: [String]
text: String
): RegistrationsResponse!
signup(id: ID!): Signup!
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React from 'react';
import { useTranslation } from 'react-i18next';

import useOrganizationOptions from '../../../../domain/organization/hooks/useOrganizationOptions';
import getValue from '../../../../utils/getValue';
import FilterTag, { FilterTagProps } from '../FilterTag';

type Props = Omit<FilterTagProps, 'text' | 'type'>;

const PublisherFilterTag: React.FC<Props> = ({ value, ...rest }) => {
const { t } = useTranslation();
const { loading, options } = useOrganizationOptions();

const name = getValue(options.find((o) => o.value === value)?.label, '');

return (
<FilterTag
{...rest}
text={loading ? t('common.loading') : name}
type="publisher"
value={value}
/>
);
};

export default PublisherFilterTag;
39 changes: 23 additions & 16 deletions src/common/components/publisherSelector/PublisherSelector.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,19 @@
import React, { useMemo } from 'react';
import { useTranslation } from 'react-i18next';

import { organizationPathBuilder } from '../../../domain/organization/utils';
import {
getOrganizationOption,
organizationPathBuilder,
} from '../../../domain/organization/utils';
import useUser from '../../../domain/user/hooks/useUser';
import useUserOrganizations from '../../../domain/user/hooks/useUserOrganizations';
import {
OrganizationFieldsFragment,
useOrganizationQuery,
} from '../../../generated/graphql';
import { useOrganizationQuery } from '../../../generated/graphql';
import useLocale from '../../../hooks/useLocale';
import { OptionType } from '../../../types';
import getPathBuilder from '../../../utils/getPathBuilder';
import getValue from '../../../utils/getValue';
import Combobox, { SingleComboboxProps } from '../combobox/Combobox';

const getOption = (organization: OrganizationFieldsFragment): OptionType => {
return {
label: getValue(organization.name, ''),
value: getValue(organization.id, ''),
};
};

export type PublisherSelectorProps = {
publisher?: string | null;
} & Omit<SingleComboboxProps<string | null>, 'toggleButtonAriaLabel'>;
Expand All @@ -33,6 +27,7 @@ const PublisherSelector: React.FC<PublisherSelectorProps> = ({
...rest
}) => {
const { t } = useTranslation();
const locale = useLocale();
const { user } = useUser();
const { loading, organizations } = useUserOrganizations(user);

Expand All @@ -48,17 +43,29 @@ const PublisherSelector: React.FC<PublisherSelectorProps> = ({
const selectedOrganization = React.useMemo(
() =>
organizationData?.organization
? getOption(organizationData.organization)
? getOrganizationOption({
idPath: 'id',
locale,
organization: organizationData.organization,
t,
})
: null,
[organizationData]
[locale, organizationData?.organization, t]
);

const options = useMemo(() => {
if (publisher) {
return selectedOrganization ? [selectedOrganization] : [];
}
return organizations.map((org) => getOption(org));
}, [organizations, publisher, selectedOrganization]);
return organizations.map((org) =>
getOrganizationOption({
idPath: 'id',
locale,
organization: org,
t,
})
);
}, [locale, organizations, publisher, selectedOrganization, t]);

return (
<Combobox
Expand Down
8 changes: 5 additions & 3 deletions src/common/components/searchPanel/SearchPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export type SearchRowProps = {
searchInputLabel: string;
searchInputPlaceholder: string;
searchInputValue: string;
selector?: ReactElement;
selectors?: ReactElement[];
};

const SearchRow: FC<SearchRowProps> = ({
Expand All @@ -25,11 +25,13 @@ const SearchRow: FC<SearchRowProps> = ({
searchInputLabel,
searchInputPlaceholder,
searchInputValue,
selector,
selectors,
}) => {
return (
<div className={styles.searchRow}>
{selector && <SelectorColumn>{selector}</SelectorColumn>}
{selectors?.map((selector, index) => (
<SelectorColumn key={index}>{selector}</SelectorColumn>
))}
<TextSearchColumn>
<SearchInput
className={searchInputClassName}
Expand Down
2 changes: 1 addition & 1 deletion src/common/components/searchPanel/searchPanel.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
margin-top: var(--spacing-m);
margin-bottom: var(--spacing-m);

@include medium-up {
@include large-up {
display: flex;
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/domain/app/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1111,6 +1111,7 @@
"buttonSearch": "Search events",
"labelEventType": "Type",
"labelPlace": "Search venue",
"labelPublisher": "Search publisher",
"labelSearch": "Search Linked Events",
"placeholderSearch": "Search events"
}
Expand Down Expand Up @@ -1952,6 +1953,7 @@
"buttonSearch": "Search",
"labelEventType": "Type",
"labelPlace": "Search venue",
"labelPublisher": "Search publisher",
"labelSearch": "Search registrations",
"placeholderSearch": "Search registrations"
},
Expand Down
2 changes: 2 additions & 0 deletions src/domain/app/i18n/fi.json
Original file line number Diff line number Diff line change
Expand Up @@ -1204,6 +1204,7 @@
"buttonSearch": "Etsi tapahtumia",
"labelEventType": "Tyyppi",
"labelPlace": "Etsi tapahtumapaikkaa",
"labelPublisher": "Etsi julkaisijaa",
"labelSearch": "Hae Linked Events -rajapinnasta",
"placeholderSearch": "Hae tapahtumia"
}
Expand Down Expand Up @@ -1952,6 +1953,7 @@
"buttonSearch": "Etsi",
"labelEventType": "Tyyppi",
"labelPlace": "Etsi tapahtumapaikkaa",
"labelPublisher": "Etsi julkaisijaa",
"labelSearch": "Hae ilmoittautumisia",
"placeholderSearch": "Hae ilmoittautumisia"
},
Expand Down
2 changes: 2 additions & 0 deletions src/domain/app/i18n/sv.json
Original file line number Diff line number Diff line change
Expand Up @@ -1111,6 +1111,7 @@
"buttonSearch": "Sök efter evenemang",
"labelEventType": "Typ",
"labelPlace": "Sök plats",
"labelPublisher": "Sök utgivare",
"labelSearch": "Sök efter evenemang från Linked Events",
"placeholderSearch": "Sök efter evenemang"
}
Expand Down Expand Up @@ -1952,6 +1953,7 @@
"buttonSearch": "Sök",
"labelEventType": "Typ",
"labelPlace": "Sök plats",
"labelPublisher": "Sök utgivare",
"labelSearch": "Sök registreringar",
"placeholderSearch": "Sök registreringar"
},
Expand Down
68 changes: 34 additions & 34 deletions src/domain/eventSearch/searchPanel/SearchPanel.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
import { ClassNames } from '@emotion/react';
import { IconCalendar, IconHeart, IconLocation, Koros } from 'hds-react';
import {
IconCalendar,
IconGroup,
IconHeart,
IconLocation,
Koros,
} from 'hds-react';
import React from 'react';
import { useTranslation } from 'react-i18next';
import { useLocation, useNavigate } from 'react-router';

import Breadcrumb from '../../../common/components/breadcrumb/Breadcrumb';
import Button from '../../../common/components/button/Button';
import DateSelectorDropdown, {
DATE_FIELDS,
} from '../../../common/components/dateSelectorDropdown/DateSelectorDropdown';
import DateSelectorDropdown from '../../../common/components/dateSelectorDropdown/DateSelectorDropdown';
import MultiSelectDropdown from '../../../common/components/multiSelectDropdown/MultiSelectDropdown';
import SearchInput from '../../../common/components/searchInput/SearchInput';
import { ROUTES, testIds } from '../../../constants';
import useEventSearchHelpers from '../../../hooks/useEventSearchHelpers';
import useLocale from '../../../hooks/useLocale';
import useSearchState from '../../../hooks/useSearchState';
import { OptionType } from '../../../types';
Expand All @@ -28,11 +33,13 @@ import {
getEventSearchQuery,
} from '../../events/utils';
import PlaceSelector from './placeSelector/PlaceSelector';
import PublisherSelector from './publisherSelector/PublisherSelector';
import styles from './searchPanel.module.scss';

type SearchState = {
end: Date | null;
place: string[];
publisher: string[];
start: Date | null;
text: string;
type: EVENT_TYPE[];
Expand All @@ -50,48 +57,31 @@ const SearchPanel: React.FC = () => {
const [searchState, setSearchState] = useSearchState<SearchState>({
end: null,
place: [],
publisher: [],
start: null,
text: '',
type: [],
});

const {
handleChangeDate,
handleChangePlaces,
handleChangePublishers,
handleChangeText,
handleChangeTypes,
} = useEventSearchHelpers(setSearchState);

const handleSearch = () => {
navigate({
pathname: `/${locale}${ROUTES.SEARCH}`,
search: getEventSearchQuery(searchState, location.search),
});
};

const handleChangePlaces = (newPlaces: OptionType[]) => {
setSearchState({ place: newPlaces.map((item) => item.value) });
};

const handleChangeEventTypes = (newTypes: OptionType[]) => {
setSearchState({
type: newTypes.map((type) => type.value) as EVENT_TYPE[],
});
};

const handleChangeText = (text: string) => {
setSearchState({ text });
};

const handleChangeDate = (field: DATE_FIELDS, value: Date | null) => {
switch (field) {
case DATE_FIELDS.END_DATE:
setSearchState({ end: value });
break;
case DATE_FIELDS.START_DATE:
setSearchState({ start: value });
break;
}
};

React.useEffect(() => {
const { end, places, start, text, types } = getEventSearchInitialValues(
location.search
);
setSearchState({ end, place: places, start, text, type: types });
const { end, places, publisher, start, text, types } =
getEventSearchInitialValues(location.search);
setSearchState({ end, place: places, publisher, start, text, type: types });
}, [location.search, setSearchState]);

return (
Expand Down Expand Up @@ -157,7 +147,7 @@ const SearchPanel: React.FC = () => {
<div>
<MultiSelectDropdown
icon={<IconHeart />}
onChange={handleChangeEventTypes}
onChange={handleChangeTypes}
options={eventTypeOptions}
showSearch={true}
toggleButtonLabel={t(
Expand All @@ -174,6 +164,16 @@ const SearchPanel: React.FC = () => {
}
/>
</div>
<div>
<PublisherSelector
icon={<IconGroup aria-hidden />}
onChange={handleChangePublishers}
toggleButtonLabel={t(
'eventSearchPage.searchPanel.labelPublisher'
)}
value={searchState.publisher}
/>
</div>
</div>
</div>
<div className={styles.buttonWrapper}>
Expand Down
Loading
Loading