Commit 1e3d640e authored by Maksym Tishchenko's avatar Maksym Tishchenko Committed by Matija Obreza

Inventory Group form completed

parent 1f71e927
......@@ -266,7 +266,8 @@
},
"details": {
"title": "Inventory group",
"members": "Members"
"members": "Members",
"delete": "Do you really want to delete {{name}} group?"
},
"acquisition": {
"names": "Names",
......
import { put, takeEvery } from 'redux-saga/effects';
import { call, put, takeEvery } from 'redux-saga/effects';
// Constants
import {
RECEIVE_INVENTORY_GROUP,
RECEIVE_INVENTORY_GROUP_LIST,
REMOVE_INVENTORY_GROUP,
SAGA_RECEIVE_INVENTORY_GROUP,
SAGA_RECEIVE_INVENTORY_GROUP_SUCCESS,
SAGA_REMOVE_INVENTORY_GROUP,
SAGA_LIST_INVENTORY_GROUP,
SET_INCOMING_NAMES,
SET_INCOMING_ACCESSIONS,
......@@ -17,11 +20,15 @@ import { IPageRequest, FilteredPage, Page } from '@gringlobal/client/model/page'
import { InventoryService } from '@gringlobal/client/service';
import { dereferenceReferences3 } from '@gringlobal/client/utilities';
import Accession from '@gringlobal/client/model/gringlobal/Accession';
import { ApiCall } from '@gringlobal/client/model/common';
import { sagaNavigate } from '@gringlobal/client/action/navigation';
export const inventoryGroupPublicSagas = [
takeEvery(SAGA_LIST_INVENTORY_GROUP, listInventoryGroupSaga),
takeEvery(SAGA_RECEIVE_INVENTORY_GROUP, getInventoryGroupSaga),
takeEvery(SAGA_RECEIVE_INVENTORY_GROUP_SUCCESS, receiveInventoryGroupSaga),
takeEvery(SAGA_REMOVE_INVENTORY_GROUP, removeInventoryGroupSaga),
];
export const getInventoryGroupAction = (id: number | string) => ({
......@@ -37,6 +44,11 @@ export const listInventoryGroupAction = (filter: AccessionInvGroupFilter = {}, p
},
});
export const receiveInventoryGroupSuccessAction = (inventoryGroup: AccessionInvGroup) => ({
type: SAGA_RECEIVE_INVENTORY_GROUP_SUCCESS,
payload: { inventoryGroup },
});
export const loadMoreInventoryGroupAction = (inventoryGroup: FilteredPage<AccessionInvGroup>) => {
return {
type: SAGA_LIST_INVENTORY_GROUP,
......@@ -59,6 +71,28 @@ function* getInventoryGroupSaga(action) {
});
}
function* removeInventoryGroupSaga(action) {
yield put({
type: 'API',
target: REMOVE_INVENTORY_GROUP,
method: InventoryService.removeGroup,
params: [action.payload.id],
onSuccess: (group: AccessionInvGroup) => {
return (function* () {
yield call(sagaNavigate, '/inventory/group');
return group;
})();
},
});
}
function* receiveInventoryGroupSaga(action) {
yield put({
type: RECEIVE_INVENTORY_GROUP,
payload: { apiCall: ApiCall.success(action.payload.inventoryGroup) },
});
}
function * listInventoryGroupSaga(action) {
yield put({
type: 'API',
......@@ -80,6 +114,11 @@ function * listInventoryGroupSaga(action) {
});
}
export const removeInventoryGroupAction = (id: number) => ({
type: SAGA_REMOVE_INVENTORY_GROUP,
payload: { id },
});
/**
* Store accession names in the reducer
*
......
export const RECEIVE_INVENTORY_GROUP_LIST = 'success/INVENTORY_GROUP/public/RECEIVE_INVENTORY_GROUP_LIST';
export const RECEIVE_INVENTORY_GROUP = 'success/INVENTORY_GROUP/public/RECEIVE_INVENTORY_GROUP';
export const REMOVE_INVENTORY_GROUP = 'success/INVENTORY_GROUP/public/REMOVE_INVENTORY_GROUP';
export const SAGA_LIST_INVENTORY_GROUP = 'saga/INVENTORY_GROUP/public/SAGA_LIST_INVENTORY_GROUP';
export const SAGA_RECEIVE_INVENTORY_GROUP = 'saga/INVENTORY_GROUP/public/RECEIVE_INVENTORY_GROUP';
export const SAGA_RECEIVE_INVENTORY_GROUP_SUCCESS = 'saga/INVENTORY_GROUP/public/RECEIVE_INVENTORY_GROUP_SUCCESS';
export const SAGA_REMOVE_INVENTORY_GROUP = 'saga/INVENTORY_GROUP/public/REMOVE_INVENTORY_GROUP';
export const SET_INCOMING_NAMES = 'success/INVENTORY_GROUP/public/SET_INCOMING_NAMES';
export const SET_INCOMING_ACCESSIONS = 'success/INVENTORY_GROUP/public/SET_INCOMING_ACCESSIONS';
import update from 'immutability-helper';
// Constants
import { RECEIVE_INVENTORY_GROUP_LIST, RECEIVE_INVENTORY_GROUP, SET_INCOMING_NAMES, SET_INCOMING_ACCESSIONS } from 'inventorygroup/constants';
import {
RECEIVE_INVENTORY_GROUP_LIST,
RECEIVE_INVENTORY_GROUP,
SET_INCOMING_NAMES,
SET_INCOMING_ACCESSIONS,
REMOVE_INVENTORY_GROUP,
} from 'inventorygroup/constants';
// Model
import AccessionInvGroup from '@gringlobal/client/model/gringlobal/AccessionInvGroup';
import { FilteredPage } from '@gringlobal/client/model/page';
......@@ -71,6 +77,31 @@ const publicReducer = (state = initialState, action) => {
},
});
}
case REMOVE_INVENTORY_GROUP: {
const { apiCall: { data } } = action.payload;
if (data) {
if (state.inventoryGroupListCall && state.inventoryGroupListCall.data && state.inventoryGroupListCall.data.content) {
const updatedGroups = state.inventoryGroupListCall.data.content.filter((group) => group.id !== data.id);
return update(state, {
inventoryGroupCall: { $set: null },
inventoryGroupListCall: {
data: {
content: {
$set: updatedGroups,
},
totalElements: {
$apply: (total) => total - 1,
},
},
},
});
}
return update(state, {
inventoryGroupCall: { $set: null },
});
}
return state;
}
case SET_INCOMING_NAMES: {
const { names } = action.payload;
return update(state, {
......
......@@ -6,7 +6,8 @@
},
"details": {
"title": "Inventory group",
"members": "Members"
"members": "Members",
"delete": "Do you really want to delete {{name}} group?"
},
"acquisition": {
"names": "Names",
......
......@@ -19,6 +19,7 @@ import Filters from 'inventorygroup/ui/c/Filters';
import withBrowsePageBase, { WithBrowsePageBase } from 'ui/common/withBrowsePageBase';
import { CooperatorOwnedTableConfiguration as TableConfiguration } from '@gringlobal/client/ui/common/table/TableConfiguration';
import PageTitle from '@gringlobal/client/ui/common/PageTitle';
import EditGroupDialog from 'inventorygroup/ui/c/EditGroupDialog';
// import { CodeValueDisplay } from 'common/CodeValue';
// import Number from '@gringlobal/client/ui/common/Number';
......@@ -60,6 +61,10 @@ class BrowsePage extends React.Component<IBrowsePageProps> {
({}) => listInventoryGroupAction(),
];
public state = {
editInvGroupDialogIsOpen: false,
};
public constructor(props) {
super(props);
......@@ -80,10 +85,20 @@ class BrowsePage extends React.Component<IBrowsePageProps> {
console.log(`Column ${toggledColumn} was toggled. Have ${selectedColumns}`);
};
private openEditInvGroupDialog = () => {
this.setState({ editInvGroupDialogIsOpen: true });
};
private closeEditInvGroupDialog = () => {
this.setState({ editInvGroupDialogIsOpen: false });
};
public render() {
const { data, t, onSortChange, applyFilter, loadMore } = this.props;
const columns = InventoryGroupTableConfig.getColumns(data && data.content ? data.content[0] : null);
const { editInvGroupDialogIsOpen } = this.state;
return (
<>
<PageTitle title={ t('inventorygroup.public.p.browse.title') }/>
......@@ -106,7 +121,9 @@ class BrowsePage extends React.Component<IBrowsePageProps> {
sort={ data && data.sort }
onSortChange={ onSortChange }
/>
<AddNewButton/>
<AddNewButton action={ this.openEditInvGroupDialog }/>
<EditGroupDialog isOpen={ editInvGroupDialogIsOpen } createNew={ true } onClose={ this.closeEditInvGroupDialog }/>
</>
);
}
......
......@@ -4,7 +4,7 @@ import { bindActionCreators, compose } from 'redux';
import { WithTranslation, withTranslation } from 'react-i18next';
// Action
import { ApiCall } from '@gringlobal/client/model/common';
import { getInventoryGroupAction } from 'inventorygroup/action/public';
import { getInventoryGroupAction, removeInventoryGroupAction } from 'inventorygroup/action/public';
import Loading from '@gringlobal/client/ui/common/Loading';
import { Card, CardContent, CardHeader, CardActions, Button } from '@material-ui/core';
import Tab from '@material-ui/core/Tab';
......@@ -24,12 +24,15 @@ import { dereferenceReferences3 } from '@gringlobal/client/utilities';
import { Page, SortDirection, IPageRequest } from '@gringlobal/client/model/page';
import AccessionInvGroupMap from '@gringlobal/client/model/gringlobal/AccessionInvGroupMap';
import PageTitle from '@gringlobal/client/ui/common/PageTitle';
import EditGroupDialog from 'inventorygroup/ui/c/EditGroupDialog';
import confirm from '@gringlobal/client/utilities/confirmAlert';
interface IDetailsPageProps extends React.ClassAttributes<any>, WithTranslation {
groupId: number;
getInventoryGroupAction: (id: number) => void;
inventoryGroupCall: ApiCall<AccessionInvGroup>;
removeInventoryGroupAction: (id: number) => void;
}
......@@ -66,6 +69,7 @@ class InventoryDetailsPage extends React.Component<IDetailsPageProps> {
prevId: null,
selectedTab: 'members',
members: null,
editInvGroupDialogIsOpen: false,
};
public constructor(props) {
......@@ -137,6 +141,24 @@ class InventoryDetailsPage extends React.Component<IDetailsPageProps> {
});
}
private openEditInvGroupDialog = () => {
this.setState({ editInvGroupDialogIsOpen: true });
};
private closeEditInvGroupDialog = () => {
this.setState({ editInvGroupDialogIsOpen: false });
};
public handleRemove = () => {
const { removeInventoryGroupAction, t, groupId, inventoryGroupCall } = this.props;
confirm(t('inventorygroup.public.p.details.delete', { name: inventoryGroupCall.data.groupName }), {
confirmLabel: t('common:label.yes'),
abortLabel: t('common:label.no'),
}).then(() => {
removeInventoryGroupAction(+groupId);
});
};
public render(): React.ReactNode {
const { inventoryGroupCall, t } = this.props;
if (!inventoryGroupCall) {
......@@ -146,7 +168,7 @@ class InventoryDetailsPage extends React.Component<IDetailsPageProps> {
const { loading, data: inventoryGroup } = inventoryGroupCall;
const { selectedTab } = this.state;
const { members } = this.state;
const { members, editInvGroupDialogIsOpen } = this.state;
return (
<>
......@@ -227,12 +249,14 @@ class InventoryDetailsPage extends React.Component<IDetailsPageProps> {
</CardContent>
<CardActions>
<Button variant="contained" color="primary">Test</Button>
<Button variant="contained" color="secondary">Edit</Button>
<Button variant="outlined" color="secondary">Remove</Button>
<Button onClick={ this.openEditInvGroupDialog } variant="contained" color="secondary">Edit</Button>
<Button onClick={ this.handleRemove } variant="outlined" color="secondary">Remove</Button>
<Button variant="text" color="secondary">Do something</Button>
</CardActions>
</Card>
</TabPanel>
<EditGroupDialog isOpen={ editInvGroupDialogIsOpen } onClose={ this.closeEditInvGroupDialog }/>
</>
}
</>
......@@ -247,6 +271,7 @@ const mapStateToProps = (state, ownProps) => ({
const mapDispatchToProps = (dispatch) => bindActionCreators({
getInventoryGroupAction,
removeInventoryGroupAction,
}, dispatch);
......
import * as React from 'react';
import { connect } from 'react-redux';
import { WithTranslation, withTranslation } from 'react-i18next';
// model
import AccessionInvGroup from '@gringlobal/client/model/gringlobal/AccessionInvGroup';
// action
import { receiveInventoryGroupSuccessAction } from 'inventorygroup/action/public.ts';
import Dialog from '@material-ui/core/Dialog';
import DialogContent from '@material-ui/core/DialogContent';
import DialogTitle from '@material-ui/core/DialogTitle';
import EditGroupForm from './EditGroupForm';
import { bindActionCreators } from 'redux';
import { InventoryService } from '@gringlobal/client/service';
interface IEditGroupDialogProps extends React.ClassAttributes<any>, WithTranslation {
receiveInventoryGroupSuccessAction: (accessionInvGroup: AccessionInvGroup) => void;
inventoryGroup: AccessionInvGroup;
saveGroup: (accessionInvGroup: AccessionInvGroup) => void;
isOpen: boolean;
createNew: boolean;
onClose: () => void;
}
class EditGroupDialog extends React.Component<IEditGroupDialogProps, any> {
public state = {
apiError: null,
};
private handleSubmit = (accessionInvGroup: AccessionInvGroup) => {
const { onClose, receiveInventoryGroupSuccessAction, createNew } = this.props;
let inventoryPromise: Promise<AccessionInvGroup>;
this.setState({ apiError: null });
if (createNew) {
inventoryPromise = InventoryService.createGroup(accessionInvGroup)
} else {
inventoryPromise = InventoryService.updateGroup(accessionInvGroup)
}
inventoryPromise.then((inventoryGroup) => {
receiveInventoryGroupSuccessAction(inventoryGroup);
onClose();
}).catch((e) => {
this.setState({ apiError: e.data && e.data.error || e.toString() });
});
};
public componentDidUpdate(prevProps: Readonly<IEditGroupDialogProps>) {
const { isOpen } = this.props;
if (isOpen === true && prevProps.isOpen === false) {
this.setState({ apiError: null });
return;
}
}
public render() {
const { inventoryGroup, isOpen, t, onClose } = this.props;
const { apiError } = this.state;
return (
<div>
{ isOpen &&
<Dialog
open={ isOpen }
onClose={ onClose }
maxWidth="sm"
fullWidth
disableEnforceFocus
>
<DialogTitle>{ t('inventorygroup.public.p.details.title') }</DialogTitle>
<DialogContent>
<EditGroupForm
initialValues={ inventoryGroup }
onClose={ onClose }
onSubmit={ this.handleSubmit }
error={ apiError }
/>
</DialogContent>
</Dialog>
}
</div>
);
}
}
const mapStateToProps = (state) => ({
inventoryGroup: state.inventorygroup.public.inventoryGroupCall ? state.inventorygroup.public.inventoryGroupCall.data : undefined,
});
const mapDispatchToProps = (dispatch) => bindActionCreators({
receiveInventoryGroupSuccessAction,
}, dispatch);
export default connect(mapStateToProps, mapDispatchToProps)(withTranslation()(EditGroupDialog));
import { Field, Form, FormProps, FormRenderProps } from 'react-final-form';
import { WithStyles } from '@material-ui/core/styles';
import { WithTranslation, withTranslation } from 'react-i18next';
import { Button, DialogActions, Grid } from '@material-ui/core';
import { TextField } from '@gringlobal/client/ui/common/form/TextField';
import { YesNoSwitch } from '@gringlobal/client/ui/common/form/Toggle';
import * as React from 'react';
import AccessionInvGroup from '@gringlobal/client/model/gringlobal/AccessionInvGroup';
interface IEditGroupForm extends React.ClassAttributes<any>, FormProps, WithTranslation {
error: string;
initialValues: Partial<AccessionInvGroup>;
onClose: () => void;
}
class EditGroupForm extends React.Component<IEditGroupForm, any> {
public constructor(props: any) {
super(props);
}
public render() {
const { t, onClose, onSubmit, initialValues, error } = this.props;
return (
<Form
initialValues={ initialValues }
onSubmit={ onSubmit }
>
{ (props: FormRenderProps & WithStyles) => (
<form onSubmit={ props.handleSubmit }>
<Grid container direction={ 'column' } spacing={ 2 }>
<Grid item xs={ 12 } sm={ 12 }>
<Field
placeholder={ t('client:model.AccessionInvGroup.groupName') }
name="groupName"
type="text"
component={ TextField }
label={ t('client:model.AccessionInvGroup.groupName') }
/>
</Grid>
<Grid item xs={ 12 } sm={ 12 }>
<Field
placeholder={ t('client:model._.note') }
name="note"
type="text"
component={ TextField }
label={ t('client:model._.note') }
/>
</Grid>
<Grid item xs={ 12 } sm={ 12 }>
<Field
label={ t('client:model._.isWebVisible') }
name="isWebVisible"
component={ YesNoSwitch }
labelPlacement="end"
/>
</Grid>
{ error && <Grid item xs={ 12 } sm={ 12 } style={ { color: 'red' } }>{ error }</Grid> }
</Grid>
<DialogActions>
<Button type="submit" variant="contained" color="primary">{ t('common:action.submit') }</Button>
<Button variant="contained" type="button" onClick={ onClose }>{ t('common:action.cancel') }</Button>
</DialogActions>
</form>
)}
</Form>
);
}
}
export default withTranslation()(EditGroupForm);
Markdown is supported
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