Skip to content

Commit

Permalink
Feature/menu searchable (#110)
Browse files Browse the repository at this point in the history
* feat: create component modal for multiple uses

* feat: create component modal for multiple uses

* feat: #96 create menu for search

* feat: #96 create menu for search

* feat: merge

* feat: open tab on list interraction and start global search

* feat: open tab on list interraction and start global search

Co-authored-by: André Gava <andre.gava_dextra@totalexpress.com.br>
  • Loading branch information
AndreLZGava and André Gava authored Dec 6, 2021
1 parent 24e25aa commit d0020f2
Show file tree
Hide file tree
Showing 6 changed files with 185 additions and 87 deletions.
35 changes: 21 additions & 14 deletions src/app/components/SearchMenu/MenuItem/index.tsx
Original file line number Diff line number Diff line change
@@ -1,43 +1,50 @@
import React from 'react';
import { FiPlus } from 'react-icons/fi';
import { SearchSource } from '..';
import { SearchSource } from '../../../util/DefaultEntities';
import RoundedButton from '../../RoundedButton';

interface MenuItemProps {
keyPress(e: React.KeyboardEvent): void;
selectedItem: number;
order: number;
item: SearchSource;
index: number;
}

const MenuItem: React.FC<MenuItemProps> = ({
selectedItem,
keyPress,
order,
item,
index,
}) => {
return (
<>
<li>
<li
className={
index ===
(selectedItem % 2 ? (selectedItem - 1) / 2 : selectedItem / 2 - 1)
? 'li-selected'
: ''
}
>
<span
tabIndex={order - 1}
className={selectedItem === order - 1 ? 'selected' : ''}
onClick={(e: React.MouseEvent) => item.handler.onClick(e)}
onKeyDown={keyPress}
>
{<item.icon size={20} />}
{<item.icon size={20} style={{ color: item.iconColor }} />}
{item.label}
</span>
<RoundedButton
className={
selectedItem === order ? 'secondary selected' : 'secondary'
}
onClick={(e: React.MouseEvent) => item.action.onClick(e)}
onKeyDown={keyPress}
tabIndex={order}
icon={item.iconAction}
color="secondary"
/>
{item.iconAction && (
<RoundedButton
className={selectedItem === order ? 'primary selected' : 'primary'}
onClick={(e: React.MouseEvent) => item.action.onClick(e)}
onKeyDown={keyPress}
tabIndex={order}
icon={item.iconAction}
/>
)}
</li>
</>
);
Expand Down
96 changes: 31 additions & 65 deletions src/app/components/SearchMenu/index.tsx
Original file line number Diff line number Diff line change
@@ -1,87 +1,42 @@
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { IconBaseProps } from 'react-icons';
import { FaHandshake } from 'react-icons/fa';
import { FiBook, FiPlus, FiSearch, FiUser } from 'react-icons/fi';
import { SearchSource, entities } from '../../util/DefaultEntities';
import i18n from '../../i18n';
import Input from '../Input/index';
import Modal from '../Modal';
import MenuItem from './MenuItem';
import { FiSearch } from 'react-icons/fi';
import { on, off } from '../../util/EventHandler';

interface SearchMenuProps {
setOpen(): void;
isOpen: boolean;
}

export interface SearchSource {
label: string;
icon?: React.ComponentType<IconBaseProps>;
iconAction: React.ComponentType<IconBaseProps>;
handler: {
onClick(e: React.MouseEvent): void;
onPress(e: React.KeyboardEvent, item?: SearchSource): void;
};
action: {
onClick(e: React.MouseEvent): void;
onPress(e: React.KeyboardEvent, item?: SearchSource): void;
};
}

const SearchMenu: React.FC<SearchMenuProps> = ({ isOpen, setOpen }) => {
const [selectedItem, setSelectedItem] = useState(-1);
const [maxItems, setMaxItems] = useState(6);
const [searchResult, setSearchResult] = useState<SearchSource[]>([]);
const [inputSearch, setInputSearch] = useState('');

const searchSourceMemo: SearchSource[] = useMemo(() => {
return [
{
label: i18n.t('borrow.label'),
icon: FaHandshake,
iconAction: FiPlus,
handler: {
onClick: () => console.log('emprestimo list click'),
onPress: () => console.log('emprestimo list press'),
},
action: {
onClick: () => console.log('emprestimo action click'),
onPress: () => console.log('emprestimo action press'),
},
},
{
label: i18n.t('person.label'),
icon: FiUser,
iconAction: FiPlus,
handler: {
onClick: () => console.log('pessoa list click'),
onPress: () => console.log('pessoa list press'),
},
action: {
onClick: () => console.log('pessoa action click'),
onPress: () => console.log('pessoa action press'),
},
},
{
label: i18n.t('title.label'),
icon: FiBook,
iconAction: FiPlus,
handler: {
onClick: () => console.log('titulo list click'),
onPress: () => console.log('titulo list press'),
},
action: {
onClick: () => console.log('titulo action click'),
onPress: () => console.log('titulo action press'),
},
},
];
return entities;
}, []);

useEffect(() => {
setSelectedItem(-1);
setSearchResult(searchSourceMemo);

setMaxItems(searchSourceMemo.length * 2);
}, [isOpen, searchSourceMemo]);

useEffect(() => {
on('globalSearch', globalSearchHandler);

return function cleanup() {
off('globalSearch', globalSearchHandler);
};
});

const handleSetSelectedItem = useCallback(
(position: number): void => {
setSelectedItem(
Expand Down Expand Up @@ -129,14 +84,17 @@ const SearchMenu: React.FC<SearchMenuProps> = ({ isOpen, setOpen }) => {

const handleChange = useCallback(
(e: React.ChangeEvent<HTMLInputElement>) => {
setInputSearch(e.target.value);
const value = e.target.value;
setInputSearch(value);
const results = searchSourceMemo.filter((item) =>
item.label
.toLocaleLowerCase()
.startsWith(e.target.value.toLocaleLowerCase())
item.label.toLocaleLowerCase().startsWith(value.toLocaleLowerCase())
);
const resultsDb: SearchSource[] = [];
results.push(...resultsDb);

if (value.length > 3) {
const resultsDb: SearchSource[] = globalSearchHandler(value);
results.push(...resultsDb);
}

const finalResult: SearchSource[] = results.sort((a, b) =>
a.label < b.label ? -1 : 1
);
Expand All @@ -147,6 +105,14 @@ const SearchMenu: React.FC<SearchMenuProps> = ({ isOpen, setOpen }) => {
[searchSourceMemo]
);

const globalSearchHandler = useCallback((search) => {
const retorno: any = window.api.sendSync('globalSearch', {
entity: 'Any',
value: search,
});
return retorno;
}, []);

const handleKeys = useCallback(
(event, clicked): void => {
const mapKeys = [
Expand Down Expand Up @@ -202,9 +168,9 @@ const SearchMenu: React.FC<SearchMenuProps> = ({ isOpen, setOpen }) => {
{searchResult.map((item, index) => (
<MenuItem
key={`menu-${index}`}
index={index}
order={(index + 1) * 2}
item={item}
// mouseInterraction={handleClick}
keyPress={handleKeyPress}
selectedItem={selectedItem}
/>
Expand Down
6 changes: 4 additions & 2 deletions src/app/styles/global.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,6 @@ export default createGlobalStyle`
ul{
li{
list-style: none;
border-bottom: 1px solid ${(props) =>
rgba(props.theme.colors.text, 0.4)};
padding: 10px;
&:first-child {
padding-top: 16px;
Expand Down Expand Up @@ -119,4 +117,8 @@ export default createGlobalStyle`
box-shadow: 0 0 10px ${(props) => rgba(props.theme.colors.text, 0.9)};
border-radius: 10px;
}
.li-selected{
background-color: ${(props) => props.theme.colors.background};
}
`;
116 changes: 116 additions & 0 deletions src/app/util/DefaultEntities.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import { FaHandshake } from 'react-icons/fa';
import { IconBaseProps } from 'react-icons';
import { FiBook, FiPlus, FiSettings, FiUser } from 'react-icons/fi';
import i18n from '../i18n';
import { trigger } from './EventHandler';
import { AppEvent } from '../../common/AppEvent';
import Borrow from '../components/Borrow';

export interface SearchSource {
name: string;
label: string;
icon: React.ComponentType<IconBaseProps>;
iconColor: string;
iconAction?: React.ComponentType<IconBaseProps>;
handler: {
onClick(e: React.MouseEvent): void;
onPress(e: React.KeyboardEvent, item?: SearchSource): void;
};
action: {
onClick(e: React.MouseEvent): void;
onPress(e: React.KeyboardEvent, item?: SearchSource): void;
};
}

export const entities: SearchSource[] = [
{
name: 'borrow',
label: i18n.t('borrow.label'),
icon: FaHandshake,
iconColor: '#50fa7b',
iconAction: FiPlus,
handler: {
onClick: (): void => {
trigger(AppEvent.quickSearch);
trigger(AppEvent.borrowTab);
},
onPress: (): void => {
trigger(AppEvent.quickSearch);
trigger(AppEvent.borrowTab);
},
},
action: {
onClick: () => console.log('emprestimo action click'),
onPress: () => console.log('emprestimo action press'),
},
},
{
name: 'person',
label: i18n.t('person.label'),
icon: FiUser,
iconColor: '#ff78f7',
iconAction: FiPlus,
handler: {
onClick: (): void => {
trigger(AppEvent.quickSearch);
trigger(AppEvent.personTab);
},
onPress: (): void => {
trigger(AppEvent.quickSearch);
trigger(AppEvent.personTab);
},
},
action: {
onClick: () => console.log('pessoa action click'),
onPress: () => console.log('pessoa action press'),
},
},
{
name: 'title',
label: i18n.t('title.label'),
icon: FiBook,
iconColor: '#4ad0ff',
iconAction: FiPlus,
handler: {
onClick: (): void => {
trigger(AppEvent.quickSearch);
trigger(AppEvent.titleTab);
},
onPress: (): void => {
trigger(AppEvent.quickSearch);
trigger(AppEvent.titleTab);
},
},
action: {
onClick: () => console.log('titulo action click'),
onPress: () => console.log('titulo action press'),
},
},
{
name: 'settings',
label: i18n.t('settings.label'),
icon: FiSettings,
iconColor: '#e3bb06',
iconAction: FiSettings,
handler: {
onClick: (): void => {
trigger(AppEvent.quickSearch);
trigger(AppEvent.settingsTab);
},
onPress: (): void => {
trigger(AppEvent.quickSearch);
trigger(AppEvent.settingsTab);
},
},
action: {
onClick: (): void => {
trigger(AppEvent.quickSearch);
trigger(AppEvent.settingsTab);
},
onPress: (): void => {
trigger(AppEvent.quickSearch);
trigger(AppEvent.settingsTab);
},
},
},
];
1 change: 1 addition & 0 deletions src/common/AppEvent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export enum AppEvent {
personTab = 'personTab',
titleTab = 'titleTab',
quickSearch = 'quickSearch',
globalSearch = 'globalSearch',
closeCurrentTab = 'closeCurrentTab',
settingsTab = 'settingsTab',
setTheme = 'setTheme',
Expand Down
Loading

0 comments on commit d0020f2

Please sign in to comment.