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

Create Edit Form #744

Merged
merged 10 commits into from
Dec 20, 2023
23 changes: 18 additions & 5 deletions frontend/src/app/tasks/TaskList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,19 @@

import Box from '@mui/joy/Box'

import { useGetTasks, useDeleteTask } from './hooks/useTask'
import { TaskBox } from './components/Task'
import { Project } from '@/domain/Project'
import { TaskType } from '@/domain/TaskType'

export const TaskList = () => {
import { useGetTasks } from './hooks/useTask'
import { TaskBox } from './components/TaskBox'

type TaskListProps = {
projects: Array<Project>
taskTypes: Array<TaskType>
}

export const TaskList = ({ projects, taskTypes }: TaskListProps) => {
const tasks = useGetTasks()
const { deleteTask } = useDeleteTask()

return (
<Box
Expand All @@ -22,7 +29,13 @@ export const TaskList = () => {
}}
>
{tasks.map((task) => (
<TaskBox key={task.id} task={task} deleteTask={deleteTask} />
<TaskBox
projects={projects}
taskTypes={taskTypes}
key={task.id}
task={task}
tasks={tasks}
/>
))}
</Box>
)
Expand Down
175 changes: 175 additions & 0 deletions frontend/src/app/tasks/__tests__/components/EditTask.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
import { EditTask } from '../../components/EditTask'
import { screen, renderWithUser } from '@/test-utils/test-utils'
import { useEditTask } from '../../hooks/useTask'

jest.mock('../../hooks/useTask')

const setupEditTaskForm = ({ closeForm = () => {} }: { closeForm?: () => void }) => {
const tasks = [
{
date: '2023-12-12',
story: 'story',
description: 'task description',
taskType: 'task-type-0',
projectId: 0,
userId: 0,
startTime: '13:50',
endTime: '14:00',
id: 0,
projectName: 'Holidays',
customerName: 'customer'
}
]

const task = {
date: '2023-12-12',
story: 'story',
description: 'task description',
taskType: 'task-type-0',
projectId: 0,
userId: 0,
startTime: '13:50',
endTime: '14:00',
id: 0,
projectName: 'Holidays',
customerName: 'customer'
}

const projects = [
{
id: 1,
isActive: true,
invoice: null,
init: '2023-11-17',
end: '2023-11-17',
estimatedHours: null,
movedHours: null,
description: 'Holidays',
projectType: null,
scheduleType: null,
customerId: 1,
areaId: 1
}
]

const taskTypes = [
{ name: 'mock task type', slug: 'task-type-0', active: true },
{ name: 'mock task type 2', slug: 'mock-test-2', active: true }
]

return renderWithUser(
<EditTask
closeForm={closeForm}
projects={projects}
taskTypes={taskTypes}
tasks={tasks}
task={task}
/>
)
}

describe('EditTask', () => {
beforeEach(() => {
;(useEditTask as jest.Mock).mockReturnValue({ editTask: () => {} })
})

it('Calls closeForm after clicking on Close form button', async () => {
const closeForm = jest.fn()
const { user } = setupEditTaskForm({ closeForm })

await user.click(screen.getByRole('button', { name: 'Close Form' }))

expect(closeForm).toBeCalled()
})

describe('Validation', () => {
it("Doesn't submit if it doesn't have a selected project", async () => {
const editTask = jest.fn()
;(useEditTask as jest.Mock).mockReturnValue({ editTask })

const { user } = setupEditTaskForm({})

await user.clear(screen.getByRole('combobox', { name: 'Select project' }))

await user.type(
screen.getByRole('combobox', { name: 'Select project' }),
'non existent project'
)

await user.keyboard('{Tab}')

await user.keyboard('{Enter}')

expect(editTask).not.toHaveBeenCalled()
})

it("Doesn't submit if it doesn't have a start time", async () => {
const editTask = jest.fn()
;(useEditTask as jest.Mock).mockReturnValue({ editTask })

const { user } = setupEditTaskForm({})

await user.clear(screen.getByRole('combobox', { name: 'From' }))

await user.keyboard('{Enter}')

expect(editTask).not.toHaveBeenCalled()
})

it("Doesn't submit if it doesn't have a end time", async () => {
const editTask = jest.fn()
;(useEditTask as jest.Mock).mockReturnValue({ editTask })

const { user } = setupEditTaskForm({})

await user.clear(screen.getByRole('combobox', { name: 'To' }))

await user.keyboard('{Enter}')

expect(editTask).not.toHaveBeenCalled()
})
})

describe('Submit', () => {
it('Submits the form with the correct values', async () => {
const editTask = jest.fn()
;(useEditTask as jest.Mock).mockReturnValue({ editTask })

const { user } = setupEditTaskForm({})

await user.clear(screen.getByRole('combobox', { name: 'Select project' }))
await user.type(screen.getByRole('combobox', { name: 'Select project' }), 'Holi')
await user.click(screen.getByRole('option', { name: 'Holidays' }))

await user.clear(screen.getByRole('combobox', { name: 'To' }))
await user.type(screen.getByRole('combobox', { name: 'To' }), '0:15')

await user.clear(screen.getByRole('combobox', { name: 'From' }))
await user.type(screen.getByRole('combobox', { name: 'From' }), '0:00')

await user.type(screen.getByRole('textbox', { name: 'Task description' }), '!')

await user.clear(screen.getByRole('combobox', { name: 'Select task type' }))
await user.click(screen.getByRole('combobox', { name: 'Select task type' }))
await user.click(screen.getByRole('option', { name: 'mock-test-2' }))

await user.type(screen.getByRole('textbox', { name: 'Story' }), '!')

await user.click(screen.getByRole('button', { name: 'Save' }))

expect(editTask).toHaveBeenCalledWith({
date: '2023-12-12',
customerName: 'customer',
description: 'task description!',
endTime: '0:15',
startTime: '0:00',
story: 'story!',
taskType: 'mock-test-2',
userId: 0,
id: 0,
projectId: 1,
projectName: 'Holidays'
})
})
})
})
108 changes: 108 additions & 0 deletions frontend/src/app/tasks/components/EditTask.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import Box from '@mui/joy/Box'
import Stack from '@mui/joy/Stack'
import Button from '@mui/joy/Button'

import { Task } from '@/domain/Task'
import { TaskType } from '@/domain/TaskType'
import { Project } from '@/domain/Project'

import { Select } from '@/ui/Select/Select'
import { TextArea } from '@/ui/TextArea/TextArea'
import { Input } from '@/ui/Input/Input'

import { TimePicker } from './TimePicker'
import { useEditTaskForm } from '../hooks/useEditTaskForm'

type EditTaskProps = {
task: Task
tasks: Array<Task>
projects: Array<Project>
taskTypes: Array<TaskType>
closeForm: () => void
}

export const EditTask = ({ task, tasks, projects, taskTypes, closeForm }: EditTaskProps) => {
const { handleChange, handleProject, formState, handleSubmit, resetForm } = useEditTaskForm({
task,
tasks,
closeForm
})

return (
<Stack
onSubmit={(e) => {
e.preventDefault()
handleSubmit()
}}
component="form"
gap="8px"
width="400px"
>
<Select
onChange={(value) => handleProject(value, projects)}
value={formState.projectName}
name="projectId"
label="Select project"
placeholder="Select project"
options={projects.map((project) => project.description)}
required
/>
<Select
name="taskType"
label="Select task type"
value={formState.taskType || ''}
onChange={(value) => handleChange('taskType', value)}
options={taskTypes.map((taskType) => taskType.slug)}
placeholder="Select task type"
/>
<Box display="flex" gap="8px">
<TimePicker
name="startTime"
label="From"
sx={{ width: '196px' }}
value={formState.startTime}
onChange={(value) => handleChange('startTime', value)}
required
/>

<TimePicker
name="endTime"
label="To"
sx={{ width: '196px' }}
value={formState.endTime}
onChange={(value) => handleChange('endTime', value)}
required
/>
</Box>
<TextArea
name="description"
onChange={(e) => handleChange('description', e.target.value)}
label="Task description"
placeholder="Task description..."
value={formState.description}
/>
<Input
value={formState.story}
onChange={(e) => handleChange('story', e.target.value)}
name="story"
placeholder="Story"
label="Story"
/>
<Box display="flex" justifyContent="flex-end" gap="8px">
<Button
sx={{ padding: '4px 8px', backgroundColor: 'white' }}
onClick={() => {
resetForm()
closeForm()
}}
variant="outlined"
>
Close Form
</Button>
<Button sx={{ width: '82px' }} type="submit">
Save
</Button>
</Box>
</Stack>
)
}
Loading