Merge pull request #9689 from overleaf/jel-dash-state

[web] Fix dash view state updating

GitOrigin-RevId: e46acf5de76a19ddd66cab3581edc971125dfdee
This commit is contained in:
Jessica Lawshe 2022-09-26 12:39:52 -05:00 committed by Copybot
parent 1b822621a1
commit 341ee52c3f
10 changed files with 60 additions and 66 deletions

View file

@ -35,10 +35,7 @@ function ArchiveProjectButton({
const handleArchiveProject = useCallback(async () => { const handleArchiveProject = useCallback(async () => {
await archiveProject(project.id) await archiveProject(project.id)
updateProjectViewData({ ...project, archived: true, selected: false })
// update view
project.archived = true
updateProjectViewData(project)
}, [project, updateProjectViewData]) }, [project, updateProjectViewData])
if (project.archived) return null if (project.archived) return null

View file

@ -14,7 +14,8 @@ type CopyButtonProps = {
} }
function CopyProjectButton({ project, children }: CopyButtonProps) { function CopyProjectButton({ project, children }: CopyButtonProps) {
const { addClonedProjectToViewData } = useProjectListContext() const { addClonedProjectToViewData, updateProjectViewData } =
useProjectListContext()
const { t } = useTranslation() const { t } = useTranslation()
const text = t('copy') const text = t('copy')
const [showModal, setShowModal] = useState(false) const [showModal, setShowModal] = useState(false)
@ -31,16 +32,17 @@ function CopyProjectButton({ project, children }: CopyButtonProps) {
}, [isMounted]) }, [isMounted])
const handleAfterCloned = useCallback( const handleAfterCloned = useCallback(
project => { clonedProject => {
eventTracking.send( eventTracking.send(
'project-list-page-interaction', 'project-list-page-interaction',
'project action', 'project action',
'Clone' 'Clone'
) )
addClonedProjectToViewData(project) addClonedProjectToViewData(clonedProject)
updateProjectViewData({ ...project, selected: false })
setShowModal(false) setShowModal(false)
}, },
[addClonedProjectToViewData] [addClonedProjectToViewData, project, updateProjectViewData]
) )
if (project.archived || project.trashed) return null if (project.archived || project.trashed) return null

View file

@ -32,11 +32,12 @@ function TrashProjectButton({ project, children }: TrashProjectButtonProps) {
const handleTrashProject = useCallback(async () => { const handleTrashProject = useCallback(async () => {
await trashProject(project.id) await trashProject(project.id)
updateProjectViewData({
// update view ...project,
project.trashed = true trashed: true,
project.archived = false archived: false,
updateProjectViewData(project) selected: false,
})
}, [project, updateProjectViewData]) }, [project, updateProjectViewData])
if (project.trashed) return null if (project.trashed) return null

View file

@ -25,9 +25,7 @@ function UnarchiveProjectButton({
const handleUnarchiveProject = useCallback(async () => { const handleUnarchiveProject = useCallback(async () => {
await unarchiveProject(project.id) await unarchiveProject(project.id)
// update view updateProjectViewData({ ...project, archived: false, selected: false })
project.archived = false
updateProjectViewData(project)
}, [project, updateProjectViewData]) }, [project, updateProjectViewData])
if (!project.archived) return null if (!project.archived) return null

View file

@ -24,9 +24,7 @@ function UntrashProjectButton({
const handleUntrashProject = useCallback(async () => { const handleUntrashProject = useCallback(async () => {
await untrashProject(project.id) await untrashProject(project.id)
// update view updateProjectViewData({ ...project, trashed: false, selected: false })
project.trashed = false
updateProjectViewData(project)
}, [project, updateProjectViewData]) }, [project, updateProjectViewData])
if (!project.trashed) return null if (!project.trashed) return null

View file

@ -21,8 +21,7 @@ export default function ProjectListTableRow({
const handleCheckboxChange = useCallback( const handleCheckboxChange = useCallback(
(event: React.ChangeEvent<HTMLInputElement>) => { (event: React.ChangeEvent<HTMLInputElement>) => {
project.selected = event.target.checked updateProjectViewData({ ...project, selected: event.target.checked })
updateProjectViewData(project)
}, },
[project, updateProjectViewData] [project, updateProjectViewData]
) )

View file

@ -28,17 +28,14 @@ function ArchiveProjectsButton() {
const handleArchiveProjects = useCallback(async () => { const handleArchiveProjects = useCallback(async () => {
for (const project of selectedProjects) { for (const project of selectedProjects) {
await archiveProject(project.id) await archiveProject(project.id)
// update view updateProjectViewData({ ...project, archived: true, selected: false })
project.archived = true
project.selected = false
updateProjectViewData(project)
} }
}, [selectedProjects, updateProjectViewData]) }, [selectedProjects, updateProjectViewData])
return ( return (
<> <>
<Tooltip <Tooltip
id="tooltip-download-projects" id="tooltip-archive-projects"
description={text} description={text}
overlayProps={{ placement: 'bottom', trigger: ['hover', 'focus'] }} overlayProps={{ placement: 'bottom', trigger: ['hover', 'focus'] }}
> >

View file

@ -28,18 +28,19 @@ function TrashProjectsButton() {
const handleTrashProjects = useCallback(async () => { const handleTrashProjects = useCallback(async () => {
for (const project of selectedProjects) { for (const project of selectedProjects) {
await trashProject(project.id) await trashProject(project.id)
// update view updateProjectViewData({
project.trashed = true ...project,
project.archived = false trashed: true,
project.selected = false archived: false,
updateProjectViewData(project) selected: false,
})
} }
}, [selectedProjects, updateProjectViewData]) }, [selectedProjects, updateProjectViewData])
return ( return (
<> <>
<Tooltip <Tooltip
id="tooltip-download-projects" id="tooltip-trash-projects"
description={text} description={text}
overlayProps={{ placement: 'bottom', trigger: ['hover', 'focus'] }} overlayProps={{ placement: 'bottom', trigger: ['hover', 'focus'] }}
> >

View file

@ -11,10 +11,7 @@ function UntrashProjectsButton() {
const handleUntrashProjects = useCallback(async () => { const handleUntrashProjects = useCallback(async () => {
for (const [, project] of Object.entries(selectedProjects)) { for (const [, project] of Object.entries(selectedProjects)) {
await untrashProject(project.id) await untrashProject(project.id)
// update view updateProjectViewData({ ...project, trashed: false, selected: false })
project.trashed = false
project.selected = false
updateProjectViewData(project)
} }
}, [selectedProjects, updateProjectViewData]) }, [selectedProjects, updateProjectViewData])

View file

@ -81,7 +81,7 @@ type ProjectListContextValue = {
addTag: (tag: Tag) => void addTag: (tag: Tag) => void
renameTag: (tagId: string, newTagName: string) => void renameTag: (tagId: string, newTagName: string) => void
deleteTag: (tagId: string) => void deleteTag: (tagId: string) => void
updateProjectViewData: (project: Project) => void updateProjectViewData: (newProjectData: Project) => void
removeProjectFromView: (project: Project) => void removeProjectFromView: (project: Project) => void
removeProjectFromTagInView: (tagId: string, projectId: string) => void removeProjectFromTagInView: (tagId: string, projectId: string) => void
searchText: string searchText: string
@ -245,11 +245,16 @@ export function ProjectListProvider({ children }: ProjectListProviderProps) {
const selectOrUnselectAllProjects = useCallback( const selectOrUnselectAllProjects = useCallback(
checked => { checked => {
const projects = visibleProjects.map(project => { const visibleProjectIds = visibleProjects.map(p => p.id)
project.selected = checked setLoadedProjects(loadedProjects =>
return project loadedProjects.map(p => {
}) if (visibleProjectIds.includes(p.id)) {
setVisibleProjects(projects) return { ...p, selected: checked }
} else {
return p
}
})
)
}, },
[visibleProjects] [visibleProjects]
) )
@ -321,39 +326,38 @@ export function ProjectListProvider({ children }: ProjectListProviderProps) {
const addClonedProjectToViewData = useCallback( const addClonedProjectToViewData = useCallback(
project => { project => {
// clone API not using camelCase and does not return all data // clone API not using camelCase and does not return all data
project.id = project.project_id
const owner = { const owner = {
id: project.owner?._id, id: project.owner?._id,
email: project.owner?.email, email: project.owner?.email,
firstName: project.owner?.first_name, firstName: project.owner?.first_name,
lastName: project.owner?.last_name, lastName: project.owner?.last_name,
} }
project.owner = owner
project.lastUpdatedBy = project.owner const clonedProject = {
project.source = 'owner' ...project,
project.trashed = false id: project.project_id,
project.archived = false owner,
loadedProjects.push(project) lastUpdatedBy: owner,
const loadedProjectsSorted = sortProjects(loadedProjects, sort) source: 'owner',
const visibleProjectsSorted = sortProjects(visibleProjects, sort) trashed: false,
setVisibleProjects(visibleProjectsSorted) archived: false,
setLoadedProjects(loadedProjectsSorted) }
setLoadedProjects(loadedProjects => {
return sortProjects([...loadedProjects, clonedProject], sort)
})
}, },
[loadedProjects, visibleProjects, sort] [sort]
) )
const updateProjectViewData = useCallback( const updateProjectViewData = useCallback((newProjectData: Project) => {
(project: Project) => { setLoadedProjects(loadedProjects => {
const projects = loadedProjects.map((p: Project) => { return loadedProjects.map((p: Project) =>
if (p.id === project.id) { p.id === newProjectData.id ? { ...newProjectData } : p
p = project )
} })
return p }, [])
})
setLoadedProjects(projects)
},
[loadedProjects]
)
const removeProjectFromView = useCallback( const removeProjectFromView = useCallback(
(project: Project) => { (project: Project) => {