mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
[WEB-522] chore: estimate restructure and handled error while creating estimates (#4817)
* dev:updated estimate UI * dev: updated error messages in estimate point create
This commit is contained in:
parent
9145234a6c
commit
b3626d815f
10
packages/types/src/estimate.d.ts
vendored
10
packages/types/src/estimate.d.ts
vendored
@ -75,3 +75,13 @@ export type TEstimateUpdateStageKeys =
|
||||
| EEstimateUpdateStages.CREATE
|
||||
| EEstimateUpdateStages.EDIT
|
||||
| EEstimateUpdateStages.SWITCH;
|
||||
|
||||
export type TEstimateTypeErrorObject = {
|
||||
oldValue: string;
|
||||
newValue: string;
|
||||
message: string | undefined;
|
||||
};
|
||||
|
||||
export type TEstimateTypeError =
|
||||
| Record<number, TEstimateTypeErrorObject>
|
||||
| undefined;
|
||||
|
@ -3,7 +3,7 @@
|
||||
import { FC, useEffect, useMemo, useState } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { ChevronLeft } from "lucide-react";
|
||||
import { IEstimateFormData, TEstimateSystemKeys, TEstimatePointsObject } from "@plane/types";
|
||||
import { IEstimateFormData, TEstimateSystemKeys, TEstimatePointsObject, TEstimateTypeError } from "@plane/types";
|
||||
import { Button, TOAST_TYPE, setToast } from "@plane/ui";
|
||||
// components
|
||||
import { EModalPosition, EModalWidth, ModalCore } from "@/components/core";
|
||||
@ -28,25 +28,59 @@ export const CreateEstimateModal: FC<TCreateEstimateModal> = observer((props) =>
|
||||
// states
|
||||
const [estimateSystem, setEstimateSystem] = useState<TEstimateSystemKeys>(EEstimateSystem.POINTS);
|
||||
const [estimatePoints, setEstimatePoints] = useState<TEstimatePointsObject[] | undefined>(undefined);
|
||||
const [estimatePointCreate, setEstimatePointCreate] = useState<TEstimatePointsObject[] | undefined>(undefined);
|
||||
const [estimatePointCreateError, setEstimatePointCreateError] = useState<number[]>([]);
|
||||
const [estimatePointError, setEstimatePointError] = useState<TEstimateTypeError>(undefined);
|
||||
const [buttonLoader, setButtonLoader] = useState(false);
|
||||
|
||||
const handleUpdatePoints = (newPoints: TEstimatePointsObject[] | undefined) => setEstimatePoints(newPoints);
|
||||
|
||||
const handleEstimatePointError = (
|
||||
key: number,
|
||||
oldValue: string,
|
||||
newValue: string,
|
||||
message: string | undefined,
|
||||
mode: "add" | "delete" = "add"
|
||||
) => {
|
||||
setEstimatePointError((prev) => {
|
||||
if (mode === "add") {
|
||||
return { ...prev, [key]: { oldValue, newValue, message } };
|
||||
} else {
|
||||
const newError = { ...prev };
|
||||
delete newError[key];
|
||||
return newError;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (isOpen) {
|
||||
setEstimateSystem(EEstimateSystem.POINTS);
|
||||
setEstimatePoints(undefined);
|
||||
setEstimatePointError([]);
|
||||
}
|
||||
}, [isOpen]);
|
||||
|
||||
const validateEstimatePointError = () => {
|
||||
let estimateError = false;
|
||||
if (!estimatePointError) return estimateError;
|
||||
|
||||
Object.keys(estimatePointError || {}).forEach((key) => {
|
||||
const currentKey = key as unknown as number;
|
||||
if (
|
||||
estimatePointError[currentKey]?.oldValue != estimatePointError[currentKey]?.newValue ||
|
||||
estimatePointError[currentKey]?.newValue === "" ||
|
||||
estimatePointError[currentKey]?.message
|
||||
) {
|
||||
estimateError = true;
|
||||
}
|
||||
});
|
||||
|
||||
return estimateError;
|
||||
};
|
||||
|
||||
const handleCreateEstimate = async () => {
|
||||
setEstimatePointCreateError([]);
|
||||
if (estimatePointCreate === undefined || estimatePointCreate?.length === 0) {
|
||||
if (!validateEstimatePointError()) {
|
||||
try {
|
||||
if (!workspaceSlug || !projectId || !estimatePoints) return;
|
||||
|
||||
setButtonLoader(true);
|
||||
const payload: IEstimateFormData = {
|
||||
estimate: {
|
||||
@ -57,7 +91,6 @@ export const CreateEstimateModal: FC<TCreateEstimateModal> = observer((props) =>
|
||||
estimate_points: estimatePoints,
|
||||
};
|
||||
await createEstimate(workspaceSlug, projectId, payload);
|
||||
|
||||
setButtonLoader(false);
|
||||
setToast({
|
||||
type: TOAST_TYPE.SUCCESS,
|
||||
@ -74,12 +107,32 @@ export const CreateEstimateModal: FC<TCreateEstimateModal> = observer((props) =>
|
||||
});
|
||||
}
|
||||
} else {
|
||||
setEstimatePointCreateError(estimatePointCreate.map((point) => point.key));
|
||||
setEstimatePointError((prev) => {
|
||||
const newError = { ...prev };
|
||||
Object.keys(newError || {}).forEach((key) => {
|
||||
const currentKey = key as unknown as number;
|
||||
if (
|
||||
newError[currentKey]?.newValue != "" &&
|
||||
newError[currentKey]?.oldValue === newError[currentKey]?.newValue
|
||||
) {
|
||||
delete newError[currentKey];
|
||||
} else {
|
||||
newError[currentKey].message =
|
||||
newError[currentKey].message ||
|
||||
"Estimate point can't be empty. Enter a value in each field or remove those you don't have values for.";
|
||||
}
|
||||
});
|
||||
return newError;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// derived values
|
||||
const renderEstimateStepsCount = useMemo(() => (estimatePoints ? "2" : "1"), [estimatePoints]);
|
||||
// const isEstimatePointError = useMemo(() => {
|
||||
// if (!estimatePointError) return false;
|
||||
// return Object.keys(estimatePointError).length > 0;
|
||||
// }, [estimatePointError]);
|
||||
|
||||
return (
|
||||
<ModalCore isOpen={isOpen} position={EModalPosition.TOP} width={EModalWidth.XXL}>
|
||||
@ -122,20 +175,16 @@ export const CreateEstimateModal: FC<TCreateEstimateModal> = observer((props) =>
|
||||
estimateType={estimateSystem}
|
||||
estimatePoints={estimatePoints}
|
||||
setEstimatePoints={setEstimatePoints}
|
||||
estimatePointCreate={estimatePointCreate}
|
||||
setEstimatePointCreate={(value) => {
|
||||
setEstimatePointCreateError([]);
|
||||
setEstimatePointCreate(value);
|
||||
}}
|
||||
estimatePointCreateError={estimatePointCreateError}
|
||||
estimatePointError={estimatePointError}
|
||||
handleEstimatePointError={handleEstimatePointError}
|
||||
/>
|
||||
)}
|
||||
{estimatePointCreateError.length > 0 && (
|
||||
{/* {isEstimatePointError && (
|
||||
<div className="pt-5 text-sm text-red-500">
|
||||
Estimate points can't be empty. Enter a value in each field or remove those you don't have
|
||||
values for.
|
||||
</div>
|
||||
)}
|
||||
)} */}
|
||||
</div>
|
||||
|
||||
<div className="relative flex justify-end items-center gap-3 px-5 pt-5 border-t border-custom-border-200">
|
||||
|
@ -1,9 +1,9 @@
|
||||
"use client";
|
||||
|
||||
import { Dispatch, FC, SetStateAction, useCallback } from "react";
|
||||
import { Dispatch, FC, SetStateAction, useCallback, useState } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { Plus } from "lucide-react";
|
||||
import { TEstimatePointsObject, TEstimateSystemKeys } from "@plane/types";
|
||||
import { TEstimatePointsObject, TEstimateSystemKeys, TEstimateTypeError } from "@plane/types";
|
||||
import { Button, Sortable } from "@plane/ui";
|
||||
// components
|
||||
import { EstimatePointCreate, EstimatePointItemPreview } from "@/components/estimates/points";
|
||||
@ -17,9 +17,14 @@ type TEstimatePointCreateRoot = {
|
||||
estimateType: TEstimateSystemKeys;
|
||||
estimatePoints: TEstimatePointsObject[];
|
||||
setEstimatePoints: Dispatch<SetStateAction<TEstimatePointsObject[] | undefined>>;
|
||||
estimatePointCreate: TEstimatePointsObject[] | undefined;
|
||||
setEstimatePointCreate: Dispatch<SetStateAction<TEstimatePointsObject[] | undefined>>;
|
||||
estimatePointCreateError: number[];
|
||||
estimatePointError?: TEstimateTypeError;
|
||||
handleEstimatePointError?: (
|
||||
key: number,
|
||||
oldValue: string,
|
||||
newValue: string,
|
||||
message: string | undefined,
|
||||
mode: "add" | "delete"
|
||||
) => void;
|
||||
};
|
||||
|
||||
export const EstimatePointCreateRoot: FC<TEstimatePointCreateRoot> = observer((props) => {
|
||||
@ -31,10 +36,11 @@ export const EstimatePointCreateRoot: FC<TEstimatePointCreateRoot> = observer((p
|
||||
estimateType,
|
||||
estimatePoints,
|
||||
setEstimatePoints,
|
||||
estimatePointCreate,
|
||||
setEstimatePointCreate,
|
||||
estimatePointCreateError,
|
||||
estimatePointError,
|
||||
handleEstimatePointError,
|
||||
} = props;
|
||||
// states
|
||||
const [estimatePointCreate, setEstimatePointCreate] = useState<TEstimatePointsObject[] | undefined>(undefined);
|
||||
|
||||
const handleEstimatePoint = useCallback(
|
||||
(mode: "add" | "remove" | "update", value: TEstimatePointsObject) => {
|
||||
@ -90,11 +96,13 @@ export const EstimatePointCreateRoot: FC<TEstimatePointCreateRoot> = observer((p
|
||||
|
||||
const handleCreate = () => {
|
||||
if (estimatePoints && estimatePoints.length + (estimatePointCreate?.length || 0) <= estimateCount.max - 1) {
|
||||
const currentKey = estimatePoints.length + (estimatePointCreate?.length || 0) + 1;
|
||||
handleEstimatePointCreate("add", {
|
||||
id: undefined,
|
||||
key: estimatePoints.length + (estimatePointCreate?.length || 0) + 1,
|
||||
key: currentKey,
|
||||
value: "",
|
||||
});
|
||||
handleEstimatePointError && handleEstimatePointError(currentKey, "", "", undefined, "add");
|
||||
}
|
||||
};
|
||||
|
||||
@ -119,6 +127,14 @@ export const EstimatePointCreateRoot: FC<TEstimatePointCreateRoot> = observer((p
|
||||
handleEstimatePoint("update", { ...value, value: estimatePointValue })
|
||||
}
|
||||
handleEstimatePointValueRemove={() => handleEstimatePoint("remove", value)}
|
||||
estimatePointError={estimatePointError?.[value.key] || undefined}
|
||||
handleEstimatePointError={(
|
||||
newValue: string,
|
||||
message: string | undefined,
|
||||
mode: "add" | "delete" = "add"
|
||||
) =>
|
||||
handleEstimatePointError && handleEstimatePointError(value.key, value.value, newValue, message, mode)
|
||||
}
|
||||
/>
|
||||
)}
|
||||
onChange={(data: TEstimatePointsObject[]) => handleDragEstimatePoints(data)}
|
||||
@ -140,7 +156,11 @@ export const EstimatePointCreateRoot: FC<TEstimatePointCreateRoot> = observer((p
|
||||
}
|
||||
closeCallBack={() => handleEstimatePointCreate("remove", estimatePoint)}
|
||||
handleCreateCallback={() => estimatePointCreate.length === 1 && handleCreate()}
|
||||
isError={estimatePointCreateError.includes(estimatePoint.key) ? true : false}
|
||||
estimatePointError={estimatePointError?.[estimatePoint.key] || undefined}
|
||||
handleEstimatePointError={(newValue: string, message: string | undefined, mode: "add" | "delete" = "add") =>
|
||||
handleEstimatePointError &&
|
||||
handleEstimatePointError(estimatePoint.key, estimatePoint.value, newValue, message, mode)
|
||||
}
|
||||
/>
|
||||
))}
|
||||
{estimatePoints && estimatePoints.length + (estimatePointCreate?.length || 0) <= estimateCount.max - 1 && (
|
||||
|
@ -1,9 +1,9 @@
|
||||
"use client";
|
||||
|
||||
import { FC, useState, FormEvent, useEffect } from "react";
|
||||
import { FC, useState, FormEvent } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { Check, Info, X } from "lucide-react";
|
||||
import { TEstimatePointsObject, TEstimateSystemKeys } from "@plane/types";
|
||||
import { TEstimatePointsObject, TEstimateSystemKeys, TEstimateTypeErrorObject } from "@plane/types";
|
||||
import { Spinner, TOAST_TYPE, Tooltip, setToast } from "@plane/ui";
|
||||
// helpers
|
||||
import { cn } from "@/helpers/common.helper";
|
||||
@ -22,7 +22,8 @@ type TEstimatePointCreate = {
|
||||
handleEstimatePointValue?: (estimateValue: string) => void;
|
||||
closeCallBack: () => void;
|
||||
handleCreateCallback: () => void;
|
||||
isError: boolean;
|
||||
estimatePointError?: TEstimateTypeErrorObject | undefined;
|
||||
handleEstimatePointError?: (newValue: string, message: string | undefined, mode?: "add" | "delete") => void;
|
||||
};
|
||||
|
||||
export const EstimatePointCreate: FC<TEstimatePointCreate> = observer((props) => {
|
||||
@ -35,21 +36,14 @@ export const EstimatePointCreate: FC<TEstimatePointCreate> = observer((props) =>
|
||||
handleEstimatePointValue,
|
||||
closeCallBack,
|
||||
handleCreateCallback,
|
||||
isError,
|
||||
estimatePointError,
|
||||
handleEstimatePointError,
|
||||
} = props;
|
||||
// hooks
|
||||
const { creteEstimatePoint } = useEstimate(estimateId);
|
||||
// states
|
||||
const [estimateInputValue, setEstimateInputValue] = useState("");
|
||||
const [loader, setLoader] = useState(false);
|
||||
const [error, setError] = useState<string | undefined>(undefined);
|
||||
|
||||
useEffect(() => {
|
||||
if (isError && error === undefined && estimateInputValue.length > 0) {
|
||||
setError("Confirm this value first or discard it.");
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [isError]);
|
||||
|
||||
const handleSuccess = (value: string) => {
|
||||
handleEstimatePointValue && handleEstimatePointValue(value);
|
||||
@ -58,13 +52,14 @@ export const EstimatePointCreate: FC<TEstimatePointCreate> = observer((props) =>
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
handleEstimatePointError && handleEstimatePointError(estimateInputValue, undefined, "delete");
|
||||
setEstimateInputValue("");
|
||||
closeCallBack();
|
||||
};
|
||||
|
||||
const handleEstimateInputValue = (value: string) => {
|
||||
setError(undefined);
|
||||
setEstimateInputValue(value);
|
||||
handleEstimatePointError && handleEstimatePointError(value, undefined);
|
||||
};
|
||||
|
||||
const handleCreate = async (event: FormEvent<HTMLFormElement>) => {
|
||||
@ -72,7 +67,7 @@ export const EstimatePointCreate: FC<TEstimatePointCreate> = observer((props) =>
|
||||
|
||||
if (!workspaceSlug || !projectId) return;
|
||||
|
||||
setError(undefined);
|
||||
handleEstimatePointError && handleEstimatePointError(estimateInputValue, undefined, "delete");
|
||||
|
||||
if (estimateInputValue) {
|
||||
const currentEstimateType: EEstimateSystem | undefined = estimateType;
|
||||
@ -91,7 +86,7 @@ export const EstimatePointCreate: FC<TEstimatePointCreate> = observer((props) =>
|
||||
isEstimateValid = true;
|
||||
}
|
||||
} else if (currentEstimateType && currentEstimateType === EEstimateSystem.CATEGORIES) {
|
||||
if (estimateInputValue && estimateInputValue.length > 0) {
|
||||
if (estimateInputValue && estimateInputValue.length > 0 && Number(estimateInputValue) < 0) {
|
||||
isEstimateValid = true;
|
||||
}
|
||||
}
|
||||
@ -108,7 +103,7 @@ export const EstimatePointCreate: FC<TEstimatePointCreate> = observer((props) =>
|
||||
await creteEstimatePoint(workspaceSlug, projectId, payload);
|
||||
|
||||
setLoader(false);
|
||||
setError(undefined);
|
||||
handleEstimatePointError && handleEstimatePointError(estimateInputValue, undefined, "delete");
|
||||
setToast({
|
||||
type: TOAST_TYPE.SUCCESS,
|
||||
title: "Estimate point created",
|
||||
@ -117,7 +112,11 @@ export const EstimatePointCreate: FC<TEstimatePointCreate> = observer((props) =>
|
||||
handleClose();
|
||||
} catch {
|
||||
setLoader(false);
|
||||
setError("We are unable to process your request, please try again.");
|
||||
handleEstimatePointError &&
|
||||
handleEstimatePointError(
|
||||
estimateInputValue,
|
||||
"We are unable to process your request, please try again."
|
||||
);
|
||||
setToast({
|
||||
type: TOAST_TYPE.ERROR,
|
||||
title: "Estimate point creation failed",
|
||||
@ -132,22 +131,24 @@ export const EstimatePointCreate: FC<TEstimatePointCreate> = observer((props) =>
|
||||
}
|
||||
} else {
|
||||
setLoader(false);
|
||||
setError(
|
||||
[EEstimateSystem.POINTS, EEstimateSystem.TIME].includes(estimateType)
|
||||
? "Estimate point needs to be a numeric value."
|
||||
: "Estimate point needs to be a character value."
|
||||
);
|
||||
handleEstimatePointError &&
|
||||
handleEstimatePointError(
|
||||
estimateInputValue,
|
||||
[EEstimateSystem.POINTS, EEstimateSystem.TIME].includes(estimateType)
|
||||
? "Estimate point needs to be a numeric value."
|
||||
: "Estimate point needs to be a character value."
|
||||
);
|
||||
}
|
||||
} else setError("Estimate value already exists.");
|
||||
} else setError("Estimate value cannot be empty.");
|
||||
} else handleEstimatePointError && handleEstimatePointError(estimateInputValue, "Estimate value already exists.");
|
||||
} else handleEstimatePointError && handleEstimatePointError(estimateInputValue, "Estimate value cannot be empty.");
|
||||
};
|
||||
|
||||
return (
|
||||
<form onSubmit={handleCreate} className="relative flex items-center gap-2 text-base">
|
||||
<form onSubmit={handleCreate} className="relative flex items-center gap-2 text-base pr-2.5">
|
||||
<div
|
||||
className={cn(
|
||||
"relative w-full border rounded flex items-center my-1",
|
||||
error ? `border-red-500` : `border-custom-border-200`
|
||||
estimatePointError?.message ? `border-red-500` : `border-custom-border-200`
|
||||
)}
|
||||
>
|
||||
<input
|
||||
@ -158,8 +159,8 @@ export const EstimatePointCreate: FC<TEstimatePointCreate> = observer((props) =>
|
||||
placeholder="Enter estimate point"
|
||||
autoFocus
|
||||
/>
|
||||
{error && (
|
||||
<Tooltip tooltipContent={error} position="bottom">
|
||||
{estimatePointError?.message && (
|
||||
<Tooltip tooltipContent={estimatePointError?.message} position="bottom">
|
||||
<div className="flex-shrink-0 w-3.5 h-3.5 overflow-hidden mr-3 relative flex justify-center items-center text-red-500">
|
||||
<Info size={14} />
|
||||
</div>
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { FC, useEffect, useRef, useState } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { GripVertical, Pencil, Trash2 } from "lucide-react";
|
||||
import { TEstimatePointsObject, TEstimateSystemKeys } from "@plane/types";
|
||||
import { TEstimatePointsObject, TEstimateSystemKeys, TEstimateTypeErrorObject } from "@plane/types";
|
||||
// components
|
||||
import { EstimatePointUpdate, EstimatePointDelete } from "@/components/estimates/points";
|
||||
// plane web constants
|
||||
@ -17,6 +17,8 @@ type TEstimatePointItemPreview = {
|
||||
estimatePoints: TEstimatePointsObject[];
|
||||
handleEstimatePointValueUpdate?: (estimateValue: string) => void;
|
||||
handleEstimatePointValueRemove?: () => void;
|
||||
estimatePointError?: TEstimateTypeErrorObject | undefined;
|
||||
handleEstimatePointError?: (newValue: string, message: string | undefined) => void;
|
||||
};
|
||||
|
||||
export const EstimatePointItemPreview: FC<TEstimatePointItemPreview> = observer((props) => {
|
||||
@ -30,6 +32,8 @@ export const EstimatePointItemPreview: FC<TEstimatePointItemPreview> = observer(
|
||||
estimatePoints,
|
||||
handleEstimatePointValueUpdate,
|
||||
handleEstimatePointValueRemove,
|
||||
estimatePointError,
|
||||
handleEstimatePointError,
|
||||
} = props;
|
||||
// state
|
||||
const [estimatePointEditToggle, setEstimatePointEditToggle] = useState(false);
|
||||
@ -90,6 +94,8 @@ export const EstimatePointItemPreview: FC<TEstimatePointItemPreview> = observer(
|
||||
handleEstimatePointValueUpdate && handleEstimatePointValueUpdate(estimatePointValue)
|
||||
}
|
||||
closeCallBack={() => setEstimatePointEditToggle(false)}
|
||||
estimatePointError={estimatePointError}
|
||||
handleEstimatePointError={handleEstimatePointError}
|
||||
/>
|
||||
)}
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
import { FC, useEffect, useState, FormEvent } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { Check, Info, X } from "lucide-react";
|
||||
import { TEstimatePointsObject, TEstimateSystemKeys } from "@plane/types";
|
||||
import { TEstimatePointsObject, TEstimateSystemKeys, TEstimateTypeErrorObject } from "@plane/types";
|
||||
import { Spinner, TOAST_TYPE, Tooltip, setToast } from "@plane/ui";
|
||||
// helpers
|
||||
import { cn } from "@/helpers/common.helper";
|
||||
@ -23,6 +23,8 @@ type TEstimatePointUpdate = {
|
||||
estimatePoint: TEstimatePointsObject;
|
||||
handleEstimatePointValueUpdate: (estimateValue: string) => void;
|
||||
closeCallBack: () => void;
|
||||
estimatePointError?: TEstimateTypeErrorObject | undefined;
|
||||
handleEstimatePointError?: (newValue: string, message: string | undefined, mode?: "add" | "delete") => void;
|
||||
};
|
||||
|
||||
export const EstimatePointUpdate: FC<TEstimatePointUpdate> = observer((props) => {
|
||||
@ -36,13 +38,14 @@ export const EstimatePointUpdate: FC<TEstimatePointUpdate> = observer((props) =>
|
||||
estimatePoint,
|
||||
handleEstimatePointValueUpdate,
|
||||
closeCallBack,
|
||||
estimatePointError,
|
||||
handleEstimatePointError,
|
||||
} = props;
|
||||
// hooks
|
||||
const { updateEstimatePoint } = useEstimatePoint(estimateId, estimatePointId);
|
||||
// states
|
||||
const [loader, setLoader] = useState(false);
|
||||
const [estimateInputValue, setEstimateInputValue] = useState<string | undefined>(undefined);
|
||||
const [error, setError] = useState<string | undefined>(undefined);
|
||||
|
||||
useEffect(() => {
|
||||
if (estimateInputValue === undefined && estimatePoint) setEstimateInputValue(estimatePoint?.value || "");
|
||||
@ -60,7 +63,7 @@ export const EstimatePointUpdate: FC<TEstimatePointUpdate> = observer((props) =>
|
||||
};
|
||||
|
||||
const handleEstimateInputValue = (value: string) => {
|
||||
setError(undefined);
|
||||
handleEstimatePointError && handleEstimatePointError(value, undefined);
|
||||
setEstimateInputValue(() => value);
|
||||
};
|
||||
|
||||
@ -69,7 +72,7 @@ export const EstimatePointUpdate: FC<TEstimatePointUpdate> = observer((props) =>
|
||||
|
||||
if (!workspaceSlug || !projectId) return;
|
||||
|
||||
setError(undefined);
|
||||
handleEstimatePointError && handleEstimatePointError(estimateInputValue || "", undefined, "delete");
|
||||
|
||||
if (estimateInputValue) {
|
||||
const currentEstimateType: EEstimateSystem | undefined = estimateType;
|
||||
@ -97,7 +100,8 @@ export const EstimatePointUpdate: FC<TEstimatePointUpdate> = observer((props) =>
|
||||
if (estimateId != undefined) {
|
||||
if (estimateInputValue === estimatePoint.value) {
|
||||
setLoader(false);
|
||||
setError(undefined);
|
||||
handleEstimatePointError && handleEstimatePointError(estimateInputValue, undefined);
|
||||
|
||||
handleClose();
|
||||
} else
|
||||
try {
|
||||
@ -109,7 +113,7 @@ export const EstimatePointUpdate: FC<TEstimatePointUpdate> = observer((props) =>
|
||||
await updateEstimatePoint(workspaceSlug, projectId, payload);
|
||||
|
||||
setLoader(false);
|
||||
setError(undefined);
|
||||
handleEstimatePointError && handleEstimatePointError(estimateInputValue, undefined, "delete");
|
||||
handleClose();
|
||||
setToast({
|
||||
type: TOAST_TYPE.SUCCESS,
|
||||
@ -118,7 +122,11 @@ export const EstimatePointUpdate: FC<TEstimatePointUpdate> = observer((props) =>
|
||||
});
|
||||
} catch {
|
||||
setLoader(false);
|
||||
setError("We are unable to process your request, please try again.");
|
||||
handleEstimatePointError &&
|
||||
handleEstimatePointError(
|
||||
estimateInputValue,
|
||||
"We are unable to process your request, please try again."
|
||||
);
|
||||
setToast({
|
||||
type: TOAST_TYPE.ERROR,
|
||||
title: "Estimate modification failed",
|
||||
@ -130,22 +138,25 @@ export const EstimatePointUpdate: FC<TEstimatePointUpdate> = observer((props) =>
|
||||
}
|
||||
} else {
|
||||
setLoader(false);
|
||||
setError(
|
||||
[EEstimateSystem.POINTS, EEstimateSystem.TIME].includes(estimateType)
|
||||
? "Estimate point needs to be a numeric value."
|
||||
: "Estimate point needs to be a character value."
|
||||
);
|
||||
handleEstimatePointError &&
|
||||
handleEstimatePointError(
|
||||
estimateInputValue,
|
||||
[EEstimateSystem.POINTS, EEstimateSystem.TIME].includes(estimateType)
|
||||
? "Estimate point needs to be a numeric value."
|
||||
: "Estimate point needs to be a character value."
|
||||
);
|
||||
}
|
||||
} else setError("Estimate value already exists.");
|
||||
} else setError("Estimate value cannot be empty.");
|
||||
} else handleEstimatePointError && handleEstimatePointError(estimateInputValue, "Estimate value already exists.");
|
||||
} else
|
||||
handleEstimatePointError && handleEstimatePointError(estimateInputValue || "", "Estimate value cannot be empty.");
|
||||
};
|
||||
|
||||
return (
|
||||
<form onSubmit={handleUpdate} className="relative flex items-center gap-2 text-base">
|
||||
<form onSubmit={handleUpdate} className="relative flex items-center gap-2 text-base pr-2.5">
|
||||
<div
|
||||
className={cn(
|
||||
"relative w-full border rounded flex items-center my-1",
|
||||
error ? `border-red-500` : `border-custom-border-200`
|
||||
estimatePointError?.message ? `border-red-500` : `border-custom-border-200`
|
||||
)}
|
||||
>
|
||||
<input
|
||||
@ -156,9 +167,9 @@ export const EstimatePointUpdate: FC<TEstimatePointUpdate> = observer((props) =>
|
||||
placeholder="Enter estimate point"
|
||||
autoFocus
|
||||
/>
|
||||
{error && (
|
||||
{estimatePointError?.message && (
|
||||
<>
|
||||
<Tooltip tooltipContent={error} position="bottom">
|
||||
<Tooltip tooltipContent={estimatePointError?.message} position="bottom">
|
||||
<div className="flex-shrink-0 w-3.5 h-3.5 overflow-hidden mr-3 relative flex justify-center items-center text-red-500">
|
||||
<Info size={14} />
|
||||
</div>
|
||||
|
Loading…
Reference in New Issue
Block a user