- Clear stage prior to implementing replacement for collapsed lanes (with virtual lists)
Signed-off-by: Dave Richer <dave@imexsystems.ca>
This commit is contained in:
@@ -6,7 +6,6 @@ import { PageHeader } from "@ant-design/pro-layout";
|
||||
import React, { useEffect, useMemo, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { Sticky, StickyContainer } from "react-sticky";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import styled from "styled-components";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
@@ -64,7 +63,7 @@ export function ProductionBoardKanbanComponent({
|
||||
}, [associationSettings]);
|
||||
|
||||
useEffect(() => {
|
||||
const boardData = createBoardData(
|
||||
const boardData = createFakeBoardData(
|
||||
[...bodyshop.md_ro_statuses.production_statuses, ...(bodyshop.md_ro_statuses.additional_board_statuses || [])],
|
||||
data,
|
||||
filter
|
||||
@@ -114,89 +113,90 @@ export function ProductionBoardKanbanComponent({
|
||||
};
|
||||
|
||||
// TODO, refine and use action
|
||||
const onDragEnd = async ({ draggableId, type, source, reason, mode, destination, combine }) => {
|
||||
//cardId, sourceLaneId, targetLaneId, position, cardDetails
|
||||
logImEXEvent("kanban_drag_end");
|
||||
|
||||
// Early Gate
|
||||
if (!type || type !== "lane" || !source || !destination) return;
|
||||
|
||||
setIsMoving(true);
|
||||
|
||||
const sameColumnTransfer = source.droppableId === destination.droppableId;
|
||||
const targetLane = boardLanes.lanes[Number.parseInt(destination.droppableId)];
|
||||
const sourceLane = boardLanes.lanes[Number.parseInt(source.droppableId)];
|
||||
const sourceCard = getCardByID(boardLanes, draggableId);
|
||||
|
||||
const movedCardWillBeFirst = destination.index === 0;
|
||||
const movedCardWillBeLast = destination.index > targetLane.cards.length - 1;
|
||||
const movedCardIsFirstNewCard = movedCardWillBeFirst && movedCardWillBeLast;
|
||||
|
||||
const lastCardInTargetLane = targetLane.cards[targetLane.cards.length - 1];
|
||||
|
||||
const oldChildCard = sourceLane.cards[destination.index + 1];
|
||||
|
||||
const onDragEnd = async (...args) => {
|
||||
console.dir(args);
|
||||
// //cardId, sourceLaneId, targetLaneId, position, cardDetails
|
||||
// logImEXEvent("kanban_drag_end");
|
||||
//
|
||||
const newChildCard = movedCardWillBeLast
|
||||
? null
|
||||
: targetLane.cards[
|
||||
sameColumnTransfer
|
||||
? destination.index - destination.index > 0
|
||||
? destination.index
|
||||
: destination.index + 1
|
||||
: destination.index
|
||||
];
|
||||
|
||||
const oldChildCardNewParent = oldChildCard ? sourceCard.metadata.kanbanparent : null;
|
||||
|
||||
let movedCardNewKanbanParent;
|
||||
if (movedCardWillBeFirst) {
|
||||
movedCardNewKanbanParent = "-1";
|
||||
} else if (movedCardWillBeLast) {
|
||||
movedCardNewKanbanParent = lastCardInTargetLane.id;
|
||||
} else if (!!newChildCard) {
|
||||
movedCardNewKanbanParent = newChildCard.metadata.kanbanparent;
|
||||
} else {
|
||||
console.log("==> !!!!!!Couldn't find a parent.!!!! <==");
|
||||
}
|
||||
const newChildCardNewParent = newChildCard ? draggableId : null;
|
||||
try {
|
||||
const update = await client.mutate({
|
||||
mutation: generate_UPDATE_JOB_KANBAN(
|
||||
oldChildCard ? oldChildCard.id : null,
|
||||
oldChildCardNewParent,
|
||||
draggableId,
|
||||
movedCardNewKanbanParent,
|
||||
targetLane.id,
|
||||
newChildCard ? newChildCard.id : null,
|
||||
newChildCardNewParent
|
||||
)
|
||||
});
|
||||
|
||||
insertAuditTrail({
|
||||
jobid: draggableId,
|
||||
operation: AuditTrailMapping.jobstatuschange(targetLane.id),
|
||||
type: "jobstatuschange"
|
||||
});
|
||||
|
||||
if (update.errors) {
|
||||
notification["error"]({
|
||||
message: t("production.errors.boardupdate", {
|
||||
message: JSON.stringify(update.errors)
|
||||
})
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
notification["error"]({
|
||||
message: t("production.errors.boardupdate", {
|
||||
message: error.message
|
||||
})
|
||||
});
|
||||
} finally {
|
||||
setIsMoving(false);
|
||||
}
|
||||
// // Early Gate
|
||||
// if (!type || type !== "lane" || !source || !destination) return;
|
||||
//
|
||||
// setIsMoving(true);
|
||||
//
|
||||
// const sameColumnTransfer = source.droppableId === destination.droppableId;
|
||||
// const targetLane = boardLanes.lanes[Number.parseInt(destination.droppableId)];
|
||||
// const sourceLane = boardLanes.lanes[Number.parseInt(source.droppableId)];
|
||||
// const sourceCard = getCardByID(boardLanes, draggableId);
|
||||
//
|
||||
// const movedCardWillBeFirst = destination.index === 0;
|
||||
// const movedCardWillBeLast = destination.index > targetLane.cards.length - 1;
|
||||
// const movedCardIsFirstNewCard = movedCardWillBeFirst && movedCardWillBeLast;
|
||||
//
|
||||
// const lastCardInTargetLane = targetLane.cards[targetLane.cards.length - 1];
|
||||
//
|
||||
// const oldChildCard = sourceLane.cards[destination.index + 1];
|
||||
//
|
||||
// //
|
||||
// const newChildCard = movedCardWillBeLast
|
||||
// ? null
|
||||
// : targetLane.cards[
|
||||
// sameColumnTransfer
|
||||
// ? destination.index - destination.index > 0
|
||||
// ? destination.index
|
||||
// : destination.index + 1
|
||||
// : destination.index
|
||||
// ];
|
||||
//
|
||||
// const oldChildCardNewParent = oldChildCard ? sourceCard.metadata.kanbanparent : null;
|
||||
//
|
||||
// let movedCardNewKanbanParent;
|
||||
// if (movedCardWillBeFirst) {
|
||||
// movedCardNewKanbanParent = "-1";
|
||||
// } else if (movedCardWillBeLast) {
|
||||
// movedCardNewKanbanParent = lastCardInTargetLane.id;
|
||||
// } else if (!!newChildCard) {
|
||||
// movedCardNewKanbanParent = newChildCard.metadata.kanbanparent;
|
||||
// } else {
|
||||
// console.log("==> !!!!!!Couldn't find a parent.!!!! <==");
|
||||
// }
|
||||
// const newChildCardNewParent = newChildCard ? draggableId : null;
|
||||
// try {
|
||||
// const update = await client.mutate({
|
||||
// mutation: generate_UPDATE_JOB_KANBAN(
|
||||
// oldChildCard ? oldChildCard.id : null,
|
||||
// oldChildCardNewParent,
|
||||
// draggableId,
|
||||
// movedCardNewKanbanParent,
|
||||
// targetLane.id,
|
||||
// newChildCard ? newChildCard.id : null,
|
||||
// newChildCardNewParent
|
||||
// )
|
||||
// });
|
||||
//
|
||||
// insertAuditTrail({
|
||||
// jobid: draggableId,
|
||||
// operation: AuditTrailMapping.jobstatuschange(targetLane.id),
|
||||
// type: "jobstatuschange"
|
||||
// });
|
||||
//
|
||||
// if (update.errors) {
|
||||
// notification["error"]({
|
||||
// message: t("production.errors.boardupdate", {
|
||||
// message: JSON.stringify(update.errors)
|
||||
// })
|
||||
// });
|
||||
// }
|
||||
// } catch (error) {
|
||||
// notification["error"]({
|
||||
// message: t("production.errors.boardupdate", {
|
||||
// message: error.message
|
||||
// })
|
||||
// });
|
||||
// } finally {
|
||||
// setIsMoving(false);
|
||||
// }
|
||||
// };
|
||||
};
|
||||
|
||||
const totalHrs = useMemo(
|
||||
() =>
|
||||
data
|
||||
@@ -219,45 +219,7 @@ export function ProductionBoardKanbanComponent({
|
||||
[data]
|
||||
);
|
||||
|
||||
const selectedBreakpoint = Object.entries(Grid.useBreakpoint())
|
||||
.filter((screen) => !!screen[1])
|
||||
.slice(-1)[0];
|
||||
|
||||
const standardSizes = {
|
||||
xs: "250",
|
||||
sm: "250",
|
||||
md: "250",
|
||||
lg: "250",
|
||||
xl: "250",
|
||||
xxl: "250"
|
||||
};
|
||||
|
||||
const compactSizes = {
|
||||
xs: "150",
|
||||
sm: "150",
|
||||
md: "150",
|
||||
lg: "150",
|
||||
xl: "155",
|
||||
xxl: "155"
|
||||
};
|
||||
|
||||
const width = selectedBreakpoint
|
||||
? associationSettings && associationSettings.kanban_settings && associationSettings.kanban_settings.compact
|
||||
? compactSizes[selectedBreakpoint[0]]
|
||||
: standardSizes[selectedBreakpoint[0]]
|
||||
: "250";
|
||||
|
||||
const StickyHeader = ({ title }) => (
|
||||
<Sticky>
|
||||
{({ style }) => (
|
||||
<div className="react-trello-column-header" style={{ ...style, zIndex: "99", backgroundColor: "#e3e3e3" }}>
|
||||
<UnorderedListOutlined style={{ marginRight: "5px" }} /> {title}
|
||||
</div>
|
||||
)}
|
||||
</Sticky>
|
||||
);
|
||||
|
||||
const NormalHeader = ({ title }) => (
|
||||
const Header = ({ title }) => (
|
||||
<div className="react-trello-column-header" style={{ backgroundColor: "#e3e3e3" }}>
|
||||
<UnorderedListOutlined style={{ marginRight: "5px" }} /> {title}
|
||||
</div>
|
||||
@@ -285,7 +247,7 @@ export function ProductionBoardKanbanComponent({
|
||||
|
||||
const components = {
|
||||
Card: (cardProps) => ProductionBoardCard({ card: cardProps, technician, bodyshop, cardSettings }),
|
||||
LaneHeader: cardSettings.stickyheader && orientation === "horizontal" ? StickyHeader : NormalHeader
|
||||
LaneHeader: Header
|
||||
};
|
||||
|
||||
if (loading) {
|
||||
@@ -293,7 +255,7 @@ export function ProductionBoardKanbanComponent({
|
||||
}
|
||||
|
||||
return (
|
||||
<Container width={width}>
|
||||
<div>
|
||||
<IndefiniteLoading loading={isMoving} />
|
||||
<PageHeader
|
||||
title={
|
||||
@@ -316,41 +278,15 @@ export function ProductionBoardKanbanComponent({
|
||||
/>
|
||||
{cardSettings.cardcolor && <CardColorLegend cardSettings={cardSettings} bodyshop={bodyshop} />}
|
||||
<ProductionListDetailComponent jobs={data} />
|
||||
{cardSettings.stickyheader ? (
|
||||
<StickyContainer>
|
||||
<Board
|
||||
data={boardLanes}
|
||||
onDragEnd={onDragEnd}
|
||||
style={{ height: "100%", backgroundColor: "transparent", overflowY: "auto" }}
|
||||
components={components}
|
||||
orientation={orientation}
|
||||
collapsibleLanes
|
||||
/>
|
||||
</StickyContainer>
|
||||
) : (
|
||||
<div>
|
||||
<Board
|
||||
data={boardLanes}
|
||||
onDragEnd={onDragEnd}
|
||||
style={{ backgroundColor: "transparent", overflowY: "auto" }}
|
||||
components={components}
|
||||
collapsibleLanes
|
||||
orientation={orientation}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</Container>
|
||||
<Board
|
||||
data={boardLanes}
|
||||
onDragEnd={onDragEnd}
|
||||
components={components}
|
||||
collapsibleLanes
|
||||
orientation={orientation}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(ProductionBoardKanbanComponent);
|
||||
|
||||
const Container = styled.div`
|
||||
.react-trello-card-skeleton,
|
||||
.react-trello-card,
|
||||
.react-trello-card-adder-form {
|
||||
box-sizing: border-box;
|
||||
max-width: ${(props) => props.width}px;
|
||||
min-width: ${(props) => props.width}px;
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.react-trello-card {
|
||||
border-radius: 3px;
|
||||
background-color: #fff;
|
||||
padding: 4px;
|
||||
margin-bottom: 7px;
|
||||
}
|
||||
//.react-trello-card {
|
||||
// border-radius: 3px;
|
||||
// background-color: #fff;
|
||||
// padding: 4px;
|
||||
// margin-bottom: 7px;
|
||||
//}
|
||||
|
||||
// .react-trello-card-skeleton,
|
||||
// .react-trello-card,
|
||||
@@ -33,12 +33,12 @@
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.react-trello-column {
|
||||
padding: 10px;
|
||||
border-radius: 2px;
|
||||
background-color: #eee;
|
||||
margin: 5px;
|
||||
}
|
||||
//.react-trello-column {
|
||||
// padding: 10px;
|
||||
// border-radius: 2px;
|
||||
// background-color: #eee;
|
||||
// margin: 5px;
|
||||
//}
|
||||
|
||||
.react-trello-column input:focus {
|
||||
outline: none;
|
||||
@@ -84,6 +84,10 @@
|
||||
width: 100%;
|
||||
padding: 0px;
|
||||
}
|
||||
.height-preserving-container:empty {
|
||||
min-height: calc(var(--child-height));
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.react-trello-card-adder-form__title:focus {
|
||||
outline: none;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
import React, { forwardRef, useCallback, useEffect, useRef, useState } from "react";
|
||||
import classNames from "classnames";
|
||||
import PropTypes from "prop-types";
|
||||
import { bindActionCreators } from "redux";
|
||||
@@ -7,55 +7,32 @@ import isEqual from "lodash/isEqual";
|
||||
import { v1 } from "uuid";
|
||||
|
||||
import * as actions from "../../../redux/trello/trello.actions.js";
|
||||
import { Droppable, Draggable } from "../dnd/lib/index.js";
|
||||
import { Draggable, Droppable } from "../dnd/lib";
|
||||
import { Virtuoso, VirtuosoGrid } from "react-virtuoso";
|
||||
|
||||
function HeightPreservingItem({ children, ...props }) {
|
||||
const [size, setSize] = useState(0);
|
||||
const { "data-known-size": knownSize = 0 } = props;
|
||||
|
||||
useEffect(() => {
|
||||
if (knownSize !== 0) {
|
||||
setSize(knownSize);
|
||||
}
|
||||
}, [knownSize]);
|
||||
|
||||
return (
|
||||
<div
|
||||
{...props}
|
||||
className="height-preserving-container"
|
||||
style={{
|
||||
"--child-height": `${size}px`
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lane is a React component that represents a lane in a Trello-like board.
|
||||
* It uses Redux for state management and provides a variety of props to customize its behavior.
|
||||
*
|
||||
* @component
|
||||
* @param {Object} props - Component props
|
||||
* @param {Object} props.actions - Redux actions
|
||||
* @param {string} props.id - The unique identifier for the lane
|
||||
* @param {string} props.boardId - The unique identifier for the board
|
||||
* @param {string} props.title - The title of the lane
|
||||
* @param {number} props.index - The index of the lane
|
||||
* @param {Function} props.laneSortFunction - Function to sort the cards in the lane
|
||||
* @param {Object} props.style - The CSS styles to apply to the lane
|
||||
* @param {Object} props.cardStyle - The CSS styles to apply to the cards
|
||||
* @param {Object} props.tagStyle - The CSS styles to apply to the tags
|
||||
* @param {Object} props.titleStyle - The CSS styles to apply to the title
|
||||
* @param {Object} props.labelStyle - The CSS styles to apply to the label
|
||||
* @param {Array} props.cards - The cards in the lane
|
||||
* @param {string} props.label - The label of the lane
|
||||
* @param {boolean} props.draggable - Whether the lane is draggable
|
||||
* @param {boolean} props.collapsibleLanes - Whether the lanes are collapsible
|
||||
* @param {boolean} props.droppable - Whether the lane is droppable
|
||||
* @param {Function} props.onCardClick - Callback function when a card is clicked
|
||||
* @param {Function} props.onBeforeCardDelete - Callback function before a card is deleted
|
||||
* @param {Function} props.onCardDelete - Callback function when a card is deleted
|
||||
* @param {Function} props.onCardAdd - Callback function when a card is added
|
||||
* @param {Function} props.onCardUpdate - Callback function when a card is updated
|
||||
* @param {Function} props.onLaneDelete - Callback function when a lane is deleted
|
||||
* @param {Function} props.onLaneUpdate - Callback function when a lane is updated
|
||||
* @param {Function} props.onLaneClick - Callback function when a lane is clicked
|
||||
* @param {Function} props.onLaneScroll - Callback function when a lane is scrolled
|
||||
* @param {boolean} props.editable - Whether the lane is editable
|
||||
* @param {boolean} props.cardDraggable - Whether the cards are draggable
|
||||
* @param {string} props.cardDragClass - The CSS class to apply when a card is being dragged
|
||||
* @param {string} props.cardDropClass - The CSS class to apply when a card is dropped
|
||||
* @param {boolean} props.canAddLanes - Whether lanes can be added to the board
|
||||
* @param {boolean} props.hideCardDeleteIcon - Whether to hide the card delete icon
|
||||
* @param {Object} props.components - Custom components to use in the lane
|
||||
* @param {Function} props.getCardDetails - Function to get the details of a card
|
||||
* @param {Function} props.handleDragStart - Callback function when a drag starts
|
||||
* @param {Function} props.handleDragEnd - Callback function when a drag ends
|
||||
* @param {string} props.orientation - The orientation of the lane ("horizontal" or "vertical")
|
||||
* @param {string} props.className - The CSS class to apply to the lane
|
||||
* @param {number} props.currentPage - The current page of the lane
|
||||
* @param {Object} props.otherProps - Any other props to pass to the lane
|
||||
* @returns {JSX.Element} A lane in a Trello-like board
|
||||
*/
|
||||
function Lane({
|
||||
actions,
|
||||
id,
|
||||
@@ -101,20 +78,9 @@ function Lane({
|
||||
const [currentPageFinal, setCurrentPageFinal] = useState(currentPage);
|
||||
const [addCardMode, setAddCardMode] = useState(false);
|
||||
const [collapsed, setCollapsed] = useState(false);
|
||||
// const [isDraggingOver, setIsDraggingOver] = useState(false);
|
||||
|
||||
const laneRef = useRef(null);
|
||||
|
||||
const flexStyle = useMemo(() => {
|
||||
return orientation === "vertical"
|
||||
? {
|
||||
display: "flex",
|
||||
flexWrap: "wrap",
|
||||
minHeight: "10px"
|
||||
}
|
||||
: {};
|
||||
}, [orientation]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isEqual(cards, currentPageFinal)) {
|
||||
setCurrentPageFinal(currentPage);
|
||||
@@ -222,17 +188,19 @@ function Lane({
|
||||
collapsibleLanes && setCollapsed(!collapsed);
|
||||
};
|
||||
|
||||
// const groupName = `TrelloBoard${boardId}Lane`;
|
||||
|
||||
const renderDragContainer = (isDraggingOver) => {
|
||||
const stableCards = collapsed ? [] : cards;
|
||||
|
||||
const cardList = sortCards(stableCards, laneSortFunction).map((card, idx) => {
|
||||
const onDeleteCard = () => removeCard(card.id);
|
||||
const cardToRender = (
|
||||
const Card = React.memo(({ provided, item: card, isDragging }) => {
|
||||
const onDeleteCard = () => removeCard(card.id);
|
||||
return (
|
||||
<div
|
||||
{...provided.draggableProps}
|
||||
{...provided.dragHandleProps}
|
||||
ref={provided.innerRef}
|
||||
style={provided.draggableProps.style}
|
||||
className={`item ${isDragging ? "is-dragging" : ""}`}
|
||||
key={card.id}
|
||||
>
|
||||
<components.Card
|
||||
key={card.id}
|
||||
index={idx}
|
||||
style={card.style || cardStyle}
|
||||
className="react-trello-card"
|
||||
onDelete={onDeleteCard}
|
||||
@@ -244,48 +212,122 @@ function Lane({
|
||||
editable={editable}
|
||||
{...card}
|
||||
/>
|
||||
);
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
return cardDraggable && (!card.hasOwnProperty("draggable") || card.draggable) ? (
|
||||
<Draggable key={card.id} draggableId={card.id} index={card.idx}>
|
||||
{(provided, snapshot) => {
|
||||
return (
|
||||
<div
|
||||
ref={provided.innerRef}
|
||||
{...provided.draggableProps}
|
||||
{...provided.dragHandleProps}
|
||||
style={{
|
||||
...provided.draggableProps.style
|
||||
}}
|
||||
>
|
||||
{cardToRender}
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
</Draggable>
|
||||
) : (
|
||||
<span key={card.id}>{cardToRender}</span>
|
||||
);
|
||||
});
|
||||
const renderDraggable = (index, item) => (
|
||||
<Draggable draggableId={item.id} index={index} key={item.id}>
|
||||
{(provided, snapshot) => <Card provided={provided} item={item} isDragging={snapshot.isDragging} />}
|
||||
</Draggable>
|
||||
);
|
||||
|
||||
const renderAddCardLink = () =>
|
||||
editable && !addCardMode && <components.AddCardLink onClick={showEditableCard} laneId={id} />;
|
||||
|
||||
const renderNewCardForm = () =>
|
||||
addCardMode && <components.NewCardForm onCancel={hideEditableCard} laneId={id} onAdd={addNewCard} />;
|
||||
|
||||
const ItemWrapper = ({ children, ...props }) => (
|
||||
<div
|
||||
{...props}
|
||||
style={{
|
||||
display: "flex",
|
||||
flex: 1,
|
||||
whiteSpace: "nowrap"
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
|
||||
const gridComponents = {
|
||||
List: forwardRef(({ style, children, ...props }, ref) => (
|
||||
<div
|
||||
ref={ref}
|
||||
{...props}
|
||||
style={{
|
||||
display: "flex",
|
||||
flexWrap: "wrap",
|
||||
...style
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
)),
|
||||
Item: ({ children, ...props }) => (
|
||||
<div
|
||||
{...props}
|
||||
style={{
|
||||
width: "10%",
|
||||
display: "flex",
|
||||
alignContent: "stretch",
|
||||
boxSizing: "border-box"
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
};
|
||||
|
||||
const renderDroppable = (provided, renderedCards) => {
|
||||
const Component = orientation === "vertical" ? VirtuosoGrid : Virtuoso;
|
||||
|
||||
const commonProps = {
|
||||
useWindowScroll: true,
|
||||
data: renderedCards
|
||||
};
|
||||
|
||||
const componentProps =
|
||||
orientation === "vertical"
|
||||
? {
|
||||
...commonProps,
|
||||
scrollerRef: provided.innerRef,
|
||||
listClassName: "grid-container",
|
||||
itemClassName: "grid-item",
|
||||
components: gridComponents,
|
||||
itemContent: (index, item) => <ItemWrapper>{renderDraggable(index, item)}</ItemWrapper>
|
||||
}
|
||||
: {
|
||||
...commonProps,
|
||||
overscan: {
|
||||
main: 22,
|
||||
reverse: 22
|
||||
},
|
||||
components: { Item: HeightPreservingItem },
|
||||
itemContent: (index, item) => renderDraggable(index, item),
|
||||
scrollerRef: provided.innerRef
|
||||
};
|
||||
|
||||
return (
|
||||
<Droppable direction={orientation === "horizontal" ? "vertical" : "grid"} droppableId={`${index}`} type="lane">
|
||||
{(provided, snapshot) => (
|
||||
<div
|
||||
{...provided.droppableProps}
|
||||
ref={provided.innerRef}
|
||||
className={allClassNames}
|
||||
style={{
|
||||
...provided.droppableProps.style,
|
||||
...flexStyle
|
||||
}}
|
||||
>
|
||||
{cardList}
|
||||
{editable && !addCardMode && <components.AddCardLink onClick={showEditableCard} laneId={id} />}
|
||||
{addCardMode && <components.NewCardForm onCancel={hideEditableCard} laneId={id} onAdd={addNewCard} />}
|
||||
{provided.placeholder}
|
||||
</div>
|
||||
<div
|
||||
{...provided.droppableProps}
|
||||
ref={provided.innerRef}
|
||||
className={allClassNames}
|
||||
style={{ ...provided.droppableProps.style }}
|
||||
>
|
||||
<Component {...componentProps} />
|
||||
{renderAddCardLink()}
|
||||
{renderNewCardForm()}
|
||||
{provided.placeholder}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const renderDragContainer = () => {
|
||||
if (collapsed) return <></>;
|
||||
const renderedCards = sortCards(cards, laneSortFunction);
|
||||
return (
|
||||
<Droppable
|
||||
droppableId={id}
|
||||
type="lane"
|
||||
direction={orientation === "horizontal" ? "vertical" : "grid"}
|
||||
mode="virtual"
|
||||
renderClone={(provided, snapshot, rubric) => (
|
||||
<Card provided={provided} isDragging={snapshot.isDragging} item={renderedCards[rubric.source.index]} />
|
||||
)}
|
||||
>
|
||||
{(provided) => renderDroppable(provided, renderedCards)}
|
||||
</Droppable>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -89,42 +89,47 @@ const LaneHelper = {
|
||||
},
|
||||
|
||||
// TODO: This has been updated to new DND Lib, verified.
|
||||
moveCardAcrossLanes: (state, { fromLaneId, toLaneId, cardId, index }) => {
|
||||
// Clone the state to avoid mutation
|
||||
const newLanes = cloneDeep(state.lanes);
|
||||
|
||||
// Find the source and destination lanes using the lane indices
|
||||
const fromLane = newLanes[fromLaneId];
|
||||
const toLane = newLanes[toLaneId];
|
||||
|
||||
// Find the card in the source lane
|
||||
const cardIndex = fromLane.cards.findIndex((card) => card.id === cardId);
|
||||
if (cardIndex === -1) {
|
||||
throw new Error("Card not found in the source lane");
|
||||
}
|
||||
|
||||
// Remove the card from the source lane
|
||||
const [card] = fromLane.cards.splice(cardIndex, 1);
|
||||
|
||||
// Insert the card into the destination lane at the specified index
|
||||
toLane.cards.splice(index, 0, card);
|
||||
|
||||
let idx = 0;
|
||||
|
||||
// Update the lane and card indexes for all lanes
|
||||
newLanes.forEach((lane, laneIndex) => {
|
||||
lane.cards.forEach((card, cardIndex) => {
|
||||
card.idx = idx;
|
||||
card.laneIndex = laneIndex;
|
||||
card.cardIndex = cardIndex;
|
||||
card.laneId = lane.id;
|
||||
idx++;
|
||||
});
|
||||
});
|
||||
|
||||
return update(state, {
|
||||
lanes: { $set: newLanes }
|
||||
});
|
||||
moveCardAcrossLanes: (state, ...args) => {
|
||||
return state;
|
||||
// console.dir({
|
||||
// state,
|
||||
// args: { fromLaneId, toLaneId, cardId, index }
|
||||
// });
|
||||
// // Clone the state to avoid mutation
|
||||
// const newLanes = cloneDeep(state.lanes);
|
||||
//
|
||||
// // Find the source and destination lanes using the lane indices
|
||||
// const fromLane = newLanes[fromLaneId];
|
||||
// const toLane = newLanes[toLaneId];
|
||||
//
|
||||
// // Find the card in the source lane
|
||||
// const cardIndex = fromLane.cards.findIndex((card) => card.id === cardId);
|
||||
// if (cardIndex === -1) {
|
||||
// throw new Error("Card not found in the source lane");
|
||||
// }
|
||||
//
|
||||
// // Remove the card from the source lane
|
||||
// const [card] = fromLane.cards.splice(cardIndex, 1);
|
||||
//
|
||||
// // Insert the card into the destination lane at the specified index
|
||||
// toLane.cards.splice(index, 0, card);
|
||||
//
|
||||
// let idx = 0;
|
||||
//
|
||||
// // Update the lane and card indexes for all lanes
|
||||
// newLanes.forEach((lane, laneIndex) => {
|
||||
// lane.cards.forEach((card, cardIndex) => {
|
||||
// card.idx = idx;
|
||||
// card.laneIndex = laneIndex;
|
||||
// card.cardIndex = cardIndex;
|
||||
// card.laneId = lane.id;
|
||||
// idx++;
|
||||
// });
|
||||
// });
|
||||
//
|
||||
// return update(state, {
|
||||
// lanes: { $set: newLanes }
|
||||
// });
|
||||
},
|
||||
|
||||
updateCardsForLane: (state, { laneId, cards }) => {
|
||||
|
||||
@@ -9,10 +9,7 @@ const getBoardWrapperStyles = (props) => {
|
||||
// TODO: The white-space: nowrap; would be a good place to offer further customization
|
||||
// This will be put in the lane settings and marked as 'Horizontal Wrapping'
|
||||
return `
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
overflow-x: auto;
|
||||
white-space: nowrap;
|
||||
white-space: nowrap;
|
||||
`;
|
||||
}
|
||||
return "";
|
||||
@@ -22,14 +19,13 @@ const getSectionStyles = (props) => {
|
||||
if (props.orientation === "horizontal") {
|
||||
return `
|
||||
display: inline-flex;
|
||||
position: relative;
|
||||
flex-direction: column;
|
||||
white-space: nowrap;
|
||||
overflow-y: none;
|
||||
`;
|
||||
}
|
||||
return `
|
||||
margin-bottom: 10px;
|
||||
position: relative;
|
||||
flex-direction: column;
|
||||
`;
|
||||
};
|
||||
|
||||
@@ -80,6 +76,7 @@ export const StyleHorizontal = styled.div`
|
||||
// TODO: This will need to be changed
|
||||
min-width: 250px;
|
||||
min-height: 25px;
|
||||
margin-bottom: 42px;
|
||||
}
|
||||
|
||||
.react-trello-lane.lane-collapsed {
|
||||
@@ -99,6 +96,12 @@ export const StyleVertical = styled.div`
|
||||
.react-trello-board {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.grid-container {
|
||||
}
|
||||
|
||||
.grid-item {
|
||||
}
|
||||
`;
|
||||
|
||||
export const CustomPopoverContainer = styled(PopoverContainer)`
|
||||
@@ -148,10 +151,9 @@ export const CustomPopoverContent = styled(PopoverContent)`
|
||||
`;
|
||||
|
||||
export const BoardWrapper = styled.div`
|
||||
background-color: #ffffff;
|
||||
overflow-y: scroll;
|
||||
padding: 5px;
|
||||
color: #393939;
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
${getBoardWrapperStyles};
|
||||
`;
|
||||
|
||||
@@ -166,7 +168,7 @@ export const Section = styled.section`
|
||||
background-color: #e3e3e3;
|
||||
border-radius: 3px;
|
||||
margin: 2px 2px;
|
||||
padding: 5px;
|
||||
padding: 2px;
|
||||
${getSectionStyles};
|
||||
`;
|
||||
|
||||
@@ -195,7 +197,6 @@ export const LaneFooter = styled.div`
|
||||
|
||||
export const ScrollableLane = styled.div`
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
min-width: 250px;
|
||||
overflow-x: hidden;
|
||||
align-self: center;
|
||||
|
||||
Reference in New Issue
Block a user