Support for all event types (#212)

This commit is contained in:
czifumasa 2025-09-04 22:58:04 +02:00 committed by GitHub
parent 4d468b8d2e
commit 4d05cd9448
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 169 additions and 48 deletions

View File

@ -12,20 +12,14 @@ import {
mapToSource, mapToSource,
} from '../util/gedcom_util'; } from '../util/gedcom_util';
import {AdditionalFiles} from './additional-files'; import {AdditionalFiles} from './additional-files';
import {Events} from './events'; import {ALL_SUPPORTED_EVENT_TYPES, Events} from './events';
import {MultilineText} from './multiline-text'; import {MultilineText} from './multiline-text';
import {Sources} from './sources'; import {Sources} from './sources';
import {TranslatedTag} from './translated-tag'; import {TranslatedTag} from './translated-tag';
import {WrappedImage} from './wrapped-image'; import {WrappedImage} from './wrapped-image';
const EXCLUDED_TAGS = [ const EXCLUDED_TAGS = [
'BIRT', ...ALL_SUPPORTED_EVENT_TYPES,
'BAPM',
'CHR',
'EVEN',
'CENS',
'DEAT',
'BURI',
'NAME', 'NAME',
'SEX', 'SEX',
'FAMC', 'FAMC',

View File

@ -18,6 +18,7 @@ import {
mapToSource, mapToSource,
pointerToId, pointerToId,
resolveDate, resolveDate,
resolveType,
Source, Source,
} from '../util/gedcom_util'; } from '../util/gedcom_util';
import {FileEntry} from './additional-files'; import {FileEntry} from './additional-files';
@ -52,7 +53,8 @@ interface Props {
} }
interface EventData { interface EventData {
type: string; tag: string;
type?: string;
date?: DateOrRange; date?: DateOrRange;
age?: string; age?: string;
personLink?: GedcomEntry; personLink?: GedcomEntry;
@ -64,25 +66,73 @@ interface EventData {
indi: string; indi: string;
} }
const EVENT_TAGS = [ const BIRTH_EVENT_TAGS = ['BIRT'];
'BIRT', const INDI_EVENT_TAGS = [
'ADOP',
'BAPM', 'BAPM',
'CHR', 'BARM',
'FAMS', 'BASM',
'EVEN', 'BLES',
'CENS', 'CENS',
'DEAT', 'CHR',
'BURI', 'CHRA',
'CONF',
'EDUC',
'EMIG',
'EVEN',
'FAMS',
'FCOM',
'GRAD',
'IMMI',
'NATU',
'ORDN',
'OCCU',
'PROP',
'RESI',
'RETI',
'WILL',
'_DEG',
'_ELEC',
'_MDCL',
'_MILT',
]; ];
const FAMILY_EVENT_TAGS = ['MARR', 'DIV']; const FAMILY_EVENT_TAGS = [
'ANUL',
'CENS',
'DIV',
'DIVF',
'ENGA',
'EVEN',
'MARB',
'MARC',
'MARL',
'MARR',
'MARS',
];
const LIFE_EVENT_TAGS = [...INDI_EVENT_TAGS, ...FAMILY_EVENT_TAGS];
const DEATH_EVENT_TAGS = ['DEAT'];
const AFTER_DEATH_EVENT_TAGS = ['BURI', 'CREM', 'PROB'];
const SORTED_EVENT_TYPE_GROUPS = [
BIRTH_EVENT_TAGS,
LIFE_EVENT_TAGS,
DEATH_EVENT_TAGS,
AFTER_DEATH_EVENT_TAGS,
];
export const ALL_SUPPORTED_EVENT_TYPES = [
...BIRTH_EVENT_TAGS,
...LIFE_EVENT_TAGS,
...DEATH_EVENT_TAGS,
...AFTER_DEATH_EVENT_TAGS,
];
function EventHeader(props: {event: EventData}) { function EventHeader(props: {event: EventData}) {
const intl = useIntl(); const intl = useIntl();
return ( return (
<div className="item-header"> <div className="item-header">
<Header as="span" size="small"> <Header as="span" size="small">
<TranslatedTag tag={props.event.type} /> <TranslatedTag tag={getEventTitle(props.event)} />
</Header> </Header>
{props.event.date ? ( {props.event.date ? (
<Header as="span" textAlign="right" sub> <Header as="span" textAlign="right" sub>
@ -93,6 +143,13 @@ function EventHeader(props: {event: EventData}) {
); );
} }
function getEventTitle(event: EventData) {
if (event.tag === 'EVEN' && event.type) {
return event.type;
}
return event.tag;
}
function getSpouse(indi: string, familyEntry: GedcomEntry, gedcom: GedcomData) { function getSpouse(indi: string, familyEntry: GedcomEntry, gedcom: GedcomData) {
const spouseReference = familyEntry.tree const spouseReference = familyEntry.tree
.filter((familySubEntry) => ['WIFE', 'HUSB'].includes(familySubEntry.tag)) .filter((familySubEntry) => ['WIFE', 'HUSB'].includes(familySubEntry.tag))
@ -110,13 +167,13 @@ function getAge(
gedcom: GedcomData, gedcom: GedcomData,
intl: IntlShape, intl: IntlShape,
): string | undefined { ): string | undefined {
if (eventEntry.tag !== 'DEAT') { if (!DEATH_EVENT_TAGS.includes(eventEntry.tag)) {
return undefined; return undefined;
} }
const deathDate = resolveDate(eventEntry); const deathDate = resolveDate(eventEntry);
const birthDate = gedcom.indis[indi].tree const birthDate = gedcom.indis[indi].tree
.filter((indiSubEntry) => indiSubEntry.tag === 'BIRT') .filter((indiSubEntry) => BIRTH_EVENT_TAGS.includes(indiSubEntry.tag))
.map((birthEvent) => resolveDate(birthEvent)) .map((birthEvent) => resolveDate(birthEvent))
.find((topolaDate) => topolaDate); .find((topolaDate) => topolaDate);
@ -176,10 +233,25 @@ function eventSources(entry: GedcomEntry, gedcom: GedcomData): Source[] {
} }
function eventNotes(entry: GedcomEntry, gedcom: GedcomData): string[][] { function eventNotes(entry: GedcomEntry, gedcom: GedcomData): string[][] {
return entry.tree const externalNotes = entry.tree
.filter((subentry) => ['NOTE', 'TYPE'].includes(subentry.tag)) .filter((subEntry) => subEntry.tag === 'NOTE')
.map((note) => dereference(note, gedcom, (gedcom) => gedcom.other)) .map((note) => dereference(note, gedcom, (gedcom) => gedcom.other));
.map((note) => getData(note));
//for generic 'EVEN' tag 'TYPE is mandatory and is part of the header, for other types it can be worth it to display it as a note
const type =
entry.tag !== 'EVEN'
? entry.tree.filter((subEntry) => subEntry.tag === 'TYPE')
: [];
//entry.data contains event description, so it's also displayed in notes section
return (
[entry, ...type, ...externalNotes]
.filter((entry) => !!entry.data)
/* In Gedcom 'Y' only indicates event occurred, but it doesn't contain any valuable information
like place, date or description, so it should be omitted when fetching entry data. */
.filter((entry) => entry.data !== 'Y')
.map((note) => getData(note))
);
} }
function toEvent( function toEvent(
@ -203,8 +275,9 @@ function toIndiEvent(
const date = resolveDate(entry) || null; const date = resolveDate(entry) || null;
return [ return [
{ {
tag: entry.tag,
date: date ? getDate(date.data) : undefined, date: date ? getDate(date.data) : undefined,
type: entry.tag, type: resolveType(entry),
age: getAge(entry, indi, gedcom, intl), age: getAge(entry, indi, gedcom, intl),
place: eventPlace(entry), place: eventPlace(entry),
images: eventImages(entry, gedcom), images: eventImages(entry, gedcom),
@ -224,17 +297,18 @@ function toFamilyEvents(
const family = dereference(entry, gedcom, (gedcom) => gedcom.fams); const family = dereference(entry, gedcom, (gedcom) => gedcom.fams);
return flatMap(FAMILY_EVENT_TAGS, (tag) => return flatMap(FAMILY_EVENT_TAGS, (tag) =>
family.tree.filter((entry) => entry.tag === tag), family.tree.filter((entry) => entry.tag === tag),
).map((familyMarriageEvent) => { ).map((familyEvent) => {
const date = resolveDate(familyMarriageEvent) || null; const date = resolveDate(familyEvent) || null;
return { return {
tag: familyEvent.tag,
date: date ? getDate(date.data) : undefined, date: date ? getDate(date.data) : undefined,
type: familyMarriageEvent.tag, type: resolveType(familyEvent),
personLink: getSpouse(indi, family, gedcom), personLink: getSpouse(indi, family, gedcom),
place: eventPlace(familyMarriageEvent), place: eventPlace(familyEvent),
images: eventImages(familyMarriageEvent, gedcom), images: eventImages(familyEvent, gedcom),
files: eventFiles(familyMarriageEvent, gedcom), files: eventFiles(familyEvent, gedcom),
notes: eventNotes(familyMarriageEvent, gedcom), notes: eventNotes(familyEvent, gedcom),
sources: eventSources(familyMarriageEvent, gedcom), sources: eventSources(familyEvent, gedcom),
indi: indi, indi: indi,
}; };
}); });
@ -267,9 +341,9 @@ function Event(props: {event: EventData}) {
export function Events(props: Props) { export function Events(props: Props) {
const intl = useIntl(); const intl = useIntl();
const events = flatMap(EVENT_TAGS, (tag) => const events = flatMap(SORTED_EVENT_TYPE_GROUPS, (eventTypeGroup) =>
props.entries props.entries
.filter((entry) => entry.tag === tag) .filter((entry) => eventTypeGroup.includes(entry.tag))
.map((eventEntry) => toEvent(eventEntry, props.gedcom, props.indi, intl)) .map((eventEntry) => toEvent(eventEntry, props.gedcom, props.indi, intl))
.flatMap((events) => events) .flatMap((events) => events)
.sort((event1, event2) => compareDates(event1.date, event2.date)), .sort((event1, event2) => compareDates(event1.date, event2.date)),

View File

@ -3,27 +3,49 @@ import {FormattedMessage} from 'react-intl';
const TAG_DESCRIPTIONS = new Map([ const TAG_DESCRIPTIONS = new Map([
['ADOP', 'Adoption'], ['ADOP', 'Adoption'],
['BAPM', 'Baptism'], ['BAPM', 'Baptism'],
['BARM', 'Bar Mitzvah'],
['BASM', 'Bas Mitzvah'],
['BIRT', 'Birth'], ['BIRT', 'Birth'],
['BLES', 'Blessing'],
['BURI', 'Burial'], ['BURI', 'Burial'],
['CENS', 'Census'], ['CENS', 'Census'],
['CHR', 'Christening'], ['CHR', 'Christening'],
['CHRA', 'Adult christening'],
['CONF', 'Confirmation'],
['CREM', 'Cremation'], ['CREM', 'Cremation'],
['DEAT', 'Death'], ['DEAT', 'Death'],
['DEG', 'Degree'],
['DIV', 'Divorce'],
['DIVF', 'Divorce filed'],
['EDUC', 'Education'], ['EDUC', 'Education'],
['ELEC', 'Elected'],
['EMAIL', 'E-mail'], ['EMAIL', 'E-mail'],
['EMIG', 'Emigration'], ['EMIG', 'Emigration'],
['ENGA', 'Engagement'],
['EVEN', 'Event'], ['EVEN', 'Event'],
['FACT', 'Fact'], ['FACT', 'Fact'],
['FCOM', 'First communion'],
['GRAD', 'Graduation'],
['IMMI', 'Immigration'], ['IMMI', 'Immigration'],
['MARB', 'Marriage bann'],
['MARC', 'Marriage contract'],
['MARL', 'Marriage license'],
['MARR', 'Marriage'], ['MARR', 'Marriage'],
['DIV', 'Divorce'], ['MARS', 'Marriage settlement'],
['MDCL', 'Medical info'],
['MILT', 'Military services'], ['MILT', 'Military services'],
['NATU', 'Naturalization'], ['NATU', 'Naturalization'],
['OCCU', 'Occupation'],
['TITL', 'Title'],
['WWW', 'WWW'],
['OBJE', 'Additional files'], ['OBJE', 'Additional files'],
['OCCU', 'Occupation'],
['ORDN', 'Ordination'],
['PROB', 'Probate'],
['PROP', 'Property'],
['RESI', 'Residence'],
['RETI', 'Retirement'],
['SOUR', 'Sources'], ['SOUR', 'Sources'],
['TITL', 'Title'],
['WILL', 'Will'],
['WWW', 'WWW'],
['birth', 'Birth name'], ['birth', 'Birth name'],
['married', 'Married name'], ['married', 'Married name'],
['maiden', 'Maiden name'], ['maiden', 'Maiden name'],

View File

@ -39,27 +39,54 @@
"select_wikitree_id.comment": "Wpisz identyfikator profilu {wikiTreeLink}. Przykłady: {example1}, {example2}", "select_wikitree_id.comment": "Wpisz identyfikator profilu {wikiTreeLink}. Przykłady: {example1}, {example2}",
"select_wikitree_id.cancel": "Anuluj", "select_wikitree_id.cancel": "Anuluj",
"select_wikitree_id.load": "Otwórz", "select_wikitree_id.load": "Otwórz",
"gedcom.ADOP": "Adopcja",
"gedcom.BAPM": "Chrzest", "gedcom.BAPM": "Chrzest",
"gedcom.BARM": "Bar Micwa",
"gedcom.BASM": "Bat Micwa",
"gedcom.BIRT": "Narodziny", "gedcom.BIRT": "Narodziny",
"gedcom.BLES": "Błogosławieństwo",
"gedcom.BURI": "Pogrzeb", "gedcom.BURI": "Pogrzeb",
"gedcom.CENS": "Spis ludności", "gedcom.CENS": "Spis ludności",
"gedcom.CHR": "Chrzest", "gedcom.CHR": "Chrzest",
"gedcom.CHRA": "Chrzest dorosłych",
"gedcom.CONF": "Bierzmowanie",
"gedcom.CREM": "Kremacja",
"gedcom.DEAT": "Śmierć", "gedcom.DEAT": "Śmierć",
"gedcom.DEG": "Stopień naukowy",
"gedcom.DIV": "Rozwód",
"gedcom.DIVF": "Wniesienie pozwu o rozwód",
"gedcom.DSCR": "Opis", "gedcom.DSCR": "Opis",
"gedcom.EDUC": "Wykształcenie", "gedcom.EDUC": "Wykształcenie",
"gedcom.ELEC": "Wybór na stanowisko",
"gedcom.EMAIL": "E-mail", "gedcom.EMAIL": "E-mail",
"gedcom.EMIG": "Emigracja",
"gedcom.ENGA": "Zaręczyny",
"gedcom.EVEN": "Wydarzenie", "gedcom.EVEN": "Wydarzenie",
"gedcom.FACT": "Fakt", "gedcom.FACT": "Fakt",
"gedcom.MILT": "Służba wojskowa", "gedcom.FCOM": "Pierwsza komunia",
"gedcom.OCCU": "Zawód", "gedcom.GRAD": "Ukończenie szkoły",
"gedcom.RIN": "ID", "gedcom.IMMI": "Imigracja",
"gedcom.TITL": "Tytuł", "gedcom.MARB": "Zapowiedzi małżeńskie",
"gedcom.WWW": "Strona WWW", "gedcom.MARC": "Kontrakt małżeński",
"gedcom.OBJE": "Dodatkowe pliki", "gedcom.MARL": "Licencja małżeńska",
"gedcom.SOUR": "Źródła",
"gedcom._UPD": "Ostatnia aktualizacja",
"gedcom.MARR": "Małżeństwo", "gedcom.MARR": "Małżeństwo",
"gedcom.DIV": "Rozwód", "gedcom.MARS": "Ugoda małżeńska",
"gedcom.MDCL": "Informacje medyczne",
"gedcom.MILT": "Służba wojskowa",
"gedcom.NATU": "Nadanie obywatelstwa",
"gedcom.OBJE": "Dodatkowe pliki",
"gedcom.OCCU": "Zawód",
"gedcom.ORDN": "Święcenia",
"gedcom.PROB": "Postępowanie spadkowe",
"gedcom.PROP": "Nieruchomość",
"gedcom.RESI": "Miejsce zamieszkania",
"gedcom.RETI": "Emerytura",
"gedcom.RIN": "ID",
"gedcom.SOUR": "Źródła",
"gedcom.TITL": "Tytuł",
"gedcom.WILL": "Testament",
"gedcom.WWW": "Strona WWW",
"gedcom._UPD": "Ostatnia aktualizacja",
"gedcom.birth": "Nazwisko rodowe", "gedcom.birth": "Nazwisko rodowe",
"gedcom.married": "Nazwisko po małżeństwie", "gedcom.married": "Nazwisko po małżeństwie",
"gedcom.maiden": "Nazwisko panieńskie", "gedcom.maiden": "Nazwisko panieńskie",

View File

@ -332,6 +332,10 @@ export function resolveDate(entry: GedcomEntry) {
return entry.tree.find((subEntry) => subEntry.tag === 'DATE'); return entry.tree.find((subEntry) => subEntry.tag === 'DATE');
} }
export function resolveType(entry: GedcomEntry) {
return entry.tree.find((subEntry) => subEntry.tag === 'TYPE')?.data;
}
export function mapToSource( export function mapToSource(
sourceEntryReference: GedcomEntry, sourceEntryReference: GedcomEntry,
gedcom: GedcomData, gedcom: GedcomData,