ToolJet/frontend/src/Editor/Components/KanbanBoard/CardPopover.jsx
Arpit b48fd53ec2
[Feature] Kanban board widget (#3049)
* init kanban board widget

* kanban board

* reverts to beautifully

* kanban UI updates and dnd fixes

* bugfix: when dropped outside the col, should return back to it inital position

* updates min-width of the column

* container and widget styles

* style fixes: column container onDrag

* adds button for new group

* fixes new card overflow

* add btn for adding cards

* groups and cards updated

* add property definition

* improves draggable card position while drag is active

* handle delete group/col

* handle col/group title updates

* handles editing card title

* style fixes for input cursor

* cleanup

* card popover with codehinter fields

* minor card fixes

* updates exposed variable

* simplify boardData into cols and cards

* adds width and min-width style definations

* build board from queries

* handle draggable rbd-id

* removes add group card and delete group option

* fixes typos

* show empty state message

* fixes typos

* removes card extra border color

* fixes column typi and cards updates issue

* adds enableAddCard property defination

* adds accent color options

* default style accent color

* accent color fix

* revets popover with hinter

* fixes card drag and drop

* removes hook

* fixes: state synced with property defination updates(col and cards data)

* fixes: on re-arranging the card via dnd, update the card content

* handles if card columnId is updated

* adds card container layer

* clean up

* dark theme

* fixes card onDrop issue

* renamed the exposed variable data --> lists

* adds custom resolvers to the popover

* handle widget crash when non iterables are passed

* updates default card and col value

* fixes dnd issues for dynamic card values

* refactor: cleanup

* handles empty and undefined cardData

* fixes Height of widget is changing when popover thing is displayed.

* fixes: updating card data in widget inspector

* fixes: updating column data in widget inspector

* fixes adding cards for newly created groups/columns

* clean up

* Add kanban event onCardAdded and expose lastAddedCard

* Add onCardRemoved action and expsed lastRemovedCard variable

* Add events and variables for card movement and selection

* Add card edit feature for kanban widget

* Rename lastAddedRemoved to lastRemovedCard in kanban

* Rename lists to columns on kanban board

* Set max height of kanban column to respond to widget height

* Have "Add description" link if there is no description for Kanban cards

* kanban docs

* Change text from "add +" to "Add card" on kanban

* Validate card data before update

* Add tip about card id type on kanban documentation

* Add default min width and width for kanban

Co-authored-by: Sherfin Shamsudeen <sherfin94@gmail.com>
Co-authored-by: Shubhendra <withshubh@gmail.com>
2022-06-14 11:06:36 +05:30

157 lines
5.3 KiB
JavaScript

import React, { useEffect, useRef, useState } from 'react';
export const CardEventPopover = function ({
show,
offset,
kanbanCardWidgetId,
popoverClosed,
card,
updateCardProperty,
index,
keyIndex,
}) {
const parentRef = useRef(null);
const [showPopover, setShow] = useState(show);
const [top, setTop] = useState(0);
const [left, setLeft] = useState(0);
const [titleInputBoxValue, setTitleInputBoxValue] = useState(card.title ?? '');
const [descriptionTextAreaValue, setDescriptionTextAreaValue] = useState(card.description ?? '');
const [titleHovered, setTitleHovered] = useState(false);
const [descriptionHovered, setDescriptionHovered] = useState(false);
const [titleEditMode, setTitleEditMode] = useState(false);
const [descriptionEditMode, setDescriptionEditMode] = useState(false);
const minHeight = 400;
let kanbanBounds;
const kanbanElement = document.getElementById(kanbanCardWidgetId);
const handleClickOutside = (event) => {
if (parentRef.current && !parentRef.current.contains(event.target)) {
popoverClosed();
}
};
useEffect(() => {
document.addEventListener('click', handleClickOutside, true);
return () => {
document.removeEventListener('click', handleClickOutside, true);
};
});
useEffect(() => {
setShow(show);
}, [show]);
useEffect(() => {
if (offset?.top && showPopover) {
const _left = offset.left - kanbanBounds.x + offset.width;
const _top = ((offset.top - kanbanBounds.y) * 100) / kanbanBounds.height;
setTop(_top);
setLeft(_left);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [offset?.top, showPopover]);
if (kanbanElement && showPopover) {
kanbanBounds = kanbanElement.getBoundingClientRect();
}
const darkMode = localStorage.getItem('darkMode') === 'true';
return (
<div
style={{
position: 'absolute',
zIndex: 100,
width: '300px',
maxWidth: '300px',
height: 300,
top: `${top}%`,
left,
display: showPopover ? 'block' : 'none',
}}
role="tooltip"
x-placement="left"
className={`popover bs-popover-left shadow-lg ${darkMode && 'popover-dark-themed theme-dark'}`}
ref={parentRef}
id={`${kanbanCardWidgetId}-popover`}
>
{parentRef.current && showPopover && (
<div className="popover-body" style={{ padding: 'unset', width: '100%', height: 100, zIndex: 11 }}>
<div className="rows p-2 overflow-auto">
<div
className="row overflow-auto"
onMouseEnter={() => setTitleHovered(true)}
onMouseLeave={() => setTitleHovered(false)}
>
{titleEditMode ? (
<div>
<input
type="text"
className="form-control"
defaultValue={titleInputBoxValue}
onChange={(event) => setTitleInputBoxValue(event.target.value)}
onBlur={() => {
updateCardProperty(keyIndex, index, 'title', titleInputBoxValue);
setTitleEditMode(false);
}}
/>
</div>
) : (
<h3>
{card?.title ?? ''}
<img
src="/assets/images/icons/editor/edit.svg"
style={{ visibility: titleHovered ? 'visible' : 'hidden', height: 15, width: 15, paddingLeft: 1 }}
onClick={() => setTitleEditMode(true)}
/>
</h3>
)}
</div>
<div
className="row overflow-auto d-flex align-items-center flex-column"
onMouseEnter={() => setDescriptionHovered(true)}
onMouseLeave={() => setDescriptionHovered(false)}
style={{ maxHeight: 250 }}
>
{descriptionEditMode ? (
<textarea
className="form-control"
style={{ width: '95%' }}
onChange={(event) => setDescriptionTextAreaValue(event.target.value)}
onBlur={() => {
updateCardProperty(keyIndex, index, 'description', descriptionTextAreaValue);
setDescriptionEditMode(false);
}}
rows={10}
>
{descriptionTextAreaValue}
</textarea>
) : (
<p>
{['', undefined].includes(card.description) ? (
<a style={{ color: 'grey' }} onClick={() => setDescriptionEditMode(true)}>
Add description
</a>
) : (
card.description
)}
<img
src="/assets/images/icons/editor/edit.svg"
style={{
visibility: descriptionHovered ? 'visible' : 'hidden',
height: 15,
width: 15,
paddingLeft: 1,
}}
onClick={() => setDescriptionEditMode(true)}
/>
</p>
)}
</div>
</div>
</div>
)}
</div>
);
};