Kurmansky
3 years ago
45 changed files with 16683 additions and 15701 deletions
@ -0,0 +1,11 @@
@@ -0,0 +1,11 @@
|
||||
export interface ICreateFactory { |
||||
parentId?: number; |
||||
description?: string; |
||||
directorId: number; |
||||
name: string; |
||||
shortName: string; |
||||
} |
||||
|
||||
export interface IUpdateFactory extends ICreateFactory { |
||||
id: number; |
||||
} |
@ -0,0 +1,26 @@
@@ -0,0 +1,26 @@
|
||||
import { ICreateFactory, IUpdateFactory } from "./requests.interface"; |
||||
import { ApiResponse } from "../http.types"; |
||||
import http from "../http.service"; |
||||
import { IFactory } from "@/shared"; |
||||
|
||||
const fetchFactories = (): ApiResponse<IFactory[]> => { |
||||
return http.get<IFactory[]>("factories", null); |
||||
}; |
||||
|
||||
const createFactory = (payload: ICreateFactory): ApiResponse<IFactory> => { |
||||
return http.post<IFactory>("factories", payload); |
||||
}; |
||||
const updateFactory = (payload: IUpdateFactory): ApiResponse<IFactory> => { |
||||
return http.put<IFactory>("factories", payload); |
||||
}; |
||||
|
||||
const deleteFactory = (id: number): ApiResponse<void> => { |
||||
return http.delete<void>(`factories/${id}`); |
||||
}; |
||||
|
||||
export const factoriesApi = { |
||||
fetchFactories, |
||||
createFactory, |
||||
updateFactory, |
||||
deleteFactory, |
||||
}; |
@ -1,3 +1,4 @@
@@ -1,3 +1,4 @@
|
||||
export * from './auth/requests' |
||||
export * from './account/requests' |
||||
export * from './taxonomies/requests' |
||||
export * from "./auth/requests"; |
||||
export * from "./account/requests"; |
||||
export * from "./taxonomies/requests"; |
||||
export * from "./factories/requests"; |
||||
|
@ -1,8 +1,6 @@
@@ -1,8 +1,6 @@
|
||||
|
||||
|
||||
export const config = { |
||||
apiUrl: 'http://localhost:3000/admin', |
||||
socketUrl: 'http://localhost:3000', |
||||
} |
||||
apiUrl: "http://185.69.154.136:5000/admin/", |
||||
socketUrl: "http://localhost:3000", |
||||
}; |
||||
|
||||
export default config |
||||
export default config; |
||||
|
@ -1,64 +1,75 @@
@@ -1,64 +1,75 @@
|
||||
import config from './index'; |
||||
import moment from 'moment'; |
||||
var restClient = require('../lib/rest-client'); |
||||
import config from "./index"; |
||||
import moment from "moment"; |
||||
var restClient = require("../lib/rest-client"); |
||||
|
||||
function checkHttpStatus(response) { |
||||
if (response.status >= 200 && response.status < 300) { |
||||
return response |
||||
} else { |
||||
// let error = new Error(response ? (response.statusText || 'Error') : 'Error');
|
||||
// error.response = response;
|
||||
return Promise.resolve().then(() => { |
||||
return response.json(); |
||||
}).then(res => { |
||||
res.status = response.status; |
||||
return Promise.reject(res) |
||||
}); |
||||
if (response.status >= 200 && response.status < 300) { |
||||
return response; |
||||
} else { |
||||
// let error = new Error(response ? (response.statusText || 'Error') : 'Error');
|
||||
// error.response = response;
|
||||
return Promise.resolve() |
||||
.then(() => { |
||||
return response.json(); |
||||
}) |
||||
.then((res) => { |
||||
res.status = response.status; |
||||
return Promise.reject(res); |
||||
}); |
||||
|
||||
return Promise.reject(response) |
||||
// throw error;
|
||||
} |
||||
return Promise.reject(response); |
||||
// throw error;
|
||||
} |
||||
} |
||||
|
||||
function makeRequest({ url, method, headers, bodyJSObject }) { |
||||
let header_tmp = Object.assign({}, this.headers, headers); |
||||
let header_tmp = Object.assign({}, this.headers, headers); |
||||
|
||||
let body = bodyJSObject ? JSON.stringify(bodyJSObject) : undefined; |
||||
if (header_tmp.hasOwnProperty('Content-Type') && header_tmp['Content-Type'] == 'multipart/form-data') { |
||||
body = bodyJSObject; |
||||
delete header_tmp['Accept']; |
||||
delete header_tmp['Content-Type']; |
||||
} |
||||
return fetch(url, |
||||
{ |
||||
method: method || "GET", |
||||
headers: header_tmp, |
||||
body: body, |
||||
mode: 'cors' |
||||
}).then(checkHttpStatus).then(response => { |
||||
return response.json(); |
||||
}); |
||||
let body = bodyJSObject ? JSON.stringify(bodyJSObject) : undefined; |
||||
if ( |
||||
header_tmp.hasOwnProperty("Content-Type") && |
||||
header_tmp["Content-Type"] == "multipart/form-data" |
||||
) { |
||||
body = bodyJSObject; |
||||
delete header_tmp["Accept"]; |
||||
delete header_tmp["Content-Type"]; |
||||
} |
||||
return fetch(url, { |
||||
method: method || "GET", |
||||
headers: header_tmp, |
||||
body: body, |
||||
mode: "cors", |
||||
}) |
||||
.then(checkHttpStatus) |
||||
.then((response) => { |
||||
return response.json(); |
||||
}); |
||||
} |
||||
|
||||
let token = ''; |
||||
let token = ""; |
||||
|
||||
if (localStorage.getItem('remember_me') && localStorage.getItem('remember_me') == 'yes') { |
||||
token = localStorage.getItem('token') |
||||
} else if (localStorage.getItem('expiret_date') && moment(localStorage.getItem('expiret_date')) > moment()) { |
||||
token = localStorage.getItem('token'); |
||||
if ( |
||||
localStorage.getItem("remember_me") && |
||||
localStorage.getItem("remember_me") == "yes" |
||||
) { |
||||
token = localStorage.getItem("token"); |
||||
} else if ( |
||||
localStorage.getItem("expiret_date") && |
||||
moment(localStorage.getItem("expiret_date")) > moment() |
||||
) { |
||||
token = localStorage.getItem("token"); |
||||
} else { |
||||
token = '' |
||||
token = ""; |
||||
} |
||||
|
||||
|
||||
restClient.config({ |
||||
baseUrl: config.apiUrl + '/api', |
||||
headers: { |
||||
'Accept': 'application/json', |
||||
'Content-Type': 'application/json', |
||||
'Authorization': 'Bearer ' + token |
||||
}, |
||||
requestMethod: makeRequest |
||||
baseUrl: config.apiUrl + "/api", |
||||
headers: { |
||||
Accept: "application/json", |
||||
"Content-Type": "application/json", |
||||
Authorization: "Bearer " + token, |
||||
}, |
||||
requestMethod: makeRequest, |
||||
}); |
||||
|
||||
export default restClient; |
@ -1,129 +0,0 @@
@@ -1,129 +0,0 @@
|
||||
import React, { Component } from 'react' |
||||
import PropTypes from 'prop-types' |
||||
import { connect } from 'react-redux' |
||||
import { Table, Popconfirm } from 'antd'; |
||||
import './style.scss'; |
||||
import { setItemFactory, showModal, deleteFactory } from '../../actions'; |
||||
import { getPermissionCheck } from '../../../../lib/helper'; |
||||
import TableGrid from '../../../../components/TableGrid/TableGrig'; |
||||
|
||||
class DataFactory extends Component { |
||||
constructor(props) { |
||||
super(props) |
||||
|
||||
} |
||||
|
||||
|
||||
render() { |
||||
let {data, active_factory, profile} = this.props; |
||||
let permissions = profile.permissions || {}; |
||||
const columns = [ |
||||
{ |
||||
name: 'Назва', |
||||
dataIndex: 'name', |
||||
key: 'name', |
||||
resizable: true, |
||||
sortable: true, |
||||
filter: true, |
||||
}, |
||||
{ |
||||
name: 'Дії', |
||||
key: 'action', |
||||
width: 100, |
||||
formatter: ({row}) => ( |
||||
<span> |
||||
{getPermissionCheck('factory', 'update', profile) ? <a className="lnr lnr-pencil" href='javascript:;' onClick={() => { |
||||
this.props.setItemFactory(row); |
||||
this.props.showModal(true); |
||||
}}></a> : null} |
||||
<span style={{padding: '10px'}}> </span> |
||||
{getPermissionCheck('factory', 'destroy', profile) ? <Popconfirm |
||||
title="Ви справді хочете видалити?" |
||||
onConfirm={() => {this.props.deleteFactory(row.id)}} |
||||
> |
||||
<a className="lnr lnr-trash" href="javascript:;"></a> |
||||
</Popconfirm> : null} |
||||
</span> |
||||
), |
||||
} |
||||
]; |
||||
|
||||
let clientHeight = document.body.clientHeight - 128 - 52 - 90; |
||||
|
||||
let collumsList = [ |
||||
{title: 'Назва', key: 'name'}, |
||||
{title: 'Дії', key: 'action'}, |
||||
|
||||
]; |
||||
|
||||
let defaultCollumsActive = ['name', 'action']; |
||||
|
||||
|
||||
return <div><TableGrid |
||||
data_table={data.filter(item => item.parent_factory == active_factory)} |
||||
columns={columns} |
||||
tableName={'log_users'} |
||||
tableHeight={clientHeight} |
||||
collumsList={collumsList} |
||||
defaultCollumsActive={defaultCollumsActive} |
||||
onRow={(record, rowIndex) => { |
||||
return { |
||||
onDoubleClick: (event) => { |
||||
// history.push('/profile/' + record.id) |
||||
if(getPermissionCheck('factory', 'update', profile)){ |
||||
this.props.setItemFactory(record); |
||||
this.props.showModal(true); |
||||
} |
||||
}, |
||||
|
||||
}; |
||||
}} |
||||
/></div> |
||||
|
||||
return ( |
||||
<div> |
||||
<Table |
||||
dataSource={data.filter(item => item.parent_factory == active_factory)} |
||||
bordered |
||||
pagination={false} |
||||
onRow={(record, rowIndex) => { |
||||
return { |
||||
onClick: (event) => {}, // click row |
||||
onDoubleClick: (event) => { |
||||
// history.push('/profile/' + record.id) |
||||
if(getPermissionCheck('factory', 'update', profile)){ |
||||
this.props.setItemFactory(record); |
||||
this.props.showModal(true); |
||||
} |
||||
}, // double click row |
||||
onContextMenu: (event) => {}, // right button click row |
||||
onMouseEnter: (event) => {}, // mouse enter row |
||||
onMouseLeave: (event) => {}, // mouse leave row |
||||
}; |
||||
}} |
||||
columns={columns} |
||||
rowKey={(record) => record.id} |
||||
/> |
||||
</div> |
||||
) |
||||
} |
||||
} |
||||
|
||||
DataFactory.propTypes = { |
||||
|
||||
} |
||||
|
||||
const mapStateToProps = (state, ownProps) => ({ |
||||
is_load: state.factory.is_load, |
||||
data: state.factory.data, |
||||
active_factory: state.factory.active_factory, |
||||
profile: state.auth.profile, |
||||
}) |
||||
|
||||
const mapDispatchToProps = { |
||||
setItemFactory, |
||||
deleteFactory, |
||||
showModal |
||||
} |
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(DataFactory) |
@ -1,9 +0,0 @@
@@ -1,9 +0,0 @@
|
||||
.factory { |
||||
.ant-table-wrapper{ |
||||
.ant-empty-image{ |
||||
img{ |
||||
width: auto; |
||||
} |
||||
} |
||||
} |
||||
} |
@ -1,119 +0,0 @@
@@ -1,119 +0,0 @@
|
||||
import React, { Component } from 'react' |
||||
import PropTypes from 'prop-types' |
||||
import { connect } from 'react-redux' |
||||
import validationFields from '../../../../lib/validate'; |
||||
import { Field, reduxForm } from 'redux-form'; |
||||
import InputField from '../../../../components/Fields/InputField'; |
||||
import {ButtonToolbar, Button} from 'reactstrap' |
||||
import TreeSelectField from '../../../../components/Fields/TreeSelectField'; |
||||
import { genTree } from '../../../../lib/helper'; |
||||
import _ from 'lodash' |
||||
import SelectField from '../../../../components/Fields/SelectField'; |
||||
import { createFactory, updateFactory, showModal } from '../../actions'; |
||||
import SelectMultyField from '../../../../components/Fields/SelectMultyField'; |
||||
|
||||
|
||||
|
||||
class FormFactory extends Component { |
||||
constructor(props) { |
||||
super(props) |
||||
|
||||
} |
||||
|
||||
submit = (values) => { |
||||
if(values.id){ |
||||
this.props.updateFactory(values.id, values); |
||||
} else { |
||||
this.props.createFactory(values); |
||||
} |
||||
this.props.showModal(false); |
||||
} |
||||
|
||||
render() { |
||||
let {handleSubmit, factory, users} = this.props; |
||||
return ( |
||||
<form className="form" onSubmit={handleSubmit(this.submit)}> |
||||
<Field |
||||
name='name' |
||||
component={InputField} |
||||
type="text" |
||||
placeholder="Назва" |
||||
label="Назва" |
||||
/> |
||||
<Field |
||||
name='short_name' |
||||
component={InputField} |
||||
type="text" |
||||
placeholder="Коротка назва" |
||||
label="Коротка назва" |
||||
/> |
||||
<Field |
||||
name='parent_factory' |
||||
component={TreeSelectField} |
||||
placeholder="Батьківська категорія" |
||||
label="Батьківська категорія" |
||||
tree={genTree(_.cloneDeep(factory), undefined, undefined, 'parent_factory')} |
||||
/> |
||||
<Field |
||||
name='director' |
||||
component={SelectField} |
||||
placeholder="Директор" |
||||
label="Директор" |
||||
options={users.map(item => ({title: item.name, value: item.id}))} |
||||
/> |
||||
<Field |
||||
name='director_permissions' |
||||
component={SelectMultyField} |
||||
placeholder="Права доступу на підприємство" |
||||
label="Права доступу на підприємство" |
||||
options={[ |
||||
{title: 'Перегляд задач', value: 'find'}, |
||||
{title: 'Створення задач', value: 'create'}, |
||||
{title: 'Редагування задач', value: 'update'}, |
||||
{title: 'Видалення задач', value: 'destroy'}, |
||||
]} |
||||
/> |
||||
<ButtonToolbar className="form__button-toolbar"> |
||||
<Button color="primary" type="submit">Зберегти</Button> |
||||
</ButtonToolbar> |
||||
</form> |
||||
) |
||||
} |
||||
} |
||||
|
||||
FormFactory.propTypes = { |
||||
|
||||
} |
||||
|
||||
FormFactory = reduxForm({ |
||||
form: 'form_factory', |
||||
validate: (values) => { |
||||
let fields = [ |
||||
{name: 'name', rules: [{name: 'required', message: 'Заповнити обовязково'}]}, |
||||
// {name: 'password', rules: [{name: 'required', message: 'Заповнити обовязково'}]}, |
||||
] |
||||
|
||||
let error = validationFields(fields, values); |
||||
|
||||
if(values.id == values.parent_factory && values.parent_factory){ |
||||
error.parent_factory = 'Невірна батьківська категорія' |
||||
} |
||||
|
||||
return error; |
||||
|
||||
} |
||||
})(FormFactory); |
||||
|
||||
const mapStateToProps = (state, ownProps) => ({ |
||||
factory: state.factory.data, |
||||
initialValues: Object.assign({}, state.factory.item_factory) , |
||||
users: state.factory.users, |
||||
}) |
||||
|
||||
const mapDispatchToProps = { |
||||
createFactory, |
||||
updateFactory, |
||||
showModal, |
||||
} |
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(FormFactory) |
@ -0,0 +1,167 @@
@@ -0,0 +1,167 @@
|
||||
import React, { FC } from "react"; |
||||
import { ButtonToolbar, Button } from "reactstrap"; |
||||
import _ from "lodash"; |
||||
import { |
||||
IFactory, |
||||
InputField, |
||||
IUser, |
||||
SelectField, |
||||
SelectMultiField, |
||||
} from "@/shared"; |
||||
import { Controller, useForm } from "react-hook-form"; |
||||
import { TreeSelectField } from "@/components/Fields"; |
||||
import { genTree } from "@/lib/helper"; |
||||
import { |
||||
ICreateFactory, |
||||
IUpdateFactory, |
||||
} from "@/api/factories/requests.interface"; |
||||
|
||||
interface IProps { |
||||
selectedFactory: IFactory; |
||||
factories: IFactory[]; |
||||
users: IUser[]; |
||||
updateFactory: (factory: IUpdateFactory) => void; |
||||
createFactory: (factory: ICreateFactory) => void; |
||||
closeModal: () => void; |
||||
} |
||||
|
||||
export const FormFactory: FC<IProps> = ({ |
||||
selectedFactory, |
||||
factories, |
||||
users, |
||||
updateFactory, |
||||
createFactory, |
||||
closeModal, |
||||
}) => { |
||||
const { control, handleSubmit } = useForm<Omit<IFactory, "children">>({ |
||||
defaultValues: { ...selectedFactory }, |
||||
}); |
||||
|
||||
const filterParentsTree = ( |
||||
factories: IFactory[], |
||||
selectedFactory: IFactory |
||||
) => { |
||||
const filteredFactories = factories.filter((it) => { |
||||
return it.id !== selectedFactory.id && it.id !== selectedFactory.parentId; |
||||
}); |
||||
|
||||
for (let i; i < filteredFactories.length; i++) { |
||||
if (filteredFactories[i].children.length) { |
||||
filterParentsTree(filteredFactories[i].children, selectedFactory); |
||||
} |
||||
} |
||||
|
||||
return filteredFactories; |
||||
}; |
||||
|
||||
const getParentsTree = () => { |
||||
let parentsTree: any; |
||||
|
||||
if (selectedFactory) { |
||||
const filteredFactories = filterParentsTree(factories, selectedFactory); |
||||
|
||||
parentsTree = genTree( |
||||
filteredFactories, |
||||
undefined, |
||||
undefined, |
||||
"parentId" |
||||
); |
||||
} else { |
||||
parentsTree = genTree(factories, undefined, undefined, "parentId"); |
||||
} |
||||
|
||||
return parentsTree; |
||||
}; |
||||
|
||||
const submit = (values) => { |
||||
if (values.id) { |
||||
updateFactory(values); |
||||
} else { |
||||
createFactory(values); |
||||
} |
||||
closeModal(); |
||||
}; |
||||
|
||||
const parentCategoryTree = getParentsTree(); |
||||
|
||||
return ( |
||||
<form className="form" onSubmit={handleSubmit(submit)}> |
||||
<Controller |
||||
name="name" |
||||
control={control} |
||||
render={({ field: { value, onChange } }) => ( |
||||
<InputField |
||||
placeholder={"Назва"} |
||||
label={"Назва"} |
||||
onChange={onChange} |
||||
value={value} |
||||
/> |
||||
)} |
||||
/> |
||||
|
||||
<Controller |
||||
name="shortName" |
||||
control={control} |
||||
render={({ field: { value, onChange } }) => ( |
||||
<InputField |
||||
placeholder={"Коротка назва"} |
||||
label={"Коротка назва"} |
||||
onChange={onChange} |
||||
value={value} |
||||
/> |
||||
)} |
||||
/> |
||||
|
||||
<Controller |
||||
name="parentId" |
||||
control={control} |
||||
render={({ field: { onChange, onBlur, value, ref } }) => ( |
||||
<TreeSelectField |
||||
register={{ onChange, onBlur, ref, value }} |
||||
label="Батьківська категорія" |
||||
placeholder="Батьківська категорія" |
||||
tree={parentCategoryTree} |
||||
/> |
||||
)} |
||||
/> |
||||
|
||||
<Controller |
||||
name="directorId" |
||||
control={control} |
||||
defaultValue={5} |
||||
render={({ field: { onChange } }) => ( |
||||
<SelectField |
||||
onChange={onChange} |
||||
label="Директор" |
||||
placeholder="Директор" |
||||
options={users} |
||||
/> |
||||
)} |
||||
/> |
||||
|
||||
<Controller |
||||
name="usersAccessPermission" |
||||
control={control} |
||||
render={({ field: { onChange } }) => ( |
||||
<SelectMultiField |
||||
onChange={onChange} |
||||
label="Права доступу на підприємство" |
||||
placeholder="Права доступу на підприємство" |
||||
options={[ |
||||
{ title: "Перегляд задач", value: "find" }, |
||||
{ title: "Створення задач", value: "create" }, |
||||
{ title: "Редагування задач", value: "update" }, |
||||
{ title: "Видалення задач", value: "destroy" }, |
||||
]} |
||||
/> |
||||
)} |
||||
/> |
||||
|
||||
<ButtonToolbar className="form__button-toolbar"> |
||||
<Button color="primary" type="submit"> |
||||
Зберегти |
||||
</Button> |
||||
</ButtonToolbar> |
||||
</form> |
||||
); |
||||
}; |
@ -1,69 +0,0 @@
@@ -1,69 +0,0 @@
|
||||
import React, { Component } from 'react' |
||||
import PropTypes from 'prop-types' |
||||
import { Button, Modal, ModalHeader, ModalBody, ModalFooter } from 'reactstrap'; |
||||
import { connect } from 'react-redux' |
||||
import { showModal } from '../../actions'; |
||||
import FormFactory from '../FormFactory' |
||||
|
||||
class ModalForm extends Component { |
||||
constructor(props) { |
||||
super(props) |
||||
} |
||||
|
||||
componentWillMount() { |
||||
|
||||
} |
||||
|
||||
componentDidMount() { |
||||
|
||||
} |
||||
|
||||
componentWillReceiveProps(nextProps) { |
||||
|
||||
} |
||||
|
||||
componentWillUnmount() { |
||||
|
||||
} |
||||
|
||||
toggle = () => { |
||||
this.props.showModal(false) |
||||
} |
||||
|
||||
|
||||
render() { |
||||
let {show_modal} = this.props; |
||||
let color = 'primary'; |
||||
return ( |
||||
<Modal |
||||
isOpen={show_modal} |
||||
toggle={this.toggle} |
||||
className={`modal-dialog--${color} modal-dialog--header`} |
||||
> |
||||
<div className="modal__header"> |
||||
<button className="lnr lnr-cross modal__close-btn" type="button" onClick={this.toggle} /> |
||||
<h4 className="bold-text modal__title" style={{color: 'white'}}>Підприємство</h4> |
||||
</div> |
||||
<div className="modal__body"> |
||||
<FormFactory/> |
||||
</div> |
||||
</Modal> |
||||
) |
||||
} |
||||
} |
||||
|
||||
ModalForm.propTypes = { |
||||
|
||||
} |
||||
|
||||
|
||||
|
||||
const mapStateToProps = (state, ownProps) => ({ |
||||
show_modal: state.factory.show_modal, |
||||
}) |
||||
|
||||
const mapDispatchToProps = { |
||||
showModal |
||||
} |
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(ModalForm) |
@ -0,0 +1,57 @@
@@ -0,0 +1,57 @@
|
||||
import { |
||||
ICreateFactory, |
||||
IUpdateFactory, |
||||
} from "@/api/factories/requests.interface"; |
||||
import { IFactory, Loader } from "@/shared"; |
||||
import React, { FC } from "react"; |
||||
import { Modal } from "reactstrap"; |
||||
import { FormFactory } from "../FormFactory"; |
||||
|
||||
interface IProps { |
||||
isOpen: boolean; |
||||
selectedFactory: IFactory; |
||||
factories: IFactory[]; |
||||
closeModal: () => void; |
||||
createFactory: (factory: ICreateFactory) => void; |
||||
updateFactory: (factory: IUpdateFactory) => void; |
||||
} |
||||
|
||||
export const ModalForm: FC<IProps> = ({ |
||||
isOpen, |
||||
selectedFactory, |
||||
factories, |
||||
closeModal, |
||||
createFactory, |
||||
updateFactory, |
||||
}) => { |
||||
return ( |
||||
<Modal |
||||
isOpen={isOpen} |
||||
toggle={closeModal} |
||||
className={`modal-dialog--primary modal-dialog--header`} |
||||
> |
||||
<div className="modal__header"> |
||||
<button |
||||
className="lnr lnr-cross modal__close-btn" |
||||
type="button" |
||||
onClick={closeModal} |
||||
/> |
||||
|
||||
<h4 className="bold-text modal__title" style={{ color: "white" }}> |
||||
Підприємство |
||||
</h4> |
||||
</div> |
||||
|
||||
<div className="modal__body"> |
||||
<FormFactory |
||||
selectedFactory={selectedFactory} |
||||
factories={factories} |
||||
users={[]} |
||||
closeModal={closeModal} |
||||
updateFactory={updateFactory} |
||||
createFactory={createFactory} |
||||
/> |
||||
</div> |
||||
</Modal> |
||||
); |
||||
}; |
@ -1,167 +0,0 @@
@@ -1,167 +0,0 @@
|
||||
import React, { Component } from 'react'; |
||||
import PropTypes from 'prop-types'; |
||||
import {Tree, Popconfirm, Input } from 'antd'; |
||||
import { connect } from 'react-redux'; |
||||
import { genTree, getPermissionCheck } from '../../../../lib/helper'; |
||||
import _ from 'lodash'; |
||||
import { selectFactory, setItemFactory, showModal, deleteFactory } from '../../actions'; |
||||
import './style.scss'; |
||||
const { Search } = Input; |
||||
|
||||
|
||||
const getParentKey = (id, tree) => { |
||||
let parentKey; |
||||
for (let i = 0; i < tree.length; i++) { |
||||
const node = tree[i]; |
||||
if (node.children) { |
||||
if (node.children.some(item => item.id === id)) { |
||||
parentKey = node.id; |
||||
} else if (getParentKey(id, node.children)) { |
||||
parentKey = getParentKey(id, node.children); |
||||
} |
||||
} |
||||
} |
||||
return parentKey; |
||||
}; |
||||
|
||||
|
||||
|
||||
class TreeFactory extends Component { |
||||
constructor(props) { |
||||
super(props) |
||||
this.state = { |
||||
autoExpandParent: false, |
||||
searchValue: '', |
||||
expandedKeys: [] |
||||
} |
||||
} |
||||
|
||||
onSelect = (value) => { |
||||
// if(value[0]){ |
||||
// this.props.selectFactory(value[0]); |
||||
// } else { |
||||
// this.props.selectFactory(null); |
||||
// } |
||||
} |
||||
|
||||
onExpand = expandedKeys => { |
||||
this.setState({ |
||||
expandedKeys, |
||||
autoExpandParent: false, |
||||
}); |
||||
}; |
||||
|
||||
renderTitle = (item) => { |
||||
let {profile} = this.props; |
||||
|
||||
const {searchValue} = this.state; |
||||
|
||||
const index = item.name.indexOf(searchValue); |
||||
const beforeStr = item.name.substr(0, index); |
||||
const afterStr = item.name.substr(index + searchValue.length); |
||||
|
||||
const title = index > -1 ? ( |
||||
<span> |
||||
{beforeStr} |
||||
<span style={{color: 'white', background: '#0cbf00'}}>{searchValue}</span> |
||||
{afterStr} |
||||
</span> |
||||
) : ( |
||||
<span>{item.name}</span> |
||||
); |
||||
|
||||
return <div className="tree-title" onDoubleClick={() => { |
||||
|
||||
console.log("TreeFactory -> renderTitle -> item", item) |
||||
this.props.setItemFactory(item); |
||||
this.props.showModal(true); |
||||
}}> |
||||
{(item.children && item.children.length) && <i className="fas fa-folder"></i>} |
||||
{(!item.children || !item.children.length) && <i className="lnr lnr-apartment"></i>} |
||||
<div className="text">{title}</div> |
||||
{getPermissionCheck('factory', 'destroy', profile) ? <Popconfirm |
||||
title="Ви справді хочете видалити?" |
||||
onConfirm={() => {this.props.deleteFactory(item.id)}} |
||||
> |
||||
<a className="lnr lnr-trash" href="javascript:;"></a> |
||||
</Popconfirm> : null} |
||||
</div> |
||||
} |
||||
|
||||
renderTree = (tree) => { |
||||
if(Array.isArray(tree)){ |
||||
return tree.map(item => <Tree.TreeNode title={this.renderTitle(item)} key={item.id}> |
||||
{item.children ? this.renderTree(item.children) : null} |
||||
</Tree.TreeNode>) |
||||
} |
||||
} |
||||
|
||||
onChange = (e) => { |
||||
const { value } = e.target; |
||||
let {data} = this.props; |
||||
if(!value){ |
||||
this.setState({ |
||||
searchValue: value, |
||||
expandedKeys: [], |
||||
autoExpandParent: true, |
||||
}); |
||||
return; |
||||
} |
||||
let tree = genTree(_.cloneDeep(data)); |
||||
const expandedKeys = data |
||||
.map(item => { |
||||
if (item.name.indexOf(value) > -1) { |
||||
return getParentKey(item.id, tree); |
||||
} |
||||
return null; |
||||
}) |
||||
.filter((item, i, self) => item && self.indexOf(item) === i); |
||||
this.setState({ |
||||
searchValue: value, |
||||
expandedKeys, |
||||
autoExpandParent: true, |
||||
}); |
||||
} |
||||
|
||||
render() { |
||||
let {data} = this.props; |
||||
let tree = genTree(_.cloneDeep(data)); |
||||
const { autoExpandParent, expandedKeys } = this.state; |
||||
return ( |
||||
<div className="TreeFactory"> |
||||
<Search style={{ marginBottom: 8, maxWidth: 200 }} placeholder="Search" onChange={this.onChange} /> |
||||
<Tree |
||||
onSelect={this.onSelect} |
||||
showArrow |
||||
autoExpandParent={autoExpandParent} |
||||
onExpand={this.onExpand} |
||||
expandedKeys={expandedKeys} |
||||
> |
||||
{this.renderTree(tree)} |
||||
|
||||
</Tree> |
||||
</div> |
||||
) |
||||
} |
||||
} |
||||
|
||||
TreeFactory.propTypes = { |
||||
|
||||
} |
||||
|
||||
|
||||
|
||||
const mapStateToProps = (state, ownProps) => ({ |
||||
is_load: state.factory.is_load, |
||||
data: state.factory.data, |
||||
profile: state.auth.profile, |
||||
}) |
||||
|
||||
const mapDispatchToProps = { |
||||
selectFactory, |
||||
setItemFactory, |
||||
showModal, |
||||
deleteFactory, |
||||
} |
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(TreeFactory) |
@ -0,0 +1,151 @@
@@ -0,0 +1,151 @@
|
||||
import { Input, Popconfirm, Tree } from "antd"; |
||||
import React, { FC, useMemo, useState, useCallback, useEffect } from "react"; |
||||
import { genTree, getPermissionCheck } from "@/lib/helper"; |
||||
import _ from "lodash"; |
||||
import { IFactory, IUser } from "@/shared"; |
||||
import "./style.scss"; |
||||
|
||||
interface IProps { |
||||
factories: IFactory[]; |
||||
profile: IUser; |
||||
openModal: () => void; |
||||
setSelectedFactory: (factory: IFactory) => void; |
||||
deleteFactory: (id: number) => void; |
||||
} |
||||
|
||||
export const TreeFactory: FC<IProps> = ({ |
||||
factories, |
||||
profile, |
||||
openModal, |
||||
deleteFactory, |
||||
setSelectedFactory, |
||||
}) => { |
||||
const [searchVal, setSearchVal] = useState<string>(""); |
||||
const [expandedKeys, setExpandedKeys] = useState<string[]>([]); |
||||
const [autoExpandParent, setAutoExpandParent] = useState<boolean>(false); |
||||
|
||||
const preparedTree = genTree(_.cloneDeep(factories)); |
||||
|
||||
const getParentKey = (id, tree) => { |
||||
let parentKey; |
||||
|
||||
tree.forEach((el) => { |
||||
if (el.children) { |
||||
if (el.children.some((it) => it.id === id)) { |
||||
parentKey = el.id; |
||||
} else if (getParentKey(id, el.children)) { |
||||
parentKey = getParentKey(id, el.children); |
||||
} |
||||
} |
||||
}); |
||||
|
||||
return parentKey; |
||||
}; |
||||
|
||||
const findParentKeys = (arr: IFactory[], str: string): string[] => |
||||
arr |
||||
.map((item) => { |
||||
if (item.name.toLowerCase().indexOf(str.toLowerCase()) > -1) { |
||||
const parentKey = getParentKey(item.id, preparedTree); |
||||
|
||||
return parentKey; |
||||
} |
||||
if (item.children.length) return findParentKeys(item.children, str); |
||||
}) |
||||
.filter((item, i, self) => { |
||||
return item && self.indexOf(item) === i; |
||||
}); |
||||
|
||||
const onExpend = (expandedKeys: string[]) => { |
||||
setExpandedKeys(expandedKeys); |
||||
setAutoExpandParent(false); |
||||
}; |
||||
|
||||
const onChange = (value: string) => { |
||||
if (!value) { |
||||
setSearchVal(value); |
||||
setExpandedKeys([]); |
||||
setAutoExpandParent(true); |
||||
return; |
||||
} |
||||
|
||||
const expandedKeys = findParentKeys(factories, value); |
||||
|
||||
setSearchVal(value); |
||||
setAutoExpandParent(true); |
||||
setExpandedKeys(expandedKeys); |
||||
}; |
||||
|
||||
const renderTitle = (item) => { |
||||
const index = item.name.indexOf(searchVal); |
||||
const beforeStr = item.name.substr(0, index); |
||||
const afterStr = item.name.substr(index + searchVal.length); |
||||
|
||||
const title = |
||||
index > -1 ? ( |
||||
<span> |
||||
{beforeStr} |
||||
<span style={{ color: "white", background: "#0cbf00" }}> |
||||
{searchVal} |
||||
</span> |
||||
{afterStr} |
||||
</span> |
||||
) : ( |
||||
<span>{item.name}</span> |
||||
); |
||||
|
||||
return ( |
||||
<div |
||||
className="tree-title" |
||||
onClick={() => { |
||||
setSelectedFactory(item); |
||||
}} |
||||
> |
||||
<div style={{ display: "flex" }} onClick={openModal}> |
||||
{item.children.length ? <i className="fas fa-folder" /> : null} |
||||
{!item.children.length ? <i className="lnr lnr-apartment" /> : null} |
||||
<div className="text">{title}</div> |
||||
</div> |
||||
{getPermissionCheck("factory", "destroy", profile) && ( |
||||
<Popconfirm |
||||
title="Ви справді хочете видалити?" |
||||
onConfirm={() => deleteFactory(item.id)} |
||||
> |
||||
<a className="lnr lnr-trash" href="javascript:;" /> |
||||
</Popconfirm> |
||||
)} |
||||
</div> |
||||
); |
||||
}; |
||||
|
||||
const renderTree = useCallback( |
||||
(preparedTree) => { |
||||
if (Array.isArray(preparedTree)) { |
||||
return preparedTree.map((item) => ( |
||||
<Tree.TreeNode title={renderTitle(item)} key={item.id}> |
||||
{item.children ? renderTree(item.children) : null} |
||||
</Tree.TreeNode> |
||||
)); |
||||
} |
||||
}, |
||||
[factories, searchVal] |
||||
); |
||||
|
||||
return ( |
||||
<div className="TreeFactory"> |
||||
<Input.Search |
||||
style={{ marginBottom: 8, maxWidth: 200 }} |
||||
placeholder="Search" |
||||
onChange={(e) => onChange(e.target.value)} |
||||
/> |
||||
|
||||
<Tree |
||||
onExpand={onExpend} |
||||
autoExpandParent={autoExpandParent} |
||||
expandedKeys={expandedKeys} |
||||
> |
||||
{renderTree(preparedTree)} |
||||
</Tree> |
||||
</div> |
||||
); |
||||
}; |
@ -0,0 +1 @@
@@ -0,0 +1 @@
|
||||
export * from "./use-factory.hook"; |
@ -0,0 +1,69 @@
@@ -0,0 +1,69 @@
|
||||
import { useSelector } from "react-redux"; |
||||
import { IUpdateFactory } from "./../../../api/factories/requests.interface"; |
||||
import { useEffect, useState } from "react"; |
||||
import { factoriesService } from "@/services/domain"; |
||||
import { IFactory } from "@/shared"; |
||||
import { ICreateFactory } from "@/api/factories/requests.interface"; |
||||
import { isLoadingFactories } from "@/store/factories"; |
||||
|
||||
export const useFactory = () => { |
||||
const [factories, setFactories] = useState<IFactory[]>([]); |
||||
const [needRefetch, setRefetch] = useState<boolean>(false); |
||||
|
||||
const isLoading = useSelector(isLoadingFactories); |
||||
|
||||
const fetchFactories = async () => { |
||||
const factories = await factoriesService.fetchFactories(); |
||||
|
||||
setFactories(factories); |
||||
}; |
||||
|
||||
useEffect(() => { |
||||
fetchFactories(); |
||||
}, []); |
||||
|
||||
useEffect( |
||||
() => { |
||||
if (needRefetch) { |
||||
fetchFactories(); |
||||
setRefetch(false); |
||||
} |
||||
}, |
||||
[needRefetch] |
||||
); |
||||
|
||||
const createFactory = async (factory: ICreateFactory) => { |
||||
const createdFactory = await factoriesService.createFactory(factory); |
||||
|
||||
setRefetch(true); |
||||
}; |
||||
|
||||
const updateFactory = async (factory: IUpdateFactory) => { |
||||
const updatedFactory = await factoriesService.updateFactory(factory); |
||||
|
||||
factories.forEach((it) => { |
||||
if (it.id !== factory.id) return it; |
||||
else return updatedFactory; |
||||
}); |
||||
|
||||
setFactories(factories); |
||||
setRefetch(true); |
||||
}; |
||||
|
||||
const deleteFactory = async (id: number) => { |
||||
await factoriesService.deleteFactory(id); |
||||
|
||||
factories.filter((it) => it.id !== id); |
||||
|
||||
setFactories(factories); |
||||
setRefetch(true); |
||||
}; |
||||
|
||||
return { |
||||
factories, |
||||
isLoading, |
||||
createFactory, |
||||
updateFactory, |
||||
deleteFactory, |
||||
}; |
||||
}; |
@ -1,103 +0,0 @@
@@ -1,103 +0,0 @@
|
||||
import React, { Component } from 'react' |
||||
import PropTypes from 'prop-types' |
||||
import { Col, Container, Row, Card, CardBody, Button } from 'reactstrap'; |
||||
import { connect } from 'react-redux' |
||||
import TreeFactory from './components/TreeFactory'; |
||||
import { getFactory, showModal, setItemFactory, deleteFactory } from './actions'; |
||||
import DataFactory from './components/DataFactory'; |
||||
import ModalForm from './components/ModalForm' |
||||
import { Popconfirm } from 'antd'; |
||||
import { getPermissionCheck } from '../../lib/helper'; |
||||
import histoty from '../../lib/histoty'; |
||||
import './style.scss'; |
||||
|
||||
class Factory extends Component { |
||||
constructor(props) { |
||||
super(props) |
||||
|
||||
} |
||||
|
||||
componentWillMount() { |
||||
|
||||
} |
||||
|
||||
componentDidMount() { |
||||
this.props.getFactory() |
||||
} |
||||
|
||||
componentWillReceiveProps(nextProps) { |
||||
|
||||
} |
||||
|
||||
componentWillUnmount() { |
||||
|
||||
} |
||||
|
||||
render() { |
||||
let {active_factory, profile} = this.props; |
||||
let permissions = profile.permissions || {}; |
||||
if(!getPermissionCheck('factory', 'find', profile)){ |
||||
histoty.push('/'); |
||||
} |
||||
return ( |
||||
<Container className="factory"> |
||||
<Row> |
||||
<Col md={12}> |
||||
<Card> |
||||
<CardBody> |
||||
<ModalForm/> |
||||
<Row> |
||||
<div className='col-md-12 justify-content-end flex'> |
||||
{getPermissionCheck('factory', 'create', profile) ? <Button color="primary" size='sm' onClick={() => { |
||||
this.props.setItemFactory({}); |
||||
this.props.showModal(true); |
||||
}}><i className="fal fa-building"></i> Створити</Button> : null} |
||||
{/* {getPermissionCheck('factory', 'destroy', profile) ? <Popconfirm |
||||
title="Ви справді хочете видалити?" |
||||
onConfirm={() => { |
||||
this.props.deleteFactory(active_factory) |
||||
}} |
||||
disabled={!active_factory} |
||||
> |
||||
<Button color="danger" disabled={!active_factory} size='sm'> <i className="fal fa-trash-alt"></i> Видалити</Button> |
||||
</Popconfirm> : null} */} |
||||
|
||||
</div> |
||||
</Row> |
||||
<Row> |
||||
<Col md={12}> |
||||
<TreeFactory/> |
||||
</Col> |
||||
|
||||
</Row> |
||||
</CardBody> |
||||
</Card> |
||||
</Col> |
||||
</Row> |
||||
</Container> |
||||
) |
||||
} |
||||
} |
||||
|
||||
Factory.propTypes = { |
||||
|
||||
} |
||||
|
||||
|
||||
|
||||
const mapStateToProps = (state, ownProps) => ({ |
||||
is_load: state.factory.is_load, |
||||
active_factory: state.factory.active_factory, |
||||
data: state.factory.data, |
||||
profile: state.auth.profile, |
||||
}) |
||||
|
||||
const mapDispatchToProps = { |
||||
getFactory, |
||||
setItemFactory, |
||||
deleteFactory, |
||||
showModal, |
||||
|
||||
} |
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(Factory) |
@ -0,0 +1,74 @@
@@ -0,0 +1,74 @@
|
||||
import { getPermissionCheck } from "@/lib/helper"; |
||||
import { IFactory, Loader } from "@/shared"; |
||||
import { getProfile } from "@/store/account"; |
||||
import { Button, Card, Col, Row } from "antd"; |
||||
import React, { FC, useState } from "react"; |
||||
import { useSelector } from "react-redux"; |
||||
import { Container } from "reactstrap"; |
||||
import { ModalForm } from "./components/ModalForm"; |
||||
import { TreeFactory } from "./components/TreeFactory"; |
||||
import { useFactory } from "./hooks"; |
||||
|
||||
export const Factory: FC = () => { |
||||
const [isOpenModal, setOpenModal] = useState<boolean>(false); |
||||
const [selectedFactory, setFactory] = useState<IFactory>(); |
||||
|
||||
const profile = useSelector(getProfile); |
||||
const { |
||||
isLoading, |
||||
factories, |
||||
createFactory, |
||||
updateFactory, |
||||
deleteFactory, |
||||
} = useFactory(); |
||||
|
||||
return ( |
||||
<Container className="factory"> |
||||
<Row> |
||||
<Col md={12} /> |
||||
<Card> |
||||
<ModalForm |
||||
isOpen={isOpenModal} |
||||
selectedFactory={selectedFactory} |
||||
factories={factories} |
||||
closeModal={() => setOpenModal(false)} |
||||
createFactory={createFactory} |
||||
updateFactory={updateFactory} |
||||
/> |
||||
|
||||
<Row> |
||||
<div className="col-md-12 justify-content-end flex"> |
||||
{getPermissionCheck("factory", "create", profile) ? ( |
||||
<Button |
||||
type="primary" |
||||
onClick={() => { |
||||
setOpenModal(true); |
||||
setFactory(null); |
||||
}} |
||||
> |
||||
<i className="fal fa-building" /> Створити |
||||
</Button> |
||||
) : null} |
||||
</div> |
||||
</Row> |
||||
|
||||
<Row> |
||||
<Col md={12}> |
||||
{isLoading ? ( |
||||
<Loader /> |
||||
) : ( |
||||
<TreeFactory |
||||
factories={factories} |
||||
profile={profile} |
||||
openModal={() => setOpenModal(true)} |
||||
setSelectedFactory={setFactory} |
||||
deleteFactory={deleteFactory} |
||||
/> |
||||
)} |
||||
</Col> |
||||
</Row> |
||||
</Card> |
||||
</Row> |
||||
</Container> |
||||
); |
||||
}; |
@ -1,27 +1,31 @@
@@ -1,27 +1,31 @@
|
||||
import React from 'react'; |
||||
import React from "react"; |
||||
import { SignInForm } from "../components"; |
||||
import logo from '@/assets/img/logo_task2.png' |
||||
import logo from "@/assets/img/logo_task2.png"; |
||||
|
||||
interface IProps { } |
||||
interface IProps {} |
||||
|
||||
export const SignIn = (props: IProps) => { |
||||
|
||||
|
||||
return ( |
||||
<div className="account"> |
||||
<div className="account__wrapper"> |
||||
<div className="account__card"> |
||||
<div className="account__head" style={{ border: 'none', paddingLeft: 0 }}> |
||||
<div |
||||
className="account__head" |
||||
style={{ border: "none", paddingLeft: 0 }} |
||||
> |
||||
<h3 className="account__title"> |
||||
<span className="account__logo"> |
||||
<img style={{ width: '140px', marginLeft: '-5px' }} src={logo} /> |
||||
<img |
||||
style={{ width: "140px", marginLeft: "-5px" }} |
||||
src={logo} |
||||
/> |
||||
</span> |
||||
</h3> |
||||
<h4 className="account__subhead subhead"></h4> |
||||
<h4 className="account__subhead subhead" /> |
||||
</div> |
||||
<SignInForm /> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
) |
||||
} |
||||
); |
||||
}; |
||||
|
@ -0,0 +1,65 @@
@@ -0,0 +1,65 @@
|
||||
import { simpleDispatch } from "@/store/store-helpers"; |
||||
import { IFactory } from "@/shared"; |
||||
import { factoriesApi } from "@/api"; |
||||
import { |
||||
ICreateFactory, |
||||
IUpdateFactory, |
||||
} from "@/api/factories/requests.interface"; |
||||
import { FactoriesIsLoading } from "@/store/factories"; |
||||
|
||||
const fetchFactories = async (): Promise<IFactory[]> => { |
||||
simpleDispatch(new FactoriesIsLoading({ isLoading: true })); |
||||
try { |
||||
const { data: factoriesList } = await factoriesApi.fetchFactories(); |
||||
|
||||
return factoriesList; |
||||
} catch (err) { |
||||
console.log("FETCH FACTORIES ERROR: ", err); |
||||
} finally { |
||||
simpleDispatch(new FactoriesIsLoading({ isLoading: false })); |
||||
} |
||||
}; |
||||
|
||||
const createFactory = async (payload: ICreateFactory): Promise<IFactory> => { |
||||
simpleDispatch(new FactoriesIsLoading({ isLoading: true })); |
||||
try { |
||||
const { data: newFactory } = await factoriesApi.createFactory(payload); |
||||
|
||||
return newFactory; |
||||
} catch (err) { |
||||
console.log("CREATE FACTORY ERROR: ", err); |
||||
} finally { |
||||
simpleDispatch(new FactoriesIsLoading({ isLoading: false })); |
||||
} |
||||
}; |
||||
|
||||
const updateFactory = async (payload: IUpdateFactory): Promise<IFactory> => { |
||||
simpleDispatch(new FactoriesIsLoading({ isLoading: true })); |
||||
try { |
||||
const { data: updatedFactory } = await factoriesApi.updateFactory(payload); |
||||
|
||||
return updatedFactory; |
||||
} catch (err) { |
||||
console.log("UPDATE FACTORY ERROR: ", err); |
||||
} finally { |
||||
simpleDispatch(new FactoriesIsLoading({ isLoading: false })); |
||||
} |
||||
}; |
||||
|
||||
const deleteFactory = async (id: number): Promise<void> => { |
||||
simpleDispatch(new FactoriesIsLoading({ isLoading: true })); |
||||
try { |
||||
await factoriesApi.deleteFactory(id); |
||||
} catch (err) { |
||||
console.log("DELETE FACTORY ERROR: ", err); |
||||
} finally { |
||||
simpleDispatch(new FactoriesIsLoading({ isLoading: false })); |
||||
} |
||||
}; |
||||
|
||||
export const factoriesService = { |
||||
fetchFactories, |
||||
createFactory, |
||||
updateFactory, |
||||
deleteFactory, |
||||
}; |
@ -1 +1,4 @@
@@ -1 +1,4 @@
|
||||
export * from './auth.service' |
||||
export * from "./auth.service"; |
||||
export * from "./factories.service"; |
||||
export * from "./account.service"; |
||||
export * from "./taxonomies.service"; |
||||
|
@ -0,0 +1,3 @@
@@ -0,0 +1,3 @@
|
||||
export * from "./input-field.component"; |
||||
export * from "./select-field.component"; |
||||
export * from "./select-multi-field.component"; |
@ -0,0 +1,29 @@
@@ -0,0 +1,29 @@
|
||||
import React, { FC, CSSProperties } from "react"; |
||||
import { Input } from "antd"; |
||||
|
||||
interface IProps { |
||||
label: string; |
||||
value: string | number; |
||||
placeholder: string; |
||||
style?: CSSProperties; |
||||
onChange: (val: string) => void; |
||||
} |
||||
|
||||
export const InputField: FC<IProps> = ({ |
||||
label, |
||||
value, |
||||
placeholder, |
||||
style, |
||||
onChange, |
||||
}) => { |
||||
return ( |
||||
<div style={{ ...style, width: "100%", marginBottom: 20 }}> |
||||
<span>{label}</span> |
||||
<Input |
||||
placeholder={placeholder} |
||||
value={value} |
||||
onChange={({ target: { value } }) => onChange(value)} |
||||
/> |
||||
</div> |
||||
); |
||||
}; |
@ -0,0 +1,54 @@
@@ -0,0 +1,54 @@
|
||||
import React, { FC } from "react"; |
||||
import { Select } from "antd"; |
||||
|
||||
interface IProps { |
||||
options: any[]; |
||||
label: string; |
||||
placeholder: string; |
||||
isDisabled?: boolean; |
||||
touched?: boolean; |
||||
error?: string; |
||||
onChange: (val: string) => void; |
||||
} |
||||
|
||||
export const SelectField: FC<IProps> = ({ |
||||
options, |
||||
label, |
||||
placeholder, |
||||
isDisabled, |
||||
touched, |
||||
error, |
||||
onChange, |
||||
}) => { |
||||
return ( |
||||
<div className="form__form-group select-field"> |
||||
{label ? <span className="form__form-group-label">{label}</span> : null} |
||||
|
||||
<div className="form__form-group-field"> |
||||
<div className="form__form-group-input-wrap"> |
||||
<Select |
||||
showSearch |
||||
style={{ width: "100%" }} |
||||
placeholder={placeholder} |
||||
optionFilterProp="children" |
||||
onChange={onChange} |
||||
disabled={isDisabled} |
||||
allowClear |
||||
filterOption={(input, { props }) => |
||||
props.title.toLowerCase().indexOf(input.toLowerCase()) >= 0 |
||||
} |
||||
> |
||||
{options.map((item, index) => ( |
||||
<Select.Option key={item.value + "-" + index} value={item.value}> |
||||
{item.title} |
||||
</Select.Option> |
||||
))} |
||||
</Select> |
||||
|
||||
{touched && |
||||
error && <span className="form__form-group-error">{error}</span>} |
||||
</div> |
||||
</div> |
||||
</div> |
||||
); |
||||
}; |
@ -0,0 +1,83 @@
@@ -0,0 +1,83 @@
|
||||
import { Select } from "antd"; |
||||
import React, { FC } from "react"; |
||||
|
||||
interface IProps { |
||||
label?: string; |
||||
placeholder: string; |
||||
options: any[]; |
||||
touched?: boolean; |
||||
error?: string; |
||||
input?: any; |
||||
onChange: () => void; |
||||
} |
||||
|
||||
export const SelectMultiField: FC<IProps> = ({ |
||||
label, |
||||
placeholder, |
||||
options, |
||||
touched, |
||||
error, |
||||
input, |
||||
onChange, |
||||
}) => { |
||||
return ( |
||||
<div className="form__form-group select-field"> |
||||
{label ? <span className="form__form-group-label">{label}</span> : null} |
||||
|
||||
<div className="form__form-group-field"> |
||||
<div className="form__form-group-input-wrap"> |
||||
<div style={{ position: "relative" }}> |
||||
<Select |
||||
showSearch |
||||
style={{ width: "100%" }} |
||||
placeholder={placeholder} |
||||
optionFilterProp="children" |
||||
mode="multiple" |
||||
onChange={onChange} |
||||
allowClear |
||||
filterOption={(input, { props }) => |
||||
props.title.toLowerCase().indexOf(input.toLowerCase()) >= 0 |
||||
} |
||||
> |
||||
{options.map((item, index) => ( |
||||
<Select.Option |
||||
key={item.value + "-" + index} |
||||
value={item.value} |
||||
> |
||||
{item.title} |
||||
</Select.Option> |
||||
))} |
||||
</Select> |
||||
|
||||
{!input?.value || !input?.value.length ? ( |
||||
<span |
||||
className="ant-select-arrow" |
||||
style={{ outline: "currentcolor none medium" }} |
||||
> |
||||
<i |
||||
aria-label="icon: down" |
||||
className="anticon anticon-down ant-select-arrow-icon" |
||||
> |
||||
<svg |
||||
viewBox="64 64 896 896" |
||||
className="" |
||||
data-icon="down" |
||||
width="1em" |
||||
height="1em" |
||||
fill="currentColor" |
||||
aria-hidden="true" |
||||
> |
||||
<path d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z" /> |
||||
</svg> |
||||
</i> |
||||
</span> |
||||
) : null} |
||||
</div> |
||||
|
||||
{touched && |
||||
error && <span className="form__form-group-error">{error}</span>} |
||||
</div> |
||||
</div> |
||||
</div> |
||||
); |
||||
}; |
@ -1,3 +1,4 @@
@@ -1,3 +1,4 @@
|
||||
export * from './form' |
||||
export * from './layouts' |
||||
export * from './elements' |
||||
export * from "./form"; |
||||
export * from "./layouts"; |
||||
export * from "./elements"; |
||||
export * from "./fields"; |
||||
|
@ -0,0 +1,15 @@
@@ -0,0 +1,15 @@
|
||||
export interface IFactory { |
||||
id: number; |
||||
name: string; |
||||
shortName: string; |
||||
description: string; |
||||
path?: string; |
||||
directorId: number; |
||||
authorId: number; |
||||
parentId?: number; |
||||
children?: IFactory[]; |
||||
usersAccessPermission: any[]; |
||||
createdAt: string; |
||||
updatedAt: string; |
||||
}; |
||||
|
@ -1,6 +1,7 @@
@@ -1,6 +1,7 @@
|
||||
export * from './token-pair.interfaces' |
||||
export * from './user.interfaces' |
||||
export * from './permissions.interface' |
||||
export * from './comment.interfaces' |
||||
export * from './task.interfaces' |
||||
export * from './taxonomy.interfaces' |
||||
export * from "./token-pair.interfaces"; |
||||
export * from "./user.interfaces"; |
||||
export * from "./permissions.interface"; |
||||
export * from "./comment.interfaces"; |
||||
export * from "./task.interfaces"; |
||||
export * from "./taxonomy.interfaces"; |
||||
export * from "./factories.interfaces"; |
||||
|
@ -1,54 +1,53 @@
@@ -1,54 +1,53 @@
|
||||
import { ETaxonomyType } from "../enums"; |
||||
|
||||
export interface ITaxonomy { |
||||
/** Ідентифікатор */ |
||||
id: number |
||||
/** Ідентифікатор */ |
||||
id: number; |
||||
|
||||
/** Ідентифікатор батьківської таксономії */ |
||||
parentId?: number |
||||
/** Ідентифікатор батьківської таксономії */ |
||||
parentId?: number; |
||||
|
||||
/** Дочерні таксономії */ |
||||
children?: ITaxonomy[] |
||||
/** Дочерні таксономії */ |
||||
children?: ITaxonomy[]; |
||||
|
||||
/** Назва */ |
||||
name?: string |
||||
/** Назва */ |
||||
name?: string; |
||||
|
||||
/** Тип класифікації */ |
||||
type: ETaxonomyType |
||||
/** Тип класифікації */ |
||||
type: ETaxonomyType; |
||||
|
||||
/** Чи видалено */ |
||||
isDeleted?: boolean |
||||
/** Чи видалено */ |
||||
isDeleted?: boolean; |
||||
|
||||
/** Чи за замовчуванням */ |
||||
isDefault?: boolean |
||||
/** Чи за замовчуванням */ |
||||
isDefault?: boolean; |
||||
|
||||
/** Посилання на зображення */ |
||||
iconUrl?: string |
||||
/** Посилання на зображення */ |
||||
iconUrl?: string; |
||||
} |
||||
|
||||
export interface ICreateOrUpdateTaxonomy { |
||||
/** Ідентифікатор */ |
||||
id?: number |
||||
/** Ідентифікатор */ |
||||
id?: number; |
||||
|
||||
/** Ідентифікатор батьківської таксономії */ |
||||
parentId?: number |
||||
/** Ідентифікатор батьківської таксономії */ |
||||
parentId?: number; |
||||
|
||||
/** Дочерні таксономії */ |
||||
children?: ITaxonomy[] |
||||
/** Дочерні таксономії */ |
||||
children?: ITaxonomy[]; |
||||
|
||||
/** Назва */ |
||||
name?: string |
||||
/** Назва */ |
||||
name?: string; |
||||
|
||||
/** Тип класифікації */ |
||||
type: ETaxonomyType |
||||
/** Тип класифікації */ |
||||
type: ETaxonomyType; |
||||
|
||||
/** Чи видалено */ |
||||
isDeleted?: boolean |
||||
/** Чи видалено */ |
||||
isDeleted?: boolean; |
||||
|
||||
/** Чи за замовчуванням */ |
||||
isDefault?: boolean |
||||
|
||||
/** Посилання на зображення */ |
||||
iconUrl?: string |
||||
/** Чи за замовчуванням */ |
||||
isDefault?: boolean; |
||||
|
||||
/** Посилання на зображення */ |
||||
iconUrl?: string; |
||||
} |
||||
|
@ -0,0 +1,3 @@
@@ -0,0 +1,3 @@
|
||||
export * from "./reducer"; |
||||
export * from "./selectors"; |
||||
export * from "./types"; |
@ -0,0 +1,19 @@
@@ -0,0 +1,19 @@
|
||||
import { TFactoriesActions } from "./types"; |
||||
import { createReducer } from "@bitalikrty/redux-create-reducer"; |
||||
|
||||
export interface IFactoriesState { |
||||
isLoading: boolean; |
||||
} |
||||
|
||||
const initialState: IFactoriesState = { |
||||
isLoading: false, |
||||
}; |
||||
|
||||
export const factoriesReducer = createReducer< |
||||
IFactoriesState, |
||||
TFactoriesActions |
||||
>(initialState, { |
||||
IS_LOADING_FACTORIES: (state, action) => { |
||||
return { ...state, isLoading: action.payload.isLoading }; |
||||
}, |
||||
}); |
@ -0,0 +1,4 @@
@@ -0,0 +1,4 @@
|
||||
import { RootState } from "@/store"; |
||||
|
||||
export const isLoadingFactories = (state: RootState) => |
||||
state.factories.isLoading; |
@ -0,0 +1,10 @@
@@ -0,0 +1,10 @@
|
||||
export class FactoriesIsLoading { |
||||
readonly type = "IS_LOADING_FACTORIES"; |
||||
constructor( |
||||
public readonly payload: { |
||||
isLoading: boolean; |
||||
} |
||||
) {} |
||||
} |
||||
|
||||
export type TFactoriesActions = FactoriesIsLoading; |
@ -1,37 +1,31 @@
@@ -1,37 +1,31 @@
|
||||
import { |
||||
createStore, |
||||
combineReducers, |
||||
} from 'redux' |
||||
import { GlobalContainerService } from '@/services/system' |
||||
import { authReducer, IAuthState } from './auth' |
||||
import { composeWithDevTools } from 'redux-devtools-extension' |
||||
import { accountReducer, IAccountState } from "./account" |
||||
import { ISharedState, sharedReducer } from "./shared" |
||||
import { ITaxonomiesState, TaxonomiesReducer } from './taxonomies/reducer'; |
||||
|
||||
import { createStore, combineReducers } from "redux"; |
||||
import { GlobalContainerService } from "@/services/system"; |
||||
import { authReducer, IAuthState } from "./auth"; |
||||
import { composeWithDevTools } from "redux-devtools-extension"; |
||||
import { accountReducer, IAccountState } from "./account"; |
||||
import { ISharedState, sharedReducer } from "./shared"; |
||||
import { ITaxonomiesState, TaxonomiesReducer } from "./taxonomies/reducer"; |
||||
import { factoriesReducer, IFactoriesState } from "./factories"; |
||||
|
||||
const rootReducer = combineReducers<{ |
||||
auth: IAuthState |
||||
account: IAccountState |
||||
taxonomies: ITaxonomiesState |
||||
shared: ISharedState |
||||
auth: IAuthState; |
||||
account: IAccountState; |
||||
taxonomies: ITaxonomiesState; |
||||
shared: ISharedState; |
||||
factories: IFactoriesState; |
||||
}>({ |
||||
auth: authReducer, |
||||
account: accountReducer, |
||||
taxonomies: TaxonomiesReducer, |
||||
// task: taskReducer,
|
||||
shared: sharedReducer, |
||||
}) |
||||
|
||||
export type RootState = ReturnType<typeof rootReducer> |
||||
|
||||
auth: authReducer, |
||||
account: accountReducer, |
||||
taxonomies: TaxonomiesReducer, |
||||
// task: taskReducer,
|
||||
shared: sharedReducer, |
||||
factories: factoriesReducer, |
||||
}); |
||||
|
||||
const store = createStore( |
||||
rootReducer, |
||||
composeWithDevTools() |
||||
) |
||||
export type RootState = ReturnType<typeof rootReducer>; |
||||
|
||||
const store = createStore(rootReducer, composeWithDevTools()); |
||||
|
||||
GlobalContainerService.set('store', store) |
||||
GlobalContainerService.set("store", store); |
||||
|
||||
export default store |
||||
export default store; |
||||
|
Loading…
Reference in new issue