From c6118dd447b2d659c2f057e688336b5bdfa16e3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Espino?= Date: Thu, 15 Oct 2020 00:47:10 +0200 Subject: [PATCH] Removing the need of the global showCard --- src/client/components/boardComponent.tsx | 23 ++++---- src/client/components/cardDialog.tsx | 60 +++++++++++++------- src/client/components/tableComponent.tsx | 19 +++---- src/client/components/tableRow.tsx | 15 ++++- src/client/components/workspaceComponent.tsx | 7 +-- src/client/octoTypes.ts | 1 - src/client/pages/boardPage.tsx | 36 ------------ 7 files changed, 77 insertions(+), 84 deletions(-) diff --git a/src/client/components/boardComponent.tsx b/src/client/components/boardComponent.tsx index 3e59cc252..3e29edc31 100644 --- a/src/client/components/boardComponent.tsx +++ b/src/client/components/boardComponent.tsx @@ -15,12 +15,13 @@ import { BoardCard } from "./boardCard" import { BoardColumn } from "./boardColumn" import Button from "./button" import { Editable } from "./editable" +import { CardDialog } from "./cardDialog" +import RootPortal from "./rootPortal" type Props = { mutator: Mutator, boardTree?: BoardTree showView: (id: string) => void - showCard: (card: IBlock) => void showFilter: (el: HTMLElement) => void setSearchText: (text: string) => void } @@ -28,6 +29,7 @@ type Props = { type State = { isHoverOnCover: boolean isSearching: boolean + shownCard: IBlock | null } class BoardComponent extends React.Component { @@ -37,7 +39,7 @@ class BoardComponent extends React.Component { constructor(props: Props) { super(props) - this.state = { isHoverOnCover: false, isSearching: !!this.props.boardTree?.getSearchText() } + this.state = { isHoverOnCover: false, isSearching: !!this.props.boardTree?.getSearchText(), shownCard: null } } componentDidUpdate(prevPros: Props, prevState: State) { @@ -66,6 +68,11 @@ class BoardComponent extends React.Component { return (
+ {this.state.shownCard && + + this.setState({shownCard: null})}/> + } +
{ card={card} visiblePropertyTemplates={visiblePropertyTemplates} key={card.id} - onClick={() => { this.showCard(card) }} + onClick={() => { this.setState({shownCard: card}) }} onDragStart={() => { this.draggedCard = card }} onDragEnd={() => { this.draggedCard = undefined }} /> )} @@ -187,7 +194,7 @@ class BoardComponent extends React.Component { card={card} visiblePropertyTemplates={visiblePropertyTemplates} key={card.id} - onClick={() => { this.showCard(card) }} + onClick={() => { this.setState({shownCard: card}) }} onDragStart={() => { this.draggedCard = card }} onDragEnd={() => { this.draggedCard = undefined }} /> )} @@ -223,12 +230,6 @@ class BoardComponent extends React.Component { Menu.shared.showAtElement(e.target as HTMLElement) } - async showCard(card?: IBlock) { - console.log(`showCard: ${card?.title}`) - - await this.props.showCard(card) - } - async addCard(groupByValue?: string) { const { mutator, boardTree } = this.props const { activeView, board } = boardTree @@ -238,7 +239,7 @@ class BoardComponent extends React.Component { if (boardTree.groupByProperty) { card.properties[boardTree.groupByProperty.id] = groupByValue } - await mutator.insertBlock(card, "add card", async () => { await this.showCard(card) }, async () => { await this.showCard(undefined) }) + await mutator.insertBlock(card, "add card", async () => { await this.setState({shownCard: card}) }, async () => { await this.setState({shownCard: null}) }) } async propertyNameChanged(option: IPropertyOption, text: string) { diff --git a/src/client/components/cardDialog.tsx b/src/client/components/cardDialog.tsx index 2a47ac310..56892ea3f 100644 --- a/src/client/components/cardDialog.tsx +++ b/src/client/components/cardDialog.tsx @@ -8,6 +8,8 @@ import { Mutator } from "../mutator" import { IBlock } from "../octoTypes" import { OctoUtils } from "../octoUtils" import { PropertyMenu } from "../propertyMenu" +import { OctoListener } from "../octoListener" +import { OctoClient } from "../octoClient" import { Utils } from "../utils" import Button from "./button" import { Editable } from "./editable" @@ -15,45 +17,67 @@ import { MarkdownEditor } from "./markdownEditor" type Props = { boardTree: BoardTree - cardTree: CardTree + card: IBlock mutator: Mutator onClose: () => void } type State = { isHoverOnCover: boolean + cardTree: CardTree | null } class CardDialog extends React.Component { private titleRef = React.createRef() - private keydownHandler: any + private cardListener: OctoListener constructor(props: Props) { super(props) - this.state = { isHoverOnCover: false } + this.state = { isHoverOnCover: false, cardTree: null } + } + + keydownHandler = (e: KeyboardEvent) => { + if (e.target !== document.body) { return } + + if (e.keyCode === 27) { + this.close() + e.stopPropagation() + } } componentDidMount() { - this.titleRef.current.focus() - this.keydownHandler = (e: KeyboardEvent) => { - if (e.target !== document.body) { return } + this.cardListener = new OctoListener() + this.cardListener.open(this.props.card.id, async () => { + await cardTree.sync() + this.setState({cardTree: cardTree}) + }) + const cardTree = new CardTree(new OctoClient(), this.props.card.id) + cardTree.sync().then(() => { + this.setState({cardTree}) + }); - if (e.keyCode === 27) { - this.close() - e.stopPropagation() - } - } document.addEventListener("keydown", this.keydownHandler) } + componentDidUpdate(prevProps: Props, prevState: State) { + if (this.titleRef.current && prevState.cardTree === null && this.state.cardTree !== null) { + this.titleRef.current.focus() + } + } + componentWillUnmount() { document.removeEventListener("keydown", this.keydownHandler) } render() { - const { boardTree, cardTree, mutator } = this.props + const { boardTree, mutator, card } = this.props + const { cardTree } = this.state const { board } = boardTree - const { card, comments } = cardTree + if (cardTree === null) { + return null + } + + const { comments } = cardTree const newCommentPlaceholderText = "Add a comment..." @@ -332,8 +356,7 @@ class CardDialog extends React.Component { } async sendComment(text: string) { - const { mutator, cardTree } = this.props - const { card } = cardTree + const { mutator, card } = this.props Utils.assertValue(card) @@ -342,8 +365,8 @@ class CardDialog extends React.Component { } private showContentBlockMenu(e: React.MouseEvent, block: IBlock) { - const { mutator, cardTree } = this.props - const { card } = cardTree + const { mutator, card } = this.props + const { cardTree } = this.state const index = cardTree.contents.indexOf(block) const options: MenuOption[] = [] @@ -409,8 +432,7 @@ class CardDialog extends React.Component { } private iconClicked(e: React.MouseEvent) { - const { mutator, cardTree } = this.props - const { card } = cardTree + const { mutator, card } = this.props Menu.shared.options = [ { id: "random", name: "Random" }, diff --git a/src/client/components/tableComponent.tsx b/src/client/components/tableComponent.tsx index 988fd133b..97b83ced2 100644 --- a/src/client/components/tableComponent.tsx +++ b/src/client/components/tableComponent.tsx @@ -13,12 +13,13 @@ import { Utils } from "../utils" import Button from "./button" import { Editable } from "./editable" import { TableRow } from "./tableRow" +import { CardDialog } from "./cardDialog" +import RootPortal from "./rootPortal" type Props = { mutator: Mutator, boardTree?: BoardTree showView: (id: string) => void - showCard: (card: IBlock) => void showFilter: (el: HTMLElement) => void setSearchText: (text: string) => void } @@ -26,6 +27,7 @@ type Props = { type State = { isHoverOnCover: boolean isSearching: boolean + shownCard: IBlock | null } class TableComponent extends React.Component { @@ -36,7 +38,7 @@ class TableComponent extends React.Component { constructor(props: Props) { super(props) - this.state = { isHoverOnCover: false, isSearching: !!this.props.boardTree?.getSearchText() } + this.state = { isHoverOnCover: false, isSearching: !!this.props.boardTree?.getSearchText(), shownCard: null } } componentDidUpdate(prevPros: Props, prevState: State) { @@ -63,6 +65,10 @@ class TableComponent extends React.Component { return (
+ {this.state.shownCard && + + this.setState({shownCard: null})}/> + }
{ boardTree={boardTree} card={card} focusOnMount={focusOnMount} - showCard={(c) => { this.showCard(c) }} onKeyDown={(e) => { if (e.keyCode === 13) { // Enter: Insert new card if on last row @@ -347,12 +352,6 @@ class TableComponent extends React.Component { Menu.shared.showAtElement(e.target as HTMLElement) } - async showCard(card: IBlock) { - console.log(`showCard: ${card.title}`) - - await this.props.showCard(card) - } - focusOnCardTitle(cardId: string) { const tableRowRef = this.cardIdToRowMap.get(cardId) Utils.log(`focusOnCardTitle, ${tableRowRef?.current ?? "undefined"}`) @@ -368,7 +367,7 @@ class TableComponent extends React.Component { "add card", async () => { if (show) { - this.showCard(card) + this.setState({shownCard: card}) } else { // Focus on this card's title inline on next render this.cardIdToFocusOnRender = card.id diff --git a/src/client/components/tableRow.tsx b/src/client/components/tableRow.tsx index fc6d6d7d2..97a6058cc 100644 --- a/src/client/components/tableRow.tsx +++ b/src/client/components/tableRow.tsx @@ -4,21 +4,26 @@ import { Mutator } from "../mutator" import { IBlock } from "../octoTypes" import { OctoUtils } from "../octoUtils" import { Editable } from "./editable" +import { CardDialog } from "./cardDialog" +import RootPortal from "./rootPortal" type Props = { mutator: Mutator boardTree: BoardTree card: IBlock focusOnMount: boolean - showCard: (card: IBlock) => void onKeyDown: (e: React.KeyboardEvent) => void } type State = { + showCard: boolean } class TableRow extends React.Component { private titleRef = React.createRef() + state = { + showCard: false + } componentDidMount() { if (this.props.focusOnMount) { @@ -27,7 +32,7 @@ class TableRow extends React.Component { } render() { - const { mutator, boardTree, card, showCard, onKeyDown } = this.props + const { mutator, boardTree, card, onKeyDown } = this.props const { board, activeView } = boardTree const openButonRef = React.createRef() @@ -48,7 +53,11 @@ class TableRow extends React.Component { />
-
{ showCard(card) }}>Open
+
{ this.setState({showCard: true}) }}>Open
+ {this.state.showCard && + + this.setState({showCard: false})}/> + }
{/* Columns, one per property */} diff --git a/src/client/components/workspaceComponent.tsx b/src/client/components/workspaceComponent.tsx index eed77b353..875a8883e 100644 --- a/src/client/components/workspaceComponent.tsx +++ b/src/client/components/workspaceComponent.tsx @@ -14,7 +14,6 @@ type Props = { boardTree?: BoardTree showBoard: (id: string) => void showView: (id: string) => void - showCard: (card: IBlock) => void showFilter: (el: HTMLElement) => void setSearchText: (text: string) => void } @@ -34,7 +33,7 @@ class WorkspaceComponent extends React.Component { } private mainComponent() { - const { mutator, boardTree, showCard, showFilter, setSearchText, showView } = this.props + const { mutator, boardTree, showFilter, setSearchText, showView } = this.props const { activeView } = boardTree || {} if (!activeView) { @@ -43,11 +42,11 @@ class WorkspaceComponent extends React.Component { switch (activeView?.viewType) { case "board": { - return + return } case "table": { - return + return } default: { diff --git a/src/client/octoTypes.ts b/src/client/octoTypes.ts index d02c379e5..ed72ddea3 100644 --- a/src/client/octoTypes.ts +++ b/src/client/octoTypes.ts @@ -17,7 +17,6 @@ interface IBlock { // These are methods exposed by the top-level page to components interface IPageController { - showCard(card: IBlock): Promise showBoard(boardId: string): void showView(viewId: string): void showFilter(anchorElement?: HTMLElement): void diff --git a/src/client/pages/boardPage.tsx b/src/client/pages/boardPage.tsx index ad4ee5f03..05add66cd 100644 --- a/src/client/pages/boardPage.tsx +++ b/src/client/pages/boardPage.tsx @@ -110,22 +110,6 @@ export default class BoardPage extends React.Component { const { board, activeView } = this.state.boardTree || {} const mutator = new Mutator(this.octo) - // TODO Move all this into the root portal component when that is merged - if (this.state.boardTree && this.state.boardTree.board && shownCardTree) { - ReactDOM.render( - { this.showCard(undefined) }}>, - Utils.getElementById("overlay") - ) - } else { - const overlay = document.getElementById("overlay") - if (overlay) { - ReactDOM.render( -
, - overlay - ) - } - } - if (this.filterAnchorElement) { const element = this.filterAnchorElement const bodyRect = document.body.getBoundingClientRect() @@ -161,7 +145,6 @@ export default class BoardPage extends React.Component { workspaceTree={workspaceTree} boardTree={this.state.boardTree} showView={(id) => { this.showView(id) }} - showCard={(card) => { this.showCard(card) }} showBoard={(id) => { this.showBoard(id) }} showFilter={(el) => { this.showFilter(el) }} setSearchText={(text) => { this.setSearchText(text) }} /> @@ -209,25 +192,6 @@ export default class BoardPage extends React.Component { } // IPageController - - async showCard(card: IBlock) { - this.cardListener.close() - - if (card) { - const cardTree = new CardTree(this.octo, card.id) - await cardTree.sync() - this.setState({...this.state, shownCardTree: cardTree}) - - this.cardListener = new OctoListener() - this.cardListener.open(card.id, async () => { - await cardTree.sync() - this.forceUpdate() - }) - } else { - this.setState({...this.state, shownCardTree: undefined}) - } - } - showBoard(boardId: string) { const { boardTree } = this.state