import { formatDatetime } from "@probo/helpers"; import { useTranslate } from "@probo/i18n"; import { Button, Dialog, DialogContent, DialogFooter, type DialogRef, DurationPicker, Input, Label, PropertyRow, Textarea, useDialogRef, } from "@probo/ui"; import { Breadcrumb } from "@probo/ui"; import type { ReactNode } from "react"; import { Controller } from "react-hook-form"; import { useFragment, useRelayEnvironment } from "react-relay"; import { graphql } from "relay-runtime"; import { z } from "zod"; import type { TaskFormDialogFragment$key } from "#/__generated__/core/TaskFormDialogFragment.graphql"; import { MeasureSelectField } from "#/components/form/MeasureSelectField"; import { PeopleSelectField } from "#/components/form/PeopleSelectField"; import { useFormWithSchema } from "#/hooks/useFormWithSchema"; import { updateStoreCounter } from "#/hooks/useMutationWithIncrement"; import { useMutationWithToasts } from "#/hooks/useMutationWithToasts"; import { useOrganizationId } from "#/hooks/useOrganizationId"; const taskFragment = graphql` fragment TaskFormDialogFragment on Task { id description name # eslint-disable-next-line relay/unused-fields state timeEstimate deadline assignedTo { id } measure { id } } `; const taskCreateMutation = graphql` mutation TaskFormDialogCreateMutation( $input: CreateTaskInput! $connections: [ID!]! ) { createTask(input: $input) { taskEdge @prependEdge(connections: $connections) { node { ...TaskFormDialogFragment } } } } `; export const taskUpdateMutation = graphql` mutation TaskFormDialogUpdateMutation($input: UpdateTaskInput!) { updateTask(input: $input) { task { ...TaskFormDialogFragment } } } `; const createTaskSchema = z.object({ name: z.string().min(1), description: z.string().optional().nullable(), timeEstimate: z.string().optional().nullable(), assignedToId: z.string().optional().nullable(), measureId: z.preprocess( val => (val === "" || val == null ? null : val), z.string().nullable().optional(), ), deadline: z.string().optional().nullable(), }); const updateTaskSchema = z.object({ name: z.string().min(1), description: z.string().optional().nullable(), timeEstimate: z.string().optional().nullable(), assignedToId: z.preprocess( val => (val === "" || val == null ? null : val), z.string().nullable().optional(), ), measureId: z.preprocess( val => (val === "" || val == null ? null : val), z.string().nullable().optional(), ), deadline: z.string().optional().nullable(), }); type Props = { children?: ReactNode; task?: TaskFormDialogFragment$key; connection?: string; ref?: DialogRef; measureId?: string; }; export default function TaskFormDialog(props: Props) { const { children, connection, ref, task: taskKey, measureId } = props; const { __ } = useTranslate(); const newRef = useDialogRef(); const dialogRef = ref ?? newRef; const organizationId = useOrganizationId(); const task = useFragment(taskFragment, taskKey); const relayEnv = useRelayEnvironment(); const [mutate] = useMutationWithToasts( task ? taskUpdateMutation : taskCreateMutation, { successMessage: __(`Task ${task ? "updated" : "created"} successfully.`), errorMessage: __(`Failed to ${task ? "update" : "create"} task`), }, ); const isUpdating = !!task; const { control, handleSubmit, register, formState, reset } = useFormWithSchema(isUpdating ? updateTaskSchema : createTaskSchema, { defaultValues: { name: task?.name ?? "", description: task?.description ?? "", timeEstimate: task?.timeEstimate ?? "", assignedToId: task?.assignedTo?.id ?? "", measureId: task?.measure?.id ?? measureId ?? "", deadline: task?.deadline?.split("T")[0] ?? "", }, }); const onSubmit = async (data: z.infer) => { if (task) { await mutate({ variables: { input: { taskId: task.id, name: data.name, description: data.description || null, timeEstimate: data.timeEstimate || null, deadline: formatDatetime(data.deadline) ?? null, assignedToId: data.assignedToId ?? null, measureId: data.measureId || null, }, }, }); } else { await mutate({ variables: { input: { organizationId, name: data.name, description: data.description || null, timeEstimate: data.timeEstimate || null, deadline: formatDatetime(data.deadline) ?? null, assignedToId: data.assignedToId || null, measureId: data.measureId || null, }, connections: [connection!], }, onCompleted: (_response, errors) => { if (!errors && data.measureId) { updateStoreCounter(relayEnv, data.measureId, "tasks(first:0)", 1); } }, }); reset(); } dialogRef.current?.close(); }; const showMeasure = !measureId; return ( )} >
void handleSubmit(onSubmit)(e)}>