Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(form-workspaces/2): add form workspaces modals #4051

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion frontend/src/features/workspace/WorkspaceContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,6 @@ export const WorkspaceContent = ({
>
<WorkspaceHeader
isLoading={isLoading}
totalFormCount={totalFormCount}
handleOpenCreateFormModal={createFormModalDisclosure.onOpen}
/>
</Container>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { BiDotsHorizontalRounded } from 'react-icons/bi'
import { MenuButton, useDisclosure } from '@chakra-ui/react'

import IconButton from '~components/IconButton'
import Menu from '~components/Menu'

import { DeleteWorkspaceModal } from '../WorkspaceModals/DeleteWorkspaceModal'
import { RenameWorkspaceModal } from '../WorkspaceModals/RenameWorkspaceModal'

export const WorkspaceEditDropdown = (): JSX.Element => {
const renameModal = useDisclosure()
const deleteModal = useDisclosure()

return (
<>
<RenameWorkspaceModal
onClose={renameModal.onClose}
isOpen={renameModal.isOpen}
/>
<DeleteWorkspaceModal
onClose={deleteModal.onClose}
isOpen={deleteModal.isOpen}
/>

<Menu placement="bottom-start">
{({ isOpen }) => (
<>
<MenuButton
as={IconButton}
_active={{ bg: 'secondary.100' }}
isActive={isOpen}
aria-label="Edit Workspace"
icon={<BiDotsHorizontalRounded />}
variant="clear"
colorScheme="secondary"
/>
<Menu.List>
<Menu.Item onClick={renameModal.onOpen}>
Rename workspace
</Menu.Item>
<Menu.Item onClick={deleteModal.onOpen}>
Delete workspace
</Menu.Item>
</Menu.List>
</>
)}
</Menu>
</>
)
}
Original file line number Diff line number Diff line change
@@ -1,29 +1,24 @@
import { useState } from 'react'
import { BiPlus } from 'react-icons/bi'
import { Skeleton, Stack, Text } from '@chakra-ui/react'
import { Flex, Stack, Text } from '@chakra-ui/react'

import { useIsMobile } from '~hooks/useIsMobile'
import Button from '~components/Button'

import { SortOption } from '~features/workspace/types'

import { WorkspaceEditDropdown } from './WorkspaceEditDropdown'
import { WorkspaceSortDropdown } from './WorkspaceSortDropdown'

export interface WorkspaceHeaderProps {
/**
* Number of forms in the workspace.
* Defaults to '---' (to account for loading or error states)
*/
totalFormCount?: number | '---'
isLoading: boolean
handleOpenCreateFormModal: () => void
}

/**
* Header for listing number of forms, or updating the sort order of listed forms, etc.
* Header for editing workspace, or updating the sort order of listed forms, etc.
*/
export const WorkspaceHeader = ({
totalFormCount = '---',
isLoading,
handleOpenCreateFormModal,
}: WorkspaceHeaderProps): JSX.Element => {
Expand All @@ -37,15 +32,19 @@ export const WorkspaceHeader = ({
align={{ base: 'flex-start', md: 'center' }}
spacing="1rem"
>
<Text
flex={1}
as="h2"
textStyle="h2"
display="flex"
color="secondary.500"
>
All forms (<Skeleton isLoaded={!isLoading}>{totalFormCount}</Skeleton>)
</Text>
<Flex alignItems="center">
<Text
flex={1}
as="h2"
textStyle="h2"
display="flex"
color="secondary.500"
>
All forms
</Text>
<WorkspaceEditDropdown />
</Flex>

<Stack
w={{ base: '100%', md: 'auto' }}
spacing="1rem"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { useDisclosure } from '@chakra-ui/react'
import { Meta, Story } from '@storybook/react'

import { userHandlers } from '~/mocks/msw/handlers/user'

import { getMobileViewParameters } from '~utils/storybook'

import {
CreateWorkspaceModal,
CreateWorkspaceModalProps,
} from './CreateWorkspaceModal'

export default {
title: 'Pages/WorkspacePage/CreateWorkspaceModal',
component: CreateWorkspaceModal,
parameters: {
layout: 'fullscreen',
// Prevent flaky tests due to modal animating in.
chromatic: { pauseAnimationAtEnd: true },
msw: userHandlers({ delay: 0 }),
},
} as Meta

const Template: Story<CreateWorkspaceModalProps> = (args) => {
const modalProps = useDisclosure({ defaultIsOpen: true })

return (
<CreateWorkspaceModal
{...args}
{...modalProps}
onClose={() => console.log('close modal')}
/>
)
}

export const CreateWorkspace = Template.bind({})

export const CreateWorkspaceMobile = Template.bind({})
CreateWorkspaceMobile.parameters = getMobileViewParameters()
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import { useForm } from 'react-hook-form'
import {
FormControl,
Modal,
ModalBody,
ModalCloseButton,
ModalContent,
ModalFooter,
ModalHeader,
ModalOverlay,
Stack,
Text,
useBreakpointValue,
} from '@chakra-ui/react'

import { useIsMobile } from '~hooks/useIsMobile'
import { WORKSPACE_TITLE_VALIDATION_RULES } from '~utils/workspaceValidation'
import Button from '~components/Button'
import FormErrorMessage from '~components/FormControl/FormErrorMessage'
import Input from '~components/Input'

type CreateWorkspaceInputProps = {
title: string
}

export interface CreateWorkspaceModalProps {
isOpen: boolean
onClose: () => void
}

export const CreateWorkspaceModal = ({
isOpen,
onClose,
}: CreateWorkspaceModalProps): JSX.Element => {
const {
handleSubmit,
formState: { errors },
register,
} = useForm<CreateWorkspaceInputProps>({
defaultValues: {
title: '',
},
})
const modalSize = useBreakpointValue({
base: 'mobile',
xs: 'mobile',
md: 'md',
})
const isMobile = useIsMobile()

// TODO (hans): Implement create workspace functionality
const handleCreateWorkspace = handleSubmit((data) => {
onClose()
})

return (
<Modal isOpen={isOpen} onClose={onClose} size={modalSize}>
<ModalOverlay />
<ModalContent>
<ModalHeader>Create workspace</ModalHeader>
<ModalCloseButton />
<ModalBody>
<Text textStyle="subhead-1">Workspace name</Text>
<FormControl isRequired isInvalid={!!errors.title}>
<Input
mt="0.75rem"
autoFocus
{...register('title', WORKSPACE_TITLE_VALIDATION_RULES)}
/>
<FormErrorMessage>{errors?.title?.message}</FormErrorMessage>
</FormControl>
</ModalBody>

<ModalFooter>
<Stack
w="100vw"
direction={{ base: 'column', md: 'row' }}
spacing={{ base: '2rem', md: '1rem' }}
gap={{ base: '1rem', md: 'inherit' }}
flexDir={{ base: 'column-reverse', md: 'inherit' }}
justifyContent="flex-end"
>
<Button
onClick={onClose}
variant="clear"
colorScheme="secondary"
isFullWidth={isMobile}
>
Cancel
</Button>
<Button onClick={handleCreateWorkspace} isFullWidth={isMobile}>
Create workspace
</Button>
</Stack>
</ModalFooter>
</ModalContent>
</Modal>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { useDisclosure } from '@chakra-ui/react'
import { Meta, Story } from '@storybook/react'

import { userHandlers } from '~/mocks/msw/handlers/user'

import { getMobileViewParameters } from '~utils/storybook'

import {
DeleteWorkspaceModal,
DeleteWorkspaceModalProps,
} from '../WorkspaceModals/DeleteWorkspaceModal'

export default {
title: 'Pages/WorkspacePage/DeleteWorkspaceModal',
component: DeleteWorkspaceModal,
parameters: {
layout: 'fullscreen',
// Prevent flaky tests due to modal animating in.
chromatic: { pauseAnimationAtEnd: true },
msw: userHandlers({ delay: 0 }),
},
} as Meta

const Template: Story<DeleteWorkspaceModalProps> = (args) => {
const modalProps = useDisclosure({ defaultIsOpen: true })

return (
<DeleteWorkspaceModal
{...args}
{...modalProps}
onClose={() => console.log('close modal')}
/>
)
}
export const DeleteWorkspace = Template.bind({})

export const DeleteWorkspaceMobile = Template.bind({})
DeleteWorkspaceMobile.parameters = getMobileViewParameters()
Loading