diff --git a/src/api/community-api/search.ts b/src/api/community-api/search.ts index c2117309c..c834df8fc 100644 --- a/src/api/community-api/search.ts +++ b/src/api/community-api/search.ts @@ -44,6 +44,20 @@ export const extractTopicsFromSearch = ( return uniqueTopics; }; +export const searchCommunityRequests = (queryTerm: string) => { + if (queryTerm.length > 0) { + return axios + .get( + `${FDK_COMMUNITY_BASE_URI}/api/search?term=${queryTerm}&in=titles&matchWords=all&category=6` + ) + .then(({ data }) => data); + } else { + return axios + .get(`${FDK_COMMUNITY_BASE_URI}/api/search?&category=6`) + .then(({ data }) => data); + } +}; + export const pruneNodebbTemplateTags = (raw_text: string) => raw_text.replace( /(?:\|\s)(?:\[{2})(.*?)(?:\]{2}:)(.*?)(?:\s\|)/g, diff --git a/src/components/with-community/redux/action-types.ts b/src/components/with-community/redux/action-types.ts index f711add72..0799e8aec 100644 --- a/src/components/with-community/redux/action-types.ts +++ b/src/components/with-community/redux/action-types.ts @@ -12,3 +12,7 @@ export const RESET_POSTS = 'RESET_POSTS' as const; export const GET_REQUESTS = 'GET_REQUESTS' as const; export const GET_REQUESTS_SUCCEEDED = 'GET_REQUESTS_SUCCEEDED' as const; export const GET_REQUESTS_FAILED = 'GET_REQUESTS_FAILED' as const; + +export const SEARCH_REQUESTS_REQUESTED = 'SEARCH_REQUESTS_REQUESTED' as const; +export const SEARCH_REQUESTS_SUCCEEDED = 'SEARCH_REQUESTS_SUCCEEDED' as const; +export const SEARCH_REQUESTS_FAILED = 'SEARCH_REQUESTS_FAILED' as const; diff --git a/src/components/with-community/redux/actions.ts b/src/components/with-community/redux/actions.ts index f3af3ae1b..ebdad19e4 100644 --- a/src/components/with-community/redux/actions.ts +++ b/src/components/with-community/redux/actions.ts @@ -9,7 +9,10 @@ import { RESET_POSTS, GET_REQUESTS, GET_REQUESTS_FAILED, - GET_REQUESTS_SUCCEEDED + GET_REQUESTS_SUCCEEDED, + SEARCH_REQUESTS_REQUESTED, + SEARCH_REQUESTS_SUCCEEDED, + SEARCH_REQUESTS_FAILED } from './action-types'; import type { @@ -50,6 +53,37 @@ export function searchTopicsFailed(message: string) { }; } +export function searchRequestsRequested(queryTerm: string) { + return { + type: SEARCH_REQUESTS_REQUESTED, + payload: { + queryTerm + } + }; +} + +export function searchRequestsSucceeded( + topics: CommunityTopic[], + multiplePages: boolean +) { + return { + type: SEARCH_REQUESTS_SUCCEEDED, + payload: { + topics, + multiplePages + } + }; +} + +export function searchRequestsFailed(message: string) { + return { + type: SEARCH_REQUESTS_FAILED, + payload: { + message + } + }; +} + export function getRecentPostsRequested(term: CommunityTerm) { return { type: GET_RECENT_POSTS_REQUESTED, diff --git a/src/components/with-community/redux/reducer.ts b/src/components/with-community/redux/reducer.ts index 1d6e29a62..9a6a5ff0e 100644 --- a/src/components/with-community/redux/reducer.ts +++ b/src/components/with-community/redux/reducer.ts @@ -11,7 +11,10 @@ import { RESET_TOPICS, RESET_POSTS, GET_REQUESTS, - GET_REQUESTS_SUCCEEDED + GET_REQUESTS_SUCCEEDED, + SEARCH_REQUESTS_REQUESTED, + SEARCH_REQUESTS_SUCCEEDED, + SEARCH_REQUESTS_FAILED } from './action-types'; import type { Actions } from '../../../types'; @@ -34,11 +37,11 @@ export default function reducer( return state .set('topics', fromJS(action.payload.topics)) .set('multiplePages', fromJS(action.payload.multiplePages)); + case SEARCH_TOPICS_FAILED: case GET_RECENT_POSTS_REQUESTED: return state.set('posts', fromJS([])); case GET_RECENT_POSTS_SUCCEEDED: return state.set('posts', fromJS(action.payload.posts)); - case SEARCH_TOPICS_FAILED: case RESET_TOPICS: return state.set('topics', fromJS([])); case GET_RECENT_POSTS_FAILED: @@ -48,6 +51,13 @@ export default function reducer( return state.set('requests', fromJS([])); case GET_REQUESTS_SUCCEEDED: return state.set('requests', fromJS(action.payload.requests)); + case SEARCH_REQUESTS_REQUESTED: + return state.set('topics', fromJS([])); + case SEARCH_REQUESTS_SUCCEEDED: + return state + .set('topics', fromJS(action.payload.topics)) + .set('multiplePages', fromJS(action.payload.multiplePages)); + case SEARCH_REQUESTS_FAILED: default: return state; } diff --git a/src/components/with-community/redux/saga.ts b/src/components/with-community/redux/saga.ts index 0c6e19db3..e9f69c929 100644 --- a/src/components/with-community/redux/saga.ts +++ b/src/components/with-community/redux/saga.ts @@ -3,7 +3,8 @@ import { all, call, put, takeLatest } from 'redux-saga/effects'; import { SEARCH_TOPICS_REQUESTED, GET_RECENT_POSTS_REQUESTED, - GET_REQUESTS + GET_REQUESTS, + SEARCH_REQUESTS_REQUESTED } from './action-types'; import * as actions from './actions'; @@ -13,6 +14,7 @@ import { getTopicById, pruneNodebbTemplateTags, searchCommunity, + searchCommunityRequests, getRequests } from '../../../api/community-api/search'; @@ -46,6 +48,33 @@ function* searchTopicsRequested({ } } +function* searchRequestsRequested({ + payload: { queryTerm } +}: ReturnType) { + try { + const postHits: CommunityPost = yield call( + searchCommunityRequests, + queryTerm + ); + const { multiplePages } = postHits; + const topics: CommunityTopic[] = ( + (yield all( + extractTopicsFromSearch(postHits).map(({ tid }) => + call(getTopicById, tid) + ) + )) as CommunityTopic[] + ).filter(Boolean); + + if (topics.length > 0) { + yield put(actions.searchTopicsSucceeded(topics, multiplePages)); + } else { + yield put(actions.searchTopicsFailed('')); + } + } catch (e: any) { + yield put(actions.searchTopicsFailed(e.message)); + } +} + function* recentPostsRequested({ payload: { term } }: ReturnType) { @@ -84,6 +113,7 @@ export default function* saga() { yield all([ takeLatest(SEARCH_TOPICS_REQUESTED, searchTopicsRequested), takeLatest(GET_RECENT_POSTS_REQUESTED, recentPostsRequested), - takeLatest(GET_REQUESTS, getCommunityRequests) + takeLatest(GET_REQUESTS, getCommunityRequests), + takeLatest(SEARCH_REQUESTS_REQUESTED, searchRequestsRequested) ]); } diff --git a/src/pages/requests/index.tsx b/src/pages/requests/index.tsx index dcf2049ea..867a052ac 100644 --- a/src/pages/requests/index.tsx +++ b/src/pages/requests/index.tsx @@ -1,4 +1,4 @@ -import React, { FC, useEffect } from 'react'; +import React, { FC, useEffect, useState } from 'react'; import { compose } from 'redux'; import Link from '@fellesdatakatalog/link'; import withCommunity, { @@ -11,25 +11,33 @@ import { formatDate } from '../../lib/date-utils'; import Banner from '../../components/banner'; import localization from '../../lib/localization'; import env from '../../env'; +import Button from '@fellesdatakatalog/button'; const { FDK_COMMUNITY_BASE_URI } = env; interface Props extends CommunityProps {} const RequestsPage: FC = ({ - requests, - communityActions: { getCommunityRequests } + topics, + communityActions: { searchRequestsRequested } }) => { useEffect(() => { - getCommunityRequests(); + searchRequestsRequested(''); }, []); - const notDeletedRequests = requests?.topics?.filter( - topic => topic.deleted === 0 - ); + const notDeletedRequests = topics?.filter(topic => topic.deleted === 0); + const [search, setSearch] = useState(''); return (
+ + setSearch(event.target.value)} + > + + +

{localization.formatString(localization.requestsPage.ingress, { diff --git a/src/pages/requests/styled.ts b/src/pages/requests/styled.ts index bbb042efc..c562c34f2 100755 --- a/src/pages/requests/styled.ts +++ b/src/pages/requests/styled.ts @@ -50,11 +50,16 @@ const InfoText = styled.div` margin-bottom: 50px; `; +const Row = styled.div` + display: flex; +`; + export default { RequestRow, RequestsTitleRow, RequestTitle, RequestInfo, RequestLink, - InfoText + InfoText, + Row };