2024-05-27 04:17:31 +00:00
|
|
|
import { FC, Fragment, useEffect, useRef, useState } from "react";
|
2024-05-23 08:11:30 +00:00
|
|
|
import { Check, GripVertical, MoveRight, Pencil, Trash2, X } from "lucide-react";
|
|
|
|
import { Select } from "@headlessui/react";
|
2024-05-27 04:17:31 +00:00
|
|
|
import { TEstimatePointsObject } from "@plane/types";
|
2024-05-23 10:28:14 +00:00
|
|
|
import { Draggable } from "@plane/ui";
|
2024-05-27 04:17:31 +00:00
|
|
|
// constants
|
|
|
|
import { EEstimateUpdateStages } from "@/constants/estimates";
|
|
|
|
// components
|
2024-05-23 08:11:30 +00:00
|
|
|
import { InlineEdit } from "./inline-editable";
|
|
|
|
|
2024-05-27 04:17:31 +00:00
|
|
|
type TEstimatePointItem = {
|
|
|
|
mode: EEstimateUpdateStages;
|
2024-05-24 09:37:44 +00:00
|
|
|
item: TEstimatePointsObject;
|
2024-05-27 04:17:31 +00:00
|
|
|
editItem: (value: string) => void;
|
2024-05-23 08:11:30 +00:00
|
|
|
deleteItem: () => void;
|
|
|
|
};
|
|
|
|
|
2024-05-27 04:17:31 +00:00
|
|
|
const EstimatePointItem: FC<TEstimatePointItem> = (props) => {
|
|
|
|
// props
|
|
|
|
const { mode, item, editItem, deleteItem } = props;
|
|
|
|
const { id, key, value } = item;
|
|
|
|
// ref
|
2024-05-23 08:11:30 +00:00
|
|
|
const inputRef = useRef<HTMLInputElement>(null);
|
2024-05-27 04:17:31 +00:00
|
|
|
// states
|
|
|
|
const [inputValue, setInputValue] = useState<string | undefined>(undefined);
|
2024-05-23 08:11:30 +00:00
|
|
|
const [isEditing, setIsEditing] = useState(false);
|
2024-05-27 04:17:31 +00:00
|
|
|
const [showDeleteUI, setShowDeleteUI] = useState(false);
|
2024-05-23 08:11:30 +00:00
|
|
|
|
2024-05-27 04:17:31 +00:00
|
|
|
useEffect(() => {
|
|
|
|
if (inputValue === undefined) setInputValue(value);
|
|
|
|
}, [value, inputValue]);
|
|
|
|
|
|
|
|
const handleSave = () => {
|
2024-05-23 08:11:30 +00:00
|
|
|
if (id) {
|
2024-05-27 04:17:31 +00:00
|
|
|
// Make the api call to save the estimate point
|
|
|
|
// Show a spinner
|
|
|
|
setIsEditing(false);
|
2024-05-23 08:11:30 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2024-05-27 04:17:31 +00:00
|
|
|
const handleEdit = (value: string) => {
|
|
|
|
if (id) {
|
|
|
|
setIsEditing(true);
|
|
|
|
setTimeout(() => {
|
|
|
|
inputRef.current?.focus();
|
|
|
|
inputRef.current?.select();
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
setInputValue(value);
|
|
|
|
editItem(value);
|
|
|
|
}
|
2024-05-23 08:11:30 +00:00
|
|
|
};
|
|
|
|
|
2024-05-27 04:17:31 +00:00
|
|
|
const handleDelete = () => {
|
2024-05-23 08:11:30 +00:00
|
|
|
if (id) {
|
2024-05-27 04:17:31 +00:00
|
|
|
setShowDeleteUI(true);
|
|
|
|
} else {
|
|
|
|
deleteItem();
|
2024-05-23 08:11:30 +00:00
|
|
|
}
|
|
|
|
};
|
2024-05-27 04:17:31 +00:00
|
|
|
|
2024-05-23 08:11:30 +00:00
|
|
|
return (
|
|
|
|
<Draggable data={item}>
|
2024-05-27 04:17:31 +00:00
|
|
|
{mode === EEstimateUpdateStages.CREATE && (
|
|
|
|
<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) => handleEdit(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}
|
|
|
|
>
|
|
|
|
<Trash2 size={14} className="text-custom-text-200" />
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
|
|
|
|
{mode === EEstimateUpdateStages.EDIT && (
|
|
|
|
<>
|
|
|
|
<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>
|
|
|
|
</>
|
|
|
|
)}
|
|
|
|
|
|
|
|
{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">
|
2024-05-23 08:11:30 +00:00
|
|
|
<input
|
|
|
|
type="text"
|
|
|
|
value={value}
|
|
|
|
onChange={() => {}}
|
2024-05-27 04:17:31 +00:00
|
|
|
className="border rounded-md border-custom-border-300 p-3 flex-grow"
|
2024-05-23 08:11:30 +00:00
|
|
|
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>
|
|
|
|
)}
|
2024-05-27 04:17:31 +00:00
|
|
|
|
2024-05-23 08:11:30 +00:00
|
|
|
{!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>
|
2024-05-27 04:17:31 +00:00
|
|
|
)} */}
|
2024-05-23 08:11:30 +00:00
|
|
|
</Draggable>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
2024-05-27 04:17:31 +00:00
|
|
|
export { EstimatePointItem };
|