Refactored WikiTreeMenu component from class-based to functional

This commit is contained in:
Przemek Wiech 2021-11-03 11:17:42 +01:00
parent be3592f51b
commit b6c96ae336

View File

@ -1,12 +1,12 @@
import * as queryString from 'query-string'; import * as queryString from 'query-string';
import * as React from 'react';
import wikitreeLogo from './wikitree.png'; import wikitreeLogo from './wikitree.png';
import {analyticsEvent} from '../util/analytics'; import {analyticsEvent} from '../util/analytics';
import {Button, Form, Header, Input, Modal} from 'semantic-ui-react';
import {Component, createRef, useEffect, useRef, useState} from 'react';
import {FormattedMessage, injectIntl, WrappedComponentProps} from 'react-intl'; import {FormattedMessage, injectIntl, WrappedComponentProps} from 'react-intl';
import {getLoggedInUserName} from '../datasource/wikitree'; import {getLoggedInUserName} from '../datasource/wikitree';
import {MenuItem, MenuType} from './menu_item'; import {MenuItem, MenuType} from './menu_item';
import {RouteComponentProps} from 'react-router-dom'; import {RouteComponentProps} from 'react-router-dom';
import {Header, Button, Modal, Input, Form, Ref} from 'semantic-ui-react';
enum WikiTreeLoginState { enum WikiTreeLoginState {
UNKNOWN, UNKNOWN,
@ -18,81 +18,50 @@ interface Props {
menuType: MenuType; menuType: MenuType;
} }
interface State {
dialogOpen: boolean;
wikiTreeId?: string;
}
/** Displays and handles the "Select WikiTree ID" menu. */ /** Displays and handles the "Select WikiTree ID" menu. */
export class WikiTreeMenu extends React.Component< export function WikiTreeMenu(props: RouteComponentProps & Props) {
RouteComponentProps & Props, const [dialogOpen, setDialogOpen] = useState(false);
State const [wikiTreeId, setWikiTreeId] = useState('');
> { const inputRef = useRef<Input>(null);
state: State = {
dialogOpen: false,
};
inputRef: React.RefObject<HTMLElement> = React.createRef(); useEffect(() => {
if (dialogOpen) {
private openDialog() { setWikiTreeId('');
this.setState(Object.assign({}, this.state, {dialogOpen: true}), () => inputRef.current!.focus();
(this.inputRef.current!.firstChild as HTMLInputElement).focus(), }
); }, [dialogOpen]);
}
/** Cancels any of the open dialogs. */
private handleClose() {
this.setState(
Object.assign({}, this.state, {
dialogOpen: false,
}),
);
}
/** Select button clicked in the "Select WikiTree ID" dialog. */ /** Select button clicked in the "Select WikiTree ID" dialog. */
private handleSelectId() { function handleSelectId() {
this.setState( setDialogOpen(false);
Object.assign({}, this.state, { if (!wikiTreeId) {
dialogOpen: false, return;
}),
);
if (this.state.wikiTreeId) {
analyticsEvent('wikitree_id_selected');
const search = queryString.parse(this.props.location.search);
const standalone =
search.standalone !== undefined ? search.standalone : true;
this.props.history.push({
pathname: '/view',
search: queryString.stringify({
indi: this.state.wikiTreeId,
source: 'wikitree',
standalone,
}),
});
} }
} analyticsEvent('wikitree_id_selected');
const search = queryString.parse(props.location.search);
/** Called when the WikiTree ID input is typed into. */ const standalone =
private handleIdChange(value: string) { search.standalone !== undefined ? search.standalone : true;
this.setState( props.history.push({
Object.assign({}, this.state, { pathname: '/view',
wikiTreeId: value, search: queryString.stringify({
indi: wikiTreeId,
source: 'wikitree',
standalone,
}), }),
); });
} }
private enterId(event: React.MouseEvent, id: string) { function enterId(event: React.MouseEvent, id: string) {
event.preventDefault(); // Do not follow link in href. event.preventDefault(); // Do not follow link in href.
(this.inputRef.current!.firstChild as HTMLInputElement).value = id; setWikiTreeId(id);
this.handleIdChange(id); inputRef.current!.focus();
(this.inputRef.current!.firstChild as HTMLInputElement).focus();
} }
private wikiTreeIdModal() { function wikiTreeIdModal() {
return ( return (
<Modal <Modal
open={this.state.dialogOpen} open={dialogOpen}
onClose={() => this.handleClose()} onClose={() => setDialogOpen(false)}
centered={false} centered={false}
> >
<Header> <Header>
@ -107,7 +76,7 @@ export class WikiTreeMenu extends React.Component<
/> />
</Header> </Header>
<Modal.Content> <Modal.Content>
<Form onSubmit={() => this.handleSelectId()}> <Form onSubmit={handleSelectId}>
<p> <p>
<FormattedMessage <FormattedMessage
id="select_wikitree_id.comment" id="select_wikitree_id.comment"
@ -126,7 +95,7 @@ export class WikiTreeMenu extends React.Component<
), ),
example1: ( example1: (
<span <span
onClick={(e) => this.enterId(e, 'Wojtyla-13')} onClick={(e) => enterId(e, 'Wojtyla-13')}
className="link-span" className="link-span"
> >
Wojtyla-13 Wojtyla-13
@ -134,7 +103,7 @@ export class WikiTreeMenu extends React.Component<
), ),
example2: ( example2: (
<span <span
onClick={(e) => this.enterId(e, 'Skłodowska-2')} onClick={(e) => enterId(e, 'Skłodowska-2')}
className="link-span" className="link-span"
> >
Skłodowska-2 Skłodowska-2
@ -143,22 +112,22 @@ export class WikiTreeMenu extends React.Component<
}} }}
/> />
</p> </p>
<Ref innerRef={this.inputRef}> <Input
<Input fluid
fluid value={wikiTreeId}
onChange={(e, data) => this.handleIdChange(data.value)} onChange={(_, data) => setWikiTreeId(data.value)}
/> ref={inputRef}
</Ref> />
</Form> </Form>
</Modal.Content> </Modal.Content>
<Modal.Actions> <Modal.Actions>
<Button secondary onClick={() => this.handleClose()}> <Button secondary onClick={() => setDialogOpen(false)}>
<FormattedMessage <FormattedMessage
id="select_wikitree_id.cancel" id="select_wikitree_id.cancel"
defaultMessage="Cancel" defaultMessage="Cancel"
/> />
</Button> </Button>
<Button primary onClick={() => this.handleSelectId()}> <Button primary onClick={handleSelectId}>
<FormattedMessage <FormattedMessage
id="select_wikitree_id.load" id="select_wikitree_id.load"
defaultMessage="Load" defaultMessage="Load"
@ -169,23 +138,18 @@ export class WikiTreeMenu extends React.Component<
); );
} }
render() { return (
return ( <>
<> <MenuItem menuType={props.menuType} onClick={() => setDialogOpen(true)}>
<MenuItem <img src={wikitreeLogo} alt="WikiTree logo" className="menu-icon" />
menuType={this.props.menuType} <FormattedMessage
onClick={() => this.openDialog()} id="menu.select_wikitree_id"
> defaultMessage="Select WikiTree ID"
<img src={wikitreeLogo} alt="WikiTree logo" className="menu-icon" /> />
<FormattedMessage </MenuItem>
id="menu.select_wikitree_id" {wikiTreeIdModal()}
defaultMessage="Select WikiTree ID" </>
/> );
</MenuItem>
{this.wikiTreeIdModal()}
</>
);
}
} }
interface LoginState { interface LoginState {
@ -194,7 +158,7 @@ interface LoginState {
} }
/** Displays and handles the "Log in to WikiTree" menu. */ /** Displays and handles the "Log in to WikiTree" menu. */
class WikiTreeLoginMenuComponent extends React.Component< class WikiTreeLoginMenuComponent extends Component<
RouteComponentProps & WrappedComponentProps & Props, RouteComponentProps & WrappedComponentProps & Props,
LoginState LoginState
> { > {
@ -202,8 +166,8 @@ class WikiTreeLoginMenuComponent extends React.Component<
wikiTreeLoginState: WikiTreeLoginState.UNKNOWN, wikiTreeLoginState: WikiTreeLoginState.UNKNOWN,
}; };
wikiTreeLoginFormRef: React.RefObject<HTMLFormElement> = React.createRef(); wikiTreeLoginFormRef: React.RefObject<HTMLFormElement> = createRef();
wikiTreeReturnUrlRef: React.RefObject<HTMLInputElement> = React.createRef(); wikiTreeReturnUrlRef: React.RefObject<HTMLInputElement> = createRef();
/** /**
* Redirect to the WikiTree Apps login page with a return URL pointing to * Redirect to the WikiTree Apps login page with a return URL pointing to