diff --git a/webapp/src/components/shareBoard/shareBoardButton.tsx b/webapp/src/components/shareBoard/shareBoardButton.tsx index 90cb81e51..cd0a12760 100644 --- a/webapp/src/components/shareBoard/shareBoardButton.tsx +++ b/webapp/src/components/shareBoard/shareBoardButton.tsx @@ -24,12 +24,74 @@ import BlackCheckboxOutline from '../../widgets/icons/blackCheckboxOutline' import ShareBoardDialog from './shareBoard' +const valueCategoriesInitialValue: StatusCategory[] = [ + { + id: 'category_id_1', + title: 'Not Started', + options: [ + {id: 'status_id_1', value: 'Pending Design', color: 'propColorPurple'}, + {id: 'status_id_2', value: 'TODO', color: 'propColorYellow'}, + {id: 'status_id_3', value: 'Pending Specs', color: 'propColorGray'}, + ], + emptyState: { + icon: (), + color: '--sys-dnd-indicator-rgb', + text: ( + + ), + }, + }, + { + id: 'category_id_2', + title: 'In progress', + options: [ + {id: 'status_id_4', value: 'In Progress', color: 'propColorBrown'}, + {id: 'status_id_5', value: 'In Review', color: 'propColorRed'}, + {id: 'status_id_6', value: 'In QA', color: 'propColorPink'}, + {id: 'status_id_7', value: 'Awaiting Cherrypick', color: 'propColorOrange'}, + ], + emptyState: { + icon: (), + color: '--away-indicator-rgb', + text: ( + + ), + }, + }, + { + id: 'category_id_3', + title: 'Completed', + options: [ + {id: 'status_id_20', value: 'Done', color: 'propColorPink'}, + {id: 'status_id_21', value: 'Branch Cut', color: 'propColorGreen'}, + {id: 'status_id_22', value: 'Released', color: 'propColorDefault'}, + ], + emptyState: { + icon: (), + color: '--online-indicator-rgb', + text: ( + + ), + }, + }, +] + type Props = { enableSharedBoards: boolean } const ShareBoardButton = (props: Props) => { const [showShareDialog, setShowShareDialog] = useState(false) const board = useAppSelector(getCurrentBoard) + const [valueCategories, setValueCategories] = useState(valueCategoriesInitialValue) const iconForBoardType = () => { if (board.type === BoardTypeOpen) { @@ -38,67 +100,6 @@ const ShareBoardButton = (props: Props) => { return } - const valueCategories: StatusCategory[] = [ - { - id: 'category_id_1', - title: 'Not Started', - options: [ - {id: 'status_id_1', value: 'Pending Design', color: 'propColorPurple'}, - {id: 'status_id_2', value: 'TODO', color: 'propColorYellow'}, - {id: 'status_id_3', value: 'Pending Specs', color: 'propColorGray'}, - ], - emptyState: { - icon: (), - color: '--sys-dnd-indicator-rgb', - text: ( - - ), - }, - }, - { - id: 'category_id_2', - title: 'In progress', - options: [ - {id: 'status_id_4', value: 'In Progress', color: 'propColorBrown'}, - {id: 'status_id_5', value: 'In Review', color: 'propColorRed'}, - {id: 'status_id_6', value: 'In QA', color: 'propColorPink'}, - {id: 'status_id_7', value: 'Awaiting Cherrypick', color: 'propColorOrange'}, - ], - emptyState: { - icon: (), - color: '--away-indicator-rgb', - text: ( - - ), - }, - }, - { - id: 'category_id_3', - title: 'Completed', - options: [ - {id: 'status_id_20', value: 'Done', color: 'propColorPink'}, - {id: 'status_id_21', value: 'Branch Cut', color: 'propColorGreen'}, - {id: 'status_id_22', value: 'Released', color: 'propColorDefault'}, - ], - emptyState: { - icon: (), - color: '--online-indicator-rgb', - text: ( - - ), - }, - }, - ] - return (
diff --git a/webapp/src/components/standardProperties/statusProperty/editStatusDialog.tsx b/webapp/src/components/standardProperties/statusProperty/editStatusDialog.tsx index acef358c3..af3a34b5a 100644 --- a/webapp/src/components/standardProperties/statusProperty/editStatusDialog.tsx +++ b/webapp/src/components/standardProperties/statusProperty/editStatusDialog.tsx @@ -1,12 +1,10 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React, {useEffect, useState} from 'react' +import React, {useCallback, useEffect, useState} from 'react' import {FormattedMessage} from 'react-intl' -import {useCallback} from 'preact/hooks' - -import {DragDropContext, Droppable, Draggable} from 'react-beautiful-dnd' +import {DragDropContext, Droppable, Draggable, DropReason, DropResult} from 'react-beautiful-dnd' import PlusIcon from '../../../widgets/icons/plus' @@ -14,11 +12,12 @@ import InfoIcon from '../../../widgets/icons/info' import './editStatusDialog.scss' import ActionDialog from '../../actionDialog/actionDialog' -import Label from '../../../widgets/label' import {IPropertyOption} from '../../../blocks/board' import DragHandle from '../../../widgets/icons/dragHandle' import EditIcon from '../../../widgets/icons/edit' +import {IDType, Utils} from '../../../utils' + import EditableLabel from './editableLabel/editableLabel' export type StatusCategoryEmptyState = { @@ -29,6 +28,7 @@ export type StatusCategoryEmptyState = { export type EditablePropertyOption = IPropertyOption & { editing?: boolean + focused?: boolean } export type StatusCategory = { @@ -46,9 +46,9 @@ type Props = { const EditStatusPropertyDialog = (props: Props): JSX.Element => { const [valueCategories, setValueCategories] = useState([]) + const [focusedValueID, setFocusedValueID] = useState() useEffect(() => { - console.log('setting: ' + props.valueCategories.length) setValueCategories(props.valueCategories) }, [props.valueCategories]) @@ -59,11 +59,33 @@ const EditStatusPropertyDialog = (props: Props): JSX.Element => { /> ) - const generateValueRow = (option: EditablePropertyOption, index: number): JSX.Element => { + const handleAddNewValue = (statusCategoryID: string, newOptionValue: IPropertyOption): void => { + const categoryIndex = valueCategories.findIndex((valueCategory) => valueCategory.id === statusCategoryID) + if (categoryIndex < 0) { + Utils.logError(`category with ID: ${statusCategoryID} not found`) + return + } + + const valueIndex = valueCategories[categoryIndex].options.findIndex((option) => option.id === newOptionValue.id) + if (valueIndex < 0) { + Utils.logError(`Value with ID ${newOptionValue.id} not found`) + return + } + + const updatedValueCategories = [...valueCategories] + updatedValueCategories[categoryIndex].options[valueIndex] = newOptionValue + + setFocusedValueID('') + setValueCategories(updatedValueCategories) + props.onUpdate(updatedValueCategories) + } + + const generateValueRow = (categoryID: string, option: EditablePropertyOption, index: number): JSX.Element => { return ( {(provided) => (
{
handleAddNewValue(categoryID, newOptionValue)} />
@@ -110,27 +134,45 @@ const EditStatusPropertyDialog = (props: Props): JSX.Element => { } const handleAddCategoryValue = (categoryID: string) => { - console.log('asdasd') const categoryIndex = valueCategories.findIndex((valueCategory) => valueCategory.id === categoryID) if (categoryIndex < 0) { return } const newOption: EditablePropertyOption = { - id: '', + id: Utils.createGuid(IDType.None), value: '', color: 'propColorOrange', - editing: true, } const updatedValueCategories = [...valueCategories] updatedValueCategories[categoryIndex].options.unshift(newOption) + + setFocusedValueID(newOption.id) setValueCategories(updatedValueCategories) } - const onDragEndHandler = () => {} + const onDragEndHandler = useCallback(async (result: DropResult) => { + const {destination, source, type} = result - console.log(valueCategories) + if (type !== 'statusCategory' || !destination) { + return + } + + console.log(`destination: ${destination} source: ${source} type: ${type}`) + + const updatedValues = Array.from(valueCategories) + + const sourceCategoryIndex = updatedValues.findIndex((valueCategory) => valueCategory.id === source.droppableId) + const destinationCategoryIndex = updatedValues.findIndex((valueCategory) => valueCategory.id === destination.droppableId) + + const draggedObject = valueCategories[sourceCategoryIndex].options[source.index] + + updatedValues[sourceCategoryIndex].options.splice(source.index, 1) + updatedValues[destinationCategoryIndex].options.splice(destination.index, 0, draggedObject) + + setValueCategories(updatedValues) + }, [valueCategories]) return ( {
- + {(provided) => (
{ } { valueCategory.options.length > 0 && - valueCategory.options.map((option, index) => generateValueRow(option, index)) + valueCategory.options.map((option, index) => generateValueRow(valueCategory.id, option, index)) }
{provided.placeholder} diff --git a/webapp/src/components/standardProperties/statusProperty/editableLabel/editableLabel.scss b/webapp/src/components/standardProperties/statusProperty/editableLabel/editableLabel.scss index 295359cbd..d04030f1f 100644 --- a/webapp/src/components/standardProperties/statusProperty/editableLabel/editableLabel.scss +++ b/webapp/src/components/standardProperties/statusProperty/editableLabel/editableLabel.scss @@ -1,9 +1,10 @@ -.Label { +.EditableLabel { input { border: none; background: none; border-bottom: 1px solid; border-radius: 0; max-width: 100%; - } + text-transform: uppercase; + } } \ No newline at end of file diff --git a/webapp/src/components/standardProperties/statusProperty/editableLabel/editableLabel.tsx b/webapp/src/components/standardProperties/statusProperty/editableLabel/editableLabel.tsx index b63aeec7f..deba574f0 100644 --- a/webapp/src/components/standardProperties/statusProperty/editableLabel/editableLabel.tsx +++ b/webapp/src/components/standardProperties/statusProperty/editableLabel/editableLabel.tsx @@ -1,6 +1,6 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React from 'react' +import React, {useState} from 'react' import Label from '../../../../widgets/label' @@ -11,23 +11,40 @@ import './editableLabel.scss' type Props = { option: IPropertyOption editing?: boolean + focus?: boolean + onBlur?: (newOptionValue: IPropertyOption) => void } const EditableLabel = (props: Props): JSX.Element => { - const {option} = props + const [value, setValue] = useState(props.option.value) - const displayValue = ({option.value}) + const handleOnBlur = () => { + const newOptionValue = { + ...props.option, + value, + } + + if (props.onBlur) { + props.onBlur(newOptionValue) + } + } + + const displayValue = ({props.option.value}) const editValue = ( setValue(e.target.value)} + onBlur={handleOnBlur} /> ) return (