mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
chore: editing and deleting the existing estimate updates
This commit is contained in:
parent
1e59d5b735
commit
bdb0674d35
@ -5,7 +5,7 @@ import { Button, Sortable } from "@plane/ui";
|
||||
// components
|
||||
import { EstimatePointItem } from "@/components/estimates";
|
||||
// constants
|
||||
import { EEstimateSystem, EEstimateUpdateStages, ESTIMATE_SYSTEMS } from "@/constants/estimates";
|
||||
import { EEstimateSystem, EEstimateUpdateStages, ESTIMATE_SYSTEMS, maxEstimatesCount } from "@/constants/estimates";
|
||||
|
||||
type TEstimateCreateStageTwo = {
|
||||
estimateSystem: EEstimateSystem;
|
||||
@ -17,7 +17,6 @@ export const EstimateCreateStageTwo: FC<TEstimateCreateStageTwo> = (props) => {
|
||||
const { estimateSystem, estimatePoints, handleEstimatePoints } = props;
|
||||
|
||||
const currentEstimateSystem = ESTIMATE_SYSTEMS[estimateSystem] || undefined;
|
||||
const maxEstimatesCount = 11;
|
||||
|
||||
const addNewEstimationPoint = () => {
|
||||
const currentEstimationPoints = estimatePoints;
|
||||
@ -60,6 +59,7 @@ export const EstimateCreateStageTwo: FC<TEstimateCreateStageTwo> = (props) => {
|
||||
data={estimatePoints}
|
||||
render={(value: TEstimatePointsObject, index: number) => (
|
||||
<EstimatePointItem
|
||||
estimateId={undefined}
|
||||
mode={EEstimateUpdateStages.CREATE}
|
||||
item={value}
|
||||
editItem={(value: string) => editEstimationPoint(index, value)}
|
||||
|
@ -1,67 +1,83 @@
|
||||
import { FC, Fragment, useEffect, useRef, useState } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { Check, GripVertical, MoveRight, Pencil, Trash2, X } from "lucide-react";
|
||||
import { Select } from "@headlessui/react";
|
||||
import { TEstimatePointsObject } from "@plane/types";
|
||||
import { Draggable } from "@plane/ui";
|
||||
import { Draggable, Spinner } from "@plane/ui";
|
||||
// constants
|
||||
import { EEstimateUpdateStages } from "@/constants/estimates";
|
||||
// components
|
||||
import { InlineEdit } from "./inline-editable";
|
||||
// helpers
|
||||
import { cn } from "@/helpers/common.helper";
|
||||
import { useEstimate } from "@/hooks/store";
|
||||
|
||||
type TEstimatePointItem = {
|
||||
estimateId: string | undefined;
|
||||
mode: EEstimateUpdateStages;
|
||||
item: TEstimatePointsObject;
|
||||
editItem: (value: string) => void;
|
||||
deleteItem: () => void;
|
||||
};
|
||||
|
||||
const EstimatePointItem: FC<TEstimatePointItem> = (props) => {
|
||||
export const EstimatePointItem: FC<TEstimatePointItem> = observer((props) => {
|
||||
// props
|
||||
const { mode, item, editItem, deleteItem } = props;
|
||||
const { estimateId, mode, item, editItem, deleteItem } = props;
|
||||
const { id, key, value } = item;
|
||||
// hooks
|
||||
const { asJson: estimate, updateEstimate, deleteEstimate } = useEstimate(estimateId);
|
||||
// ref
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
// states
|
||||
const [inputValue, setInputValue] = useState<string | undefined>(undefined);
|
||||
const [isEditing, setIsEditing] = useState(false);
|
||||
const [showDeleteUI, setShowDeleteUI] = useState(false);
|
||||
// handling editing states
|
||||
const [estimateEditLoader, setEstimateEditLoader] = useState(false);
|
||||
const [deletedEstimateValue, setDeletedEstimateValue] = useState<string | undefined>(undefined);
|
||||
const [isEstimateEditing, setIsEstimateEditing] = useState(false);
|
||||
const [isEstimateDeleting, setIsEstimateDeleting] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (inputValue === undefined) setInputValue(value);
|
||||
if (inputValue === undefined || inputValue != value) setInputValue(value);
|
||||
}, [value, inputValue]);
|
||||
|
||||
const handleSave = () => {
|
||||
if (id) {
|
||||
// Make the api call to save the estimate point
|
||||
// Show a spinner
|
||||
setIsEditing(false);
|
||||
}
|
||||
const handleCreateEdit = (value: string) => {
|
||||
setInputValue(value);
|
||||
editItem(value);
|
||||
};
|
||||
|
||||
const handleEdit = (value: string) => {
|
||||
const handleEdit = async () => {
|
||||
if (id) {
|
||||
setIsEditing(true);
|
||||
setTimeout(() => {
|
||||
inputRef.current?.focus();
|
||||
inputRef.current?.select();
|
||||
});
|
||||
try {
|
||||
setEstimateEditLoader(true);
|
||||
await updateEstimate({ estimate_points: [{ id: id, key: key, value: value }] });
|
||||
setIsEstimateEditing(false);
|
||||
setEstimateEditLoader(false);
|
||||
} catch (error) {
|
||||
setEstimateEditLoader(false);
|
||||
}
|
||||
} else {
|
||||
setInputValue(value);
|
||||
editItem(value);
|
||||
if (inputValue) editItem(inputValue);
|
||||
}
|
||||
};
|
||||
|
||||
const handleDelete = () => {
|
||||
const handleDelete = async () => {
|
||||
if (id) {
|
||||
setShowDeleteUI(true);
|
||||
try {
|
||||
setEstimateEditLoader(true);
|
||||
await deleteEstimate(deletedEstimateValue);
|
||||
setIsEstimateDeleting(false);
|
||||
setEstimateEditLoader(false);
|
||||
} catch (error) {
|
||||
setEstimateEditLoader(false);
|
||||
}
|
||||
} else {
|
||||
deleteItem();
|
||||
}
|
||||
};
|
||||
|
||||
const selectDropdownOptions = estimate && estimate?.points ? estimate?.points.filter((point) => point.id !== id) : [];
|
||||
|
||||
return (
|
||||
<Draggable data={item}>
|
||||
{mode === EEstimateUpdateStages.CREATE && (
|
||||
{!id && (
|
||||
<div className="border border-custom-border-200 rounded relative flex items-center px-2.5 gap-2">
|
||||
<div className="rounded-sm w-6 h-6 flex-shrink-0 relative flex justify-center items-center hover:bg-custom-background-80 transition-colors cursor-pointer">
|
||||
<GripVertical size={14} className="text-custom-text-200" />
|
||||
@ -70,8 +86,8 @@ const EstimatePointItem: FC<TEstimatePointItem> = (props) => {
|
||||
ref={inputRef}
|
||||
type="text"
|
||||
value={inputValue}
|
||||
onChange={(e) => handleEdit(e.target.value)}
|
||||
className="flex-grow border-none bg-transparent focus:ring-0 focus:border-0 focus:outline-none py-2.5"
|
||||
onChange={(e) => handleCreateEdit(e.target.value)}
|
||||
className="flex-grow border-none bg-transparent focus:ring-0 focus:border-0 focus:outline-none py-2.5 w-full"
|
||||
/>
|
||||
<div
|
||||
className="rounded-sm w-6 h-6 flex-shrink-0 relative flex justify-center items-center hover:bg-custom-background-80 transition-colors cursor-pointer"
|
||||
@ -82,122 +98,120 @@ const EstimatePointItem: FC<TEstimatePointItem> = (props) => {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{mode === EEstimateUpdateStages.EDIT && (
|
||||
{id && (
|
||||
<>
|
||||
<div className="border border-custom-border-200 rounded relative flex items-center px-2.5 gap-2">
|
||||
<div className="rounded-sm w-6 h-6 flex-shrink-0 relative flex justify-center items-center hover:bg-custom-background-80 transition-colors cursor-pointer">
|
||||
<GripVertical size={14} className="text-custom-text-200" />
|
||||
{mode === EEstimateUpdateStages.EDIT && (
|
||||
<>
|
||||
{!isEstimateEditing && !isEstimateDeleting && (
|
||||
<div className="border border-custom-border-200 rounded relative flex items-center px-2.5 gap-2">
|
||||
<div className="rounded-sm w-6 h-6 flex-shrink-0 relative flex justify-center items-center hover:bg-custom-background-80 transition-colors cursor-pointer">
|
||||
<GripVertical size={14} className="text-custom-text-200" />
|
||||
</div>
|
||||
<div className="py-2.5 flex-grow" onClick={() => setIsEstimateEditing(true)}>
|
||||
{value}
|
||||
</div>
|
||||
<div
|
||||
className="rounded-sm w-6 h-6 flex-shrink-0 relative flex justify-center items-center hover:bg-custom-background-80 transition-colors cursor-pointer"
|
||||
onClick={() => setIsEstimateEditing(true)}
|
||||
>
|
||||
<Pencil size={14} className="text-custom-text-200" />
|
||||
</div>
|
||||
<div
|
||||
className="rounded-sm w-6 h-6 flex-shrink-0 relative flex justify-center items-center hover:bg-custom-background-80 transition-colors cursor-pointer"
|
||||
onClick={() => setIsEstimateDeleting(true)}
|
||||
>
|
||||
<Trash2 size={14} className="text-custom-text-200" />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{(isEstimateEditing || isEstimateDeleting) && (
|
||||
<div className="relative flex items-center gap-2">
|
||||
<div className="flex-grow relative flex items-center gap-3">
|
||||
<div className="flex-grow border border-custom-border-200 rounded">
|
||||
<input
|
||||
ref={inputRef}
|
||||
type="text"
|
||||
value={inputValue}
|
||||
onChange={(e) => setInputValue(e.target.value)}
|
||||
className={cn(
|
||||
"flex-grow border-none focus:ring-0 focus:border-0 focus:outline-none p-2.5 w-full",
|
||||
isEstimateDeleting ? `bg-custom-background-90` : `bg-transparent`
|
||||
)}
|
||||
disabled={isEstimateDeleting}
|
||||
/>
|
||||
</div>
|
||||
{isEstimateDeleting && <MoveRight size={14} />}
|
||||
{isEstimateDeleting && (
|
||||
<div className="relative flex-grow rounded border border-custom-border-200 flex items-center gap-3 p-2.5">
|
||||
<Select
|
||||
className="bg-transparent flex-grow focus:ring-0 focus:border-0 focus:outline-none"
|
||||
value={deletedEstimateValue}
|
||||
onChange={(e) => setDeletedEstimateValue(e.target.value)}
|
||||
>
|
||||
<option value={undefined}>None</option>
|
||||
{selectDropdownOptions.map((option) => (
|
||||
<option key={option?.id} value={option?.value}>
|
||||
{option?.value}
|
||||
</option>
|
||||
))}
|
||||
</Select>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{estimateEditLoader ? (
|
||||
<div className="w-6 h-6 flex-shrink-0 relative flex justify-center items-center rota">
|
||||
<Spinner className="w-4 h-4" />
|
||||
</div>
|
||||
) : (
|
||||
<div
|
||||
className={cn(
|
||||
"rounded-sm w-6 h-6 flex-shrink-0 relative flex justify-center items-center hover:bg-custom-background-80 transition-colors cursor-pointer",
|
||||
isEstimateEditing ? `text-green-500` : `text-red-500`
|
||||
)}
|
||||
onClick={() => (isEstimateEditing ? handleEdit() : handleDelete())}
|
||||
>
|
||||
{isEstimateEditing ? <Check size={14} /> : <Trash2 size={14} />}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div
|
||||
className="rounded-sm w-6 h-6 flex-shrink-0 relative flex justify-center items-center hover:bg-custom-background-80 transition-colors cursor-pointer"
|
||||
onClick={() => (isEstimateEditing ? setIsEstimateEditing(false) : setIsEstimateDeleting(false))}
|
||||
>
|
||||
<X size={14} className="text-custom-text-200" />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
{mode === EEstimateUpdateStages.SWITCH && (
|
||||
<div className="flex-grow relative flex items-center gap-3">
|
||||
<div className="flex-grow border border-custom-border-200 rounded">
|
||||
<input
|
||||
ref={inputRef}
|
||||
type="text"
|
||||
value={inputValue}
|
||||
onChange={(e) => setInputValue(e.target.value)}
|
||||
className="flex-grow border-none focus:ring-0 focus:border-0 focus:outline-none p-2.5 bg-custom-background-90 w-full"
|
||||
disabled
|
||||
/>
|
||||
</div>
|
||||
<MoveRight size={14} />
|
||||
<div className="flex-grow border border-custom-border-200 rounded">
|
||||
<input
|
||||
ref={inputRef}
|
||||
type="text"
|
||||
value={inputValue}
|
||||
onChange={(e) => setInputValue(e.target.value)}
|
||||
className="flex-grow border-none bg-transparent focus:ring-0 focus:border-0 focus:outline-none p-2.5 w-full"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<input
|
||||
ref={inputRef}
|
||||
type="text"
|
||||
value={inputValue}
|
||||
onChange={(e) => setInputValue(e.target.value)}
|
||||
className="flex-grow border-none bg-transparent focus:ring-0 focus:border-0 focus:outline-none py-2.5"
|
||||
/>
|
||||
<div
|
||||
className="rounded-sm w-6 h-6 flex-shrink-0 relative flex justify-center items-center hover:bg-custom-background-80 transition-colors cursor-pointer"
|
||||
onClick={handleDelete}
|
||||
>
|
||||
<Pencil size={14} className="text-custom-text-200" />
|
||||
</div>
|
||||
<div
|
||||
className="rounded-sm w-6 h-6 flex-shrink-0 relative flex justify-center items-center hover:bg-custom-background-80 transition-colors cursor-pointer"
|
||||
onClick={handleDelete}
|
||||
>
|
||||
<Trash2 size={14} className="text-custom-text-200" />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
{mode === EEstimateUpdateStages.SWITCH && (
|
||||
<div className="border border-custom-border-200 rounded relative flex items-center px-2.5 gap-2">
|
||||
<div className="rounded-sm w-6 h-6 flex-shrink-0 relative flex justify-center items-center hover:bg-custom-background-80 transition-colors cursor-pointer">
|
||||
<GripVertical size={14} className="text-custom-text-200" />
|
||||
</div>
|
||||
<input
|
||||
ref={inputRef}
|
||||
type="text"
|
||||
value={inputValue}
|
||||
onChange={(e) => setInputValue(e.target.value)}
|
||||
className="flex-grow border-none bg-transparent focus:ring-0 focus:border-0 focus:outline-none py-2.5"
|
||||
/>
|
||||
<div
|
||||
className="rounded-sm w-6 h-6 flex-shrink-0 relative flex justify-center items-center hover:bg-custom-background-80 transition-colors cursor-pointer"
|
||||
onClick={handleDelete}
|
||||
>
|
||||
<Pencil size={14} className="text-custom-text-200" />
|
||||
</div>
|
||||
<div
|
||||
className="rounded-sm w-6 h-6 flex-shrink-0 relative flex justify-center items-center hover:bg-custom-background-80 transition-colors cursor-pointer"
|
||||
onClick={handleDelete}
|
||||
>
|
||||
<Trash2 size={14} className="text-custom-text-200" />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* <div className="border border-custom-border-200 rounded relative flex items-center px-2.5 gap-3">
|
||||
<GripVertical size={14} className="text-custom-text-200" />
|
||||
<input
|
||||
ref={inputRef}
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={() => {}}
|
||||
className="flex-grow border-none bg-transparent focus:ring-0 focus:border-0 focus:outline-none py-2.5"
|
||||
/>
|
||||
<Pencil size={14} className="text-custom-text-200" />
|
||||
<Trash2 size={14} className="text-custom-text-200" />
|
||||
<Check size={14} className="text-custom-text-200" />
|
||||
<X size={14} className="text-custom-text-200" />
|
||||
</div> */}
|
||||
|
||||
{/* {isEditing && (
|
||||
<div className="flex justify-between items-center gap-4">
|
||||
<input
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={() => {}}
|
||||
className="border rounded-md border-custom-border-300 p-3 flex-grow"
|
||||
ref={inputRef}
|
||||
/>
|
||||
<div>
|
||||
<div className="flex gap-4 justify-between items-center">
|
||||
<Check className="w-6 h-6" onClick={handleSave} />
|
||||
<X className="w-6 h-6" onClick={() => setIsEditing(false)} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!isEditing && (
|
||||
<div className="border rounded-md border-custom-border-300 mb-2 p-3 flex justify-between items-center">
|
||||
<div className="flex items-center">
|
||||
<GripVertical className="w-4 h-4" />
|
||||
{!showDeleteUI ? <InlineEdit value={value} /> : value}
|
||||
{showDeleteUI && (
|
||||
<Fragment>
|
||||
<MoveRight className="w-4 h-4 mx-2" />
|
||||
<Select>
|
||||
<option value="active">Active</option>
|
||||
<option value="paused">Paused</option>
|
||||
<option value="delayed">Delayed</option>
|
||||
<option value="canceled">Canceled</option>
|
||||
</Select>
|
||||
<Check className="w-4 h-4 rounded-md" />
|
||||
<X className="w-4 h-4 rounded-md" onClick={() => setShowDeleteUI(false)} />
|
||||
</Fragment>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex gap-4 items-center">
|
||||
<Pencil className="w-4 h-4" onClick={handleEdit} />
|
||||
{!showDeleteUI && <Trash2 className="w-4 h-4" onClick={handleDelete} />}
|
||||
</div>
|
||||
</div>
|
||||
)} */}
|
||||
</Draggable>
|
||||
);
|
||||
};
|
||||
|
||||
export { EstimatePointItem };
|
||||
});
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { FC, useEffect, useMemo, useState } from "react";
|
||||
import cloneDeep from "lodash/cloneDeep";
|
||||
import { observer } from "mobx-react";
|
||||
import { ChevronLeft } from "lucide-react";
|
||||
import { IEstimateFormData, TEstimatePointsObject, TEstimateUpdateStageKeys, TEstimateSystemKeys } from "@plane/types";
|
||||
@ -46,10 +45,7 @@ export const UpdateEstimateModal: FC<TUpdateEstimateModal> = observer((props) =>
|
||||
}
|
||||
};
|
||||
|
||||
const handleUpdatePoints = (newPoints: TEstimatePointsObject[] | undefined) => {
|
||||
const points = cloneDeep(newPoints);
|
||||
setEstimatePoints(points);
|
||||
};
|
||||
const handleUpdatePoints = (newPoints: TEstimatePointsObject[] | undefined) => setEstimatePoints(newPoints);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isOpen) {
|
||||
@ -109,8 +105,6 @@ export const UpdateEstimateModal: FC<TUpdateEstimateModal> = observer((props) =>
|
||||
}
|
||||
};
|
||||
|
||||
console.log("estimateStage", estimateEditType);
|
||||
|
||||
return (
|
||||
<ModalCore isOpen={isOpen} handleClose={handleClose} position={EModalPosition.TOP} width={EModalWidth.XXL}>
|
||||
<div className="relative space-y-6 py-5">
|
||||
|
@ -4,6 +4,8 @@ import { IEstimate, TEstimatePointsObject, TEstimateUpdateStageKeys } from "@pla
|
||||
import { Button, Sortable } from "@plane/ui";
|
||||
// components
|
||||
import { EstimatePointItem } from "@/components/estimates";
|
||||
// constants
|
||||
import { EEstimateUpdateStages, maxEstimatesCount } from "@/constants/estimates";
|
||||
|
||||
type TEstimateUpdateStageTwo = {
|
||||
estimate: IEstimate;
|
||||
@ -19,7 +21,6 @@ export const EstimateUpdateStageTwo: FC<TEstimateUpdateStageTwo> = (props) => {
|
||||
|
||||
const addNewEstimationPoint = () => {
|
||||
const currentEstimationPoints = estimatePoints;
|
||||
|
||||
const newEstimationPoint: TEstimatePointsObject = {
|
||||
key: currentEstimationPoints.length + 1,
|
||||
value: "0",
|
||||
@ -27,32 +28,61 @@ export const EstimateUpdateStageTwo: FC<TEstimateUpdateStageTwo> = (props) => {
|
||||
handleEstimatePoints([...currentEstimationPoints, newEstimationPoint]);
|
||||
};
|
||||
|
||||
const deleteEstimationPoint = (index: number) => {
|
||||
const editEstimationPoint = (index: number, value: string) => {
|
||||
const newEstimationPoints = estimatePoints;
|
||||
newEstimationPoints.splice(index, 1);
|
||||
newEstimationPoints[index].value = value;
|
||||
handleEstimatePoints(newEstimationPoints);
|
||||
};
|
||||
|
||||
const updatedSortedKeys = (updatedEstimatePoints: TEstimatePointsObject[]) =>
|
||||
updatedEstimatePoints.map((item, index) => ({
|
||||
const deleteEstimationPoint = (index: number) => {
|
||||
let newEstimationPoints = estimatePoints;
|
||||
newEstimationPoints.splice(index, 1);
|
||||
newEstimationPoints = newEstimationPoints.map((item, index) => ({
|
||||
...item,
|
||||
key: index + 1,
|
||||
}));
|
||||
handleEstimatePoints(newEstimationPoints);
|
||||
};
|
||||
|
||||
const updatedSortedKeys = (updatedEstimatePoints: TEstimatePointsObject[]) => {
|
||||
const sortedEstimatePoints = updatedEstimatePoints.map((item, index) => ({
|
||||
...item,
|
||||
key: index + 1,
|
||||
})) as TEstimatePointsObject[];
|
||||
return sortedEstimatePoints;
|
||||
};
|
||||
|
||||
if (!estimateEditType) return <></>;
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<Sortable
|
||||
data={estimatePoints}
|
||||
render={(value: TEstimatePointsObject, index: number) => (
|
||||
<EstimatePointItem item={value} deleteItem={() => deleteEstimationPoint(index)} />
|
||||
<div className="space-y-1">
|
||||
<div className="text-sm font-medium text-custom-text-300">
|
||||
{estimateEditType === EEstimateUpdateStages.SWITCH ? "Estimate type switching" : currentEstimateSystem?.type}
|
||||
</div>
|
||||
<div className="space-y-3">
|
||||
<Sortable
|
||||
data={estimatePoints}
|
||||
render={(value: TEstimatePointsObject, index: number) => (
|
||||
<EstimatePointItem
|
||||
estimateId={estimate?.id || undefined}
|
||||
mode={estimateEditType}
|
||||
item={value}
|
||||
editItem={(value: string) => editEstimationPoint(index, value)}
|
||||
deleteItem={() => deleteEstimationPoint(index)}
|
||||
/>
|
||||
)}
|
||||
onChange={(data: TEstimatePointsObject[]) => handleEstimatePoints(updatedSortedKeys(data))}
|
||||
keyExtractor={(item: TEstimatePointsObject) => item?.id?.toString() || item.value.toString()}
|
||||
/>
|
||||
{estimateEditType === EEstimateUpdateStages.EDIT && (
|
||||
<>
|
||||
{estimatePoints && estimatePoints.length <= maxEstimatesCount && (
|
||||
<Button size="sm" prependIcon={<Plus />} onClick={addNewEstimationPoint}>
|
||||
Add {currentEstimateSystem?.type}
|
||||
</Button>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
onChange={(data: TEstimatePointsObject[]) => handleEstimatePoints(updatedSortedKeys(data))}
|
||||
keyExtractor={(item: TEstimatePointsObject) => item?.id?.toString() || item.value.toString()}
|
||||
/>
|
||||
|
||||
<Button prependIcon={<Plus />} onClick={addNewEstimationPoint}>
|
||||
Add {currentEstimateSystem?.name}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@ -1,3 +1,6 @@
|
||||
// types
|
||||
import { TEstimateSystems } from "@plane/types";
|
||||
|
||||
export enum EEstimateSystem {
|
||||
POINTS = "points",
|
||||
CATEGORIES = "categories",
|
||||
@ -10,8 +13,7 @@ export enum EEstimateUpdateStages {
|
||||
SWITCH = "switch",
|
||||
}
|
||||
|
||||
// types
|
||||
import { TEstimateSystems } from "@plane/types";
|
||||
export const maxEstimatesCount = 11;
|
||||
|
||||
export const ESTIMATE_SYSTEMS: TEstimateSystems = {
|
||||
points: {
|
||||
|
@ -28,11 +28,11 @@ export interface IEstimate extends IEstimateType {
|
||||
estimatePoints: Record<string, IEstimatePoint>;
|
||||
// computed
|
||||
asJson: IEstimateType;
|
||||
EstimatePointIds: string[] | undefined;
|
||||
estimatePointIds: string[] | undefined;
|
||||
estimatePointById: (estimateId: string) => IEstimatePointType | undefined;
|
||||
// actions
|
||||
updateEstimate: (payload: IEstimateFormData) => Promise<void>;
|
||||
deleteEstimate: (estimatePointId: string) => Promise<void>;
|
||||
deleteEstimate: (estimatePointId: string | undefined) => Promise<void>;
|
||||
}
|
||||
|
||||
export class Estimate implements IEstimate {
|
||||
@ -80,7 +80,7 @@ export class Estimate implements IEstimate {
|
||||
estimatePoints: observable,
|
||||
// computed
|
||||
asJson: computed,
|
||||
EstimatePointIds: computed,
|
||||
estimatePointIds: computed,
|
||||
// actions
|
||||
updateEstimate: action,
|
||||
deleteEstimate: action,
|
||||
@ -126,7 +126,7 @@ export class Estimate implements IEstimate {
|
||||
};
|
||||
}
|
||||
|
||||
get EstimatePointIds() {
|
||||
get estimatePointIds() {
|
||||
const { estimatePoints } = this;
|
||||
if (!estimatePoints) return undefined;
|
||||
|
||||
@ -159,7 +159,7 @@ export class Estimate implements IEstimate {
|
||||
}
|
||||
};
|
||||
|
||||
deleteEstimate = async (estimatePointId: string) => {
|
||||
deleteEstimate = async (estimatePointId: string | undefined) => {
|
||||
try {
|
||||
const { workspaceSlug, projectId } = this.store.router;
|
||||
if (!workspaceSlug || !projectId || !estimatePointId) return;
|
||||
|
Loading…
Reference in New Issue
Block a user