From 1a333036afa7ff1e5a1c247c280b62cd5e11b4ac Mon Sep 17 00:00:00 2001 From: Kushagra Gour Date: Wed, 17 Jul 2019 14:02:44 +0530 Subject: [PATCH] =?UTF-8?q?Migrate=20SavedItemPane=20to=20functional=20com?= =?UTF-8?q?ponent=20=F0=9F=A5=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/SavedItemPane.jsx | 284 +++++++++++++++---------------- src/components/app.jsx | 12 +- 2 files changed, 142 insertions(+), 154 deletions(-) diff --git a/src/components/SavedItemPane.jsx b/src/components/SavedItemPane.jsx index 8bb11d7..3a55d8c 100644 --- a/src/components/SavedItemPane.jsx +++ b/src/components/SavedItemPane.jsx @@ -1,62 +1,63 @@ -import { h, Component } from 'preact'; +import { h } from 'preact'; +import { useState, useEffect, useRef } from 'preact/hooks'; import { log } from '../utils'; import { trackEvent } from '../analytics'; import { ItemTile } from './ItemTile'; -import { Trans, NumberFormat, t } from '@lingui/macro'; +import { Trans, t } from '@lingui/macro'; import { I18n } from '@lingui/react'; -export default class SavedItemPane extends Component { - constructor(props) { - super(props); - // this.items = []; - } +export default function SavedItemPane({ + itemsMap, + isOpen, + closeHandler, + onItemSelect, + onitemRemove, + onItemFork, + onExport, + mergeImportedItems +}) { + const [items, setItems] = useState([]); + const [filteredItems, setFilteredItems] = useState([]); + const searchInputRef = useRef(); - static getDerivedStateFromProps({ items = {} }, state) { - const newItems = Object.values(items); + useEffect(() => { + if (!itemsMap) return; + const newItems = Object.values(itemsMap); newItems.sort(function(a, b) { return b.updatedOn - a.updatedOn; }); - return { - items: newItems - }; - } - shouldComponentUpdate(nextProps, nextState) { - return ( - nextProps.items !== this.props.items || - nextProps.isOpen !== this.props.isOpen || - nextState.filteredItems !== this.state.filteredItems - ); - } + setItems(newItems); + setFilteredItems(newItems); + }, [itemsMap]); - componentDidUpdate(prevProps) { + useEffect(() => { // Opening - if (this.props.isOpen && !prevProps.isOpen) { - window.searchInput.value = ''; - window.searchInput.focus(); + if (isOpen) { + searchInputRef.current.value = ''; + searchInputRef.current.focus(); } // Closing - if (!this.props.isOpen && prevProps.isOpen) { - this.setState({ - filteredItems: undefined - }); + if (!isOpen) { + setFilteredItems([]); } + }, [isOpen]); + + function onCloseIntent() { + closeHandler(); } - onCloseIntent() { - this.props.closeHandler(); + function itemClickHandler(item) { + onItemSelect(item); } - itemClickHandler(item) { - this.props.itemClickHandler(item); - } - itemRemoveBtnClickHandler(item, e) { + function itemRemoveBtnClickHandler(item, e) { e.stopPropagation(); - this.props.itemRemoveBtnClickHandler(item); + onitemRemove(item); } - itemForkBtnClickHandler(item, e) { + function itemForkBtnClickHandler(item, e) { e.stopPropagation(); - this.props.itemForkBtnClickHandler(item); + onItemFork(item); } - keyDownHandler(event) { - if (!this.props.isOpen) { + function keyDownHandler(event) { + if (!isOpen) { return; } @@ -84,22 +85,21 @@ export default class SavedItemPane extends Component { } if (isEnterKeyPressed && selectedItemElement) { - const item = this.props.items[selectedItemElement.dataset.itemId]; - console.log('opening', item); - this.props.itemClickHandler(item); + const item = itemsMap[selectedItemElement.dataset.itemId]; + onItemSelect(item); trackEvent('ui', 'openItemKeyboardShortcut'); } // Fork shortcut inside saved creations panel with Ctrl/⌘ + F if (isForkKeyPressed) { event.preventDefault(); - const item = this.props.items[selectedItemElement.dataset.itemId]; - this.props.itemForkBtnClickHandler(item); + const item = itemsMap[selectedItemElement.dataset.itemId]; + itemForkBtnClickHandler(item); trackEvent('ui', 'forkKeyboardShortcut'); } } - importFileChangeHandler(e) { + function importFileChangeHandler(e) { var file = e.target.files[0]; var reader = new FileReader(); @@ -108,7 +108,7 @@ export default class SavedItemPane extends Component { try { items = JSON.parse(progressEvent.target.result); log(items); - this.props.mergeImportedItems(items); + mergeImportedItems(items); } catch (exception) { log(exception); alert( @@ -122,125 +122,115 @@ export default class SavedItemPane extends Component { reader.readAsText(file, 'utf-8'); } - importBtnClickHandler(e) { + function importBtnClickHandler(e) { var input = document.createElement('input'); input.type = 'file'; input.style.display = 'none'; input.accept = 'accept="application/json'; document.body.appendChild(input); - input.addEventListener('change', this.importFileChangeHandler.bind(this)); + input.addEventListener('change', importFileChangeHandler); input.click(); trackEvent('ui', 'importBtnClicked'); e.preventDefault(); } - searchInputHandler(e) { - const text = e.target.value.toLowerCase(); + function searchInputHandler(e) { + const text = e.target.value.toLowerCase().trim(); if (!text) { - this.setState({ - filteredItems: this.state.items - }); + setFilteredItems(items); } else { - this.setState({ - filteredItems: this.state.items.filter( - item => item.title.toLowerCase().indexOf(text) !== -1 - ) - }); + setFilteredItems( + items.filter(item => item.title.toLowerCase().indexOf(text) !== -1) + ); } trackEvent('ui', 'searchInputType'); } - render( - { isOpen, exportBtnClickHandler }, - { filteredItems = this.state.items, items = [] } - ) { - return ( - - {({ i18n }) => ( -
+ {({ i18n }) => ( +
+ -
-

- My Library ({filteredItems.length}) -

+ X + +
+

+ My Library ({filteredItems.length}) +

-
- - -
-
- - -
- {!filteredItems.length && items.length ? ( -
- No match found. -
- ) : null} - {filteredItems.map(item => ( - - ))} - {!items.length ? ( -
-

- Nothing saved here. -

- -
- ) : null} +
+ +
- )} - - ); - } +
e.preventDefault()}> + +
+ +
+ {!filteredItems.length && items.length ? ( +
+ No match found. +
+ ) : null} + {filteredItems.map(item => ( + itemClickHandler(item)} + onForkBtnClick={() => itemForkBtnClickHandler(item)} + onRemoveBtnClick={() => itemRemoveBtnClickHandler(item)} + /> + ))} + {!items.length ? ( +
+

+ Nothing saved here. +

+ +
+ ) : null} +
+
+ )} + + ); } diff --git a/src/components/app.jsx b/src/components/app.jsx index 001bfe5..fd3803e 100644 --- a/src/components/app.jsx +++ b/src/components/app.jsx @@ -1665,15 +1665,13 @@ export default class App extends Component {