Skip to content

Commit

Permalink
feat(workspaces): remove form from workspace (#6754)
Browse files Browse the repository at this point in the history
* feat: route to remove workspace from forms

* feat: FE mutation to remove form from workspaces

* feat: add remove form from workspace to row actions

* chore: remove deprecated workspace form routes

* fix: design review

* fix: show workspace header for empty workspaces

* fix: span the workspace content

* test: workspace route test for removing from

* feat: use a post request for removing forms for extensibility

* test: update tests

* fix: update remove form workspace service users

* test: fix admin form controller tests

* refactor: abstract out empty workspace components

* chore: update meta action name and messages

* refactor: de-DRY workspace click

* chore: remove unused method and imports

* fix: revert mobile margins

* fix: prevent overflow of folder name in mobile
  • Loading branch information
foochifa authored Oct 23, 2023
1 parent 5cb8689 commit e1a6c33
Show file tree
Hide file tree
Showing 23 changed files with 281 additions and 262 deletions.
56 changes: 32 additions & 24 deletions frontend/src/features/workspace/WorkspaceContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,14 @@ import { RolloutAnnouncementModal } from '~features/rollout-announcement/Rollout
import { useUser } from '~features/user/queries'

import CreateFormModal from './components/CreateFormModal'
import { EmptyWorkspace } from './components/EmptyWorkspace'
import {
EmptyDefaultWorkspace,
EmptyNewWorkspace,
} from './components/EmptyWorkspace'
import { WorkspaceFormRows } from './components/WorkspaceFormRow'
import { WorkspaceHeader } from './components/WorkspaceHeader'
import { useWorkspaceContext } from './WorkspaceContext'

export const CONTAINER_MAXW = '69.5rem'

export const WorkspaceContent = (): JSX.Element => {
const { isLoading, totalFormsCount, isDefaultWorkspace } =
useWorkspaceContext()
Expand All @@ -43,47 +44,54 @@ export const WorkspaceContent = (): JSX.Element => {
isOpen={createFormModalDisclosure.isOpen}
onClose={createFormModalDisclosure.onClose}
/>
{totalFormsCount === 0 ? (
<EmptyWorkspace
{totalFormsCount === 0 && isDefaultWorkspace ? (
<EmptyDefaultWorkspace
handleOpenCreateFormModal={createFormModalDisclosure.onOpen}
isLoading={isLoading}
isFolder={!isDefaultWorkspace}
/>
) : (
<Grid
bg="neutral.100"
templateColumns="1fr"
templateRows="auto 1fr auto"
minH="100vh"
templateAreas="'header' 'main' 'footer'"
templateAreas=" 'header' 'main'"
overflowY="scroll"
>
<Container
gridArea="header"
maxW={CONTAINER_MAXW}
maxW="100%"
borderBottom="1px solid var(--chakra-colors-neutral-300)"
px="2rem"
px={{ base: '2rem', md: '4rem' }}
py="1rem"
>
<InlineMessage useMarkdown mb="2rem" mx="-2rem">
{dashboardMessage}
</InlineMessage>
{isDefaultWorkspace && (
<InlineMessage
useMarkdown
mb="2rem"
mx="-2rem"
justifyContent="center"
>
{dashboardMessage}
</InlineMessage>
)}
<WorkspaceHeader
handleOpenCreateFormModal={createFormModalDisclosure.onOpen}
/>
</Container>
<Box gridArea="main">
<RolloutAnnouncementModal
onClose={() => setHasSeenAnnouncement(true)}
isOpen={isAnnouncementModalOpen}
/>
<WorkspaceFormRows />
</Box>
<Container
gridArea="footer"
pt={{ base: '1rem', md: '1.5rem' }}
maxW={CONTAINER_MAXW}
/>
{totalFormsCount === 0 && !isDefaultWorkspace ? (
<EmptyNewWorkspace isLoading={isLoading} />
) : (
<Box gridArea="main">
<RolloutAnnouncementModal
onClose={() => setHasSeenAnnouncement(true)}
isOpen={isAnnouncementModalOpen}
/>
<WorkspaceFormRows />
</Box>
)}

<Container pt={{ base: '1rem', md: '1.5rem' }} />
</Grid>
)}
</>
Expand Down
8 changes: 8 additions & 0 deletions frontend/src/features/workspace/WorkspaceService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,14 @@ export const deleteWorkspace = async ({
return ApiService.delete(`${ADMIN_WORKSPACES_ENDPOINT}/${destWorkspaceId}`)
}

export const removeFormsFromWorkspaces = async ({
formIds,
}: {
formIds: string[]
}): Promise<void> => {
return ApiService.post(`${ADMIN_WORKSPACES_ENDPOINT}/remove`, { formIds })
}

export const createEmailModeForm = async (
body: CreateEmailFormBodyDto,
): Promise<FormDto> => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { EmptyWorkspace, EmptyWorkspacePage } from './EmptyWorkspace'

export const EmptyDefaultWorkspace = ({
isLoading,
handleOpenCreateFormModal,
}: EmptyWorkspacePage) => (
<EmptyWorkspace
isLoading={isLoading}
handleOpenCreateFormModal={handleOpenCreateFormModal}
title={"You don't have any forms yet"}
subText={'Get started by creating a new form'}
/>
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { EmptyWorkspace, EmptyWorkspacePage } from './EmptyWorkspace'

export const EmptyNewWorkspace = ({ isLoading }: EmptyWorkspacePage) => (
<EmptyWorkspace
isLoading={isLoading}
title={'You don’t have any forms in this folder yet'}
subText={'Organise your forms by grouping them into folders'}
/>
)
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { BiPlus } from 'react-icons/bi'
import { Box, Flex, Text } from '@chakra-ui/react'
import { Flex, Text } from '@chakra-ui/react'

import { useIsMobile } from '~hooks/useIsMobile'
import { fillHeightCss } from '~utils/fillHeightCss'
Expand All @@ -9,15 +9,20 @@ import { EmptyWorkspaceSvgr } from './EmptyWorkspaceSvgr'

export interface EmptyWorkspacePage {
isLoading: boolean
handleOpenCreateFormModal: () => void
isFolder?: boolean
handleOpenCreateFormModal?: () => void
}

interface EmptyWorkspaceProps extends EmptyWorkspacePage {
title: string
subText: string
}

export const EmptyWorkspace = ({
isLoading,
handleOpenCreateFormModal,
isFolder,
}: EmptyWorkspacePage): JSX.Element => {
title,
subText,
}: EmptyWorkspaceProps): JSX.Element => {
const isMobile = useIsMobile()

return (
Expand All @@ -31,16 +36,12 @@ export const EmptyWorkspace = ({
css={fillHeightCss}
>
<Text as="h2" textStyle="h2" color="primary.500" mb="1rem">
{isFolder
? 'You don’t have any forms in this folder yet'
: "You don't have any forms yet"}
{title}
</Text>
<Text textStyle="body-1" color="secondary.500">
{isFolder
? 'Organise your forms by grouping them into folders'
: 'Get started by creating a new form'}
{subText}
</Text>
{!isFolder && (
{!!handleOpenCreateFormModal && (
<Button
isFullWidth={isMobile}
isDisabled={isLoading}
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { EmptyWorkspace } from './EmptyWorkspace'
export { EmptyDefaultWorkspace } from './EmptyDefaultWorkspace'
export { EmptyNewWorkspace } from './EmptyNewWorkspace'
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export const RowActions = (props: RowActionsProps): JSX.Element => {
return (
<Box
pos="absolute"
right="2rem"
right={{ base: '2rem', md: '4rem' }}
top={{ md: '1.5rem' }}
bottom={{ base: '1.5rem', md: 'initial' }}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,20 +179,26 @@ const MoveWorkspaceDrawer = ({
formMeta: AdminDashboardFormMetaDto
buttonProps: Partial<ButtonProps>
}) => {
const { handleMoveForm } = useRowAction(formMeta)
const { handleRemoveFormFromWorkspaces, handleMoveForm } =
useRowAction(formMeta)
const { workspaces, getFormWorkspace } = useWorkspaceContext()

const handleWorkspaceClick = useCallback(
(destWorkspace: Workspace) =>
handleMoveForm(destWorkspace._id.toString(), destWorkspace.title),
[handleMoveForm],
)

const currFormWorkspace = useMemo(
() => getFormWorkspace(formMeta._id),
[formMeta, getFormWorkspace],
)

// if workspace selected is current workspace, delete
// else move to selected workspace
const handleWorkspaceAction = useCallback(
(destWorkspace: Workspace, currFormWorkspace?: Workspace) => {
if (destWorkspace._id === currFormWorkspace?._id)
handleRemoveFormFromWorkspaces()
else handleMoveForm(destWorkspace._id.toString(), destWorkspace.title)
},
[handleMoveForm, handleRemoveFormFromWorkspaces],
)

if (!workspaces) return null

return (
Expand All @@ -210,7 +216,7 @@ const MoveWorkspaceDrawer = ({
<Button
{...buttonProps}
key={workspace._id}
onClick={() => handleWorkspaceClick(workspace)}
onClick={() => handleWorkspaceAction(workspace, currFormWorkspace)}
>
<Flex justifyContent="space-between" w="100%" alignItems="center">
<Text textStyle="body-1" noOfLines={1}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,20 +41,26 @@ const MoveWorkspaceDropdown = ({
setIsMoveWorkspace: Dispatch<SetStateAction<boolean>>
formMeta: AdminDashboardFormMetaDto
}) => {
const { handleMoveForm } = useRowAction(formMeta)
const { handleMoveForm, handleRemoveFormFromWorkspaces } =
useRowAction(formMeta)
const { workspaces, getFormWorkspace } = useWorkspaceContext()

const handleWorkspaceClick = useCallback(
(destWorkspace: Workspace) =>
handleMoveForm(destWorkspace._id.toString(), destWorkspace.title),
[handleMoveForm],
)

const currFormWorkspace = useMemo(
() => getFormWorkspace(formMeta._id),
[formMeta, getFormWorkspace],
)

// if workspace selected is current workspace, delete
// else move to selected workspace
const handleWorkspaceAction = useCallback(
(destWorkspace: Workspace, currFormWorkspace?: Workspace) => {
if (destWorkspace._id === currFormWorkspace?._id)
handleRemoveFormFromWorkspaces()
else handleMoveForm(destWorkspace._id.toString(), destWorkspace.title)
},
[handleMoveForm, handleRemoveFormFromWorkspaces],
)

if (!workspaces) return null

return (
Expand All @@ -70,7 +76,7 @@ const MoveWorkspaceDropdown = ({
{workspaces.map((workspace) => (
<Menu.Item
key={workspace._id}
onClick={() => handleWorkspaceClick(workspace)}
onClick={() => handleWorkspaceAction(workspace, currFormWorkspace)}
>
<Flex
justifyContent="space-between"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ type UseRowActionReturn = {
handleCollaborators: () => void
handleDeleteForm: () => void
handleShareForm: () => void
handleRemoveFormFromWorkspaces: () => void
handleMoveForm: (destWorkspaceId: string, destWorkspaceTitle: string) => void
isFormAdmin: boolean
}
Expand All @@ -24,7 +25,8 @@ export const useRowAction = (
formMeta: AdminDashboardFormMetaDto,
): UseRowActionReturn => {
const { user } = useUser()
const { moveWorkspaceMutation } = useWorkspaceMutations()
const { moveWorkspaceMutation, removeFormFromWorkspacesMutation } =
useWorkspaceMutations()

const {
onOpenDupeFormModal,
Expand Down Expand Up @@ -79,13 +81,20 @@ export const useRowAction = (
[formMeta, moveWorkspaceMutation],
)

const handleRemoveFormFromWorkspaces = useCallback(async () => {
await removeFormFromWorkspacesMutation.mutateAsync({
formId: formMeta._id.toString(),
})
}, [formMeta, removeFormFromWorkspacesMutation])

return {
adminFormLink,
previewFormLink,
handleShareForm,
handleDuplicateForm,
handleCollaborators,
handleDeleteForm,
handleRemoveFormFromWorkspaces,
handleMoveForm,
isFormAdmin,
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Box, Divider, Flex, Stack, Text } from '@chakra-ui/react'

import { CONTAINER_MAXW } from '~features/workspace/WorkspaceContent'
import { useWorkspaceContext } from '~features/workspace/WorkspaceContext'

import { WorkspaceFormRow } from './WorkspaceFormRow'
Expand All @@ -10,7 +9,7 @@ import { WorkspaceRowsProvider } from './WorkspaceRowsContext'

const WorkspaceFormRowsSkeleton = () => {
return (
<Stack maxW={CONTAINER_MAXW} m="auto" spacing={0} divider={<Divider />}>
<Stack m="auto" spacing={0} divider={<Divider />}>
<WorkspaceFormRowSkeleton />
<WorkspaceFormRowSkeleton />
<WorkspaceFormRowSkeleton />
Expand Down Expand Up @@ -51,9 +50,13 @@ export const WorkspaceFormRows = (): JSX.Element => {

return (
<WorkspaceRowsProvider>
<Stack maxW={CONTAINER_MAXW} m="auto" spacing={0} divider={<Divider />}>
<Stack m="auto" spacing={0} divider={<Divider />}>
{displayedForms.map((meta) => (
<WorkspaceFormRow px="2rem" key={meta._id} formMeta={meta} />
<WorkspaceFormRow
px={{ base: '2rem', md: '4rem' }}
key={meta._id}
formMeta={meta}
/>
))}
</Stack>
</WorkspaceRowsProvider>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ export const WorkspaceHeader = ({
alignSelf="center"
>
<Skeleton isLoaded={!isLoading} alignSelf="center">
<Flex maxW="30.5rem">
<Flex maxW={{ base: '9.75rem', md: '30.5rem' }}>
<Text textStyle="h2" color="secondary.500" noOfLines={1}>
{headerText}
</Text>
Expand All @@ -109,13 +109,15 @@ export const WorkspaceHeader = ({
{isDesktop ? (
// Combination box used in desktop mode.
<Box gridArea="searchFilter">
<WorkspaceSearchbar
placeholder="Search by title"
value={activeSearch}
onChange={setActiveSearch}
filterValue={activeFilter}
onFilter={setActiveFilter}
/>
{totalFormsCount ? (
<WorkspaceSearchbar
placeholder="Search by title"
value={activeSearch}
onChange={setActiveSearch}
filterValue={activeFilter}
onFilter={setActiveFilter}
/>
) : null}
</Box>
) : (
<MobileWorkspaceSearchbar
Expand Down
Loading

0 comments on commit e1a6c33

Please sign in to comment.