mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Merge pull request #9689 from overleaf/jel-dash-state
[web] Fix dash view state updating GitOrigin-RevId: e46acf5de76a19ddd66cab3581edc971125dfdee
This commit is contained in:
parent
1b822621a1
commit
341ee52c3f
10 changed files with 60 additions and 66 deletions
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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]
|
||||||
)
|
)
|
||||||
|
|
|
@ -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'] }}
|
||||||
>
|
>
|
||||||
|
|
|
@ -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'] }}
|
||||||
>
|
>
|
||||||
|
|
|
@ -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])
|
||||||
|
|
||||||
|
|
|
@ -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)) {
|
||||||
|
return { ...p, selected: checked }
|
||||||
|
} else {
|
||||||
|
return p
|
||||||
|
}
|
||||||
})
|
})
|
||||||
setVisibleProjects(projects)
|
)
|
||||||
},
|
},
|
||||||
[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) => {
|
||||||
|
|
Loading…
Reference in a new issue