diff --git a/src/fragmentarium/domain/archaeology.test.ts b/src/fragmentarium/domain/archaeology.test.ts index 17e8cccbd..e259bf7e4 100644 --- a/src/fragmentarium/domain/archaeology.test.ts +++ b/src/fragmentarium/domain/archaeology.test.ts @@ -122,6 +122,7 @@ test('createArchaeology', () => { }) ).toEqual(archaeology) }) + test.each([ [ 'with full info', @@ -182,7 +183,7 @@ test.each([ 'a house (Residential), II (1200 BCE - 1150 BCE, date notes).', ], [ - 'with CE date', + 'with CE date (en-US)', { date: { start: new PartialDate(1920, 6, 5), @@ -190,12 +191,29 @@ test.each([ notes: '', }, }, - 'a house (Residential), II (1920/6/5).', + 'a house (Residential), II (06/05/1920).', + 'en-US', ], -])('Correctly builds findspot info %s', (_info, overrideParams, expected) => { - const findspot = findspotFactory.build({ - ...defaultParams, - ...overrideParams, - }) - expect(findspot.toString()).toEqual(expected) -}) + [ + 'with CE date (de-DE)', + { + date: { + start: new PartialDate(1920, 6, 5), + end: null, + notes: '', + }, + }, + 'a house (Residential), II (06/05/1920).', + 'de-DE', + ], +])( + 'Correctly builds findspot info %s', + (_info, overrideParams, expected, locale) => { + const findspot = findspotFactory.build({ + ...defaultParams, + ...overrideParams, + }) + + expect(findspot.toString(locale)).toEqual(expected) + } +) diff --git a/src/fragmentarium/domain/archaeology.ts b/src/fragmentarium/domain/archaeology.ts index 814a1405d..c804347eb 100644 --- a/src/fragmentarium/domain/archaeology.ts +++ b/src/fragmentarium/domain/archaeology.ts @@ -41,9 +41,22 @@ export class PartialDate { } toString(): string { - return this.year >= 0 - ? _.reject([this.year, this.month, this.day], _.isNil).join('/') - : `${Math.abs(this.year)} BCE` + return this.toLocaleString() + } + + toLocaleString(locale = 'default'): string { + const options: Intl.DateTimeFormatOptions = this.day + ? { year: 'numeric', month: '2-digit', day: '2-digit' } + : this.month + ? { year: 'numeric', month: '2-digit' } + : { year: 'numeric' } + + if (this.year >= 0) { + const date = new Date(this.year, (this.month || 1) - 1, this.day || 1) + return new Intl.DateTimeFormat(locale, options).format(date) + } else { + return `${Math.abs(this.year)} BCE` + } } } export type DateRange = { diff --git a/src/fragmentarium/ui/info/Details.css b/src/fragmentarium/ui/info/Details.css index f4d0b24b9..8e980db84 100644 --- a/src/fragmentarium/ui/info/Details.css +++ b/src/fragmentarium/ui/info/Details.css @@ -4,7 +4,7 @@ } .Details__item { - margin-bottom: 0.2em; + margin-bottom: 0.4em; } .Details__item--extra-margin { diff --git a/src/fragmentarium/ui/info/Details.test.tsx b/src/fragmentarium/ui/info/Details.test.tsx index 1cc7d17f5..f0d47c579 100644 --- a/src/fragmentarium/ui/info/Details.test.tsx +++ b/src/fragmentarium/ui/info/Details.test.tsx @@ -16,6 +16,7 @@ import { measuresFactory, } from 'test-support/fragment-data-fixtures' import { joinFactory } from 'test-support/join-fixtures' +import { PartialDate } from 'fragmentarium/domain/archaeology' import { Periods } from 'common/period' import FragmentService from 'fragmentarium/application/FragmentService' @@ -99,7 +100,7 @@ describe('All details', () => { ) }) - it('Renders colection', () => { + it('Renders collection', () => { expect( screen.getByText(`(${fragment.collection} Collection)`) ).toBeInTheDocument() @@ -153,6 +154,7 @@ describe('All details', () => { screen.getByText(`Accession no.: ${fragment.accession}`) ).toBeInTheDocument() }) + it('Renders excavation', () => { expect( screen.getByText( @@ -160,6 +162,7 @@ describe('All details', () => { ) ).toBeInTheDocument() }) + it('Renders provenance', () => { expect( screen.getByText(`Provenance: ${fragment.archaeology?.site?.name}`) @@ -167,6 +170,60 @@ describe('All details', () => { }) }) +describe('ExcavationDate', () => { + it('renders excavation date when isRegularExcavation is true', async () => { + const excavationDate = { + start: new PartialDate(2024, 10, 5), + end: new PartialDate(2024, 10, 10), + } + + fragment = fragmentFactory.build({ + archaeology: { + isRegularExcavation: true, + date: excavationDate, + }, + }) + + await renderDetails() + + expect(screen.getByText('Regular Excavation')).toBeInTheDocument() + expect(screen.getByText('2024.10.05 – 2024.10.10')).toBeInTheDocument() // or use the specific date format + }) + + it('renders only start date when end date is missing', async () => { + const excavationDate = { + start: new PartialDate(2024, 10, 5), + end: null, + } + + fragment = fragmentFactory.build({ + archaeology: { + isRegularExcavation: true, + date: excavationDate, + }, + }) + + await renderDetails() + + expect(screen.getByText('Regular Excavation')).toBeInTheDocument() + expect(screen.getByText('2024.10.05')).toBeInTheDocument() + }) + + it('does not render excavation date when isRegularExcavation is false', async () => { + fragment = fragmentFactory.build({ + archaeology: { + isRegularExcavation: false, + date: undefined, + }, + }) + + await renderDetails() + + expect(screen.queryByText('Regular Excavation')).not.toBeInTheDocument() + expect(screen.queryByText('2024.10.05')).not.toBeInTheDocument() + }) +}) + describe('Missing details', () => { beforeEach(async () => { const archaeology = archaeologyFactory.build({ @@ -200,14 +257,14 @@ describe('Missing details', () => { it('Does not render undefined', () => expect(screen.queryByText('undefined')).not.toBeInTheDocument()) - it('Does not render colection', () => + it('Does not render collection', () => expect(screen.queryByText('Collection')).not.toBeInTheDocument()) it(`Renders dash for joins`, () => { expect(screen.getByText(/Joins:/)).toHaveTextContent('-') }) - it('Does not renders missing measures', () => { + it('Does not render missing measures', () => { expect( screen.getByText( `${fragment.measures.length} (L) × ${fragment.measures.thickness} (T) cm` diff --git a/src/fragmentarium/ui/info/Details.tsx b/src/fragmentarium/ui/info/Details.tsx index e629ea847..7152a5c53 100644 --- a/src/fragmentarium/ui/info/Details.tsx +++ b/src/fragmentarium/ui/info/Details.tsx @@ -12,6 +12,7 @@ import FragmentService from 'fragmentarium/application/FragmentService' import Bluebird from 'bluebird' import { MesopotamianDate } from 'chronology/domain/Date' import DatesInTextSelection from 'chronology/ui/DateEditor/DatesInTextSelection' +import { DateRange, PartialDate } from 'fragmentarium/domain/archaeology' interface Props { readonly fragment: Fragment @@ -107,6 +108,39 @@ function Provenance({ fragment }: Props): JSX.Element { return <>Provenance: {fragment.archaeology?.site?.name || '-'}> } +function ExcavationDate({ fragment }: Props): JSX.Element { + const isRegularExcavation = fragment.archaeology?.isRegularExcavation + const date = fragment.archaeology?.date + + const formatDate = (date: DateRange) => { + const locale = navigator.language + const start = new PartialDate( + date.start.year, + date.start.month, + date.start.day + ).toLocaleString(locale) + const end = date.end + ? new PartialDate( + date.end.year, + date.end.month, + date.end.day + ).toLocaleString(locale) + : '' + return end ? `${start} – ${end}` : start + } + + return ( + <> + {isRegularExcavation && ( + <> + Regular Excavation + {date && <> ({formatDate(date)})>} + > + )} + > + ) +} + interface DetailsProps { readonly fragment: Fragment readonly updateGenres: (genres: Genres) => void @@ -150,6 +184,9 @@ function Details({