diff --git a/CHANGELOG.md b/CHANGELOG.md
index b61478b9..53096e9d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,9 @@ All notable changes to this project will be documented in this file.
## [Unreleased]
+- [#279](https://github.com/os2display/display-admin-client/pull/279)
+ - Eventdatabase v2 feed source - Change subscription endpoint.
+ - Eventdatabase v2 feed source - Fixed options load.
- [#271](https://github.com/os2display/display-admin-client/pull/271)
- Added new feed source: Eventdatabasen v2.
diff --git a/src/components/slide/content/poster/poster-single-search.jsx b/src/components/slide/content/poster/poster-single-search.jsx
index f84b900d..725b3b07 100644
--- a/src/components/slide/content/poster/poster-single-search.jsx
+++ b/src/components/slide/content/poster/poster-single-search.jsx
@@ -1,11 +1,11 @@
-import { React, useEffect, useRef, useState } from "react";
+import { React, useEffect, useState } from "react";
import { Button, Row } from "react-bootstrap";
import Col from "react-bootstrap/Col";
-import AsyncSelect from "react-select/async";
import { useTranslation } from "react-i18next";
import PropTypes from "prop-types";
+import { MultiSelect } from "react-multi-select-component";
+import Form from "react-bootstrap/Form";
import FormInput from "../../../util/forms/form-input";
-import Select from "../../../util/forms/select";
import { getHeaders, loadDropdownOptionsPromise } from "./poster-helper";
/**
@@ -24,54 +24,44 @@ function PosterSingleSearch({
}) {
const { t } = useTranslation("common", { keyPrefix: "poster-selector-v2" });
- const [singleSearch, setSingleSearch] = useState("");
- const [singleSearchType, setSingleSearchType] = useState("title");
- const [singleSearchTypeValue, setSingleSearchTypeValue] = useState("");
+ const [title, setTitle] = useState("");
+ const [organizations, setOrganizations] = useState([]);
+ const [locations, setLocations] = useState([]);
+ const [tags, setTags] = useState([]);
- const timeoutRef = useRef(null);
+ const [locationOptions, setLocationOptions] = useState([]);
+ const [tagOptions, setTagOptions] = useState([]);
+ const [organizationOptions, setOrganizationOptions] = useState([]);
- const debounceOptions = (inputValue) => {
- // Debounce result to avoid searching while typing.
- return new Promise((resolve, reject) => {
- if (timeoutRef.current) {
- clearTimeout(timeoutRef.current);
- }
-
- timeoutRef.current = setTimeout(() => {
- loadDropdownOptionsPromise(
- optionsEndpoint,
- getHeaders(),
- inputValue,
- singleSearchType
- )
- .then((data) => resolve(data))
- .catch((reason) => reject(reason));
- }, 500);
- });
- };
+ useEffect(() => {
+ loadDropdownOptionsPromise(optionsEndpoint, getHeaders(), "", "tags").then(
+ (r) => setTagOptions(r)
+ );
+
+ loadDropdownOptionsPromise(
+ optionsEndpoint,
+ getHeaders(),
+ "",
+ "locations"
+ ).then((r) => setLocationOptions(r));
+
+ loadDropdownOptionsPromise(
+ optionsEndpoint,
+ getHeaders(),
+ "",
+ "organizations"
+ ).then((r) => setOrganizationOptions(r));
+ }, []);
const singleSearchFetch = () => {
const params = {
type: "events",
};
- const singleSearchTypeValueId = singleSearchTypeValue?.value;
-
- switch (singleSearchType) {
- case "title":
- params.title = singleSearch;
- break;
- case "tags":
- params.tag = singleSearchTypeValueId;
- break;
- case "organizations":
- params.organization = singleSearchTypeValueId;
- break;
- case "locations":
- params.location = singleSearchTypeValueId;
- break;
- default:
- }
+ params.title = title;
+ params.tag = tags.map(({ value }) => value);
+ params.organization = organizations.map(({ value }) => value);
+ params.location = locations.map(({ value }) => value);
setLoading(true);
@@ -89,124 +79,79 @@ function PosterSingleSearch({
});
};
- const singleSearchTypeOptions = [
- {
- key: "singleSearchTypeOptions1",
- value: "title",
- title: t("single-search-type-title"),
- },
- {
- key: "singleSearchTypeOptions2",
- value: "organizations",
- title: t("single-search-type-organization"),
- },
- {
- key: "singleSearchTypeOptions3",
- value: "locations",
- title: t("single-search-type-location"),
- },
- {
- key: "singleSearchTypeOptions4",
- value: "tags",
- title: t("single-search-type-tag"),
- },
- ];
-
- useEffect(() => {
- setSingleSearchTypeValue("");
- }, [singleSearchType]);
-
return (
-
-
-
+ >
);
}
diff --git a/src/components/slide/content/poster/poster-single.jsx b/src/components/slide/content/poster/poster-single.jsx
index 0ae89043..ca3744de 100644
--- a/src/components/slide/content/poster/poster-single.jsx
+++ b/src/components/slide/content/poster/poster-single.jsx
@@ -134,7 +134,7 @@ function PosterSingle({ configurationChange, feedSource, configuration }) {
- {t("preview-updates-after-save")}
+ {t("subscription-preview-of-events-helptext")}
diff --git a/src/components/slide/content/poster/poster-subscription-criteria.jsx b/src/components/slide/content/poster/poster-subscription-criteria.jsx
index c63e0ca0..d2da9977 100644
--- a/src/components/slide/content/poster/poster-subscription-criteria.jsx
+++ b/src/components/slide/content/poster/poster-subscription-criteria.jsx
@@ -1,7 +1,7 @@
-import AsyncSelect from "react-select/async";
-import { React, useRef } from "react";
+import { React, useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import PropTypes from "prop-types";
+import { MultiSelect } from "react-multi-select-component";
import { getHeaders, loadDropdownOptionsPromise } from "./poster-helper";
/**
@@ -21,80 +21,60 @@ function PosterSubscriptionCriteria({
subscriptionPlaceValue,
subscriptionOrganizerValue,
subscriptionTagValue,
- subscriptionNumberValue,
+ subscriptionNumberValue = 5,
},
handleSelect,
}) {
const { t } = useTranslation("common", { keyPrefix: "poster-selector-v2" });
- const locationTimeoutRef = useRef(null);
- const organizationTimeoutRef = useRef(null);
- const tagTimeoutRef = useRef(null);
-
// The user can choose between 1-10 entries to display.
const numberOptions = Array.from(Array(10).keys());
- const debounceOptions = (inputValue, type) => {
- // Debounce promise.
- return new Promise((resolve, reject) => {
- let timeoutRef = null;
+ const [locations, setLocations] = useState([]);
+ const [tags, setTags] = useState([]);
+ const [organizations, setOrganizations] = useState([]);
- switch (type) {
- case "locations":
- timeoutRef = locationTimeoutRef;
- break;
- case "organizations":
- timeoutRef = organizationTimeoutRef;
- break;
- case "tags":
- timeoutRef = tagTimeoutRef;
- break;
- default:
- return;
- }
+ useEffect(() => {
+ loadDropdownOptionsPromise(optionsEndpoint, getHeaders(), "", "tags").then(
+ (r) => setTags(r)
+ );
- if (timeoutRef.current) {
- clearTimeout(timeoutRef.current);
- }
+ loadDropdownOptionsPromise(
+ optionsEndpoint,
+ getHeaders(),
+ "",
+ "locations"
+ ).then((r) => setLocations(r));
- timeoutRef.current = setTimeout(() => {
- loadDropdownOptionsPromise(
- optionsEndpoint,
- getHeaders(),
- inputValue,
- type
- )
- .then((data) => resolve(data))
- .catch((reason) => reject(reason));
- }, 500);
- });
- };
+ loadDropdownOptionsPromise(
+ optionsEndpoint,
+ getHeaders(),
+ "",
+ "organizations"
+ ).then((r) => setOrganizations(r));
+ }, []);
return (
<>
{t("filters")}
-
@@ -107,20 +87,19 @@ function PosterSubscriptionCriteria({
>
{t("filters-organizer")}
-
- debounceOptions(inputValue, "organizations")
+
+ handleSelect("subscriptionOrganizerValue", newValue)
}
- value={subscriptionOrganizerValue}
- onChange={(newValue) => {
- handleSelect("subscriptionOrganizerValue", newValue);
- }}
+ value={subscriptionOrganizerValue ?? []}
+ placeholder={t("subscription-search-placeholder")}
+ labelledBy={t("filters-organizer")}
/>
@@ -133,18 +112,19 @@ function PosterSubscriptionCriteria({
>
{t("filters-tag")}
- debounceOptions(inputValue, "tags")}
- value={subscriptionTagValue}
- onChange={(newValue) => {
- handleSelect("subscriptionTagValue", newValue);
- }}
+
+ handleSelect("subscriptionTagValue", newValue)
+ }
+ value={subscriptionTagValue ?? []}
+ placeholder={t("subscription-search-placeholder")}
+ labelledBy={t("filters-tag")}
/>
diff --git a/src/components/slide/content/poster/poster-subscription.jsx b/src/components/slide/content/poster/poster-subscription.jsx
index 9f7161bc..d62eb93f 100644
--- a/src/components/slide/content/poster/poster-subscription.jsx
+++ b/src/components/slide/content/poster/poster-subscription.jsx
@@ -1,7 +1,7 @@
import { React, useEffect, useState } from "react";
import PropTypes from "prop-types";
import { useTranslation } from "react-i18next";
-import { Alert, Row, Spinner } from "react-bootstrap";
+import { Row, Spinner } from "react-bootstrap";
import Col from "react-bootstrap/Col";
import { formatDate, getHeaders } from "./poster-helper";
import PosterSubscriptionCriteria from "./poster-subscription-criteria";
@@ -21,15 +21,15 @@ function PosterSubscription({
}) {
const { t } = useTranslation("common", { keyPrefix: "poster-selector-v2" });
- const [subscriptionEvents, setSubscriptionEvents] = useState(null);
+ const [subscriptionOccurrences, setSubscriptionOccurrences] = useState(null);
const [loadingResults, setLoadingResults] = useState(false);
const [firstAdmin] = admin;
const optionsEndpoint = firstAdmin.endpointOption ?? null;
- const searchEndpoint = firstAdmin.endpointSearch ?? null;
+ const subscriptionEndpoint = firstAdmin.endpointSubscription ?? null;
const {
- subscriptionNumberValue = [],
+ subscriptionNumberValue = 5,
subscriptionPlaceValue = [],
subscriptionOrganizerValue = [],
subscriptionTagValue = [],
@@ -45,36 +45,35 @@ function PosterSubscription({
const subscriptionFetch = () => {
const query = new URLSearchParams({
- type: "events",
- itemsPerPage: subscriptionNumberValue,
+ numberOfItems: subscriptionNumberValue,
});
const places = subscriptionPlaceValue.map(({ value }) => value);
places.forEach((place) => {
- query.append("location", place);
+ query.append("location[]", place);
});
const organizers = subscriptionOrganizerValue.map(({ value }) => value);
organizers.forEach((organizer) => {
- query.append("organization", organizer);
+ query.append("organization[]", organizer);
});
const tags = subscriptionTagValue.map(({ value }) => value);
tags.forEach((tag) => {
- query.append("tag", tag);
+ query.append("tag[]", tag);
});
setLoadingResults(true);
- fetch(`${searchEndpoint}?${query}`, {
+ fetch(`${subscriptionEndpoint}?${query}`, {
headers: getHeaders(),
})
.then((response) => response.json())
.then((data) => {
- setSubscriptionEvents(data);
+ setSubscriptionOccurrences(data);
})
.finally(() => {
setLoadingResults(false);
@@ -94,12 +93,6 @@ function PosterSubscription({
{t("selected-type-subscription")}
{t("subscription-helptext")}
-
-
- {t("preview-updates-after-save")}
-
-
-
- {subscriptionEvents?.length > 0 &&
- subscriptionEvents?.map(
+ {subscriptionOccurrences?.length > 0 &&
+ subscriptionOccurrences?.map(
({
- entityId,
- occurrences,
- imageUrls,
+ eventId,
+ imageThumbnail,
+ image,
+ startDate,
+ endDate,
title,
organizer,
+ place,
}) => {
- const firstOccurrence =
- occurrences.length > 0 ? occurrences[0] : null;
-
return (
-
+
@@ -147,18 +140,11 @@ function PosterSubscription({
{organizer?.name}
|
+ {place?.name} |
- {firstOccurrence && firstOccurrence.place?.name}
- |
-
- {firstOccurrence && (
- <>
- {`${formatDate(
- firstOccurrence.start,
- "L"
- )} - ${formatDate(firstOccurrence.end, "L")}`}
- >
- )}
+ {formatDate(startDate, "L HH:mm")}
+ {" - "}
+ {formatDate(endDate, "L HH:mm")}
|
);
@@ -167,6 +153,10 @@ function PosterSubscription({
+
+
+ {t("subscription-preview-of-events-helptext")}
+
@@ -194,6 +184,7 @@ PosterSubscription.propTypes = {
endpointEntity: PropTypes.string,
endpointOption: PropTypes.string,
endpointSearch: PropTypes.string,
+ endpointSubscription: PropTypes.string,
})
),
}).isRequired,
diff --git a/src/translations/da/common.json b/src/translations/da/common.json
index 61b2a937..891338aa 100644
--- a/src/translations/da/common.json
+++ b/src/translations/da/common.json
@@ -1104,6 +1104,9 @@
"search-result-image": "Billede på begivenheden",
"single-search-type": "Søgekriterium",
"single-search-title": "Søgetekst",
+ "single-search-organizations": "Arrangør",
+ "single-search-locations": "Sted",
+ "single-search-tags": "Tags",
"single-search-select": "Søgetekst",
"single-search-button": "Søg",
"single-search-type-title": "Titel",
@@ -1113,7 +1116,6 @@
"single-search-type-tag": "Tag",
"single-search-placeholder": "Vælg...",
"single-search-loading": "Søger...",
- "preview-updates-after-save": "Bemærk! Forhåndsvisningen opdaterer først efter slide bliver gemt.",
"remove": "Afvælg",
"no-results": "0 begivenheder fundet",
"single-override-title": "Overskriv overskrift",
@@ -1129,6 +1131,7 @@
"poster-feed-type-single": "Enkelt",
"poster-feed-type-subscription": "Abonnement",
"select-mode": "Vælg visningstype",
+ "subscription-preview-of-events-helptext": "Bemærk! Forhåndsvisningen bliver først opdateret efter slidet er gemt.",
"subscription-helptext": "Kombiner \"sted\", \"arrangør\", \"tags\" og \"antal slides\" for at opsætte abonnementet på begivenheder.",
"filters": "Vælg filtre",
"filters-place": "Sted",