Skip to content

Commit

Permalink
feat(Conditional Actions): Table conditional actions PoC #1
Browse files Browse the repository at this point in the history
  • Loading branch information
Manu Ramirez committed Mar 2, 2021
1 parent 8c42b88 commit 2d732a9
Show file tree
Hide file tree
Showing 4 changed files with 240 additions and 7 deletions.
1 change: 1 addition & 0 deletions packages/cascara/src/lib/mock/fakeData.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export const generateFakeInteractions = (qty) =>
matchedIntent,
phrase: faker.lorem.sentence(5),
response: faker.random.boolean(),
type: faker.random.arrayElement(['faq', 'other', 'interaction']),
user: `${firstName} ${lastName}`,
});
});
6 changes: 6 additions & 0 deletions packages/cascara/src/ui/Table/Table.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ const propTypes = {
* An event handler you can pass to handle every event your table emits.*/
onAction: pt.func,

/** Resolve record actions.
* A function that returns the actions available to the current row */
resolveRecordActions: pt.func,

/** Unique ID Attribute.
*
* specifies the attribute that uniquely identifies every object in the 'data' array. */
Expand All @@ -54,6 +58,7 @@ const Table = ({
data = [],
dataConfig = {},
onAction = (type, data) => type,
resolveRecordActions,
uniqueIdAttribute,
...rest
}) => {
Expand All @@ -71,6 +76,7 @@ const Table = ({
data,
dataConfig,
onAction,
resolveRecordActions,
uniqueIdAttribute,
}}
{...rest}
Expand Down
18 changes: 11 additions & 7 deletions packages/cascara/src/ui/Table/TableRow.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,21 +35,25 @@ const propTypes = {
const TableRow = ({ config = {}, record = {} }) => {
const { id, columns } = config;
const {
resolveRecordActions,
dataConfig: { actionButtonMenuIndex = 0, actions: userDefinedActions = [] },
} = useContext(ModuleContext);

// If a resolver is passed, get actions from it
const actions = resolveRecordActions
? resolveRecordActions(record, userDefinedActions)
: resolveRecordActions; // otherwise continue as normal

const outsideButtonActions = [];
const insideButtonActions = [];
userDefinedActions
actions
.filter(({ module }) => module === 'button')
.map((action, index) =>
index >= actionButtonMenuIndex
? insideButtonActions.push(action)
: outsideButtonActions.push(action)
);
const specialActions = userDefinedActions.filter(
({ module }) => module !== 'button'
);

const specialActions = actions.filter(({ module }) => module !== 'button');
const outsideActions = [...specialActions, ...outsideButtonActions];

const renderActionModule = (action, index) => {
Expand All @@ -68,7 +72,7 @@ const TableRow = ({ config = {}, record = {} }) => {
);
};

const actions = (
const rowActions = (
<td className={styles.CellActions} key={`${id}-actionbar`}>
{outsideActions.map(renderActionModule)}
{Boolean(insideButtonActions.length) ? (
Expand All @@ -94,7 +98,7 @@ const TableRow = ({ config = {}, record = {} }) => {
});

if (userDefinedActions.length) {
rowCells.push(actions);
rowCells.push(rowActions);
}

return (
Expand Down
222 changes: 222 additions & 0 deletions packages/cascara/src/ui/Table/fixtures/Conditional.Actions.fixture.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
import React, { PureComponent } from 'react';
import { Dropdown, Header } from 'semantic-ui-react';

import JsonPlaceholder from '../../../placeholders/JsonPlaceholder';

import { generateFakeInteractions } from '../../../lib/mock/fakeData';
import Table from '..';

const defaultColumns = [
{
attribute: 'created',
isEditable: true,
isLabeled: false,
label: 'Created',
module: 'text',
},
{
attribute: 'phrase',
isEditable: false,
isLabeled: false,
label: 'Phrase',
module: 'text',
},
{
attribute: 'user',
isEditable: true,
isLabeled: false,
label: 'User',
module: 'email',
},
{
attribute: 'response',
isEditable: true,
isLabeled: false,
label: 'Response',
module: 'checkbox',
},
{
attribute: 'deflected',
isEditable: true,
isLabeled: false,
label: 'Deflected',
module: 'checkbox',
},
{
attribute: 'matchedIntent',
isEditable: true,
isLabeled: false,
label: 'Matched Intent',
module: 'text',
},

{
attribute: 'type',
isEditable: true,
isLabeled: false,
label: 'Type',
module: 'text',
},
];

class Fixture extends PureComponent {
state = {
columns: [...defaultColumns],
data: generateFakeInteractions(50).map((interaction) => ({
...interaction,
})),
display: [...defaultColumns],
};

handleColumnSelection = (_, { value: selectedColumns }) => {
const { columns } = this.state;
const newDisplay = columns
.filter((column) => selectedColumns.includes(column.attribute))
.reverse();

this.setState({ display: newDisplay });
};

handleRecordUpdate = (record) => {
const { data } = this.state;

const updatedData = data.map((recordInState) => {
if (recordInState.eid !== record.eid) {
return recordInState;
}

return {
...recordInState,
...record,
};
});

this.setState({ data: updatedData });
};

handleTableAction = (caller, data) => {
// eslint-ignore-next-line no-console
console.log(`Action: '${caller.name}' has been invoked:`);
// eslint-ignore-next-line no-console
console.table(data);

switch (caller.name) {
case 'edit.save':
this.handleRecordUpdate(data);
break;

default:
return;
}
};

resolveRecordActions(record, actions) {
return actions.reduce((actionsForRecord, action) => {
switch (action.name) {
/**
* Idealy, Cascara actions would always go first
* because they go outside the ActionsMenu.
*
* Since that is something we cannot control, we
* will have to filter them out inside Cascara. */
case 'edit':
// do not show if record is deflected
if (!record.deflected) {
actionsForRecord.push(action);
}
break;

case 'view.faq':
// do not show view button for FAQs
if (record.type !== 'faq') {
actionsForRecord.push(action);
}
break;

default:
actionsForRecord.push(action);
}

return actionsForRecord;
}, []);
}

render() {
const { columns, data, display } = this.state;
const dataConfig = {
actionButtonMenuIndex: 0,
actions: [
{
content: 'test',
module: 'button',
name: 'test',
},
{
content: 'stuff',
module: 'button',
name: 'stuff',
},
{
content: 'okay',
module: 'button',
name: 'okay',
},
{
content: 'View FAQ',
module: 'button',
name: 'view.faq',
},
{
module: 'edit',
name: 'edit',
},
],
display,
};

const availableColumns = columns.map((columnDef) => ({
key: columnDef.attribute,
text: columnDef.content,
value: columnDef.attribute,
}));

const selectedColumns = display.map((columnDef) => columnDef.attribute);

return (
<>
<JsonPlaceholder data={dataConfig} title='dataConfig' />
<JsonPlaceholder
data={{ availableColumns, selectedColumns }}
title='available vs. selected columns'
/>
<Header as='h4'>
<Header.Content>
Displaying columns: <br />
<Dropdown
header='Select columns...'
key={'select'}
labeled
multiple
onChange={this.handleColumnSelection}
options={availableColumns}
placeholder='select columns...'
selectedLabel={'Display columns'}
selection
value={selectedColumns}
/>
</Header.Content>
</Header>

<Table
data={data}
dataConfig={dataConfig}
onAction={this.handleTableAction}
resolveRecordActions={this.resolveRecordActions}
uniqueIdAttribute={'eid'}
/>
</>
);
}
}

export default Fixture;

0 comments on commit 2d732a9

Please sign in to comment.