Skip to content

Commit

Permalink
implemented workflow tracker based on route. uses redux.
Browse files Browse the repository at this point in the history
  • Loading branch information
Alex Medesan committed Nov 30, 2020
1 parent 477e9a8 commit 40dd7de
Show file tree
Hide file tree
Showing 8 changed files with 366 additions and 0 deletions.
119 changes: 119 additions & 0 deletions src/ProgressWorkflow.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import React, { useEffect, useState } from 'react';
import { Portal } from 'react-portal';
import { useDispatch, useSelector } from 'react-redux';
import { getWorkflowProgress } from './actions';
import './less/editor.less';

/**
* @summary The React component that allows the footnotes block view to be
* edited using a form in a sidebar portal.
* @param {object} props Contains the props received by any Edit component of a
* registered Volto block: `selected`, `block`, `data`, `onChangeBlock` etc.
*/
const ProgressWorkflow = (props) => {
const { content, pathname } = props;
const currentStateKey = content?.review_state;
const dispatch = useDispatch();

const [visible, setVisible] = useState(false);
const [workflowProgressSteps, setWorkflowProgressSteps] = useState([]);
const [currentState, setCurrentState] = useState({});
const workflowProgress = useSelector((state) => state?.workflowProgress);

const setVisibleSide = () => {
setVisible(!visible);
};

const findCurrentState = (steps, done) => {
const arrayContainingCurrentState = steps.find(
(itemElements) => itemElements[1] === done,
);
const indexOfCurrentSateKey = arrayContainingCurrentState[0].indexOf(
currentStateKey,
);
const title = arrayContainingCurrentState[2][indexOfCurrentSateKey];
const description = arrayContainingCurrentState[3][indexOfCurrentSateKey];

setCurrentState({
done,
title,
description,
});
};

useEffect(() => {
if (workflowProgress.result) {
findCurrentState(
workflowProgress.result.steps,
workflowProgress.result.done,
);
setWorkflowProgressSteps(workflowProgress.result.steps);
}
}, [workflowProgress]);

// Similar to componentDidMount and componentDidUpdate:
// used only once at mount
useEffect(() => {
dispatch(getWorkflowProgress(pathname));
}, [dispatch, pathname, props]); // to be used only once at mount

const itemTracker = (tracker) => (
<li
className={`progress__item ${
tracker[0].indexOf(currentStateKey) > -1
? 'progress__item--active'
: tracker[1] < currentState.done
? 'progress__item--completed'
: 'progress__item'
}`}
>
{tracker[2].map((title) => (
<p className="progress__title">{title}</p>
))}
</li>
);

const currentStateClass = {
published: 'published',
private: 'private',
};

return (
<>
<Portal
node={__CLIENT__ && document.querySelector('#toolbar .toolbar-actions')}
>
<>
<div
className={`review-state-text ${
currentStateClass[currentStateKey]
? currentStateClass[currentStateKey]
: ''
}`}
>
{currentState.title}
</div>
<div>
<button
className="circle-right-btn"
id="toolbar-cut-blocks"
onClick={setVisibleSide}
>
{`${currentState.done}%`}
</button>
{visible ? (
<div className="sidenav-ol">
<ul className="progress">
{workflowProgressSteps.map((progressItem) =>
itemTracker(progressItem),
)}
</ul>
</div>
) : null}
</div>
</>
</Portal>
</>
);
};
export default ProgressWorkflow;
1 change: 1 addition & 0 deletions src/actionTypes/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const WORKFLOW_PROGRESS = 'WORKFLOW_PROGRESS';
20 changes: 20 additions & 0 deletions src/actions/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { WORKFLOW_PROGRESS } from '@eeacms/volto-workflow-progress/actionTypes';

/**
* getGeonames function.
* @function getGeonames
* @param {url} url URL.
* @returns {Object} Object.
*/
export function getWorkflowProgress(item) {
return {
type: WORKFLOW_PROGRESS,
request: {
op: 'get',
path: `${item}/@workflow.progress`,
headers: {
Accept: 'application/json',
},
},
};
}
3 changes: 3 additions & 0 deletions src/icons/progress-tracker copy.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/icons/progress-tracker.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
22 changes: 22 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,26 @@
import ProgressWorkflow from './ProgressWorkflow';
import { workflowProgress } from './reducers';

const applyConfig = (config) => {
config.addonReducers = {
...config.addonReducers,
workflowProgress,
};

config.settings = {
...config.settings,
appExtras: [
...config.appExtras,
{
match: '',
component: ProgressWorkflow,
props: {
'google-tag': '123456',
},
},
],
};

return config;
};

Expand Down
130 changes: 130 additions & 0 deletions src/less/editor.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@


.circle-right-btn {
height: 45px;
width: 45px;
border-radius: 50%;
border: 2px solid #007eb1 !important;
font-size:16px;
font-weight: 600;
color: #007eb1 !important;
text-align: center !important;
text-decoration: none;
display: inline-block !important;
margin: 4px 2px;
cursor: pointer !important;
}

.sidenav-ol {
width: 200px;
position: fixed;
z-index: 1;
top: 0;
left: 80px;
background: #fff;
overflow-x: hidden;
padding: 8px 0;
box-shadow: 0 1px 2px 0 #c7d5d8;
}

.progressContainer {
position: relative;
width: 300px;
height: 100vh;
margin: 0 auto;
overflow: hidden;
padding: 2rem;
color: #fff;
background: #607D8B;
-moz-box-shadow: 0 0 15px rgba(0, 0, 0, 0.3);
-webkit-box-shadow: 0 0 15px rgba(0, 0, 0, 0.3);
box-shadow: 0 0 15px rgba(0, 0, 0, 0.3);
}

.progress {
position: relative;
padding: 0 1rem 0 3.5rem;
margin: 2rem 0 0;
list-style: none;
}

.review-state-text {
color: rgb(0, 123, 193);
text-align: center;
font-weight: 500;
}
.review-state-text {
color: rgb(246, 168, 8);
}
.review-state-text.published {
color: rgb(0, 123, 193);
}
.review-state-text.private {
color:rgb(237, 64, 51);
}

.progress__item {
position: relative;
min-height: 75px;
counter-increment: list;
padding-left: 0.5rem;
opacity: 0.4;
}
.progress__item:before {
content: "";
position: absolute;
left: -1.5rem;
top: 28px;
height: 60%;
width: 1px;
border-left: 1px solid #607D8B;
}
.progress__item:after {
content: counter(list);
position: absolute;
top: 0;
left: -2.5rem;
width: 26px;
height: 26px;
border-radius: 50%;
background: #607D8B;
color: white;
font-weight: 400;
font-size: 13px;
line-height: 2rem;
text-align: center;
border: 1px solid #607D8B;
}
.progress__item:last-child:before {
border: none;
}
.progress__item.progress__item--completed:before {
border-color: green;
}
.progress__item.progress__item--completed {
opacity: 1;
color: green;
}
.progress__item.progress__item--completed:after {
content: "\2713";
font-weight: 400;
background: green;
color: white;
}
.progress__item.progress__item--active {
opacity: 1;
}
.progress__item.progress__item--active:after {
background: #607D8B;
color: white;
}

.progress__title {
padding: 0.4rem 0 0.5rem;
margin: 0;
font-size: 1rem;
}

.progress__info {
font-size: 13px;
}
68 changes: 68 additions & 0 deletions src/reducers/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/**
* Data Figure reducer.
* @module reducers/workflowProgress
*/

import { WORKFLOW_PROGRESS } from '@eeacms/volto-workflow-progress/actionTypes';

const initialState = {
get: {
loaded: false,
loading: false,
error: null,
},
subrequests: {},
};

/**
* Get request key
* @function getRequestKey
* @param {string} actionType Action type.
* @returns {string} Request key.
*/
function getRequestKey(actionType) {
return actionType.split('_')[0].toLowerCase();
}

/**
* Data figure reducer.
* @function workflowProgress
* @param {Object} state Current state.
* @param {Object} action Action to be handled.
* @returns {Object} New state.
*/
export function workflowProgress(state = initialState, action = {}) {
let { result } = action;
switch (action.type) {
case `${WORKFLOW_PROGRESS}_PENDING`:
return {
...state,
[getRequestKey(action.type)]: {
loading: true,
loaded: false,
error: null,
},
};
case `${WORKFLOW_PROGRESS}_SUCCESS`:
return {
...state,
[getRequestKey(action.type)]: {
loading: false,
loaded: true,
error: null,
},
result,
};
case `${WORKFLOW_PROGRESS}_FAIL`:
return {
...state,
[getRequestKey(action.type)]: {
loading: false,
loaded: false,
error: action.error,
},
};
default:
return state;
}
}

0 comments on commit 40dd7de

Please sign in to comment.