mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
chore: handled inline errors in the estimate switch
This commit is contained in:
parent
c2e07c6b7c
commit
8822c8b184
@ -1,7 +1,10 @@
|
|||||||
import { FC } from "react";
|
import { FC } from "react";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { MoveRight } from "lucide-react";
|
import { Info, MoveRight } from "lucide-react";
|
||||||
import { TEstimatePointsObject } from "@plane/types";
|
import { TEstimatePointsObject } from "@plane/types";
|
||||||
|
import { Tooltip } from "@plane/ui";
|
||||||
|
// helpers
|
||||||
|
import { cn } from "@/helpers/common.helper";
|
||||||
// hooks
|
// hooks
|
||||||
import { useEstimatePoint } from "@/hooks/store";
|
import { useEstimatePoint } from "@/hooks/store";
|
||||||
|
|
||||||
@ -10,10 +13,19 @@ type TEstimatePointItemSwitchPreview = {
|
|||||||
estimatePointId: string | undefined;
|
estimatePointId: string | undefined;
|
||||||
estimatePoint: TEstimatePointsObject;
|
estimatePoint: TEstimatePointsObject;
|
||||||
handleEstimatePoint: (value: string) => void;
|
handleEstimatePoint: (value: string) => void;
|
||||||
|
errorType?: string;
|
||||||
|
isError?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const EstimatePointItemSwitchPreview: FC<TEstimatePointItemSwitchPreview> = observer((props) => {
|
export const EstimatePointItemSwitchPreview: FC<TEstimatePointItemSwitchPreview> = observer((props) => {
|
||||||
const { estimateId, estimatePointId, estimatePoint: currentEstimatePoint, handleEstimatePoint } = props;
|
const {
|
||||||
|
estimateId,
|
||||||
|
estimatePointId,
|
||||||
|
estimatePoint: currentEstimatePoint,
|
||||||
|
handleEstimatePoint,
|
||||||
|
errorType = "",
|
||||||
|
isError = false,
|
||||||
|
} = props;
|
||||||
// hooks
|
// hooks
|
||||||
const { asJson: estimatePoint } = useEstimatePoint(estimateId, estimatePointId);
|
const { asJson: estimatePoint } = useEstimatePoint(estimateId, estimatePointId);
|
||||||
|
|
||||||
@ -26,14 +38,34 @@ export const EstimatePointItemSwitchPreview: FC<TEstimatePointItemSwitchPreview>
|
|||||||
<div className="flex-shrink-0 w-4 h-4 relative flex justify-center items-center">
|
<div className="flex-shrink-0 w-4 h-4 relative flex justify-center items-center">
|
||||||
<MoveRight size={12} />
|
<MoveRight size={12} />
|
||||||
</div>
|
</div>
|
||||||
<div className="relative w-full border rounded flex items-center border-custom-border-200">
|
<div
|
||||||
|
className={cn(
|
||||||
|
"relative w-full border rounded flex items-center",
|
||||||
|
isError ? `border-red-500` : `border-custom-border-200`
|
||||||
|
)}
|
||||||
|
>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
value={currentEstimatePoint?.value}
|
value={currentEstimatePoint?.value}
|
||||||
onChange={(e) => handleEstimatePoint(e.target.value)}
|
onChange={(e) => handleEstimatePoint(e.target.value)}
|
||||||
className="border-none focus:ring-0 focus:border-0 focus:outline-none p-2.5 w-full bg-transparent"
|
className="border-none focus:ring-0 focus:border-0 focus:outline-none p-2.5 w-full bg-transparent"
|
||||||
autoFocus
|
autoFocus
|
||||||
|
placeholder="Enter estimate point value"
|
||||||
/>
|
/>
|
||||||
|
{isError && (
|
||||||
|
<>
|
||||||
|
<Tooltip
|
||||||
|
tooltipContent={
|
||||||
|
errorType === "empty-fields" ? "please fill this estimate point." : `Repeating estimate point`
|
||||||
|
}
|
||||||
|
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>
|
||||||
|
</Tooltip>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -6,6 +6,8 @@ import { Button, TOAST_TYPE, setToast } from "@plane/ui";
|
|||||||
import { EstimatePointItemSwitchPreview } from "@/components/estimates/points";
|
import { EstimatePointItemSwitchPreview } from "@/components/estimates/points";
|
||||||
// constants
|
// constants
|
||||||
import { EEstimateSystem, EEstimateUpdateStages, ESTIMATE_SYSTEMS } from "@/constants/estimates";
|
import { EEstimateSystem, EEstimateUpdateStages, ESTIMATE_SYSTEMS } from "@/constants/estimates";
|
||||||
|
// helpers
|
||||||
|
import { isEstimatePointValuesRepeated } from "@/helpers/estimates";
|
||||||
// hooks
|
// hooks
|
||||||
import { useEstimate } from "@/hooks/store";
|
import { useEstimate } from "@/hooks/store";
|
||||||
|
|
||||||
@ -25,6 +27,7 @@ export const EstimatePointSwitchRoot: FC<TEstimatePointSwitchRoot> = observer((p
|
|||||||
const { asJson: estimate, estimatePointIds, estimatePointById, updateEstimateSwitch } = useEstimate(estimateId);
|
const { asJson: estimate, estimatePointIds, estimatePointById, updateEstimateSwitch } = useEstimate(estimateId);
|
||||||
// states
|
// states
|
||||||
const [estimatePoints, setEstimatePoints] = useState<TEstimatePointsObject[] | undefined>(undefined);
|
const [estimatePoints, setEstimatePoints] = useState<TEstimatePointsObject[] | undefined>(undefined);
|
||||||
|
const [estimateError, setEstimateError] = useState<{ type: string; ids: string[] } | undefined>(undefined);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!estimatePointIds) return;
|
if (!estimatePointIds) return;
|
||||||
@ -44,9 +47,34 @@ export const EstimatePointSwitchRoot: FC<TEstimatePointSwitchRoot> = observer((p
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const validateEstimateErrorHandlers = () => {
|
||||||
|
const currentEstimateError = (estimatePoints || [])
|
||||||
|
?.map((estimatePoint) => {
|
||||||
|
if (!estimatePoint.value || estimatePoint.value === "") return estimatePoint.id;
|
||||||
|
})
|
||||||
|
.filter((estimatePointId) => estimatePointId !== undefined) as string[];
|
||||||
|
setEstimateError({ type: "empty-fields", ids: currentEstimateError });
|
||||||
|
|
||||||
|
if (currentEstimateError.length > 0) return true;
|
||||||
|
else return false;
|
||||||
|
};
|
||||||
|
|
||||||
const handleSwitchEstimate = async () => {
|
const handleSwitchEstimate = async () => {
|
||||||
try {
|
try {
|
||||||
if (!workspaceSlug || !projectId) return;
|
if (!workspaceSlug || !projectId) return;
|
||||||
|
setEstimateError(undefined);
|
||||||
|
if (!validateEstimateErrorHandlers()) {
|
||||||
|
const isRepeated =
|
||||||
|
(estimateSystemSwitchType &&
|
||||||
|
estimatePoints &&
|
||||||
|
isEstimatePointValuesRepeated(
|
||||||
|
estimatePoints?.map((estimatePoint) => estimatePoint?.value),
|
||||||
|
estimateSystemSwitchType,
|
||||||
|
undefined
|
||||||
|
)) ||
|
||||||
|
false;
|
||||||
|
|
||||||
|
if (!isRepeated) {
|
||||||
const validatedEstimatePoints: TEstimatePointsObject[] = [];
|
const validatedEstimatePoints: TEstimatePointsObject[] = [];
|
||||||
if ([EEstimateSystem.POINTS, EEstimateSystem.TIME].includes(estimateSystemSwitchType)) {
|
if ([EEstimateSystem.POINTS, EEstimateSystem.TIME].includes(estimateSystemSwitchType)) {
|
||||||
estimatePoints?.map((estimatePoint) => {
|
estimatePoints?.map((estimatePoint) => {
|
||||||
@ -83,6 +111,20 @@ export const EstimatePointSwitchRoot: FC<TEstimatePointSwitchRoot> = observer((p
|
|||||||
message: "something went wrong",
|
message: "something went wrong",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
setToast({
|
||||||
|
type: TOAST_TYPE.ERROR,
|
||||||
|
title: "Error!",
|
||||||
|
message: "Estimate point values cannot be repeated",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setToast({
|
||||||
|
type: TOAST_TYPE.ERROR,
|
||||||
|
title: "Error!",
|
||||||
|
message: "Please fill all the estimate point fields",
|
||||||
|
});
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.ERROR,
|
type: TOAST_TYPE.ERROR,
|
||||||
@ -95,7 +137,7 @@ export const EstimatePointSwitchRoot: FC<TEstimatePointSwitchRoot> = observer((p
|
|||||||
if (!workspaceSlug || !projectId || !estimateId || !estimatePoints) return <></>;
|
if (!workspaceSlug || !projectId || !estimateId || !estimatePoints) return <></>;
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="space-y-3">
|
<div className="space-y-3 px-5 pb-5">
|
||||||
<div className="text-sm font-medium flex items-center gap-2">
|
<div className="text-sm font-medium flex items-center gap-2">
|
||||||
<div className="w-full">Current {estimate?.type}</div>
|
<div className="w-full">Current {estimate?.type}</div>
|
||||||
<div className="flex-shrink-0 w-4 h-4" />
|
<div className="flex-shrink-0 w-4 h-4" />
|
||||||
@ -106,9 +148,11 @@ export const EstimatePointSwitchRoot: FC<TEstimatePointSwitchRoot> = observer((p
|
|||||||
<EstimatePointItemSwitchPreview
|
<EstimatePointItemSwitchPreview
|
||||||
key={estimateObject?.id}
|
key={estimateObject?.id}
|
||||||
estimateId={estimateId}
|
estimateId={estimateId}
|
||||||
estimatePointId={estimateObject.id}
|
estimatePointId={estimateObject?.id}
|
||||||
estimatePoint={estimateObject}
|
estimatePoint={estimateObject}
|
||||||
handleEstimatePoint={(value: string) => handleEstimatePoints(index, value)}
|
handleEstimatePoint={(value: string) => handleEstimatePoints(index, value)}
|
||||||
|
errorType={estimateError?.type}
|
||||||
|
isError={estimateObject?.id ? estimateError?.ids?.includes(estimateObject.id) : false}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
@ -67,12 +67,18 @@ export const UpdateEstimateModal: FC<TUpdateEstimateModal> = observer((props) =>
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
{!estimateEditType && (
|
||||||
<div className="px-5">
|
<div className="px-5">
|
||||||
{!estimateEditType && <EstimateUpdateStageOne handleEstimateEditType={handleEstimateEditType} />}
|
<EstimateUpdateStageOne handleEstimateEditType={handleEstimateEditType} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
{estimateEditType && estimateId && (
|
{estimateEditType && estimateId && (
|
||||||
<>
|
<>
|
||||||
{estimateEditType === EEstimateUpdateStages.EDIT && (
|
{estimateEditType === EEstimateUpdateStages.EDIT && (
|
||||||
|
<div className="px-5">
|
||||||
<EstimatePointEditRoot workspaceSlug={workspaceSlug} projectId={projectId} estimateId={estimateId} />
|
<EstimatePointEditRoot workspaceSlug={workspaceSlug} projectId={projectId} estimateId={estimateId} />
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
{estimateEditType === EEstimateUpdateStages.SWITCH && estimateSystemSwitchType && (
|
{estimateEditType === EEstimateUpdateStages.SWITCH && estimateSystemSwitchType && (
|
||||||
<EstimatePointSwitchRoot
|
<EstimatePointSwitchRoot
|
||||||
|
Loading…
Reference in New Issue
Block a user