Skip to content

Commit

Permalink
Merge pull request #920 from City-of-Helsinki/UHF-9530-linked-events-…
Browse files Browse the repository at this point in the history
…keywords

UHF-9576 linked events keywords
  • Loading branch information
hyrsky authored Mar 15, 2024
2 parents fda238d + 8deb7b7 commit c2eec06
Show file tree
Hide file tree
Showing 13 changed files with 118 additions and 9 deletions.
2 changes: 1 addition & 1 deletion dist/css/styles.min.css

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/js/linkedevents.min.js

Large diffs are not rendered by default.

15 changes: 14 additions & 1 deletion hdbt.theme
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use Drupal\helfi_tpr\Entity\Unit;
use Drupal\image\Entity\ImageStyle;
use Drupal\image\Plugin\Field\FieldType\ImageItem;
use Drupal\language\ConfigurableLanguageManagerInterface;
use Drupal\link\LinkItemInterface;
use Drupal\menu_link_content\Plugin\Menu\MenuLinkContent;
use Drupal\node\Entity\Node;
use Drupal\node\NodeInterface;
Expand Down Expand Up @@ -1629,6 +1630,7 @@ function hdbt_preprocess_pager(&$variables): void {
function hdbt_preprocess_paragraph__event_list(&$variables): void {
// Expose event list variables to frontend.
if (isset($variables['paragraph'])) {
/** @var \Drupal\helfi_react_search\Entity\EventList $paragraph */
$paragraph = $variables['paragraph'];
$settings = [];

Expand All @@ -1643,9 +1645,20 @@ function hdbt_preprocess_paragraph__event_list(&$variables): void {
$settings['field_event_count'] = '3';
}

$langcode = \Drupal::languageManager()
->getCurrentLanguage()
->getId();

$settings['field_filter_keywords'] = array_map(static fn ($term) => [
'id' => $term->get('field_keyword_id')->getString(),
'name' => $term->getName(),
], $paragraph->getFilterKeywords($langcode));

if ($paragraph->hasField('field_api_url') && !$paragraph->get('field_api_url')->isEmpty()) {
$linkedEvents = Drupal::service('helfi_react_search_linked_events');
$events_public_url = $paragraph->get('field_api_url')->first()->getUrl()->toString();
$link_field = $events_public_url = $paragraph->get('field_api_url')->first();
assert($link_field instanceof LinkItemInterface);
$events_public_url = $link_field->getUrl()->toString();
$settings['events_public_url'] = $events_public_url;
$params = $linkedEvents->parseParams($events_public_url);
$eventUrl = $linkedEvents->getEventsRequest($params, $settings['field_event_count']);
Expand Down
44 changes: 44 additions & 0 deletions src/js/react/apps/linkedevents/components/TopicsFilter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { Select } from 'hds-react';
import { useAtomValue, useAtom, useSetAtom } from 'jotai';

import { topicsAtom, topicSelectionAtom, updateParamsAtom} from '../store';
import SearchComponents from '../enum/SearchComponents';
import ApiKeys from '../enum/ApiKeys';

function TopicsFilter() {
const topics = useAtomValue(topicsAtom);
const [topicSelection, setTopicsFilter] = useAtom(topicSelectionAtom);
const updateParams = useSetAtom(updateParamsAtom);

const onChange = (value: any) => {
setTopicsFilter(value);
updateParams({ [ApiKeys.KEYWORDS]: value.map((topic: any) => topic.value).join(',') });
};

const selectLabel: string = Drupal.t('Event topic', {}, { context: 'React search: topics filter' });

return (
<div className='hdbt-search__filter event-form__filter--topics'>
<Select
className='hdbt-search__dropdown'
clearButtonAriaLabel={Drupal.t('Clear @label selection', {'@label': selectLabel}, { context: 'React search clear selection label' })}
label={selectLabel}
multiselect
// @ts-ignore
options={topics}
value={topicSelection}
id={SearchComponents.TOPICS}
onChange={onChange}
placeholder={Drupal.t('All topics', {}, { context: 'React search: topics filter' })}
selectedItemRemoveButtonAriaLabel={Drupal.t('Remove item', {}, { context: 'React search: remove item aria label' })}
theme={{
'--focus-outline-color': 'var(--hdbt-color-black)',
'--multiselect-checkbox-background-selected': 'var(--hdbt-color-black)',
'--placeholder-color': 'var(--hdbt-color-black)',
}}
/>
</div>
);
}

export default TopicsFilter;
21 changes: 16 additions & 5 deletions src/js/react/apps/linkedevents/containers/FormContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
formErrorsAtom,
updateUrlAtom,
} from '../store';
import TopicsFilter from '../components/TopicsFilter';


function FormContainer() {
Expand All @@ -24,15 +25,22 @@ function FormContainer() {
const errors = useAtomValue(formErrorsAtom);
const url = useAtomValue(urlAtom);
const updateUrl = useSetAtom(updateUrlAtom);
const { showLocation, showFreeFilter, showRemoteFilter, showTimeFilter } = filterSettings;
const {
showLocation,
showFreeFilter,
showRemoteFilter,
showTimeFilter,
showTopicsFilter,
} = filterSettings;

const onSubmit = () => {
updateUrl();
};

const handleSubmit = (e: FormEvent) => {
e.preventDefault();
onSubmit(); return false;
onSubmit();
return false;
};

const bothCheckboxes = showFreeFilter && showRemoteFilter;
Expand All @@ -42,7 +50,7 @@ function FormContainer() {
const freeLabel = bothCheckboxes ? freeTranslation : `${showOnlyLabel} ${freeTranslation.toLowerCase()}`;
const remoteLabel = bothCheckboxes ? remoteTranslation : `${showOnlyLabel} ${remoteTranslation.toLowerCase()}`;

const showForm = showLocation || showFreeFilter || showTimeFilter || showRemoteFilter;
const showForm = showLocation || showFreeFilter || showTimeFilter || showRemoteFilter || showTopicsFilter;
const HeadingTag = eventListTitle ? 'h3' : 'h2';

if (!showForm) {
Expand All @@ -54,14 +62,17 @@ function FormContainer() {
<HeadingTag className='event-list__filter-title'>{Drupal.t('Filter events', {}, { context: 'Events search: search form title' })}</HeadingTag>
<div className='event-form__filters-container'>
<div className='event-form__filter-section-container'>
{
showTopicsFilter &&
<TopicsFilter />
}
{
showLocation &&
<LocationFilter />
}
{
showTimeFilter &&
<DateSelect
/>
<DateSelect />
}
</div>
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import FilterButton from '@/react/common/FilterButton';
import {
resetFormAtom,
locationSelectionAtom,
topicSelectionAtom,
freeFilterAtom,
remoteFilterAtom,
startDateAtom,
Expand All @@ -29,16 +30,23 @@ const SelectionsContainer = ({ url }: SelectionsContainerProps) => {
const startDate = useAtomValue(startDateAtom);
const endDate = useAtomValue(endDateAtom);
const [locationSelection, setLocationSelection] = useAtom(locationSelectionAtom);
const [topicsSelection, setTopicsSelection] = useAtom(topicSelectionAtom);
const resetForm = useSetAtom(resetFormAtom);

const showClearButton = locationSelection.length || startDate || endDate || freeFilter || remoteFilter;
const showClearButton = locationSelection.length || topicsSelection.length || startDate || endDate || freeFilter || remoteFilter;

if (!url) {
return null;
}

return (
<FilterBulletsWrapper showClearButton={showClearButton} resetForm={resetForm} url={url}>
<ListFilterPills
updater={setTopicsSelection}
valueKey={ApiKeys.KEYWORDS}
values={topicsSelection}
url={url}
/>
<ListFilterPills
updater={setLocationSelection}
valueKey={ApiKeys.LOCATION}
Expand Down
1 change: 1 addition & 0 deletions src/js/react/apps/linkedevents/enum/ApiKeys.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export const ApiKeys = {
KEYWORDS: 'keyword_OR',
FREE: 'is_free',
LOCATION: 'location',
PAGESIZE: 'page_size',
Expand Down
1 change: 1 addition & 0 deletions src/js/react/apps/linkedevents/enum/SearchComponents.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const SearchComponents = {
TOPICS: 'topics',
LOCATION: 'location',
DATE: 'date',
END_DISABLED: 'end_disabled',
Expand Down
16 changes: 16 additions & 0 deletions src/js/react/apps/linkedevents/store.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import Location from './types/Location';
import OptionType from './types/OptionType';
import FormErrors from './types/FormErrors';
import ApiKeys from './enum/ApiKeys';
import Topic from './types/Topic';

interface Options {
[key: string]: string
Expand Down Expand Up @@ -54,9 +55,14 @@ const createBaseAtom = () => {
showTimeFilter: settings?.field_event_time,
showFreeFilter: settings?.field_free_events,
showRemoteFilter: settings?.field_remote_events,
showTopicsFilter: settings?.field_filter_keywords.length > 0,
eventCount: Number(settings?.field_event_count)
};
const locations = transformLocations(settings?.places);
const topics: Topic[] = settings?.field_filter_keywords.map(topic => ({
value: topic.id,
label: topic.name.charAt(0).toUpperCase() + topic.name.slice(1),
}));

let baseUrl;
let initialParams;
Expand All @@ -76,6 +82,7 @@ const createBaseAtom = () => {
initialUrl: eventsApiUrl,
initialParams,
locations,
topics,
eventListTitle,
eventsPublicUrl,
};
Expand All @@ -101,6 +108,10 @@ export const locationAtom = atom(
(get) => get(baseAtom)?.locations
);

export const topicsAtom = atom(
(get) => get(baseAtom)?.topics
);

export const titleAtom = atom(
(get) => get(baseAtom)?.eventListTitle
);
Expand All @@ -115,6 +126,8 @@ export const settingsAtom = atom(
showLocation: false,
showRemoteFilter: false,
showTimeFilter: false,
showTopicsFilter: false,
topics: [],
eventCount: 3
}
);
Expand All @@ -127,6 +140,8 @@ export const paramsAtom = atom(new URLSearchParams());

export const locationSelectionAtom = atom<OptionType[]>([] as OptionType[]);

export const topicSelectionAtom = atom<Topic[]>([]);

export const startDateAtom = atom<DateTime|undefined>(undefined);

export const endDateAtom = atom<DateTime|undefined>(undefined);
Expand All @@ -146,6 +161,7 @@ export const resetFormAtom = atom(null, (get, set) => {
const initialParams = get(initialParamsAtom);

set(locationSelectionAtom, []);
set(topicSelectionAtom, []);
set(startDateAtom, undefined);
set(endDateAtom, undefined);
set(endDisabledAtom, false);
Expand Down
3 changes: 3 additions & 0 deletions src/js/react/apps/linkedevents/types/FilterSettings.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import Topic from './Topic';

type FilterSettings = {
showLocation: boolean,
showTimeFilter: boolean,
showFreeFilter: boolean,
showRemoteFilter: boolean,
showTopicsFilter: boolean,
eventCount: number
};

Expand Down
7 changes: 7 additions & 0 deletions src/js/react/apps/linkedevents/types/Topic.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

export type Topic = {
value: string,
label: string
};

export default Topic;
4 changes: 4 additions & 0 deletions src/js/types/drupalSettings.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ declare namespace drupalSettings {
field_free_events: boolean,
field_remote_events: boolean,
field_event_count: string,
field_filter_keywords: {
id: string,
name: string,
}[],
places: {
[key:string]: {
id: string,
Expand Down
1 change: 1 addition & 0 deletions src/scss/06_components/paragraphs/_event-list.scss
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ $tag-vertical-padding: 5px;
}

.event-form__filter--location,
.event-form__filter--topics,
.event-form__filter--date {
flex-basis: 100%;

Expand Down

0 comments on commit c2eec06

Please sign in to comment.