mirror of
https://github.com/PeWu/topola-viewer.git
synced 2026-02-18 02:55:48 +00:00
Refactored the Events component
Split collecting data from rendering HTML
This commit is contained in:
parent
1a8e9e7edf
commit
6107aef874
@ -1,7 +1,7 @@
|
|||||||
import * as queryString from 'query-string';
|
import * as queryString from 'query-string';
|
||||||
import flatMap from 'array.prototype.flatmap';
|
import flatMap from 'array.prototype.flatmap';
|
||||||
import {calcAge} from '../util/age_util';
|
import {calcAge} from '../util/age_util';
|
||||||
import {compareDates, translateDate} from '../util/date_util';
|
import {compareDates, formatDateOrRange} from '../util/date_util';
|
||||||
import {DateOrRange, getDate} from 'topola';
|
import {DateOrRange, getDate} from 'topola';
|
||||||
import {dereference, GedcomData, getData, getName} from '../util/gedcom_util';
|
import {dereference, GedcomData, getData, getName} from '../util/gedcom_util';
|
||||||
import {GedcomEntry} from 'parse-gedcom';
|
import {GedcomEntry} from 'parse-gedcom';
|
||||||
@ -37,13 +37,13 @@ interface Props {
|
|||||||
entries: GedcomEntry[];
|
entries: GedcomEntry[];
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Event {
|
interface EventData {
|
||||||
type: string;
|
type: string;
|
||||||
date: DateOrRange | undefined;
|
date?: DateOrRange;
|
||||||
header: JSX.Element;
|
age?: string;
|
||||||
subHeader: JSX.Element | null;
|
personLink?: GedcomEntry;
|
||||||
place: JSX.Element | null;
|
place?: string[];
|
||||||
notes: JSX.Element | null;
|
notes: string[][];
|
||||||
}
|
}
|
||||||
|
|
||||||
const EVENT_TAGS = [
|
const EVENT_TAGS = [
|
||||||
@ -59,111 +59,65 @@ const EVENT_TAGS = [
|
|||||||
|
|
||||||
const FAMILY_EVENT_TAGS = ['MARR', 'DIV'];
|
const FAMILY_EVENT_TAGS = ['MARR', 'DIV'];
|
||||||
|
|
||||||
function eventHeader(tag: string, date: GedcomEntry | null, intl: IntlShape) {
|
function EventHeader(props: {event: EventData}) {
|
||||||
|
const intl = useIntl();
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<span style={{textTransform: 'uppercase'}} className="ui small header">
|
<span style={{textTransform: 'uppercase'}} className="ui small header">
|
||||||
<TranslatedTag tag={tag} />
|
<TranslatedTag tag={props.event.type} />
|
||||||
</span>
|
</span>
|
||||||
{date && date.data ? (
|
{props.event.date ? (
|
||||||
<span className="ui sub header right floated">
|
<span className="ui sub header right floated">
|
||||||
{translateDate(date.data, intl)}
|
{formatDateOrRange(props.event.date, intl)}
|
||||||
</span>
|
</span>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function eventFamilyDetails(
|
function getSpouse(indi: string, familyEntry: GedcomEntry, gedcom: GedcomData) {
|
||||||
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))
|
||||||
.find((familySubEntry) => !familySubEntry.data.includes(indi));
|
.find((familySubEntry) => !familySubEntry.data.includes(indi));
|
||||||
|
|
||||||
if (spouseReference) {
|
if (!spouseReference) {
|
||||||
const spouse = dereference(
|
return undefined;
|
||||||
spouseReference,
|
|
||||||
gedcom,
|
|
||||||
(gedcom) => gedcom.indis,
|
|
||||||
);
|
|
||||||
return <PersonLink person={spouse} />;
|
|
||||||
}
|
}
|
||||||
return null;
|
return dereference(spouseReference, gedcom, (gedcom) => gedcom.indis);
|
||||||
}
|
}
|
||||||
|
|
||||||
function eventAdditionalDetails(
|
function getAge(
|
||||||
eventEntry: GedcomEntry,
|
eventEntry: GedcomEntry,
|
||||||
indi: string,
|
indi: string,
|
||||||
gedcom: GedcomData,
|
gedcom: GedcomData,
|
||||||
intl: IntlShape,
|
intl: IntlShape,
|
||||||
) {
|
): string | undefined {
|
||||||
if (eventEntry.tag === 'DEAT') {
|
if (eventEntry.tag !== 'DEAT') {
|
||||||
const deathDate = resolveDate(eventEntry);
|
return undefined;
|
||||||
|
|
||||||
const birthDate = gedcom.indis[indi].tree
|
|
||||||
.filter((indiSubEntry) => indiSubEntry.tag === 'BIRT')
|
|
||||||
.map((birthEvent) => resolveDate(birthEvent))
|
|
||||||
.find((topolaDate) => topolaDate);
|
|
||||||
|
|
||||||
if (birthDate && deathDate) {
|
|
||||||
return (
|
|
||||||
<div className="meta">
|
|
||||||
{calcAge(birthDate?.data, deathDate?.data, intl)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return null;
|
const deathDate = resolveDate(eventEntry);
|
||||||
|
|
||||||
|
const birthDate = gedcom.indis[indi].tree
|
||||||
|
.filter((indiSubEntry) => indiSubEntry.tag === 'BIRT')
|
||||||
|
.map((birthEvent) => resolveDate(birthEvent))
|
||||||
|
.find((topolaDate) => topolaDate);
|
||||||
|
|
||||||
|
if (!birthDate || !deathDate) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return calcAge(birthDate?.data, deathDate?.data, intl);
|
||||||
}
|
}
|
||||||
|
|
||||||
function eventPlace(entry: GedcomEntry) {
|
function eventPlace(entry: GedcomEntry) {
|
||||||
const place = entry.tree.find((subEntry) => subEntry.tag === 'PLAC');
|
const place = entry.tree.find((subEntry) => subEntry.tag === 'PLAC');
|
||||||
if (place && place.data) {
|
return place?.data ? getData(place) : undefined;
|
||||||
return <div className="description">{getData(place)}</div>;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function eventNotes(entry: GedcomEntry, gedcom: GedcomData) {
|
function eventNotes(entry: GedcomEntry, gedcom: GedcomData): string[][] {
|
||||||
const notes = entry.tree
|
return entry.tree
|
||||||
.filter((subentry) => ['NOTE', 'TYPE'].includes(subentry.tag))
|
.filter((subentry) => ['NOTE', 'TYPE'].includes(subentry.tag))
|
||||||
.map((note) => dereference(note, gedcom, (gedcom) => gedcom.other))
|
.map((note) => dereference(note, gedcom, (gedcom) => gedcom.other))
|
||||||
.map((note) => noteDetails(note));
|
.map((note) => getData(note));
|
||||||
|
|
||||||
if (notes && notes.length) {
|
|
||||||
return (
|
|
||||||
<div className="description">
|
|
||||||
{notes.map((note, index) => (
|
|
||||||
<div key={index}>{note}</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function noteDetails(entry: GedcomEntry) {
|
|
||||||
return (
|
|
||||||
<MultilineText
|
|
||||||
lines={getData(entry).map((line, index) => (
|
|
||||||
<i key={index}>{line}</i>
|
|
||||||
))}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function eventDetails(event: Event) {
|
|
||||||
return (
|
|
||||||
<div className="content">
|
|
||||||
{event.header}
|
|
||||||
{event.subHeader}
|
|
||||||
{event.place}
|
|
||||||
{event.notes}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function toEvent(
|
function toEvent(
|
||||||
@ -171,9 +125,9 @@ function toEvent(
|
|||||||
gedcom: GedcomData,
|
gedcom: GedcomData,
|
||||||
indi: string,
|
indi: string,
|
||||||
intl: IntlShape,
|
intl: IntlShape,
|
||||||
): Event[] {
|
): EventData[] {
|
||||||
if (entry.tag === 'FAMS') {
|
if (entry.tag === 'FAMS') {
|
||||||
return toFamilyEvents(entry, gedcom, indi, intl);
|
return toFamilyEvents(entry, gedcom, indi);
|
||||||
}
|
}
|
||||||
return toIndiEvent(entry, gedcom, indi, intl);
|
return toIndiEvent(entry, gedcom, indi, intl);
|
||||||
}
|
}
|
||||||
@ -183,14 +137,13 @@ function toIndiEvent(
|
|||||||
gedcom: GedcomData,
|
gedcom: GedcomData,
|
||||||
indi: string,
|
indi: string,
|
||||||
intl: IntlShape,
|
intl: IntlShape,
|
||||||
): Event[] {
|
): EventData[] {
|
||||||
const date = resolveDate(entry) || null;
|
const date = resolveDate(entry) || null;
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
date: date ? getDate(date.data) : undefined,
|
date: date ? getDate(date.data) : undefined,
|
||||||
type: entry.tag,
|
type: entry.tag,
|
||||||
header: eventHeader(entry.tag, date, intl),
|
age: getAge(entry, indi, gedcom, intl),
|
||||||
subHeader: eventAdditionalDetails(entry, indi, gedcom, intl),
|
|
||||||
place: eventPlace(entry),
|
place: eventPlace(entry),
|
||||||
notes: eventNotes(entry, gedcom),
|
notes: eventNotes(entry, gedcom),
|
||||||
},
|
},
|
||||||
@ -205,8 +158,7 @@ function toFamilyEvents(
|
|||||||
entry: GedcomEntry,
|
entry: GedcomEntry,
|
||||||
gedcom: GedcomData,
|
gedcom: GedcomData,
|
||||||
indi: string,
|
indi: string,
|
||||||
intl: IntlShape,
|
): EventData[] {
|
||||||
): Event[] {
|
|
||||||
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),
|
||||||
@ -215,14 +167,43 @@ function toFamilyEvents(
|
|||||||
return {
|
return {
|
||||||
date: date ? getDate(date.data) : undefined,
|
date: date ? getDate(date.data) : undefined,
|
||||||
type: familyMarriageEvent.tag,
|
type: familyMarriageEvent.tag,
|
||||||
header: eventHeader(familyMarriageEvent.tag, date, intl),
|
personLink: getSpouse(indi, family, gedcom),
|
||||||
subHeader: eventFamilyDetails(indi, family, gedcom),
|
|
||||||
place: eventPlace(familyMarriageEvent),
|
place: eventPlace(familyMarriageEvent),
|
||||||
notes: eventNotes(familyMarriageEvent, gedcom),
|
notes: eventNotes(familyMarriageEvent, gedcom),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function Event(props: {event: EventData}) {
|
||||||
|
return (
|
||||||
|
<div className="ui attached item">
|
||||||
|
<div className="content">
|
||||||
|
<EventHeader event={props.event} />
|
||||||
|
{!!props.event.age && <div className="meta">{props.event.age}</div>}
|
||||||
|
{!!props.event.personLink && (
|
||||||
|
<PersonLink person={props.event.personLink} />
|
||||||
|
)}
|
||||||
|
{!!props.event.place && (
|
||||||
|
<div className="description">{props.event.place}</div>
|
||||||
|
)}
|
||||||
|
{!!props.event.notes.length && (
|
||||||
|
<div className="description">
|
||||||
|
{props.event.notes.map((note, index) => (
|
||||||
|
<div key={index}>
|
||||||
|
<MultilineText
|
||||||
|
lines={note.map((line, index) => (
|
||||||
|
<i key={index}>{line}</i>
|
||||||
|
))}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export function Events(props: Props) {
|
export function Events(props: Props) {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
@ -231,16 +212,13 @@ export function Events(props: Props) {
|
|||||||
.filter((entry) => entry.tag === tag)
|
.filter((entry) => entry.tag === 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)),
|
||||||
.map((event) => eventDetails(event)),
|
|
||||||
);
|
);
|
||||||
if (events && events.length) {
|
if (events.length) {
|
||||||
return (
|
return (
|
||||||
<div className="ui segment divided items">
|
<div className="ui segment divided items">
|
||||||
{events.map((eventElement, index) => (
|
{events.map((event, index) => (
|
||||||
<div className="ui attached item" key={index}>
|
<Event event={event} key={index} />
|
||||||
{eventElement}
|
|
||||||
</div>
|
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user