Files
Airframe-React/app/routes/Interface/DragAndDropElements/components/MultipleVerticalLists.js
2022-12-03 18:46:13 +01:00

267 lines
9.6 KiB
JavaScript
Executable File

import React from 'react';
import PropTypes from 'prop-types';
import _ from 'lodash';
import {
DragDropContext,
Droppable,
Draggable
} from 'react-beautiful-dnd';
import uid from 'uuid/v4';
import { faker } from '@faker-js/faker/locale/fr';
import classNames from 'classnames';
import {
Card,
CardHeader,
CardTitle,
Media,
Avatar,
AvatarAddOn
} from './../../../../components';
import { randomAvatar, randomArray } from './../../../../utilities';
import { reorder, move } from './utilities';
import classes from './common.scss';
// Utility Functions
//=========================================================
const generateItem = () => ({
id: uid(),
type: 'single',
name: `${faker.name.firstName()} ${faker.name.lastName()}`,
title: faker.name.jobType(),
avatarUrl: randomAvatar(),
status: randomArray(['success', 'warning', 'danger'])
});
const getListClass = (isDraggedOver) =>
classNames(classes['list'], {
[classes['list--drag-over']]: isDraggedOver
});
const getItemClass = (isDragging) =>
classNames(classes['list-group-item'], {
[classes['list-group-item--dragging']]: isDragging
});
// Draggable List Component
//=========================================================
const VerticalList = React.memo((props) => {
return (
<Droppable droppableId={ props.listId }>
{(provided, snapshot) => (
<div
ref={provided.innerRef}
className={`list-group list-group-flush flex-grow-1 ${getListClass(snapshot.isDraggingOver)}`}
>
{props.items.map((item, index) => (
<Draggable
key={item.id}
draggableId={item.id}
index={index}>
{(provided, draggableSnapshot) => (
<div
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
className={`list-group-item ${getItemClass(draggableSnapshot.isDragging)}`}
>
<Media>
<Media left className="align-self-center pr-3">
<i className="fa fa-ellipsis-v text-muted" />
</Media>
<Media left middle className="mr-4 align-self-center">
<Avatar.Image
size="md"
className="d-block"
src={ item.avatarUrl }
addOns={[
<AvatarAddOn.Icon
className="fa fa-circle"
color="white"
key="avatar-icon-bg"
/>,
<AvatarAddOn.Icon
className="fa fa-circle"
color={ item.status }
key="avatar-icon-fg"
/>
]}
/>
</Media>
<Media body>
<span className="mt-0 h6 mb-1">
{ item.name }
</span>
<p className="mb-0 text-muted text-truncate">
{ item.title }
</p>
</Media>
</Media>
</div>
)}
</Draggable>
))}
</div>
)}
</Droppable>
);
});
VerticalList.propTypes = {
items: PropTypes.array,
listId: PropTypes.string,
title: PropTypes.string
}
// Draggable Column Component
//=========================================================
class Column extends React.Component {
static propTypes = {
children: PropTypes.node,
id: PropTypes.string,
index: PropTypes.number,
title: PropTypes.string
}
render() {
const { children, id, index, title } = this.props;
return (
<Draggable
draggableId={id}
index={index}
>
{(provided) => (
<div
className="col-md-4"
ref={provided.innerRef}
{...provided.draggableProps}
>
<Card className="h-100">
<CardHeader {...provided.dragHandleProps} className="b-0 bg-none">
<CardTitle className="h6 mb-0">
<i className="fa fa-ellipsis-v mr-3 text-muted" />
{ title }
</CardTitle>
</CardHeader>
{ children }
</Card>
</div>
)}
</Draggable>
)
}
}
// Demo Component
//=========================================================
const initialState = {
listAItems: _.times(_.random(2, 4), generateItem),
listBItems: _.times(_.random(3, 8), generateItem),
listCItems: _.times(_.random(3, 8), generateItem),
lists: [
{ id: 'listA', title: 'All Candidates' },
{ id: 'listB', title: 'Candidates Interview' },
{ id: 'listC', title: 'Candidates Testing' }
]
};
export class MultipleVerticalLists extends React.Component {
static propTypes = {
className: PropTypes.string
}
state = _.clone(initialState);
constructor (props) {
super(props);
this.onDragEnd = this.onDragEnd.bind(this);
}
onDragEnd(result) {
const { source, destination } = result;
// Swap column positions
if (source.droppableId === 'board') {
if (destination.droppableId !== 'board') {
return;
}
const lists = reorder(
this.state.lists,
source.index,
destination.index
);
this.setState({ lists });
return;
}
// dropped outside the list
if (!destination) {
return;
}
// Handle List Items
if (source.droppableId === destination.droppableId) {
const items = reorder(
this.state[`${source.droppableId}Items`],
source.index,
destination.index
);
this.setState({
[`${source.droppableId}Items`]: items
});
} else {
const result = move(
this.state[`${source.droppableId}Items`],
this.state[`${destination.droppableId}Items`],
source,
destination
);
this.setState(_.mapKeys(result, (val, key) => `${key}Items`));
}
}
recoverInitialState() {
this.setState(initialState);
}
render() {
const { className } = this.props;
const { lists } = this.state;
return (
<div className={ className }>
<DragDropContext onDragEnd={this.onDragEnd}>
<Droppable
droppableId="board"
type="COLUMN"
direction="horizontal"
>
{(provided) => (
<div
className="row"
ref={provided.innerRef}
{...provided.droppableProps}
>
{_.map(lists, (list, index) => (
<Column
id={list.id}
index={ index }
title={list.title}
key={ list.id }
>
<VerticalList
listId={list.id}
items={this.state[`${list.id}Items`]}
/>
</Column>
))}
</div>
)}
</Droppable>
</DragDropContext>
</div>
)
}
}