Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

app-project: Add OrganizationLink to ProjectHeader and Hero components #4567

Merged
merged 16 commits into from
Jun 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/app-project/public/locales/en/components.json
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@
"collect": "Collect",
"recents": "Recents",
"admin": "Admin page",
"organization": "From the organization:",
"ApprovedIcon": {
"title": "Zooniverse Approved"
},
Expand Down
20 changes: 17 additions & 3 deletions packages/app-project/src/components/ProjectHeader/ProjectHeader.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
Background,
DropdownNav,
LocaleSwitcher,
OrganizationLink,
Nav,
ProjectTitle,
UnderReviewLabel
Expand All @@ -21,7 +22,7 @@ const StyledBox = styled(Box)`
`

function ProjectHeader({
adminMode,
adminMode = false,
className = ''
}) {
const { width, height, ref } = useResizeDetector({
Expand All @@ -31,9 +32,10 @@ function ProjectHeader({
const {
availableLocales,
inBeta,
organizationTitle,
organizationSlug,
title
} = useStores()

const hasTranslations = availableLocales?.length > 1
const maxColumnWidth = hasTranslations ? 1000 : 900
const isNarrow = width < maxColumnWidth
Expand All @@ -47,11 +49,21 @@ function ProjectHeader({
return (
<StyledBox ref={ref} className={className}>
<Background />
{(organizationTitle && !useDropdownNav) ? (
<OrganizationLink
slug={organizationSlug}
title={organizationTitle}
/>
) : null}
<StyledBox
align='center'
direction={direction}
justify='between'
pad='medium'
pad={{
bottom: 'medium',
horizontal: 'medium',
top: (organizationTitle && !useDropdownNav) ? 'none' : 'medium'
}}
>
<Box direction={direction} gap='small'>
<Box
Expand Down Expand Up @@ -85,6 +97,8 @@ function ProjectHeader({
<DropdownNav
adminMode={adminMode}
margin={ isNarrow ? { top: 'xsmall' } : { top : 0 }}
organizationSlug={organizationSlug}
organizationTitle={organizationTitle}
/>
) : (
<Nav adminMode={adminMode} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@ const {
LaunchApproved,
LoggedIn,
MultipleLanguages,
NotLoggedIn
NotLoggedIn,
OrganizationLink
} = composeStories(Stories)

describe('Component > ProjectHeader', function () {
let languageButton, navMenu, projectAvatar, projectBackground, projectTitle
let languageButton, navMenu, projectAvatar, projectBackground, projectTitle, organizationLink

before(function () {
nock('https://talk-staging.zooniverse.org')
Expand All @@ -40,6 +41,7 @@ describe('Component > ProjectHeader', function () {
projectTitle = screen.getByRole('heading', { level: 1, name: 'Snapshot Serengeti' })
navMenu = screen.getByRole('navigation', { name: 'ProjectHeader.ProjectNav.ariaLabel' })
languageButton = screen.queryByRole('button', { name: 'ProjectHeader.LocaleSwitcher.label'})
organizationLink = screen.queryByRole('link', { name: 'Snapshot Safari' })
})

it('should display the project title', function () {
Expand All @@ -61,6 +63,10 @@ describe('Component > ProjectHeader', function () {
it('should not show the language menu button', function () {
expect(languageButton).to.be.null()
})

it('should not show the organization link', function () {
expect(organizationLink).to.be.null()
})
})

describe('when not logged in', function () {
Expand Down Expand Up @@ -165,4 +171,17 @@ describe('Component > ProjectHeader', function () {
expect(languageButton).to.exist()
})
})

describe('with an organization', function () {
let organizationLink

before(function () {
render(<OrganizationLink />)
organizationLink = screen.getByRole('link', { name: 'Snapshot Safari' })
})

it('should show the organization link', async function () {
expect(organizationLink).to.exist()
})
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@ const mockRouter = {
}
}

const ORGANIZATION = {
id: '1',
listed: true,
slug: 'zooniverse/snapshot-safari',
strings: {
title: 'Snapshot Safari'
}
}

export default {
title: 'Project App / Shared / Project Header',
component: ProjectHeader
Expand Down Expand Up @@ -302,3 +311,42 @@ MultipleLanguages.args = {
}
}
}

export function OrganizationLink({ organization, project }) {
const snapshot = {
organization,
project
}
applySnapshot(OrganizationLink.store, snapshot)
return (
<RouterContext.Provider value={mockRouter}>
<Provider store={OrganizationLink.store}>
<ProjectHeader />
</Provider>
</RouterContext.Provider>
)
}
OrganizationLink.store = initStore(true)
OrganizationLink.args = {
adminMode: false,
className: '',
organization: ORGANIZATION,
project: {
avatar: {
src: 'https://panoptes-uploads.zooniverse.org/project_avatar/442e8392-6c46-4481-8ba3-11c6613fba56.jpeg'
},
background: {
src: 'https://panoptes-uploads.zooniverse.org/project_background/7a3c6210-f97d-4f40-9ab4-8da30772ee01.jpeg'
},
configuration: {
languages: ['en']
},
slug: 'zooniverse/snapshot-serengeti',
strings: {
display_name: 'Snapshot Serengeti'
},
links: {
active_workflows: ['1']
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ const StyledDropButton = styled(DropButton)`
`}
}
`

const defaultMargin = {
top: 0
}
Expand All @@ -45,6 +46,8 @@ function DropdownNav({
adminMode = false,
className,
margin = defaultMargin,
organizationSlug = '',
organizationTitle = '',
}) {
const { t } = useTranslation('components')
const navLinks = useProjectNavigation(adminMode)
Expand All @@ -70,19 +73,47 @@ function DropdownNav({
as='ul'
pad='0px'
>
{navLinks.map(navLink => (
<>
{navLinks.map(navLink => (
<Box
as='li'
key={navLink.href}
>
<NavLink
color='white'
link={navLink}
StyledAnchor={StyledAnchor}
weight='bold'
/>
</Box>
))}
</>
{organizationTitle ? (
<Box
as='li'
key={navLink.href}
key={organizationSlug}
>
<NavLink
color='white'
link={navLink}
StyledAnchor={StyledAnchor}
weight='bold'
<StyledAnchor
href={`/organizations/${organizationSlug}`}
label={(
<Box pad='none'>
<SpacedText
color='white'
size='xsmall'
>
{t('ProjectHeader.organization')}
</SpacedText>
<SpacedText
color='white'
weight='bold'
>
{organizationTitle}
</SpacedText>
</Box>
)}
/>
</Box>
))}
) : null}
</Box>
</Box>
)
Expand Down Expand Up @@ -121,7 +152,11 @@ DropdownNav.propTypes = {
/** CSS class */
className: string,
/** Margin for the dropdown button (Grommet t-shirt size, CSS length or Grommet margin object.) */
margin: oneOfType([string, object])
margin: oneOfType([string, object]),
/** Organization slug */
organizationSlug: string,
/** Organization title */
organizationTitle: string
}

export default DropdownNav
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import userEvent from '@testing-library/user-event'
import nock from 'nock'

import * as Stories from './DropdownNav.stories.js'
const { Default, LoggedIn, AdminMode } = composeStories(Stories)
const { Default, LoggedIn, AdminMode, WithOrganizationLink } = composeStories(Stories)

describe('Component > ProjectHeader > Dropdown Nav', function () {
before(function () {
Expand Down Expand Up @@ -105,4 +105,31 @@ describe('Component > ProjectHeader > Dropdown Nav', function () {
expect(navLinks[navLinks.length - 1].href).to.equal('https://www.zooniverse.org/admin/project_status/zooniverse/snapshot-serengeti')
})
})

describe('with organization link', function () {
let dropdownButton, navMenu

before(async function () {
const user = userEvent.setup({ delay: 'none' })
render(<WithOrganizationLink />)
dropdownButton = screen.queryByRole('button', { name: 'ProjectHeader.exploreProject' })
await user.click(dropdownButton)
navMenu = await screen.findByRole('navigation', { name: 'ProjectHeader.ProjectNav.ariaLabel' })
})

it('should show the menu button', function () {
expect(dropdownButton).to.exist()
})

it('should open the navigation menu', function () {
expect(navMenu).to.exist()
})

it('should show the organization link', function () {
const navLinks = within(navMenu).getAllByRole('link')
expect(navLinks.length).to.be.above(0)
expect(navLinks[0].href).to.equal('https://localhost/zooniverse/snapshot-serengeti/about/research')
expect(navLinks[navLinks.length - 1].href).to.equal('https://localhost/organizations/zooniverse/snapshot-safari')
})
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -123,3 +123,39 @@ export function AdminMode(props) {
)
}
AdminMode.store = initStore(true)

export function WithOrganizationLink(props) {
const snapshot = {
project: {
avatar: {
src: 'https://panoptes-uploads.zooniverse.org/project_avatar/442e8392-6c46-4481-8ba3-11c6613fba56.jpeg'
},
background: {
src: 'https://panoptes-uploads.zooniverse.org/project_background/7a3c6210-f97d-4f40-9ab4-8da30772ee01.jpeg'
},
beta_approved: false,
configuration: {
languages: ['en']
},
launch_approved: false,
slug: 'zooniverse/snapshot-serengeti',
strings: {
display_name: 'Snapshot Serengeti'
},
links: {
active_workflows: ['1']
}
}
}
applySnapshot(WithOrganizationLink.store, snapshot)
return (
<Provider store={WithOrganizationLink.store}>
<DropdownNav
organizationSlug='zooniverse/snapshot-safari'
organizationTitle='Snapshot Safari'
{...props}
/>
</Provider>
)
}
WithOrganizationLink.store = initStore(true)
Loading