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

Feature add search tools [WIP] #1212

Draft
wants to merge 17 commits into
base: dev
Choose a base branch
from
Draft
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 server/template.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export default ({ url, bodyClass, title, description }) => marinate`
${prefetchImagesHTML}

<!-- Meta Tags -->
<meta name="apple-itunes-app" content="app-id=myAppStoreID, affiliate-data=myAffiliateData, app-argument=myURL">
<meta charset="utf-8" />
<meta name="theme-color" content="${ONLINE_COLOR}" />
<meta name="description" content="${description}" />
Expand Down
2 changes: 1 addition & 1 deletion server/utils/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export * from './get-metadata-from-request';
export * from './create-metadata-from-response';
export * from './suffix-app-name';
export * from './suffix-app-name';
51 changes: 42 additions & 9 deletions src/js/components/Autocomplete.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import React, { Component, Fragment } from "react";
import PropTypes from "prop-types";
import { Link } from 'react-router-dom';
import { Link, withRouter } from 'react-router-dom';

import Larivaar from '../components/Larivaar';
import CrossIcon from '@/components/Icons/Times';
import Larivaar from '@/components/Larivaar';
import { toSearchURL } from '@/util';
class Autocomplete extends Component {
static propTypes = {
isShowFullResults: PropTypes.bool,
onItemClick: PropTypes.func,
getSuggestions: PropTypes.func.isRequired,
searchOptions: PropTypes.object.isRequired,
value: PropTypes.string.isRequired,
Expand All @@ -23,6 +25,17 @@ class Autocomplete extends Component {
};
}

resetSearchResults = () => {
this.setState((prevState) =>
({
...prevState,
activeSuggestion: -1,
filteredSuggestions: [],
showSuggestions: false,
})
);
}

onKeyDown = e => {
const { activeSuggestion, filteredSuggestions } = this.state;
const isEnterKey = e.keyCode == 13;
Expand All @@ -33,6 +46,11 @@ class Autocomplete extends Component {
if (isEnterKey) {
if (isActiveSuggestion) e.preventDefault();

this.resetSearchResults();
this.props.history.push(filteredSuggestions[activeSuggestion].url);
this.props.onItemClick && this.props.onItemClick();

} else if (e.keyCode === 38) {
window.location = filteredSuggestions[activeSuggestion].url;

this.setState({
Expand Down Expand Up @@ -70,9 +88,16 @@ class Autocomplete extends Component {

componentDidUpdate(prevProps) {
const prevInput = prevProps.value;

if (this.props.value !== prevInput) {
const { isShowFullResults, getSuggestions, searchOptions, value: userInput } = this.props;
const { searchOptions } = this.props;
const { searchOptions: prevSearchOptions } = prevProps;
if (this.props.value !== prevInput ||
searchOptions.raag !== prevSearchOptions.raag ||
searchOptions.source !== prevSearchOptions.source ||
searchOptions.writer !== prevSearchOptions.writer ||
searchOptions.type !== prevSearchOptions.type
) {
const { getSuggestions, searchOptions } = this.props;
const userInput = this.props.value;
const isSearchTypeAng = searchOptions.type === 5;
const isQueryValid = userInput.length >= 2 && !isSearchTypeAng;
clearTimeout(this.state.suggestionTimeout);
Expand Down Expand Up @@ -132,15 +157,23 @@ class Autocomplete extends Component {
}
} = this;

console.log(this.props, 'AUTOCOMPLETE...')

let suggestionsListComponent;

if (showSuggestions && value) {
if (filteredSuggestions.length) {
suggestionsListComponent = (
<ul
className="search-result"
id="suggestions"
className="search-result"
onKeyDown={this.onKeyDown} >
<button
className="clear-autocomplete"
onClick={setQueryAs('')}
>
<CrossIcon />
</button>
{filteredSuggestions.map((suggestion, index) => {
let className = searchOptions.type !== 3 ? "gurbani-font " : " ";
const isLastIdx = index === (filteredSuggestions.length - 1);
Expand Down Expand Up @@ -182,10 +215,10 @@ class Autocomplete extends Component {
</Larivaar>
{searchOptions.type === 3 && (<p className="gurbani-font">{suggestion.pankti}</p>)}
</a>}
</li>
</li >
);
})}
</ul>
</ul >
);
} else {
suggestionsListComponent = (
Expand All @@ -204,4 +237,4 @@ class Autocomplete extends Component {
}
}

export default Autocomplete;
export default withRouter(Autocomplete);
3 changes: 2 additions & 1 deletion src/js/components/Fetch/Fetch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export default class Fetch extends React.PureComponent<
public componentDidMount() {
this.mounted = true;
const { url, options, transform, timeout } = this.props;
console.log(url, options, "this.props.componentDidMount,")

this.fetchData(url, options, transform, timeout);
}
Expand Down Expand Up @@ -75,7 +76,7 @@ export default class Fetch extends React.PureComponent<
setTimeout(reject, timeout, TEXTS.TIMEOUT_ERROR)
);


debugger;
// If timeoutPromise completes before fetch the top level catch is executed
return Promise.race([timeoutPromise, fetch(url, options)])
.then(res =>
Expand Down
17 changes: 17 additions & 0 deletions src/js/components/FilterTypes/FilterOptions.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from 'react';

export const FilterOptions = ({ list }: { list: object[] }) => {
return (
<>
{list.map((obj) => {
// There is always just 1 key,value pair
for (const [key, name] of Object.entries(obj))
return (
<option key={key} value={key}>
{name}
</option>
);
})}
</>
);
};
109 changes: 109 additions & 0 deletions src/js/components/FilterTypes/FilterTypes.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import React, { useMemo, useEffect } from 'react';
import { TYPES, SOURCES, SEARCH_TYPES, SOURCES_WITH_ANG } from '@/constants';
import { FilterOptions } from './FilterOptions';
import { useFetchFilterLists } from './hooks';

interface FilterTypesProps {
isShowFilterByRaags?: boolean;
isShowFilterByWriters?: boolean;
filterType: string;
filterSource: string;
filterRaag?: string | number;
filterWriter?: string | number;
onFilterTypeChange: (e: React.ChangeEvent) => {};
onFilterSourceChange: (e: React.ChangeEvent) => {};
onFilterRaagChange?: (e: React.ChangeEvent) => {};
onFilterWriterChange?: (e: React.ChangeEvent) => {};
}

export const FilterTypes: React.FC<FilterTypesProps> = React.memo(
({
isShowFilterByRaags = true,
isShowFilterByWriters = true,
filterType,
filterSource,
filterRaag,
filterWriter,
onFilterTypeChange,
onFilterSourceChange,
onFilterRaagChange,
onFilterWriterChange,
}) => {
const {
isFetching,
raags: filterRaagsList,
writers: filterWritersList,
} = useFetchFilterLists({ isShowFilterByRaags, isShowFilterByWriters });
const isFilterTypeAng = parseInt(filterType) === SEARCH_TYPES['ANG'];
const allFiltersAng = Object.keys(SOURCES_WITH_ANG);

// Just converting it to [{key: value}] format
const filterTypesList = useMemo(
() => TYPES.map((type, idx) => ({ [idx]: type })),
[TYPES]
);
const filterSourcesList = useMemo(
() =>
Object.entries(
isFilterTypeAng ? SOURCES_WITH_ANG : SOURCES
).map(([key, value]) => ({ [key]: value })),
[isFilterTypeAng]
);

useEffect(() => {
return () => console.log('DISMANTLE<<<<<<<<<<<<<,,');
}, []);

if (isFetching) {
return <div className="spinner"></div>;
}

return (
<>
{/* SEARCH FILTER TYPE */}
{filterTypesList && (
<select
name="type"
id="search-type"
value={filterType}
onChange={onFilterTypeChange}
>
<FilterOptions list={filterTypesList} />
</select>
)}

{/* BAANI SOURCE FILTER TYPE */}
<select
name="source"
value={
isFilterTypeAng && !allFiltersAng.includes(filterSource)
? 'G'
: filterSource
}
onChange={onFilterSourceChange}
>
<FilterOptions list={filterSourcesList} />
filterSourceList{' '}
</select>

{/*RAAG FILTER TYPE*/}
{isShowFilterByRaags && (
<select name="raag" value={filterRaag} onChange={onFilterRaagChange}>
<FilterOptions list={filterRaagsList} />
</select>
)}

{/*WRITER FILTER TYPE*/}
{isShowFilterByWriters && (
<select
name="writer"
value={filterWriter}
onChange={onFilterWriterChange}
>
<FilterOptions list={filterWritersList} />
</select>
)}
</>
);
}
);
1 change: 1 addition & 0 deletions src/js/components/FilterTypes/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './use-fetch-filter-lists';
83 changes: 83 additions & 0 deletions src/js/components/FilterTypes/hooks/use-fetch-filter-lists.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { useState, useEffect } from 'react';
import { filterListsCache } from '../utils';

export const useFetchFilterLists = ({
isShowFilterByRaags,
isShowFilterByWriters,
}: {
isShowFilterByRaags: boolean;
isShowFilterByWriters: boolean;
}) => {
const [isFetching, setIsFetching] = useState<Boolean>(false);
console.log(filterListsCache, 'filter list cache object,');

const [raags, setRaags] = useState<{ id: string }[]>(filterListsCache.raags);
const [writers, setWriters] = useState<{ id: string }[]>(
filterListsCache.writers
);

useEffect(() => {
const fetchListAsync = async (apiUrl: string, type?: string) => {
const response = await fetch(apiUrl);
if (response.status !== 200) {
throw new Error('There was some error fetching data');
}

if (type === 'raag') {
const raags = await response.json();
const filterRaags = raags.rows.map(
({ RaagID: id, RaagEnglish: en }) => {
const filterRaag = {
[id]: id === 0 ? 'All Raags' : en,
};
return filterRaag;
}
);
// cache the results for raags.
filterListsCache.raags = filterRaags;
setRaags(filterRaags);
return;
}

const writers = await response.json();
console.log(writers, 'writers ........');
const filterWriters = writers.rows.map(
({ WriterID: id, WriterEnglish: en }) => {
const filterWriter = {
[id]: id === 0 ? 'All Writers' : en,
};
return filterWriter;
}
);

// cache the results for writers.
filterListsCache.writers = filterWriters;
setWriters(filterWriters);
};

(async () => {
setIsFetching(true);

if (isShowFilterByRaags) {
// If we don't have raags in cache, then fetch it.
if (!filterListsCache.raags.length) {
await fetchListAsync(`${API_URL}/raags`, 'raag');
}
}
if (isShowFilterByWriters) {
// If we don't have writers in cache, then fetch it.
if (!filterListsCache.writers.length) {
await fetchListAsync(`${API_URL}/writers`);
}
}

setIsFetching(false);
})();
}, []);

return {
isFetching,
raags,
writers,
};
};
1 change: 1 addition & 0 deletions src/js/components/FilterTypes/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './FilterTypes';
9 changes: 9 additions & 0 deletions src/js/components/FilterTypes/utils/filter-lists-cache.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
interface IFilterListsCache {
raags: { id: string }[];
writers: { id: string }[];
}

export default {
raags: [],
writers: [],
} as IFilterListsCache;
1 change: 1 addition & 0 deletions src/js/components/FilterTypes/utils/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as filterListsCache } from './filter-lists-cache';
Loading