Added "Select WikiTree ID" to the menu

This commit is contained in:
Przemek Wiech 2020-04-09 23:41:45 +02:00
parent b1d2ac5734
commit c3b988e4b7
4 changed files with 200 additions and 18 deletions

View File

@ -133,8 +133,18 @@ class GedcomUrlDataSource implements DataSource {
/** Loading data from the WikiTree API. */
class WikiTreeDataSource implements DataSource {
isNewData(args: Arguments, state: State): boolean {
// WikiTree is always a single data source.
return false;
if (state.selection && state.selection.id === args.indi) {
// Selection unchanged -> don't reload.
return false;
}
if (
state.data &&
state.data.chartData.indis.some((indi) => indi.id === args.indi)
) {
// New selection exists in current view -> animate instead of reloading.
return false;
}
return true;
}
async loadData(args: Arguments): Promise<TopolaData> {
@ -379,7 +389,7 @@ export class App extends React.Component<RouteComponentProps, {}> {
this.setState(
Object.assign({}, this.state, {
data: undefined,
selection: undefined,
selection: {id: args.indi},
hash: args.hash,
error: undefined,
loading: true,

View File

@ -126,3 +126,8 @@ div.ui.card.intro {
.content .ui.image.blockImage {
display: block;
}
.link-span {
color: #4183c4;
cursor: pointer;
}

View File

@ -25,6 +25,9 @@ import {
Responsive,
} from 'semantic-ui-react';
const WIKITREE_LOGO_URL =
'https://www.wikitree.com/photo.php/a/a5/WikiTree_Images.png';
enum WikiTreeLoginState {
UNKNOWN,
NOT_LOGGED_IN,
@ -39,7 +42,9 @@ enum ScreenSize {
/** Menus and dialogs state. */
interface State {
loadUrlDialogOpen: boolean;
wikiTreeIdDialogOpen: boolean;
url?: string;
wikiTreeId?: string;
wikiTreeLoginState: WikiTreeLoginState;
wikiTreeLoginUsername?: string;
searchResults: SearchResultProps[];
@ -87,6 +92,7 @@ export class TopBar extends React.Component<
> {
state: State = {
loadUrlDialogOpen: false,
wikiTreeIdDialogOpen: false,
searchResults: [],
wikiTreeLoginState: WikiTreeLoginState.UNKNOWN,
};
@ -96,6 +102,7 @@ export class TopBar extends React.Component<
};
urlInputRef: React.RefObject<Input> = React.createRef();
wikiTreeIdInputRef: React.RefObject<Input> = React.createRef();
wikiTreeLoginFormRef: React.RefObject<HTMLFormElement> = React.createRef();
wikiTreeReturnUrlRef: React.RefObject<HTMLInputElement> = React.createRef();
searchRef?: {setValue(value: string): void};
@ -163,12 +170,24 @@ export class TopBar extends React.Component<
);
}
/** Cancels the "Load from URL" dialog. */
private handleClose() {
this.setState(Object.assign({}, this.state, {loadUrlDialogOpen: false}));
private openWikiTreeIdDialog() {
this.setState(
Object.assign({}, this.state, {wikiTreeIdDialogOpen: true}),
() => this.wikiTreeIdInputRef.current!.focus(),
);
}
/** Upload button clicked in the "Load from URL" dialog. */
/** Cancels any of the open dialogs. */
private handleClose() {
this.setState(
Object.assign({}, this.state, {
loadUrlDialogOpen: false,
wikiTreeIdDialogOpen: false,
}),
);
}
/** Load button clicked in the "Load from URL" dialog. */
private handleLoad() {
this.setState(
Object.assign({}, this.state, {
@ -184,11 +203,43 @@ export class TopBar extends React.Component<
}
}
/** Called when the URL input is typed into. */
private handleUrlChange(event: React.SyntheticEvent) {
/** Select button clicked in the "Select WikiTree ID" dialog. */
private handleSelectWikiTreeId() {
this.setState(
Object.assign({}, this.state, {
url: (event.target as HTMLInputElement).value,
wikiTreeIdDialogOpen: false,
}),
);
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,
}),
});
}
}
/** Called when the URL input is typed into. */
private handleUrlChange(value: string) {
this.setState(
Object.assign({}, this.state, {
url: value,
}),
);
}
/** Called when the URL input is typed into. */
private handleWikiTreeIdChange(value: string) {
this.setState(
Object.assign({}, this.state, {
wikiTreeId: value,
}),
);
}
@ -289,7 +340,7 @@ export class TopBar extends React.Component<
<Input
placeholder="https://"
fluid
onChange={(e) => this.handleUrlChange(e)}
onChange={(e, data) => this.handleUrlChange(data.value)}
ref={this.urlInputRef}
/>
<p>
@ -324,6 +375,95 @@ export class TopBar extends React.Component<
);
}
private enterWikiTreeId(event: React.MouseEvent, id: string) {
event.preventDefault(); // Do not follow link in href.
((this.wikiTreeIdInputRef.current as unknown) as {
inputRef: HTMLInputElement;
}).inputRef.value = id;
this.handleWikiTreeIdChange(id);
}
private wikiTreeIdModal() {
return (
<Modal
open={this.state.wikiTreeIdDialogOpen}
onClose={() => this.handleClose()}
centered={false}
>
<Header>
<img
src={WIKITREE_LOGO_URL}
alt="WikiTree logo"
style={{width: '32px', height: '32px'}}
/>
<FormattedMessage
id="select_wikitree_id.title"
defaultMessage="Select WikiTree ID"
children={(txt) => txt}
/>
</Header>
<Modal.Content>
<Form onSubmit={() => this.handleLoad()}>
<p>
<FormattedMessage
id="select_wikitree_id.comment"
defaultMessage={
'Enter a {wikiTreeLink} profile ID. Examples: {example1}, {example2}.'
}
values={{
wikiTreeLink: (
<a
href="https://wikitree.com/"
target="_blank"
rel="noopener noreferrer"
>
WikiTree
</a>
),
example1: (
<span
onClick={(e) => this.enterWikiTreeId(e, 'Wojtyla-13')}
className="link-span"
>
Wojtyla-13
</span>
),
example2: (
<span
onClick={(e) => this.enterWikiTreeId(e, 'Skłodowska-2')}
className="link-span"
>
Skłodowska-2
</span>
),
}}
/>
</p>
<Input
fluid
onChange={(e, data) => this.handleWikiTreeIdChange(data.value)}
ref={this.wikiTreeIdInputRef}
/>
</Form>
</Modal.Content>
<Modal.Actions>
<Button secondary onClick={() => this.handleClose()}>
<FormattedMessage
id="select_wikitree_id.cancel"
defaultMessage="Cancel"
/>
</Button>
<Button primary onClick={() => this.handleSelectWikiTreeId()}>
<FormattedMessage
id="select_wikitree_id.load"
defaultMessage="Load"
/>
</Button>
</Modal.Actions>
</Modal>
);
}
private search() {
return (
<Search
@ -521,9 +661,23 @@ export class TopBar extends React.Component<
/>
</>
);
const loadWikiTreeItem = (
<>
<img
src={WIKITREE_LOGO_URL}
alt="WikiTree logo"
style={{width: '24px', height: '24px'}}
/>
<FormattedMessage
id="menu.select_wikitree_id"
defaultMessage="Select WikiTree ID"
/>
</>
);
const commonElements = (
<>
{this.loadFromUrlModal()}
{this.wikiTreeIdModal()}
<input
className="hidden"
type="file"
@ -555,6 +709,9 @@ export class TopBar extends React.Component<
<Dropdown.Item onClick={() => this.openLoadUrlDialog()}>
{loadUrlItem}
</Dropdown.Item>
<Dropdown.Item onClick={() => this.openWikiTreeIdDialog()}>
{loadWikiTreeItem}
</Dropdown.Item>
</Dropdown.Menu>
</Dropdown>
) : (
@ -565,6 +722,9 @@ export class TopBar extends React.Component<
<Menu.Item onClick={() => this.openLoadUrlDialog()}>
{loadUrlItem}
</Menu.Item>
<Menu.Item onClick={() => this.openWikiTreeIdDialog()}>
{loadWikiTreeItem}
</Menu.Item>
</>
);
return (
@ -583,6 +743,9 @@ export class TopBar extends React.Component<
<Dropdown.Item onClick={() => this.openLoadUrlDialog()}>
{loadUrlItem}
</Dropdown.Item>
<Dropdown.Item onClick={() => this.openWikiTreeIdDialog()}>
{loadWikiTreeItem}
</Dropdown.Item>
<Dropdown.Divider />
{commonElements}
</>
@ -594,9 +757,6 @@ export class TopBar extends React.Component<
if (!this.props.showWikiTreeLogin) {
return null;
}
const wikiTreeLogoUrl =
'https://www.wikitree.com/photo.php/a/a5/WikiTree_Images.png';
switch (this.state.wikiTreeLoginState) {
case WikiTreeLoginState.NOT_LOGGED_IN:
const loginForm = (
@ -619,7 +779,7 @@ export class TopBar extends React.Component<
return (
<Menu.Item onClick={() => this.wikiTreeLogin()}>
<img
src={wikiTreeLogoUrl}
src={WIKITREE_LOGO_URL}
alt="WikiTree logo"
style={{width: '24px', height: '24px'}}
/>
@ -636,7 +796,7 @@ export class TopBar extends React.Component<
<>
<Dropdown.Item onClick={() => this.wikiTreeLogin()}>
<img
src={wikiTreeLogoUrl}
src={WIKITREE_LOGO_URL}
alt="WikiTree logo"
style={{width: '24px', height: '24px'}}
/>
@ -670,7 +830,7 @@ export class TopBar extends React.Component<
return (
<Menu.Item title={tooltip}>
<img
src={wikiTreeLogoUrl}
src={WIKITREE_LOGO_URL}
alt="WikiTree logo"
style={{width: '24px', height: '24px'}}
/>
@ -686,7 +846,7 @@ export class TopBar extends React.Component<
<>
<Menu.Item title={tooltip}>
<img
src={wikiTreeLogoUrl}
src={WIKITREE_LOGO_URL}
alt="WikiTree logo"
style={{width: '24px', height: '24px'}}
/>
@ -725,6 +885,7 @@ export class TopBar extends React.Component<
<Dropdown.Item
href="https://github.com/PeWu/topola-viewer"
target="_blank"
rel="noopener noreferrer"
>
<FormattedMessage
id="menu.github"
@ -753,6 +914,7 @@ export class TopBar extends React.Component<
<Menu.Item
href="https://github.com/PeWu/topola-viewer"
target="_blank"
rel="noopener noreferrer"
>
<FormattedMessage
id="menu.github"

View File

@ -2,6 +2,7 @@
"menu.open": "Otwórz",
"menu.open_file": "Otwórz plik",
"menu.load_from_url": "Otwórz URL",
"menu.select_wikitree_id": "WikiTree ID",
"menu.print": "Drukuj",
"menu.download": "Pobierz",
"menu.pdf_file": "Plik PDF",
@ -32,6 +33,10 @@
"load_from_url.comment": "Dane z podanego adresu URL zostaną załadowane poprzez usługę {link} w celu uniknięcia problemów z CORS.",
"load_from_url.cancel": "Anuluj",
"load_from_url.load": "Otwórz",
"select_wikitree_id.title": "Podaj WikiTree ID",
"select_wikitree_id.comment": "Wpisz identyfikator profilu {wikiTreeLink}. Przykłady: {example1}, {example2}",
"select_wikitree_id.cancel": "Anuluj",
"select_wikitree_id.load": "Otwórz",
"gedcom.BAPM": "Chrzest",
"gedcom.BIRT": "Narodziny",
"gedcom.BURI": "Pogrzeb",