Refactored TopBar component from class-based to functional

This commit is contained in:
Przemek Wiech 2021-11-02 12:50:41 +01:00
parent 632964e8b9
commit 0386655fe0

View File

@ -1,5 +1,4 @@
import * as queryString from 'query-string'; import * as queryString from 'query-string';
import * as React from 'react';
import {Dropdown, Icon, Menu} from 'semantic-ui-react'; import {Dropdown, Icon, Menu} from 'semantic-ui-react';
import {FormattedMessage} from 'react-intl'; import {FormattedMessage} from 'react-intl';
import {IndiInfo, JsonGedcomData} from 'topola'; import {IndiInfo, JsonGedcomData} from 'topola';
@ -38,32 +37,32 @@ interface Props {
showWikiTreeMenus: boolean; showWikiTreeMenus: boolean;
} }
export class TopBar extends React.Component<RouteComponentProps & Props> { export function TopBar(props: RouteComponentProps & Props) {
private changeView(view: string) { function changeView(view: string) {
const location = this.props.location; const location = props.location;
const search = queryString.parse(location.search); const search = queryString.parse(location.search);
if (search.view !== view) { if (search.view !== view) {
search.view = view; search.view = view;
location.search = queryString.stringify(search); location.search = queryString.stringify(search);
this.props.history.push(location); props.history.push(location);
} }
} }
private chartMenus(screenSize: ScreenSize) { function chartMenus(screenSize: ScreenSize) {
if (!this.props.showingChart) { if (!props.showingChart) {
return null; return null;
} }
const chartTypeItems = ( const chartTypeItems = (
<> <>
<Dropdown.Item onClick={() => this.changeView('hourglass')}> <Dropdown.Item onClick={() => changeView('hourglass')}>
<Icon name="hourglass" /> <Icon name="hourglass" />
<FormattedMessage <FormattedMessage
id="menu.hourglass" id="menu.hourglass"
defaultMessage="Hourglass chart" defaultMessage="Hourglass chart"
/> />
</Dropdown.Item> </Dropdown.Item>
{this.props.allowAllRelativesChart ? ( {props.allowAllRelativesChart ? (
<Dropdown.Item onClick={() => this.changeView('relatives')}> <Dropdown.Item onClick={() => changeView('relatives')}>
<Icon name="users" /> <Icon name="users" />
<FormattedMessage <FormattedMessage
id="menu.relatives" id="menu.relatives"
@ -71,7 +70,7 @@ export class TopBar extends React.Component<RouteComponentProps & Props> {
/> />
</Dropdown.Item> </Dropdown.Item>
) : null} ) : null}
<Dropdown.Item onClick={() => this.changeView('fancy')}> <Dropdown.Item onClick={() => changeView('fancy')}>
<Icon name="users" /> <Icon name="users" />
<FormattedMessage <FormattedMessage
id="menu.fancy" id="menu.fancy"
@ -84,7 +83,7 @@ export class TopBar extends React.Component<RouteComponentProps & Props> {
case ScreenSize.LARGE: case ScreenSize.LARGE:
return ( return (
<> <>
<Menu.Item onClick={() => this.props.eventHandlers.onPrint()}> <Menu.Item onClick={props.eventHandlers.onPrint}>
<Icon name="print" /> <Icon name="print" />
<FormattedMessage id="menu.print" defaultMessage="Print" /> <FormattedMessage id="menu.print" defaultMessage="Print" />
</Menu.Item> </Menu.Item>
@ -102,25 +101,19 @@ export class TopBar extends React.Component<RouteComponentProps & Props> {
className="item" className="item"
> >
<Dropdown.Menu> <Dropdown.Menu>
<Dropdown.Item <Dropdown.Item onClick={props.eventHandlers.onDownloadPdf}>
onClick={() => this.props.eventHandlers.onDownloadPdf()}
>
<FormattedMessage <FormattedMessage
id="menu.pdf_file" id="menu.pdf_file"
defaultMessage="PDF file" defaultMessage="PDF file"
/> />
</Dropdown.Item> </Dropdown.Item>
<Dropdown.Item <Dropdown.Item onClick={props.eventHandlers.onDownloadPng}>
onClick={() => this.props.eventHandlers.onDownloadPng()}
>
<FormattedMessage <FormattedMessage
id="menu.png_file" id="menu.png_file"
defaultMessage="PNG file" defaultMessage="PNG file"
/> />
</Dropdown.Item> </Dropdown.Item>
<Dropdown.Item <Dropdown.Item onClick={props.eventHandlers.onDownloadSvg}>
onClick={() => this.props.eventHandlers.onDownloadSvg()}
>
<FormattedMessage <FormattedMessage
id="menu.svg_file" id="menu.svg_file"
defaultMessage="SVG file" defaultMessage="SVG file"
@ -141,9 +134,9 @@ export class TopBar extends React.Component<RouteComponentProps & Props> {
<Dropdown.Menu>{chartTypeItems}</Dropdown.Menu> <Dropdown.Menu>{chartTypeItems}</Dropdown.Menu>
</Dropdown> </Dropdown>
<SearchBar <SearchBar
data={this.props.data!} data={props.data!}
onSelection={this.props.eventHandlers.onSelection} onSelection={props.eventHandlers.onSelection}
{...this.props} {...props}
/> />
</> </>
); );
@ -151,34 +144,28 @@ export class TopBar extends React.Component<RouteComponentProps & Props> {
case ScreenSize.SMALL: case ScreenSize.SMALL:
return ( return (
<> <>
<Dropdown.Item onClick={() => this.props.eventHandlers.onPrint()}> <Dropdown.Item onClick={props.eventHandlers.onPrint}>
<Icon name="print" /> <Icon name="print" />
<FormattedMessage id="menu.print" defaultMessage="Print" /> <FormattedMessage id="menu.print" defaultMessage="Print" />
</Dropdown.Item> </Dropdown.Item>
<Dropdown.Divider /> <Dropdown.Divider />
<Dropdown.Item <Dropdown.Item onClick={props.eventHandlers.onDownloadPdf}>
onClick={() => this.props.eventHandlers.onDownloadPdf()}
>
<Icon name="download" /> <Icon name="download" />
<FormattedMessage <FormattedMessage
id="menu.download_pdf" id="menu.download_pdf"
defaultMessage="Downlod PDF" defaultMessage="Downlod PDF"
/> />
</Dropdown.Item> </Dropdown.Item>
<Dropdown.Item <Dropdown.Item onClick={props.eventHandlers.onDownloadPng}>
onClick={() => this.props.eventHandlers.onDownloadPng()}
>
<Icon name="download" /> <Icon name="download" />
<FormattedMessage <FormattedMessage
id="menu.download_png" id="menu.download_png"
defaultMessage="Download PNG" defaultMessage="Download PNG"
/> />
</Dropdown.Item> </Dropdown.Item>
<Dropdown.Item <Dropdown.Item onClick={props.eventHandlers.onDownloadSvg}>
onClick={() => this.props.eventHandlers.onDownloadSvg()}
>
<Icon name="download" /> <Icon name="download" />
<FormattedMessage <FormattedMessage
id="menu.download_svg" id="menu.download_svg"
@ -194,7 +181,7 @@ export class TopBar extends React.Component<RouteComponentProps & Props> {
} }
} }
private title() { function title() {
return ( return (
<Menu.Item> <Menu.Item>
<b>Topola Genealogy</b> <b>Topola Genealogy</b>
@ -202,16 +189,16 @@ export class TopBar extends React.Component<RouteComponentProps & Props> {
); );
} }
private fileMenus(screenSize: ScreenSize) { function fileMenus(screenSize: ScreenSize) {
// In standalone WikiTree mode, show only the "Select WikiTree ID" menu. // In standalone WikiTree mode, show only the "Select WikiTree ID" menu.
if (!this.props.standalone && this.props.showWikiTreeMenus) { if (!props.standalone && props.showWikiTreeMenus) {
switch (screenSize) { switch (screenSize) {
case ScreenSize.LARGE: case ScreenSize.LARGE:
return <WikiTreeMenu menuType={MenuType.Menu} {...this.props} />; return <WikiTreeMenu menuType={MenuType.Menu} {...props} />;
case ScreenSize.SMALL: case ScreenSize.SMALL:
return ( return (
<> <>
<WikiTreeMenu menuType={MenuType.Dropdown} {...this.props} /> <WikiTreeMenu menuType={MenuType.Dropdown} {...props} />
<Dropdown.Divider /> <Dropdown.Divider />
</> </>
); );
@ -219,7 +206,7 @@ export class TopBar extends React.Component<RouteComponentProps & Props> {
} }
// Don't show "open" menus in non-standalone mode. // Don't show "open" menus in non-standalone mode.
if (!this.props.standalone) { if (!props.standalone) {
return null; return null;
} }
@ -227,7 +214,7 @@ export class TopBar extends React.Component<RouteComponentProps & Props> {
case ScreenSize.LARGE: case ScreenSize.LARGE:
// Show dropdown if chart is shown, otherwise show individual menu // Show dropdown if chart is shown, otherwise show individual menu
// items. // items.
const menus = this.props.showingChart ? ( const menus = props.showingChart ? (
<Dropdown <Dropdown
trigger={ trigger={
<div> <div>
@ -238,16 +225,16 @@ export class TopBar extends React.Component<RouteComponentProps & Props> {
className="item" className="item"
> >
<Dropdown.Menu> <Dropdown.Menu>
<UploadMenu menuType={MenuType.Dropdown} {...this.props} /> <UploadMenu menuType={MenuType.Dropdown} {...props} />
<UrlMenu menuType={MenuType.Dropdown} {...this.props} /> <UrlMenu menuType={MenuType.Dropdown} {...props} />
<WikiTreeMenu menuType={MenuType.Dropdown} {...this.props} /> <WikiTreeMenu menuType={MenuType.Dropdown} {...props} />
</Dropdown.Menu> </Dropdown.Menu>
</Dropdown> </Dropdown>
) : ( ) : (
<> <>
<UploadMenu menuType={MenuType.Menu} {...this.props} /> <UploadMenu menuType={MenuType.Menu} {...props} />
<UrlMenu menuType={MenuType.Menu} {...this.props} /> <UrlMenu menuType={MenuType.Menu} {...props} />
<WikiTreeMenu menuType={MenuType.Menu} {...this.props} /> <WikiTreeMenu menuType={MenuType.Menu} {...props} />
</> </>
); );
return menus; return menus;
@ -255,17 +242,17 @@ export class TopBar extends React.Component<RouteComponentProps & Props> {
case ScreenSize.SMALL: case ScreenSize.SMALL:
return ( return (
<> <>
<UploadMenu menuType={MenuType.Dropdown} {...this.props} /> <UploadMenu menuType={MenuType.Dropdown} {...props} />
<UrlMenu menuType={MenuType.Dropdown} {...this.props} /> <UrlMenu menuType={MenuType.Dropdown} {...props} />
<WikiTreeMenu menuType={MenuType.Dropdown} {...this.props} /> <WikiTreeMenu menuType={MenuType.Dropdown} {...props} />
<Dropdown.Divider /> <Dropdown.Divider />
</> </>
); );
} }
} }
private wikiTreeLoginMenu(screenSize: ScreenSize) { function wikiTreeLoginMenu(screenSize: ScreenSize) {
if (!this.props.showWikiTreeMenus) { if (!props.showWikiTreeMenus) {
return null; return null;
} }
return ( return (
@ -274,14 +261,14 @@ export class TopBar extends React.Component<RouteComponentProps & Props> {
menuType={ menuType={
screenSize === ScreenSize.SMALL ? MenuType.Dropdown : MenuType.Menu screenSize === ScreenSize.SMALL ? MenuType.Dropdown : MenuType.Menu
} }
{...this.props} {...props}
/> />
{screenSize === ScreenSize.SMALL ? <Dropdown.Divider /> : null} {screenSize === ScreenSize.SMALL ? <Dropdown.Divider /> : null}
</> </>
); );
} }
private mobileMenus() { function mobileMenus() {
return ( return (
<> <>
<Dropdown <Dropdown
@ -294,9 +281,9 @@ export class TopBar extends React.Component<RouteComponentProps & Props> {
icon={null} icon={null}
> >
<Dropdown.Menu> <Dropdown.Menu>
{this.fileMenus(ScreenSize.SMALL)} {fileMenus(ScreenSize.SMALL)}
{this.chartMenus(ScreenSize.SMALL)} {chartMenus(ScreenSize.SMALL)}
{this.wikiTreeLoginMenu(ScreenSize.SMALL)} {wikiTreeLoginMenu(ScreenSize.SMALL)}
<Dropdown.Item <Dropdown.Item
href="https://github.com/PeWu/topola-viewer" href="https://github.com/PeWu/topola-viewer"
@ -310,23 +297,19 @@ export class TopBar extends React.Component<RouteComponentProps & Props> {
</Dropdown.Item> </Dropdown.Item>
</Dropdown.Menu> </Dropdown.Menu>
</Dropdown> </Dropdown>
{this.props.standalone ? ( {props.standalone ? <Link to="/">{title()}</Link> : title()}
<Link to="/">{this.title()}</Link>
) : (
this.title()
)}
</> </>
); );
} }
private desktopMenus() { function desktopMenus() {
return ( return (
<> <>
{this.props.standalone ? <Link to="/">{this.title()}</Link> : null} {props.standalone ? <Link to="/">{title()}</Link> : null}
{this.fileMenus(ScreenSize.LARGE)} {fileMenus(ScreenSize.LARGE)}
{this.chartMenus(ScreenSize.LARGE)} {chartMenus(ScreenSize.LARGE)}
<Menu.Menu position="right"> <Menu.Menu position="right">
{this.wikiTreeLoginMenu(ScreenSize.LARGE)} {wikiTreeLoginMenu(ScreenSize.LARGE)}
<Menu.Item <Menu.Item
href="https://github.com/PeWu/topola-viewer" href="https://github.com/PeWu/topola-viewer"
target="_blank" target="_blank"
@ -342,30 +325,28 @@ export class TopBar extends React.Component<RouteComponentProps & Props> {
); );
} }
render() { return (
return ( <>
<> <Menu
<Menu as={Media}
as={Media} greaterThanOrEqual="large"
greaterThanOrEqual="large" attached="top"
attached="top" inverted
inverted color="blue"
color="blue" size="large"
size="large" >
> {desktopMenus()}
{this.desktopMenus()} </Menu>
</Menu> <Menu
<Menu as={Media}
as={Media} at="small"
at="small" attached="top"
attached="top" inverted
inverted color="blue"
color="blue" size="large"
size="large" >
> {mobileMenus()}
{this.mobileMenus()} </Menu>
</Menu> </>
</> );
);
}
} }