Commit f93a6b27 authored by Matija Obreza's avatar Matija Obreza
Browse files

Merge branch '31-list-request-actions' into 'master'

List Request actions

Closes #31

See merge request grin-global/grin-global-ui!91
parents 15d6b221 7d1f2cc5
......@@ -349,6 +349,17 @@
"completedDate": "Completed Date",
"feedback": "Feedback"
},
"OrderRequestAction": {
"actionNameCode": "Action Name",
"startedDate": "Start Date",
"startedDateCode": "Start Date Format",
"completedDate": "Completed Date",
"completedDateCode": "Completed Date Format",
"cooperator": "Cooperator",
"actionCost": "Action cost",
"actionInformation": "Action Information",
"orderRequestId": "Order Request ID"
},
"OrderRequestItem": {
"id": "Order Request Item ID",
"orderRequest": "Order Number",
......
......@@ -24,7 +24,9 @@ class OrderRequestAction {
public actionInformation: string;
public orderRequestId: number;
public static CodeGroup = {
actionNameCode: 'ORDER_REQUEST_ACTION',
}
}
export default OrderRequestAction;
......@@ -338,6 +338,17 @@
"completedDate": "Completed Date",
"feedback": "Feedback"
},
"OrderRequestAction": {
"actionNameCode": "Action Name",
"startedDate": "Start Date",
"startedDateCode": "Start Date Format",
"completedDate": "Completed Date",
"completedDateCode": "Completed Date Format",
"cooperator": "Cooperator",
"actionCost": "Action cost",
"actionInformation": "Action Information",
"orderRequestId": "Order Request ID"
},
"OrderRequestItem": {
"id": "Order Request Item ID",
"orderRequest": "Order Number",
......
import * as React from 'react';
interface IProps {
children: JSX.Element;
children: React.ReactNode;
index: any;
value: any;
};
......
......@@ -487,7 +487,9 @@
"list": "Requests for material"
},
"details": {
"title": "Request"
"title": "Request",
"items": "Items",
"actions": "Actions"
}
},
"c": {
......
......@@ -7,6 +7,7 @@ import {
SAGA_RECEIVE_REQUEST, RECEIVE_REQUEST,
SAGA_RECEIVE_REQUEST_ITEMS, RECEIVE_REQUEST_ITEMS,
SAGA_CREATE_REQUEST, RECEIVE_NEW_REQUEST, CLEAR_REQUEST,
SAGA_RECEIVE_REQUEST_ACTIONS, RECEIVE_REQUEST_ACTIONS,
} from 'request/constants';
// Model
import OrderRequest from '@gringlobal/client/model/gringlobal/OrderRequest';
......@@ -17,6 +18,7 @@ import { IPageRequest, FilteredPage, Page, SortDirection } from '@gringlobal/cli
// Service
import { RequestService } from '@gringlobal/client/service';
import { dereferenceReferences3 } from '@gringlobal/client/utilities';
import OrderRequestAction from '@gringlobal/client/model/gringlobal/OrderRequestAction';
// import OrderRequestItem from '@gringlobal/client/model/gringlobal/OrderRequestItem';
......@@ -26,6 +28,7 @@ export const requestPublicSagas = [
takeEvery(SAGA_CREATE_REQUEST, createOrderRequestSaga),
takeEvery(RECEIVE_NEW_REQUEST, redirectToNewRequestSaga),
takeEvery(SAGA_RECEIVE_REQUEST_ITEMS, listOrderRequestItemsSaga),
takeEvery(SAGA_RECEIVE_REQUEST_ACTIONS, listOrderRequestActionsSaga),
];
function* getOrderRequestSaga(action) {
......@@ -90,6 +93,29 @@ function * listOrderRequestsSaga(action) {
});
}
function* listOrderRequestActionsSaga(action) {
const filter = { id: [ action.payload.id ] };
const pageRequest = { direction: [ SortDirection.DESC ], properties: [ 'createdDate' ] };
yield put({
type: 'API',
target: RECEIVE_REQUEST_ACTIONS,
method: RequestService.listOrderActions,
params: [filter, pageRequest],
onSuccess: (requestActions: FilteredPage<OrderRequestAction>) => {
dereferenceReferences3(requestActions.content, {
coo: { id: [ 'ownedBy', 'createdBy', 'modifiedBy' ] },
});
return requestActions;
},
});
}
export const listOrderRequestActionsAction = (id: number | string) => ({
type: SAGA_RECEIVE_REQUEST_ACTIONS,
payload: { id },
});
export const listOrderRequestsAction = (filter: OrderRequestFilter = {}, pageR: IPageRequest = { page: 0, size: 100, direction: [ SortDirection.DESC ], properties: [ 'modifiedDate' ] }) => ({
type: SAGA_LIST_REQUESTS,
payload: {
......
......@@ -3,8 +3,10 @@ export const SAGA_LIST_REQUESTS = 'saga/request/public/LIST';
export const SAGA_RECEIVE_REQUEST_ITEMS = 'saga/request/public/RECEIVE_ITEMS';
export const SAGA_CREATE_REQUEST = 'saga/request/public/CREATE';
export const RECEIVE_NEW_REQUEST = 'saga/request/public/RECEIVE_NEW';
export const SAGA_RECEIVE_REQUEST_ACTIONS = 'saga/request/public/RECEIVE_ACTIONS';
export const CLEAR_REQUEST = 'success/request/public/CLEAR_REQUEST';
export const RECEIVE_REQUEST = 'success/request/public/RECEIVE_REQUEST';
export const RECEIVE_REQUESTS_LIST = 'success/request/public/LIST';
export const RECEIVE_REQUEST_ITEMS = 'success/request/public/RECEIVE_ITEMS';
export const RECEIVE_REQUEST_ACTIONS = 'success/request/public/RECEIVE_ACTIONS';
import update from 'immutability-helper';
// Constants
import { RECEIVE_REQUESTS_LIST, RECEIVE_REQUEST, CLEAR_REQUEST, RECEIVE_REQUEST_ITEMS } from 'request/constants';
import { RECEIVE_REQUESTS_LIST, RECEIVE_REQUEST, CLEAR_REQUEST, RECEIVE_REQUEST_ITEMS, RECEIVE_REQUEST_ACTIONS } from 'request/constants';
// Model
import OrderRequest from '@gringlobal/client/model/gringlobal/OrderRequest';
import { FilteredPage } from '@gringlobal/client/model/page';
import { ApiCall } from '@gringlobal/client/model/common';
import Inventory from '@gringlobal/client/model/gringlobal/Inventory';
import OrderRequestAction from '@gringlobal/client/model/gringlobal/OrderRequestAction';
const initialState: {
requestList: ApiCall<FilteredPage<OrderRequest>>,
request: ApiCall<OrderRequest>,
requestItems: ApiCall<FilteredPage<Inventory>>,
requestActions: ApiCall<FilteredPage<OrderRequestAction>>,
} = {
requestList: null,
request: null,
requestItems: null,
requestActions: null,
};
const publicReducer = (state = initialState, action) => {
......@@ -24,6 +27,7 @@ const publicReducer = (state = initialState, action) => {
return update(state, {
request: { $set: null },
requestItems: { $set: null },
requestActions: { $set: null },
});
}
case RECEIVE_REQUEST: {
......@@ -92,6 +96,17 @@ const publicReducer = (state = initialState, action) => {
},
});
}
case RECEIVE_REQUEST_ACTIONS: {
if (!action.payload) {
return update(state, { requestActions: { $set: null } });
}
const { apiCall } = action.payload;
return update(state, {
requestActions: {
$set: apiCall,
},
});
}
default:
return state;
}
......
......@@ -5,7 +5,9 @@
"list": "Requests for material"
},
"details": {
"title": "Request"
"title": "Request",
"items": "Items",
"actions": "Actions"
}
},
"c": {
......
......@@ -6,10 +6,9 @@ import { WithTranslation, withTranslation } from 'react-i18next';
// Action
import { ApiCall } from '@gringlobal/client/model/common';
import { getOrderRequestAction, listOrderRequestItemsAction } from 'request/action/public';
import { getOrderRequestAction, listOrderRequestItemsAction, listOrderRequestActionsAction } from 'request/action/public';
import { RequestService } from '@gringlobal/client/service';
import OrderRequest from '@gringlobal/client/model/gringlobal/OrderRequest';
import ContentHeader from '@gringlobal/client/ui/common/heading/ContentHeader';
import Loading from '@gringlobal/client/ui/common/Loading';
import { Card, CardContent, CardHeader, CardActions, Button } from '@material-ui/core';
import { Properties, PropertiesItem } from '@gringlobal/client/ui/common/Properties';
......@@ -25,6 +24,12 @@ import { CodeValueDisplay } from 'common/CodeValue';
import { InventoryName } from 'common/Inventory';
import ButtonBar from '@gringlobal/client/ui/common/button/ButtonBar';
import PageTitle from '@gringlobal/client/ui/common/PageTitle';
import OrderRequestAction from '@gringlobal/client/model/gringlobal/OrderRequestAction';
import { BasicRequestActionsTable as RequestActionsTable } from 'request/ui/c/RequestActionsTable';
import Tab from '@material-ui/core/Tab';
import HeaderTabs from '@gringlobal/client/ui/common/tabs/HeaderTabs';
import TabPanel from '@gringlobal/client/ui/common/tabs/TabPanel';
import SlotLayout from '@gringlobal/client/ui/common/layout/SlotLayout';
const OrderRequestItemTableConfig = new TableConfiguration({
defaultColumns: [
......@@ -47,9 +52,11 @@ const OrderRequestItemTableConfig = new TableConfiguration({
interface IDetailsPageProps extends React.ClassAttributes<any>, WithTranslation {
id: number;
getOrderRequestAction: (id: string | number) => void;
listOrderRequestActionsAction: (id: string | number) => void;
listOrderRequestItemsAction: (id: number, filter: OrderRequestItemFilter) => void;
requestCall: ApiCall<OrderRequest>;
requestItemsCall: ApiCall<FilteredPage<OrderRequestItem>>;
requestActionsCall: ApiCall<FilteredPage<OrderRequestAction>>;
}
class OrderRequestDetailsPage extends React.Component<IDetailsPageProps> {
......@@ -61,6 +68,7 @@ class OrderRequestDetailsPage extends React.Component<IDetailsPageProps> {
public state = {
selectedItems: [],
selectedTab: 'request',
}
public constructor(props) {
......@@ -82,9 +90,10 @@ class OrderRequestDetailsPage extends React.Component<IDetailsPageProps> {
}
private reloadData = () => {
const { id, getOrderRequestAction, listOrderRequestItemsAction } = this.props;
const { id, getOrderRequestAction, listOrderRequestItemsAction, listOrderRequestActionsAction } = this.props;
getOrderRequestAction(id);
listOrderRequestItemsAction(id, {});
listOrderRequestActionsAction(id);
}
private rowToggled = (toggledRow: number, selectedRows: number[], rowData: any) => {
......@@ -130,9 +139,15 @@ class OrderRequestDetailsPage extends React.Component<IDetailsPageProps> {
});
}
private selectTab = (event, newValue) => {
this.setState({
selectedTab: newValue,
});
};
public render(): React.ReactNode {
const { requestCall, requestItemsCall, t } = this.props;
const { selectedItems } = this.state;
const { requestCall, requestItemsCall, requestActionsCall, t } = this.props;
const { selectedItems, selectedTab } = this.state;
const columns = OrderRequestItemTableConfig.getColumns(requestItemsCall && requestItemsCall.data && requestItemsCall.data.content ? requestItemsCall.data.content[0] : null);
if (!requestCall) {
return null;
......@@ -143,89 +158,108 @@ class OrderRequestDetailsPage extends React.Component<IDetailsPageProps> {
return (
<>
<PageTitle title={ request ? request.localNumber ? request.localNumber : `${t('request.public.p.details.title')} ${request.id}` : t('request.public.p.details.title') }/>
<ContentHeader
title={
request ? <>
{ request.localNumber ? request.localNumber : request.id }
</> : t('request.public.p.details.title')
}
/>
{ loading && <Loading/> }
{ request &&
<>
<Card>
<CardContent>
<Properties>
<PropertiesItem title={ t('client:model.OrderRequest.orderTypeCode') }>
<CodeValueDisplay codeGroup={ OrderRequest.CodeValues.orderTypeCode } value={ request.orderTypeCode } />
</PropertiesItem>
{ [ 'localNumber', 'orderObtainedVia', 'intendedUseNote', 'specialInstruction', 'note' ].map((property) => (
<PropertiesItem key={ property } title={ t(`client:model.OrderRequest.${property}`, `client:model._.${property}`) }>
{ request[property] }
</PropertiesItem>
)) }
<PropertiesItem title={ t('client:model.OrderRequest.intendedUseCode') }>
<CodeValueDisplay codeGroup={ OrderRequest.CodeValues.intendedUseCode } value={ request.intendedUseCode } />
</PropertiesItem>
{ request.ownedDate &&
<PropertiesItem title={ t('client:model._.ownedDate') }>
<PrettyDate value={ request.ownedDate } />
</PropertiesItem>
}
{ request.ownedBy &&
<PropertiesItem title={ t('client:model._.ownedBy') }>
<Link to={ `/cooperator/${ request.ownedBy.id }` }>
{ request.ownedBy.firstName }
</Link>
</PropertiesItem>
}
</Properties>
</CardContent>
<CardActions>
<ButtonBar>
<Link to={ `/request/${request.id}/add` }><Button variant="contained" color="primary">{ t('Add material...') }</Button></Link>
<Button variant="contained" color="primary" onClick={ this.verifyItemList }>{ t('Verify item list') }</Button>
<Button variant="contained" color="secondary">Edit</Button>
<Button variant="outlined" color="secondary">Remove</Button>
<Button variant="text" color="secondary">Do something</Button>
</ButtonBar>
</CardActions>
</Card>
<Card>
<CardHeader title="Items" />
{ requestItemsCall && requestItemsCall.data && requestItemsCall.data.totalElements > 0 &&
<CardActions>
<ButtonBar>
<Button onClick={ this.toggleSelectAll }>{ t('Select all') }</Button>
{ Object.keys(OrderRequestItemStatus).map((itemStatus) => (
<Button
key={ itemStatus } variant="contained" color="secondary"
disabled={ selectedItems.length === 0 }
onClick={ this.updateItemStatus(itemStatus as OrderRequestItemStatus) }
>
<CodeValueDisplay value={ itemStatus } codeGroup={ OrderRequestItem.CodeValue.statusCode } />
</Button>
)) }
</ButtonBar>
</CardActions>
<HeaderTabs
value={ selectedTab }
textColor="primary"
onChange={ this.selectTab }
variant="scrollable"
scrollButtons="auto"
aria-label="Request tabs"
>
<Tab value="request" label={ t('request.public.p.details.title') } />
<Tab value="actions" label={ t('request.public.p.details.actions') } />
</HeaderTabs>
<TabPanel value={ selectedTab } index="request">
{ loading && <Loading/> }
{ request &&
<SlotLayout
fixedContent={
<>
<Card>
<CardHeader title={
request
? <>{ request.localNumber ? request.localNumber : request.id }</>
: t('request.public.p.details.title')
}/>
<CardContent>
<Properties>
<PropertiesItem title={ t('client:model.OrderRequest.orderTypeCode') }>
<CodeValueDisplay codeGroup={ OrderRequest.CodeValues.orderTypeCode } value={ request.orderTypeCode } />
</PropertiesItem>
{ [ 'localNumber', 'orderObtainedVia', 'intendedUseNote', 'specialInstruction', 'note' ].map((property) => (
<PropertiesItem key={ property } title={ t(`client:model.OrderRequest.${property}`, `client:model._.${property}`) }>
{ request[property] }
</PropertiesItem>
)) }
<PropertiesItem title={ t('client:model.OrderRequest.intendedUseCode') }>
<CodeValueDisplay codeGroup={ OrderRequest.CodeValues.intendedUseCode } value={ request.intendedUseCode } />
</PropertiesItem>
{ request.ownedDate &&
<PropertiesItem title={ t('client:model._.ownedDate') }>
<PrettyDate value={ request.ownedDate } />
</PropertiesItem>
}
{ request.ownedBy &&
<PropertiesItem title={ t('client:model._.ownedBy') }>
<Link to={ `/cooperator/${ request.ownedBy.id }` }>
{ request.ownedBy.firstName }
</Link>
</PropertiesItem>
}
</Properties>
</CardContent>
<CardActions>
<ButtonBar>
<Link to={ `/request/${request.id}/add` }><Button variant="contained" color="primary">{ t('Add material...') }</Button></Link>
<Button variant="contained" color="primary" onClick={ this.verifyItemList }>{ t('Verify item list') }</Button>
<Button variant="contained" color="secondary">Edit</Button>
<Button variant="outlined" color="secondary">Remove</Button>
<Button variant="text" color="secondary">Do something</Button>
</ButtonBar>
</CardActions>
</Card>
</>
}
<Table
noWrap
tableKey="request-items-list"
type={ 'OrderRequestItem' }
columns={ columns }
data={ requestItemsCall && requestItemsCall.data && requestItemsCall.data.content }
tableConfig={ OrderRequestItemTableConfig }
total={ requestItemsCall && requestItemsCall.data && requestItemsCall.data.content && requestItemsCall.data.totalElements }
selectedItems={ selectedItems }
// sort={ requestItemsCall && requestItemsCall.data && requestItemsCall.data.sort }
// onSortChange={ onSortChange }
onRowToggled={ this.rowToggled }
/>
</Card>
</>
}
>
<Card>
<CardHeader title={ t('request.public.p.details.items') } />
{ requestItemsCall && requestItemsCall.data && requestItemsCall.data.totalElements > 0 &&
<CardActions>
<ButtonBar>
<Button onClick={ this.toggleSelectAll }>{ t('Select all') }</Button>
{ Object.keys(OrderRequestItemStatus).map((itemStatus) => (
<Button
key={ itemStatus } variant="contained" color="secondary"
disabled={ selectedItems.length === 0 }
onClick={ this.updateItemStatus(itemStatus as OrderRequestItemStatus) }
>
<CodeValueDisplay value={ itemStatus } codeGroup={ OrderRequestItem.CodeValue.statusCode } />
</Button>
)) }
</ButtonBar>
</CardActions>
}
<Table
noWrap
tableKey="request-items-list"
type={ 'OrderRequestItem' }
columns={ columns }
data={ requestItemsCall && requestItemsCall.data && requestItemsCall.data.content }
tableConfig={ OrderRequestItemTableConfig }
total={ requestItemsCall && requestItemsCall.data && requestItemsCall.data.content && requestItemsCall.data.totalElements }
selectedItems={ selectedItems }
// sort={ requestItemsCall && requestItemsCall.data && requestItemsCall.data.sort }
// onSortChange={ onSortChange }
onRowToggled={ this.rowToggled }
/>
</Card>
</SlotLayout>
}
</TabPanel>
<TabPanel value={ selectedTab } index="actions">
<RequestActionsTable actions={ requestActionsCall.data && requestActionsCall.data.content }/>
</TabPanel>
</>
);
}
......@@ -235,11 +269,13 @@ const mapStateToProps = (state, ownProps) => ({
id: ownProps.match.params.id,
requestCall: state.request.public.request,
requestItemsCall: state.request.public.requestItems,
requestActionsCall: state.request.public.requestActions,
});
const mapDispatchToProps = (dispatch) => bindActionCreators({
getOrderRequestAction,
listOrderRequestItemsAction,
listOrderRequestActionsAction,
}, dispatch);
......
import * as React from 'react';
// Model
import OrderRequestAction from '@gringlobal/client/model/gringlobal/OrderRequestAction';
// UI
import { CooperatorOwnedTableConfiguration as TableConfiguration } from '@gringlobal/client/ui/common/table/TableConfiguration';
import Table, { Renderers, TextAlign } from '@gringlobal/client/ui/common/table/Table';
import { CodeValueDisplay } from 'common/CodeValue';
const BasicRequestActionsTableConfigProps = {
defaultColumns: [
'startedDate',
'completedDate',
'actionNameCode',
'note',
'createdBy',
'modifiedBy',
],
defaultColumnSettings: {
id: { readonly: true, align: TextAlign.right },
},
columnsRenderers: {
startedDate: Renderers.DATE_RENDERER,
completedDate: Renderers.DATE_RENDERER,
actionNameCode: (codeValue) => <CodeValueDisplay codeGroup={ OrderRequestAction.CodeGroup.actionNameCode } value={ codeValue } />,
},
};
const BasicRequestActionsTableConfig = new TableConfiguration(BasicRequestActionsTableConfigProps);
export const BasicRequestActionsTable = ({ actions }: { actions: OrderRequestAction[] }) => {
return (
<Table
noWrap
tableKey="request-basic-actionlist-table"
type={ 'OrderRequestAction' }
columns={ BasicRequestActionsTableConfig.defaultColumns }
data={ actions }
tableConfig={ BasicRequestActionsTableConfig }
/>
)
};
This diff is collapsed.
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment