diff --git a/lib/components/modals/Modal.tsx b/lib/components/modals/Modal.tsx
index 55a5b9e29..f031e9953 100644
--- a/lib/components/modals/Modal.tsx
+++ b/lib/components/modals/Modal.tsx
@@ -1,6 +1,7 @@
import { useContext, useEffect, type MouseEventHandler, type PropsWithChildren, type ReactNode } from 'react'
import ReactDOM from 'react-dom'
import { X } from 'lucide-react'
+import { apply } from '@twind/core'
import { Span } from '../Span'
import { tx, tw } from '../../twind'
import type { Languages } from '../../hooks/useLanguage'
@@ -130,7 +131,8 @@ export const Modal = ({
/>
)}
+ className={tx(apply('fixed left-1/2 top-1/2 -translate-y-1/2 -translate-x-1/2 flex flex-col p-4 bg-white rounded-xl shadow-xl'), modalClassName)}
+ >
{children}
diff --git a/lib/components/user-input/Checkbox.tsx b/lib/components/user-input/Checkbox.tsx
index 75c564047..096b04d87 100644
--- a/lib/components/user-input/Checkbox.tsx
+++ b/lib/components/user-input/Checkbox.tsx
@@ -3,6 +3,7 @@ import * as CheckboxPrimitive from '@radix-ui/react-checkbox'
import type { CheckedState } from '@radix-ui/react-checkbox'
import { Check, Minus } from 'lucide-react'
import { tw, tx } from '../../twind'
+import type { AppColor } from '../../twind/config'
import type { LabelProps } from './Label'
import { Label } from './Label'
@@ -18,7 +19,8 @@ type CheckboxProps = {
onChange?: (checked: boolean) => void,
onChangeTristate?: (checked: CheckedState) => void,
size?: number,
- className?: string
+ className?: string,
+ color?: AppColor
}
/**
@@ -34,12 +36,12 @@ const ControlledCheckbox = ({
onChange,
onChangeTristate,
size = 18,
- className = ''
+ className = '',
+ color = 'hw-primary',
}: CheckboxProps) => {
// Make sure there is an appropriate minimum
const usedSize = Math.max(size, 14)
const innerIconSize = usedSize - 4
-
return (
diff --git a/tasks/components/layout/TaskDetailView.tsx b/tasks/components/layout/TaskDetailView.tsx
deleted file mode 100644
index 8b403a954..000000000
--- a/tasks/components/layout/TaskDetailView.tsx
+++ /dev/null
@@ -1,482 +0,0 @@
-import { useTranslation, type PropsForTranslation } from '@helpwave/common/hooks/useTranslation'
-import { tw, tx } from '@helpwave/common/twind'
-import { ToggleableInput } from '@helpwave/common/components/user-input/ToggleableInput'
-import { Textarea } from '@helpwave/common/components/user-input/Textarea'
-import { Button } from '@helpwave/common/components/Button'
-import { X } from 'lucide-react'
-import { TimeDisplay } from '@helpwave/common/components/TimeDisplay'
-import { Span } from '@helpwave/common/components/Span'
-import { Input } from '@helpwave/common/components/user-input/Input'
-import type { Languages } from '@helpwave/common/hooks/useLanguage'
-import { useRouter } from 'next/router'
-import { useEffect, useState } from 'react'
-import { LoadingAnimation } from '@helpwave/common/components/LoadingAnimation'
-import { LoadingAndErrorComponent } from '@helpwave/common/components/LoadingAndErrorComponent'
-import { ConfirmDialog } from '@helpwave/common/components/modals/ConfirmDialog'
-import { ModalHeader } from '@helpwave/common/components/modals/Modal'
-import { useAuth } from '@helpwave/api-services/authentication/useAuth'
-import type { TaskDTO, TaskStatus } from '@helpwave/api-services/types/tasks/task'
-import { emptyTask } from '@helpwave/api-services/types/tasks/task'
-import {
- usePersonalTaskTemplateQuery,
- useWardTaskTemplateQuery
-} from '@helpwave/api-services/mutations/tasks/task_template_mutations'
-import {
- useAssignTaskMutation,
- useSubTaskAddMutation,
- useTaskCreateMutation,
- useTaskQuery,
- useTaskUpdateMutation,
- useUnassignTaskMutation
-} from '@helpwave/api-services/mutations/tasks/task_mutations'
-import type { TaskTemplateDTO } from '@helpwave/api-services/types/tasks/tasks_templates'
-import { formatDate } from '@helpwave/common/util/date'
-import { TaskTemplateListColumn } from '../TaskTemplateListColumn'
-import { SubtaskView } from '../SubtaskView'
-import { TaskVisibilitySelect } from '@/components/selects/TaskVisibilitySelect'
-import { TaskStatusSelect } from '@/components/selects/TaskStatusSelect'
-import { AssigneeSelect } from '@/components/selects/AssigneeSelect'
-
-type TaskDetailViewTranslation = {
- close: string,
- notes: string,
- subtasks: string,
- assignee: string,
- dueDate: string,
- status: string,
- visibility: string,
- creationTime: string,
- private: string,
- public: string,
- create: string,
- delete: string,
- deleteTask: string,
- deleteTaskDescription: string,
- publish: string,
- publishTask: string,
- publishTaskDescription: string,
- finish: string
-}
-
-const defaultTaskDetailViewTranslation: Record = {
- en: {
- close: 'Close',
- notes: 'Notes',
- subtasks: 'Subtasks',
- assignee: 'Assignee',
- dueDate: 'Due date',
- status: 'Status',
- visibility: 'Visibility',
- creationTime: 'Creation time',
- private: 'private',
- public: 'public',
- create: 'Create',
- delete: 'Delete',
- deleteTask: 'Delete Task',
- deleteTaskDescription: 'The Tasks will be irrevocably removed',
- publish: 'Publish',
- publishTask: 'Publish task',
- publishTaskDescription: 'This cannot be undone',
- finish: 'Finish task',
- },
- de: {
- close: 'Schließen',
- notes: 'Notizen',
- subtasks: 'Unteraufgaben',
- assignee: 'Verantwortlich',
- dueDate: 'Fälligkeitsdatum',
- status: 'Status',
- visibility: 'Sichtbarkeit',
- creationTime: 'Erstell Zeit',
- private: 'privat',
- public: 'öffentlich',
- create: 'Hinzufügen',
- delete: 'Löschen',
- deleteTask: 'Task löschen',
- deleteTaskDescription: 'Der Tasks wird unwiederruflich gelöscht',
- publish: 'Veröffentlichen',
- publishTask: 'Task Veröffentlichen',
- publishTaskDescription: 'Diese Handlung kann nicht rückgängig gemacht werden',
- finish: 'Fertigstellen',
- }
-}
-
-type TaskDetailViewSidebarProps = {
- task: TaskDTO,
- setTask: (task: TaskDTO) => void,
- isCreating: boolean
-}
-
-const TaskDetailViewSidebar = ({
- overwriteTranslation,
- task,
- setTask,
- isCreating
-}: PropsForTranslation) => {
- const translation = useTranslation(defaultTaskDetailViewTranslation, overwriteTranslation)
-
- const [isShowingPublicDialog, setIsShowingPublicDialog] = useState(false)
- const { organization } = useAuth()
-
- const updateTaskMutation = useTaskUpdateMutation()
-
- const assignTaskToUserMutation = useAssignTaskMutation()
- const unassignTaskToUserMutation = useUnassignTaskMutation()
-
- const updateTaskLocallyAndExternally = (task: TaskDTO) => {
- setTask(task)
- if (!isCreating) {
- updateTaskMutation.mutate(task)
- }
- }
-
- return (
-
-
setIsShowingPublicDialog(false)}
- onCancel={() => setIsShowingPublicDialog(false)}
- onCloseClick={() => setIsShowingPublicDialog(false)}
- onConfirm={() => {
- setIsShowingPublicDialog(false)
- const newTask = {
- ...task,
- isPublicVisible: true
- }
- setTask(newTask)
- updateTaskLocallyAndExternally(newTask)
- }}
- titleText={translation.publishTask}
- descriptionText={translation.publishTaskDescription}
- />
-
-
-
-
{
- setTask({ ...task, assignee })
- if (!isCreating) {
- assignTaskToUserMutation.mutate({ taskId: task.id, userId: assignee })
- }
- }}
- />
-
-
-
-
-
-
- {
- if (!event.target.value) {
- event.preventDefault()
- return
- }
- const dueDate = new Date(event.target.value)
- updateTaskLocallyAndExternally({
- ...task,
- dueDate
- })
- }}
- />
- { /* TODO reenable when backend has implemented a remove duedate
-
- */}
-
-
-
-
- {
- const newTask = { ...task, status }
- if (!isCreating) {
- updateTaskMutation.mutate(newTask)
- }
- setTask(newTask)
- }}
- />
-
-
-
- {!isCreating ? (
-
- {task.isPublicVisible ? translation.public : translation.private}
- {!task.isPublicVisible && !isCreating && (
-
- )}
-
- ) : null}
- {isCreating && (
-
{
- setTask({ ...task, isPublicVisible: !task.isPublicVisible })
- }}
- />
- )}
-
- {task.createdAt && (
-
- {translation.creationTime}
-
-
- )}
-
- )
-}
-
-export type TaskDetailViewProps = {
- /**
- * A not set or empty taskId is seen as creating a new task
- */
- taskId?: string,
- wardId: string,
- patientId: string,
- onClose: () => void,
- initialStatus?: TaskStatus
-}
-
-/**
- * The view for changing or creating a task and it's information
- */
-export const TaskDetailView = ({
- overwriteTranslation,
- patientId,
- taskId = '',
- wardId,
- initialStatus,
- onClose
-}: PropsForTranslation) => {
- const translation = useTranslation(defaultTaskDetailViewTranslation, overwriteTranslation)
- const [selectedTemplateId, setSelectedTemplateId] = useState(undefined)
- const [isShowingDeleteDialog, setIsShowingDeleteDialog] = useState(false)
- const router = useRouter()
- const { user } = useAuth()
-
- const minTaskNameLength = 4
- const maxTaskNameLength = 32
-
- const isCreating = taskId === ''
- const {
- data,
- isLoading,
- isError
- } = useTaskQuery(taskId)
-
- const [task, setTask] = useState({
- ...emptyTask,
- status: initialStatus ?? 'todo'
- })
-
- const addSubtaskMutation = useSubTaskAddMutation(taskId)
-
- const assignTaskToUserMutation = useAssignTaskMutation()
- const updateTaskMutation = useTaskUpdateMutation()
-
- const createTaskMutation = useTaskCreateMutation(newTask => {
- newTask.subtasks.forEach(value => addSubtaskMutation.mutate({ ...value, taskId: newTask.id }))
- if (newTask.assignee) {
- assignTaskToUserMutation.mutate({ taskId: newTask.id, userId: newTask.assignee })
- }
- onClose()
- }, patientId)
-
- useEffect(() => {
- if (data && taskId) {
- setTask(data)
- }
- }, [data, taskId])
-
- const {
- data: personalTaskTemplatesData,
- isLoading: personalTaskTemplatesIsLoading,
- error: personalTaskTemplatesError
- } = usePersonalTaskTemplateQuery(user?.id)
- const {
- data: wardTaskTemplatesData,
- isLoading: wardTaskTemplatesIsLoading,
- error: wardTaskTemplatesError
- } = useWardTaskTemplateQuery(wardId)
-
- const taskNameMinimumLength = 1
- const isValid = task.name.length >= taskNameMinimumLength
-
- const updateTaskLocallyAndExternally = (task: TaskDTO) => {
- setTask(task)
- if (!isCreating) {
- updateTaskMutation.mutate(task)
- }
- }
-
- const buttons = (
-
- {!isCreating ?
- (
- <>
-
- {task.status !== 'done' && (
-
- )}
- >
- )
- :
- (
-
- )
- }
-
- )
-
- const tasksDetails = (
-
-
setTask({ ...task, name })}
- onEditCompleted={(text) => updateTaskLocallyAndExternally({ ...task, name: text })}
- labelClassName={tw('text-2xl font-bold')}
- minLength={minTaskNameLength}
- maxLength={maxTaskNameLength}
- size={24}
- />
- )}
- onCloseClick={onClose}
- />
-
-
-
-
-
setTask({ ...task, subtasks })}/>
-
-
-
- {buttons}
-
- )
-
- const taskTemplates =
- personalTaskTemplatesData && wardTaskTemplatesData
- ? [
- ...(personalTaskTemplatesData.map((taskTemplate) => ({
- taskTemplate,
- type: 'personal' as const
- }))),
- ...(wardTaskTemplatesData.map((taskTemplate) => ({
- taskTemplate,
- type: 'ward' as const
- })))
- ].sort((a, b) => a.taskTemplate.name.localeCompare(b.taskTemplate.name))
- : []
-
- const templateSidebar = (
-
- {personalTaskTemplatesData && wardTaskTemplatesData && (
- {
- setSelectedTemplateId(id)
- setTask({ ...task, name, notes, subtasks })
- }}
- onColumnEditClick={() => router.push(`/ward/${wardId}/templates`)}
- />
- )}
- {(personalTaskTemplatesIsLoading || wardTaskTemplatesIsLoading || personalTaskTemplatesError || wardTaskTemplatesError) ?
- : null}
-
- )
-
- return (
- <>
- {
- // deleteTaskMutation.mutate(task.id)
- setIsShowingDeleteDialog(false)
- }}
- onCancel={() => setIsShowingDeleteDialog(false)}
- onCloseClick={() => setIsShowingDeleteDialog(false)}
- onBackgroundClick={() => setIsShowingDeleteDialog(false)}
- buttonOverwrites={[{}, {}, { color: 'hw-negative' }]}
- />
-
-
- {isCreating && templateSidebar}
- {tasksDetails}
-
-
- >
- )
-}
diff --git a/tasks/components/modals/TaskDetailModal.tsx b/tasks/components/modals/TaskDetailModal.tsx
index 0c0ab394a..65905d651 100644
--- a/tasks/components/modals/TaskDetailModal.tsx
+++ b/tasks/components/modals/TaskDetailModal.tsx
@@ -1,30 +1,584 @@
-import { tx } from '@helpwave/common/twind'
-import { Modal, type ModalProps, type ModalHeaderProps } from '@helpwave/common/components/modals/Modal'
-import type { TaskDetailViewProps } from '@/components/layout/TaskDetailView'
-import { TaskDetailView } from '@/components/layout/TaskDetailView'
+import { tw, tx } from '@helpwave/common/twind'
+import { Modal, type ModalProps, type ModalHeaderProps, ModalHeader } from '@helpwave/common/components/modals/Modal'
+import { useEffect, useState } from 'react'
+import type { Languages } from '@helpwave/common/hooks/useLanguage'
+import { noop } from '@helpwave/common/util/noop'
+import { Checkbox } from '@helpwave/common/components/user-input/Checkbox'
+import { formatDate } from '@helpwave/common/util/date'
+import { Avatar } from '@helpwave/common/components/Avatar'
+import { ArrowLeftFromLine, ArrowRightFromLine, Plus, X } from 'lucide-react'
+import type { TaskDTO, TaskStatus } from '@helpwave/api-services/types/tasks/task'
+import { emptyTask } from '@helpwave/api-services/types/tasks/task'
+import type { PropsForTranslation } from '@helpwave/common/hooks/useTranslation'
+import { useTranslation } from '@helpwave/common/hooks/useTranslation'
+import { apply } from '@twind/core'
+import { useAuth } from '@helpwave/api-services/authentication/useAuth'
+import {
+ useAssignTaskMutation, useSubTaskAddMutation, useSubTaskUpdateMutation, useTaskCreateMutation, useTaskQuery,
+ useTaskUpdateMutation,
+ useUnassignTaskMutation
+} from '@helpwave/api-services/mutations/tasks/task_mutations'
+import { ConfirmDialog } from '@helpwave/common/components/modals/ConfirmDialog'
+import { Span } from '@helpwave/common/components/Span'
+import { Button } from '@helpwave/common/components/Button'
+import { Input } from '@helpwave/common/components/user-input/Input'
+import { TimeDisplay } from '@helpwave/common/components/TimeDisplay'
+import { LoadingAndErrorComponent } from '@helpwave/common/components/LoadingAndErrorComponent'
+import { ToggleableInput } from '@helpwave/common/components/user-input/ToggleableInput'
+import { Textarea } from '@helpwave/common/components/user-input/Textarea'
+import { TaskVisibilitySelect } from '@/components/selects/TaskVisibilitySelect'
+import { TaskStatusSelect } from '@/components/selects/TaskStatusSelect'
+import { AssigneeSelect } from '@/components/selects/AssigneeSelect'
-export type TaskDetailModalProps =
- Omit
- & TaskDetailViewProps
+type TaskDetailViewTranslation = {
+ close: string,
+ notes: string,
+ subtasks: string,
+ assignee: string,
+ dueDate: string,
+ status: string,
+ visibility: string,
+ creationTime: string,
+ private: string,
+ public: string,
+ create: string,
+ delete: string,
+ deleteTask: string,
+ deleteTaskDescription: string,
+ publish: string,
+ publishTask: string,
+ publishTaskDescription: string,
+ finish: string,
+ following: string,
+ previous: string,
+ addTask: string
+}
+
+const defaultTaskDetailViewTranslation: Record = {
+ en: {
+ close: 'Close',
+ notes: 'Notes',
+ subtasks: 'Subtasks',
+ assignee: 'Assignee',
+ dueDate: 'Due date',
+ status: 'Status',
+ visibility: 'Visibility',
+ creationTime: 'Creation time',
+ private: 'private',
+ public: 'public',
+ create: 'Create',
+ delete: 'Delete',
+ deleteTask: 'Delete Task',
+ deleteTaskDescription: 'The Tasks will be irrevocably removed',
+ publish: 'Publish',
+ publishTask: 'Publish task',
+ publishTaskDescription: 'This cannot be undone',
+ finish: 'Finish task',
+ following: 'Following Tasks',
+ previous: 'Previous Tasks',
+ addTask: 'Add Task'
+ },
+ de: {
+ close: 'Schließen',
+ notes: 'Notizen',
+ subtasks: 'Unteraufgaben',
+ assignee: 'Verantwortlich',
+ dueDate: 'Fälligkeitsdatum',
+ status: 'Status',
+ visibility: 'Sichtbarkeit',
+ creationTime: 'Erstell Zeit',
+ private: 'privat',
+ public: 'öffentlich',
+ create: 'Hinzufügen',
+ delete: 'Löschen',
+ deleteTask: 'Task löschen',
+ deleteTaskDescription: 'Der Tasks wird unwiederruflich gelöscht',
+ publish: 'Veröffentlichen',
+ publishTask: 'Task Veröffentlichen',
+ publishTaskDescription: 'Diese Handlung kann nicht rückgängig gemacht werden',
+ finish: 'Fertigstellen',
+ following: 'Nachfolgende Tasks',
+ previous: 'Vorherige Tasks',
+ addTask: 'Task hinzufügen'
+ }
+}
+
+type SubTaskTileProps = {
+ name: string,
+ isDone: boolean,
+ assignee?: string,
+ dueDate?: Date,
+ onClick?: () => void,
+ onDoneClick?: (isDone: boolean) => void
+}
+
+const SubTaskTile = ({
+ name,
+ isDone,
+ dueDate,
+ assignee,
+ onClick = noop,
+ onDoneClick = noop,
+}: SubTaskTileProps) => {
+ return (
+
+
+
+ {name}
+
+
+ {dueDate && (
{formatDate(dueDate)})}
+ { /* TODO replace url later on */}
+ {assignee ? (
) : (
+
+ )}
+
+
+ )
+}
+
+type TaskRelationType = 'following' | 'previous'
+
+type ExpandableSidebarProps = {
+ tasks: TaskDTO[],
+ type: TaskRelationType,
+ isExpanded: boolean,
+ onExpansionChange: (isExpanded: boolean) => void,
+ onTaskSelected?: (task: TaskDTO) => void,
+ onAddClick?: (type: TaskRelationType) => void,
+ onSubtaskChange?: (task: TaskDTO) => void,
+ className?: string
+}
+
+const ExpandableSidebar = ({
+ tasks,
+ type,
+ isExpanded,
+ onExpansionChange,
+ onTaskSelected = noop,
+ onAddClick = noop,
+ onSubtaskChange = noop,
+ className = '',
+}: PropsForTranslation) => {
+ const translation = useTranslation(defaultTaskDetailViewTranslation)
+
+ return (
+ {
+ if (!isExpanded) {
+ onExpansionChange(true)
+ }
+ }}>
+
+ {isExpanded && (
{type === 'following' ? translation.following : translation.previous})}
+ {tasks.map(task => isExpanded ?
+ (
+
onTaskSelected(task)}
+ onDoneClick={isDone => onSubtaskChange({ ...task, status: isDone ? 'done' : 'todo' })}
+ />
+ ) :
+ (
+
+ )
+ )}
+ {isExpanded ? (
+
+ ) : (
+
+ )}
+
+
+
+ )
+}
+
+type InformationSectionProps = {
+ task: TaskDTO,
+ setTask: (task: TaskDTO) => void,
+ isCreating: boolean
+}
+
+const InformationSection = ({
+ overwriteTranslation,
+ task,
+ setTask,
+ isCreating
+}: PropsForTranslation) => {
+ const translation = useTranslation(defaultTaskDetailViewTranslation, overwriteTranslation)
+
+ const [isShowingPublicDialog, setIsShowingPublicDialog] = useState(false)
+ const { organization } = useAuth()
+
+ const updateTaskMutation = useTaskUpdateMutation()
+
+ const assignTaskToUserMutation = useAssignTaskMutation()
+ const unassignTaskToUserMutation = useUnassignTaskMutation()
+
+ const updateTaskLocallyAndExternally = (task: TaskDTO) => {
+ setTask(task)
+ if (!isCreating) {
+ updateTaskMutation.mutate(task)
+ }
+ }
+
+ return (
+
+
setIsShowingPublicDialog(false)}
+ onCancel={() => setIsShowingPublicDialog(false)}
+ onCloseClick={() => setIsShowingPublicDialog(false)}
+ onConfirm={() => {
+ setIsShowingPublicDialog(false)
+ const newTask = {
+ ...task,
+ isPublicVisible: true
+ }
+ setTask(newTask)
+ updateTaskLocallyAndExternally(newTask)
+ }}
+ titleText={translation.publishTask}
+ descriptionText={translation.publishTaskDescription}
+ />
+
+
+
+
{
+ setTask({ ...task, assignee })
+ if (!isCreating) {
+ assignTaskToUserMutation.mutate({ taskId: task.id, userId: assignee })
+ }
+ }}
+ />
+
+
+
+
+
+
+ {
+ if (!event.target.value) {
+ event.preventDefault()
+ return
+ }
+ const dueDate = new Date(event.target.value)
+ updateTaskLocallyAndExternally({
+ ...task,
+ dueDate
+ })
+ }}
+ />
+ { /* TODO reenable when backend has implemented a remove duedate
+
+ */}
+
+
+
+
+ {
+ const newTask = { ...task, status }
+ if (!isCreating) {
+ updateTaskMutation.mutate(newTask)
+ }
+ setTask(newTask)
+ }}
+ />
+
+
+
+ {!isCreating ? (
+
+ {task.isPublicVisible ? translation.public : translation.private}
+ {!task.isPublicVisible && !isCreating && (
+
+ )}
+
+ ) : null}
+ {isCreating && (
+
{
+ setTask({ ...task, isPublicVisible: !task.isPublicVisible })
+ }}
+ />
+ )}
+
+ {task.createdAt && (
+
+ {translation.creationTime}
+
+
+ )}
+
+ )
+}
+
+type ExpansionState = {
+ previousExpanded: boolean,
+ followingExpanded: boolean
+}
+
+export type TaskDetailModalProps = Omit & {
+ taskId?: string,
+ patientId: string,
+ initialStatus?: TaskStatus,
+ onClose: () => void
+}
/**
- * A Modal Wrapper for the task detail view
+ * A Modal showing the details of a Task
*/
export const TaskDetailModal = ({
taskId,
- wardId,
patientId,
onClose,
initialStatus,
modalClassName,
+ overwriteTranslation,
...modalProps
-}: TaskDetailModalProps) => {
+}: PropsForTranslation) => {
+ const translation = useTranslation(defaultTaskDetailViewTranslation, overwriteTranslation)
+ const [isShowingDeleteDialog, setIsShowingDeleteDialog] = useState(false)
+ const [expansionState, setExpansionState] = useState({
+ previousExpanded: false,
+ followingExpanded: false
+ })
+ const { previousExpanded, followingExpanded } = expansionState
+
+ const minTaskNameLength = 4
+ const maxTaskNameLength = 32
+
+ const isCreating = taskId === ''
+ const {
+ data,
+ isLoading,
+ isError
+ } = useTaskQuery(taskId)
+
+ const [task, setTask] = useState({
+ ...emptyTask,
+ status: initialStatus ?? 'todo'
+ })
+
+ const addSubtaskMutation = useSubTaskAddMutation(taskId)
+ const updateSubtask = useSubTaskUpdateMutation(taskId)
+
+ const assignTaskToUserMutation = useAssignTaskMutation()
+ const updateTaskMutation = useTaskUpdateMutation()
+
+ const createTaskMutation = useTaskCreateMutation(newTask => {
+ newTask.subtasks.forEach(value => addSubtaskMutation.mutate({ ...value, taskId: newTask.id }))
+ if (newTask.assignee) {
+ assignTaskToUserMutation.mutate({ taskId: newTask.id, userId: newTask.assignee })
+ }
+ onClose()
+ }, patientId)
+
+ useEffect(() => {
+ if (data && taskId) {
+ setTask(data)
+ }
+ }, [data, taskId])
+
+ const taskNameMinimumLength = 1
+ const isValid = task.name.length >= taskNameMinimumLength
+
+ const updateTaskLocallyAndExternally = (task: TaskDTO) => {
+ setTask(task)
+ if (!isCreating) {
+ updateTaskMutation.mutate(task)
+ }
+ }
+
+ const expandedWidth = 250 // Width when expanded
+ const notExpandedWidth = 56 // Width when not expanded
+ const offset = ((previousExpanded ? expandedWidth : notExpandedWidth) - (followingExpanded ? expandedWidth : notExpandedWidth)) / 2
+
+ const buttons = (
+
+ {!isCreating ?
+ (
+ <>
+
+ {task.status !== 'done' && (
+
+ )}
+ >
+ )
+ :
+ (
+
+ )
+ }
+
+ )
+
return (
= 0 ? '+' : ''}${offset}px)]`, modalClassName)}
{...modalProps}
>
-
+ {
+ // deleteTaskMutation.mutate(task.id)
+ setIsShowingDeleteDialog(false)
+ }}
+ onCancel={() => setIsShowingDeleteDialog(false)}
+ onCloseClick={() => setIsShowingDeleteDialog(false)}
+ onBackgroundClick={() => setIsShowingDeleteDialog(false)}
+ buttonOverwrites={[{}, {}, { color: 'hw-negative' }]}
+ />
+
+ setTask({ ...task, name })}
+ onEditCompleted={(text) => updateTaskLocallyAndExternally({ ...task, name: text })}
+ labelClassName={tw('text-2xl font-bold')}
+ minLength={minTaskNameLength}
+ maxLength={maxTaskNameLength}
+ size={24}
+ />
+ )}
+ onCloseClick={onClose}
+ />
+
+
updateSubtask.mutate({ id: subtask.id, name: subtask.name, isDone: subtask.status === 'done' })}
+ isExpanded={previousExpanded}
+ onExpansionChange={isExpanded => setExpansionState({ ...expansionState, previousExpanded: isExpanded })}
+ className={tx({
+ [`min-w-[${expandedWidth}px] max-w-[${expandedWidth}px]`]: previousExpanded,
+ [`min-w-[${notExpandedWidth}px] max-w-[${notExpandedWidth}px]`]: !previousExpanded,
+ })}
+ />
+
+
+
+
+ {buttons}
+
+ ({
+ // TODO change this once tasks as subtasks is implemented
+ id: subtask.id,
+ name: subtask.name,
+ status: subtask.isDone ? 'done' : 'todo',
+ notes: '',
+ subtasks: [],
+ isPublicVisible: false
+ }))}
+ type="following"
+ // TODO check this when Tasks as Subtasks API is merged
+ onSubtaskChange={subtask => updateSubtask.mutate({ id: subtask.id, name: subtask.name, isDone: subtask.status === 'done' })}
+ isExpanded={followingExpanded}
+ onExpansionChange={isExpanded => setExpansionState({ ...expansionState, followingExpanded: isExpanded })}
+ className={tx({
+ [`min-w-[${expandedWidth}px] max-w-[${expandedWidth}px]`]: followingExpanded,
+ [`min-w-[${notExpandedWidth}px] max-w-[${notExpandedWidth}px]`]: !followingExpanded,
+ })}
+ />
+
+
)
}