2021-05-18 14:20:15 +00:00
|
|
|
import { SetCollections, SetFiles } from 'pages/gallery';
|
2021-05-20 09:04:48 +00:00
|
|
|
import React, { useEffect, useState, useRef } from 'react';
|
2021-05-18 04:32:37 +00:00
|
|
|
import styled from 'styled-components';
|
2021-05-21 09:46:56 +00:00
|
|
|
import AsyncSelect from 'react-select/async';
|
2021-05-20 08:00:02 +00:00
|
|
|
import { File, getLocalFiles } from 'services/fileService';
|
|
|
|
import {
|
|
|
|
Collection,
|
|
|
|
getLocalCollections,
|
|
|
|
getNonEmptyCollections,
|
|
|
|
} from 'services/collectionService';
|
2021-05-21 09:46:56 +00:00
|
|
|
import { Bbox, parseHumanDate, searchLocation } from 'services/searchService';
|
2021-05-20 08:19:37 +00:00
|
|
|
import { getFilesWithCreationDay, getFilesInsideBbox } from 'utils/search';
|
2021-05-21 09:46:56 +00:00
|
|
|
import constants from 'utils/strings/constants';
|
|
|
|
import { formatDate } from 'utils/common';
|
2021-05-18 04:32:37 +00:00
|
|
|
|
|
|
|
const Wrapper = styled.div<{ open: boolean }>`
|
|
|
|
background-color: #111;
|
|
|
|
color: #fff;
|
|
|
|
min-height: 64px;
|
|
|
|
align-items: center;
|
|
|
|
box-shadow: 0 0 5px rgba(0, 0, 0, 0.7);
|
|
|
|
margin-bottom: 10px;
|
|
|
|
position: fixed;
|
|
|
|
top: 0;
|
|
|
|
width: 100%;
|
2021-05-18 07:47:03 +00:00
|
|
|
display: flex;
|
|
|
|
align-items: center;
|
|
|
|
justify-content: center;
|
2021-05-18 06:52:11 +00:00
|
|
|
z-index: 200;
|
2021-05-18 07:47:03 +00:00
|
|
|
padding: 0 20%;
|
|
|
|
display: ${(props) => (props.open ? 'flex' : 'none')};
|
2021-05-18 04:32:37 +00:00
|
|
|
`;
|
|
|
|
|
2021-05-21 09:46:56 +00:00
|
|
|
enum SearchType {
|
|
|
|
DATE,
|
|
|
|
LOCATION,
|
|
|
|
}
|
|
|
|
interface SearchParams {
|
|
|
|
type: SearchType;
|
|
|
|
label: string;
|
|
|
|
value: Bbox | Date;
|
2021-05-18 07:47:03 +00:00
|
|
|
}
|
|
|
|
interface Props {
|
2021-05-18 14:20:15 +00:00
|
|
|
isOpen: boolean;
|
2021-05-18 07:47:03 +00:00
|
|
|
setOpen: (value) => void;
|
2021-05-18 14:20:15 +00:00
|
|
|
loadingBar: any;
|
|
|
|
setFiles: SetFiles;
|
|
|
|
setCollections: SetCollections;
|
2021-05-18 07:47:03 +00:00
|
|
|
}
|
|
|
|
export default function SearchBar(props: Props) {
|
2021-05-20 08:00:02 +00:00
|
|
|
const [allFiles, setAllFiles] = useState<File[]>([]);
|
|
|
|
const [allCollections, setAllCollections] = useState<Collection[]>([]);
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
const main = async () => {
|
|
|
|
setAllFiles(await getLocalFiles());
|
|
|
|
setAllCollections(await getLocalCollections());
|
|
|
|
};
|
|
|
|
main();
|
|
|
|
}, []);
|
2021-05-18 14:20:15 +00:00
|
|
|
|
2021-05-20 09:04:48 +00:00
|
|
|
const searchBarRef = useRef(null);
|
|
|
|
useEffect(() => {
|
|
|
|
if (props.isOpen) {
|
|
|
|
setTimeout(() => {
|
|
|
|
searchBarRef.current?.focus();
|
|
|
|
}, 200);
|
|
|
|
}
|
|
|
|
}, [props.isOpen]);
|
|
|
|
|
2021-05-21 09:46:56 +00:00
|
|
|
const getOptions = (inputValue) => {
|
|
|
|
return getAutoCompleteSuggestion(inputValue);
|
|
|
|
};
|
|
|
|
const getAutoCompleteSuggestion = async (searchPhrase: string) => {
|
|
|
|
const searchedDate = parseHumanDate(searchPhrase);
|
|
|
|
let option = new Array<SearchParams>();
|
|
|
|
if (searchedDate != null) {
|
|
|
|
option.push({
|
|
|
|
type: SearchType.DATE,
|
|
|
|
value: searchedDate,
|
|
|
|
label: formatDate(searchedDate),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
const searchResults = await searchLocation(searchPhrase);
|
|
|
|
option.push(
|
|
|
|
...searchResults.map(
|
|
|
|
(searchResult) =>
|
|
|
|
({
|
|
|
|
type: SearchType.LOCATION,
|
|
|
|
value: searchResult.bbox,
|
|
|
|
label: searchResult.placeName,
|
|
|
|
} as SearchParams)
|
|
|
|
)
|
|
|
|
);
|
|
|
|
return option;
|
|
|
|
};
|
2021-05-20 08:19:37 +00:00
|
|
|
|
2021-05-21 09:46:56 +00:00
|
|
|
const filterFiles = (selectedOption: SearchParams) => {
|
|
|
|
if (!selectedOption) {
|
|
|
|
return;
|
|
|
|
}
|
2021-05-20 08:00:02 +00:00
|
|
|
let resultFiles: File[] = [];
|
2021-05-20 08:19:37 +00:00
|
|
|
|
2021-05-21 09:46:56 +00:00
|
|
|
switch (selectedOption.type) {
|
|
|
|
case SearchType.DATE:
|
|
|
|
const searchedDate = selectedOption.value as Date;
|
|
|
|
const filesWithSameDate = getFilesWithCreationDay(
|
|
|
|
allFiles,
|
|
|
|
searchedDate
|
|
|
|
);
|
|
|
|
console.log(filesWithSameDate);
|
|
|
|
resultFiles = filesWithSameDate;
|
|
|
|
case SearchType.LOCATION:
|
|
|
|
const bbox = selectedOption.value as Bbox;
|
|
|
|
|
2021-05-20 08:19:37 +00:00
|
|
|
const filesTakenAtLocation = getFilesInsideBbox(allFiles, bbox);
|
2021-05-21 09:46:56 +00:00
|
|
|
resultFiles = filesTakenAtLocation;
|
2021-05-20 08:00:02 +00:00
|
|
|
}
|
2021-05-20 08:19:37 +00:00
|
|
|
|
2021-05-20 08:00:02 +00:00
|
|
|
props.setFiles(resultFiles);
|
|
|
|
props.setCollections(
|
|
|
|
getNonEmptyCollections(allCollections, resultFiles)
|
|
|
|
);
|
2021-05-18 14:20:15 +00:00
|
|
|
};
|
2021-05-20 08:00:02 +00:00
|
|
|
const closeSearchBar = ({ resetForm }) => {
|
2021-05-18 14:20:15 +00:00
|
|
|
props.setOpen(false);
|
2021-05-20 08:00:02 +00:00
|
|
|
props.setFiles(allFiles);
|
|
|
|
props.setCollections(allCollections);
|
2021-05-18 14:20:15 +00:00
|
|
|
resetForm();
|
|
|
|
};
|
2021-05-21 09:46:56 +00:00
|
|
|
|
|
|
|
const customStyles = {
|
|
|
|
control: (provided, { isFocused }) => ({
|
|
|
|
...provided,
|
|
|
|
backgroundColor: '#282828',
|
|
|
|
color: '#d1d1d1',
|
|
|
|
borderColor: isFocused && '#2dc262',
|
|
|
|
boxShadow: isFocused && '0 0 3px #2dc262',
|
|
|
|
':hover': {
|
|
|
|
borderColor: '#2dc262',
|
|
|
|
},
|
|
|
|
}),
|
|
|
|
input: (provided) => ({
|
|
|
|
...provided,
|
|
|
|
color: '#d1d1d1',
|
|
|
|
}),
|
|
|
|
menu: (provided) => ({
|
|
|
|
...provided,
|
|
|
|
backgroundColor: '#282828',
|
|
|
|
}),
|
|
|
|
option: (provided, { isFocused }) => ({
|
|
|
|
...provided,
|
|
|
|
backgroundColor: isFocused && '#343434',
|
|
|
|
}),
|
|
|
|
dropdownIndicator: (provided) => ({
|
|
|
|
...provided,
|
|
|
|
display: 'none',
|
|
|
|
}),
|
|
|
|
indicatorSeparator: (provided) => ({
|
|
|
|
...provided,
|
|
|
|
display: 'none',
|
|
|
|
}),
|
|
|
|
clearIndicator: (provided) => ({
|
|
|
|
...provided,
|
|
|
|
':hover': { color: '#d2d2d2' },
|
|
|
|
}),
|
|
|
|
singleValue: (provided, state) => ({
|
|
|
|
...provided,
|
|
|
|
backgroundColor: '#282828',
|
|
|
|
color: '#d1d1d1',
|
|
|
|
}),
|
|
|
|
};
|
2021-05-18 07:47:03 +00:00
|
|
|
return (
|
2021-05-18 14:20:15 +00:00
|
|
|
<Wrapper open={props.isOpen}>
|
2021-05-21 09:46:56 +00:00
|
|
|
<>
|
|
|
|
<div
|
|
|
|
style={{
|
|
|
|
flex: 1,
|
|
|
|
maxWidth: '600px',
|
|
|
|
margin: '10px',
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
<AsyncSelect
|
|
|
|
cacheOptions
|
|
|
|
ref={searchBarRef}
|
|
|
|
placeholder={constants.SEARCH_HINT}
|
|
|
|
loadOptions={getOptions}
|
|
|
|
onChange={filterFiles}
|
|
|
|
isClearable
|
|
|
|
styles={customStyles}
|
|
|
|
noOptionsMessage={() => null}
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
style={{
|
|
|
|
margin: '0',
|
|
|
|
display: 'flex',
|
|
|
|
alignItems: 'center',
|
|
|
|
cursor: 'pointer',
|
|
|
|
}}
|
|
|
|
onClick={() => closeSearchBar({ resetForm: () => null })}
|
|
|
|
>
|
|
|
|
<svg
|
|
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
|
|
height={25}
|
|
|
|
viewBox={`0 0 25 25`}
|
|
|
|
width={25}
|
|
|
|
>
|
|
|
|
<path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41z"></path>
|
|
|
|
</svg>
|
|
|
|
</div>
|
|
|
|
</>
|
2021-05-18 07:47:03 +00:00
|
|
|
</Wrapper>
|
|
|
|
);
|
2021-05-18 04:32:37 +00:00
|
|
|
}
|