mirror of
https://github.com/PeWu/topola-viewer.git
synced 2026-02-18 02:55:48 +00:00
Implement age calculation for death event (#80)
This commit is contained in:
parent
6b030a1ccc
commit
0b8084e3bc
@ -1,5 +1,6 @@
|
|||||||
import flatMap from 'array.prototype.flatmap';
|
import flatMap from 'array.prototype.flatmap';
|
||||||
import {compareDates, translateDate} from '../util/date_util';
|
import {compareDates, translateDate} from '../util/date_util';
|
||||||
|
import {calcAge} from '../util/age_util';
|
||||||
import {DateOrRange, getDate} from 'topola';
|
import {DateOrRange, getDate} from 'topola';
|
||||||
import {dereference, GedcomData, getData} from '../util/gedcom_util';
|
import {dereference, GedcomData, getData} from '../util/gedcom_util';
|
||||||
import {GedcomEntry} from 'parse-gedcom';
|
import {GedcomEntry} from 'parse-gedcom';
|
||||||
@ -80,6 +81,31 @@ function eventFamilyDetails(
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function eventAdditionalDetails(
|
||||||
|
eventEntry: GedcomEntry,
|
||||||
|
indi: string,
|
||||||
|
gedcom: GedcomData,
|
||||||
|
intl: IntlShape,
|
||||||
|
) {
|
||||||
|
if (eventEntry.tag === 'DEAT') {
|
||||||
|
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 (
|
||||||
|
<div className="meta">
|
||||||
|
{calcAge(birthDate?.data, deathDate?.data, intl)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
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) {
|
if (place && place.data) {
|
||||||
@ -151,7 +177,7 @@ function toIndiEvent(
|
|||||||
date: date ? getDate(date.data) : undefined,
|
date: date ? getDate(date.data) : undefined,
|
||||||
type: entry.tag,
|
type: entry.tag,
|
||||||
header: eventHeader(entry.tag, date, intl),
|
header: eventHeader(entry.tag, date, intl),
|
||||||
subHeader: null,
|
subHeader: eventAdditionalDetails(entry, indi, gedcom, intl),
|
||||||
place: eventPlace(entry),
|
place: eventPlace(entry),
|
||||||
notes: eventNotes(entry, gedcom),
|
notes: eventNotes(entry, gedcom),
|
||||||
},
|
},
|
||||||
|
|||||||
@ -65,6 +65,10 @@
|
|||||||
"date.after": "po {from}",
|
"date.after": "po {from}",
|
||||||
"date.before": "przed {to}",
|
"date.before": "przed {to}",
|
||||||
"error.error": "Błąd",
|
"error.error": "Błąd",
|
||||||
|
"age.exact": "{age, plural, =0 {Mniej niż 1 rok} one {{qualifier} 1 rok} many {{qualifier} # lat} other {{qualifier} # lata}}",
|
||||||
|
"age.less": "Mniej niż {age, plural, =0 {1 rok} one {1 rok} many {# lat} other {# lata}}",
|
||||||
|
"age.more": "Więcej niż {age, plural, =0 {0 lat} one {1 rok} many {# lat} other {# lata}}",
|
||||||
|
"age.between": "Między {ageFrom} a {ageTo, plural, =0 {0 lat} one {1 rok} many {# lat} other {# lata}}",
|
||||||
"error.failed_pdf": "Nie udało się utworzyć pliku PDF. Spróbuj jeszcze raz z mniejszym diagramem lub pobierz plik SVG.",
|
"error.failed_pdf": "Nie udało się utworzyć pliku PDF. Spróbuj jeszcze raz z mniejszym diagramem lub pobierz plik SVG.",
|
||||||
"error.failed_png": "Nie udało się utworzyć pliku PNG. Spróbuj jeszcze raz z mniejszym diagramem lub pobierz plik SVG.",
|
"error.failed_png": "Nie udało się utworzyć pliku PNG. Spróbuj jeszcze raz z mniejszym diagramem lub pobierz plik SVG.",
|
||||||
"error.failed_to_load_file": "Błąd wczytywania pliku",
|
"error.failed_to_load_file": "Błąd wczytywania pliku",
|
||||||
|
|||||||
120
src/util/age_util.spec.ts
Normal file
120
src/util/age_util.spec.ts
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
import expect from 'expect';
|
||||||
|
import {createIntl} from 'react-intl';
|
||||||
|
import {calcAge} from './age_util';
|
||||||
|
|
||||||
|
const intl = createIntl({
|
||||||
|
locale: 'en',
|
||||||
|
messages: {},
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('calcAge()', () => {
|
||||||
|
it('age 1 year', () => {
|
||||||
|
const age = calcAge('1999', '2000', intl);
|
||||||
|
expect(age).toEqual('1 year');
|
||||||
|
});
|
||||||
|
it('age multiple years', () => {
|
||||||
|
const age = calcAge('1999', '2003', intl);
|
||||||
|
expect(age).toEqual('4 years');
|
||||||
|
});
|
||||||
|
it('0 years as Less than 1 year', () => {
|
||||||
|
const age = calcAge('1 Sep 1990', '1 Oct 1990', intl);
|
||||||
|
expect(age).toEqual('Less than 1 year');
|
||||||
|
});
|
||||||
|
it('age with qualifier', () => {
|
||||||
|
const age = calcAge('ABT 1990', '2021', intl);
|
||||||
|
expect(age).toEqual('about 31 years');
|
||||||
|
});
|
||||||
|
it('age for full dates', () => {
|
||||||
|
const age = calcAge('1 Sep 1990', '1 Sep 2021', intl);
|
||||||
|
expect(age).toEqual('31 years');
|
||||||
|
});
|
||||||
|
it('age with round down respecting leap years', () => {
|
||||||
|
const age = calcAge('2 Sep 1990', '1 Sep 2021', intl);
|
||||||
|
expect(age).toEqual('30 years');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('age with exact and range between', () => {
|
||||||
|
const age = calcAge('1990', 'BET 2020 AND 2021', intl);
|
||||||
|
expect(age).toEqual('Between 30 and 31 years');
|
||||||
|
});
|
||||||
|
it('age with exact and range after', () => {
|
||||||
|
const age = calcAge('1990', 'AFT 2021', intl);
|
||||||
|
expect(age).toEqual('More than 31 years');
|
||||||
|
});
|
||||||
|
it('age with exact and range before', () => {
|
||||||
|
const age = calcAge('1990', 'BEF 2021', intl);
|
||||||
|
expect(age).toEqual('Less than 31 years');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('age with range between and exact', () => {
|
||||||
|
const age = calcAge('BET 1990 AND 1991', '2021', intl);
|
||||||
|
expect(age).toEqual('Between 30 and 31 years');
|
||||||
|
});
|
||||||
|
it('age with 2 ranges between', () => {
|
||||||
|
const age = calcAge('BET 1990 AND 1991', 'BET 2020 AND 2021', intl);
|
||||||
|
expect(age).toEqual('Between 29 and 31 years');
|
||||||
|
});
|
||||||
|
it('age with range between and range after', () => {
|
||||||
|
const age = calcAge('BET 1990 AND 1991', 'AFT 2021', intl);
|
||||||
|
expect(age).toEqual('More than 30 years');
|
||||||
|
});
|
||||||
|
it('age with range between and range before', () => {
|
||||||
|
const age = calcAge('BET 1990 AND 1991', 'BEF 2021', intl);
|
||||||
|
expect(age).toEqual('Less than 31 years');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('age with range after and exact', () => {
|
||||||
|
const age = calcAge('AFT 1990', '2021', intl);
|
||||||
|
expect(age).toEqual('Less than 31 years');
|
||||||
|
});
|
||||||
|
it('age with range after and range between', () => {
|
||||||
|
const age = calcAge('AFT 1990', 'BET 2020 AND 2021', intl);
|
||||||
|
expect(age).toEqual('Less than 31 years');
|
||||||
|
});
|
||||||
|
it('age with range after and before', () => {
|
||||||
|
const age = calcAge('AFT 1990', 'BEF 2021', intl);
|
||||||
|
expect(age).toEqual('Less than 31 years');
|
||||||
|
});
|
||||||
|
it('age with 2 ranges after cannot be calculated', () => {
|
||||||
|
const age = calcAge('AFT 1990', 'AFT 2021', intl);
|
||||||
|
expect(age).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('age with range before and exact', () => {
|
||||||
|
const age = calcAge('BEF 1990', '2021', intl);
|
||||||
|
expect(age).toEqual('More than 31 years');
|
||||||
|
});
|
||||||
|
it('age with ranges before and between', () => {
|
||||||
|
const age = calcAge('BEF 1990', 'BET 2020 AND 2021', intl);
|
||||||
|
expect(age).toEqual('More than 30 years');
|
||||||
|
});
|
||||||
|
it('age with ranges before and after', () => {
|
||||||
|
const age = calcAge('BEF 1990', 'AFT 2021', intl);
|
||||||
|
expect(age).toEqual('More than 31 years');
|
||||||
|
});
|
||||||
|
it('age with 2 ranges before cannot be calculated', () => {
|
||||||
|
const age = calcAge('BEF 1990', 'BEF 2021', intl);
|
||||||
|
expect(age).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('age with death before birth cannot be calculated', () => {
|
||||||
|
const age = calcAge('2021', '1990', intl);
|
||||||
|
expect(age).toBeUndefined();
|
||||||
|
});
|
||||||
|
it('age with overlapping between ranges cannot be calculated', () => {
|
||||||
|
const age = calcAge('BET 1990 AND 2000', 'BET 1999 AND 2021 ', intl);
|
||||||
|
expect(age).toBeUndefined();
|
||||||
|
});
|
||||||
|
it('age with invalid between range cannot be calculated', () => {
|
||||||
|
const age = calcAge('BET 1999 AND 1990', ' 2021 ', intl);
|
||||||
|
expect(age).toBeUndefined();
|
||||||
|
});
|
||||||
|
it('age without birth cannot be calculated', () => {
|
||||||
|
const age = calcAge('', '2021', intl);
|
||||||
|
expect(age).toBeUndefined();
|
||||||
|
});
|
||||||
|
it('age without death cannot be calculated', () => {
|
||||||
|
const age = calcAge('1990', '', intl);
|
||||||
|
expect(age).toBeUndefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
242
src/util/age_util.ts
Normal file
242
src/util/age_util.ts
Normal file
@ -0,0 +1,242 @@
|
|||||||
|
import {Date as TopolaDate} from 'topola/dist/data';
|
||||||
|
import {IntlShape} from 'react-intl';
|
||||||
|
import {DateOrRange, getDate} from 'topola';
|
||||||
|
import {
|
||||||
|
areDateRangesOverlapped,
|
||||||
|
compareDates,
|
||||||
|
formatDateQualifier,
|
||||||
|
isDateRangeClosed,
|
||||||
|
isValidDateOrRange,
|
||||||
|
toDateObject,
|
||||||
|
} from './date_util';
|
||||||
|
|
||||||
|
function formatExactAge(
|
||||||
|
birthDate: TopolaDate,
|
||||||
|
deathDate: TopolaDate,
|
||||||
|
intl: IntlShape,
|
||||||
|
): string {
|
||||||
|
const ageInYears = calcDateDifferenceInYears(birthDate, deathDate);
|
||||||
|
const qualifier = birthDate.qualifier || deathDate.qualifier;
|
||||||
|
const translatedQualifier =
|
||||||
|
qualifier && formatDateQualifier(qualifier, intl) + ' ';
|
||||||
|
|
||||||
|
return intl.formatMessage(
|
||||||
|
{
|
||||||
|
id: 'age.exact',
|
||||||
|
defaultMessage:
|
||||||
|
'{qualifier}{age, plural, =0 {Less than 1 year} one {1 year} other {# years}}',
|
||||||
|
},
|
||||||
|
{age: ageInYears, qualifier: translatedQualifier},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatAgeMoreThan(
|
||||||
|
birthDate: TopolaDate,
|
||||||
|
deathDate: TopolaDate,
|
||||||
|
intl: IntlShape,
|
||||||
|
): string {
|
||||||
|
const ageInYears = calcDateDifferenceInYears(birthDate, deathDate);
|
||||||
|
return intl.formatMessage(
|
||||||
|
{
|
||||||
|
id: 'age.more',
|
||||||
|
defaultMessage:
|
||||||
|
'More than {age, plural, =0 {0 years} one {1 year} other {# years}}',
|
||||||
|
},
|
||||||
|
{age: ageInYears},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatAgeLessThan(
|
||||||
|
birthDate: TopolaDate,
|
||||||
|
deathDate: TopolaDate,
|
||||||
|
intl: IntlShape,
|
||||||
|
): string {
|
||||||
|
const ageInYears = calcDateDifferenceInYears(birthDate, deathDate);
|
||||||
|
return intl.formatMessage(
|
||||||
|
{
|
||||||
|
id: 'age.less',
|
||||||
|
defaultMessage:
|
||||||
|
'Less than {age, plural, =0 {1 year} one {1 year} other {# years}}',
|
||||||
|
},
|
||||||
|
{age: ageInYears},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatAgeBetween(
|
||||||
|
birthDateFrom: TopolaDate,
|
||||||
|
birthDateTo: TopolaDate,
|
||||||
|
deathDateFrom: TopolaDate,
|
||||||
|
deathDateTo: TopolaDate,
|
||||||
|
intl: IntlShape,
|
||||||
|
): string {
|
||||||
|
const ageInYearsFrom = calcDateDifferenceInYears(birthDateTo, deathDateFrom);
|
||||||
|
const ageInYearsTo = calcDateDifferenceInYears(birthDateFrom, deathDateTo);
|
||||||
|
return intl.formatMessage(
|
||||||
|
{
|
||||||
|
id: 'age.between',
|
||||||
|
defaultMessage:
|
||||||
|
'Between {ageFrom} and {ageTo, plural, =0 {0 years} one {1 year} other {# years}}',
|
||||||
|
},
|
||||||
|
{ageFrom: ageInYearsFrom, ageTo: ageInYearsTo},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function canCalculateAge(
|
||||||
|
birthDate: DateOrRange | undefined,
|
||||||
|
deathDate: DateOrRange | undefined,
|
||||||
|
): boolean {
|
||||||
|
if (birthDate && deathDate) {
|
||||||
|
// cannot calculate if there is no valid birth or death date
|
||||||
|
if (!isValidDateOrRange(birthDate) || !isValidDateOrRange(deathDate)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//cannot calculate if death date is before birth date
|
||||||
|
if (compareDates(birthDate, deathDate) > 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// cannot calculate if closed date range for birth or death are overlapping
|
||||||
|
if (
|
||||||
|
birthDate.dateRange &&
|
||||||
|
deathDate.dateRange &&
|
||||||
|
isDateRangeClosed(birthDate?.dateRange) &&
|
||||||
|
isDateRangeClosed(deathDate?.dateRange)
|
||||||
|
) {
|
||||||
|
return !areDateRangesOverlapped(birthDate.dateRange, deathDate.dateRange);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function calcDateDifferenceInYears(
|
||||||
|
firstDate: TopolaDate,
|
||||||
|
secondDate: TopolaDate,
|
||||||
|
): number {
|
||||||
|
const firstDateObject = toDateObject(firstDate);
|
||||||
|
const secondDateObject = toDateObject(secondDate);
|
||||||
|
|
||||||
|
const dateDiff = new Date(
|
||||||
|
secondDateObject.valueOf() - firstDateObject.valueOf(),
|
||||||
|
);
|
||||||
|
return Math.abs(dateDiff.getUTCFullYear() - 1970);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function calcAge(
|
||||||
|
birthGedcomDate: string | undefined,
|
||||||
|
deathGedcomDate: string | undefined,
|
||||||
|
intl: IntlShape,
|
||||||
|
): string | undefined {
|
||||||
|
if (birthGedcomDate && deathGedcomDate) {
|
||||||
|
const birthDateOrRange = getDate(birthGedcomDate);
|
||||||
|
const deathDateOrRange = getDate(deathGedcomDate);
|
||||||
|
if (canCalculateAge(birthDateOrRange, deathDateOrRange)) {
|
||||||
|
if (birthDateOrRange?.date) {
|
||||||
|
if (deathDateOrRange?.date) {
|
||||||
|
return formatExactAge(
|
||||||
|
birthDateOrRange.date,
|
||||||
|
deathDateOrRange.date,
|
||||||
|
intl,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
deathDateOrRange?.dateRange?.from &&
|
||||||
|
deathDateOrRange.dateRange?.to
|
||||||
|
) {
|
||||||
|
return formatAgeBetween(
|
||||||
|
birthDateOrRange.date,
|
||||||
|
birthDateOrRange.date,
|
||||||
|
deathDateOrRange?.dateRange?.from,
|
||||||
|
deathDateOrRange?.dateRange?.to,
|
||||||
|
intl,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (deathDateOrRange?.dateRange?.from) {
|
||||||
|
return formatAgeMoreThan(
|
||||||
|
birthDateOrRange.date,
|
||||||
|
deathDateOrRange.dateRange?.from,
|
||||||
|
intl,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (deathDateOrRange?.dateRange?.to) {
|
||||||
|
return formatAgeLessThan(
|
||||||
|
birthDateOrRange.date,
|
||||||
|
deathDateOrRange.dateRange?.to,
|
||||||
|
intl,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
birthDateOrRange?.dateRange?.from &&
|
||||||
|
birthDateOrRange?.dateRange?.to
|
||||||
|
) {
|
||||||
|
if (deathDateOrRange?.date) {
|
||||||
|
return formatAgeBetween(
|
||||||
|
birthDateOrRange?.dateRange?.from,
|
||||||
|
birthDateOrRange?.dateRange?.to,
|
||||||
|
deathDateOrRange?.date,
|
||||||
|
deathDateOrRange?.date,
|
||||||
|
intl,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
deathDateOrRange?.dateRange?.from &&
|
||||||
|
deathDateOrRange.dateRange?.to
|
||||||
|
) {
|
||||||
|
return formatAgeBetween(
|
||||||
|
birthDateOrRange?.dateRange?.from,
|
||||||
|
birthDateOrRange?.dateRange?.to,
|
||||||
|
deathDateOrRange?.dateRange?.from,
|
||||||
|
deathDateOrRange?.dateRange?.to,
|
||||||
|
intl,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (deathDateOrRange?.dateRange?.from) {
|
||||||
|
return formatAgeMoreThan(
|
||||||
|
birthDateOrRange.dateRange?.to,
|
||||||
|
deathDateOrRange.dateRange?.from,
|
||||||
|
intl,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (deathDateOrRange?.dateRange?.to) {
|
||||||
|
return formatAgeLessThan(
|
||||||
|
birthDateOrRange.dateRange?.from,
|
||||||
|
deathDateOrRange.dateRange?.to,
|
||||||
|
intl,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (birthDateOrRange?.dateRange?.from) {
|
||||||
|
if (deathDateOrRange?.date) {
|
||||||
|
return formatAgeLessThan(
|
||||||
|
birthDateOrRange.dateRange?.from,
|
||||||
|
deathDateOrRange.date,
|
||||||
|
intl,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (deathDateOrRange?.dateRange?.to) {
|
||||||
|
return formatAgeLessThan(
|
||||||
|
birthDateOrRange.dateRange?.from,
|
||||||
|
deathDateOrRange.dateRange?.to,
|
||||||
|
intl,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (birthDateOrRange?.dateRange?.to) {
|
||||||
|
if (deathDateOrRange?.date) {
|
||||||
|
return formatAgeMoreThan(
|
||||||
|
birthDateOrRange?.dateRange?.to,
|
||||||
|
deathDateOrRange.date,
|
||||||
|
intl,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (deathDateOrRange?.dateRange?.from) {
|
||||||
|
return formatAgeMoreThan(
|
||||||
|
birthDateOrRange?.dateRange?.to,
|
||||||
|
deathDateOrRange.dateRange?.from,
|
||||||
|
intl,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -14,19 +14,8 @@ function formatDate(date: TopolaDate, intl: IntlShape) {
|
|||||||
if (!hasDay && !hasMonth && !hasYear) {
|
if (!hasDay && !hasMonth && !hasYear) {
|
||||||
return date.text || '';
|
return date.text || '';
|
||||||
}
|
}
|
||||||
const dateObject = new Date(
|
const dateObject = toDateObject(date);
|
||||||
hasYear ? date.year! : 0,
|
const translatedQualifier = formatDateQualifier(date.qualifier, intl);
|
||||||
hasMonth ? date.month! - 1 : 0,
|
|
||||||
hasDay ? date.day! : 1,
|
|
||||||
);
|
|
||||||
|
|
||||||
const qualifier = date.qualifier && date.qualifier.toLowerCase();
|
|
||||||
const translatedQualifier =
|
|
||||||
qualifier &&
|
|
||||||
intl.formatMessage({
|
|
||||||
id: `date.${qualifier}`,
|
|
||||||
defaultMessage: DATE_QUALIFIERS.get(qualifier) || qualifier,
|
|
||||||
});
|
|
||||||
|
|
||||||
const formatOptions: Intl.DateTimeFormatOptions = {
|
const formatOptions: Intl.DateTimeFormatOptions = {
|
||||||
day: hasDay ? 'numeric' : undefined,
|
day: hasDay ? 'numeric' : undefined,
|
||||||
@ -76,6 +65,22 @@ function formatDateRage(dateRange: DateRange, intl: IntlShape) {
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function formatDateQualifier(
|
||||||
|
qualifier: string | undefined,
|
||||||
|
intl: IntlShape,
|
||||||
|
): string {
|
||||||
|
const lowerCaseQualifier = qualifier && qualifier.toLowerCase();
|
||||||
|
return (
|
||||||
|
(lowerCaseQualifier &&
|
||||||
|
intl.formatMessage({
|
||||||
|
id: `date.${lowerCaseQualifier}`,
|
||||||
|
defaultMessage:
|
||||||
|
DATE_QUALIFIERS.get(lowerCaseQualifier) || lowerCaseQualifier,
|
||||||
|
})) ||
|
||||||
|
''
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/** Formats a DateOrRange object. */
|
/** Formats a DateOrRange object. */
|
||||||
export function formatDateOrRange(
|
export function formatDateOrRange(
|
||||||
dateOrRange: DateOrRange | undefined,
|
dateOrRange: DateOrRange | undefined,
|
||||||
@ -98,19 +103,10 @@ export function translateDate(gedcomDate: string, intl: IntlShape): string {
|
|||||||
return formatDateOrRange(getDate(gedcomDate), intl);
|
return formatDateOrRange(getDate(gedcomDate), intl);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Compares a dates given in GEDCOM format. */
|
export function compareTopolaDates(
|
||||||
export function compareDates(
|
date1: TopolaDate | undefined,
|
||||||
firstDateOrRange: DateOrRange | undefined,
|
date2: TopolaDate | undefined,
|
||||||
secondDateOrRange: DateOrRange | undefined,
|
|
||||||
): number {
|
): number {
|
||||||
const date1 =
|
|
||||||
firstDateOrRange &&
|
|
||||||
(firstDateOrRange.date ||
|
|
||||||
(firstDateOrRange.dateRange && firstDateOrRange.dateRange.from));
|
|
||||||
const date2 =
|
|
||||||
secondDateOrRange &&
|
|
||||||
(secondDateOrRange.date ||
|
|
||||||
(secondDateOrRange.dateRange && secondDateOrRange.dateRange.from));
|
|
||||||
if (!date1 || !date1.year || !date2 || !date2.year) {
|
if (!date1 || !date1.year || !date2 || !date2.year) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -128,3 +124,63 @@ export function compareDates(
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Compares a dates given in GEDCOM format. */
|
||||||
|
export function compareDates(
|
||||||
|
firstDateOrRange: DateOrRange | undefined,
|
||||||
|
secondDateOrRange: DateOrRange | undefined,
|
||||||
|
): number {
|
||||||
|
const date1 =
|
||||||
|
firstDateOrRange &&
|
||||||
|
(firstDateOrRange.date ||
|
||||||
|
(firstDateOrRange.dateRange &&
|
||||||
|
(firstDateOrRange.dateRange.from || firstDateOrRange.dateRange.to)));
|
||||||
|
const date2 =
|
||||||
|
secondDateOrRange &&
|
||||||
|
(secondDateOrRange.date ||
|
||||||
|
(secondDateOrRange.dateRange &&
|
||||||
|
(secondDateOrRange.dateRange.from || secondDateOrRange.dateRange.to)));
|
||||||
|
return compareTopolaDates(date1, date2);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function areDateRangesOverlapped(
|
||||||
|
range1: DateRange,
|
||||||
|
range2: DateRange,
|
||||||
|
): boolean {
|
||||||
|
return (
|
||||||
|
compareTopolaDates(range1.from, range2.to) <= 0 &&
|
||||||
|
compareTopolaDates(range1.to, range2.from) >= 0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isValidDateOrRange(
|
||||||
|
dateOrRange: DateOrRange | undefined,
|
||||||
|
): boolean {
|
||||||
|
// invalid when range is closed and start is before end
|
||||||
|
if (isDateRangeClosed(dateOrRange?.dateRange)) {
|
||||||
|
return (
|
||||||
|
compareTopolaDates(
|
||||||
|
dateOrRange?.dateRange?.from,
|
||||||
|
dateOrRange?.dateRange?.to,
|
||||||
|
) <= 0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
//valid when there is exact date or date range has start or end defined
|
||||||
|
return !!(
|
||||||
|
dateOrRange?.date ||
|
||||||
|
dateOrRange?.dateRange?.from ||
|
||||||
|
dateOrRange?.dateRange?.to
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isDateRangeClosed(range: DateRange | undefined): boolean {
|
||||||
|
return !!(range?.from && range?.to);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function toDateObject(date: TopolaDate): Date {
|
||||||
|
return new Date(
|
||||||
|
date.year !== undefined ? date.year! : 0,
|
||||||
|
date.month !== undefined ? date.month! - 1 : 0,
|
||||||
|
date.day !== undefined ? date.day! : 1,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user