Skip to content

Commit

Permalink
Feat/menu (#156)
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: doing interactive menu

Co-authored-by: André Gava <[email protected]>
  • Loading branch information
AndreLZGava and André Gava authored Feb 25, 2022
1 parent 6c556f8 commit 2b42c42
Show file tree
Hide file tree
Showing 15 changed files with 359 additions and 18 deletions.
3 changes: 2 additions & 1 deletion src/app/components/SearchMenu/MenuItem/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react';
import React, { useEffect } from 'react';
import { SearchSource } from '../../../util/DefaultEntities';
import RoundedButton from '../../RoundedButton';

Expand All @@ -17,6 +17,7 @@ const MenuItem: React.FC<MenuItemProps> = ({
item,
index,
}) => {

return (
<>
<li
Expand Down
40 changes: 30 additions & 10 deletions src/app/components/SearchMenu/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import Modal from '../Modal';
import MenuItem from './MenuItem';
import { FiSearch } from 'react-icons/fi';
import { on, off } from '../../util/EventHandler';
import BehaviourFactory from '../../factory/BehaviourFactory';
import { AdapterBaseProps } from '../../../electron/database/adapter/AdapterBase';

interface SearchMenuProps {
setOpen(): void;
Expand All @@ -24,9 +26,12 @@ const SearchMenu: React.FC<SearchMenuProps> = ({ isOpen, setOpen }) => {

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

setMaxItems(searchSourceMemo.length * 2);
if (!isOpen) {
setInputSearch('');
}
}, [isOpen, searchSourceMemo]);

useEffect(() => {
Expand Down Expand Up @@ -82,14 +87,30 @@ const SearchMenu: React.FC<SearchMenuProps> = ({ isOpen, setOpen }) => {
[searchResult, selectedItem]
);

const globalSearchHandler = useCallback((search) => {
const retorno: any = window.api.sendSync('globalSearch', {
entity: 'Any',
value: search,
const factorySearchHandler = useCallback((ret) => {
const processed = ret.map((item: AdapterBaseProps) => {
console.log(item);
return BehaviourFactory.make(item);
});
return retorno;
return processed;
}, []);

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

return factorySearchHandler(ret);
},
[factorySearchHandler]
);

const sortMenu = (results: any) => {
return results.sort((a: any, b: any) => (a.label < b.label ? -1 : 1));
};

const handleChange = useCallback(
(e: React.ChangeEvent<HTMLInputElement>) => {
const value = e.target.value;
Expand All @@ -103,9 +124,8 @@ const SearchMenu: React.FC<SearchMenuProps> = ({ isOpen, setOpen }) => {
results.push(...resultsDb);
}

const finalResult: SearchSource[] = results.sort((a, b) =>
a.label < b.label ? -1 : 1
);
const finalResult: SearchSource[] = sortMenu(results);

setSearchResult(finalResult);
setMaxItems(finalResult.length * 2);
setSelectedItem(-1);
Expand Down Expand Up @@ -150,7 +170,7 @@ const SearchMenu: React.FC<SearchMenuProps> = ({ isOpen, setOpen }) => {
return (
isOpen && (
<>
<Modal isOpen={isOpen} setIsOpen={setOpen} customClass='quick-search'>
<Modal isOpen={isOpen} setIsOpen={setOpen} customClass="quick-search">
<div>
<Input
name="search-menu"
Expand Down
4 changes: 2 additions & 2 deletions src/app/components/Tabs/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ const Tabs: React.FC = () => {
type: type,
title: `${type}.label`,
action: action,
item: undefined,
item: item ? item : undefined,
};

addTab(tab);
Expand Down Expand Up @@ -194,7 +194,7 @@ const Tabs: React.FC = () => {
[tabItems]
);

useEffect(()=>{
useEffect(() => {
setActiveTab(selectedTab);
}, [selectedTab]);

Expand Down
1 change: 0 additions & 1 deletion src/app/components/Title/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import TitleUpdate from './Update';

const Title: React.FC<{ action: string, item?: unknown }> = ({ action, item }) => {
const title = item as Title;

return (
<>
{action === 'create' && <TitleCreate />}
Expand Down
22 changes: 22 additions & 0 deletions src/app/factory/BehaviourFactory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import Person from './Person';
import Title from './Title';
import {AdapterBaseProps} from '../../electron/database/adapter/AdapterBase';
import { SearchSource } from '../util/DefaultEntities';

interface Product {
[key: string]: Person | Title;
}

class BehaviourFactory {
static readonly factories: Product = {
Person: new Person(),
Title: new Title(),
};

static make(item: AdapterBaseProps): SearchSource {
const classElement = this.factories[item.handler];
return classElement.execute(item);
}
}

export default BehaviourFactory;
23 changes: 23 additions & 0 deletions src/app/factory/IconFactory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { FaPlus, FaUser, FaBook, FaHandshake } from 'react-icons/fa';
import { FiBook } from 'react-icons/fi';
import { IconBaseProps } from 'react-icons';

interface Product {
[key: string]: React.ComponentType<IconBaseProps>;
}

class IconFactory {
static readonly icons: Product = {
FiBook: FiBook,
FaPlus: FaPlus,
FaUser: FaUser,
FaBook: FaBook,
FaHandshake: FaHandshake,
};

static icon(param: string): React.ComponentType<IconBaseProps> {
return this.icons[param];
}
}

export default IconFactory;
57 changes: 57 additions & 0 deletions src/app/factory/Person.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { trigger } from '../util/EventHandler';
import { AppEvent } from '../../common/AppEvent';
import { Actions } from '../../common/Actions';
import IconFactory from './IconFactory';
import {AdapterBaseProps} from '../../electron/database/adapter/AdapterBase';
import { SearchSource } from '../util/DefaultEntities';

class Person {
execute(item: AdapterBaseProps): SearchSource {
const icon = IconFactory.icon(item.icon);
const iconAction = IconFactory.icon(item.iconAction);

const newItem = {
name: item.name,
label: item.label,
complement: item.complement,
icon: icon,
iconColor: item.iconColor,
iconAction: iconAction,
handler: {
onClick: (): void => {
trigger(AppEvent.quickSearch);
trigger(AppEvent.personTab, {
action: Actions.read,
value: item.item,
});
},
onPress: (): void => {
trigger(AppEvent.quickSearch);
trigger(AppEvent.personTab, {
action: Actions.read,
value: item.item,
});
},
},
action: {
onClick: (): void => {
trigger(AppEvent.quickSearch);
trigger(AppEvent.borrowTab, {
action: Actions.create,
value: item.item,
});
},
onPress: (): void => {
trigger(AppEvent.quickSearch);
trigger(AppEvent.borrowTab, {
action: Actions.create,
value: item.item,
});
},
},
};
return newItem;
}
}

export default Person;
56 changes: 56 additions & 0 deletions src/app/factory/Title.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { trigger } from '../util/EventHandler';
import { AppEvent } from '../../common/AppEvent';
import { Actions } from '../../common/Actions';
import IconFactory from './IconFactory';
import {AdapterBaseProps} from '../../electron/database/adapter/AdapterBase';
import { SearchSource } from '../util/DefaultEntities';

class Title {
execute(item: AdapterBaseProps): SearchSource {
const icon = IconFactory.icon(item.icon);
const iconAction = IconFactory.icon(item.iconAction);
const newItem = {
name: item.name,
label: item.label,
complement: item.complement,
icon: icon,
iconColor: item.iconColor,
iconAction: iconAction,
handler: {
onClick: (): void => {
trigger(AppEvent.quickSearch);
trigger(AppEvent.titleTab, {
action: Actions.read,
value: item.item,
});
},
onPress: (): void => {
trigger(AppEvent.quickSearch);
trigger(AppEvent.titleTab, {
action: Actions.read,
value: item.item,
});
},
},
action: {
onClick: (): void => {
trigger(AppEvent.quickSearch);
trigger(AppEvent.borrowTab, {
action: Actions.create,
value: item.item,
});
},
onPress: (): void => {
trigger(AppEvent.quickSearch);
trigger(AppEvent.borrowTab, {
action: Actions.create,
value: item.item,
});
},
},
};
return newItem;
}
}

export default Title;
2 changes: 1 addition & 1 deletion src/app/util/DefaultEntities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ import { FiBook, FiSettings, FiUser } from 'react-icons/fi';
import i18n from '../i18n';
import { trigger } from './EventHandler';
import { AppEvent } from '../../common/AppEvent';
import Borrow from '../components/Borrow';
import { Actions } from '../../common/Actions';

export interface SearchSource {
name: string;
label: string;
complement?: string,
icon: React.ComponentType<IconBaseProps>;
iconColor: string;
iconAction?: React.ComponentType<IconBaseProps>;
Expand Down
20 changes: 19 additions & 1 deletion src/electron/Main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ import BorrowRepository from './database/repository/BorrowRepository';
import TitlePublisherRepository from './database/repository/TitlePublisherRepository';
import UserRepository from './database/repository/UserRepository';
import PersonRepository from './database/repository/PersonRepository';
import TitleAdapter from '../electron/database/adapter/TitleAdapter';
import PersonAdapter from '../electron/database/adapter/PersonAdapter';

declare const MAIN_WINDOW_WEBPACK_ENTRY: string;
declare const MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY: string;
Expand Down Expand Up @@ -352,7 +354,23 @@ export default class Main {

ipcMain.on('globalSearch', async (event, content: Event[]) => {
try {
event.returnValue = [];
const { value, entity } = content[0];
const titleAdapter = new TitleAdapter();
const personAdapter = new PersonAdapter();

const titles = await titleAdapter.defineData(
await this.getCustomRepository('Title', TitleRepository).globalSearch(
value
)
);

const people = await personAdapter.defineData(
await this.getCustomRepository('User', PersonRepository).globalSearch(
value
)
);

event.returnValue = [...titles, ...people];
} catch (err) {
log.error(err);
}
Expand Down
26 changes: 26 additions & 0 deletions src/electron/database/adapter/AdapterBase.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Title } from '../models/Title.schema';
import { User } from '../models/User.schema';

export type AdapterBaseProps = {
name: string;
label: string;
complement?: string;
icon: string;
iconColor: string;
iconAction: string;
handler: string;
action: string;
item: Title | User;
};

interface BaseAdapterContract {
defineData(dataFromRepository: Title[] | User[]): Promise<AdapterBaseProps[]>;
}

export default class AdapterBase implements BaseAdapterContract {
defineData(
dataFromRepository: Title[] | User[]
): Promise<AdapterBaseProps[]> {
throw new Error('Method not implemented.');
}
}
31 changes: 31 additions & 0 deletions src/electron/database/adapter/PersonAdapter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Title } from '../models/Title.schema';
import { User } from '../models/User.schema';
import AdapterBase, { AdapterBaseProps } from './AdapterBase';

export default class PersonAdapter implements AdapterBase {
public async defineData(
dataFromRepository: Title[] | User[]
): Promise<AdapterBaseProps[]> {
try {
const data = dataFromRepository.map((item: Title | User) => {
const processedItem = {
name: item.name,
label: item.name,
complement: item.name,
icon: 'FaUser',
iconColor: '#ff78f7',
iconAction: 'FaHandshake',
handler: 'Person',
action: 'Person',
item: item,
};

return processedItem;
});
return data;
} catch (err) {
console.log(err);
throw err;
}
}
}
Loading

0 comments on commit 2b42c42

Please sign in to comment.