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} - /> -
-
-
-