Skip to content

Commit

Permalink
feat(kanban): add new item functionality to the first column
Browse files Browse the repository at this point in the history
- Added showNewOnFirstColumn and newItemLabel props to Kanban component.
- Updated Kanban styles to support new item addition.
- Modified Column component to display a new item button when the first column is empty.
- Updated mock data to include additional tasks.
Ticket: task/Dashboards-135
Reviewed-by: @MIGUELez11
Refs: #176
  • Loading branch information
johan-fx authored Jun 29, 2024
1 parent 65574d0 commit 363c370
Show file tree
Hide file tree
Showing 5 changed files with 201 additions and 68 deletions.
18 changes: 17 additions & 1 deletion packages/components/src/informative/Kanban/Kanban.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import reorder, { reorderQuoteMap } from './helpers/reorder';

export const KANBAN_DEFAULT_PROPS = {
itemRender: ({ value }) => <>{value.title}</>,
showNewOnFirstColumn: true,
newItemLabel: 'Add new item',
};
export const KANBAN_PROP_TYPES = {
value: PropTypes.shape({
Expand All @@ -22,11 +24,22 @@ export const KANBAN_PROP_TYPES = {
}),
isCombineEnabled: PropTypes.bool,
onChange: PropTypes.func,
onNew: PropTypes.func,
icon: PropTypes.node,
itemRender: PropTypes.oneOfType([PropTypes.node, PropTypes.func]),
showNewOnFirstColumn: PropTypes.bool,
newItemLabel: PropTypes.string,
};

const Kanban = ({ value, onChange, icon, itemRender }) => {
const Kanban = ({
value,
onChange,
icon,
itemRender,
showNewOnFirstColumn,
onNew,
newItemLabel,
}) => {
const { classes } = KanbanStyles({});

const onDragEnd = (result) => {
Expand Down Expand Up @@ -73,6 +86,9 @@ const Kanban = ({ value, onChange, icon, itemRender }) => {
index={index}
itemRender={itemRender}
icon={icon}
showNew={showNewOnFirstColumn && index === 0}
onNew={onNew}
newItemLabel={newItemLabel}
/>
))}
{provided.placeholder}
Expand Down
113 changes: 58 additions & 55 deletions packages/components/src/informative/Kanban/Kanban.styles.js
Original file line number Diff line number Diff line change
@@ -1,58 +1,61 @@
import { createStyles } from '@mantine/styles';

export const KanbanStyles = createStyles((theme, {}) => {
return {
root: {
overflow: 'auto',
whiteSpace: 'nowrap',
height: '100%',
maxHeight: '100%',
padding: theme.spacing[2],
backgroundColor: '#F8F9FB',
gap: theme.spacing[2],
display: 'flex',
const KanbanStyles = createStyles((theme) => ({
root: {
display: 'flex',
overflow: 'auto',
whiteSpace: 'nowrap',
height: '100%',
maxHeight: '100%',
gap: theme.spacing[2],
alignItems: 'stretch',
padding: theme.spacing[2],
backgroundColor: '#F8F9FB',
},
column: {
display: 'inline-flex',
position: 'relative',
width: '300px',
minWidth: '300px',
flexDirection: 'column',
backgroundColor: '#F2F4F8',
borderRadius: theme.spacing[1],
},
columnHeader: {
paddingLeft: theme.spacing[4],
paddingRight: theme.spacing[4],
paddingTop: theme.spacing[3],
color: '#4D5358',
fontSize: '16px',
fontWeight: 600,
lineHeight: '24px',
fontFamily: 'Albert Sans',
display: 'flex',
gap: theme.spacing[2],
alignItems: 'center',
},
scroll: {
padding: theme.spacing[2],
},
listDraggingOver: {
backgroundColor: '#EDEFF5',
borderRadius: 4,
},
list: {
minHeight: '100px',
},
iconBig: {
position: 'absolute',
bottom: 20,
left: 20,
zIndex: 0,
img: {
filter: 'brightness(0) invert(1)',
},
column: {
height: '100%',
display: 'inline-flex',
position: 'relative',
width: '300px',
minWidth: '300px',
flexDirection: 'column',
backgroundColor: '#F2F4F8',
borderRadius: theme.spacing[1],
},
columnHeader: {
paddingLeft: theme.spacing[4],
paddingRight: theme.spacing[4],
paddingTop: theme.spacing[3],
color: '#4D5358',
fontSize: '16px',
fontWeight: 600,
lineHeight: '24px',
fontFamily: 'Albert Sans',
display: 'flex',
gap: theme.spacing[2],
alignItems: 'center',
},
scroll: {
padding: theme.spacing[2],
},
listDraggingOver: {
backgroundColor: '#EDEFF5',
borderRadius: 4,
},
list: {
minHeight: '100px',
},
iconBig: {
position: 'absolute',
bottom: 20,
left: 20,
zIndex: 0,
img: {
filter: 'brightness(0) invert(1)',
},
},
};
});
},
newItem: {
padding: theme.spacing[2],
},
}));

export { KanbanStyles };
54 changes: 42 additions & 12 deletions packages/components/src/informative/Kanban/components/Column.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,25 @@
import React from 'react';
import PropTypes from 'prop-types';
import { ScrollArea } from '@mantine/core';
import { Draggable } from 'react-beautiful-dnd';
import { Box } from '../../../layout/Box';
import { KanbanStyles } from '../Kanban.styles';
import { Draggable } from 'react-beautiful-dnd';
import { QuoteList } from './QuoteList';
import { ImageLoader } from '../../../misc';
import { ScrollArea } from '@mantine/core';
import { NewItem } from './NewItem';

const Column = ({ value, index, isScrollable, isCombineEnabled, itemRender, icon, ...props }) => {
const { classes, cx } = KanbanStyles({});
const Column = ({
value,
index,
isScrollable,
isCombineEnabled,
itemRender,
icon,
onNew,
showNew,
newItemLabel,
}) => {
const { classes } = KanbanStyles({});

return (
<Draggable draggableId={value.id} index={index} isDragDisabled={true}>
Expand All @@ -32,19 +44,37 @@ const Column = ({ value, index, isScrollable, isCombineEnabled, itemRender, icon
<Box>{value.cards.length}</Box>
</Box>
<ScrollArea className={classes.scroll} style={{ width: '100%', height: '100%' }}>
<QuoteList
listId={value.id}
listType="QUOTE"
value={value.cards}
internalScroll={isScrollable}
isCombineEnabled={Boolean(isCombineEnabled)}
itemRender={itemRender}
/>
{showNew && !value.cards?.length ? (
<Box className={classes.newItem}>
<NewItem label={newItemLabel} onClick={onNew} />
</Box>
) : (
<QuoteList
listId={value.id}
listType="QUOTE"
value={value.cards}
internalScroll={isScrollable}
isCombineEnabled={Boolean(isCombineEnabled)}
itemRender={itemRender}
/>
)}
</ScrollArea>
</Box>
)}
</Draggable>
);
};

Column.propTypes = {
value: PropTypes.object,
index: PropTypes.number,
isScrollable: PropTypes.bool,
isCombineEnabled: PropTypes.bool,
itemRender: PropTypes.func,
icon: PropTypes.string,
onNew: PropTypes.func,
showNew: PropTypes.bool,
newItemLabel: PropTypes.string,
};

export { Column };
50 changes: 50 additions & 0 deletions packages/components/src/informative/Kanban/components/NewItem.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import React from 'react';
import PropTypes from 'prop-types';
import { noop, capitalize } from 'lodash';
import { AddCircleIcon } from '@bubbles-ui/icons/solid';
import { UnstyledButton, createStyles } from '@mantine/core';
import { Box } from '../../../layout/Box';

const useStyles = createStyles((theme) => ({
root: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
borderRadius: theme.other.global.border.radius.md,
border: `2px dashed ${theme.other.dropzone.border.color.default}`,
cursor: 'pointer',
gap: 4,
width: '100%',
paddingBlock: theme.spacing[7],
'&:hover': {
backgroundColor: theme.other.dropzone.background.color.hover,
},
},
label: {
color: theme.other.global.content.color.text.default,
...theme.other.global.content.typo.body['md--bold'],
},
icon: {
color: theme.other.global.content.color.icon.default,
},
}));

function NewItem({ label, onClick = noop }) {
const { classes } = useStyles({}, { name: 'NewLibraryCardButton' });
return (
<UnstyledButton className={classes.root} onClick={onClick}>
<Box className={classes.icon}>
<AddCircleIcon width={24} height={24} />
</Box>
<Box className={classes.label}>{capitalize(label)}</Box>
</UnstyledButton>
);
}

NewItem.propTypes = {
label: PropTypes.string.isRequired,
onClick: PropTypes.func.isRequired,
};

export { NewItem };
34 changes: 34 additions & 0 deletions packages/components/src/informative/Kanban/mock/mock.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,40 @@ export const mock = {
deleted_at: null,
fromCalendar: true,
},
{
id: '642b7dd7-a219-4792-87f3-5e62c6b223234',
title: 'Next task 3',
calendar: '9c1ec044-beb7-4f86-b1db-0c8b365ee786',
startDate: '2022-01-11T23:00:00.000Z',
endDate: '2022-01-13T22:59:59.000Z',
isAllDay: 1,
repeat: 'dont_repeat',
type: 'plugins.calendar.task',
status: 'active',
data: { column: '734c8a98-ce1b-4d8a-912f-f65eeb850f24' },
deleted: 0,
created_at: '2022-01-24T09:59:50.000Z',
updated_at: '2022-01-24T09:59:50.000Z',
deleted_at: null,
fromCalendar: true,
},
{
id: '642b7dd7-a219-4792-87f3-5e62csdfsdfs',
title: 'Next task 4',
calendar: '9c1ec044-beb7-4f86-b1db-0c8b365ee786',
startDate: '2022-01-11T23:00:00.000Z',
endDate: '2022-01-13T22:59:59.000Z',
isAllDay: 1,
repeat: 'dont_repeat',
type: 'plugins.calendar.task',
status: 'active',
data: { column: '734c8a98-ce1b-4d8a-912f-f65eeb850f24' },
deleted: 0,
created_at: '2022-01-24T09:59:50.000Z',
updated_at: '2022-01-24T09:59:50.000Z',
deleted_at: null,
fromCalendar: true,
},
],
},
{
Expand Down

0 comments on commit 363c370

Please sign in to comment.