From 03ff85f40b458dfdfa725618a83209d2ae48152d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20Jim=C3=A9nez?= Date: Thu, 14 Nov 2024 14:30:58 +0000 Subject: [PATCH 1/5] Add a display of isRegularExcavation and date --- src/fragmentarium/domain/archaeology.test.ts | 36 ++++++++--- src/fragmentarium/domain/archaeology.ts | 19 +++++- src/fragmentarium/ui/info/Details.css | 2 +- src/fragmentarium/ui/info/Details.test.tsx | 63 +++++++++++++++++++- src/fragmentarium/ui/info/Details.tsx | 37 ++++++++++++ 5 files changed, 141 insertions(+), 16 deletions(-) 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({
  • +
  • + +
  • {`Findspot: ${findspotString || '-'}`}
  • Date: Thu, 14 Nov 2024 20:23:27 +0000 Subject: [PATCH 2/5] Correct tests --- src/fragmentarium/domain/archaeology.test.ts | 11 ++++++++- src/fragmentarium/ui/info/Details.test.tsx | 26 +++++++++++--------- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/src/fragmentarium/domain/archaeology.test.ts b/src/fragmentarium/domain/archaeology.test.ts index e259bf7e4..920f33103 100644 --- a/src/fragmentarium/domain/archaeology.test.ts +++ b/src/fragmentarium/domain/archaeology.test.ts @@ -135,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', @@ -144,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', @@ -181,6 +189,7 @@ test.each([ date: { ...defaultParams.date, notes: 'date notes' }, }, 'a house (Residential), II (1200 BCE - 1150 BCE, date notes).', + 'en-US', ], [ 'with CE date (en-US)', @@ -214,6 +223,6 @@ test.each([ ...overrideParams, }) - expect(findspot.toString(locale)).toEqual(expected) + expect(findspot.toString()).toEqual(expected) } ) diff --git a/src/fragmentarium/ui/info/Details.test.tsx b/src/fragmentarium/ui/info/Details.test.tsx index f0d47c579..2a9228a95 100644 --- a/src/fragmentarium/ui/info/Details.test.tsx +++ b/src/fragmentarium/ui/info/Details.test.tsx @@ -171,42 +171,47 @@ 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, 10, 5), + 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('2024.10.05 – 2024.10.10')).toBeInTheDocument() // or use the specific date format + 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, 10, 5), + 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('2024.10.05')).toBeInTheDocument() + expect(screen.getByText('05/10/2024')).toBeInTheDocument() }) it('does not render excavation date when isRegularExcavation is false', async () => { @@ -216,11 +221,10 @@ describe('ExcavationDate', () => { date: undefined, }, }) - await renderDetails() - expect(screen.queryByText('Regular Excavation')).not.toBeInTheDocument() - expect(screen.queryByText('2024.10.05')).not.toBeInTheDocument() + expect(screen.queryByText(/Regular Excavation/)).not.toBeInTheDocument() + expect(screen.queryByText(/10\/05\/2024/)).not.toBeInTheDocument() }) }) From ce3d481a3deacd2e0719a9d08e36edcc89a3e915 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20Jim=C3=A9nez?= Date: Thu, 14 Nov 2024 23:50:03 +0000 Subject: [PATCH 3/5] Add notes to display --- src/fragmentarium/ui/info/Details.css | 5 +++++ src/fragmentarium/ui/info/Details.tsx | 14 +++++++++----- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/fragmentarium/ui/info/Details.css b/src/fragmentarium/ui/info/Details.css index 8e980db84..dd93e450d 100644 --- a/src/fragmentarium/ui/info/Details.css +++ b/src/fragmentarium/ui/info/Details.css @@ -7,6 +7,11 @@ margin-bottom: 0.4em; } +.Details__item--provenance { + list-style-position: inside; + list-style-type: disc; +} + .Details__item--extra-margin { margin-bottom: 1em; } diff --git a/src/fragmentarium/ui/info/Details.tsx b/src/fragmentarium/ui/info/Details.tsx index 7152a5c53..b0f82b039 100644 --- a/src/fragmentarium/ui/info/Details.tsx +++ b/src/fragmentarium/ui/info/Details.tsx @@ -111,6 +111,7 @@ function Provenance({ fragment }: Props): JSX.Element { 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 @@ -135,6 +136,7 @@ function ExcavationDate({ fragment }: Props): JSX.Element { <> Regular Excavation {date && <> ({formatDate(date)})} + {dateNotes && <>, {dateNotes}} )} @@ -178,16 +180,18 @@ function Details({
  • -
  • - -
  • -
  • +
  • + +
  • +
  • -
  • {`Findspot: ${findspotString || '-'}`}
  • +
  • {`Findspot: ${ + findspotString || '-' + }`}
  • Date: Fri, 15 Nov 2024 18:25:08 +0000 Subject: [PATCH 4/5] Fix tests --- src/fragmentarium/ui/fragment/ArchaeologyEditor.tsx | 1 + src/fragmentarium/ui/info/Details.test.tsx | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) 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.test.tsx b/src/fragmentarium/ui/info/Details.test.tsx index 2a9228a95..28c1a2f4c 100644 --- a/src/fragmentarium/ui/info/Details.test.tsx +++ b/src/fragmentarium/ui/info/Details.test.tsx @@ -193,8 +193,8 @@ describe('ExcavationDate', () => { }) await renderDetails() - expect(screen.getByText('Regular Excavation')).toBeInTheDocument() - expect(screen.getByText('05/10/2024 – 10/10/2024')).toBeInTheDocument() + 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 () => { @@ -210,8 +210,8 @@ describe('ExcavationDate', () => { }) await renderDetails() - expect(screen.getByText('Regular Excavation')).toBeInTheDocument() - expect(screen.getByText('05/10/2024')).toBeInTheDocument() + expect(screen.getByText(/Regular Excavation/)).toBeInTheDocument() + expect(screen.getByText(/05\/10\/2024/)).toBeInTheDocument() }) it('does not render excavation date when isRegularExcavation is false', async () => { From bda620daf7b4a12cbefbb3c83e26e5f4ef5b8b3a Mon Sep 17 00:00:00 2001 From: Ilya Khait Date: Mon, 18 Nov 2024 12:44:18 +0000 Subject: [PATCH 5/5] Refactor --- src/fragmentarium/domain/archaeology.ts | 43 ++++++++++++++++++------- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/src/fragmentarium/domain/archaeology.ts b/src/fragmentarium/domain/archaeology.ts index c804347eb..42ab99a50 100644 --- a/src/fragmentarium/domain/archaeology.ts +++ b/src/fragmentarium/domain/archaeology.ts @@ -45,20 +45,41 @@ export class PartialDate { } 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` + 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