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

Project: Modal workflow selection #1976

Merged
merged 11 commits into from
Jan 27, 2021
62 changes: 50 additions & 12 deletions packages/app-project/src/screens/ClassifyPage/ClassifyPage.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { Box, Grid } from 'grommet'
import dynamic from 'next/dynamic'
import { useRouter } from 'next/router'
import { arrayOf, func, shape, string } from 'prop-types'
import React from 'react'
import { withResponsiveContext } from '@zooniverse/react-components'
import React, { useState } from 'react'
import { Modal, withResponsiveContext } from '@zooniverse/react-components'

import ThemeModeToggle from '@components/ThemeModeToggle'
import ProjectName from '@components/ProjectName'
Expand All @@ -14,6 +15,7 @@ import YourStats from './components/YourStats'
import StandardLayout from '@shared/components/StandardLayout'

import WorkflowSelector from '@shared/components/WorkflowSelector'
import SubjectSetPicker from '@shared/components/SubjectSetPicker'

const ClassifierWrapper = dynamic(() =>
import('./components/ClassifierWrapper'), { ssr: false }
Expand All @@ -25,8 +27,25 @@ function ClassifyPage (props) {
? ['auto']
: ['1em', 'auto', '1em']

const [ activeWorkflow ] = workflows.filter(workflow => workflow.id === workflowID)
const canClassify = activeWorkflow?.grouped ? !!subjectSetID : !!workflowID
const [ workflowFromUrl ] = workflows.filter(workflow => workflow.id === workflowID)
const canClassify = workflowFromUrl?.grouped ? !!subjectSetID : !!workflowID
const router = useRouter()
const { owner, project } = router?.query || {}
const [ activeWorkflow, setActiveWorkflow ] = useState(workflowFromUrl)

function onSelectWorkflow(event, workflow) {
if (workflow.grouped) {
event.preventDefault()
setActiveWorkflow(workflow)
return false
}
return true
}

function onClose() {
setActiveWorkflow(null)
}

return (
<StandardLayout>

Expand All @@ -37,16 +56,35 @@ function ClassifyPage (props) {
>

<Box as='main' fill='horizontal'>
{!canClassify && (
<Modal
active
closeFn={onClose}
headingBackground='brand'
title={activeWorkflow ? (activeWorkflow.displayName || 'Choose a subject set') : 'Choose a workflow'}
titleColor='neutral-6'
>
{!activeWorkflow ?
<WorkflowSelector
onSelect={onSelectWorkflow}
workflows={workflows}
/> :
<SubjectSetPicker
onClose={onClose}
owner={owner}
project={project}
workflow={activeWorkflow}
/>
}
</Modal>
)}
<Grid columns={responsiveColumns} gap='small'>
<ProjectName />
{canClassify ?
<ClassifierWrapper
onAddToCollection={addToCollection}
subjectSetID={subjectSetID}
workflowID={workflowID}
/> :
<WorkflowSelector activeWorkflow={activeWorkflow} workflows={workflows} />
}
<ClassifierWrapper
onAddToCollection={addToCollection}
subjectSetID={subjectSetID}
workflowID={workflowID}
/>
<ThemeModeToggle />
</Grid>
</Box>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import YourStats from './components/YourStats'
import ConnectWithProject from '@shared/components/ConnectWithProject'
import ProjectStatistics from '@shared/components/ProjectStatistics'
import WorkflowSelector from '@shared/components/WorkflowSelector'
import SubjectSetPicker from '@shared/components/SubjectSetPicker'

describe('Component > ClassifyPage', function () {
let wrapper
Expand Down Expand Up @@ -81,8 +82,12 @@ describe('Component > ClassifyPage', function () {
wrapper = shallow(<ClassifyPage workflowID='1234' workflows={workflows} />)
})

it('should show a workflow selector', function () {
expect(wrapper.find(WorkflowSelector)).to.have.lengthOf(1)
it('should not show a workflow selector', function () {
expect(wrapper.find(WorkflowSelector)).to.have.lengthOf(0)
})

it('should show a subject set picker', function () {
expect(wrapper.find(SubjectSetPicker)).to.have.lengthOf(1)
})
})

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { Box, Grid } from 'grommet'
import { arrayOf, shape, string } from 'prop-types'
import React from 'react'

import Background from '../Background'
import Introduction from '../Introduction'
import WorkflowSelector from '@shared/components/WorkflowSelector'
import WorkflowMenu from '../WorkflowMenu'
import ContentBox from '@shared/components/ContentBox'

function NarrowLayout (props) {
Expand All @@ -23,7 +24,9 @@ function NarrowLayout (props) {
<Grid margin={{ top: 'medium-neg', horizontal: 'medium' }}>
<ContentBox gap='medium' >
<Introduction />
<WorkflowSelector workflows={workflows} />
<WorkflowMenu
workflows={workflows}
/>
</ContentBox>
</Grid>
</Box>
Expand All @@ -34,4 +37,9 @@ NarrowLayout.defaultProps = {
workflows: []
}

NarrowLayout.propTypes = {
workflows: arrayOf(shape({
id: string.isRequired
}))
}
export default NarrowLayout
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import React from 'react'
import NarrowLayout from './NarrowLayout'
import Background from '../Background'
import Introduction from '../Introduction'
import WorkflowSelector from '@shared/components/WorkflowSelector'
import WorkflowMenu from '../WorkflowMenu'

describe('Component > Hero > NarrowLayout', function () {
let wrapper
Expand All @@ -25,8 +25,8 @@ describe('Component > Hero > NarrowLayout', function () {
expect(wrapper.find(Introduction)).to.have.lengthOf(1)
})

it('should render the `WorkflowSelector` component', function () {
expect(wrapper.find(WorkflowSelector)).to.have.lengthOf(1)
it('should render the `WorkflowMenu` component', function () {
expect(wrapper.find(WorkflowMenu)).to.have.lengthOf(1)
})

})
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { Box } from 'grommet'
import { arrayOf, shape, string } from 'prop-types'
import React from 'react'
import styled from 'styled-components'

import Background from '../Background'
import Introduction from '../Introduction'
import WorkflowSelector from '@shared/components/WorkflowSelector'
import WorkflowMenu from '../WorkflowMenu'
import ContentBox from '@shared/components/ContentBox'

const GrowBox = styled(Box)`
Expand All @@ -30,10 +31,22 @@ function WideLayout (props) {
width='38%'
>
<Introduction />
<WorkflowSelector workflows={workflows} />
<WorkflowMenu
workflows={workflows}
/>
</StyledContentBox>
</GrowBox>
)
}

WideLayout.defaultProps = {
workflows: []
}

WideLayout.propTypes = {
workflows: arrayOf(shape({
id: string.isRequired
}))
}

export default WideLayout
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import React from 'react'
import WideLayout from './WideLayout'
import Background from '../Background'
import Introduction from '../Introduction'
import WorkflowSelector from '@shared/components/WorkflowSelector'
import WorkflowMenu from '../WorkflowMenu'

describe('Component > Hero > WideLayout', function () {
let wrapper
Expand All @@ -25,8 +25,8 @@ describe('Component > Hero > WideLayout', function () {
expect(wrapper.find(Introduction)).to.have.lengthOf(1)
})

it('should render the `WorkflowSelector` component', function () {
expect(wrapper.find(WorkflowSelector)).to.have.lengthOf(1)
it('should render the `WorkflowMenu` component', function () {
expect(wrapper.find(WorkflowMenu)).to.have.lengthOf(1)
})

})
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import asyncStates from '@zooniverse/async-states'
import zooTheme from '@zooniverse/grommet-theme'
import { Grommet } from 'grommet'
import { Provider } from 'mobx-react'
import { mockWorkflow as mockGroupedWorkflow } from '@shared/components/SubjectSetPicker/helpers'
import WorkflowMenu from './WorkflowMenu'

const store = {
project: {
background: {
src: 'https://panoptes-uploads.zooniverse.org/production/project_background/260e68fd-d3ec-4a94-bb32-43ff91d5579a.jpeg'
},
description: 'Learn about and help document the wonders of nesting Western Bluebirds.',
display_name: 'Nest Quest Go: Western Bluebirds',
slug: 'brbcornell/nest-quest-go-western-bluebirds',
workflow_description: `Choose your own adventure! There are many ways to engage with this project:
1) "Nest Site": Smartphone-friendly, helps us understand where Western Bluebirds build their nests.
2) "Location": Smartphone-friendly, series of questions on the geographic location of the nest.
3) "Nest Attempt: Smartphone-friendly, for data-entry lovers to record nest attempt data on cards.
4) "Comments": For transcription lovers, we ask you to transcribe all the written comments on the cards.`
},
user: {
loadingState: asyncStates.success
}
}

const WORKFLOWS = [
{
completeness: 0.65,
default: false,
displayName: 'The Family and the Fishing Net',
id: '12345'
},
{
completeness: 0,
default: false,
displayName: 'Games Without Frontiers',
id: '7890'
},
{
completeness: 0.99,
default: false,
displayName: 'Shock The Monkey',
id: '5678'
}
]

function StoryContext (props) {
const { children, theme } = props

return (
<Grommet
background={{
dark: 'dark-1',
light: 'light-1'
}}
theme={theme}
themeMode={(theme.dark) ? 'dark' : 'light'}
>
<Provider store={store}>
{children}
</Provider>
</Grommet>
)
}

export default {
title: 'Project App / Screens / Project Home / Workflow Menu',
component: WorkflowMenu,
args: {
dark: false,
workflows: [ ...WORKFLOWS, mockGroupedWorkflow ]
}
}

export function Default({ dark, workflows }) {
return (
<StoryContext theme={{ ...zooTheme, dark }}>
<WorkflowMenu workflows={workflows} />
</StoryContext>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import counterpart from 'counterpart'
import { arrayOf, shape, string } from 'prop-types'
import { useRouter } from 'next/router'
import React, { useState } from 'react'
import { Modal } from '@zooniverse/react-components'

import WorkflowSelector from '@shared/components/WorkflowSelector'
import SubjectSetPicker from '@shared/components/SubjectSetPicker'

import en from './locales/en'
counterpart.registerTranslations('en', en)

export default function WorkflowMenu({ workflows }) {
const [ activeWorkflow, setActiveWorkflow ] = useState()
const router = useRouter()
const { owner, project } = router?.query || {}

function onSelectWorkflow(event, workflow) {
if (workflow.grouped) {
event.preventDefault()
setActiveWorkflow(workflow)
return false
}
return true
}

function onClose() {
setActiveWorkflow(null)
}

return (
<>
<WorkflowSelector
onSelect={onSelectWorkflow}
workflows={workflows}
/>
{activeWorkflow &&
<Modal
active
closeFn={onClose}
headingBackground='brand'
title={activeWorkflow.displayName || counterpart('WorkflowMenu.chooseASubjectSet')}
titleColor='neutral-6'
>
<SubjectSetPicker
onClose={onClose}
owner={owner}
project={project}
workflow={activeWorkflow}
/>
</Modal>
}
</>
)
}

WorkflowMenu.defaultProps = {
workflows: []
}

WorkflowMenu.propTypes = {
workflows: arrayOf(shape({
id: string.isRequired
}))
}
Loading