From aff2b1811eadee4c59bebe789fca4d21f97db17e Mon Sep 17 00:00:00 2001 From: guru_sainath Date: Fri, 14 Jun 2024 16:17:28 +0530 Subject: [PATCH] [WEB-522] feat: revamp estimates (#394) * Move code from EE to CE repo * chore: folder structure updates * Move sortabla and radio input to packages/ui * chore: updated empty and loading screens * chore: delete an estimate point * chore: estimate point response change * chore: updated create estimate and handled the build error * chore: migration fixes * chore: updated create estimate * chore: create estimate workflow update * chore: editing and deleting the existing estimate updates * chore: updating the new estinates in update modal * chore: ui changed * chore: response changes of get and post * chore: new field added in estimates * chore: individual endpoint for estimate points * chore: typo changes * chore: create estimate point * chore: integrated new endpoints * chore: update key value pair * chore: update sorting in the estimates * Add custom option in the estimate templates * chore: handled current project active estimate * chore: handle estimate update worklfow * chore: handled estimates switch * chore: handled estimate edit * chore: handled close button in estimate edit * chore: updated ceate estimare workflow * chore: updated switch estimate * chore: UI and typos * chore: resolved build error * chore: updated delete dropdown and handled the repeated values while creating and updating the estimate point * chore: handled inline errors in the estimate switch * chore: handled active and availability vadilation * chore: handled create and update components in projecr estimates * chore: added migration * Add category specific values for custom template * chore: estimate dropdown handled in issues * chore: estimate alerts * chore: updated alerts * Extract the list row actions * fix: updated and handled the estimate points * fix: upgrader ee banner * Fix issues with sortable * Fix sortable spacing issue in create estimate modal * fix: updated the issue create sorting * chore: removed radio button from ui and updated in the estimates * chore: resolved import error in packaged ui * chore: handled props in create modal * chore: enabled estimated edit and ui changes * chore: handled repeated values in estimate switch * chore: handled estimate create and edit modal * chore: resolved conflicts and added estimate update and switch in ee * chore: resolved conflicts on estimates * chore: resolved file imports * chore: updated file intendation * chore: space fixes * chore: updated error handling in the estimate update * chore: updated error handling in the estimate switch * chore: updated yarn.lock * chore: updated yarn.lock indent --------- Co-authored-by: Satish Gandham Co-authored-by: NarayanBavisetti --- .../estimates/estimate-list-item-buttons.tsx | 29 ++- web/ee/components/estimates/index.ts | 1 + .../components/estimates/points/edit-root.tsx | 236 ++++++++++++++++++ web/ee/components/estimates/points/index.ts | 2 + .../estimates/points/switch/index.ts | 2 + .../estimates/points/switch/preview.tsx | 65 +++++ .../estimates/points/switch/root.tsx | 224 +++++++++++++++++ web/ee/components/estimates/update/index.ts | 1 + web/ee/components/estimates/update/modal.tsx | 87 ++++++- .../components/estimates/update/stage-one.tsx | 52 ++++ web/ee/constants/estimates.ts | 40 ++- 11 files changed, 736 insertions(+), 3 deletions(-) create mode 100644 web/ee/components/estimates/points/edit-root.tsx create mode 100644 web/ee/components/estimates/points/index.ts create mode 100644 web/ee/components/estimates/points/switch/index.ts create mode 100644 web/ee/components/estimates/points/switch/preview.tsx create mode 100644 web/ee/components/estimates/points/switch/root.tsx create mode 100644 web/ee/components/estimates/update/stage-one.tsx diff --git a/web/ee/components/estimates/estimate-list-item-buttons.tsx b/web/ee/components/estimates/estimate-list-item-buttons.tsx index 4e5008ea53..f1996a5ec6 100644 --- a/web/ee/components/estimates/estimate-list-item-buttons.tsx +++ b/web/ee/components/estimates/estimate-list-item-buttons.tsx @@ -1 +1,28 @@ -export * from "ce/components/estimates/estimate-list-item-buttons"; +import { FC } from "react"; +import { observer } from "mobx-react"; +import { Pen } from "lucide-react"; + +type TEstimateListItem = { + estimateId: string; + isAdmin: boolean; + isEstimateEnabled: boolean; + isEditable: boolean; + onEditClick?: (estimateId: string) => void; + onDeleteClick?: (estimateId: string) => void; +}; + +export const EstimateListItemButtons: FC = observer((props) => { + const { estimateId, isAdmin, isEditable, onEditClick } = props; + + if (!isAdmin || !isEditable) return <>; + return ( +
+ +
+ ); +}); diff --git a/web/ee/components/estimates/index.ts b/web/ee/components/estimates/index.ts index 4ad250c456..918b72d8d7 100644 --- a/web/ee/components/estimates/index.ts +++ b/web/ee/components/estimates/index.ts @@ -1,2 +1,3 @@ export * from "./estimate-list-item-buttons"; export * from "./update"; +export * from "./points"; diff --git a/web/ee/components/estimates/points/edit-root.tsx b/web/ee/components/estimates/points/edit-root.tsx new file mode 100644 index 0000000000..17b3f3f038 --- /dev/null +++ b/web/ee/components/estimates/points/edit-root.tsx @@ -0,0 +1,236 @@ +import { Dispatch, FC, Fragment, SetStateAction, useState } from "react"; +import { observer } from "mobx-react"; +import { ChevronLeft, Plus } from "lucide-react"; +import { TEstimatePointsObject, TEstimateTypeError, TEstimateUpdateStageKeys } from "@plane/types"; +import { Button, Sortable, TOAST_TYPE, setToast } from "@plane/ui"; +// components +import { EstimatePointItemPreview, EstimatePointCreate } from "@/components/estimates/points"; +// hooks +import { useEstimate } from "@/hooks/store"; +// plane web constants +import { EEstimateUpdateStages, estimateCount } from "@/plane-web/constants/estimates"; + +type TEstimatePointEditRoot = { + workspaceSlug: string; + projectId: string; + estimateId: string; + mode?: EEstimateUpdateStages; + setEstimateEditType?: Dispatch>; + handleClose: () => void; +}; + +export const EstimatePointEditRoot: FC = observer((props) => { + // props + const { workspaceSlug, projectId, estimateId, setEstimateEditType, handleClose } = props; + // hooks + const { asJson: estimate, estimatePointIds, estimatePointById, updateEstimateSortOrder } = useEstimate(estimateId); + // states + const [estimatePointCreate, setEstimatePointCreate] = useState(undefined); + const [estimatePointError, setEstimatePointError] = useState(undefined); + + const estimatePoints: TEstimatePointsObject[] = + estimatePointIds && estimatePointIds.length > 0 + ? (estimatePointIds.map((estimatePointId: string) => { + const estimatePoint = estimatePointById(estimatePointId); + if (estimatePoint) return { id: estimatePointId, key: estimatePoint.key, value: estimatePoint.value }; + }) as TEstimatePointsObject[]) + : ([] as TEstimatePointsObject[]); + + const handleEstimatePointCreate = (mode: "add" | "remove", value: TEstimatePointsObject) => { + switch (mode) { + case "add": + setEstimatePointCreate((prevValue) => { + prevValue = prevValue ? [...prevValue] : []; + return [...prevValue, value]; + }); + break; + case "remove": + setEstimatePointCreate((prevValue) => { + prevValue = prevValue ? [...prevValue] : []; + return prevValue.filter((item) => item.key !== value.key); + }); + break; + default: + break; + } + }; + + const handleDragEstimatePoints = async (updatedEstimatedOrder: TEstimatePointsObject[]) => { + try { + const updatedEstimateKeysOrder = updatedEstimatedOrder.map((item, index) => ({ ...item, key: index + 1 })); + await updateEstimateSortOrder(workspaceSlug, projectId, updatedEstimateKeysOrder); + setToast({ + type: TOAST_TYPE.SUCCESS, + title: "Estimates re-ordered", + message: "Estimates have been re-ordered in your project.", + }); + } catch { + setToast({ + type: TOAST_TYPE.ERROR, + title: "Estimate re-order failed", + message: "We were unable to re-order the estimates, please try again", + }); + } + }; + + 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; + } + }); + }; + + 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: currentKey, + value: "", + }); + handleEstimatePointError && handleEstimatePointError(currentKey, "", "", undefined, "add"); + } + }; + + 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 handleEstimateDone = async () => { + if (!validateEstimatePointError()) { + handleClose(); + } else { + 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 { + // NOTE: validate the estimate type + 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; + }); + } + }; + + if (!workspaceSlug || !projectId || !estimateId) return <>; + return ( + <> +
+
+
setEstimateEditType && setEstimateEditType(undefined)} + className="flex-shrink-0 cursor-pointer w-5 h-5 flex justify-center items-center" + > + +
+
Edit estimate system
+
+ + +
+ +
+
{estimate?.type}
+
+ ( + + {value?.id && estimate?.type ? ( + + handleEstimatePointError && + handleEstimatePointError(value.key, value.value, newValue, message, mode) + } + /> + ) : null} + + )} + onChange={(data: TEstimatePointsObject[]) => handleDragEstimatePoints(data)} + keyExtractor={(item: TEstimatePointsObject) => item?.id?.toString() || item.value.toString()} + /> +
+ + {estimatePointCreate && + estimatePointCreate.map( + (estimatePoint) => + estimate?.type && ( + handleEstimatePointCreate("remove", estimatePoint)} + estimatePoints={estimatePoints} + handleCreateCallback={() => estimatePointCreate.length === 1 && handleCreate()} + 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 && ( + + )} +
+ + ); +}); diff --git a/web/ee/components/estimates/points/index.ts b/web/ee/components/estimates/points/index.ts new file mode 100644 index 0000000000..48b14a3049 --- /dev/null +++ b/web/ee/components/estimates/points/index.ts @@ -0,0 +1,2 @@ +export * from "./edit-root"; +export * from "./switch"; diff --git a/web/ee/components/estimates/points/switch/index.ts b/web/ee/components/estimates/points/switch/index.ts new file mode 100644 index 0000000000..5dab2e2b2e --- /dev/null +++ b/web/ee/components/estimates/points/switch/index.ts @@ -0,0 +1,2 @@ +export * from "./root"; +export * from "./preview"; diff --git a/web/ee/components/estimates/points/switch/preview.tsx b/web/ee/components/estimates/points/switch/preview.tsx new file mode 100644 index 0000000000..8e993506c6 --- /dev/null +++ b/web/ee/components/estimates/points/switch/preview.tsx @@ -0,0 +1,65 @@ +import { FC } from "react"; +import { observer } from "mobx-react"; +import { Info, MoveRight } from "lucide-react"; +import { TEstimatePointsObject, TEstimateTypeErrorObject } from "@plane/types"; +import { Tooltip } from "@plane/ui"; +// helpers +import { cn } from "@/helpers/common.helper"; +// hooks +import { useEstimatePoint } from "@/hooks/store"; + +type TEstimatePointItemSwitchPreview = { + estimateId: string; + estimatePointId: string | undefined; + estimatePoint: TEstimatePointsObject; + handleEstimatePoint: (value: string) => void; + estimatePointError?: TEstimateTypeErrorObject | undefined; +}; + +export const EstimatePointItemSwitchPreview: FC = observer((props) => { + const { + estimateId, + estimatePointId, + estimatePoint: currentEstimatePoint, + handleEstimatePoint, + estimatePointError, + } = props; + // hooks + const { asJson: estimatePoint } = useEstimatePoint(estimateId, estimatePointId); + + if (!estimatePoint) return <>; + return ( +
+
+ {estimatePoint?.value} +
+
+ +
+
+ handleEstimatePoint(e.target.value)} + className="border-none focus:ring-0 focus:border-0 focus:outline-none p-2.5 w-full bg-transparent" + autoFocus + placeholder="Enter estimate point value" + /> + {estimatePointError?.message && ( + <> + +
+ +
+
+ + )} +
+
+ ); +}); diff --git a/web/ee/components/estimates/points/switch/root.tsx b/web/ee/components/estimates/points/switch/root.tsx new file mode 100644 index 0000000000..42b8f11a02 --- /dev/null +++ b/web/ee/components/estimates/points/switch/root.tsx @@ -0,0 +1,224 @@ +import { Dispatch, FC, SetStateAction, useEffect, useState } from "react"; +import { observer } from "mobx-react"; +import { ChevronLeft } from "lucide-react"; +import { + IEstimateFormData, + TEstimatePointsObject, + TEstimateSystemKeys, + TEstimateTypeError, + TEstimateUpdateStageKeys, +} from "@plane/types"; +import { Button, TOAST_TYPE, setToast } from "@plane/ui"; +// hooks +import { useEstimate } from "@/hooks/store"; +// plane web components +import { EstimatePointItemSwitchPreview } from "@/plane-web/components/estimates"; +// plane web constants +import { EEstimateSystem, EEstimateUpdateStages, ESTIMATE_SYSTEMS } from "@/plane-web/constants/estimates"; + +type TEstimatePointSwitchRoot = { + setEstimateEditType?: Dispatch>; + estimateSystemSwitchType: TEstimateSystemKeys; + workspaceSlug: string; + projectId: string; + estimateId: string; + handleClose: () => void; + mode?: EEstimateUpdateStages; +}; + +export const EstimatePointSwitchRoot: FC = observer((props) => { + // props + const { setEstimateEditType, estimateSystemSwitchType, workspaceSlug, projectId, estimateId, handleClose } = props; + // hooks + const { asJson: estimate, estimatePointIds, estimatePointById, updateEstimateSwitch } = useEstimate(estimateId); + // states + const [estimatePoints, setEstimatePoints] = useState(undefined); + const [estimatePointError, setEstimatePointError] = useState(undefined); + + 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 (!estimatePointIds) return; + setEstimatePoints( + estimatePointIds.map((estimatePointId: string) => { + const estimatePoint = estimatePointById(estimatePointId); + if (estimatePoint) return { id: estimatePointId, key: estimatePoint.key, value: "" }; + }) as TEstimatePointsObject[] + ); + }, [estimatePointById, estimatePointIds]); + + const handleEstimatePoints = (index: number, value: string) => { + setEstimatePoints((prevValue) => { + prevValue = prevValue ? [...prevValue] : []; + prevValue[index].value = value; + handleEstimatePointError(prevValue[index].key, "", "", undefined, "delete"); + return prevValue; + }); + }; + + const isValidEstimatePoints = (estimateSystemSwitchType: TEstimateSystemKeys) => { + let isValid: boolean = false; + + // validate if the fields are empty + const isNonEmptyPoints = []; + estimatePoints?.map((estimatePoint) => { + if (estimatePoint.value && estimatePoint.value != "" && estimatePoint.value.length > 0) { + isNonEmptyPoints.push(estimatePoint.value); + } else { + handleEstimatePointError(estimatePoint.key, "", "", "Please fill this estimate point field"); + } + }); + if (isNonEmptyPoints.length === estimatePoints?.length) { + isValid = true; + } else { + isValid = false; + } + + // validate if fields are repeated + const repeatedValues: string[] = []; + estimatePoints?.map((estimatePoint) => { + if (estimatePoint.value && estimatePoint.value != "") { + if (repeatedValues.includes(estimatePoint.value)) { + handleEstimatePointError(estimatePoint.key, "", "", "Estimate point value cannot be repeated"); + } else { + repeatedValues.push(estimatePoint.value); + } + } + }); + if (repeatedValues.length === estimatePoints?.length) { + isValid = true; + } else { + isValid = false; + } + + // validate if fields are valid in points and time required number values and categories required string values + const estimatePointArray: string[] = []; + if ([(EEstimateSystem.TIME, EEstimateSystem.POINTS)].includes(estimateSystemSwitchType)) { + estimatePoints?.map((estimatePoint) => { + if (estimateSystemSwitchType && estimatePoint.value && estimatePoint.value != "") { + if (Number(estimatePoint.value) && Number(estimatePoint.value) >= 0) { + estimatePointArray.push(estimatePoint.value); + } else { + handleEstimatePointError(estimatePoint.key, "", "", "Estimate point value should be a number."); + } + } + }); + } else if (estimateSystemSwitchType === EEstimateSystem.CATEGORIES) { + estimatePoints?.map((estimatePoint) => { + if (estimatePoint.value && estimatePoint.value != "") { + if (estimatePoint.value.length > 0 && isNaN(Number(estimatePoint.value))) { + estimatePointArray.push(estimatePoint.value); + } else { + handleEstimatePointError(estimatePoint.key, "", "", "Estimate point value should be a string."); + } + } + }); + } + if (estimatePointArray.length === estimatePoints?.length) { + isValid = true; + } else { + isValid = false; + } + + return isValid; + }; + + const handleSwitchEstimate = async () => { + try { + if (!workspaceSlug || !projectId) return; + + const isEstimatesValid = estimateSystemSwitchType && isValidEstimatePoints(estimateSystemSwitchType); + + if (isEstimatesValid) { + const validatedEstimatePoints: TEstimatePointsObject[] = []; + estimatePoints?.map((estimatePoint) => { + validatedEstimatePoints.push(estimatePoint); + }); + + const payload: IEstimateFormData = { + estimate: { + name: ESTIMATE_SYSTEMS[estimateSystemSwitchType]?.name, + type: estimateSystemSwitchType, + }, + estimate_points: validatedEstimatePoints, + }; + await updateEstimateSwitch(workspaceSlug, projectId, payload); + + setToast({ + type: TOAST_TYPE.SUCCESS, + title: "Estimate system created", + message: "Created and Enabled successfully", + }); + handleClose(); + } + } catch (error) { + setToast({ + type: TOAST_TYPE.ERROR, + title: "Error!", + message: "something went wrong", + }); + } + }; + + if (!workspaceSlug || !projectId || !estimateId || !estimatePoints) return <>; + return ( + <> +
+
+
setEstimateEditType && setEstimateEditType(undefined)} + className="flex-shrink-0 cursor-pointer w-5 h-5 flex justify-center items-center" + > + +
+
Edit estimate system
+
+
+ +
+
+
Current {estimate?.type}
+
+
New {estimateSystemSwitchType}
+
+ + {estimatePoints.map((estimateObject, index) => ( + handleEstimatePoints(index, value)} + estimatePointError={estimatePointError?.[estimateObject.key] || undefined} + /> + ))} +
+ +
+ + + +
+ + ); +}); diff --git a/web/ee/components/estimates/update/index.ts b/web/ee/components/estimates/update/index.ts index 031608e25f..7de8cb9889 100644 --- a/web/ee/components/estimates/update/index.ts +++ b/web/ee/components/estimates/update/index.ts @@ -1 +1,2 @@ export * from "./modal"; +export * from "./stage-one"; diff --git a/web/ee/components/estimates/update/modal.tsx b/web/ee/components/estimates/update/modal.tsx index 5c7d0b725f..8dd54c4b45 100644 --- a/web/ee/components/estimates/update/modal.tsx +++ b/web/ee/components/estimates/update/modal.tsx @@ -1 +1,86 @@ -export * from "ce/components/estimates/update/modal"; +import { FC, useEffect, useState } from "react"; +import { observer } from "mobx-react"; +import { TEstimateSystemKeys, TEstimateUpdateStageKeys } from "@plane/types"; +// components +import { EModalPosition, EModalWidth, ModalCore } from "@/components/core"; +// hooks +import { useEstimate } from "@/hooks/store"; +// plane web components +import { + EstimateUpdateStageOne, + EstimatePointEditRoot, + EstimatePointSwitchRoot, +} from "@/plane-web/components/estimates"; +// plane web constants +import { EEstimateSystem, EEstimateUpdateStages } from "@/plane-web/constants/estimates"; + +type TUpdateEstimateModal = { + workspaceSlug: string; + projectId: string; + estimateId: string | undefined; + isOpen: boolean; + handleClose: () => void; +}; + +export const UpdateEstimateModal: FC = observer((props) => { + // props + const { workspaceSlug, projectId, estimateId, isOpen, handleClose } = props; + // hooks + const { asJson: estimate } = useEstimate(estimateId); + // states + const [estimateEditType, setEstimateEditType] = useState(undefined); + const [estimateSystemSwitchType, setEstimateSystemSwitchType] = useState(undefined); + + useEffect(() => { + if (isOpen) { + setEstimateEditType(undefined); + setEstimateSystemSwitchType(undefined); + } + }, [isOpen]); + + const handleEstimateEditType = (type: TEstimateUpdateStageKeys) => { + if (type === EEstimateUpdateStages.SWITCH && estimate?.type) + setEstimateSystemSwitchType( + estimate?.type === EEstimateSystem.CATEGORIES ? EEstimateSystem.POINTS : EEstimateSystem.CATEGORIES + ); + setEstimateEditType(type); + }; + + return ( + +
+ {!estimateEditType && ( + + )} + + {estimateEditType && estimateId && ( + <> + {estimateEditType === EEstimateUpdateStages.EDIT && ( + + )} + {estimateEditType === EEstimateUpdateStages.SWITCH && estimateSystemSwitchType && ( + + )} + + )} +
+
+ ); +}); diff --git a/web/ee/components/estimates/update/stage-one.tsx b/web/ee/components/estimates/update/stage-one.tsx new file mode 100644 index 0000000000..bd55bacd6c --- /dev/null +++ b/web/ee/components/estimates/update/stage-one.tsx @@ -0,0 +1,52 @@ +"use client"; + +import { FC } from "react"; +import { TEstimateUpdateStageKeys } from "@plane/types"; +import { Button } from "@plane/ui"; +// plane web constants +import { ESTIMATE_OPTIONS_STAGE_ONE } from "@/plane-web/constants/estimates"; + +type TEstimateUpdateStageOne = { + estimateEditType?: TEstimateUpdateStageKeys; + handleClose: () => void; + handleEstimateEditType?: (stage: TEstimateUpdateStageKeys) => void; +}; + +export const EstimateUpdateStageOne: FC = (props) => { + const { estimateEditType, handleClose, handleEstimateEditType } = props; + + return ( + <> +
+
Edit estimate system
+
+ + {!estimateEditType && ( +
+ {ESTIMATE_OPTIONS_STAGE_ONE && + Object.keys(ESTIMATE_OPTIONS_STAGE_ONE).map((stage) => { + const currentStage = stage as TEstimateUpdateStageKeys; + return ( +
handleEstimateEditType && handleEstimateEditType(currentStage)} + > +

{ESTIMATE_OPTIONS_STAGE_ONE?.[currentStage]?.title}

+

+ {ESTIMATE_OPTIONS_STAGE_ONE?.[currentStage]?.description} +

+
+ ); + })} +
+ )} + +
+ +
+ + ); +}; diff --git a/web/ee/constants/estimates.ts b/web/ee/constants/estimates.ts index 06376ef9dd..ed63985569 100644 --- a/web/ee/constants/estimates.ts +++ b/web/ee/constants/estimates.ts @@ -1 +1,39 @@ -export * from "ce/constants/estimates"; +import { EEstimateSystem, EEstimateUpdateStages, estimateCount, ESTIMATE_SYSTEMS } from "ce/constants/estimates"; + +estimateCount.max = 12; + +ESTIMATE_SYSTEMS.points.templates.fibonacci.values = [ + ...ESTIMATE_SYSTEMS.points.templates.fibonacci.values, + { id: undefined, key: 7, value: "21" }, + { id: undefined, key: 8, value: "34" }, + { id: undefined, key: 9, value: "55" }, +]; + +ESTIMATE_SYSTEMS.points.templates.linear.values = [ + ...ESTIMATE_SYSTEMS.points.templates.linear.values, + { id: undefined, key: 7, value: "7" }, + { id: undefined, key: 8, value: "8" }, + { id: undefined, key: 9, value: "9" }, +]; + +ESTIMATE_SYSTEMS.points.templates.squares.values = [ + ...ESTIMATE_SYSTEMS.points.templates.squares.values, + { id: undefined, key: 7, value: "49" }, + { id: undefined, key: 8, value: "64" }, + { id: undefined, key: 9, value: "81" }, +]; + +export { EEstimateSystem, EEstimateUpdateStages, estimateCount, ESTIMATE_SYSTEMS }; + +export const ESTIMATE_OPTIONS_STAGE_ONE: Partial< + Record +> = { + [EEstimateUpdateStages.EDIT]: { + title: "Add, update or remove estimates", + description: "Manage current system either adding, updating or removing the points or categories.", + }, + [EEstimateUpdateStages.SWITCH]: { + title: "Change estimate type", + description: "Convert your points system to categories system and vice versa.", + }, +};