mirror of
https://github.com/PeWu/topola-viewer.git
synced 2025-12-23 18:50:04 +00:00
Name types in details panel (#109)
This commit is contained in:
parent
a92f06e43d
commit
0733690058
12
package-lock.json
generated
12
package-lock.json
generated
@ -5,7 +5,6 @@
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "topola-viewer",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"@artsy/fresnel": "^1.3.1",
|
||||
@ -38,6 +37,7 @@
|
||||
"semantic-ui-css": "^2.4.1",
|
||||
"semantic-ui-react": "^2.0.3",
|
||||
"topola": "^3.5.0",
|
||||
"turbocommons-ts": "^3.8.0",
|
||||
"unified": "^10.1.0",
|
||||
"wikitree-js": "^0.1.0"
|
||||
},
|
||||
@ -22907,6 +22907,11 @@
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/turbocommons-ts": {
|
||||
"version": "3.8.0",
|
||||
"resolved": "https://registry.npmjs.org/turbocommons-ts/-/turbocommons-ts-3.8.0.tgz",
|
||||
"integrity": "sha512-EQRCm2r944M/TqzfRutaCwTN+eHVLPAedaWF8catAHd49biN1UjB9CGLTBT2kI3i9lCccSt84s8YFf54u1WcAg=="
|
||||
},
|
||||
"node_modules/tweetnacl": {
|
||||
"version": "0.14.5",
|
||||
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
|
||||
@ -44181,6 +44186,11 @@
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"turbocommons-ts": {
|
||||
"version": "3.8.0",
|
||||
"resolved": "https://registry.npmjs.org/turbocommons-ts/-/turbocommons-ts-3.8.0.tgz",
|
||||
"integrity": "sha512-EQRCm2r944M/TqzfRutaCwTN+eHVLPAedaWF8catAHd49biN1UjB9CGLTBT2kI3i9lCccSt84s8YFf54u1WcAg=="
|
||||
},
|
||||
"tweetnacl": {
|
||||
"version": "0.14.5",
|
||||
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
|
||||
|
||||
@ -33,6 +33,7 @@
|
||||
"semantic-ui-css": "^2.4.1",
|
||||
"semantic-ui-react": "^2.0.3",
|
||||
"topola": "^3.5.0",
|
||||
"turbocommons-ts": "^3.8.0",
|
||||
"unified": "^10.1.0",
|
||||
"wikitree-js": "^0.1.0"
|
||||
},
|
||||
|
||||
@ -14,12 +14,13 @@ import {GedcomEntry} from 'parse-gedcom';
|
||||
import {IntlShape} from 'react-intl';
|
||||
import {TopolaError} from '../util/error';
|
||||
import {isValidDateOrRange} from '../util/date_util';
|
||||
import {StringUtils} from 'turbocommons-ts';
|
||||
import {
|
||||
getAncestors as getAncestorsApi,
|
||||
getRelatives as getRelativesApi,
|
||||
clientLogin,
|
||||
getLoggedInUserName,
|
||||
Person
|
||||
Person,
|
||||
} from 'wikitree-js';
|
||||
|
||||
/** Prefix for IDs of private individuals. */
|
||||
@ -66,7 +67,7 @@ async function getAncestors(
|
||||
if (cachedData) {
|
||||
return JSON.parse(cachedData);
|
||||
}
|
||||
const result = getAncestorsApi(key, {}, getApiOptions(handleCors));
|
||||
const result = await getAncestorsApi(key, {}, getApiOptions(handleCors));
|
||||
setSessionStorageItem(cacheKey, JSON.stringify(result));
|
||||
return result;
|
||||
}
|
||||
@ -225,6 +226,12 @@ export async function loadWikiTree(
|
||||
generation++;
|
||||
}
|
||||
|
||||
//Map from human-readable person id to person names
|
||||
const personNames = new Map<
|
||||
string,
|
||||
{birth?: string; married?: string; aka?: string}
|
||||
>();
|
||||
|
||||
// Map from person id to the set of families where they are a spouse.
|
||||
const families = new Map<number, Set<string>>();
|
||||
// Map from family id to the set of children.
|
||||
@ -268,6 +275,9 @@ export async function loadWikiTree(
|
||||
`https://www.wikitree.com${person.PhotoData.path}`,
|
||||
);
|
||||
}
|
||||
|
||||
personNames.set(person.Name, convertPersonNames(person));
|
||||
|
||||
if (person.Spouses) {
|
||||
Object.values(person.Spouses).forEach((spouse) => {
|
||||
const famId = getFamilyId(person.Id, spouse.Id);
|
||||
@ -314,7 +324,7 @@ export async function loadWikiTree(
|
||||
});
|
||||
|
||||
const chartData = normalizeGedcom({indis, fams});
|
||||
const gedcom = buildGedcom(chartData, fullSizePhotoUrls);
|
||||
const gedcom = buildGedcom(chartData, fullSizePhotoUrls, personNames);
|
||||
return {chartData, gedcom};
|
||||
}
|
||||
|
||||
@ -387,6 +397,50 @@ function convertPerson(person: Person, intl: IntlShape): JsonIndi {
|
||||
}
|
||||
return indi;
|
||||
}
|
||||
/**
|
||||
Resolve birth name, married name and aka name with following logic:
|
||||
- birth name is always prioritized and is set if exists and is not unknown
|
||||
- married name is based on LastNameCurrent and is set if it's different than birth name
|
||||
and one of the spouses has it as their birth name
|
||||
- aka name is based on LastNameOther and is set if it's different than others
|
||||
*/
|
||||
function convertPersonNames(person: Person) {
|
||||
return {
|
||||
birth:
|
||||
person.LastNameAtBirth !== 'Unknown' ? person.LastNameAtBirth : undefined,
|
||||
married:
|
||||
person.Spouses &&
|
||||
person.LastNameCurrent !== 'Unknown' &&
|
||||
person.LastNameCurrent !== person.LastNameAtBirth &&
|
||||
Object.entries(person.Spouses)
|
||||
.flatMap(([, spousePerson]) =>
|
||||
spousePerson.LastNameAtBirth.split(/[- ,]/),
|
||||
)
|
||||
.filter(
|
||||
(spousePersonNamePart) =>
|
||||
/* In some languages the same names can differ a bit between genders,
|
||||
so regular equals comparison cannot be used.
|
||||
To verify if spouse has the same name, person name is split to include people with double names,
|
||||
then there is a check if any name part is at least 75% similar to spouse name.
|
||||
*/
|
||||
person.LastNameCurrent.split(/[- ,]/).filter(
|
||||
(personNamePart) =>
|
||||
StringUtils.compareSimilarityPercent(
|
||||
spousePersonNamePart,
|
||||
personNamePart,
|
||||
) >= 75,
|
||||
).length,
|
||||
).length
|
||||
? person.LastNameCurrent
|
||||
: undefined,
|
||||
aka:
|
||||
person.LastNameOther !== 'Unknown' &&
|
||||
person.LastNameAtBirth !== person.LastNameOther &&
|
||||
person.LastNameCurrent !== person.LastNameOther
|
||||
? person.LastNameOther
|
||||
: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a date in the format returned by WikiTree and converts in to
|
||||
@ -468,6 +522,24 @@ function dateOrRangeToGedcom(dateOrRange: DateOrRange): string {
|
||||
return '';
|
||||
}
|
||||
|
||||
function nameToGedcom(type: string, firstName?: string, lastName?: string) {
|
||||
return {
|
||||
level: 1,
|
||||
pointer: '',
|
||||
tag: 'NAME',
|
||||
data: `${firstName || ''} /${lastName || ''}/`,
|
||||
tree: [
|
||||
{
|
||||
level: 2,
|
||||
pointer: '',
|
||||
tag: 'TYPE',
|
||||
data: type,
|
||||
tree: [],
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
function eventToGedcom(event: JsonEvent): GedcomEntry[] {
|
||||
const result = [];
|
||||
if (isValidDateOrRange(event)) {
|
||||
@ -524,6 +596,7 @@ function imageToGedcom(
|
||||
function indiToGedcom(
|
||||
indi: JsonIndi,
|
||||
fullSizePhotoUrl: Map<string, string>,
|
||||
personNames: {birth?: string; married?: string; aka?: string},
|
||||
): GedcomEntry {
|
||||
// WikiTree URLs replace spaces with underscores.
|
||||
const escapedId = indi.id.replace(/ /g, '_');
|
||||
@ -532,16 +605,21 @@ function indiToGedcom(
|
||||
pointer: `@${indi.id}@`,
|
||||
tag: 'INDI',
|
||||
data: '',
|
||||
tree: [
|
||||
{
|
||||
level: 1,
|
||||
pointer: '',
|
||||
tag: 'NAME',
|
||||
data: `${indi.firstName || ''} /${indi.lastName || ''}/`,
|
||||
tree: [],
|
||||
},
|
||||
],
|
||||
tree: [],
|
||||
};
|
||||
|
||||
if (personNames.birth) {
|
||||
record.tree.push(nameToGedcom('birth', indi.firstName, personNames.birth));
|
||||
}
|
||||
if (personNames.married) {
|
||||
record.tree.push(
|
||||
nameToGedcom('married', indi.firstName, personNames.married),
|
||||
);
|
||||
}
|
||||
if (personNames.aka) {
|
||||
record.tree.push(nameToGedcom('aka', indi.firstName, personNames.aka));
|
||||
}
|
||||
|
||||
if (indi.birth) {
|
||||
record.tree.push({
|
||||
level: 1,
|
||||
@ -653,11 +731,16 @@ function famToGedcom(fam: JsonFam): GedcomEntry {
|
||||
function buildGedcom(
|
||||
data: JsonGedcomData,
|
||||
fullSizePhotoUrls: Map<string, string>,
|
||||
personNames: Map<string, {birth?: string; married?: string; aka?: string}>,
|
||||
): GedcomData {
|
||||
const gedcomIndis: {[key: string]: GedcomEntry} = {};
|
||||
const gedcomFams: {[key: string]: GedcomEntry} = {};
|
||||
data.indis.forEach((indi) => {
|
||||
gedcomIndis[indi.id] = indiToGedcom(indi, fullSizePhotoUrls);
|
||||
gedcomIndis[indi.id] = indiToGedcom(
|
||||
indi,
|
||||
fullSizePhotoUrls,
|
||||
personNames.get(indi.id) || {},
|
||||
);
|
||||
});
|
||||
data.fams.forEach((fam) => {
|
||||
gedcomFams[fam.id] = famToGedcom(fam);
|
||||
|
||||
@ -11,6 +11,7 @@ import {GedcomEntry} from 'parse-gedcom';
|
||||
import {MultilineText} from './multiline-text';
|
||||
import {TranslatedTag} from './translated-tag';
|
||||
import {Header, Item} from 'semantic-ui-react';
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
import {WrappedImage} from './wrapped-image';
|
||||
|
||||
const EXCLUDED_TAGS = [
|
||||
@ -83,18 +84,27 @@ function noteDetails(entry: GedcomEntry) {
|
||||
}
|
||||
|
||||
function nameDetails(entry: GedcomEntry) {
|
||||
const fullName = entry.data.replaceAll('/', '');
|
||||
|
||||
const nameType = entry.tree.find(
|
||||
(entry) => entry.tag === 'TYPE' && entry.data !== 'Unknown',
|
||||
)?.data;
|
||||
|
||||
return (
|
||||
<Header size="large">
|
||||
{entry.data
|
||||
.split('/')
|
||||
.filter((name) => !!name)
|
||||
.map((name, index) => (
|
||||
<div key={index}>
|
||||
{name}
|
||||
<br />
|
||||
</div>
|
||||
))}
|
||||
</Header>
|
||||
<>
|
||||
<Header as="span" size="large">
|
||||
{fullName ? (
|
||||
fullName
|
||||
) : (
|
||||
<FormattedMessage id="name.unknown_name" defaultMessage="N.N." />
|
||||
)}
|
||||
</Header>
|
||||
{fullName && nameType && (
|
||||
<Item.Meta>
|
||||
<TranslatedTag tag={nameType} />
|
||||
</Item.Meta>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@ import {compareDates, formatDateOrRange} from '../util/date_util';
|
||||
import {DateOrRange, getDate} from 'topola';
|
||||
import {dereference, GedcomData, getData, getName} from '../util/gedcom_util';
|
||||
import {GedcomEntry} from 'parse-gedcom';
|
||||
import {IntlShape, useIntl} from 'react-intl';
|
||||
import {FormattedMessage, IntlShape, useIntl} from 'react-intl';
|
||||
import {Link, useLocation} from 'react-router-dom';
|
||||
import {MultilineText} from './multiline-text';
|
||||
import {pointerToId} from '../util/gedcom_util';
|
||||
@ -16,9 +16,6 @@ function PersonLink(props: {person: GedcomEntry}) {
|
||||
const location = useLocation();
|
||||
|
||||
const name = getName(props.person);
|
||||
if (!name) {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
const search = queryString.parse(location.search);
|
||||
search['indi'] = pointerToId(props.person.pointer);
|
||||
@ -26,7 +23,11 @@ function PersonLink(props: {person: GedcomEntry}) {
|
||||
return (
|
||||
<Item.Meta>
|
||||
<Link to={{pathname: '/view', search: queryString.stringify(search)}}>
|
||||
{name}
|
||||
{name ? (
|
||||
name
|
||||
) : (
|
||||
<FormattedMessage id="name.unknown_name" defaultMessage="N.N." />
|
||||
)}
|
||||
</Link>
|
||||
</Item.Meta>
|
||||
);
|
||||
|
||||
@ -22,6 +22,11 @@ const TAG_DESCRIPTIONS = new Map([
|
||||
['OCCU', 'Occupation'],
|
||||
['TITL', 'Title'],
|
||||
['WWW', 'WWW'],
|
||||
['birth', 'Birth name'],
|
||||
['married', 'Married name'],
|
||||
['maiden', 'Maiden name'],
|
||||
['immigrant', 'Immigrant name'],
|
||||
['aka', 'Also known as'],
|
||||
]);
|
||||
|
||||
interface Props {
|
||||
|
||||
@ -6,10 +6,7 @@ import {FormattedMessage, useIntl} from 'react-intl';
|
||||
import {MenuItem, MenuType} from './menu_item';
|
||||
import {useEffect, useRef, useState} from 'react';
|
||||
import {useHistory, useLocation} from 'react-router';
|
||||
import {
|
||||
getLoggedInUserName,
|
||||
navigateToLoginPage,
|
||||
} from 'wikitree-js';
|
||||
import {getLoggedInUserName, navigateToLoginPage} from 'wikitree-js';
|
||||
|
||||
interface Props {
|
||||
menuType: MenuType;
|
||||
|
||||
@ -55,6 +55,10 @@
|
||||
"gedcom.WWW": "Stránka WWW",
|
||||
"gedcom.RELI": "Vyznání",
|
||||
"gedcom._UPD": "Poslední aktualizace",
|
||||
"gedcom.birth": "Rodinné jméno",
|
||||
"gedcom.married": "Manželské jméno",
|
||||
"gedcom.maiden": "Jméno za svobodna",
|
||||
"gedcom.aka": "Také znám(a) jako",
|
||||
"date.abt": "kolem",
|
||||
"date.cal": "spočteno",
|
||||
"date.est": "asi",
|
||||
|
||||
@ -51,6 +51,10 @@
|
||||
"gedcom.TITL": "Titel",
|
||||
"gedcom.WWW": "Website",
|
||||
"gedcom._UPD": "Zuletzt aktualisiert",
|
||||
"gedcom.birth": "Geburtsname",
|
||||
"gedcom.married": "Ehenamen",
|
||||
"gedcom.maiden": "Mädchenname",
|
||||
"gedcom.aka": "Auch bekannt als",
|
||||
"date.abt": "about",
|
||||
"date.cal": "berechnet",
|
||||
"date.est": "geschätzt",
|
||||
|
||||
@ -50,6 +50,10 @@
|
||||
"gedcom.RIN": "ID",
|
||||
"gedcom.TITL": "Titre",
|
||||
"gedcom.WWW": "Site Web",
|
||||
"gedcom.birth": "Nom de naissance",
|
||||
"gedcom.married": "Nom marital",
|
||||
"gedcom.maiden": "Nom de jeune fille",
|
||||
"gedcom.aka": "Alias",
|
||||
"gedcom._UPD": "Dernière mise à jour",
|
||||
"date.abt": "environ",
|
||||
"date.cal": "calculé",
|
||||
|
||||
@ -53,6 +53,10 @@
|
||||
"gedcom.TITL": "Titolo",
|
||||
"gedcom.WWW": "Sito web",
|
||||
"gedcom._UPD": "Ultimo aggiornamento",
|
||||
"gedcom.birth": "Nome alla nascita",
|
||||
"gedcom.married": "Nome da coniugato/a",
|
||||
"gedcom.maiden": "Nome da nubile",
|
||||
"gedcom.aka": "Conosciuto anche come",
|
||||
"date.abt": "circa",
|
||||
"date.cal": "calcolato",
|
||||
"date.est": "stimato",
|
||||
|
||||
@ -58,6 +58,11 @@
|
||||
"gedcom._UPD": "Ostatnia aktualizacja",
|
||||
"gedcom.MARR": "Małżeństwo",
|
||||
"gedcom.DIV": "Rozwód",
|
||||
"gedcom.birth": "Nazwisko rodowe",
|
||||
"gedcom.married": "Nazwisko po małżeństwie",
|
||||
"gedcom.maiden": "Nazwisko panieńskie",
|
||||
"gedcom.immigrant": "Nazwisko po imigracji",
|
||||
"gedcom.aka": "Alias",
|
||||
"date.abt": "około",
|
||||
"date.cal": "wyliczone",
|
||||
"date.est": "oszacowane",
|
||||
@ -85,5 +90,6 @@
|
||||
"config.colors": "Kolory",
|
||||
"config.colors.NO_COLOR": "brak",
|
||||
"config.colors.COLOR_BY_GENERATION": "według pokolenia",
|
||||
"config.colors.COLOR_BY_SEX": "według płci"
|
||||
"config.colors.COLOR_BY_SEX": "według płci",
|
||||
"name.unknown_name": "N.N."
|
||||
}
|
||||
|
||||
@ -59,6 +59,10 @@
|
||||
"gedcom.TITL": "Титул",
|
||||
"gedcom.WWW": "Веб-сайт WWW",
|
||||
"gedcom._UPD": "Последнее обновление",
|
||||
"gedcom.birth": "Имя при рождении",
|
||||
"gedcom.married": "Имя в браке",
|
||||
"gedcom.maiden": "Девичья фамилия",
|
||||
"gedcom.aka": "Он(а) же",
|
||||
"date.abt": "около",
|
||||
"date.cal": "рассчитано",
|
||||
"date.est": "приблизительно",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user