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

feat: add search field #1798

Merged
merged 3 commits into from
Oct 23, 2023
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
2 changes: 1 addition & 1 deletion src/api/community-api/search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export const searchCommunityRequests = (
)
.then(({ data }) => data);

export const getAllRequests = () =>
export const getRequestCategory = () =>
axios
.get(`${FDK_COMMUNITY_BASE_URI}/api/category/6`)
.then(({ data }) => data);
Expand Down
7 changes: 6 additions & 1 deletion src/app/breadcrumbs/breadcrumbs.component.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ import {
PATHNAME_ABOUT_DATA_SERVICES,
PATHNAME_ABOUT_CONCEPTS,
PATHNAME_ABOUT_INFORMATIONMODELS,
PATHNAME_AI
PATHNAME_AI,
PATHNAME_REQUESTS
} from '../../constants/constants';
import DatasetBreadcrumb from './dataset-breadcrumb';
import DataServiceBreadcrumb from './data-service-breadcrumb';
Expand Down Expand Up @@ -135,6 +136,10 @@ const routes = [
{
path: PATHNAME_AI,
breadcrumb: () => <PathNameBreadcrumb pathName='ai' />
},
{
path: PATHNAME_REQUESTS,
breadcrumb: () => <PathNameBreadcrumb pathName='requests' />
}
];

Expand Down
5 changes: 5 additions & 0 deletions src/components/search-field/MagnifyingGlass.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
64 changes: 64 additions & 0 deletions src/components/search-field/search-field.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import React, { FC, ChangeEvent, useState, KeyboardEvent } from 'react';
import { Input, SearchField as StyledSearchField, SvgWrapper } from './styled';
import MagnifyingGlassSVG from './MagnifyingGlass.svg';

type IconPosType = 'left' | 'right';

interface SearchFieldProps {
ariaLabel: string;
placeholder?: string;
error?: boolean;
startIcon?: JSX.Element;
endIcon?: JSX.Element;
onSearchSubmit?: (inputValue: string) => void | any;
iconPos?: IconPosType;
}

const SearchField: FC<SearchFieldProps> = ({
ariaLabel,
startIcon,
endIcon = <MagnifyingGlassSVG />,
placeholder = 'Input placeholder ...',
error = false,
onSearchSubmit
}) => {
const [inputValue, setInputValue] = useState('');
const conditionalPlaceholder = error ? 'Invalid input' : placeholder;

const onInput = (changeEvent: ChangeEvent<HTMLInputElement>) => {
setInputValue(changeEvent.target.value);

if (onSearchSubmit && changeEvent.target.value === '') {
onSearchSubmit('');
}
};

const onSubmit = (event: KeyboardEvent<HTMLInputElement> | 'clicked') => {
if (onSearchSubmit) {
if (event === 'clicked' || event?.key === 'Enter') {
onSearchSubmit(inputValue);
}
}
};

return (
<StyledSearchField
ariaLabel={ariaLabel}
error={error}
iconPos={startIcon ? 'left' : 'right'}
>
{startIcon}
<Input
aria-label={ariaLabel}
placeholder={conditionalPlaceholder}
type='search'
value={inputValue}
onInput={onInput}
onKeyUp={onSubmit}
/>
<SvgWrapper onClick={() => onSubmit('clicked')}>{endIcon}</SvgWrapper>
</StyledSearchField>
);
};

export { SearchField, type SearchFieldProps };
73 changes: 73 additions & 0 deletions src/components/search-field/styled.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import styled, { css } from 'styled-components';
import { SearchFieldProps } from './search-field';

const SearchField = styled.div<SearchFieldProps>`
min-width: 10rem;
max-width: 30rem;
height: 3.6rem;
background-color: #ffffff;
display: flex;
align-items: center;
box-sizing: border-box;
border: solid 1px #d5d7d9;
border-radius: 4px;
align-self: flex-end;

:hover {
outline: 0.07rem solid #121619;
}

svg {
${({ iconPos }) =>
iconPos && iconPos === 'right'
? css`
margin-right: 1.2rem;
`
: css`
margin-left: 1.2rem;
`}
}

${({ error }) =>
error &&
css`
input {
color: #803353;
}
input::placeholder {
color: #803353;
}
border-color: #803353;
background-color: #f7f0f3;
:hover {
border-color: #803353;
}
`}

@media (max-width: 900px) {
align-self: center;
}
`;

const Input = styled.input`
margin: 0 1.6rem 0 1.6rem;
width: 100%;
font-size: 1.6rem;
background: none;
border: 0;

:focus-visible {
outline: none;
border: 0;
}
`;

const SvgWrapper = styled.figure`
display: contents;

:hover {
cursor: pointer;
}
`;

export { Input, SearchField, SvgWrapper };
11 changes: 9 additions & 2 deletions src/components/with-community/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ import { connect } from 'react-redux';

import * as actions from './redux/actions';

import type { CommunityPost, CommunityTopic, Pagination } from '../../types';
import type {
CommunityCategory,
CommunityPost,
CommunityTopic,
Pagination
} from '../../types';

export interface Props {
topics: CommunityTopic[];
Expand All @@ -13,6 +18,7 @@ export interface Props {
communityActions: typeof actions;
requests: CommunityTopic[];
pagination: Pagination;
requestCategory: CommunityCategory;
}

const withCommunity = (Component: ComponentType<any>) => {
Expand All @@ -23,7 +29,8 @@ const withCommunity = (Component: ComponentType<any>) => {
multiplePages: state.CommunityReducer.get('multiplePages'),
posts: state.CommunityReducer.get('posts').toJS(),
requests: state.CommunityReducer.get('requests').toJS(),
pagination: state.CommunityReducer.get('pagination').toJS()
pagination: state.CommunityReducer.get('pagination').toJS(),
requestCategory: state.CommunityReducer.get('requestCategory').toJS()
});

const mapDispatchToProps = (dispatch: Dispatch) => ({
Expand Down
7 changes: 7 additions & 0 deletions src/components/with-community/redux/action-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,10 @@ export const RESET_POSTS = 'RESET_POSTS' 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;

export const GET_REQUEST_CATEGORY_REQUESTED =
'GET_REQUEST_CATEGORY_REQUESTED' as const;
export const GET_REQUEST_CATEGORY_SUCCEEDED =
'GET_REQUEST_CATEGORY_SUCCEEDED' as const;
export const GET_REQUEST_CATEGORY_FAILED =
'GET_REQUEST_CATEGORY_FAILED' as const;
38 changes: 36 additions & 2 deletions src/components/with-community/redux/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,18 @@ import {
RESET_POSTS,
SEARCH_REQUESTS_REQUESTED,
SEARCH_REQUESTS_SUCCEEDED,
SEARCH_REQUESTS_FAILED
SEARCH_REQUESTS_FAILED,
GET_REQUEST_CATEGORY_REQUESTED,
GET_REQUEST_CATEGORY_SUCCEEDED,
GET_REQUEST_CATEGORY_FAILED
} from './action-types';

import type { CommunityPost, CommunityTopic, Pagination } from '../../../types';
import type {
CommunityCategory,
CommunityPost,
CommunityTopic,
Pagination
} from '../../../types';
import { CommunityTerm } from '../../../types/enums';

export function searchTopicsRequested(queryTerm: string) {
Expand Down Expand Up @@ -121,3 +129,29 @@ export function resetPosts() {
type: RESET_POSTS
};
}

export function getRequestCategoryRequested() {
return {
type: GET_REQUEST_CATEGORY_REQUESTED
};
}

export function getRequestCategorySucceeded(
requestCategory: CommunityCategory
) {
return {
type: GET_REQUEST_CATEGORY_SUCCEEDED,
payload: {
requestCategory
}
};
}

export function getRequestCategoryFailed(message: string) {
return {
type: GET_REQUEST_CATEGORY_FAILED,
payload: {
message
}
};
}
19 changes: 16 additions & 3 deletions src/components/with-community/redux/reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ import {
RESET_POSTS,
SEARCH_REQUESTS_REQUESTED,
SEARCH_REQUESTS_SUCCEEDED,
SEARCH_REQUESTS_FAILED
SEARCH_REQUESTS_FAILED,
GET_REQUEST_CATEGORY_REQUESTED,
GET_REQUEST_CATEGORY_SUCCEEDED,
GET_REQUEST_CATEGORY_FAILED
} from './action-types';

import type { Actions } from '../../../types';
Expand All @@ -22,7 +25,8 @@ const initialState = fromJS({
multiplePages: false,
posts: [],
requests: [],
pagination: {}
pagination: {},
requestCategory: {}
});

export default function reducer(
Expand All @@ -47,12 +51,21 @@ export default function reducer(
case RESET_POSTS:
return state.set('posts', fromJS([]));
case SEARCH_REQUESTS_REQUESTED:
return state.set('topics', fromJS([]));
return state.set('requests', fromJS([]));
case SEARCH_REQUESTS_SUCCEEDED:
return state
.set('requests', fromJS(action.payload.requests))
.set('pagination', fromJS(action.payload.pagination));
case SEARCH_REQUESTS_FAILED:
case GET_REQUEST_CATEGORY_REQUESTED:
return state.set('requestCategory', fromJS([]));
case GET_REQUEST_CATEGORY_SUCCEEDED:
return state.set(
'requestCategory',
fromJS(action.payload.requestCategory)
);
case GET_REQUEST_CATEGORY_FAILED:

default:
return state;
}
Expand Down
24 changes: 20 additions & 4 deletions src/components/with-community/redux/saga.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ import { all, call, put, takeLatest } from 'redux-saga/effects';
import {
SEARCH_TOPICS_REQUESTED,
GET_RECENT_POSTS_REQUESTED,
SEARCH_REQUESTS_REQUESTED
SEARCH_REQUESTS_REQUESTED,
GET_REQUEST_CATEGORY_REQUESTED
} from './action-types';
import * as actions from './actions';

import {
extractTopicsFromSearch,
getAllRequests,
getRecentPosts,
getRequestCategory,
getTopicById,
pruneNodebbTemplateTags,
searchCommunity,
Expand Down Expand Up @@ -47,6 +48,20 @@ function* searchTopicsRequested({
}
}

function* getRequestCategoryRequested() {
try {
const requestCategory: CommunityCategory = yield call(getRequestCategory);

if (requestCategory !== null && requestCategory !== undefined) {
yield put(actions.getRequestCategorySucceeded(requestCategory));
} else {
yield put(actions.getRequestCategoryFailed(''));
}
} catch (e: any) {
yield put(actions.getRequestCategoryFailed(e.message));
}
}

function* searchRequestsRequested({
payload: { queryTerm, sortOption, page }
}: ReturnType<typeof actions.searchRequestsRequested>) {
Expand All @@ -59,7 +74,7 @@ function* searchRequestsRequested({
);
const { pagination } = postHits;

const allRequestTopics: CommunityCategory = yield call(getAllRequests);
const allRequestTopics: CommunityCategory = yield call(getRequestCategory);
const { topics } = allRequestTopics;

const requests: CommunityTopic[] = (
Expand Down Expand Up @@ -106,6 +121,7 @@ export default function* saga() {
yield all([
takeLatest(SEARCH_TOPICS_REQUESTED, searchTopicsRequested),
takeLatest(GET_RECENT_POSTS_REQUESTED, recentPostsRequested),
takeLatest(SEARCH_REQUESTS_REQUESTED, searchRequestsRequested)
takeLatest(SEARCH_REQUESTS_REQUESTED, searchRequestsRequested),
takeLatest(GET_REQUEST_CATEGORY_REQUESTED, getRequestCategoryRequested)
]);
}
Loading