From d0020f2d7de82e7c57a20b8c189ce90213729b63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Luiz=20Gava?= Date: Mon, 6 Dec 2021 08:15:30 -0300 Subject: [PATCH] Feature/menu searchable (#110) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 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 --- .../components/SearchMenu/MenuItem/index.tsx | 35 +++--- src/app/components/SearchMenu/index.tsx | 96 +++++---------- src/app/styles/global.ts | 6 +- src/app/util/DefaultEntities.ts | 116 ++++++++++++++++++ src/common/AppEvent.ts | 1 + src/electron/Main.ts | 18 ++- 6 files changed, 185 insertions(+), 87 deletions(-) create mode 100644 src/app/util/DefaultEntities.ts diff --git a/src/app/components/SearchMenu/MenuItem/index.tsx b/src/app/components/SearchMenu/MenuItem/index.tsx index e454d15..552e2e9 100644 --- a/src/app/components/SearchMenu/MenuItem/index.tsx +++ b/src/app/components/SearchMenu/MenuItem/index.tsx @@ -1,6 +1,5 @@ import React from 'react'; -import { FiPlus } from 'react-icons/fi'; -import { SearchSource } from '..'; +import { SearchSource } from '../../../util/DefaultEntities'; import RoundedButton from '../../RoundedButton'; interface MenuItemProps { @@ -8,6 +7,7 @@ interface MenuItemProps { selectedItem: number; order: number; item: SearchSource; + index: number; } const MenuItem: React.FC = ({ @@ -15,29 +15,36 @@ const MenuItem: React.FC = ({ keyPress, order, item, + index, }) => { return ( <> -
  • +
  • item.handler.onClick(e)} onKeyDown={keyPress} > - {} + {} {item.label} - item.action.onClick(e)} - onKeyDown={keyPress} - tabIndex={order} - icon={item.iconAction} - color="secondary" - /> + {item.iconAction && ( + item.action.onClick(e)} + onKeyDown={keyPress} + tabIndex={order} + icon={item.iconAction} + /> + )}
  • ); diff --git a/src/app/components/SearchMenu/index.tsx b/src/app/components/SearchMenu/index.tsx index be2a73f..edaae27 100644 --- a/src/app/components/SearchMenu/index.tsx +++ b/src/app/components/SearchMenu/index.tsx @@ -1,31 +1,17 @@ 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; - iconAction: React.ComponentType; - 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 = ({ isOpen, setOpen }) => { const [selectedItem, setSelectedItem] = useState(-1); const [maxItems, setMaxItems] = useState(6); @@ -33,55 +19,24 @@ const SearchMenu: React.FC = ({ isOpen, setOpen }) => { 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( @@ -129,14 +84,17 @@ const SearchMenu: React.FC = ({ isOpen, setOpen }) => { const handleChange = useCallback( (e: React.ChangeEvent) => { - 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 ); @@ -147,6 +105,14 @@ const SearchMenu: React.FC = ({ 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 = [ @@ -202,9 +168,9 @@ const SearchMenu: React.FC = ({ isOpen, setOpen }) => { {searchResult.map((item, index) => ( diff --git a/src/app/styles/global.ts b/src/app/styles/global.ts index e9e05f8..7ebc9a2 100644 --- a/src/app/styles/global.ts +++ b/src/app/styles/global.ts @@ -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; @@ -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}; + } `; diff --git a/src/app/util/DefaultEntities.ts b/src/app/util/DefaultEntities.ts new file mode 100644 index 0000000..f8e6f15 --- /dev/null +++ b/src/app/util/DefaultEntities.ts @@ -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; + iconColor: string; + iconAction?: React.ComponentType; + 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); + }, + }, + }, +]; diff --git a/src/common/AppEvent.ts b/src/common/AppEvent.ts index 6c6c893..3322e8b 100644 --- a/src/common/AppEvent.ts +++ b/src/common/AppEvent.ts @@ -4,6 +4,7 @@ export enum AppEvent { personTab = 'personTab', titleTab = 'titleTab', quickSearch = 'quickSearch', + globalSearch = 'globalSearch', closeCurrentTab = 'closeCurrentTab', settingsTab = 'settingsTab', setTheme = 'setTheme', diff --git a/src/electron/Main.ts b/src/electron/Main.ts index 0ff6805..63bd141 100644 --- a/src/electron/Main.ts +++ b/src/electron/Main.ts @@ -78,7 +78,7 @@ export default class Main { Contact, Settings, Borrow, - BorrowRenovation + BorrowRenovation, ], }); } @@ -127,6 +127,10 @@ export default class Main { event.returnValue = await repository.list(content[0].value); }); + ipcMain.on('globalSearch', async (event, content: Event[]) => { + event.returnValue = []; + }); + const mainWindow = new BrowserWindow({ icon: this.getIcon(), minWidth: 800, @@ -170,14 +174,16 @@ export default class Main { try { const rawdata = fs.readFileSync('./selected-language.json'); const language: { language: string } = JSON.parse(rawdata.toString()); - return language.language; - } catch (err) { - return 'en-US'; - } + return language.language; + } catch (err) { + return 'en-US'; + } } protected async handleTranslations(window: BrowserWindow): Promise { - this.translations = await this.bootstrap.startI18n(this.getSelectedLanguage()); + this.translations = await this.bootstrap.startI18n( + this.getSelectedLanguage() + ); Menu.setApplicationMenu( Menu.buildFromTemplate(