Merge pull request #9567 from overleaf/ab-react-dash-keep-selected-filter

[web] Remember selected dashboard filter on page reload

GitOrigin-RevId: c5abbd4e74ed48c127ae5e60f69a0bd98fbfc876
This commit is contained in:
Davinder Singh 2022-09-15 10:58:27 +01:00 committed by Copybot
parent 0c5cdc2023
commit 3bacd89399
3 changed files with 66 additions and 31 deletions

View file

@ -15,13 +15,13 @@ function SidebarFilter({ filter, text }: SidebarFilterProps) {
const {
filter: activeFilter,
selectFilter,
selectedTag,
selectedTagId,
} = useProjectListContext()
return (
<li
className={
selectedTag === undefined && filter === activeFilter ? 'active' : ''
selectedTagId === undefined && filter === activeFilter ? 'active' : ''
}
>
<Button onClick={() => selectFilter(filter)}>{text}</Button>

View file

@ -5,7 +5,10 @@ import { useTranslation } from 'react-i18next'
import { Tag } from '../../../../../../app/src/Features/Tags/types'
import ColorManager from '../../../../ide/colors/ColorManager'
import Icon from '../../../../shared/components/icon'
import { useProjectListContext } from '../../context/project-list-context'
import {
UNCATEGORIZED_KEY,
useProjectListContext,
} from '../../context/project-list-context'
import CreateTagModal from './create-tag-modal'
import DeleteTagModal from './delete-tag-modal'
import RenameTagModal from './rename-tag-modal'
@ -15,7 +18,7 @@ export default function TagsList() {
const {
tags,
untaggedProjectsCount,
selectedTag,
selectedTagId,
selectTag,
addTag,
renameTag,
@ -98,7 +101,7 @@ export default function TagsList() {
{_.sortBy(tags, ['name']).map((tag, index) => {
return (
<li
className={`tag ${selectedTag === tag._id ? 'active' : ''}`}
className={`tag ${selectedTagId === tag._id ? 'active' : ''}`}
key={index}
>
<Button
@ -113,7 +116,7 @@ export default function TagsList() {
}}
>
<Icon
type={selectedTag === tag._id ? 'folder-open' : 'folder'}
type={selectedTagId === tag._id ? 'folder-open' : 'folder'}
/>
</span>
<span className="name">
@ -153,8 +156,15 @@ export default function TagsList() {
</li>
)
})}
<li className={`tag untagged ${selectedTag === null ? 'active' : ''}`}>
<Button className="tag-name" onClick={() => selectTag(null)}>
<li
className={`tag untagged ${
selectedTagId === UNCATEGORIZED_KEY ? 'active' : ''
}`}
>
<Button
className="tag-name"
onClick={() => selectTag(UNCATEGORIZED_KEY)}
>
<span className="name">{t('uncategorized')}</span>
<span className="subdued"> ({untaggedProjectsCount})</span>
</Button>

View file

@ -14,6 +14,7 @@ import {
Project,
Sort,
} from '../../../../../types/project/dashboard/api'
import usePersistedState from '../../../shared/hooks/use-persisted-state'
import getMeta from '../../../utils/meta'
import useAsync from '../../../shared/hooks/use-async'
import { getProjects } from '../util/api'
@ -46,6 +47,8 @@ const filters: FilterMap = {
},
}
export const UNCATEGORIZED_KEY = 'uncategorized'
type ProjectListContextValue = {
visibleProjects: Project[]
setVisibleProjects: React.Dispatch<React.SetStateAction<Project[]>>
@ -59,8 +62,8 @@ type ProjectListContextValue = {
untaggedProjectsCount: number
filter: Filter
selectFilter: (filter: Filter) => void
selectedTag?: string | null
selectTag: (tagName: string | null) => void
selectedTagId?: string | undefined
selectTag: (tagId: string) => void
addTag: (tag: Tag) => void
renameTag: (tagId: string, newTagName: string) => void
deleteTag: (tagId: string) => void
@ -86,9 +89,14 @@ export function ProjectListProvider({ children }: ProjectListProviderProps) {
by: 'lastUpdated',
order: 'desc',
})
const [filter, setFilter] = useState<Filter>('all')
const [selectedTag, setSelectedTag] = useState<string | null>()
const [tags, setTags] = useState<Tag[]>([])
const [filter, setFilter] = usePersistedState<Filter>(
'project-list-filter',
'all'
)
const [selectedTagId, setSelectedTagId] = usePersistedState<
string | undefined
>('project-list-selected-tag-id', undefined)
const [tags, setTags] = useState<Tag[]>(getMeta('ol-tags', []) as Tag[])
const [searchText, setSearchText] = useState('')
const {
isLoading: loading,
@ -98,8 +106,6 @@ export function ProjectListProvider({ children }: ProjectListProviderProps) {
} = useAsync<GetProjectsResponseBody>()
const isLoading = isIdle ? true : loading
useEffect(() => setTags(getMeta('ol-tags', []) as Tag[]), [])
useEffect(() => {
setLoadProgress(40)
runAsync(getProjects({ by: 'lastUpdated', order: 'desc' }))
@ -122,8 +128,8 @@ export function ProjectListProvider({ children }: ProjectListProviderProps) {
)
}
if (selectedTag !== undefined) {
if (selectedTag === null) {
if (selectedTagId !== undefined) {
if (selectedTagId === UNCATEGORIZED_KEY) {
const taggedProjectIds = _.uniq(
_.flatten(tags.map(tag => tag.project_ids))
)
@ -134,17 +140,30 @@ export function ProjectListProvider({ children }: ProjectListProviderProps) {
!taggedProjectIds.includes(project.id)
)
} else {
const tag = _.find(tags, tag => tag._id === selectedTag)
filteredProjects = filteredProjects.filter(project =>
tag?.project_ids?.includes(project.id)
)
const tag = _.find(tags, tag => tag._id === selectedTagId)
if (tag) {
filteredProjects = filteredProjects.filter(project =>
tag?.project_ids?.includes(project.id)
)
} else {
setFilter('all')
setSelectedTagId(undefined)
}
}
} else {
filteredProjects = _.filter(filteredProjects, filters[filter])
}
setVisibleProjects(filteredProjects)
}, [loadedProjects, tags, filter, selectedTag, searchText])
}, [
loadedProjects,
tags,
filter,
setFilter,
selectedTagId,
setSelectedTagId,
searchText,
])
const untaggedProjectsCount = useMemo(() => {
const taggedProjectIds = _.uniq(_.flatten(tags.map(tag => tag.project_ids)))
@ -156,14 +175,20 @@ export function ProjectListProvider({ children }: ProjectListProviderProps) {
).length
}, [tags, loadedProjects])
const selectFilter = useCallback((filter: Filter) => {
setFilter(filter)
setSelectedTag(undefined)
}, [])
const selectFilter = useCallback(
(filter: Filter) => {
setFilter(filter)
setSelectedTagId(undefined)
},
[setFilter, setSelectedTagId]
)
const selectTag = useCallback((tagId: string | null) => {
setSelectedTag(tagId)
}, [])
const selectTag = useCallback(
(tagId: string) => {
setSelectedTagId(tagId)
},
[setSelectedTagId]
)
const addTag = useCallback((tag: Tag) => {
setTags(tags => _.uniqBy(_.concat(tags, [tag]), '_id'))
@ -219,7 +244,7 @@ export function ProjectListProvider({ children }: ProjectListProviderProps) {
isLoading,
loadProgress,
renameTag,
selectedTag,
selectedTagId,
selectFilter,
selectTag,
setSearchText,
@ -241,7 +266,7 @@ export function ProjectListProvider({ children }: ProjectListProviderProps) {
isLoading,
loadProgress,
renameTag,
selectedTag,
selectedTagId,
selectFilter,
selectTag,
setSearchText,