diff --git a/mw-webapp/src/component/editableText/EditableText.tsx b/mw-webapp/src/component/editableText/EditableText.tsx index 788fdcf35..96a5bd096 100644 --- a/mw-webapp/src/component/editableText/EditableText.tsx +++ b/mw-webapp/src/component/editableText/EditableText.tsx @@ -1,6 +1,7 @@ import {HTMLInputTypeAttribute, useState} from "react"; import clsx from "clsx"; import {renderSpan} from "src/component/editableText/renderSpan"; +import {FormatterInputValue} from "src/component/input/formatters"; import {Input} from "src/component/input/Input"; import {KeySymbols} from "src/utils/KeySymbols"; import styles from "src/component/editableText/EditableText.module.scss"; @@ -11,9 +12,9 @@ import styles from "src/component/editableText/EditableText.module.scss"; interface EditableTextProps { /** - * Cell item's text + * Cell item's value */ - text: T; + value: T; /** * Function that update element on Enter click or unfocused @@ -47,15 +48,15 @@ interface EditableTextProps { /** * Render Input or span depend on client actions */ -export const EditableText = (props: EditableTextProps) => { +export const EditableValue = (props: EditableTextProps) => { const [isEditing, setIsEditing] = useState(false); - const [text, setText] = useState(props.text); + const [value, setValue] = useState(props.value); /** * HandleChangeFinish */ const handleChangeFinish = () => { - props.onChangeFinish(text); + props.onChangeFinish(value); setIsEditing(false); }; @@ -69,12 +70,19 @@ export const EditableText = (props: EditableTextProps }; /** - * Check type of coming value and convert it to Number if need to use input with type "number" + * Update value */ - const setValue = (value: string) => { - const number = Number(value) ?? 0; - const updatedValue = props.type === "number" ? number : value; - setText(updatedValue as T); + const updateValue = (updatedValue: string | number) => { + setValue(updatedValue as T); + }; + + /** + * Get formatted value + */ + const getFormattedValue = (incomingValue: string | number) => { + return typeof incomingValue === "number" + ? FormatterInputValue.withNoFirstZero(incomingValue) + : FormatterInputValue.defaultStringFormatter(incomingValue); }; /** @@ -82,11 +90,12 @@ export const EditableText = (props: EditableTextProps */ const renderInput = () => ( ); @@ -101,7 +110,7 @@ export const EditableText = (props: EditableTextProps > {isEditing ? renderInput() - : renderSpan(text) + : renderSpan(value) } ); diff --git a/mw-webapp/src/component/input/Input.tsx b/mw-webapp/src/component/input/Input.tsx index 1c3138269..dc07ed780 100644 --- a/mw-webapp/src/component/input/Input.tsx +++ b/mw-webapp/src/component/input/Input.tsx @@ -1,17 +1,18 @@ import {HTMLInputTypeAttribute} from "react"; import clsx from "clsx"; import {InputMode} from "src/component/input/InputMode"; +import {ParserInputValue} from "src/component/input/parsers"; import styles from "src/component/input/Input.module.scss"; /** * Input's props */ -interface InputProps { +interface InputProps { /** * Input's value */ - value: string | number; + value: T; /** * Input's type (what type of value is expected) @@ -61,25 +62,52 @@ interface InputProps { /** * Tracks the value entered into the input */ - onChange: (value: string) => void; + onChange: (value: T) => void; + + /** + * Formatting value + */ + formatter?: (value: T) => T; + + /** + * Parsing formatted value + */ + parser?: (value: string) => T; } /** * Input component */ -export const Input = (props: InputProps) => { +export const Input = (props: InputProps) => { /** * Event handler for the input change event */ const onChange = (event: React.ChangeEvent) => { - props.onChange(event.target.value); + let parsedValue: T; + + switch (props.type) { + case "number": { + parsedValue = props.parser + ? props.parser(event.target.value) + : ParserInputValue.defaultNumberParser(event.target.value); + break; + } + case "string": + default: { + parsedValue = props.parser + ? props.parser(event.target.value) + : ParserInputValue.defaultTextParser(event.target.value); + break; + } + } + props.onChange(parsedValue); }; return ( (value: string): T { + return value as T; + } + + /** + * Default number parser + */ + public static defaultNumberParser(value: string): T { + return Number(value) as T; + } + +} diff --git a/mw-webapp/src/component/userCard/UserCard.tsx b/mw-webapp/src/component/userCard/UserCard.tsx index d413d1dc8..9a45f4a7f 100644 --- a/mw-webapp/src/component/userCard/UserCard.tsx +++ b/mw-webapp/src/component/userCard/UserCard.tsx @@ -28,7 +28,7 @@ export const UserCard = (props: UserCardProps) => { const navigate = useNavigate(); return ( - navigate(pages.way.getPath({uuid: props.userPreview.uuid}))}> + navigate(pages.user.getPath({uuid: props.userPreview.uuid}))}> diff --git a/mw-webapp/src/component/wayCard/WayCard.module.scss b/mw-webapp/src/component/wayCard/WayCard.module.scss index 40fcfdbd7..c44be62ef 100644 --- a/mw-webapp/src/component/wayCard/WayCard.module.scss +++ b/mw-webapp/src/component/wayCard/WayCard.module.scss @@ -65,7 +65,7 @@ $wayCardAdditionalHeight: 105px; .wayTags { display: -webkit-box; - overflow: hidden; + align-items: center; -webkit-box-orient: vertical; -webkit-line-clamp: 1; } diff --git a/mw-webapp/src/component/wayCard/wayTag/WayTag.module.scss b/mw-webapp/src/component/wayCard/wayTag/WayTag.module.scss index 493643d87..a6ffc3237 100644 --- a/mw-webapp/src/component/wayCard/wayTag/WayTag.module.scss +++ b/mw-webapp/src/component/wayCard/wayTag/WayTag.module.scss @@ -8,6 +8,6 @@ $WayTagBorderRadius: 1000px; padding: $WayTagPadding; border-radius: $WayTagBorderRadius; margin-right: $marginMedium; - background-color: var(--secondaryBackgroundColor); + background-color: var(--primaryBackgroundColor); color: var(--fourthBackgroundColor); } diff --git a/mw-webapp/src/logic/wayPage/goalMetricsBlock/GoalMetricItem.tsx b/mw-webapp/src/logic/wayPage/goalMetricsBlock/GoalMetricItem.tsx index efda49763..fbcf0a22c 100644 --- a/mw-webapp/src/logic/wayPage/goalMetricsBlock/GoalMetricItem.tsx +++ b/mw-webapp/src/logic/wayPage/goalMetricsBlock/GoalMetricItem.tsx @@ -1,7 +1,7 @@ import {TrashIcon} from "@radix-ui/react-icons"; import {Checkbox} from "src/component/checkbox/Сheckbox"; import {Confirm} from "src/component/confirm/Confirm"; -import {EditableText} from "src/component/editableText/EditableText"; +import {EditableValue} from "src/component/editableText/EditableText"; import {HorizontalContainer} from "src/component/horizontalContainer/HorizontalContainer"; import {Tooltip} from "src/component/tooltip/Tooltip"; import {Metric} from "src/model/businessModel/Metric"; @@ -58,8 +58,8 @@ export const GoalMetricItem = (props: SingleGoalMetricProps) => { onChange={(isDone) => props.updateMetric({...props.metric, isDone, doneDate: new Date()})} /> - props.updateMetric({...props.metric, description})} isEditable={props.isEditable} /> diff --git a/mw-webapp/src/logic/wayPage/reportsTable/reportsColumns/ReportsColumns.tsx b/mw-webapp/src/logic/wayPage/reportsTable/reportsColumns/ReportsColumns.tsx index 73ba36f66..3af98f834 100644 --- a/mw-webapp/src/logic/wayPage/reportsTable/reportsColumns/ReportsColumns.tsx +++ b/mw-webapp/src/logic/wayPage/reportsTable/reportsColumns/ReportsColumns.tsx @@ -4,7 +4,7 @@ import {clsx} from "clsx"; import {Button} from "src/component/button/Button"; import {Checkbox} from "src/component/checkbox/Сheckbox"; import {Confirm} from "src/component/confirm/Confirm"; -import {EditableText} from "src/component/editableText/EditableText"; +import {EditableValue} from "src/component/editableText/EditableText"; import {EditableTextarea} from "src/component/editableTextarea/editableTextarea"; import {HorizontalContainer} from "src/component/horizontalContainer/HorizontalContainer"; import {Link} from "src/component/link/Link"; @@ -274,12 +274,12 @@ export const Columns = (props: ColumnsProps) => { position={PositionTooltip.RIGHT} content={`Time${Symbols.NO_BREAK_SPACE}spent on job`} > - - updateJobDoneTime(jobDone, getValidatedTime(time))} + updateJobDoneTime(jobDone, getValidatedTime(Number(time)))} className={styles.editableTime} isEditable={isUserOwnerOrMentor} /> @@ -460,11 +460,11 @@ export const Columns = (props: ColumnsProps) => { position={PositionTooltip.RIGHT} content={`Estimated${Symbols.NO_BREAK_SPACE}time for the plan`} > - updatePlanTime(plan, getValidatedTime(estimationTime))} + onChangeFinish={(estimationTime) => updatePlanTime(plan, getValidatedTime(Number(estimationTime)))} className={styles.editableTime} isEditable={plan.ownerUuid === user?.uuid} />