@@ -73,10 +73,7 @@ const createTaskSchema = z.object({
|
||||
name: z.string().min(1),
|
||||
description: z.string().optional().nullable(),
|
||||
timeEstimate: z.string().optional().nullable(),
|
||||
assignedToId: z.preprocess(
|
||||
(val) => (val === "" || val == null ? undefined : val),
|
||||
z.string({ required_error: "Assigned to is required" }).min(1, "Assigned to is required")
|
||||
),
|
||||
assignedToId: z.string().optional().nullable(),
|
||||
measureId: z.preprocess(
|
||||
(val) => (val === "" || val == null ? undefined : val),
|
||||
z.string({ required_error: "Measure is required" }).min(1, "Measure is required")
|
||||
@@ -88,7 +85,7 @@ const updateTaskSchema = z.object({
|
||||
name: z.string().min(1),
|
||||
description: z.string().optional().nullable(),
|
||||
timeEstimate: z.string().optional().nullable(),
|
||||
assignedToId: z.string().optional(),
|
||||
assignedToId: z.string().optional().nullable(),
|
||||
measureId: z.string().optional(),
|
||||
deadline: z.string().optional().nullable(),
|
||||
});
|
||||
@@ -137,6 +134,7 @@ export default function TaskFormDialog(props: Props) {
|
||||
description: data.description || null,
|
||||
timeEstimate: data.timeEstimate || null,
|
||||
deadline: formatDatetime(data.deadline) ?? null,
|
||||
assignedToId: data.assignedToId ?? null,
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -149,7 +147,7 @@ export default function TaskFormDialog(props: Props) {
|
||||
description: data.description || null,
|
||||
timeEstimate: data.timeEstimate || null,
|
||||
deadline: formatDatetime(data.deadline) ?? null,
|
||||
assignedToId: data.assignedToId,
|
||||
assignedToId: data.assignedToId || null,
|
||||
measureId: data.measureId,
|
||||
},
|
||||
connections: [props.connection!],
|
||||
@@ -165,7 +163,6 @@ export default function TaskFormDialog(props: Props) {
|
||||
dialogRef.current?.close();
|
||||
});
|
||||
const showMeasure = !props.measureId && !isUpdating;
|
||||
const isCreating = !isUpdating;
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
@@ -198,18 +195,17 @@ export default function TaskFormDialog(props: Props) {
|
||||
{/* Properties form */}
|
||||
<div className="py-5 px-6 bg-subtle">
|
||||
<Label>{__("Properties")}</Label>
|
||||
{isCreating && (
|
||||
<PropertyRow
|
||||
label={__("Assigned to")}
|
||||
error={formState.errors.assignedToId?.message}
|
||||
>
|
||||
<PeopleSelectField
|
||||
name="assignedToId"
|
||||
control={control}
|
||||
organizationId={organizationId}
|
||||
/>
|
||||
</PropertyRow>
|
||||
)}
|
||||
<PropertyRow
|
||||
label={__("Assigned to")}
|
||||
error={formState.errors.assignedToId?.message}
|
||||
>
|
||||
<PeopleSelectField
|
||||
name="assignedToId"
|
||||
control={control}
|
||||
organizationId={organizationId}
|
||||
optional={true}
|
||||
/>
|
||||
</PropertyRow>
|
||||
{showMeasure && (
|
||||
<PropertyRow
|
||||
label={__("Measure")}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import { promisifyMutation } from "@probo/helpers";
|
||||
import { promisifyMutation, formatDate, formatDuration } from "@probo/helpers";
|
||||
import { usePageTitle } from "@probo/hooks";
|
||||
import { useTranslate } from "@probo/i18n";
|
||||
import {
|
||||
ActionDropdown,
|
||||
Avatar,
|
||||
Card,
|
||||
DropdownItem,
|
||||
IconArrowCornerDownLeft,
|
||||
@@ -40,6 +39,8 @@ type Props = {
|
||||
name: string;
|
||||
state: "TODO" | "DONE";
|
||||
description?: string | null;
|
||||
timeEstimate?: string | null;
|
||||
deadline?: string | null;
|
||||
measure?: {
|
||||
id: string;
|
||||
name: string;
|
||||
@@ -128,7 +129,7 @@ export default function TasksCard({ tasks, connectionId }: Props) {
|
||||
}
|
||||
|
||||
type TaskRowProps = {
|
||||
task: ItemOf<Props["tasks"]> & TaskFormDialogFragment$key;
|
||||
task: ItemOf<Props["tasks"]>;
|
||||
connectionId: string;
|
||||
hasAnyAction: boolean;
|
||||
};
|
||||
@@ -207,30 +208,48 @@ function TaskRow(props: TaskRowProps) {
|
||||
<TaskStateIcon state={props.task.state} />
|
||||
</button>
|
||||
</div>
|
||||
<div className="text-sm space-y-1">
|
||||
<div className="text-sm space-y-1 flex-1">
|
||||
<h2 className="font-medium">{props.task.name}</h2>
|
||||
{props.task.measure && (
|
||||
<p className="text-txt-secondary flex items-center gap-2">
|
||||
<IconArrowCornerDownLeft className="scale-x-[-1]" size={16} />
|
||||
<Link
|
||||
className="hover:underline"
|
||||
to={`/organizations/${organizationId}/measures/${props.task.measure?.id}`}
|
||||
>
|
||||
{props.task.measure?.name}
|
||||
</Link>
|
||||
{props.task.description && (
|
||||
<p className="text-txt-secondary whitespace-pre-wrap break-words">
|
||||
{props.task.description}
|
||||
</p>
|
||||
)}
|
||||
<div className="flex flex-wrap items-center gap-3 text-txt-secondary text-xs">
|
||||
{props.task.measure && (
|
||||
<span className="flex items-center gap-1">
|
||||
<IconArrowCornerDownLeft className="scale-x-[-1]" size={14} />
|
||||
<Link
|
||||
className="hover:underline"
|
||||
to={`/organizations/${organizationId}/measures/${props.task.measure?.id}`}
|
||||
>
|
||||
{props.task.measure?.name}
|
||||
</Link>
|
||||
</span>
|
||||
)}
|
||||
{props.task.timeEstimate && (
|
||||
<span>{formatDuration(props.task.timeEstimate, __)}</span>
|
||||
)}
|
||||
{props.task.deadline && (
|
||||
<time dateTime={props.task.deadline}>
|
||||
{formatDate(props.task.deadline)}
|
||||
</time>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{props.task.assignedTo?.fullName && (
|
||||
<div className="text-sm text-txt-secondary ml-auto mr-8">
|
||||
<Link
|
||||
className="hover:underline"
|
||||
to={`/organizations/${organizationId}/people/${props.task.assignedTo.id}`}
|
||||
>
|
||||
{props.task.assignedTo.fullName}
|
||||
</Link>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex gap-2 items-center">
|
||||
{isUpdating && <Spinner size={16} />}
|
||||
{props.task.assignedTo && (
|
||||
<Link
|
||||
to={`/organizations/${organizationId}/people/${props.task.assignedTo?.id}`}
|
||||
>
|
||||
<Avatar name={props.task.assignedTo?.fullName ?? ""} />
|
||||
</Link>
|
||||
)}
|
||||
{props.hasAnyAction && (
|
||||
<ActionDropdown>
|
||||
{isAuthorized("Task", "updateTask") && (
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @generated SignedSource<<1cc9998f8dcbb02ac977744023d372d6>>
|
||||
* @generated SignedSource<<1d9eed2918f5f58de18ef4ea5f0058b7>>
|
||||
* @lightSyntaxTransform
|
||||
* @nogrep
|
||||
*/
|
||||
@@ -12,6 +12,7 @@ import { ConcreteRequest } from 'relay-runtime';
|
||||
import { FragmentRefs } from "relay-runtime";
|
||||
export type TaskState = "DONE" | "TODO";
|
||||
export type UpdateTaskInput = {
|
||||
assignedToId?: string | null | undefined;
|
||||
deadline?: any | null | undefined;
|
||||
description?: string | null | undefined;
|
||||
name?: string | null | undefined;
|
||||
|
||||
Reference in New Issue
Block a user