Skip to content

Commit 65e205a

Browse files
authored
Merge pull request #380 from openstax/sorting-studies
Added a feature to sort studies based on duration
2 parents 2d9ad23 + 14701de commit 65e205a

File tree

2 files changed

+80
-11
lines changed

2 files changed

+80
-11
lines changed

frontend/src/screens/learner.tsx

Lines changed: 60 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { React, useState } from '@common'
1+
import { React, styled } from '@common'
22
import { ParticipantStudy } from '@api'
33
import { Footer, TopNavBar } from '@components'
44
import { useEnvironment, useIsMobileDevice } from '@lib'
@@ -11,10 +11,10 @@ import { EffectCards, FreeMode, Navigation, Pagination } from 'swiper/modules';
1111
import { LearnerWelcomeModal } from './learner/learner-welcome-modal';
1212
import { UnsupportedCountryModal } from './learner/unsupported-country-modal';
1313
import { Badge, Box, Container, Flex, Group, Stack, Text, TextInput, Title } from '@mantine/core';
14-
import { IconSearch, IconX } from '@tabler/icons-react';
14+
import { IconSearch, IconX, IconPlus, IconMinus } from '@tabler/icons-react';
1515
import { groupBy, filter } from 'lodash';
1616
import { colors } from '@theme'
17-
import { useMemo } from 'react';
17+
import { useEffect, useMemo, useState } from 'react';
1818
import { orderBy, sortBy, uniqBy } from 'lodash-es';
1919

2020
const HighlightedStudies: FC = () => {
@@ -114,17 +114,69 @@ export const SearchResults: FC<{search: string, filteredStudies: ParticipantStud
114114
)
115115
}
116116

117+
const Circle = styled.div({
118+
borderRadius: '50%',
119+
border: `1px solid ${colors.blue}`,
120+
backgroundColor: colors.white,
121+
width: '.875rem',
122+
height: '.875rem',
123+
display: 'flex',
124+
justifyContent: 'center',
125+
alignItems: 'center',
126+
})
127+
128+
const StudyDuration: FC<{duration: Set<Number>, setDuration: Function, durationText: Number}> = ({ duration, setDuration, durationText }) => {
129+
130+
const handleDurationChange = (duration:Number) => {
131+
setDuration((prev:Set<Number>) => {
132+
const newDuration = new Set<Number>(prev)
133+
if(newDuration.has(duration)){
134+
newDuration.delete(duration)
135+
}else{
136+
newDuration.add(duration)
137+
}
138+
return newDuration
139+
})
140+
}
141+
142+
const [active, setActive] = useState<Boolean>(() => {
143+
return duration.has(durationText)
144+
})
145+
146+
useEffect(() => {
147+
setActive(() => {
148+
return duration.has(durationText)
149+
})
150+
}, [duration, durationText])
151+
152+
return (
153+
<Flex justify='center' align='center' gap='.5rem'
154+
pt='.25rem' pb='.25rem' pl='.625rem' pr='.625rem'
155+
bg={ active? colors.blue: colors.white }
156+
style={{ border: `1px solid ${colors.blue}`, borderRadius: '50rem', transition: 'all .1s ease-in', cursor: 'pointer' }}
157+
onClick={() => {
158+
handleDurationChange(durationText)
159+
}}>
160+
<Text size='sm' c={ active? colors.white: colors.blue }>~{String(durationText)} min</Text>
161+
<Circle>{active? <IconMinus size={10} color={colors.blue} stroke={3}/>: <IconPlus size={10} color={colors.blue} stroke={3}/>}</Circle>
162+
</Flex>
163+
)
164+
}
117165
export const StudiesContainer = () => {
118-
const { search, setSearch, filteredStudies } = useSearchStudies()
166+
const { search, setSearch, duration, setDuration, filteredStudies } = useSearchStudies()
119167

120168
return (
121169
<Container my='lg'>
122170
<Stack gap='lg'>
123-
<Flex justify='space-between' wrap='wrap'>
124-
<StudiesTitle search={search} filteredStudies={filteredStudies} />
125-
171+
<StudiesTitle search={search} filteredStudies={filteredStudies} />
172+
<Group justify='space-between' wrap='wrap' >
173+
<Flex justify='center' align='center' gap='md'>
174+
<StudyDuration duration={duration} durationText={5} setDuration={setDuration}></StudyDuration>
175+
<StudyDuration duration={duration} durationText={15} setDuration={setDuration}></StudyDuration>
176+
<StudyDuration duration={duration} durationText={25} setDuration={setDuration}></StudyDuration>
177+
</Flex>
126178
<SearchBar search={search} setSearch={setSearch} />
127-
</Flex>
179+
</Group>
128180

129181
<SearchResults search={search} filteredStudies={filteredStudies} />
130182

frontend/src/screens/learner/studies.ts

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { useApi } from '@lib'
22
import { useMutation, useQuery, useQueryClient } from 'react-query';
33
import { useMemo, useState } from 'react';
4+
import { isMultiSession, getNextAvailableStage } from '@models';
45
import Fuse from 'fuse.js'
56
import { LandStudyRequest, LearningPath, ParticipantStudy } from '@api';
67
import { orderBy } from 'lodash-es';
@@ -76,6 +77,7 @@ export const useParticipantStudies = () => {
7677

7778
export const useSearchStudies = () => {
7879
const [search, setSearch] = useState('')
80+
const [duration, setDuration] = useState(new Set<Number>([5, 15, 25]))
7981
const [filteredStudies, setFilteredStudies] = useState<ParticipantStudy[]>([])
8082
const { isLoading, studies } = useParticipantStudies()
8183

@@ -93,18 +95,33 @@ export const useSearchStudies = () => {
9395

9496
const fuse = new Fuse(studies, fuseOptions);
9597

98+
const filterStudiesBasedOnDuration = (studies: ParticipantStudy[]) => {
99+
return studies.filter((study) => {
100+
if(!isMultiSession(study) && duration.has(study.totalDuration)) return study
101+
102+
if(isMultiSession(study)) {
103+
const availableStage = getNextAvailableStage(study)
104+
if (availableStage && availableStage.durationMinutes && duration.has(availableStage.durationMinutes)) return study
105+
}
106+
})
107+
}
108+
96109
useMemo(() => {
97110
if (search) {
98111
const mappedResults = fuse.search(search).map(result => result.item)
99-
setFilteredStudies(mappedResults)
112+
const filteredResults = filterStudiesBasedOnDuration(mappedResults)
113+
setFilteredStudies(filteredResults)
100114
} else {
101-
setFilteredStudies(studies)
115+
const filteredResults = filterStudiesBasedOnDuration(studies)
116+
setFilteredStudies(filteredResults)
102117
}
103-
}, [search, isLoading])
118+
}, [search, isLoading, duration])
104119

105120
return {
106121
search,
107122
setSearch,
123+
duration,
124+
setDuration,
108125
filteredStudies,
109126
}
110127
}

0 commit comments

Comments
 (0)