From 4669503d08a68752b0fe1b25ef6d78d69c820a72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20Jim=C3=A9nez?= <39047733+ejimsan@users.noreply.github.com> Date: Mon, 18 Nov 2024 13:54:41 +0100 Subject: [PATCH] Add a display of isRegularExcavation and date (#509) * Add a display of isRegularExcavation and date * Correct tests * Add notes to display * Fix tests * Refactor --------- Co-authored-by: Ilya Khait --- src/fragmentarium/domain/archaeology.test.ts | 45 ++++++++++--- src/fragmentarium/domain/archaeology.ts | 40 ++++++++++- .../ui/fragment/ArchaeologyEditor.tsx | 1 + src/fragmentarium/ui/info/Details.css | 7 +- src/fragmentarium/ui/info/Details.test.tsx | 67 ++++++++++++++++++- src/fragmentarium/ui/info/Details.tsx | 47 ++++++++++++- 6 files changed, 188 insertions(+), 19 deletions(-) diff --git a/src/fragmentarium/domain/archaeology.test.ts b/src/fragmentarium/domain/archaeology.test.ts index 17e8cccbd..920f33103 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', @@ -134,6 +135,7 @@ test.each([ }, 'some area > a house (Residential), II (1200 BCE - 1150 BCE), ' + 'Room 42, On the floor (primary context). General notes.', + 'de-DE', ], [ 'with secondary context', @@ -143,36 +145,43 @@ test.each([ date: null, }, 'a house (Residential), II, in shelf (secondary context).', + 'de-DE', ], [ 'with area and notes', { area: 'some area', notes: 'General notes.' }, 'some area > a house (Residential), II (1200 BCE - 1150 BCE). General notes.', + 'de-DE', ], [ 'without area or notes', { area: '' }, 'a house (Residential), II (1200 BCE - 1150 BCE).', + 'en-US', ], [ 'without notes', { notes: '' }, 'a house (Residential), II (1200 BCE - 1150 BCE).', + 'en-US', ], [ 'without building', { building: '' }, '(Residential), II (1200 BCE - 1150 BCE).', + 'de-DE', ], [ 'without buildingType', { buildingType: null }, 'a house, II (1200 BCE - 1150 BCE).', + 'en-US', ], [ 'without levelLayerPhase and date', { levelLayerPhase: '', date: null }, 'a house (Residential).', + 'de-DE', ], [ 'with date notes', @@ -180,9 +189,10 @@ test.each([ date: { ...defaultParams.date, notes: 'date notes' }, }, 'a house (Residential), II (1200 BCE - 1150 BCE, date notes).', + 'en-US', ], [ - 'with CE date', + 'with CE date (en-US)', { date: { start: new PartialDate(1920, 6, 5), @@ -190,12 +200,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()).toEqual(expected) + } +) diff --git a/src/fragmentarium/domain/archaeology.ts b/src/fragmentarium/domain/archaeology.ts index 814a1405d..42ab99a50 100644 --- a/src/fragmentarium/domain/archaeology.ts +++ b/src/fragmentarium/domain/archaeology.ts @@ -41,11 +41,45 @@ 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 { + if (this.isBCE()) { + return this.formatBCE() + } + return this.formatCE(locale) + } + + private isBCE(): boolean { + return this.year < 0 + } + + private formatBCE(): string { + return `${Math.abs(this.year)} BCE` + } + + private formatCE(locale: string): string { + const options = this.getDateFormatOptions() + const date = this.createDate() + return new Intl.DateTimeFormat(locale, options).format(date) + } + + private getDateFormatOptions(): Intl.DateTimeFormatOptions { + if (this.day) { + return { year: 'numeric', month: '2-digit', day: '2-digit' } + } + if (this.month) { + return { year: 'numeric', month: '2-digit' } + } + return { year: 'numeric' } + } + + private createDate(): Date { + return new Date(this.year, (this.month || 1) - 1, this.day || 1) } } + export type DateRange = { start: PartialDate end?: PartialDate | null diff --git a/src/fragmentarium/ui/fragment/ArchaeologyEditor.tsx b/src/fragmentarium/ui/fragment/ArchaeologyEditor.tsx index f06cfc14a..d5d257a31 100644 --- a/src/fragmentarium/ui/fragment/ArchaeologyEditor.tsx +++ b/src/fragmentarium/ui/fragment/ArchaeologyEditor.tsx @@ -194,6 +194,7 @@ class ArchaeologyEditor extends Component { type="checkbox" id={_.uniqueId('isRegularExcavation-')} label="Regular Excavation" + aria-label="regular-excavation" checked={this.state.isRegularExcavation} onChange={this.updateIsRegularExcavation} /> diff --git a/src/fragmentarium/ui/info/Details.css b/src/fragmentarium/ui/info/Details.css index f4d0b24b9..dd93e450d 100644 --- a/src/fragmentarium/ui/info/Details.css +++ b/src/fragmentarium/ui/info/Details.css @@ -4,7 +4,12 @@ } .Details__item { - margin-bottom: 0.2em; + margin-bottom: 0.4em; +} + +.Details__item--provenance { + list-style-position: inside; + list-style-type: disc; } .Details__item--extra-margin { diff --git a/src/fragmentarium/ui/info/Details.test.tsx b/src/fragmentarium/ui/info/Details.test.tsx index 1cc7d17f5..28c1a2f4c 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,64 @@ describe('All details', () => { }) }) +describe('ExcavationDate', () => { + beforeEach(() => { + fragmentService.fetchGenres.mockResolvedValue([]) + fragmentService.fetchPeriods.mockResolvedValue([]) + Object.defineProperty(navigator, 'language', { + value: 'en-US', + writable: true, + }) + }) + + it('renders excavation date when isRegularExcavation is true', async () => { + const excavationDate = { + start: new PartialDate(2024, 5, 10), + 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(/05\/10\/2024 – 10\/10\/2024/)).toBeInTheDocument() + }) + + it('renders only start date when end date is missing', async () => { + const excavationDate = { + start: new PartialDate(2024, 5, 10), + end: null, + } + fragment = fragmentFactory.build({ + archaeology: { + isRegularExcavation: true, + date: excavationDate, + }, + }) + await renderDetails() + + expect(screen.getByText(/Regular Excavation/)).toBeInTheDocument() + expect(screen.getByText(/05\/10\/2024/)).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(/10\/05\/2024/)).not.toBeInTheDocument() + }) +}) + describe('Missing details', () => { beforeEach(async () => { const archaeology = archaeologyFactory.build({ @@ -200,14 +261,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..b0f82b039 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,41 @@ 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 dateNotes = date?.notes + + 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)})} + {dateNotes && <>, {dateNotes}} + + )} + + ) +} + interface DetailsProps { readonly fragment: Fragment readonly updateGenres: (genres: Genres) => void @@ -145,12 +181,17 @@ function Details({
  • + +
  • +
  • -
  • - +
  • +
  • -
  • {`Findspot: ${findspotString || '-'}`}
  • +
  • {`Findspot: ${ + findspotString || '-' + }`}