Skip to content

Commit

Permalink
Newsletter section (#450)
Browse files Browse the repository at this point in the history
* Newsletter section created

* Update Routes

* add eBL Newsletter 15 to about-news

* Update news section

* Update About News

* Implement MD static loading, menu & routes

* Format markdown

* Move menu to the right

* Style

* Update Newsletter 10-14

* Upload Newsletter 1-9, update 10-11

* Format all md to satisfy markdownlint

* Sync md. import & update

* Adjust about & news behavior on tab and url change

* Adjust bibliography routes and tests

* Add tests

---------

Co-authored-by: Enrique Jiménez <[email protected]>
Co-authored-by: Ilya Khait <[email protected]>
  • Loading branch information
3 people authored Feb 21, 2024
1 parent 4b6ca50 commit a4249cb
Show file tree
Hide file tree
Showing 30 changed files with 997 additions and 50 deletions.
1 change: 1 addition & 0 deletions .env.test
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ REACT_APP_AUTH0_AUDIENCE=dictionary-api
REACT_APP_DICTIONARY_API_URL=http://example.com
REACT_APP_SENTRY_DSN=http://example.com/sentry
REACT_APP_CORRECTIONS_EMAIL=[email protected]
REACT_APP_INFO_EMAIL=[email protected]
REACT_APP_GA_TRACKING_ID=G-XXXXXXXXXX
2 changes: 2 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ jobs:
build-args: |
REACT_APP_AUTH0_DOMAIN=auth.ebl.lmu.de
REACT_APP_CORRECTIONS_EMAIL=ebl-support+corrections@culture.lmu.de
[email protected]
REACT_APP_AUTH0_CLIENT_ID=${{ secrets.REACT_APP_AUTH0_CLIENT_ID }}
REACT_APP_AUTH0_AUDIENCE=${{ secrets.REACT_APP_AUTH0_AUDIENCE }}
REACT_APP_DICTIONARY_API_URL=/api
Expand Down Expand Up @@ -96,6 +97,7 @@ jobs:
build-args: |
REACT_APP_AUTH0_DOMAIN=auth.ebl.lmu.de
REACT_APP_CORRECTIONS_EMAIL=ebl-support+corrections@culture.lmu.de
[email protected]
REACT_APP_AUTH0_CLIENT_ID=${{ secrets.REACT_APP_AUTH0_CLIENT_ID }}
REACT_APP_AUTH0_AUDIENCE=${{ secrets.REACT_APP_AUTH0_AUDIENCE }}
REACT_APP_DICTIONARY_API_URL=/test/api
Expand Down
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ ARG REACT_APP_AUTH0_AUDIENCE
ARG REACT_APP_DICTIONARY_API_URL
ARG REACT_APP_SENTRY_DSN
ARG REACT_APP_CORRECTIONS_EMAIL
ARG REACT_APP_INFO_EMAIL
ARG REACT_APP_GA_TRACKING_ID

RUN yarn build
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ REACT_APP_AUTH0_AUDIENCE=<Auth0 audience>
REACT_APP_DICTIONARY_API_URL=<eBL API URL>
REACT_APP_SENTRY_DSN=<Sentry DSN>
REACT_APP_CORRECTIONS_EMAIL=<Email for submitting corrections>
REACT_APP_INFO_EMAIL=<Email for general questions and contact>
REACT_APP_GA_TRACKING_ID=<Google Analytics 4 tracking (measurement) Id>
```

Expand Down
9 changes: 7 additions & 2 deletions src/App.test.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import AppDriver from 'test-support/AppDriver'
import FakeApi from 'test-support/FakeApi'
import { statisticsFactory } from 'test-support/fragment-fixtures'
import { tabIds as aboutTabIds } from 'about/ui/about'

test.each([
'/',
'/bibliography',
'/bibliography_new',
'/bibliography/entry_id',
'/bibliography/afo-register',
'/bibliography/references',
'/bibliography/references/new-reference',
'/bibliography/references/entry_id',
'/dictionary',
'/dictionary/object_id',
'/corpus',
Expand All @@ -17,7 +20,9 @@ test.each([
'/fragmentarium/fragment_number',
'/callback',
'/about',
...aboutTabIds.map((tabId) => '/about/' + tabId),
'/tools',
...['date-converter', 'list-of-kings'].map((tabId) => '/about/' + tabId),
'/signs',
])('%s renders without crashing', async (route) => {
const fakeApi = new FakeApi().allowStatistics(statisticsFactory.build())
Expand Down
11 changes: 11 additions & 0 deletions src/about/ui/__snapshots__/about.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,17 @@ exports[`Snapshot 1`] = `
>
Bibliography
</a>
<a
aria-controls="about-tabpane-news"
aria-selected="false"
class="nav-item nav-link"
data-rb-event-key="news"
href="#"
id="about-tab-news"
role="tab"
>
News
</a>
</nav>
<div
class="tab-content"
Expand Down
15 changes: 5 additions & 10 deletions src/about/ui/about.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@ import Bluebird from 'bluebird'
import '@testing-library/jest-dom/extend-expect'
import MarkupService from 'markup/application/MarkupService'
import { markupDtoSerialized } from 'test-support/markup-fixtures'
import { act, render, screen, waitFor } from '@testing-library/react'
import { act, render } from '@testing-library/react'
import { MemoryRouter } from 'react-router-dom'
import { waitForSpinnerToBeRemoved } from 'test-support/waitForSpinnerToBeRemoved'

jest.mock('markup/application/MarkupService')

Expand All @@ -29,17 +28,13 @@ test('Snapshot', async () => {
markupServiceMock.fromString.mockReturnValue(
Bluebird.resolve(markupDtoSerialized)
)

let container
await act(async () => {
const { container } = await render(
container = await render(
<MemoryRouter>
<About markupService={markupServiceMock} activeTab="corpus" />
</MemoryRouter>
)
await waitForSpinnerToBeRemoved(screen)
await waitFor(() => {
expect(screen.queryByText('Loading...')).not.toBeInTheDocument()
})
expect(container).toMatchSnapshot()
).container
})
expect(container).toMatchSnapshot()
})
83 changes: 60 additions & 23 deletions src/about/ui/about.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState } from 'react'
import React, { useEffect, useState } from 'react'
import { Tabs, Tab } from 'react-bootstrap'
import { useHistory } from 'react-router-dom'
import AppContent from 'common/AppContent'
Expand All @@ -9,6 +9,7 @@ import AboutProject from 'about/ui/project'
import AboutFragmentarium from 'about/ui/fragmentarium'
import AboutCorpus from 'about/ui/corpus'
import AboutSigns from 'about/ui/signs'
import AboutNews from 'about/ui/news'
import AboutDictionary from 'about/ui/dictionary'
import AboutBibliography from 'about/ui/bibliography'
import _ from 'lodash'
Expand All @@ -24,52 +25,88 @@ export const tabIds = [
] as const
export type TabId = typeof tabIds[number]

function getTabs({
markupService,
activeSection,
}: {
markupService: MarkupService
activeSection?: string
}): React.ReactElement[] {
return [
<Tab key="project" eventKey="project" title="eBL Project">
{AboutProject(markupService)}
</Tab>,
<Tab key="fragmentarium" eventKey="fragmentarium" title="Fragmentarium">
{AboutFragmentarium(markupService)}
</Tab>,
<Tab key="corpus" eventKey="corpus" title="Corpus">
{AboutCorpus(markupService)}
</Tab>,
<Tab key="signs" eventKey="signs" title="Signs">
{AboutSigns()}
</Tab>,
<Tab key="dictionary" eventKey="dictionary" title="Dictionary">
{AboutDictionary(markupService)}
</Tab>,
<Tab key="bibliography" eventKey="bibliography" title="Bibliography">
{AboutBibliography(markupService)}
</Tab>,
<Tab key="news" eventKey="news" title="News">
{AboutNews({
activeNewsletterNumber: activeSection
? parseInt(activeSection)
: undefined,
})}
</Tab>,
]
}

export default function About({
markupService,
activeTab,
activeSection,
}: {
markupService: MarkupService
activeTab: TabId
activeSection?: string
}): JSX.Element {
const history = useHistory()
const [selectedTab, setSelectedTab] = useState(activeTab)
const handleSelect = (selectedTab: TabId) => {
history.push(selectedTab)
setSelectedTab(selectedTab)
const handleSelect = (newTab: TabId) => {
if (newTab === activeTab) {
return
}
history.push(`/about/${newTab}`)
setSelectedTab(newTab)
}

useEffect(() => {
if (activeTab === selectedTab) {
return
}
setSelectedTab(activeTab)
}, [selectedTab, activeTab])

return (
<AppContent
title="About"
crumbs={[
new TextCrumb('About'),
new TextCrumb(_.capitalize(selectedTab)),
...(selectedTab === 'news'
? [new TextCrumb(`Nr. ${activeSection}`)]
: []),
]}
>
<Tabs
id="about"
defaultActiveKey={selectedTab}
onSelect={(selectedTab) => handleSelect(selectedTab as TabId)}
activeKey={selectedTab}
onSelect={(newTab) => handleSelect(newTab as TabId)}
mountOnEnter
unmountOnExit
>
<Tab eventKey="project" title="eBL Project">
{AboutProject(markupService)}
</Tab>
<Tab eventKey="fragmentarium" title="Fragmentarium">
{AboutFragmentarium(markupService)}
</Tab>
<Tab eventKey="corpus" title="Corpus">
{AboutCorpus(markupService)}
</Tab>
<Tab eventKey="signs" title="Signs">
{AboutSigns()}
</Tab>
<Tab eventKey="dictionary" title="Dictionary">
{AboutDictionary(markupService)}
</Tab>
<Tab eventKey="bibliography" title="Bibliography">
{AboutBibliography(markupService)}
</Tab>
{getTabs({ activeSection, markupService })}
</Tabs>
</AppContent>
)
Expand Down
50 changes: 50 additions & 0 deletions src/about/ui/news.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import React from 'react'
import { render, screen } from '@testing-library/react'
import AboutNews from './news'
import { newsletters } from './news'
import { Router } from 'react-router-dom'
import { createMemoryHistory } from 'history'
import { fireEvent } from '@testing-library/react'

test('renders AboutNews component with default newsletter', () => {
const history = createMemoryHistory()
render(
<Router history={history}>
<AboutNews />
</Router>
)
expect(
screen.getByText(new RegExp(`eBL Newsletter ${newsletters[0].number}`))
).toBeInTheDocument()
})

test('renders AboutNews component with complete menu', () => {
const history = createMemoryHistory()
render(
<Router history={history}>
<AboutNews />
</Router>
)
newsletters.forEach((newsletter) => {
expect(
screen.getByText(new RegExp(`^Nr. ${newsletter.number}$`))
).toBeInTheDocument()
})
})

test('updates active newsletter on link click', () => {
const history = createMemoryHistory()
render(
<Router history={history}>
<AboutNews />
</Router>
)
const secondNewsletterLink = screen.getByText(
new RegExp(`Nr. ${newsletters[1].number}`)
)
fireEvent.click(secondNewsletterLink)
expect(history.location.pathname).toBe(`/about/news/${newsletters[1].number}`)
expect(
screen.getByText(new RegExp(`eBL Newsletter ${newsletters[1].number}`))
).toBeInTheDocument()
})
Loading

0 comments on commit a4249cb

Please sign in to comment.